From a6c3f69699a826738bcb8ee2ff0de13540a322d7 Mon Sep 17 00:00:00 2001 From: Pablo Balbi Date: Fri, 16 Oct 2020 15:03:02 +0000 Subject: [PATCH] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 1d9b0ce05914baa8c9d213265122f934bf3ab983 Merge: 2b19a4803 4100ab291 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Fri Oct 16 05:05:29 2020 -0700 Merge pull request #4460 from max-schaefer/js/unsafe-shell-command-construction-infeasible-paths Approved by asgerf commit 2b19a480307728438d4a7270ebfe49c98a266550 Merge: a92a701c3 27fc610c0 Author: Anders Schack-Mulligen Date: Fri Oct 16 13:54:35 2020 +0200 Merge pull request #3880 from hvitved/dataflow/precise-aps Data flow: Precise access paths commit 27fc610c0d99dc76e186efc5b9042f7875392021 Author: Tom Hvitved Date: Mon Sep 21 11:26:59 2020 +0200 Python: Update expected test output commit 5f01fda1ef78e5f8b65fd4be94247e61879d34b6 Author: Tom Hvitved Date: Mon Sep 21 10:29:00 2020 +0200 Data flow: Sync files commit 82e56d4ebb26f255055814c92538c59029a07f46 Author: Tom Hvitved Date: Mon Sep 21 10:27:38 2020 +0200 Data flow: Simplify `pathStep` and `pathIntoCallable` commit 94f110f739cae6ef1adf451b1f2c1d4618797837 Author: Anders Schack-Mulligen Date: Thu Sep 17 10:50:14 2020 +0200 Sync. commit b4ecfaeda3b1bb1b45f159e3a558d92aa573c445 Author: Anders Schack-Mulligen Date: Thu Sep 17 10:19:04 2020 +0200 Dataflow: Remove inconsistent AccessPath.getType(). commit d88c551f640dfe6e1b9a82257b8ec5ebe224ff20 Author: Anders Schack-Mulligen Date: Thu Sep 17 10:09:56 2020 +0200 Dataflow: qldoc fix commit 98f10b29b85d007c1943d0f9d16dbfac6ffde927 Author: Anders Schack-Mulligen Date: Fri Sep 11 10:54:24 2020 +0200 Dataflow: Simplify SCC: remove some apa params. commit 4e2f7860403f270e7633433cd53df367cb75310c Author: Anders Schack-Mulligen Date: Thu Sep 10 16:30:24 2020 +0200 Dataflow: Precalculate AccessPath to avoid massive recursion. commit ca534ccb03b3a635bb14266d482a796f84f68d25 Author: Mathias Vorreiter Pedersen Date: Fri Aug 21 11:24:47 2020 +0200 C++: Update inline expectation comments commit 570b624eb705f9e9c2dd442e5545b2ae69c91f14 Author: Tom Hvitved Date: Thu Jul 2 15:47:43 2020 +0200 C++: Update expected test output commit d48a6a55552e7f758fa6305ab07ca7f888bcf414 Author: Tom Hvitved Date: Thu Jul 2 15:47:33 2020 +0200 C#: Update expected test output commit d608138c0c4f43c1c584d7337dd7408bf23abb38 Author: Tom Hvitved Date: Fri Aug 21 10:28:19 2020 +0200 Data flow: Sync files commit a35a178080d5807f39524039f6bcfd76a5ef00d3 Author: Tom Hvitved Date: Wed Jul 29 13:17:27 2020 +0200 Data flow: Precise access paths commit 0dc066c5157588dc213da73d4b4f431e8da6f412 Author: Tom Hvitved Date: Wed Jul 29 13:17:09 2020 +0200 Data flow: Rename `AccessPath` to `AccessPathApprox` commit a92a701c353ef04072c79311371f47e2c1420ce5 Merge: da9e33a72 a10c0138e Author: Aditya Sharad <6874315+adityasharad@users.noreply.github.com> Date: Thu Oct 15 10:19:25 2020 -0700 Merge pull request #4479 from github/lgtm.com Merge lgtm.com back into main commit da9e33a72ce96db08ea748801bfe9514b87e7f33 Merge: 5142bfaf0 f32a7be87 Author: Mathias Vorreiter Pedersen Date: Thu Oct 15 17:38:16 2020 +0200 Merge pull request #4477 from dbartol/dbartol/PrintIRLocalFlow C++: Add ability to dump local dataflow info in IR dumps commit 5142bfaf017cfef5c7ca5075af0854014dfa003d Merge: 58baec5b0 89f535232 Author: Rasmus Wriedt Larsen Date: Thu Oct 15 17:26:31 2020 +0200 Merge pull request #4453 from yoff/python-port-unsafe-deserialization Python: port unsafe deserialization commit 58baec5b067b995f3709d9e4a052f142ff59c291 Merge: 388f60f81 9c8e968cb Author: Rasmus Wriedt Larsen Date: Thu Oct 15 17:10:59 2020 +0200 Merge pull request #4364 from yoff/SharedDataflow_ArgumentPassing Python: Shared dataflow, argument passing commit 388f60f818112b679f82d006d3e28efa081f2581 Merge: b05cc2eaf b2a2412f1 Author: Joe Farebrother Date: Thu Oct 15 16:05:38 2020 +0100 Merge pull request #4430 from joefarebrother/tainttrackingutils-refactor Java: Refactor part of TaintTrackingUtil.qll commit 89f5352324ceb2e4adfdd00e8e1f305d5c9041ac Author: Rasmus Lerchedahl Petersen Date: Thu Oct 15 16:41:41 2020 +0200 Python: fix QL format commit f32a7be8747c5466b7ff945687f1e4a7ac99ea79 Author: Dave Bartolomeo Date: Thu Oct 15 10:16:13 2020 -0400 Fix formatting commit ef32488596d0394d2e9078f823b0827fefbc459b Merge: cc7d32c27 b05cc2eaf Author: Rasmus Lerchedahl Petersen Date: Thu Oct 15 15:45:35 2020 +0200 Merge branch 'main' of github.com:github/codeql into python-port-unsafe-deserialization commit b05cc2eafd099d56655765803cc664430c739884 Merge: ab7d28b3f fb05f0248 Author: James Fletcher <42464962+jf205@users.noreply.github.com> Date: Thu Oct 15 14:39:52 2020 +0100 Merge pull request #4475 from github/banner-template [CodeQL docs] Update footer in Sphinx template commit fb05f0248982d1c32280975b7999e48f6e878840 Author: James Fletcher <42464962+jf205@users.noreply.github.com> Date: Thu Oct 15 14:24:28 2020 +0100 Apply suggestions from code review Co-authored-by: Shati Patel <42641846+shati-patel@users.noreply.github.com> commit ab7d28b3fb04027f77cbc07cb9a32d5f0e9a15be Merge: 1b8d14077 43cee8567 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Thu Oct 15 06:15:55 2020 -0700 Merge pull request #4482 from RasmusWL/promote-script Approved by tausbn commit 1b8d14077a79c35ec56fa4176dfdccce860c5bfa Merge: e62c9b138 7848c5f54 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Oct 15 13:00:33 2020 +0100 Merge pull request #4481 from rvermeulen/patch-1 C++: Fix qldoc for getIncludeText commit 43cee8567c402a4ac1ad9916b579cb0110154163 Author: Rasmus Wriedt Larsen Date: Mon Sep 28 11:59:26 2020 +0200 Python: Add script to promote experimental security queries commit cc7d32c27c3765734f50633ad491357339739ebe Merge: 172e05843 c36ad7dd9 Author: Rasmus Lerchedahl Petersen Date: Thu Oct 15 13:01:38 2020 +0200 Merge branch 'python-port-unsafe-deserialization' of github.com:yoff/codeql into python-port-unsafe-deserialization commit 172e0584387f686285086d14edc967a995e27808 Author: Rasmus Lerchedahl Petersen Date: Thu Oct 15 12:56:29 2020 +0200 Python: `unsafe` -> `mayExecuteInput` commit 00566f0eee88f7d6682b463672f0cc4150d43b1a Author: Rasmus Lerchedahl Petersen Date: Thu Oct 15 12:40:16 2020 +0200 Python: Extend DataFlow::CfgNode when appropriate commit c36ad7dd9b345da1431227c6bf04cd22178d452c Author: yoff Date: Thu Oct 15 12:35:21 2020 +0200 Apply suggestions from code review Co-authored-by: Taus commit e62c9b1382340d82cc6dfd0277640073b18d30e1 Merge: 36f6e97ca 5a91736b7 Author: Tamás Vajk Date: Thu Oct 15 12:16:53 2020 +0200 Merge pull request #4472 from tamasvajk/feature/cleanup-3 C#: Change public fields to properties commit 36f6e97cad146f9c2be23bfcdffe5f27fdd28a78 Merge: c8b93148a 872801732 Author: Tom Hvitved Date: Thu Oct 15 11:56:32 2020 +0200 Merge pull request #4371 from hvitved/csharp/library-flow-refactor C#: Reimplement flow-summary compilation commit 7848c5f54dcea11d1ec31cdbb9c3f8ddf1de6e8f Author: Remco Vermeulen Date: Thu Oct 15 11:49:18 2020 +0200 Fix qldoc for getIncludeText The '<' was HTML encoded for some reason. commit 9c8e968cba7998af6955c3ea3ba3bfd685948a37 Author: Rasmus Lerchedahl Petersen Date: Thu Oct 15 11:47:34 2020 +0200 Python: Fix bad merge commit c8b93148a2418f2d632b7978d722555d01db8d2e Merge: 60ce02ac1 ce967e124 Author: Taus Date: Thu Oct 15 10:52:43 2020 +0200 Merge pull request #4424 from RasmusWL/python-model-python2-specific-command-execution Python: model Python 2 specific command execution commit 60ce02ac188dc387eaf636e22281b8966208594e Merge: c5810d623 fc71ca747 Author: Anders Schack-Mulligen Date: Thu Oct 15 10:46:35 2020 +0200 Merge pull request #4469 from JLLeitschuh/additional-file-taint Java: Track taint through java.io.File::toPath & java.nio.file.Path::toFile commit 872801732869f2618712f4cf19856287c9cd2ad0 Author: Tom Hvitved Date: Thu Oct 15 10:40:19 2020 +0200 C#: Increase `fieldFlowBranchLimit` in test 68014fd3bf662453f1cd9a44a8b05008e79474e2 means that more accessors are properly extracted, and consequently the calls to `get_Item` in the test have more dispatch targets. Increasing `fieldFlowBranchLimit` makes the test pass again. commit c5810d623b9a3b3d2b261b882bab74fa37865d62 Merge: 466c22f4a f8190feef Author: Rasmus Wriedt Larsen Date: Thu Oct 15 10:29:33 2020 +0200 Merge pull request #4474 from tausbn/python-fix-tostring-divergence Python: Fix divergence in tuple/subscripted type `toString` commit a10c0138e90e96be3b1309794c7f1ba8250f4365 Merge: 535c8cc87 78c58c241 Author: Arthur Baars Date: Thu Oct 15 10:00:43 2020 +0200 Merge commit '78c58c24158e3ee4fd78318194d56591af90da69' into lgtm.com commit ce967e124932557f18609c991b09e6676ed99d28 Merge: 680a6eb2a 466c22f4a Author: Rasmus Wriedt Larsen Date: Thu Oct 15 09:58:20 2020 +0200 Merge branch 'main' into python-model-python2-specific-command-execution commit 0766eef49b10b2fb7b501af2ec5479bb95d87976 Merge: d2b90662a 466c22f4a Author: Rasmus Lerchedahl Petersen Date: Thu Oct 15 09:49:21 2020 +0200 Merge branch 'main' of github.com:github/codeql into SharedDataflow_ArgumentPassing commit dfb687fd47ba8f0145633f790c396c7a7e97026e Author: Dave Bartolomeo Date: Wed Oct 14 18:02:45 2020 -0400 C++: Add ability to dump local dataflow info in IR dumps This change adds a new module, `PrintIRLocalFlow.qll`, which can be imported into any query that uses both `PrintIR.qll` and the IR dataflow library. The IR dump printed by `PrintIR.qll` will be annotated with information about how each operand and instruction participates in dataflow. For each operand and instruction, the following propeties are displayed: - `flow`: Which local operands/instructions have flow to this node, and which local operands/instruction this node has flow to. - `source`: `true` if this node is a source - `sink`: `true` if this node is a sink - `barrier`: Lists which kinds of barrier this node is. Can be zero or more of `full`, `in`, `out`, and `guard`. If the node is a guard barrier, the IR of the guarding instruction is also printed. We already had a way to print additional properties for instructions and blocks, but not for operands. I added support for operand properties to `IRPropertyProvider`. These are now printed in a curly-brace-enclosed list immediately after the corresponding operand. When printing flow, instructions are identified by their result ID (e.g., `m128`). Operands are identified by both the result ID of their instruction and their kind (e.g., `r145.left`). For flow from an operand to its use instruction, it just prints `result` at the operand, and prints only the operand kind on the instruction. Example output: ``` # 344| m344_34(vector>) = Chi : total:m344_20{flow:def->@, @->result}, partial:m344_33{flow:def->@, @->result} # 344| flow = total->@, partial->@, +m344_33->@, @->+r347_3, @->v347_7.side_effect, @->m347_9.total, @->m344_20.1 ``` The `+` annotations indicate when the flow came from `isAdditionalFlowStep()`, rather than built-in local flow. commit 98d8ec488e43632865b8045f9ee534522310da55 Author: james Date: Wed Oct 14 15:41:24 2020 +0100 add banner to sphinx template commit d2b90662a3c2bdc9cac1a477e9e2c546168a038b Author: Rasmus Lerchedahl Petersen Date: Wed Oct 14 17:31:13 2020 +0200 Python: implement ToString on mappings commit 466c22f4a8d805dc464f76360fbe927002d4996c Merge: 5f6f85c99 5db4f906d Author: Taus Date: Wed Oct 14 16:41:42 2020 +0200 Merge pull request #4435 from RasmusWL/python-port-code-injection Python: port code injection query commit 6a3aed337f858ab3441bea55ddf72761ef3cbb3c Author: Rasmus Lerchedahl Petersen Date: Wed Oct 14 16:35:43 2020 +0200 Python `self` -> `range` commit 352418cb5d20923c9b2b9378c88d41e9ba4ce920 Author: Rasmus Lerchedahl Petersen Date: Wed Oct 14 16:33:55 2020 +0200 Python: track safe loaders commit f8190feef27dc591d8a6b0806e4c86be0643fa57 Author: Taus Brock-Nannestad Date: Wed Oct 14 15:21:22 2020 +0200 Python: Fix divergence in tuple/subscripted type `toString` A slightly more complicated version of the situation in https://github.com/github/codeql/pull/2507 could cause the `toString` calculation to diverge. Although the previous PR took tuples nested inside tuples into account (and subscripted types cannot be nested inside each other in our modelling), it did not account for having this nesting be interleaved, and this is what caused the divergence. I have not done the usual "test case first to show the problem exists", since this would also diverge and take forever to fail. The instance observed in `scipy` was likely caused by something akin to ```python x = () while True: x = x[(x,)] ``` Finally, to prevent this from happening with other types, I went through and checked each instance where the string representation of an `ObjectInternal` might potentially contain a reference to itself (and thus explode). I encapsulated this in a `bounded_toString` helper predicate, and used this in all the cases where I was able to determine that the above _could_ happen. commit 5f6f85c9982f4736d978be13765020f30e6882cf Merge: 92ccb795f fdb489fc9 Author: yoff Date: Wed Oct 14 15:37:39 2020 +0200 Merge pull request #4465 from tausbn/python-remove-essa-flow Python: Remove flow between ESSA variables commit b8cba381cf1ec148ae3b6b920b96a935afa7e51b Merge: 3a281a1bd 92ccb795f Author: Rasmus Lerchedahl Petersen Date: Wed Oct 14 15:01:30 2020 +0200 Merge branch 'main' of github.com:github/codeql into python-port-unsafe-deserialization commit 5a91736b7aa19baf2c35ea3ae47ccbf108c764f5 Author: Tamas Vajk Date: Wed Oct 14 14:08:48 2020 +0200 C#: Change public fields to properties commit 3a281a1bd6682815cb6344048f836426f908dd02 Author: Rasmus Lerchedahl Petersen Date: Wed Oct 14 14:40:11 2020 +0200 Python: Adjust comments and tests commit 5db4f906d015b44cff56b4b2ae4b6092b16b0d9f Merge: 1fde477a8 92ccb795f Author: Rasmus Wriedt Larsen Date: Wed Oct 14 14:22:02 2020 +0200 Merge branch 'main' into python-port-code-injection commit 91806da2fa696e08993a04e17dfdce9a34875b8e Author: Tom Hvitved Date: Wed Oct 14 09:38:45 2020 +0200 C#: Address review comments commit 5d1a5920c719e7569ae25ba6fc07eb26d1a5ec38 Author: Tom Hvitved Date: Fri Sep 25 10:40:09 2020 +0200 C#: Reimplement flow-summary compilation commit 444e607338965f218690dc99577bed68579453f4 Author: Tom Hvitved Date: Wed Oct 7 11:57:13 2020 +0200 C#: Add missing flow through library code using `params` arguments commit f2dc2d912a93744acfbacb180aa28dca7e81f60b Author: Tom Hvitved Date: Wed Oct 7 14:00:34 2020 +0200 C#: Add inter-procedural data-flow test for `StringBuilder` commit ffe79f688d67349d1884708d7d9d7200785f9d18 Author: yoff Date: Wed Oct 14 14:08:16 2020 +0200 Apply suggestions from code review Co-authored-by: Rasmus Wriedt Larsen commit 92ccb795fde5decdc60f370c1a4c3350f90f9745 Merge: 61ecec7d1 74bd04548 Author: Taus Date: Wed Oct 14 13:29:51 2020 +0200 Merge pull request #4415 from RasmusWL/python-flask-routed-parameter Python: Add support for routed parameters in flask commit 1fde477a8fc445e3b310b101c70d9949530d65e6 Author: Rasmus Wriedt Larsen Date: Wed Oct 14 13:22:35 2020 +0200 Python: Refactor argument matching commit 680a6eb2a61e5006fafd9bf37ae78f7173c1ce4a Author: Rasmus Wriedt Larsen Date: Wed Oct 14 13:21:04 2020 +0200 Python: Refactor argument matching (more) commit 61ecec7d1791b8d4e36a75deae3666826aab2aa0 Merge: 27f474f0e f3c07e384 Author: Rasmus Wriedt Larsen Date: Wed Oct 14 13:08:57 2020 +0200 Merge pull request #4467 from tausbn/python-fix-import-type-tracking Python: Fix unwanted module type tracking commit 27f474f0e999aa582699e0b23deefd11bf564310 Merge: 8127d9b93 4d9d2155f Author: yoff Date: Wed Oct 14 12:13:35 2020 +0200 Merge pull request #4429 from RasmusWL/python-model-invoke Python: model invoke library commit dc7e7890f09e6f9ea977d41db8e522ebafdc48e4 Author: Rasmus Lerchedahl Petersen Date: Wed Oct 14 12:03:05 2020 +0200 Python: Clearer naming and comments (I hope) commit f3c07e3849a05d74add9e333f3ebaec646f11ff4 Author: Taus Brock-Nannestad Date: Wed Oct 14 11:58:14 2020 +0200 Python: Fix up import helper tests commit 4100ab2919cd42874019e20ac4a41701e912c509 Author: Max Schaefer Date: Wed Oct 14 10:03:27 2020 +0100 JavaScript: Add another test to show that flow through functions still works. commit 1c04c07f07045ec3cfbdcdf729032b385eaa3820 Author: Max Schaefer Date: Mon Oct 12 14:52:23 2020 +0100 JavaScript: Eliminate source of false positives in UnsafeShellCommandConstruction. commit 8127d9b93e2bab133758577f67bd4326a3de7655 Merge: b49aa677d ce9624e61 Author: Tamás Vajk Date: Wed Oct 14 11:02:40 2020 +0200 Merge pull request #4404 from tamasvajk/feature/cleanup-2 C# extractor code cleanup commit b0cfa1d92df1d460c4f17e9302323fadf89cf71d Author: Rasmus Wriedt Larsen Date: Wed Oct 14 10:53:18 2020 +0200 Python: Make "..Call" modeling classes extend DataFlow::CfgNode commit bfa5d18476cd55ecbe85a48cf7f5c4967496fc3e Author: Rasmus Wriedt Larsen Date: Wed Oct 14 10:49:38 2020 +0200 Python: Use new importNode commit 7d600e4e8e0eb1ead82f263ed4236de62d155d4d Merge: 0b0763953 83937baca Author: Rasmus Wriedt Larsen Date: Wed Oct 14 10:48:38 2020 +0200 Merge branch 'main' into python-port-code-injection commit 4d9d2155fc36eed3e53a71b0d6ec0a79bf0af863 Author: Rasmus Wriedt Larsen Date: Wed Oct 14 10:44:58 2020 +0200 Python: Make "..Call" modeling classes extend DataFlow::CfgNode commit b0e79890e688a6f4d69e764052d4ebc3e03f95a4 Author: Rasmus Wriedt Larsen Date: Wed Oct 14 10:43:22 2020 +0200 Python: Use new importNode commit 4597ba64d07bdf3204519700ef1f542f5ae9f746 Merge: 662235bad 83937baca Author: Rasmus Wriedt Larsen Date: Wed Oct 14 10:41:37 2020 +0200 Merge branch 'main' into python-model-invoke commit eff47457bfbaf68c11501c88a61e14f9371626c4 Author: Rasmus Wriedt Larsen Date: Wed Oct 14 10:35:37 2020 +0200 Python: Refactor argument matching commit 2ea71f574cfa71e8e2b1cbda49364d0d3d0e2604 Author: Rasmus Wriedt Larsen Date: Wed Oct 14 10:33:03 2020 +0200 Python: Make "..Call" modeling classes extend DataFlow::CfgNode commit 2e30f58aa2f16e9447e22ffe4e061a189ad1c224 Author: Rasmus Wriedt Larsen Date: Wed Oct 14 10:27:56 2020 +0200 Python: Use new importNode commit ecf70c5f303d6c123de118df82c1cd3c2b105aff Merge: dcd103ea7 83937baca Author: Rasmus Wriedt Larsen Date: Wed Oct 14 10:36:43 2020 +0200 Merge branch 'main' into python-model-python2-specific-command-execution commit 74bd045488572fca673e3694f55fa0f747ca6cd9 Author: Rasmus Wriedt Larsen Date: Wed Oct 14 10:24:46 2020 +0200 Python: Make "..Call" modeling classes extend DataFlow::CfgNode commit ba158f33171daa3fdac231b0376e02ef5e9d1344 Author: Rasmus Wriedt Larsen Date: Wed Oct 14 10:17:35 2020 +0200 Python: Use new importNode commit 49d2e68d1202fcebd0c9c1850a08db80354b11d4 Merge: ce85ac3ce 83937baca Author: Rasmus Wriedt Larsen Date: Wed Oct 14 10:16:00 2020 +0200 Merge branch 'main' into python-flask-routed-parameter commit b0ebb5b6d1b1323c7f4aa6f9916fb4489b29dbec Author: Rasmus Lerchedahl Petersen Date: Wed Oct 14 09:51:24 2020 +0200 Python: Adjust tag format commit 93383747bd4ef2ea741fd3be04316fc88168040a Author: Rasmus Lerchedahl Petersen Date: Wed Oct 14 09:28:58 2020 +0200 Python: Use more common name for concept commit a76d276b489c5076cf907dbf33a7a1f27926b8a0 Author: Rasmus Lerchedahl Petersen Date: Wed Oct 14 08:44:04 2020 +0200 Python: Adjust `getARelevantTag` commit 3b9ea3a958542f3485d9e2335f498c693f714724 Author: yoff Date: Wed Oct 14 08:24:26 2020 +0200 Apply suggestions from code review Co-authored-by: Rasmus Wriedt Larsen commit fc71ca747d1082cff7371ed279eee5cb9b13b770 Author: Jonathan Leitschuh Date: Tue Oct 13 21:15:09 2020 -0400 Java: Track taint through java.io.File::toPath & java.nio.file.Path::toFile commit 7d86b53b710822be514f0821b3f32d9373b7ff59 Author: Taus Brock-Nannestad Date: Tue Oct 13 22:47:57 2020 +0200 Python: Fix unwanted module type tracking commit 76e5b59dab05aae5e80e30c24c40f8ab1a99e1bf Author: Taus Brock-Nannestad Date: Tue Oct 13 22:47:03 2020 +0200 Python: Add test case for unwanted module type tracking commit b49aa677d0f84512013fd8683d19121cc7b58bf9 Merge: 83937baca 58727cb8a Author: Robert Marsh Date: Tue Oct 13 15:17:54 2020 -0400 Merge pull request #4459 from geoffw0/setex C++: Additional taint flows through std::set commit 1f2390455c5edc7386e34c0a103d4687e8f997dd Author: yoff Date: Tue Oct 13 19:15:33 2020 +0200 Update python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll Co-authored-by: Taus commit 5d66c485d50e56dbb5e36f3695f7b460769ab6c7 Author: Rasmus Lerchedahl Petersen Date: Tue Oct 13 19:12:52 2020 +0200 Python: IPA type for arguemnt mappings Not sure how arg2 in line 118 is achieved commit 83937bacae35fdf41f3e0ec761bdeb5f497c6c1a Merge: b895641a8 2c5996f69 Author: Taus Date: Tue Oct 13 18:08:07 2020 +0200 Merge pull request #4448 from RasmusWL/python-simplify-import-modeling Python: simplify import modeling commit 2c5996f6944a6ecc7f06d1caeea070365c41cbbd Author: Rasmus Wriedt Larsen Date: Tue Oct 13 17:21:21 2020 +0200 Python: Refactor subprocess_attr type-tracker Co-authored-by: Taus commit fdb489fc934f161b22f82fe89985fe01bc71ac2d Author: Taus Brock-Nannestad Date: Tue Oct 13 16:35:41 2020 +0200 Python: Remove flow between ESSA variables This required a minor change in the type tracker implementation, but apart from that no other changes appear to be needed. Seems to clean up the test output quite a bit. commit 05b744701e1ccd12cf06514b28278c5358d0a9e2 Author: yoff Date: Tue Oct 13 15:31:50 2020 +0200 Apply suggestions from code review Co-authored-by: Taus commit b895641a8398deb9675b33d8001745bba9bae221 Merge: 83d6d6041 182912623 Author: Rasmus Wriedt Larsen Date: Tue Oct 13 15:08:28 2020 +0200 Merge pull request #4464 from tausbn/python-remove-dataflowcfgnode Python: Get rid of `DataFlowCfgNode` commit 76c9b8c49fcd17e38598e01684527f5b6a98e5b7 Author: Rasmus Wriedt Larsen Date: Fri Oct 9 14:37:23 2020 +0200 Python: Expose importNode instead of importModule/importMember Since predicate name `import` is not allowed, I adopted `importNode` as it sort of matches what `exprNode` does. --- Due to only using `importMember` in `os_attr` we previously didn't handle `import os.path as alias` :| I did creat a hotfix for this (https://github.com/github/codeql/pull/4446), but in doing so I realized the core of the problem: We're exposing ourselves to making these kinds of mistakes by having BOTH importModule and importMember, and we don't really gain anything from doing this! We do loose the ability to easily only modeling `from mod import val` and not `import mod.val`, but I don't think that will ever be relevant. This change will also make us to recognize some invalid code, for example in import os.system as runtime_error we would now model that `runtime_error` is a reference to the `os.system` function (although the actual import would result in a runtime error). Overall these are tradeoffs I'm willing to make, as it does makes things simpler from a QL modeling point of view, and THAT sounds nice :+1: commit ce9624e61d8aff64168ecd29e894f09905ccffb8 Author: Tamas Vajk Date: Tue Oct 13 14:50:46 2020 +0200 C#: Remove unneeded vscode settings from settings.json commit 4bfd55f1af6338689bbac86bb3b933bae75f8397 Author: Rasmus Wriedt Larsen Date: Fri Oct 9 14:00:25 2020 +0200 Python: Show problem with os.path modeling This is not a very good test for showing that we don't handle direct imports, but it was the best I had available without inventing something new. It's very fragile, since any of these would propagate taint (due to handling all `join` calls as if the qualifier was a string): ospath_alias.join(ts) ospath_alias.join(ts, "foo", "bar") But this test DOES serve the purpose of illustrating that my fix works :D commit ce793c357f8bb9f374148cb43b0004cbffa6eff0 Author: Tamas Vajk Date: Tue Oct 13 14:16:28 2020 +0200 C#: Adjust parameters of DefinitionField ctor commit ea53ea0994ba808221a7e250ac31a138de86fa70 Author: Tamas Vajk Date: Mon Oct 5 14:04:48 2020 +0200 C#: Prefer keywords over type names commit 8afac251209cf0940d5338993bbc26394a5098ce Author: Tamas Vajk Date: Mon Oct 5 14:02:16 2020 +0200 C#: Add params modifier on override commit 63e173198d5ae4605c135911d7bbaad2b5ff142d Author: Tamas Vajk Date: Mon Oct 5 14:01:49 2020 +0200 C#: Make static member on generic class private commit 6cf20d569da284a055db538af9c859814a51934b Author: Tamas Vajk Date: Mon Oct 5 13:59:32 2020 +0200 C#: Remove overrides that do nothing commit 9b349eb84458a17bfc5247b9746659186fbecd17 Author: Tamas Vajk Date: Mon Oct 5 13:43:49 2020 +0200 C#: Use Contains instead of IndexOf commit 5b33f43b78edf9498501e5a010747919db06c25b Author: Tamas Vajk Date: Mon Oct 5 13:35:52 2020 +0200 C#: Use nameof commit f84669904bd3617ff6cc90fbd7f31b1760a87e55 Author: Tamas Vajk Date: Mon Oct 5 11:05:46 2020 +0200 C#: Fix typo commit 7075c6f8cae59663aca958646d05122c9fdf04d8 Author: Tamas Vajk Date: Mon Oct 5 11:01:33 2020 +0200 C#: Fix public property naming commit a4fec39c110bca9d8982c21a9e019259733af66d Author: Tamas Vajk Date: Mon Oct 5 10:52:45 2020 +0200 C#: Move fields to locals where possible commit b07aceff6b30240111db93c6da5d3c3bd5e0d684 Author: Tamas Vajk Date: Mon Oct 5 10:46:56 2020 +0200 C#: Fix exception throwing commit 6dfe90e479bca519f14c5d49086255265decd16e Author: Tamas Vajk Date: Mon Oct 5 10:33:02 2020 +0200 C#: Change array-returning properties commit 7721c7bba7af1e8efb27c286a9abf666ca8009d2 Author: Tamas Vajk Date: Mon Oct 5 10:23:19 2020 +0200 C#: Remove redundant conditions commit cbdd13127e960d3652caf45d6606aa8f5f4e6ee0 Author: Tamas Vajk Date: Mon Oct 5 10:21:06 2020 +0200 C#: Convert publicly visible fields to properties commit d5382f2cfdaa1c75a1ffaf7ebd11484504c0e668 Author: Tamas Vajk Date: Fri Oct 2 17:04:37 2020 +0200 C#: Fix modifier orders commit fbc128fcc794a7ecab60dbc9dcf9ffe78fcadce6 Author: Tamas Vajk Date: Fri Oct 2 17:02:49 2020 +0200 C#: Fix type parameter names commit 2e350caf9f4df1eab37f8e87adabc653f06ba8e1 Author: Tamas Vajk Date: Fri Oct 2 15:45:48 2020 +0200 C#: Fix private field and local variable naming commit ecb29a267b5a2d58ea6d0bebb4f2b03d77b51f8e Author: Tamas Vajk Date: Fri Oct 2 14:33:10 2020 +0200 C#: Add editor config naming rules commit baf6f59bfc7d0cd93d46f03c65d84f4a950f5356 Author: Tamas Vajk Date: Fri Oct 2 14:27:27 2020 +0200 C#: Add braces to multiline block statements commit 28694513a13c233e02f7731ba58f2d59db75ec61 Author: Tamas Vajk Date: Fri Oct 2 14:23:04 2020 +0200 C#: Use pattern matching commit 155453d9cb38d1a62f766aa74f8d09b127548501 Author: Tamas Vajk Date: Fri Oct 2 14:07:01 2020 +0200 C#: Format single line if statements commit aec4481cfb0880b997f77ed2dad038563fbf722b Author: Tamas Vajk Date: Fri Oct 2 13:45:38 2020 +0200 C#: Use var everywhere commit 7d544e34afac03d4ef9d819d8dcf26a031b27d05 Author: Tamas Vajk Date: Fri Oct 2 13:41:22 2020 +0200 C#: Add declaration visibility modifiers commit 466e0cf08543ba2756c71b6a29aed8af1dc9a81d Author: Tamas Vajk Date: Fri Oct 2 13:40:49 2020 +0200 C#: Remove naming styles from editor config, add IDE diagnostic severities commit ec6ed90c497679864a69a7f86c9df9cbb91a7fe1 Author: Tamas Vajk Date: Fri Oct 2 13:09:25 2020 +0200 C#: Add final new line to files commit 2e215640327973e8f99485640873fdacaab9e8e9 Author: Tamas Vajk Date: Fri Oct 2 13:06:03 2020 +0200 C#: Fix formatting with 'dotnet format' commit 7f86768a4930de584a6e267586ecd3feb477b000 Author: Tamas Vajk Date: Fri Oct 2 12:46:45 2020 +0200 C#: Reformat LINQ extension method call-chains commit 115a216ea9a61ac0e900ae604f0e9cd938e954b3 Author: Tamas Vajk Date: Fri Oct 2 12:25:54 2020 +0200 C#: Format nested ternary operators commit c38bf5ee5b1f49046b35ddb206df3ec5cc48acd1 Author: Tamas Vajk Date: Fri Oct 2 11:56:50 2020 +0200 C#: Reduce nesting and fix some formatting commit e73ced2275fa8e1f3690f1941ea02906ef685eb1 Author: Tamas Vajk Date: Fri Oct 2 11:49:35 2020 +0200 C#: Add sealed modifier to classes to fix dispose-pattern, remove explicit IDisposable implementations commit 397be7e98ffbd33dc1e15d76693448df3586bdfe Author: Tamas Vajk Date: Fri Oct 2 11:42:10 2020 +0200 C#: Change constructor visibility to protected in abstract classes commit 71faa512709e812523c73e2c95cc97c6c06d1b5b Author: Tamas Vajk Date: Fri Oct 2 11:36:42 2020 +0200 C#: Dispose IDisposables commit e208f3d21d67e867cc3b4096a564920c0517118d Author: Tamas Vajk Date: Fri Oct 2 11:29:28 2020 +0200 C#: Simplify null checks with pattern matching, ??, and ?: commit 504f56adeb46219065e77fb81c0afe712da8a45d Author: Tamas Vajk Date: Fri Oct 2 11:17:12 2020 +0200 C#: Simplify object initialization commit b793af571ee0102bb316a264bfe00bb6b874b74a Author: Tamas Vajk Date: Fri Oct 2 11:14:46 2020 +0200 C#: Remove unnecessary usings commit ec63acfb0cbf02167ccb1cf9553ca573f593efbd Author: Tamas Vajk Date: Fri Oct 2 11:04:25 2020 +0200 C#: Inline out variable declarations commit f2e6b42aa45c4a2f2ce96d8da78b3ddb21de9471 Author: Tamas Vajk Date: Fri Oct 2 10:52:13 2020 +0200 C#: Add type parameter in/out commit 33672a4058415bed35c6cdffa88b6abe0506e5fe Author: Tamas Vajk Date: Tue Oct 6 13:59:19 2020 +0200 C#: Simplify using statements commit 412b87c5c71bdf08c0b1350d51c90372a602fed0 Author: Tamas Vajk Date: Fri Oct 2 10:37:38 2020 +0200 C#: Fix loop that iterates only once commit 79eff0682863ed98c5f8c418361976f812f2d4d7 Author: Tamas Vajk Date: Fri Oct 2 10:29:09 2020 +0200 C#: Remove unused out argument commit 921d3eeaec9000cc81902235c349e41b07f0c390 Author: Tamas Vajk Date: Fri Oct 2 10:24:18 2020 +0200 C#: Mark members static (remove unused members) commit 68a45e7e9dda451335e36f0996c1ce24d8545af4 Author: Tamas Vajk Date: Fri Oct 2 10:10:50 2020 +0200 C: Remove unused fields commit 0c9aaa3dce5b0d9e3f8b63578664a8a61b701506 Author: Tamas Vajk Date: Fri Oct 2 10:00:27 2020 +0200 C#: Remove unused parameters commit 93c6d5ea584a6a8870b9087a0b3b728101958246 Author: Tamas Vajk Date: Fri Oct 2 09:52:40 2020 +0200 C#: Fix empty array creation commit 2d3985742fe084d009bb4f337671f302fd097a76 Author: Tamas Vajk Date: Fri Oct 2 09:48:58 2020 +0200 C#: Fix length/emptiness checks commit b7e8b48e9e6e43760da6c1218bb7da98f9fe5239 Author: Rasmus Lerchedahl Petersen Date: Tue Oct 13 13:06:47 2020 +0200 Python: Move concept tests out These tests should be fleshed out at some point, but currently they test all that we model. commit 1829126230a615ca5ba5950590e2c28be474d6fb Author: Taus Brock-Nannestad Date: Tue Oct 13 13:04:59 2020 +0200 Python: Get rid of `DataFlowCfgNode` Should make modelling data flow nodes that are also specific subclasses of `ControlFlowNode` a bit smoother. commit 83d6d6041ac9930070d3421e0529573c3e1c4c00 Merge: d3f8fb5e5 96db3459d Author: Erik Krogh Kristensen Date: Tue Oct 13 12:50:00 2020 +0200 Merge pull request #4462 from erik-krogh/strayTodo JS: remove stray todo commit b2a2412f1d9395e92685d415cc570a239372c34e Author: Joe Farebrother Date: Tue Oct 13 11:30:02 2020 +0100 Java: Clean up the constructor flow steps commit 4685f2d5f2f61d2606c34544fddf2ab751497e52 Author: Rasmus Lerchedahl Petersen Date: Tue Oct 13 12:03:23 2020 +0200 Python: Address many review comments still need to move concept tests commit 662235bad804c8df85b66f9538e1bd592a2f7092 Author: Rasmus Wriedt Larsen Date: Tue Oct 13 11:56:21 2020 +0200 Python: Use classRef instead of class_ Discussed offline with Taus commit d3f8fb5e53b5ed64ca76c41efb664ca63eeec046 Merge: e2b0c6062 3288cf1a7 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Tue Oct 13 02:56:21 2020 -0700 Merge pull request #4423 from tausbn/python-add-attribute-access-interface Approved by RasmusWL commit 96db3459d0257571252d2e5468f7b00ef5454fed Author: Erik Krogh Kristensen Date: Tue Oct 13 11:48:06 2020 +0200 remove stray todo commit dcd103ea7329a5adaf29d106117397be3f118f9b Author: Rasmus Wriedt Larsen Date: Tue Oct 13 10:31:35 2020 +0200 Python: Fix grammar Co-authored-by: Taus commit ce85ac3ce12fe446ae0ae780d625da6fcbfc2fdb Author: Rasmus Wriedt Larsen Date: Tue Oct 13 10:15:03 2020 +0200 Python: Remove solved TODO commit 2e430325be5e9d20fac6a98a1be581455ca3bf2b Author: Rasmus Wriedt Larsen Date: Tue Oct 13 10:05:35 2020 +0200 Python: Refactor argument matching to use set literals Co-authored-by: Taus commit e2b0c60627201f7938d2b5050e634863f361431a Merge: 3b7cf7fd2 9ac70e304 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Oct 12 11:41:21 2020 -0700 Merge pull request #4449 from max-schaefer/js/api-graphs-type-handling-improvements Approved by erik-krogh commit 3b7cf7fd27f1f6caacaa3702947c154969802444 Merge: fc4a3426a c63f7cb40 Author: Robert Marsh Date: Mon Oct 12 14:17:17 2020 -0400 Merge pull request #4439 from geoffw0/mapex C++: Additional taint flows through std::map commit 9ac70e3044908ba728cd5f1f3123894baf49c2c7 Author: Max Schaefer Date: Mon Oct 12 16:29:11 2020 +0100 JavaScript: Clarify the relationship between `MkCanonicalName{Def,Use}` with an upper-case `M` and `mkCanonicalName{Def,Use}` with a lower-case `m`. commit aa8bacb72402e061a925ecb919b29c56f0af06d8 Author: Joe Farebrother Date: Mon Oct 12 15:36:14 2020 +0100 Java: Update test output commit 3416911ac6942fd3a59c531ce1ec5e38bbdd185c Author: Joe Farebrother Date: Mon Oct 12 15:23:01 2020 +0100 Java: Refector out StringBuilder and Number taint preserving callables commit eafde05a55be693e376fe4831043809ae61791fa Author: Joe Farebrother Date: Mon Oct 12 14:43:21 2020 +0100 Java: Expand flow step refactoring to Callables Also add some missing flow steps for StringBuilder commit 7e2c49fadd80e50aa4b5d9bf84e5ce6a99739639 Author: Joe Farebrother Date: Mon Oct 12 14:05:50 2020 +0100 Java: Fix a couple of flow step issues Co-authored-by: Anders Schack-Mulligen commit 4a8b7f64e860acc84301fdef0c937b07a47e17e6 Author: Joe Farebrother Date: Fri Oct 9 12:20:09 2020 +0100 Java: Rename returnsTaint to returnsTaintFrom commit ca9038350cff194e0536f5c97889c748fc48c16d Author: Joe Farebrother Date: Fri Oct 9 11:30:30 2020 +0100 Java: Add `this.` and fix mistake commit 5d487b97da8a7336bed12029a3d790eb03c41ef9 Author: Joe Farebrother Date: Thu Oct 8 17:02:49 2020 +0100 Java: Merge `TaintPreservingMethod` with `TaintTransferringMethod` commit a510f5886528864cc27b1cb052a80132ad0c4df7 Author: Joe Farebrother Date: Thu Oct 8 16:34:04 2020 +0100 Java: Implement code review changes commit 91ce02aad46fba33ba74bc83266984299c51f665 Author: Joe Farebrother Date: Thu Oct 8 11:32:28 2020 +0100 Java: Fix bug involving varadic parameters commit 79209af9c0b2fc1299a9c5e5f83cf71274ce14ed Author: Joe Farebrother Date: Wed Oct 7 12:58:11 2020 +0100 Java: Refactor out flow steps for more frameworks. commit 92fd8c4128f50667ab8a78de371513b10af9e7be Author: Joe Farebrother Date: Tue Oct 6 17:37:01 2020 +0100 Java: Move new definitions to new file commit 60a7666105309176686bfbe0742b14036e18ce25 Author: Joe Farebrother Date: Tue Oct 6 16:50:44 2020 +0100 Java: Refactor Android SQLite flow steps commit ca60f2cc18097f16abdb3dad6332cc1ca870555c Author: Joe Farebrother Date: Tue Oct 6 13:49:02 2020 +0100 Java: Fix failing tests commit ff6c5c219c84c1a765f48cdbea25c8f0fd94be4b Author: Joe Farebrother Date: Tue Oct 6 11:11:24 2020 +0100 Java: Start TaintTrackingUtils refactor commit 551d86c6eae8c2ff5e89509a4e449ab058970d98 Author: Joe Farebrother Date: Mon Oct 5 11:33:12 2020 +0100 Java: Define classes for taint propagation methods commit fc4a3426acee036a5a7ba97b49d2a361324ba78e Merge: 24da4cc34 0c70be145 Author: Arthur Baars Date: Mon Oct 12 16:42:11 2020 +0200 Merge pull request #4457 from daniel-beck/file-taint Java: Track taint through java.io.File constructor and #toURI; URI#toURL commit 3288cf1a75a1d19817821a02ce9732e580ac68af Author: Taus Brock-Nannestad Date: Mon Oct 12 16:38:21 2020 +0200 Python: Hopefully final changes to documentation. commit cd33d358aa43a108eac202971a09af4817a6674d Author: Max Schaefer Date: Mon Oct 12 14:50:47 2020 +0100 JavaScript: Add a test showing a false positive from UnsafeShellCommandConstruction due to infeasible paths. The path from the API entry point to the sink contains a "return" step. A client of the library cannot match that step, resulting in an infeasible path. commit 24da4cc34446a7ec1802d1f6ca7c310a1b0ec16e Merge: 8eb84b259 0459248b9 Author: Jonas Jensen Date: Mon Oct 12 15:38:13 2020 +0200 Merge pull request #4421 from jbj/SimpleRangeAnalysis-guard-overflow C++: Demonstrate overflowing guard bounds commit 433a36225b7451e72783c3d88a80a26282757036 Author: yoff Date: Mon Oct 12 15:26:53 2020 +0200 Apply suggestions from code review Co-authored-by: Rasmus Wriedt Larsen commit 0459248b9fb11de4f9c22c7e089a59350af069c0 Merge: 30b9d13a4 6d1634ef8 Author: Jonas Jensen Date: Mon Oct 12 14:29:09 2020 +0200 Merge remote-tracking branch 'upstream/main' into SimpleRangeAnalysis-guard-overflow commit 8eb84b25996343939fb9dd191ffb0e87dab699e8 Merge: 6d1634ef8 98ab38a63 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Oct 12 05:26:53 2020 -0700 Merge pull request #4391 from max-schaefer/js/api-graph-reexport Approved by asgerf commit 6d1634ef8f6a08f54ad6a74995045b1d73b37cc7 Merge: 35985a918 a0cbeb609 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Oct 12 05:23:29 2020 -0700 Merge pull request #4329 from erik-krogh/DVSA Approved by esbena commit b07c7abacc34b71d4426cd12cb55853d565277da Author: Taus Brock-Nannestad Date: Mon Oct 12 13:49:08 2020 +0200 Python: Clear up attribute name access QLDoc commit 35985a9189f395cf5595a486f5af930f02bf0a61 Merge: 6440db786 9d1f64d35 Author: Tom Hvitved Date: Mon Oct 12 13:01:39 2020 +0200 Merge pull request #4452 from hvitved/csharp/ssa/overlapping-captured-defs C#: Avoid overlapping SSA definitions for `ref`/`out` captured variables commit 6440db786dee4af0f295d525c302b9ffceb3c9c0 Merge: 725194a3b 9b12ceae8 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Oct 12 11:20:09 2020 +0100 Merge pull request #4420 from jbj/SimpleRangeAnalysis-widen-Expr C++: SimpleRangeAnalysis: widen recursive *, +, - commit 58727cb8ad20ec39d77ec751624135f9f9e2b520 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Oct 12 10:52:50 2020 +0100 C++: Update change note. commit 4363f08b45df19caf464fa33f4e906cf893bb185 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Oct 12 10:47:08 2020 +0100 C++: Model std::set::emplace and emplace_hint. commit 30b9d13a4524c345443df33c32f162b7fd1a43f1 Author: Jonas Jensen Date: Mon Oct 12 11:25:38 2020 +0200 C++: Correct annotation in test commit 5d87117dc792bd16cbf6001f513c273d4a021289 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Oct 12 10:10:40 2020 +0100 C++: Model std::set::lower_bound, upper_bound, equal_range. commit 9b12ceae8d69165c1746372af19f4a370240b6c0 Author: Jonas Jensen Date: Tue Oct 6 13:28:07 2020 +0200 C++: SimpleRangeAnalysis: widen recursive *, +, - The number of candidate bounds during the main `SimpleRangeAnalysis` recursion was in principle always exponential in the size of the program, but in practice it did not get out of hand when only `+` and `-` operations were supported. Now that `*` is also supported, the range analysis started timing out on the SinaMostafanejad/OpenRDM project. The problematic expressions in that project are of the form a*x*x*x + b*x*x + c*x + d where most of the variables involved are recursive definitions and are therefore likely to have a large number of candidate bounds. The fix here is to identify those few binary operations that are most likely to cause an explosion in the number of bounds and apply widening to them. Previously, widening was only applied at definitions. commit bbeea452e1ca5f352553264d86d9ec1a5ca0661f Author: Jonas Jensen Date: Mon Oct 12 11:06:54 2020 +0200 C++: Add test with widening of binary Expr commit fc19bba0bdbde5f3e693a604a1f722f5f0747759 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Oct 12 10:01:57 2020 +0100 C++: Model std::set::merge and correct test annotations. commit 9d1f64d35d27321a4c50976ebd712f04f7d243e4 Author: Tom Hvitved Date: Fri Oct 9 15:47:05 2020 +0200 C#: Avoid overlapping SSA definitions for `ref`/`out` captured variables commit 725194a3b8c8d09786c2758604b5c31deb021ded Merge: c8cacb9fe 091e3a293 Author: Anders Schack-Mulligen Date: Mon Oct 12 08:56:19 2020 +0200 Merge pull request #4447 from aschackmull/dataflow/postupdate-flow-consistency Dataflow: Introduce consistency check for flow targeting PostUpdateNodes commit 0c70be145f366446fc593b1617268b4bd9728693 Author: Daniel Beck Date: Sat Oct 10 20:29:01 2020 +0200 Track taint through java.io.File constructor and #toURI; URI#toURL commit c63f7cb409ecc76d157a69093074f082155ddcb1 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Oct 9 16:33:54 2020 +0100 C++: Taint through emplace from qualifier to return value. commit 270517d3797d1e2e8b58ed8cb3030e93d905447e Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Oct 9 16:05:56 2020 +0100 C++: Revise model of emplace and emplace_hint. Note that 2 of the 3 taint regressions we shouldn't be getting because we don't yet do taint through keys. commit 49c121d370007c76eddabbfd07c266b6627e56b0 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Oct 9 15:56:06 2020 +0100 C++: More test cases covering other std::pair constructors. commit 091e3a2931d43bdcf35f8763f9301193d58ad5c7 Author: Anders Schack-Mulligen Date: Fri Oct 9 16:25:14 2020 +0200 Dataflow: Adjust test output. commit 4bd56fdbe44bc4d0ae09ee47200c3b1ee94322e8 Author: Rasmus Lerchedahl Petersen Date: Fri Oct 9 16:13:47 2020 +0200 Python: Implement framework sinks commit 0d8bd01e10549c5ee2f4db76d8d74775c02d4b19 Author: Rasmus Lerchedahl Petersen Date: Fri Oct 9 16:11:37 2020 +0200 Python: Port query and add test commit 723699a58422bd61b6fb0bb12733b76acdda01b0 Author: Tom Hvitved Date: Fri Oct 9 15:38:37 2020 +0200 C#: Add SSA test for overlapping captured variable definitions commit c8cacb9fee0a66c589f0f24406d1f5210842959d Merge: 4c9ffcec2 42ee13630 Author: James Fletcher <42464962+jf205@users.noreply.github.com> Date: Fri Oct 9 14:47:39 2020 +0100 Merge pull request #4451 from github/jf205-patch-2 Fix typo in CodeQL docs template commit 61a78e28acf01617ecd325dd98dd13a792d3fe90 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Oct 9 14:46:17 2020 +0100 C++: Fix map::merge. commit 42ee136306e3c462768cc6bdef9e31339ceca2d1 Author: James Fletcher <42464962+jf205@users.noreply.github.com> Date: Fri Oct 9 14:33:45 2020 +0100 Update layout.html commit a0cbeb6093536da08f6e18781f44965dcb5ed1b9 Author: Erik Krogh Kristensen Date: Fri Oct 9 14:54:34 2020 +0200 add change note commit 2fb19f0b117b422d1047af50a0cc969175dd25b9 Author: Erik Krogh Kristensen Date: Fri Oct 9 14:50:16 2020 +0200 refactor into a single regular expression with two capture groups commit f6f8bbd1d8657395de8eb65ab0f3704b294ccb01 Author: Erik Krogh Kristensen Date: Fri Oct 9 14:46:31 2020 +0200 Update javascript/ql/src/semmle/javascript/frameworks/ServerLess.qll Co-authored-by: Esben Sparre Andreasen commit 1c043447e8be5802c3c0b9910e8ce4786125bc49 Author: Anders Schack-Mulligen Date: Fri Oct 9 14:29:52 2020 +0200 Dataflow: Introduce consistency check for flow targeting PostUpdateNodes. commit 4c9ffcec2714424f72569123441b91ac90adc1bf Merge: 2436c5625 493b80c44 Author: Jonas Jensen Date: Fri Oct 9 13:30:05 2020 +0200 Merge pull request #4396 from geoffw0/stringsets C++: Use [, ...] syntax more widely. commit 2436c5625888e94f30734bdbab7d34ca08dc2c8d Merge: b0d01cfe8 6d78c7b46 Author: James Fletcher <42464962+jf205@users.noreply.github.com> Date: Fri Oct 9 11:40:47 2020 +0100 Merge pull request #4444 from github/codeql-style-updates [CodeQL docs] First pass at style updates for docs microsite commit b0d01cfe8d317fb15839488dc9369079f7e2fa96 Merge: 412524103 3af3d87ec Author: Alexander Eyers-Taylor Date: Fri Oct 9 10:45:11 2020 +0100 Merge pull request #4370 from jbj/range-analysis-mega-change-note C++: Change note for several range-analysis PRs commit 6d78c7b46e97b023169548f7d212bb06868baa2f Author: james Date: Fri Oct 9 10:04:39 2020 +0100 fix path to primer.css in template commit 1f1be3bf9a76893179e42e419985ae54f8db2457 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Oct 9 10:04:22 2020 +0100 C++: Block try_emplace arg 0. commit de429067855224fd9dc18ca99a393362873139a7 Author: james Date: Fri Oct 9 10:00:41 2020 +0100 hide header text on small screens and fix body width commit 2fe986eb7940022a885e286f996b2c13714f2963 Author: james Date: Thu Oct 8 14:22:49 2020 +0100 add local primer.css commit 8786fe1ab82c7a74155361f509f615c2166ba17a Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Oct 9 09:55:50 2020 +0100 C++: Add test missing test case involving tainted key. commit 412524103c4f96570b181db5dca015d34d38b09c Merge: 3894ecf77 ca4e5014a Author: Tom Hvitved Date: Fri Oct 9 10:54:56 2020 +0200 Merge pull request #4437 from hvitved/csharp/cfg/compiler-generated-array-lengths C#: Include compiler-generated array lengths in the CFG commit 3894ecf7792ec8c52fb02711c6232ff4a3ecc6d3 Merge: f42cbcbea 4bf6f6ac7 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Fri Oct 9 00:37:38 2020 -0700 Merge pull request #4441 from max-schaefer/js/add-negative-api-graphs-test Approved by erik-krogh commit 3b328baaef479e6d34fa2cfbde4cfbf58c6e2906 Author: Erik Krogh Kristensen Date: Thu Oct 8 21:54:23 2020 +0200 changes based on review commit 65b90c411c88502f694c326c4d314b1ac8173977 Author: Erik Krogh Kristensen Date: Thu Oct 8 21:28:50 2020 +0200 Update javascript/ql/src/semmle/javascript/security/dataflow/CodeInjectionCustomizations.qll Co-authored-by: Esben Sparre Andreasen commit 4bf6f6ac7ca3a899af3bc2a20d4ac9dd5dbd01a0 Author: Max Schaefer Date: Thu Oct 8 19:53:23 2020 +0100 JavaScript: Add a negative test for API graphs. The test ensures that flow summarization won't label property `f` of the first parameter of `assertNotNull` as a sink, which would be very imprecise. commit 493b80c44d81c4c764a199794dabfab0c59880c3 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Oct 8 17:46:50 2020 +0100 C++: Fix incorrect translations to hasQualifiedName. commit f42cbcbeae99d8fe309b80205af27331f0d82c7d Merge: b409cf6ce f3f908383 Author: Tamás Vajk Date: Thu Oct 8 18:23:12 2020 +0200 Merge pull request #4428 from tamasvajk/feature/force-nuget-single-restore C#: Add '-DisableParallelProcessing' flag to nuget restore in Autobuilder commit 60eec7b1363c0182d54c567b4495a48646b993ca Author: Taus Date: Thu Oct 8 18:14:20 2020 +0200 Python: Update python/ql/src/experimental/dataflow/internal/Attributes.qll Co-authored-by: Rasmus Wriedt Larsen commit d46453caaa6dd28ab0ed5a183fa077e4e17f4c61 Author: Taus Brock-Nannestad Date: Thu Oct 8 18:08:55 2020 +0200 Python: Support named imports as attribute reads Required a small change in `DataFlow::importModule` to get the desired behaviour (cf. the type trackers defined in `moduleattr.ql`, but this should be harmless. The node that is added doesn't have any flow anywhere. commit c555cfa22af4d03c8479f54509044001720eab9e Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Oct 8 16:55:45 2020 +0100 C++: Replace isParameterDeref(_). commit f3f908383b4fc900d355ee78411f19f707e12dd2 Author: Tamas Vajk Date: Thu Oct 8 17:07:40 2020 +0200 C#: Adjust autobuilder tests for added nuget.exe flag commit 522f41377ffad825525636d78f577c950bb53c06 Author: Tamas Vajk Date: Wed Oct 7 12:20:14 2020 +0200 C#: Add '-DisableParallelProcessing' flag to nuget restore in Autobuilder commit e01e4b5bdedee58785c6b02858f542f9e5e8c16c Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Oct 8 14:29:08 2020 +0100 C++: Fix QLDoc comments. commit 5c1a510e4a2b7463b3f73556bb1bd24f32995ae7 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Oct 7 12:17:13 2020 +0100 C++: Model map::lower_bound, upper_bound and equal_range. commit ef9a7c8cdb05cc3138abe61f9f3a9be667e02b28 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Oct 7 11:55:46 2020 +0100 C++: Model map::merge. commit b7ab89c892282c7a670cfcb6ea514a06af4554b9 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Oct 7 11:48:16 2020 +0100 C++: Model map::emplace, emplace_hint and map::try_emplace. commit b409cf6cea7d0e6645e39a97c4ee3e012d315c0c Merge: f179e7ebf 662736eb2 Author: Jonas Jensen Date: Thu Oct 8 15:18:15 2020 +0200 Merge pull request #4389 from gsingh93/bitwise-and Improve range analysis for bitwise and commit 6394b1b478bca1a51bba47c1cdf96629131fdf60 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Oct 8 13:46:00 2020 +0100 C++: Additional test cases for emplace. commit df447c0af9ec7d62b428ebdfb5d21efcad2c1203 Author: Taus Brock-Nannestad Date: Thu Oct 8 15:01:24 2020 +0200 Python: Remove flow from `getAttributeName` commit ceb249680ec909086ef8e841489315583134cb20 Author: Taus Brock-Nannestad Date: Thu Oct 8 15:00:14 2020 +0200 Python: Reuse existing `node` fields Also changes `x = TCfgNode(y)` to `x.asCfgNode() = y` where applicable. commit 31596ef56988d1f97fcc13bf551bc84bde5e0af7 Author: Taus Brock-Nannestad Date: Thu Oct 8 14:55:27 2020 +0200 Python: Clean up and extend built-in call node classes commit e9ecc00b370ba137ae550f86ea7483401367e6e5 Author: Taus Brock-Nannestad Date: Thu Oct 8 14:53:54 2020 +0200 Python: Implement and use `mayHaveAttributeName` commit 61d5372d077d92959ee6f2f03678baa4556e1a29 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Oct 8 13:43:49 2020 +0100 C++: Test spacing. commit 4c4dd0c9590e3aefb5533cc3f3afd2e0f7987c67 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Oct 7 12:06:28 2020 +0100 C++: Fix a bug in the tests. commit f179e7ebf491484b3b7e4bc81f96dfd3668efe5c Merge: ce8567c64 396f35339 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Thu Oct 8 03:09:38 2020 -0700 Merge pull request #4291 from asgerf/js/lean-dependency-installation-plainjava Approved by erik-krogh commit 0b0763953ea093facbf3d4b88ca9c06c79bd9a62 Author: Rasmus Wriedt Larsen Date: Thu Oct 8 11:15:36 2020 +0200 Python: Update description of CodeInjection Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> commit 7d086b23ffe6f1806368a95783cd5e25a21c308c Author: yoff Date: Thu Oct 8 10:53:52 2020 +0200 Update python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll Co-authored-by: Rasmus Wriedt Larsen commit ca4e5014ae16b2a50ea2cc358771eb29d31cce64 Author: Tom Hvitved Date: Thu Oct 8 10:12:17 2020 +0200 C#: Include compiler-generated array lengths in the CFG commit 19796a4c9c93cafb8e8be9d427fd9b3c1e588b3d Author: Rasmus Lerchedahl Petersen Date: Thu Oct 8 10:35:01 2020 +0200 Python: Improve tests and make `validTest` happy commit ce8567c64a5ebc856352a8891c0ffbe169c1c8db Merge: b70f5bc95 af36718dc Author: Tom Hvitved Date: Thu Oct 8 10:32:13 2020 +0200 Merge pull request #4293 from hvitved/csharp/cfg/assertions C#: Model assertions in the CFG commit cc0661bce17c28a3ce3ce43f9eda20ae77bcb3db Author: Rasmus Lerchedahl Petersen Date: Thu Oct 8 10:11:00 2020 +0200 Python: More/better comments commit b70f5bc95435ce9735d010e0bcd1b30ac8eb5147 Merge: cb00f8bcc 31816af11 Author: Tom Hvitved Date: Thu Oct 8 09:13:43 2020 +0200 Merge pull request #4433 from hvitved/csharp/dataflow/switch-expr C#: Add missing data-flow for switch expressions commit cb00f8bcc4dd0b1c50c2222657847f6af6aaef86 Merge: 06f1c898d 94dc11c45 Author: Anders Schack-Mulligen Date: Thu Oct 8 09:10:04 2020 +0200 Merge pull request #4362 from tamasvajk/feature/sign-analysis-cleanup Sign analysis cleanup commit 662736eb2d8d522eb384221d29a34268c147cc99 Author: Gulshan Singh Date: Wed Oct 7 12:45:08 2020 -0700 Fix compiler error after removing getLOp/getROp commit 06f1c898dcd6d1945559d710dceb21c9b30e4041 Merge: a9bb7b526 4df6a4161 Author: Tamás Vajk Date: Wed Oct 7 21:21:20 2020 +0200 Merge pull request #4349 from tamasvajk/feature/modulus-analysis ModulusAnalysis shared between C# and Java commit 46ec7fbf6e3428b62284aec7b440917a9b860c59 Author: Rasmus Wriedt Larsen Date: Wed Oct 7 21:09:26 2020 +0200 Python: Make builtin `compile` function additional taint step commit c69a61bac544c64c12ef3d57d128a31b4de2f9c7 Author: Rasmus Wriedt Larsen Date: Wed Oct 7 20:37:43 2020 +0200 Python: Model exec and eval calls as CodeExecution commit 73971cff76977151cff08aa7db3d021622af05fe Author: Rasmus Wriedt Larsen Date: Wed Oct 7 19:11:32 2020 +0200 Python: Model exec statement (Python 2 only) as CodeExecution commit 453c391bb0d779702eb5c3019c1e6f7d422273db Author: Rasmus Wriedt Larsen Date: Wed Oct 7 18:58:16 2020 +0200 Python: Add CodeExecution tests for stdlib commit a9bb7b526ccf2df5c4717e172bb92cec4e8c4d50 Merge: cec6bbea5 68014fd3b Author: Tom Hvitved Date: Wed Oct 7 18:49:30 2020 +0200 Merge pull request #4413 from hvitved/csharp/indexer-explicit-interface C#: Fix extraction of library indexers with explicit interface implementations commit 0af86cba508e86f65c75238d3261ddd8a528a741 Author: Rasmus Wriedt Larsen Date: Wed Oct 7 18:47:23 2020 +0200 Python: Port CodeInjection query and the dummy test-case we already have commit 5f6e4d47ca570be71c7f74e843e1c1f37c8904fd Author: Rasmus Wriedt Larsen Date: Wed Oct 7 18:22:45 2020 +0200 Python: Add CodeExecution concept commit 9fc6ae82d3229399a4500ade5380e3fc8aab1f33 Author: james Date: Wed Oct 7 16:15:25 2020 +0100 update template for sphinx codeql docs commit b04962b5b929367618aa9d815558ba718b3e5d7a Author: james Date: Wed Oct 7 16:14:58 2020 +0100 small changes to conf.py commit 439f0a030edce761d6eabbc40d5f0413d7b11565 Author: james Date: Wed Oct 7 16:14:35 2020 +0100 tidy up custom css commit 31816af11efdbc58c8266cea7e35fc8f8aaa8383 Author: Tom Hvitved Date: Wed Oct 7 17:02:01 2020 +0200 C#: Add missing data-flow for switch expressions commit 9c503c159159ae40288a1e2b69442a8132dfc908 Author: Tom Hvitved Date: Wed Oct 7 16:58:55 2020 +0200 C#: Add more data/control-flow tests commit 4df6a4161666c080c3e2bbfb704a4d950d08c7e1 Author: Tamas Vajk Date: Tue Oct 6 09:36:42 2020 +0200 ModulusAnalysis shared between C# and Java commit cec6bbea57ddbf66eda5037fa146edef53b0601a Merge: 88575799e 36ddbcdd7 Author: Tamás Vajk Date: Wed Oct 7 16:03:27 2020 +0200 Merge pull request #4418 from tamasvajk/feature/reenable-test C#: Reenable disabled test on OSX commit 8196cfd21af2002fe051bf2f78181490ce44e26d Author: Rasmus Lerchedahl Petersen Date: Wed Oct 7 15:56:35 2020 +0200 Python: Attempt at clearer naming of parameters commit 35b0b6b4720fe4aa5872709a3b8db709f6ab41ad Author: yoff Date: Wed Oct 7 15:48:44 2020 +0200 Update python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll Co-authored-by: Rasmus Wriedt Larsen commit 27a75c0bd1169f73232012e243b170759637aa93 Merge: 7e6f0b0bc 88575799e Author: Rasmus Lerchedahl Petersen Date: Wed Oct 7 15:43:31 2020 +0200 Merge branch 'main' of github.com:github/codeql into SharedDataflow_ArgumentPassing commit 239ea809755233284493bd6df6f5cd3ed08cdff1 Author: james Date: Wed Oct 7 14:37:35 2020 +0100 add new css styles commit af36718dc63edabe37d48ee445ee46dd2f454aff Author: Tom Hvitved Date: Wed Oct 7 15:15:18 2020 +0200 C#: QL doc adjustments commit 7e6f0b0bc32a89ec88609534bf724105ece66362 Author: yoff Date: Wed Oct 7 15:11:15 2020 +0200 Apply suggestions from code review Co-authored-by: Rasmus Wriedt Larsen commit 68014fd3bf662453f1cd9a44a8b05008e79474e2 Author: Tom Hvitved Date: Tue Oct 6 10:35:09 2020 +0200 C#: Fix extraction of library indexers with explicit interface implementations commit bec33b745e1415f927b8f3e111b0a721ce1c5790 Author: Rasmus Wriedt Larsen Date: Wed Oct 7 14:54:51 2020 +0200 Python: Use `range` instead of `self` for ::Range pattern Following the suggestions from https://github.com/github/codeql/pull/4357 commit a4ce9417bc0b86c9fb072b249e717016d55d0f37 Author: Tom Hvitved Date: Tue Oct 6 10:34:57 2020 +0200 C#: Add test for missing accessors commit 88575799e95f3d04ccb6a794ed181f90c3c05545 Merge: 6ddda1fa1 e15758ba7 Author: Tom Hvitved Date: Wed Oct 7 13:26:49 2020 +0200 Merge pull request #4417 from hvitved/csharp/named-tuple-tests C#: Add test for named tuple types commit c09695af7d3c307f68f52debbcf5d986d81f21a1 Author: Rasmus Wriedt Larsen Date: Wed Oct 7 12:29:19 2020 +0200 Python: Properly handle invoke.task decorator commit 67c5c590d2c7c98e68489b64c11751438c6b651a Author: Rasmus Wriedt Larsen Date: Fri Oct 2 18:52:14 2020 +0200 Python: Expose getParameter on ParameterNode commit 6d7f4a048bac4daaa71fcee1a95adb1e8ec59296 Author: Rasmus Wriedt Larsen Date: Wed Oct 7 12:26:49 2020 +0200 Python: Attempt to model invoke.task decorator commit c9219b37441eeef6284ae09438570c1f3e27b0b3 Author: Rasmus Wriedt Larsen Date: Wed Oct 7 12:21:30 2020 +0200 Clean module imports commit ebff1794fc511dbca2274e9e9bcc872b86b9e298 Author: Rasmus Wriedt Larsen Date: Wed Oct 7 12:16:53 2020 +0200 Python: Model invoke.context.Context commit 4ef5202382490d107f149b97ca1906fa10e98db3 Author: Rasmus Wriedt Larsen Date: Wed Oct 7 11:47:38 2020 +0200 Python: Add simple model for invoke.run and invoke.sudo and I sorted the list in Frameworks.qll, that kinda makes sense :) commit 300a8cdf7db14308b32e5a67b90f0e57430616bb Author: Rasmus Wriedt Larsen Date: Wed Oct 7 11:23:03 2020 +0200 Python: Add tests for the 'invoke' package commit d2d8d009eb7dd1e298136a0a20bd903d8b7db181 Author: Tamas Vajk Date: Thu Sep 24 13:02:10 2020 +0200 Sync Bound between C# and Java commit 40a7f5aa1fd7acd2c5fd7118aef9aaad20aee14a Author: Tamas Vajk Date: Fri Sep 25 17:15:47 2020 +0200 Java: Minor fix to modulus analysis to handle constant expressions and not only compile time constants commit 56882102494382ed43d7468110cfc4ed578cb432 Author: Tamas Vajk Date: Mon Sep 28 10:00:49 2020 +0200 Java: add test for modulus analysis commit 7721db206eab9523d189a9b5b2fd9c9c08ee6d1f Author: Rasmus Wriedt Larsen Date: Wed Oct 7 10:55:33 2020 +0200 Python: Don't double report paths for platform.popen and popen2.* I was a bit surprised that we hadn't double reported for popen2, but it turns out that the implementation (at least on unix) looks like: ``` def popen2(cmd, bufsize=-1, mode='t'): ... = Popen3(cmd, False, bufsize) ... ``` but since the modeling I did only considers calls to `Popen3` only if it has been imported from the `popen2` module, we don't consider that call as a sink. commit 94dc11c45a6cf01240628ed74d0c491431059388 Author: Tamas Vajk Date: Wed Oct 7 10:56:01 2020 +0200 Revert getNonIntegerValue unification commit 36812af2c27098318f6b787909f698a9cefa34c3 Author: Rasmus Wriedt Larsen Date: Wed Oct 7 10:54:03 2020 +0200 Python: Add test for Python2 specific command injection commit 737b2b896f5a36585481e8e9a20f46c7ba45834e Author: Rasmus Wriedt Larsen Date: Wed Oct 7 10:49:22 2020 +0200 Python: Fix QLDoc for popen2 module commit d8a9eacd02afe80b952b0be6daeef2494c780b38 Author: Rasmus Wriedt Larsen Date: Wed Oct 7 10:47:28 2020 +0200 Python: Remove TODO comment for popen2 module commit 7233ffa50f249db18aae7b8fc8fc2ebd251a094e Author: Gulshan Singh Date: Tue Oct 6 23:57:05 2020 -0700 Address review comments commit 1ed026fcce16f3e8fe4059971b0a9bf987db1a73 Author: Erik Krogh Kristensen Date: Wed Sep 23 13:55:21 2020 +0200 add a RemoteFlowSource for serverless handlers commit 050ed97d9c0cab94ae4062a1466cf2daecbafcdb Author: Erik Krogh Kristensen Date: Wed Sep 23 13:49:43 2020 +0200 add node-serialize as a js/code-injection sink commit 6ddda1fa1dfb4eca979a9d8d98238c955f555d7d Merge: 984194d30 4f56a9724 Author: Tom Hvitved Date: Tue Oct 6 20:59:00 2020 +0200 Merge pull request #4330 from tamasvajk/feature/upgrade-to-dotnet31 C#: Upgrade to .net core app 3.1 commit 6c4fd7c1ff1101889a69568cdff289deb8a50493 Author: Rasmus Wriedt Larsen Date: Tue Oct 6 19:17:41 2020 +0200 Python: Model Python 2 only platform.popen command execution commit 12e4e07cae7ae5c976488974629aa6f513e8b341 Author: Rasmus Wriedt Larsen Date: Tue Oct 6 19:14:52 2020 +0200 Python: Model Python 2 only module popen2 commit 8c2f55fbd05e9c3d3c20c7cecdfeaaca3f3cb1a3 Author: Rasmus Wriedt Larsen Date: Tue Oct 6 18:59:01 2020 +0200 Python: Model Python 2 only os.popen2, popen3, popen4 functions commit 6ec7ab2fd976f8e78409996d30fccbfc48aa52be Author: Rasmus Wriedt Larsen Date: Tue Oct 6 18:49:50 2020 +0200 Python: Add test of Python 2 specific SystemCommandExecution commit b905a3d5e3daeb906553db6f141c20db23e52ce4 Author: Taus Brock-Nannestad Date: Tue Oct 6 16:36:29 2020 +0200 Python: Attribute access API commit 98ab38a630f51486a2fcc04337bbb36eb2b2cf7a Author: Max Schaefer Date: Tue Oct 6 15:32:21 2020 +0100 JavaScript: Add yet another API-graph test with re-exports. commit 4f56a97244f225638e7acabe3fc7a9cd9b1a6a68 Author: Tamas Vajk Date: Tue Sep 29 09:33:55 2020 +0200 C#: Adjust expected files for .net 3.1 upgrade commit 56604e005aa3b788bb8a64cd48bbb5e3c2ddb9c9 Author: Tamas Vajk Date: Wed Sep 23 14:47:10 2020 +0200 C#: Upgrade to .net core app 3.1 commit 984194d3082d307392f4fe05a19d549fcd347eb5 Merge: 4e116ba0d 4db964fca Author: Jonas Jensen Date: Tue Oct 6 15:43:12 2020 +0200 Merge pull request #4406 from geoffw0/set C++: Models for std::set and std::unordered_set commit 1d9acbfca9391e14d771e0fcbd35ac122a4e3df6 Author: Jonas Jensen Date: Tue Oct 6 14:51:11 2020 +0200 C++: Demonstrate overflowing guard bounds commit 1d8051eee05dc910fa20795b1da4d8cbaa221560 Author: Max Schaefer Date: Tue Sep 29 19:47:56 2020 +0100 JavaScript: Further improve handling of re-exports in API graphs. commit d054206004f2a4787931cbd06772e0147e410388 Author: Max Schaefer Date: Tue Sep 29 19:45:11 2020 +0100 JavaScript: Improve handling of re-exports in API graphs. commit 96bf82e1ca8459d49f4908561d41d715afe07e5d Author: Max Schaefer Date: Tue Sep 29 19:44:32 2020 +0100 JavaScript: Make new source-node classes in API graphs more general and more useful. commit 95b6b16b579be889555f0d45328d7ab2fb67c72d Author: Max Schaefer Date: Tue Sep 29 19:43:24 2020 +0100 JavaScript: Add another API-graph test with re-exports. commit 4e116ba0dbc5797afab043640aa4051c54839fce Merge: 0753c8a31 99213b94f Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Tue Oct 6 06:13:21 2020 -0700 Merge pull request #4419 from erik-krogh/jsxFactory Approved by asgerf commit 0753c8a31b5eb2bd58e12a65c399a01068899b85 Merge: ef703e72d f7f82ffe4 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Tue Oct 6 06:10:21 2020 -0700 Merge pull request #4247 from erik-krogh/CVE760-reexport Approved by asgerf commit ef703e72d8963fc97a12af8fa4e96534fab2d88f Merge: 5bc7e19c4 a962a8a3b Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Tue Oct 6 06:09:48 2020 -0700 Merge pull request #4401 from asgerf/js/angular-prerequisites Approved by erik-krogh commit 396f353397277432cb3b5309939e531c460184bc Author: Asger Feldthaus Date: Tue Oct 6 14:06:10 2020 +0100 JS: Reapply fixed to javadoc commit 5bc7e19c4495c78346f3c2fca99ca5570e975a98 Merge: 021435292 f9c5b864b Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Tue Oct 6 05:46:24 2020 -0700 Merge pull request #4414 from yoff/SharedDataflow_Conditionals Approved by RasmusWL commit 021435292bd745ced64df03b9e8fe031515bf53b Merge: 7e6fa7b4b 8e82687ab Author: Anders Schack-Mulligen Date: Tue Oct 6 14:42:35 2020 +0200 Merge pull request #4341 from joefarebrother/location-tostring Java: Include column numbers in Location.toString commit f9c5b864bbd3474c864d34996f7167e11cf0f1f6 Author: Rasmus Lerchedahl Petersen Date: Tue Oct 6 13:12:12 2020 +0200 Python: Fix test of parenthesized form commit 7e6fa7b4bed8a52cfb9127f81f1d60565e1b7aa1 Merge: 3c41548aa d6dc4bb65 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Tue Oct 6 03:41:36 2020 -0700 Merge pull request #4392 from erik-krogh/flask Approved by asgerf commit 3c41548aa60af32c55dfbac05dcbd6448b922590 Merge: bc1d3de8f 89710928c Author: Arthur Baars Date: Tue Oct 6 12:31:17 2020 +0200 Merge pull request #4336 from aibaars/android-database Java: add Android database taint and SQL injection sinks commit f7f82ffe4e24110a564b93fbf1be3b8a12d00b94 Merge: 7d8bb339b bc1d3de8f Author: Erik Krogh Kristensen Date: Tue Oct 6 12:28:44 2020 +0200 Merge branch 'main' into CVE760-reexport commit bc1d3de8fe7d2f5a1ee1afd8d646101b095e6622 Merge: 75d55c87b 18f7f2b55 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Tue Oct 6 03:24:43 2020 -0700 Merge pull request #4376 from erik-krogh/simpParam Approved by asgerf commit 99213b94f577dd0b0a2830f4081c6d96a66fb1e0 Author: Erik Krogh Kristensen Date: Tue Oct 6 12:23:15 2020 +0200 detect uses of jsxFactory and jsxFragmentFactory in js/unused-local-variable commit 8e82687ab6a2d1958b74c6282037585ceea76ac5 Author: Joe Date: Wed Sep 23 12:19:43 2020 +0100 Java: Include column numbers in Location.toString commit 75d55c87b3783f9bdb850059dda25dec8ccba034 Merge: 8d09885ae fbe115c04 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Tue Oct 6 03:15:12 2020 -0700 Merge pull request #4412 from RasmusWL/python-typetracking-across-modules Approved by yoff commit 5374b66029d4193e31014f29ec1438761be3d318 Author: Asger Feldthaus Date: Tue Sep 22 14:27:17 2020 +0100 JS: Make CachedOperation private commit 433e3e7e4ed08a71d1c9521fc956e4d7e6c619b5 Author: Asger F Date: Tue Sep 22 14:17:51 2020 +0100 JS: Expand doc string in installFromTarballurl Co-authored-by: Erik Krogh Kristensen commit 4e2b990d1471d6bf61257c4e493fd40da30dfa20 Author: Asger F Date: Tue Sep 22 14:07:21 2020 +0100 Add doc string to semVerToken Co-authored-by: Erik Krogh Kristensen commit 0ddd825ea657b6b2db7f0eba8eed8e1e9af9e715 Author: Asger Feldthaus Date: Tue Sep 22 14:25:13 2020 +0100 JS: Address some more review comments commit b1bd6122326d4976a9ac777410d91f31a519605d Author: Asger Feldthaus Date: Tue Sep 22 14:04:42 2020 +0100 JS: Undo unused export commit 26b7d57a94bec66ebcf7ab3d0b6279ce2f5d7ec3 Author: Asger Feldthaus Date: Mon Sep 21 12:45:37 2020 +0100 JS: Parse preferred version directly commit 85224aad34ea1a5d870f0ba897ccecc86ddf0e22 Author: Asger Feldthaus Date: Fri Sep 18 11:52:53 2020 +0100 JS: Address some review comments commit 57a588ceb6d841e6fb7214da3a90f80a07369ddb Author: Asger Feldthaus Date: Thu Sep 17 14:42:56 2020 +0100 JS: Share extraction results via symlinks commit c84e43d95b0ee3100dc332c5ee179625c60aa873 Author: Asger Feldthaus Date: Wed May 27 17:24:07 2020 +0100 JS: Replace yarn with manual dependency resolution commit f5c3aa3d39b451bdd68ee8334e6bed294650fd89 Author: Asger Feldthaus Date: Sat Sep 5 10:16:53 2020 +0100 JS: Handle types/typings fields in package.json commit 0220ab678416490042a4fdc76932c37c97dafe50 Author: Asger Feldthaus Date: Wed May 27 11:15:16 2020 +0100 JS: Move some TypeScript classes into .ts.extractor commit 8d09885ae66c8c05beee6e56d1889fa0d99610be Merge: eece3ad35 576085af5 Author: Tamás Vajk Date: Tue Oct 6 11:45:41 2020 +0200 Merge pull request #4378 from tamasvajk/feature/flow-summary-nullable Flow summary nullable commit e15758ba7f645c4ec841bab32c130478198aaa8a Author: Tom Hvitved Date: Tue Oct 6 11:42:11 2020 +0200 C#: Add test for named tuple types commit 36ddbcdd7171f54ec5a6182bdc47b582df22b2b4 Author: Tamas Vajk Date: Tue Oct 6 11:41:48 2020 +0200 C#: Reenable disabled test on OSX commit d26a89b95e105939ed20c1ef78da90e280398bd3 Author: Rasmus Wriedt Larsen Date: Tue Oct 6 11:35:18 2020 +0200 Python: Fix QLDoc for RouteSetup commit b82727d0b8b2a3ddaa58380d0d1c396adea16b07 Author: Rasmus Wriedt Larsen Date: Tue Oct 6 11:03:25 2020 +0200 Python: Consider routed parameter if URL pattern unknown commit a962a8a3bdb2a50db21345e06db634ff531d2c16 Author: Asger Feldthaus Date: Tue Oct 6 10:01:36 2020 +0100 JS: Autoformat commit c31cdaacb22ebd00a63728ee183743416c552844 Author: Asger Feldthaus Date: Tue Oct 6 10:01:04 2020 +0100 JS: Add test for getFieldTypeAnnotation commit 16bad003a013e19b521ad0ef74be59d72657d5c4 Author: Rasmus Wriedt Larsen Date: Tue Oct 6 10:58:46 2020 +0200 Python: Add test for routed params with unknown url pattern commit 0f077f5d7d483a04e5be899b28ffe521a2941f7f Author: Rasmus Lerchedahl Petersen Date: Tue Oct 6 10:54:23 2020 +0200 Python: Add flow inside `IfExprNode`s commit 8f13d586b7662f39f60e9613aebeec511ebb861e Author: Rasmus Lerchedahl Petersen Date: Tue Oct 6 10:49:15 2020 +0200 Python: More tests of conditonals Also use better formatter (better because comments are close to what they comment) commit 89710928c8b31b16f0ac584a3c48f3bab38a7d1f Merge: cf6036f9b 6bd355784 Author: Arthur Baars Date: Tue Oct 6 10:48:22 2020 +0200 Merge branch 'main' into android-database commit eece3ad35293bfc31bd099d00eb2b33dd2f486f6 Merge: 6bd355784 dd5fb6ce1 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Tue Oct 6 01:48:21 2020 -0700 Merge pull request #4411 from github/asgerf/exclude-js-tests Approved by esbena commit 6bd355784ae80011d517cfb8890b1d6c5053e0f7 Merge: 77abff7c9 c39bca524 Author: Tom Hvitved Date: Tue Oct 6 10:45:19 2020 +0200 Merge pull request #4353 from hvitved/csharp/dataflow/task-precise C#: Precise data-flow for `System.Threading.Tasks` commit 0109805ab0643b743334d8ee72042277dd37ac78 Author: Max Schaefer Date: Tue Oct 6 09:45:03 2020 +0100 JavaScript: Use new API in NoSQL models. commit 8277d5c08f9d8f6b462ba86a90952efda1365675 Author: Max Schaefer Date: Mon Oct 5 16:41:44 2020 +0100 JavaScript: Introduce convenience predicate for working with typed API-graph nodes. commit 9206549a389f7ea009f4ae269405a26320464b33 Author: Max Schaefer Date: Mon Oct 5 16:22:40 2020 +0100 JavaScript: Make integration of TypeScript canonical names with modules in API graphs more consistent. Previously, canonical names were direct successors of module definitions/uses, now they are successors of exports/imports. commit dd5fb6ce129201a302ebd682694aa260ba4413e4 Author: Asger F Date: Tue Oct 6 08:46:43 2020 +0100 Exclude JS tests from code scanning commit 576085af5016c56a7d71de752c0260a6372ac8b9 Author: Tamas Vajk Date: Thu Oct 1 11:57:02 2020 +0200 Add extra information to nullable conversion test file commit faf663a334ada867a6e3abe9b4ba14dff7cc4a42 Author: Tamas Vajk Date: Thu Oct 1 08:11:06 2020 +0200 C#: Flow summary for Nullable commit 77abff7c9065be0b9942db3609654022bd686aa3 Merge: 339c0721c 3b7006460 Author: Tamás Vajk Date: Tue Oct 6 09:01:48 2020 +0200 Merge pull request #4405 from tamasvajk/feature/lazy-flow C#: Improve data flow summary for System.Lazy<> commit fbe115c046afe1b67618b139318fc2e0667a76a3 Author: Rasmus Wriedt Larsen Date: Tue Oct 6 03:08:55 2020 +0200 Python: Show TypeTracking doesn't work for module members commit f03a8a838b676b9b0767bb06ef5cb5b83b4aafba Author: Rasmus Wriedt Larsen Date: Tue Oct 6 02:49:49 2020 +0200 Python: Make any routed parameter a RemoteFlowSource I'm not 100% sure whether this approach makes everything too magic, but I like the fact that you can't _forget_ to make routed params remove-flow sources. commit b78c665f34b1b756e377870dfe65bbd3d402d7c7 Author: Rasmus Wriedt Larsen Date: Tue Oct 6 02:48:02 2020 +0200 Python: Model RouteSetup for flask commit d27e6955b4846b483a4a8dc6849b22425cdb7785 Author: Rasmus Wriedt Larsen Date: Tue Oct 6 02:47:19 2020 +0200 Python: Add test setup for HTTP::Server::RouteSetup commit ebc3d32ff13f94d981b763ef8883219454ef83f1 Author: Rasmus Wriedt Larsen Date: Tue Oct 6 02:02:29 2020 +0200 Python: Add concept for HTTP server modeling If we want to separate out into a file, we can always do this with ``` import experimental.semmle.python.HTTP as HTTP ``` commit 9f1aa8ca0c98bb2a30f73f48830a6ce5fa1ef2d7 Author: Rasmus Wriedt Larsen Date: Fri Oct 2 18:52:14 2020 +0200 Python: Expose getParameter on ParameterNode commit d7526c40ba804fa9b082591ca0c3e5e79437df6f Author: Rasmus Wriedt Larsen Date: Wed Sep 30 14:33:14 2020 +0200 Python: Copy old flask tests to new dataflow setup commit d6dc4bb6553e6c04fe33d0c88fcee5803cbde305 Author: Erik Krogh Kristensen Date: Sat Oct 3 14:35:54 2020 +0200 allow flask url_for urls in TargetBlank.ql commit 7d8bb339b6fb9a4bed2fcc3ed20b59719e6c8b23 Author: Erik Krogh Kristensen Date: Mon Oct 5 21:24:02 2020 +0200 add support for destructuring object exports in `getAnExportedValue` commit 339c0721c5e1ac25bea75dd4168616ec488c4238 Merge: e95b66555 c0a67a8d7 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Oct 5 12:30:53 2020 -0700 Merge pull request #4344 from esbena/js/fixup-cwe-20-to-cwe-020 Approved by erik-krogh commit e95b665556176c3f9454213183adc79e766e1d3d Merge: 6b2ae5d1a 2753a4f37 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Oct 5 12:01:34 2020 -0700 Merge pull request #4363 from erik-krogh/nosql-api Approved by max-schaefer commit 6b2ae5d1ade14c472820f313267a30d0769d2fd2 Merge: b7dcd5c55 a6d7b1f9d Author: Jonas Jensen Date: Mon Oct 5 19:46:32 2020 +0200 Merge pull request #4393 from MathiasVP/no-more-flow-into-read-side-effect C++: No more flow into ReadSideEffect instructions commit b7dcd5c557299eb0e2acde33a2fae09fe3ed797f Merge: 297f1c75e 1efe461a9 Author: Robert Marsh Date: Mon Oct 5 12:22:27 2020 -0400 Merge pull request #4395 from geoffw0/modelbeginend C++: Merge StdSequenceContainerBeginEnd into the general BeginOrEndFunction commit c39bca52405531281774ea287a1d2950652dd8a3 Author: Tom Hvitved Date: Mon Oct 5 17:14:37 2020 +0200 C#: Model data-flow for `System.Threading.Tasks.Task.GetAwaiter()` commit c1b5357e74ba2f908c865e29dc703b8ea39ee581 Author: Erik Krogh Kristensen Date: Mon Oct 5 16:53:05 2020 +0200 remove stray todo commit 4db964fca919d3fb4894d4c5267865a6a46be28b Merge: d4a1acedd 297f1c75e Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Oct 5 15:16:42 2020 +0100 Merge branch 'main' into set commit d93b37d5c5ba60b9ddb707b143e2bba69265b4cd Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Oct 5 15:11:23 2020 +0100 C++: Autoformat some more files. commit 297f1c75e45dde557bd03ccc1e42ccab9115bc33 Merge: 4ec14b1b0 855d2b50d Author: Jonas Jensen Date: Mon Oct 5 15:28:10 2020 +0200 Merge pull request #4345 from geoffw0/map C++: Models for std::pair, std::map and std::unordered_map commit a6d7b1f9d937d8164574f540c99618cead5d1614 Author: Mathias Vorreiter Pedersen Date: Mon Oct 5 15:21:15 2020 +0200 Update cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll Co-authored-by: Jonas Jensen commit e95aefe0b2f5f9ac061c5322b7cb70cc97d4ac82 Author: Mathias Vorreiter Pedersen Date: Mon Oct 5 15:13:33 2020 +0200 C++: Now that PrimaryArgumentNode is an OperandNode we want a specialized toString on it commit 2753a4f3791cce90de765210480257dfd3c57fbc Author: Erik Krogh Kristensen Date: Mon Oct 5 15:11:04 2020 +0200 Apply suggestions from code review Co-authored-by: Max Schaefer <54907921+max-schaefer@users.noreply.github.com> commit 4ec14b1b0203802f7d633e10d5ed4432014d06c4 Merge: 48fa8aacd 4d62033a1 Author: Tom Hvitved Date: Mon Oct 5 15:04:50 2020 +0200 Merge pull request #4399 from hvitved/csharp/error-type-population C#: Handle population of error types commit 48fa8aacd578587adb93da512fccc712af3d0c8a Merge: 30f29e0ba fee99105d Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Oct 5 05:58:48 2020 -0700 Merge pull request #4403 from asgerf/js/remove-tslint-dependency Approved by erik-krogh commit 3b70064606a0df939af48900f6b0fcae2c4707b3 Author: Tamas Vajk Date: Mon Oct 5 14:45:14 2020 +0200 C#: Improve data flow summary for System.Lazy<> commit d162c3d8c619ead910355180223234eaebac10b6 Author: Mathias Vorreiter Pedersen Date: Mon Oct 5 14:29:57 2020 +0200 C++: Accept more test changes commit 855d2b50d70c97e9ea4e7007e71ee54bf71bfc3b Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Oct 5 13:00:51 2020 +0100 C++: Correct test comments. commit 30f29e0ba7d1e74e6c95858bd8d5b9f573669870 Merge: e660ac54d 252f8aa89 Author: Anders Schack-Mulligen Date: Mon Oct 5 13:45:06 2020 +0200 Merge pull request #4320 from aibaars/multipart-request Java: add Spring::MultipartRequest as taint source commit c757813d65964bb7631b826173d387e6ee6fc662 Merge: 2dc8fba7f e660ac54d Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Oct 5 12:32:49 2020 +0100 Merge branch 'main' into map commit e660ac54da863fd46660cb23e4cbde322b91a7df Merge: 43b2c9053 ca4781eb7 Author: Anders Schack-Mulligen Date: Mon Oct 5 13:25:54 2020 +0200 Merge pull request #4358 from joefarebrother/format-taint Java: Add taint steps through string formatting methods commit 591c17d7cf6cc458d387773d7a64e9039d7743a3 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Oct 5 12:22:08 2020 +0100 C++: Rearrange comments. commit 6c87b08c69d10ecebc2889c5d4c1c4ffa09518f3 Author: Mathias Vorreiter Pedersen Date: Mon Oct 5 12:54:11 2020 +0200 C++: Respond to review comments: - ArgumentNode is now abstract - PrimaryArgumentNode is now an OperandNode. - ArgumentIndirectionNode is now merged into SideEffectArgumentNode. commit fee99105da0194473d2d4fdfe20b3121e314a77e Author: Asger Feldthaus Date: Mon Oct 5 11:53:58 2020 +0100 JS: Remove tslint dependency commit 478cfd7310718d549fff1fc87c70cf9f865bcda0 Author: Rasmus Lerchedahl Petersen Date: Mon Oct 5 12:43:30 2020 +0200 Python: Small clean-up commit 43b2c9053887414b1468aa99d3054462bae0f833 Merge: d38121f54 98e93a7b9 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Oct 5 03:12:23 2020 -0700 Merge pull request #4400 from max-schaefer/js/api-graph-classrefs Approved by asgerf commit 488a55b9dd6263947d37fee616a262501a59a2e6 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Oct 5 10:39:32 2020 +0100 C++: Autoformat. commit f449da2fdbb19ae8257fb414c0abe599d80b7291 Author: Rasmus Lerchedahl Petersen Date: Mon Oct 5 11:39:18 2020 +0200 Python: Write explanatory examples. commit 4c14f5dbb78d5e84efa0a5c4bd5b2292f56a6d2b Merge: 072e1967c d38121f54 Author: Mathias Vorreiter Pedersen Date: Mon Oct 5 11:03:42 2020 +0200 Merge branch 'main' into no-more-flow-into-read-side-effect commit 8689a9b3b9bb350908d5fad4cd1918a51dea3a28 Author: Asger Feldthaus Date: Wed Sep 30 15:30:56 2020 +0100 JS: Fix a bad join order in barrierGuardBlocksNode commit 790d2ba0fce4c937d86acbfea54d520ae355ed68 Author: Asger Feldthaus Date: Sat Oct 3 10:15:39 2020 +0100 JS: Fix FPs from ParameterFieldAsPropWrite.getPropertyNameExpr commit cad259fb83975edad339f9ec1f59e0f76be684c4 Author: Asger Feldthaus Date: Tue Sep 29 12:01:38 2020 +0100 JS: Use more types in DOM model commit 3dabff6b171793df97b5ab126dfd14c7be7d0ef1 Author: Asger Feldthaus Date: Tue Sep 29 11:08:22 2020 +0100 JS: Recognize field types in untyped code commit 4d62033a159d50b3ec261aa632a5ebb7e0813fcc Author: Tom Hvitved Date: Mon Oct 5 10:14:13 2020 +0200 C#: Handle population of error types commit d38121f54a5f6e9144a99b6beebf9562a5969cdd Merge: 78c58c241 8d5febf9c Author: Mathias Vorreiter Pedersen Date: Mon Oct 5 09:16:50 2020 +0200 Merge pull request #4394 from geoffw0/oddsends2 C++: Clean up and add to taint tests commit 8e27904f659c30aac41a0c91e41ba70a1b596c6b Author: Rasmus Lerchedahl Petersen Date: Sun Oct 4 15:34:25 2020 +0200 Python: Add explanatory comment. commit 34638890100b05f81f0b2c560ab0a97e93c531be Author: Rasmus Lerchedahl Petersen Date: Sun Oct 4 09:40:06 2020 +0200 Python: Add comments commit 385e213fcfc36e30734894a1714df18905906d2a Author: Rasmus Lerchedahl Petersen Date: Sun Oct 4 09:33:30 2020 +0200 Python: Fix comments commit ce18bff274f9135765dd6328baf333b50c5a668a Author: Rasmus Lerchedahl Petersen Date: Sat Oct 3 23:34:39 2020 +0200 Python: Support method calls commit 856ad0769481947ddb582090fcb3069024c0f047 Author: Erik Krogh Kristensen Date: Sat Oct 3 22:07:34 2020 +0200 join-order improvement in NoSQL.qll commit c0b251ad9ef07561fc5ebda9285a843e40bff912 Author: Tom Hvitved Date: Sun Sep 27 19:43:41 2020 +0200 C#: Precise data-flow for `System.Threading.Tasks` commit 26544f322a9b36e67ea789800ed732068db76121 Author: Tom Hvitved Date: Sun Sep 27 20:00:00 2020 +0200 C#: Update data-flow tests for `System.Threading.Tasks` commit 78c58c24158e3ee4fd78318194d56591af90da69 Merge: 754d82c32 b5d05f99c Author: Arthur Baars Date: Fri Oct 2 20:48:43 2020 +0200 Merge pull request #4384 from tausbn/python-fix-package-locations Python: Fix `hasLocationInfo` for packages commit 754d82c32528e0854f0852245ef558849e1cf1e8 Merge: 30ed6a0da 5ce0974eb Author: Alexander Eyers-Taylor Date: Fri Oct 2 18:33:36 2020 +0100 Merge pull request #4382 from github/alexet-patch-1 Fix the name of the vscode extension recommendation commit 30ed6a0dac94bd5b50a01bfc57b3b7e15c409c3e Merge: fce76e279 daa1bcc06 Author: Alexander Eyers-Taylor Date: Fri Oct 2 18:31:25 2020 +0100 Merge pull request #4385 from aibaars/drop-queries Drop 'tech-inventory' and 'code duplication' queries from the standard query suites commit 3536d84bdf5e03cbed13dc3b7ddde240f97ee948 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Oct 2 17:57:02 2020 +0100 C++: Use [, ...] syntax more widely. commit 1efe461a98d7718d24fdb2ca7172f040002349db Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Oct 2 16:57:51 2020 +0100 C++: Move the rest of of StdSequenceContainerBeginEnd into BeginOrEndFunction. commit 8d5bd2289bcb3c5a966b3167dfcba8d59a48da4f Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Oct 2 16:56:37 2020 +0100 C++: Remove parts of StdSequenceContainerBeginEnd in favour of BeginOrEndFunction. commit 8d5febf9c4c067ec4b51aa9c072ee5641af039b9 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Oct 2 17:26:47 2020 +0100 C++: Add a couple more test cases that have been discussed. commit cc170bd513339a31131691398a4d1d8b98b71f7e Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Oct 2 17:12:13 2020 +0100 C++: Test layout. commit 1a93090778b05bb8914ad7d1b8051b9a3070af42 Author: Tom Hvitved Date: Fri Sep 18 12:01:10 2020 +0200 C#: Improve guards SSA logic in the context of control-flow splitting commit f1d6f7cd0c128092b0314a491ce585a910e20aa4 Author: Tom Hvitved Date: Fri Sep 18 11:41:19 2020 +0200 C#: Model assertions in the CFG commit 2dc8fba7fe91cf309e41b8bdcdf5257319d97076 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Oct 2 16:39:23 2020 +0100 C++: Remove StdMapBeginEnd as we now have a general model BeginOrEndFunction in main. commit 0d6bd6facb14c68133b2f178af56e8da3b30b98b Merge: 4b0e9a4fb fce76e279 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Oct 2 16:24:03 2020 +0100 Merge branch 'main' into map commit d4a1acedde307c14631fefcbd00ff733dccd4534 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Oct 2 16:23:48 2020 +0100 C++: Remove StdSetBeginEnd as we now have a general model BeginOrEndFunction in main. commit daa1bcc06e069a850f76e2363c7a2a0dafa07c74 Author: Arthur Baars Date: Thu Oct 1 20:28:14 2020 +0200 Also mark 'tech inventory' queries as deprecated commit fc45b6cd3cee747044469669fc3680bf2ec79f64 Author: Arthur Baars Date: Thu Oct 1 19:43:14 2020 +0200 Drop 'tech-inventory' and 'code duplication' queries from the standard query suites commit 88a93964a7f8b0666c6b0f3cf033c343d9de585e Merge: cafd32095 fce76e279 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Oct 2 16:17:48 2020 +0100 Merge branch 'main' into set commit 28ab092e9f16ee41e17efc414212e4a635ff6803 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Oct 2 15:54:26 2020 +0100 C++: Add 'tainted' markers to standalone_iterators.cpp test. commit fce76e27990b13bb137a4ef3fa6e751697a60dd8 Merge: 2e4a61428 e5b9ac8d9 Author: Taus Date: Fri Oct 2 16:14:34 2020 +0200 Merge pull request #4354 from RasmusWL/python-command-execution-modeling Python: Better command execution modeling commit 2e4a61428d01fad5e5e99124326b11b4ee77cc84 Merge: 55d25d90f 2acfd4cdb Author: Taus Date: Fri Oct 2 16:13:25 2020 +0200 Merge pull request #4346 from RasmusWL/python-add-implicit-init-test Python: add test for implicit __init__.py files commit 072e1967c13ad70773aa986fbec3243a28ac1cd9 Author: Mathias Vorreiter Pedersen Date: Fri Oct 2 15:51:29 2020 +0200 C++: Accept more tests commit 17f0ac4b208991ddbf4f04a0fe52b135ee1df043 Author: Tom Hvitved Date: Wed Sep 16 14:19:02 2020 +0200 C#: Add more CFG assertion tests commit 55d25d90fab275c1a5ff46459055fbcd7eb9a2fc Merge: aa707e937 bc68578c8 Author: Tom Hvitved Date: Fri Oct 2 15:12:33 2020 +0200 Merge pull request #4386 from hvitved/csharp/remove-deprecated-queries C#: Remove deprecated external queries commit e5b9ac8d9c38af3d214b52943bc1375eea7a49f2 Author: Rasmus Wriedt Larsen Date: Fri Oct 2 14:12:41 2020 +0200 Python: Use getCommand as tag in ConceptsTest commit eb67986916e55bd253c7a9fe995bdf7e3240a593 Author: Rasmus Wriedt Larsen Date: Fri Oct 2 14:11:07 2020 +0200 Python: Exlucde only command injection sinks in os and subprocess commit 48902c07a4830ce527d315d5a1d2dff82f3c7898 Author: Mathias Vorreiter Pedersen Date: Fri Oct 2 14:10:58 2020 +0200 C++: Accept test changes commit 8f4982d3f5bfb24d2fdaf2f6a9c0d479db50ea4e Author: Mathias Vorreiter Pedersen Date: Fri Oct 2 14:10:28 2020 +0200 C++: Remove flow into ReadSideEffect instructions in simpleInstructionLocalFlowStep commit 68eacef23c91bd6a576a6d835a054a12bb4bf670 Author: Rasmus Wriedt Larsen Date: Fri Oct 2 13:38:54 2020 +0200 Python: Refactor OsExecCall and friends for better readability commit de07d9e5d98ccd02f9b9c27ab3e38a4970789d0c Author: Rasmus Wriedt Larsen Date: Fri Oct 2 13:34:33 2020 +0200 Python: Highlight that os.popen is not only problem for extra alerts commit b5d05f99c99e3835579ef8206949332be51dc0d2 Author: Taus Brock-Nannestad Date: Fri Oct 2 12:04:43 2020 +0200 Python: Fix test output commit 4b0e9a4fb1b927924dc5070fc1bae9c2c2dc37c2 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Oct 2 10:55:13 2020 +0100 C++: Remove the model of make_pair. commit 0b6096ebfe0fbdecde26c8be4be687dd8f51da76 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Oct 2 10:51:34 2020 +0100 C++: Define make_pair and declare std::forward in the test. commit 6acb1990748303a17cc0177752e57ae6b5072aa4 Author: Erik Krogh Kristensen Date: Fri Oct 2 11:09:50 2020 +0200 improve precision using `getAnImmediateUse` to check parameter names commit abdbe92720b0b32742c0cb5e1bfb0cf8d9ae7129 Author: Erik Krogh Kristensen Date: Tue Sep 29 15:43:52 2020 +0200 refactor the NoSQL model to use API graphs commit 98e93a7b9da765d4f0f31eb4c9a955b5fa8ee8f0 Author: Max Schaefer Date: Thu Oct 1 12:05:12 2020 +0100 JavaScript: Improve API-graph support for function-style classes. commit bd32faf934bd26957a16a0aa2ac092c5759d2342 Author: Rasmus Lerchedahl Petersen Date: Fri Oct 2 10:06:54 2020 +0200 Python: annotate new test commit 2a4d21a989b0c095228a7e41cd6611060ce8712e Author: Rasmus Lerchedahl Petersen Date: Fri Oct 2 10:02:29 2020 +0200 Python: Test method call commit aa707e93703ef2ec0f3a32de80c92141ef09453e Merge: 48c6f34f9 578ea1ae4 Author: Chris Smowton Date: Fri Oct 2 08:51:36 2020 +0100 Merge pull request #4381 from smowton/smowton/admin/fix-owasp-broken-links Fix OWASP broken links commit 1cf3196b611fc321ed5d30df09f0b38614290263 Author: Tamas Vajk Date: Thu Oct 1 15:52:07 2020 +0200 Fix additional PR review findings commit 01de550ef8c1de5cfd880fc2d61121d0089d8b66 Author: Tamas Vajk Date: Wed Sep 30 08:19:05 2020 +0200 Make predicates private commit f52cf264ec4014b84174248784321033fc6c33fd Author: Tamas Vajk Date: Tue Sep 29 16:52:49 2020 +0200 Refactor specificSubExprSign commit f03146d12f68c7b8f16657c1851e5109dc41fc63 Author: Tamas Vajk Date: Tue Sep 29 15:26:20 2020 +0200 Refactor fieldSign commit 21ff1a0445dc9c8d6a9513a96fa1c87fc29f6ba3 Author: Tamas Vajk Date: Tue Sep 29 14:53:59 2020 +0200 Address some of the PR review findings commit 638d0399a8b0173dde4aa228202c6d8a00e06364 Author: Tamas Vajk Date: Tue Sep 29 12:49:42 2020 +0200 Java, C#: Refactor explicitSsaDefSign in sign analysis commit 7545fe74e3c2ea69384f199cb6c4fc80ddaa9719 Author: Tamas Vajk Date: Tue Sep 29 12:10:35 2020 +0200 Java, C#: Refactor implicitSsaDefSign in sign analysis commit 37fc1d6f0fbd4a5bb0d3375de9e00969c2f6039e Author: Tamas Vajk Date: Tue Sep 29 11:19:02 2020 +0200 Java, C#: cleanup sign analysis Add missing QL doc, improve readability commit f026d3a1e693941ea0434b82eb773675704176c7 Author: Gulshan Singh Date: Thu Oct 1 23:22:33 2020 -0700 C++: Improve bitwise and range analysis commit 78625b764dd2f0c4f90d15e09d02b59524566c22 Author: Gulshan Singh Date: Thu Oct 1 16:07:06 2020 -0700 C++: Add test for bitwise and ranges commit bc68578c8bfd2c6710c930314e2cf6f1878ae9da Author: Tom Hvitved Date: Thu Oct 1 21:11:47 2020 +0200 C#: Remove deprecated external queries commit 48c6f34f91deea2844c67961ea5f8d5ae5c13471 Merge: f7f05476a e0ca4dafb Author: Jonas Jensen Date: Thu Oct 1 20:19:56 2020 +0200 Merge pull request #4372 from matt-gretton-dann/cpp20-constinit Add support for Variable.is_constinit() commit f7f05476a2b6ca10d3d884dfab6228ec039e7dff Merge: e555b6b2a e712d16e7 Author: Aditya Sharad <6874315+adityasharad@users.noreply.github.com> Date: Thu Oct 1 09:55:19 2020 -0700 Merge pull request #4375 from adityasharad/javascript/client-side-url-redirect-regexp JavaScript: Track taint through RegExp.prototype.exec for URL redirection commit ad9f306352625297ef678ef2e742ec04b95dc9e1 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Oct 1 17:38:09 2020 +0100 C++: Model taint flow only when the second component of a pair would be tainted. commit e555b6b2a899ae6329ad9e46a8af864d66d3d793 Merge: c027f3bd2 d5f8cbc50 Author: Ian Lynagh Date: Thu Oct 1 17:16:20 2020 +0100 Merge pull request #4380 from github/igfoo/unnamed C++: Accept test changes in unnamed entity naming commit 75f4051cb5bcc9302fcffe0486d635c6dd843d6c Author: Taus Brock-Nannestad Date: Thu Oct 1 17:21:53 2020 +0200 Python: Fix `hasLocationInfo` for packages commit ca4781eb78e572fd9e18d8e3bb7c2155d2fd7f37 Author: Joe Date: Thu Oct 1 15:58:32 2020 +0100 Java: Remove use of StringFormatMethod in TaintTrackingUtils commit 0841e92a6b871e6151f5138c117b809d598290eb Author: Rasmus Lerchedahl Petersen Date: Thu Oct 1 16:26:12 2020 +0200 Python: Test for method call commit 5ce0974eb2d4501fcd4eff872416f033bd1319de Author: Alexander Eyers-Taylor Date: Thu Oct 1 14:40:45 2020 +0100 Fix the name of the vscode extension recommendation The name is case sensitive so it didn't work before. commit 5326125b70c0860434a5dd2b28a380a9b154bf9c Author: Rasmus Lerchedahl Petersen Date: Thu Oct 1 15:28:26 2020 +0200 Python: Handle positional construtor arguments commit c027f3bd2b044881fd178119b0b23aab31769253 Merge: 36450a899 2bbaa4e17 Author: Anders Schack-Mulligen Date: Thu Oct 1 15:11:49 2020 +0200 Merge pull request #4324 from tamasvajk/feature/unsigned-sign-analysis Handle unsigned types in sign analysis (C# and Java) commit 36450a89982496c59448efcd6e5dd6088992ec3a Merge: d54a05745 4dec2171d Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Thu Oct 1 06:00:17 2020 -0700 Merge pull request #4338 from erik-krogh/nodejs-server-request-data Approved by asgerf commit d54a0574578d42868fb274c73c3246666c61d574 Merge: 0158e2ffe fbd62abd6 Author: Erik Krogh Kristensen Date: Thu Oct 1 14:58:45 2020 +0200 Merge pull request #4377 from erik-krogh/babelCrash JS: prevent crash when TemplateLiteral is used in import commit 578ea1ae43950adea8082fd7bb4eac65463b5d62 Author: Chris Smowton Date: Thu Oct 1 13:09:52 2020 +0100 Fix OWASP broken links commit 18f7f2b559cbe1fadf4cf748582b78fc483b7bf6 Author: Erik Krogh Kristensen Date: Thu Oct 1 13:49:31 2020 +0200 autoformat commit 4dec2171dabf38374b13d25c755e48bc7bb1e841 Author: Erik Krogh Kristensen Date: Thu Oct 1 13:21:56 2020 +0200 add http request server data as a RemoteFlowSource commit 3247b300aeea54f6a167f488559634485ecd30b1 Author: Rasmus Wriedt Larsen Date: Thu Oct 1 12:55:11 2020 +0200 Python: Fix problem with missing use-use flow commit 9b3509f0ba20c4ad0ffd31dd8f88be4b2e55e874 Author: Rasmus Wriedt Larsen Date: Thu Oct 1 12:51:44 2020 +0200 Python: Highlight problem with missing use-use flow commit 2187389da108753ff3c69d5cd3d2c1e42c6e2ac4 Author: Rasmus Lerchedahl Petersen Date: Thu Oct 1 12:48:38 2020 +0200 Python: Show constructor keyword arg problem Also make tests runnable commit 0158e2ffefd61fe0821247f60b81f0dc2ffa1116 Merge: 7f075202c dfc443601 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Thu Oct 1 03:33:45 2020 -0700 Merge pull request #4374 from max-schaefer/js/api-graph Approved by erik-krogh commit db23dad6ec9d0c53220eff2874d5fa89758ab358 Author: Rasmus Lerchedahl Petersen Date: Thu Oct 1 12:33:42 2020 +0200 Python: Allow callables to connect to calls freely commit 7f075202c681f0245c9401913132c78941288748 Merge: 282d3e8f7 bfb653a34 Author: Max Schaefer <54907921+max-schaefer@users.noreply.github.com> Date: Thu Oct 1 11:33:01 2020 +0100 Merge pull request #4367 from erik-krogh/sql-api JS: Fixing an API-graph gotcha in `SQL.qll` commit fbd62abd64307acd1e1e3a3eb72335afa4d66a98 Author: Erik Krogh Kristensen Date: Thu Oct 1 11:24:54 2020 +0200 prevent crash when TemplateLiteral is used in import commit 75b9237b81db3de31f4066e548bc505c8efd59c5 Author: Erik Krogh Kristensen Date: Thu Oct 1 10:26:34 2020 +0200 use Parameter instead of SimpleParameter in the AngularJS model commit c675d72629b5d9f87a6c141aa5fc41c2014f0b0d Author: Erik Krogh Kristensen Date: Wed Sep 30 15:55:26 2020 +0200 use Parameter instead of SimpleParameter in remaining route-handler models commit f65ba114859fc1c134692e36e9f422cac8650b01 Author: Erik Krogh Kristensen Date: Wed Sep 30 15:13:17 2020 +0200 use Parameter instead of SimpleParameter in AMD.qll commit b092df48a55c8a1f7585b4c9a103aa6427b9aff1 Author: Rasmus Lerchedahl Petersen Date: Thu Oct 1 10:15:19 2020 +0200 Python: Location and toString for KwUnpacked commit e712d16e7e31273e397d88299f635d22c75aef9c Author: Aditya Sharad Date: Wed Sep 30 15:10:49 2020 -0700 JavaScript: Track taint through RegExp.prototype.exec for URL redirection Regexp literals are currently handled, but not `RegExp` objects. commit 29a162bc9cfe30b2476e93bbe0d6276574039443 Author: Rasmus Lerchedahl Petersen Date: Wed Sep 30 23:55:02 2020 +0200 Python: Proper flow **arg -> **param commit cafd32095326e867e817b3935f156a30b85d1141 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Sep 30 17:37:56 2020 +0100 C++: Add set/map constructor models. commit 6520f9d0fb3981093a43b1d2d800358d3bcd2096 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Sep 30 17:21:13 2020 +0100 C++: Add basic std::set models. commit 5bc7d3a9b28af484a1684ec475ecaf3fb4153721 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Sep 25 16:39:33 2020 +0100 C++: Add tests for std::set and std::unordered_set. commit 428c2a3fdac52ab759dc5972a8e8182efc6aa074 Merge: c4a2e1d6d d69477789 Author: Rasmus Wriedt Larsen Date: Wed Sep 30 17:38:59 2020 +0200 Merge branch 'main' into python-command-execution-modeling commit e0ca4dafb855e15f4cbddab272379cafa8d1115e Author: Matthew Gretton-Dann Date: Wed Sep 30 16:31:45 2020 +0100 Add support for Variable.is_constinit() commit c4a2e1d6d169429349df26df5151c4ad51401408 Author: Rasmus Wriedt Larsen Date: Wed Sep 30 17:24:50 2020 +0200 Python: Rewrite attribute lookup helpers for better performance Not that they actually had a huge problem right now, just that using the old pattern HAS lead to bad performance in the past. See https://github.com/github/codeql/pull/4361 commit 952cc89c2a4490ee850c31a072876f276f0f2a24 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Sep 30 15:57:28 2020 +0100 C++: Improve make_pair in stl.h (using remove_reference). commit 7ecd229ce79da6920fa4683a3cb89aa4dc011310 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Sep 30 11:47:20 2020 +0100 C++: Improve make_pair in stl.h (jbj solution). commit 282d3e8f7e4d8be3e3f12479c3d308353fb33cdb Merge: 32bf7d6bd 4faeede5c Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Sep 30 15:43:32 2020 +0100 Merge pull request #4322 from jbj/range-analysis-custom-defs C++: Support custom defs in SimpleRangeAnalysis commit 32bf7d6bdfe42ebc33ddccb6b57112faca44c110 Merge: d69477789 03d8fc729 Author: Taus Date: Wed Sep 30 16:15:46 2020 +0200 Merge pull request #4256 from fatenhealy/Noblowfish CWE-327 BrokenCryptoAlgorithm recommendation to AES instead of Blowfish commit b0ed7af897a95883437127eaa64bd10687589506 Author: Rasmus Lerchedahl Petersen Date: Wed Sep 30 15:54:12 2020 +0200 Python: Approximate **arg -> **param commit 4ae422ce1633d98887f6f32a28467d10998892e0 Author: Rasmus Lerchedahl Petersen Date: Wed Sep 30 15:28:29 2020 +0200 Python: Add test for extraneous overflow arguments commit bfb653a34a02719211564a41d1dcf24056bfb75d Author: Erik Krogh Kristensen Date: Wed Sep 30 15:15:27 2020 +0200 rename getAReference to getAnImmediateUse commit eb973b39fe780a8915bd90e8a5573a0530200c2a Author: Erik Krogh Kristensen Date: Wed Sep 30 15:12:17 2020 +0200 Update javascript/ql/src/semmle/javascript/frameworks/SQL.qll Co-authored-by: Max Schaefer <54907921+max-schaefer@users.noreply.github.com> commit cf6036f9b4d79ee59fe1bd199bf9099f4e5c550d Author: Arthur Baars Date: Wed Sep 30 14:42:19 2020 +0200 Java: fix some android database sinks commit 03d8fc7296b18e5244d2b72eb3b7f2634a40bb3f Author: Faten Healy <5361987+fatenhealy@users.noreply.github.com> Date: Wed Sep 30 22:18:36 2020 +1000 changed to AES commit 3af3d87ecd2970207742c23309f8f27ee7dca7e0 Author: Jonas Jensen Date: Wed Sep 30 13:52:23 2020 +0200 C++: Change note for several range-analysis PRs commit d316cb512e9df7a9e34abe048a789c62c245dd9b Author: Erik Krogh Kristensen Date: Wed Sep 30 13:24:29 2020 +0200 deprecate `exports` and replace uses with the new `getAnExportedValue` commit 4adc26eb629f373fcfe7a9be200436bc087d8ac4 Author: Rasmus Wriedt Larsen Date: Wed Sep 30 13:31:56 2020 +0200 Python: Fix command injection example code `subprocess.Popen(["ls", "-la"], shell=True)` correspond to running `sh -c "ls" -la` So it doesn't follow the pattern of the rest of the test file. commit d69477789437a3e22d1b5d1e880658916e4914d0 Merge: b1c826e5c 1595fed2d Author: Taus Date: Wed Sep 30 13:35:16 2020 +0200 Merge pull request #4369 from RasmusWL/python-ospathjoin-taintstep Python: Add taint-step for os.path.join commit b24e9590333be9252cd00cfa396a7fa76dd944e5 Author: Erik Krogh Kristensen Date: Wed Sep 30 13:29:47 2020 +0200 add `getAnInvocation` to the ApiGraphs API commit 9c1253c8af933e36fa921bd91e44e6cb430834fe Author: Rasmus Wriedt Larsen Date: Wed Sep 30 13:29:21 2020 +0200 Python: Remove flow out of CommandInjection sinks commit b720bfdd11d39d776e7fb84d7f7d9772fff1cd13 Author: Erik Krogh Kristensen Date: Wed Sep 30 13:15:06 2020 +0200 Apply suggestions from code review Co-authored-by: Asger F commit 00966bba0d10670ab0857ad085f7134d7a99bc23 Author: Rasmus Lerchedahl Petersen Date: Wed Sep 30 13:11:23 2020 +0200 Python: update test expectations commit a2d12f0440762bee7c2a61d8a26e96fb7f11efc8 Author: Rasmus Wriedt Larsen Date: Wed Sep 30 13:00:10 2020 +0200 Python: Update CommandInjection.expected commit b1c826e5c0dace238e5e21224d4a95665c40a128 Merge: 8d4f7e2db 68f6d9332 Author: Jonas Jensen Date: Wed Sep 30 12:54:55 2020 +0200 Merge pull request #4135 from rdmarsh2/rdmarsh2/cpp/output-iterators-1 C++: Output iterators in AST taint tracking commit 061c2a754f2c631673929daa820c61d23ac157f6 Author: Arthur Baars Date: Wed Sep 30 12:11:29 2020 +0200 Java: tests for android database flow steps commit a13e845127f4e7a2cc8cd8d8581bf12c0d296306 Author: Arthur Baars Date: Wed Sep 30 10:30:33 2020 +0200 Java: tests for android database sinks commit 39f5284dccd0a13f982f0026a4248fe6eb5d3933 Author: Arthur Baars Date: Tue Sep 29 14:12:53 2020 +0200 Java: add stubs for some android database classes commit 449fb24ef6cbae61a0e6bce36c2930691620b8b1 Author: Arthur Baars Date: Tue Sep 29 18:10:05 2020 +0200 Java: android add taint and SQL sink for ContentProvider/Resolver commit efd5b6ff66208d237d619d04b12ff8df8f273dea Author: Arthur Baars Date: Mon Sep 28 19:48:21 2020 +0200 Java: SQLite: make classes private commit 28c965765b93bcfba39e272e4a0ee7e81c7b13fa Author: Arthur Baars Date: Mon Sep 28 19:28:43 2020 +0200 Move query sinks into SQLite.qll commit b3aae276baf5fbf633ad6dbd0b229badb49ef352 Author: Arthur Baars Date: Mon Sep 28 18:22:12 2020 +0200 Add types to SQLite.qll commit 6db4f839cbd769870d0f610e1c11c85f96e8e202 Author: Arthur Baars Date: Wed Sep 23 18:07:16 2020 +0200 Java: add Android database taint and SQL injection sinks commit 30d048f9d4196d62201efff38514093b62566a82 Author: Rasmus Lerchedahl Petersen Date: Tue Sep 29 15:36:38 2020 +0200 Python: Support unpacking of keyword arguments. commit e02cfbf6b0367a3957543695ced7f102556ff89d Author: Rasmus Lerchedahl Petersen Date: Tue Sep 29 13:50:04 2020 +0200 Python: Support keyword overflow arguments commit 27af9bbae8edd85860d2661b707eeb9bc2c55af1 Author: Rasmus Lerchedahl Petersen Date: Tue Sep 29 13:14:45 2020 +0200 Python: Support overflow positional arguments Currently ignoring starred arguments commit 8f2ef94b3e8f658c8aef3e2b8963277738257104 Author: Rasmus Lerchedahl Petersen Date: Tue Sep 29 09:40:48 2020 +0200 Python: Hook up keyword arguments commit f5244aab8cfdbb27a4d4fab7e9518cbb10e742ab Author: Rasmus Lerchedahl Petersen Date: Thu Aug 13 15:43:40 2020 +0200 Python: Add testfiles commit 1595fed2d6760b11953238c946796f918ba0f613 Author: Rasmus Wriedt Larsen Date: Wed Sep 30 11:44:37 2020 +0200 Python: Add preliminary taint tests for pathlib commit 0542c3b91e299f6d2efdff9e624106ddb63cd522 Author: Rasmus Wriedt Larsen Date: Wed Sep 30 11:42:36 2020 +0200 Python: Model os.path.join and add taint-step commit efa248471831fe521f88a781d7f61ee9ea7f2b13 Author: Rasmus Wriedt Larsen Date: Wed Sep 30 11:16:15 2020 +0200 Python: Add taint test for os.path.join Surprisingly the first two just worked, due to our very general handling of any `join` methods :D commit aa6fad558cfa863c24cc2857c3e57414a8391261 Author: Rasmus Wriedt Larsen Date: Wed Sep 30 11:15:53 2020 +0200 Python: Minor cleanup in taint-step tests commit e0b25798ff46378de19b717b995f5fcc60b02293 Author: Erik Krogh Kristensen Date: Wed Sep 30 10:36:08 2020 +0200 remove type-tracking from `getAReference`, and rewrite qldocs commit b3efa282776b3887414f6587a27dc6704031729a Merge: 6cb2ca63a 8d4f7e2db Author: Rasmus Wriedt Larsen Date: Wed Sep 30 10:24:11 2020 +0200 Merge branch 'main' into python-command-execution-modeling commit 68f6d9332523df633415e8550818a760c57f985b Author: Jonas Jensen Date: Wed Sep 30 09:49:56 2020 +0200 C++: Autoformat fixup commit 8d4f7e2db7ec3b7559a3e358fd1b8a7203ce7474 Merge: 60c310d1b d184aa7c0 Author: Anders Schack-Mulligen Date: Wed Sep 30 07:55:24 2020 +0200 Merge pull request #4366 from joefarebrother/field-rvalue-lvalue Java: Make `FieldRead` and `FieldWrite` extend `RValue` and `LValue` commit d5f8cbc50c55e5a63e36e6c8111b49f0f6901d63 Author: Ian Lynagh Date: Tue Sep 29 14:24:04 2020 +0100 C++: Accept test changes in unnamed entity naming commit 65441705ef9025149b2f39d12f4b6ac62f6aa344 Author: Erik Krogh Kristensen Date: Tue Sep 29 18:22:48 2020 +0200 renamings based on review commit c3f5a6dcac88dc9cf459858a80a42aecee0c49cf Author: Erik Krogh Kristensen Date: Tue Sep 29 18:17:36 2020 +0200 introduce API::Node::getACall() commit 69f4ac25c4885bc478e8c34b65785f287affd221 Author: Erik Krogh Kristensen Date: Tue Sep 29 18:11:31 2020 +0200 renamings based on review commit 1596436f7e52070880cb404b9a9b0cc96e71bd36 Author: Erik Krogh Kristensen Date: Tue Sep 29 18:05:50 2020 +0200 rename getASourceUse to getAReference commit adc05022f380f222c25be7f1875181a6b3ab3e4e Author: Erik Krogh Kristensen Date: Tue Sep 29 18:21:41 2020 +0200 update comment in test case Co-authored-by: Max Schaefer <54907921+max-schaefer@users.noreply.github.com> commit be07d27a4c3594d5de4f77c17de8e6a7d874f4ef Author: Joe Date: Tue Sep 29 16:36:34 2020 +0100 Java: Improve tests commit 38573316571092993a0e5e9b3804903087014b77 Author: Erik Krogh Kristensen Date: Tue Sep 29 16:19:32 2020 +0200 avoid .getReturn().getAUse().(DataFlow::InvokeNode) in the SQL model commit deae9256ddbcbf2e47ed22a1d5df26e906bfd519 Author: Erik Krogh Kristensen Date: Tue Sep 29 15:50:28 2020 +0200 add convenience method to API graphs commit efc3a2523790d1c2c8ab739645e543686a5ad873 Author: Joe Date: Tue Sep 29 16:02:51 2020 +0100 Java: Don't pass taint through the format methods of `Console` commit eccfa5d26a0041c8c30967829a1092925cca4202 Author: Joe Farebrother Date: Tue Sep 29 15:34:05 2020 +0100 Fix documentation typo Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> commit d184aa7c06910096b51bfd3baa773ae90b937fe4 Author: Joe Date: Tue Sep 29 15:24:51 2020 +0100 Make `FieldRead` and `FieldWrite` extend `LValue` and `RValue` commit 60c310d1bfd5c332d13e2465e4cee5b017fdc445 Merge: d7add29dc fee279f95 Author: yoff Date: Tue Sep 29 15:41:14 2020 +0200 Merge pull request #4361 from RasmusWL/python-new-flask-perf-fix Python: Hotfix performance problem with flask methods commit d7add29dc22c227ca7ad6f81fb3b6cc80882d056 Merge: 910c19e61 51f1f03f5 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Tue Sep 29 06:32:01 2020 -0700 Merge pull request #4359 from erik-krogh/cookieWrites Approved by esbena commit 910c19e6132126255837443742520435e2705fe3 Merge: 11f39a9d8 89195d7ad Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Tue Sep 29 02:57:32 2020 -0700 Merge pull request #4348 from erik-krogh/needle Approved by esbena commit 51f1f03f5ffc440ca8da5d491a8bc9190b3281d7 Author: Erik Krogh Kristensen Date: Tue Sep 29 11:56:10 2020 +0200 add change note for js/missing-token-validation commit 11f39a9d8881da4714ba090416d4c704fcafc69d Merge: 060c19a06 b8154d41b Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Tue Sep 29 02:09:53 2020 -0700 Merge pull request #4342 from erik-krogh/track-where-prop Approved by asgerf commit fee279f952297a39723bace5735f9c1220c2887d Author: Rasmus Wriedt Larsen Date: Tue Sep 29 10:47:32 2020 +0200 Python: Hotfix performance problem with flask methods This improves runtime for command injection query on https://lgtm.com/projects/g/alibaba/funcraft from +200 seconds (I did not care to wait more) down to ~55 seconds on my machine. This type of tracking predicate with string as additional argument apparently causes trouble :| commit 89195d7ada85c2ce74eae884e1fd372efb538c0f Author: Erik Krogh Kristensen Date: Tue Sep 29 10:13:48 2020 +0200 add change note for needle commit 52d94f61770936720321554f17eb7b773d602e47 Author: Erik Krogh Kristensen Date: Tue Sep 29 10:12:46 2020 +0200 use `getABoundCallbackParameter` instead of `getCallback` and `getParameter`. commit 060c19a063ec1939051ae22c30f5e844dca9b6a3 Merge: 8a76195f0 664342dd0 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Sep 28 12:31:42 2020 -0700 Merge pull request #4352 from erik-krogh/destructing-redirect Approved by esbena commit e04404b713487c0876d4331384e538fba938bb49 Author: Erik Krogh Kristensen Date: Mon Sep 28 21:17:25 2020 +0200 also recognize cookie writes are leading to cookie access commit dfc44360129cb268330cccbdd84273b5883dcf7e Author: Max Schaefer Date: Mon Sep 28 15:34:47 2020 +0100 JavaScript: Teach API graphs to recognise arguments supplied in partial function applications. commit 6de29a6dd39874fb22d7accc8749a3fe69849941 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Sep 28 17:52:10 2020 +0100 C++: Provide std::pair constructor initializers. commit 8a76195f04db356ae8e305939a6104ecb0709e5e Merge: 93edaa75e 7609ce2d4 Author: Ian Lynagh Date: Mon Sep 28 17:27:37 2020 +0100 Merge pull request #4356 from github/igfoo/front_end C++: accept test changes from extractor frontend upgrade commit 8059230bbcbf58ccac28e560de41c38e8c5ecb0e Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Sep 28 16:59:28 2020 +0100 Update cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll Co-authored-by: Jonas Jensen commit 773bc48a914e77d1db257d2c72e07f8a419e5b45 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Sep 28 16:37:29 2020 +0100 C++: Use a more modern make_pair. commit 759324ca1bb0faa7c0d9f889ee3879730b1f9a6f Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Sep 28 16:51:21 2020 +0100 Update cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll Co-authored-by: Jonas Jensen commit bea38fcd074d4e0079f0ee63de1c43bf1e6057f1 Author: Joe Date: Mon Sep 28 16:25:45 2020 +0100 Java: Add taint modelling for string format methods commit 93edaa75ebeeba7a1506a1631ac73f5bfbcedaba Merge: 75262ddac a635503be Author: Tom Hvitved Date: Mon Sep 28 16:18:10 2020 +0200 Merge pull request #4309 from tamasvajk/feature/enum-value-init Extract constant value of enum member equal clauses commit 2bbaa4e17374b294f955ae9c895727d9fd5ca352 Author: Tamas Vajk Date: Wed Sep 23 10:40:04 2020 +0200 Handle unsigned types in sign analysis (C# and Java) commit c0a67a8d7bff6238805a5a852626d4364d880a2e Author: Esben Sparre Andreasen Date: Mon Sep 28 14:27:10 2020 +0200 JS: another CWE-20 -> CWE-020 commit 75262ddace96633b3e1092764e4ce40f2e4a689d Merge: 165779ea0 ec2b3f0b6 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Sep 28 04:55:19 2020 -0700 Merge pull request #4328 from erik-krogh/indirect-fix2 Approved by esbena commit 165779ea09ab54587651bbd6da7340baaa4dd6cd Merge: 18bdc054c 713bdae77 Author: Jonas Jensen Date: Mon Sep 28 13:37:12 2020 +0200 Merge pull request #4343 from rdmarsh2/rdmarsh2/cpp/ir-construction-qldoc C++: Add some IR QLDoc commit 7609ce2d4718fbfc171e3ddfb4fdcbfb8cbc01c9 Author: Nick Rolfe Date: Tue Aug 4 18:10:27 2020 +0100 C++: accept test changes from extractor frontend upgrade commit 18bdc054cd00abc6b237316d5add4a683a91b0c4 Merge: 274147c87 0ccbaf9e8 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Sep 28 02:42:21 2020 -0700 Merge pull request #4347 from max-schaefer/js/handle-empty-pkgjson Approved by asgerf commit 6cb2ca63a6f9e3883c07b1964603e7fa5dd7cf43 Author: Rasmus Wriedt Larsen Date: Mon Sep 28 11:23:06 2020 +0200 Python: tests to show modeling is very syntactical commit 274147c87a8a2c75817f99c4cda1b545babe8f00 Merge: 20c4d94cc 5256c0ba3 Author: Joe Farebrother Date: Mon Sep 28 10:21:25 2020 +0100 Merge pull request #4339 from joefarebrother/printAST-java-var-decls Java: Add synthetic nodes for `LocalVariableDeclExpr`s in the AST view commit 3af5c720cc552608f1570aeb185dd8be3d39bc2a Author: Rasmus Wriedt Larsen Date: Mon Sep 28 11:16:34 2020 +0200 Python: Add test of more indirect command injection sinks commit f7f656418960208d97c25c686466b803e80d0f74 Author: Rasmus Wriedt Larsen Date: Mon Sep 28 11:13:04 2020 +0200 Python: Model subprocess.Popen (and helpers) commit 62dc0dd2632fad4c5f77225d6fa0e554d1b19073 Author: Rasmus Wriedt Larsen Date: Thu Sep 24 18:40:35 2020 +0200 Python: Model os.exec* os.spawn* and os.posix_spawn* I also had to exclude the inline expectation tests from files outside the test repo. commit c440fd0c09eb43d80be492329bc81ae57c773804 Author: Rasmus Wriedt Larsen Date: Thu Sep 24 18:24:03 2020 +0200 Python: Adjust expectations for system command executions I mostly did this to show my reviewers that the tests actually run and do something ;) commit 060720aae7d460627378359763cde591b518c5e8 Author: Rasmus Wriedt Larsen Date: Thu Sep 24 18:16:49 2020 +0200 Python: Add tests for all SystemCommandExecution from stdlib Overall idea is that `test/experimental/meta/ConceptsTest.qll` will set up inline expectation tests for all the classes defined in `Concepts.qll`, so any time you model a new instance of Concepts, you simply just import that file. That makes the tests a little verbose, but allows us to share test-setup between all the different frameworks we model. Note that since the definitions of SystemCommandExecution subclasses are scattered across multieple framework modeling qll files, it think it makes the most sense to have the tests for each framework in one location. I'm not 100% convinced about if this is the right choice or not (especially when we want to write tests for sanitizers), but for now I'm going to try it out at least. commit a635503be0987f4b3148f12f97cc093cd9596b54 Author: Tamas Vajk Date: Fri Sep 25 10:57:02 2020 +0200 Add test cases to UselessCastToSelf commit 3577b27f49ce6b38453d1a7413c70e87356aac57 Author: Tamas Vajk Date: Fri Sep 25 09:58:08 2020 +0200 Fix to not report on enum member initialization commit 77bb1b2cd9dbc80e174fad7307e3c79940ea0506 Author: Tamas Vajk Date: Mon Sep 21 17:43:38 2020 +0200 C#: Extract constant value of enum member equal clauses commit a6b62a383835f9ec50dc44aac4709bf2ebded438 Author: Tamas Vajk Date: Tue Sep 22 08:42:06 2020 +0200 C#: Add enum init value test commit 11587c930be898eb893c5cf9889812aa6b0a5034 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Sep 28 09:19:35 2020 +0100 C++: Autoformat. commit 20c4d94ccca12cc27f7a422395f1db930d0ba3bc Merge: fc84286b5 48bf6d55a Author: Tamás Vajk Date: Mon Sep 28 09:34:54 2020 +0200 Merge pull request #4318 from tamasvajk/feature/pointer-cast C#: Add implicit cast from array to pointer commit 664342dd0f2f273d702c14a2c05d715700df5b85 Author: Erik Krogh Kristensen Date: Sat Sep 26 21:31:06 2020 +0200 change `SimpleParameter` to `Parameter` in the express model to support destructuring parameters commit 27dc49ff7a6f0e1c0724367b628291b97f6b4407 Author: Robert Marsh Date: Fri Sep 25 17:49:01 2020 -0700 C++: Fix performance issue in PartialDefinition commit 713bdae77adc8f91fb7f43ac69823d93d4088b2c Author: Robert Marsh Date: Fri Sep 25 13:54:58 2020 -0700 C++: sync identical files commit 9240256a9f0910b6aac8da05c087d6208f353f7f Author: Robert Marsh Date: Fri Sep 25 11:55:39 2020 -0700 C++: fix QLDoc commit 2acfd4cdb1775ab311e36d4147c229bb3c7cf3ce Author: Rasmus Wriedt Larsen Date: Fri Sep 25 18:28:31 2020 +0200 Python: Show we're able to handle example with __init__.py files commit fc84286b561588667b60182506562eeaedfaac04 Merge: ea5feb2b0 4621e6d8c Author: Taus Date: Fri Sep 25 14:53:57 2020 +0200 Merge pull request #3830 from yoff/SharedDataflow_FieldFlow Python: Shared dataflow: Field flow commit ea5feb2b0a289f2f9c08321c409ba8da28abaa66 Merge: 4deb43f36 6163e6cf5 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Fri Sep 25 05:21:03 2020 -0700 Merge pull request #4331 from erik-krogh/DVNA-files Approved by esbena commit 6b9aea82ca963f065e6ade87bada4693ec634944 Author: Erik Krogh Kristensen Date: Fri Sep 25 14:13:31 2020 +0200 model method calls in the needle library commit a22ddb145bd0124aea81ff0d3afc40005c1c73c0 Author: Erik Krogh Kristensen Date: Fri Sep 25 13:53:22 2020 +0200 model calls to needle commit 4621e6d8c043b90154affc42642e44bbcacb4f00 Author: Rasmus Lerchedahl Petersen Date: Fri Sep 25 13:37:39 2020 +0200 Python: fix QL format commit 88bba466986728a89faf7721278d6da5b86e326f Author: Rasmus Lerchedahl Petersen Date: Fri Sep 25 13:35:30 2020 +0200 Python: Modify tests based on review The extra hist in `test.py` seen in `globalStep.expected` are due to the removal of manual filtering code. (That code was from when dataflow had many strange things in it.) commit 0ccbaf9e88f9053edf990a0aedfc035bc606ade9 Author: Max Schaefer Date: Fri Sep 25 12:12:39 2020 +0100 JavaScript: Handle empty `package.json` files gracefully. commit 5256c0ba39caba0b2939c5626e2edc3f7e9dc92b Author: Joe Date: Fri Sep 25 11:19:13 2020 +0100 Java: Improve PrintAst tests and rename things Add tests for `EnhcancedForStmt`s and `InstanceOfExpr`s. Rename LocalVarDeclParent to SingleLocalVarDeclParent commit c56ff986d4808e69a20db3ab0100a97a41956da9 Author: yoff Date: Fri Sep 25 11:56:50 2020 +0200 Apply suggestions from code review Co-authored-by: Taus commit 85607fe2d574bc6c123c62fa21b8af8fd55aab09 Author: Rasmus Wriedt Larsen Date: Fri Sep 25 11:56:45 2020 +0200 Python: Adjust location for .expected output commit 3d5511221e3fdeb53d4a91d6eb3d133d25190649 Author: Rasmus Wriedt Larsen Date: Fri Sep 25 11:44:54 2020 +0200 Python: Add test for implicit __init__.py files commit 120a569c6f1dec110b3434b259a54384502e9918 Author: Rasmus Wriedt Larsen Date: Fri Sep 25 11:40:49 2020 +0200 Python: Explain how CallGraph test.py even works Also remove options file, since it did nothing at all (and blocked experimental/library-tests/options from taking effect) commit 09b5fb675398e4fca24a2c55d9e2670fc55e4f69 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Sep 25 10:41:25 2020 +0100 C++: Fix comments. commit 4deb43f3616f7a88130580ea551158b97aa9e710 Merge: 7b1dbb436 66815c9d3 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Fri Sep 25 02:39:46 2020 -0700 Merge pull request #4323 from RasmusWL/python-new-command-injection-query Approved by tausbn commit 6fd1bf89c1197d7a5316eb82d963c846afed04b4 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Sep 25 09:55:08 2020 +0100 C++: Change note. commit ba0a2e16657d43fb26a55b39d408208f219b5adb Author: Esben Sparre Andreasen Date: Fri Sep 25 10:28:05 2020 +0200 JS: tag consistency: replace cwe-20 with cwe-020 commit 7b1dbb4364c9a2d6a6b712e77486a74e8e41efe4 Merge: 19316930c dc7b44789 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Fri Sep 25 00:18:55 2020 -0700 Merge pull request #4337 from max-schaefer/js/fix-indirect-command-injection Approved by asgerf commit 1445b3186464a33e04d67b1e1bb019f790f901d7 Author: Robert Marsh Date: Thu Sep 24 16:34:16 2020 -0700 C++: QLDoc for Operand commit e51b9215e4b3c391d7227ca163b298baa316fec6 Author: Robert Marsh Date: Thu Sep 24 15:56:29 2020 -0700 C++: QLDoc for Overlap in IR construction commit e9b1d817c757ee96747cdbba3c935e05a7a9bf92 Author: Robert Marsh Date: Thu Sep 24 15:55:57 2020 -0700 C++: QLDoc for VirtualVariable in IR construction commit 46ff4d524fe3ff18b76a006e099fab12072a903e Author: Robert Marsh Date: Thu Sep 24 14:54:31 2020 -0700 C++: autoformat commit b8154d41b17995c0248dcbafee307c93356c67d7 Author: Erik Krogh Kristensen Date: Thu Sep 24 20:55:25 2020 +0200 type-track objects where the "$where" property has been written commit ca06637de0d4adaeb27286e8385ad42073dcec4f Author: Robert Marsh Date: Thu Sep 24 10:40:45 2020 -0700 C++: add qldoc comment commit ec3c1568d2b0717f400d7e1505a70bdb372cef25 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Sep 24 18:21:47 2020 +0100 C++: Model erase. commit 8b91d5077d0ea0f036ebcfed66f765240aeb48c2 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Sep 24 18:06:41 2020 +0100 C++: Model find. commit d550741c0c82d105c88d9800d15169a041e7c4cb Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Sep 24 17:50:23 2020 +0100 C++: Model insert_or_assign. commit c51294e423cce5e325c4966cb74b18e98e81b2e9 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Sep 24 17:39:49 2020 +0100 C++: Model operator[] and at. commit 13b15d9bcd9ed989caa3a16d20f6beb0f4999720 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Sep 24 17:26:44 2020 +0100 C++: Model swap. commit 6119bf3430a1fd0f57a562b3be693a37ec0e1898 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Sep 24 17:10:41 2020 +0100 C++: Model begin and end. commit 25e0c680c6a04c91194e34dc036693189c788ed6 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Sep 24 13:18:17 2020 +0100 C++: Model insert. commit 094b06ec2accc225ba57df0a1686e972d700d252 Author: Robert Marsh Date: Thu Sep 24 10:37:38 2020 -0700 C++: remove unneeded predicate commit 19316930cd2c22bcbc7ee33a48798696f69caabe Merge: e012dce75 d34bd51f6 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Thu Sep 24 10:14:46 2020 -0700 Merge pull request #4310 from asgerf/js/extract-xml-with-codeql Approved by aibaars, esbena commit 0dca7f81bc1f5804e45bc4230f1f5a67d86e89df Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Sep 24 15:15:40 2020 +0100 C++: Model std::swap. commit e012dce7559658a844c247d66678d190f7fb91dc Merge: 3ef3e6e14 f794eaa67 Author: Jonas Jensen Date: Thu Sep 24 16:43:25 2020 +0200 Merge pull request #4334 from github/faster-skip-copy-value-instructions C++: Manual recursion in `skipCopyValueInstructions` commit 49f9a76c547bbfe86c2f84a03375c81d58c4fb9c Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Sep 22 13:21:17 2020 +0100 C++: Add tests for std::map and std::unordered_map. commit 3ef3e6e1400bf6b6d61481942f24582a497a33fd Merge: d4d4c0f3f 71da9045e Author: Anders Schack-Mulligen Date: Thu Sep 24 16:07:49 2020 +0200 Merge pull request #4319 from hvitved/python-java-block-precedes-var Java/Python: Reduce size of `blockPrecedesVar` commit 9c8a4682377ea2a65985552531754e27ebfda030 Author: Joe Date: Thu Sep 24 12:12:28 2020 +0100 Java: PrintAst: Add synthetic nodes for other declarations commit 3e960c1e0bdac2062fbe047152acc9d73f75f30c Author: Joe Date: Wed Sep 23 17:53:30 2020 +0100 Java: PrintAst: Refactor exceptions to the usual AST of expressions and statements using dispatch commit 1f9960762425b676b64a9a150ded4015a6ff9606 Author: Joe Date: Wed Sep 23 17:11:20 2020 +0100 Java: PrintAst: Improve test commit 45651cf1236a6aa2c4aeb723c7b49a664d63baa4 Author: Joe Date: Wed Sep 23 16:58:35 2020 +0100 Java: PrintAst: Add a synthetic node for the initialisers of for statements commit d4d4c0f3f98ee43275bd030a42c4a106b3b1ee98 Merge: 780a07e89 589426367 Author: Anders Schack-Mulligen Date: Thu Sep 24 12:58:45 2020 +0200 Merge pull request #4325 from aibaars/hibernate-changenote Java: change note for Hiberate ORM improvements commit 6163e6cf5f5dcb58e8fd7ab7d7e13c341cf987d2 Author: Erik Krogh Kristensen Date: Thu Sep 24 09:53:06 2020 +0200 adjust test case for XML entity expansion commit 780a07e89c178c40bd2f179cceb377a80659905f Merge: 7970fef3e b7d0939f4 Author: Mathias Vorreiter Pedersen Date: Thu Sep 24 09:01:06 2020 +0200 Merge pull request #4332 from jbj/ExtendedRangeAnalysis-stub C++: ExtendedRangeAnalysis stub implementation commit 7970fef3e4edccd339afd32a4edc520d8a2e37a1 Merge: 9b14a70ee b6d93ae81 Author: Tom Hvitved Date: Thu Sep 24 08:27:01 2020 +0200 Merge pull request #4315 from hvitved/merge-rc-1.25 Merge rc/1.25 into main commit 89332ca3037ac3b8c0c664cfe0ad90f9e44a421c Author: Robert Marsh Date: Wed Sep 23 15:29:51 2020 -0700 C++: autoformat commit 774dcc7c5292696d69e3b5a1726b7aa164028450 Author: Robert Marsh Date: Wed Sep 23 15:29:37 2020 -0700 C++: New model class for iterator op* and op[] commit 71a605b7d9b691ecee102e7226d1b4944815e726 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Sep 18 10:11:34 2020 +0100 C++: Add tests for std::pair. commit 48bf6d55aa3cb2807ea7776101e9e175588c936a Author: Tamas Vajk Date: Wed Sep 23 12:19:42 2020 +0200 C#: Add implicit cast from array to pointer commit f794eaa67020fd988523fbc5f8c51a9acb9c313c Author: Mathias Vorreiter Pedersen Date: Wed Sep 23 16:26:40 2020 +0200 C++: Manual recursion in skipCopyValueInstructions instead of transitive closure commit 83f0514475e0a8a7054e403e3fef699db3cc409b Author: Erik Krogh Kristensen Date: Wed Sep 23 15:50:14 2020 +0200 add req.files as a RequestInputAccess in the Express model commit b7d0939f4a0991815d5077a33f86aa6b0407fc20 Author: Jonas Jensen Date: Wed Sep 23 15:50:07 2020 +0200 C++: ExtendedRangeAnalysis stub implementation Just to demonstrate how things fit together, I've created `SubtractSelf.qll` that adds a (hopefully sound) version of the test extension that was already used in `extensibility.ql`. commit 589426367106d302490fbe3ef74a4713cc6a60da Author: Arthur Baars Date: Wed Sep 23 15:37:55 2020 +0200 Java: improve change note Co-authored-by: Anders Schack-Mulligen commit dc7b447895deae5925bf25389eb81c6e3709b607 Author: Max Schaefer Date: Wed Sep 23 10:24:49 2020 +0100 JavaScript: Make alert locations for command injection more precise. commit 439aadf0b614a639330104ec63f0d7360e63b166 Author: Max Schaefer Date: Wed Sep 23 09:57:20 2020 +0100 JavaScript: Do even more type tracking in command injection. commit ef18b39124ee97439f02db83e150ffa88d52d313 Author: Max Schaefer Date: Wed Sep 23 09:52:50 2020 +0100 JavaScript: Fix use of type backtracker in `IndirectCommandArgument.qll`. commit 825fc2228ba10ab1fb7e62ebf303f488947f4931 Author: Max Schaefer Date: Wed Sep 23 09:45:30 2020 +0100 JavaScript: Add two new command-injection tests. commit 66815c9d3d6a9075032b6c98d0d9e696d6f4acc2 Author: Rasmus Wriedt Larsen Date: Wed Sep 23 14:30:48 2020 +0200 Python: Suppress unused variable warnings in DataFlowPrivate commit 9b14a70eef88e5b67c295ac40061f9585e5a8f52 Merge: d652b95b2 d8176bc00 Author: Tamás Vajk Date: Wed Sep 23 14:12:07 2020 +0200 Merge pull request #4316 from tamasvajk/feature/local-functions C#: Change TrapStackBehaviour of local functions commit 2868d5bf34648dddcf29ffa3f0d4107e08013740 Author: Tamas Vajk Date: Tue Sep 22 10:54:25 2020 +0200 C#: Add pointer cast test cases commit 6aec2ec67359bc18e4ef859dbed1d08918331b46 Author: Rasmus Wriedt Larsen Date: Wed Sep 23 11:18:32 2020 +0200 Python: Fix os.popen modeling Co-authored-by: yoff commit 624cdd339aab6411a9c0889a8de47e5e206e39e0 Author: Rasmus Wriedt Larsen Date: Wed Sep 23 11:18:12 2020 +0200 Python: Fix grammar Co-authored-by: yoff commit d652b95b21aee9c4b0aa81e2f91249429edb579d Merge: 03e20eed0 8de57c7d1 Author: Tom Hvitved Date: Wed Sep 23 09:11:11 2020 +0200 Merge pull request #4011 from hvitved/csharp/asp-extraction-pre-finalize C#: Move ASP extraction from auto builder to `pre-finalize.{sh,cmd}` commit 03e20eed055b5e3afacce2e968850ae399156b1b Merge: 5ab5e75b8 5f96c37b2 Author: Tamás Vajk Date: Wed Sep 23 08:57:32 2020 +0200 Merge pull request #4314 from tamasvajk/feature/switch-case-expr C#: Fix switch case expression types commit ef4461ce544b3c28c20e6546b1368fc46e4afed9 Author: Rasmus Lerchedahl Petersen Date: Tue Sep 22 23:48:28 2020 +0200 Python: Address review comments commit 5ab5e75b8549cbeea4c6a3e0f7ea4f82ff8b7cf0 Merge: 475519c9e a89d13a5e Author: Tamás Vajk Date: Tue Sep 22 23:06:12 2020 +0200 Merge pull request #4255 from fatenhealy/IncreaseInsufficientKeySizeValue Increase insufficient key size value from 1024 to 2048 commit aece0ff65271219717e7dda416813d6352a88eeb Author: yoff Date: Tue Sep 22 22:33:46 2020 +0200 Apply suggestions from code review Co-authored-by: Taus commit ec2b3f0b6ca6d07613b0b68cb13d89fc80e6f9f4 Author: Erik Krogh Kristensen Date: Tue Sep 22 21:02:26 2020 +0200 better join-order fix in HTTP commit e28a45b8e68a0527a57c5ff1bcc8bed0dce4b3ec Merge: 772a51508 475519c9e Author: Robert Marsh Date: Tue Sep 22 11:17:38 2020 -0700 Merge branch 'main' into rdmarsh2/cpp/output-iterators-1 Resolve test output conflicts from IR model improvements commit 252f8aa89d8a7df958805540ab827ed517cb2a8b Author: Arthur Baars Date: Tue Sep 22 15:20:40 2020 +0200 Java: add Spring::MultipartRequest as taint source commit b382711f14d19a4455b4d46c003db399709576c9 Author: Arthur Baars Date: Tue Sep 22 18:55:07 2020 +0200 Java: change note for Hiberate ORM improvements commit 475519c9eee5bb1f43066ed1f5cda8f69c5a6513 Merge: 54c35748f d728c3948 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Tue Sep 22 08:51:51 2020 -0700 Merge pull request #4267 from asgerf/js/log-typescript-memory Approved by esbena commit 4faeede5cd60ea2ec114b5865ca1f62798400801 Author: Jonas Jensen Date: Tue Sep 22 16:55:25 2020 +0200 C++: Remove unnecessary comment on import commit 71a75ce596ec78f8072ed3d2499242d5af487b7d Author: Rasmus Wriedt Larsen Date: Tue Sep 22 16:24:30 2020 +0200 Python: Handle bound methods in flask modeling commit 5709189c2a70e0ad832d8e438586e0034093c355 Author: Rasmus Wriedt Larsen Date: Tue Sep 22 16:10:50 2020 +0200 Python: Expand flask test commit e614365963086bfabc373a7e40fe3ff0750e1fb7 Author: Rasmus Wriedt Larsen Date: Tue Sep 22 16:09:22 2020 +0200 Python: Adopt new approach in flask modeling Removed all the dict-like stuff, not sure that is how we should do things. commit a82fa04d8a49fa8147d484a6798c6c397216d90e Author: Rasmus Wriedt Larsen Date: Tue Sep 22 14:41:07 2020 +0200 Python: Add worked example of taint step modeling of external libs This can't be seen on the example, but I went through quite a lot of iterations before arriving at this fairly simple solution. commit 00ea0cebc344284360a26d489fd359b29c5383f4 Author: Rasmus Wriedt Larsen Date: Mon Sep 21 20:55:53 2020 +0200 Python: More Flask modeling kinda works It "kinda" works now, but it really is not a pretty solution. Adding all these "tracked" objects is SUPER annoying... it _would_ be possible to skip them, but that seems like it will give the wrong edges for dataflow/taintflow queries :| A good chunk of it should be able to be removed with access-paths like C# does for library modeling. Some of it could be solved by better type-tracking API like API Graphs... but it seems like we generally are just lacking the nice-to-have features like `.getAMemberCall` and the like. See https://github.com/github/codeql/pull/4082/files#diff-9aa94c4d713ef9d8da73918ff53db774L33 commit 3c08590ee4e13c9b40b3c60750ef013e500a5606 Author: Rasmus Wriedt Larsen Date: Mon Sep 21 20:52:36 2020 +0200 Python: Expand flask tests a bit commit 2bdd0284dc0a152a677fc72ec79532bf7c6a5ab7 Author: Rasmus Wriedt Larsen Date: Mon Sep 21 14:44:09 2020 +0200 Python: Port py-command-line-injection with new dataflow commit 7c205dd3fc25add98d9c8e679b66a8671043b21d Author: Rasmus Wriedt Larsen Date: Mon Sep 21 14:39:15 2020 +0200 Python: First attempt at modeling Flask commit cdc5ca7aec72791f54bede7e9bfa1d8ec0af0090 Author: Rasmus Wriedt Larsen Date: Mon Sep 21 14:38:14 2020 +0200 Python: Model os.system and os.popen commit 0265f263018f58305966d37e690a991d04960939 Author: Rasmus Wriedt Larsen Date: Mon Sep 21 14:00:42 2020 +0200 Python: Add importModule and importMember DataFlow helpers commit 2551173156b24cb01a3dab53344ea1d882fcd6ad Author: Rasmus Wriedt Larsen Date: Mon Sep 21 13:55:48 2020 +0200 Python: Update example in QLDoc for TypeTracker commit 9fd8b0431ae8e58ddadce0b68cab4cd7c7befcad Author: Jonas Jensen Date: Tue Sep 22 15:45:17 2020 +0200 C++: Add a SimpleRangeAnalysisDefinition test def commit 826632d6a96b636f54ce674a3e0a1b8e755c71b8 Author: Jonas Jensen Date: Tue Sep 22 14:02:14 2020 +0200 C++: Add a test of def overrides The def used in this test is not overridden yet. commit d1f453be368103541800393a669e6014edac1092 Author: Jonas Jensen Date: Tue Sep 22 13:40:27 2020 +0200 C++: import SimpleRangeAnalysisInternal This ensures that `getFullyConverted{Lower,Upper}Bounds` are available where they need to be called. commit 8065bf15ad865d50ebed795dd12eb6f6079a8921 Author: Jonas Jensen Date: Tue Sep 22 13:37:24 2020 +0200 C++: Per-variable overrides Without these changes, there was no way to tell which variables were overridden by a given instance of `SimpleRangeAnalysisDefinition`. All four overrides are needed because they fit into different mutual recursions of the `SimpleRangeAnalysis` implementation. commit 7dce4d0a6e5944cf349277c6da6f8d4311df4159 Author: Jonas Jensen Date: Tue Sep 22 13:39:22 2020 +0200 C++: Rename: name the file the same as the class commit 54c35748f0b4a233f0c8e30fdabb438b2d89de21 Merge: 66e2ed9b6 06dbec78f Author: Tamás Vajk Date: Tue Sep 22 15:33:33 2020 +0200 Merge pull request #4193 from tamasvajk/feature/sign-analysis C#: Sign analysis commit 66e2ed9b6591e93ac5da69c9b7d6b2052f7584d4 Merge: 036a36a47 1f4028f4a Author: Anders Schack-Mulligen Date: Tue Sep 22 15:29:40 2020 +0200 Merge pull request #4031 from aibaars/hibernate Add additional Hibernate SQL sinks commit 131cf8d2ecc8ab772d35fde72916cb1f4b31860a Author: Rasmus Lerchedahl Petersen Date: Tue Sep 22 15:02:31 2020 +0200 Python: Fix compilation error commit 036a36a4741d6fc10b3b42be1cce50f2bcd78977 Merge: 717ea2369 dafd45f0f Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Tue Sep 22 05:58:48 2020 -0700 Merge pull request #4317 from max-schaefer/js/api-node-depth Approved by asgerf commit 535c8cc87e9c2cde062591a8d6778f596128e8db Author: Mathias Vorreiter Pedersen Date: Thu Sep 17 21:13:02 2020 +0200 C++: Cache simpleLocalFlowStep instead of simpleInstructionLocalFlowStep commit 717ea2369c519f2fc2674ce849355a7b60f5fcb1 Merge: 9a306866c 32b0f1b48 Author: Erik Krogh Kristensen Date: Tue Sep 22 14:35:50 2020 +0200 Merge pull request #4311 from erik-krogh/indirect-fix JS: improve join-order for HTTP::isDecoratedCall commit 9a306866c53dcb5aa96e82d52d59b6836025cbb7 Merge: 47506a859 4571ba38a Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Tue Sep 22 05:34:35 2020 -0700 Merge pull request #4282 from erik-krogh/es2021 Approved by esbena commit e836bae20ffaacd925a1f6d999452fa266f4d8db Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Sep 18 10:45:27 2020 +0100 C++: Tidy up test stl.h a little. commit b065d8724e75630271556beadb9c46fb28a0ee8a Author: Rasmus Lerchedahl Petersen Date: Tue Sep 22 13:52:30 2020 +0200 Python: Fixup comments after merge commit 3e2331c87f6b30d846494e6a1e5b53e35b75fe2c Merge: 08b51e67c 5cbf498a2 Author: Rasmus Lerchedahl Petersen Date: Tue Sep 22 13:32:36 2020 +0200 Merge branch 'main' of github.com:github/codeql into SharedDataflow_FieldFlow commit ee211b02fb1651e24cc89f9468162c9a4429d91d Merge: 47506a859 eb5782d90 Author: Jonas Jensen Date: Tue Sep 22 13:27:56 2020 +0200 Merge remote-tracking branch 'lcartey/cpp/range-analysis-custom-defs' into range-analysis-custom-defs commit 5f96c37b283a956e94ddf0960f564800ada9f5d9 Author: Tamas Vajk Date: Tue Sep 22 09:40:07 2020 +0200 C#: Fix switch case expression types commit 47506a859e5bcfe9732221219c2cc4de19d1a432 Merge: 269b7101c 9baf2b9ef Author: Anders Schack-Mulligen Date: Tue Sep 22 13:16:05 2020 +0200 Merge pull request #4287 from joefarebrother/exectainted-array Java: Improve the ExecTainted query commit 269b7101c0b4faaafc4c10857b566819268b1e1f Merge: 5cbf498a2 e86bc0c6a Author: Jonas Jensen Date: Tue Sep 22 13:15:05 2020 +0200 Merge pull request #4273 from lcartey/cpp/custom-range-analysis-override C++: Support overriding existing simple range analysis bounds commit a89d13a5eef8f33d79161987639bf4b8d4c460f6 Author: Tamas Vajk Date: Tue Sep 22 11:20:22 2020 +0200 C#: Add change notes for increased required key size in 'cs/insufficient-key-size' commit 8de57c7d198b6b8b06b34adb1a23b9fcf7a55b64 Author: Tom Hvitved Date: Tue Aug 4 10:25:09 2020 +0200 C#: Move ASP extraction from auto builder to `pre-finalize.{sh,cmd}` commit e86bc0c6ac7a5478610a9622b04ec3f516c79b78 Author: Jonas Jensen Date: Tue Sep 22 11:53:05 2020 +0200 C++: Autoformat fixup commit d34bd51f6167add2b022130280d8d27035c98f0d Author: Asger Feldthaus Date: Tue Sep 22 10:28:40 2020 +0100 JS: Call codeql.exe instead of codeql.cmd commit bc09bc45bc79e3c1759a9e1598eb4f4a2fe2fa71 Author: Asger Feldthaus Date: Tue Sep 22 10:17:30 2020 +0100 JS: Concatenate paths properly commit c35a5d120a477e79fbbbd8c26e91fe21de7b4da1 Author: Faten Healy <5361987+fatenhealy@users.noreply.github.com> Date: Thu Sep 10 16:28:02 2020 +1000 C#: Increasing required size of RSA key to 2048 commit cc979d0b5f2d1467eaaad26493f0356af3177ce5 Author: Tamas Vajk Date: Tue Sep 22 09:36:33 2020 +0200 C#: Add switch case expression type test commit 71da9045e5361c261c1acb5af5ddb7bdfbcbd828 Author: Tom Hvitved Date: Tue Sep 22 11:00:26 2020 +0200 Java/Python: Reduce size of `blockPrecedesVar` commit 32b0f1b480a279573687ac277023b727a6c657f6 Author: Erik Krogh Kristensen Date: Tue Sep 22 10:28:43 2020 +0200 add code example to isDecoratedCall commit dafd45f0f4c056e5d8ce199db111050c935f6b08 Author: Max Schaefer Date: Thu Sep 17 12:07:00 2020 +0100 JavaScript: Add a few metric queries for API graphs. commit 46ba4a1fa8ee4a8494fa2bdc5624b5c1ad995de7 Author: Max Schaefer Date: Thu Sep 17 11:58:01 2020 +0100 JavaScript: Expose another useful predicate on API-graph nodes. commit 5cbf498a2d16a2a4e98e623c2ded5eeb0d671024 Merge: c56d5eb90 873e87162 Author: Jonas Jensen Date: Tue Sep 22 10:23:17 2020 +0200 Merge pull request #4302 from MathiasVP/fix-field-conflation-after-4230 C++: Fix field conflation after #4230 commit ec49c444ef99291d0b9f080c944dac1f43477649 Author: Erik Krogh Kristensen Date: Tue Sep 22 10:06:34 2020 +0200 Apply suggestions from code review Co-authored-by: Esben Sparre Andreasen commit d8176bc00de78f51107f68bd73cc5b84a5549ee0 Author: Tamas Vajk Date: Tue Sep 22 09:53:35 2020 +0200 C#: Change TrapStackBehaviour of local functions commit b6d93ae81df3d4edf3683e7be527fcadfb90c282 Merge: c56d5eb90 83340e2a6 Author: Tom Hvitved Date: Tue Sep 22 09:35:39 2020 +0200 Merge remote-tracking branch 'upstream/rc/1.25' into merge-rc-1.25 commit c56d5eb90eec1ba01bc1cfe29314a18bd213d4d8 Merge: 724baaf26 947ad02db Author: Jonas Jensen Date: Tue Sep 22 09:23:10 2020 +0200 Merge pull request #4295 from rdmarsh2/rdmarsh2/cpp/ir-qualifier-flow C++: Improved qualifier flow in IR taint tracking commit 83340e2a621159b4ec3c5783c244639ee1e7a1e8 Merge: 637ea4ad6 e54937756 Author: Tom Hvitved Date: Tue Sep 22 09:20:53 2020 +0200 Merge pull request #4212 from hvitved/csharp/path-transformers C#: Implement support for path transformers commit 772a51508f09f8b8b7d2e256db11dab0fbfd33f6 Author: Robert Marsh Date: Mon Sep 21 16:19:41 2020 -0700 C++: Update test comment commit 9e3bfe1968c3c39339bf638ce47a709c9a1effc4 Author: Robert Marsh Date: Mon Sep 21 16:17:16 2020 -0700 C++: Fix iterator flow context sensitivity commit 913881b17b869602b45e37d5044949e1ba72bde8 Author: Robert Marsh Date: Mon Sep 21 16:10:37 2020 -0700 C++: Add test for iterator false positive commit 4243504c8baa3330ee0a7cedd8590704039f6eff Author: Erik Krogh Kristensen Date: Mon Sep 21 23:20:16 2020 +0200 improve join-order for HTTP::isDecoratedCall commit 947ad02db9f5422d6715737acb0a3982817eabd4 Author: Robert Marsh Date: Mon Sep 21 11:38:57 2020 -0700 C++: autoformat commit e70bb20f349ccfd43df7670f290d52dfcb52d734 Author: Asger Feldthaus Date: Tue Sep 15 12:25:07 2020 +0100 JS: Support XML extraction when run with codeql commit 08b51e67c42eb257c7e9ad76516021ae206dc07f Author: Rasmus Lerchedahl Petersen Date: Mon Sep 21 17:44:36 2020 +0200 Python: Update test annotation commit 73d2d9b1f86fafee048949059ef5d74b5400b9c7 Author: Rasmus Lerchedahl Petersen Date: Mon Sep 21 17:32:22 2020 +0200 Python: Make constructor calls post-update nodes commit 724baaf26aa0649c4b08df3a924f664f43e12d8f Merge: 557db3381 2f9f51dbd Author: Taus Date: Mon Sep 21 17:13:48 2020 +0200 Merge pull request #4308 from RasmusWL/python-private-import-of-DataFlowPrivate Python: Make import of DataFlowPrivate private commit 06dbec78f7fe8be7b82aa55ef9dbc1b42b1f52bc Author: Tom Hvitved Date: Tue Sep 15 12:47:42 2020 +0200 C#: Add `Guard::controlsBasicBlock()` and simplify `Guard::isEquality()` commit 8bf4a4209c9026c3b87a59a24df26c8c093c4552 Author: Tamas Vajk Date: Wed Sep 2 16:52:17 2020 +0200 C#: Sign analysis Synced between Java and C# through `identical-files.json`. commit 2f9f51dbd8c5186a4b7245b438bbfffb5022a21b Author: Rasmus Wriedt Larsen Date: Mon Sep 21 16:08:17 2020 +0200 Python: Fix tests that use DataFlowPrivate commit 557db3381dc4f14e0be7f26803dc15740bfdcb02 Merge: d3ea20cd2 9d7a2d2b5 Author: yoff Date: Mon Sep 21 15:51:19 2020 +0200 Merge pull request #4265 from tausbn/python-add-global-flow-steps Python: Add `ModuleVariableNode` to keep track of global reads and writes commit d3ea20cd2ce14564c3e3ac78c8b1fb964ff144f0 Merge: 4a3118b13 99fd323de Author: Tom Hvitved Date: Mon Sep 21 15:44:48 2020 +0200 Merge pull request #4271 from github/matt-gretton-dann/csharp-dont-trace-macos-pkill Don't trace through pkill or pgrep on macOS. commit 441fbe32154b93702eaba6c8ad23658aaa0812fc Author: Tamas Vajk Date: Thu Sep 3 15:17:06 2020 +0200 Add Java test file for sign analysis commit 873e871620590ea0b1d4c1240b5154896aa56f7f Author: Mathias Vorreiter Pedersen Date: Mon Sep 21 14:35:37 2020 +0200 C++: Handle more cases in arrayReadStep. commit 73cd5ceb80c3f47983f4ea8c4881eaae4e204e91 Author: Mathias Vorreiter Pedersen Date: Mon Sep 21 14:17:49 2020 +0200 C++: Accept tests. Due to the removal of overlap between the reads steps there are fewer repeated edges in path explanations. commit 6aca82fa828bfc88e5a6062668f6ca03b5f7e12e Author: Rasmus Wriedt Larsen Date: Mon Sep 21 13:52:58 2020 +0200 Python: Make import of DataFlowPrivate private Otherwise you are able to use `DataFlow::isExpressionNode` where `isExpressionNode` is defined in `DataFlowPrivate.qll`. commit 9d7a2d2b5d2fa60ac4b0f4d7a03449c6c677d093 Merge: 1d6558b4e 4a3118b13 Author: Taus Date: Mon Sep 21 13:50:20 2020 +0200 Merge branch 'main' into python-add-global-flow-steps commit 4a3118b13e6b5318c0b02bc8bfb5b00d22b43564 Merge: 016e6d200 233dd4363 Author: Anders Schack-Mulligen Date: Mon Sep 21 13:28:20 2020 +0200 Merge pull request #4246 from RasmusWL/java-fix-ssa-varBlockReaches Java: Minor fixup for SSA AdjacentUsesImpl::varBlockReaches commit 016e6d2001026e2856912398075e2160acdcb941 Merge: d867172d2 9e7a1934e Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Sep 21 04:09:51 2020 -0700 Merge pull request #4275 from erik-krogh/CVE760-indirect Approved by esbena commit 62d42f20d9d16e73e65be9b1c7b2bbd8423f2d8f Author: Mathias Vorreiter Pedersen Date: Mon Sep 21 12:45:49 2020 +0200 C++: use(x) is no longer an array read. commit 233dd43635b99337d829b2c51dff6716dc822054 Author: Rasmus Wriedt Larsen Date: Mon Sep 21 12:11:25 2020 +0200 Java: Port varBlockReaches fix to BaseSSA.qll commit 1d6558b4e80fd2913adbb4f56b25388f05304eef Author: Taus Brock-Nannestad Date: Mon Sep 21 11:46:18 2020 +0200 Python: Add a bit more documentation to `ModuleVariableNode` commit c560c7584c4889bedc032fe53695e75b696f02ec Author: Mathias Vorreiter Pedersen Date: Mon Sep 21 11:08:06 2020 +0200 C++: Add QLDoc for BufferMayWriteSideEffectFieldStoreQualifierNode commit 49dd5763526089a3434ec8999becb51588514b7f Author: Mathias Vorreiter Pedersen Date: Mon Sep 21 10:59:16 2020 +0200 C++: Add more tests commit 4571ba38a5f1249be8e2a766bc567bc5e655e644 Author: Erik Krogh Kristensen Date: Mon Sep 21 10:51:36 2020 +0200 add change-note for es2021 commit 4bc91c4439a36f09fb6ea249e3d9703c76c6bdc6 Author: Erik Krogh Kristensen Date: Thu Sep 17 14:10:07 2020 +0200 add support for Promise.any commit 9f1b3d61b9fa6a87969cfedf4bdf38e3388a19a6 Author: Erik Krogh Kristensen Date: Thu Sep 17 14:04:07 2020 +0200 add test for numeric separators commit b09015380ac778d9376bf54a5f253af064bb1813 Author: Erik Krogh Kristensen Date: Thu Sep 17 14:00:44 2020 +0200 add support for String.prototype.replaceAll commit 0dbdbfa6596a026c4403635b8ad0dac98a80e73e Author: Erik Krogh Kristensen Date: Thu Sep 17 13:13:55 2020 +0200 bump extractor version commit 87d4e13584297992d169cf7fc6816f94fb5543cf Author: Erik Krogh Kristensen Date: Thu Sep 17 12:42:37 2020 +0200 added support for ES2021 assignment operators commit 9e7a1934ea46f7d810f0c74ba3bfdccc2a43391a Author: Erik Krogh Kristensen Date: Mon Sep 21 10:45:43 2020 +0200 add express and HTTP to change-notes commit 4dfc0680e257badb8f8abd894dbdffcf58dfefcb Author: Erik Krogh Kristensen Date: Mon Sep 21 10:42:19 2020 +0200 support non SourceNode receiver for partialInvoke in routeHandlerStep commit 4cde48cfb80731d15fbd483ee759ef4893b552d1 Author: Erik Krogh Kristensen Date: Mon Sep 21 10:23:21 2020 +0200 change comma to dot in qldoc commit edebbd640ed9969545c53667f7986d172e906ad2 Author: Erik Krogh Kristensen Date: Mon Sep 21 10:18:22 2020 +0200 revert change to return-type commit 6dd7675a972f9887b47dcca11745eb532a496a78 Author: Mathias Vorreiter Pedersen Date: Mon Sep 21 09:31:30 2020 +0200 Update cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll Co-authored-by: Jonas Jensen commit 6c050d3160512c30b70a0471962930481cd7ccaf Author: Erik Krogh Kristensen Date: Sun Sep 20 22:21:42 2020 +0200 revert change of return-type commit ae228cb5b23fe9ad5882306194dc526d75a9da7e Author: Erik Krogh Kristensen Date: Sun Sep 20 22:15:03 2020 +0200 move new predicates to a more fitting location commit 5fd4c7a422792e8d56d42aa1b93d4eb46671de9d Author: Erik Krogh Kristensen Date: Sun Sep 20 22:06:48 2020 +0200 use PartialInvokeNode commit bef09254ee2fee131a78225ffe4c7761528cb735 Author: Erik Krogh Kristensen Date: Sun Sep 20 21:59:33 2020 +0200 rename forwardingCall to isAForwardingRouteHandlerCall commit 62332121b261ae4483803e177def80ba90d4671b Author: Erik Krogh Kristensen Date: Sun Sep 20 21:57:55 2020 +0200 remove getNumParameter constraint commit 3aaa2d11a72481b6f1050dbe5d1cfd1694321e85 Author: Erik Krogh Kristensen Date: Sun Sep 20 21:54:56 2020 +0200 rename decoratedRouteHandler to isDecoratedCall commit 9aa0cfb35cd6e5455a321c3b67b7e8cca6a36ddd Author: Rasmus Lerchedahl Petersen Date: Fri Sep 18 22:11:21 2020 +0200 Python: class callable -> class call Only have one type of callable, but have an extra type of call. A constructor call directs to an init callable (should also handle `call` overrides at some point). commit b2f1c435a864bf9ae8a3975b89d7fb215a890d6d Author: Rasmus Lerchedahl Petersen Date: Fri Sep 18 09:50:00 2020 +0200 Python: update test expectations commit e1323617363b902f3647e9457a4d04209e12338e Author: Rasmus Lerchedahl Petersen Date: Thu Sep 17 17:18:01 2020 +0200 Python: Add missing .expected file commit e50b66554dfeba72c91b15cd58247ce133902022 Author: Rasmus Lerchedahl Petersen Date: Thu Sep 17 16:30:05 2020 +0200 Python: Add explorative test commit aa281671774d13f669c3e9d025997b0640d78ec6 Author: Rasmus Lerchedahl Petersen Date: Thu Sep 17 11:39:17 2020 +0200 Python: Add malloc nodes commit 27b25565ca78a99c0565e65b767c8425d4ff28ee Author: Rasmus Lerchedahl Petersen Date: Wed Sep 16 13:00:09 2020 +0200 Python: Implement field-stores, -reads, and -content commit a2d006fe479ed4ca35457fa9c98da17cb2572da8 Author: Rasmus Lerchedahl Petersen Date: Wed Sep 16 12:55:19 2020 +0200 Python: Tests for field flow commit 6b3557ec589ef56197f1672b5d33f9b76e7ecdcf Author: Robert Marsh Date: Fri Sep 18 15:42:14 2020 -0700 C++: cache localAdditionalTaintStep commit bc3e74f7d6c7d6fc989546ba60aefffdec2fe49c Merge: 12be90a6a d867172d2 Author: Robert Marsh Date: Fri Sep 18 15:40:43 2020 -0700 Merge branch 'main' into rdmarsh2/cpp/ir-qualifier-flow Fix test conflicts commit 12be90a6af9110b424155a0c8f0771e3c499d7c9 Author: Robert Marsh Date: Fri Sep 18 15:00:01 2020 -0700 C++: remove unneeded cast commit c179a07fc7e6604a314a7f785b7f80b12b1cda35 Author: Robert Marsh Date: Fri Sep 18 14:43:39 2020 -0700 C++: fix constructor models commit bd7f5a41d1016b001fa1f8dbf3988fac6d93cfb1 Author: Robert Marsh Date: Fri Sep 18 14:19:29 2020 -0700 C++: autoformat commit b84bf5e9bb5a3a4562592a558290d476b68f83d3 Author: Robert Marsh Date: Fri Sep 18 14:18:38 2020 -0700 C++: QLDoc for IteratorPartialDefinitionNode commit 107e9770da5ebde3e06ba7fefd5952a0154ed105 Author: Robert Marsh Date: Fri Sep 18 14:12:33 2020 -0700 C++: remove accidentally committed test code commit d867172d274315da58d4403146fd3305cb17dca4 Merge: dff9f8264 aac2e0ebf Author: Tom Hvitved Date: Fri Sep 18 19:40:34 2020 +0200 Merge pull request #4300 from hvitved/csharp/runtime-checks-bypass-bad-magic C#: Avoid bad magic in `RuntimeChecksBypass.ql` commit 11c85f0fb55d1928c28f395ed06297b2bab892be Author: Taus Brock-Nannestad Date: Fri Sep 18 18:14:47 2020 +0200 Python: Clean up various jump/local data flow steps Removes steps from `ModuleVariableNode`s from `essaFlowStep`, and instead puts them only in `jumpStep`. This cleans up the logic a bit. This slightly broke the type tracker implementation (as it relied on `essaFlowStep` being fairly liberal), so I have rewritten it to explicitly rely on just familiar predicates for local and jump steps. Additionally, we disallow Essa-to-Essa steps where exactly one of the two nodes corresponds to a global variable (i.e. only local-local and global-global steps). commit 53da751b15c698ca44795ccdf35e166e651de589 Author: Mathias Vorreiter Pedersen Date: Fri Sep 18 17:12:27 2020 +0200 C++: Accept tests commit b6b17fe95e1b0d451a60cc179c5ed4feff0a2f76 Author: Mathias Vorreiter Pedersen Date: Fri Sep 18 17:12:09 2020 +0200 C++: Add a read and store step that replace ArrayContent with FieldContent when we realize that the target of a store is a field. commit 9baf2b9eff89bfa3dad5d88ee3bbc655be5ed6bc Author: Joe Date: Fri Sep 18 15:42:03 2020 +0100 Fix cartesian product commit dff9f8264bfac9a5ef7d5e1c6f36b231cae5b801 Merge: b3bf570fb 409085920 Author: Tom Hvitved Date: Fri Sep 18 16:24:20 2020 +0200 Merge pull request #4296 from hvitved/csharp/useless-upcast-nomagic C#: Avoid bad magic in `UselessUpcast.ql` commit abb1731be77cdfb4105fe471b3519d88b8783739 Author: Joe Date: Fri Sep 18 15:21:03 2020 +0100 Java: Simplify the implementation of ExecTainted commit b3bf570fb701bb9af19fdac0e7af7a3e9aae202e Merge: b4edbe477 2c6f587ee Author: Anders Schack-Mulligen Date: Fri Sep 18 16:08:40 2020 +0200 Merge pull request #4301 from lcartey/java/update-cwe-claims Java: Update some CWE claims commit 3cc38feebca8016c152ebe4c80af963c9d024ac1 Author: Joe Date: Fri Sep 18 14:51:38 2020 +0100 Fix a couple of typos in QLDoc comments commit b4edbe47738bdd6577965a21a52d5b17e91dc533 Merge: 4f9d2f118 b40941b89 Author: Mathias Vorreiter Pedersen Date: Fri Sep 18 15:16:33 2020 +0200 Merge pull request #4298 from MathiasVP/field-conflation-with-array-content C++: Add test demonstrating field conflation after merging #4230 commit 4f9d2f118dfe2c4935fdc50228864f85e931b97d Merge: 6463a9425 325813409 Author: Anders Schack-Mulligen Date: Fri Sep 18 14:17:26 2020 +0200 Merge pull request #4288 from joefarebrother/printAST-java Java: Add a container node for Imports in the PrintAst view commit aac2e0ebfb0206c36310d5e1476db728346c21c5 Author: Tom Hvitved Date: Fri Sep 18 14:11:55 2020 +0200 C#: Avoid bad magic in `RuntimeChecksBypass.ql` Before: ``` [2020-09-18 14:03:57] (2587s) Tuple counts for RuntimeChecksBypass::uncheckedWrite#bbf#antijoin_rhs#1: 1270 ~8% {2} r1 = SCAN RuntimeChecksBypass::uncheckedWrite#bbf#shared AS I OUTPUT I.<1>, I.<0> 188197390 ~0% {3} r2 = JOIN r1 WITH #Callable::Callable::calls_dispred#bfPlus AS R ON FIRST 1 OUTPUT R.<1>, r1.<1>, r1.<0> 2425784042 ~1% {3} r3 = JOIN r2 WITH Expr::Expr::getEnclosingCallable_dispred#ff_10#join_rhs AS R ON FIRST 1 OUTPUT r2.<1>, R.<1>, r2.<2> 58 ~9% {2} r4 = JOIN r3 WITH project#RuntimeChecksBypass::checkedWrite#bfff AS R ON FIRST 2 OUTPUT r3.<0>, r3.<2> return r4 ``` After: ``` [2020-09-18 14:08:48] (5s) Tuple counts for RuntimeChecksBypass::uncheckedWrite#fff#antijoin_rhs: 24704473 ~2% {2} r1 = SCAN DataFlowPublic::localExprFlow#ff AS I OUTPUT I.<1>, I.<0> 23784154 ~6% {4} r2 = JOIN r1 WITH Expr::Expr::getEnclosingCallable_dispred#ff AS R ON FIRST 1 OUTPUT r1.<1>, 28, R.<0>, R.<1> 201391 ~2% {2} r3 = JOIN r2 WITH expressions AS R ON FIRST 2 OUTPUT r2.<2>, r2.<3> 23784154 ~0% {3} r4 = JOIN r1 WITH Expr::Expr::getEnclosingCallable_dispred#ff AS R ON FIRST 1 OUTPUT r1.<1>, R.<0>, R.<1> 1065242 ~20% {2} r5 = JOIN r4 WITH expr_value AS R ON FIRST 1 OUTPUT r4.<1>, r4.<2> 1266633 ~16% {2} r6 = r3 \/ r5 return r6 ``` commit 6463a9425866f65806a372e32da93478917885fc Merge: c67605f15 c7b6374e5 Author: Jonas Jensen Date: Fri Sep 18 13:58:16 2020 +0200 Merge pull request #4297 from github/igfoo/compileTimeConstantInt C++: Improve `compileTimeConstantInt` commit 2c6f587ee9937a4b6b9f66d840de402cc598ab82 Author: lcartey@github.com Date: Fri Sep 18 12:51:24 2020 +0100 Java: Add coverage claim for CWE 193 (off by one) commit 39200566c3545f6bf89ddca6281e43a009524ca0 Author: lcartey@github.com Date: Fri Sep 18 12:30:52 2020 +0100 Java: Update CWE claims for XXE. This matches the claims in the C# equivalent. commit b40941b89c1dd18fc25170091817540a07791311 Author: Mathias Vorreiter Pedersen Date: Fri Sep 18 13:23:23 2020 +0200 C++: Add test demonstrating field conflation after merging #4230 commit 40908592078e6279ada9250a81c54c6c0330789b Author: Tom Hvitved Date: Fri Sep 18 12:14:52 2020 +0200 C#: Avoid bad magic in `UselessUpcast.ql` commit 3258134098d243fe7538b3740d944da736b20a8e Author: Joe Date: Fri Sep 18 10:41:06 2020 +0100 Java: Remove superfluous conjunct commit 32f43a84beedffc49c8dc8a6a0a5593e799acde6 Author: lcartey@github.com Date: Fri Sep 18 10:20:21 2020 +0100 Java: Add CWE 564 (SQL Injection: Hibernate) commit c67605f15c862415a5de4800358e7f93a1d7c932 Merge: 8c615ece8 3520b8677 Author: Jonas Jensen Date: Fri Sep 18 10:56:51 2020 +0200 Merge pull request #4230 from MathiasVP/mathiasvp/array-field-flow C++: Replace `field -> object` taint rule with `ArrayContent` dataflow commit 8c615ece8a4d0e60e1cdd775c5af49432c864693 Merge: 3ef6e8a58 c6ff805a0 Author: Mathias Vorreiter Pedersen Date: Fri Sep 18 10:18:21 2020 +0200 Merge pull request #4292 from MathiasVP/mathiasvp/cache-simpleLocalFlowStep C++: Cache simpleLocalFlowStep instead of simpleInstructionLocalFlowStep commit 3ef6e8a580f5401ad8db467a022ddb441990b1eb Merge: 3d07ba9d0 5cc11f1c4 Author: Mathias Vorreiter Pedersen Date: Fri Sep 18 10:17:47 2020 +0200 Merge pull request #4283 from geoffw0/stringstream4 C++: Model getline commit 0b16f81f8b448d0840d15afefc46a96c10e9e611 Author: Erik Krogh Kristensen Date: Thu Sep 17 15:41:50 2020 +0200 improve performance by using `RouteHandlerCandidate` commit b4e75bf567be04bb83bdf42e49492df90565ed98 Author: Erik Krogh Kristensen Date: Thu Sep 17 00:35:03 2020 +0200 update expected output commit 1f95311342f58522b8d6ae56c7b6adad5c3e5dfc Author: Erik Krogh Kristensen Date: Wed Sep 16 13:09:53 2020 +0200 further loosen the RouteHandlerCandidate heuristic commit 3eaa56ed604eddacf3a16f24267a0c8acbfd7068 Author: Erik Krogh Kristensen Date: Wed Sep 16 11:19:55 2020 +0200 support containers with decorated route handlers commit c087e94d4767b55d4b1304d65b2ea279797e760d Author: Erik Krogh Kristensen Date: Wed Sep 16 11:18:35 2020 +0200 add additional indirect route-handler steps commit 02c1d689e48a5c7744e8bf5339b9a67c8acf832a Author: Erik Krogh Kristensen Date: Wed Sep 16 11:17:07 2020 +0200 support indirect route-handlers for NodeJS commit dafcd59148272620a569255a2c482b4f0b12eb74 Author: Erik Krogh Kristensen Date: Wed Sep 16 09:53:30 2020 +0200 add another indirect route-handler test commit 43e5c0212cc3a562dbe033b4eac7cb1626401b63 Author: Erik Krogh Kristensen Date: Tue Sep 15 23:30:23 2020 +0200 add basic support for indirect route handlers commit 3a83cc71fe7bd578f01bcd19b1a436e316175bdf Author: Robert Marsh Date: Thu Sep 17 18:03:02 2020 -0700 C++: use qualifier flow in more models commit 556ace004f0a953d745b2f1b34feccd6c3e06389 Author: Robert Marsh Date: Thu Sep 17 17:39:50 2020 -0700 C++: use qualifiers in string constructor model commit 6b7b64d7bead4436c052f3ed6bb42d216a9689c5 Author: Robert Marsh Date: Thu Sep 17 17:10:11 2020 -0700 C++: IR data and taint flow through qualifiers commit f73ff988e0b72de126ba914e26429d9fb83766d3 Author: Robert Marsh Date: Thu Sep 17 16:55:36 2020 -0700 C++: improve cast and ptr handling in taint test commit c6ff805a079d66071f095b586e6c5a11ea136711 Author: Mathias Vorreiter Pedersen Date: Thu Sep 17 21:13:02 2020 +0200 C++: Cache simpleLocalFlowStep instead of simpleInstructionLocalFlowStep commit 3d07ba9d0b16c1b6c783a7ca84bda67e0451c29f Merge: 63afe1da7 8e1d9e099 Author: Robert Marsh Date: Thu Sep 17 14:52:59 2020 -0400 Merge pull request #4290 from MathiasVP/mathiasvp/fix-join-order-in-single-field-flow C++: Fix bad join order introduced by #4270 commit 8e1d9e0996806884746849eb50ae2b49b49b237c Author: Mathias Vorreiter Pedersen Date: Thu Sep 17 19:23:01 2020 +0200 C++: Fix bad join order introduced by #4270 commit 9c643ec1cdb9bf2a5068ce5638d0a216e1c94b64 Author: Joe Date: Thu Sep 17 17:46:05 2020 +0100 Java: Fix formatting commit 69fd579dfd35fa638f3f5629095c4c0c7473ccf0 Author: Joe Date: Thu Sep 17 17:37:16 2020 +0100 Java: Fix QLDoc commit 2da6234317e18f316791695cae00f1c889d91067 Author: Joe Date: Thu Sep 17 17:31:24 2020 +0100 Java: Fix QLDoc commit 6d0df7cb3a5f67059085a7c000d05b9b857a7f1f Author: Joe Date: Thu Sep 17 17:29:36 2020 +0100 Java: Add a container node for Imports in the PrintAst view commit 810baad63ffce5d94eab63ae6553629fbd8b1a4d Author: Joe Date: Thu Sep 17 17:13:55 2020 +0100 Java: Fix formatting commit fcfc8367203b0eee0977efc49b975d9f331a5020 Author: Joe Date: Thu Sep 17 16:47:55 2020 +0100 Java: Add tests for ExecTainted commit b6cf1cce207c32f28092f82454c6ae9d17441886 Author: Joe Date: Thu Sep 17 15:53:04 2020 +0100 Java: Make the equivalent changes to ExecTaintedLocal commit 6bfc0afaeb1cfc0e11911197e82c9c9bf4cce35d Author: Joe Date: Thu Sep 17 15:01:04 2020 +0100 Java: Improve the ExecTainted query commit c7b6374e55cfe4d542b5e90a1650bfbeb3b8020e Author: Ian Lynagh Date: Tue Sep 15 12:44:35 2020 +0100 C++: Improve `compileTimeConstantInt` It is possible for the frontend to make (bool)e where e has a constant value 0, but the (implicit) cast has no constant value. This was causing us to not understand assume(0) correctly. Now compileTimeConstantInt will handle casts itself if necessary. commit 5cc11f1c44c7b2bd6cc0b1573c0995eb49c0df5c Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Sep 17 12:45:08 2020 +0100 C++: Additional model for 'this' flow through chains. commit 73399cb5f7e45ed60593bad56d15e34722d62f9e Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Sep 16 11:22:17 2020 +0100 C++: Model GetLine. commit 2c15e6f934052c26b09c4bfb92481ad5b24b1bfc Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Sep 15 18:14:53 2020 +0100 C++: Add test cases. commit 63afe1da780b4e585d855f01f85f5052e053ba16 Merge: 86404af50 c17ae3ad6 Author: Mathias Vorreiter Pedersen Date: Thu Sep 17 14:19:52 2020 +0200 Merge pull request #4276 from geoffw0/stringstream3 C++: More stringstream models. commit f93c44a688bebe62cfb45e1d486c14970768c1a5 Author: Taus Brock-Nannestad Date: Thu Sep 17 13:26:55 2020 +0200 Python: Fix typo commit 1d462ae1569d9e34d0b4d442432cda65dfeb4a35 Author: Taus Brock-Nannestad Date: Thu Sep 17 13:22:27 2020 +0200 Python: Fix misnamed variable. commit 797ac23db770f7f97c00b0d5a76dd454a8df9c47 Author: Taus Brock-Nannestad Date: Thu Sep 17 13:20:58 2020 +0200 Python: Clean up global flow test commit 4d6125841d426fe8271c0035ba16eab7ea38acd6 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Sep 15 11:28:22 2020 +0100 C++: Clean up multiply defined functions. commit c17ae3ad6c01fd1580e8ae3636438741823d3373 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Sep 17 11:34:10 2020 +0100 C++: Correct dataflow for return (*this). commit 9458861b1822405c03fbbbe575a9e509d755ce54 Author: Taus Brock-Nannestad Date: Thu Sep 17 12:04:30 2020 +0200 Python: Add missing global flow test commit 691d0f3fb255cc3dd33747fa2d50be68d3210c18 Merge: 44c523345 86404af50 Author: Robert Marsh Date: Wed Sep 16 13:52:59 2020 -0700 Merge branch 'main' into rdmarsh2/cpp/output-iterators-1 Fix merge conflict in test expectations commit 44c5233459a67643a405200398fb5dc70c60fea2 Author: Robert Marsh Date: Wed Sep 16 12:49:15 2020 -0700 C++: accept test output commit 086d074a26e55d45ff6e7c70a91124eee0c3fac7 Author: Robert Marsh Date: Wed Sep 16 12:48:38 2020 -0700 C++: make PartialDefinition abstract commit fa0e27b2de6c9fa8d9fbe500b4ba7accda8b0cbe Author: Robert Marsh Date: Wed Sep 16 12:34:52 2020 -0700 C++: move interprocedural iterator flow to taint commit ee76d9b33d33fe534d939dc256daf95f071e2bb7 Author: Taus Brock-Nannestad Date: Wed Sep 16 19:04:27 2020 +0200 Python: Clean up tests commit e179df7c430fb1389fe2b5cac6eb04b0c894c38a Author: Taus Date: Wed Sep 16 18:21:50 2020 +0200 Python: Apply suggestions from code review Co-authored-by: Rasmus Wriedt Larsen commit 86404af50100b409b18e62651295e79393a6016a Merge: 4b423feef 3005f252c Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Sep 16 17:21:07 2020 +0100 Merge pull request #4270 from MathiasVP/mathiasvp/single-field-flow-fix-cwe190test C++: Use underlying type when checking whether a type is a single-field struct. commit f1a9547b380a7061e8200bfe44aaef2455d994c9 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Sep 16 16:44:39 2020 +0100 C++: Split off putback. commit 4b423feef9030bcd654f1b3f5438d94fbc714f08 Merge: c2175b678 949b81b07 Author: Taus Date: Wed Sep 16 15:19:41 2020 +0200 Merge pull request #4245 from RasmusWL/python-dataflow-dynamic-tuple-tests Python: Add dataflow tests for dynamic tuple creation commit c2175b678caf7183fd17e8001334459280f84dab Merge: 5079deb92 fa255f353 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Wed Sep 16 06:01:35 2020 -0700 Merge pull request #4263 from erik-krogh/importScripts Approved by esbena commit 3520b86771bb6202654ae6c9a575f350c2da9c23 Author: Mathias Vorreiter Pedersen Date: Wed Sep 16 14:51:11 2020 +0200 C++: Accept test changes. commit 2d3e23ebb04191d17d3ec03f79e8cef8d6d43643 Author: Taus Brock-Nannestad Date: Wed Sep 16 14:46:04 2020 +0200 Python: Cleanup, docs, and an extra test case commit eedbe839b5626daf213a3c90bb33ca52048acf98 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Sep 14 11:15:46 2020 +0100 C++: Update change note. commit c4de071a4c2eddce353071e9506f1eaa87dbc6af Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Sep 14 11:14:06 2020 +0100 C++: Flow through swap. commit eb7bd6e1765d33595b663979b048a16bd96fe37f Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Sep 14 11:04:45 2020 +0100 C++: Flow through putback. commit 7cc60a30a6070739e991c732104db6ee8ce09cc9 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Sep 14 10:58:05 2020 +0100 C++: Flow through get, peek, read, readsome. commit 56390c1aef542fccf5838e5f2739dfff5f7d8a09 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Sep 11 13:41:36 2020 +0100 C++: Flow through operator>>. commit 3026eb4b8532d3b3dedaf7d8441a5e06bb628d29 Author: Mathias Vorreiter Pedersen Date: Wed Sep 16 14:26:01 2020 +0200 Revert "C++: Remove the same rule in TaintTrackingUtil.qll as 78b24b76a0 removed from DefaultTaintTracking.qll" This reverts commit 0b97a4a182bc19a9d32cea6364cc3e051be439a0. commit 92d81edae664243cc2f28ae8f0921dc90a3c295e Author: Mathias Vorreiter Pedersen Date: Wed Sep 16 14:25:42 2020 +0200 Revert "C++: Remove the problematic taint tracking rule. It seems like we get the flows from dataflow already now." This reverts commit 78b24b76a09d680ac6581597f0ecfe25596ed18f. commit 5079deb92a0ffaaeecb68274295ac922cc043960 Merge: 4f70af500 23a9d0764 Author: Tamás Vajk Date: Wed Sep 16 11:08:33 2020 +0200 Merge pull request #4268 from tamasvajk/feature/java-range-analysis-fn Java: Fix range analysis false negative commit 0b97a4a182bc19a9d32cea6364cc3e051be439a0 Author: Mathias Vorreiter Pedersen Date: Wed Sep 16 10:54:23 2020 +0200 C++: Remove the same rule in TaintTrackingUtil.qll as 78b24b76a0 removed from DefaultTaintTracking.qll commit 4f70af500c6a9b536f0aa4e87640595dfefc9f25 Merge: d828bc5f3 7e9b1a297 Author: Joe Farebrother Date: Wed Sep 16 09:46:19 2020 +0100 Merge pull request #4261 from joefarebrother/printAST-java Java: Add PrintAst commit 7b456d6162433734fc273bbc3418a4298950a757 Merge: 50ad4cfec d828bc5f3 Author: Mathias Vorreiter Pedersen Date: Wed Sep 16 10:45:31 2020 +0200 Merge branch 'main' into mathiasvp/array-field-flow commit d828bc5f3a70706067acffe5c3154918c5240d42 Merge: c8a3baf35 e46ae9b98 Author: Rasmus Wriedt Larsen Date: Wed Sep 16 10:00:26 2020 +0200 Merge pull request #4251 from yoff/SharedDataflow_BarrierGuards Python: Implement `BarrierGuard` commit c8a3baf3562f39ff42584ca34e7b7e409b91f246 Merge: 17bd67869 78560833a Author: Mathias Vorreiter Pedersen Date: Wed Sep 16 09:29:39 2020 +0200 Merge pull request #4272 from jbj/dataflow-partial-access C++: Add AST flow through arrays commit e46ae9b98d4ad9a8a3e4c2d6dc0e09cf4602d6d2 Author: Rasmus Lerchedahl Petersen Date: Tue Sep 15 21:45:47 2020 +0200 Python: Move some query predicates to debug commit 17bd678699de109aebdb3623da6f79c667720a96 Merge: 9296a12a9 795bf0d93 Author: Matthew Gretton-Dann <53790742+matt-gretton-dann@users.noreply.github.com> Date: Tue Sep 15 19:34:42 2020 +0100 Merge pull request #4140 from github/matt-gretton-dann/fix-deleted-constructors Update tests for extractor changes with ctors commit 795bf0d93c5bddd999b41b8e51b7d3edde5f666e Author: Matthew Gretton-Dann Date: Wed Aug 26 14:17:24 2020 +0100 Update tests for extractor changes with ctors commit 9296a12a91e5d961a81413039ac6507aeb06190f Merge: b3c50aed5 a912a328a Author: Matthew Gretton-Dann <53790742+matt-gretton-dann@users.noreply.github.com> Date: Tue Sep 15 17:39:38 2020 +0100 Merge pull request #4260 from github/igfoo/coroutines C++: Add coroutines* tables commit 7cdd290b90203d957c50f592ff80a85f0529b93a Author: Taus Brock-Nannestad Date: Tue Sep 15 18:25:24 2020 +0200 Python: Disregard module-time reads. commit 7e9b1a2975fd2c4f9df857d7367b34c024f531df Author: Joe Date: Tue Sep 15 17:15:00 2020 +0100 Java: PrintAst: Fix more formatting issues commit a912a328a2feb6f6f69f67407a72d11196219545 Author: Ian Lynagh Date: Mon Sep 14 12:08:28 2020 +0100 C++: Add an upgrade script commit 56388b57bd0e83359ecc3dab2e322a69f0067cef Author: Ian Lynagh Date: Mon Sep 14 12:07:39 2020 +0100 C++: Update stats for new coroutines* tables commit 99c4bc517562ec7dc16e5c913f3d31aa44dc76c4 Author: Ian Lynagh Date: Wed Sep 9 13:15:33 2020 +0100 C++: Add coroutine metadata tables commit eaea860d3e8f68c617030bc765bcc729dfcd9f8e Author: lcartey@github.com Date: Tue Sep 15 15:34:48 2020 +0100 C++: Test for overriding existing simple range analysis ranges. commit 78560833a105c948dca2585afa698c6a03fcd718 Author: Jonas Jensen Date: Tue Sep 15 13:20:54 2020 +0200 C++: Add a test distilled from real code Author: @rvermeulen. The consistency warnings go away because `sink` is defined with a body in this file. commit 3be8fa5155e6f303651bdfb5b7d99ac6f7675640 Author: Joe Date: Tue Sep 15 15:10:56 2020 +0100 Java: PrintAst: Fix formatting commit 50ad4cfec4e80387fa67e8f9a21eeb45128a20fd Author: Mathias Vorreiter Pedersen Date: Tue Sep 15 16:03:21 2020 +0200 C++: Add comments to {Array,Pointer}StoreNode and arrayStoreStepChi. commit 28338eb32e253fb9ca0f601f3a2a0dee8eebc03e Author: Joe Date: Mon Sep 14 14:36:50 2020 +0100 Java: PrintAst: Various minor fixes of typos Fix references to C# Fix getAPrimaryQlClass for JavadocTag Fix typo for Import Update test outputs commit b3c50aed5e0a307ae35966f9d8abc7165663d5d9 Merge: 159353d54 826c40fca Author: Jonas Jensen Date: Tue Sep 15 15:49:36 2020 +0200 Merge pull request #4262 from github/igfoo/location C++: Deprecate Location subclasses commit 53ab8dac0642afbfc776445bd484796dddda1558 Author: Joe Date: Mon Sep 14 12:57:39 2020 +0100 Java: PrintAst: Fix failing tests commit 112b6d28a11ebdd14c15971c4f4d59af83074dce Author: Joe Date: Fri Sep 11 17:06:46 2020 +0100 Java: PrintAst: Handle multiple javadocs in one element correctly commit e38b583ec4b008752940971941de043d56691243 Author: Joe Date: Fri Sep 11 16:42:51 2020 +0100 Java: PrintAst: Add tests commit b73e7d8390a9932eeef7551f5db36bdd1527f805 Author: Joe Date: Fri Sep 11 13:06:18 2020 +0100 Java: PrintAST: Support Javadoc commit c3320eeb3ce48e8f7028d57cc938e2b5e33cbb1d Author: Joe Date: Fri Sep 11 12:33:17 2020 +0100 Java: Improve getAPrimaryQlClass Implement it for more types Fix typos commit 908f025888db9e27a5f57c3a0700d63dd85c9684 Author: Joe Date: Thu Sep 10 17:40:12 2020 +0100 Java: PrintAst: Fix a couple of issues related to Annotations commit c20f8026664153224e79299d24ac1279387c77f7 Author: Joe Date: Thu Sep 10 15:42:06 2020 +0100 Java: PrintAst: Supprt generic parameters commit 19af3e5e305c4f13895a02db96ce4284aef929fe Author: Joe Date: Thu Sep 10 10:47:47 2020 +0100 Java: Add PrintAST commit 084992d40b1f4a60555be502aa5f04fefea35e98 Author: lcartey@github.com Date: Tue Sep 15 14:39:20 2020 +0100 C++: Support overriding existing range bounds The current support only allows the user to supply bounds for previously unsupported expressions or for variable accesses. This commit allows SimpleRangeAnalysisExprs to override built-in range definitions. commit 159353d545e417a373d7d3181e6e3c05f1ac020a Merge: 951e3093d efe3ac0a3 Author: Anders Schack-Mulligen Date: Tue Sep 15 15:43:24 2020 +0200 Merge pull request #4269 from joefarebrother/PrintAST-java-rename Java: Rename PrintAst.qll to PrettyPrintAst.qll commit bdce24735c7a5467d611d324400e2436fcaf3531 Author: Jonas Jensen Date: Mon Sep 14 16:06:56 2020 +0200 C++: Add flow through arrays This works by adding data-flow edges to skip over array expressions when reading from arrays. On the post-update side, there was already code to skip over array expressions when storing to arrays. That happens in `valueToUpdate` in `AddressFlow.qll`, which needed just a small tweak to support assignments with non-field expressions at the top-level LHS, like `*a = ...` or `a[0] = ...`. The new code in `AddressFlow.qll` is copy-pasted from `EscapesTree.qll`, and there is already a note in these files saying that they share a lot of code and must be maintained in sync. commit 99fd323deddbbe938047258e84bf0617cb0d220e Author: Matthew Gretton-Dann Date: Tue Sep 15 13:37:22 2020 +0100 Don't trace through pkill or pgrep on macOS. commit 2e737eda1e8d61bf00abdd140ef4d069d7cbc697 Author: Taus Brock-Nannestad Date: Tue Sep 15 14:25:26 2020 +0200 Python: Add a few function-local import tests commit d5e9f367473fb9464450ebcc571bc6f221bfe0fc Author: Taus Brock-Nannestad Date: Tue Sep 15 14:23:20 2020 +0200 Python: Add "enclosing callable" for `ModuleVariableNode` I've named this `DataFlowModuleScope` since it's not really a callable (and all of the relevant methods are empty anyway). commit 27b8dc2b135becfc8a5a12833b84071c89ee061e Author: Jonas Jensen Date: Mon Sep 14 16:15:51 2020 +0200 C++: Add tests for flow through arrays commit 3005f252ca55713f8eb7bb993ee359c19b7208d9 Author: Mathias Vorreiter Pedersen Date: Tue Sep 15 13:34:50 2020 +0200 C++: Fix annotation commit 0ba72c66850ce0833eee2b7364d635fc22de6915 Author: Mathias Vorreiter Pedersen Date: Tue Sep 15 12:49:22 2020 +0200 C++: Accept changes. commit 265a641d06662ab7fb6d28c4caba93a0a31ea3b0 Author: Mathias Vorreiter Pedersen Date: Tue Sep 15 12:49:16 2020 +0200 C++: Use the underlying type to check whether a type is a single-field struct. commit 951e3093d257b2f451f933d75339928a21838a12 Merge: 2de94abe9 88bbc2f1f Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Tue Sep 15 03:47:40 2020 -0700 Merge pull request #4231 from erik-krogh/CVE767 Approved by asgerf commit d18dd5ab09021dcc0fbffd4e2a2979db5f323e5b Author: Mathias Vorreiter Pedersen Date: Tue Sep 15 12:32:15 2020 +0200 C++: Add testcase demonstrating the underlying problem in 6ca9c449af. commit efe3ac0a3779096199c39bdbb49ef73b47efa215 Author: Joe Date: Thu Sep 3 17:09:13 2020 +0100 Java: Rename the existing file called PrintAst.qll commit 2de94abe9f756921b00aa7e03c417ccca1b098f7 Merge: 25412da84 6fb534f17 Author: Erik Krogh Kristensen Date: Tue Sep 15 12:29:25 2020 +0200 Merge pull request #4244 from erik-krogh/badJQueryJoin JS: Fix Bad join orders in UnsafeJQueryPlugin commit fa255f35344bee18aa3460d129deb3fa189cfeb4 Author: Erik Krogh Kristensen Date: Tue Sep 15 12:23:48 2020 +0200 add test for self.importScripts(..) commit 25412da845aabc50de077b607bdce39f6526087f Merge: 1fbb0fbf5 6b035df66 Author: Jonas Jensen Date: Tue Sep 15 12:19:26 2020 +0200 Merge pull request #4253 from geoffw0/stringstream2 C++: Model more stringstream features commit cc5109d693ace064d63bf20e0bb4062941a8288f Author: Erik Krogh Kristensen Date: Tue Sep 15 12:14:51 2020 +0200 Update change-notes/1.26/analysis-javascript.md Co-authored-by: Esben Sparre Andreasen commit 23a9d0764eccd2a57ba6399c784f6d8ab2d3c9f3 Author: Tamas Vajk Date: Tue Sep 15 12:00:21 2020 +0200 Java: Fix range analysis false negative commit 1fbb0fbf546cc099469333b513432fdf571b996b Merge: d095d6b56 6ca9c449a Author: Mathias Vorreiter Pedersen Date: Tue Sep 15 12:08:00 2020 +0200 Merge pull request #4266 from geoffw0/cwe190tests C++: CWE-190 Tests. commit c66473cb8a2263669f298f614b032be95596dc38 Author: Tamas Vajk Date: Fri Sep 11 10:11:23 2020 +0200 Java: Add test for range analysis commit d728c3948c85b2bf782b38693071e44933f1bf82 Author: Asger Feldthaus Date: Tue Sep 15 09:17:42 2020 +0100 JS: Log the amount of memory passed to TypeScript process commit d095d6b56b59a169aff6acd6b853c1ae0b420e89 Merge: c106b6777 6c716331d Author: Tom Hvitved Date: Tue Sep 15 09:30:29 2020 +0200 Merge pull request #4139 from hvitved/csharp/cfg/foreach-loop-empty C#: Skip `foreach` loop bodies in the CFG when the iteration expression is empty commit 5f2cafc4f5571f06928b43cbb37d97b5a7044640 Author: Robert Marsh Date: Mon Sep 14 14:36:19 2020 -0700 C++: Interprocedural iterator flow commit c5b5a4fd558ca3527bac46100be1b48a72aaa8cd Author: Erik Krogh Kristensen Date: Mon Sep 14 20:39:51 2020 +0200 improve performance of NodeJS::NodeModule::exports commit c1cb19abd7ddc37e5e0688862bc8a7fc3f7a30d5 Author: Erik Krogh Kristensen Date: Thu Sep 10 00:32:35 2020 +0200 add level PreCallGrapSteps to the callgraph commit f2ecb63e5ae7209c2a9fd1c215c46ccbfdf22ae5 Author: Erik Krogh Kristensen Date: Thu Sep 10 00:05:39 2020 +0200 add a direct Export step as a PreCallGraphStep commit 29457c52dc0b8b79f3866461f490ecf3628fb552 Author: Erik Krogh Kristensen Date: Wed Sep 9 23:37:45 2020 +0200 add reexported test to PackageExports test commit 61f6580d1ec6a9e3b0980839e2ed062c7a2ccba1 Author: Erik Krogh Kristensen Date: Wed Sep 9 23:18:12 2020 +0200 add API in `PackageExports.qll` for getting a value exported under a name commit d3653b3030954d82488ac06e5c3d752e805d5d0e Author: Erik Krogh Kristensen Date: Wed Sep 9 15:23:31 2020 +0200 add support for re-exports using the spread operator for NodeJS exports commit 0c14e2b69a23d92cf56d85baa38f2b7928a5a3dd Author: Mathias Vorreiter Pedersen Date: Mon Sep 14 23:08:50 2020 +0200 C++: Fix annotations in taint.cpp commit 3e56db7f83e29fe96e87036df237ca52086e9125 Author: Mathias Vorreiter Pedersen Date: Mon Sep 14 20:52:55 2020 +0200 C++: Make fieldReadStep private commit 7cd6137b343da1317ead8689ca6fd46ba753f5f2 Merge: 78b24b76a c106b6777 Author: Mathias Vorreiter Pedersen Date: Mon Sep 14 20:45:06 2020 +0200 Merge branch 'main' into mathiasvp/array-field-flow commit 6ca9c449af4cd4d4ad68f4eee369f1920cc1dafc Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Sep 14 16:18:33 2020 +0100 C++: Add a test demonstrating the recent regression. commit 839cd829ce1dca3111e617ecdfd4e9a2239fd0ba Author: Rasmus Lerchedahl Petersen Date: Mon Sep 14 18:48:55 2020 +0200 Python: Fix formatting commit 3727c482276f78ea23435e8b9ad14557f8d383ee Author: Taus Brock-Nannestad Date: Mon Sep 14 18:12:20 2020 +0200 Python: Record test changes Some of the places where flow has disappeared look a bit suspect, so I don't consider this to be the final word on these tests. commit 0bb726f21ce231fbeac86bc6264ac5772e044ca0 Author: Taus Brock-Nannestad Date: Mon Sep 14 17:57:45 2020 +0200 Python: Fix up merge weirdness commit 5efc06da2c87639d3818514844c89e739f905930 Author: yoff Date: Mon Sep 14 17:08:39 2020 +0200 Update python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll Co-authored-by: Rasmus Wriedt Larsen commit 4c028523586d8c18b5ae987f6f3074b002bddf4d Author: Rasmus Lerchedahl Petersen Date: Mon Sep 14 16:56:46 2020 +0200 Python: add missing * (and a rename) commit 03a3c4f4b2fa1bffe0d2876f790264948c495155 Author: Erik Krogh Kristensen Date: Mon Sep 14 16:47:12 2020 +0200 update expected output commit f4f96ce04dc647754d3155a9b68963f6421e4763 Author: Erik Krogh Kristensen Date: Mon Sep 14 16:46:58 2020 +0200 use new source in client-side-url-redirect test commit cb7de2714aec1ad1326743018b06e27b87e76880 Author: Erik Krogh Kristensen Date: Mon Sep 14 16:46:47 2020 +0200 add `onmessage` handlers registered using global property as `PostMessageEventHandler` commit c106b6777cbac3df6f289255d01f66fcecb65be2 Merge: d21c101c0 1d92cbb65 Author: Asger F Date: Mon Sep 14 15:17:29 2020 +0100 Merge pull request #4254 from asgerf/js/bump-extractor-version-string JS: Bump extractor version string commit 283be1920112f66216d0ee51e1e38dc8d9c84d6f Author: Erik Krogh Kristensen Date: Mon Sep 14 16:02:03 2020 +0200 add change-note for importScripts commit 6e84ac8e6c15ee508fb95c0e6930d63ba04da51c Author: Erik Krogh Kristensen Date: Mon Sep 14 16:01:54 2020 +0200 add test for importScripts commit 2e3df74dcef23a342e16d30dc10958452fcafa7f Author: Erik Krogh Kristensen Date: Mon Sep 14 15:58:29 2020 +0200 add importScripts as a sink for js/client-side-unvalidated-url-redirection commit 22097a9e13cd8fe286d63d1e742731f474dec4c6 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Sep 14 14:25:47 2020 +0100 C++: Add some CWE-190 tests I had lying around. commit ecc5a4a1f677a48cd3f4eacbd1aff086682b33a7 Author: Rasmus Lerchedahl Petersen Date: Mon Sep 14 15:32:03 2020 +0200 Python: testIsTrue -> branch commit 2a4e28db16b486999bce72b370e4e6b7de6b987d Author: yoff Date: Mon Sep 14 15:28:01 2020 +0200 Apply suggestions from code review Will make the same renames in the changed code also.. Co-authored-by: Rasmus Wriedt Larsen commit 033529e85e7f6b958010e72a85b64594936a73ba Author: Rasmus Lerchedahl Petersen Date: Mon Sep 14 15:24:46 2020 +0200 Python: avoid creating big predicate commit e197f52b6df76da1c3208eb80484ebed31e127c0 Merge: 0b641c5ce d21c101c0 Author: Taus Brock-Nannestad Date: Mon Sep 14 15:13:07 2020 +0200 Merge branch 'main' into python-add-global-flow-steps commit 0b641c5ce9de69dbc178620b21ac19acce6658df Author: Taus Brock-Nannestad Date: Mon Sep 14 15:05:16 2020 +0200 Python: Update type tracking and strange-essaflow tests commit 5fb33c90bc8cfc022916132766d7f7a3e6fc5d0f Author: Taus Brock-Nannestad Date: Mon Sep 14 14:57:32 2020 +0200 Python: Add `ModuleVariableNode` to dataflow commit 543876f980e54657aed93a9aa9c22b5dfbae9c63 Author: Rasmus Lerchedahl Petersen Date: Mon Sep 14 14:46:15 2020 +0200 Python: Fix `getAGuardedNode` commit 826c40fcac5243b78cf001625fc6ede4459b47cf Author: Ian Lynagh Date: Mon Sep 14 13:14:18 2020 +0100 C++: Deprecate Location subclasses The main Location class should always be used. commit d21c101c0d58130ae46869c4bcad7e45b27d5046 Merge: f5f4b8e25 0fb9dc5ba Author: Tamás Vajk Date: Mon Sep 14 13:57:36 2020 +0200 Merge pull request #4041 from tamasvajk/feature/update-roslyn C#: upgrade Roslyn dependencies to version 3.7 commit f5f4b8e25bce261beaa6630de1f95302aef32411 Author: Tamás Vajk Date: Mon Sep 14 13:43:57 2020 +0200 C#: Enable nullability of Semmle.Extraction.CSharp.Standalone (#4115) commit 637ea4ad6f7f70283f90e654f2612ef1357b8ab7 Merge: 86755215a 3414063f2 Author: Rasmus Wriedt Larsen Date: Mon Sep 14 13:18:24 2020 +0200 Merge pull request #4226 from RasmusWL/python-missing-1.25-change-notes Python: Add missing 1.25 change notes commit 0fb9dc5bacc01dc8ed3270254d7c306d0a87f60b Author: Tom Hvitved Date: Mon Sep 14 11:24:46 2020 +0200 C#: Adjust caching of tuple types commit 6b035df660c4a9df533a4c202d0b1b0baa9ea4d4 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Sep 11 17:16:55 2020 +0100 C++: Repair taint flow from previous. commit e54937756129301eebb6428f97a3bd03eb0929b3 Author: Tom Hvitved Date: Mon Sep 14 11:00:59 2020 +0200 C#: Construct `File::TransformedPathLazy` lazily This avoids calling the path transformer for `GeneratedFile`s. commit 19746023d9d402a416af8ff0dd68101d61c733c9 Author: Tom Hvitved Date: Mon Sep 14 10:07:28 2020 +0200 C#: Tidy code for constructing underlying tuple structs commit 6fb534f178c624a4476c2ef66f51ff68ae51e2e8 Author: Erik Krogh Kristensen Date: Mon Sep 14 09:59:48 2020 +0200 fix catastrophic join order in UnsafeJQueryPlugin commit 9502869e3c2f38131c6549901181c97838d40361 Author: Erik Krogh Kristensen Date: Mon Sep 14 09:59:22 2020 +0200 improve join-order for aliasPropertyPresenceStep commit 021aa647c1f95942f32c72626a800a8dbd79da5a Merge: 34a57e2bd 2d57abdcb Author: Jonas Jensen Date: Mon Sep 14 09:37:27 2020 +0200 Merge pull request #4142 from MathiasVP/mathiasvp/read-step-without-memory-operands C++: Use IR alias analysis for field flow commit 78b24b76a09d680ac6581597f0ecfe25596ed18f Author: Mathias Vorreiter Pedersen Date: Mon Sep 14 09:26:41 2020 +0200 C++: Remove the problematic taint tracking rule. It seems like we get the flows from dataflow already now. commit 34a57e2bd42a369ad64d09d66254d81f05347bff Merge: fee7ce6c7 ad11f76ec Author: Mathias Vorreiter Pedersen Date: Mon Sep 14 09:16:32 2020 +0200 Merge pull request #4252 from jbj/normalize-bounds C++: SimpleRangeAnalysis: Always normalize bounds after a computation commit 6f20516f8433bdab89610c805a360d5b0b9eb3ca Author: Faten Healy <5361987+fatenhealy@users.noreply.github.com> Date: Sun Sep 13 21:07:28 2020 +1000 Update broken_crypto.py to AES instead of Blowfish commit 826fc0a630cb4742875221c31ee3d9ab269b76ca Author: Faten Healy <5361987+fatenhealy@users.noreply.github.com> Date: Sun Sep 13 21:04:07 2020 +1000 Update BrokenCryptoAlgorithm - Blowfish to AES commit 1d92cbb655399655f2e83e0d70678ae02ebfde8e Author: Asger Feldthaus Date: Sat Sep 12 09:22:12 2020 +0100 JS: Bump extractor version string commit e0f5b208da911f8a9dfe4220943645e8e0124cbe Author: Taus Brock-Nannestad Date: Fri Sep 11 18:17:25 2020 +0200 Python: Fix broken test of global typetracker flow The missing `global g` annotation meant `g = x` was interpreted as a local assignment. commit eb5782d90822bcf6f3551aa599c4e0a0dde0fd93 Author: lcartey@github.com Date: Fri Sep 11 17:12:10 2020 +0100 C++: Support customizable ranges for RangeSsaDefinitions. commit b404a339a4d0982533d76cb0187b1908fc19b9a4 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Sep 11 16:15:47 2020 +0100 C++: Correct isQualifierObject -> isQualifierAddress. commit fee7ce6c7f15bf062b6bdc892828306218669dc9 Merge: 903bc007b f16835618 Author: Jonas Jensen Date: Fri Sep 11 16:53:43 2020 +0200 Merge pull request #4221 from rajivshah3/fix/cpp-av-32-include C++: Allow .inc files to be included commit d3ca140eeb7a0aa2901047a07fe079320d0d619d Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Sep 11 15:04:52 2020 +0100 C++: Account for pointer / reference parameters to operator<<. commit 0eb8b6c7b0fe71ba182e85eac902d028aa6570f5 Author: Rasmus Lerchedahl Petersen Date: Fri Sep 11 14:24:49 2020 +0200 Python: Address review commit 3414063f2eedf3444c65cf3232193e4270476e2c Author: Calum Grant <42069085+calumgrant@users.noreply.github.com> Date: Fri Sep 11 13:16:26 2020 +0100 Update change-notes/1.25/analysis-python.md Co-authored-by: Rasmus Wriedt Larsen commit 903bc007b886a394f510c544662b7fadd922c4b8 Merge: 172becd67 b71a8e2ad Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Fri Sep 11 04:41:38 2020 -0700 Merge pull request #4082 from max-schaefer/js/api-graph Approved by asgerf commit 172becd67fde0bcc3ea9020de6457be7f000a564 Merge: d60b7c729 65d48a32b Author: Jonas Jensen Date: Fri Sep 11 13:26:08 2020 +0200 Merge pull request #4250 from lcartey/cpp/expose-getdefbounds C++: Expose getDef(Upper|Lower)Bound as an internal predicate. commit 2d57abdcbe48dc5c10ba516b1907a12ab3ff079e Merge: ad602b892 d60b7c729 Author: Mathias Vorreiter Pedersen Date: Fri Sep 11 12:47:29 2020 +0200 Merge branch 'main' into mathiasvp/read-step-without-memory-operands commit d648150322cc8a746895bc52f76ed0dde2e028df Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Sep 11 11:07:55 2020 +0100 C++: Autoformat. commit dd53e3fe65d9281d930ee93fd26c8dcdd54b0c98 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Sep 10 11:32:52 2020 +0100 C++: Fix data flow to return value. commit 597757d76ffe4f1a737700d9ed32fbeaaf67c65e Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Sep 10 11:04:11 2020 +0100 C++: Model std::stringstream put and write. commit 66a5c38eef2a0980549e8588b8f326fd2662eb4c Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Sep 10 09:51:01 2020 +0100 C++: Model std::stringstream constructor. commit ad11f76ec6cbe0e2a0b3b1935b853e68b9f90f1e Author: Jonas Jensen Date: Fri Sep 11 11:56:53 2020 +0200 C++: Always normalize bounds after a computation This stops some cases of `-0.0` from propagating through the range analysis, fixing a false positive on arvidn/libtorrent. There seems to be no need for a corresponding change in the caller of `getDefLowerBoundsImpl` since that predicate only contains computations that cannot introduce negative zero. commit 5dbb4af5b5e822dc0f0b0434f2e88fc382f64ed0 Author: Rasmus Lerchedahl Petersen Date: Fri Sep 11 11:55:51 2020 +0200 Python: Implement `BarrierGuard` commit 0c8e06ba68167d7fff52ff76236e020c7020b5bc Author: Jonas Jensen Date: Fri Sep 11 11:52:39 2020 +0200 C++: Tests for -0.0 in range analysis commit 6c5b30d2a4eeb9af52c5e7f5788e110b1574a9ab Author: Tom Hvitved Date: Fri Sep 11 11:48:31 2020 +0200 C#: Update CIL consistency test commit f225a17639dfad79643653eb1afee25c970bcb77 Author: Tom Hvitved Date: Fri Sep 11 11:40:53 2020 +0200 C#: Even more reflection for retrieving meta data handle commit 65d48a32b8c19587944b460c1af8cd5e9e3b6073 Author: lcartey@github.com Date: Fri Aug 28 19:46:45 2020 +0100 C++: Expose getDef(Upper|Lower)Bound as an internal predicate. commit d60b7c729740b358e66fe4f2a2eecad9e38c107c Author: Tamas Vajk Date: Tue Sep 8 12:53:13 2020 +0200 C#: Improve empty collection check to not report on collections with property writes commit ff0910408931d4e95d8ef0451d3fcbcabbb5f96d Merge: 9659afdf0 399da6837 Author: Mathias Vorreiter Pedersen Date: Fri Sep 11 09:25:50 2020 +0200 Merge branch 'main' into mathiasvp/array-field-flow commit 399da6837a7f617500d43043498fdcffa2912ece Merge: 31495b876 ceb198f65 Author: Mathias Vorreiter Pedersen Date: Fri Sep 11 08:59:03 2020 +0200 Merge pull request #4227 from jbj/SimpleRangeAnalysis-NotExpr C++: Support `(bool)x` and `!x` in SimpleRangeAnalysis commit 31495b876eb44de489858cba0b748e71867c341a Author: Bas van Schaik <5082246+sj@users.noreply.github.com> Date: Thu Sep 10 20:25:02 2020 +0100 Python script to generate lists of code scanning queries in CSV format (#4177) * Create a PowerShell script that can be used to report on the set of queries inside of a particular QL Suite. * Translate PowerShell script into Python * support running this script from anywhere within the CodeQL git repo * print non-fatal error if metadata is not available * make sure warning about missing pack is printed to stderr * only run on pushes against main and rcs * detect repo by checking remote, rather than first SHA * specify full sha of dsaltares/fetch-gh-release-asset * trigger workflow on PR that modifies paths of interest Co-authored-by: Justin Hutchings Co-authored-by: Aditya Sharad <6874315+adityasharad@users.noreply.github.com> commit 52d8f7d3959910f58ef3a6a5497a2a2e1534c905 Merge: f716f9690 92e7a5676 Author: Rasmus Wriedt Larsen Date: Thu Sep 10 16:12:28 2020 +0200 Merge pull request #4235 from yoff/SharedDataflow_UseUseFlow Python: Port use-use implementation from Java commit 92e7a5676d4315c337efc3946e2a24fe2d433f27 Author: Rasmus Lerchedahl Petersen Date: Thu Sep 10 15:17:30 2020 +0200 Python: Address review comments commit 3a19b1e7fd7d60d00248dfe42a2e5946308567f6 Author: yoff Date: Thu Sep 10 15:06:06 2020 +0200 Apply suggestions from code review Co-authored-by: Rasmus Wriedt Larsen commit 2cc635f7e05f72095a4bc65f30b9075a1f244a12 Author: Tom Hvitved Date: Thu Sep 10 14:09:12 2020 +0200 C#: Add DB upgrade script commit 01e766c745f19b33a040816fb49daa7dc68241e8 Author: Tom Hvitved Date: Thu Sep 10 14:02:34 2020 +0200 C#: Disable uniqueness constraint from `explicitly_implements` The documentation on `ExplicitInterfaceImplementations` says "Properties imported from metadata can explicitly implement more than one property", so the constraint appears to be invalid. commit 643a8b57c30427acd519c24db089a38c63e37646 Author: Tamas Vajk Date: Mon Sep 7 15:46:53 2020 +0200 C#: Explicitly handle underlying tuple types commit 221b92de04e2a81050b3e06fe3b3c6a9e15ea17a Author: Tamas Vajk Date: Tue Aug 11 11:02:43 2020 +0200 C#: upgrade Roslyn dependencies to version 3.7 commit fb3060dc3dc314c5181c69adb30992aea6397a65 Author: Rasmus Wriedt Larsen Date: Thu Sep 10 13:47:36 2020 +0200 Java: Minor fixup for SSA AdjacentUsesImpl::varBlockReaches This should not change anything in regards to correctness overall -- what we really care about is `varBlockStep`, and that checks `varOccursInBlock(v, b2)`. However, the comment is a bit easier to read together with the code now (and probably also gives slightly smaller predicate result size). commit 949b81b07cfbadf21137869410cc838ae8d9a582 Author: Rasmus Wriedt Larsen Date: Thu Sep 10 13:42:10 2020 +0200 Python: Add dataflow tests for dynamic tuple creation Inspired by the FP-report in https://github.com/github/codeql/issues/4239 commit f716f9690b4ca4da17d5b774e7fe8c806413298f Merge: a9f322e6c 50cc5d58e Author: Rasmus Wriedt Larsen Date: Thu Sep 10 13:28:04 2020 +0200 Merge pull request #4132 from yoff/SharedDataflow_NestedComprehensions Python: Shared dataflow, nested comprehensions commit a9f322e6c3ee801b8478fca2b899dbf745d8e1bb Merge: 2a3d0072d 9629f1c2f Author: Tom Hvitved Date: Thu Sep 10 12:43:43 2020 +0200 Merge pull request #4241 from hvitved/csharp/autobuild-cmd-exit-code C#: Correctly propagate exit code in `autobuild.cmd` commit 2a3d0072d29d8812a8a592e79dc6be452336f3f6 Merge: fed973f9c fcf39eaac Author: Tom Hvitved Date: Thu Sep 10 12:39:01 2020 +0200 Merge pull request #4242 from hvitved/csharp/fix-failing-windows-tests C#: Fix broken auto-builder tests on Windows commit fed973f9c490f6faf8a3574f97e0c8f4f9157336 Merge: 34a03ec52 bb9cf72a3 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Sep 10 10:46:30 2020 +0100 Merge pull request #4229 from MathiasVP/mathiasvp/make_shared_make_unique-models C++: Add taint models for std::make_unique and std::make_shared commit 34a03ec523cbc392a5c22306d0958a5133feff05 Merge: c45743588 2c0157553 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Sep 10 10:33:16 2020 +0100 Merge pull request #4213 from rdmarsh2/rdmarsh2/cpp/explicit-conversion-perf C++: Improve performance of getExplicitlyConverted commit 9629f1c2f43ac450e968a5220062822364b686b3 Author: Tom Hvitved Date: Thu Sep 10 11:09:38 2020 +0200 C#: Also propagate exit code in `pre-finalize.cmd` commit 2eb8ea85fbd2a2fb0505f40e04ffb6fcd38e0e63 Author: Rasmus Lerchedahl Petersen Date: Thu Sep 10 10:59:26 2020 +0200 Python: update test expectations commit deb1a4ceb972841cab6d66e9b72d5a3b97a645a7 Merge: 7b10a3a54 c45743588 Author: Rasmus Lerchedahl Petersen Date: Thu Sep 10 10:55:34 2020 +0200 Merge branch 'main' of github.com:github/codeql into SharedDataflow_UseUseFlow commit fcf39eaac16dfa4f9b48ee0b7ce59c7890ca3ebe Author: Tom Hvitved Date: Thu Sep 10 10:34:32 2020 +0200 C#: Fix broken auto-builder tests on Windows commit 88bbc2f1f455c924b3789e9d0868ca20154dcb11 Author: Erik Krogh Kristensen Date: Tue Sep 8 21:35:19 2020 +0200 add change note commit a32db3de4bc0b18fa569a0eaeec8fa36462440ff Author: Tom Hvitved Date: Thu Sep 10 10:22:02 2020 +0200 Simplify exit code logic Co-authored-by: Arthur Baars commit 50cc5d58e96739299c6dd7ee83fa35ae84560d2c Merge: fae915bbb c45743588 Author: Rasmus Lerchedahl Petersen Date: Thu Sep 10 10:20:55 2020 +0200 Merge branch 'main' of github.com:github/codeql into SharedDataflow_NestedComprehensions commit 4cc1e4d1f19f16fa01f1802e76a1a3c4e42ebbf2 Author: Tom Hvitved Date: Thu Sep 10 10:01:43 2020 +0200 C#: Correctly propagate exit code in `autobuild.cmd` commit b71a8e2ad0d47b270bdd7853d0437087b4077153 Author: Max Schaefer Date: Thu Sep 10 08:44:06 2020 +0100 JavaScript: Expose an API-graph predicate that is useful for flow summaries. commit c45743588c1fe18f6a81b4c7836f901510f9bafe Merge: f4f47bd5e 1ce3ac74a Author: Tom Hvitved Date: Thu Sep 10 08:43:39 2020 +0200 Merge pull request #4237 from hvitved/csharp/autobuilder/nuget C#: Download nuget.exe in auto-builder if it does not exist commit 7b10a3a5460863b12046768ce6576b272dff0c57 Author: Rasmus Lerchedahl Petersen Date: Thu Sep 10 08:36:00 2020 +0200 Python: fix comment and source uses commit 10633019a6081ee9b169d3a022d2132789e057af Author: Robert Marsh Date: Wed Sep 9 12:45:17 2020 -0700 C++: autoformat commit 2e187a51ae6db786322ed979e6fa449e494352a7 Author: Robert Marsh Date: Wed Sep 9 12:45:06 2020 -0700 C++: test for interprocedurl iterator flow commit bb9cf72a31fa29c3dcdfd1501d94081adabfacad Merge: 17867f25a f4f47bd5e Author: Mathias Vorreiter Pedersen Date: Wed Sep 9 20:51:56 2020 +0200 Merge branch 'main' into mathiasvp/make_shared_make_unique-models commit 2c0157553f80e6fa6a6020d6d5fe5a36a8c9516b Author: Robert Marsh Date: Wed Sep 9 11:49:22 2020 -0700 C++: accept test improvement from conversions Duplicate results were due to a mishandling of implicit array-to-pointer conversions. commit 46a07fa9b2cd79298f257042bd1f9fa153a5aa42 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Sep 9 18:22:06 2020 +0100 C++: Model std::stringstream::str. commit f4f47bd5edb70d02eddbe143a817f5144b0815d1 Merge: 17ccc137a b8e057f7a Author: Taus Date: Wed Sep 9 17:51:24 2020 +0200 Merge pull request #4236 from RasmusWL/python-experimental-taint-sanitizers Python: Expand on taint sanitizer tests commit 1ce3ac74a163db08f4ae7c40c39037af10502efa Author: Tom Hvitved Date: Wed Sep 9 16:35:37 2020 +0200 Address review comments commit 17ccc137aec11e9a2d70732db87cb79a194f5c8e Merge: dfb8761bd 2172fb6e6 Author: Taus Date: Wed Sep 9 16:26:36 2020 +0200 Merge pull request #4238 from RasmusWL/dataflow-small-fix-for-naming Dataflow: small fixes for naming in taint tracking commit ad602b892b0f70f6f5657130e8c2d71ed96fcd15 Merge: 9c1837e3b dfb8761bd Author: Mathias Vorreiter Pedersen Date: Wed Sep 9 16:17:23 2020 +0200 Merge branch 'main' into mathiasvp/read-step-without-memory-operands commit dfb8761bdc350492ce3aadfee9520042e08278a0 Author: Tamás Vajk Date: Wed Sep 9 16:12:48 2020 +0200 C#: Add flag to Standalone extractor to use the self contained .Net framework (#4233) commit b8e057f7ad12a090cbbbfb913b6cfa8aacdfc677 Author: Rasmus Wriedt Larsen Date: Wed Sep 9 15:57:53 2020 +0200 Python: isSanitizerGuard test is future work commit b1567827a05905967cab1748797a7c7833e66a17 Author: Rasmus Lerchedahl Petersen Date: Wed Sep 9 15:52:07 2020 +0200 Python: Repair flow out of post-update nodes commit e91d321d2846b02184d2f25aded0ba465e62bfe6 Merge: a1cec1237 d8bb49b9a Author: Mathias Vorreiter Pedersen Date: Wed Sep 9 15:31:46 2020 +0200 Merge pull request #4234 from geoffw0/stringstream C++: Tests and initial models for taint through std::stringstream / std::ostream. commit 17867f25a75e196de4b6d1e2a01f0bb6686efee0 Author: Mathias Vorreiter Pedersen Date: Wed Sep 9 15:27:56 2020 +0200 C++: Accept more test changes commit ceb198f65d4d2b61cae860323d2bc0c23605b230 Merge: 911dec6f8 a1cec1237 Author: Jonas Jensen Date: Wed Sep 9 14:50:00 2020 +0200 Merge remote-tracking branch 'upstream/main' into SimpleRangeAnalysis-NotExpr commit 2172fb6e650880d68747f9204d50e7af1fefc624 Author: Rasmus Wriedt Larsen Date: Wed Sep 9 14:30:33 2020 +0200 Dataflow: s/data flow/taint propagation/ in QLDoc for sanitizers commit d8bb49b9a02fbc75a7148551b337e1fe8b4f124c Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Sep 9 13:18:07 2020 +0100 C++: We get a few additional results for DefaultTaintTracking as well. commit d90f0be2c4d32791b63edb73a45c45027d85925f Author: Rasmus Wriedt Larsen Date: Wed Sep 9 14:11:56 2020 +0200 Dataflow: defaultTaintBarrier => defaultTaintSanitizer Just keeping things a bit more consistent :) commit 947040aafe9aa4d1241ab357a623003d88121303 Author: Tom Hvitved Date: Tue Sep 8 20:10:58 2020 +0200 C#: Download nuget.exe in auto-builder if it does not exist commit ab8cc23ce7eb17f17412b8ef8ddc12cc1c5ae1dd Author: Rasmus Wriedt Larsen Date: Wed Sep 9 13:57:25 2020 +0200 Python: Expand on taint sanitizer tests Most interesting to look at the custom sanitizers. Once we have use-use flow, we should handle this case: ``` s = TAINTED_STRING emulated_authentication_check(s) ensure_not_tainted(s) ``` commit 9e59d79a726c44677d0af2412b29486c2449517a Author: Rasmus Lerchedahl Petersen Date: Wed Sep 9 13:51:24 2020 +0200 Python: Repair flow from pre-update nodes commit ce7f82ddc6dae71cb09132ec59a368ebb2c6cd46 Author: Rasmus Lerchedahl Petersen Date: Wed Sep 9 13:27:14 2020 +0200 Python: Add def-use jump-steps commit 8b23461eb5639756582cf8d240ce9de032986d10 Author: Mathias Vorreiter Pedersen Date: Wed Sep 9 12:22:53 2020 +0200 C++: Update change note. commit 8226515138806a829ad2e632c4ffd78cb50df888 Author: Mathias Vorreiter Pedersen Date: Wed Sep 9 12:22:29 2020 +0200 C++: Add a taint model for std::{shared, unique}_ptr::get commit 417424ab759aae7a47179fd2d3480aa51a35cd3a Author: Mathias Vorreiter Pedersen Date: Wed Sep 9 12:21:09 2020 +0200 C++: Add QLDoc and fix comment in isArray (review comments) commit c661f43316a48295bab163d9290ebd2919f93821 Author: Rasmus Lerchedahl Petersen Date: Thu Sep 3 11:19:35 2020 +0200 Python: Port use-use implementation from Java commit db3f81a98f3b8b8475536df2566123993ff872f8 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Sep 9 11:16:14 2020 +0100 C++: Correct QLDoc. commit 3013ef54ef4d611785cc2f059a4ae49b7f1ebefb Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Sep 9 11:09:47 2020 +0100 C++: Change note. commit a1cec12377159bfd84cc7d05cb93ac331cd18715 Merge: 9de1fb7c1 efe3fd7f1 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Wed Sep 9 10:13:14 2020 +0100 Merge pull request #4220 from erik-krogh/colonCmd Approved by esbena commit 038688a55c5519a40c15950a323fdf0ea45d13ae Author: Rasmus Wriedt Larsen Date: Wed Sep 9 10:34:40 2020 +0200 Python: Minor updates to 1.25 change notes backporting fixes from `@sj` commit 9de1fb7c18929e29e59d2cedd79af7d30aec3cd8 Merge: 9879c6c20 f92f84e3d Author: Mathias Vorreiter Pedersen Date: Wed Sep 9 10:02:37 2020 +0200 Merge pull request #4222 from jbj/BlockStmt C++/Java/JS: Rename Block -> BlockStmt commit cffe573d0610a143cac9ebc62355fee0f0e4b16b Author: Erik Krogh Kristensen Date: Tue Sep 8 21:30:41 2020 +0200 add taint-steps for underscore methods commit eb80705e99c8e519cb71b967ad4c85d2680748bf Author: Erik Krogh Kristensen Date: Tue Sep 8 15:45:42 2020 +0200 add a taint-step for `require("bluebird").mapSeries()` commit b97c09a3197550b3eda390b424cb07702a6f27df Author: Erik Krogh Kristensen Date: Tue Sep 8 15:09:27 2020 +0200 use tuples to simplify arrayFunctionTaintStep commit bb97829e1d5ff436939abce2261c489736a389ef Author: Erik Krogh Kristensen Date: Tue Sep 8 15:06:35 2020 +0200 add a model for the ClientRequest `new require("net").Socket()` commit d5097d820d23bd6fb52f3ee77424e70bcca26c03 Author: Erik Krogh Kristensen Date: Tue Sep 8 10:02:59 2020 +0200 support direct callbacks to require("net").createServer commit efe3fd7f1e156033eb876709bd98930ed6698cce Author: Erik Krogh Kristensen Date: Wed Sep 9 09:41:15 2020 +0200 Update change-notes/1.26/analysis-javascript.md Co-authored-by: Esben Sparre Andreasen commit 30b5975274763d2e2885ad58e8caca683277b6fb Author: Robert Marsh Date: Tue Sep 8 14:51:08 2020 -0700 C++: autoformat commit eab1557e27cfefef7b826960e3840e5ba79279e1 Author: Robert Marsh Date: Tue Sep 8 14:09:57 2020 -0700 C++: output iterator flow via FlowVar commit 13c45b6664a6b4fcad59a60a096236cb702d21b0 Author: Robert Marsh Date: Thu Aug 27 15:09:01 2020 -0700 C++: remove unnecessary parameter in FlowVar.qll commit c8cdf68bf9b8881faae02f89ca3cb5091ec1c926 Author: Robert Marsh Date: Tue Aug 25 16:34:36 2020 -0700 C++: Remove StdStringBeginEnd commit 703db0b9a6ffdb53af4cef150cf1ae6f10ca4517 Author: Robert Marsh Date: Tue Aug 25 15:26:18 2020 -0700 C++: noisy output iterators in AST taint tracking commit 983f54f11a74736eed61075c24229032131d09a2 Author: Robert Marsh Date: Tue Aug 25 15:21:16 2020 -0700 C++: simple tests for vector output iterators commit 9659afdf09646fb51dc1159aefd46740dc94643f Author: Mathias Vorreiter Pedersen Date: Tue Sep 8 22:25:33 2020 +0200 C++: Accept more test changes commit 44bdf9821794b01e943a6210f167320d55945484 Author: Robert Marsh Date: Tue Sep 8 13:02:51 2020 -0700 C++: simplify and explain getExplicitlyConverted commit 65cc9888d517b76df5c7d1321365972c309c2f6e Merge: 083a4b2ab 9879c6c20 Author: Robert Marsh Date: Tue Sep 8 12:29:34 2020 -0700 Merge branch 'main' into rdmarsh2/cpp/explicit-conversion-perf commit 083a4b2abc36e442baa877e07b0456ccd220bfca Author: Robert Marsh Date: Tue Sep 8 12:28:16 2020 -0700 C++: handle non-casts in hasExplicitConversion commit f025d09bf0be8ac49f8cebfe647adafdc90c188e Author: Mathias Vorreiter Pedersen Date: Tue Sep 8 19:12:00 2020 +0200 C++: Accept test changes commit 978b74f235e9311b1c2136951f09dca876e18622 Author: Mathias Vorreiter Pedersen Date: Tue Sep 8 19:11:48 2020 +0200 C++: Implement taint model for make_shared and make_unique commit 7ac5e84925b3a9150428bfcad0c6e88ca37a7bdf Author: Mathias Vorreiter Pedersen Date: Tue Sep 8 19:03:54 2020 +0200 C++: Add make_shared and make_unique test cases commit 90c7a79272d777a743c4a5e95b1cf34564a08ed2 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Sep 8 16:45:13 2020 +0100 C++: Fix the object/refs up. commit 5a3d41879a43c95efedebb4223e1f9695429ba37 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Sep 8 16:32:15 2020 +0100 C++: Change some of the taint flows to data flows. commit 8a143bec3a737fa06871c5afa938adbbe2cc3724 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Sep 8 16:20:36 2020 +0100 C++: Reverse taint through operator<<. commit b73ff8da639097688439deb50497279d37ac6c43 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Sep 8 13:41:14 2020 +0100 C++: Flow through operator<<. commit 911dec6f8674a233877c3210bc84f49106e519bd Author: Jonas Jensen Date: Tue Sep 8 16:41:37 2020 +0200 C++: SimpleRangeAnalysis (bool)x and !x support commit 1b6da062cf1608b519b796f7cf0021a46e7b3a88 Author: Jonas Jensen Date: Tue Sep 8 16:41:19 2020 +0200 C++: RangeAnalysis tests for bool conversions commit 1f4028f4a08a7faa99b614a6af6ecc36ef2eeb66 Author: Arthur Baars Date: Tue Sep 8 16:24:57 2020 +0200 Java: Add new SQL sinks for Hibernate versions 4 and 6 commit 4515d27ad23ae9e508659c259322f5bf0a2ca418 Merge: 38679b6d9 9879c6c20 Author: Erik Krogh Kristensen Date: Tue Sep 8 14:10:15 2020 +0000 Merge branch 'main' of https://github.com/github/codeql into pr/erik-krogh/4220 commit 38679b6d9220740d284349d8fe06723576b3806b Author: Erik Krogh Kristensen Date: Tue Sep 8 14:04:40 2020 +0000 add change note commit 9879c6c204cb0bad8da26448363510c337f28d22 Merge: 075ce6edb 442de2e2d Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Tue Sep 8 14:52:17 2020 +0100 Merge pull request #4184 from aschackmull/java/cleanup-queryinjection Approved by aibaars commit 442de2e2d2de8dea44a26f27aba2e6e695c9cf00 Author: Anders Schack-Mulligen Date: Tue Sep 8 15:09:39 2020 +0200 Java: Add qldoc. commit 86755215ad19e98b7e9490a7205ca4bd436bf1df Merge: 8e8c65a16 02da80aa2 Author: Anders Schack-Mulligen Date: Tue Sep 8 14:50:46 2020 +0200 Merge pull request #4225 from aschackmull/java/changenote-1.25 Java: Add 1.25 change notes. commit 02da80aa25fc7690bef9a4c77c057571b2c27406 Author: Anders Schack-Mulligen Date: Tue Sep 8 14:40:33 2020 +0200 Java: Remove "New Queries" section. commit 5d14688848fc79419093fb0bdf2003595c07e937 Merge: 41147d245 075ce6edb Author: Mathias Vorreiter Pedersen Date: Tue Sep 8 14:38:58 2020 +0200 Merge branch 'main' into mathiasvp/array-field-flow commit 41147d245dbc5a27e022655e0e388bd06c035c00 Author: Mathias Vorreiter Pedersen Date: Tue Sep 8 14:35:22 2020 +0200 C++: Accept test changes commit faae2e782a7bfa7c2ff4742d1615d4af4055bc4b Author: Mathias Vorreiter Pedersen Date: Tue Sep 8 14:35:09 2020 +0200 C++: Implement field flow for operator[] writes and pointer deref writes. commit 2979f9813ee0ba08779623a72106f00ab35e30d8 Author: Rasmus Wriedt Larsen Date: Tue Sep 8 14:27:12 2020 +0200 Python: Add missing change notes I looked through PRs between rc/1.24 and rc/1.25 and added missing change notes for: - https://github.com/github/codeql/pull/3314 - https://github.com/github/codeql/pull/3302 - https://github.com/github/codeql/pull/3212 - https://github.com/github/codeql/pull/3453 - https://github.com/github/codeql/pull/3407 - https://github.com/github/codeql/pull/3563 ``` git log --grep="Merge pull request" --format=oneline rc/1.24..rc/1.25 -- python/ ``` commit b1e6e3a6f23c9f6c03c4f8b752aa5f6a38112da1 Author: Anders Schack-Mulligen Date: Tue Sep 8 14:18:20 2020 +0200 Java: Add 1.25 change notes. commit f92f84e3d412c6a583ba024c91e7b31415e45fc7 Merge: 0935d1e15 075ce6edb Author: Jonas Jensen Date: Tue Sep 8 14:09:46 2020 +0200 Merge remote-tracking branch 'upstream/main' into BlockStmt commit 075ce6edbfc09b9ddf95b7bf6e1676b8411486bd Merge: 22b3b0a5f d49bc4ccd Author: Nick Rolfe Date: Tue Sep 8 12:44:24 2020 +0100 Merge pull request #4178 from github/igfoo/48-coroutine-support-3 C++: Add initial support for coroutines operators commit 4d0a1ee8578a061f3286b6e4b7a626e4d9211921 Author: Tom Hvitved Date: Tue Sep 8 09:29:35 2020 +0200 Address review comments commit 0935d1e155fcd456d69e0a2e869cbd06e092e00e Author: Jonas Jensen Date: Tue Sep 8 08:25:52 2020 +0200 JS: Deprecate the Block class alias commit 464d3630a2554ccc943c2e0b3566c7d182642452 Author: Jonas Jensen Date: Tue Sep 8 08:19:18 2020 +0200 Java: Rename Block -> BlockStmt commit ab90f06ddff9811106f93c46f65e073d69c205c3 Author: Jonas Jensen Date: Mon Sep 7 16:48:29 2020 +0200 C++: Rename Block -> BlockStmt commit f1683561811c7db4814439b38531ceb8a5292dde Author: Rajiv Shah Date: Mon Sep 7 18:09:21 2020 -0400 C++: Allow .inc files to be included commit d49bc4ccda21fd2c2b13a9dbf9f9def8da80740d Author: Ian Lynagh Date: Mon Sep 7 20:39:11 2020 +0100 C++: Tweak qldoc for coroutines commit 4bf545548b5173f1a525e5b90646d1e9138f1722 Author: Ian Lynagh Date: Fri Sep 4 01:18:27 2020 +0100 C++: Tweak to make qlformat happy commit 86c58afa4869bf2b8f5df5f6af29e9f50e84bd39 Author: Ian Lynagh Date: Thu Sep 3 20:14:44 2020 +0100 C++: Update stats for co_await/co_yield/co_return commit 49f7baf5a980c170375c9df52be06c7f8e9999df Author: Ian Lynagh Date: Thu Sep 3 12:47:29 2020 +0100 C++: Add an upgrade script commit cca276be84e57cbb8e6e71f021108f24f5422896 Author: Ian Lynagh Date: Wed Aug 26 18:01:10 2020 +0100 C++: Remove co_await range-based-for support for now Initial impl won't support it commit 78b522722cafea6e9e54cbdc35937d8eb2d8e346 Author: Ian Lynagh Date: Wed Aug 26 17:13:25 2020 +0100 C++: Split CoReturnStmt.getExpr into CoReturnStmt.{getOperand,getExpr} commit 8b8b9d6fe3e6436fa74a6e1f6459ee20847e270f Author: Matthew Gretton-Dann Date: Mon Aug 17 17:00:33 2020 +0100 Actually sort add Statement support This commit fixes the previous one. commit 5df5e6dfcecd10326f9a095792b016ddf8f54c93 Author: Matthew Gretton-Dann Date: Mon Aug 17 15:02:14 2020 +0100 Add initial QL support classes for coroutines Add classes for expressions co_yield and co_await. Adds classes for statements co_return and `for co_await`. commit 8199b3a230621c131439fbcd27a4e740cf2d65e3 Author: Matthew Gretton-Dann Date: Tue Mar 10 11:18:07 2020 +0000 C++: Add DB schema support for coroutines commit 6ef67af7436e48baae3253dcb1462215a3902eb1 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Sep 7 11:07:56 2020 +0100 C++: Add models for stringstream methods. commit fafd2f0a7c470e8bdcbcca80e68e278ce4595fc6 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Sep 7 11:05:29 2020 +0100 C++: Add test cases for stringstream / ostream. commit 22b3b0a5f16793603cae0c65df8b26f483bf8be9 Merge: d3f19721e 61998afc5 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Sep 7 17:34:14 2020 +0100 Merge pull request #3953 from RasmusWL/python-more-call-graph-tracing Approved by tausbn commit b8a492473b557742f7c2b7f31fad2e4c03766026 Author: Max Schaefer Date: Mon Sep 7 14:26:10 2020 +0100 JavaScript: Stop tracking canonical function names in API graphs. This blows up on the TypeScript compiler, and is likely to be much less useful than tracking type names and namespaces, which we still do. commit d3f19721e6dec20d01eadf01847b7757e65b6621 Merge: 3493c93d7 8ada928b1 Author: Asger F Date: Mon Sep 7 16:21:32 2020 +0100 Merge pull request #4153 from erik-krogh/snake_case_pr JS: rename dbscheme predicates to consistently use snake_case in dbscheme commit 9c1837e3b31b7bbc017c7e8d583de08fc88270e3 Author: Mathias Vorreiter Pedersen Date: Mon Sep 7 16:49:36 2020 +0200 C++: Rename getField to getAField following review comments. commit 3493c93d7be1c442d6e897710ef727313f2c5c2d Merge: 3a7bf2a15 b3d18ef61 Author: Jonas Jensen Date: Mon Sep 7 15:27:07 2020 +0200 Merge pull request #4218 from MathiasVP/mathiasvp/fix-fp-av82 C++: Add cases for conditional and comma operator in AV Rule 82 commit 6c716331d99f0a997cfa52d7e22b031887dd5016 Author: Tom Hvitved Date: Wed Aug 26 14:31:02 2020 +0200 C#: Skip `foreach` loop bodies in the CFG when the iteration expression is empty commit 9e240b7397cce037290917bd6c186a0a767e9ced Author: Tom Hvitved Date: Wed Aug 26 13:48:40 2020 +0200 C#: Add more CFG loop unrolling tests commit 61998afc56c3a2cb122c10b3d635ddfa0fb6341a Author: Rasmus Wriedt Larsen Date: Mon Sep 7 15:05:24 2020 +0200 Python: Remove unnecessary comment Was introduced in 5d031d7abe7d09a1a03c99ce54b57824ef5dd623 when I actually fixed the loop variable capture problem. commit 37f1ce312256e36553c3951fba3c5c0c8f40ad9c Author: Tom Hvitved Date: Mon Sep 7 08:57:49 2020 +0200 C#: Implement support for path transformers commit 423d87b8127f70dcd852c47f5247e1ee771b121f Author: Max Schaefer Date: Mon Sep 7 14:02:37 2020 +0100 JavaScript: Rename `TNode` to `TApiNode`. This prevents spurious recomputation of a cached stage. commit fb37330f5e3f86c1c8e1e5275527bae757c1aefc Author: Rasmus Wriedt Larsen Date: Mon Sep 7 14:59:07 2020 +0200 Python: Fix grammar Co-authored-by: Taus commit 55b79f445c79983cc2e0026895a3797108117a9c Author: Erik Krogh Kristensen Date: Mon Sep 7 14:28:28 2020 +0200 recognize commands with slash and underscore commit 3a7bf2a15a16dc985fd912f29c0c0cc48f76c0cd Merge: 0fe5d7537 cfd606a4e Author: Jonas Jensen Date: Mon Sep 7 13:37:20 2020 +0200 Merge pull request #3933 from MathiasVP/alternative-instruction-operand-flow C++: Alternate instruction -> operand flow commit 320879bc1e570292155f4bb62ef1b685b3441ef8 Author: Erik Krogh Kristensen Date: Mon Sep 7 13:12:38 2020 +0200 recognize colon in command-prefixes commit 0fe5d753750d81c7ca6da9339e44d2683826289a Merge: 85f6388a1 a4890ef99 Author: Jonas Jensen Date: Mon Sep 7 13:02:22 2020 +0200 Merge pull request #4196 from MathiasVP/mathiasvp/field-to-object-taint-tests C++: Add field to object taint tests commit 85f6388a1948ddf4f3b3eb32505c3d8e5d9bd63b Merge: 68f421f9c 417563763 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Sep 7 11:23:23 2020 +0100 Merge pull request #4206 from erik-krogh/consistentJquery Approved by esbena commit 68f421f9c377a539bf56534a46777ac1b50f951e Merge: b5872fe84 e2c205deb Author: Tom Hvitved Date: Mon Sep 7 11:25:46 2020 +0200 Merge pull request #4205 from tamasvajk/feature/printast-accessor C#: Add stable order for generated accessors in printed AST commit 8ada928b16f7914b27cd63b3862a05b145ab3570 Merge: 9ed9ecd33 b5872fe84 Author: Erik Krogh Kristensen Date: Mon Sep 7 11:12:57 2020 +0200 Merge branch 'main' into snake_case_pr commit 4175637631208e0656ed293b256876672204538c Author: Erik Krogh Kristensen Date: Mon Sep 7 11:08:21 2020 +0200 add change note for unsafe-jquery commit 61e2e5647c8f0b0975b1dc4acfce67762b6c3c5c Author: Erik Krogh Kristensen Date: Mon Sep 7 11:05:56 2020 +0200 autoformat commit b5872fe8484e67c1e328515d105e3dc36b8e9bc7 Merge: 2a70da4da 961554eb6 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Sep 7 09:48:05 2020 +0100 Merge pull request #3873 from asger-semmle/js/type-qualified-name-fallback Approved by erik-krogh commit 2a70da4da6697e98db0002e9ecfcf61e0a26190f Merge: ae9f58489 266365d0b Author: yoff Date: Mon Sep 7 10:16:18 2020 +0200 Merge pull request #4210 from tausbn/python-remove-spurious-global-flow Python: Remove implicit uses from `essaFlowStep` commit ae9f58489d7fe07e14e92468f2a62e330f2f4ee4 Merge: eea893483 720e8c432 Author: yoff Date: Mon Sep 7 09:54:12 2020 +0200 Merge pull request #4159 from RasmusWL/python-port-dataflow-tests Python: port dataflow tests commit 14567f531408c47f9e7b58ef9b0a34bb2c5e4c65 Author: Tom Hvitved Date: Mon Sep 7 08:57:12 2020 +0200 C#: Support wild-cards in file patterns Implements the specification at https://wiki.semmle.com/display/SDmaster/project-layout+format by compiling file path specifications to regular expressions. commit b3d18ef610be714849dfb5b7fdc682148401b898 Author: Mathias Vorreiter Pedersen Date: Mon Sep 7 08:59:08 2020 +0200 C++: Add cases for conditional and comma operator in AV RUle 82 commit a5ac8ebc2f6bfc5c3837424718662b420e932bac Author: Mathias Vorreiter Pedersen Date: Sat Sep 5 11:47:22 2020 +0200 C++: Don't import internals. commit 4be138d790ca4dad50b0cb0e4dcf166f778b30dc Author: Robert Marsh Date: Fri Sep 4 14:17:56 2020 -0700 C++: Improve performance of getExplicitlyConverted commit a4890ef99c6c310875fa662c8832a6533e19874d Author: Mathias Vorreiter Pedersen Date: Fri Sep 4 18:32:28 2020 +0200 C++: Add annotations describing whether the flow is an instance of field-to-object flow commit cfd606a4e0bcb135833214126969b229108593a7 Merge: 9887d8b7e eea893483 Author: Mathias Vorreiter Pedersen Date: Fri Sep 4 18:26:38 2020 +0200 Merge branch 'main' into alternative-instruction-operand-flow commit 208b85c7fc608372fec4797da6e857e12c2d090d Merge: ed7e499b0 eea893483 Author: Mathias Vorreiter Pedersen Date: Fri Sep 4 18:04:15 2020 +0200 Merge branch 'main' into mathiasvp/read-step-without-memory-operands commit eea893483d519233c9c8fc82f433155dab930e12 Merge: f92139d2b 43d8e8325 Author: Jonas Jensen Date: Fri Sep 4 17:52:48 2020 +0200 Merge pull request #4209 from geoffw0/taintbits C++: Fix a few remaining holes in taint through std::string commit f92139d2b0fdb7e4745b40a932f2c68a81055dbd Merge: 5ffc959e3 156a174cf Author: Jonas Jensen Date: Fri Sep 4 17:52:35 2020 +0200 Merge pull request #4202 from geoffw0/localhidesparam C++: Improve handling of template functions in cpp/declaration-hides-parameter commit ed7e499b02ea3b664edbd6a643339392cc6d20d6 Merge: c67951682 5ffc959e3 Author: Mathias Vorreiter Pedersen Date: Fri Sep 4 17:25:36 2020 +0200 Merge branch 'main' into mathiasvp/read-step-without-memory-operands commit c67951682a1b88006676b790e474a57cb0368ae5 Author: Mathias Vorreiter Pedersen Date: Thu Sep 3 21:27:54 2020 +0200 C++: Fix two bad join orders in readStep and storeStep. And use a min aggregate to guarentee that a FieldContent's toString has at most one result. commit 266365d0b650e81d108801cb8dd3acee6698d146 Author: Taus Brock-Nannestad Date: Fri Sep 4 16:38:59 2020 +0200 Python: Update `strange-essaflow` test commit 260763a7486fa3a3a94de249f0451ff0ceb9dbaf Author: Taus Brock-Nannestad Date: Fri Sep 4 16:35:49 2020 +0200 Python: Update consistency test results commit df1448cfb24698dc6b08ad4b322ff6e9e07f0ce3 Merge: 98266ad5d 5ffc959e3 Author: Taus Brock-Nannestad Date: Fri Sep 4 16:28:03 2020 +0200 Merge branch 'main' into python-remove-spurious-global-flow commit 156a174cf494d0643cdc7bf04c2c6b80f6c19cac Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Sep 4 14:55:55 2020 +0100 C++: Add explanation. commit 96098c5244065d5558dc51df5ff4abbbc2ca4463 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Sep 4 14:52:01 2020 +0100 C++: Simplify getConstructedFrom. commit 5ffc959e32b5d260608e789ccf6a3b980a1e0287 Merge: 5d1c2a368 cf57afd10 Author: Taus Date: Fri Sep 4 15:47:22 2020 +0200 Merge pull request #4211 from RasmusWL/python-strange-essaflow Python: Add example of strange DataFlow::jumpStep commit 2472b40b319c3c8935f4ab87b5597fe5c8200d14 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Sep 4 14:37:23 2020 +0100 C++: Fix test comments. commit 43d8e83258bc8cf477160acedb56dc5fcbf666e0 Merge: 6c40e22f4 5d1c2a368 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Sep 4 14:26:42 2020 +0100 Merge branch 'main' into taintbits commit 720e8c432e2e82fbe21656871031458b44122f6d Author: Rasmus Wriedt Larsen Date: Fri Sep 4 15:08:57 2020 +0200 Python: Update comment for validTest expectations commit 5d1c2a36892c2105a36795fa77f730e98f5cab98 Merge: 59c7907ee fbe42fb64 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Sep 4 13:47:59 2020 +0100 Merge pull request #4204 from jbj/SimpleRangeAnalysis-NEExpr C++: Support `!= constant` in range analysis commit cf57afd1023a36622660fc0676506e77f4160c89 Author: Rasmus Wriedt Larsen Date: Fri Sep 4 14:39:16 2020 +0200 Python: Add example of strange DataFlow::jumpStep The example code is just copied from command injection tests, that is not too important. The important part is that `jumpStep` says there is flow from the import of `os` to `app.route()` :O commit 59c7907ee4775b29d49611748a96bd8a61709c6c Merge: fd715a5b6 6aae75799 Author: Taus Date: Fri Sep 4 14:30:10 2020 +0200 Merge pull request #4207 from RasmusWL/python-typetracker-small-fixes Python: Small fixes for TypeTracker commit 98266ad5da33af817585afb67374a84444581b4b Author: Taus Brock-Nannestad Date: Fri Sep 4 14:22:43 2020 +0200 Python: Remove implicit uses from `essaFlowStep` commit f13a4f5771b81182ff5de5487d4aa314f64f3dfc Author: Erik Krogh Kristensen Date: Fri Sep 4 13:59:16 2020 +0200 require that the plugin and sink are in the same toplevel commit 6aae75799ede63bcb24e1441a3f08688e6d77c18 Author: Rasmus Wriedt Larsen Date: Fri Sep 4 13:36:25 2020 +0200 Python: Fix import in type tracking test Fixes 7855576a6 commit fd715a5b66c3cab37dffca7673f3496cdeba4bb0 Merge: 958f89905 4387d106a Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Fri Sep 4 12:20:12 2020 +0100 Merge pull request #4179 from RasmusWL/python-tainttracking-ala-go Approved by tausbn, yoff commit d47c852767acd286d491ddd43f66a5fb246f3ba1 Author: Erik Krogh Kristensen Date: Fri Sep 4 12:44:18 2020 +0200 autoformat commit 958f89905d4acdc76d771ab8fbba76fcf2d72980 Merge: 7a00fbc65 d2a91970f Author: Jonas Jensen Date: Fri Sep 4 12:42:34 2020 +0200 Merge pull request #4197 from github/aeisenberg/devcontainer-settings Update devcontainer memory settings commit cfc91cc5f127880090ad6533a65bc8b8e10cc290 Author: Max Schaefer Date: Fri Sep 4 10:57:21 2020 +0100 JavaScript: Drop "feature" terminology. It turned out to be more confusing than helpful, so we're back with plain old API-graph "nodes". commit 9ed9ecd333156499a16ea84b4c7eb89d118b9a14 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:39 2020 +0200 copied updated dbscheme to upgrade folder commit 6e54cf426c23442838425e9ee050b280aa0ce5ae Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:39 2020 +0200 autoformat commit 5a159abd751fee9363025b4f80525241326dcefb Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:33 2020 +0200 renamed "interfacedefinition" to "interface_definition" commit 3785a10ee8ec51db6a07287ec753a5eb68a6e04f Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:32 2020 +0200 renamed "classdefinition" to "class_definition" commit 5467efe117558490eabcd8bc34a2e24e188f302b Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:31 2020 +0200 renamed "typeassertion" to "type_assertion" commit 4af9508506a675de1087ae8b6df55335f99f87a4 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:30 2020 +0200 renamed "importspecifier" to "import_specifier" commit 35caaf5c93c8b9269f0c9d431bccc9c15bd8eb81 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:30 2020 +0200 renamed "comprehensionblock" to "comprehension_block" commit 273ae710b01209da86026e6c366850647d529976 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:29 2020 +0200 renamed "comprehensionexpr" to "comprehension_expr" commit 586a823ce717b9e863999ed45e8611e59cff42ab Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:28 2020 +0200 renamed "exprparent" to "expr_parent" commit b28cbf310eac4368abed82da73bcfa8cd1c32ed0 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:28 2020 +0200 renamed "typedefinition" to "type_definition" commit bcbd1f045f25da60c1f506b598c07889c6474e3c Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:27 2020 +0200 renamed "namespacedefinition" to "namespace_definition" commit 8c812dcdfb77e20f9f20769b922d616df0f8f1db Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:26 2020 +0200 renamed "exportdeclaration" to "export_declaration" commit 4f8d2156c02111580541e223b3365685272a3e98 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:26 2020 +0200 renamed "declstmt" to "decl_stmt" commit 5e58d34e19217ac4321879da94ec70dd5a9e3dae Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:25 2020 +0200 renamed "exportasnamespacedeclaration" to "export_as_namespace_declaration" commit 723a1b84836168abfffc2c22cabb23cad8c413cc Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:24 2020 +0200 renamed "enumdeclaration" to "enum_declaration" commit 0d5db155e60be307ab6c5d48af98abdb378d1860 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:23 2020 +0200 renamed "typealiasdeclaration" to "type_alias_declaration" commit 232dbe9fd1f0598ab8728d7aac86677398c5b638 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:23 2020 +0200 renamed "interfacedeclaration" to "interface_declaration" commit 7b94cf7d8ebf405ae8bf3feaa3956aecef633cac Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:22 2020 +0200 renamed "doccomment" to "doc_comment" commit 9a66f3a7218baa1c4f1d3b41d0191b7d4c48164a Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:21 2020 +0200 renamed "slashstarcomment" to "slashstar_comment" commit 13a593c7b44776ff0cf712b3156a6e651383d696 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:21 2020 +0200 renamed "slashslashcomment" to "slashslash_comment" commit 132d6d0068244e541194a9af374927d3df95b5fa Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:20 2020 +0200 renamed "htmlcommentstart" to "html_comment_start" commit 6be328b400713c00e3df0453b5435942071e36f1 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:19 2020 +0200 renamed "blockcomment" to "block_comment" commit 03617fe18b2f0c5217a0af1e87a66a325659cc64 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:18 2020 +0200 renamed "linecomment" to "line_comment" commit 136345d745a7e7c1abc103704b8a04dfa1d94626 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:17 2020 +0200 renamed "htmlcomment" to "html_comment" commit db0747876ef9847332154e165d62082a9f178bd6 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:16 2020 +0200 renamed "booleanliteraltype" to "boolean_literal_type" commit 5ea08b9c0cbdafd0145f1d4c5738aaa39a7d3c9d Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:16 2020 +0200 renamed "bigintliteraltype" to "bigint_literal_type" commit a35e0f93069c83bc3565607d6559f955475dced8 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:15 2020 +0200 renamed "biginttype" to "bigint_type" commit 0c0abefe5a436146f7295aba7ed2e8ca8d257529 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:14 2020 +0200 renamed "unknowntype" to "unknown_type" commit 2481775af5a08cc2d1286f18e63a3bdc0e3d9090 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:13 2020 +0200 renamed "stringliteraltype" to "string_literal_type" commit bd3ab9d5997286c25b67229d9f6bb4b68e82b637 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:12 2020 +0200 renamed "numberliteraltype" to "number_literal_type" commit 6f277a7435ce1196508398892fa1c8144e36ec6b Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:11 2020 +0200 renamed "thistype" to "this_type" commit 27540e77b1880f020aab3dcf522e0580dc34c2c4 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:10 2020 +0200 renamed "lexicaltypevariabletype" to "lexical_type_variable_type" commit 9bab197a80299568d21822b92c874640e4a758bc Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:09 2020 +0200 renamed "tupletype" to "tuple_type" commit 38d033644c3fb4288dec6961579431d214241679 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:08 2020 +0200 renamed "intersectiontype" to "intersection_type" commit 2b3e8869c6bc83f23c6c260265b828ba4c0079c5 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:07 2020 +0200 renamed "objectkeywordtype" to "objectkeyword_type" commit 174afbc0df56e1e987d640e2c57279d63cb12042 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:06 2020 +0200 renamed "uniquesymboltype" to "unique_symbol_type" commit a1daf0a428223d074d89afaa50a73c6dd6a798e4 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:06 2020 +0200 renamed "plainsymboltype" to "plain_symbol_type" commit b1812b1be2da6cce7196e75fb0a986098c6f9b1c Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:05 2020 +0200 renamed "nevertype" to "never_type" commit 8b2769953f9ce7e5c0d50b82b17d0c5ba3eba326 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:04 2020 +0200 renamed "nulltype" to "null_type" commit 1891a3fb4963c29d1a56af9b5889dd4a6e1a9d84 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:03 2020 +0200 renamed "undefinedtype" to "undefined_type" commit d95fc64f87496bba46bf444a65887c1375ace65e Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:02 2020 +0200 renamed "voidtype" to "void_type" commit 37bdea4011613d858a4cc4868ba35c1f17b7b772 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:01 2020 +0200 renamed "typeoftype" to "typeof_type" commit 11214b574efbee1e0e6bbb0e51b697d91e68bd55 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:55:00 2020 +0200 renamed "canonicaltypevariabletype" to "canonical_type_variable_type" commit 1d9dd92389a8d086d0b19a961df4bfae2e6a4e67 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:59 2020 +0200 renamed "objecttype" to "object_type" commit b72daf6559f29898c5835fa57f498ffd8c38c309 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:58 2020 +0200 renamed "typereference" to "type_reference" commit 01e3888c365777e47272b1ee42fd3850066e2278 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:57 2020 +0200 renamed "falsetype" to "false_type" commit b3c3069c24eb999d5894c72e8a54d8a582302c21 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:57 2020 +0200 renamed "truetype" to "true_type" commit 2a7b6310ad52f989fc1c788fc93096b37d4c1264 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:56 2020 +0200 renamed "uniontype" to "union_type" commit 0475e9e93c0dd62079ab1e39de618ecf00bf8d45 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:55 2020 +0200 renamed "numbertype" to "number_type" commit e0880c8cb17963e0baa0591981f2ad44d18e1f76 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:55 2020 +0200 renamed "stringtype" to "string_type" commit 579d4e0d75e3e4aa84775431973738a94a6b83c8 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:54 2020 +0200 renamed "anytype" to "any_type" commit 62afd50d71010644f94e37f31b2cc017cfc3fd4a Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:53 2020 +0200 renamed "typeidentifier" to "type_identifier" commit e2e10c3a75d52548431b0ed64423fd51be7f03e6 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:52 2020 +0200 renamed "conditionaltypescope" to "conditional_type_scope" commit 3553fe8ed8bad5fc560a0a458b0eb16b4df61907 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:52 2020 +0200 renamed "externalmodulescope" to "external_module_scope" commit 602f627e140526aa1f3b38028bc973d94a5d7934 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:51 2020 +0200 renamed "enumscope" to "enum_scope" commit 4fe2b9dcdaa37480eb63f15365388b63b45fbaed Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:50 2020 +0200 renamed "mappedtypescope" to "mapped_type_scope" commit 8b09f1dcb2c219f757c652dec12a7ad9d5ced3d3 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:50 2020 +0200 renamed "typealiasscope" to "type_alias_scope" commit f76329c9e3030b930f4932fa86a64d19cfc2fb67 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:49 2020 +0200 renamed "interfacescope" to "interface_scope" commit 24f0b20c3a1ae737db61635684944de2be086045 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:48 2020 +0200 renamed "classdeclscope" to "class_decl_scope" commit 07cef9ec3688e1ed4008be7f71a69aaa7dcbd0e1 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:47 2020 +0200 renamed "namespacescope" to "namespace_scope" commit 345b1ee1885cc07eac2d933c58bfe46a703fe205 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:47 2020 +0200 renamed "classexprscope" to "class_expr_scope" commit 8370573df02b97da948af1c4e8dee06f17239755 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:46 2020 +0200 renamed "comprehensionblockscope" to "comprehension_block_scope" commit 9be0740b934bcc3adeb316adfeec6401f8b7f0ba Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:45 2020 +0200 renamed "forinscope" to "for_in_scope" commit 310f9708eae4a61fcc90180e4c1c7b885e4251ae Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:44 2020 +0200 renamed "forscope" to "for_scope" commit a45103d07d11feccd62d6a57714a1399ed2fc48c Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:44 2020 +0200 renamed "blockscope" to "block_scope" commit 93aa812744b2a4eb52fda84f035d032c7e739a26 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:43 2020 +0200 renamed "modulescope" to "module_scope" commit 5f06bf05bd8b483288210b2d8d7d9c0003913de6 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:42 2020 +0200 renamed "catchscope" to "catch_scope" commit a8719634819399d79ab0bb7b9a6ef41d8434465c Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:41 2020 +0200 renamed "functionscope" to "function_scope" commit 1341f4beb430548827639f69b4a979b0186fea33 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:41 2020 +0200 renamed "globalscope" to "global_scope" commit 05e0d1a02dbee92d81b1db28b8c84cefd4d0f922 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:40 2020 +0200 renamed "importmetaexpr" to "import_meta_expr" commit ef5e1b0862ebb85899312b9f328eb78ab907c65f Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:39 2020 +0200 renamed "nullishcoalescingexpr" to "nullishcoalescing_expr" commit b2f28cab272e985f5fdcdb2a139f98876d2af48f Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:38 2020 +0200 renamed "bigintliteral" to "bigint_literal" commit 56c440b57716d974fcfc0fd68cb0388cbe6d4b71 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:37 2020 +0200 renamed "astypeassertion" to "as_type_assertion" commit ccdfe25f888475e3b551ad44ae8b68074ff58e27 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:37 2020 +0200 renamed "prefixtypeassertion" to "prefix_type_assertion" commit 27a017671dde94fa0378b7495c2dad807c18ad88 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:36 2020 +0200 renamed "dynamicimport" to "dynamic_import" commit 94b5645de214cddcbf411001f2470013210f2850 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:35 2020 +0200 renamed "externalmodulereference" to "external_module_reference" commit dec030558a10a804a0d004df7f60a064ccf5b1f9 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:35 2020 +0200 renamed "bindexpr" to "bind_expr" commit 1fa3e4d2f12a32d13daa7235445a91267aa77d7d Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:34 2020 +0200 renamed "exportnamespacespecifier" to "export_namespace_specifier" commit 004ea10f2ccc797933a9df9469dac3e343bb1820 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:33 2020 +0200 renamed "exportdefaultspecifier" to "export_default_specifier" commit 4b99d056d216ad726b30507ddd552291b53bc347 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:32 2020 +0200 renamed "functionsentexpr" to "function_sent_expr" commit 45e6797a275e462ad4c4ba06fc1f61caa7818d32 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:32 2020 +0200 renamed "awaitexpr" to "await_expr" commit 0785b9b81dc9ae0fdfa9e4f1024da509082d7aec Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:31 2020 +0200 renamed "jsxelement" to "jsx_element" commit cdc97bf1f408af0a60dbb3b9b71ef91466d5b015 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:30 2020 +0200 renamed "assignexpexpr" to "assign_exp_expr" commit 5d06fe37e72c55696f053e2b9c2fa96443161707 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:29 2020 +0200 renamed "expexpr" to "exp_expr" commit 144c064e9399619e0ecaa6231e37b72af350d44c Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:29 2020 +0200 renamed "namedexportspecifier" to "named_export_specifier" commit 0cf6cca676a3479921bbfad30e5eceea9ca8e2ef Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:28 2020 +0200 renamed "importnamespacespecifier" to "import_namespace_specifier" commit bc287ba4720312262d3013e9922b418eb12f99a0 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:27 2020 +0200 renamed "importdefaultspecifier" to "import_default_specifier" commit ae32211080461247f4ce6980166543694fbb7530 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:27 2020 +0200 renamed "namedimportspecifier" to "named_import_specifier" commit 2e0d886d2b2228e4893d394abb9ba84aa453c2fd Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:26 2020 +0200 renamed "newtargetexpr" to "newtarget_expr" commit a3f2c8f234493c260bb03a1168995c74af097ec8 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:25 2020 +0200 renamed "superexpr" to "super_expr" commit 2efb2a2392b0e8b5ffacce91aedfdd596f943e21 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:24 2020 +0200 renamed "classexpr" to "class_expr" commit b34a471235f2d0267c9924450be37c39465205ff Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:24 2020 +0200 renamed "vardecl" to "var_decl" commit fa14369816e4277968a110281855abd4ac784496 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:23 2020 +0200 renamed "forofcomprehensionblock" to "for_of_comprehension_block" commit 013b7f19b9ea2ea3b1102e76eeee52090bdd9785 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:22 2020 +0200 renamed "forincomprehensionblock" to "for_in_comprehension_block" commit e8ceed247bbb3f936b01dade8658fb0953a32d56 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:21 2020 +0200 renamed "generatorexpr" to "generator_expr" commit 840bd90c0290ec9164bb2b7ba45c245a644d7e26 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:20 2020 +0200 renamed "arraycomprehensionexpr" to "array_comprehension_expr" commit cd879a6445acd05444e1782e649c0b70a2d868f2 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:20 2020 +0200 renamed "templateelement" to "template_element" commit 2edf0b248bd38971e369fd4e1c89392782966f22 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:19 2020 +0200 renamed "templateliteral" to "template_literal" commit 16a79a2f036a37dc5fa8d775b44e7ada57952415 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:18 2020 +0200 renamed "taggedtemplateexpr" to "tagged_template_expr" commit 63728196840ba1efb303a2c788583aab1dc8d11a Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:17 2020 +0200 renamed "yieldexpr" to "yield_expr" commit a4b2c9a1149e0150a5bbece11a7b97acfe3bad79 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:17 2020 +0200 renamed "objectpattern" to "object_pattern" commit 79a8dcada3aeb5e83c766fc2f7c7246bbc127424 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:16 2020 +0200 renamed "arraypattern" to "array_pattern" commit fdd25ef5f8aaa09a8ea38680eb8eeb7ba40838ff Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:15 2020 +0200 renamed "spreadelement" to "spread_element" commit 7944ab23243e389a0af9d8de5bbc8ac63acf18e5 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:14 2020 +0200 renamed "vardeclarator" to "var_declarator" commit 5d47248878d7d004b08f7a8f8f7caac23d10cecf Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:14 2020 +0200 renamed "parexpr" to "par_expr" commit fb7b0eb6293b660abddaa1fd2ab2726f2fd5c4e8 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:13 2020 +0200 renamed "postdecexpr" to "postdec_expr" commit 68d6b3f236528e652d39d3c83a79a10ea534c023 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:12 2020 +0200 renamed "predecexpr" to "predec_expr" commit ff70caf2a0fad26699e50759e8b78df686681372 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:11 2020 +0200 renamed "postincexpr" to "postinc_expr" commit bb8a8eeb771f3dc957ade6a9527e2cd32ed8f68a Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:11 2020 +0200 renamed "preincexpr" to "preinc_expr" commit 7a1c751062fd01641ec7423688b33aa3a89a6156 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:10 2020 +0200 renamed "assignandexpr" to "assign_and_expr" commit 01b0a53d4883779ef1b9089c2a72176e7de9594b Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:09 2020 +0200 renamed "assignxorexpr" to "assign_xor_expr" commit 8a5a25bdc3c7fefc30a805dd8e71670bfe72b887 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:08 2020 +0200 renamed "assignorexpr" to "assign_or_expr" commit 0cece7f7d70e09a41af97a435e5d888b80e468f3 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:08 2020 +0200 renamed "assignurshiftexpr" to "assign_urshift_expr" commit f0fc6b3d7a12c7774292376f77c4672d7fee934c Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:07 2020 +0200 renamed "assignrshiftexpr" to "assign_rshift_expr" commit dae29372cff2f96780bbfadb58295be306a1e116 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:06 2020 +0200 renamed "assignlshiftexpr" to "assign_lshift_expr" commit 7e05a721f8799a6e00dc5172dbcb195b1068410a Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:05 2020 +0200 renamed "assignmodexpr" to "assign_mod_expr" commit a9eefac985532066026c6f5ffdff5b5af27f3c5d Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:04 2020 +0200 renamed "assigndivexpr" to "assign_div_expr" commit aadee91def3fe52dc65894365f950dd6ba0d7b6b Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:03 2020 +0200 renamed "assignmulexpr" to "assign_mul_expr" commit e9e7097edbd03c8b1aec913d1a67e596ee2b5229 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:02 2020 +0200 renamed "assignsubexpr" to "assign_sub_expr" commit 1833464d2397b87c050010436743006a69b01a43 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:01 2020 +0200 renamed "assignaddexpr" to "assign_add_expr" commit f32c89b652ff80470f4db4d368a487339016a08a Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:01 2020 +0200 renamed "assignexpr" to "assign_expr" commit 10a412175d40290e9e15fb41c9e46cee460dc460 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:54:00 2020 +0200 renamed "logorexpr" to "logor_expr" commit cabe2af8e3f85e3ad6d49290582a7cedfeae660e Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:59 2020 +0200 renamed "logandexpr" to "logand_expr" commit ae4593f9421a57865b395abfef48583e3bcc880f Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:58 2020 +0200 renamed "instanceofexpr" to "instanceof_expr" commit 416d2bd6098e12e598998060c2a6abac863669a8 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:57 2020 +0200 renamed "inexpr" to "in_expr" commit 006ba2e0bf69ca543a3d63bbe0cc9ac920d370b6 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:57 2020 +0200 renamed "bitandexpr" to "bitand_expr" commit b0fce918c6fcfbbce96452eb8f50e4dc738b8448 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:56 2020 +0200 renamed "xorexpr" to "xor_expr" commit c0a8e3ff90b5064c4f5e0ba3f9025e0a8c936ac9 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:55 2020 +0200 renamed "bitorexpr" to "bitor_expr" commit 335406d2123f92107db95fb09aaa7e276b95ae25 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:55 2020 +0200 renamed "modexpr" to "mod_expr" commit a0b75a36062b7781ae54e78251e3316ef609256f Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:54 2020 +0200 renamed "divexpr" to "div_expr" commit df85a37f6e2d3ddc11a5c6bcd8e232fe1955abcb Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:53 2020 +0200 renamed "mulexpr" to "mul_expr" commit 3d03974d8ed30160d5031ace90054ffd18bee336 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:52 2020 +0200 renamed "subexpr" to "sub_expr" commit 3af0cad6aa2ef09bd3ab9e532b20f5f4d2575b29 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:52 2020 +0200 renamed "addexpr" to "add_expr" commit 11f7fabba8b6c2da9daef49ffc85fe2299bc6d26 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:51 2020 +0200 renamed "urshiftexpr" to "urshift_expr" commit 6b38ed0e1e67e46b949457af22430babdda2e731 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:50 2020 +0200 renamed "rshiftexpr" to "rshift_expr" commit b7c441e514ae39eb16c55ea59b4a71d06326816a Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:49 2020 +0200 renamed "lshiftexpr" to "lshift_expr" commit 1f07e6afc10d2f23164299674c78cb310f63abb0 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:49 2020 +0200 renamed "geexpr" to "ge_expr" commit 4b625e7ac77a815f04a4f5c4eea204e2c437eb10 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:48 2020 +0200 renamed "gtexpr" to "gt_expr" commit ce0eabf9988a44068d735a5be5ffea272afadf27 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:47 2020 +0200 renamed "leexpr" to "le_expr" commit 2744a37dbbd6db8097ff4558b806a016fd181f2c Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:46 2020 +0200 renamed "ltexpr" to "lt_expr" commit 17705100d4a675947d5327f76ed6525bbf8e1822 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:46 2020 +0200 renamed "neqqexpr" to "neqq_expr" commit c634f274eee7fe07ea41bc00ff05a5cc24a069ff Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:45 2020 +0200 renamed "eqqexpr" to "eqq_expr" commit 428e599cd290e4cb5fb0c1048d329368775d78e5 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:44 2020 +0200 renamed "neqexpr" to "neq_expr" commit 51abeebb6696fdbdd9b5a43e2c9d1be703df0731 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:43 2020 +0200 renamed "eqexpr" to "eq_expr" commit 3b1f3f85bb994cda4ec17c4852cc6cfa95400f4f Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:43 2020 +0200 renamed "deleteexpr" to "delete_expr" commit 82c049c713bffa65c89d3838e9971514ded22a53 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:42 2020 +0200 renamed "voidexpr" to "void_expr" commit f4c171944093442ad734dd2e08eddcc9e853d8ed Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:41 2020 +0200 renamed "typeofexpr" to "typeof_expr" commit 5dfbcdc32cf5b44c0569ffecd8a07e99f396ebf1 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:40 2020 +0200 renamed "bitnotexpr" to "bit_not_expr" commit d1f9d03d2c42a08a05d2b542e2285d5b22ea658a Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:40 2020 +0200 renamed "lognotexpr" to "log_not_expr" commit 7752eabccb9f2a725a5516e9787935e5ff60c271 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:39 2020 +0200 renamed "plusexpr" to "plus_expr" commit 3604535270126b968c5cd7e9f2e40c7702b7cd51 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:38 2020 +0200 renamed "negexpr" to "neg_expr" commit e7ef9929443d7f0ed27447a31a72dac5436e43de Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:37 2020 +0200 renamed "indexexpr" to "index_expr" commit 6c47f7eaba4a21d489f12180888745b99be53e24 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:37 2020 +0200 renamed "dotexpr" to "dot_expr" commit f5e40ac727ab0136ab939ad3b96ef30a5da30c9c Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:36 2020 +0200 renamed "callexpr" to "call_expr" commit 3e8f9a15497f0193381b101b79b482a06d8be4db Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:35 2020 +0200 renamed "newexpr" to "new_expr" commit d58ae720726f8a871d545f8be7321f5f5fcfb89f Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:34 2020 +0200 renamed "conditionalexpr" to "conditional_expr" commit 4c8245036e28f17cef8b6a366264980a9100b373 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:34 2020 +0200 renamed "seqexpr" to "seq_expr" commit 05fbb2902ef37f13123013c8ee0dc68109ec753a Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:33 2020 +0200 renamed "objexpr" to "obj_expr" commit 7317ee9992e519653a4d3a5cfb9e3fd1f8c1394a Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:32 2020 +0200 renamed "arrayexpr" to "array_expr" commit 29b03aebd91678eccae4a2f4323076ece3e946eb Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:32 2020 +0200 renamed "thisexpr" to "this_expr" commit fa8ae793f21bb98c2c7c7cd50888153dc72f6481 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:31 2020 +0200 renamed "regexpliteral" to "regexp_literal" commit 91c3e51503281851b853af936d99892de303e8e3 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:30 2020 +0200 renamed "stringliteral" to "string_literal" commit 960576438c72599efee30253d95ba2e275182bfa Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:29 2020 +0200 renamed "numberliteral" to "number_literal" commit f212e85426631f2edf9f7749b04edd1cf240fba9 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:29 2020 +0200 renamed "booleanliteral" to "boolean_literal" commit 6beaec0c71962d28a2861e79e4b76b7f162347c7 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:28 2020 +0200 renamed "nullliteral" to "null_literal" commit 612e12c5a543012ea7fab2ea5e459ea9ce7b7663 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:27 2020 +0200 renamed "exportassigndeclaration" to "export_assign_declaration" commit 3c04b4982c515921c16517aeda6fcb12801997e7 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:26 2020 +0200 renamed "importequalsdeclaration" to "import_equals_declaration" commit ec1f538503df1ca837a84689073c18030d2ceb4c Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:26 2020 +0200 renamed "exportnameddeclaration" to "export_named_declaration" commit 8eacd32f8e5fd88f722335f175e0a163120600e1 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:25 2020 +0200 renamed "exportdefaultdeclaration" to "export_default_declaration" commit 5c3b69f323e4421d58e8c5c32f390426f5e42180 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:24 2020 +0200 renamed "exportalldeclaration" to "export_all_declaration" commit bdfeecdee16373d00e94445acaee9058439e3274 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:23 2020 +0200 renamed "importdeclaration" to "import_declaration" commit 1da70213402e4a99f6de11936010d1f753d7b59b Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:23 2020 +0200 renamed "classdeclstmt" to "class_decl_stmt" commit 893b743b579f659c7b68ee20065e46bd51796186 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:22 2020 +0200 renamed "foreachstmt" to "for_each_stmt" commit 442d3e5f7032572f172d12d24fddbc8651058929 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:21 2020 +0200 renamed "legacy_letstmt" to "legacy_let_stmt" commit 945e2c7fe05c2e1faa3f581681887d78bc58b034 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:20 2020 +0200 renamed "letstmt" to "let_stmt" commit 38c902f43be9dc4fcad66536a2e54f063fd51d42 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:19 2020 +0200 renamed "constdeclstmt" to "const_decl_stmt" commit 231583a3f86d7d74d1e0bc0a0bbbd6e97c118bf7 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:19 2020 +0200 renamed "forofstmt" to "for_of_stmt" commit c56746929d9c94cb3f3c581b4480a9e719388adc Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:18 2020 +0200 renamed "catchclause" to "catch_clause" commit d0e4748defbe1d96d5311bfde539288fd76785d5 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:17 2020 +0200 renamed "vardeclstmt" to "var_decl_stmt" commit 6f667a6e826c427b24f26780830c8aa6eb3a3bcb Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:16 2020 +0200 renamed "functiondeclstmt" to "function_decl_stmt" commit 3ef8fb72cd17f95041ac8e379b557782cc330b73 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:16 2020 +0200 renamed "debuggerstmt" to "debugger_stmt" commit 454893d23435a5901dd241581c1ce16e5c09dd20 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:15 2020 +0200 renamed "forinstmt" to "for_in_stmt" commit 712a6dfccd019648cb2c6cff00e620f4aec1aa8d Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:14 2020 +0200 renamed "forstmt" to "for_stmt" commit 4c24e2d8bac337242368ef276a0432e54b357e15 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:13 2020 +0200 renamed "dowhilestmt" to "do_while_stmt" commit ed585de1a0cd5534196c8a02f5db9bf060a633c2 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:13 2020 +0200 renamed "whilestmt" to "while_stmt" commit f749d46fe86cdd11aa734e2fd4b2e353b7eff31e Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:12 2020 +0200 renamed "trystmt" to "try_stmt" commit 4762c9eac8f37e93d1508207191a9014c1a669ba Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:11 2020 +0200 renamed "throwstmt" to "throw_stmt" commit 5e2c25eacd809b6a246308e8f003629c0653a3eb Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:10 2020 +0200 renamed "returnstmt" to "return_stmt" commit b3746efec8462ed7a3982351b2b74fe40797e074 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:10 2020 +0200 renamed "switchstmt" to "switch_stmt" commit 3f47afa5959f92477fd5ad06d56a95a51b398463 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:09 2020 +0200 renamed "withstmt" to "with_stmt" commit 569c5f19cbb9ad4251338baa98dbb553234315b1 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:08 2020 +0200 renamed "continuestmt" to "continue_stmt" commit 4a44f0ee23ebe66df57175e4842f1d6d88ba8ec9 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:07 2020 +0200 renamed "breakstmt" to "break_stmt" commit ded939468ecb338157335b0ef2731a9deb994bf5 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:07 2020 +0200 renamed "labeledstmt" to "labeled_stmt" commit 90b45c405201367158ae877e74e157b9927a797c Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:06 2020 +0200 renamed "ifstmt" to "if_stmt" commit a752ef79a208925311fd4b95f029bccfd62b313e Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:05 2020 +0200 renamed "exprstmt" to "expr_stmt" commit 03c8eb87d285c5e3385708063c938e7953931930 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:04 2020 +0200 renamed "blockstmt" to "block_stmt" commit 54edbca268d757ae918d73fff3afcda16394b8d0 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:04 2020 +0200 renamed "emptystmt" to "empty_stmt" commit fe121fb2bae36d34d413909cf4d25064747ff323 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:03 2020 +0200 renamed "globalaugmentationdeclaration" to "global_augmentation_declaration" commit b4ccf4eb60c30a9e38b15df5ea99ec9a626390bd Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:02 2020 +0200 renamed "externalmoduledeclaration" to "external_module_declaration" commit f7cce51152a853221b66c55671dfe666b516c6d6 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:01 2020 +0200 renamed "namespacedeclaration" to "namespace_declaration" commit 5f9ae889e09f2e8382fde2afc4150bf81fb44363 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:53:00 2020 +0200 renamed "functionexpr" to "function_expr" commit 868214dfff349a9ae01ad3bfe82e2144f10cc32f Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:59 2020 +0200 renamed "arrowfunctionexpr" to "arrow_function_expr" commit 42084b55cc77cd7d292448f9a8988ef8303945ec Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:58 2020 +0200 renamed "stmtparent" to "stmt_parent" commit 05deebbe9ebc546c46b6b5c60f1f6a7a2c65654a Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:58 2020 +0200 renamed "jsxemptyexpr" to "jsx_empty_expr" commit e5e8951b2056e8d8075000f5b80180e35eb8ac14 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:57 2020 +0200 renamed "expressionwithtypearguments" to "expression_with_type_arguments" commit 334bbd83a890e4c41b19d906636f4f713494b6c6 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:56 2020 +0200 renamed "jsxqualifiedname" to "jsx_qualified_name" commit 61cf752e67f5c9790502e33b4920f737db73cbb3 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:55 2020 +0200 renamed "equalitytest" to "equality_test" commit 7bff2a18f0482774ddcae47ac99f51f2a50fd4dc Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:55 2020 +0200 renamed "declarablenode" to "declarable_node" commit 1a979f52ab8fafac9bda594c1b308d641c677007 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:54 2020 +0200 renamed "classorinterface" to "class_or_interface" commit 5efa551c803d0d191915514f41c723d7b9b537ce Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:53 2020 +0200 renamed "literaltype" to "literal_type" commit 906865b0572d737453e8d6ee0bd84014b8b615d3 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:52 2020 +0200 renamed "typevariabletype" to "typevariable_type" commit fea92773bd7b5d42ec3c46adf339521f6dd44716 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:51 2020 +0200 renamed "unionorintersectiontype" to "union_or_intersection_type" commit 5355e23c1ad61cec66e7dc26b937794cd8e7bb63 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:51 2020 +0200 renamed "symboltype" to "symbol_type" commit cdcf9e87fd27418c3b5774c3644134b6961ed7d8 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:50 2020 +0200 renamed "functiontypeexpr" to "function_typeexpr" commit 910b328022660768a9087bc542a9ef417dd7d945 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:49 2020 +0200 renamed "importtypeexpr" to "import_typeexpr" commit 95aa5a171aa3cb5cdb5987179f640cb28a9a54f3 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:48 2020 +0200 renamed "namespaceaccess" to "namespace_access" commit a7bfca6fea4a0789b3123ca91366811e7492aebb Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:47 2020 +0200 renamed "literaltypeexpr" to "literal_typeexpr" commit a46f1cd0702ded4e90e62d8d7f50ecb37516dc5c Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:46 2020 +0200 renamed "readonlytypeexpr" to "readonly_typeexpr" commit 28fc1d8267c73e0960f308dcdd70ed6762a5a190 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:45 2020 +0200 renamed "bigintliteraltypeexpr" to "bigint_literal_typeexpr" commit bb78c3e7594f239af5edbc6a622ef14137e57d30 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:45 2020 +0200 renamed "resttypeexpr" to "rest_typeexpr" commit 584901e8af89a5710aacf1154d1844f9951c095f Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:44 2020 +0200 renamed "optionaltypeexpr" to "optional_typeexpr" commit f784579c4b5b0a30e046885aa6a94097d62bc169 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:43 2020 +0200 renamed "importvartypeaccess" to "import_var_type_access" commit cb0080ab075164508fd1bd55acb86011b8359fd2 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:42 2020 +0200 renamed "importnamespaceaccess" to "import_namespace_access" commit fe4f3d3656ceb47a0d79b11d52af5190880d5a75 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:42 2020 +0200 renamed "importtypeaccess" to "import_type_access" commit 27af8f0a42a74df9f4848c14a2790fec6de71616 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:41 2020 +0200 renamed "infertypeexpr" to "infer_typeexpr" commit a04f99b24dc6ff2db197bc0b3c07c1e3040c5afc Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:40 2020 +0200 renamed "conditionaltypeexpr" to "conditional_typeexpr" commit 8ca7f3aa5c11e41c5726edb25da05c66c36d6ac0 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:40 2020 +0200 renamed "mappedtypeexpr" to "mapped_typeexpr" commit 9535fb404568a74ec4102be85cf56eb03523580d Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:39 2020 +0200 renamed "qualifiednamespaceaccess" to "qualified_namespace_access" commit a88d52086613d86388bfb2069121cd4c70080eb1 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:38 2020 +0200 renamed "localnamespaceaccess" to "local_namespace_access" commit d91ba5ac54913c00d4edcb8de3d9e0b3d039890c Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:37 2020 +0200 renamed "constructortypeexpr" to "constructor_typeexpr" commit bdb08156b457428b364d69f3f86b3fbf7f425226 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:37 2020 +0200 renamed "plainfunctiontypeexpr" to "plain_function_typeexpr" commit 7dd107c2be4774a8d11e53f9290f214637ec4cf6 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:36 2020 +0200 renamed "typeparameter" to "type_parameter" commit b3fa43ab1d4f2d1d9f9988afdfb4984c4530866d Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:35 2020 +0200 renamed "interfacetypeexpr" to "interface_typeexpr" commit 8ee4f79727f4d27ef81a07eb83934bc97f258882 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:34 2020 +0200 renamed "predicatetypeexpr" to "predicate_typeexpr" commit 224290c861212f7bc10bc6849f790e9fc6c9dbfb Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:33 2020 +0200 renamed "thisvartypeaccess" to "this_var_type_access" commit 0e4ff336525afa35b988ee1030afa079f58940c3 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:33 2020 +0200 renamed "qualifiedvartypeaccess" to "qualified_var_type_access" commit 0f02263d835c8f98d8496cb407b77f2575b35bcd Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:32 2020 +0200 renamed "localvartypeaccess" to "local_var_type_access" commit ac4a2ae6e0ba71d6654c478c70518ad866346b01 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:31 2020 +0200 renamed "typeoftypeexpr" to "typeof_typeexpr" commit 2b2fb83cdc20ea5f8257ba3cda26f1485f4cbe63 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:30 2020 +0200 renamed "typelabel" to "type_label" commit 2ba01ec13ce570767ac328fc80ee00b4b526abbe Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:30 2020 +0200 renamed "generictypeexpr" to "generic_typeexpr" commit 3caf5c925823c7f21e2b6a1af7ed522f27e58670 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:29 2020 +0200 renamed "qualifiedtypeaccess" to "qualified_type_access" commit af569397038eb702da9ceba14252d3ae880544b7 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:28 2020 +0200 renamed "keyoftypeexpr" to "keyof_typeexpr" commit 30500fcf9bf391f4d0a43bf3228b42f43ce16c06 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:27 2020 +0200 renamed "tupletypeexpr" to "tuple_typeexpr" commit 3591c22d823433177023e5fa13db85f57800c05d Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:26 2020 +0200 renamed "parenthesizedtypeexpr" to "parenthesized_typeexpr" commit 36e76c1146c5ddafbd1e8684dc00a13e1f86da65 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:26 2020 +0200 renamed "intersectiontypeexpr" to "intersection_typeexpr" commit 0c1b1fd8361578766a4ce90f4e11c47d8735609a Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:25 2020 +0200 renamed "indexedaccesstypeexpr" to "indexed_access_typeexpr" commit 52c6ce057d640e61208fca6ddf5550574c7e9ac1 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:24 2020 +0200 renamed "uniontypeexpr" to "union_typeexpr" commit 2b822a56ff2562e487537e7016bb1667a8fdcd4c Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:23 2020 +0200 renamed "arraytypeexpr" to "array_typeexpr" commit 8b7d37ef9d26c4cee36565f8d78e3a31ad12b414 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:23 2020 +0200 renamed "booleanliteraltypeexpr" to "boolean_literal_typeexpr" commit 31d66dd1cd17b29ffb5673389d0f79489285928b Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:22 2020 +0200 renamed "numberliteraltypeexpr" to "number_literal_typeexpr" commit d72dd3253e83d39de4653b6927abe1c8ac4a4e2f Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:21 2020 +0200 renamed "stringliteraltypeexpr" to "string_literal_typeexpr" commit d6391b48304527f68eee91bbd528933648af2c0e Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:20 2020 +0200 renamed "keywordtypeexpr" to "keyword_typeexpr" commit edae1a7ad393c22c6a89ee56ca0e760517ea0deb Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:19 2020 +0200 renamed "typedecl" to "type_decl" commit 54bd914477afc695640fca7629a7a1a28129d5ba Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:19 2020 +0200 renamed "localtypeaccess" to "local_type_access" commit 81909b58dc9bbd3bf4e86f2f3e81256b0126c459 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:18 2020 +0200 renamed "exprortype" to "expr_or_type" commit d7553461b0ff74f17c3485c79f0370678f34f3ba Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:17 2020 +0200 renamed "exprorstmt" to "expr_or_stmt" commit 22bce641b7f92f6e6470a1a57ab2fcbc5da81242 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:16 2020 +0200 renamed "isAsync" to "is_async" commit ba645b555f47c42087b8abd35bfc3e0ae082306d Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:15 2020 +0200 renamed "hasRestParameter" to "has_rest_parameter" commit b3f7c26669c0d0aae49587ba7ded05f0c2c0de24 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:14 2020 +0200 renamed "isGenerator" to "is_generator" commit a57f93b41ef829da65920606fddcf156b28d2bc7 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:13 2020 +0200 renamed "unicodePropertyEscapeValue" to "unicode_property_escapevalue" commit 3ed310fb7b6bec39ca34ad59b71f67136fc2d6da Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:12 2020 +0200 renamed "unicodePropertyEscapeName" to "unicode_property_escapename" commit acc13ddd04e79119fe1f748573b1a77bf1bbbb54 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:12 2020 +0200 renamed "namedBackref" to "named_backref" commit 23127cb4af11ed25e2f96e62869198ccb14a4ab2 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:11 2020 +0200 renamed "charClassEscape" to "char_class_escape" commit 21733afc3245fc6d516ea74a426353831f4a67a3 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:10 2020 +0200 renamed "regexpConstValue" to "regexp_const_value" commit 9a1a439c76579e86a55a4dd99c7632f281111800 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:09 2020 +0200 renamed "isInverted" to "is_inverted" commit fbcd3dd89343c600cd9d633ee351259066e777a3 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:08 2020 +0200 renamed "isNamedCapture" to "is_named_capture" commit 2dc9022aa6a544286de57bfa1039b208c505afff Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:08 2020 +0200 renamed "isCapture" to "is_capture" commit 35b5b660c5e51c75a9d5f57c25d3d8c819f4baf2 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:07 2020 +0200 renamed "rangeQuantifierUpperBound" to "range_quantifier_upper_bound" commit defbee2567e425f523f5609eacebb5ab38db19fa Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:06 2020 +0200 renamed "rangeQuantifierLowerBound" to "range_quantifier_lower_bound" commit 0962af51d2f0f716fa45843c2d80f006959a5c03 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:05 2020 +0200 renamed "isGreedy" to "is_greedy" commit 37432232b8d049c45561ef41475dddfb68732e0f Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:05 2020 +0200 renamed "regexpParseErrors" to "regexp_parse_errors" commit fdb615fb9162d4deae5d36f1d8249f46a117bee6 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:04 2020 +0200 renamed "jsParseErrors" to "js_parse_errors" commit b5d6cbd5b3d7fd168eaf2e4d142a79bf41ff63f6 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:03 2020 +0200 renamed "hasAssertsKeyword" to "has_asserts_keyword" commit fc7f02414724a7d1b85315aa01315b4013bd1a99 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:02 2020 +0200 renamed "isOptionalParameterDeclaration" to "is_optional_parameter_declaration" commit 3f3b4d65bda3ac387ac075f55ecdb585e3479325 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:01 2020 +0200 renamed "hasDefiniteAssignmentAssertion" to "has_definite_assignment_assertion" commit 8ae48bbf8b4c8876998bc346977b39c37a72f20b Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:01 2020 +0200 renamed "isOptionalMember" to "is_optional_member" commit 8c969f0539b8f8b43b63bb6c5d460806b72e14bf Author: Erik Krogh Kristensen Date: Fri Sep 4 11:52:00 2020 +0200 renamed "hasTypeKeyword" to "has_type_keyword" commit 007447b0ad1546d19bbfc922c6a9a05fb8df9e4e Author: Erik Krogh Kristensen Date: Fri Sep 4 11:51:59 2020 +0200 renamed "hasReadonlyKeyword" to "has_readonly_keyword" commit 4b74c1d4b3ab4bb1a9e600bdb3a554b7cd5d0368 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:51:58 2020 +0200 renamed "hasProtectedKeyword" to "has_protected_keyword" commit 719c0d2030f295b19ea01dcbbd7d992eb1cee603 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:51:58 2020 +0200 renamed "hasPrivateKeyword" to "has_private_keyword" commit 82ddbc3b47211b871e97d573ccb7ff5cf59c65dd Author: Erik Krogh Kristensen Date: Fri Sep 4 11:51:57 2020 +0200 renamed "hasPublicKeyword" to "has_public_keyword" commit 29e5bdb4d70ef26772d9c97d593f2fdc2dbc0422 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:51:56 2020 +0200 renamed "isAbstractClass" to "is_abstract_class" commit a0afcaa3a8676da5aeb95ce4661781254945a750 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:51:55 2020 +0200 renamed "isConstEnum" to "is_const_enum" commit ac345fbecdd0b2872bc042064602af1ac438ccea Author: Erik Krogh Kristensen Date: Fri Sep 4 11:51:54 2020 +0200 renamed "isAbstractMember" to "is_abstract_member" commit 2c3b3e7173e6d27544b586c94a39703f325aa5db Author: Erik Krogh Kristensen Date: Fri Sep 4 11:51:54 2020 +0200 renamed "isStatic" to "is_static" commit 10439fb5226a681e7865368e1ae7b57bcc563357 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:51:53 2020 +0200 renamed "isMethod" to "is_method" commit 6382f6d202779208cc5c4225ab99f5324bf6f96a Author: Erik Krogh Kristensen Date: Fri Sep 4 11:51:52 2020 +0200 renamed "isComputed" to "is_computed" commit 2204b1e92d6f8da2a685a5a7c4e51d6f308f09fd Author: Erik Krogh Kristensen Date: Fri Sep 4 11:51:51 2020 +0200 renamed "isArgumentsObject" to "is_arguments_object" commit 3fb561d72beaf62dc5a7c75da13cdf9d6f88c49b Author: Erik Krogh Kristensen Date: Fri Sep 4 11:51:50 2020 +0200 renamed "isDelegating" to "is_delegating" commit ba600acd5e84f9bb73a4bce0be0b40975d2d615e Author: Erik Krogh Kristensen Date: Fri Sep 4 11:51:50 2020 +0200 renamed "arraySize" to "array_size" commit 83b89fa52d2ada26efc79757182b91e89aa0cc85 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:51:49 2020 +0200 renamed "exprContainers" to "expr_containers" commit 30ba7d29a133f8f40f5039bf23b247bd440b1ac7 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:51:48 2020 +0200 renamed "enclosingStmt" to "enclosing_stmt" commit 99f8887844837b7d084e932f94b63f92f05a95ed Author: Erik Krogh Kristensen Date: Fri Sep 4 11:51:47 2020 +0200 renamed "isForAwaitOf" to "is_for_await_of" commit 621e702e9994f0fa24265353bbebb6b840235d9c Author: Erik Krogh Kristensen Date: Fri Sep 4 11:51:46 2020 +0200 renamed "hasDeclareKeyword" to "has_declare_keyword" commit 49b71d515ce70f7bd1cc255f6147bc6a1f00f5d0 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:51:45 2020 +0200 renamed "isInstantiated" to "is_instantiated" commit 76f728aacd4153e6f1ee017c7c7338193f3fe2d6 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:51:45 2020 +0200 renamed "jumpTargets" to "jump_targets" commit 059d72858afe59eae330e5cdfbaff093b72a55bd Author: Erik Krogh Kristensen Date: Fri Sep 4 11:51:44 2020 +0200 renamed "stmtContainers" to "stmt_containers" commit 07fd747069c23e0273305c72be89ac1986df795a Author: Erik Krogh Kristensen Date: Fri Sep 4 11:51:43 2020 +0200 renamed "isClosureModule" to "is_closure_module" commit 2a2901f6ae502f78335969fea62593f5f9bacc9c Author: Erik Krogh Kristensen Date: Fri Sep 4 11:51:42 2020 +0200 renamed "isES2015Module" to "is_es2015_module" commit 8782c2b8e053e13f6b9da4eb630d4645e13df7c6 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:51:41 2020 +0200 renamed "isNodejs" to "is_nodejs" commit 4fb6d6060c5ba84e565646f1587528d3dd692898 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:51:40 2020 +0200 renamed "isModule" to "is_module" commit 39ff727ec76ba9896d76e4c1d2898206b522056b Author: Erik Krogh Kristensen Date: Fri Sep 4 11:51:39 2020 +0200 renamed "isExterns" to "is_externs" commit 05c38da2cb25a9e37e5f6c87b201eed6e64f5c1f Author: Erik Krogh Kristensen Date: Fri Sep 4 11:51:38 2020 +0200 add section to Aliases.qll for deprecated dbscheme relations commit 41eed43aa4e70985f7c3b7ae3e126b9e3b038896 Author: Erik Krogh Kristensen Date: Fri Sep 4 11:51:38 2020 +0200 create upgrade folder for renamings commit 961554eb6f3527e1e0ff43fdf4666ed02f4c4149 Author: Asger Feldthaus Date: Fri Sep 4 10:42:26 2020 +0100 JS: Autoformat commit 7a00fbc654c198a172b39bd23c0a5a6c9f437408 Merge: 2f480597e 29bf98ad2 Author: yoff Date: Fri Sep 4 11:35:24 2020 +0200 Merge pull request #4154 from RasmusWL/python-more-complete-dataflow-tests Python more complete dataflow tests commit 2f480597ef2767c4263fb733ab365eb1354d6dce Merge: 58f51899c 7e6ebfd63 Author: Rasmus Wriedt Larsen Date: Fri Sep 4 11:15:15 2020 +0200 Merge pull request #4157 from RasmusWL/add-labeler-action Enable labeler action again commit f12fa52e223c2d6d71472716524d3d21bf504a03 Author: Rasmus Wriedt Larsen Date: Fri Sep 4 11:11:30 2020 +0200 Python: Update inline example for TypeTracker usage commit 189c94f9e3ac85db5e8867d3c33439a9ace5edba Author: Rasmus Wriedt Larsen Date: Fri Sep 4 11:10:10 2020 +0200 Python: Add TypeTracker::end() Copied from JS commit 7855576a698157dddcb6d49b80f31875d9419a76 Author: Rasmus Wriedt Larsen Date: Fri Sep 4 10:58:20 2020 +0200 Python: TypeTracker only exposes its own interface This is especially important if the TypeTracker needs to be publicly imported by DataFlowPublic. commit 6c40e22f45d18019b4a94adb5c3040ac8f7b217d Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Sep 4 09:42:00 2020 +0100 C++: Support further reverse taint flows on things that return *this. commit 018b0a5abfc1dcdd9b52e103d8f464cd5667a3a8 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Sep 4 09:36:32 2020 +0100 C++: Model std::string front, back and push_back. commit 6e734a894fe4205c907ec951c40367b89ff315c0 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Sep 4 09:22:53 2020 +0100 C++: Additional test cases for std::string. commit e2c205deb4ed5862992a757810a799cea751b514 Author: Tamas Vajk Date: Fri Sep 4 10:37:38 2020 +0200 C#: Add stable order for generated accessors in printed AST commit fd0515629851e89add9287f43a4ad04aa44ef5c4 Author: Erik Krogh Kristensen Date: Fri Sep 4 10:26:06 2020 +0200 clarifying comment on the last jQuery inconsistency commit b18f51806cb2da25b141f8ffe7dee42a5e358721 Author: Erik Krogh Kristensen Date: Thu Sep 3 22:48:44 2020 +0200 regain the lost property presence result commit 0704be4d4154ff717cfae54798ea2cfd322d8846 Author: Asger F Date: Fri Sep 4 08:55:31 2020 +0100 Update javascript/ql/src/semmle/javascript/TypeScript.qll Co-authored-by: Erik Krogh Kristensen commit 252902d245d9ff62620b25e494a4bf638168d3a2 Author: Max Schaefer Date: Thu Sep 3 20:11:19 2020 +0100 JavaScript: Restructure API-graph tests. With the old test runner we cannot have `VerifyAssertions.qlref`s for each individual test that reference a shared `VerifyAssertions.ql` in the parent directory, since it doesn't like nested tests. Instead, we have to turn `VerifyAssertions.ql` into `VerifyAssertions.qll`, and each `VerifyAsssertions.qlref` into a `VerifyAssertions.ql` that imports it. But then that doesn't work with our old directory structure, since the import path would have to contain the invalid identifier `library-tests`. As a workaround, I have moved the API graph tests into a directory without dashes in its path. commit 6fccf5aa701394bdaff5a5d82bb1180e58ad3132 Author: Erik Krogh Kristensen Date: Thu Sep 3 15:48:30 2020 +0200 use `isLikelyIntentionalHtmlSink` in the sink instead of in the where clause commit 58f51899c931af7abb90ca80f19523d6136880aa Merge: 7f18c3377 d946a61d6 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Fri Sep 4 08:21:22 2020 +0100 Merge pull request #4173 from erik-krogh/targetBlankFP Approved by esbena commit 7f18c3377e7d2b1c1021cc070a9f7aea046b6009 Merge: b7774b2a8 701e189c1 Author: Tom Hvitved Date: Fri Sep 4 09:20:39 2020 +0200 Merge pull request #4017 from hvitved/csharp/unqualify-trap-ids3 C#: Remove assembly prefixes from TRAP labels commit fbe42fb64cc166720c4bc503c15bd2f05502b973 Author: Jonas Jensen Date: Tue Sep 1 15:40:44 2020 +0200 C++: Support `!= constant` in range analysis commit d061b09fe0c18d0f2dc938dd25d7a59077eb7a1f Author: Jonas Jensen Date: Tue Sep 1 13:27:33 2020 +0200 C++: Test showing no support for `!=` and `!` commit cb433a0c0fb5f6c715694f5b82eded3d7ce25af2 Author: Max Schaefer Date: Thu Sep 3 16:15:48 2020 +0100 JavaScript: Add test for custom API-graph entry points. commit 58702e4c52b67ea1833b49c93000f6e4bb2eea09 Author: Max Schaefer Date: Thu Sep 3 16:14:31 2020 +0100 JavaScript: Rename `EntryPoint.getADef` to `getARhs`. commit f3173ca968554ce84a657293e2c128fc83b2f2d4 Author: Max Schaefer Date: Thu Sep 3 14:28:24 2020 +0100 JavaScript: Add a few unit tests for API graphs. commit 985399f4cf16e83f4d54aba12df622158e9bdfad Author: Max Schaefer Date: Thu Sep 3 08:36:28 2020 +0100 JavaScript: Move `ApiGraphs` library to `semmle.javascript` and import it from `javascript.qll`. commit aaa70e4ad37868f5286f63ce9a667f57620e201c Author: Max Schaefer Date: Thu Sep 3 08:32:00 2020 +0100 JavaScript: Make API-graph edge labels accessible outside `ApiGraphs.qll`. commit 7239f1fb6fec6fe6474e3c144b901f72cc628ce8 Author: Max Schaefer Date: Thu Sep 3 08:27:36 2020 +0100 JavaScript: Distinguish more carefully between def and use nodes in API graphs. In particular, we now have two different kinds of module features: module definitions and module uses. For the most part, `API::Definition`s correspond to right-hand sides in the data-flow graph, and `API::Use`s correspond to references. However, module definitions can have references (via the CommonJS `module` variable), and so can their exports (via `module.exports` or `exports`). Note that this is different from references to uses of the module, which are simply imports. commit b7774b2a82ea1d034cf269c9f87d005e5d212665 Merge: f18049755 50d9a8514 Author: Mathias Vorreiter Pedersen Date: Thu Sep 3 21:45:36 2020 +0200 Merge pull request #4201 from geoffw0/insert C++: Model iterator versions of string and vector methods commit 1d04c89927cb3c923a8f3bcd37ba57f75c44b478 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Sep 3 18:54:36 2020 +0100 C++: Autoformat. commit 5124660831e127da0c18019355698784e491fa6e Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Sep 3 18:54:27 2020 +0100 C++: Change note. commit 2d7552358b0f0ded5394672b9d8db5e35b515c0c Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Sep 3 18:28:34 2020 +0100 C++: Put in a better fix. commit a1c7fd8fec971c787a077bd1dd55b40bc1e215b1 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Sep 3 18:45:47 2020 +0100 C++: Remove the workaround for CPP-331. commit 5150bf30e76e645d4c946982151cefc738d33316 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Sep 3 18:43:38 2020 +0100 C++: Add another test case inspired by CPP-331. commit 1483306c4cb54bd731034b795076c3ca9f56d9c8 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Sep 3 15:07:28 2020 +0100 C++: Add more tests. commit f180497554c8b2aa0e636784b5a76cdeef2f27c0 Merge: c8ffde20f cd64ce7b1 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Thu Sep 3 16:46:56 2020 +0100 Merge pull request #4192 from max-schaefer/js/ssa__implicitinit Approved by asgerf commit d8fbf60cbf877bf819cf22e2a5a837acd55a1e69 Author: Max Schaefer Date: Thu Sep 3 08:26:14 2020 +0100 JavaScript: Weaken a few types to stay under BDD node limit. `SourceNode` in cached layers seems particularly problematic. commit e77948103f8a132c71d5909b2d340b384218b52e Author: Max Schaefer Date: Thu Sep 3 08:22:21 2020 +0100 JavaScript: Remove `AdditionalFeature` from `ApiGraphs`. I ended up not using it for flow summaries, so at this point it is purely speculative generality. We can reintroduce it later if we need to. commit 924ef6ae5d6c86118985c83c9a1bce472c62bcbf Author: Max Schaefer <54907921+max-schaefer@users.noreply.github.com> Date: Thu Sep 3 14:04:23 2020 +0100 Apply suggestions from code review Co-authored-by: Erik Krogh Kristensen commit 29bf98ad26016d774a78a7d48d5833752236adf1 Author: Rasmus Wriedt Larsen Date: Thu Sep 3 15:03:53 2020 +0200 Python: Fix CUSTOM_SOURCE dataflow regression test commit c05f5c1bc26f3e97a9dd829cf984c5e7bd4c098b Author: Asger Feldthaus Date: Thu Jul 2 12:28:51 2020 +0100 JS: Change note commit 393db73d0aaa5c66085619e67d46fb79cd97087f Author: Asger Feldthaus Date: Thu Jul 30 14:50:51 2020 +0100 JS: Update test commit bfcc434a6136212e369229c0a9e4e4ea9a3856f6 Author: Asger Feldthaus Date: Thu Jul 2 12:26:51 2020 +0100 JS: Use both local and global names in hasQualifiedName commit f7552a77c3aa24c0986a127893ba30634274453e Author: Asger Feldthaus Date: Thu Jul 2 12:42:31 2020 +0100 JS: Add metric for number of types with qualified names commit febbe1229a6279287585f049935bf278954c9238 Merge: 9a821bf44 2ba84be56 Author: Rasmus Wriedt Larsen Date: Thu Sep 3 14:58:20 2020 +0200 Merge branch 'main' into python-more-complete-dataflow-tests commit c8ffde20f4e28d30613847429beeeecf4241a748 Merge: ed54fdcb0 bf34b0760 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Thu Sep 3 13:55:32 2020 +0100 Merge pull request #4195 from RasmusWL/python-taint-default-sanitizer Approved by tausbn commit ed54fdcb06f4c3ae67277bdcbb09e03af8e72540 Merge: d56ea2201 116e7d006 Author: Erik Krogh Kristensen Date: Thu Sep 3 14:50:03 2020 +0200 Merge pull request #4118 from dellalibera/js/ldap [javascript] CodeQL to detect LDAP Injection commit d56ea220185089ce97be038dc59920cf63924f46 Merge: b8ae87470 395255395 Author: Erik Krogh Kristensen Date: Thu Sep 3 13:56:40 2020 +0200 Merge pull request #4200 from erik-krogh/typeaheadInconsistencyComment JS: adjust comment about inconsistency for XSS in typeahead commit d946a61d6e98cd561f2844b0500049b83208b19f Author: Erik Krogh Kristensen Date: Thu Sep 3 13:32:54 2020 +0200 update expected output commit b8ae87470d712409d4ca9586422ed979b7e5ac0c Merge: aa4237c27 8c7431c4a Author: Nick Rolfe Date: Thu Sep 3 12:22:04 2020 +0100 Merge pull request #4182 from github/igfoo/cfg C++: Remove some remnants of the extractor CFG commit 50d9a85143739086fab0d1bd2ef7fe680cb20689 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Sep 2 17:52:03 2020 +0100 C++: Update change note. commit d4cbb25e09f15c1c3dc5d8d5623ee7638f3bd5be Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Sep 2 17:29:23 2020 +0100 C++: Model std::string constructors and container constructors that use iterators. commit 1ac0aa169d0ed352f0b5c7090f577d307173cd88 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Sep 2 17:44:55 2020 +0100 C++: Add a few more test cases. commit 1ad404c605f9bb3c63bf619bb89edd13732a2670 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Sep 2 17:21:12 2020 +0100 C++: Extend model to include std::forward_list::insert_after. commit fcacb22cada18a0c12df0432a5d9f1974e3f5c66 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Sep 2 17:13:40 2020 +0100 C++: Use [] in std::string begin model. commit 95ca4b674d53bcd960e31aa668d9a9ce8cdf1e8b Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Sep 2 16:59:49 2020 +0100 C++: Add model for std::vector::insert. commit f61c7ffc1a16935c137b0bb54c22b8fa18b2074c Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Sep 2 16:49:18 2020 +0100 C++: Add support for iterator parameters to std::vector::assign. commit 8e9faac36343798d1a7308d7cc8139e4d5a78f56 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Sep 2 16:13:15 2020 +0100 C++: Add support for std::vector begin and end. commit 4d47eaa08de54b5f5170975dcb482e73372459c1 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Sep 2 16:00:11 2020 +0100 C++: Add support for iterator parameters to std::string::assign. commit 98f84646d6e76f954a1351d98b4afef64d45866b Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Sep 2 15:21:26 2020 +0100 C++: Result changes due to iterators PR, which adds support for std::string begin and end, and iterator parameters to std::string::insert and some similar functions. commit 7917dff84389a9865b445d23028d5239221ce123 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Sep 1 11:22:18 2020 +0100 C++: Add test cases for std::string and std::vector using iterator methods. commit fcdbe0f512d7b75b129030121171ec769ca55982 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Sep 1 14:47:00 2020 +0100 C++: Add a const conversion constructor to std::iterator in the tests. commit 9a821bf449de9f42965a59a7fb586470b94047f7 Merge: 654c4f39a aad51af4c Author: Rasmus Wriedt Larsen Date: Thu Sep 3 11:28:42 2020 +0200 Merge pull request #4 from yoff/RasmusWL-python-more-complete-dataflow-tests Python: Annotate test file commit aad51af4cea6aad2e56cf17fc7faa4c7378ebb69 Author: Rasmus Lerchedahl Petersen Date: Thu Sep 3 11:25:41 2020 +0200 Python: use concrete iterable source commit 8997799e4d83a2b58e3d0cac87cd4b36a311cde4 Merge: 5f3eda0a2 b958c3b83 Author: yoff Date: Thu Sep 3 11:14:52 2020 +0200 Merge pull request #1 from RasmusWL/RasmusWL-python-more-complete-dataflow-tests Small fixups to your PR to my PR commit b958c3b833706e4344cc0640e673079d2ffabae0 Author: Rasmus Wriedt Larsen Date: Thu Sep 3 11:13:32 2020 +0200 Python: Update comment for test8 commit aa4237c27cb4e515eab322795e5e6660c4326b7e Merge: 2ba84be56 bb0e5d571 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Thu Sep 3 09:57:00 2020 +0100 Merge pull request #4191 from erik-krogh/v8Syntax Approved by esbena commit 3952553953d89c82f188ad3d3559c91822fbaad8 Author: Erik Krogh Kristensen Date: Thu Sep 3 10:50:40 2020 +0200 adjust comment about inconsistency for XSS in typeahead commit 116e7d006d87b0fb67cbeb0de8e88e4bd93b2570 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Thu Sep 3 10:32:18 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-090/LdapInjection.qhelp Co-authored-by: Erik Krogh Kristensen commit bfae0ef5d5bda274bcb2ba14ce3942677440eda0 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Thu Sep 3 10:32:08 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-090/LdapInjection.qhelp Co-authored-by: Erik Krogh Kristensen commit 2ba84be565201bc0dee4f5c87ab626ca4664235e Merge: 00668b536 87d39db95 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Thu Sep 3 09:18:15 2020 +0100 Merge pull request #4185 from erik-krogh/unusedArrDestruct Approved by esbena commit 4fdd2cd7946ea0282a727248478dc3ede5deeb3b Author: Erik Krogh Kristensen Date: Thu Sep 3 10:06:52 2020 +0200 add change note commit 1f9749fbfe1db95ef62f44fdd2d717601d04ff70 Author: Erik Krogh Kristensen Date: Thu Sep 3 09:39:01 2020 +0200 revert `mailto:` change in TargetBlank.ql commit d7a96d685abbad9b899b8c8e681107787b5713f7 Author: Erik Krogh Kristensen Date: Thu Sep 3 09:37:43 2020 +0200 simplify implementation of `getDelimiterMatchingRegexp` commit 87d39db95fea1a05e6103ee6a4811649122b9ec3 Author: Erik Krogh Kristensen Date: Thu Sep 3 08:58:33 2020 +0200 add change note commit ec21236bbaa661a6d25ebcd2468dea666198545b Author: Erik Krogh Kristensen Date: Thu Sep 3 08:51:10 2020 +0200 update docstring for `isNonLastDestructedArrayElement` Co-authored-by: Esben Sparre Andreasen commit fb3148a7a81914deec4e510128e49bb5018ff37a Author: Erik Krogh Kristensen Date: Wed Sep 2 20:55:33 2020 +0200 autoformat commit 0fed7c0745b5f90372cc5399fa681d2c473e7062 Author: Mathias Vorreiter Pedersen Date: Wed Sep 2 22:53:45 2020 +0200 C++/C#: Sync identical files commit ec3c1f114c6e8b222349ff54ce4edd7865803198 Author: Max Schaefer Date: Wed Sep 2 21:40:34 2020 +0100 JavaScript: Simplify steps through promises. commit fa26eed3e25a3de11306b20d912f9ca18c542e4a Author: Mathias Vorreiter Pedersen Date: Wed Sep 2 22:29:38 2020 +0200 Update cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll Co-authored-by: Dave Bartolomeo commit 428bcc5e03de3f89e8179ee627ea336f2982d1c4 Author: Mathias Vorreiter Pedersen Date: Wed Sep 2 22:29:28 2020 +0200 Update cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll Co-authored-by: Dave Bartolomeo commit 00668b536a8a0959f47decfa37bd491af3b78682 Merge: 8e86d56bc babe69d6e Author: Arthur Baars Date: Wed Sep 2 21:04:39 2020 +0200 Merge pull request #4188 from aibaars/csharp-buildless C#: autobuild: fix buildless mode for CodeQL commit d2a91970f3d182a90b9c9703301abba3e23478e5 Author: Andrew Eisenberg Date: Wed Sep 2 12:04:34 2020 -0700 Update devcontainer memory settings CodeQL CLI needs a minimum of 2G of memory. By default, the memory used is slightly less than that, leading to poor performance. commit 702192c316ced35725dd187dbc682d2bc3c365e0 Author: Max Schaefer Date: Wed Sep 2 19:52:13 2020 +0100 JavaScript: Make implicit inits of `module` and `exports` source nodes. This is instead of making every access to those variables source nodes, and fixes a regression in `DeadStoreOfProperty`. commit 9840a7ddfb4302ca0b132be60055ac0bc1c3697d Author: Max Schaefer Date: Wed Sep 2 14:34:52 2020 +0100 JavaScript: Add utility predicate `SSA::implicitInit`. commit d81d80430eff7f7ac67923b6760aaa9935ac0735 Author: Max Schaefer Date: Wed Sep 2 17:35:38 2020 +0100 JavaScript: Add a regression test for `DeadStoreOfProperty`. commit df498181526f21c665f38fa105db6f849e6cfe1d Author: Max Schaefer Date: Wed Sep 2 17:31:35 2020 +0100 JavaScript: Address review comments. commit 8c7431c4aee838b4b1ff076fa6ea0b9e18318c3c Author: Ian Lynagh Date: Wed Sep 2 19:08:02 2020 +0100 C++: Put {true,false}cond_base back as deprecated predicates for now commit c980ccf7c56cb7c2095f95c3b2aa459bf284be7e Author: Ian Lynagh Date: Tue Sep 1 21:38:44 2020 +0100 C++: Add an upgrade script commit 8ce1edbed3f07f2c302095e47e836d48f5dfd9dc Author: Ian Lynagh Date: Tue Sep 1 21:37:34 2020 +0100 C++: Update stats now CFG tables have been removed commit 26639a113e3991e755464ce4089e67a6e34076dd Author: Tom Hvitved Date: Wed Sep 2 19:41:22 2020 +0200 C#: Rename `Layout.Condition` to `FilePattern` and move to separate file commit 82d92dc726bbd6fe083db957312f66c9ada2e57b Author: Max Schaefer Date: Wed Aug 26 16:01:34 2020 +0100 JavaScript: Avoid bad join order. The optimiser decided that it would be a great idea to start the pipeline with `getReturn().getAUse().(DataFlow::InvokeNode)`. It's not. commit 500f7bd8faa8a46e8d0fcdc3f4efdb72f7464489 Author: Max Schaefer Date: Wed Aug 26 15:25:31 2020 +0100 JavaScript: Reduce complexity of `SystemCommandExecutors` charpred. commit e3a99060716716222becb374adfcb8d080170655 Author: Max Schaefer Date: Tue Aug 25 11:14:16 2020 +0100 JavaScript: Switch `MissingRateLimiting.qll` to API graphs. The added test shows how this helps us avoid false positives. commit e34a821cc6a49c2bad98aebca03f66e99fe4f560 Author: Max Schaefer Date: Mon Jun 22 16:00:47 2020 +0100 JavaScript: Switch system-command executor modelling from source nodes to API graphs. commit 6d68036d85dbc8ebec9171f7890ccf38f12d8ca9 Author: Max Schaefer Date: Wed Jun 24 09:56:01 2020 +0100 JavaScript: Add test demonstrating more SQL flow. commit 68b3ccdc6546b38153805c08bf4e30f24af9bf8d Author: Max Schaefer Date: Mon Jun 22 14:14:57 2020 +0100 JavaScript: Switch SQL modelling from source nodes to API graphs. commit f3e9104be4deed58ebee4c7746475dd783936b34 Author: Max Schaefer Date: Fri Aug 14 09:40:05 2020 +0100 JavaScript: Add implementation of API graphs. commit babe69d6e9e974ed501732b76b6d3a27f63184ae Author: Arthur Baars Date: Wed Sep 2 17:59:16 2020 +0200 Update unit tests commit 3cbc4cf0b90058685927d4b8988816ee473108e4 Author: Mathias Vorreiter Pedersen Date: Wed Sep 2 17:30:40 2020 +0200 C++: Add field to object taint tests commit bf34b07605b4db81e8fddf74ad79b08ffc60aadb Author: Rasmus Wriedt Larsen Date: Wed Sep 2 16:56:05 2020 +0200 Python: Add a few taint tests for default sanitizer specifically the ones removes from dataflow tests in https://github.com/yoff/codeql/pull/1 commit 8e86d56bce7953bedd34dfa135d9d527a8a4cde5 Merge: 90f013d74 8aab0c8be Author: Taus Date: Wed Sep 2 16:34:35 2020 +0200 Merge pull request #4189 from RasmusWL/python-experimental-file-structure Python: Move files in experimental dirs to be consistent commit 90f013d74f3be2ae38a21cf60da5bbaca820ad12 Merge: 2c0e9f0c8 aedfa47cb Author: Arthur Baars Date: Wed Sep 2 16:12:42 2020 +0200 Merge pull request #4176 from aibaars/missing-qhelp Add missing QHelp files commit 2c0e9f0c8617224f3361ba1bbee5ee1b8bc2c84d Merge: c01730850 8e8c65a16 Author: Asger F Date: Wed Sep 2 15:12:25 2020 +0100 Merge pull request #4186 from github/rc/1.25 Mergeback: 1.25 -> main commit 7f5f6b15f7fb2796fdbf710bd363c045947ec072 Author: Mathias Vorreiter Pedersen Date: Wed Sep 2 16:05:40 2020 +0200 C++: Make FieldContent private again commit 4387d106aa48c5ae8c5d77e030cf4a8e8a96a519 Author: Rasmus Wriedt Larsen Date: Wed Sep 2 15:36:50 2020 +0200 Python: Fix formatting (last time, promise) commit 8aab0c8be75cef9f12b2ef948fdfabed315b3713 Author: Rasmus Wriedt Larsen Date: Wed Sep 2 15:27:34 2020 +0200 Python: Fix .qlref for experimental security tests commit cd64ce7b1a77988a72ff2f496279e72c2636550e Author: Max Schaefer Date: Wed Sep 2 14:34:52 2020 +0100 JavaScript: Add utility predicate `SSA::implicitInit`. commit c017308505ce2fca326a3a675ee8e43680e6e720 Merge: 576021349 6cbdc7ad8 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Wed Sep 2 14:23:39 2020 +0100 Merge pull request #4134 from erik-krogh/genCalls Approved by asgerf commit 785f335ab8a910332b73205877474e8361b49a42 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Wed Sep 2 15:22:33 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-090/LdapInjectionCustomizations.qll Co-authored-by: Erik Krogh Kristensen commit 548cb65a64decc804c515f3a01b52f1ce3eeef57 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Wed Sep 2 15:22:23 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-090/LdapInjectionCustomizations.qll Co-authored-by: Erik Krogh Kristensen commit 26046a4847e786a4a0a084bce4ed2b8bc2b098b4 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Wed Sep 2 15:22:07 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-090/LdapInjectionCustomizations.qll Co-authored-by: Erik Krogh Kristensen commit 6ad88bf93f366cf4a178331b6576a9d707496937 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Wed Sep 2 15:21:55 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-090/LdapInjection.ql Co-authored-by: Erik Krogh Kristensen commit 3ed646571680ac914ae6556b7f9f657dde56730d Author: Arthur Baars Date: Wed Sep 2 15:18:31 2020 +0200 Address comments commit 57602134902450543a23ccb646bed79d5d26d4e8 Merge: ca8fd6197 fdfa75f3e Author: Jonas Jensen Date: Wed Sep 2 15:16:35 2020 +0200 Merge pull request #4190 from lcartey/cpp/range-analysis-extensible-assign-ops C++: Support `AssignOperation`s with `SimpleRangeAnalysisExpr`s commit ed6c1798e2487dcd0f034d9096a400f0974b1ffd Author: Anders Schack-Mulligen Date: Wed Sep 2 14:47:01 2020 +0200 Java: Fix reference to Unit. commit ca8fd6197a3c11d10d1586193eaddd9b323dccbe Merge: 48a1ee623 7a54d0b49 Author: Anders Schack-Mulligen Date: Wed Sep 2 14:41:26 2020 +0200 Merge pull request #4187 from RasmusWL/java-experimental-file-structure Java: Move files in experiemntal dirs to be consistent commit 69c1eadfdcd061296a7953157f0f1676633aae75 Merge: 5546830af 48a1ee623 Author: Mathias Vorreiter Pedersen Date: Wed Sep 2 14:21:23 2020 +0200 Merge branch 'main' into mathiasvp/read-step-without-memory-operands commit bb0e5d571889beeec6720c9e93d3eda7be45fe59 Author: Erik Krogh Kristensen Date: Wed Sep 2 14:05:59 2020 +0200 give V8 build-ins their correct name commit bf3a266f581ccbe14497dc50b7ecd85a243c1890 Author: Rasmus Wriedt Larsen Date: Wed Sep 2 13:51:00 2020 +0200 Python: dataflow regression tests: remove taint tracking tests they will be reintroduced in an other PR commit 5546830af7eaaf1e6dcedebe48ce8eb1c38458cc Author: Mathias Vorreiter Pedersen Date: Wed Sep 2 13:03:28 2020 +0200 C++: Fix a join order in readStep using the unbindInt predicate from the shared dataflow library. This is the tuple counts on ChakraCore before the fix: (5539s) Tuple counts for DataFlowPrivate::readStep#fff: 3208924 ~0% {2} r1 = SCAN Operand::NonPhiMemoryOperand::getAnyDef_dispred#3#ff AS I OUTPUT I.<1>, I.<0> 3208924 ~2% {2} r2 = JOIN r1 WITH DataFlowUtil::TInstructionNode#ff AS R ON FIRST 1 OUTPUT r1.<1>, R.<1> 751306 ~8% {2} r3 = JOIN r2 WITH Instruction::CopyInstruction::getSourceValueOperand_dispred#3#ff_10#join_rhs AS R ON FIRST 1 OUTPUT R.<1>, r2.<1> 751306 ~0% {3} r4 = JOIN r3 WITH DataFlowUtil::TInstructionNode#ff AS R ON FIRST 1 OUTPUT r3.<0>, r3.<1>, R.<1> 751306 ~0% {4} r5 = JOIN r4 WITH Instruction::CopyInstruction::getSourceValueOperand_dispred#3#ff AS R ON FIRST 1 OUTPUT R.<1>, r4.<1>, r4.<0>, r4.<2> 751306 ~2% {4} r6 = JOIN r5 WITH Operand::NonPhiMemoryOperand::getAnyDef_dispred#3#ff AS R ON FIRST 1 OUTPUT R.<1>, r5.<1>, r5.<2>, r5.<3> 209341 ~0% {4} r7 = JOIN r6 WITH Instruction::Instruction::getResultType_dispred#fb AS R ON FIRST 1 OUTPUT R.<1>, r6.<1>, r6.<2>, r6.<3> 7115323 ~1% {6} r8 = JOIN r7 WITH DataFlowPrivate::FieldContent#class#ffff_1023#join_rhs AS R ON FIRST 1 OUTPUT R.<2>, R.<3>, r7.<1>, r7.<2>, r7.<3>, R.<1> 81341188413 ~0% {5} r9 = JOIN r8 WITH SSAConstruction::Cached::getUsedInterval#fff_120#join_rhs AS R ON FIRST 2 OUTPUT r8.<3>, R.<2>, r8.<2>, r8.<4>, r8.<5> 137684 ~7% {3} r10 = JOIN r9 WITH Instruction::CopyInstruction::getSourceValueOperand_dispred#3#ff AS R ON FIRST 2 OUTPUT r9.<2>, r9.<4>, r9.<3> 751306 ~0% {3} r11 = JOIN r4 WITH Instruction::LoadInstruction::getSourceAddress_dispred#ff AS R ON FIRST 1 OUTPUT R.<1>, r4.<1>, r4.<2> 94306 ~0% {3} r12 = JOIN r11 WITH Instruction::FieldInstruction::getField_dispred#3#ff AS R ON FIRST 1 OUTPUT R.<1>, r11.<1>, r11.<2> 152363 ~6% {3} r13 = JOIN r12 WITH DataFlowPrivate::FieldContent::getField_dispred#ff_10#join_rhs AS R ON FIRST 1 OUTPUT r12.<1>, R.<1>, r12.<2> 290047 ~22% {3} r14 = r10 \/ r13 return r14 and after: (851s) Tuple counts for DataFlowPrivate::readStep#fff: 3208924 ~0% {2} r1 = SCAN Operand::NonPhiMemoryOperand::getAnyDef_dispred#3#ff AS I OUTPUT I.<1>, I.<0> 3208924 ~2% {2} r2 = JOIN r1 WITH DataFlowUtil::TInstructionNode#ff AS R ON FIRST 1 OUTPUT r1.<1>, R.<1> 751306 ~8% {2} r3 = JOIN r2 WITH Instruction::CopyInstruction::getSourceValueOperand_dispred#3#ff_10#join_rhs AS R ON FIRST 1 OUTPUT R.<1>, r2.<1> 751306 ~0% {3} r4 = JOIN r3 WITH DataFlowUtil::TInstructionNode#ff AS R ON FIRST 1 OUTPUT r3.<0>, r3.<1>, R.<1> 751306 ~0% {4} r5 = JOIN r4 WITH Instruction::CopyInstruction::getSourceValueOperand_dispred#3#ff AS R ON FIRST 1 OUTPUT r4.<0>, r4.<1>, r4.<2>, R.<1> 751306 ~0% {5} r6 = JOIN r5 WITH Instruction::CopyInstruction::getSourceValueOperand_dispred#3#ff AS R ON FIRST 1 OUTPUT R.<1>, r5.<1>, r5.<0>, r5.<2>, r5.<3> 751306 ~0% {5} r7 = JOIN r6 WITH Operand::NonPhiMemoryOperand::getAnyDef_dispred#3#ff AS R ON FIRST 1 OUTPUT R.<1>, r6.<1>, r6.<2>, r6.<3>, r6.<4> 209341 ~1% {5} r8 = JOIN r7 WITH Instruction::Instruction::getResultType_dispred#fb AS R ON FIRST 1 OUTPUT R.<1>, r7.<1>, r7.<2>, r7.<3>, r7.<4> 7115323 ~0% {7} r9 = JOIN r8 WITH DataFlowPrivate::FieldContent#class#ffff_1023#join_rhs AS R ON FIRST 1 OUTPUT r8.<4>, r8.<1>, r8.<2>, r8.<3>, R.<1>, R.<2>, R.<3> 7116087 ~0% {9} r10 = JOIN r9 WITH SSAConstruction::Cached::getUsedInterval#fff@staged_ext AS R ON FIRST 1 OUTPUT r9.<1>, r9.<2>, r9.<3>, r9.<0>, r9.<4>, r9.<5>, r9.<6>, R.<1>, R.<2> 449879 ~4% {9} r11 = SELECT r10 ON r10.<5> <= r10.<7> 193804 ~1% {9} r12 = SELECT r11 ON r11.<5> >= r11.<7> 154980 ~0% {9} r13 = SELECT r12 ON r12.<6> <= r12.<8> 137684 ~0% {9} r14 = SELECT r13 ON r13.<6> >= r13.<8> 137684 ~7% {3} r15 = SCAN r14 OUTPUT r14.<0>, r14.<4>, r14.<2> 751306 ~0% {3} r16 = JOIN r4 WITH Instruction::LoadInstruction::getSourceAddress_dispred#ff AS R ON FIRST 1 OUTPUT R.<1>, r4.<1>, r4.<2> 94306 ~0% {3} r17 = JOIN r16 WITH Instruction::FieldInstruction::getField_dispred#3#ff AS R ON FIRST 1 OUTPUT R.<1>, r16.<1>, r16.<2> 152363 ~6% {3} r18 = JOIN r17 WITH DataFlowPrivate::FieldContent::getField_dispred#ff_10#join_rhs AS R ON FIRST 1 OUTPUT r17.<1>, R.<1>, r17.<2> 290047 ~22% {3} r19 = r15 \/ r18 return r19 commit 552637a446698aa16e441e3d646687dba17b3f42 Author: Rasmus Wriedt Larsen Date: Wed Sep 2 13:50:24 2020 +0200 Python: dataflow regression tests: fix flow_in_iteration commit 4977790617e3c947852f7f7cb72e8c4f617b7eb8 Author: Rasmus Wriedt Larsen Date: Wed Sep 2 13:46:47 2020 +0200 Python: dataflow regression tests: fix source2 commit 7d00b49d05c0cf8f12be25d718782532c38bed9b Author: Mathias Vorreiter Pedersen Date: Tue Sep 1 21:34:48 2020 +0200 C++: Accept test changes commit 34c5da563e5f9d482d7c10ddf16ceb22ff3c0eb3 Author: Rasmus Wriedt Larsen Date: Wed Sep 2 13:39:01 2020 +0200 Python: Move files in experiemntal dirs to be consistent Except for dataflow (where we have a lot of changes, and I don't want to introduce lots of merge conflicts right now). commit 9c8b829d65caac7c04ff4b1b40078276e1a80462 Author: Rasmus Wriedt Larsen Date: Wed Sep 2 13:27:35 2020 +0200 Python: Fix formatting commit 223d94219e63aee83b30f5b3e4441679998c920a Author: Arthur Baars Date: Wed Sep 2 13:23:23 2020 +0200 C#: autobuild: fix buildless mode for CodeQL commit fdfa75f3ec670ae6dd1cfc9f07c162c4931a980f Author: lcartey@github.com Date: Wed Sep 2 11:20:05 2020 +0100 C++: Range analysis, allow extensible assign operations - defDependsOnDef supporting all analyzable AssignOperations - getDef(Upper|Lower)Bound supporting all analyzable AssignOperations commit 7a54d0b493ea5ec7637061d4ecd4670b34f872ad Author: Rasmus Wriedt Larsen Date: Wed Sep 2 13:19:21 2020 +0200 Java: Move files in experiemntal dirs to be consistent commit 8e8c65a1645d1addce5edce14b49fb7117f89c55 Merge: c9e22ab27 e949c167f Author: Jonas Jensen Date: Wed Sep 2 13:11:29 2020 +0200 Merge pull request #4146 from jbj/partiallyDefinesVariableAt C++: Fix two join orders in FlowVar.qll commit a24db0941838b387c125760880e89613b390b149 Author: Erik Krogh Kristensen Date: Wed Sep 2 11:19:50 2020 +0200 only flag unused array-destructs if it is the last variable commit 48a1ee62336c1f9ffa572d9881846d9610ffd83a Merge: 29b375965 e6bfffaed Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Wed Sep 2 10:38:50 2020 +0100 Merge pull request #4130 from erik-krogh/bbFix Approved by asgerf commit 89829e870d601696cfb4a512bbd4f77ad455f2a2 Author: Anders Schack-Mulligen Date: Wed Sep 2 11:17:56 2020 +0200 Java: Clean up SqlInjectionLib. commit 701e189c1b0008d664610189e514d61695aa9b23 Author: Tom Hvitved Date: Wed Sep 2 10:51:12 2020 +0200 C#: Add change note commit 1b769ebac9f961e8b70b88a31abca14a31d719f2 Author: Tom Hvitved Date: Wed Sep 2 10:43:50 2020 +0200 C#: Address more review comments commit 51dc1515ab2d66833f52683ee64bbb2ba3efde0c Author: Tom Hvitved Date: Mon Aug 31 13:18:14 2020 +0200 C#: Address review comments commit 92bf830a8afd2393ca06eb5e8d24d7a87cb8bfcf Author: Tom Hvitved Date: Mon Aug 17 14:31:34 2020 +0200 C#: Avoid bad magic in `UselessUpcast.ql` commit c7f776984f9468ecaabf6eaf272362d8ca99fb7a Author: Tom Hvitved Date: Thu Aug 27 14:06:41 2020 +0200 C#: Add CFG tests for callables with multiple implementations commit 8a0355720a5d65c721ef66a8e5777d8bfb363ed0 Author: Tom Hvitved Date: Thu Aug 27 14:29:20 2020 +0200 C#: Make `Callable::get[Expression|Statement]Body()` return all possible implementations Previosly, we returned only the body belonging to "the most likely" implementation, based on a CFG size heuristics. However, now that more callables are mapped to the same entity, it makes more sense to treat such callables (to some extent) like partial methods. This means, for instance, that data flow will branch out to all possible implementations, much like we do for virtual dispatch. commit afbbafe132e1c286bb3da090bf450396d23a9481 Author: Tom Hvitved Date: Wed Aug 5 14:38:34 2020 +0200 C#: Simplify `TypeRef.qll` commit d17f88bbcdd77e2467df85619778c7990ca6f43e Author: Tom Hvitved Date: Thu Aug 27 14:29:14 2020 +0200 C#: Remove assembly prefix from all extractor IDs commit 7628caa2db66182e857386a048780f0e57556ee8 Author: Calum Grant Date: Mon Jun 8 09:55:45 2020 +0100 C#: Avoid typerefs for constructed types. commit aa992690159540dcf15168244a32b3ac0d7dd8c5 Author: Calum Grant Date: Mon May 18 21:03:48 2020 +0100 C#: Fix merge conflicts. Unfortunately, the type of `symbolEntityCache` needed to be the same as `objectEntityCache` to fix nullability warnings. commit 0cfe424fc212df6394f2dc1d751ab8e569adc1e7 Author: Calum Grant Date: Mon May 18 09:28:50 2020 +0100 C#: Address review comments. commit 9a51192d86cec1f62f007e3ba902b2519852ba71 Author: Calum Grant Date: Wed May 13 12:04:50 2020 +0100 C#: Move TypeRefs into a separate file and import it privately. Reorder imports into alphabetical order. commit 4740b47f5db7595a80c4116696c8e1dabee8983d Author: Calum Grant Date: Wed May 6 14:48:20 2020 +0100 C#: Minor edits commit f4b15944610ae2b47e9410cca5f55ae62458c131 Author: Calum Grant Date: Tue May 5 19:16:51 2020 +0100 C#: Unqualify method names and nested types. commit f61fdc6891e0f29e3d4ed88224fa57ed15d4a4ff Author: Calum Grant Date: Fri Apr 24 13:05:16 2020 +0100 C#: Only resolve a single, canonical type for each typeref. commit 90517580a52f9bf4aa832de945514a276941d04e Author: Calum Grant Date: Mon Apr 20 15:06:42 2020 +0100 C#: Address review comment: Make dictionary type more specific. commit cd51a67c0dd4239c45a7e6da965b35dbcd9baddd Author: Calum Grant Date: Mon Apr 20 09:32:35 2020 +0100 C#: Take nullability into account when creating symbol entities. Otherwise, an entity with the wrong (cached) nullability could be created. commit d1cde2a8151dcb68445186d12d82feed64e18ae3 Author: Calum Grant Date: Tue Apr 7 19:58:48 2020 +0100 C#: Address review comment. commit 4657ddcb7c40c268e7e76192f33973a39429002f Author: Calum Grant Date: Wed Feb 12 16:23:48 2020 +0000 C#: Avoid qualifying explicit interface implementations. commit 6649d72a2d863a765ceea9fbcc1957c78d64b2ab Author: Calum Grant Date: Wed Feb 12 13:52:17 2020 +0000 C#: Qualify type parameters with the entity that declares them commit 6e5c2ef0e73b028aa2516482724d7a3a3f9cca36 Author: Calum Grant Date: Tue Feb 11 19:34:56 2020 +0000 C#: Remove assembly qualifier from some trap-ids. commit 29b3759655cfb6c783108d31c67bcf01ee631828 Merge: db45b2980 6a96c53d1 Author: Calum Grant <42069085+calumgrant@users.noreply.github.com> Date: Wed Sep 2 09:42:14 2020 +0100 Merge pull request #3961 from tausbn/python-add-typetracker Python: Add type tracker and step summary implementation. commit 9887d8b7ebe2cee6458fbf27a3c84f2976934436 Author: Mathias Vorreiter Pedersen Date: Wed Sep 2 10:33:12 2020 +0200 C++: Remove redundant rules commit f0a0f41c3c17f64518b299a8df6c68ce949f787e Author: Erik Krogh Kristensen Date: Mon Aug 31 16:02:25 2020 +0200 allow urls that are prefixed with `#` or `?` in js/unsafe-external-link commit db45b2980620ce6968e8215ebb06291a15658529 Merge: cc61e6117 015bf6e87 Author: Jonas Jensen Date: Wed Sep 2 07:57:35 2020 +0200 Merge pull request #4102 from rdmarsh2/rdmarsh2/cpp/input-iterators-1 C++: Basic input iterator models commit 042d07161c33719016b52e99c8917fe620f981d5 Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Tue Sep 1 22:43:31 2020 +0200 Rename getQueryCall to getQueryCallSink commit 15562e48149f245dbdb13c91d60a9eda4853e16a Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Tue Sep 1 22:28:58 2020 +0200 Update LdapjsSearchOptions commit e2e55455c152b0945747dc211293d6f1d157448f Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Tue Sep 1 22:23:07 2020 +0200 Update LdapjsSearchOptions and getQueryCall commit 015bf6e8795b516d04a25e0c3df47b9d5283c299 Author: Robert Marsh Date: Tue Sep 1 13:08:44 2020 -0700 C++: Add reverse flow when `this` ptr is returned commit 2a57fa22e3e174734fa8ac9d8e143536c725e6e2 Author: Robert Marsh Date: Tue Sep 1 12:51:50 2020 -0700 C++: handle reference args to iterator operators commit 8f00acd4e2904d4563f67c7745418116b4c02841 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Tue Sep 1 21:00:49 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-090/Ldapjs.qll Co-authored-by: Erik Krogh Kristensen commit 78ebcee5707e8bdc198d0fb5e66b05706f0af7f4 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Tue Sep 1 21:00:38 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-090/Ldapjs.qll Co-authored-by: Erik Krogh Kristensen commit b86b9ba510cb2935bd25ed10316c438234e28dbf Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Tue Sep 1 21:00:21 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-090/LdapInjectionCustomizations.qll Co-authored-by: Erik Krogh Kristensen commit 28729915d7b5240f39969b07fcd9894812d36024 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Tue Sep 1 20:56:25 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-090/Ldapjs.qll Co-authored-by: Erik Krogh Kristensen commit 1b50477fae10b407d6f7eca3749d03a43beb017b Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Tue Sep 1 20:55:44 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-090/Ldapjs.qll Co-authored-by: Erik Krogh Kristensen commit 44e728016bde9d07dd9a542ddb0867c795e4ad45 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Tue Sep 1 20:54:58 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-090/LdapInjection.qhelp Co-authored-by: Erik Krogh Kristensen commit 6cbdc7ad8f6d2292334ff31b4eb0cab4fee62f00 Author: Erik Krogh Kristensen Date: Tue Sep 1 20:16:49 2020 +0200 autoformat commit d4293ad9c3c9e26d22b8e74f43b9c477d0df717c Author: Mathias Vorreiter Pedersen Date: Tue Sep 1 18:25:46 2020 +0200 C++: Fix code after review comments. commit cc61e6117e45b7597b652bb6b37885de74e4b80b Merge: 311e62f21 441825919 Author: Anders Schack-Mulligen Date: Tue Sep 1 16:19:17 2020 +0200 Merge pull request #3542 from porcupineyhairs/mongoJava Java : add MongoDB injection sinks commit 311e62f21d2ece6693522908cf2abbca51d9eebb Merge: caa680c72 bcad18f49 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Tue Sep 1 15:06:47 2020 +0100 Merge pull request #4081 from aschackmull/java/dispatch-ctx-this-param Approved by aibaars commit 1cba09dde259d6f047a9f8a79092614d2df3f26f Author: Ian Lynagh Date: Tue Sep 1 14:03:54 2020 +0100 C++: Remove some remnants of the extractor CFG commit ab06c459f4919502fd78da180b228b9721077ca2 Author: Rasmus Wriedt Larsen Date: Tue Sep 1 14:42:11 2020 +0200 Python: Make validTest error on empty output again I accidentially disabled that when introducing the ability to handle more than one OK. commit caa680c72e2cfa646ab3788a0146b1ed85b41e4f Merge: b9a6183ec c5e3333d1 Author: yoff Date: Tue Sep 1 14:38:33 2020 +0200 Merge pull request #4149 from RasmusWL/python-more-additional-taint-steps Python: more additional taint steps commit 0cc018fec0aa27579f6617955b6725544efbc094 Author: Rasmus Wriedt Larsen Date: Tue Sep 1 14:23:51 2020 +0200 Python: Taint tracking setup alá Go \## TaintFlow sources The class `RemoteFlowSource` is very similarly defined as the other languages [C++](https://github.com/github/codeql/blob/ac22e7950c126a9407e02d4b468a4b690a9868e2/cpp/ql/src/semmle/code/cpp/security/FlowSources.qll), [Java](https://github.com/github/codeql/blob/6de612a56605eea2a2262f33e86d891f38033667/java/ql/src/semmle/code/java/dataflow/FlowSources.qll), [C#](https://github.com/github/codeql/blob/fddbce0b7bb8dc7e97971a0af7b01902954d1d49/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsources/Remote.qll), [JS](https://github.com/github/codeql/blob/78334af3540dfd776ba4fdb561692161c515ca66/javascript/ql/src/semmle/javascript/security/dataflow/RemoteFlowSources.qll), and [Go](https://github.com/github/codeql-go/blob/24b3133e0cce6a36e5727fdb393efa2cc4379de4/ql/src/semmle/go/security/FlowSources.qll). There are some minor differences: - Java/C++ defines the class in `FlowSources.qll` - C# uses `csharp/ql/src/semmle/code/csharp/security/dataflow/flowsources/Remote.qll`, and provide `StoredFlowSource` and `LocalFlowSource` in separate classes. - JS uses `RemoteFlowSources.qll`. - JS defines additional predicate `RemoteFlowSource.isUserControlledObject` - Go uses the class name `UntrustedFlowSource`, but still defined in `ql/src/semmle/go/security/FlowSources.qll` - Go uses the `::Range` pattern to allow both extensibility and refinement The big difference is how a RemoteFlowSource is specified: - Java and C# have all subclasses of `RemoteFlowSource` defined in the same file - Go and JS defines subclasses for frameworks in the actual framework `.qll` file, and all frameworks are transitively imported by `import go` or `import javascript` (so subclasses are always in scope). - C++ uses class `RemoteFlowFunction` to do all the heavy lifting (and its subclasses are transitively imported). \### What we will do Use file `RemoteFlowSource.qll`, define subclasses in framework library classes. _Why? Personally I really like it, Go/JS is already doing it, and Tom expressed a preference for doing the same for C# (although that is not what they are doing today)._ Jonas gave this advice: > Whether you split the definitions between multiple files or keep them all in one file, the property you want is that all definitions are included when the abstract class is included. Otherwise you can get unexpected results via transitive includes. We will make imports of all frameworks in the same file that defines `RemoteFlowSource`, as it seems to be the least intrusive change. If that turns out to be a problem, we can also move them to `python.qll` (the other way is not so easy). \## TaintFlow sinks [JS](https://github.com/github/codeql/blob/473787a4268a5e90b4a653ee8bcdb3681f7867ff/javascript/ql/src/semmle/javascript/Concepts.qll) and [Go](https://github.com/github/codeql-go/blob/ecff1e6a164b18da20daa9611933df4aace20915/ql/src/semmle/go/Concepts.qll) defines abstract base classes for interesting sinks in `Concepts.qll` (and all uses the `::Range` pattern in Go). I really like this idea, since it allows multiple queries to reuse the same sink definitions, and it makes it _easy_ to discover what default sinks are available. Personally I'm not 100% on board with the naming, but I don't have any good reason to change the naming convention. \## Framework modeling Following the model from Go ([example](https://github.com/github/codeql-go/blob/main/ql/src/semmle/go/frameworks/Gin.qll)), I propose that we make every definition in a framework modeling `private`. This allows some greater flexibility in changing our modeling, since we don't need to think about keeping deprecated versions around for a whole year. It _does_ have the downside that someone writing a query can't reuse the classes/predicates for a framework, but it didn't seem to be too big of a concern. If we need to provide access, we can always make the definitions non-private (the other way is not so easy). \## Customizations Also introduced `Customizations.qll` like in JS/Java/Go (to replace `site.qll`) commit 6a96c53d1563c3a25aaf60d1f2f5a7dfc74650a9 Author: Taus Brock-Nannestad Date: Tue Sep 1 14:04:31 2020 +0200 Python: Add missing `getNode` invocation commit 26d14aba987a18bb33f48fc21d30653aad0d5d57 Author: Taus Brock-Nannestad Date: Tue Sep 1 14:00:30 2020 +0200 Python: Use `nodeFrom`/`nodeTo` instead of `pred`/`succ` commit b9a6183ec2e99da7d3dc61386ee8305bc2764fca Merge: 2729d109a e5d7208c1 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Tue Sep 1 12:43:56 2020 +0100 Merge pull request #4175 from aschackmull/java/adjust-cwe-089-qltest Approved by aibaars commit 2628c05e43f15badcb2c78da9f2483104e409ff3 Author: Erik Krogh Kristensen Date: Tue Sep 1 13:12:44 2020 +0200 split out comment over multiple lines commit c6947320ea04315f4359fc778ef78ac353a07971 Author: Erik Krogh Kristensen Date: Tue Sep 1 13:11:44 2020 +0200 use `isAsyncOrGenerator` instead of `isOrdinary` commit 2729d109a57b45b78dc4b28c089f66d65093fc23 Merge: aa3b26852 82692876d Author: Arthur Baars Date: Tue Sep 1 13:02:24 2020 +0200 Merge pull request #4123 from aschackmull/java/records-dataflow Java: Add data flow for record getters. commit e5d7208c126a2e64ba7fc8b103a1321a3d042eec Author: Anders Schack-Mulligen Date: Tue Sep 1 12:49:09 2020 +0200 Java: Adjust a few qltests. commit aedfa47cb47c5eccc8a89956fef9fe64ea98a4f2 Author: Arthur Baars Date: Tue Sep 1 12:18:38 2020 +0200 Add missing QHelp files commit c5e3333d10b1a2607b5eb02d7021a384e435aaab Author: Rasmus Wriedt Larsen Date: Tue Sep 1 12:01:34 2020 +0200 Python: Update expected tests after last commit I'm pushing too fast it seems commit e0cfe8123efdf623a2d4f0579a2700cae149d583 Author: Rasmus Wriedt Larsen Date: Tue Sep 1 11:58:11 2020 +0200 Python: Update comments for new taint tests I see I didn't keep them up to date as I implemented things commit cda88a5e64dc4dd16c1d1f7828490965f3c9eadf Author: Rasmus Wriedt Larsen Date: Tue Sep 1 11:53:06 2020 +0200 Python: Refactor: use DataFlow::Node.asExpr() commit ddc55a18cf88fd74767874fad0be708525f3fcad Author: Rasmus Wriedt Larsen Date: Tue Sep 1 11:50:46 2020 +0200 Python: Fix taint handling of copy.deepcopy (test results didn't change) Thanks @yoff :+1: commit e5a361c23051b2f21b922ff2ca56cbab7a5c0514 Author: Rasmus Wriedt Larsen Date: Tue Sep 1 11:50:33 2020 +0200 Python: Better taint tests for copy.deepcopy commit aa3b2685259461a8a0e1247242a66d475d640e56 Merge: c25dd4be8 023f2e97c Author: Mathias Vorreiter Pedersen Date: Tue Sep 1 11:48:41 2020 +0200 Merge pull request #4162 from jbj/ssa-ref-parameters C++: SSA and range analysis for reference parameters commit 82692876d8f9805bbf83530a5e25b9cbb4116db1 Author: Anders Schack-Mulligen Date: Tue Sep 1 11:24:30 2020 +0200 Java: Add some test cases. commit 472363b86e64e49b1210edb03d7d6d9cf9127906 Merge: 91a23096b 1dae99e4a Author: Mathias Vorreiter Pedersen Date: Tue Sep 1 11:08:52 2020 +0200 Merge branch 'main' into mathiasvp/read-step-without-memory-operands commit c25dd4be8c9072d971387da873e4b5f6e58ace84 Merge: 1dae99e4a 0f555d42e Author: Anders Schack-Mulligen Date: Tue Sep 1 11:03:19 2020 +0200 Merge pull request #3363 from ggolawski/xslt-injection CodeQL query to detect XSLT injections commit 1dae99e4a526dcd022d89b7f67dc86c15ef7f3f1 Merge: beca44ec2 4f07733b0 Author: Anders Schack-Mulligen Date: Tue Sep 1 10:58:02 2020 +0200 Merge pull request #3543 from porcupineyhairs/WebsocketReadAsSource Java: add websocket reads as remote flow source. commit 91a23096bb0cd542dac78ecca08d79fd8fddc454 Author: Mathias Vorreiter Pedersen Date: Tue Sep 1 10:54:54 2020 +0200 C#: Sync identical files commit 3cca74e65455c887d2d77dbf73b0eadd57557d58 Author: Mathias Vorreiter Pedersen Date: Tue Sep 1 10:54:46 2020 +0200 C++: Accept test changes commit 9de570b300dd0cdbe336549d79a4b7b1f1197c99 Author: Mathias Vorreiter Pedersen Date: Tue Sep 1 10:54:09 2020 +0200 C++: Use the newly added predicates in field flow. This commit also adds a Class column to the FieldContent branch so FieldContent has a pretty toString implementation again. commit 1e13a399323be4a64963d38a143d004d7c6f33eb Author: Mathias Vorreiter Pedersen Date: Tue Sep 1 10:53:48 2020 +0200 C++: Add getUpdatedInterval predicate to ChiInstructions, and getUsedInterval predicate to NonPhiMemoryOperands. commit beca44ec2f540653d116754afbe8f4e97626e4a6 Merge: 35494ab97 2bdd3d771 Author: Anders Schack-Mulligen Date: Tue Sep 1 09:27:50 2020 +0200 Merge pull request #4172 from rvermeulen/java/xss-sink-extensible Java: Customizable XSS analysis commit 87b657054f1b944e3e832121b165d2c31dafef43 Author: Robert Marsh Date: Mon Aug 31 14:53:05 2020 -0700 C++: reverse flow for iterator operator qualifiers commit d4cf92e3745ac813db4e214e40632e34bb65cb17 Author: Robert Marsh Date: Mon Aug 31 14:52:29 2020 -0700 C++: Improve non-member iterator operator detection commit 10005dd1994b3428a6ebe1228be809e93de4eb40 Merge: 2a6c62440 35494ab97 Author: Robert Marsh Date: Mon Aug 31 14:19:13 2020 -0700 Merge branch 'main' into rdmarsh2/cpp/input-iterators-1Merge changes to input/output models for functions that return `this`and resolve conflicting changes to taint tests. commit 2bdd3d7712182464ad17110dacdce1a0e9372af8 Author: Remco Vermeulen Date: Mon Aug 31 17:28:51 2020 +0200 Apply qldoc suggestions Co-authored-by: Anders Schack-Mulligen commit ec64606d5a4c96cb7b7e2812e37f931ec64965f2 Author: Taus Brock-Nannestad Date: Mon Aug 31 17:23:02 2020 +0200 Python: Remove `CopyStep` branch type commit eb6443df210d68ae5faa8a4bdbd1636f5f1257dd Merge: 3547c70d3 8e1f99af9 Author: Taus Brock-Nannestad Date: Mon Aug 31 17:22:13 2020 +0200 Merge branch 'python-add-typetracker' of github.com:tausbn/ql into python-add-typetracker commit 8e1f99af99c87b2131c7d7b4391250e5e3f4c319 Author: Taus Date: Mon Aug 31 17:20:12 2020 +0200 Python: Apply suggestions from code review Co-authored-by: Rasmus Wriedt Larsen commit 3547c70d35b38513a965c34cdea3d5bf9aaae571 Author: Taus Brock-Nannestad Date: Mon Aug 31 17:17:37 2020 +0200 Python: Add tests with redefinition of fields/variables commit 06103f4ff2032767adaf0bfd74c485e3c7437bb7 Author: Taus Brock-Nannestad Date: Mon Aug 31 17:16:31 2020 +0200 Python: Consistently use attribute/`attr` commit 35494ab97c7f5e6b16e1008e05cec3d8d42edb40 Merge: 79e87a6c3 22ccae600 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Aug 31 15:15:27 2020 +0100 Merge pull request #4171 from max-schaefer/js/promise-flow-public Approved by erik-krogh commit 79e87a6c3d85eb425eb7881044ba25f8aac9ec46 Merge: 4e963a8a8 28578fd57 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Aug 31 15:02:49 2020 +0100 Merge pull request #4088 from aschackmull/java/string-formatted Approved by aibaars commit f7edf28d0d89e361aa95bf8a7b4f62649b1315fa Author: Erik Krogh Kristensen Date: Mon Aug 31 16:01:28 2020 +0200 allow mailto links in js/unsafe-external-link commit cf2eacd7a6ab690c680e1eeb175e09f8d3352421 Author: Rasmus Wriedt Larsen Date: Mon Aug 31 14:59:05 2020 +0200 Python: Adjust additional taint after PostUpdateNode addition Still no results though :( commit 4e73abc254b34be9b714c7793b975b0eab29d9b5 Merge: 2d2b036b8 dc9cc20fd Author: Rasmus Wriedt Larsen Date: Mon Aug 31 14:34:42 2020 +0200 Merge branch 'main' into python-more-additional-taint-steps commit 4e963a8a8e9b6bfeb4aa386420e54443ac6fdbed Merge: dc9cc20fd b20570285 Author: Tom Hvitved Date: Mon Aug 31 14:32:09 2020 +0200 Merge pull request #4165 from hvitved/csharp/foreach-guard C#: Fix bug in guards logic for `foreach` loops commit dc9cc20fdd9458619ce2f8c3ee0918316ba3c7aa Merge: 9d6b2e768 750735c70 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Aug 31 11:57:44 2020 +0100 Merge pull request #4161 from yoff/SharedDataflow_PostUpdateNodes Approved by RasmusWL, aschackmull, hvitved, jbj commit 22ccae6006e7dfa019a49ca4b79714659e95ba8e Author: Max Schaefer Date: Mon Aug 31 11:55:10 2020 +0100 JavaScript: Make `PromiseFlow` module public. commit 9d6b2e7684a46537931bff67087f6df6cfc219a1 Merge: b89a22b58 99c952463 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Aug 31 11:54:25 2020 +0100 Merge pull request #4042 from aschackmull/java/xsssink-extensible Approved by aibaars commit b89a22b58364a04f4dd94ec1c10e2d92c5d71b44 Merge: 813d14791 66d39bb5f Author: Anders Schack-Mulligen Date: Mon Aug 31 12:45:06 2020 +0200 Merge pull request #4170 from aibaars/drop-inefficient-toarray Java: remove InefficientToArray.ql commit 66d39bb5f69fc757d8870f5b1dcb3b1fb37be2b0 Author: Arthur Baars Date: Mon Aug 31 10:39:00 2020 +0200 Java: remove InefficientToArray.ql This query was deprecated 4 years ago. Fixes: #4167 commit 5f3eda0a22acde7be7edf6f05b70653ccf715dfa Author: Rasmus Lerchedahl Petersen Date: Mon Aug 31 09:06:13 2020 +0200 Python: Annotate test file Also add test of custom flow commit 0f555d42ed1eb848ec4c1cee35b2ca82327ce8df Author: Grzegorz Golawski Date: Sun Aug 30 22:55:17 2020 +0200 Fix test commit 441825919c1437e7a919d22395905734fb9a67f9 Author: Porcupiney Hairs Date: Fri May 22 01:13:57 2020 +0530 Java : add MongoDB injection sinks commit 5e462a897d373262a692d159c6db9d2cf3a025e7 Merge: 37f441076 813d14791 Author: Grzegorz Golawski Date: Sun Aug 30 22:45:31 2020 +0200 Merge branch 'main' into xslt-injection commit 37f4410764ca4a2804ae935fe2ef49dd4c7a52bf Author: Grzegorz Golawski Date: Sun Aug 30 22:32:57 2020 +0200 Fix test commit 4f07733b06ea62aab3da3b455246089d08a1cd11 Author: Porcupiney Hairs Date: Sun Aug 30 04:54:02 2020 +0530 remove U+200B commit 104c9b5dac1157f66b048181985b7602f33121c1 Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Sat Aug 29 11:24:58 2020 +0200 Move sinks into separate classes commit 8f987238228fd86f98ace537bc7cd22e519470ac Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sat Aug 29 11:18:41 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-090/LdapInjectionCustomizations.qll Co-authored-by: Erik Krogh Kristensen commit 7108d28395089c1cda977405dfe8a8f1cbc93815 Author: Taus Brock-Nannestad Date: Fri Aug 28 21:21:29 2020 +0200 Python: Remove failing non-inline test It is subsumed by `tracked.ql` anyway. commit 5d853e840adce8108f76783e2adcfd30fcbb79e1 Merge: 8b78b6b1d 813d14791 Author: Taus Brock-Nannestad Date: Fri Aug 28 19:59:58 2020 +0200 Merge branch 'main' into python-add-typetracker commit 8b78b6b1dcd180f116e4427d9df0d66c9bbec5b0 Author: Taus Brock-Nannestad Date: Fri Aug 28 19:55:52 2020 +0200 Python: Add inline tests Nodes to which we track type tracking flow from the source (any identifier named `tracked`) are indicated with a `$tracked` tag, and `$tracked=attr_name` if the attribute is for the specified attribute of the given node. For nodes that do have flow from `tracked`, I indicate this in one of two ways: - If it's expected due to the design of type tracking, I omit the `$tracked tag. - If it's flow that _ought_ to be there, I indicate it as a false negative: `$f-:tracked` Currently, only an instance of global flow is in the latter category. commit fbe8b64dd408eaa7a0cdb2d84f6091626202ea68 Author: Taus Brock-Nannestad Date: Fri Aug 28 19:55:14 2020 +0200 Python: Add support for attribute reads and writes commit 023f2e97c19a3cc6a924a30dbe59b4820bba9792 Author: Jonas Jensen Date: Fri Aug 28 16:50:23 2020 +0200 C++: Really accept test results this time commit b205702853e17f110ad0b0b7174e1b432391093d Author: Tom Hvitved Date: Fri Aug 28 15:18:09 2020 +0200 C#: Fix bug in guards logic for `foreach` loops commit ddb33c914bc84f6d8539179ee63df0b87a17b2f8 Author: Tom Hvitved Date: Fri Aug 28 15:13:18 2020 +0200 C#: Add test that demonstrates issue with guards logic for `foreach` statements commit 813d14791d6bea399bc96fa9b7143603eef6e6c4 Merge: 93e0bd9d8 f4060723b Author: Asger F Date: Fri Aug 28 14:02:08 2020 +0100 Merge pull request #4043 from erik-krogh/ts4 JS: Add support for TypeScript 4 commit 750735c70c3f0f362b3def4506cbbc47cbcf7d70 Author: Rasmus Lerchedahl Petersen Date: Fri Aug 28 15:00:01 2020 +0200 Dataflow: Update test expectations commit 2c613a72b992fcc482d8d38d22f9abe4c7a6e51d Author: Jonas Jensen Date: Fri Aug 28 14:56:19 2020 +0200 C++: Autoformat commit a25cc2d9c76eae409aee98fadea4cc80d8837771 Author: Jonas Jensen Date: Fri Aug 28 14:54:44 2020 +0200 C++: Accept range-analysis test results commit a4cb7749323785d6628d682c0338bd9001826b91 Author: lcartey@github.com Date: Tue Aug 25 11:25:53 2020 +0100 C++: Support dereferenced variables in simple range analysis - Support inference of guards on reference variables - Support type bounds for reference variables - Support reference variables when widening - Support reference variables when determining arithmetic assignment commit 027f22d8e7df4170e9cd541921a9712761ecd125 Author: Jonas Jensen Date: Fri Aug 28 14:38:36 2020 +0200 C++: Test that range analysis ignores references commit a3a3423db25ce56d1569d609fa6387e89fec44f6 Author: Jonas Jensen Date: Fri Aug 28 14:33:01 2020 +0200 C++: Treat reference parameters as non-references commit 6b8d9f2a774f131f3ab42f1bdfa09b517e84e4a2 Merge: 9503c5d8b 93e0bd9d8 Author: Rasmus Lerchedahl Petersen Date: Fri Aug 28 13:01:14 2020 +0200 Merge branch 'main' of github.com:github/codeql into SharedDataflow_PostUpdateNodes commit 9503c5d8bb9320a4c53824db4cf7450f56c7a4f3 Author: Rasmus Lerchedahl Petersen Date: Fri Aug 28 12:59:11 2020 +0200 Python: Add post-update nodes commit f4060723bbde76150dae54eb10647ec95f869404 Author: Erik Krogh Kristensen Date: Fri Aug 28 12:21:37 2020 +0200 add stats for new properties commit 93e0bd9d8530bb6ec260db91d58f5375f42e435d Merge: 6eca97bc3 18c65e9f7 Author: Calum Grant <42069085+calumgrant@users.noreply.github.com> Date: Fri Aug 28 11:21:39 2020 +0100 Merge pull request #4126 from tamasvajk/feature/array-index C#: Fix computed sizes for implicitly sized array creation commit 6eca97bc3298cce290d379c73ee28cd94055eec5 Merge: 647ed03a2 7e2cf9a85 Author: Tom Hvitved Date: Fri Aug 28 12:06:54 2020 +0200 Merge pull request #4113 from tamasvajk/feature/nullability-extraction-cil Enable nullability checks on Semmle.Extraction.CIL commit 647ed03a2b7be7c827d5755a2519f9a30755ad70 Merge: 8caaf8f17 29eaacdea Author: Tom Hvitved Date: Fri Aug 28 12:03:03 2020 +0200 Merge pull request #4136 from tamasvajk/feature/qldocs C#: Add missing QlDocs commit 8caaf8f17c6d90fb3221fe5fd526cef1813995f9 Merge: afe234dad 496d856c4 Author: Taus Date: Fri Aug 28 11:33:00 2020 +0200 Merge pull request #4158 from RasmusWL/python-reformualte-js-team-comment Python: Reformualte explanation of experience from JS commit 2d2b036b8cedd9ca777bffcbd3c573591d997e86 Author: Rasmus Wriedt Larsen Date: Fri Aug 28 11:25:46 2020 +0200 Python: Fix expected output for moved taint tests commit 7213da195c5df0ceaf427cb3aa27084c09d2b6ff Author: Rasmus Wriedt Larsen Date: Fri Aug 28 11:22:42 2020 +0200 Python: Use standard naming scheme for taint flow tests We got into problems since using `string.py` would shadow the string module from the standard library. By some reason I adopted a pattern of `_` as suffix, but let us just use the standard pattern of `test_` prefix like a normal testing framework like pytest does. commit 621e3f6c3c8ccc8f91eea255c795053005d48e95 Author: Rasmus Wriedt Larsen Date: Fri Aug 28 11:17:23 2020 +0200 Python: Add dataflow test of deep call graph commit 45ab723423fa4859bc0caf8ab2c3a138eb6a3b16 Author: Rasmus Wriedt Larsen Date: Fri Aug 28 11:12:25 2020 +0200 Python: Add dataflow test for `a,b = b,a` Also enables a single test to output more than one OK commit 496d856c48215ec03e73c23eb77c30812736607a Author: Rasmus Wriedt Larsen Date: Fri Aug 28 10:49:33 2020 +0200 Python: Reformualte explanation of experience from JS commit 038cca814a9cfba11cb6b5979b9a5f2ad5b85a79 Merge: eb84f97e7 afe234dad Author: Erik Krogh Kristensen Date: Fri Aug 28 10:27:49 2020 +0200 Merge branch 'main' into ts4 commit afe234dade0d8d1eb0af184a794fe523b33009f3 Merge: 55d7ac88f deff36e9a Author: Taus Date: Fri Aug 28 10:23:06 2020 +0200 Merge pull request #4156 from RasmusWL/python-fix-changenote-fstring-taint Python: fstring taint change note should be for 1.26 commit 55d7ac88f9cea1a30c0088b8be78befc2fae6fb4 Merge: 80cb8be40 9b3da1f6c Author: Jonas Jensen Date: Fri Aug 28 10:05:42 2020 +0200 Merge pull request #4148 from geoffw0/vecextra C++: Improvements to string and vector models. commit 80cb8be405f8eae1c1f189be5f9edf1d2d082576 Merge: ac9486997 e7a0bc6be Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Fri Aug 28 08:52:58 2020 +0100 Merge pull request #4155 from asger-semmle/js/lower-duplicate-element-id-precision Approved by esbena commit 7e6ebfd63664ba768fd5b300a3fa1e6d333838b1 Author: Rasmus Wriedt Larsen Date: Fri Aug 28 09:31:46 2020 +0200 Enable labeler action again This time using `pull_request_target`, so it will work properly with forks. See https://docs.github.com/en/actions/reference/events-that-trigger-workflows#pull_request_target This reverts commit d5d6093e751d252897d266faf61d5a2923c9df2a. commit ac9486997845355ed20ab9668c34a0e36c50672a Merge: ceddc2497 9aa140464 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Fri Aug 28 08:31:38 2020 +0100 Merge pull request #3978 from dellalibera/js/insecure-cookies Approved by esbena commit deff36e9af3eeb1c0bd5dfef68509e2c5c8ee0de Author: Rasmus Wriedt Larsen Date: Fri Aug 28 08:52:40 2020 +0200 Python: fstring taint change note should be for 1.26 This fixes problem introduced in https://github.com/github/codeql/pull/4127 commit 29eaacdeaf720fad0e87c9019959ac7bbe1b014e Author: Tamas Vajk Date: Fri Aug 28 08:39:16 2020 +0200 Fix typos and comment styling commit ceddc2497ab259abedc42219a64b08b4871d12ef Merge: 1206ff588 6f62803e1 Author: Mathias Vorreiter Pedersen Date: Thu Aug 27 20:00:13 2020 +0200 Merge pull request #4151 from geoffw0/reftaint C++: Taint tests for array and reference assignments. commit 2a6c6244073ff3d1a418fda3498197ca14375437 Author: Robert Marsh Date: Thu Aug 27 10:27:53 2020 -0700 C++: fix up some iterator taint flows commit 1206ff5889a888a142202899da9b806844848609 Merge: 36ac11165 9da6da610 Author: Taus Date: Thu Aug 27 18:05:55 2020 +0200 Merge pull request #4150 from RasmusWL/python-dataflow-private-import Python: Make import of python private in shared dataflow commit 9b3da1f6c79ca1a614e1af9615d5aa5cfd02bd96 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 27 16:55:45 2020 +0100 C++: Autoformat. commit 208cd4c888bf262279c38a50134dbf0a63f9b850 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 27 15:54:27 2020 +0100 C++: Fix assign in the test stl.h. commit f12d29de07d0c88b4b74e3b967a0b53243b5eee1 Author: Rasmus Wriedt Larsen Date: Thu Aug 27 17:36:10 2020 +0200 Python: Add taint test of more colleciton methods commit 7112aa2e9afe3a183517671bec2eadc10831a190 Merge: cec3694c8 e7322d114 Author: Taus Brock-Nannestad Date: Thu Aug 27 17:05:26 2020 +0200 Merge branch 'main' into python-add-typetracker commit e7a0bc6be68d9d436201c5edf6153c314037ddf3 Author: Asger Feldthaus Date: Thu Aug 27 15:48:15 2020 +0100 JS: Lower precision of ambiguous HTML ID attribute commit 927a4faa5829f52b96b4637cc30a7acf3c6c36cd Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 27 15:40:07 2020 +0100 C++: Remove the non-reference case that we shouldn't need. commit 654c4f39ac0283c8092346bfa1a688fdb2149bfa Author: Rasmus Wriedt Larsen Date: Thu Aug 27 16:32:26 2020 +0200 Python: Add missing `module.py` to consistency/regression tests commit 071b303ea06e13cb00751bec080a05670531dc03 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 27 15:17:04 2020 +0100 C++: Make the other versions consistent with this. commit 36ac1116596bc9b2f965dc4352752d0d4f2cea97 Merge: c507b337f 797e290a6 Author: Rasmus Wriedt Larsen Date: Thu Aug 27 16:23:08 2020 +0200 Merge pull request #4152 from tausbn/python-sync-inline-test-expectations-files Python: Sync InlineExpectationsTest.qll between Python and C++ commit f1e11f1efd4ae23833cbc7587598d39045e981e1 Author: Rasmus Wriedt Larsen Date: Thu Aug 27 16:17:12 2020 +0200 Python: updated expected output from new shared dataflow tests I did not verify whether these changes are OK or not, simply ran and accepted the tests. commit 865d91de805e00337751903dec7167bd3aa8b7ef Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 27 15:04:00 2020 +0100 C++: Fix getAValueTypeParameterIndex(). commit b11b5784b24b1ba74333d5a33b25b5727057d868 Author: Rasmus Wriedt Larsen Date: Thu Aug 27 16:08:51 2020 +0200 Python: Adtop more complete tests from old dataflow impl The ones in test/experimental/dataflow/[consistency,regression]/test.py was a copy from test/library-tests/taint/dataflow/test.py. However, test/library-tests/taint/dataflow/test.py only contains a subset of test/library-tests/taint/config/test.py, that only contains a subset of test/library-tests/taint/general/test.py This commit updates the experimental dataflow tests to be a copy of the test/library-tests/taint/general/test.py file. There seems to have been a few changes to the file after it being copied, in `test_truth` and `test_early_exit`. I have no reproduced those changes. commit c507b337f2cb58e9acec22b285a88b3578ca0c2d Merge: e7322d114 07610e089 Author: Jonas Jensen Date: Thu Aug 27 16:07:13 2020 +0200 Merge pull request #3921 from catenacyber/NullCheckParam C++: Adds another redundant null check rule commit 816b8abd7cf8d3963fe8cc2f768a08b0b1f57acb Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 27 13:42:11 2020 +0100 C++: Add a test case using a const int *. commit 7e2cf9a8583808dc1f0f5a96ae8c70506b322c08 Author: Tamas Vajk Date: Thu Aug 27 15:11:55 2020 +0200 Adjust code review findings commit fcd426210f791a2619e7d7146a1ff8e265554bc3 Author: Tamas Vajk Date: Thu Aug 27 14:43:16 2020 +0200 C#: Add missing QlDoc for code duplication commit 797e290a6778930fe4f4133428fbfac54915935f Author: Taus Brock-Nannestad Date: Thu Aug 27 14:12:40 2020 +0200 Python+CPP: Change `values` to `value` commit dccbcc15b3654f2ebd1d12708c5cf89cf9ce48b8 Author: Taus Brock-Nannestad Date: Thu Aug 27 13:35:24 2020 +0200 Python: Sync InlineExpectationsTest.qll between Python and C++ Also changes `valuesasas` to `values` in the test example. commit 9da6da6106e8f1d096786c17938a170b26829cbe Author: Rasmus Wriedt Larsen Date: Thu Aug 27 13:29:41 2020 +0200 Python: Fix imports in shraed dataflow tests commit e7322d114f89aae7a18693656bac7846087103e6 Merge: d3175a789 09025c219 Author: Taus Date: Thu Aug 27 13:20:56 2020 +0200 Merge pull request #4077 from yoff/MagicMethods Python: Add support for magic methods commit d3175a789924243abf6a7ef7ef4fbab24521ef2c Merge: 30ac2f9c8 dcabd3797 Author: Taus Date: Thu Aug 27 13:19:23 2020 +0200 Merge pull request #4110 from yoff/SharedDataflow_ParsimoniousFlowNodes Python: Shared dataflow, parsimonious flow nodes commit 30ac2f9c84b6e474531bc460200242b694cf683a Merge: a750252c0 e193e12b3 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Thu Aug 27 12:18:41 2020 +0100 Merge pull request #4143 from tausbn/python-add-inline-test-expectations-library Approved by RasmusWL commit a750252c0724e2377588573f5427b261c8cb0f0b Merge: 35e1c04b9 569e54e7b Author: Taus Date: Thu Aug 27 13:16:07 2020 +0200 Merge pull request #4147 from RasmusWL/python-remove-symlink Python: Remove symlink from experimental test commit a5a3078b58a4429c81fdf7480487baf0e1fd394b Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 27 11:52:07 2020 +0100 C++: Add a test case using a typedef int. commit 35e1c04b935862a360ed206d9c9e9733fad38f8d Merge: 67278d9c9 2ac732c50 Author: Tom Hvitved Date: Thu Aug 27 12:38:49 2020 +0200 Merge pull request #4144 from hvitved/csharp/autobuilder/vsdevcmd C#: Teach autobuilder about `VsDevCmd.bat` commit 6f62803e1f79d608285a1ec9e0afb5702de257cd Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Aug 25 15:27:40 2020 +0100 C++: Taint tests for array and reference assignments. commit 909bff231362c51896bb828ae1528b7b592ae3d0 Author: Rasmus Wriedt Larsen Date: Thu Aug 27 11:48:56 2020 +0200 Python: Make import of python private in shared dataflow commit 627363d6eab353db7bca063531eea6e9afab53bd Author: Rasmus Wriedt Larsen Date: Thu Aug 27 11:37:56 2020 +0200 Python: Test taint step for string augmented assignment Apprently it just works :confused: :magic: commit 111da4c35203f170f20e60c5f8030c7f79fc08f8 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Aug 26 18:42:24 2020 +0100 C++: Add a model of std::vector::assign. commit 569e54e7bb43a242548e1a67d23119d5186fc4db Author: Rasmus Wriedt Larsen Date: Thu Aug 27 11:19:55 2020 +0200 Python: Remove symlink from experimental test commit e949c167fa6ff0b32ba9e6925fafa6c12cdfbf4a Author: Jonas Jensen Date: Thu Aug 27 11:14:47 2020 +0200 C++: Add back `getSubBasicBlockStart` It turns out this predicate was used in a test, and that use can't be replaced with the new `partiallyDefinesVariableAt` predicate since `partiallyDefinesVariableAt` doesn't hold for a `PartialDefinition` that defines something other than a variable. commit 0952fb9777da98702093b6c915f418ea58bb92e7 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Aug 26 18:32:46 2020 +0100 C++: Minor correction in one of the string models. commit fbac4ce44f5313bd3341837a048f2d36d7524b64 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Aug 26 18:10:15 2020 +0100 C++: Split StdStringCStr and allow reverse flow on data. commit fbff44ea45ee2910cd7cc3637e8ecf0515bcbb8a Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Aug 26 15:37:11 2020 +0100 C++: Add reverse taint as well. commit 6ae96baaf6940e7f02697febf505ffe3e5552a75 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Aug 26 14:48:10 2020 +0100 C++: Model std::vector::data. commit 2235c19593986e096f45eba2369b98d09bf906c3 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Aug 26 13:14:27 2020 +0100 C++: Add test cases for 'assign' and extra cases for 'data'. commit d0081dfbfa954fc8a7eee666389dbc298431af13 Author: Rasmus Wriedt Larsen Date: Thu Aug 27 10:54:06 2020 +0200 Python: Attempt at taint step for list.append/set.add commit af20c3e082349d289d406a2c55ecc67e26d2c20b Author: Rasmus Wriedt Larsen Date: Thu Aug 27 10:44:14 2020 +0200 Python: Make new taint tracking tests runnable again since the files was called `collection`, that conflicted with import system :| commit f3e98c3beaed0a7b10bebd1db832153d26659b83 Author: Jonas Jensen Date: Thu Aug 27 09:25:45 2020 +0200 C++: Fix join order of FlowVar::definedPartiallyAt This predicate was very slow on kamailio/kamailio: (696s) Tuple counts for FlowVar::FlowVar::definedPartiallyAt_dispred#ff: 703569 ~3% {3} r1 = SCAN FlowVar::FlowVar_internal::TBlockVar#fff AS I OUTPUT I.<1>, I.<0>, I.<2> 7679540588 ~3% {3} r2 = JOIN r1 WITH FlowVar::PartialDefinitions::PartialDefinition::partiallyDefines_dispred#ff_10#join_rhs AS R ON FIRST 1 OUTPUT R.<1>, r1.<1>, r1.<2> 567217 ~2% {2} r3 = JOIN r2 WITH project#FlowVar::PartialDefinitions::PartialDefinition#class#fff#2 AS R ON FIRST 2 OUTPUT r2.<2>, r2.<0> return r3 After this change, the predicate takes no time at all: (22s) Tuple counts for FlowVar::FlowVar::definedPartiallyAt_dispred#ff: 703569 ~3% {3} r1 = SCAN FlowVar::FlowVar_internal::TBlockVar#fff AS I OUTPUT I.<1>, I.<0>, I.<2> 567217 ~2% {2} r2 = JOIN r1 WITH FlowVar::PartialDefinitions::PartialDefinition::partiallyDefinesVariableAt#fff_120#join_rhs AS R ON FIRST 2 OUTPUT r1.<2>, R.<2> return r2 Looking at the code, it turned out that the predicates `partiallyDefines` and `getSubBasicBlockStart` were almost always used together and could therefore be merged into a single predicate to get better join orderings. The predicate `partiallyDefinesThis` was never used. commit 2b720b332b1f9060d456ddd11cff4611b12ff20c Author: Jonas Jensen Date: Thu Aug 27 09:39:47 2020 +0200 C++: Fix join order in reachesWithoutAssignment The negation in this predicate did not get pulled into an `#antijoin_rhs` predicate but got materialized as part of each iteration, which meant that the temporary `ControlFlowNode` column did not get projected away. The tuple counts looked like this on kamailio/kamailio (iteration 20): 5724 ~13% {3} r9 = JOIN r8 WITH BasicBlocks::Cached::bb_successor_cached#ff@staged_ext AS R ON FIRST 2 OUTPUT r8.<2>, r8.<3>, r8.<1> 5724 ~12% {3} r10 = JOIN r8 WITH BasicBlocks::Cached::bb_successor_cached#ff@staged_ext AS R ON FIRST 2 OUTPUT r8.<3>, r8.<2>, r8.<1> 124717061 ~11% {4} r11 = JOIN r10 WITH project#FlowVar::FlowVar_internal::assignmentLikeOperation#ffff_10#join_rhs AS R ON FIRST 1 OUTPUT R.<1>, r10.<2>, r10.<1>, r10.<0> 66 ~0% {3} r12 = JOIN r11 WITH project#BasicBlocks::Cached::basic_block_member AS R ON FIRST 2 OUTPUT r11.<2>, r11.<3>, r11.<1> 66 {3} r13 = MATERIALIZE r12 AS antijoin_rhs 5658 ~14% {3} r14 = r9 AND NOT r13(r9.<0>, r9.<1>, r9.<2>) After manually pulling out the join inside the negation, the time per iteration drops from ~30 to <1s. The pipeline above is replaced with 892394 ~0% {4} r6 = r5 AND NOT FlowVar::FlowVar_internal::assignsToVar#fb AS R(r5.<3>, r5.<2>) 892394 ~0% {4} r7 = SCAN r6 OUTPUT r6.<1>, r6.<3>, r6.<0>, r6.<2> 5658 ~11% {3} r8 = JOIN r7 WITH BasicBlocks::Cached::bb_successor_cached#ff@staged_ext AS R ON FIRST 2 OUTPUT r7.<2>, r7.<1>, r7.<3> commit 9aa1404646a77ac48dbfc6c5445a9e82b031029c Author: Esben Sparre Andreasen Date: Thu Aug 27 09:44:45 2020 +0200 JS: fix formatting of InsecureCookie.qll commit 2ac732c50a2692cf24e8e78c6834feb6cc5b4964 Author: Tom Hvitved Date: Wed Aug 26 20:11:54 2020 +0200 C#: Teach autobuilder about `VsDevCmd.bat` commit 09025c2198b47c4596aa63971239677bb67c3ec1 Author: Rasmus Lerchedahl Petersen Date: Thu Aug 27 08:40:13 2020 +0200 Python: Fix test, update results and annotations commit 67278d9c9386e8c23975248c691c287cad61c688 Merge: 01a61469d d27442e84 Author: Esben Sparre Andreasen Date: Thu Aug 27 08:08:17 2020 +0200 Merge pull request #4141 from esbena/js/clarify-sanitization JS: make sanitization a "common" technique rather than "important" commit 736f76b685fd80b2ce82b1a89c71cf2c4dabf9a1 Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Thu Aug 27 02:12:17 2020 +0200 Simplify getQueryCall commit 30e7f958a8dfe8ec07a920dd93c4ccda1b62c4f2 Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Thu Aug 27 01:42:16 2020 +0200 Highlight API call commit c0edc08315b4754b9492801615e56800c5222026 Author: Robert Marsh Date: Wed Aug 26 16:19:03 2020 -0700 C++: Simplify non-member iterator operator models commit 994e845ab0540b254b5d3a793411f5f1cdd336ee Author: Robert Marsh Date: Wed Aug 26 16:08:39 2020 -0700 C++: use set literals in iterator models commit 7eeec0d76508f0658fc54f53d7c6a7b28ad0e2d3 Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Thu Aug 27 01:07:13 2020 +0200 Correct typo example commit cbe879ae73df44067124e293324ab641c96f3243 Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Thu Aug 27 01:05:49 2020 +0200 Correct typo examples commit 6f0cc16979c7b21d167fcce05f361221a0d320bb Author: Robert Marsh Date: Wed Aug 26 15:52:53 2020 -0700 C++: remove non-existent operators from model commit 68ff480892126c3a8dae80e36e5cf7cdb2a8c5ac Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Thu Aug 27 00:51:08 2020 +0200 Update .qhelp commit 13f443d2c3ce81f0b90c1f42236725c49fa6fc52 Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Thu Aug 27 00:48:29 2020 +0200 Update getLdapjsClientDNMethodName commit 616113aeff9e0c87a3fd3f184f5c57df44b17022 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Thu Aug 27 00:47:29 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-090/Ldapjs.qll Co-authored-by: Erik Krogh Kristensen commit 94bd9c6d3eeaf7b1fa2fa5b6ebd161c2cfdec36a Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Thu Aug 27 00:43:38 2020 +0200 Rename LdapjsDN to LdapjsDNArgument and add it as Sink commit 7d36b3b4d2e85d6090f193505e097ee7bfc1f00f Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Thu Aug 27 00:26:54 2020 +0200 Correct typo commit 2305a642eb1b0d6847054d056fd3f54150f419c6 Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Thu Aug 27 00:24:50 2020 +0200 Correct typo commit 23287aacee8eced8a4346f8aafd7165de39635b3 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Thu Aug 27 00:17:55 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-090/Ldapjs.qll Co-authored-by: Erik Krogh Kristensen commit f12ac8ca60516dd320532ba2feff73b9a32ed39d Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Thu Aug 27 00:17:33 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-090/Ldapjs.qll Co-authored-by: Erik Krogh Kristensen commit cd1d50b63791d7e7834067da76f35e34f48973db Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Wed Aug 26 23:50:15 2020 +0200 Update expected output commit dcf51c75e9f019de168e6d2d82ba56efc43abbe3 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Wed Aug 26 23:33:52 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql Co-authored-by: Esben Sparre Andreasen commit 3f6eef8437cd7f4aa76c28ac84ea6aeb28151325 Author: Porcupiney Hairs Date: Tue May 12 22:45:48 2020 +0530 Java: add websocket reads as remote flow source. Currently, JAX-WS reads are considered as untrusted. However, `java.net.http.WebSocket` reads are not marked as such. This PR adds support for the same. commit bd21fc5601ced760067119f3099da87e5e764a7a Author: Rasmus Wriedt Larsen Date: Wed Aug 26 20:37:48 2020 +0200 Python: Autoformat commit c24e3452f58f2c6baca483a215fbee7bc6e9f8bd Author: Rasmus Wriedt Larsen Date: Wed Aug 26 20:28:33 2020 +0200 Python: Add more expected collection taint steps commit 423139bc2206d02a505fb1216e13029255728e9d Author: Rasmus Wriedt Larsen Date: Wed Aug 26 20:21:15 2020 +0200 Python: Add additional taint steps for iterable-unpacking commit d27442e8466263674c953d7a4b39468a93b1ff4e Author: Esben Sparre Andreasen Date: Wed Aug 26 20:18:54 2020 +0200 Apply suggestions from code review Co-authored-by: Felicity Chapman commit afb160fbbb8748eea42dc72da1200a75b568817c Author: Rasmus Wriedt Larsen Date: Wed Aug 26 20:18:31 2020 +0200 Python: Add additional taint steps for for-iteration commit e2a89aa296047776c710552d59a60928e4f4c35b Author: Rasmus Wriedt Larsen Date: Wed Aug 26 19:31:11 2020 +0200 Python: Add additional taint steps for copy deepcopy was already handled somehow, don't really know how :D commit b974dadca178577bbd3541e5702e397828332854 Author: Rasmus Wriedt Larsen Date: Wed Aug 26 19:19:14 2020 +0200 Python: Add additional taint steps for containers commit b6049765a819124d5cf4481dcd141d7a55287f5c Author: Rasmus Wriedt Larsen Date: Wed Aug 26 19:16:20 2020 +0200 Python: Add a few more collection taint tests commit 32f9d30136f77dde2422d346af4eadf86e7b9434 Author: Rasmus Wriedt Larsen Date: Wed Aug 26 11:52:56 2020 +0200 Python: Add syntactic taint steps for json methods commit 41e24ae93f2074687047608ce768ca419018843f Author: Rasmus Wriedt Larsen Date: Wed Aug 26 11:45:44 2020 +0200 Python: Add non-syntactical test for taint of json methods commit 5f9aa4c3b9abf44c9b58b701bcda44c83f38a0ec Author: Rasmus Wriedt Larsen Date: Wed Aug 26 11:30:03 2020 +0200 Python: Restructure defaultAdditionalTaintStep tests This makes it easier to add a new test-case, and makes it easier to work with the existing files. It does have a downside on making it a bit more annoying looking at TestTaint.expected, and possible longer runtime, but I think it's still worth it. commit a1ada625964c747c66ff0409cd5037d355fcb78a Author: Rasmus Wriedt Larsen Date: Tue Aug 25 14:16:18 2020 +0200 Python: Remodel taint tests for shared lib I took the bits from ql/test/library-tests/taint/ that seemed easy to port. I left out namedtuple for now, but it is part of internal tracking ticket, so won't be forgotten. commit 12211657928e4b2749c356760f2313fde2b72682 Merge: d900a7073 01a61469d Author: Mathias Vorreiter Pedersen Date: Wed Aug 26 19:13:54 2020 +0200 Merge branch 'main' into mathiasvp/read-step-without-memory-operands commit 01a61469d3be365b134f646a36bcc3b7afecf841 Merge: b1946c60d 0f221ccfa Author: Dave Bartolomeo Date: Wed Aug 26 13:00:19 2020 -0400 Merge pull request #4137 from tausbn/python-cpp-make-inline-test-libs-language-agnostic CPP: Make inline expectation test library language agnostic. commit d900a70738a5fd5d708d8790ca97a41994e10806 Author: Mathias Vorreiter Pedersen Date: Wed Aug 26 18:10:21 2020 +0200 C++: Accept test changes in query tests commit dcabd37974e6648b36960b9e1812ce0a5ea803ef Author: Rasmus Lerchedahl Petersen Date: Wed Aug 26 17:58:35 2020 +0200 Python: Update test expectations commit bf6211f6396d7006c0006b8f59ba03beb25e5713 Merge: 8e2b2540f b1946c60d Author: Rasmus Lerchedahl Petersen Date: Wed Aug 26 17:50:17 2020 +0200 Merge branch 'main' of github.com:github/codeql into SharedDataflow_ParsimoniousFlowNodes commit 6c173047e6f5ea567631bbcf4266b7767e4c1ec8 Merge: 47e35c530 3140b43db Author: Rasmus Lerchedahl Petersen Date: Wed Aug 26 17:43:27 2020 +0200 Merge branch 'MagicMethods' of github.com:yoff/codeql into MagicMethods commit 47e35c530dfba08344c937ceed35c7ddb8c61656 Merge: de1c75c27 b1946c60d Author: Rasmus Lerchedahl Petersen Date: Wed Aug 26 17:42:44 2020 +0200 Merge branch 'main' of github.com:github/codeql into MagicMethods commit 0f221ccfa2b17fea5f33c0d46424a221da290fdb Merge: a824d75e4 b1946c60d Author: Taus Brock-Nannestad Date: Wed Aug 26 17:23:25 2020 +0200 Merge branch 'main' into python-cpp-make-inline-test-libs-language-agnostic commit dd8984dfc58b8919ee9bc8ed63e8a961c06bc9b7 Author: Mathias Vorreiter Pedersen Date: Wed Aug 26 16:14:58 2020 +0200 C++: Keep ExplicitFieldStoreQualifierNode private commit e193e12b3f28d647dde1e0806f6f4c36cda65e33 Author: Taus Brock-Nannestad Date: Wed Aug 26 16:10:04 2020 +0200 Python: Add support for inline test expectations library commit b1946c60dd7332550f91dccdf57f8885ecb40ef4 Merge: f60abd8cf 13148b42d Author: Taus Date: Wed Aug 26 16:06:01 2020 +0200 Merge pull request #4127 from RasmusWL/python-tainttracking-fstring Python: Handle f-strings in (current) taint tracking commit a824d75e4f5cfcbf74cf47e13f92af728f6b31fc Author: Taus Brock-Nannestad Date: Wed Aug 26 16:02:26 2020 +0200 C++: Add documentation for the `LineComment` class commit 18c65e9f73b22d1c13f024ea7bf9d42e1acd180f Author: Tamas Vajk Date: Wed Aug 26 15:57:41 2020 +0200 Fix typo in change notes commit e4807c0181c394ce4a66e46e8a36d99ad213ce16 Author: Mathias Vorreiter Pedersen Date: Wed Aug 26 15:41:43 2020 +0200 C++: Accept test changes commit 9d9c78c9f6797b79be45b5f057832e5c516ecb9f Author: Mathias Vorreiter Pedersen Date: Wed Aug 26 15:28:23 2020 +0200 C++: Use the information provided by the IR alias analysis to detect dataflow read and store steps. commit 2a8ee90828c9e955f84d5db3fb5639cff1c244e0 Author: Mathias Vorreiter Pedersen Date: Wed Aug 26 14:32:57 2020 +0200 C++: Demonstrate lack of flow when taking the address of a field and loading it afterwards commit 89305865d071b68b1dd71820676121850ab0e6e3 Author: Esben Sparre Andreasen Date: Wed Aug 26 15:41:54 2020 +0200 JS: make sanitization a "common" technique rather than "important" commit 3f54e5d310aed44988657dd4c0a066b0faf6d9bc Author: Tamas Vajk Date: Wed Aug 26 15:12:11 2020 +0200 Add change note commit f60abd8cf9240fbd75e736ea1fd6093cd4675c0f Merge: 00316dca8 3f04530d8 Author: Jonas Jensen Date: Wed Aug 26 13:44:02 2020 +0200 Merge pull request #4125 from geoffw0/oparray2 C++: Model operator[] commit 00316dca8baae1081771dfb927fb85a8307b9cbe Merge: 9ef827641 3ead154c9 Author: Nick Rolfe Date: Wed Aug 26 12:29:41 2020 +0100 Merge pull request #4120 from github/igfoo/global_vars C++: Give fewer types to global variables commit f8ba4c15796012590bfade9acb363754782bad89 Author: Taus Brock-Nannestad Date: Wed Aug 26 13:06:24 2020 +0200 CPP: Make inline expectation test library language agnostic. In preparation for adding this to Python, I have split out the definition of the comment class in a separate file (which will be specific to each language). commit 9ef827641f1cf9d56ff0f04d314f637ac4a8060c Author: Tamás Vajk Date: Wed Aug 26 12:41:00 2020 +0200 C#: Add .editorconfig file (#4129) commit 8a4754f8d75ad97d962f7e51aff85a18bf7802ce Author: Tamas Vajk Date: Wed Aug 26 11:48:02 2020 +0200 C#: Add missing QlDoc for frameworks commit 4be15af06a0eafa7018ccf65086073cc57506828 Author: Tamas Vajk Date: Wed Aug 26 11:18:40 2020 +0200 C#: Add missing QlDoc for various predicates commit ce68e458e0ef830d7774f3d519672ad80bef960c Author: Tamas Vajk Date: Wed Aug 26 10:32:23 2020 +0200 C#: Add QlDoc for predicates in Helpers commit 048428a6fa75f04d5d3f9506a80a137952be0e00 Author: Tamas Vajk Date: Wed Aug 26 09:31:13 2020 +0200 C#: Add missinq QlDoc for Serialization classes, remove unused DangerousCallable commit 3f04530d84408db74523c1b0016437a848066e67 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Aug 26 09:34:06 2020 +0100 C++: Autoformat. commit 36a9e4717818a65160c77ec10c02536377109c83 Author: Tamas Vajk Date: Wed Aug 26 09:13:01 2020 +0200 C#: Add missing QlDoc for dotnet base constructs commit 61427393beaa68a7b8f4d599249ebe983bcef8d0 Author: Erik Krogh Kristensen Date: Wed Aug 26 09:11:39 2020 +0200 add qldoc to Generators.qll file commit c9e22ab2716b29514435c9691776a73cbb3fe4a5 Merge: 97c107b92 b4c3ea41d Author: Max Schaefer <54907921+max-schaefer@users.noreply.github.com> Date: Wed Aug 26 07:47:28 2020 +0100 Merge pull request #4133 from owen-mc/docs/add-go-frameworks Add go frameworks to docs commit b4c3ea41d13caceaffc2b7bcbcdc39b0cf4e266b Author: Owen Mansel-Chan Date: Tue Aug 25 16:33:51 2020 +0100 Add go frameworks to docs commit 57f3c73d3d3f4786b0d38af6a94e96de8471d0b6 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Wed Aug 26 02:08:31 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-090/LdapInjectionCustomizations.qll Co-authored-by: Erik Krogh Kristensen commit 6979c394fe8f3c494b0e930773b00aebc26d7879 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Wed Aug 26 02:08:18 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-090/LdapInjection.qhelp Co-authored-by: Erik Krogh Kristensen commit 355c7bc3b5673eaba9e151f2cda3d44baf82ef71 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Wed Aug 26 02:08:08 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-090/LdapInjection.qhelp Co-authored-by: Erik Krogh Kristensen commit e027c8cc1356224ebda40585eeb838e8ea182269 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Wed Aug 26 01:48:05 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen commit a1f64e26cfd0056d2e35716f2cb579ec8d9171d7 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Wed Aug 26 01:47:52 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen commit 3bd7615a75167fc75c899197b80ca4bc1b35ea01 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Wed Aug 26 01:47:37 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen commit 57cf447188583ee0bb93533a5ae7d3cec2d69b4c Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Wed Aug 26 01:46:59 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen commit 28d3343e2b9fc5f2376548d7c4093ad00d52c0e0 Merge: 000fa33d5 b2cd98a98 Author: Robert Marsh Date: Tue Aug 25 19:36:13 2020 -0400 Merge pull request #4122 from jbj/constexpr-const-test C++: Demonstrate that constexpr implies const commit 83260740ff7150bf246e96d357c79d74de8ee32b Author: Robert Marsh Date: Tue Aug 25 13:28:13 2020 -0700 C++: QLDoc for `StdStringBeginEnd` commit c3a65148bc1c8353647c4af535635c685bf32f9b Author: Robert Marsh Date: Tue Aug 25 13:24:54 2020 -0700 C++: add some missing QLDoc commit 34ddbc0dc222cafe56c28e47533b7a018e654f00 Author: Robert Marsh Date: Tue Aug 25 13:22:00 2020 -0700 C++: add `std::string::end` to model commit fae915bbb5fce3fd4322bb0265921c7f407751ab Author: Rasmus Lerchedahl Petersen Date: Tue Aug 25 21:02:17 2020 +0200 Python: QL doc commit e6bfffaed327b2943bb241803e7b68aa0345c86d Author: Erik Krogh Kristensen Date: Mon Aug 17 22:56:51 2020 +0200 update basic-block on `ExceptionalFunctionReturnNode` and `FunctionReturnNode` commit 840f30f7bc31d715c1ba9ad725e08c26e08311f3 Author: Erik Krogh Kristensen Date: Tue Aug 25 12:46:45 2020 +0200 add basic-block test to dataflow tests commit 90422fe70520997f4a479d02c2a9eb997e3df4d0 Author: Erik Krogh Kristensen Date: Tue Aug 25 20:00:41 2020 +0200 add support for delegating yield commit 6a07e1e82b41da91ee3235ef3195e9f0ca76b3f7 Author: Erik Krogh Kristensen Date: Tue Aug 25 14:17:05 2020 +0200 add more passing tests commit afaaea8922d003dedf4699fb3caef84c5a8779fe Author: Erik Krogh Kristensen Date: Tue Aug 25 14:13:15 2020 +0200 support basic generators commit fdf45f02f1aa49803a6a00cde99351a865dd52cd Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Aug 25 18:53:11 2020 +0100 C++: Autoformat. commit c083c6235debcf041c2373e89a98b41ec6d60e92 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Aug 25 15:51:53 2020 +0100 C++: Explicitly model data flow in through reference return values. commit 997388b075eedc38f03abfda3f1ab99062a63742 Author: Tamas Vajk Date: Tue Aug 25 17:11:34 2020 +0200 Fix first set of code review comments commit 551ae42fb987813ab807bda8573ef68983a88a3a Merge: d67f57a0b 000fa33d5 Author: Rasmus Lerchedahl Petersen Date: Tue Aug 25 15:45:20 2020 +0200 Merge branch 'main' of github.com:github/codeql into SharedDataflow_NestedComprehensions commit d67f57a0bb67096ea3c5a7c757abc2655e0bfb13 Author: Rasmus Lerchedahl Petersen Date: Tue Aug 25 15:39:37 2020 +0200 Python: Remove dead code commit 000fa33d544a953de22f3dc9c735c9b158d24b35 Merge: 92c97b177 2608509fa Author: Taus Date: Tue Aug 25 15:38:14 2020 +0200 Merge pull request #4013 from yoff/SharedDataflow_SequenceFlow Python: Shared dataflow: Content flow commit 56b78a664eeb289bfdc99fc482008708dfc6160f Author: Rasmus Lerchedahl Petersen Date: Tue Aug 25 15:36:26 2020 +0200 Python: Store step for generators commit ecf3928ed1ed8e0afcb6f5a30f85797d9cf4d316 Author: Rasmus Lerchedahl Petersen Date: Tue Aug 25 15:21:08 2020 +0200 Python: Handle comprehensions with multiple `for`s commit 92c97b1778ce379beb6d257dc4029e2317d4b711 Merge: 74db25d80 2dbf83b57 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Tue Aug 25 14:14:47 2020 +0100 Merge pull request #4124 from RasmusWL/python-taint-tracking-string-methods Approved by yoff commit 592ed8a3a1e5747f1ea38a84f0e630b4cfa878c3 Author: Erik Krogh Kristensen Date: Tue Aug 25 14:02:57 2020 +0200 remove ordinary return flow from generator functions commit 76a07f7292656ed1711acf58a31350648f53a509 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Aug 25 12:30:06 2020 +0100 C++: Use [, ...] syntax. commit d31987d49679562621b9984f8064ac8582e15fee Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Aug 25 12:21:06 2020 +0100 C++: Additional QLDoc. commit 23a792b8c62edf1731090a26855b1c1fa14aa5d2 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Aug 25 12:13:32 2020 +0100 C++: Add tests of nested vectors. commit 2dbf83b579d3f7ffc86c7ae26920f16708ed941a Author: Rasmus Wriedt Larsen Date: Tue Aug 25 13:06:27 2020 +0200 Python: TaintTracking: Move tests of py3 string methods commit cf121cc4d07dd7383162741c3c3add4b5c71588e Author: Rasmus Wriedt Larsen Date: Tue Aug 25 13:05:27 2020 +0200 Python: TaintTracking: stringMethods => stringManipualtion commit 1cdb6be5312b0358b5c5d80bab714be2e236f7a4 Merge: e91581e9f 74db25d80 Author: Rasmus Lerchedahl Petersen Date: Tue Aug 25 13:05:13 2020 +0200 Merge branch 'main' of github.com:github/codeql into SharedDataflow_NestedComprehensions commit 238e0845aa0c319bd7771a6b38a937ec7dab8c91 Author: Rasmus Wriedt Larsen Date: Tue Aug 25 12:50:41 2020 +0200 Python: Minor refactoring commit 0439b83c60ada1efecb011061214bae5704d0cbf Author: Rasmus Wriedt Larsen Date: Tue Aug 25 12:49:36 2020 +0200 Python: Taint when using unicode commit 2a29e26687e4f132d56d3011009dcf0db29a85b3 Author: Rasmus Wriedt Larsen Date: Tue Aug 25 12:41:53 2020 +0200 Python: Fix grammar Co-authored-by: yoff commit 74db25d80c964622ff2aaac13f6f23025acd5906 Author: Tamás Vajk Date: Tue Aug 25 11:44:08 2020 +0200 C#: Enable nullability on Semmle.Extraction.CIL.Driver (#4114) commit 722b1a24f665596a6026cc4c6833fa49e4fc760c Merge: 844abc51e 61d464889 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Tue Aug 25 10:20:32 2020 +0100 Merge pull request #4087 from erik-krogh/thisJsx Approved by asgerf commit 844abc51e85be7888996293cef52b8d363e33924 Merge: dc62cd166 b0d4e7965 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Tue Aug 25 10:17:28 2020 +0100 Merge pull request #4108 from erik-krogh/packType Approved by asgerf commit 483bd0e8633420c6e9f9cd158bb3c718b17d2292 Author: Rasmus Wriedt Larsen Date: Tue Aug 25 11:15:11 2020 +0200 Python: Fix shared taint tracking tests Since there was a .ql file, qltest tried to run a test in test/experimental/dataflow/taintracking/ which failed since there was no code. commit 3140b43db2862b08d1ec975e0bba6b453c0f4eab Author: yoff Date: Tue Aug 25 10:48:01 2020 +0200 Apply suggestions from code review Co-authored-by: Taus commit dc62cd166c8bb599d870c91f798f5e970b56bf83 Author: Tamás Vajk Date: Tue Aug 25 08:40:30 2020 +0200 C#: Enable nullability checks in Semmle.Extraction.Tests (#4112) commit 9aa373516530b623b436f860625b1088c149bf05 Author: Robert Marsh Date: Mon Aug 24 14:19:34 2020 -0700 C++: add tests for non-std:: iterators commit 66e3739e726033c02a034c3c99bde1d7fee87b88 Author: Tamas Vajk Date: Mon Aug 24 22:41:08 2020 +0200 Fix failing PrintAst test commit b0d4e79653c39a5dd3e2cb0c6506bd316abaa522 Author: Erik Krogh Kristensen Date: Mon Aug 24 21:36:34 2020 +0200 split out trap tests to avoid "package.json" naming conflict in trap test commit adbfad21efeda61e5eedccc0e532816caf21a4f9 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Aug 24 18:05:30 2020 +0100 C++: Correct the localFlow test. commit 22f5ae4ad432f7a4ad60181ccdeddf145e667d92 Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Mon Aug 24 18:53:37 2020 +0200 Format code commit c0aaed2fac689c2b80f7d545ce69aec7d102ebed Merge: ae807f7f3 e2c6a01c0 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Aug 24 17:36:18 2020 +0100 Merge branch 'main' into oparray2 commit ae807f7f33964008e4e049c02e985baa28f6fe81 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Aug 24 16:58:23 2020 +0100 C++: Autoformat. commit 13148b42d314e9cc7d5971cf2cbbbcaa9641d1e1 Author: Rasmus Wriedt Larsen Date: Mon Aug 24 17:20:16 2020 +0200 Python: Handle taint of f-strings commit 2f090df6d3c809e835cebb5118f9381f582d72a6 Author: Rasmus Wriedt Larsen Date: Mon Aug 24 17:16:49 2020 +0200 Python: Transform comments to QLDoc for security.strings.Basic commit 2608509fa7cb8212d72dafa98836e5e7b1c4ba95 Merge: e1343c7f1 e2c6a01c0 Author: Rasmus Lerchedahl Petersen Date: Mon Aug 24 17:16:33 2020 +0200 Merge branch 'main' of github.com:github/codeql into SharedDataflow_SequenceFlow commit e91581e9fabaa90949914796fa7340b768390f5d Author: Rasmus Lerchedahl Petersen Date: Mon Aug 24 17:15:31 2020 +0200 Python: Experiments with nested comprhensions commit be2acc00dbedeb5de90276f48a382149ba70c480 Author: Rasmus Wriedt Larsen Date: Mon Aug 24 17:14:51 2020 +0200 Python: Add test for tainted f-string commit e2c6a01c0086dcf2fdf0df05b8c8998894dcc61f Merge: 765c40ef0 bbbb0a2c5 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Aug 24 15:57:10 2020 +0100 Merge pull request #4097 from erik-krogh/createRequire Approved by esbena commit d96ef73033c2b8521b0892714b5a983bc9564d07 Author: Rasmus Wriedt Larsen Date: Mon Aug 24 16:29:30 2020 +0200 Python: Handle taint for f-strings Which we seem to not handle in the current taint tracking :O f-strings needs to be Python 3 only, so enabled that test setup. I really liked the idea for having the version specific tests right next to the normal tests, so you don't have to look in test/experimental/3/dataflow/i/will/forget/to/look/here. commit 3dea6b32182c0dce8a7c91d0df7be3ff3b3e40e9 Author: Tamas Vajk Date: Mon Aug 24 16:10:42 2020 +0200 C#: Change implicitly sized array test input commit 7516825b5faa3cc24df18f2b559aec583bd42510 Author: Tamas Vajk Date: Mon Aug 24 16:08:13 2020 +0200 C#: Fix computed sizes for implicitly sized array creation commit 1c38a4d5d6353cf2cd79ad380654011e959b1a94 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Aug 24 14:33:51 2020 +0100 Update cpp/ql/src/semmle/code/cpp/dataflow/internal/TaintTrackingUtil.qll Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> commit 699cafa890d5d269649e1f559d1f9a67840ed6ec Author: Tamas Vajk Date: Mon Aug 24 15:27:35 2020 +0200 C#: Add implicitly sized array creations to tests commit d3c8ffb995b1f838d83afbab73ce5ed5f4a8b714 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Aug 24 11:27:54 2020 +0100 C++: Clean up, comment, and restrict the new flow to the post-update node of the returned reference. commit f2caa8a2b0b4d18efd52b630d0ccb9595d962d0d Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Aug 24 10:23:40 2020 +0100 C++: Reverse taint through function models returning a reference. commit f25ef26c37650f347283ffd1f999689424b16a84 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Aug 21 20:16:52 2020 +0100 C++: Permit taint flow to the left side of an assignment. commit 1da78ada14195581d3cc364c9b43ce7e95f89c81 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Aug 21 12:04:40 2020 +0100 C++: Model 'operator[]' and 'at' for std::string, std::vector and other containers. commit cb4b4e91abc61e548d70bf7a9430dbd388439961 Author: Rasmus Wriedt Larsen Date: Mon Aug 24 14:50:46 2020 +0200 Python: Taint for string multiplication commit b688fe68d60d09e0f59399e631b2e9b65afd5ab3 Author: Rasmus Wriedt Larsen Date: Mon Aug 24 14:44:22 2020 +0200 Python: Add options file to shared dataflow tests Since there isn't one in top-level of experimental, making a single import made tests go really slow :| commit 5125c7a55c645d382cb0a5f805f3cccd03c71a96 Author: Rasmus Wriedt Larsen Date: Mon Aug 24 14:44:01 2020 +0200 Python: Add taint tests for encode/decode functions commit f6770c5b88a61bbb9983e93aa83fd86b4e86633e Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Aug 24 13:43:48 2020 +0100 C++: Add tests for std::string 'operator[]' and 'at()'. commit 31b398937a6f88e41b0b25dabbeab4588c0cb9b2 Author: Rasmus Wriedt Larsen Date: Mon Aug 24 14:17:09 2020 +0200 Python: Handle taint from `bytes(obj)` commit 1e447c5ca2c2b8c740258865715576a59a95afe7 Author: Rasmus Wriedt Larsen Date: Mon Aug 24 14:15:27 2020 +0200 Python: Handle taint for % formatting commit 80745e8881067ba6e44246fc5159057ed04c4687 Author: Rasmus Wriedt Larsen Date: Mon Aug 24 13:53:09 2020 +0200 Python: Model string methods in shared taint tracking library commit a77f118b62775be4216a15353e0e4e4166729831 Author: Rasmus Wriedt Larsen Date: Thu Aug 20 17:07:10 2020 +0200 Python: Shared taint tracking: Handle string concat + subcript commit 61f89ca3c34f5d0145b2fbeae27897d5ccad9131 Author: Rasmus Wriedt Larsen Date: Thu Aug 20 16:55:34 2020 +0200 Python: Add tests for shared taint tracking for strings I adopted the TestTaint testing setup that I made for the "old" taint tracking tests. This time around we should figure out if we can use .qlref or similar so it doesn't end up in multiple copies that are not kept up to date :| The `repr` predicate could probably be placed somewhere better. For now I just wanted something that could help me. I considered just expanding the `repr` predicate in `ql/src/semmle/python/strings.qll`, but since it's currently used by queries, I didn't want to do anything about it. Anyway, the output it gives is much more useful than seeing this ;) ``` | test.py:20 | ok | str_operations | test.py:20:9:20:10 | ts | | test.py:21 | fail | str_operations | test.py:21:9:21:18 | BinaryExpr | | test.py:22 | fail | str_operations | test.py:22:9:22:18 | BinaryExpr | | test.py:23 | fail | str_operations | test.py:23:9:23:21 | Subscript | | test.py:24 | fail | str_operations | test.py:24:9:24:13 | Subscript | | test.py:25 | fail | str_operations | test.py:25:9:25:18 | Subscript | | test.py:26 | fail | str_operations | test.py:26:9:26:13 | Subscript | | test.py:27 | fail | str_operations | test.py:27:9:27:15 | str() | | test.py:35 | fail | str_methods | test.py:35:9:35:23 | Attribute() | | test.py:36 | fail | str_methods | test.py:36:9:36:21 | Attribute() | | test.py:37 | fail | str_methods | test.py:37:9:37:22 | Attribute() | | test.py:38 | fail | str_methods | test.py:38:9:38:23 | Attribute() | | test.py:40 | fail | str_methods | test.py:40:9:40:19 | Attribute() | | test.py:41 | fail | str_methods | test.py:41:9:41:23 | Attribute() | | test.py:42 | fail | str_methods | test.py:42:9:42:36 | Attribute() | | test.py:44 | fail | str_methods | test.py:44:9:44:25 | Attribute() | | test.py:45 | fail | str_methods | test.py:45:9:45:45 | Attribute() | | test.py:47 | fail | str_methods | test.py:47:9:47:21 | Attribute() | | test.py:48 | fail | str_methods | test.py:48:9:48:19 | Attribute() | | test.py:49 | fail | str_methods | test.py:49:9:49:18 | Attribute() | | test.py:51 | fail | str_methods | test.py:51:9:51:32 | Attribute() | | test.py:52 | fail | str_methods | test.py:52:9:52:34 | Attribute() | | test.py:54 | fail | str_methods | test.py:54:9:54:21 | Attribute() | | test.py:55 | fail | str_methods | test.py:55:9:55:19 | Attribute() | | test.py:56 | fail | str_methods | test.py:56:9:56:18 | Attribute() | | test.py:57 | fail | str_methods | test.py:57:9:57:21 | Attribute() | | test.py:58 | fail | str_methods | test.py:58:9:58:18 | Attribute() | | test.py:59 | fail | str_methods | test.py:59:9:59:18 | Attribute() | | test.py:60 | fail | str_methods | test.py:60:9:60:21 | Attribute() | | test.py:62 | fail | str_methods | test.py:62:9:62:26 | Attribute() | | test.py:63 | fail | str_methods | test.py:63:9:63:42 | Attribute() | | test.py:65 | fail | str_methods | test.py:65:9:65:26 | Attribute() | | test.py:66 | fail | str_methods | test.py:66:9:66:42 | Attribute() | | test.py:69 | fail | str_methods | test.py:69:9:69:25 | Attribute() | | test.py:70 | fail | str_methods | test.py:70:9:70:26 | Attribute() | | test.py:71 | fail | str_methods | test.py:71:9:71:22 | Attribute() | | test.py:72 | fail | str_methods | test.py:72:9:72:21 | Attribute() | | test.py:73 | fail | str_methods | test.py:73:9:73:23 | Attribute() | | test.py:78 | ok | str_methods | test.py:78:9:78:39 | Attribute() | ``` commit b2cd98a98f6312f9c7ec0f33c59a0b2f5e9f7e80 Author: Jonas Jensen Date: Mon Aug 24 13:42:40 2020 +0200 C++: Confirm correct behaviour on C++20 Making `constexpr` imply `const` was correct for C++11 and was a correct emulation of a GCC bug on GCC < 5.0. This test confirms that the problem isn't there in C++20. commit 07610e0899bcd5902658073b3b39f381a0e66541 Author: Philippe Antoine Date: Mon Aug 24 13:12:54 2020 +0200 Format document commit 3ead154c9ac768fe305fa44d012760356e70f284 Author: Ian Lynagh Date: Mon Aug 24 11:51:52 2020 +0100 C++: Add VariableDeclarationEntry test to library-tests/variables/global commit 309346841ab6bb6163ab00c70c03da917a60258a Merge: 5acfd92e0 765c40ef0 Author: Erik Krogh Kristensen Date: Mon Aug 24 12:44:24 2020 +0200 Merge branch 'main' into packType commit 5acfd92e0fef7a7ba959f577d251d314a2190c31 Author: Erik Krogh Kristensen Date: Mon Aug 24 12:42:19 2020 +0200 bump the extractor version commit d633410e3cfd15d3adae2ecbd16832f85531c793 Author: Erik Krogh Kristensen Date: Mon Aug 24 12:42:08 2020 +0200 make the extractor not crash on invalid "package.json" files commit eb84f97e7f6a12a8fab3fe231003c5e5a3e3a7d7 Merge: db57f3661 765c40ef0 Author: Erik Krogh Kristensen Date: Mon Aug 24 12:20:48 2020 +0200 Merge branch 'main' into ts4 commit 765c40ef0377e59e9ded1bf5324143badf615be5 Merge: b8d6f7674 65a1769d4 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Aug 24 11:18:42 2020 +0100 Merge pull request #4019 from erik-krogh/asyncCalls Approved by asgerf commit d82fee11b1b72a1739b34c48dcf6c1119be8817f Author: Anders Schack-Mulligen Date: Mon Aug 24 11:51:04 2020 +0200 Java: Add data flow for record getters. commit cd8e9a1eced851de066ef19d08d8c3394d9f5f14 Author: Jonas Jensen Date: Mon Aug 24 11:39:41 2020 +0200 C++: Demonstrate that constexpr implies const This test shows that a member function declared `constexpr` also gets a `const` specifier. commit b8d6f76749edcb1cc1278f568940a21c38d405c5 Merge: a93a84fb2 2817602a9 Author: Taus Date: Mon Aug 24 11:36:30 2020 +0200 Merge pull request #4056 from yoff/SharedDataflow_ParameterTests Python: Shared dataflow, parameter routing tests commit fb62ce6d25dae6464d387efaec2586e185b7a3f6 Author: Ian Lynagh Date: Mon Aug 24 00:49:33 2020 +0100 C++: Give fewer types to global variables Follows change in the extractor. commit 6f750dac882a2e865c1f4e4cea51bdc7bf55f4bf Merge: eed6fe96a a93a84fb2 Author: Mathias Vorreiter Pedersen Date: Sun Aug 23 18:46:07 2020 +0200 Merge remote-tracking branch 'origin/main' into alternative-instruction-operand-flow commit 3e97ec85b228d28f67d1bbeaf933f2c12bdc11bb Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Sun Aug 23 15:24:29 2020 +0200 Add CodeQL to detect LDAP Injection in JS commit bc0d21879d77e750f38ea0ae53913cb874e9e19a Merge: 141d24081 a93a84fb2 Author: Robert Marsh Date: Fri Aug 21 14:36:27 2020 -0700 Merge branch 'main' into rdmarsh2/cpp/input-iterators-1 Resolve test conflict commit 141d240813b35e2a32c36afc54632ab2c7f72cdf Author: Robert Marsh Date: Fri Aug 21 14:22:44 2020 -0700 C++: autoformat commit 4c82753e8d2b1febc87eb2463301a761ede4a9b0 Author: Robert Marsh Date: Fri Aug 21 14:22:32 2020 -0700 C++: remove constexpr in stl.h temporarily commit 94d4e05c257482427c34a7238414b1dfdb0018db Author: Robert Marsh Date: Fri Aug 21 14:00:40 2020 -0700 C++: Fix iterator taint flow commit 656340f5c66d335bc203159bc2978e88852022f1 Author: Robert Marsh Date: Fri Aug 21 13:48:36 2020 -0700 C++: more tests for string iterator flow commit db57f3661ec2fd8348267a68e3747f4458f17dc0 Merge: e00951edf a93a84fb2 Author: Erik Krogh Kristensen Date: Fri Aug 21 15:08:30 2020 +0200 Merge branch 'main' into ts4 commit 65a1769d43c587c771c47a82071daa44e8b702fc Merge: e1ecc4662 a93a84fb2 Author: Erik Krogh Kristensen Date: Fri Aug 21 14:58:27 2020 +0200 Merge branch 'main' into asyncCalls commit 1b655f90467244810c414b75385fd0f3d132704f Author: Erik Krogh Kristensen Date: Fri Aug 21 14:45:24 2020 +0200 use threadsafe cache stored in ExtractorState commit 7aca84cd45c3951604a38cf61ceeb1a4dc8a3643 Author: Erik Krogh Kristensen Date: Fri Aug 21 14:31:49 2020 +0200 search directly for "package.json" instead of iterating through the files in a folder commit 3f0f2c796c09c690b605a99541d3db96729c70a7 Author: Erik Krogh Kristensen Date: Fri Aug 21 14:27:47 2020 +0200 pass `extension` instead of `locationManager` to `isAlways*Module` commit bbbb0a2c5e0c59ccd0a01adde1c19a56f18bc5d6 Author: Erik Krogh Kristensen Date: Fri Aug 21 14:14:05 2020 +0200 specialize `module.createRequire` support to ES2015 modules commit a93a84fb2e75d5181094260e9cc7d7cffca90ae0 Merge: d05954e5c 46f10fc03 Author: Calum Grant <42069085+calumgrant@users.noreply.github.com> Date: Fri Aug 21 11:57:29 2020 +0100 Merge pull request #4065 from hvitved/csharp/dataflow-type-restriction C#: Restrict `DataFlowType` to types belonging to `Node`s commit d05954e5ccf62d77fbf49fbdc0d30c7a9bc12bbf Merge: 86b91cec8 7fb8e0e27 Author: yoff Date: Fri Aug 21 12:20:22 2020 +0200 Merge pull request #4109 from RasmusWL/python-basic-taint-tracking Python: Basic taint tracking with shared library commit e1343c7f1e36dd25f12ac7e1434032e57f292081 Author: Rasmus Lerchedahl Petersen Date: Fri Aug 21 11:15:04 2020 +0200 Python: Support set literals. commit ccff84d5463b5a5e2dc96766fff2991ab172bb3b Author: Rasmus Lerchedahl Petersen Date: Fri Aug 21 10:40:22 2020 +0200 Python: Test flow into conprehension commit f9b1c5e4bd4e36355e98ea32eadb7b60454cc889 Author: Rasmus Lerchedahl Petersen Date: Fri Aug 21 10:04:27 2020 +0200 Python: Fix bug pointed out by reviewer commit e00951edf078d8d99752f14722e2d9ce8994867e Author: Erik Krogh Kristensen Date: Fri Aug 21 09:50:27 2020 +0200 update TypeScript to 4.0.2 commit bfd9c0860f19eefc9e8a23496ffc15503e6cf8da Author: yoff Date: Fri Aug 21 09:43:29 2020 +0200 Apply suggestions from code review Co-authored-by: Rasmus Wriedt Larsen commit 8e2b2540facb9f0d03c51b8f7a00391336ec5081 Author: yoff Date: Fri Aug 21 09:39:00 2020 +0200 Apply suggestions from code review Co-authored-by: Rasmus Wriedt Larsen commit 86b91cec8a6a37fb0671525fb38222ad3712ef65 Merge: ea77828a6 b9e3b327d Author: Tom Hvitved Date: Fri Aug 21 09:22:05 2020 +0200 Merge pull request #4111 from tamasvajk/feature/nullability-extraction C#: Fix nullability warning in Semmle.Extraction commit ea77828a6a765f90fc1c8060193e87395417f684 Merge: 29183fa0a b8cde180b Author: Tom Hvitved Date: Fri Aug 21 09:09:20 2020 +0200 Merge pull request #4116 from hvitved/csharp/print-ast-order-top-level C#: Order top-level elements by location in `PrintAst.qll` commit b8cde180b91d1f6c902fb4e18854e1006c1050f6 Author: Tom Hvitved Date: Thu Aug 20 18:34:47 2020 +0200 C#: Order top-level elements by location in `PrintAst.qll` commit 29183fa0a1d08ae12fea2e90c26c5441d01d86e8 Merge: 508ade29f cef681d00 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Thu Aug 20 23:07:02 2020 +0100 Merge pull request #4067 from erik-krogh/noBin Approved by esbena commit 508ade29f47fb05d470930051b4102d39d4ebb6c Merge: d56a03389 fa8edeed6 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Thu Aug 20 21:23:24 2020 +0100 Merge pull request #4106 from erik-krogh/depTracked Approved by esbena commit 9cdee63ed7967f32a585f502caac1674ba316ea7 Author: Tamas Vajk Date: Wed Aug 19 14:53:40 2020 +0200 C#: Enable nullability checks on Semmle.Extraction.CIL commit b9e3b327d647145121292fd23712c93051051fd2 Author: Tamas Vajk Date: Thu Aug 13 10:14:39 2020 +0200 C#: Fix nullability warning in Semmle.Extraction commit cef681d009addd7e0ad0b6a0f127219bc6650842 Author: Erik Krogh Kristensen Date: Thu Aug 20 15:58:44 2020 +0200 bump extractor version (again) commit 68f7942820c982bc0824dcc12fb0e98cfee06f30 Merge: bf88c81f7 d56a03389 Author: Erik Krogh Kristensen Date: Thu Aug 20 15:58:15 2020 +0200 Merge branch 'main' into noBin commit d56a03389c99a207fd03ba7bd1cf1c64f81fe6e3 Merge: 2a8ff8785 3d171f358 Author: Jonas Jensen Date: Thu Aug 20 15:53:35 2020 +0200 Merge pull request #4107 from geoffw0/vecmethods C++: Initial models for std::vector commit bcad18f490fc6bb4086d0d444366db256793deb3 Author: Anders Schack-Mulligen Date: Thu Jun 25 12:49:39 2020 +0200 Java: Use the instance argument type in call contexts. commit 94e6fd9199d118c92a1f80107f1be69690062430 Author: Rasmus Lerchedahl Petersen Date: Thu Aug 20 15:16:23 2020 +0200 Python: Convenience methods asVar, asCfgNode, and asExpr commit fa8edeed6a146aa836567ba5476fcc7c36cb4fce Author: Erik Krogh Kristensen Date: Thu Aug 20 15:05:38 2020 +0200 change StoredXss example to use TypeTracking commit 906705f84c2f4adedadca1ed6f5f88a5f38f96df Author: Erik Krogh Kristensen Date: Thu Aug 20 15:01:40 2020 +0200 add `SourceNode` example to the `TrackedNode` deprecation description commit 5a734730de1b7a4de1fd479881714a550e9f8869 Author: Rasmus Lerchedahl Petersen Date: Thu Aug 20 15:00:42 2020 +0200 Python: Control flow nodes are dataflow nodes iff they are expression nodes We could refine this later, but it seems to work for now... commit 7fb8e0e2774c21af9f5c0868fdc51f7567a93ee4 Author: Rasmus Wriedt Larsen Date: Thu Aug 20 14:24:35 2020 +0200 Python: Add basic shared taint tracking test commit 0baac8fd54e64b86f0a496a020d99abe9919ede7 Author: Rasmus Wriedt Larsen Date: Tue Aug 18 17:36:10 2020 +0200 Python: Adjust shared taint tracking skeleton So it fits the setup from Java/Go, with AdditionalTaintStep class. commit 3d171f358a781db972d43481c3cc9775ddd6a95e Merge: 258b61c5f 2a8ff8785 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 20 13:29:28 2020 +0100 Merge remote-tracking branch 'upstream/main' into vecmethods commit 372e1a3d84cadd7d21ed7f558df6572f897ee648 Author: Erik Krogh Kristensen Date: Thu Aug 20 14:26:15 2020 +0200 support the "type" field on `package.json` files while extracting commit 2a8ff8785a5f726caadcafb6d4c910f8ce4aedef Author: Tamás Vajk Date: Thu Aug 20 14:24:43 2020 +0200 C#: Add AST printing (#4038) commit 258b61c5f89e5b25734f7ca8e93bc5ea254a51fd Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 20 12:53:23 2020 +0100 Update cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll Co-authored-by: Jonas Jensen commit 689c637d48113961afe96265ae060279eb9685e3 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 20 12:52:40 2020 +0100 C++: Rename things. commit ec7a65777bbbbb06328978fbbccc85bdf33b4c81 Merge: 6adedac33 341ab2ee0 Author: Anders Schack-Mulligen Date: Thu Aug 20 13:17:07 2020 +0200 Merge pull request #3855 from JLLeitschuh/feat/JLL/jOOQ_SQL_injection Add jOOQ methods as SQL Injection Sinks commit bf88c81f78584b7f56a70af8276067807a51c601 Author: Erik Krogh Kristensen Date: Thu Aug 20 12:57:48 2020 +0200 bump extractor version commit a3475693856b0f6ab4037f7f917ff9c6c43f6505 Author: Erik Krogh Kristensen Date: Thu Aug 20 12:57:05 2020 +0200 inline StandardCharsets.UTF_8 commit 410ef8fe0eab786aec263510c47f82d5e1c1aacb Author: Erik Krogh Kristensen Date: Thu Aug 20 12:50:43 2020 +0200 exit early if the default encoding is not UTF-8 commit fe41521e0c45096cb5d948e7935a5a43c2fab072 Author: Erik Krogh Kristensen Date: Thu Aug 20 12:46:17 2020 +0200 add tutorial for how to get around TrackedNodes deprecation commit 61158e759bcd22de9b0533fa31fa59263f293989 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 20 10:57:17 2020 +0100 C++: Improve StdContainerConstructor model. commit acd143710347debbc38d231a3f0176440ba5742b Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 20 10:46:12 2020 +0100 C++: Change note. commit f2ac4fa94a24995745b9623a9b753913599719c9 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 20 10:44:54 2020 +0100 C++: Autoformat. commit cda9fd250bac5ca073b802ad0255c8de3812112e Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 20 09:31:31 2020 +0100 C++: Model vector methods. commit 620126d38cd9dbc0d6b4d60eb8d1fdb8dc8e8614 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Aug 18 19:25:47 2020 +0100 C++: Add vector taint cases to test. commit 8f68f512dfdf62efd67e119c0d94017183827384 Author: Erik Krogh Kristensen Date: Thu Aug 20 11:26:22 2020 +0200 deprecate TrackedNodes.qll commit 43c8efdf63671b028cbc0c4d91bc10a749f48b80 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Aug 19 17:29:54 2020 +0100 C++: Repair the range based for test. commit 6adedac337d43b9e8c47d1ee3bd31e5fadc488e6 Merge: 65b4d35ad 5b42e242a Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Thu Aug 20 10:05:30 2020 +0100 Merge pull request #4096 from erik-krogh/qlMod Approved by esbena commit 8afa92d881466450d68725b5025d62d53264d7d9 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Aug 18 13:14:24 2020 +0100 C++: Add more detail to the vector class in the test stl.h. commit 65b4d35add69bb0ec72bb69898b9a4b1d9d8ba0b Merge: 6dc124441 beeadea48 Author: Tom Hvitved Date: Thu Aug 20 10:14:56 2020 +0200 Merge pull request #4055 from tamasvajk/feature/partial-methods C#: Add body to partial methods commit 6dc124441073dc3d27565525237033223ef49573 Merge: aa522b54c acb08287a Author: Tom Hvitved Date: Thu Aug 20 10:11:36 2020 +0200 Merge pull request #4064 from hvitved/csharp/gvn-speedup C#: Speed up `Implements.qll` and `Unification.qll` commit aa522b54c14075c49caa73406612706cd4c8e693 Merge: a457d54ad b1c0e6f62 Author: Mathias Vorreiter Pedersen Date: Thu Aug 20 09:22:05 2020 +0200 Merge pull request #4098 from jbj/SimpleRangeAnalysis-mul-constant C++: Support multiplication by constants in range analysis commit 5b42e242af6a90fdbacdf74a64c363514aae5adb Author: Erik Krogh Kristensen Date: Thu Aug 20 09:18:26 2020 +0200 add change note for supporting ".cjs" files commit b1c0e6f626690e2434ecaa2da24a50c544aaba41 Merge: 01a226bdc a457d54ad Author: Jonas Jensen Date: Thu Aug 20 08:20:31 2020 +0200 Merge remote-tracking branch 'upstream/main' into SimpleRangeAnalysis-mul-constant commit 6b1243e8b4bcf638f949199d9554e50460d7b63b Author: Robert Marsh Date: Wed Aug 19 16:23:00 2020 -0700 C++: respond to PR comments on Iterator.qll commit 20188b7bc2358ca56d84088bb3f941a6271c0028 Author: Robert Marsh Date: Tue Aug 18 17:05:37 2020 -0700 C++: input iterator models commit d32d6c9d8d60114e13ac74f528f43beb1cb2a997 Author: Robert Marsh Date: Tue Aug 18 14:17:01 2020 -0700 WIP: more iterator cases commit d50dd090be6998afae7fc1872f6a927eeed45c8a Author: Robert Marsh Date: Tue Aug 18 13:29:34 2020 -0700 C++: rename to Iterator*Operator commit 85af74eb06fe30576fa005d8145c1deb5b53c1fa Author: Robert Marsh Date: Mon Aug 17 17:31:16 2020 -0700 C++: Models for bidirectional input iterators commit a457d54ad1e65938c4fcd2a648322859faa4ebda Merge: b14bc4275 21d16d13f Author: Robert Marsh Date: Wed Aug 19 14:42:04 2020 -0400 Merge pull request #4078 from jbj/SimpleRangeAnalysis-AssignMulExpr C++: Range analysis for unsigned AssignMulExpr commit 18e946d4aae17c30367a66a6dfbba6d1b2f0b61a Author: Rasmus Lerchedahl Petersen Date: Wed Aug 19 17:56:02 2020 +0200 Python: Small rearrangement commit b14bc42756d7086d27985f37aa04b29750461ec8 Merge: a23bb6d5e d76b25ec2 Author: Jonas Jensen Date: Wed Aug 19 16:40:46 2020 +0200 Merge pull request #4090 from geoffw0/strmethods C++: Model taint through many more methods in std::string commit a23bb6d5ec973c9a54febd660ee73521d90c8784 Merge: e7709f73e bdf4ae5f2 Author: Tom Hvitved Date: Wed Aug 19 16:12:22 2020 +0200 Merge pull request #4095 from hvitved/csharp/dataflow/ap5 C#: Increase `accessPathLimit` from 3 to 5 commit 21d16d13fce104fc65bf7577d49c72c32317f35a Merge: edc5e5fbc e7709f73e Author: Jonas Jensen Date: Wed Aug 19 14:50:40 2020 +0200 Merge remote-tracking branch 'upstream/main' into SimpleRangeAnalysis-AssignMulExpr commit e7709f73e9da9b5b0134061b39dc2e93b9019574 Merge: 83884c0dc 13577967f Author: Anders Schack-Mulligen Date: Wed Aug 19 13:30:01 2020 +0200 Merge pull request #4099 from hvitved/java/dataflow/unique-encl-callable Java: Use `unique` aggregate in `Node::getEnclosingCallable()` commit 28578fd5721b4ccae192d21efdcd723091ad6743 Author: Anders Schack-Mulligen Date: Wed Aug 19 13:12:24 2020 +0200 Java: Autoformat. commit 83884c0dc527298597f19dae63bd6c18c118827b Merge: 3e8f62fa5 2e2f99cab Author: Jonas Jensen Date: Wed Aug 19 12:58:27 2020 +0200 Merge pull request #4089 from jbj/jbj/printFloat-precise C++: Accept float.toString changes in tests commit bd53a711d33071108efa0680abe403d296e4986d Merge: 176aa06fa 3e8f62fa5 Author: Rasmus Lerchedahl Petersen Date: Wed Aug 19 11:42:41 2020 +0200 Merge branch 'main' of github.com:github/codeql into SharedDataflow_SequenceFlow commit eed6fe96ae797173e89b6f9114a4a054a74c0399 Merge: bb3254d4a 1f432dc45 Author: Mathias Vorreiter Pedersen Date: Wed Aug 19 11:18:51 2020 +0200 Merge branch 'main' into alternative-instruction-operand-flow commit 3d5c1560e44291f3bb9ee267c1f2b050f7066167 Author: Erik Krogh Kristensen Date: Tue Aug 18 14:10:18 2020 +0200 basic support for `.cjs` files commit 103f739d16fed34eaf3c66695e8c29e475f0940f Author: Erik Krogh Kristensen Date: Tue Aug 18 13:03:16 2020 +0200 add test for types of modules commit 3e8f62fa5f77f5872adbd406ac1bdad729a64f89 Merge: 2319c289a d7849bc13 Author: Jonas Jensen Date: Wed Aug 19 09:58:49 2020 +0200 Merge pull request #4100 from nickrolfe/ssa_errors C++: fix compilation errors in ssa.cpp commit 2319c289aa346231ec6757f9684a68d61a1c14bf Merge: bc7791624 246d9b8c7 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Wed Aug 19 08:47:07 2020 +0100 Merge pull request #4092 from erik-krogh/strictExtractor Approved by esbena commit 176aa06fad13406b7471e99c868e349eabbe2b12 Author: Rasmus Lerchedahl Petersen Date: Wed Aug 19 09:21:16 2020 +0200 Python: Address review comments commit 5e84754f731906e5dced4da7c74b744a15f4ee89 Author: yoff Date: Wed Aug 19 08:03:47 2020 +0200 Update python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll Co-authored-by: Rasmus Wriedt Larsen commit 06bd436aea945c46783ff50db72a0124e37f0c12 Author: yoff Date: Wed Aug 19 08:02:53 2020 +0200 Update python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll Co-authored-by: Rasmus Wriedt Larsen commit 8fbb447f4c78f9deb859ebc439e70f6c933da9c3 Author: yoff Date: Wed Aug 19 08:02:29 2020 +0200 Update python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll Co-authored-by: Taus commit 1c3b945e55f283d7e04d916ec85fea2d68780680 Author: yoff Date: Wed Aug 19 08:01:54 2020 +0200 Update python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll Co-authored-by: Taus commit 43a5e74c65a3afb330b045bec757c4290eeb153a Author: yoff Date: Wed Aug 19 08:01:42 2020 +0200 Update python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll Co-authored-by: Taus commit d7849bc13f8ac3fe23334fe127ed6e30a343ffc9 Author: Nick Rolfe Date: Tue Aug 18 18:39:00 2020 +0100 C++: fix compilation errors in ssa.cpp commit 341ab2ee0e123717b711887344698ecfaecf4b5b Author: Jonathan Leitschuh Date: Tue Aug 18 13:20:56 2020 -0400 Fix formatting on jOOQ.qll commit 01a226bdcfe72bad1d53b581d1a846be9d814e10 Author: Jonas Jensen Date: Tue Aug 18 16:53:29 2020 +0200 C++: Rename multipliesBy->effectivelyMultipliesBy From code review of #4098. commit b65f82210fb87a4d86fe929295f7b22cf9ddfbbd Merge: f79c140dc bc7791624 Author: Jonas Jensen Date: Tue Aug 18 16:51:56 2020 +0200 Merge remote-tracking branch 'upstream/main' into SimpleRangeAnalysis-mul-constant commit f79c140dc1abce69786c7f4e17d577041a46a860 Author: Jonas Jensen Date: Tue Aug 18 16:48:23 2020 +0200 C++: Cosmetic: use [0, 1] instead of [0 .. 1] commit fd0937eb01ce19393bdd0b00d027b46000c1b646 Author: Jonas Jensen Date: Tue Aug 18 16:47:29 2020 +0200 C++: Accept improved IntegerOverflowTainted test commit dd5b561f08e2437fa62ad747d9b56c39d7ec2899 Author: Jonas Jensen Date: Tue Aug 18 16:45:24 2020 +0200 C++: Use getValue(e) instead of e.getValue() commit de1c75c279a97d7aa6039d208f79522b63f64f7c Author: Rasmus Lerchedahl Petersen Date: Tue Aug 18 16:34:04 2020 +0200 Python: QL format commit 97c107b9265611164f681fbfb2427bf2365e983c Merge: 378e3b2df 8ad694730 Author: James Fletcher <42464962+jf205@users.noreply.github.com> Date: Tue Aug 18 14:37:55 2020 +0100 Merge pull request #4091 from jf205/link-quotes-ql-handbook QL language reference: update links to match GitHub docs style commit 378e3b2df4f2b6265298cefdedc19ee9e58450a7 Merge: a19963e9b b212af08a Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Tue Aug 18 14:26:34 2020 +0100 Merge pull request #4075 from shati-patel/docs-branch-rename Docs: Rename default branch commit 13577967f3373319d88accf866c387f9af9ccf52 Author: Tom Hvitved Date: Tue Aug 18 15:16:00 2020 +0200 Data flow: Document `Node::getEnclosingCallable()` commit f8364dc74b085246f17dd87b5909ee4d16c80cf0 Author: Rasmus Lerchedahl Petersen Date: Tue Aug 18 15:11:20 2020 +0200 Python: QL doc commit 129e528e1cbb395487e5144b44ec8de1cd4058ca Author: Tom Hvitved Date: Tue Aug 18 15:09:08 2020 +0200 Java: Use `unique` aggregate in `Node::getEnclosingCallable()` I noticed while running tuple stats on JDK that the functionality of `Node::getEnclosingCallable()` is not know to the QL compiler (possibly because it is defined recursively). Here is an example pipeline before: ``` [2020-08-18 14:45:03] (29s) Starting to evaluate predicate DataFlowImpl::flowFwdIn#ffffffff#cur_delta/8[93]@efe539 (iteration 93) [2020-08-18 14:45:04] (30s) Tuple counts for DataFlowImpl::flowFwdIn#ffffffff#cur_delta: 4034 ~4% {6} r1 = SCAN DataFlowImpl::flowFwd#ffffff#prev_delta AS I OUTPUT I.<0>, I.<5>, I.<1>, I.<2>, I.<3>, I.<4> 11410 ~4% {7} r2 = JOIN r1 WITH DataFlowImpl::flowIntoCallNodeCand2#ffffff_1502#join_rhs AS R ON FIRST 2 OUTPUT r1.<5>, r1.<2>, r1.<3>, r1.<4>, r1.<1>, R.<2>, R.<3> 11095 ~2% {7} r3 = JOIN r2 WITH DataFlowImpl::TNil#ff_1#join_rhs AS R ON FIRST 1 OUTPUT r2.<1>, r2.<2>, r2.<3>, r2.<0>, r2.<4>, r2.<5>, r2.<6> 11661 ~0% {10} r4 = JOIN r1 WITH DataFlowImpl::flowIntoCallNodeCand2#ffffff_150234#join_rhs AS R ON FIRST 2 OUTPUT r1.<0>, r1.<2>, r1.<3>, r1.<4>, r1.<5>, r1.<1>, R.<2>, R.<3>, R.<4>, R.<5> 1489 ~0% {10} r5 = SELECT r4 ON r4.<9> = true 1489 ~16% {7} r6 = SCAN r5 OUTPUT r5.<1>, r5.<2>, r5.<3>, r5.<4>, r5.<5>, r5.<6>, r5.<7> 12584 ~14% {7} r7 = r3 \/ r6 4966 ~6% {8} r8 = JOIN r7 WITH DataFlowImplCommon::Cached::TSpecificCall#ff_10#join_rhs AS R ON FIRST 1 OUTPUT r7.<5>, R.<1>, r7.<0>, r7.<1>, r7.<2>, r7.<3>, r7.<4>, r7.<6> 1115 ~6% {8} r9 = JOIN r8 WITH DataFlowImplCommon::Cached::DispatchWithCallContext::reducedViableImplInCallContext#fff_02#join_rhs AS R ON FIRST 2 OUTPUT r8.<0>, r8.<1>, r8.<2>, r8.<3>, r8.<4>, r8.<5>, r8.<6>, r8.<7> 1652 ~11% {8} r10 = JOIN r9 WITH DataFlowImplCommon::Cached::DispatchWithCallContext::prunedViableImplInCallContext#fff@staged_ext AS R ON FIRST 2 OUTPUT r9.<7>, R.<2>, r9.<2>, r9.<3>, r9.<4>, r9.<5>, r9.<6>, r9.<0> 4966 ~0% {8} r11 = JOIN r7 WITH DataFlowImplCommon::Cached::TSpecificCall#ff_10#join_rhs AS R ON FIRST 1 OUTPUT r7.<0>, r7.<1>, r7.<2>, r7.<3>, r7.<4>, r7.<5>, r7.<6>, R.<1> 3851 ~0% {8} r12 = r11 AND NOT DataFlowImplCommon::Cached::DispatchWithCallContext::reducedViableImplInCallContext#fff_02#join_rhs AS R(r11.<5>, r11.<7>) 3851 ~7% {7} r13 = SCAN r12 OUTPUT r12.<5>, r12.<0>, r12.<1>, r12.<2>, r12.<3>, r12.<4>, r12.<6> 3763916 ~0% {8} r14 = JOIN r13 WITH VirtualDispatch::viableCallable#ff AS R ON FIRST 1 OUTPUT r13.<6>, R.<1>, r13.<1>, r13.<2>, r13.<3>, r13.<4>, r13.<5>, r13.<0> 3765568 ~0% {8} r15 = r10 \/ r14 4604 ~20% {7} r16 = JOIN r7 WITH DataFlowImplCommon::Cached::TSomeCall#f@staged_ext AS R ON FIRST 1 OUTPUT r7.<5>, r7.<0>, r7.<1>, r7.<2>, r7.<3>, r7.<4>, r7.<6> 1383356 ~0% {8} r17 = JOIN r16 WITH VirtualDispatch::viableCallable#ff AS R ON FIRST 1 OUTPUT r16.<6>, R.<1>, r16.<1>, r16.<2>, r16.<3>, r16.<4>, r16.<5>, r16.<0> 5148924 ~0% {8} r18 = r15 \/ r17 1076 ~20% {7} r19 = JOIN r7 WITH DataFlowImplCommon::Cached::TAnyCallContext#f@staged_ext AS R ON FIRST 1 OUTPUT r7.<5>, r7.<0>, r7.<1>, r7.<2>, r7.<3>, r7.<4>, r7.<6> 660959 ~3% {8} r20 = JOIN r19 WITH VirtualDispatch::viableCallable#ff AS R ON FIRST 1 OUTPUT r19.<6>, R.<1>, r19.<1>, r19.<2>, r19.<3>, r19.<4>, r19.<5>, r19.<0> 5809883 ~0% {8} r21 = r18 \/ r20 1938 ~2% {7} r22 = JOIN r7 WITH DataFlowImplCommon::Cached::TReturn#fff_2#join_rhs AS R ON FIRST 1 OUTPUT r7.<5>, r7.<0>, r7.<1>, r7.<2>, r7.<3>, r7.<4>, r7.<6> 1184996 ~5% {8} r23 = JOIN r22 WITH VirtualDispatch::viableCallable#ff AS R ON FIRST 1 OUTPUT r22.<6>, R.<1>, r22.<1>, r22.<2>, r22.<3>, r22.<4>, r22.<5>, r22.<0> 6994879 ~0% {8} r24 = r21 \/ r23 11590 ~18% {8} r25 = JOIN r24 WITH DataFlowUtil::Node::getEnclosingCallable#ff AS R ON FIRST 2 OUTPUT r24.<0>, r24.<2>, r24.<3>, r24.<4>, r24.<5>, r24.<6>, r24.<7>, r24.<1> 11378 ~10% {9} r26 = JOIN r25 WITH project#DataFlowImpl::flowCand#fffff#10 AS R ON FIRST 1 OUTPUT r25.<1>, r25.<2>, r25.<3>, r25.<4>, r25.<5>, r25.<6>, r25.<0>, r25.<7>, R.<1> 11378 ~10% {9} r27 = SELECT r26 ON r26.<8> >= r26.<4> 11378 ~10% {9} r28 = SELECT r27 ON r27.<8> <= r27.<4> 11378 ~13% {8} r29 = SCAN r28 OUTPUT r28.<5>, r28.<7>, r28.<0>, r28.<1>, r28.<2>, r28.<3>, r28.<4>, r28.<6> 149 ~43% {7} r30 = JOIN r29 WITH DataFlowImplCommon::Cached::recordDataFlowCallSite#ff@staged_ext AS R ON FIRST 2 OUTPUT r29.<0>, r29.<2>, r29.<3>, r29.<4>, r29.<5>, r29.<6>, r29.<7> 149 ~45% {8} r31 = JOIN r30 WITH DataFlowImplCommon::Cached::TSpecificCall#ff@staged_ext AS R ON FIRST 1 OUTPUT r30.<1>, r30.<2>, r30.<3>, r30.<4>, r30.<5>, r30.<0>, r30.<6>, R.<1> 11378 ~10% {8} r32 = SCAN r28 OUTPUT r28.<0>, r28.<1>, r28.<2>, r28.<3>, r28.<4>, r28.<5>, r28.<6>, r28.<7> 11229 ~9% {8} r33 = r32 AND NOT DataFlowImplCommon::Cached::recordDataFlowCallSite#ff@staged_ext AS R(r32.<5>, r32.<7>) 11229 ~17% {7} r34 = SCAN r33 OUTPUT r33.<0>, r33.<1>, r33.<2>, r33.<3>, r33.<4>, r33.<5>, r33.<6> 11229 ~11% {8} r35 = JOIN r34 WITH DataFlowImplCommon::Cached::TSomeCall#f@staged_ext AS R CARTESIAN PRODUCT OUTPUT r34.<0>, r34.<1>, r34.<2>, r34.<3>, r34.<4>, r34.<5>, r34.<6>, R.<0> 11378 ~11% {8} r36 = r31 \/ r35 11378 ~11% {8} r37 = r36 AND NOT DataFlowImpl::flowFwdIn#ffffffff#prev AS R(r36.<5>, r36.<6>, r36.<0>, r36.<7>, r36.<1>, r36.<2>, r36.<3>, r36.<4>) 11378 ~9% {8} r38 = SCAN r37 OUTPUT r37.<5>, r37.<6>, r37.<0>, r37.<7>, r37.<1>, r37.<2>, r37.<3>, r37.<4> return r38 ``` And after: ``` [2020-08-18 15:02:55] (121s) Starting to evaluate predicate DataFlowImpl::flowFwdIn#ffffffff#cur_delta/8[93]@5ed760 (iteration 93) [2020-08-18 15:02:55] (121s) Tuple counts for DataFlowImpl::flowFwdIn#ffffffff#cur_delta: 3918 ~2% {6} r1 = SCAN DataFlowImpl::flowFwd#ffffff#prev_delta AS I OUTPUT I.<0>, I.<5>, I.<1>, I.<2>, I.<3>, I.<4> 16820 ~0% {7} r2 = JOIN r1 WITH DataFlowImpl::flowIntoCallNodeCand2#fffff_1402#join_rhs AS R ON FIRST 2 OUTPUT r1.<5>, r1.<2>, r1.<3>, r1.<4>, r1.<1>, R.<2>, R.<3> 16525 ~1% {7} r3 = JOIN r2 WITH DataFlowImpl::TNil#ff_1#join_rhs AS R ON FIRST 1 OUTPUT r2.<6>, r2.<1>, r2.<2>, r2.<3>, r2.<0>, r2.<4>, r2.<5> 16820 ~0% {9} r4 = JOIN r1 WITH DataFlowImpl::flowIntoCallNodeCand2#fffff_14023#join_rhs AS R ON FIRST 2 OUTPUT r1.<0>, r1.<2>, r1.<3>, r1.<4>, r1.<5>, r1.<1>, R.<2>, R.<3>, R.<4> 1211 ~0% {9} r5 = SELECT r4 ON r4.<8> = true 1211 ~0% {7} r6 = SCAN r5 OUTPUT r5.<7>, r5.<1>, r5.<2>, r5.<3>, r5.<4>, r5.<5>, r5.<6> 17736 ~6% {7} r7 = r3 \/ r6 17736 ~4% {8} r8 = JOIN r7 WITH DataFlowUtil::Node::getEnclosingCallable_dispred#ff AS R ON FIRST 1 OUTPUT r7.<1>, r7.<2>, r7.<3>, r7.<4>, r7.<5>, r7.<6>, r7.<0>, R.<1> 6757 ~3% {9} r9 = JOIN r8 WITH DataFlowImplCommon::Cached::TSpecificCall#ff_10#join_rhs AS R ON FIRST 1 OUTPUT r8.<5>, R.<1>, r8.<7>, r8.<0>, r8.<1>, r8.<2>, r8.<3>, r8.<4>, r8.<6> 112 ~62% {9} r10 = JOIN r9 WITH DataFlowImplCommon::Cached::DispatchWithCallContext::prunedViableImplInCallContext#fff@staged_ext AS R ON FIRST 3 OUTPUT r9.<0>, r9.<1>, r9.<3>, r9.<4>, r9.<5>, r9.<6>, r9.<7>, r9.<8>, r9.<2> 112 ~62% {8} r11 = JOIN r10 WITH DataFlowImplCommon::Cached::DispatchWithCallContext::reducedViableImplInCallContext#fff_02#join_rhs AS R ON FIRST 2 OUTPUT r10.<7>, r10.<2>, r10.<3>, r10.<4>, r10.<5>, r10.<6>, r10.<0>, r10.<8> 6757 ~0% {9} r12 = JOIN r8 WITH DataFlowImplCommon::Cached::TSpecificCall#ff_10#join_rhs AS R ON FIRST 1 OUTPUT r8.<5>, r8.<7>, r8.<0>, r8.<1>, r8.<2>, r8.<3>, r8.<4>, r8.<6>, R.<1> 6757 ~0% {9} r13 = JOIN r12 WITH VirtualDispatch::viableCallable#ff AS R ON FIRST 2 OUTPUT r12.<2>, r12.<3>, r12.<4>, r12.<5>, r12.<6>, r12.<0>, r12.<7>, r12.<1>, r12.<8> 4945 ~0% {9} r14 = r13 AND NOT DataFlowImplCommon::Cached::DispatchWithCallContext::reducedViableImplInCallContext#fff_02#join_rhs AS R(r13.<5>, r13.<8>) 4945 ~4% {8} r15 = SCAN r14 OUTPUT r14.<6>, r14.<0>, r14.<1>, r14.<2>, r14.<3>, r14.<4>, r14.<5>, r14.<7> 5057 ~5% {8} r16 = r11 \/ r15 7628 ~12% {8} r17 = JOIN r8 WITH DataFlowImplCommon::Cached::TSomeCall#f@staged_ext AS R ON FIRST 1 OUTPUT r8.<5>, r8.<7>, r8.<0>, r8.<1>, r8.<2>, r8.<3>, r8.<4>, r8.<6> 7628 ~9% {8} r18 = JOIN r17 WITH VirtualDispatch::viableCallable#ff AS R ON FIRST 2 OUTPUT r17.<7>, r17.<2>, r17.<3>, r17.<4>, r17.<5>, r17.<6>, r17.<0>, r17.<1> 12685 ~14% {8} r19 = r16 \/ r18 1411 ~10% {8} r20 = JOIN r8 WITH DataFlowImplCommon::Cached::TAnyCallContext#f@staged_ext AS R ON FIRST 1 OUTPUT r8.<5>, r8.<7>, r8.<0>, r8.<1>, r8.<2>, r8.<3>, r8.<4>, r8.<6> 1411 ~11% {8} r21 = JOIN r20 WITH VirtualDispatch::viableCallable#ff AS R ON FIRST 2 OUTPUT r20.<7>, r20.<2>, r20.<3>, r20.<4>, r20.<5>, r20.<6>, r20.<0>, r20.<1> 14096 ~14% {8} r22 = r19 \/ r21 17736 ~10% {8} r23 = JOIN r7 WITH DataFlowUtil::Node::getEnclosingCallable_dispred#ff AS R ON FIRST 1 OUTPUT r7.<6>, R.<1>, r7.<1>, r7.<2>, r7.<3>, r7.<4>, r7.<5>, r7.<0> 17736 ~4% {8} r24 = JOIN r23 WITH VirtualDispatch::viableCallable#ff AS R ON FIRST 2 OUTPUT r23.<2>, r23.<3>, r23.<4>, r23.<5>, r23.<6>, r23.<0>, r23.<7>, r23.<1> 1940 ~0% {8} r25 = JOIN r24 WITH DataFlowImplCommon::Cached::TReturn#fff_2#join_rhs AS R ON FIRST 1 OUTPUT r24.<6>, r24.<0>, r24.<1>, r24.<2>, r24.<3>, r24.<4>, r24.<5>, r24.<7> 16036 ~13% {8} r26 = r22 \/ r25 14256 ~8% {9} r27 = JOIN r26 WITH project#DataFlowImpl::flowCand#fffff#10 AS R ON FIRST 1 OUTPUT r26.<1>, r26.<2>, r26.<3>, r26.<4>, r26.<5>, r26.<6>, r26.<0>, r26.<7>, R.<1> 14256 ~8% {9} r28 = SELECT r27 ON r27.<8> >= r27.<4> 14256 ~8% {9} r29 = SELECT r28 ON r28.<8> <= r28.<4> 14256 ~9% {8} r30 = SCAN r29 OUTPUT r29.<5>, r29.<7>, r29.<0>, r29.<1>, r29.<2>, r29.<3>, r29.<4>, r29.<6> 122 ~28% {7} r31 = JOIN r30 WITH DataFlowImplCommon::Cached::recordDataFlowCallSite#ff@staged_ext AS R ON FIRST 2 OUTPUT r30.<0>, r30.<2>, r30.<3>, r30.<4>, r30.<5>, r30.<6>, r30.<7> 122 ~30% {8} r32 = JOIN r31 WITH DataFlowImplCommon::Cached::TSpecificCall#ff@staged_ext AS R ON FIRST 1 OUTPUT r31.<1>, r31.<2>, r31.<3>, r31.<4>, r31.<5>, r31.<0>, r31.<6>, R.<1> 14256 ~3% {8} r33 = SCAN r29 OUTPUT r29.<0>, r29.<1>, r29.<2>, r29.<3>, r29.<4>, r29.<5>, r29.<6>, r29.<7> 14134 ~3% {8} r34 = r33 AND NOT DataFlowImplCommon::Cached::recordDataFlowCallSite#ff@staged_ext AS R(r33.<5>, r33.<7>) 14134 ~12% {7} r35 = SCAN r34 OUTPUT r34.<0>, r34.<1>, r34.<2>, r34.<3>, r34.<4>, r34.<5>, r34.<6> 14134 ~7% {8} r36 = JOIN r35 WITH DataFlowImplCommon::Cached::TSomeCall#f@staged_ext AS R CARTESIAN PRODUCT OUTPUT r35.<0>, r35.<1>, r35.<2>, r35.<3>, r35.<4>, r35.<5>, r35.<6>, R.<0> 14256 ~7% {8} r37 = r32 \/ r36 14256 ~7% {8} r38 = r37 AND NOT DataFlowImpl::flowFwdIn#ffffffff#prev AS R(r37.<5>, r37.<6>, r37.<0>, r37.<7>, r37.<1>, r37.<2>, r37.<3>, r37.<4>) 14256 ~9% {8} r39 = SCAN r38 OUTPUT r38.<5>, r38.<6>, r38.<0>, r38.<7>, r38.<1>, r38.<2>, r38.<3>, r38.<4> return r39 ``` commit a72d05ccdbcef4e1d0fb5e2eb6d6bbe2cb73f409 Author: Jonas Jensen Date: Tue Aug 18 15:07:35 2020 +0200 C++: Change note for *= and constant * commit b316644ac290d1e26dbcdd0ac52f71decd5b3b59 Author: Jonas Jensen Date: Tue Aug 18 14:17:42 2020 +0200 C++: SimpleRangeAnalysis for *= by constant commit 1e65ed222814827898ae725b2444c36491a51439 Author: Erik Krogh Kristensen Date: Tue Aug 18 14:43:03 2020 +0200 support module.createRequire commit aab603d26154802a08741e25ec15f82519763702 Author: Rasmus Lerchedahl Petersen Date: Tue Aug 18 14:37:59 2020 +0200 Python: QL doc commit bc779162467fe46ecd3d206a915d9bc04b74135d Merge: ca1f5317b 6ae53b186 Author: Tom Hvitved Date: Tue Aug 18 14:35:01 2020 +0200 Merge pull request #4093 from tamasvajk/feature/change-notes C#: Add change notes for C# analysis commit 8ad6947308626c92e26cf87fd72aefa1f2e1947a Author: james Date: Tue Aug 18 13:19:23 2020 +0100 add quotes to several more links commit d0eaa139740252814270cb0021adab46f50a45b7 Author: Rasmus Lerchedahl Petersen Date: Tue Aug 18 14:14:38 2020 +0200 Python: Magic -> Special and reaarange classes commit ca1f5317b39e29013625d3b7e397b7d078cf440d Merge: f761a604f 5d485859a Author: Jonas Jensen Date: Tue Aug 18 13:59:53 2020 +0200 Merge pull request #4068 from geoffw0/uncontrolled-alloc-size C++: Downgrade `cpp/uncontrolled-allocation-size` query precision. commit f761a604f32d311b8669640ccbd3c7ecdaa4f1bd Merge: f75f5ab12 0cf4c9998 Author: Tom Hvitved Date: Tue Aug 18 13:43:02 2020 +0200 Merge pull request #4094 from tamasvajk/feature/comp-gen-array-size C# Compiler generated flag for length arguments of implicitly sized arrays commit acb08287abad1f39b2c184ed24ee665094c63555 Author: Tom Hvitved Date: Tue Aug 18 13:38:46 2020 +0200 C#: Rename `isComplete()` to `isFullyConstructed()` commit bdf4ae5f27ef3f957c09634a29c8fad82ea5c61f Author: Tom Hvitved Date: Tue Aug 18 13:30:16 2020 +0200 C#: Increase `accessPathLimit` from 3 to 5 commit f75f5ab1250dbf3a0daa78e46eb514b573f4945e Merge: 9decb47bf a2fc92b9d Author: Anders Schack-Mulligen Date: Tue Aug 18 13:06:11 2020 +0200 Merge pull request #3838 from hvitved/dataflow/flow-fwd-ctx Data flow: Use precise call contexts in `flowFwd()` commit b9bf11adb49739f1c5f5a889aa19806ce5b3e46c Author: yoff Date: Tue Aug 18 12:59:57 2020 +0200 Update python/ql/src/semmle/python/Magic.qll Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> commit 571520602dfd2ddce58f5a5312a36e41c1def3e0 Author: yoff Date: Tue Aug 18 12:59:20 2020 +0200 Update python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> commit 59cee284b5b027647cc23b3a5f557eacad810412 Author: yoff Date: Tue Aug 18 12:59:04 2020 +0200 Update python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> commit bbf925fcc4993f16bdfdd4d3cf31a0796af2a060 Author: Rasmus Lerchedahl Petersen Date: Tue Aug 18 12:56:15 2020 +0200 Python: Magic subscript and format (this in preparation for addressing reviews) commit 246d9b8c701dc9470af0c9e4fabbdc909be40901 Author: Erik Krogh Kristensen Date: Tue Aug 18 12:51:36 2020 +0200 update expected trap files commit 0cf4c99986f4c8820e979132922b1c214ec501a4 Author: Tamas Vajk Date: Tue Aug 18 12:06:01 2020 +0200 C#: Change compiler generated flag for length arguments of implicitly sized arrays commit 99e62ceee6d41fdb335bbed5a2802ae06bdc2819 Author: Tamas Vajk Date: Tue Aug 18 11:44:24 2020 +0200 C#: Add test for length argument of implicitly sized arrays commit b6b72729f6869b2acb83917e2be61fb0fcea6e81 Author: Jonas Jensen Date: Fri Aug 14 16:56:15 2020 +0200 C++: SimpleRangeAnalysis for MulExpr by constant commit 03cb95c82bfbf92aa61cc498af81d60507e81b9c Author: Erik Krogh Kristensen Date: Tue Aug 18 11:20:04 2020 +0200 bump extractor version commit 6ae53b18652c5a275c9a6a50bee8bd8d98a05059 Author: Tamas Vajk Date: Tue Aug 18 11:10:04 2020 +0200 C#: Add change notes for C# analysis commit 2e2f99cabfe0c0109105108868e8cc5b40699949 Author: Jonas Jensen Date: Tue Aug 18 10:39:57 2020 +0200 C++: Correctly classify the MulExpr rounding bugs commit a7d9715fd9ea4b26b6f285bdfb789c880230e80b Author: Jonas Jensen Date: Mon Aug 10 17:36:33 2020 +0200 C++: BinaryOperation.hasOperands QLDoc borrowed from JavaScript. Implementation borrowed from Java. Parameter names changed. commit beeadea48fd51179f8e452515d6731df403609c6 Author: Tamas Vajk Date: Tue Aug 18 10:26:31 2020 +0200 Add extra tests for partial methods commit d1b3963e2dce91d4fe8519e580737dcaaeeea066 Author: Erik Krogh Kristensen Date: Tue Aug 18 10:12:01 2020 +0200 correctly treat ES2015 modules as being in strict-mode in the extractor commit 27345c64f3c29b37c04cf5a35a935c2f928c9273 Author: Jonas Jensen Date: Tue Aug 18 09:32:05 2020 +0200 C++: Also accept PointlessComparison test changes commit eba2c4331f38b949362374a4d0d129032a4b9024 Author: Tamas Vajk Date: Tue Aug 18 09:23:38 2020 +0200 Add launch.json to gitignore commit 61d464889333fcca57fcaa41c553711b723f17d6 Author: Erik Krogh Kristensen Date: Mon Aug 17 22:53:16 2020 +0200 update expected output of trap test commit eb5dfe8438ba50cfefd3c1d01309682555df20ef Author: Erik Krogh Kristensen Date: Mon Aug 17 22:46:20 2020 +0200 autoformat commit b6b424dd00320fb1df712c05b081c26b66ee6115 Author: james Date: Mon Aug 17 21:14:08 2020 +0100 remove spurious spaces commit b150c6497f6bb5ef5495c55d892058656157a916 Author: james Date: Mon Aug 17 21:08:33 2020 +0100 update links commit 5d485859af12092a16af3320f869b8002752fed9 Merge: be91cec7a 9decb47bf Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Aug 17 20:49:35 2020 +0100 Merge remote-tracking branch 'upstream/main' into uncontrolled-alloc-size commit be91cec7add88307c86169ee6a18826384fd54c7 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Aug 17 20:43:25 2020 +0100 C++: Add change note. commit d76b25ec2216bac4f18740fb0c6304f84c314dac Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Aug 17 17:47:20 2020 +0100 C++: Change note. commit 390af0d7d21ec03cbe482a7ec9d68d0d37607707 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Aug 17 17:46:25 2020 +0100 C++: Autoformat. commit 0234bca6ca384d474898113502d7ad0c9085bb24 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Aug 17 17:14:25 2020 +0100 C++: Fix a hole in StdStringAppend and clarify comments. commit 9decb47bf0bcf318a0c55ad814b2064de0479383 Merge: 4b4b8a9fa f90d77912 Author: Robert Marsh Date: Mon Aug 17 12:55:26 2020 -0400 Merge pull request #4076 from jbj/SimpleRangeAnalysis-AssignOperation C++: Fix SimpleRangeAnalysis for AssignOperation commit a11ca06189410a765d16b7a10f0efeae0170cb95 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Aug 17 16:34:38 2020 +0100 C++: Implement more std::string models. commit 9204940830b210beb937f9c9d599f6ccd5d9dc44 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Aug 17 16:00:26 2020 +0100 C++: Add test cases for std::string methods. commit 789e781eb70add0d048cc236937897a28b42828c Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Aug 17 12:28:07 2020 +0100 C++: Add prototypes for std::string methods to test. commit ca7c045d312b2b1e926800c4afe21429757566ec Author: Rasmus Lerchedahl Petersen Date: Mon Aug 17 16:24:00 2020 +0200 Python: bad re match made the tests fail.. commit bb3254d4abe46630458f4d30e2127fd7c75ad476 Merge: 2e9c0fc6a 7dd267774 Author: Mathias Vorreiter Pedersen Date: Mon Aug 17 16:21:10 2020 +0200 Merge branch 'main' into alternative-instruction-operand-flow commit 73d1fac88ec574644239a4259d6edbd16af32cee Author: Erik Krogh Kristensen Date: Mon Aug 17 16:20:26 2020 +0200 support named tuples where not all tuple elements are named commit 4b4b8a9faa847e7421fb09881da4b047cbe52409 Merge: c917cd02b f7273b866 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Aug 17 14:46:57 2020 +0100 Merge pull request #4074 from jbj/SimpleRangeAnalysis-extensible C++: extensible range analysis commit a2fc92b9dbafa432032464b7ffd084ba43599c08 Author: Tom Hvitved Date: Mon Aug 17 15:46:43 2020 +0200 Data flow: Address review comments commit 83ed41b24744c98c2dcc696cc40c35038ba9a89c Author: Erik Krogh Kristensen Date: Mon Aug 17 15:43:43 2020 +0200 move indices comment into plain comment commit 0f87a89fd11782b091a184b795c35978dcd3dc91 Author: Erik Krogh Kristensen Date: Mon Aug 17 15:31:41 2020 +0200 use typeLabel instead of typeDecl Co-authored-by: Asger F commit c28889225aa7fc7ee84caf2902a0373fcfa05fc8 Author: Erik Krogh Kristensen Date: Thu Aug 13 13:49:30 2020 +0200 skip binary files when extracting JavaScript commit e03fe81ce780963c7494285e9e00dda8e0d57190 Author: Jonas Jensen Date: Mon Aug 17 15:07:00 2020 +0200 C++: Accept float.toString changes in tests commit a5701db3fafe5fd47201188f067f148e2e9bdfeb Author: Anders Schack-Mulligen Date: Mon Aug 17 15:01:48 2020 +0200 Java: Support String.formatted in the format string queries. commit c917cd02bd45227aaeda969d6de1e3ddf6d46885 Merge: 8876dd51c 15a74493e Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Aug 17 13:54:25 2020 +0100 Merge pull request #4054 from erik-krogh/urlIncludes Approved by esbena commit a19963e9b7912bc6f6eac590b8b1c2d043e3566d Merge: 1d4978aa6 a1394c363 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Aug 17 13:42:12 2020 +0100 Merge pull request #3930 from erik-krogh/fastProp Approved by esbena commit 6f28ddf1f8860be8ad55ac13dabdf944aadfa573 Author: Erik Krogh Kristensen Date: Mon Aug 17 14:23:42 2020 +0200 proper support for `this` inside a JSX-name commit 8eacef34678eea61a4bdfbf23652f10e52be26dc Author: Rasmus Lerchedahl Petersen Date: Mon Aug 17 12:01:36 2020 +0200 Python: Add QL doc commit 676690acb2a09a51347a46d0b4603ef3d065b53d Merge: bfdb58020 8876dd51c Author: Rasmus Lerchedahl Petersen Date: Mon Aug 17 11:42:45 2020 +0200 Merge branch 'main' of github.com:github/codeql into SharedDataflow_ParsimoniousFlowNodes commit 894b3f2cd4002d8c5cfef20bf6e5eacc1532f193 Author: Remco Vermeulen Date: Mon Aug 17 11:40:08 2020 +0200 Add or change qldocs commit bfdb580206d2e00933488f39cefd493f246ed943 Author: Rasmus Lerchedahl Petersen Date: Mon Aug 17 11:37:52 2020 +0200 Python: Experiemntal cleanup strategy commit edc5e5fbcf2f87d50d2327f865fa0ed5138b7d2a Author: Jonas Jensen Date: Mon Aug 17 10:58:45 2020 +0200 C++: Simplify defDependsOnDef for AssignOperation These cases were unnecessarily transitive. There is no need for `defDependsOnDef` to be transitive since that's handled in `defDependsOnDefTransitively`. The dependency information from the LHS of an `AssignmentOperation` is now deduced the say way as the information from the RHS: by calling `exprDependsOnDef`. This should effectively give us the same information and recursion structure as if the operation (`x += e`) were desugared (`x = x + e`). commit 8db5c4f2e2f283c912c0eeee7c9acba615e10118 Author: Remco Vermeulen Date: Mon Aug 17 10:41:27 2020 +0200 Abstract additional taint step commit 8876dd51c7c05fa98105ae03b6d99b949f1cd9fb Merge: 28a765681 357109a41 Author: Tom Hvitved Date: Mon Aug 17 10:36:56 2020 +0200 Merge pull request #4079 from hvitved/csharp/xml-data-flow-config C#: Use `DataFlow3` instead of `DataFlow2` in `Xml.qll` to avoid overlap commit 518459c0f7e29320aaa219923c433d07f20d00d6 Author: Remco Vermeulen Date: Mon Aug 17 10:31:44 2020 +0200 Abstract Xss sanitizer Turn the Xss sanitizer into an abstract class to support customizations and provide a default implementation. commit 28a765681348e119e849303f7e0a4d8e890cda72 Merge: 768e5190a 4947e1d81 Author: Tom Hvitved Date: Mon Aug 17 09:08:44 2020 +0200 Merge pull request #4073 from aschackmull/java/move-test Java: Temporarily move a qltest. commit 8ec91ef0c69e7fa51562395a9f6150b6c865bb02 Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Sun Aug 16 15:23:29 2020 +0200 Change polarity predicate isInsecure commit 5d6e6be4e45033c5e90770ba489350417085bc1e Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Sun Aug 16 15:02:52 2020 +0200 Add query-tests commit 3e9142bf7187c6ecfff8182c78c443ca0840784c Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Sun Aug 16 14:58:37 2020 +0200 Remove examples commit 2a322976c62a45a9f5f68337bb25ab395236288d Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Sun Aug 16 14:57:04 2020 +0200 Changed .qhelp commit 91d44854c07c42a666e7996fae85618bb4241f05 Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Sun Aug 16 14:53:31 2020 +0200 Replace class and module name commit d4b231b86796ba2ed1572aaf9a07b082832ce357 Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Sun Aug 16 14:48:26 2020 +0200 Replace regex commit e2908026c556bb2ec89c25b4c21d0f51bd45410d Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Sun Aug 16 14:41:55 2020 +0200 Remove redundancy commit 1ba39e4130e6d1fc190f4e11d19161ad8f638e72 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun Aug 16 14:34:19 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen commit 05ffd672d70635d2b07330996d814f14ee005945 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun Aug 16 14:33:38 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen commit ab20beba565c5de0ac2a2d9dc09eecd82b3d0e77 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun Aug 16 14:32:51 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen commit bfef84e1b57983ef7fc950ba72af6a737d3fad81 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun Aug 16 14:32:05 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen commit a2e945645022db47e7c152a97d46f6bdedba1ce1 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun Aug 16 14:31:21 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen commit 14c8e4ce768fc48c5578084b01c731537ce5e4d3 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun Aug 16 14:30:45 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen commit 275b8dfda2e16047b31251c7317f2442df0cc630 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun Aug 16 14:29:36 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen commit 9292e3b80e0e1c81cd30da93d0772994a54e738b Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun Aug 16 14:28:39 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen commit ab128f71728a353d832c13f9a4e96e267febf3cf Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun Aug 16 14:27:26 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen commit 40e101de5af10c36853484fa895728f382bd0948 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun Aug 16 14:26:15 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen commit 97f039af3adc79c220a5fff032d84c4d360be5e2 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun Aug 16 14:25:11 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen commit fb3ffb895a841e55693804ed34032b99eb54d695 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun Aug 16 14:23:17 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen commit e46301475915102e52443e9a67abbb3ba617fd01 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun Aug 16 14:21:56 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen commit 5cae3005f39b73ec67363eae15f1119b27ceb917 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun Aug 16 14:20:22 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen commit 10bd745740e76ddb09fec19429f2e900d9680dda Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun Aug 16 14:18:54 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen commit 8d26b810eee5f8e2340998ea5a35fca33fb8d382 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun Aug 16 14:17:16 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen commit 0c121062b6b2e6ceafff652403b8dbb0b58fd071 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun Aug 16 14:13:54 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen commit 67fccac8a97f7902504eb079fa22a2a1c90cf8e6 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun Aug 16 14:13:03 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen commit 768e5190a1c9d40a4acc7143c461c3b114e7fd59 Merge: e9a36b252 89c2b6dc4 Author: Jonas Jensen Date: Fri Aug 14 15:59:46 2020 +0200 Merge pull request #4080 from geoffw0/split C++: Split test file stl.cpp commit 89c2b6dc4b7ae899dc63cc4d5ed008efb8e35c49 Merge: a839f1fae e9a36b252 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Aug 14 14:03:34 2020 +0100 Merge remote-tracking branch 'upstream/master' into split commit 7ea3fc04c82e405e977e96f0dd979218ce527f31 Author: Rasmus Lerchedahl Petersen Date: Fri Aug 14 14:46:39 2020 +0200 Python: adjust test annotation (for after feature) commit 4bc04486cbcc637c38d420375beb25c4add97795 Author: Rasmus Lerchedahl Petersen Date: Fri Aug 14 14:41:35 2020 +0200 Python: Annotate tests (as before the new feature) commit 357109a410e2983814dff8298f536121356a81db Author: Tom Hvitved Date: Fri Aug 14 14:33:12 2020 +0200 C#: Use `DataFlow3` instead of `DataFlow2` in `Xml.qll` to avoid overlap `semmle.code.csharp.frameworks.system.Xml` is imported in `LibraryTypeDataFlow.qll`, and therefore part of the default namespace. This means that the use of `DataFlow2` inside `Xml.qll` overlaps with some queries. Bumping to `DataFlow3` resolves the issue. commit 2817602a97ef06fb5cb80a40b703a1b8ca54c181 Merge: 3f2fcbf0a e9a36b252 Author: Rasmus Lerchedahl Petersen Date: Fri Aug 14 14:27:57 2020 +0200 Merge branch 'master' of github.com:github/codeql into SharedDataflow_ParameterTests commit fe72b559d3746a8a441fdabdb4a1b18665ab967a Author: Jonas Jensen Date: Thu Aug 13 15:10:20 2020 +0200 C++: Range analysis for unsigned AssignMulExpr This is essentially a copy-paste job of `AssignAddExpr`, together with the math from the `UnsignedMulExpr` support. commit e808d3033acfa0de5d4827c7e5eac53010f42d2f Author: Rasmus Lerchedahl Petersen Date: Fri Aug 14 14:19:18 2020 +0200 Python: Add magic to DataFlowCall commit e9a36b25243bc92e763511e83764c035611c4968 Merge: 8cbd4974a a1a1218f9 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Fri Aug 14 13:17:45 2020 +0100 Merge pull request #4062 from tausbn/python-fix-unknown-import-star Approved by yoff commit f90d779122a376ff50ba9f05b205181079091eb9 Author: Jonas Jensen Date: Fri Aug 14 14:05:27 2020 +0200 C++: Fix SimpleRangeAnalysis for AssignOperation The range analysis wasn't producing useful bounds for `AssignOperation`s (`+=`, `-=`) unless their RHS involved a variable. This is because a shortcut was made in the `analyzableDef` predicate, which used to specify that an analyzable definition was one for which we'd specified the dependencies. But we can't distinguish between having _no dependencies_ and having _no specification of the dependencies_. The fix is to be more explicit about which definitions are analyzable. To avoid too much repetition I'm still calling out to `analyzableExpr` in the new code. commit 4211f7f346d9b3a2da37688605ce7f293f461126 Merge: 360ddc631 8cbd4974a Author: Rasmus Lerchedahl Petersen Date: Fri Aug 14 13:26:27 2020 +0200 Merge branch 'master' of github.com:github/codeql into MagicMethods commit 360ddc6314439036a312d33615fa515a6717611f Author: Rasmus Lerchedahl Petersen Date: Fri Aug 14 13:25:17 2020 +0200 Python: better charPred commit b212af08a6cffbb434f3c8a2795a579e092792fd Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Fri Aug 14 11:47:53 2020 +0100 Docs: Rename default branch commit 1d4978aa6ecd1236902008aeb80842d288131698 Merge: 4a07bd5a1 5fed92b2d Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Fri Aug 14 11:57:09 2020 +0100 Merge pull request #4046 from jf205/link-quotes-learn-ql Learning CodeQL docs: update links to match GitHub docs style commit 8cbd4974ae014db774633df7e716b83301fd23e4 Merge: e01e702f4 955693784 Author: Taus Date: Fri Aug 14 12:45:55 2020 +0200 Merge pull request #3981 from yoff/SharedDataflow_Classes Python: Dataflow, test magic methods commit e01e702f46ffd4505043f12297828b7a3cacf5ba Merge: 82f982696 a6bcbe797 Author: Jonas Jensen Date: Fri Aug 14 12:42:12 2020 +0200 Merge pull request #4060 from bgianfo/patch-1 C++: Detect GoogleTest tests cases in FNumberOfTests.ql commit f7273b86657db896223569b52d4e39713f00748b Author: Jonas Jensen Date: Fri Aug 14 12:15:08 2020 +0200 C++: Add custom modeling to extensibility.ql commit ee3312503e3c9889d62338402a323d62cd2133e2 Author: Jonas Jensen Date: Fri Aug 14 10:06:12 2020 +0200 C++: Add test for extensible range analysis This commit demonstrates that the range is too wide before custom modeling has been added to the test. commit bf7732ec9d7197a19c5ca83020cf661a8fe97244 Author: Jonas Jensen Date: Fri Aug 14 12:14:38 2020 +0200 C++: Silence QL compiler errors commit 1deb1e64299245989db783dcf574b97aef4bbde2 Author: Jonas Jensen Date: Fri Aug 14 09:49:42 2020 +0200 C++: Add SimpleRangeAnalysisExpr.dependsOnChild commit 1b5b374a8e4c3beed21eb3d9a915b114172f4418 Author: Jonas Jensen Date: Thu Aug 13 16:57:33 2020 +0200 C++: Move getFullyConverted{Upper,Lower}Bounds Rather than being public, these internal predicates are now exposed through a `SimpleRangeAnalysisInternal` module so it's clear that they are not for general use. commit 18ba562c2528bdfe348ebd30d5d71767ef0ba54e Author: Jonas Jensen Date: Fri Aug 14 12:14:05 2020 +0200 C++: Fix: remember to bind `e` commit 1c0e83a374698a63e2ddf5274cd413732d92c492 Author: Jonas Jensen Date: Thu Aug 13 16:14:23 2020 +0200 C++: Autoformat fixup commit aa78c6e750f21fca420d5fa053b78a53525a9b8c Author: Jonas Jensen Date: Thu Aug 13 16:12:43 2020 +0200 C++: Move to experimental And rename to `SimpleRangeAnalysisExpr` to clarify which of our range analysis libraries this belongs to. commit cdddf5fd40e4b6b3757a049f6a739aff528cf79d Merge: 0638b512b 82f982696 Author: Jonas Jensen Date: Fri Aug 14 12:26:59 2020 +0200 Merge remote-tracking branch 'upstream/master' into SimpleRangeAnalysis-extensible-base commit 9556937840999239728c141e6549655b5f599795 Author: Rasmus Lerchedahl Petersen Date: Fri Aug 14 11:29:58 2020 +0200 Python: address review comments commit 5ed31070452beabb70ff8d1dadbae32c02f8fd9a Author: Rasmus Lerchedahl Petersen Date: Fri Aug 14 11:12:23 2020 +0200 Python: Start scaffold for magic methods commit e518cbabd678557352bcc83b8238ac6afcedf588 Author: Tom Hvitved Date: Wed Jul 29 09:44:33 2020 +0200 Python: Sync data flow files commit 9ebf8d1d580f8f5b68a62a256ae1d8b74aa9b79c Author: Tom Hvitved Date: Mon Jun 29 20:02:37 2020 +0200 Data flow: Sync files commit 2d29fa1d157456b9f41c1025d43c06c4c0e3d0ad Author: Tom Hvitved Date: Thu Jun 4 11:13:23 2020 +0200 Data flow: Use precise call contexts in `flowFwd()` commit 8d49ad73252a133262499544a66581b16d2f548e Author: yoff Date: Fri Aug 14 10:53:37 2020 +0200 Update python/ql/test/experimental/dataflow/coverage/datamodel.py Co-authored-by: Taus commit 4b336e9b01f589b3d18db8d15cc40ec764795fd0 Author: yoff Date: Fri Aug 14 10:53:10 2020 +0200 Update python/ql/test/experimental/dataflow/coverage/classes.py Co-authored-by: Taus commit 82f982696699c12f3b1e6d59d40d0325cab6e436 Merge: ed06604b4 21246624b Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Fri Aug 14 08:34:48 2020 +0100 Merge pull request #4044 from aschackmull/java/xsssink-printwriter-format Approved by aibaars commit 4947e1d817fbb80ce803b4795b3ef54ef1a7db3a Author: Anders Schack-Mulligen Date: Fri Aug 14 09:25:32 2020 +0200 Java: Temporarily move a qltest. commit ed06604b464f58fee5532b9be1af52fbcb538349 Merge: de87f8fc4 498b350ad Author: Robert Marsh Date: Thu Aug 13 16:59:47 2020 -0400 Merge pull request #4045 from geoffw0/plus C++: Model more of std::string in models. commit 4a07bd5a153894bff469b93ac338fec66ed0a35f Merge: b1be3672e 36373fce9 Author: Robert Marsh Date: Thu Aug 13 16:54:09 2020 -0400 Merge pull request #4032 from jbj/asExpr-docs C++: Clarify the docs on DataFlow::Node::asExpr commit a6bcbe79743426a2bb4cbbfa57b3b4f04a8f7ee1 Author: Brian Gianforcaro Date: Thu Aug 13 00:13:18 2020 +0000 C++: Detect GoogleTest tests cases in FNumberOfTests.ql Co-authored-by: Jonas Jensen commit 498b350addaf843b55b85762ff70cb0e5bdd1c00 Merge: 734933300 de87f8fc4 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 13 18:21:28 2020 +0100 Merge remote-tracking branch 'upstream/master' into plus commit a839f1fae5c5e962bc38c950871b9de90a7dcc8c Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 13 18:17:02 2020 +0100 C++: Split off stringstream.cpp. commit 49d2f66ddbd52981570d5742bbe8c24dd828a2df Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 13 18:08:58 2020 +0100 C++: Tidy up sources and sinks. commit f343eb91431b4369aed484fbf2831cbbdd37e5fc Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 13 17:47:25 2020 +0100 C++: Split stl.cpp into string.cpp and vector.cpp. commit 5d7f771933465e4417ec73561aff2280d0d4507c Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 13 17:43:21 2020 +0100 C++: Split off stl.h from stl.cpp. commit de87f8fc4240e35680343de16af775da851388f3 Merge: 93f95b1c2 f5abf74e0 Author: Robert Marsh Date: Thu Aug 13 12:33:52 2020 -0400 Merge pull request #4057 from geoffw0/sal C++: SAL.qll QLDoc and cleanup commit 93f95b1c2246effa2a6eaa02a1e92c241cf82880 Merge: ecbbcc2f6 5e5a112c3 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 13 16:59:31 2020 +0100 Merge pull request #4053 from jbj/SimpleRangeAnalysis-mul C++: SimpleRangeAnalysis: unsigned multiplication commit 3d60756d40a005dc8007047695e56636f01f539c Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 13 15:45:57 2020 +0100 C++: Downgrade the query precision. commit ecbbcc2f617330ba2a5abafc74387dd768824b54 Merge: 6c60589db cca2d9d82 Author: Anders Schack-Mulligen Date: Thu Aug 13 16:40:28 2020 +0200 Merge pull request #4066 from Marcono1234/marcono1234/simplify-VarAccess-isLValue [Java] Simplify VarAccess.isLValue() commit 7349333006343c4e9a1768b4a8e25d87b2d6a53e Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 13 14:44:51 2020 +0100 C++: Taint through char append. commit 3c0e7a709f4289cde3222b3705d124279996a407 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 13 14:22:11 2020 +0100 C++: Add a test of append with CharT. commit 732a8fa4c9c17fa7a463d397d87d1fca353f59b9 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 13 12:44:54 2020 +0100 C++: Add another member function. commit 36373fce9bb1f81f4f1c6a02b0f2758081ca57bf Author: Jonas Jensen Date: Mon Aug 10 12:01:13 2020 +0200 C++: Deprecate DataFlow::definitionByReferenceNode This predicate name was only used in IR data flow, not in AST data flow. commit 3f383784cd571ff1db4aac5b96011166aa5eba6c Author: Jonas Jensen Date: Mon Aug 10 12:00:54 2020 +0200 C++: QLDoc formatting fixup commit f70a17b858f2635c517dad2691ae6dba8945eea4 Author: Jonas Jensen Date: Mon Aug 10 11:49:27 2020 +0200 C++: clearer wording in asExpr doc Co-authored-by: Aditya Sharad <6874315+adityasharad@users.noreply.github.com> commit 5ae8b02bde2588fb741164eaa916c657d0e03f6a Author: Jonas Jensen Date: Fri Aug 7 15:28:18 2020 +0200 C++: Clarify the docs on DataFlow::Node::asExpr For IR data flow I also added a `definitionByReferenceNodeFromArgument` predicate to improve compatibility with AST data flow. commit 6c60589dbde44f2b3be5d3f41844c2edc132d3de Merge: 3469ad7ca 2c7bb8c51 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Thu Aug 13 14:02:18 2020 +0100 Merge pull request #4063 from erik-krogh/noJsMsg Approved by esbena commit 3469ad7ca624a7b9af7cb05224e16925acbeb842 Merge: 8891ae70b d6e9b07a9 Author: Anders Schack-Mulligen Date: Thu Aug 13 13:35:52 2020 +0200 Merge pull request #3600 from luchua-bc/java-sensitive-log4j2-logging Add Log4J 2 and a new search string secret commit 46f10fc032132bf3f0c5ae140fbde15104743a39 Author: Tom Hvitved Date: Thu Aug 13 13:09:29 2020 +0200 C#: Restrict `DataFlowType` to types belonging to `Node`s commit cca2d9d8253253a8a76f04e548b0169395de489e Author: Marcono1234 Date: Thu Aug 13 13:12:57 2020 +0200 Simplify VarAccess.isLValue() commit dcccdee22739f95f389fbfe81efb81766bdfd311 Author: Tom Hvitved Date: Wed Aug 12 21:10:05 2020 +0200 C#: Speed up `Implements.qll` and `Unification.qll` Restrict constructed GVN types to those that are complete, and reduce intermediate string construction in `toString()` computations. commit b1be3672e7d9ddb3926469a8052aa4c2d051703d Merge: e603f5cc4 78948139f Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Thu Aug 13 11:31:52 2020 +0100 Merge pull request #4058 from shati-patel/metadata Docs: Add metadata option missing from reference table commit 15a74493e0b10209066cad34c56cc1878ad2678c Author: Erik Krogh Kristensen Date: Thu Aug 13 11:45:58 2020 +0200 more permissive path elements in `js/incomplete-url-substring-sanitization` commit 3fb9c2880693d07ed18bd5c762b20ff6a2023f47 Author: Erik Krogh Kristensen Date: Thu Aug 13 11:33:31 2020 +0200 adjust comment about slash position commit dc6943b739f0a5603917ebaf5818c4186045cd22 Author: Erik Krogh Kristensen Date: Thu Aug 13 11:34:53 2020 +0200 Update change-notes/1.26/analysis-javascript.md Co-authored-by: Esben Sparre Andreasen commit 2c7bb8c51f55795d1820650d1f5940ba79516e51 Author: Erik Krogh Kristensen Date: Thu Aug 13 11:18:27 2020 +0200 adjust error message when files have been found while extracting commit a1a1218f95f1161aa9f48bf593ff97d8324ea99b Author: Taus Brock-Nannestad Date: Thu Aug 13 10:50:28 2020 +0200 Python: Ignore `from foo import *` when `foo` is absent. commit dc5c0f8e7a72970698a53525ab27b468a18144e4 Author: Taus Brock-Nannestad Date: Thu Aug 13 10:49:11 2020 +0200 Python: Add test case for missing modules commit f5abf74e0f3ff43763d2b17dbad5ffaa91d96873 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 13 09:05:22 2020 +0100 Update cpp/ql/src/Microsoft/SAL.qll Co-authored-by: Robert Marsh commit 8891ae70b67a2a0fc9d3aa603c57c9aa89f37c3c Merge: 66541f260 6f83c55eb Author: Anders Schack-Mulligen Date: Thu Aug 13 09:53:57 2020 +0200 Merge pull request #3938 from lcartey/java/untrusted-data-to-external-api Java: Untrusted data used in external APIs commit d35d3f4271dabf653f4c3f9f910f5c274c77383c Author: Erik Krogh Kristensen Date: Thu Aug 13 09:37:55 2020 +0200 add test for catch with type `unknown` commit d95d427c5b6019792cf53902df771bcd0b9068dd Author: Erik Krogh Kristensen Date: Thu Aug 13 09:22:32 2020 +0200 better support for the `&&=`, `||=`, and `??=` operators commit 5e5a112c364261ff1a01029abe4eabfcab0e01dc Author: Jonas Jensen Date: Thu Aug 13 08:37:13 2020 +0200 C++: Change note commit 3f2fcbf0aee6db5e2399ca509cba626b00be5684 Author: Rasmus Lerchedahl Petersen Date: Thu Aug 13 08:23:12 2020 +0200 Python: Remove most noise in the query output Just a quick change, the query should probably be rewritten commit 2cc7712d40dc9780e0eea17e83873c167012b785 Author: Rasmus Lerchedahl Petersen Date: Thu Aug 13 08:02:42 2020 +0200 Python: Annotate test cases commit 5fed92b2d04810f0e92978f3a8817a99c704c09c Author: james Date: Wed Aug 12 20:30:24 2020 +0100 remove new line commit 78948139fd34c7e3768ae622edbce0240a6d9310 Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Wed Aug 12 17:25:54 2020 +0100 Add metadata option missing from reference table commit 2655616a0a31123dfac52d9fb4db94cd0d18ccec Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Aug 12 16:59:15 2020 +0100 C++: Autoformat. commit 9719da864300d3746073acbf2b6168a1b272ca54 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Aug 12 16:58:50 2020 +0100 C++: Move a class that looks like it's intended to be public (and is used outside of the library) above the 'Implementation details' threshold. commit d444778535984753d04486154f7be016a7bba762 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Aug 12 16:57:43 2020 +0100 C++: Make a few things in SAL.qll private where it looks like that was intended (and they're not used outside the file). commit aa6cb51bbac9f2fca2b7d6e558d9f4e1340c0d2f Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Aug 12 16:55:26 2020 +0100 C++: QLDoc SAL.qll. commit 6dfa2ea9d56c4a22f0806666a9a16edd40afbdf1 Author: Rasmus Lerchedahl Petersen Date: Wed Aug 12 16:59:06 2020 +0200 Python: update test expectation commit fd9eb1d40b82e593aa43749101c9f34e92449ada Author: Erik Krogh Kristensen Date: Wed Aug 12 16:55:55 2020 +0200 use Identifier instead of just a plain string when getting tuple-element-names commit 20ffb3fd4c0cd402973244f828d89a619b57d96a Author: Rasmus Lerchedahl Petersen Date: Wed Aug 12 15:43:07 2020 +0200 Python: tests for argument routing Needs annotations commit def1d888c624d5f0e27a14b009f5a41773cf4d35 Author: Tamas Vajk Date: Wed Aug 12 15:22:14 2020 +0200 C#: Add body of partial methods commit 6f83c55ebde327f2444921a65915378ffd5290d5 Author: lcartey@github.com Date: Wed Aug 12 13:48:59 2020 +0100 Java: Switch to `low` as a precision Code Scanning doesn't support "very-low" commit 66541f260bca41de238ede8d944437504268877e Merge: aa9dfa0d6 656ff9c44 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Wed Aug 12 13:28:18 2020 +0100 Merge pull request #4012 from erik-krogh/getId Approved by asgerf, esbena commit dc55ce2bf04ee27d7dcf410e1b0ab2309ccfe244 Author: Erik Krogh Kristensen Date: Wed Aug 12 14:27:33 2020 +0200 add change note commit 1d111c3e1f56e0bbb802e9352ef0c24c3c81b41e Author: Erik Krogh Kristensen Date: Wed Aug 12 14:25:35 2020 +0200 expand what urls are detected by `js/incomplete-url-substring-sanitization` commit 56ff8cf0844ad235aacccd66f092db2b88f05434 Author: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Wed Aug 12 13:12:06 2020 +0100 Apply suggestions from code review Co-authored-by: Felicity Chapman commit aa9dfa0d6f452ee39125e8220a720ae50cc4063f Merge: e80cc6321 5a3acc231 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Wed Aug 12 13:07:22 2020 +0100 Merge pull request #4039 from intrigus-lgtm/patch-3 Approved by erik-krogh commit b99ca601543cb4db2fa48ae32dee0b23f99e2fd6 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Aug 12 12:43:28 2020 +0100 C++: Address review comments. commit a7a016c5df3ee65c489464fd618fc03077e25f34 Author: Erik Krogh Kristensen Date: Wed Aug 12 13:29:43 2020 +0200 update expected output commit b4679cb8cf510a2f56175225690a085a6c98a458 Author: Jonas Jensen Date: Wed Aug 12 13:09:23 2020 +0200 C++: Autoformat fixup commit 93d8d8eb1dbf13aaf8a92ff7ffa3559e472b0251 Author: Jonas Jensen Date: Tue Aug 11 16:28:53 2020 +0200 C++: Demonstrate range analysis MulExpr bugs Unless these issues can be reproduced in far less contrived code, I don't think they will cause problems in practice. commit 0e33eae960c71daeee64f064bb770bdd72df0eb8 Author: Erik Krogh Kristensen Date: Wed Aug 12 10:58:18 2020 +0200 add dbscheme upgrade script commit bc02348a83f91570fa21ebf1900da5f1dcfe7804 Author: james Date: Wed Aug 12 09:54:42 2020 +0100 fix up table and remove another extra space commit f9f5a69a9fa3966850e050a221fa931f4976d573 Author: James Fletcher <42464962+jf205@users.noreply.github.com> Date: Wed Aug 12 09:53:12 2020 +0100 Apply suggestions from @hubwriter's code review Co-authored-by: Alistair Christie <54933897+hubwriter@users.noreply.github.com> commit 4d723ba27658211b09a721a8aea5cad4637d4369 Author: james Date: Wed Aug 12 09:48:00 2020 +0100 remove some spurious spaces commit 0dbe64eee7860af42b626ef549b286673b0c83d9 Author: james Date: Wed Aug 12 09:32:33 2020 +0100 address some review comments stray quote commit 26dcd2faaedf19936be62428912d82920f0b0ec4 Author: Erik Krogh Kristensen Date: Wed Aug 12 10:33:49 2020 +0200 add support for getting the name from named tuple elements commit e603f5cc48155cc632acb899264392b2d6c76b5e Merge: d214cecf4 6dad027eb Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Wed Aug 12 09:29:37 2020 +0100 Merge pull request #4052 from github/max-schaefer-patch-2 Approved by shati-patel commit 6b6172fa5bd12d74f258c37b5fd7429d387fbf96 Author: lcartey@github.com Date: Wed Aug 12 09:21:14 2020 +0100 Java: ExternalAPIs: Further review comments - Extra qldoc - Remove unnecessary module commit 6dad027eb66b1fbd5e7391457351356b14bc4a16 Author: Max Schaefer <54907921+max-schaefer@users.noreply.github.com> Date: Wed Aug 12 09:11:57 2020 +0100 Go: Claim support for 1.15 Go 1.15 was just released, and there are [no changes](https://golang.org/doc/go1.15#language) to the language, so we might as well list it as supported. commit 1ee96a4b4f43b249a051c05b1f6c0c40a259cc94 Author: Jonas Jensen Date: Tue Aug 11 11:55:39 2020 +0200 C++: SimpleRangeAnalysis: unsigned multiplication commit 211ef610399a253512246e5574d3f2e34f9255be Author: Erik Krogh Kristensen Date: Wed Aug 12 09:29:34 2020 +0200 add change note commit b10130524806768455bfd8d23cceb54e850426b4 Author: Erik Krogh Kristensen Date: Wed Aug 12 09:27:43 2020 +0200 autoformat commit e80cc63219275d2dbcc9ebb77cd12fa8383f8f09 Merge: 0476b97f6 dcfbb8667 Author: Robert Marsh Date: Tue Aug 11 15:49:31 2020 -0400 Merge pull request #3861 from dilanbhalla/privatedata C++: Private Data File/Buffer Writes commit e1ecc4662cc6c5857345e2c3bf42eab105e79c7c Author: Erik Krogh Kristensen Date: Tue Aug 11 20:00:22 2020 +0200 fix typo Co-authored-by: Asger F commit 0ff10c319da2e2865115fc11a88777bf26416e81 Author: james Date: Tue Aug 11 15:40:42 2020 +0100 update lots of links commit a655124213f9111b055a07ee012526a2d24f6883 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Aug 11 17:28:31 2020 +0100 C++: I think this is more correct. commit 50558257fc98a567e2e31288fa8cbf5b06428382 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Aug 11 17:05:49 2020 +0100 C++: Change note. commit 128b8328b980a49e553b654772bf4ed06ce58578 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Aug 11 16:16:02 2020 +0100 C++: Autoformat. commit f62ad750481b9d0d72147e3d221a859bf3c1aa5b Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Aug 11 15:25:48 2020 +0100 C++: Taint through std::string operator+=. commit cf6f53082323e133e701c08091508e39476ea165 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Aug 11 15:02:36 2020 +0100 C++: Taint through std::string operator+. commit a57dfd6b678605d0066ad84bed1569063bebd12f Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Aug 11 11:31:28 2020 +0100 C++: Taint through std::string append. commit f824a893ca6dd7902e8f958a46704b10c8531c48 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Aug 10 16:46:47 2020 +0100 C++: Add test cases for appending strings. commit 030ab4f626064b5f81395674fb5499f6eaa088ef Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Aug 10 10:56:58 2020 +0100 C++: Add string append operators to the test (changes layout). commit 2ea25b9d90502cf08efa7246762f4db7f4e04a0e Author: Jonas Jensen Date: Tue Aug 11 16:45:42 2020 +0200 C++: Precise printing of integer bounds The pretty-printing of a QL `float` didn't include enough digits to tell whether a large number had accurate bounds. The `toString` value of a float appears to be more precise. commit e1d4b989239295de2850f8df9e70a12e2afee645 Author: lcartey@github.com Date: Tue Aug 11 15:28:55 2020 +0100 Java: Add further missing

to qhelp commit 8a65dd2cd6551a8b396825960518faa752eb9d47 Author: lcartey@github.com Date: Tue Aug 11 15:28:06 2020 +0100 Java: Address review comments commit 656ff9c441861021e54b55f9299b3157d8f5163d Author: Erik Krogh Kristensen Date: Tue Aug 11 15:40:30 2020 +0200 autoformat commit 21246624b4aa1fee03b6a4088898bc35a8dbfb82 Author: Anders Schack-Mulligen Date: Tue Aug 11 15:15:39 2020 +0200 Java: Add PrintWriter.format as XSS sink. commit a1394c363a9c4dc4e2f7f50bdd59a11074d1ab6b Author: Erik Krogh Kristensen Date: Tue Aug 11 14:49:51 2020 +0200 more consistent naming of predicates commit 2974c4923f3bdb39ed67f9051cbd3ec20285cac3 Author: Erik Krogh Kristensen Date: Tue Aug 11 14:43:25 2020 +0200 introduce and use `isAPropertyWrite` commit 8f6721e0876836d52683d671be4b8cec84603c6f Author: Erik Krogh Kristensen Date: Tue Aug 11 14:40:13 2020 +0200 add explanation for purity-check in `getANodeAfterWrite`/`getANodeBeforeWrite` and move them into an internal module commit 9e768375ce0639fcfc6cf8d9eb25f4ca096948aa Author: Erik Krogh Kristensen Date: Tue Aug 11 14:27:12 2020 +0200 mention purity check in docstring for `maybeAssignsAccessedPropInBlock` commit 374b1b7b97720b89654bb0fe80048fe907a96922 Author: Erik Krogh Kristensen Date: Tue Aug 11 14:24:49 2020 +0200 apply manual magic in both cases in `maybeAssignsAccessedPropInBlock` commit dd4d00293d07f140f53ef524930b4edc62e1728c Author: Rasmus Lerchedahl Petersen Date: Tue Aug 11 14:16:02 2020 +0200 Python: remaining class tests commit d2c87d0a2ee5c5079be78a26c1cbd6e43f27efde Author: Erik Krogh Kristensen Date: Tue Aug 11 13:55:01 2020 +0200 add support for the new assign expression in TypeScript 4 commit 2f34990ae6ae700a033847ac2ba20519b36d597f Author: Erik Krogh Kristensen Date: Tue Aug 11 11:49:39 2020 +0200 add another test for spread elements in tuple types commit ea583fe86242e6e676d83c59e659296aef489171 Author: Erik Krogh Kristensen Date: Tue Aug 11 11:47:28 2020 +0200 add basic support for named tuple elements commit 2612e0c5dd8acec40f65b4297a0efd8932a9cba5 Author: Erik Krogh Kristensen Date: Tue Aug 11 10:19:27 2020 +0200 add test for spread in tuple in non-last position commit b602a36a24198473c1e8222389f48721f7f598a8 Author: Erik Krogh Kristensen Date: Tue Aug 11 10:18:06 2020 +0200 add test for generic spreads in a tuple commit 08c017eb0909b5fd612a3ae5e9b370c16f9ca2e0 Author: Erik Krogh Kristensen Date: Tue Aug 11 10:17:28 2020 +0200 change where tuples elements are loaded from to match TS 4.0 commit ba2d19c70f6bb60b0a0e446460149c8667800c98 Author: Erik Krogh Kristensen Date: Tue Aug 11 11:46:21 2020 +0200 upgrade ts version in package.json commit 99c95246396071b898f9fd746c45643255d657d8 Author: Anders Schack-Mulligen Date: Tue Aug 11 13:09:27 2020 +0200 Java: Make XssSink extensible. commit 394991164fecbe11586432d3d92db1b16c4a7d36 Author: Rasmus Lerchedahl Petersen Date: Tue Aug 11 13:05:35 2020 +0200 Python: Update test expectations commit f834d71bab3c93d7a6f0cdb929fbffdb468e34a2 Author: Rasmus Lerchedahl Petersen Date: Tue Aug 11 11:22:11 2020 +0200 Python: split out data model tests commit 2c5de7f50e3f5ee91d06945ffbfad74859e0e31a Author: Rasmus Lerchedahl Petersen Date: Tue Aug 11 10:48:23 2020 +0200 Python: fix r/l confusion commit 0476b97f638c558d5bbb87a95f1788fc3598c019 Merge: 1f432dc45 7bd5464b0 Author: Jonas Jensen Date: Tue Aug 11 10:09:37 2020 +0200 Merge pull request #3789 from dilanbhalla/cpp C++ Memory Unsafe Functions commit 12dfc4afd9673e619a7acc44205c5209f1c452bb Author: Rasmus Lerchedahl Petersen Date: Tue Aug 11 08:16:49 2020 +0200 Python: clean up validity check code commit 3929e013505a0a58f3469cfe625990e3a68d1617 Author: Rasmus Lerchedahl Petersen Date: Tue Aug 11 08:10:46 2020 +0200 Python: tests for async iterators/context managers commit 681657f0706a6583c01c14d53cf6d8b1417e5914 Merge: 5da37f5cf 1f432dc45 Author: Rasmus Lerchedahl Petersen Date: Tue Aug 11 07:24:17 2020 +0200 Merge branch 'master' of github.com:github/codeql into SharedDataflow_Classes commit 5a3acc231efce2442494403ec86e855f59994ac5 Author: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> Date: Tue Aug 11 01:01:53 2020 +0200 Fix typo commit 7bd5464b01fc20161f78857b22fc7f810fbe39db Author: dilanbhalla <35575727+dilanbhalla@users.noreply.github.com> Date: Mon Aug 10 15:43:16 2020 -0700 Update cpp/ql/src/experimental/Security/CWE/CWE-120/MemoryUnsafeFunctionScan.qhelp Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> commit 4dcaa7be57311a69e9adef640d5d068c19949cee Author: dilanbhalla Date: Mon Aug 10 15:30:09 2020 -0700 pr fixes commit dcfbb866745ab0fb9d88ecb5a78dfd9687ac8736 Author: dilanbhalla Date: Mon Aug 10 15:14:12 2020 -0700 pr fixes commit 5da37f5cf4c0797feb8b1394d425c30e1309e4c7 Author: Rasmus Lerchedahl Petersen Date: Mon Aug 10 17:07:00 2020 +0200 Python: Update test expectations commit dc5167bbe7502829bb79910f9d8a048e512422cb Author: Erik Krogh Kristensen Date: Mon Aug 10 11:52:45 2020 +0000 autoformat commit 34778578dbfd29fb5b8e91b1f7e3051253590432 Author: Erik Krogh Kristensen Date: Mon Aug 10 13:34:36 2020 +0200 fill in docstring commit 9bcac10d9e03d42699f1108caa8737dc46f35c47 Author: Erik Krogh Kristensen Date: Mon Aug 10 13:28:25 2020 +0200 summarize exceptions thrown by immidiatly awaited function calls commit 1f432dc45fbf809f29dcb3904b2f08f9b48de3f8 Merge: 7c4e10df1 3cf11eca2 Author: Jonas Jensen Date: Mon Aug 10 12:10:29 2020 +0200 Merge pull request #4023 from geoffw0/loopdir C++: Exclude decrementing unsigned counters from inconsistentLoopDirection.ql commit a963f15100f2fdd5b5d0b217091fb29d2cf6bf0e Author: Rasmus Lerchedahl Petersen Date: Mon Aug 10 11:54:24 2020 +0200 Python: format strings are unnecessary and mess up For some reason, we got no results when format strings were present. commit 85de5aa16b35d18d78414212269fa286ea97b576 Author: Erik Krogh Kristensen Date: Mon Aug 10 10:51:21 2020 +0200 add `deprecated` modifier Co-authored-by: Asger F commit d214cecf4da65f143d0f548ad732d0377200e984 Merge: 7f8bf2132 64f58b74f Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Aug 10 09:47:09 2020 +0100 Merge pull request #4028 from asger-semmle/js/scope-manager-npe Approved by max-schaefer commit 959c6315c41ae2dfa9a3445d3ee6ca863ad8a1f3 Author: Rasmus Lerchedahl Petersen Date: Mon Aug 10 09:24:45 2020 +0200 Python: update reference to fix tests commit 410b6965625ecb401e759c80caf3de8025045e89 Author: Erik Krogh Kristensen Date: Mon Aug 10 09:09:29 2020 +0200 add deprecated aliases `getId()` forwarding to `getIdentifier()` commit 639d914a47e014513b82e6d67bac673df518caec Author: Rasmus Lerchedahl Petersen Date: Mon Aug 10 08:58:16 2020 +0200 Python: test Awaitable, framework for async test commit 7c4e10df1793da354fe720e54f70f104b11690e8 Merge: 5874ecc28 aab2e6f80 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Aug 10 07:50:21 2020 +0100 Merge pull request #4014 from erik-krogh/stringify Approved by esbena commit 02478774c3f829f4318b205003e5a18d7cf3fbea Author: Rasmus Lerchedahl Petersen Date: Mon Aug 10 08:11:25 2020 +0200 Python: tests for context managers commit 30dc77e5387dcaac0bc0d94f535f89f833f9cad2 Author: Erik Krogh Kristensen Date: Sat Aug 8 21:26:45 2020 +0200 update expected output commit 244052f419aa797434fb780a4828134fa402a054 Author: Erik Krogh Kristensen Date: Sat Aug 8 21:20:20 2020 +0200 autoformat commit 5b7c7f933cc98a949b75e8840e9d6e6ec2930fe4 Author: Rasmus Lerchedahl Petersen Date: Sat Aug 8 00:31:29 2020 +0200 Python: tests for numeric classes commit f6d6f91a42429be198e7417153c1f3f59ada611a Author: Rasmus Lerchedahl Petersen Date: Fri Aug 7 23:39:42 2020 +0200 Python: tests for containers commit aff4535965d4cc70b79a45307ebbc7d1bb38122c Author: Rasmus Lerchedahl Petersen Date: Fri Aug 7 23:07:58 2020 +0200 Python: fix tests for descriptors commit 5874ecc28b0b0c623dbb405a9a619c4d0cabeab3 Merge: 1b0cfc96b b821f918e Author: Arthur Baars Date: Fri Aug 7 21:39:23 2020 +0200 Merge pull request #3976 from luchua-bc/java-unsecure-basic-auth Java: Insecure basic authentication commit d84294df3d0253d588736868c4d18b316c4b7711 Author: Rasmus Lerchedahl Petersen Date: Fri Aug 7 20:07:02 2020 +0200 Python: Check that tests are valid commit 2680afcdc9008f2b575dd6b3b4cadca8f2bad89f Author: Erik Krogh Kristensen Date: Fri Aug 7 19:09:44 2020 +0200 deduplicate some implementation in `storeStep` and `loadStep` commit 3cf11eca2af3db744452a236cde1b3484cf4df1d Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Aug 7 17:28:51 2020 +0100 C++: And more test cases. commit aab2e6f803578ccbe8fd0ffaf68ffe54f6966138 Author: Erik Krogh Kristensen Date: Fri Aug 7 18:20:22 2020 +0200 update name of test file commit 7670e7da979b594aab5e69da9d8e4de94f2f4571 Author: Erik Krogh Kristensen Date: Fri Aug 7 18:17:46 2020 +0200 retarget change-note for 1.26 commit 7d491afaebca2d869352a1c17105be45a853510e Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Aug 7 17:05:13 2020 +0100 C++: More test cases. commit 54fd7d97c07078f13c15509a6a76c2d12e60b6dc Author: Erik Krogh Kristensen Date: Fri Aug 7 18:00:10 2020 +0200 share implementation instead of copy-pasting commit 94cf3a8ddba48d74a0a0e220e69c35dc8f78edf9 Author: Erik Krogh Kristensen Date: Fri Aug 7 17:48:55 2020 +0200 correct copy-paste note after refactorings commit 8f06e9651ffd642c6e856142e29f16525c2a556f Author: Erik Krogh Kristensen Date: Fri Aug 7 16:40:18 2020 +0200 update expected output commit b9a98f51ea25aa5fe55689ee7df70016333cadf1 Author: Erik Krogh Kristensen Date: Fri Aug 7 16:39:06 2020 +0200 update existing tests to work with FunctionReturnNode commit 0edb46c20d3404f75f185bc1f7a52118e69959f9 Author: Erik Krogh Kristensen Date: Fri Aug 7 16:38:01 2020 +0200 improve precision for load/store steps with async functions commit 26ef2f34dad31693afe476f3581caa9bb7202b23 Author: Erik Krogh Kristensen Date: Fri Aug 7 16:37:01 2020 +0200 add precise return-flow for async functions commit cc94c5ec60350dcad6b173fd631dfd4cd4f796b7 Author: Erik Krogh Kristensen Date: Fri Aug 7 16:35:46 2020 +0200 remove imprecise return-flow from async functions commit 0004c28fe8eaceb8ffadaf5a6f60927eb766a3ef Author: Erik Krogh Kristensen Date: Fri Aug 7 16:24:39 2020 +0200 introduce and use FunctionReturnNode commit b7d2e0ca63e086ba296792ef6e99440f06f80b98 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Aug 7 14:18:28 2020 +0100 C++: Make all the tests meaningful. commit 1b0cfc96b3fca38d4875df6d21ea918d477ac658 Merge: 0ba59210f 67c432028 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Fri Aug 7 13:44:23 2020 +0100 Merge pull request #4015 from erik-krogh/nonAbstract Approved by asgerf commit 0ba59210fcfaa5aeab57fd78ce18dedc2b2597fd Merge: e3a12c5fe c8911ab97 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Aug 7 13:41:49 2020 +0100 Merge pull request #4020 from jbj/taint-range-based-for-ast C++: Taint through RangeBasedForStmt (AST only) commit bdcf4198e60b9957f0da04a204d13fa028e362e1 Author: lcartey@github.com Date: Tue Jun 30 11:01:17 2020 +0100 Add additional Hibernate SQL sinks commit e3a12c5feab46b11ac0ee1b693669716a729910f Merge: c20d76349 0e54b498b Author: Anders Schack-Mulligen Date: Fri Aug 7 13:06:13 2020 +0200 Merge pull request #4004 from Marcono1234/patch-2 [Java] Clarify Wildcard.hasUpperBound() doc commit 64f58b74f6a4ac346e1199f7eca221d910d6b327 Author: Asger Feldthaus Date: Fri Aug 7 11:55:26 2020 +0100 JS: Fix extractor crash when some parameters have no type annotation commit c20d763490ccf4ea1ee9f84fca2cd20121587ebf Merge: 77db87efb 3682a902d Author: Tom Hvitved Date: Fri Aug 7 12:54:10 2020 +0200 Merge pull request #3951 from raulgarciamsft/users/raulgarciamsft/dataset_serialization C#: DataSet serialization commit c8911ab973b4324a73da73c91bd567188f0a71fe Author: Jonas Jensen Date: Fri Aug 7 12:40:00 2020 +0200 C++: Test range-based-for with std::vector too commit 77db87efb7d632f7fb0f74a42781ac6f7f6516ee Merge: c177eff3d 3ae3a879d Author: Anders Schack-Mulligen Date: Fri Aug 7 11:57:51 2020 +0200 Merge pull request #3968 from rvermeulen/java-importable-cwe-090 Java: Move LDAP injection sinks, sanitizers, and additional taint steps to importable location commit c177eff3d87bad1bc51339d37d8a76a65f7049f8 Merge: 05e956b37 f9de8eb3b Author: Arthur Baars Date: Fri Aug 7 10:31:38 2020 +0200 Merge pull request #4027 from aschackmull/java/weak-crypto-precision Java: Update precision of java/weak-cryptographic-algorithm. commit f9de8eb3b452f615ce475c0924ba8f83d07f9318 Author: Anders Schack-Mulligen Date: Fri Aug 7 09:40:21 2020 +0200 Java: Update precision of java/weak-cryptographic-algorithm. commit 05e956b374633ee3058b5f9aa227aace8dcaf88e Merge: 205dd1aea f16c26339 Author: Anders Schack-Mulligen Date: Fri Aug 7 09:32:43 2020 +0200 Merge pull request #4022 from aibaars/int-to-long Java: remove security tag from java/integer-multiplication-cast-to-long commit 0e54b498b7f3b4962928e234360c62c5af7edb71 Author: Marcono1234 Date: Sun Aug 2 15:57:33 2020 +0200 Clarify Wildcard.hasTypeBound() doc commit f477e09190705dcb69a46ec51e2714dab8cf4f4f Author: Marcono1234 Date: Sun Aug 2 15:02:51 2020 +0200 Clarify Wildcard.hasUpperBound() doc commit 3ae3a879d2491d46032e2f00fb346b1ee7688976 Author: Remco Vermeulen Date: Thu Aug 6 23:00:03 2020 +0200 Fix qldoc grammar and style mistakes Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> commit 3682a902de4552f3c853c954cf7c57226ef2e0b6 Author: Raul Garcia <42392023+raulgarciamsft@users.noreply.github.com> Date: Thu Aug 6 12:09:02 2020 -0700 Update csharp/ql/src/experimental/Security Features/Serialization/DataSetSerialization.qhelp Co-authored-by: James Fletcher <42464962+jf205@users.noreply.github.com> commit 6e18be43f3bbbc0cf85872b635caa43daefed2e4 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 6 19:27:12 2020 +0100 C++: Change note. commit 0281456948fe1fe4b6a65b038efa47dc0fff64e3 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 6 19:21:06 2020 +0100 C++: Add a 1.26 change note file (what happened to the templates?) commit 0534c69c767cad1fc22c831853da9b511ba742ca Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 6 19:11:46 2020 +0100 C++: Autoformat. commit 0b5b7fa09589fc05de9666cdc02162744d05a8ad Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 6 19:06:42 2020 +0100 C++: Fix another edge case. commit b3f3f6d95ac2b3bd54da9e7395e067e037ccd5fc Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 6 18:58:31 2020 +0100 C++: Fix edge case. commit cbf30e37ed4e47ea3fe63679aa3bf8c196015181 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 6 18:50:18 2020 +0100 C++: Fix the issue. commit a7564c9e0eb206b84368de663767ca9912f393b5 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Aug 6 18:28:41 2020 +0100 C++: Add a test of unsigned count-down loops. commit f16c2633935fd4e0caa22cbbf3c31b8fc8b908b8 Author: Arthur Baars Date: Thu Aug 6 17:42:01 2020 +0200 Java: remove security tag from java/integer-multiplication-cast-to-long commit 3db1ceeb70cbe8dc04dfa90ecd222d9f16f8df73 Author: Rasmus Lerchedahl Petersen Date: Thu Aug 6 15:42:14 2020 +0200 Python: format ql commit 614103c3b6bcea797cdeaeda2733862fa5cad0ec Author: Rasmus Lerchedahl Petersen Date: Thu Aug 6 15:40:41 2020 +0200 Python: Test calls rather than flows commit 7cc877cbbbf0d9a79e993380ff4f964520a0535c Author: Jonas Jensen Date: Thu Aug 6 15:34:23 2020 +0200 C++: Taint through RangeBasedForStmt (AST only) commit ce86a8b72e4a6f72ff8fbfcd036ef4a61b7f55ed Author: Rasmus Lerchedahl Petersen Date: Thu Aug 6 14:42:56 2020 +0200 Python: format ql commit e77ceaf4b81e8268a4972eaa2055c916d8538e39 Author: Rasmus Lerchedahl Petersen Date: Thu Aug 6 13:31:54 2020 +0200 Python: Track dictionary keys Also, less hacky comprehension, but I think we still want to fix the extractor commit 408db412dc65a804ac6ed9a53cd500736450a0bf Author: Remco Vermeulen Date: Thu Aug 6 13:29:02 2020 +0200 Add missing predicate qldoc commit 5a819422c1f369864f1bfce9820887636c54c658 Author: Remco Vermeulen Date: Thu Aug 6 12:02:34 2020 +0200 Reuse `Unit` class from `TaintTracking` commit 7f7ad88deafa1eeeb85e2a66cd6f156139fc4b34 Author: Remco Vermeulen Date: Thu Aug 6 11:35:03 2020 +0200 Limit LdapAdditionalTaintStep to Ldap configuration commit 205dd1aeadd6b2647aeab3fac700b13f560338e7 Merge: 5f635aca3 1011325cf Author: Anders Schack-Mulligen Date: Thu Aug 6 11:21:39 2020 +0200 Merge pull request #3881 from intrigus-lgtm/more-pathcreations Java: Centralize and model additional path creations. commit b821f918e5958d7405a6bf5f2861f3853b384dc4 Author: luchua-bc Date: Thu Aug 6 01:53:29 2020 +0000 Address issues with matching empty host and host in a concatenated string commit 9a8eed84405d1d42ca1ed298cbdf6fae97e427ab Author: luchua-bc Date: Wed Aug 5 19:57:31 2020 +0000 Enhance address match commit 1011325cf7d5466057a00e3efa086e11a1ecb8b4 Author: intrigus Date: Wed Aug 5 21:45:41 2020 +0200 Accept test changes. commit 7c235597de359a033d16deaa9bbd7ca06824249e Author: Rasmus Lerchedahl Petersen Date: Wed Aug 5 19:22:54 2020 +0200 Python: More precise dataflow for tuples (and dictionaries, but that is not fleshed out) commit a1411407c18c51ef9ec2857d0af974e277d4f63b Author: Remco Vermeulen Date: Wed Aug 5 17:07:05 2020 +0200 Consolidate sanitizers into default sanitizer commit 0c09d66d43d60d257492d3c9b121b9e1e7d93b1f Author: Remco Vermeulen Date: Wed Aug 5 16:53:50 2020 +0200 Consolidate different sinks into a default sink. commit f1dc36244c4733a4634131045b5e15a7e6333126 Author: Erik Krogh Kristensen Date: Tue Aug 4 15:12:59 2020 +0200 update tests and queries that used getId() commit 7f8bf213251832512642fc63311ee36a7958dc02 Merge: 63115a36f 364cc19de Author: James Fletcher <42464962+jf205@users.noreply.github.com> Date: Wed Aug 5 14:20:13 2020 +0100 Merge pull request #4016 from jf205/learn-codeql/styles CodeQL docs: update CSS and master page template commit e642808a7576ec49226932bce70d55f84e53b9a5 Author: yoff Date: Wed Aug 5 15:12:27 2020 +0200 Update python/ql/test/experimental/dataflow/coverage/classes.py Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> commit 5f635aca36fd09d38b366076bfcf1f735fdc40e9 Merge: 9e78341e4 9f5c37cca Author: Jonas Jensen Date: Wed Aug 5 14:35:05 2020 +0200 Merge pull request #3768 from geoffw0/copymove C++: Clean up ConversionConstructor. commit a89624698d3fccffa34b4cab8c819f7ad0bc0764 Author: Rasmus Lerchedahl Petersen Date: Wed Aug 5 14:28:28 2020 +0200 Python: format ql commit 2639e68a0d062beddc327ecad4b30b2f9f82a4da Author: Rasmus Lerchedahl Petersen Date: Wed Aug 5 14:16:50 2020 +0200 Python: format ql commit 81ad4552c9e2567c9177079f1411587de3eb85a7 Author: Rasmus Lerchedahl Petersen Date: Wed Aug 5 13:30:30 2020 +0200 Python: full list of magic methods to be tested commit cc5ef4d5e19b282352f5b67d978473618ba734f7 Author: Erik Krogh Kristensen Date: Wed Aug 5 13:22:41 2020 +0200 rename JsonSerializeCall to JsonStringifyCall commit 364cc19dea0f2cbb731d266e93081ebaf6c1078f Author: james Date: Wed Aug 5 10:52:58 2020 +0100 docs: update styles commit b43d410ab17b8a8d1c20327017553e39d7f1a965 Author: Erik Krogh Kristensen Date: Tue Aug 4 14:54:34 2020 +0200 add change log for JSON serializers commit f70cb2e7b32453d51f605aa24db52792980cf053 Author: Erik Krogh Kristensen Date: Tue Aug 4 14:48:11 2020 +0200 add test for new JSON serializers commit 5a3f67a68238b6616416154595e8c7b7bca18f6d Author: Erik Krogh Kristensen Date: Tue Aug 4 14:35:09 2020 +0200 introduce model for JSON.stringify and similar libraries commit 9e78341e433ea5e225dfb9598f9cb26d6b5fb952 Merge: 32d9d270f c2733ad22 Author: Anders Schack-Mulligen Date: Wed Aug 5 10:16:00 2020 +0200 Merge pull request #3928 from rvermeulen/java-importable-cwe-113 Java: Move `HeaderSplittingSink` and `WhitelistedSource` into importable library commit 67c4320287400afcc99ffed5cb7057b2ccfeabea Author: Erik Krogh Kristensen Date: Wed Aug 5 10:03:46 2020 +0200 make JumpStmt non abstract commit 016bdc161486fd6e1923202e8208f6bf1187f50b Author: Erik Krogh Kristensen Date: Wed Aug 5 09:59:30 2020 +0200 make ControlStmt non abstract commit 32d9d270fc55bf2706c8ab8ea642875784a118a5 Merge: ea0896c78 c585b2e48 Author: Anders Schack-Mulligen Date: Wed Aug 5 09:31:01 2020 +0200 Merge pull request #3948 from aibaars/java-3941 Java: stack trace exposure: address false positives commit ea0896c78b95e54584f46d11cbb06b0cd4a8d7dc Merge: 63115a36f 4990d0049 Author: Jonas Jensen Date: Wed Aug 5 09:11:53 2020 +0200 Merge pull request #3999 from MathiasVP/mathiasvp/range-based-for-loop-taint-tests C++: Add tests for taint through range-based for loops commit aa27eaf7e0dc2dd7f109b4ca2dcc645c84722ab2 Author: Raul Garcia (MSFT) Date: Tue Aug 4 15:50:58 2020 -0700 Addrssing the comments from https://github.com/github/codeql/pull/3951#discussion_r464894547 that I missed previously commit 9f5c37ccaae688e4317540f0a49f4d984933b860 Merge: c4940aaa8 63115a36f Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Aug 4 15:41:27 2020 +0100 Merge branch 'master' into copymove commit 5727e6f9f8c76bf7f0f797c09ade540ad9457ee1 Author: Erik Krogh Kristensen Date: Tue Aug 4 16:10:49 2020 +0200 make CompoundAssignExpr non-abstract commit cf3f275aa126c25c85a298c4c8620b147592ea3e Author: Erik Krogh Kristensen Date: Tue Aug 4 16:02:32 2020 +0200 make DestructuringPattern non-abstract commit d7c08f732de4296a81a0c315d670a9d5aab41922 Merge: d32e2772a 63115a36f Author: Rasmus Lerchedahl Petersen Date: Tue Aug 4 16:01:42 2020 +0200 Merge branch 'master' of github.com:github/codeql into SharedDataflow_Classes commit 63115a36f7445e31bb3bacb9c2941c831c8da9b5 Merge: 68441bdf9 07f1e133f Author: Tom Hvitved Date: Tue Aug 4 14:33:54 2020 +0200 Merge pull request #3994 from hvitved/csharp/dataflow/library-aps-adjust C#: More type-based adjustment of library-flow access paths commit 9312b42e79f4a2239c8b51833e1597a74d50274c Author: Rasmus Lerchedahl Petersen Date: Tue Aug 4 13:54:50 2020 +0200 Python: More easy-to-get content flow There are some things that should be rewritten, though, but it may involve the extractor commit 0867c5567ebfcea5a05ee0ca18cefed05c24c399 Author: Erik Krogh Kristensen Date: Tue Aug 4 13:22:19 2020 +0200 rename `getId()` to `getIdentifier()` commit 68441bdf99adf0a2ce1ccd7b101dbb94f832e539 Merge: cdea0f05b 5942bc6a4 Author: Anders Schack-Mulligen Date: Tue Aug 4 12:12:38 2020 +0200 Merge pull request #3987 from Marcono1234/patch-1 [Java] Improve InsecureJavaMail.qhelp references commit 5a96ee1a7bf92f305055b4f3918dc6fb9d2bd5c4 Author: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Tue Aug 4 09:41:40 2020 +0100 Remove parameter names from signatures Co-authored-by: Marcono1234 commit 368572f1f066b6237201210d17de95b9903a520e Author: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Tue Aug 4 09:40:59 2020 +0100 Update java/ql/src/Security/CWE/CWE-020/UntrustedDataToExternalAPI.qhelp Co-authored-by: Marcono1234 commit 7928a024247bbd26c6ad888ab7856a9d49966444 Author: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Tue Aug 4 09:40:51 2020 +0100 Add missing full stop. Co-authored-by: Marcono1234 commit e0c081a2afedcbf1822380f8a8c42280daf5c7ab Author: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Tue Aug 4 09:40:28 2020 +0100 Add missing `

` tag Co-authored-by: Felicity Chapman commit cdea0f05b0cf780f7aea9157f47532ff540be1b9 Merge: 71933a4d8 b1e604b49 Author: Anders Schack-Mulligen Date: Tue Aug 4 10:27:22 2020 +0200 Merge pull request #3946 from aibaars/util-collections-2 Java: Clean up ContainerFlow: address outstanding comments commit eccfade9288d0651451be1d6fbac0b266008fb9c Author: Erik Krogh Kristensen Date: Tue Aug 4 10:24:49 2020 +0200 rewrite parts of the DeadStoreOfProperty query commit e629e6bbb023fed9a0d14bc86dafdfc031202b95 Author: Erik Krogh Kristensen Date: Mon Aug 3 14:55:12 2020 +0200 changes based on review commit 8131618382896178c70f102715497dfbf7909633 Author: Erik Krogh Kristensen Date: Mon Aug 3 14:25:25 2020 +0200 revert making `rankedAccessPath` private commit 97aa3cc8a3c4e41be873b283b5b7065b8a1d5686 Author: Erik Krogh Kristensen Date: Thu Jul 9 10:09:20 2020 +0200 rewrite DeadStoreOfProperty to improve worst-case complexity commit dbeef312cac2615d59ddbefc85bacdfac792a744 Author: Erik Krogh Kristensen Date: Thu Jul 9 10:05:23 2020 +0200 add some TypeScript tests to DeadStoreOfProperty commit c52064af78945b2ed0953132797a4eb0fd6ddc38 Author: Raul Garcia (MSFT) Date: Mon Aug 3 16:39:41 2020 -0700 Fixing problems based on CR feedback. https://github.com/github/codeql/pull/3951#pullrequestreview-458987208 commit 71933a4d8a32d32f085f14b7b44f41d1cdcae2e4 Merge: 8855ab8c8 d1db7b350 Author: Tom Hvitved Date: Mon Aug 3 19:33:26 2020 +0200 Merge pull request #4009 from hvitved/csharp/extractor-pack-files C#: Add CodeQL extractor pack files commit 8855ab8c8cab2efec26a6a45bb40e26912dd95a7 Merge: a4f8b19ae 3487ec17d Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Aug 3 15:40:05 2020 +0100 Merge pull request #3835 from Raz0r/js/xss-protocol-sinks Approved by erik-krogh commit a4f8b19ae4be4b6943a32e82f644bc83eb7bf173 Merge: c8e5db189 f5cc14f98 Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Aug 3 15:38:51 2020 +0100 Merge pull request #3876 from erik-krogh/CWE078-Correctness Approved by esbena commit d1db7b350fbab7e52fbd2080b730a7a68aed5099 Author: Tom Hvitved Date: Mon Aug 3 14:36:06 2020 +0200 C#: Add CodeQL extractor pack files commit c8e5db189a3ffb0e5b68ed3e8f21b975711cb7db Merge: 0bbdc70cd 00e900f1b Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Aug 3 13:18:22 2020 +0100 Merge pull request #3913 from erik-krogh/topmost Approved by asgerf commit f5cc14f980a51182bf7bd0fa1829dc08bf12c86b Author: Erik Krogh Kristensen Date: Mon Aug 3 13:49:21 2020 +0200 fix typo commit 0bbdc70cdb469567faa9ee85c48d8c5914881730 Merge: dd1a8e9b2 ceb19292c Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Mon Aug 3 09:25:17 2020 +0100 Merge pull request #3864 from erik-krogh/exprString Approved by asgerf, esbena commit dd1a8e9b289b6e06a8400bb0356c74e2a10c1905 Merge: 595ab442e 17e256b2c Author: Tamás Vajk Date: Mon Aug 3 09:52:46 2020 +0200 Merge pull request #3991 from tamasvajk/feature/vscode Add VS Code tasks to build and test the C# bits commit 9d09b4c811cadb2525e3fc12d04d2d85d2c1dd54 Author: Rasmus Lerchedahl Petersen Date: Mon Aug 3 08:53:22 2020 +0200 Python: Comprehension stores commit f21777c6ce50176cdedec525b6b24f0abf2bb3a6 Author: Rasmus Lerchedahl Petersen Date: Mon Aug 3 08:16:43 2020 +0200 Python: Simplyfy sequence stores commit 4a8d532a71362729a2f510c2eb9e5e504a22e59f Author: Rasmus Lerchedahl Petersen Date: Mon Aug 3 07:25:06 2020 +0200 Python: update test expectations and annotations commit 6debc48e7965c8ec5d97759c93b6cb12ab09e09e Merge: b21da86ac 595ab442e Author: Rasmus Lerchedahl Petersen Date: Mon Aug 3 07:05:34 2020 +0200 Merge branch 'master' of github.com:github/codeql into SharedDataflow_SequenceFlow commit ff0dacf1d76a31970de4a4a6f2fa4c115d51f1cd Author: luchua-bc Date: Mon Aug 3 00:52:47 2020 +0000 Optimize the TaintTracking commit b65a03330243a4f7565487f2320b305bf16bd03b Author: luchua-bc Date: Sat Aug 1 03:42:13 2020 +0000 Shorten the regex private domain match commit ff58abb7d3b55a5d56e3214dd3d9039441349a9c Author: luchua-bc Date: Sat Aug 1 03:25:02 2020 +0000 Revamp the sink code commit 595ab442e66a0911f836ae859faebcd3f4f0177d Merge: c8dc2ee61 3e1305614 Author: Calum Grant <42069085+calumgrant@users.noreply.github.com> Date: Fri Jul 31 17:45:00 2020 +0100 Merge pull request #3996 from yoff/SharedDataflow_Syntax Python: Test all expressions that incur dataflow commit 3e13056140642d90179d1adb5a312f0d329be1c7 Author: Rasmus Lerchedahl Petersen Date: Fri Jul 31 17:20:58 2020 +0200 Python: Address most review comments commit c8dc2ee611c571d11999e2eb50bacd2b6e559829 Merge: 54ce73b40 0ea5f347f Author: Tamás Vajk Date: Fri Jul 31 16:59:36 2020 +0200 Merge pull request #3993 from tamasvajk/remove-noise Turn off C# auto-compile on topmost folder commit 17e256b2c7c3c41a0778c3f65a1f5fc5e3d8f299 Author: Tamas Vajk Date: Fri Jul 24 10:47:12 2020 +0200 C#: Add VS Code tasks to build and test the C# bits commit b21da86ac1bd54c7f5e1e01694204ef182be21ea Author: Rasmus Lerchedahl Petersen Date: Fri Jul 31 15:45:20 2020 +0200 Python: Field flow for sequence elements only from displays so far commit e8ce62e211b37a24acef3717f295ebd41b6eb73d Author: Rasmus Lerchedahl Petersen Date: Fri Jul 31 15:28:27 2020 +0200 Python: Fix missing flow annotation commit e13cf2e126be431e69750cf7786e49f382b57604 Author: Rasmus Lerchedahl Petersen Date: Fri Jul 31 14:25:09 2020 +0200 Python: fix formatting commit 54ce73b40e9455bc142932b88fc7b9bfbaf56c76 Merge: 18fa6b613 e08e7cdf3 Author: Tom Hvitved Date: Fri Jul 31 14:07:35 2020 +0200 Merge pull request #3995 from hvitved/csharp/fix-alerts C#: Fix a few alerts commit 29493f5bd73184e0859c89170d57bc09d19b0268 Author: Rasmus Lerchedahl Petersen Date: Fri Jul 31 12:38:57 2020 +0200 Python: Make the coverage test a path query commit 18fa6b613de4eccb834d29bbc05e1aff6c29ca8f Merge: 7e72ef350 246ae575b Author: CodeQL CI <68440632+codeql-ci@users.noreply.github.com> Date: Fri Jul 31 11:08:58 2020 +0100 Merge pull request #3998 from ceh-forks/ceh-fix-typos Approved by shati-patel commit 4990d004984f1bc17f1c0f218dd8c436984e2581 Author: Mathias Vorreiter Pedersen Date: Fri Jul 31 09:57:35 2020 +0200 C++: Add taint tests demonstrating lack of taint through range based for loops commit b88ef56cb498a946a5bfdda0748469cbc5b6d7b8 Author: Mathias Vorreiter Pedersen Date: Fri Jul 31 09:45:32 2020 +0200 C++: Add basic iterator definition that matches STL commit 246ae575be300c800106d43d468a5d061aca3d75 Author: Emil Hessman Date: Fri Jul 31 06:59:55 2020 +0200 Fix typos commit a5dab4e7685cd8ca597d9185580aa15d9c906382 Author: Raul Garcia (MSFT) Date: Thu Jul 30 17:05:42 2020 -0700 removing a redundant line commit 81de1b14d91ed7c86e0f36369617c6a9fd2d3623 Author: luchua-bc Date: Thu Jul 30 19:16:48 2020 +0000 Revamp the source of path query commit 64f4613a3f5db94375fe4fc358fb4b2a6c8c670c Author: Raul Garcia (MSFT) Date: Thu Jul 30 10:25:15 2020 -0700 Removing the options file as requested commit 9e74c183fef856cd29ea45d42e4d3e93c90c2ada Author: Raul Garcia (MSFT) Date: Thu Jul 30 10:24:24 2020 -0700 Fixing expected results after adding comments to the unit test .cs file commit 7e72ef350e50bbac69497795d51ee902dcda5bfc Merge: 5b1d25591 5bad003c0 Author: Arthur Baars Date: Thu Jul 30 18:39:01 2020 +0200 Merge pull request #3975 from aibaars/lgtm-suites CodeQL: complete LGTM suites commit 133e18edd9f697610157c949d065849e02dc3402 Author: Rasmus Lerchedahl Petersen Date: Thu Jul 30 18:13:39 2020 +0200 Python: Annotate missing flow commit 1467d6b419e99987a54abb420747c815f953db5e Author: Rasmus Lerchedahl Petersen Date: Thu Jul 30 17:51:17 2020 +0200 Python: Test all expressions that incur dataflow commit 5b1d25591ec895db5f42486cd147134de090e1b5 Merge: 437baf160 91762ec27 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Thu Jul 30 15:10:46 2020 +0100 Merge pull request #3979 from max-schaefer/js/more-comand-injection-models Approved by asgerf commit e08e7cdf34c56e0115657395663df10b2adc8ab4 Author: Tom Hvitved Date: Thu Jul 30 16:03:36 2020 +0200 C#: Fix a few alerts commit 07f1e133f346fd375b334090e64470835e3ec4b4 Author: Tom Hvitved Date: Thu Jul 30 14:03:33 2020 +0200 C#: More type-based adjustment of library-flow access paths This change removes the restriction that only access paths of length 1 can have the head adjusted, based on type information from the call to the relevant library-code callable. commit 437baf160ec18ee729b0e88c91e5594bbd8ecf0f Merge: 632713c47 4da74dea2 Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Thu Jul 30 14:37:48 2020 +0100 Merge pull request #3973 from shati-patel/sd-189 Add basic LGTM tutorials to CodeQL sphinx project commit 0ea5f347f7be2a894ddcf32152197e6dbca03eab Author: Tamas Vajk Date: Thu Jul 30 15:23:13 2020 +0200 Turn off C# auto-compile on topmost folder If the C# extension is installed, then it reports 25k+ errors on the C# extractor until it is properly built. This is pure noise because the solution would be opened and built from the correct subdirectory. This commit disables the C# compilation altogether. commit 632713c475aa5d89904f0d4213de277e4b0d51e2 Merge: ddbec50c0 05307b875 Author: Tom Hvitved Date: Thu Jul 30 14:20:00 2020 +0200 Merge pull request #3986 from hvitved/csharp/null-maybe-null-coalescing-assignment C#: Fix false-positives in `cs/dereferenced-value-may-be-null` commit 05307b8757d9ac38a0e54009414e1323478dadba Author: Tom Hvitved Date: Thu Jul 30 12:13:56 2020 +0200 C#: Remove more FPs in `cs/dereferenced-value-may-be-null` commit 4f4d9d35be1f9a17276cb1d8eba12cb32b0f02a8 Author: Tom Hvitved Date: Thu Jul 30 12:13:30 2020 +0200 C#: Add more nullness tests commit 4da74dea288cf55292d8289ae4ee028aba51ead0 Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Thu Jul 30 10:57:17 2020 +0100 Update C# example commit 0a4b82843299f646f41b4f66cbea54598f6950c9 Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Thu Jul 30 11:55:28 2020 +0200 Update docs/language/learn-ql/java/basic-query-java.rst Co-authored-by: Marcono1234 commit 9aaf20e6f20a754384ffa65e1d6dfc5de45f430d Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Thu Jul 30 11:55:14 2020 +0200 Update docs/language/learn-ql/java/basic-query-java.rst Co-authored-by: Marcono1234 commit 6f845b00449bf9fa5cc6e957e2c80182d45d0f61 Author: Raul Garcia (MSFT) Date: Wed Jul 29 18:01:46 2020 -0700 Using CodeQL AutoFormat commit 7923c480afa264d272ccf55b613daba87d31f893 Author: Raul Garcia (MSFT) Date: Wed Jul 29 17:14:37 2020 -0700 Fixing queries based on suggestions/comments. TODO: Auto-formatting is still pending (need guidance on how to enable it on my environment). Thanks commit 83e9d052d98de459c695d4c17776db6085f015e3 Author: Raul Garcia <42392023+raulgarciamsft@users.noreply.github.com> Date: Wed Jul 29 16:24:13 2020 -0700 Update csharp/ql/src/experimental/Security Features/Serialization/DataSetSerialization.qll Co-authored-by: Jaroslav Lobačevski commit ddbec50c07b3b19a8967813f59b10277c3bb1d28 Merge: bec415c5c 978bf3aef Author: Robert Marsh Date: Wed Jul 29 12:27:29 2020 -0700 Merge pull request #3990 from MathiasVP/mathiasvp/fix-qldoc-SemanticStackVariable C++: Fix QLDoc for `SemanticStackVariable` commit bec415c5c1b544a78cfc9d2c0cfc402fc8fe998d Merge: 4345b167e f91043e08 Author: Tom Hvitved Date: Wed Jul 29 19:58:54 2020 +0200 Merge pull request #3988 from hvitved/csharp/collection-flow-change-note C#: Add change note commit 5bad003c0c898d335e4d9c221b3ef8e9d6c3c5e3 Author: Arthur Baars Date: Mon Jul 27 17:45:36 2020 +0200 Add qlpack.yml files for example queries commit 978bf3aefcccd8320abcf9e009d16c3aa56ca466 Author: Mathias Vorreiter Pedersen Date: Wed Jul 29 15:59:19 2020 +0200 C++: Make QLDoc comment represent a valid C++ template commit d32e2772a0bcebdd7bcaf54905574888a4706361 Author: Rasmus Lerchedahl Petersen Date: Wed Jul 29 15:52:56 2020 +0200 Python: some doc, a generator, and a corotuine commit f91043e08e731596f590e1c1f68728c043be75f7 Author: Tom Hvitved Date: Wed Jul 29 10:18:03 2020 +0200 C#: Add change note commit 4345b167ece53fb95958aec7b939e437c0a246f8 Merge: c5a4a6be0 3d711b8cd Author: Tom Hvitved Date: Wed Jul 29 10:04:08 2020 +0200 Merge pull request #3935 from github/henrymercer/fix-broken-doc-link C#: Fix broken link to ECMA-335 commit 5942bc6a438ad0ca2fbf8d14f890a313991bf4e1 Author: Marcono1234 Date: Wed Jul 29 01:45:27 2020 +0200 Improve InsecureJavaMail.qhelp references commit 488a7f4d0142d1f4b2d48a8afb5cc422e572e8a2 Author: Rasmus Lerchedahl Petersen Date: Tue Jul 28 21:46:45 2020 +0200 Python: update test expectations commit c4041e55ba4596deeb247736cc8cc17e6190cd13 Author: Arthur Baars Date: Fri Jul 24 18:06:52 2020 +0200 CodeQL: complete LGTM suites commit eab64f125b52a9684229da37ee55a21accdaab8a Author: Rasmus Lerchedahl Petersen Date: Tue Jul 28 20:32:12 2020 +0200 Python: Dataflow, start on test for classes commit 5520504658b67f6931c4bf2233094d9e86e31000 Author: luchua-bc Date: Tue Jul 28 15:41:23 2020 +0000 Update expected results commit a91cc9b7ecb9153dededa8a6cd7d800d74e5db53 Author: luchua-bc Date: Tue Jul 28 15:36:12 2020 +0000 Convert the query to path-problem commit d39a33655f1cb551469e14cfb683ba2d83530baf Author: Tom Hvitved Date: Tue Jul 28 10:52:15 2020 +0200 C#: Fix false-positives in `cs/dereferenced-value-may-be-null` Dereferencing an expression of a nullable type should only be reported when the expression is not clearly non-null. commit a79f09f1deea6431e224485ecefd221b3afaa333 Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Tue Jul 28 15:25:59 2020 +0200 Add basic query for Go commit 8e8c43a25b4c6dca3df2899dad33978ac077b9db Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Tue Jul 28 13:54:06 2020 +0200 Add basic query for JavaScript commit 7f911f00eeb0d533fa0d8ab068d226536e8c3225 Author: luchua-bc Date: Tue Jul 28 11:40:21 2020 +0000 Rename to insecure basic auth commit 9edf1646c913274b9420fff2c876b30dc7a45e79 Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Tue Jul 28 12:18:45 2020 +0200 Add basic queries for C#, Java, and Python commit 0f3599039ffa80e11bb63661c0efe0ff643dc3e3 Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Tue Jul 28 11:49:17 2020 +0200 Update docs/language/learn-ql/cpp/basic-query-cpp.rst Co-authored-by: James Fletcher <42464962+jf205@users.noreply.github.com> commit ce2368de96a0dc5c6b1ad743862a345646c230ce Author: Tom Hvitved Date: Tue Jul 28 10:25:25 2020 +0200 C#: Add tests for null-coalescing assignment commit 248628b11e45f559d5b39c3d731b46466773a94f Author: luchua-bc Date: Mon Jul 27 20:31:07 2020 +0000 Enhance basic auth string search with a recursive method commit 3a23451395d60c38470830928395cdfc3dbb3c96 Author: luchua-bc Date: Mon Jul 27 18:50:47 2020 +0000 Enhance the query commit 38acea633fefe1dae5d54ca1ef2d39d846e276c9 Author: Rasmus Lerchedahl Petersen Date: Mon Jul 27 17:58:21 2020 +0200 Python: Dataflow, expand callable to classes commit c5a4a6be05ed7c59ac49c7bfb5b3546cf9b9c6f3 Merge: f40242dc3 7dfc58415 Author: Tom Hvitved Date: Mon Jul 27 16:51:24 2020 +0200 Merge pull request #3871 from hvitved/csharp/autobuilder/dotnet-delegate C#: Introduce delegate type in autobuilder commit f40242dc3f4293ac206de01864b3acd11c693ef5 Merge: f5c1de8a1 7a71ca3e0 Author: Taus Date: Mon Jul 27 14:43:39 2020 +0200 Merge pull request #3396 from porcupineyhairs/python-ssti Python : Add query to detect Server Side Template Injection commit 91762ec274ad7b1e1216d787a183fc9b0831c9f9 Author: Max Schaefer Date: Mon Jul 27 11:42:32 2020 +0100 JavaScript: Add partial model for `opener`. 3.5M weekly downloads. Note that we do not treat the first argument as a command-injection sink. While it is possible to inject commands that way, it is more likely to cause false positives where the user input is concatenated with some prefix that makes the opening heuristic decide to treat it as a URL. commit 9aa26fa4bc5248c6a620ecc03cb9b8d9411d8456 Author: Max Schaefer Date: Mon Jul 27 11:37:06 2020 +0100 JavaScript: Add model for `foreground-child`. >1M weekly downloads, so seems worth doing. commit 2f842042ea1cee4708b1c407ed46fd43aa5b395a Author: Max Schaefer Date: Mon Jul 27 11:33:24 2020 +0100 JavaScript: Model another `execa` function relevant for command injection. commit f5c1de8a17b575ae46df22381e5f4f8d9e663703 Merge: 09f45ac9f 79f412ff5 Author: Tom Hvitved Date: Mon Jul 27 11:44:58 2020 +0200 Merge pull request #3960 from calumgrant/cs/tag-inefficient-containskey C#: Fix tags typo commit 09f45ac9fe9bbecfe29179048a707d18705c2973 Merge: bb5b161d7 03cc4e179 Author: Calum Grant <42069085+calumgrant@users.noreply.github.com> Date: Mon Jul 27 10:43:04 2020 +0100 Merge pull request #3877 from calumgrant/cs/autobuilder-alerts C#: Make fields readonly commit db09ca7b68c092eaed7cef2f96ff04d2d69e6fe3 Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Mon Jul 27 09:04:27 2020 +0200 Update queries + outdated note commit 8dee3da4fee2d45d22d7f9e570c09132bc059bc9 Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Sun Jul 26 23:50:22 2020 +0200 Update .qhelp commit ac7c511d86f5da9c4ab97a9b7a8094c23c140be1 Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Sun Jul 26 23:47:53 2020 +0200 Update .qhelp commit 2cec8f7e9d5a4914f0e83a289fbee963ad89c4c2 Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Sun Jul 26 23:23:56 2020 +0200 Update .qhelp commit c469f71957051e768b8e481867a7194524a6674e Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Sun Jul 26 22:56:36 2020 +0200 Add Codeql query to detect if cookies are sent without the flag being set commit 01fb51829c231cbcfd8134789863194d70323114 Author: luchua-bc Date: Fri Jul 24 20:35:09 2020 +0000 Unsecure basic authentication commit e0016f6c5267a2caa6a67fe6253c3da7e3077faf Author: Rasmus Wriedt Larsen Date: Fri Jul 24 20:08:26 2020 +0200 Python: CG trace: Mention adding projects in README commit aca703e1316442d34f60dff40a04e6a49bff285c Author: Rasmus Wriedt Larsen Date: Fri Jul 24 20:06:53 2020 +0200 Python: CG trace: Add support for flask commit bb80635dc352e7db110c03f1c090066ab9c3ac59 Author: Rasmus Wriedt Larsen Date: Fri Jul 24 19:35:06 2020 +0200 Python: CG trace: Updated README commit ecafc760e865119ff85b965dab7b6cd0ed47d478 Author: Rasmus Wriedt Larsen Date: Fri Jul 24 19:34:51 2020 +0200 Python: CG trace: Improved debugging queries a bit commit 2407c8b07e1416f32d6cd379dfbc2c5bb0322950 Author: Rasmus Wriedt Larsen Date: Fri Jul 24 19:13:53 2020 +0200 Python: CG trace: Better handling of builtins without __module__ Not 100% perfect, but better commit 9c76618d8b29fd1f28ca1b348f5ea2141b965749 Author: Rasmus Wriedt Larsen Date: Fri Jul 24 18:59:29 2020 +0200 Python: CG trace: Make `./helper.sh` show help again commit 8057e11fe42d0f0205c033b6b3467c2da3c3994f Author: Rasmus Wriedt Larsen Date: Fri Jul 24 18:38:12 2020 +0200 Python: CG trace: Add `./helper.sh metrics` command commit 779a82ee0748dc46fc8e5df7469375485dce75f8 Author: Rasmus Wriedt Larsen Date: Fri Jul 24 18:37:48 2020 +0200 Python: CG trace: Minor cleanup in helper.sh commit 4c689434c374a58fe0a2300a088c67476f87e6a5 Author: Rasmus Wriedt Larsen Date: Fri Jul 24 17:00:13 2020 +0200 Python: CG trace: Restructure QL code commit 321d5104f01b342f415dca3f70a4aafc74332e74 Author: Rasmus Wriedt Larsen Date: Fri Jul 24 16:51:14 2020 +0200 Python: CG trace: Autogenerate BytecodeExpr.qll Some code I had lying around, just hadn't comitted. Not that useful since most of these have been disabled in 55404ae98 for now. commit a7bc9544b6b7e7ed6f3d4e131c616ea628fa66d6 Author: Rasmus Wriedt Larsen Date: Fri Jul 24 16:49:54 2020 +0200 Python: CG trace: Metrics, number of recorded calls not ignored turned out to be useful after all :P commit bb05db5c98a283b16ccec4b198749b22ba69816e Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Fri Jul 24 11:57:50 2020 +0200 Convert C/C++ article commit 367a49803bc6633ea3fbedfe9ccb20ddc2f44301 Author: Rasmus Wriedt Larsen Date: Fri Jul 24 11:19:11 2020 +0200 Python: CG trace: handle class instantiation properly in points-to commit 7a71ca3e0fe546b51f2773d34acfa6e73f83d657 Author: Porcupiney Hairs Date: Fri Jul 24 00:57:19 2020 +0530 fix tests. commit 3ead2e3dc714ec0dfa0e7e9042a451d56df43175 Author: Rasmus Wriedt Larsen Date: Thu Jul 23 20:14:49 2020 +0200 Python: CG trace: Improve performance by only logging when needed Seems like a 2x performance overall wcwidth: - DEBUG=True 5.78 seconds - DEBUG=False 2.70 seconds youtube-dl - DEBUG=True 238.90 seconds - DEBUG=False 120.70 seconds commit c49311e69efbcd210d715eb16069fd796d7afe45 Author: Rasmus Wriedt Larsen Date: Thu Jul 23 20:11:27 2020 +0200 Python: Fix JinjaSSTISinks.expected commit fbd939133e6cd5796732c930056598a2199536e0 Author: Rasmus Wriedt Larsen Date: Thu Jul 23 18:07:55 2020 +0200 Python: CG trace: More caching Improves runtime of tracing youtube-dl from 296.19 seconds to 224.50 seconds. Better, but still not that amazing :| commit ce42221cf780326aec2f8d654aa2f8c104f31871 Author: Rasmus Wriedt Larsen Date: Thu Jul 23 17:57:52 2020 +0200 Python: CG trace: Fix some printing in helper.sh commit 55404ae980e2935ba1f06e84ea2dc1d435f275c5 Author: Rasmus Wriedt Larsen Date: Thu Jul 23 17:39:43 2020 +0200 Python: CG trace: Experiment with disabling some opcodes Currently not supported in the QL code, so no reason to pay performance to record them right now :P commit 14c51eb3c74ebdafba1c8f32180acde33dd96489 Author: Rasmus Wriedt Larsen Date: Thu Jul 23 17:38:54 2020 +0200 Python: CG trace: XML exporter will tell what file it wrote to commit c45cc2aa2f22e25fc0ee036864cb95e4ddf86d4d Author: Rasmus Wriedt Larsen Date: Thu Jul 23 17:37:01 2020 +0200 Python: CG trace: Add helper.sh to run tracing against real projects commit 5d031d7abe7d09a1a03c99ce54b57824ef5dd623 Author: Rasmus Wriedt Larsen Date: Thu Jul 23 15:06:27 2020 +0200 Python: CG trace: Fix sorting of ExternalCallee Also exposed that the better_compare_for_dataclass was exposed to bad loop variable capture :| commit 03d22fa8e33aaf90b160436a81ff7452b0c9a2ed Author: Rasmus Wriedt Larsen Date: Thu Jul 23 17:32:01 2020 +0200 Python: Fix filenames in qhelp commit e283d289fd7e883b410e8954c4173c28b6f8339d Author: Rasmus Wriedt Larsen Date: Thu Jul 23 17:23:26 2020 +0200 Python: Update TemplateInjection.qhelp Moved things around so there is only a single `` tag (and had to rewrite contents a bit). commit 1e7921e575af461c479ea3445c78a7c39117a87f Author: Porcupiney Hairs Date: Thu Jul 23 20:04:32 2020 +0530 add qhelp and fix tests. commit 8e85dc755a520434bf612583e3044c14d9958ea6 Author: porcupineyhairs <61983466+porcupineyhairs@users.noreply.github.com> Date: Thu Jul 23 19:37:40 2020 +0530 Apply suggestions from code review Co-authored-by: Rasmus Wriedt Larsen commit da518ed0d582c761bdb10de93dfb5d2933b46271 Author: Rasmus Wriedt Larsen Date: Thu Jul 23 13:40:43 2020 +0200 Python: CG trace: Remove Python 3.8 only f"{var=}" usage commit bb4b8dceaa295aa790bc642c4ecbd07ac6b88919 Author: Rasmus Wriedt Larsen Date: Thu Jul 23 13:38:58 2020 +0200 Python: CG trace: More robust logging setup commit bb5b161d72a135869b5ab48b53e94c7f74afe17e Merge: 40c998fa1 2326f3174 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Thu Jul 23 11:30:45 2020 +0100 Merge pull request #3972 from shati-patel/merge-rc Approved by mchammer01 commit 2326f31749f7de9d614b214f2adfc1c2e16ccad5 Merge: 40c998fa1 eaec2d722 Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Thu Jul 23 12:18:30 2020 +0200 Merge branch 'rc/1.24' into merge-rc commit a97f942a170de13fa4f7473c41079f0978aa8b13 Author: Rasmus Wriedt Larsen Date: Thu Jul 23 11:38:34 2020 +0200 Python: Autoformat commit 40c998fa131b0f49707133729c705f92b45ebf4e Merge: a4242bcb5 7840dfce3 Author: Felicity Chapman Date: Thu Jul 23 10:37:37 2020 +0100 Merge pull request #3969 from alexey-tereshenkov-oxb/master Python: Fix typo in qhelp file commit a4242bcb5df4ff73951a7049c26adcfbe3a50317 Merge: 2e5af6762 0bb6d0c7c Author: Mathias Vorreiter Pedersen Date: Thu Jul 23 09:21:37 2020 +0200 Merge pull request #3962 from rdmarsh2/ir-barrierguard-checks-expr C++: make IR BarrierGuard::checks match AST commit 7840dfce3b64f3f77e7b428c1b202434381b76f7 Author: Alexey Tereshenkov <59651540+alexey-tereshenkov-oxb@users.noreply.github.com> Date: Wed Jul 22 20:51:29 2020 +0100 Put the closing tag back commit e2939377e94f8a3e0e588d92d59c3acefa94458e Author: Alexey Tereshenkov <59651540+alexey-tereshenkov-oxb@users.noreply.github.com> Date: Wed Jul 22 20:07:34 2020 +0100 Update python/ql/src/Expressions/WrongNumberArgumentsForFormat.qhelp Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> commit a6eb3caa5fc3f03cdf52c14bf320c54385c0b932 Author: Alexey Tereshenkov <59651540+alexey-tereshenkov-oxb@users.noreply.github.com> Date: Wed Jul 22 20:07:27 2020 +0100 Update python/ql/src/Expressions/WrongNumberArgumentsForFormat.qhelp Co-authored-by: Felicity Chapman commit 91573855719a397f9487e1f69e9b0d53e37ba5ec Author: Rasmus Wriedt Larsen Date: Wed Jul 22 17:40:59 2020 +0200 Python: CG trace: XML can export list of dataclass commit a5f566b5631b77b485f0bca834e32697c86989d5 Author: Alexey Tereshenkov <59651540+alexey-tereshenkov-oxb@users.noreply.github.com> Date: Wed Jul 22 15:39:50 2020 +0100 Fix typo commit 3320061178e0e14a890dac6d72a2f280d93844d3 Author: Remco Vermeulen Date: Wed Jul 22 16:03:52 2020 +0200 Add and adjust QL docs for classes and predicates commit 2c42d3cca5d0556d47a87ff62a58537598cd2a40 Author: Remco Vermeulen Date: Wed Jul 22 14:52:08 2020 +0200 Extract additional taint steps This is done for logical cohesion. We already have the capability of extending additional taint steps by extending `TaintTracking::AdditionalTaintStep`. commit 57e7411c0a8d52607fce91419c366f658791b924 Author: Remco Vermeulen Date: Tue Jul 21 14:51:58 2020 +0200 Extract Ldap injection sanitizers to importable lib This includes a new abstract class that represents all the Ldap injection santizers and can be used to add additional santizers through extension. commit 0d5f9113a307371f5cdb14cea25fe631ebf884ba Author: Remco Vermeulen Date: Tue Jul 21 12:36:18 2020 +0000 Extract ldap injection sink into importable library commit 746c577d726c7a43cf2e75f998b2c873c37b81df Author: Rasmus Wriedt Larsen Date: Wed Jul 22 15:49:11 2020 +0200 Python: CG trace: Update naming and add QLDoc commit 67b45164eb86fa7ca9895506f86ca8814c7e0a71 Author: Rasmus Wriedt Larsen Date: Wed Jul 22 15:19:57 2020 +0200 Python: CG trace: Partial matching of BytecodeExpr and AST not safe commit 1e89388f2bfcf333743b33365b63e3d91175f448 Author: Rasmus Wriedt Larsen Date: Wed Jul 22 14:22:04 2020 +0200 Python: CG trace: Don't abuse example dir commit ad2e336eadf6c5e68e88b0319984763364c3ec7a Author: Rasmus Wriedt Larsen Date: Wed Jul 22 13:52:41 2020 +0200 Python: CG trace: Autoformat commit ccffa7d99d442e77a91580c910292d6406dc7011 Author: Rasmus Wriedt Larsen Date: Wed Jul 22 13:12:52 2020 +0200 Python: CG trace: Ignore some calls for call-grahp metrics and provide some internal metrics as well commit b227a7ec90811480825a8d00da5951984bbdec61 Author: Rasmus Wriedt Larsen Date: Wed Jul 22 00:46:24 2020 +0200 Python: CG trace: Add overall metrics query commit 278ab4b8837d8cd94fda7a17f909137431e81d81 Author: Rasmus Wriedt Larsen Date: Wed Jul 22 00:44:27 2020 +0200 Python: CG trace: Much improved toString for QL commit a5838b66ed2a072aaf37b638f9cc9542965f6c4e Author: Rasmus Wriedt Larsen Date: Wed Jul 22 00:00:17 2020 +0200 Python: CG trace: Small improvements to QL code commit b86ca19264bb1386809f4d51ceef48630d749d96 Author: Rasmus Wriedt Larsen Date: Tue Jul 21 23:37:33 2020 +0200 Python: CG trace: Apply better_compare_for_dataclass to all commit 9bff615fadc64ac24389a1203d3a6ab959db93e7 Author: Rasmus Wriedt Larsen Date: Tue Jul 21 23:08:33 2020 +0200 Python: CG trace: Handle BUILD_LIST commit 8c8656ccca2c2450ce04dfcf570c50291c1357a7 Author: Rasmus Wriedt Larsen Date: Tue Jul 21 23:05:49 2020 +0200 Python: CG trace: Handle BUILD_TUPLE commit 0d05d96b504a9d60f735fb5771493990018594b1 Author: Rasmus Wriedt Larsen Date: Tue Jul 21 22:54:45 2020 +0200 Python: CG trace: Handle CALL_FUNCTION_EX commit 3539798c226cdde948dfa224aae4029007d5a32e Author: Rasmus Wriedt Larsen Date: Tue Jul 21 22:47:15 2020 +0200 Python: CG trace: ignore with statement for now commit 4843d29ad610b4edf1b24215c65183b8922c0647 Author: Rasmus Wriedt Larsen Date: Tue Jul 21 22:32:26 2020 +0200 Python: CG trace: Cache calls seen This improved runtime from ~10 seconds to 1 seconds when running one of the tests fo wcwidth commit ebbea0cd617b3f731c819b5b0b4d84cbf13b30c2 Author: Rasmus Wriedt Larsen Date: Tue Jul 21 22:17:17 2020 +0200 Python: CG trace: Ignore IMPORT_NAME commit 6830804112980da54c44642debc3796f829f0359 Author: Rasmus Wriedt Larsen Date: Tue Jul 21 22:08:15 2020 +0200 Python: CG trace: More logging commit 3752a256654b5406c62913d20811287743a4edc6 Author: Rasmus Wriedt Larsen Date: Tue Jul 21 22:02:25 2020 +0200 Python: CG trace: Handle LOAD_DEREF commit 61b1d3eef3b05a5128e3b502a68d15891fe5f53f Author: Rasmus Wriedt Larsen Date: Tue Jul 21 21:45:53 2020 +0200 Python: CG trace: Handle subscript commit 79c2c682d7d5da1525c32a9ea4eb41ef35ce2c54 Author: Rasmus Wriedt Larsen Date: Tue Jul 21 21:34:20 2020 +0200 Python: CG trace: Nicer logging commit 0a7e6a99385c8407dbf20cb033635075f6b34117 Author: Rasmus Wriedt Larsen Date: Tue Jul 21 19:58:59 2020 +0200 Python: CG trace: Avoid handling jumps for now commit 4e3ae98ddf31f89f2b275a0304e6504063b1ad15 Author: Rasmus Wriedt Larsen Date: Tue Jul 21 19:54:59 2020 +0200 Python: CG trace: Handle list-comprehension and iteration Which relies on LOAD_CONST and MAKE_FUNCTION commit 58f11194a89ffb17b512b74b8341938a19c6f3f4 Author: Rasmus Wriedt Larsen Date: Tue Jul 21 19:53:05 2020 +0200 Python: CG trace: Refactoring commit 290eb638f9715a5be25326f94cc309ca4f492915 Author: Rasmus Wriedt Larsen Date: Tue Jul 21 19:40:58 2020 +0200 Python: CG trace: Handle SystemExit otherwise, with-exit would end the tracer without producing any output :| commit 296d7d172579a14cc542c2ab96428b2ee75ea61b Author: Rasmus Wriedt Larsen Date: Tue Jul 21 19:39:51 2020 +0200 Python: CG trace: Allow tracing modules As would normally be invoked by `python -m ` now works with `cg-trace --module `. This is useful for tracing invocations of `pytest`. commit 91e62226629a62179de978924c75fc929dc30521 Author: Rasmus Wriedt Larsen Date: Tue Jul 21 11:41:16 2020 +0200 Python: Fix SSTI query by importing UntrustedStringKind Without a concrete ExternalStringKind class, there will be no flow for ExternalStringKind by default. commit 9dbd280d3163bafc4cc4c9cb27076544e34579a0 Author: Rasmus Wriedt Larsen Date: Tue Jul 21 11:40:01 2020 +0200 Python: Fix syntax error commit 49df4169cf448a84178e4c7cf403f13092b1148c Author: Porcupiney Hairs Date: Mon May 4 01:56:37 2020 +0530 Python : Add query to detect Server Side Template Injection commit 89e8202d1182ffdbce99428cff74859919ac96f2 Author: Rasmus Wriedt Larsen Date: Tue Jul 21 11:15:07 2020 +0200 Python: CG trace: Add some tests using classes commit eeeadad3591b35658e3c43325d63afd88ea0998b Author: Rasmus Wriedt Larsen Date: Tue Jul 21 11:14:07 2020 +0200 Python: CG trace: Don't commit examples traces all the time commit 38af1930fe2ba4fcb7d03e3f55d3a82807ff8065 Author: Rasmus Wriedt Larsen Date: Tue Jul 21 10:19:47 2020 +0200 Python: CG trace: Rename ValidRecordedCall to IdentifiedRecordedCall commit 55473c65f1e7ab3047a460a0ee45a80b887dcc5f Author: Raul Garcia (MSFT) Date: Mon Jul 20 13:54:23 2020 -0700 Improving documentation commit 9d7d6b39cb0b4b9323e4536fe682f980d8769d76 Author: Raul Garcia (MSFT) Date: Mon Jul 20 11:14:59 2020 -0700 Small fixes based on feedback commit c2733ad22e04d6af507a99e86f232d33f754fa25 Author: Remco Vermeulen Date: Mon Jul 20 14:55:00 2020 +0200 Apply grammar suggestions Co-authored-by: Anders Schack-Mulligen commit bbfea44db0247c6e07219bdecca543244ae36fc6 Author: Rasmus Wriedt Larsen Date: Mon Jul 20 14:54:05 2020 +0200 Python: CG trace: Handle multiple calls to same func on same line Such as ``` one(); one() ``` Now there are no InvalidRecordedCall in the current examples. commit cb98f4433da986be018ea7691f6a850444d5f981 Author: Rasmus Wriedt Larsen Date: Mon Jul 20 14:07:09 2020 +0200 Python: CG trace: Handle multiple calls on one line Reduced number of InvalidRecordedCall from 16 to 2. This is the calls ``` one(); one() ``` since they are not distinguishable from the expression. commit a1c1ab080b30f073d32f8aed876908f887c06f0b Author: Rasmus Wriedt Larsen Date: Mon Jul 20 14:03:37 2020 +0200 Python: CG trace: Add examples of multiple calls on one line There are currently 16 InvalidRecordedCall commit 49a90c058d0d13b6e87b8a160fd175b345490e88 Author: Rasmus Wriedt Larsen Date: Mon Jul 20 13:00:35 2020 +0200 Python: CG trace: minor adjustment to recreate-dh.sh commit 5ef817012aad4efc50db0c99e9c42231db2868de Author: Rasmus Wriedt Larsen Date: Mon Jul 20 13:00:07 2020 +0200 Python: CG trace: restructure QL for new XML format commit c2748bf7cfbd599a7dd4e3bd0eea04cc6840c2be Author: Rasmus Wriedt Larsen Date: Mon Jul 20 11:28:05 2020 +0200 Python: CG trace: reconstruct call expr from bytecode So we can differentiate multiple calls in one line. commit d46b41011117aaa720717b9d9cb0abf48051ac8a Author: Rasmus Wriedt Larsen Date: Mon Jul 20 01:22:33 2020 +0200 Python: CG trace: Proper exception handling commit f94055fa2c66afa2a06cc80a2ef4be5a9eedf540 Author: intrigus Date: Sun Jul 19 00:19:29 2020 +0200 Move tainted path ad-hoc guard back. commit 33526f61a8bdcdc1d82cc5908b68e5799b14238c Author: intrigus Date: Sun Jul 19 00:11:04 2020 +0200 Make path creation subclasses private. commit b705f7f3e9fe42db043afd2c56ec2814d2cfae19 Author: intrigus Date: Sun Jul 19 00:10:39 2020 +0200 Improve "PathCreation" Test. commit 4570444c7ed019b7e95a28c39f42c0a9d8eb17e9 Author: intrigus Date: Sat Jul 18 23:57:01 2020 +0200 Rename to getAnInput and clarify doc. commit 10ec1e078aef4e94d453c07e90e7f7635749bef1 Author: Rasmus Wriedt Larsen Date: Sat Jul 18 17:56:56 2020 +0200 Python: CG trace: Better type hints commit 8b6de17461df868e624dc096f9d0794f5c46b160 Author: Rasmus Wriedt Larsen Date: Sat Jul 18 17:55:51 2020 +0200 Python: CG trace: Use logging module for debuging commit acc5f70d4abfbfde76a636a4c75fc172be25951e Author: Rasmus Wriedt Larsen Date: Sat Jul 18 17:10:53 2020 +0200 Python: CG trace: Python 3.7 is minimal version commit 0bb6d0c7cac607bea6d6d7ba7517a3d25dfc2dd5 Author: Robert Marsh Date: Tue Jul 14 15:44:03 2020 -0700 C++: make IR BarrierGuard::checks match AST commit cec3694c893f263622ec92fe259184a7a85266f4 Author: Taus Brock-Nannestad Date: Fri Jul 17 16:36:56 2020 +0200 Python: Add type tracker and step summary implementation. commit 79f412ff54f294c21d3041cc24f4703fa3d65295 Author: Calum Grant Date: Fri Jul 17 15:30:33 2020 +0100 C#: Fix tags typo commit 6c60881cbec17a901386f669f9adc7019ff81741 Author: Rasmus Wriedt Larsen Date: Fri Jul 17 14:41:49 2020 +0200 Python: CG trace: Move code to src/ As recommended in https://blog.ionelmc.ro/2014/05/25/python-packaging/ and following pattern of black and pytest commit 0a0c24f3c5ec51c71e10492404c1ef874c6cce56 Author: Rasmus Wriedt Larsen Date: Fri Jul 17 14:30:12 2020 +0200 Python: CG trace: Make code modular commit 94a03d73a35a830c56edd15eeeaa9868eb3636d3 Author: Rasmus Wriedt Larsen Date: Fri Jul 17 13:39:57 2020 +0200 Python: CG trace: blackify And make code pass flake8 tests commit 5387294168bac38d2cb86f4f09bfb5d566ee7bc0 Author: Raul Garcia (MSFT) Date: Thu Jul 16 09:32:17 2020 -0700 Moving to experimental as requested commit 1c2e259970599785c988f90eacaba2e190f181de Author: Rasmus Wriedt Larsen Date: Thu Jul 16 18:04:04 2020 +0200 Python: CG trace: Handle builtins commit 92e8e1622ccc372cd1e199835712721a25ab5717 Author: Rasmus Wriedt Larsen Date: Thu Jul 16 16:47:23 2020 +0200 Python: CG trace: move traces to own dir commit 2e5af67626d33366f8413706a41a3cc0597f46d8 Merge: c7b668193 289a908eb Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Jul 15 18:11:09 2020 +0100 Merge pull request #3952 from MathiasVP/output-parameter-index-for-UserDefinedFormattingFunction C++: Add getOutputParameterIndex override to UserDefinedFormattingFunction class. commit c7b668193be28f81134b3e038a27e337b39d11ea Merge: 7dd267774 616bad7b5 Author: Nick Rolfe Date: Wed Jul 15 18:03:26 2020 +0100 Merge pull request #3929 from igfoo/static_assert C++: Give static assertions an enclosing element commit 289a908eb8906aae7ba25d4bc0bbbd744474bc98 Author: Mathias Vorreiter Pedersen Date: Wed Jul 15 16:24:47 2020 +0200 C++: Update qldoc in reponse to PR comments commit c4b97a3a626e821ef1a71fc14d842685ba71c152 Author: Mathias Vorreiter Pedersen Date: Wed Jul 15 16:19:51 2020 +0200 C++: Accept more test changes commit c4940aaa8648c2737ee68b34cfa0e464b040060b Merge: 37158f46e 7dd267774 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Jul 15 15:01:01 2020 +0100 Merge branch 'master' into copymove commit abcc76baec9355dd07e856d9479cb919105e5c8b Author: Rasmus Wriedt Larsen Date: Wed Jul 15 14:48:58 2020 +0200 Python: CG trace: use lxml to pretty-print xml commit edc33b651603238a55d1cd97914586b428c2da59 Author: Mathias Vorreiter Pedersen Date: Wed Jul 15 14:45:17 2020 +0200 C++: Add getOutputParameterIndex override to UserDefinedFormattingFunction and accept test changes commit d711c22cd2d38f323b1a951434e7739cf53786f8 Author: Mathias Vorreiter Pedersen Date: Wed Jul 15 14:42:45 2020 +0200 C++: Add testcase demonstrating lost query results commit 7ac4ea9bf1c20ae92ef160e31ff19a1d3cf24036 Author: Rasmus Wriedt Larsen Date: Wed Jul 15 14:41:39 2020 +0200 Python: CG trace: use standardized etree import makes it easy to switch out XML library. commit ba4207fc909b6369e87cef13db93a752927f493c Author: Rasmus Wriedt Larsen Date: Wed Jul 15 14:37:41 2020 +0200 Python: CG trace: sort output before writing/printing Allows comparing output of one run with another commit e6873956caa52509b5ca6f78f36287d6222b6024 Author: Rasmus Wriedt Larsen Date: Wed Jul 15 14:25:42 2020 +0200 Python: CG trace: add canonic_filename helper commit 3e0481b889aadf4a9e25dbecf90abb7f71e9523d Author: Raul Garcia (MSFT) Date: Tue Jul 14 17:54:54 2020 -0700 Queries to help on the detection based on misuse of DataSet and DataTable serialization that could lead to security problems. https://go.microsoft.com/fwlink/?linkid=2132227 commit 7dd26777460894c20807f6f0a86310b227518c1f Merge: dcff87fb2 174b30461 Author: Robert Marsh Date: Tue Jul 14 14:18:06 2020 -0700 Merge pull request #3950 from MathiasVP/simple-range-analysis-unsigned-multiplication-tests C++: Add test cases for range analysis for unsigned multiplication commit 896cdf9b127d9b4e9b3f9648b5dcbc0cde92aec2 Merge: f051f46ee dcff87fb2 Author: Raul Garcia (MSFT) Date: Tue Jul 14 11:16:51 2020 -0700 Merge branch 'master' of https://github.com/github/codeql commit 174b30461ad1aae501d5e8ae5bd6a4d96a5206a8 Author: Mathias Vorreiter Pedersen Date: Tue Jul 14 19:47:21 2020 +0200 C++: Fix syntax error in testfile commit dcff87fb2ea3cca0de5394d293783ed0d2c64a1d Merge: 0bee0687c 9e3a6e8d5 Author: Calum Grant <42069085+calumgrant@users.noreply.github.com> Date: Tue Jul 14 17:12:29 2020 +0100 Merge pull request #3366 from hvitved/csharp/dataflow/arrays C#: Precise data-flow for collections commit 834ad924537b5c18a723e62be608796816886432 Author: Mathias Vorreiter Pedersen Date: Tue Jul 14 16:57:47 2020 +0200 C++: Add test cases for unsigned multiplication and fix missing return value in existing tests commit 37158f46ed71d38eaa00c686f425dc6b6eddc2e5 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jul 14 15:36:43 2020 +0100 C++: Remove deprecated class from test. commit 0bee0687cbd1ba185949a3b79221064a962e1bf2 Merge: f8c03dcae f1601d643 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Tue Jul 14 15:33:45 2020 +0100 Merge pull request #3911 from RasmusWL/python-call-graph-tracing Approved by tausbn commit 3f6d8490e059278a112455138d860578b70ae4e1 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jul 14 15:09:12 2020 +0100 C++: Autoformat. commit 616bad7b5ce0c09483e236b0e96fa995fc9d09b7 Author: Ian Lynagh Date: Tue Jul 14 13:53:46 2020 +0100 C++: Add an upgrade script commit c254de464a05f5ace5271ac61cf924d6df601b99 Author: Ian Lynagh Date: Tue Jul 14 12:25:35 2020 +0100 C++: Update stats following `static_asserts` change commit f1601d643aa46158725dd59dbb3af368170b9977 Author: Rasmus Wriedt Larsen Date: Tue Jul 14 14:12:56 2020 +0200 Python: autoformat commit 1d9c3b3bcdbdaca6c26ddfad204df7fdf0186e09 Author: Rasmus Wriedt Larsen Date: Tue Jul 14 14:12:02 2020 +0200 Python: call-graph tracing: callable => callee to use consistent naming commit f8c03dcae6b5bcc869ac5ce0bd98da4b576e63c3 Merge: ee13e87f3 ee42d0839 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Tue Jul 14 13:03:02 2020 +0100 Merge pull request #3924 from RasmusWL/python-metrics-queries-for-dist-compare Approved by tausbn commit ee42d0839e6a366cfe449f42eebb1023098e2222 Author: Rasmus Wriedt Larsen Date: Tue Jul 14 11:26:05 2020 +0200 Python: Rename target => callee To use a standardised naming :) commit d913d332892d3b381c15563a01c662338376e106 Author: Rasmus Wriedt Larsen Date: Tue Jul 14 11:21:55 2020 +0200 Python: Autoformat commit ee13e87f3bc5ed0240c4faa86945ec6920020d17 Merge: 67b601807 dc7d92ba2 Author: Taus Date: Mon Jul 13 22:10:34 2020 +0200 Merge pull request #3947 from RasmusWL/python-fix-tests Python: Make experimental/library-tests/CallGraph pass for Python 2 commit 67b6018079bf9f13a9513d1fa1ab2eee4a96039d Merge: 651962947 12803f1f5 Author: Arthur Baars Date: Mon Jul 13 18:04:42 2020 +0200 Merge pull request #3729 from luchua-bc/java-hardcoded-aws-credentials Java: Hardcoded AWS credentials commit dc7d92ba2f6932789284e4346f159fb406de8434 Author: Rasmus Wriedt Larsen Date: Mon Jul 13 16:20:02 2020 +0200 Python: Autoformat experimental/library-tests/CallGraph/ commit 646efe2a20ecc6e2ab7cc39fa6199c409973a615 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Jul 13 14:55:52 2020 +0100 C++: Deprecate ConversionConstructor. commit c585b2e4835bd6c49f7393c744c97d3215f75841 Author: Arthur Baars Date: Mon Jul 13 15:25:00 2020 +0200 Java: stack trace exposure: address false positives commit 61178c533088b5d5b3420f5d84ec1e7143d28818 Merge: 301679810 fe0c5a9ea Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Jul 13 14:11:12 2020 +0100 Merge branch 'master' into copymove commit 83bd14b68705cc47c908b9f0026755dc76edd17d Author: Rasmus Wriedt Larsen Date: Mon Jul 13 14:52:28 2020 +0200 Python: Make experimental/library-tests/CallGraph pass for Python 2 The import doesn't actually work the intended way, so running ``` $ python python/ql/test/experimental/library-tests/CallGraph/test.py ``` will procude no output. but our extractor will extract the things we need, so for a quick fix this will need to suffice. commit 12803f1f5376b17c487081a49097cc17c01b51c3 Author: luchua-bc Date: Mon Jul 13 12:22:34 2020 +0000 Merge Hardcoded AWS Credentials check into the mail source folder commit b1e604b490e6b907baa2ec7489c9c8714592cb82 Author: Arthur Baars Date: Mon Jul 13 11:36:34 2020 +0200 Java: treat Stack.push as data flow instead of taint flow commit a484aff76dca5fb9158fbd0a7eae73a1db35afbd Author: Arthur Baars Date: Mon Jul 13 11:09:05 2020 +0200 Java: improve comments commit 6519629472bfe7922dedfa788b40244231ff13e2 Merge: 912c50a88 d6da31864 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Jul 13 10:00:50 2020 +0100 Merge pull request #3942 from MathiasVP/remove-abstract-preprocessor C++: Remove abstract classes from Preprocessor.qll commit 3127bb27d0a75c0fa3c695a5d40d3a0fd5c321ad Author: Rasmus Wriedt Larsen Date: Mon Jul 13 10:54:47 2020 +0200 Python: Remove strange empty line commit 0b6c3ff99d8909f1c37d2eb5f1375772f03c3e3f Author: Rasmus Wriedt Larsen Date: Mon Jul 13 10:46:03 2020 +0200 Python: Don't use PointsTo module name in metrics query To avoid confusion with the normal PointsTo module in python/ql/src/semmle/python/pointsto/PointsTo.qll commit a7d23063ded9718720ee421230359fbc6ca52265 Author: Rasmus Wriedt Larsen Date: Mon Jul 13 10:44:19 2020 +0200 Python: Fix grammar Co-authored-by: Taus commit 48e540fa9a15a0966b44e857b538d8f4d9e050cc Author: dilanbhalla Date: Mon Jul 13 01:25:42 2020 -0700 minor fixes commit db6d5c329f88d8e38a3498e9b56838f1c03291af Author: dilanbhalla Date: Mon Jul 13 00:57:05 2020 -0700 file/buffer write dataflow queries complete commit d6da3186453fa3d8ac24a0806283aebd81791b57 Author: Mathias Vorreiter Pedersen Date: Fri Jul 10 21:55:14 2020 +0200 C++: Remove abstract classes from Preprocessor.qll commit 1f6615b3b855bf008c240f434278253964017126 Merge: fa8b27833 912c50a88 Author: Jonathan Leitschuh Date: Fri Jul 10 14:36:56 2020 -0400 Merge branch 'master' into feat/JLL/jOOQ_SQL_injection * master: (485 commits) C++: Remove @stmt_while from the TConditionalStmt union type. C++: Remove abstract classes from Stmt.qll Drop Map.merge as taint step Add the printAst.ql contextual query for C++ Fix modelling of Stack.push C#: Sync identical files C++: Replace getResultType() with getResultIRType() in IR dataflow C++: Replace getResultType() with getResultIRType() in IR range analysis C++: Introduce isSigned() and isUnsigned() predicates on IRIntegerType to mirror IntegralType Add missing java import Add missing java import Mark ServletUrlRedirectSink private Java: model Object.clone Add file-level qldoc Optimize imports Join ServletUrlRedirectSink with UrlRedirectSink Extend UrlRedirectSink from DataFlow::Node Remove superfluous imports Java: ContainerFlow add comments Generalize QueryInjectionSink ... commit 912c50a881a1d57bd0cafaece4ef5bc7c75a5f7b Merge: 456a05ecd 002f930db Author: Dave Bartolomeo Date: Fri Jul 10 13:37:30 2020 -0400 Merge pull request #3937 from MathiasVP/replace-result-type-with-ir-result-type C++: Replace getResultType() with getResultIRType() commit 456a05ecd5ab75a34c17dcea2bc9eba215b2fef1 Merge: df3eb9f9c 7cc83da97 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Jul 10 16:41:45 2020 +0100 Merge pull request #3940 from MathiasVP/remove-abstract-stmt C++: Remove abstract classes and predicates from Stmt.qll commit 7cc83da97ab7ada045a91f4f7fb25bcdae840183 Author: Mathias Vorreiter Pedersen Date: Fri Jul 10 15:51:34 2020 +0200 C++: Remove @stmt_while from the TConditionalStmt union type. commit df3eb9f9c54335b7d0991ff05451692593982442 Merge: 2941f413f d00e7396c Author: Taus Date: Fri Jul 10 15:38:38 2020 +0200 Merge pull request #3790 from RasmusWL/python-add-annotated-callgraph-tests Python: Add annotated call-graph tests commit 2941f413f9711a8488911cc4e8b06e75e80e60bf Merge: a1d272e87 782759d58 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Jul 10 14:08:25 2020 +0100 Merge pull request #3931 from aeisenberg/aeisenberg/cpp-print-ast Add the printAst.ql contextual query for C++ commit bf7e3a004e4bef63604fd8b23ec276f3309a78f5 Author: Philippe Antoine Date: Fri Jul 10 14:58:00 2020 +0200 Reverting to enclosing block logic commit 50b2b12ce288289369b511a6ec8aa01c0fee25bb Author: Philippe Antoine Date: Fri Jul 10 14:40:58 2020 +0200 put back missing condition commit 3117c67a66e5a535cc6781948b7d1e9b9307bc9a Author: Philippe Antoine Date: Fri Jul 10 14:24:24 2020 +0200 Updates result message to be more precise commit 567984af3d230e333b2038215a7558096c2930d4 Author: Mathias Vorreiter Pedersen Date: Fri Jul 10 14:21:56 2020 +0200 C++: Remove abstract classes from Stmt.qll commit a1d272e8708be38d1ed554bb6e4465da852593af Merge: 05685cc89 43b61038e Author: Anders Schack-Mulligen Date: Fri Jul 10 14:19:44 2020 +0200 Merge pull request #3918 from aibaars/organise-container-flow Java: Clean up ContainerFlow, consider more methods commit 43b61038e9c781132d3e7d69b192e2b44e618250 Author: Arthur Baars Date: Fri Jul 10 13:00:14 2020 +0200 Drop Map.merge as taint step commit 2e9c0fc6a5667cf055c1127ef6178b4e4cccace2 Author: Mathias Vorreiter Pedersen Date: Fri Jul 10 11:10:41 2020 +0200 C++: Cache the TIRDataFlowNode newtype commit 05685cc896e54cc32f4e80b0cfa723491011a29b Merge: 879551fc6 6f7a8d029 Author: Robert Marsh Date: Thu Jul 9 15:02:52 2020 -0700 Merge pull request #3919 from dbartol/dbartol/IgnoreAutoBuilder C++: Add `.gitignore` for autobuilder commit c739c733feeb66491271a4ce8b08829272b3aa9e Author: Remco Vermeulen Date: Thu Jul 9 17:31:37 2020 +0200 Update class qldocs Change the ql docs to meet the style-guide points 1 and 3 for classes. commit 782759d58ed12e5af5a2e45e009b49f38cb27436 Author: Andrew Eisenberg Date: Wed Jul 8 13:55:18 2020 -0700 Add the printAst.ql contextual query for C++ This query will be used by the VS Code extension for viewing ASTs of C/C++ files. commit 0d33a77ee38d94aea322954c7d9b306452401ea5 Author: Arthur Baars Date: Thu Jul 9 15:00:59 2020 +0200 Fix modelling of Stack.push Stack.push(E) returns its argument, it does not propagate taint from the stack to the return value. commit 50f2f69f5f182f799991beff54654adc89c03a86 Author: Philippe Antoine Date: Thu Jul 9 16:14:26 2020 +0200 indent comments commit b3bb4cbf541c83eaec474a4599e9fe7a0b406508 Author: Remco Vermeulen Date: Thu Jul 9 16:14:21 2020 +0200 Rename and update qldoc of default safe header splitting source commit 06c8a0bf2067cd37778de09beb9de470a2802b21 Author: Philippe Antoine Date: Thu Jul 9 16:09:57 2020 +0200 move to experimental commit 879551fc6aff14fcba2126b57ba45a383a08cf96 Merge: c8b9b779a e183171fe Author: Anders Schack-Mulligen Date: Thu Jul 9 16:09:01 2020 +0200 Merge pull request #3936 from aibaars/object-clone Java: model Object.clone commit d2763e8149e11cf11eb0d37a0597243995244fbb Author: Philippe Antoine Date: Thu Jul 9 16:05:24 2020 +0200 Comments taken into account commit c8b9b779ae1295521a125f3164acfbcc5be2784e Merge: 99a4f8fd0 d3db4fa5b Author: Anders Schack-Mulligen Date: Thu Jul 9 16:03:29 2020 +0200 Merge pull request #3927 from rvermeulen/java-importable-cwe-601 Java: Move `UrlRedirectSink` into importable library commit 99a4f8fd0bc568471bca9d0f8019d62fa3bc2731 Merge: 2fa54552f 7428a8cd9 Author: Anders Schack-Mulligen Date: Thu Jul 9 16:00:56 2020 +0200 Merge pull request #3926 from rvermeulen/java-importable-cwe-089 Java: Move `QueryInjectionSink` into importable library commit 002f930dbafdbec07b9e5051f9787d360768bf51 Author: Mathias Vorreiter Pedersen Date: Thu Jul 9 15:54:42 2020 +0200 C#: Sync identical files commit 2fa54552f06ada6dceb913fd2390a6216d8b0202 Merge: 277185a79 0caa17ab1 Author: Jonas Jensen Date: Thu Jul 9 15:54:40 2020 +0200 Merge pull request #3914 from geoffw0/cc_followup C++: Repair swap taint tests commit 85a8280b306547578cd886a3f5c273560d0f1b85 Author: Mathias Vorreiter Pedersen Date: Thu Jul 9 15:54:15 2020 +0200 C++: Replace getResultType() with getResultIRType() in IR dataflow commit 70297396918a510bbea0a88d6c713c025366ec70 Author: Mathias Vorreiter Pedersen Date: Thu Jul 9 15:53:54 2020 +0200 C++: Replace getResultType() with getResultIRType() in IR range analysis commit a405a95b687d48264a4a28b70216092b0a6f8f6c Author: Mathias Vorreiter Pedersen Date: Thu Jul 9 15:52:09 2020 +0200 C++: Introduce isSigned() and isUnsigned() predicates on IRIntegerType to mirror IntegralType commit 277185a79282517b3408d3789cfa9ce258530c5f Merge: e167b8715 61dfebceb Author: Jonas Jensen Date: Thu Jul 9 15:45:58 2020 +0200 Merge pull request #3925 from geoffw0/rangefixup C++: Add getFullyConverted() where missing in SimpleRangeAnalysis commit b147be6fea8a9709b057431c7c277ae5328ee2dc Author: Remco Vermeulen Date: Thu Jul 9 15:13:18 2020 +0200 Restrict SafeHeaderSplittingSource to RemoteFlowSource commit 7428a8cd95918e9f01e125dde261240321e0432f Author: Remco Vermeulen Date: Thu Jul 9 15:06:26 2020 +0200 Add missing java import commit d3db4fa5b2c6cf7f6ddc25968838937ab58266e7 Author: Remco Vermeulen Date: Thu Jul 9 15:04:16 2020 +0200 Add missing java import commit 54d6c8b5f43e14c6d2c8b43df37a7df83d1e8c6c Author: Remco Vermeulen Date: Thu Jul 9 15:03:51 2020 +0200 Mark ServletUrlRedirectSink private commit 782573ed43bec819cbb9fced03015e7193ed6960 Author: Remco Vermeulen Date: Thu Jul 9 14:58:53 2020 +0200 Add and format qldocs according to the style guide. commit 4ad6357cd7f01bd8220a6331cff449f7aab30f8e Author: Remco Vermeulen Date: Thu Jul 9 14:54:46 2020 +0200 Add missing Java import commit 7435dac3d20ef0a69696621825a61fc9939874b9 Author: Remco Vermeulen Date: Thu Jul 9 14:53:59 2020 +0200 Move source and sink into importable library commit e183171feaf31e5a09f715167f68834934e36bc4 Author: Arthur Baars Date: Thu Jul 9 14:50:29 2020 +0200 Java: model Object.clone commit 641c5df79fa85dfb96354c9a9ac5b3f585312e3d Author: intrigus Date: Fri Jul 3 00:25:27 2020 +0200 Centralize and model additional path creations. commit b66f391c31b9b0a0f1b35e962508a718c2e82903 Author: Remco Vermeulen Date: Thu Jul 9 14:39:08 2020 +0200 Extend source and sink from DataFlow::Node instead of DataFlow::exprNode commit fed506a12ff2d3f02933880bb5ae26b758da9d51 Author: Remco Vermeulen Date: Thu Jul 9 14:36:23 2020 +0200 Rename TrustedSource to SafeHeaderSplittingSource commit 3d711b8cd1f47ad8efaf55d05e318bf6384ed499 Author: Henry Mercer Date: Thu Jul 9 13:15:22 2020 +0100 C#: Fix broken link to ECMA-335 commit 1212feab28aab9876f28271ce8ddf05ef51c6274 Author: Remco Vermeulen Date: Thu Jul 9 14:11:59 2020 +0200 Add file-level qldoc commit 99228d8bc2231a745539623ce72e36227f206e77 Author: Remco Vermeulen Date: Thu Jul 9 14:09:39 2020 +0200 Optimize imports commit ba9f3e2a1ed79a91e0e97ed0e29bffe43028d22d Author: Remco Vermeulen Date: Thu Jul 9 14:08:43 2020 +0200 Join ServletUrlRedirectSink with UrlRedirectSink commit 88f4b224c3523a3cb76300dbf1258313578ff15e Author: Remco Vermeulen Date: Thu Jul 9 14:05:54 2020 +0200 Extend UrlRedirectSink from DataFlow::Node commit f8078f1125e33e33ec6bd7daba5220f5c01542b0 Author: Remco Vermeulen Date: Thu Jul 9 13:43:10 2020 +0200 Remove superfluous imports commit d3d58795f1c99fb4da9ffa484a0312b57c1b8d4f Author: Arthur Baars Date: Thu Jul 9 12:40:34 2020 +0200 Java: ContainerFlow add comments Some method variants are captured by a super class. Added some comments to indicate where this happens to make review of missing methods easier in the future. commit e167b871502966059cd45b6e3258bfa70062d2c9 Merge: 777dc6305 7a1410e0d Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Thu Jul 9 11:43:45 2020 +0100 Merge pull request #3932 from max-schaefer/portals-additions Approved by esbena commit 9a84abf2590a1bca4e5e04065759be40b4c62e9d Author: Remco Vermeulen Date: Thu Jul 9 12:32:17 2020 +0200 Generalize QueryInjectionSink Extends from the more general DataFlow::Node instead of DataFlow::ExprNode commit 24c6e506aa29e36aeff21aa203256caae328bc1b Author: Arthur Baars Date: Thu Jul 9 12:16:18 2020 +0200 Java: ContainerFlow: RValue -> Expr While most flow for a qualifierToArgumentStep goes through a variable use this is not always the case. Therefore it is best to remove the restriction to RValue to allow taint steps to use postupdate nodes. See also: ba86dea657e227f9aac0371cda62e47bdef565d3 commit 0bd103ac05d409d733dfc15718e730462680234f Author: Arthur Baars Date: Wed Jul 8 22:09:17 2020 +0200 Java: add tests for Container taint steps commit 834263f72a217a09eb30d6ee642be29ee18ef925 Author: Mathias Vorreiter Pedersen Date: Thu Jul 9 11:36:54 2020 +0200 C++: Alternate instruction -> operand flow commit 5eff8d3165651cbe63b1bff5ea5ec665cc8cb32f Author: Philippe Antoine Date: Thu Jul 9 11:31:47 2020 +0200 Performance improvements suggested commit e7c89dc24ba38b18ac73c3b0307b65ebf4346140 Author: Rasmus Wriedt Larsen Date: Thu Jul 9 10:39:58 2020 +0200 Python: Fix grammar Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> commit c01844a39e08c4ca229795bbd8091d924a79a890 Author: Remco Vermeulen Date: Thu Jul 9 10:30:31 2020 +0200 Add file-level qldoc commit 7a1410e0d55eae758549ab030e49bf546d11764a Author: Max Schaefer Date: Thu Jul 9 09:22:31 2020 +0100 JavaScript: Update and expand tests. commit 42e261ac02db8440f7788943106a6b12f92b55fd Author: Remco Vermeulen Date: Thu Jul 9 10:21:24 2020 +0200 Move SqlInjectionSink and PersistenceQueryInjectionSink Join SqlInjectionSink and PersistenceQueryInjectionSink with QueryInjectionSink to make its definition more transparent. commit d07d21c9e277d82132a63ef8d2a953eefd7d8fa1 Author: Remco Vermeulen Date: Thu Jul 9 10:20:53 2020 +0200 Fix import commit 777dc6305cacb122bb5d4a94febe1764f1eb834b Merge: 0e66d0892 e8f216c76 Author: Anders Schack-Mulligen Date: Thu Jul 9 10:18:12 2020 +0200 Merge pull request #3893 from aibaars/set-map-list-copy-of Java: model some new Set,List,Map methods commit 1c47260bdef142977b94bdce074107a0e319d03c Author: Max Schaefer Date: Thu Jul 9 09:12:56 2020 +0100 JavaScript: Add support for global variables to portals. commit c40ef0556a60aef5ca39ce5f9286cbf68583b358 Author: Max Schaefer Date: Thu Jul 9 09:09:44 2020 +0100 JavaScript: Broaden scope of imports considered relevant to portals. Previously, we only considered an import relevant to portals if the path it imported was declared as a dependency. This falls down for deep imports where a specific module inside the package is imported rather than the default entry point, for imports of built-in modules like `fs`, and in cases where a developer simply forgets to declare a dependency. So instead we now consider all imports relevant whose path does not start with a dot or a slash. commit 8b4b5781e64b7faf47a6a4e59be29569196fa557 Author: Max Schaefer Date: Thu Jul 9 09:08:18 2020 +0100 JavaScript: Add utility predicate `getBasePortal(i)`. This iterates the existing `getBasePortal()` predicate `i` times. commit 0e66d0892bef1cdf5eaa742e17343cc6a64c2354 Merge: 0bbbfe58c 5fbf30590 Author: Robert Marsh Date: Wed Jul 8 14:50:54 2020 -0700 Merge pull request #3785 from MathiasVP/dataflow-operand-nodes C++: Operands as dataflow nodes commit 6367eb9ee87ea81fd5bfe6253e3cb64a30a580a6 Author: Arthur Baars Date: Wed Jul 8 22:08:27 2020 +0200 Address review comments commit 0638b512bcf02ed39e43ad1fa65665d4ed6b510d Author: lcartey@github.com Date: Wed Jul 8 17:56:31 2020 +0100 C++: Support custom range expression modeling for variable accesses commit 6e6921b11ecec09f7fe9f19b2ee610db594dc5df Author: dilanbhalla Date: Wed Jul 8 09:23:52 2020 -0700 implemented pr fixes commit 05a4798b5eb6a5a4e2fb07dd059554a34efebe7f Author: dilanbhalla Date: Wed Jul 8 09:19:46 2020 -0700 working on implementing pr fixes commit 71b70b4bd0112d96732a12245b620e0f42cb9adb Author: Ian Lynagh Date: Wed Jul 8 15:41:59 2020 +0100 C++: Give static_assert's an enclosing element commit 5f560e04659caa3c62612302f5a5886f75d2bf02 Author: Remco Vermeulen Date: Wed Jul 8 17:17:24 2020 +0200 Extract `HeaderSplittingSink` and `WhitelistedSource` - Extract `HeaderSplittingSink` and `WhitelistedSource` into an importable library. - Rename the existing `HeaderSplittingSink` implementation to `ServletHeaderSplittingSink`. commit b4929dbb97e5a0f4e096de4608eb77543c21ef21 Author: lcartey@github.com Date: Wed Jul 8 16:00:44 2020 +0100 C++: Adopt range analysis interface in the SimpleRangeAnalysis library commit 5c1275ec5deb6b689de4bd991335886a593037dd Author: lcartey@github.com Date: Wed Jul 8 16:00:07 2020 +0100 C++: Add an interface for exprs that can contribute to range analysis commit 170be9ffe8f280f5d17cb57a458200e194b8f5b7 Author: Remco Vermeulen Date: Wed Jul 8 16:47:51 2020 +0200 Move `UrlRedirectSink` into importable library - The `UrlRedirect` class is renamed to `ServletUrlRedirect`. - Abstract class `UrlRedirectSink` is defined that can be imported and used to customise CWE-601 via Customizations.qll commit 0bbbfe58cfa8cf44c5f288fb4dc4388cf3e5992b Merge: bf5c5297d bc7c83a5d Author: Jonas Jensen Date: Wed Jul 8 16:35:47 2020 +0200 Merge pull request #3916 from geoffw0/cc_followup2 C++: Add missing constructor taint test commit 06517c6f82c936a2aa50263ac17a624a597c7f63 Author: Remco Vermeulen Date: Wed Jul 8 16:24:06 2020 +0200 Move `QueryInjectionSink` into importable library This enables defining of new sinks to customise the CWE-089 queries. commit e8f216c76148fd2bcc3fddf8eb6ae3ed0b36992a Merge: 1485f7c87 6ef728884 Author: Arthur Baars Date: Wed Jul 8 15:11:13 2020 +0200 Merge remote-tracking branch 'upstream/master' into set-map-list-copy-of commit bf5c5297d39756e005c975fb9cd8a75ed9acf5ba Merge: 528f250af 72a24972e Author: Anders Schack-Mulligen Date: Wed Jul 8 15:07:50 2020 +0200 Merge pull request #3897 from aibaars/util-objects Java: data flow for `java.util.Objects` commit 528f250af3db048ac42231cbc4b7a6e1a0a3b15b Merge: 6ef728884 443c13d51 Author: Anders Schack-Mulligen Date: Wed Jul 8 15:00:14 2020 +0200 Merge pull request #3653 from lcartey/java/improve-spring-support Java: Improve modelling of Spring requests, flow steps and XSS sinks commit 443c13d516b63b395cc94c68941f3d442a58760b Merge: 3fef5cabf b88ebd69c Author: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Wed Jul 8 13:19:45 2020 +0100 Merge pull request #2 from aschackmull/java/spring-3653-2 Java: Fix qltests for https://github.com/github/codeql/pull/3653 commit b88ebd69c187411973aa4e571b615b9e6121e5c6 Author: Anders Schack-Mulligen Date: Wed Jul 8 14:12:27 2020 +0200 Java: Fix OgnlInjection qltest commit a4fe4f41b9386f8d1b8259f0fe2c883f15884bbf Author: Anders Schack-Mulligen Date: Wed Jul 8 14:09:08 2020 +0200 Java: Fix JndiInjection qltest commit 581d496167bb2e6e228114bfad3ed1f68e97a921 Author: Anders Schack-Mulligen Date: Wed Jul 8 14:04:01 2020 +0200 Java: Fix LdapInjection qltest commit 72a24972e7ad01d7a13fdb1c3754b2177ce96a0c Author: Arthur Baars Date: Wed Jul 8 13:30:24 2020 +0200 Apply suggestions from code review Co-authored-by: Anders Schack-Mulligen commit 32219e58c04d8f3aa2d196a6255f9d719465c6cb Author: Rasmus Wriedt Larsen Date: Tue Jul 7 18:50:09 2020 +0200 Python: Add basic call-graph metric queries For use with dist-compare commit 48e4759632da70beea2ececc62b54459e9219284 Merge: 3fef5cabf 6ef728884 Author: Anders Schack-Mulligen Date: Wed Jul 8 13:06:51 2020 +0200 Merge branch 'master' into java/spring-3653-2 commit 6ef7288848a8f7e8522971f38f755649a1b7bf1b Merge: b38839e84 6eac8e82a Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Wed Jul 8 12:04:39 2020 +0100 Merge pull request #3922 from aschackmull/java/stub-cleanup Approved by aibaars commit 61dfebceb92cd0b5f1e67a33cac0470bd26fe7d0 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Jul 8 11:27:20 2020 +0100 C++: Add getFullyConverted() as suggested. commit 022cafebd325d78454e7bb9174f384c4abaa11c8 Author: Erik Krogh Kristensen Date: Wed Jul 8 10:28:41 2020 +0200 make sure the consisntecy-checking library does not mix configurations commit b38839e84e5b674fa7aea51e0d598258042aa6d7 Merge: c166fee19 00a61816c Author: Anders Schack-Mulligen Date: Wed Jul 8 10:25:13 2020 +0200 Merge pull request #3920 from Marcono1234/patch-3 Improve VariableAssign.getSource documentation commit ec38df69b3a582ea2c317fc8bf3ec6956d7936e2 Author: Erik Krogh Kristensen Date: Wed Jul 8 10:24:55 2020 +0200 update consistency comments for CWE-918 commit c5285f7418ee36f03580991508c2c39cf1d68c7b Author: Erik Krogh Kristensen Date: Wed Jul 8 10:16:43 2020 +0200 update inconsistency comment for CWE-843 commit 45b6906a0d3cdda07baff9974af51a4690e1e148 Author: Erik Krogh Kristensen Date: Wed Jul 8 10:16:04 2020 +0200 move comments to match alert location for CWE-834 commit 71a3d49d2b622738c76c2e56dfcbcb3e102fe691 Author: Erik Krogh Kristensen Date: Wed Jul 8 10:15:26 2020 +0200 update comments to match alert location for CWE-807 commit d814e73023b3bf7925699b4b7786416d8afc2dbe Author: Erik Krogh Kristensen Date: Wed Jul 8 10:12:12 2020 +0200 update comment position to match alert location for CWE-798 commit bcffc97de7c3e0dd5457290ea748364f6057cd9c Author: Erik Krogh Kristensen Date: Wed Jul 8 10:10:02 2020 +0200 update comment position to match alert location for CWE-776 commit 223563434784dbf6cfca2359d775e44d2525af91 Author: Erik Krogh Kristensen Date: Wed Jul 8 10:08:51 2020 +0200 update consistency comments for CWE-754 commit 6eac8e82a38e6d8ac29d9ba349646da6a6279e34 Author: Anders Schack-Mulligen Date: Wed Jul 8 10:08:44 2020 +0200 Java: Consolidate spring-ldap-2.3.2 stubs. commit 0d64a0f2c81ced0c440d15cb73235509a36156a0 Author: Erik Krogh Kristensen Date: Wed Jul 8 10:07:34 2020 +0200 update consistency comment for CWE-730 commit 5a87628478831c5514bdc38c42e1fbbb1fe5571a Author: Erik Krogh Kristensen Date: Wed Jul 8 10:03:03 2020 +0200 update consistency comments for CWE-611 commit 1f1c09af020e3af71007d75d3de8c4a26c9152da Author: Erik Krogh Kristensen Date: Wed Jul 8 10:02:29 2020 +0200 update consistency comments for CWE-601 commit ce6a21134008132fafd579f45a48a4e6a9c0b471 Author: Erik Krogh Kristensen Date: Wed Jul 8 10:01:40 2020 +0200 update inconsistency comment for CWE-506 commit bf36137834d2cc23d3dd308fe01df18f5e400b1e Author: Erik Krogh Kristensen Date: Wed Jul 8 10:01:04 2020 +0200 update inconsistency comment for CWE-346 commit 16b0427dc4c92d80aff060529a6e9a9d9ee305fe Author: Erik Krogh Kristensen Date: Wed Jul 8 10:00:19 2020 +0200 update inconsistency comment for CWE-338 commit 40b9d34ab91c1c75ef4af98bee2d6244d6f2a639 Author: Anders Schack-Mulligen Date: Wed Jul 8 09:57:48 2020 +0200 Java: Consolidate springframework-5.2.3 stubs commit 9bcbedde46844c93f97721f5a2fba4952c22508a Author: Erik Krogh Kristensen Date: Wed Jul 8 09:55:00 2020 +0200 update consistency comment in passwords.js commit 664c5e64b442ef9387b4d02fcd62a8eff7b160dd Author: Erik Krogh Kristensen Date: Wed Jul 8 09:48:12 2020 +0200 add [INCONSISTENCY] comment in CodeInjection test commit 00e900f1b15447633fc3a6897f3cbd5bd0f01a6b Author: Erik Krogh Kristensen Date: Mon Jul 6 11:10:56 2020 +0200 only include named topmost package.json files for js/shell-command-constructed-from-input commit c166fee198cb81736893af5e5bdc507f7619ae2a Merge: 548fceb30 940fec566 Author: Anders Schack-Mulligen Date: Wed Jul 8 09:06:40 2020 +0200 Merge pull request #3894 from aibaars/util-arrays Java: model taint for java.util.Arrays commit 00a61816c08590c9524a760e5466ac738a01b3bc Author: Marcono1234 Date: Tue Jul 7 22:37:58 2020 +0200 Improve VariableAssign.getSource documentation commit 6f7a8d029ccffbd12e65c37d578afe7eade25572 Author: Dave Bartolomeo Date: Tue Jul 7 16:31:46 2020 -0400 C++: Move `.gitignore` into autobuilder directory On second thought, I'm going to make this apply only to the AutoBuilder directory. C# has it in the root of `csharp`, but they need it for their extractor as well. commit d3bcc1dae46ef1141ca6fc3cf5e5341696a268dc Author: Dave Bartolomeo Date: Tue Jul 7 16:27:43 2020 -0400 C++: Add `.gitignore` for autobuilder C# has its own additional `.gitignore` to ignore the output files of the AutoBuilder build. Now that we have our own AutoBuilder in C++, we need the same thing. commit 548fceb3068ded71ba7bcc63bffe15da5e9b9855 Merge: 1d5ef381a 7306f58e5 Author: Taus Date: Tue Jul 7 22:05:47 2020 +0200 Merge pull request #3917 from RasmusWL/python-fix-experimental-tests Python: Fix experimental tests commit 441bf98ce70d7bf6f9f1f1feeec169ead47d3261 Author: Arthur Baars Date: Tue Jul 7 20:34:13 2020 +0200 Java: add Vector::copyInto, BlockingQueue::drainTo commit c9ae2c8b2cad4f7857b255cd03900675eecb7b2a Author: Arthur Baars Date: Tue Jul 7 20:11:58 2020 +0200 Java: ContainerFlow: organize taintPreservingArgumentToQualifier commit 3b9daa2db22ecc772b1d4b2e14e935c8f1686d24 Author: dilanbhalla Date: Tue Jul 7 11:05:39 2020 -0700 added pr fixes commit 5d73b99fd1b1ee0e26115f314a07fd3084ef7a57 Author: Arthur Baars Date: Tue Jul 7 19:53:11 2020 +0200 Java: ContainerFlow: organize taintPreservingQualifierToMethod commit 7306f58e574666dbc5b954598051c2ffbc6489ea Author: Rasmus Wriedt Larsen Date: Tue Jul 7 19:44:43 2020 +0200 Python: Fix experimental tests commit 1d5ef381aee09849ad46084ed5d022b3fd34246a Merge: 22666dd46 45eccb252 Author: Rasmus Wriedt Larsen Date: Tue Jul 7 18:48:05 2020 +0200 Merge pull request #3915 from tausbn/python-qlformat-everything-again Python: Autoformat everything using `qlformat`. commit d201c4ba8ad64a5e430cd36c5998514055f5dd90 Author: dilanbhalla Date: Tue Jul 7 09:34:04 2020 -0700 fixed pr suggestions for tags/formatting commit 940fec5669e345fd9de3005cdd463c8ed717d84e Author: Arthur Baars Date: Tue Jul 7 17:26:49 2020 +0200 Drop taint tracking for Arrays.{deepToString,toString} commit 583f7f914e09bf0ee565cd1cfcaae5df2fe97e23 Author: Arthur Baars Date: Tue Jul 7 17:22:30 2020 +0200 Drop taint tracking for Arrays.{setAll, parallelSetAll, parallelPrefix} commit 45eccb25216a07f9290199fe3cabafbfaef30bc2 Author: Taus Brock-Nannestad Date: Tue Jul 7 17:01:17 2020 +0200 Python: Fix test failures. commit bc7c83a5d64ef44b9e1a4838fc6dfebdfdf1f6d1 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jul 7 15:52:31 2020 +0100 C++: Add taint test cases confirming that constructor definitions do no need to be present. commit 9cf6601d02adf1e3c9567a07164112e8ddbee881 Author: Arthur Baars Date: Fri Jul 3 20:27:50 2020 +0200 Java: Data flow for `java.util.Objects` commit 22666dd46e0262f761d98d904f93f875680c09a8 Merge: 32fcfcf97 0d9b18dbd Author: Ian Lynagh Date: Tue Jul 7 15:47:28 2020 +0100 Merge pull request #3875 from igfoo/is_constexpr C++: Accept test changes for is_constexpr commit df4d145490833d4fa594ce95442508a04b74dbb6 Merge: f07a7bf8c 32fcfcf97 Author: Taus Date: Tue Jul 7 16:33:21 2020 +0200 Merge branch 'master' into python-qlformat-everything-again commit 32fcfcf97cce37dd7bd0ad4f87e6f5473c342dff Merge: 993506d78 67db1df00 Author: Jonas Jensen Date: Tue Jul 7 15:54:34 2020 +0200 Merge pull request #3912 from aschackmull/location-doc C++/C#/JavaScript/Python: Port Location qldoc update. commit f07a7bf8cff4152845a013fa44001247e796b3a0 Author: Taus Brock-Nannestad Date: Tue Jul 7 15:43:52 2020 +0200 Python: Autoformat everything using `qlformat`. Will need subsequent PRs fixing up test failures (due to deprecated methods moving around), but other than that everything should be straight-forward. commit 3487ec17d0ea39e2229d4066c3e659cbe1bccaf5 Author: Raz0r Date: Tue Jul 7 16:17:59 2020 +0300 add tests commit d85d9b9b5bd04882d44b226008f6132249403acc Author: Erik Krogh Kristensen Date: Tue Jul 7 11:07:49 2020 +0200 autoformat commit b46b49586af95939b24ba98232868f60dec21f86 Author: Arseny Reutov Date: Fri Jul 3 17:58:03 2020 +0300 Apply suggestions from code review `interpretsValueAsJavaScript` -> `interpretsValueAsJavaScriptUrl` Co-authored-by: Asger F commit 54db6c4a3933d0bf052e16ec3afba5a00bd332ab Author: Raz0r Date: Mon Jun 29 17:46:33 2020 +0300 [js/client-side-unvalidated-url-redirection] add interpretsValueAsJavaScript predicate commit 3fef5cabf1038ad8d27966715e88f8530e2f2a3c Merge: 2978af34c f98460cfd Author: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Tue Jul 7 12:07:33 2020 +0100 Merge pull request #1 from aschackmull/java/spring-3653 Java: Review changes for https://github.com/github/codeql/pull/3653 commit 67db1df00c5b9e2a473776c07015bb7191e00a7f Author: Anders Schack-Mulligen Date: Tue Jul 7 11:39:27 2020 +0200 C++/C#/JavaScript/Python: Port Location qldoc update. commit 42227c625dc62ee309413b7877404de24ecd601b Author: Rasmus Wriedt Larsen Date: Tue Jul 7 11:33:54 2020 +0200 Python: Fix grammar Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> commit 27d1512a75d4d3cd6989982f13138514fed9c612 Author: Rasmus Wriedt Larsen Date: Mon Jul 6 19:00:57 2020 +0200 Python: MWE for call-graph tracing and ql comparison commit eaec2d722cf5bca17206ff0faf43ffdc54aab53a Merge: f917b9e3c f98491a05 Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Tue Jul 7 09:54:39 2020 +0100 Merge pull request #3888 from shati-patel/go-docs Learning CodeQL: Add new library modeling guide (Go) commit 993506d7812ef51be0716db3155ab00da32d20d2 Merge: 173e10860 0a9686709 Author: Anders Schack-Mulligen Date: Tue Jul 7 10:29:17 2020 +0200 Merge pull request #3820 from Marcono1234/patch-2 Add missing java.nio.file.Files methods to FileReadWrite.qll commit 173e108606f3cbba71b577980c57d6f5f3532b2e Merge: f2ce125e6 6ff8508d0 Author: Anders Schack-Mulligen Date: Tue Jul 7 07:58:39 2020 +0200 Merge pull request #3907 from Marcono1234/patch-1 Java: Clarify documentation for Location predicate results commit f2ce125e6168f61605d24785200b82e00eb42a5c Merge: fe0c5a9ea 5649254db Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Mon Jul 6 21:13:05 2020 +0100 Merge pull request #3902 from Marcono1234/fix-outdated-query-links Approved by shati-patel commit 8f7ff1a537f6d7fe8f2139ad9dade07fb82ec691 Author: Philippe Antoine Date: Mon Jul 6 21:45:54 2020 +0200 Adds another redundant null check rule commit 5649254dbdbb80a259b75d36472ed884e88c05dc Author: Marcono1234 Date: Mon Jul 6 20:35:11 2020 +0200 Fix broken link formatting in introduce-libraries-java.rst Co-authored-by: Shati Patel <42641846+shati-patel@users.noreply.github.com> commit 0d9b18dbd746c424fa6002c505b10acba2eba258 Author: Ian Lynagh Date: Thu Jul 2 14:15:11 2020 +0100 C++: Accept test changes for is_constexpr Generated copy and move constructors may now be marked as constexpr. commit 0caa17ab108bbf6ce9675f01adda83c5b52b2074 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Jul 6 18:47:56 2020 +0100 C++: Test the new methods. commit 52e501c41d6932b1e5cbb7eb66436a3c14a796ea Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Jul 6 18:41:25 2020 +0100 C++: Extend the 'swap' taint tests with methods that do not have recognizable signatures (copy/move assignment). commit f98491a052627c3ca376c60930d2c457bef156fc Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Mon Jul 6 18:30:01 2020 +0100 Apply suggestions from code review Co-authored-by: James Fletcher <42464962+jf205@users.noreply.github.com> commit 442ee8d1cc57f477e37fcb83eff84f619a2bdfc5 Author: Erik Krogh Kristensen Date: Mon Jul 6 14:53:47 2020 +0200 add consistency-checking for CWE-089 commit 0a9686709bf5945a16496edccf104fc6f3bf6458 Author: Marcono1234 Date: Sun Jul 5 18:43:02 2020 +0200 Fix wrong method name commit fe0c5a9ea6512e5a9e384833ae640ac8f4f7a31f Merge: 6d80445f2 9a944625d Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Mon Jul 6 17:04:30 2020 +0100 Merge pull request #3892 from asger-semmle/js/redirect-starts-with-sanitizer Approved by esbena commit d00e7396c4cc2b267896cc312b29bcd04d69524d Author: Rasmus Wriedt Larsen Date: Mon Jul 6 17:58:23 2020 +0200 Python: Consistently use camelCase in annotated call-graph tests commit 65c4e6c02ac8758231fbdbbec5218d0fb67e75f2 Author: Rasmus Wriedt Larsen Date: Mon Jul 6 17:45:13 2020 +0200 Python: Disable class instantiation annotation for now Adjusting test setup properly requires some deep thinking, and I don't think I'm ready to do that right now. Added a TODO instead. commit cd8ea78420e84fe664c8102137455defe0a3c121 Author: Rasmus Wriedt Larsen Date: Mon Jul 6 17:34:19 2020 +0200 Python: Autoformat commit 9e252d5465d9b6da4f1066fccd459cd97244771a Author: Rasmus Wriedt Larsen Date: Mon Jul 6 17:30:49 2020 +0200 Python: Explain random example commit 849159b279e220f664241e3e740e01aee61ddb0c Author: Rasmus Wriedt Larsen Date: Mon Jul 6 17:30:26 2020 +0200 Python: Unlimited import depth commit acfc62cad63f2674fd4ecf33635cc027fd13f683 Author: Rasmus Wriedt Larsen Date: Mon Jul 6 17:21:29 2020 +0200 Python: Fix grammar Co-authored-by: Taus commit f98460cfd091f56733a78c8a99d324edb8bfb485 Author: Anders Schack-Mulligen Date: Mon Jul 6 16:54:20 2020 +0200 Java: Use SpringHttpEntity class. commit ae21de90b6f1f2eecb77ae3bfabba61c2dd1fa0b Author: Anders Schack-Mulligen Date: Mon Jul 6 16:15:16 2020 +0200 Java: Misc grammar and formatting. commit b06d1c715aa804da7454ded78858ef2d4fb35ce0 Author: Anders Schack-Mulligen Date: Mon Jul 6 16:04:14 2020 +0200 Java: More qldoc and some formatting. commit 6ff8508d01355b1df5f24cd305d244a9db91f213 Author: Marcono1234 Date: Mon Jul 6 15:46:11 2020 +0200 Java: Clarify documentation for Location predicate results commit 6d80445f242551b74325b3c5dd061bd39fee622e Merge: 13c3513d7 078b6a8df Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Mon Jul 6 14:40:41 2020 +0100 Merge pull request #3851 from erik-krogh/queryStuff Approved by esbena commit 5e9e7feddc8fc02c8a04a6486f857cfcbd0b526b Author: Anders Schack-Mulligen Date: Mon Jul 6 15:39:20 2020 +0200 Java: Add some qldoc and minor formatting. commit e6658c5110c3beff29755319ec46d09371c18794 Author: Anders Schack-Mulligen Date: Mon Jul 6 15:35:16 2020 +0200 Java: Cleanup TaintTrackingUtil.qll commit 9a944625d167f7c985ef557ea819726ff1310c5b Author: Erik Krogh Kristensen Date: Mon Jul 6 15:17:15 2020 +0200 autoformat commit 5d8f9a79f1c5ee80d29143cabb01b43af4f3845c Author: Anders Schack-Mulligen Date: Mon Jul 6 14:50:33 2020 +0200 Java: Misc grammar fixes. commit a80e663ab5f1dfc2146d939ebdb8a2cce7a509bb Author: Anders Schack-Mulligen Date: Mon Jul 6 14:43:01 2020 +0200 Java: Minor typo fix and autoformat commit 2ce09219359ce3733a71ecf8bdcd913f4fdafada Author: Anders Schack-Mulligen Date: Mon Jul 6 14:35:53 2020 +0200 Java: Clean up SpringHttp.qll commit 2ae15f9ace7efff75a82b18cc47d6f3e8f13bac9 Author: Anders Schack-Mulligen Date: Mon Jul 6 14:19:13 2020 +0200 Java: Remove list, map, and StringReplaceMethod flow steps. commit a41c2d8abfaf18d5990e348ba159fa3f332b2a9e Author: Anders Schack-Mulligen Date: Mon Jul 6 14:18:16 2020 +0200 Java: Make a few predicates private and autoformat SpringController. commit 2a8b37e0041bb3b26d5a90ae8e32aed0fdee805c Author: Erik Krogh Kristensen Date: Mon Jul 6 14:15:23 2020 +0200 update consistency comments in unsafe-jquery-plugin.js Co-authored-by: Esben Sparre Andreasen commit c986f3bb7c479f12f3fb2443d5bae07ee7c21e8f Author: Erik Krogh Kristensen Date: Mon Jul 6 13:42:35 2020 +0200 add consistency checking for CWE-079 commit dc8042adeb76f11fc03f7cdf72a0e11e6f3991f5 Author: Erik Krogh Kristensen Date: Thu Jul 2 16:30:50 2020 +0200 introduce conistency-checking for CWE-078 commit 13c3513d765e0fcdcbb9059110932f83018688d9 Merge: d2734b290 858531227 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Mon Jul 6 11:41:56 2020 +0100 Merge pull request #3905 from erik-krogh/unsafeShellTypo Approved by esbena commit f917b9e3cb92f58082cbf06a7ee18fb6e63cb366 Merge: d5c643324 a969dbc6c Author: Arthur Baars Date: Mon Jul 6 11:43:16 2020 +0200 Merge pull request #3608 from aschackmull/java/backport-switchexpr-cfg-fix Java: Backport missing CFG edge fix for switch expressions commit d2734b2903d822680489230e32af024475c42697 Merge: 98d24101b f23eb0432 Author: Arthur Baars Date: Mon Jul 6 11:42:04 2020 +0200 Merge pull request #3684 from aschackmull/java/javadoctag-qldoc Java: Improve qldoc for JavadocTag. commit 98d24101b1e9aa5d3c14c05fc34c72dacae3dcb7 Merge: 73d606d2c 421a548e4 Author: Arthur Baars Date: Mon Jul 6 11:41:21 2020 +0200 Merge pull request #3687 from aschackmull/java/getanenclosingstmt Java: Add Expr.getAnEnclosingStmt. commit 73d606d2c3f241ff82a35ae0b751421be00a11b2 Merge: 163257a6c 80981ec8f Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Mon Jul 6 09:47:59 2020 +0100 Merge pull request #3844 from github/esbena-patch-3 Approved by erik-krogh commit 85853122711fbe899037e73445ba31c57fe850de Author: Erik Krogh Kristensen Date: Mon Jul 6 10:33:49 2020 +0200 fix typo in js/shell-command-constructed-from-input commit 2d9b52f750169a5aa193b1cc24c56d45eceb0bc0 Author: Marcono1234 Date: Sun Jul 5 22:32:53 2020 +0200 Update query console links in source-locations.rst, replace deprecated predicates Removes 'eclipse-cdt/cdt' and 'gradle/gradle' from the queried projects because they cannot be queried currently, and instead queries all demo projects which are currently available. commit 7b4960c9a70971e8d02e04a7f3aab6d58bd85d8f Author: Marcono1234 Date: Sun Jul 5 20:54:05 2020 +0200 Update query console links in javadoc.rst Removes 'gradle/gradle' from the queried projects because it cannot be queried currently, and instead queries all demo projects which are currently available. commit b835d7879c7047300525c04cc1e9b73c11da78f0 Author: Marcono1234 Date: Sun Jul 5 20:51:00 2020 +0200 Update query console links in introduce-libraries-java.rst Removes 'eclipse-cdt/cdt' and 'gradle/gradle' from the queried projects because they cannot be queried currently, and instead queries all demo projects which are currently available. commit 2b3b64cdbca849e7b79e476540accc2c4b1de3d3 Author: Marcono1234 Date: Sun Jul 5 20:04:36 2020 +0200 Update query console links in expressions-statements.rst Removes 'eclipse-cdt/cdt' and 'gradle/gradle' from the queried projects because they cannot be queried currently, and instead queries all demo projects which are currently available. commit c10a5986709748433a482f871c4ba75e0b311133 Author: Marcono1234 Date: Sun Jul 5 19:54:27 2020 +0200 Update query console links in call-graph.rst Removes 'eclipse-cdt/cdt' and 'gradle/gradle' from the queried projects because they cannot be queried currently, and instead queries all demo projects which are currently available. commit ab2456630ce26c4b7616f7fe6a4f0bf928fc4012 Author: Marcono1234 Date: Sun Jul 5 19:43:48 2020 +0200 Update query console links in annotations.rst Removes 'eclipse-cdt/cdt' and 'gradle/gradle' from the queried projects because they cannot be queried currently, and instead queries all demo projects which are currently available. commit 13ffd7307c29946ff5b398ef2ad4ed834f06cdd4 Author: Marcono1234 Date: Sun Jul 5 19:20:42 2020 +0200 Update query console links in types-class-hierarchy.rst Removes 'gradle/gradle' from the queried projects because it cannot be queried currently, and instead queries all demo projects which are currently available. commit f8e474f89afa969e493b4074339d1f44b51ded41 Author: Marcono1234 Date: Fri Jun 26 23:56:01 2020 +0200 Add missing java.nio.file.Files methods to FileReadWrite.qll commit d6e9b07a9ea83ced6d025e3c787ce20579433b82 Author: luchua-bc Date: Fri Jul 3 22:34:48 2020 +0000 Add JBoss BasicLogger and SciJava Logger commit b242a6170121096e8c06b008e35a32a4e417182c Author: lcartey@github.com Date: Fri Jul 3 17:32:08 2020 +0100 Java: Untrusted data used in external APIs This commit adds two queries for identifying external APIs which are used with untrusted data. These queries are intended to facilitate a security review of the application, and will report any external API which is called with untrusted data. The purpose of this is to: - review how untrusted data flows through this application - identify opportunities to improve taint modeling of sinks and taint steps. As a result this is not suitable for integration into a developer workflow, as it will likely have high false positive rate, but it may help identify false negatives for other queries. commit 19a481f809b842321f9d4b98d530d7cfdb187f11 Author: Arthur Baars Date: Thu Jul 2 19:48:19 2020 +0200 Java: Arrays: add tests commit 0b89efbee49d2d31d7817b04d2fe8ce3c65bb52d Author: Arthur Baars Date: Thu Jul 2 16:05:56 2020 +0200 Java: model Arrays::addList commit a07af79fff165f6a10ec853a1096af86e6dd9fc7 Author: Arthur Baars Date: Thu Jul 2 16:05:09 2020 +0200 Java: model java.util.Arrays commit 1485f7c87611fe98abdadb743910673eba0448e3 Author: Arthur Baars Date: Fri Jul 3 16:51:41 2020 +0200 Java: model some new Set,List,Map methods Models the taint propagation for the copyOf(..), of(..), ofEntries(..) and entry(..) methods commit 163257a6c554b5475522dd8aceea7bf0027530f1 Merge: c629f6b13 2b248fb24 Author: Max Schaefer <54907921+max-schaefer@users.noreply.github.com> Date: Fri Jul 3 16:14:29 2020 +0100 Merge pull request #3891 from aibaars/exclude-experimental CodeQL: exclude `experimental` queries from LGTM suites commit c629f6b13a9c29397ca1ac2504147f7227115a6a Merge: 687bb4dfc 5fff41f35 Author: Arthur Baars Date: Fri Jul 3 17:09:14 2020 +0200 Merge pull request #3869 from aibaars/util-collections Java: model java.util.Collections commit 687bb4dfc83c8b5f9611d6da4834a270dc8eeee6 Merge: 01c485236 b99ec29f6 Author: yoff Date: Fri Jul 3 16:03:41 2020 +0200 Merge pull request #3890 from github/tausbn-add-paths-ignore-to-code-scanning-config Code Scanning: Don't scan the Python directory. commit 01c4852360f5ee20b7f59ef4b39b9d1f4d3889db Merge: 04a0d47ab fe9520b50 Author: Taus Date: Fri Jul 3 16:03:20 2020 +0200 Merge pull request #3701 from yoff/SharedDataflow Python: Start using the shared data flow libraries commit b5104ae42d545bc75927fcb0453a1c85420cd89f Author: Asger Feldthaus Date: Fri Jul 3 14:34:59 2020 +0100 JS: Add StartsWith sanitizer commit 4c06eb8bfec5b1fbac8f04557cf7c64b1d0da0ca Author: Asger Feldthaus Date: Fri Jul 3 14:26:10 2020 +0100 JS: Add test showing FPs commit fe9520b50b035aab69a5f0d163068320e1995eb9 Author: Rasmus Lerchedahl Petersen Date: Fri Jul 3 15:04:54 2020 +0200 Python: correct doc for toString commit 5fff41f35b7dc6e51477833ab644979e600e26ff Author: Arthur Baars Date: Fri Jul 3 13:36:56 2020 +0200 Don't track taint on Map keys commit 33cf96ccb87b8e65d32e28b406e1b4ee80f71077 Author: Rasmus Lerchedahl Petersen Date: Fri Jul 3 14:11:58 2020 +0200 Python: Address review comments commit 6de612a56605eea2a2262f33e86d891f38033667 Author: Anders Schack-Mulligen Date: Fri Jul 3 14:06:54 2020 +0200 Java: Split SpringWebRequestGetMethod into its own class. commit 2b248fb24f4df415116b8e518fe7117e33287b71 Author: Arthur Baars Date: Fri Jul 3 14:03:00 2020 +0200 CodeQL: exclude queries from CodeScanning suites commit bb01dbd2aec1f1ebbfd83f5f2555cb9cc96e5d76 Author: Arthur Baars Date: Fri Jul 3 13:47:24 2020 +0200 CodeQL: exclude queries from LGTM suites commit b99ec29f6e4b5ddd45c154f128dd32a9ca14f4a7 Author: Taus Date: Fri Jul 3 13:56:25 2020 +0200 Code Scanning: Additionally exclude Java and C++. commit 39bc97857328444a3487b4af8a0520830522feba Author: Taus Date: Fri Jul 3 13:46:30 2020 +0200 Code Scanning: Don't scan the Python directory. ... Possibly some of the other language teams want to get on this? :slightly_smiling_face: If so, give me a shout! commit d201eb2c12a2dbe35fd5f3090f283a1e5fc73304 Author: yoff Date: Fri Jul 3 13:33:27 2020 +0200 Update python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll Co-authored-by: Rasmus Wriedt Larsen commit 59d611ddd51897b90134cdc8706b84d9210b265a Author: yoff Date: Fri Jul 3 13:32:03 2020 +0200 Update python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll Co-authored-by: Rasmus Wriedt Larsen commit 8891fbf006a3faf5f2deddc22466557e3105ae7c Author: yoff Date: Fri Jul 3 13:31:38 2020 +0200 Update python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll Co-authored-by: Rasmus Wriedt Larsen commit 40a67287480ecab0264db4bd67dc1492b5f98ded Author: yoff Date: Fri Jul 3 13:30:10 2020 +0200 Update python/ql/src/experimental/dataflow/internal/TaintTrackingPrivate.qll Co-authored-by: Rasmus Wriedt Larsen commit e3666004cfba2540335d57806fb7306599afba0b Author: Rasmus Lerchedahl Petersen Date: Fri Jul 3 10:37:38 2020 +0200 Python: add some links to readme commit 45bd4921614ff01c652bdf10c7500beb6b2908e7 Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Thu Jul 2 21:54:25 2020 +0100 Learning CodeQL: Add new library modeling guide (Go) commit a9e0288e5bfb77d0c62657efd108a8cfd4a72a1a Author: Rasmus Lerchedahl Petersen Date: Fri Jul 3 08:41:10 2020 +0200 Python: exclude global vars from local flow commit bdc68ce6b633e26f34ab500711d1fa61e5990181 Author: Rasmus Lerchedahl Petersen Date: Fri Jul 3 08:01:44 2020 +0200 Python: refactor `Node` class commit 6d329bce6e375f313339b288e19acd0ad2d33739 Author: luchua-bc Date: Fri Jul 3 01:13:11 2020 +0000 Add Apache Commons Logging and debugv method commit 078b6a8df2a0413cb740ade6ca32104f8b9e8e80 Author: Erik Krogh Kristensen Date: Fri Jul 3 00:21:55 2020 +0200 autoformat commit 04a0d47ab9cc38645b06a38cd950a158ef99ed1e Merge: ba634af86 527a099a2 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Thu Jul 2 18:48:05 2020 +0100 Merge pull request #3870 from hvitved/csharp/cfg/cond-out-param Approved by calumgrant commit 5f2a5f1b554503985ab1392e2658ee2bb3e962b6 Author: Arthur Baars Date: Thu Jul 2 18:19:07 2020 +0200 Java: Collections: add tests commit 03cc4e179e6d125de83994b4c5fde76b36ca093c Author: Calum Grant Date: Thu Jul 2 17:47:17 2020 +0100 C#: Make fields readonly commit ba634af86e8c00f091dd8d746f76691e7c80a31a Merge: b5c8f2238 513c2974b Author: Taus Date: Thu Jul 2 18:21:59 2020 +0200 Merge pull request #3362 from RasmusWL/python-keyword-only-args Python: properly support keyword only arguments commit 5f18fb427ac2fb930941a5a4e9cf0a7567b9ce11 Author: Rasmus Lerchedahl Petersen Date: Thu Jul 2 16:20:38 2020 +0200 Python: update TODO commit 261821b32c8bdb62289cbab56e4fe5e0e0e0a27f Merge: 2b0a09192 b5c8f2238 Author: Erik Krogh Kristensen Date: Thu Jul 2 16:08:05 2020 +0200 Merge remote-tracking branch 'upstream/master' into queryStuff commit b5c8f2238b50c2ff27da1d8fa318309aca8f8cef Merge: eecc3ca5d 3ca6031ae Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Thu Jul 2 13:54:54 2020 +0100 Merge pull request #3805 from esbena/js/seal-freeze-flow Approved by asgerf commit 513c2974bde82ad676b29432a43871f81dc75318 Merge: b2f8638ff eecc3ca5d Author: Rasmus Wriedt Larsen Date: Thu Jul 2 14:48:32 2020 +0200 Merge branch 'master' into python-keyword-only-args commit ceb19292cb1f3a6bc23b232c2613934c95141002 Author: Erik Krogh Kristensen Date: Thu Jul 2 14:47:08 2020 +0200 autoformat commit 2b0a091921d67fe40be0d9f47b3af2ed15f3ea92 Author: Erik Krogh Kristensen Date: Thu Jul 2 14:28:28 2020 +0200 split out type-tracking into two predicates, to avoid catastrophic join-order commit b2f8638ff0f7acd05b3bf8fed442ea31d0cd31cb Author: Rasmus Wriedt Larsen Date: Thu Jul 2 14:17:55 2020 +0200 Python: Update dbscheme with new comment commit eecc3ca5dd5961660ce1e6ba0ca2afaccb771bdb Merge: 97128b147 67be45f04 Author: Taus Date: Thu Jul 2 13:32:35 2020 +0200 Merge pull request #3503 from RasmusWL/python-fix-django-taint-sinks Python: Fix django taint sinks commit 7dfc5841594d5117c2bab4c1e9c51bc240ad2d6b Author: Tom Hvitved Date: Thu Jul 2 13:29:25 2020 +0200 C#: Introduce delegate type in autobuilder commit 527a099a26e05a87a95a4b67906e06662c2ac1e1 Author: Tom Hvitved Date: Thu Jul 2 13:08:25 2020 +0200 C#: Fix CFG for conditional method calls with `out` parameters commit 090205d9e9e937725180753169b17298cd49a106 Author: Tom Hvitved Date: Thu Jul 2 13:07:36 2020 +0200 C#: Add CFG test for conditional call to method with `out` parameter commit 21a4b8d6c0a279064053bdd620453051c009f75e Author: Arthur Baars Date: Thu Jul 2 13:03:15 2020 +0200 Java: remove useless casts commit d80bf3395f0a07cd39b7fc0217b7c5228df937db Author: Arthur Baars Date: Thu Jul 2 13:02:38 2020 +0200 Add Navigable variants and sort method names commit 97128b147586470d8ac325acb98f4953776ad1ed Merge: d01904d40 03c91a66c Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Thu Jul 2 11:58:32 2020 +0100 Merge pull request #3829 from asger-semmle/js/xss-substr Approved by erik-krogh commit e7b495e7d3a57fbf39105e3ce82d201c20df85e2 Author: Arthur Baars Date: Thu Jul 2 12:38:22 2020 +0200 Java: model Collections::addAll commit 26b7a301d62a8a42252448e8a8f1c005dc97b106 Merge: c78ca2616 50fee5c4a Author: Rasmus Wriedt Larsen Date: Thu Jul 2 12:27:02 2020 +0200 Merge branch 'master' into python-keyword-only-args commit 5cf5c77b09ebb00009057a0c101f8405befb43ed Author: Arthur Baars Date: Thu Jul 2 12:01:17 2020 +0200 Java: model java.util.Collections commit d01904d404e051e845d02eead88e73b0845e7cbd Merge: 50fee5c4a 398a95c65 Author: Tom Hvitved Date: Thu Jul 2 12:02:04 2020 +0200 Merge pull request #3846 from hvitved/csharp/autobuilder-refactor C#: Factor C++ parts out of autobuilder commit 67be45f04519335b983a8ef2c30e2e586720203d Merge: 9a8292718 50fee5c4a Author: Rasmus Wriedt Larsen Date: Thu Jul 2 11:55:42 2020 +0200 Merge branch 'master' into python-fix-django-taint-sinks commit 9a829271877efd74a5f7851c0ece3f692b905fe9 Author: Rasmus Wriedt Larsen Date: Thu Jul 2 11:54:41 2020 +0200 Python: Autoformat commit a947d151e5130c37a386a5333de4b74d2d5ab7d8 Author: Rasmus Wriedt Larsen Date: Thu Jul 2 11:53:25 2020 +0200 Python: Django changes now backwards compatible deprecation commit 4a7bfbe0918ddf2cb35b91e034a0ce57131933fc Author: Rasmus Wriedt Larsen Date: Thu Jul 2 11:43:23 2020 +0200 Python: Use .matches instead of .indexOf() = 0 commit 50fee5c4a1633ff9198243025abfadb01cbe8a6d Merge: 0bf1f7527 7443c9c5a Author: Anders Schack-Mulligen Date: Thu Jul 2 11:41:19 2020 +0200 Merge pull request #3817 from Marcono1234/patch-1 Fix outdated query console link commit f60a7489b58fc3b3e49fea9bb8fe79d0306b4aa4 Author: Erik Krogh Kristensen Date: Thu Jul 2 10:39:41 2020 +0200 ignore parents that doesn't have all constant roots when deciding which roots to compute getStringValue for commit bbdeca367bc1183bccef04054a6ecc02412b3ae4 Author: Erik Krogh Kristensen Date: Thu Jul 2 10:38:02 2020 +0200 use `getUnderlyingValue()` to find leafs of a string-concat commit 226e066db82633cf74e1d485d51a0d056ea923bd Author: Erik Krogh Kristensen Date: Thu Jul 2 10:12:43 2020 +0200 use strictconcat instead of concat commit 0bf1f752744aebf63340021f3c40999719e5cb36 Merge: bfb734e1d c78427569 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Thu Jul 2 09:04:35 2020 +0100 Merge pull request #3850 from aschackmull/dataflow/doc Approved by hvitved commit bfb734e1d74df1ae810feb7198cb271b767c4b9a Merge: 2bd84a3a5 7a2c65f63 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Thu Jul 2 08:30:45 2020 +0100 Merge pull request #3832 from asger-semmle/js/typescript-in-html-files3 Approved by erik-krogh commit c78427569ed6d6ccab076952bc133519142b99dd Author: Anders Schack-Mulligen Date: Thu Jul 2 09:24:33 2020 +0200 Update docs/ql-libraries/dataflow/dataflow.md Co-authored-by: Tom Hvitved commit 2bd84a3a5eefea8e5a70848df76bbb7a57e41fbc Merge: 62a656de0 a260df903 Author: Jonas Jensen Date: Thu Jul 2 08:37:19 2020 +0200 Merge pull request #3865 from geoffw0/bufferwrite-fixup C++: 'modelling' -> 'modeling' part 2. commit 62a656de0fbace4bc635cb3a9820e55fe5f02a1e Merge: 45ef3ec4a f0215d174 Author: Jonas Jensen Date: Thu Jul 2 08:32:44 2020 +0200 Merge pull request #3860 from dbartol/codeql-c-analysis-team/40/2 C++: QLDoc cleanup commit 45ef3ec4a8f5aab4a66f280f8ae80a56baf20c16 Merge: bb9c8881d f70453c54 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Wed Jul 1 20:07:58 2020 +0100 Merge pull request #3619 from erik-krogh/CWE022-Correctness Approved by asgerf commit 6f54bb1613082a069f82ef154294c646c8d5aa3a Author: Erik Krogh Kristensen Date: Wed Jul 1 10:38:01 2020 +0200 only calculate getStringValue for concatenation roots commit 398a95c65fb7a03b59f7e22f80d1080e231929b2 Author: Tom Hvitved Date: Tue Jun 30 13:28:04 2020 +0200 C#: Remove unused field commit 498ee9b5f51c628ac7b70172198cc65149e2f2bb Author: Tom Hvitved Date: Mon Jun 29 16:01:16 2020 +0200 C#: Factor C++ parts out of autobuilder commit a260df9035052ac15a1bd79d1821295147a127df Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Jul 1 17:47:56 2020 +0100 C++: 'modelling' -> 'modeling'. commit bb9c8881d6c26da27294e96bfa2a01772c8510a9 Merge: 66a6fe731 8d8e47dc2 Author: Mathias Vorreiter Pedersen Date: Wed Jul 1 18:33:26 2020 +0200 Merge pull request #3786 from geoffw0/bufferwritecleanup C++: Clean up BufferWrite.qll commit 263f00784f28673aad6c90ad9f2713ad19510c77 Author: dilanbhalla Date: Wed Jul 1 09:25:09 2020 -0700 formatting commit 25bfc3a16833618865f8ab58c279a76cb6e337ba Author: dilanbhalla Date: Wed Jul 1 09:23:36 2020 -0700 fixed references and used autoformat commit f0215d1748c4782fcd2eeff94c5f448149de0840 Author: Dave Bartolomeo Date: Wed Jul 1 11:57:56 2020 -0400 C++: Fix typo commit 8d8e47dc29b553936b0ec3c5c64a464375c839ac Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Jul 1 16:25:24 2020 +0100 C++: QLDoc other straightforward model implementations. commit e39c11574642599472082c1f8b224ce8d21a5523 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Jul 1 16:23:50 2020 +0100 C++: QLDoc Strcpy (as demanded by the tests). commit 66a6fe731714fc5f3dcb6dfc70fc4c1f0c5f0bea Merge: 6429fe48a a6d807398 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Wed Jul 1 16:08:59 2020 +0100 Merge pull request #3853 from max-schaefer/js/canonical-names Approved by asgerf commit 0b11e77457689461f3d1d2ea445d70c815a5134f Author: Rasmus Lerchedahl Petersen Date: Wed Jul 1 16:55:44 2020 +0200 Python: make compile commit 0175d5be0c4bf14b1adb21e280903c4d818c437f Author: Rasmus Lerchedahl Petersen Date: Wed Jul 1 16:44:11 2020 +0200 Sync dataflow files commit 7fb97d75f4382af31543018a76ce6045dce0e39a Merge: 79e4f1ee9 6429fe48a Author: Rasmus Lerchedahl Petersen Date: Wed Jul 1 16:43:14 2020 +0200 Merge branch 'master' of github.com:github/codeql into SharedDataflow to get updated dataflow files commit 566d7fad639cc0ee1819615a4c24c2fac27d45a8 Author: Dave Bartolomeo Date: Wed Jul 1 10:14:35 2020 -0400 C++: Autoformat some more commit 6429fe48aac1e4a37b50ce7a394de550e53afa24 Merge: 20aed8147 5af5f40ae Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Wed Jul 1 14:58:50 2020 +0100 Merge pull request #3862 from shati-patel/shati-patel-patch-1 Small terminology update commit a6d807398771727e870b33a27f31ed1ef89189a8 Author: Max Schaefer Date: Tue Jun 30 15:41:46 2020 +0100 JavaScript: Make `getADefinition` and `getAnAccess` available on all `CanonicalName`s. commit 3ca6031ae5ee28ba9e671fd798b7dcaba77955a5 Author: Esben Sparre Andreasen Date: Wed Jul 1 15:01:41 2020 +0200 JS: rename predicate commit 75451e349ae6e2783d0d9ca6f808348c3674911e Author: Esben Sparre Andreasen Date: Thu Jun 25 15:06:58 2020 +0200 JS: teach the dataflow library identity functions Object.freeze/seal commit 33c52761d4e30db77bf6be68b4911052b54866e0 Author: Esben Sparre Andreasen Date: Thu Jun 25 14:59:04 2020 +0200 JS: more dataflow and global access path testing commit 20aed81476e50b0fc2c1a4b966d91db158f9d1f7 Merge: 7d057598d cabd275ba Author: Anders Schack-Mulligen Date: Wed Jul 1 15:01:49 2020 +0200 Merge pull request #3863 from intrigus-lgtm/patch-2 Fix typo, add Oxford comma commit 9e3a6e8d5ecfb73234dececdf11bee0cb30c694e Merge: 795c5784b 50cd75971 Author: Tom Hvitved Date: Wed Jul 1 14:44:57 2020 +0200 Merge remote-tracking branch 'upstream/master' into csharp/dataflow/arrays commit cabd275baa11142a9c336d7b36d27ba86c7bfcd6 Author: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> Date: Wed Jul 1 14:49:09 2020 +0200 Fix typo, add Oxford comma commit 4aac70d3da1109d163f56db68d9de5970443044f Author: Anders Schack-Mulligen Date: Wed Jul 1 14:45:49 2020 +0200 Dataflow: update doc based on review. commit 5af5f40ae1c3ed015988ecb6c70d896a48e28494 Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Wed Jul 1 13:41:50 2020 +0100 Small terminology update commit 7d057598d8d747889929ee94cc0cd0c1347af026 Merge: 50cd75971 cff0f48d3 Author: Anders Schack-Mulligen Date: Wed Jul 1 14:23:23 2020 +0200 Merge pull request #3857 from jbj/flowthrough-bigstep-perf C++: Remove big-step relation in flow-through code commit 50cd7597189ef87d75e924d486859f21a0ca0df1 Merge: 38b73ff68 168f9404f Author: Jonas Jensen Date: Wed Jul 1 13:58:27 2020 +0200 Merge pull request #3733 from geoffw0/models5 C++: Constructor and assignment models commit 3157cd724d756b55603ac5c20cceb0ccf6145e6e Author: Erik Krogh Kristensen Date: Wed Jul 1 11:45:09 2020 +0200 add noSQL tests for type-tracking req.query commit bace2994c39639ba4201d70ca4b77923b7a88868 Author: Erik Krogh Kristensen Date: Wed Jul 1 11:38:54 2020 +0200 add test for type-tracking req.params commit 38b73ff684616ba16f4d807e238c441fdc03ba0d Merge: ef109d91e f1179cc20 Author: Anders Schack-Mulligen Date: Wed Jul 1 11:37:19 2020 +0200 Merge pull request #3854 from hvitved/dataflow/node-type-interface Data flow: Replace `getErasedRepr()` and `Node::getTypeBound()` with `getNodeType()` commit 82270104639f4ffc06e8883d2f31ae005fd76ce4 Author: Erik Krogh Kristensen Date: Wed Jul 1 11:32:51 2020 +0200 also use new type-tracking in isUserControlledObject commit 79e4f1ee932c6161e5c26d14f2885237866bbdf4 Author: Rasmus Lerchedahl Petersen Date: Wed Jul 1 09:21:36 2020 +0200 Python: Enable consistency check (currently fails) commit ef109d91ed4cbf4ceeb9e92651c96b9190d9d932 Merge: ed2077b2f 3efe1a9d1 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Wed Jul 1 08:14:57 2020 +0100 Merge pull request #3842 from hvitved/csharp/dataflow/remove-viable-impl Approved by aschackmull commit ed2077b2f429348556b833e7890896e79227aba0 Merge: e9777913a 7a023a65b Author: Tom Hvitved Date: Wed Jul 1 08:45:35 2020 +0200 Merge pull request #3841 from gavinl/master QHELP: Encryption using ECB.qhelp grammar commit 10bbd566d41dfabc9842868fd60c4d13b23dd733 Author: Dave Bartolomeo Date: Wed Jul 1 02:28:53 2020 -0400 C++: Autoformat commit 7787900bed17628a3ac4967730f55d0639e4f2ef Author: Rasmus Lerchedahl Petersen Date: Wed Jul 1 07:36:00 2020 +0200 Python: make compile and simplify commit 825f24a95373c83d712c2ee34a1082294c3bbcfb Author: Rasmus Lerchedahl Petersen Date: Wed Jul 1 07:20:26 2020 +0200 Python: simplify according to review comments commit 3388ca44ed0c24d78ca11a26f7cbb1317cc46818 Author: Rasmus Lerchedahl Petersen Date: Wed Jul 1 07:16:59 2020 +0200 Python: sync dataflow library commit e25928182194a7670a2d64ca7fa03713309f7d42 Merge: 64af5f585 e9777913a Author: Rasmus Lerchedahl Petersen Date: Wed Jul 1 07:15:32 2020 +0200 Merge branch 'master' of github.com:github/codeql into SharedDataflow to receive updates from data flow library commit 259654b1a4761a15b84725491080ffda8fd2df97 Author: dilanbhalla Date: Tue Jun 30 18:04:41 2020 -0700 moved library to experimental commit e1130a2bfa3fbb012d72187fdfa487ff9f5eab84 Author: dilanbhalla Date: Tue Jun 30 17:58:24 2020 -0700 moved privatedata to experimental commit 3fdd11a9b50616e2ca91d1241444fd9c619e8c1c Author: dilanbhalla Date: Tue Jun 30 17:22:29 2020 -0700 scanf fixes, still need to update qhelp file commit e9777913a3530a529102e1cba758933c676a3bee Merge: 286c09183 8bdcc47a5 Author: Robert Marsh Date: Tue Jun 30 16:17:37 2020 -0700 Merge pull request #3856 from geoffw0/qldoc5follow C++: Make getSecureAlgorithmRegex() work as expected. commit 6592f8c1bb38917f17d5cdca3614129b71d7ab8f Author: Dave Bartolomeo Date: Tue Jun 30 17:33:52 2020 -0400 C++: QLDoc cleanup This PR just fixes a few bits of PR feedback from my previous QLDoc PR. commit cff0f48d344569dc436e80d413d21c2af85cbb3f Author: Jonas Jensen Date: Mon Jun 29 18:57:04 2020 +0200 C++: Work around join-order issue in flow-through In this non-linear recursion, a `#prev` relation was joined earlier than the `#prev_delta` relation. As a result, each iteration of the predicate processes every tuple from previous iterations. This quadratic behavior caused severe slowdowns on oneapi-src/oneDNN. commit f462156cdf3ac2f6b862914d987d4fca36952e6a Author: dilanbhalla Date: Tue Jun 30 12:09:50 2020 -0700 private data file/buffer write commit 17beb2d86722d73cde7da891a27bac380d17e44b Author: Jonas Jensen Date: Mon Jun 29 18:56:41 2020 +0200 C++: Remove big-step relation in flow-through code This relation was originally introduced to improve performance but may no longer be necessary. The `localFlowStepPlus` predicate had an explosion of tuples on oneapi-src/oneDNN for C++. commit 8bdcc47a504d027dc8d9c7381001fc618727a250 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 30 17:43:52 2020 +0100 C++: Add a test. commit fa8b278332f4d1fb22e9bdd8c6c361678666ae3d Author: Jonathan Leitschuh Date: Tue Jun 30 11:57:17 2020 -0400 Add jOOQ methods as SQL Injection Sinks commit 54b8f8e662cee01b2254c039a852bddc0f071bbc Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 30 16:51:16 2020 +0100 C++: Make getSecureAlgorithmRegex() return a single regexp as expected, and as getInsecureAlgorithmRegex() does. commit 286c09183feb22b87ea580d2551c1aa16e539371 Merge: cb39525f3 cf75397ef Author: Mathias Vorreiter Pedersen Date: Tue Jun 30 17:44:59 2020 +0200 Merge pull request #3837 from geoffw0/qldoc5 C++/Java: Update QLDoc and terminology in Encryption.qll commit cb39525f3bbe8c0dceeceb6f99930f1acbcb3980 Merge: 8ff8b3e22 09e13ca2f Author: Mathias Vorreiter Pedersen Date: Tue Jun 30 17:44:32 2020 +0200 Merge pull request #3847 from nickrolfe/71-this-followup C++: make MemberFunction::getTypeOfThis() return PointerType commit f1179cc202888984b81f85ef03aa145cc2780e17 Author: Tom Hvitved Date: Tue Jun 30 17:06:45 2020 +0200 Java: Follow-up changes commit de3dc734ff943d802829b211d5dad82d24deb6d2 Author: Tom Hvitved Date: Tue Jun 30 17:04:38 2020 +0200 C++: Follow-up changes commit 1fa58bd82d080e3c71487cef563fde80c284dc8e Author: Tom Hvitved Date: Tue Jun 30 16:59:42 2020 +0200 Data flow: Sync files commit 6bcb8a3a5b16b53da0545a99d214f7b2fc0ac434 Author: Tom Hvitved Date: Tue Jun 30 16:58:12 2020 +0200 C#: Replace `getErasedRepr()` and `getTypeBound()` with `getNodeType()` commit 8ff8b3e22cfff5323d84fbebe2395f0322156d84 Merge: 63de58c55 5a929def9 Author: James Fletcher <42464962+jf205@users.noreply.github.com> Date: Tue Jun 30 16:21:49 2020 +0100 Merge pull request #3852 from jf205/1.24-mergeback 1.24 -> master mergeback commit 301679810115ea0a67fb4c2addcf984d5bd3fa5a Merge: c57c016ce d297ce227 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 30 16:20:41 2020 +0100 Merge branch 'master' into copymove commit c57c016ced858a542d8b3ba1afed2715da4aee3e Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 30 16:16:00 2020 +0100 C++: Go the other way. commit 63de58c5571fdb2792df60942aa657c4894254cd Merge: 989b57c51 47bb007b9 Author: Jonas Jensen Date: Tue Jun 30 17:09:15 2020 +0200 Merge pull request #3819 from dbartol/codeql-c-analysis-team/40/2 C++: More IR QLDoc (including `Opcode.qll`) commit 989b57c51df4050b534cb5b51913d49c5e79f608 Merge: 4a5299e36 7e97bd1d3 Author: yoff Date: Tue Jun 30 16:48:14 2020 +0200 Merge pull request #3822 from tausbn/python-document-internal-ast-classes Python: Document internal AST classes. commit 5a929def95dba8e322d1dfc992ff16d1d6d79cac Merge: 4a5299e36 d5c643324 Author: james Date: Tue Jun 30 15:44:29 2020 +0100 Merge branch 'rc/1.24' into 1.24-mergeback commit d5c6433245cde4e2749f2d9e91d9ceb9d255d012 Merge: c2de54f5c 472501bd6 Author: James Fletcher <42464962+jf205@users.noreply.github.com> Date: Tue Jun 30 15:43:04 2020 +0100 Merge pull request #3849 from asger-semmle/js/vue-support-rc JS: Add Vue to list of supported frameworks commit 4a5299e368ca9a4678744ac9c076f50f96149548 Merge: 224289c55 3bdfab8d8 Author: Jonas Jensen Date: Tue Jun 30 16:21:37 2020 +0200 Merge pull request #3843 from geoffw0/qldoc6 C++: Bit more QLDoc commit ed48efe5b49a8707fc613ffd61400865dcf8ec47 Author: Erik Krogh Kristensen Date: Tue Jun 30 15:52:08 2020 +0200 recognize access to a query object through function calls commit 224289c55ff70d08c5ca6e1ef7b43f003e3be56a Merge: ab876b8b7 62d56a3d7 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Tue Jun 30 14:45:41 2020 +0100 Merge pull request #3845 from max-schaefer/js/walk-sync Approved by asgerf commit cf75397ef108ed07f251f48c10058ae7a147b532 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 30 14:33:05 2020 +0100 Java: Rename tests. commit 3bdfab8d8c44d82202b24b71483853d95416df72 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 30 14:12:34 2020 +0100 C++: Autoformat. commit 4dabbac19b514422af6ff78ab3d0fc80312b2905 Author: Anders Schack-Mulligen Date: Tue Jun 30 14:57:56 2020 +0200 Dataflow: Add documentation language maintainers. commit 472501bd6fc21ae84779621a270e57ddaeeb3f14 Author: Asger Feldthaus Date: Mon Jun 29 16:09:17 2020 +0100 JS: Add Vue to list of supported frameworks commit 09e13ca2f283efeb18c459e2c52f238f8b8a363a Author: Nick Rolfe Date: Tue Jun 30 13:45:21 2020 +0100 C++: make MemberFunction::getTypeOfThis() return PointerType The dbscheme technically allows for any Type, but in practice it will always be a PointerType, so this should make it easier for users to understand. commit ab876b8b785ac77312d5bb1983ac552fc704e848 Merge: 42bca1a3f 4b6908c5b Author: Matthew Gretton-Dann <53790742+matt-gretton-dann@users.noreply.github.com> Date: Tue Jun 30 13:31:14 2020 +0100 Merge pull request #3814 from nickrolfe/71-this C++: add MemberFunction::getTypeOfThis() commit 42bca1a3fa8067e45bfc983aa86dd340dd1a8414 Merge: c850938af 1e5f84616 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Tue Jun 30 13:20:14 2020 +0100 Merge pull request #3824 from asger-semmle/js/static-regexp-capture-group-step Approved by erik-krogh, esbena commit c850938af0db731214dfd51b4a873a126a8a6035 Merge: 15a0297ca 3e616e998 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Tue Jun 30 13:16:42 2020 +0100 Merge pull request #3833 from asger-semmle/js/vue-class-component Approved by erik-krogh commit 15a0297ca2e8ba43684f99f921d82b51e947c498 Merge: 4b7d60a21 cb12d894a Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Tue Jun 30 13:14:25 2020 +0100 Merge pull request #3834 from asger-semmle/js/vue-classification Approved by erik-krogh commit 5c11c9ee4303d8c07757e8b8537e97b35baeb675 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 30 12:56:08 2020 +0100 Java: Rename additional private predicates. commit f8425b8a58674cd76d0f3a2ae971f423174a23af Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 30 12:54:21 2020 +0100 Java: Update uses. commit db0500b9ef650b5c3c41f8d92afe8c84342143ae Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 30 12:49:56 2020 +0100 Java: Direct port of changes to Java. commit 51db1475ff47cb94f1ac153d6e50c333a86f9707 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 30 12:42:12 2020 +0100 Apply suggestions from code review Co-authored-by: Jonas Jensen commit 4c088b19adf69c7b2453215484b92934e7e57ff1 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 30 12:38:02 2020 +0100 C++: Delete outdated bit. commit 4b7d60a217a6152d8cde5cebc0a6be65b3167088 Merge: c52f68e33 c7f67fafd Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Tue Jun 30 12:33:35 2020 +0100 Merge pull request #3803 from esbena/js/more-fs-promises Approved by erik-krogh commit bbb9396300216ee4bea707cee215b9e7ce2b6b4f Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 30 12:18:59 2020 +0100 C++: Improvement in Overflow.qll. commit 0ee73cce517baa4a34f807a9e5a4110aae28fce9 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 30 12:16:20 2020 +0100 Update cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll Co-authored-by: Jonas Jensen commit de25bc6c7873fd6ae409b1095c7d3daacd75b6eb Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 30 12:14:56 2020 +0100 C++: Improvement in Synchronization.qll. commit 3a3cc9a60adf7380a218d0d7c77a5c6ee9e427ee Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 30 12:06:18 2020 +0100 C++: Autoformat. commit 62d56a3d7cae253438c9b7c1b648d16333044f8a Author: Max Schaefer Date: Tue Jun 30 11:57:16 2020 +0100 JavaScript: Fix module name for `walk-sync` package. commit 80981ec8f562d64301053c5c8929b6df39f99f16 Author: Esben Sparre Andreasen Date: Tue Jun 30 12:01:02 2020 +0200 Update UnsafeHtmlExpansion-transformed.html commit 7e97bd1d369c5ddc1da9f9a770e9493bd8c832f8 Author: Taus Brock-Nannestad Date: Tue Jun 30 11:36:26 2020 +0200 Python: Address review comments. commit c52f68e337ec1d1d7f6c6395e7400d808ba26a2c Merge: f79299883 55883f60f Author: Mathias Vorreiter Pedersen Date: Tue Jun 30 10:33:29 2020 +0200 Merge pull request #3808 from geoffw0/qldoc4 C++: Yet more QLDoc commit 5c51bb79790404d05463366e1f17cd6478fdbab7 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 30 09:32:48 2020 +0100 C++: QLDoc Literal.qll. commit 7a2c65f63837bb10839a3287e0ce573f7f5af8b6 Author: Asger Feldthaus Date: Tue Jun 30 09:25:06 2020 +0100 JS: Fix virtual source root in AutoBuildTest commit f79299883a0406ed258e62d6025cb9e0b3db4294 Merge: 13cb853af acee9eb7a Author: Jonas Jensen Date: Tue Jun 30 10:21:55 2020 +0200 Merge pull request #3831 from MathiasVP/remove-abstract-decl-var-call C++: Remove abstractness from DeclarationEntry, AccessHolder and Call commit 40e02bee5360ce940a8a13c5d526c4a4d2b60ac0 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 30 09:19:41 2020 +0100 C++: QLDoc Overflow.qll. commit 010232254461534e3bf66977281198552bb283c9 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 30 09:10:21 2020 +0100 C++: QLDoc FunctionWithWrappers.qll. commit 47bb007b9a7b605a874075314f24844239cbe0fc Author: Jonas Jensen Date: Tue Jun 30 09:56:39 2020 +0200 C++: Autoformat fixups commit 13cb853af59dbfeed056d550757ee4d61de3b50c Merge: b57cfc965 aff0e0eb2 Author: Anders Schack-Mulligen Date: Tue Jun 30 09:46:02 2020 +0200 Merge pull request #3294 from ggolawski/ognl-injection CodeQL query to detect OGNL injections commit acee9eb7aba5fd8b746455fc23431f486e0259b4 Author: Mathias Vorreiter Pedersen Date: Tue Jun 30 09:19:47 2020 +0200 C++: Add comment to pseudo-abstract predicates commit 50709b235ec5d3b552c05ddedf689a8bbb936589 Author: Mathias Vorreiter Pedersen Date: Tue Jun 30 09:18:52 2020 +0200 C++: Replace implication with disjunction in charpred for Call commit c7f67fafd9ff21d9f5f509267c4144c823d4d7c8 Author: Esben Sparre Andreasen Date: Thu Jun 25 13:11:04 2020 +0200 JS: support additional promisification of the fs-module members commit 667bb323ac31d66d8a3b4c28b5ba87f3c5dcdb33 Author: Mathias Vorreiter Pedersen Date: Tue Jun 30 08:40:46 2020 +0200 C++: Rename union types to follow the naming convention of IPA types (and make them private) commit 3efe1a9d10330ca7984e9fb1cfe7f6b5a85e5759 Author: Tom Hvitved Date: Tue Jun 30 08:31:30 2020 +0200 C#: Remove unused `viableImpl` predicate commit b57cfc965aceeae8f05633906875c93904867507 Merge: d297ce227 0bd81eb4b Author: Tom Hvitved Date: Tue Jun 30 08:28:27 2020 +0200 Merge pull request #3804 from aschackmull/dataflow/dispatch-refactor Dataflow: Refactor dispatch with call context. commit 7a023a65b022225c6402d96eb509d8778454a54f Author: Gavin Lang Date: Tue Jun 30 15:33:05 2020 +1000 Grammatical issues in Encryption using ECB.qhelp commit 42657dbe3f26de8d4e2c9c5631a34a95221e4277 Author: Dave Bartolomeo Date: Mon Jun 29 14:30:12 2020 -0400 C++: Miscellaneous IR QLDoc commit 182e4ce7274c7c9965df49fdc64cfa7ac09b67a5 Author: Asger Feldthaus Date: Mon Jun 29 19:10:28 2020 +0100 JS: Autoformat commit 1fa38474e9c85d968dc1f6e375246d413886ed1b Author: Dave Bartolomeo Date: Mon Jun 29 14:09:53 2020 -0400 C++: Autoformat commit 4b6908c5bf850e4bd32fd32dfb7dd5b8a5d91678 Author: Nick Rolfe Date: Mon Jun 29 18:05:58 2020 +0100 C++: test template classes with MemberFunction::getTypeOfThis() commit fc69c16ba605552ace47952fabe7ca3eec9aafd7 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Jun 29 17:38:59 2020 +0100 C++: Deprecate some old terminology. commit 71492f90acd22ad0a33af313c29f64a7644e0c9e Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Jun 29 17:29:13 2020 +0100 C++: QLDoc Encryption.qll, improve existing QLDoc, and update terminology. commit c52653270ea618746f11e1629f827bbafb8c7567 Author: Dave Bartolomeo Date: Mon Jun 29 12:14:54 2020 -0400 C++: QLDoc for `IRConfiguration.qll` commit 87f0b0ef97b35e8154c6a144508143135a49e708 Author: Dave Bartolomeo Date: Mon Jun 29 12:10:03 2020 -0400 C++: QLDoc for `EdgeKind.qll` commit 440ea6a069e1ff68120d3e32b3669d513a1ab1e8 Author: Dave Bartolomeo Date: Mon Jun 29 12:05:56 2020 -0400 C++: QLDoc for `PrintIR.qll` commit 2043d9c7c4cf07ccd40fa7c0ecbe8f9bfaff8ef9 Author: Dave Bartolomeo Date: Mon Jun 29 11:57:18 2020 -0400 C++: QLDoc for `Operand.qll` commit ead2a143e023c44b51b5a67ecedbf311232fb3b8 Author: Dave Bartolomeo Date: Mon Jun 29 11:35:13 2020 -0400 C++: QLDoc for IRVariable Moved a couple of predicates that were only needed by IR construction into `TranslatedElement.qll` commit 1423ea0591782d1c16553533d92a0715ef8d32d5 Author: Dave Bartolomeo Date: Sun Jun 28 09:57:31 2020 -0400 C++: More `IR.qll` QLDoc commit 98348a935339eb9c3474065f74ac4dc9bd2f64e5 Author: Dave Bartolomeo Date: Sun Jun 28 09:55:38 2020 -0400 C++: QLDoc for `IR.qll` commit 88f89b3334a44bcfeeabfe2ebcad60c6d8a1de46 Author: Dave Bartolomeo Date: Sun Jun 28 09:33:16 2020 -0400 C++: QLDoc for `IRFunction.qll` commit d0af9f5808dd325a32d55abae249ee0e67827f80 Author: Dave Bartolomeo Date: Sun Jun 28 09:31:33 2020 -0400 C++: QLDoc all of `IRBlock.qll` commit 77bf564136323d05f522f9e84eb7c4806dbd25fe Author: Dave Bartolomeo Date: Fri Jun 26 17:44:51 2020 -0400 C++: Finish `Instruction.qll` QLDoc commit 6de3d5bc3dcbe4b7d17f06c95f1ae5e375ef4975 Author: Dave Bartolomeo Date: Mon Jun 29 12:41:36 2020 -0400 C++: Change opcode QLDocs to refer to instruction QLDocs As discussed in today's C++ analysis team meeting. `Opcode` is rarely used directly, so we'll just refer to the documentation for the corresponding `Instruction` class. I've preserved the script in case we want to do a bulk change of all of the `Opcode` comments, but I don't expect it will be needed if we just add a new `Opcode` or two. commit a8a7df4e5c75a5c6c888ebd313f171f75b5e2823 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Jun 29 17:08:44 2020 +0100 C++: QLDoc SensitiveExprs.qll. commit e2e5e9b2a914860ab1e539c9093d736d375ac52d Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Jun 29 16:55:14 2020 +0100 C++: QLDoc Synchronization.qll and improve existing QLDoc. commit cb12d894a6a3831521cdfa52680b5ef388ee7e22 Author: Asger Feldthaus Date: Mon Jun 29 15:54:06 2020 +0100 JS: Add test commit 326c7af4ebdda726c2adf6c0c10c0ea89126c8ba Author: Asger Feldthaus Date: Mon Jun 29 15:49:07 2020 +0100 JS: Fix incorrect classification of Vue files commit d297ce22791d8c64eaadc42f5ba45304af61dfad Merge: b53b90501 f5f30ce25 Author: Anders Schack-Mulligen Date: Mon Jun 29 16:42:36 2020 +0200 Merge pull request #3436 from artem-smotrakov/revocation-checking Java: Added a query for disabled certificate revocation checking commit b53b90501b52249bba8b4a2c8d13ca790687e8b9 Merge: da8725aa5 0779aab28 Author: Anders Schack-Mulligen Date: Mon Jun 29 16:39:39 2020 +0200 Merge pull request #3550 from luchua-bc/java-unsafe-cert-trust Java: CWE-273 Unsafe certificate trust commit 0bd81eb4b8513b9595bb02240c725cb7e1b71ce8 Author: Anders Schack-Mulligen Date: Mon Jun 29 16:22:58 2020 +0200 Dataflow: Fix reference to viableCallable. commit 55883f60f76a6d9ab0f2da1b49fd92a775c1b729 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Jun 29 13:24:19 2020 +0100 C++: Autoformat. commit da8725aa5ccb429c2e224204d39317e52b0222ab Merge: b3e68ef81 bb06014f3 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Mon Jun 29 14:46:51 2020 +0100 Merge pull request #3823 from dellalibera/js/fancy-log Approved by erik-krogh commit b3e68ef81cf5716bf8f27ddef44f21fbc2f2a0d7 Merge: e00a8f767 27b2c0269 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Mon Jun 29 13:53:10 2020 +0100 Merge pull request #3806 from erik-krogh/moreDownloads Approved by asgerf commit b05942b59920cb2f607b9ee9eb7bd2c699065a74 Author: Asger Feldthaus Date: Mon Jun 29 13:45:01 2020 +0100 JS: Add HTML file example commit 3938856e6163d622e9914fde46fecaba28fb4f9e Author: Asger Feldthaus Date: Mon Jun 29 13:42:55 2020 +0100 JS: Make this work in qltest commit 1a16d7339a57c2aec8da49abd9f0a4c5175a3d68 Author: Asger Feldthaus Date: Mon Jun 29 13:42:22 2020 +0100 JS: Set SourceType correctly commit 441d4c077a2d4b6c3589e3da0069cd040b52b420 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Jun 29 13:13:00 2020 +0100 Update cpp/ql/src/semmle/code/cpp/exprs/Cast.qll Co-authored-by: Jonas Jensen commit b469d55d1726e524f3183b193dab20a181dcd011 Author: Taus Brock-Nannestad Date: Mon Jun 29 13:32:36 2020 +0200 Python: Fix a few things in `Stmts.qll`. commit ab1dc64eeae1560ed3e35468e685311c14936fbd Author: Nick Rolfe Date: Mon Jun 29 11:54:28 2020 +0100 C++: expand qldoc on MemberFunction::getTypeOfThis() commit fcb365188beeb04943a9024bf7649272259675aa Author: Asger Feldthaus Date: Mon Jun 29 09:51:03 2020 +0100 JS: Add change note commit e46a9dac65605421b29e823224a804ae2c15dcc2 Author: Asger Feldthaus Date: Mon Jun 29 09:27:38 2020 +0100 JS: Count lines of code correctly commit 9c65318f992f4c50c53008d004e23810472dafa3 Author: Asger Feldthaus Date: Mon Jun 29 08:23:34 2020 +0100 JS: Extract TypeScript in HTML files to a snippet in virtual source root commit da58fb5e62378874f2a6d25879ba2c9dfbd8bda9 Author: Asger Feldthaus Date: Fri Jun 26 22:54:44 2020 +0100 JS: Resolve relative imports across real and virtual source roots commit d3b9ebe1d2200b365e184515e121cc91ddd2a535 Author: Asger Feldthaus Date: Mon Jun 29 08:22:54 2020 +0100 JS: Perform glob matching across source roots commit 1297d0f4146353ed81d66e125f1558160f302a0b Author: Asger Feldthaus Date: Fri Jun 26 21:48:18 2020 +0100 JS: Extract HTML before TypeScript commit 2c1567aedd6f409020c531197679bd84a9d76c1d Author: Asger Feldthaus Date: Fri Jun 26 21:26:07 2020 +0100 JS: Don't extract TypeScript from HTML commit 805deb13c01b59ea93aa0ac24a5b10189e2d90ce Author: Asger Feldthaus Date: Fri Jun 26 21:18:01 2020 +0100 JS: Fix whitespace commit 1e5f8461680cf3aa292630b3555923cf44c67b9b Author: Asger Feldthaus Date: Mon Jun 29 09:31:56 2020 +0100 JS: Use StringReplaceCall commit 6b27652b99c217d3302b6cc274c6dc73f942555c Author: Mathias Vorreiter Pedersen Date: Mon Jun 29 10:27:16 2020 +0200 C++: Remove abstractness from a couple of AST classes commit 27b2c0269354f9e72176ba843c8e887f48d87965 Author: Erik Krogh Kristensen Date: Mon Jun 29 09:58:59 2020 +0200 remove todo comment Co-authored-by: Asger F commit 8632c2a3b269cd831fcb7eb1184772c1ab4fb67f Author: Asger Feldthaus Date: Fri Jun 26 21:08:20 2020 +0100 JS: Factor out VirtualSourceRoot commit bfedcb01c4749a68f98c611d0dac47e806222713 Author: Asger Feldthaus Date: Fri Jun 26 13:20:11 2020 +0100 JS: Make TypeScript aware of custom extractor extensions commit d55e3300f335b30cdfac81d32186175e274945e0 Author: Asger Feldthaus Date: Fri Jun 26 13:13:47 2020 +0100 JS: Bundle FileExtractors into a class commit ea6b99e7263b93d8a53d0659a2f43fd7928173a2 Author: Asger Feldthaus Date: Fri Jun 26 13:04:54 2020 +0100 JS: Add shouldExtract predicate commit 164a18f02df0fbe4d138bba21ed8bc58c95f9b77 Author: Asger Feldthaus Date: Fri Jun 26 13:03:17 2020 +0100 JS: Factor out extractFiles commit da3d1a3b5f47c4cd92a65d690220c6ccd3754984 Author: Asger Feldthaus Date: Wed Jun 24 13:28:11 2020 +0100 JS: Recognize 'lang' attribute of script tags commit bdb7e3def35c75c4139512b73102cfb8749c04a0 Author: Asger F Date: Mon Jun 29 07:55:15 2020 +0100 Apply suggestions from code review Co-authored-by: Erik Krogh Kristensen commit 03c91a66c59a6c0da752a1be6e58ffe3dafec913 Author: Asger Feldthaus Date: Mon Jun 29 07:52:25 2020 +0100 JS: Update expected output commit bb06014f3db084e288ed4c5fcf2db4a256fab60c Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Sun Jun 28 22:02:02 2020 +0200 Add fancy-log commit ce32d646dc31d9f68e3aee67924032e6b99f4140 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun Jun 28 21:58:45 2020 +0200 Update javascript/ql/src/semmle/javascript/frameworks/Logging.qll Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> commit 5fbf30590e0aa0aaf0611b9223306bae0bdd044a Author: Mathias Vorreiter Pedersen Date: Sun Jun 28 20:21:51 2020 +0200 C++: Accept test changes. commit 5744356dbc1afea9d9b98444dbeb5aa98dc1105c Author: Taus Brock-Nannestad Date: Sun Jun 28 14:55:45 2020 +0200 Python: Add a bunch more `toString` docs. commit e72e662f68af149f1cdfda3df8139d480c352d2c Author: Taus Brock-Nannestad Date: Sun Jun 28 14:41:45 2020 +0200 Python: Autogenerate QLDoc for `toString` AST methods. Only adds these for the methods that do not `override` other methods (as these presumably have their own `toString` documentation). commit 9c0f877172f41b80eba650afbdc4cda1248c2872 Author: Mathias Vorreiter Pedersen Date: Sun Jun 28 11:28:43 2020 +0200 C++: Keep old instruction -> instruction flow in simpleInstructionLocalFlowStep. This means we don't have to add general operand -> instruction to the simpleLocalFlowStep relation, which seems to add a 10% performance regression. commit 9ca25d5bef94f322f13344323888a8b9daa557e2 Author: Asger Feldthaus Date: Sun Jun 28 01:38:59 2020 +0100 JS: Support .hash extraction via a few more methods commit 19db418395bf2ead576c527482a47803543d9cda Author: Asger Feldthaus Date: Sun Jun 28 01:26:11 2020 +0100 JS: Add missing store step in Xss query commit 3e616e998ead0f3fb9e8d7d972881e0bd1a5bdec Author: Asger Feldthaus Date: Sat Jun 27 21:30:25 2020 +0100 JS: Add test commit 84d21074e5d0585af5139e38c628b1b84bd55171 Author: Asger Feldthaus Date: Sat Jun 27 21:14:14 2020 +0100 JS: Support Vue class components commit aff0e0eb25052f4af981d5c4d6909c781ca1f9a3 Author: Grzegorz Golawski Date: Sat Jun 27 18:30:36 2020 +0200 Cleanup according to review comments. commit f5f30ce25ef51bd0791ecfb0103f844c3379b1b0 Author: Artem Smotrakov Date: Sat Jun 27 11:34:31 2020 +0300 Java: Simplified the query for disabled certificate revocation checking Removed a dataflow cofiguration for setting a revocation checker. Instead, the query just checks if addCertPathChecker() or setCertPathCheckers() methods are called. commit a2fa03e4f5d2f1d2599d95092a1bcbe568b93fac Author: Artem Smotrakov Date: Mon Jun 22 18:16:07 2020 +0300 Java: Improved the query for disabled certificate revocation checking - Added a taint propagation step for List.of() methods - Added a testcase with one of the List.of() method - Simplified conditions - Fixed typos commit 06e3f101ce0edc604f36f7c9cad32f499ec23a8f Author: Artem Smotrakov Date: Thu Apr 30 09:13:48 2020 +0200 Java: Added a query for disabled certificate revocation checking - Added experimental/Security/CWE/CWE-299/DisabledRevocationChecking.ql The query looks for PKIXParameters.setRevocationEnabled(false) calls. - Added RevocationCheckingLib.qll - Added a qhelp file with examples - Added tests in java/ql/test/experimental/Security/CWE/CWE-299 commit ac5b9cd1684cb523abf1b116a6b1135b263e9a5e Author: Asger Feldthaus Date: Fri Jun 26 23:15:04 2020 +0100 JS: Autoformat commit 4dcdd8a0ee6dc8dd82b5f1906b59ee3b3d49dd5b Author: Dave Bartolomeo Date: Fri Jun 26 17:25:30 2020 -0400 C++: Add last remaining QLDoc to `Opcode.qll` commit bdf121f3b846d2c8157e6a9ac861aa8a6c766fa5 Author: Dave Bartolomeo Date: Fri Jun 26 16:04:33 2020 -0400 C++: Update opcode QLDoc script to handle abstract base classes This auto-generates even more QLDoc for `Opcode.qll` commit 9135bbd5c8963a145832db9f22a916651eb08354 Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Fri Jun 26 21:33:52 2020 +0200 JS: model fancy-log (and recognize the 'dir' log level) commit 6707e3424d8c573e7c4fe8a0c594c1fcf15a47fb Author: Asger Feldthaus Date: Fri Jun 26 20:21:56 2020 +0100 JS: Prevent bad join ordering commit 24daf2c4d104adb44aca978460a9a3edb995e589 Author: Taus Brock-Nannestad Date: Fri Jun 26 21:15:30 2020 +0200 Python: Document internal AST classes. We already document these in the classes that override them, so I simply added a pointer to this information. commit 06dd3ab2cae36a077398e5de467b47fde724f6c8 Author: Asger Feldthaus Date: Thu Jun 25 17:09:27 2020 +0100 JS: Propagate into RegExp.$x commit 17af8f76506c3755e0c69520537d18fdab3c3db4 Author: Asger Feldthaus Date: Wed Jun 24 15:49:23 2020 +0100 JS: Add test for taint propagating into RegExp.$1 commit e00a8f76708e97b2dcf7fb7e6334c5568921da45 Merge: 3aefb7fad a22fb7662 Author: Dave Bartolomeo Date: Fri Jun 26 13:52:16 2020 -0400 Merge pull request #3815 from jbj/getAPrimaryQlClass C++: getCanonicalQLClass -> getAPrimaryQlClass commit 5f290520ab2e0c347e5a603b386f8da2c7b2e71b Author: Dave Bartolomeo Date: Fri Jun 26 13:45:41 2020 -0400 C++: Accept test diffs due to opcode rename commit 3aefb7fad916be03b2d066b5f7f70feffe4538e0 Merge: b015c735d e4fe236d3 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Fri Jun 26 17:05:45 2020 +0100 Merge pull request #3613 from erik-krogh/Reassigned Approved by asgerf commit 281985b845a063e1a59b1a6051f9ed934ac45f70 Author: Dave Bartolomeo Date: Fri Jun 26 11:42:32 2020 -0400 C++: Sync `Opcode.qll` QLDoc with `Instruction.qll` QLDoc For every concrete `Opcode`, there is a corresponding `Instruction` class. Rather than duplicate all of the QLDoc by hand, I wrote a quick Python script to copy the QLDoc from `Instruction.qll` to `Opcode.qll`. I don't expect that we will need to do this often, so I'm not hooking it up to a PR check or anything like that, but I did commit the script itself in case we need it again. commit 023e1dc0a29d8028dddd468631dd3725b841158c Author: Dave Bartolomeo Date: Fri Jun 26 11:39:10 2020 -0400 Instruction and opcode cleanup - Renamed `DynamicCastToVoid` to the more descriptive `CompleteObjectAddress` - Split verbose description from summary in a few Instruction QLDoc comments. - Added `Instruction` classes for the few remaining `Opcode`s that didn't have one. - Removed a use of "e.g." commit a22fb7662e293bfa2a26337731d7dd6743bb6772 Author: Jonas Jensen Date: Fri Jun 26 16:57:06 2020 +0200 C++: Autoformat fixup commit 7443c9c5adba6044f24106fd492dc00a50934fc0 Author: Marcono1234 Date: Fri Jun 26 16:40:19 2020 +0200 Fix outdated query console link #3546 changed the query but did not adjust the query link. Additionally the old query could not be re-run because some of the projects it targeted (gradle/gradle and eclipse-cdt/cdt) cannot be queried currently. It now queries all available demo projects of the query console instead. commit 0ae5fb035779cb0477e934cae9e3169d38625363 Author: Nick Rolfe Date: Fri Jun 26 15:35:55 2020 +0100 C++: auto-format test query commit 309a8e60c866be724ca419001e9f4cb6d89fe7ff Author: Nick Rolfe Date: Fri Jun 26 13:48:10 2020 +0100 C++: add more test cases for the type of `this` commit e79625ed1464daaf58f4a361d442d237127b6e23 Author: Nick Rolfe Date: Fri Jun 26 13:41:53 2020 +0100 Accept suggested qldoc change Co-authored-by: Dave Bartolomeo commit 9e9d69238ac55f3eaccb59f8f425ed9fcfeef145 Author: Nick Rolfe Date: Thu Jun 25 16:55:13 2020 +0100 C++: add test for MemberFunction::getTypeOfThis() commit 8bd3be6e7b7acca0d9ce3dadcd007b92a74d6717 Author: Nick Rolfe Date: Thu Jun 25 15:43:18 2020 +0100 C++: add MemberFunction::getTypeOfThis() commit ca25971955d3717d3e7ba5f774d339942c9d4aa2 Author: Nick Rolfe Date: Thu Jun 25 15:10:34 2020 +0100 C++: upgrade script for member_function_this_type commit 3b15d39ec620da42f195597c33ca36da0c27965f Author: Nick Rolfe Date: Thu Jun 25 11:13:48 2020 +0100 C++: update stats for new member_function_this_type table commit 133838dbf3f6125ee8a3c8ec142c1fd0060ac77a Author: Nick Rolfe Date: Wed Jun 10 18:27:53 2020 +0100 C++: update tests to expect type of `this` commit d1d7fac4cac55c1b06fbca1fe450dc24b2eaf17a Author: Nick Rolfe Date: Wed Jun 10 18:27:50 2020 +0100 C++: add member_function_this_type to dbscheme commit b015c735d06474c46d7175b4d4519050129cd360 Merge: 1b4df5742 640c194c9 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Fri Jun 26 14:20:14 2020 +0100 Merge pull request #3809 from max-schaefer/util-deprecate Approved by asgerf commit 1b4df57426ae910cde1bc417f42ca03e5212003a Merge: beb66299e e28284bd0 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Fri Jun 26 14:18:35 2020 +0100 Merge pull request #3731 from asger-semmle/js/monorepo-bugfixes Approved by erik-krogh commit 0b050204ad3b7d8cf03a03fe695278a5eaa54f24 Author: Erik Krogh Kristensen Date: Fri Jun 26 15:07:12 2020 +0200 add missing dot in qldoc commit f48948c604bfde1fcc87e7e255f9963439d9dfd3 Author: Dave Bartolomeo Date: Fri Jun 26 09:04:37 2020 -0400 C++: Opcode cleanup - Remove unused `MemoryAccessOpcode` - Make `OpcodeWithCondition` private - Add QLDoc for `Opcode` module commit beb66299e9c86b1312356743c79baef2181a216d Merge: 11c702331 7e3f2dbe4 Author: Mathias Vorreiter Pedersen Date: Fri Jun 26 14:04:48 2020 +0200 Merge pull request #3796 from dbartol/codeql-c-analysis-team/40/2 C++: QLDoc for all of `Instruction.qll` commit e4fe236d373142cda9c0707a78c1c8d6d9d6d0c8 Author: Erik Krogh Kristensen Date: Fri Jun 26 13:59:06 2020 +0200 autoformat commit 795c5784b0523d1e6914ab7e592f2abeaece1722 Author: Tom Hvitved Date: Wed May 6 11:22:35 2020 +0200 C#: Precise data flow for collections commit 11c702331a0fc7ca4d616fac8bf37eb94aa6fcb0 Merge: 3f0975f5a 9a1f90912 Author: Dave Bartolomeo Date: Fri Jun 26 07:38:10 2020 -0400 Merge pull request #3795 from rdmarsh2/rdmarsh/cpp/add-qldoc-3 C++: QLDoc for PrintAST and AST-based range analysis commit 3f0975f5a11c230a419866c64bbde2c5d979f4ef Merge: e5d23b208 4dbc8e515 Author: Rasmus Wriedt Larsen Date: Fri Jun 26 13:30:45 2020 +0200 Merge pull request #3770 from tausbn/python-add-a-bunch-of-documentation Python: Add a bunch of documentation. commit c1b26d71c3d3ad2a2719a19ea92e82a6674f582c Author: Jonas Jensen Date: Fri Jun 26 13:18:14 2020 +0200 C++: getCanonicalQLClass -> getAPrimaryQlClass Also updated the QLDoc for `getAPrimaryQlClass` to match the Go version. commit 64af5f585c10f8bd615bccec7f5814a91d4c2873 Author: Rasmus Lerchedahl Petersen Date: Fri Jun 26 13:18:07 2020 +0200 Python: Update status description commit f84adb3c26fc2ae6e50a2144dd2dbce1525c65c5 Author: Rasmus Lerchedahl Petersen Date: Fri Jun 26 13:09:35 2020 +0200 Python: stub for `clearsContent` also remove all `CastNode`s (seems to help) commit e5d23b20824af6e3fc0be47da16b77a1c4fbd05a Merge: 9d8052a43 b164f2695 Author: Taus Date: Fri Jun 26 13:05:28 2020 +0200 Merge pull request #3801 from RasmusWL/python-3521-revived Python: Add support for detecting XSLT Injection (#3521 revived) commit 640c194c92f87e1d51159903069577c7d6ecd1b7 Author: Max Schaefer Date: Fri Jun 26 09:55:38 2020 +0100 JavaScript: Model `util.deprecate` as a pre call-graph step. commit 712a2164618c29e03683d36b1537e9f1e0e917d2 Author: Max Schaefer Date: Fri Jun 26 09:56:02 2020 +0100 Add self-verifying type-tracking tests. commit 248717473e6e8265e255c2a326ce342c910693c7 Author: Rasmus Lerchedahl Petersen Date: Fri Jun 26 12:25:17 2020 +0200 Python: quick status added to `readme.md` commit b164f2695dd592530e07b49a94535a6cfc1acf0f Author: Rasmus Wriedt Larsen Date: Fri Jun 26 12:08:12 2020 +0200 Python: One more minor doc fix from review commit 08384e30af15e69ebfa1ae49e5e78d65f4752559 Author: Rasmus Wriedt Larsen Date: Fri Jun 26 12:06:31 2020 +0200 Python: Minor doc fixes from review commit 6e5f71bf433242da4d32b9ff778b90ee1d3ecfb2 Author: Rasmus Lerchedahl Petersen Date: Fri Jun 26 12:02:14 2020 +0200 Python: sync dataflow files commit e147e596520b12137ad300472d3d95fa609cc27a Merge: 43f85ef26 9d8052a43 Author: Rasmus Lerchedahl Petersen Date: Fri Jun 26 12:01:01 2020 +0200 Merge branch 'master' of github.com:github/codeql into SharedDataflow To sync files commit 43f85ef26508cf1d15238a18559bc94b4629fa4b Author: Rasmus Lerchedahl Petersen Date: Fri Jun 26 12:00:24 2020 +0200 Python: typo commit 6efbd5f9d1221ffef2a2f730a745c7f8c68e9a7e Author: Tom Hvitved Date: Fri Jun 26 11:39:22 2020 +0200 C#: Add data-flow test for `List.Clear()` commit 9d8052a434dd11455165463546d37afa32d068af Merge: 8725e0905 63752ddde Author: Jonas Jensen Date: Fri Jun 26 11:34:33 2020 +0200 Merge pull request #3813 from MathiasVP/is-argument-for-parameter-join-order C++: Improve join order for AliasAnalysis::isArgumentForParameter commit 8725e090532b3483448d523d5879c2f987df0ec4 Merge: f81fc77e9 b8ae4b7f6 Author: Calum Grant <42069085+calumgrant@users.noreply.github.com> Date: Fri Jun 26 10:14:28 2020 +0100 Merge pull request #3798 from hvitved/csharp/dataflow/async-tests C#: Move async data-flow tests from local to global commit f81fc77e9ec75d8c057f0b129f2eb81b72b1a498 Merge: 92cc59b47 690bde47a Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Fri Jun 26 10:11:10 2020 +0100 Merge pull request #3782 from erik-krogh/promiseSteps Approved by asgerf commit 63752dddef3c1fd40362e5d982ea57373f8d6bf6 Author: Mathias Vorreiter Pedersen Date: Fri Jun 26 09:08:44 2020 +0200 C++/C#: Sync identical files commit 3af679e83d97e77d7e76ceefcc17a0db8e66d737 Author: Mathias Vorreiter Pedersen Date: Fri Jun 26 09:08:04 2020 +0200 C++: Put unique around getEnclosingFunction, and specialize function argument, to improve join order. commit 92cc59b47b36d89308afa80b7a508215c2ba6150 Merge: d4c588712 4bfce4b8a Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Fri Jun 26 07:54:08 2020 +0100 Merge pull request #3800 from esbena/js/npmlog Approved by erik-krogh commit 7e3f2dbe4c300bc7d67da8d435b10f071603f809 Author: Dave Bartolomeo Date: Thu Jun 25 17:04:32 2020 -0400 C++: Improve QLDoc for `getElementSize()` commit 7cb6516bc45c85f1c56efa5abd23b714a9eb69ee Author: Erik Krogh Kristensen Date: Mon Jun 22 14:31:40 2020 +0200 make internal predicates within `DominatingPaths` smaller. commit 1ec2c549d2d23c300ee9f66e5fa30c11479ae38b Author: Erik Krogh Kristensen Date: Fri Jun 5 10:12:09 2020 +0200 autoformat commit 8b3ca73c1c1a180a68877d40ae4b6c670468003a Author: Erik Krogh Kristensen Date: Thu Jun 4 22:44:45 2020 +0200 autoformat commit 081b03c8f427f44a0a2e19f6c19e19dde23a6afd Author: Erik Krogh Kristensen Date: Thu Jun 4 16:55:31 2020 +0200 add tests that access-path domination can happen within a statement commit 47d52870f2770becb602c21bef55c8694a4fff1a Author: Erik Krogh Kristensen Date: Thu Jun 4 14:55:13 2020 +0200 Use a ControlFlowNode based API to determine domination commit 926f2c139f80dd2f2aa35acac218a9db3869b98f Author: Erik Krogh Kristensen Date: Thu Jun 4 12:54:34 2020 +0200 require that a write must dominate the enclosing stmt of a read commit 55565a51df9ed46dc6b26a4a969bbea5c8922770 Author: Erik Krogh Kristensen Date: Thu Jun 4 11:33:28 2020 +0200 don't use getEnclosingStmt commit 34d6a4dcf8b9e5da83d79cfadcd5b1993a6cb13b Author: Erik Krogh Kristensen Date: Thu Jun 4 11:25:18 2020 +0200 use Rhs of a prop-write Co-authored-by: Asger F commit cc2e61531e20fce3f43380b2477c38523e2e4893 Author: Erik Krogh Kristensen Date: Thu Jun 4 10:17:11 2020 +0200 update expected output commit f7c42ca1b52a607d5b1fd9dc791a5e6d8ccc4eb8 Author: Erik Krogh Kristensen Date: Thu Jun 4 10:16:06 2020 +0200 autoformat commit 252f805db49817f4589f4b1fc659e3cc47001530 Author: Erik Krogh Kristensen Date: Wed Jun 3 16:16:52 2020 +0200 performance improvement commit 21e5a522b036502bbea556adc52f6424dbdfe9bb Author: Erik Krogh Kristensen Date: Wed Jun 3 15:35:28 2020 +0200 give the same rank to all expressions inside a single stmt commit e467d3ccbf36f7cfde87186b0ca3c6019d929619 Author: Erik Krogh Kristensen Date: Tue Jun 2 14:54:41 2020 +0200 use dominating write check in js/path-injection commit 6bc821b1ab737cf617332e9fcfdcb42ca3333b8e Author: Erik Krogh Kristensen Date: Tue Jun 2 14:54:17 2020 +0200 add tests for dominating writes commit 2b2d691e450b40c62f48fb6948caf04fccbe0479 Author: Erik Krogh Kristensen Date: Tue Jun 2 14:53:59 2020 +0200 don't treated a property from a tainted object as tainted when there exists a dominating write commit 5e4acfbe192d65651ac097263618c1bc3dfdbb36 Author: Erik Krogh Kristensen Date: Tue Jun 2 14:52:47 2020 +0200 implement predicate for finding dominating writes to an access-path commit d4c58871225c75461a7d10a06e84d9104e3d489b Merge: 056e1a8c4 7aa44fd35 Author: Jonas Jensen Date: Thu Jun 25 19:29:35 2020 +0200 Merge pull request #3807 from geoffw0/qldoc3 C++: Even more QLDoc commit 168f9404f08b762f4a964d4c237ddd89d0ca68f5 Merge: 104298e09 056e1a8c4 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Jun 25 17:42:08 2020 +0100 Merge branch 'master' into models5 commit 056e1a8c4b563a88969d1436449dec30852dbec3 Merge: b759856cc b867512db Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Thu Jun 25 17:34:14 2020 +0100 Merge pull request #3599 from asger-semmle/js/nameditem Approved by esbena commit 488d41f7976c58ecbaafa918860add0a174f19ef Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Jun 25 16:59:36 2020 +0100 C++: QLDoc Cast.qll. commit 6639d6de83f11845a4e27fa4c4d50ba86d0a16ac Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Jun 25 16:47:07 2020 +0100 C++: QLDoc exprs\ObjectiveC.qll (deprecated). commit 1df843c8f649710179190f31c1d73acdb5aca9b1 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Jun 25 15:33:25 2020 +0100 C++: QLDoc multiple files in the exprs directory. commit b7730fb1adb38124f33fc2787fd20545930c4620 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Jun 25 15:28:27 2020 +0100 C++: QLDoc PrintfLike.qll. commit 9a1f90912966db8a920c8af6d0789697636fb123 Author: Robert Marsh Date: Thu Jun 25 09:06:38 2020 -0700 C++: Fix QLDoc for PrintAST.qll nodes/edges commit b3072b9544f0020aeb7d35cc92f20543e871eb1b Author: Robert Marsh Date: Thu Jun 25 08:54:17 2020 -0700 Apply suggestions from code review Co-authored-by: Dave Bartolomeo commit b759856ccb2b1c4363208c5e15b95aad7ffd9452 Merge: c4d43bafa 6e3609696 Author: Calum Grant <42069085+calumgrant@users.noreply.github.com> Date: Thu Jun 25 16:34:52 2020 +0100 Merge pull request #3792 from calumgrant/cs/qldoc-coverage1 C#: Improve qldoc coverage commit 690bde47aafb5d0cbe26f753f3c5aae9c90ea449 Author: Erik Krogh Kristensen Date: Thu Jun 25 16:51:10 2020 +0200 remove a .getALocalSource() that isn't needed commit e28284bd01298a83ec4bf46a4dda73c224a9af05 Author: Asger Feldthaus Date: Wed Jun 17 10:19:47 2020 +0100 JS: Fix javadoc commit ad48c4e54d1b80c698f61f1274eea2e97c2b1593 Author: Asger Feldthaus Date: Mon Jun 1 11:24:42 2020 +0100 JS: Always prepare package.json files commit 675c64d9d4b32957c0c821c7f80d60e2bab7c3c8 Author: Asger Feldthaus Date: Fri Jun 12 21:49:43 2020 +0100 JS: Prefer extracting file with tsconfig that included it commit 4c4acd50bdb05ad8badb41c06213aadd90359766 Author: Asger Feldthaus Date: Fri Jun 12 17:12:08 2020 +0100 JS: Factor out loading of tsconfig files commit cc3e62f5357459aade88219cbc8d413b8ab016fa Author: Asger Feldthaus Date: Fri Jun 12 17:00:25 2020 +0100 JS: Move stack trace limit to top of file commit cf784757997035b07430bc1eb96068122abf2a81 Author: Asger Feldthaus Date: Fri Jun 5 13:42:11 2020 +0100 JS: Only extract included files with a given tsconfig commit 6ff81377d5b5e5fce112c5597156053caf5a10a7 Author: Asger Feldthaus Date: Fri Jun 5 11:54:40 2020 +0100 JS: Also sort files in legacy extractor commit 6d15397fdc7b4ee597a11666ebde56ea5a26ed2f Author: Asger Feldthaus Date: Wed Jun 3 09:19:37 2020 +0100 JS: Ensure we never write outside the scratch dir commit ba5d6bb2e9e70f9a76d4fb4b0ce750724c068e98 Author: Asger Feldthaus Date: Wed Jun 3 12:24:01 2020 +0100 JS: Actually set fields commit dceb2110210f89c8a1b1df4ef12aa49baaf028a9 Author: Asger Feldthaus Date: Wed Jun 3 10:57:12 2020 +0100 JS: Pass source root to Node.js process commit aaf141782f1a3ee0bafab025a8226bdc3c35870b Author: Asger Feldthaus Date: Wed Jun 3 09:13:32 2020 +0100 JS: Fix source root commit cb0a2498b004857b5b56ce13af8836d4e8d31b23 Author: Asger Feldthaus Date: Wed Jun 3 23:41:40 2020 +0100 JS: Sort files commit c4d43bafa47fd9d121e2c3e7279a45d05b39594e Merge: cf0cd0045 3f91aa3b5 Author: Calum Grant <42069085+calumgrant@users.noreply.github.com> Date: Thu Jun 25 15:38:04 2020 +0100 Merge pull request #3797 from hvitved/csharp/dataflow/more-collection-tests C#: More data-flow collection tests commit c5c1c4c0af49b276a30288f3dbde1c85b5771e08 Author: Rasmus Lerchedahl Petersen Date: Thu Jun 25 16:29:41 2020 +0200 Python: started adding some coverage tests commit cf0cd00458266d7963e52fa7f9aca74d2c918d55 Merge: c39dce4d6 f9b796231 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Thu Jun 25 15:28:57 2020 +0100 Merge pull request #3627 from asger-semmle/js/unneeded-defensive-return Approved by erik-krogh commit d526a10981e34fc629f3a92400c6e9a52e901a51 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Jun 25 15:16:51 2020 +0100 C++: QLDoc TestFile.qll, StringAnalysis.qll. commit c39dce4d666dcb9432d71e6ed2729c0568804ed1 Merge: 3ce4cff18 e2a300e81 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Thu Jun 25 14:56:17 2020 +0100 Merge pull request #3781 from asger-semmle/js/deprecate-type-member-lookup Approved by erik-krogh commit c3b52fadcc0e4eab809f6c701b2d6a78fccd1038 Author: Erik Krogh Kristensen Date: Thu Jun 25 15:54:36 2020 +0200 add missing qldoc commit 7aa44fd3578cd980233ac82ecb444ee8be9dda98 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Jun 25 08:02:40 2020 +0100 C++: QLDoc Parameter.qll, Specifier.qll, commons/File.qll. commit a722bd4bd06b92690b64f52fc5feb85b8a0cc7ca Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Jun 25 14:25:44 2020 +0100 C++: QLDoc UserType.qll. commit c8fc8af340c6f91ba12b0ec90a645998007a7717 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Jun 25 14:10:28 2020 +0100 C++: QLDoc Struct.qll, TypedefType.qll, Union.qll, Variable.qll. commit 908c3b400571bae5bc3c4be7e143ac2e119299d4 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Jun 25 14:05:01 2020 +0100 C++: QLDoc SecurityOptions.qll. commit b889d3687ec8a131d925d697fcf30e06084007a6 Author: Dave Bartolomeo Date: Thu Jun 25 09:33:43 2020 -0400 C++: Fix QLDoc review feedback commit 09d969a8ad237b89e9ed978bee0c0dabe9f8e625 Author: Erik Krogh Kristensen Date: Thu Jun 25 15:16:12 2020 +0200 recognize sensitive files by file-system writes commit 8f5a3e9f4f4c7fc223df19c7dc65d5109b2cfe08 Author: Erik Krogh Kristensen Date: Thu Jun 25 14:40:35 2020 +0200 add support for getASavePath() to js/insecure-download commit dafca8fd812d8d9a6a672afc03b5f8a7d7636285 Author: Erik Krogh Kristensen Date: Thu Jun 25 14:27:28 2020 +0200 introduce flow-labels to js/insecure-download commit 9bdedb3f484d46b0ffd6285fcdd70562227e8480 Author: Erik Krogh Kristensen Date: Thu Jun 25 14:27:09 2020 +0200 introduce getASavePath to ClientRequest commit 3b4cd700c2140a74f917ce8e1a2492c7568140e4 Author: Dave Bartolomeo Date: Thu Jun 25 09:08:30 2020 -0400 Remove accidentally added file commit 6c679c328d2e13b2cc2cb7ce139523d190703ee6 Author: Anders Schack-Mulligen Date: Thu Jun 25 14:13:36 2020 +0200 Dataflow: Refactor dispatch with call context. commit 4dbc8e515a989172b34e3760a9108c257c95bce8 Author: Taus Brock-Nannestad Date: Thu Jun 25 14:19:18 2020 +0200 Python: Address a few more review comments. commit 16087582191cd7ebe4e9cfaac5bc26f350774749 Author: Taus Date: Thu Jun 25 14:16:44 2020 +0200 Python: Apply suggestions from documentation review. Co-authored-by: Felicity Chapman Co-authored-by: Rasmus Wriedt Larsen commit 3ce4cff183276acfbb23b8f606b42289f776d3e5 Merge: f2ef088d4 099e5891a Author: Jonas Jensen Date: Thu Jun 25 14:07:57 2020 +0200 Merge pull request #3802 from geoffw0/modeling C++: 'modelling' -> 'modeling'. commit f2ef088d4fd5c86b8d52fba2a74111fa54451186 Merge: b24fba8df b515c0994 Author: Jonas Jensen Date: Thu Jun 25 14:06:00 2020 +0200 Merge pull request #3783 from geoffw0/qldoc2 C++: More QLDoc commit a0bfbda51cd2ed6aa3338859b9e97713e19d94e4 Author: Mathias Vorreiter Pedersen Date: Thu Jun 25 12:55:57 2020 +0200 C++: Improve performance by not calling getDef, but instead refer to isDefinitionInexact. This gives roughly the same tuple numbers we had with only instruction nodes. commit 6dc02c719b12838452b3a3d2d5cb0f2a7473d385 Author: Dave Bartolomeo Date: Thu Jun 25 07:19:15 2020 -0400 C++: Fix typos commit 099e5891ae25c99ac1885bc18e58738de1871018 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Jun 25 11:50:43 2020 +0100 C++: 'modelling' -> 'modeling'. commit f956112042e939c148562b46fd733a05b46c3f06 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Jun 25 11:48:10 2020 +0100 C++: Autoformat. commit b515c09946db502f424faec1b4c2f44af320ee37 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Jun 25 11:46:33 2020 +0100 C++: Autoformat. commit 6201796122a600468a45dad88b49a3b44c5200cd Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Jun 25 11:42:57 2020 +0100 C++: modelling -> modeling Co-authored-by: Jonas Jensen commit 89bea604d99a5ff729cb32158ae39cb9d5eff089 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Jun 25 11:30:09 2020 +0100 C++: Fix false positive. commit 720ac026dc861afe057b5b608e5739c1b743d4f6 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Jun 25 11:21:08 2020 +0100 C++: Add false positive. commit 5489bb994663d361f9051a237b6fad89eb8b2048 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Jun 25 11:12:44 2020 +0100 C++: Autoformat. commit 8f6e56cb417957c7624068ddf8d26ec08fcf10c5 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Jun 25 11:12:09 2020 +0100 C++: Suggested change. commit f9b796231b584c1b72c28d5430191e138dd89ce5 Author: Asger Feldthaus Date: Thu Jun 25 11:10:27 2020 +0100 JS: Add regression tests commit 22ad8f717fc7403d01a3fff4f666bb2f5c228653 Author: Rasmus Wriedt Larsen Date: Thu Jun 25 12:06:52 2020 +0200 Python: Remove usage of .getASuccessor() in XSLT.qll commit 1e5eeb80096145159b5c8ec3b573019be9d8f6e9 Author: Rasmus Wriedt Larsen Date: Thu Jun 25 12:03:15 2020 +0200 Python: Move lxml.etree library stub to reduce clutter commit 4bfce4b8a373f073f5938ac411ad9f4fb7d565fa Author: Esben Sparre Andreasen Date: Thu Jun 25 12:00:30 2020 +0200 JS: model npmlog (and recognize the "verbose" log level) commit b24fba8df028bc2713b3b5a1471c6d370115d641 Merge: 4642bb276 d9a0dc098 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Thu Jun 25 11:06:25 2020 +0100 Merge pull request #3734 from dellalibera/loginjection Approved by esbena commit a109c1fc968a04dc56d6ddd217ed88aa812b1f33 Author: Asger Feldthaus Date: Fri Jun 5 16:37:56 2020 +0100 JS: Change note commit ea3560fe076c521b0511efda46139727b40ab296 Author: Asger Feldthaus Date: Fri Jun 5 11:34:43 2020 +0100 JS: Ignore document.all checks explicitly commit 3cc566f703706be4a563e959df6334ab3899cfb8 Merge: e60af68b2 4642bb276 Author: Rasmus Wriedt Larsen Date: Thu Jun 25 12:02:21 2020 +0200 Merge branch 'master' into python-3521-revived commit b867512db49ad2d81cc74d28bb5c8170a6e189bd Author: Asger Feldthaus Date: Thu Jun 25 11:01:10 2020 +0100 JS: Update test commit e60af68b293095da82fefbd8770734a595bc8571 Author: Rasmus Wriedt Larsen Date: Thu Jun 25 11:54:34 2020 +0200 Python: Move lxml.etree library stub (so merge is easy) commit 994db060c70de5783da0f959b4e2cf53f6b8745d Author: Rasmus Wriedt Larsen Date: Thu Jun 25 11:53:12 2020 +0200 Python: Use CWE-091 for XSLT As indicated here https://www.zaproxy.org/docs/alerts/90017/ commit 4642bb2767d5f2f016e1be4e5bb87f696744b85e Merge: b36c23ef6 652de80fa Author: Calum Grant <42069085+calumgrant@users.noreply.github.com> Date: Thu Jun 25 10:31:50 2020 +0100 Merge pull request #3774 from hvitved/csharp/tripleticks C#: Enable syntax highlighting in QLDoc snippets commit b36c23ef63c42e279b64e53c19a8b5306a465a89 Merge: 0b36cd44b f6c59abcd Author: Rasmus Wriedt Larsen Date: Thu Jun 25 11:26:52 2020 +0200 Merge pull request #3500 from yoff/UnmatchableDollar Python: Regexp: Handle repetions {n} (with no ,) commit 0b36cd44b86111fcb803c4264aec76919c0f6a00 Merge: 06a5242d7 a51913240 Author: Rasmus Wriedt Larsen Date: Thu Jun 25 11:21:45 2020 +0200 Merge pull request #3522 from porcupineyhairs/pythonXpath Python : Add Xpath injection query commit 6e3609696a83d5baf9ca553292e24851bca47db9 Author: Calum Grant Date: Thu Jun 25 09:59:59 2020 +0100 C#: Address review comments. commit 9f06e133132f91e973039cbf0a0de0c6dc81e726 Author: Taus Brock-Nannestad Date: Thu Jun 25 10:48:26 2020 +0200 Python: Fix incomplete renaming in `Thrift.qll`. commit 415e0c4aac99e161222e14c3d403fb29f6cf1f40 Author: Rasmus Lerchedahl Petersen Date: Thu Jun 25 10:46:33 2020 +0200 Python: add suggestion for test cases commit 2d7feb794f11bf1a73929d6ddb7dfc94b0e894fd Author: Erik Krogh Kristensen Date: Wed Jun 24 22:54:12 2020 +0200 Refactor Promises.qll to use PreCallGraphStep commit 5973fe84112cfa71a11f2291a3914376d1314ac8 Author: Rasmus Lerchedahl Petersen Date: Thu Jun 25 10:32:10 2020 +0200 Python: scaffold for testing data flow coverage commit b8ae4b7f6414e6ecb1e677e31dacdcb3f65cf7e0 Author: Tom Hvitved Date: Fri Jun 12 09:32:35 2020 +0200 C#: Move async data-flow tests from local to global commit 3f91aa3b559e089409d1b3df9c3f654dfe120653 Author: Tom Hvitved Date: Wed May 6 11:22:51 2020 +0200 C#: More data-flow collection tests commit 06a5242d7628985e26f8ed5eb029fa4dee467913 Merge: 3e6a19843 fb6e57861 Author: Dave Bartolomeo Date: Wed Jun 24 20:51:07 2020 -0400 Merge pull request #3793 from rdmarsh2/rdmarsh/cpp/ir-range-analysis-experimental C++: move IR range analysis to experimental commit 2685aa4b8b10619aef3f77d07aff8a6819542184 Author: Dave Bartolomeo Date: Wed Jun 24 20:42:02 2020 -0400 C++: Use fewer words commit 8b02f121d65563fd71e31a02677cdf2314900e8d Author: Dave Bartolomeo Date: Wed Jun 24 20:29:31 2020 -0400 C++: QLDoc for all of `Instruction.qll` I think I've now documented every class and public predicate in `Instruction.qll` I've tried to include detailed semantics of each instruction where appropriate. commit 362fbd12dc848fbc88a65c90614b59a493d80c75 Author: Robert Marsh Date: Wed Jun 24 16:45:20 2020 -0700 C++: QLDoc for PrintAST.qll commit 39aaccc1ac72c444e40d350ccbf515685e074cd9 Author: Robert Marsh Date: Wed Jun 24 16:29:20 2020 -0700 C++: Add QLDoc for AST range analysis libraries commit 3e6a19843d86bbffd6acdc865121da8d336e9ee8 Merge: 090a685d8 e0ba23d2c Author: Robert Marsh Date: Wed Jun 24 15:06:13 2020 -0700 Merge pull request #3727 from jbj/tainted-format-string-high C++: Raise cpp/tainted-format-string* precisions to high commit d32199ccccf46fb3c75c30a5576463a2e6d02fe5 Author: Calum Grant Date: Wed Jun 24 21:42:20 2020 +0100 C#: QLdoc for CIL instructions. commit 262a20cea03b52e0bd0da76ac5d19f741ec1523c Author: Calum Grant Date: Wed May 20 17:25:33 2020 +0100 C#: Add qldocs for Concurrency.qll, Documentation.qll, cil.qll and dotnet.qll. commit 02363d76c18f42f703ea2f4fe2dd79e87f36791d Author: Taus Brock-Nannestad Date: Wed Jun 24 22:43:59 2020 +0200 Python: Document `Comment.qll`. I didn't do the `toString` methods in this commit. I'm thinking they're better to do in a separate commit. (There are 48 undocumented instances!) commit fe78e68fd003e2af34c64cd61f16983a53cb7193 Author: Taus Brock-Nannestad Date: Wed Jun 24 22:38:03 2020 +0200 Python: Document a bunch of `hasLocationInfo` methods. If only we had been _somewhat consistent in how we named the parameters for these... commit 155bbbdec9ef19cacd863aa2c04ee163568e543a Author: Rasmus Wriedt Larsen Date: Wed Jun 24 22:12:26 2020 +0200 Python: Add annotated call-graph tests See the added README for in-depth details commit 682e1b60404cdd26342ee4987e9142499a72acb4 Author: Taus Brock-Nannestad Date: Wed Jun 24 22:13:46 2020 +0200 Python: Document `Comparisons.qll`. commit 090a685d869956d2339dd236dc217ad2edb1aea7 Merge: 38067b5b3 27f91b36b Author: Asger F Date: Wed Jun 24 21:09:41 2020 +0100 Merge pull request #3751 from toufik-airane/master [javascript] CWE-347: JWT Missing Secret Or Public Key Verification commit b8e744eade50dfb68f51f01264be9661929ab317 Author: Taus Brock-Nannestad Date: Wed Jun 24 22:07:47 2020 +0200 Python: Document `Class.qll`. commit 25122c9fb5ebdbd3ac3ff698dc6a8fbaeb122e1a Author: Taus Brock-Nannestad Date: Wed Jun 24 21:53:37 2020 +0200 Python: Document (parts of) `ExternalArtifact.qll`. I don't think there's any need to document the parts specific to metrics or defects, as I don't believe these are used anywhere. commit fb6e5786184f7c0a59ccd83e377b42f2cd1a4b90 Author: Robert Marsh Date: Wed Jun 24 12:47:30 2020 -0700 C++: move IR range analysis to experimental commit 8c6753a3cc1967093ad5b618f173a2bf14cc4a4b Author: Mathias Vorreiter Pedersen Date: Wed Jun 24 21:13:38 2020 +0200 C++: Accept consistency tests. commit 0552f9b0cc65056e16fe72ccf89086e052e50db6 Author: dilanbhalla Date: Wed Jun 24 11:47:34 2020 -0700 memory unsafe scan functions commit d259e8e8dfc6a589697dbc2dbadbf78c9159d5f6 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 23 14:16:46 2020 +0100 C++: Correct StrCpy.hasTaintFlow. commit c3d275d0e7682aba94b9fad7dec72be68b81a53d Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 23 14:58:07 2020 +0100 C++: Clean up SprintfBW and comment Sprintf. commit c681e6999da48ba5b10e9e22b8796ec2e06c6e02 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 23 14:00:33 2020 +0100 C++: Refine the strcat and strcpy models, have BufferWrite depend on them so that information isn't duplicated. commit d9a0dc0982d4dc9c645f1815217af475de9bb15a Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Wed Jun 24 19:31:23 2020 +0200 Remove check for console().getAMethodCall commit 38067b5b347dce0279891d2432f5f21892fdeba5 Merge: 791f31fa6 e24566e31 Author: Robert Marsh Date: Wed Jun 24 10:18:26 2020 -0700 Merge pull request #3777 from rdmarsh2/rdmarsh/csharp/autobuilder-lang-name C#/C++: Use CODEQL_EXTRACTOR__* in autobuilder commit 65eba0272dd5ae892c2084ca0d324bc716a220b9 Merge: a759905a5 791f31fa6 Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Wed Jun 24 19:15:27 2020 +0200 Merge remote-tracking branch 'upstream/master' into loginjection commit 5190c266356fe23da70e76d934b8275750cee2b1 Author: Mathias Vorreiter Pedersen Date: Wed Jun 24 18:28:41 2020 +0200 C++: Accept tests. commit 7530dc213246d4a0744ab0f145b441363ce3b6e1 Author: Mathias Vorreiter Pedersen Date: Wed Jun 24 18:28:23 2020 +0200 C++: Hide operand nodes from path explanations to make the review diff smaller. commit 5aa1b131369ea574a7ce78a511717d543297d0d1 Author: Mathias Vorreiter Pedersen Date: Wed Jun 24 18:27:53 2020 +0200 C++: Make the pre update node for ExplicitFieldStoreQualifierNode an operand node. This fixes the IR dataflow consistency errors. commit 470ee0059d564529126c05b6f8ab40bb6088b4aa Author: Mathias Vorreiter Pedersen Date: Wed Jun 24 18:27:12 2020 +0200 C++: Alternate dataflow between operands and instructions commit d7a9d3d8bc2f6a06764cbd226be42214a4fce260 Author: Mathias Vorreiter Pedersen Date: Wed Jun 24 18:26:17 2020 +0200 C++: Introduce operand dataflow node commit 0779aab28fe1baa0db8a70862e932a7a05e2a670 Author: luchua-bc Date: Wed Jun 24 15:02:16 2020 +0000 Clean up the QL code commit 791f31fa6514c18fcfcba1d685bc2d6393b6f6f6 Merge: daeb13d9f fffc88ea5 Author: Anders Schack-Mulligen Date: Wed Jun 24 16:45:34 2020 +0200 Merge pull request #3595 from luchua-bc/j2ee-server-directory-listing Java: Add check for J2EE server directory listing commit daeb13d9fdb7401665306ccf2a1cb9584e01ad95 Merge: 696d19cb1 d15c98d18 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Wed Jun 24 15:37:03 2020 +0100 Merge pull request #3779 from asger-semmle/js/metric-queries Approved by esbena commit 42f32bf76cfa3978c32360fe9455cb731b8f694b Author: Asger Feldthaus Date: Mon Jun 1 14:18:14 2020 +0100 JS: Recognize calls to .item and .namedItem commit ff0a9bfc4888179bcbaa3192c73cd04c0955c000 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Jun 24 11:57:33 2020 +0100 C++: QLDoc Stmt.qll, Block.qll. commit ed322506365f1bf3517aa12d1a3fbd42dcfc6ac6 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Jun 24 11:49:25 2020 +0100 C++: Deprecate Member.qll. commit f1aac04bdf06b97f68b71c37df5de86e900bb5e4 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Jun 24 13:23:50 2020 +0100 C++: Deprecate overly specific parts of Type.qll. commit e43ddd3f789434214a2edba953f3c2438f123241 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Jun 24 11:26:28 2020 +0100 C++: QLDoc Type.qll. commit 6bcc1a0220512b3bb93751aca99e02d1bbca590d Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 23 17:32:56 2020 +0100 C++: QLDoc NameQualifiers.qll, Namespace.qll, NestedFields.qll. commit 696d19cb1440b6f6a75c6a2c1319e18860ceb436 Merge: 3982da5c4 76ed03f75 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Wed Jun 24 13:04:04 2020 +0100 Merge pull request #3773 from erik-krogh/guardedCrypto Approved by asgerf commit 3982da5c47846a805b2cccf429d178c18c682cd3 Merge: 941177ee2 8d5077ae8 Author: Jonas Jensen Date: Wed Jun 24 11:36:39 2020 +0200 Merge pull request #3771 from hvitved/qldoc-style-tripleticks Suggest using target language syntax highlighting in QLDoc commit e2a300e8113e09e25d2c74a8bde02b43c5edbf8b Author: Asger Feldthaus Date: Tue Jun 23 12:24:13 2020 +0100 JS: Add change note commit f6c59abcd958625ed544debe8fc253fc4f7d16b4 Merge: 6e9c48bba 941177ee2 Author: Rasmus Lerchedahl Petersen Date: Wed Jun 24 11:04:07 2020 +0200 Merge branch 'master' of github.com:github/codeql into UnmatchableDollar to make CodeScan happy commit 6e9c48bba788dbb27399ae4fa4bf3c93382c3d71 Author: Rasmus Lerchedahl Petersen Date: Wed Jun 24 11:01:27 2020 +0200 Python: test zero iterations commit 226c295b4c83ab9828bdc21c252c5b4103641160 Author: Rasmus Lerchedahl Petersen Date: Wed Jun 24 10:48:51 2020 +0200 Python: format commit 941177ee25d71dc798db98c6a3a617119383f2ea Merge: 3b62bd254 ff751ac0f Author: Anders Schack-Mulligen Date: Wed Jun 24 10:19:50 2020 +0200 Merge pull request #3762 from hvitved/dataflow/clear-contents Data flow: Model field clearing commit 3b62bd254c0803e330a4d8212b77210145341aaf Merge: a723ac0d8 c2052ed15 Author: Anders Schack-Mulligen Date: Wed Jun 24 09:35:01 2020 +0200 Merge pull request #3723 from JLLeitschuh/fix/JLL/gitignore_vs_code_generated_files Add .gitignore for VS Code Generated maven project files commit 76ed03f75b8b9717d3e1eed5c4f594230e57b756 Author: Erik Krogh Kristensen Date: Wed Jun 24 09:30:43 2020 +0200 update change-note Co-authored-by: Asger F commit a723ac0d8eae2d512f30ef87f4de2201413b4118 Merge: afcc6ac71 2d32ee744 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Wed Jun 24 08:03:49 2020 +0100 Merge pull request #3767 from esbena/js/console-member-calls Approved by erik-krogh commit d15c98d18c5ed00fe9e954f0e5213b2dd2c2d7b7 Author: Asger Feldthaus Date: Tue Jun 23 17:26:41 2020 +0100 JS: Add more metrics commit afcc6ac71216d1313b920ac26a745a10550a36ae Merge: 30d9c6b9e edaa43ab0 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Jun 24 07:31:48 2020 +0100 Merge pull request #3766 from rdmarsh2/rdmarsh/cpp/add-qldoc-3 C++: Add QLDocs for Initializer.qll-Macro.qll and model classes commit e24566e3133936ab238d4269124acde51eac8240 Author: Robert Marsh Date: Tue Jun 23 15:53:25 2020 -0700 C#/C++: Use CODEQL_EXTRACTOR_CPP_ROOT in autobuild Left this out earlier because I thought it needed to point to the C# extractor root even in C++ mode, but it looks like it isn't yet used in C++ mode. commit c37c2828614065fe1d265730d21d4838d934f5e2 Author: Robert Marsh Date: Tue Jun 23 15:35:22 2020 -0700 C#/C++: Fix tests with new environment variables commit da9aa546decf0ab0d0f344cae9c196e7c6633713 Author: Robert Marsh Date: Tue Jun 23 14:47:07 2020 -0700 C#/C++: Use CODEQL_EXTRACTOR_CPP_* in autobuilder commit 30d9c6b9e426153701f9731d3dd88949ecb6e2b2 Merge: b40235232 fbaf398e7 Author: Mathias Vorreiter Pedersen Date: Tue Jun 23 22:23:03 2020 +0200 Merge pull request #3776 from geoffw0/qldoc C++: QLDoc ObjectiveC.qll, BufferWrite.qll, FileWrite.qll, OutputWrite.qll commit b40235232107d6de15e4d6ade8173914cc8a037c Merge: a2677f8df a3e7fd60f Author: Robert Marsh Date: Tue Jun 23 09:53:10 2020 -0700 Merge pull request #3775 from hvitved/dataflow/tripleticks Data flow: Enable syntax highlighting in QLDoc snippets commit edaa43ab0b4447a79bb875faca73f4d5f7ee8c22 Author: Robert Marsh Date: Tue Jun 23 09:23:08 2020 -0700 C++: respond to PR comments on qldoc commit 63d48bfe5c2b5f03a4c63ceb2ebb4de18baf6f27 Author: Asger Feldthaus Date: Tue Jun 23 17:08:09 2020 +0100 JS: Move IgnoredFile to MetaMetrics commit 35bdb4127e6dd16bef7f21fa0d143b0020360c38 Author: Asger Feldthaus Date: Mon Jun 1 11:38:39 2020 +0100 JS: Add TypedExprs metric commit fbaf398e7a42d4dfddb4f138e11f4e40c1ace9a4 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 23 16:28:00 2020 +0100 C++: QLDoc FileWrite and OutputWrite. commit e01f050db872af02cb21b1e37d11b2629dd63bfd Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 23 13:37:42 2020 +0100 C++: QLDoc BufferWrite.qll. commit dea9a13e44898ddd63603116baa4e083561785b4 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 23 12:23:46 2020 +0100 C++: QLDoc ObjectiveC.qll (deprecated). commit c70cf6d780878601c4a9b7977598568fe7474f34 Author: Rasmus Lerchedahl Petersen Date: Tue Jun 23 17:25:33 2020 +0200 Python: better (if imperfect) handling of phi node commit 652de80fa5d33b1fe2976354cd15e50bb661deed Author: Tom Hvitved Date: Tue Jun 23 16:49:31 2020 +0200 C#: Enable syntax highlighting in QLDoc snippets commit a3e7fd60f26f22aae5c5f599457d22486f28a1c7 Author: Tom Hvitved Date: Tue Jun 23 16:54:34 2020 +0200 Data flow: Enable syntax highlighting in QLDoc snippets commit fffc88ea5b853ef9ed85feb30d3c8145309f2875 Author: Bt2018 Date: Tue Jun 23 10:34:28 2020 -0400 Metadata update commit a2677f8df0bd9076638f02d2031121f4bf6c66be Merge: 0d6144391 d5895c16c Author: Taus Date: Tue Jun 23 16:16:44 2020 +0200 Merge pull request #3758 from RasmusWL/python-methods-overrides-as-recommendation Python: Changing signature in overriden method is not an error commit 79599b6cc04d87ca6594528a038805f64393b2df Author: Erik Krogh Kristensen Date: Tue Jun 23 15:57:55 2020 +0200 add change-note commit 3f8881a334396fe8c6b11cd65f09b156b307ca1d Author: Erik Krogh Kristensen Date: Tue Jun 23 15:53:19 2020 +0200 don't report insecure randomness when the insecure random is just a fallback commit f8c494716fa0800b0b4d95e83222a68ae79e1ee0 Author: luchua-bc Date: Tue Jun 23 12:48:07 2020 +0000 Fix ending line error commit 8d5077ae83b039e84413d587b53ac791bd756ffa Author: Tom Hvitved Date: Tue Jun 23 14:48:04 2020 +0200 Suggest using target language syntax highlighting in QLDoc commit 89260d6f8aeac967c94ceda7b9ab89891e408df6 Author: luchua-bc Date: Tue Jun 23 12:36:07 2020 +0000 Fix ending line error commit 1e4ec5c987d22bee2f1236552608959e77b4c55d Author: Taus Brock-Nannestad Date: Tue Jun 23 14:31:30 2020 +0200 Python: Make QLDoc for `TObject.qll` visible. commit ccf63e03bbc96dfa133c2015a160f0a4d79a28c4 Author: Taus Brock-Nannestad Date: Tue Jun 23 14:31:06 2020 +0200 Python: Document `FileOpen.qll`. commit f86011fb51d2a1fe966e11245ca09d6bda072f61 Author: Taus Brock-Nannestad Date: Tue Jun 23 14:30:42 2020 +0200 Python: Document `RedundantComparison.qll`. commit 2f93b1458e0de8beb2e4a19ea933aa2574641caf Author: Taus Brock-Nannestad Date: Tue Jun 23 14:30:17 2020 +0200 Python: Document `IsComparisons.qll`. commit d6e5a5cb0141c9c91a0e77107b0bd458c2bd0ee4 Author: Taus Brock-Nannestad Date: Tue Jun 23 14:29:34 2020 +0200 Python: Document `AdvancedFormatting.qll`. commit 513ead66d3f97034fd79608436a5c2a071e41d6d Author: Taus Brock-Nannestad Date: Tue Jun 23 14:28:40 2020 +0200 Python: Document `CallArgs.qll`. commit deabfe6e5cba6755ee6132c3ec7985a17c2cc63c Author: luchua-bc Date: Tue Jun 23 12:24:03 2020 +0000 Adjust id tag and fix ending line error commit 7642b43990535842d44907366733ee244c1df21b Author: luchua-bc Date: Tue Jun 23 12:10:07 2020 +0000 Adjust id tag and fix ending line error commit 0d6144391522b4dbb16961b422a421b3af84a56a Merge: 552b7ad3c 56124b68a Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Tue Jun 23 13:01:41 2020 +0100 Merge pull request #3753 from asger-semmle/js/xss-dom-exception-rephrasing Approved by erik-krogh commit 552b7ad3ca1aed2b471bc29644b8c7c4ff2713b4 Merge: a5a3573a3 b4f75ef41 Author: Asger F Date: Tue Jun 23 12:58:27 2020 +0100 Merge pull request #3765 from asger-semmle/js-team-sprint-merge2 JS: Merge js-team-sprint commit a5a3573a3e71aeaf8e75e9b975ae06af02fd19b4 Merge: 843c5c6c1 5cd2c7cdb Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Tue Jun 23 12:56:45 2020 +0100 Merge pull request #3757 from asger-semmle/js/unused-npm-dependencies Approved by erik-krogh commit 4f67cc269bcfff90dd61cab59d7dc6f950bd88ae Author: Asger Feldthaus Date: Tue Jun 23 11:44:07 2020 +0100 JS: Reduce ExpansiveTypes test commit 234f968294c5cfe47048ebd28dc85c97fd6df7c3 Author: Asger Feldthaus Date: Tue Jun 23 11:42:28 2020 +0100 JS: Deprecate property lookup on types commit 27f91b36b02ab1aa21a07bae7c0d92b296eab70d Author: Toufik Airane Date: Tue Jun 23 12:28:21 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql Co-authored-by: Erik Krogh Kristensen commit 37f44d98ce9a7c8771504a8a03d29c4540514a6f Author: toufik-airane Date: Tue Jun 23 12:28:03 2020 +0200 fix minor issues commit dd19ee47a1fc77f436e54b4abc922b53cde613c3 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 23 10:59:42 2020 +0100 C++: Clean up ConversionConstructor. commit b759b71ac80bf114459d1e81273bab9473270ae5 Author: Rasmus Lerchedahl Petersen Date: Tue Jun 23 11:02:33 2020 +0200 Python: explain the regression test commit ff751ac0f81cabd02c914c21cad443b99f331a6d Author: Tom Hvitved Date: Tue Jun 23 10:54:29 2020 +0200 Data flow: Sync files commit 98ed2a18acc219abbda792791e7cccfd1ff9e800 Author: Tom Hvitved Date: Tue Jun 23 10:53:24 2020 +0200 Data flow: Move field-clearing checks from `flowCandFwf0` into `flowCandFwd` commit 13b4dfa9724a0a124bcdfba4adad8422b2b14880 Author: Tom Hvitved Date: Tue Jun 23 10:53:10 2020 +0200 Data flow: Rename `BigStepBarrierNode` to `FlowCheckNode` commit 3faca03de676888736b24b706a6a0b36df28f9f3 Author: Tom Hvitved Date: Tue Jun 23 10:52:14 2020 +0200 C#: Introduce `ObjectInitializerNode` commit 83050d96f89c6b2e77afb0646754fd851a2eceab Author: Tom Hvitved Date: Mon Jun 22 20:28:10 2020 +0200 C++: Stub implementations for `clearsContent()` commit c01f570d9e5abe0caeb15529164e6ad3c262944e Author: Tom Hvitved Date: Mon Jun 22 20:28:04 2020 +0200 Java: Implement `clearsContent()` commit c057e82efa6a44bd26bb1b10912778aed9c50717 Author: Tom Hvitved Date: Mon Jun 22 20:15:41 2020 +0200 Data flow: Sync files commit e578827626307fee427ddacb017c4a78399cd6f6 Author: Tom Hvitved Date: Mon Jun 22 20:15:07 2020 +0200 Java: Add more field-flow tests commit a1d55916342d4272d50e8f765de85d3c42fdafdc Author: Tom Hvitved Date: Mon Jun 22 19:47:08 2020 +0200 C#: Model field-clearing in data-flow commit b5bc15a09750e239a683c74464a556708803b1e1 Author: Tom Hvitved Date: Mon Jun 22 19:38:43 2020 +0200 C#: Add more field-flow tests commit 843c5c6c1ef0a4f1437380a623e262c8a43c8649 Merge: 3747bd98f 7e7d7e752 Author: James Fletcher <42464962+jf205@users.noreply.github.com> Date: Tue Jun 23 09:47:25 2020 +0100 Merge pull request #3742 from jf205/sd-110 CodeQL docs: Expand QLDoc style guide commit 2d32ee74481d0608158feaaf0ce3f042dfa3c4c3 Author: Esben Sparre Andreasen Date: Tue Jun 23 10:43:08 2020 +0200 JS: support member calls of `console` commit 7e7d7e752e9499fe17cbfd4a6511a9ffa262cd78 Author: james Date: Tue Jun 23 09:42:56 2020 +0100 docs: further improvements commit 3747bd98f3b10ce860fb76bcf0117a223f438f58 Merge: 95870977c 466f36c7e Author: Jonas Jensen Date: Tue Jun 23 10:15:32 2020 +0200 Merge pull request #3694 from geoffw0/models C++: Extend the GetsFunction and SystemFunction models. commit 95870977ca43e1a0ab926ed30a9510cf92a1951e Merge: 55ce5ce47 915148f82 Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Tue Jun 23 08:34:09 2020 +0100 Merge pull request #3763 from adityasharad/java/training-example-brace Fix training example syntax commit c7cfd59651343d05bc62bd7100c2c671c535db27 Author: James Fletcher <42464962+jf205@users.noreply.github.com> Date: Tue Jun 23 08:31:48 2020 +0100 Apply suggestions from code review Co-authored-by: Shati Patel <42641846+shati-patel@users.noreply.github.com> commit 55ce5ce47a4ae96a2f9930d55f26011e42db3238 Merge: 39137510b 5a5df4de2 Author: Mathias Vorreiter Pedersen Date: Tue Jun 23 08:58:08 2020 +0200 Merge pull request #3754 from jbj/revert-flat-structs C++: Revert #3419 to fix OpenJDK performance commit a55b4660d42efd16368ae0b48202f4a669cdee8f Author: Rasmus Lerchedahl Petersen Date: Tue Jun 23 07:45:30 2020 +0200 Python: support for `with`-definitions commit c1eb71284197414ce81090dd9097e0425d19244e Author: Robert Marsh Date: Mon Jun 22 17:25:55 2020 -0700 C++: QLDoc for data and taint models commit b4f75ef414f4c8c8c9c3f2226ef5213439b4d9ed Merge: 2edeb4aa8 39137510b Author: Asger Feldthaus Date: Tue Jun 23 00:18:09 2020 +0100 Merge branch 'master' into js-team-sprint-merge2 commit 2edeb4aa8d18604fb27a1a8f44dcfcd73c1987f7 Merge: 69b44def7 ca06f6dfb Author: Asger F Date: Tue Jun 23 00:16:45 2020 +0100 Merge pull request #3735 from esbena/js/insecure-http-options JS: polish js/disabling-certificate-validation commit ca06f6dfb4e8665c441381015f348abb24bad5fc Merge: 0654823b9 69b44def7 Author: Asger F Date: Tue Jun 23 00:16:02 2020 +0100 Merge branch 'js-team-sprint' into js/insecure-http-options commit 69b44def7b022a90fb85c1fc52c6aaa83ec22f1c Merge: a067cd35a 1efd71a68 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Mon Jun 22 23:27:43 2020 +0100 Merge pull request #3759 from asger-semmle/js/sprint-suite Approved by erik-krogh commit f7cbc8a8d437d9edc79264ea3c805b261c4f45f5 Author: toufik-airane Date: Mon Jun 22 22:34:06 2020 +0200 Enhance query ouput - add valuable text to assess the query results - add an example of the output commit 0f8879716fe22645fb7dbbdccfa6a5fdf5b55e00 Author: toufik-airane Date: Mon Jun 22 21:57:58 2020 +0200 rewrite description commit 915148f82c8d1341b8f7a05a383c205e647fcd1f Author: Aditya Sharad <6874315+adityasharad@users.noreply.github.com> Date: Mon Jun 22 12:26:26 2020 -0700 C++: Fix placeholder syntax in training example commit 95f8ba433e220da8056be4e488ddbf1e6be43749 Author: Aditya Sharad <6874315+adityasharad@users.noreply.github.com> Date: Mon Jun 22 12:21:15 2020 -0700 Java: Fix training example commit 231b85cb11d55b5d429de432902fa5390768242e Author: Robert Marsh Date: Mon Jun 22 11:43:43 2020 -0700 C++: File-level QLDoc for publicly imported models commit a759905a5cf18464d6a7594956eef7c716f3c672 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Mon Jun 22 20:37:38 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll Co-authored-by: Esben Sparre Andreasen commit 364f0ca734f4093e2b16f8578d59a067ef915b6d Author: toufik-airane Date: Mon Jun 22 20:11:58 2020 +0200 rewrite description commit ac8991b1925e765f2f3e190665cd742b33ddc546 Author: toufik-airane Date: Mon Jun 22 20:09:48 2020 +0200 remove JWTMissingSecretOrPublicKeyVerification.qll commit d9ecb7d762ee79e9c088e03d81eeced254134d8b Author: toufik-airane Date: Mon Jun 22 20:06:17 2020 +0200 rewrite help commit d65b7be32b014dd8fbbfb53e632b8f69b518acb4 Author: toufik-airane Date: Mon Jun 22 20:00:52 2020 +0200 rewrite help commit bb7ba50e232001093f3480263111e37ebff82f34 Author: Toufik Airane Date: Mon Jun 22 19:27:36 2020 +0200 Apply suggestions from code review Co-authored-by: Erik Krogh Kristensen commit 3fa49a9771b64a4e39bf61cecc317bd89af1608f Author: james Date: Mon Jun 22 17:07:10 2020 +0100 address review comment about sentence style commit 676d486635f44b0ce6a356008c2e4863fc669813 Author: James Fletcher <42464962+jf205@users.noreply.github.com> Date: Mon Jun 22 17:03:31 2020 +0100 Apply suggestions from code review Co-authored-by: Jonas Jensen commit 1efd71a68163d853cbf5186bad5aa09ab64f200c Author: Asger Feldthaus Date: Mon Jun 22 16:40:55 2020 +0100 JS: Sort security suite commit 8cc41a0c844d21f43abe769c1239f920e2619803 Author: Asger Feldthaus Date: Fri Jun 19 20:36:45 2020 +0100 JS: Add new queries to security suite commit a067cd35aa29da244358d63bbbfa5572f19d8cc8 Merge: 4a459c8a7 7d54b02fb Author: Asger F Date: Mon Jun 22 16:35:15 2020 +0100 Merge pull request #3756 from esbena/js/delay-slow-query-merge JS: delay merging two slow queries commit 7d54b02fb9b95d716d5e0c4776b53f02ccfe861f Merge: 9a0bbb31f 4a459c8a7 Author: Asger F Date: Mon Jun 22 16:34:49 2020 +0100 Merge branch 'js-team-sprint' into js/delay-slow-query-merge commit 4a459c8a7d47e3a52590d28acb7f3a21dcfffac8 Merge: eca5e2df8 d4ad9a8bb Author: Asger F Date: Mon Jun 22 16:32:16 2020 +0100 Merge pull request #3755 from esbena/js/polish-imcs JS: polish js/incomplete-html-attribute-sanitization commit 39137510ba9d47f517bebcfc9770f6219cfd397d Merge: 7a5aae743 17d36cf36 Author: Jonas Jensen Date: Mon Jun 22 17:27:23 2020 +0200 Merge pull request #3736 from rneatherway/exclude-cs-vulnerable-package Exclude dependency-based query from C# Code Scanning commit 466f36c7e11715196c74a891fd397205ee247b99 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Jun 22 16:04:32 2020 +0100 C++: Autoformat. commit d5895c16c81530faa484a11e14a752f8b48cedde Author: Rasmus Wriedt Larsen Date: Mon Jun 22 16:52:45 2020 +0200 Python: Changing signature in overriden method is not an error Rather, fulfiling the Liskov substitution principle is an opinionated recommendation. Looking at `py/inheritance/incorrect-overridden-signature` and `py/mixed-tuple-returns`, it seems very appropriate that this should have `@severity recommendation`, and `@sub-severity high`. commit e8289d6fa1f77e04bbfd7dc146309b81c78b224f Author: Rasmus Lerchedahl Petersen Date: Mon Jun 22 16:36:19 2020 +0200 Python: add regression tests and organise tests commit 5cd2c7cdb20fdd5e731808cd77c72377d3d07be6 Author: Asger Feldthaus Date: Mon Jun 22 15:25:24 2020 +0100 JS: Reduce precision of js/unused-npm-dependency commit aa04a2a476e6aba438aab104b86c761f5d298303 Author: Rasmus Lerchedahl Petersen Date: Mon Jun 22 14:56:11 2020 +0200 Python: sync dataflow files commit d4ad9a8bb2406fae0ea92cc5940923bf5a416e1e Author: Esben Sparre Andreasen Date: Mon Jun 22 14:55:27 2020 +0200 Update change-notes/1.25/analysis-javascript.md Co-authored-by: Asger F commit 656c76558a6c1ebedbc44c6e2fd785603a40921f Merge: 13bb971b0 7a5aae743 Author: Rasmus Lerchedahl Petersen Date: Mon Jun 22 14:55:04 2020 +0200 Merge branch 'master' of github.com:github/codeql into SharedDataflow To sync dataflow files commit 9a0bbb31f4493e6c59a2167c163fb9b3009fad1a Author: Esben Sparre Andreasen Date: Mon Jun 22 14:46:51 2020 +0200 Revert "Merge pull request #3702 from esbena/js/memory-exhaustion" This reverts commit eca5e2df8ae759373a55a1f0ec03beef5098e825, reversing changes made to 1548eca99476e7d8adbed05c335794b25da3f0d0. commit 0a8d15ccc4acad0ca63af6d39801aa90c7c41588 Author: Esben Sparre Andreasen Date: Mon Jun 22 14:45:35 2020 +0200 Revert "Merge pull request #3672 from esbena/js/server-crashing-route-handler" This reverts commit 243e3ad9e3259b084f35111c0c30373df2b49a8e, reversing changes made to df79f2adc56838ca027f86d4e414956b0391de47. commit 3be094ea5b2e4d9d5c3ac2038dde7174bdab19b1 Author: Esben Sparre Andreasen Date: Mon Jun 8 10:20:26 2020 +0200 JS: polish js/incomplete-html-attribute-sanitization commit 13bb971b055055971220aa7047f254a6e7ed835c Author: Rasmus Lerchedahl Petersen Date: Mon Jun 22 14:26:25 2020 +0200 Python: sort out some enclosing callable confusion commit 5a5df4de262ab287d6198e4c40fcc59f55d807ed Author: Jonas Jensen Date: Mon Jun 22 14:09:06 2020 +0200 Revert "Merge pull request #3419 from MathiasVP/flat-structs" There was unfortunately a semantic merge conflict between #3419 and #3587 that caused a performance regression on (at least) OpenJDK. This reverts commit 982fb388078cf2b0950b10f5ea462c010e77ae2f, reversing changes made to b841cacb83cbb2cd6fb5832b05a1447e2ef5c7ba. commit 7a5aae7432be58fa27924a814ef3c44dd7e99512 Merge: 287bc4026 e46bd709c Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Mon Jun 22 12:59:13 2020 +0100 Merge pull request #3630 from erik-krogh/DevServer Approved by asgerf commit 56124b68a33a45d59fc205147f13b0ddc1211c65 Author: Asger F Date: Mon Jun 22 12:54:19 2020 +0100 Update javascript/ql/src/Security/CWE-079/ExceptionXss.ql Co-authored-by: Erik Krogh Kristensen commit daa1b6fc790e5759385917404b377e4c33f1d0c6 Author: Rasmus Wriedt Larsen Date: Mon Jun 22 13:41:03 2020 +0200 Python: Fix grammar in QLDoc Co-authored-by: Taus commit 287bc40264614fa83e5de68e904c517f975173a7 Merge: 7f29465f3 5d5f1b487 Author: Rasmus Wriedt Larsen Date: Mon Jun 22 13:36:06 2020 +0200 Merge pull request #3743 from tausbn/python-fix-deprecated-terms Python: Fix a bunch of deprecated terms. commit 7f29465f35437b779f0227acb6127181e5c0212d Merge: e06a54c33 8d1b080d7 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Mon Jun 22 12:31:49 2020 +0100 Merge pull request #3752 from erik-krogh/limitStr Approved by asgerf commit 4853b8a281e18c0e7ae3585b18df7ff1eb284c19 Author: toufik-airane Date: Mon Jun 22 13:26:13 2020 +0200 Try to finish the PR - Add help documentation - Empty qll file - rename examples commit e06a54c33da7e19ae7faf5023d8c462c07ca1322 Merge: f2f020fa5 72e6c9c2b Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Mon Jun 22 12:09:00 2020 +0100 Merge pull request #3494 from hvitved/dataflow/partial-flow-access-path-limit Approved by aschackmull commit 5ebaa1d30337c95cd0b83da6d207487b1716507f Author: James Fletcher <42464962+jf205@users.noreply.github.com> Date: Mon Jun 22 12:07:42 2020 +0100 Apply suggestions from code review Co-authored-by: Shati Patel <42641846+shati-patel@users.noreply.github.com> commit 8d564e06d7132364daa5587da24fea9532a26c4b Author: Rasmus Lerchedahl Petersen Date: Mon Jun 22 12:16:11 2020 +0200 Python: sync data flow files commit 104298e09a092ae14c60099674b0a760c3bc6108 Merge: c18e0aa21 71665a02f Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Jun 22 10:05:14 2020 +0100 Merge branch 'master' into models5 commit 1edb2a18925460d1faf1e5405fc682e936531552 Author: Asger Feldthaus Date: Mon Jun 22 10:44:46 2020 +0100 JS: Rephrase XSS queries that use exception/dom text as source commit f2f020fa51ad255c9cb22f833ef50b4fdabf9131 Merge: 71665a02f ca86bb860 Author: Calum Grant <42069085+calumgrant@users.noreply.github.com> Date: Mon Jun 22 10:36:45 2020 +0100 Merge pull request #3610 from hvitved/csharp/dataflow/call-sensitivity C#: Add call-sensitivity to data-flow call resolution commit 94a828aca2a4a8f13dfb9b32914ca1ca5b21f5bb Merge: b65e6fba9 71665a02f Author: Rasmus Lerchedahl Petersen Date: Mon Jun 22 11:29:00 2020 +0200 Merge branch 'master' of github.com:github/codeql into SharedDataflow To avoid CodeScan check failing commit b65e6fba9ee526a28405d92ff39aff45a09545a5 Author: Rasmus Lerchedahl Petersen Date: Mon Jun 22 11:28:28 2020 +0200 Python: attempt at capturing maximal flows (this is what used to be "all flows") commit 0654823b970b35ea88a17a9faf6710c36a2422e5 Merge: f1dad0d6e eca5e2df8 Author: Esben Sparre Andreasen Date: Mon Jun 22 11:25:25 2020 +0200 Merge branch 'js-team-sprint' into js/insecure-http-options commit f1dad0d6e0aa1e1e9bb7ed51ca7d73384e397a37 Author: Esben Sparre Andreasen Date: Mon Jun 22 11:24:33 2020 +0200 Update DisablingCertificateValidation.qhelp commit 3e898487e8d13e1444e3e4e58a03ed910dd54dca Author: Esben Sparre Andreasen Date: Mon Jun 22 11:23:40 2020 +0200 Apply suggestions from code review Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com> commit cc8367bff2b7521ad11d8cc8d0a36388e9e7a1ff Author: Rasmus Lerchedahl Petersen Date: Mon Jun 22 11:22:32 2020 +0200 Python: update readme with lessons learned commit 71665a02fa7581e3e5d18e3d4004743474adb35f Merge: ac89559b2 161ba9212 Author: Anders Schack-Mulligen Date: Mon Jun 22 10:46:00 2020 +0200 Merge pull request #3737 from Marcono1234/patch-1 Simplify NoAssignInBooleanExprs.ql commit 8d1b080d7870c115e09ae9d3c3ac5334e5e17c90 Author: Erik Krogh Kristensen Date: Mon Jun 22 10:29:53 2020 +0200 limit size of `getStringValue` commit 72e6c9c2b1b4b91a900a5b73d4ae1aef51af08a4 Author: Tom Hvitved Date: Mon May 18 10:22:25 2020 +0200 Data flow: Use `accessPathLimit()` in partial flow as well commit 47819bbcdac77017a159569983632214e5dfd35b Author: Rasmus Lerchedahl Petersen Date: Mon Jun 22 07:36:09 2020 +0200 Python: obtain remaining expected flows - implement encosing callable for more nodes - implement extra flow for ESSA global variables commit a519132407db1f89a3038b7479fa119b8e1fbc44 Author: Porcupiney Hairs Date: Mon Jun 22 01:59:08 2020 +0530 add support for libxml2 commit 7166d5422e99eda1e7c5cee0ea2a9182f765b272 Author: toufik-airane Date: Sat Jun 20 17:10:35 2020 +0200 add test file for CWE-347 Add a test file for CWE-347. The HS256 algorithm is safe, but the none algorithm is unsafe. commit 8a2a33459aa9f035c1970676bf84e5f1f935c303 Merge: b0aaca0e1 ac89559b2 Author: toufik-airane Date: Sat Jun 20 16:56:27 2020 +0200 Merge branch 'master' of github.com:toufik-airane/codeql commit b0aaca0e1c41ee12d13be7bf546533050900e600 Author: toufik-airane Date: Sat Jun 20 16:54:41 2020 +0200 JWT Missing Secret Or Public Key Verification Add an experimental CodeQL query. commit 5d5f1b487bb4049136cf13967587d594f10ccba4 Merge: 410f4781b ac89559b2 Author: Taus Brock-Nannestad Date: Fri Jun 19 21:59:17 2020 +0200 Merge branch 'master' into python-fix-deprecated-terms commit eca5e2df8ae759373a55a1f0ec03beef5098e825 Merge: 1548eca99 0463c427a Author: Asger F Date: Fri Jun 19 20:35:57 2020 +0100 Merge pull request #3702 from esbena/js/memory-exhaustion JS: add query js/memory-exhaustion commit ac89559b2074cb6d0fbbf7b7cb570540bafae9cc Merge: 81d8dc15c 00f1e57d0 Author: Jonas Jensen Date: Fri Jun 19 21:19:20 2020 +0200 Merge pull request #3744 from github/p0-patch-1 Fix typo in cpp-security-extended.qls commit 00f1e57d0c34c47189ecfa403ebaef6b55d3c2bb Author: Pavel Avgustinov <54942558+p0@users.noreply.github.com> Date: Fri Jun 19 20:16:24 2020 +0100 Update cpp-security-extended.qls commit 81d8dc15cd87ddbf18385417e4901b0379d3e2b6 Merge: 573d55a16 35487ff10 Author: Jonas Jensen Date: Fri Jun 19 21:12:33 2020 +0200 Merge pull request #3693 from geoffw0/stringtest C++: Add tests of char* -> std::string -> char* conversions. commit 410f4781b34eacb1402508b3e8c6334c33dc0297 Author: Taus Brock-Nannestad Date: Fri Jun 19 20:15:01 2020 +0200 Python: Fix one last reference. This one got lost in the big renaming somehow. commit 1548eca99476e7d8adbed05c335794b25da3f0d0 Merge: e13353f26 0f5ef2c02 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Fri Jun 19 17:00:11 2020 +0100 Merge pull request #3689 from erik-krogh/https-fix Approved by mchammer01 commit 573d55a160495f41dacaef49b4de8f8f016ce355 Merge: 2081d0cec 56670f3a5 Author: Tom Hvitved Date: Fri Jun 19 17:57:52 2020 +0200 Merge pull request #3740 from github/codeql-analysis-yml Enable code scanning commit 48e3e9c0b44e7c7cf77ef6283655b100faef0a05 Author: Taus Brock-Nannestad Date: Fri Jun 19 17:02:47 2020 +0200 Python: Do all the renames. commit f02b54fcd2e65e2ea86daad7f5e393993da9e047 Author: james Date: Fri Jun 19 15:59:22 2020 +0100 docs: add more detailed qldoc style guide commit 06d6913a206a775efeb982f17ab253497cbf8baf Author: Taus Brock-Nannestad Date: Fri Jun 19 16:55:59 2020 +0200 Python: Change "sanity" to "consistency". commit 01fb1e378699fa5ab816ff13e3126e05b0f66a60 Author: Taus Brock-Nannestad Date: Fri Jun 19 16:51:09 2020 +0200 Python: Get rid of deprecated terms in code and `.qhelp`. commit 2081d0cecc171f68f5a1423f2b9ddd610e600639 Merge: 09d7ed092 21d531f81 Author: Taus Date: Fri Jun 19 16:32:23 2020 +0200 Merge pull request #3575 from RasmusWL/python-add-qldoc-FunctionValue.getQualifiedName Python: Add QLDoc for FunctionValue.getQualifiedName commit 56670f3a5fcc841a92928154ef66aaacb6c736e9 Author: Tom Hvitved Date: Fri Jun 19 16:25:23 2020 +0200 Disable analysis for JS and Python commit 09d7ed092b905a6bf8fb8f14a6dfb1cdde8a37d4 Merge: 8107fbadc 687d6d264 Author: Jonas Jensen Date: Fri Jun 19 16:03:11 2020 +0200 Merge pull request #3612 from dbartol/github/codeql-c-analysis-team/69_union C++: Share `TInstruction` across IR stages commit c18e0aa21a06f0f9bc22edd26189d78ac11e016a Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Jun 19 14:11:12 2020 +0100 C++: Add a TODO comment. commit 0f5ef2c02af8ae2ce6d55076cd267adeaf34c8cf Merge: 7d6dac479 e13353f26 Author: Erik Krogh Kristensen Date: Fri Jun 19 14:57:44 2020 +0200 Merge branch 'js-team-sprint' into https-fix commit e13353f26aaad1d2fcb0d4e8be48c80055fcadfc Merge: bfb2e9d6e a17d152ca Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Fri Jun 19 13:56:57 2020 +0100 Merge pull request #3732 from erik-krogh/priv-file-polish Approved by mchammer01 commit 4b47483263f1ae2510a059de93f01904f4993064 Author: Tom Hvitved Date: Fri Jun 19 11:39:43 2020 +0000 Add codeql-config.yml commit e46bd709c4c0834f6e54ef1d9722d99c72cabd2f Author: Erik Krogh Kristensen Date: Fri Jun 19 14:15:50 2020 +0200 add change note commit 0ee3f4977c8bf2a5b9df99d712cdf755816ceb93 Author: Erik Krogh Kristensen Date: Fri Jun 19 14:15:46 2020 +0200 add test of webpack-dev-server and monorepo import commit c860151e8d4845d433cd0eb5dc6427368d02fc30 Author: Erik Krogh Kristensen Date: Fri Jun 19 14:15:25 2020 +0200 recognize instances of express from webpack-dev-server commit 11cc97d2866bee2563b5a1c148abbef4b7d8606c Author: Erik Krogh Kristensen Date: Fri Jun 19 14:15:10 2020 +0200 add basic support for importing from neighbouring packages commit a17d152ca4a2b123d4be8487c665af870ecfc900 Merge: 6b0adf18d bfb2e9d6e Author: Erik Krogh Kristensen Date: Fri Jun 19 13:19:10 2020 +0200 Merge branch 'js-team-sprint' into priv-file-polish commit bfb2e9d6eaf769144df402c0b798069775d113cb Merge: 20e96799e dcf617b23 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Fri Jun 19 12:18:25 2020 +0100 Merge pull request #3724 from erik-krogh/bad-random-polish Approved by mchammer01 commit ffe3f500d744a4843b220f5d5bdbf82e17d141cd Author: Tom Hvitved Date: Fri Jun 19 13:01:28 2020 +0200 Restrict languages in codeql-analysis.yml commit 457588e89376edba37a33cfaa4bbee28316651f5 Author: Esben Sparre Andreasen Date: Fri Jun 19 11:56:46 2020 +0200 JS: mention MITM commit ab8d1ea723a1c4c1d0006032556de95426f427ea Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Jun 18 18:17:45 2020 +0100 C++: Model ConversionConstructor instead of all Constructors. commit 8107fbadc249e9d569075b026388cad4c7ac4c5f Merge: 4126d5b59 ad56f1724 Author: Anders Schack-Mulligen Date: Fri Jun 19 11:50:10 2020 +0200 Merge pull request #3456 from hvitved/dataflow/precise-field-types Data flow: Track precise types during field flow commit 4126d5b59ec00336e72be900685879d50fd184d5 Merge: 44637e29e baaa31665 Author: Esben Sparre Andreasen Date: Fri Jun 19 11:43:57 2020 +0200 Merge pull request #3646 from dellalibera/master [javascript] CodeQL query to detect missing origin validation in cross-origin communication via postMessage commit 426b1da552849735099c9fbc512ff32c192b8d5e Author: Rasmus Lerchedahl Petersen Date: Fri Jun 19 11:38:15 2020 +0200 Python: update sources and sinks commit a285f6460c0209766fe9ebd6489bd6baa9e50fec Author: Tom Hvitved Date: Fri Jun 19 11:34:31 2020 +0200 Create codeql-analysis.yml commit 3f4ebd285fb9662667707008879078068a7cfeee Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Jun 18 15:10:58 2020 +0100 C++: Move models into models dir. commit 9e078da9636cef5aaf7a821a87027efe99ab4557 Author: Rasmus Lerchedahl Petersen Date: Fri Jun 19 11:25:34 2020 +0200 Python: Better definition of all flows does not become too big, when we filter out 0-step flows commit e0651b2c194b919cc7d3a594f90d048095d20ddb Merge: eebaf0f33 44637e29e Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Jun 19 10:15:25 2020 +0100 Merge remote-tracking branch 'upstream/master' into models5 commit eebaf0f3309e587f2068327f139673e7daa82e79 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri Jun 19 10:15:01 2020 +0100 C++: Modify the tests so that ConversionConstructors are tested; we don't want the general case for Constructors any more. commit ca86bb8603e344ea79fbf85d0cd07880cddf2fe9 Author: Tom Hvitved Date: Fri Jun 19 10:34:11 2020 +0200 Address review comments commit 0463c427a52a356fcab8e2372519556664f91eec Author: Esben Sparre Andreasen Date: Fri Jun 19 09:47:59 2020 +0200 Update javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com> commit b8229ca362a38a0ab35ffc22a50a1a68c1c1f1e0 Author: Esben Sparre Andreasen Date: Fri Jun 19 09:47:48 2020 +0200 Update javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com> commit e73beccc0b4f777418f62bf4806eeb5d0da4809f Author: Esben Sparre Andreasen Date: Fri Jun 19 09:47:26 2020 +0200 Update javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com> commit 2846666f3267129d7a0e814468c1a70afe79820e Author: Esben Sparre Andreasen Date: Fri Jun 19 09:47:13 2020 +0200 Update javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com> commit 4557af3c304c8566d1f4e603e79734f769cc9a1e Author: Esben Sparre Andreasen Date: Fri Jun 19 09:46:58 2020 +0200 Update javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com> commit baaa31665a545b65843fa9e6b4b0e69d53c64fa8 Author: Esben Sparre Andreasen Date: Fri Jun 19 09:05:13 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp commit 5ca6391f150f19eac150688a03442858e478b93c Author: Rasmus Lerchedahl Petersen Date: Fri Jun 19 07:49:47 2020 +0200 Python: update call graph test we also have flow into functions! commit 5a864aab8773deb50df385a5cdef20a70addab0d Author: Rasmus Lerchedahl Petersen Date: Fri Jun 19 07:29:46 2020 +0200 Python: override `genEnclosingCallable` achieved flow out of functions! commit eba64dba7cc0f2f490e73deca02fe4033fa1150c Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Thu Jun 18 19:44:46 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql Co-authored-by: Esben Sparre Andreasen commit c0271b16278f0749f430dcd051c2ef006be198ed Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Thu Jun 18 19:44:38 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp Co-authored-by: Esben Sparre Andreasen commit ffc9a449ab13272694b9a832689053a24b6847ae Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Thu Jun 18 19:43:45 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp Co-authored-by: Esben Sparre Andreasen commit e84339d5bfce450a2ab25b6827672e4e23708ac9 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Thu Jun 18 19:43:36 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp Co-authored-by: Esben Sparre Andreasen commit 71a7ec593c4f45028b653c7ef90297af75f42098 Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Thu Jun 18 19:41:07 2020 +0200 Use StringOps to identify functions used for verifing the origin commit cc9102687379dc091efb09868981833cbd0bb7cb Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Thu Jun 18 19:31:11 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll Co-authored-by: Marcono1234 commit b4f255176a0a7c4841eec0aaa66953c0453ad632 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Thu Jun 18 19:29:34 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-117/LogInjection.help Co-authored-by: Marcono1234 commit 7d6dac479c9dbce715263ff8ef9deb7d269189d5 Merge: 27a20b263 20e96799e Author: Erik Krogh Kristensen Date: Thu Jun 18 16:53:01 2020 +0200 Merge branch 'js-team-sprint' into https-fix commit dcf617b235fdf6f810c2b35b3b74a203a6affef0 Merge: 218338b4f 20e96799e Author: Erik Krogh Kristensen Date: Thu Jun 18 16:52:32 2020 +0200 Merge branch 'js-team-sprint' into bad-random-polish commit 6b0adf18d1bf6eaea113b8e8c8df5c40b49578d4 Author: Erik Krogh Kristensen Date: Thu Jun 18 16:51:15 2020 +0200 rewrite sentence in private-file-exposure qhelp commit 1556b62007c26176fc1fbe324cbd68a408295228 Merge: 9ba2c98ec 20e96799e Author: Erik Krogh Kristensen Date: Thu Jun 18 16:40:53 2020 +0200 Merge branch 'js-team-sprint' into priv-file-polish commit 9ba2c98ec0a38088e15b1f46aa437f7c1f0df9f1 Author: Erik Krogh Kristensen Date: Thu Jun 18 16:38:52 2020 +0200 Apply suggestions from doc review Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com> commit 20e96799e227878b049c48533a16506ffc401c6a Merge: 6d6f29eb8 bdda58724 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Thu Jun 18 15:32:45 2020 +0100 Merge pull request #3661 from erik-krogh/build-leaks Approved by asgerf, mchammer01 commit 44637e29eec2dffa4a6de860e85bf2883f3d2298 Merge: 03c6d7a7e c0043eb9d Author: Taus Date: Thu Jun 18 16:05:50 2020 +0200 Merge pull request #3716 from RasmusWL/python-fix-re-escape-fp Python: Fix FP in treating re.escape as regex commit 161ba92123e760a69ac139d9eac3fbb542a6951f Author: Marcono1234 Date: Thu Jun 18 15:16:09 2020 +0200 Simplify NoAssignInBooleanExprs.ql commit 9669a6a4dc1719c33e8db58dffce5fc1793eab33 Author: Rasmus Lerchedahl Petersen Date: Thu Jun 18 15:10:45 2020 +0200 Python: test for `getASuccessor` also align test names commit 03b26f7ebe322c226f1a6de67d47f9e0eea32155 Author: Rasmus Lerchedahl Petersen Date: Thu Jun 18 13:58:47 2020 +0200 Python: Remove excessive type pruning commit ab01dda5590c3eb90e6c4a53b28d9a4fd07f9e95 Author: Esben Sparre Andreasen Date: Tue Jun 16 12:33:42 2020 +0200 JS: another qhelp fixup commit c9f60d4c97829c52ba3b18f4e7bff4ce1eef92a8 Author: Esben Sparre Andreasen Date: Tue Jun 16 11:32:01 2020 +0200 JS: add lodash sinks for js/resource-exhaustion commit 96160a6334a1c17c020e6217fe306ed1d0fa7108 Author: Esben Sparre Andreasen Date: Tue Jun 16 11:13:01 2020 +0200 JS: fixup qhelp commit 3f67e90374e8d07161037e6537ce621798fd174e Author: Esben Sparre Andreasen Date: Tue Jun 16 10:05:55 2020 +0200 JS: rename query, support timeouts, add documentation, add to suite commit d9d8eb4805fe122dda9170bedb18d2face8494a2 Author: Esben Sparre Andreasen Date: Mon Jun 15 14:57:59 2020 +0200 JS: avoid type inference in the taint steps (just a nice to have) commit fa4e8914e660585ce711479c209102f8947462f4 Author: Esben Sparre Andreasen Date: Fri Jun 12 14:45:57 2020 +0200 JS: fixups commit 7b97fd07a83ebaea671f391370731f7e58079c2c Author: Esben Sparre Andreasen Date: Fri Jun 12 10:52:20 2020 +0200 JS: add query js/memory-exhaustion commit 17d36cf363d2486d5d7e4fdb12b89389ae9dc4fe Author: Robin Neatherway Date: Thu Jun 18 11:26:36 2020 +0100 Exclude dependency-based query from C# Code Scanning This query overlaps with tools such as dependabot. commit 44aa182d0d76436582c1d3025bf183761ff8fce4 Author: Esben Sparre Andreasen Date: Thu Jun 18 10:14:16 2020 +0200 Update change-notes/1.25/analysis-javascript.md Co-authored-by: Asger F commit 5e31f3a34e9eabc31faaa90475bb745f1cfedae7 Author: Esben Sparre Andreasen Date: Thu Jun 18 09:03:29 2020 +0200 JS: polish js/disabling-certificate-validation commit 1562f5c69a649a7bd605668169ef7270a49580f7 Author: Rasmus Lerchedahl Petersen Date: Thu Jun 18 07:52:29 2020 +0200 Python: General comment on dataflow between SSA variables and control flow nodes commit d283919b9202a78349a4eca24e988c3ef39283b8 Author: Rasmus Lerchedahl Petersen Date: Thu Jun 18 07:45:16 2020 +0200 Python: implemented ParameterNode, updated test commit 41c029567fb9ebe083d98acb10d00b8a6dd41bde Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Wed Jun 17 21:16:24 2020 +0200 Add CodeQL query to detect Log Injection in JS code commit 27a20b263ef3f41c88ba03cd06af8b46893e622e Merge: 7a1c161e9 fb5e13b45 Author: Erik Krogh Kristensen Date: Wed Jun 17 21:06:21 2020 +0200 Merge branch 'https-fix' of github.com:erik-krogh/ql into https-fix commit 7a1c161e9e908180a161ebf121150bcdd118da2f Merge: e8db624e7 6d6f29eb8 Author: Erik Krogh Kristensen Date: Wed Jun 17 21:04:44 2020 +0200 Merge branch 'js-team-sprint' into https-fix commit 218338b4f10c5541673c4286105c80838229c6e1 Merge: d811518a2 6d6f29eb8 Author: Erik Krogh Kristensen Date: Wed Jun 17 21:04:00 2020 +0200 Merge branch 'js-team-sprint' into bad-random-polish commit 73f26956a605d3c7f5f0e4efc2c81694021573c4 Merge: b0be0eb80 6d6f29eb8 Author: Erik Krogh Kristensen Date: Wed Jun 17 21:03:09 2020 +0200 Merge branch 'js-team-sprint' into priv-file-polish commit c20219c2b93231abf1bcaa2714a774c6838b7a9f Author: Rasmus Lerchedahl Petersen Date: Wed Jun 17 20:48:06 2020 +0200 Python: more local flow and more tests commit 35487ff1098c6f6325eddbff0bdf02e5675d611e Merge: 174fdadbf 03c6d7a7e Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Jun 17 19:00:26 2020 +0100 Merge branch 'master' into stringtest commit bdda5872474e42f362b1e10f5c0202b3489cc35c Merge: 69888f90c 6d6f29eb8 Author: Erik Krogh Kristensen Date: Wed Jun 17 19:51:30 2020 +0200 Merge branch 'js-team-sprint' into build-leaks commit c490cfdfa59dbb02e0fd5d248dac50db3fe655b8 Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Wed Jun 17 19:51:14 2020 +0200 Create another branch commit 6d6f29eb85bed7150b6aad92dd469152067938a9 Merge: ac1a0d992 a465fef7a Author: Erik Krogh Kristensen Date: Wed Jun 17 19:45:37 2020 +0200 Merge pull request #3726 from erik-krogh/bad-code-polish JS: Bad code polish commit 4ccfdef71d77e3567873fbaff3fc41bfd80658d7 Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Wed Jun 17 19:44:58 2020 +0200 Add CodeQL query to detect Log Injection in JS code commit 174fdadbf5435fe922d3660321c2344ff74e257b Merge: 40c20f273 3728e1afd Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Jun 17 18:24:30 2020 +0100 Merge branch 'master' into stringtest commit ce57a28c8f1a835169e75b7f7f97acd57dcbe03c Author: Rasmus Lerchedahl Petersen Date: Wed Jun 17 19:12:10 2020 +0200 Python: Use `CallableValue` and improve tests commit 03c6d7a7e5870aa653a04d869f2f83c7b697a6e0 Merge: 01abaf373 17737cd87 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Jun 17 17:53:10 2020 +0100 Merge pull request #3654 from jbj/controlsBlock-perf C++: Speed up IRGuardCondition::controlsBlock commit f24dc69e1d0686cc577d1df9800d51e36a26db35 Author: Rasmus Lerchedahl Petersen Date: Wed Jun 17 18:36:50 2020 +0200 Python: add flow from `ArgumentNode`s commit a45b5a7d3c485a44a0ed5f8aa2d099e10a94ab85 Author: Rasmus Lerchedahl Petersen Date: Wed Jun 17 17:41:43 2020 +0200 Python: Implemented return node but I think they receive no flow commit ad56f172462d0196dd337f216a6cdcd311f08df5 Merge: cd9538d0d 74eab3cbc Author: Tom Hvitved Date: Wed Jun 17 17:26:04 2020 +0200 Merge pull request #2 from aschackmull/dataflow/content-type-tracking Dataflow: Record content types commit a465fef7aa8780b5f168fc88568718272d513f09 Author: Erik Krogh Kristensen Date: Wed Jun 17 17:24:18 2020 +0200 shorten sentence in qhelp commit 74eab3cbc0e634956d3e2121007f3e699d8f85dd Author: Anders Schack-Mulligen Date: Wed Jun 17 17:23:35 2020 +0200 Dataflow: Fix qltest. commit 7aa911b9f4d03d895ad1963cc049a529b3e89bc7 Author: Erik Krogh Kristensen Date: Wed Jun 17 17:20:27 2020 +0200 add reference to cwe-116 in change-note commit abd9aab109b8ff1bcdca83628b53ee480e5309cb Author: Erik Krogh Kristensen Date: Wed Jun 17 17:17:29 2020 +0200 code-injection -> code injection commit 45e2b94eb53d55fcdab1639dda924f0f0cf7eb50 Author: Erik Krogh Kristensen Date: Wed Jun 17 17:19:44 2020 +0200 Apply suggestions from doc review Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com> commit 69888f90c658fe026245e15b0e66f2312ba15e84 Author: Erik Krogh Kristensen Date: Wed Jun 17 16:35:28 2020 +0200 add dot after bullet-point commit cedfaf6aafa5e3aef082c1b9b4a51fdf06734614 Author: Anders Schack-Mulligen Date: Wed Jun 17 17:09:55 2020 +0200 Dataflow: autoformat commit 543ab71dfe50b9807367941d511d3008b1187c97 Author: Anders Schack-Mulligen Date: Wed Jun 17 17:03:22 2020 +0200 Dataflow: minor review fixes. commit 25d624d64b17c293d737a2ae7a2d8249a4bbe896 Author: Rasmus Lerchedahl Petersen Date: Wed Jun 17 16:59:19 2020 +0200 Python: Implement parameter nodes commit 33fab089751c05b67b1a261948dfb8f141a57b35 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Jun 17 15:53:05 2020 +0100 C++: Autoformat. commit 687d6d264336b2f4b1f92f09ce32a279d4166ec6 Author: Dave Bartolomeo Date: Wed Jun 17 10:52:32 2020 -0400 C++: Replace `TRawInstruction()` calls Replace most direct calls to `TRawInstruction()` with calls to `getInstructionTranslatedElement()` and `getInstructionTag()`, matching existing practice. One tiny RA diff in an inconsequential join order in `getInstructionVariable`. commit 833f5b0cf3cb8a1b06b3167f1a752bf2eb2b2a70 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 16 17:14:09 2020 +0100 C++: Add flow through assignment operators. commit b9a65581ce61fe761cc9881b545944baf85ce99e Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 16 15:06:53 2020 +0100 C++: Some constructors should have dataflow instead of taint. commit 031c9b98f1b6bbe5953fb8069697b9e7952326b2 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 16 15:00:30 2020 +0100 C++: General taint flow through constructors. commit 30151c99d7e6811803d29ad26cba17a6dc27955e Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 16 12:18:47 2020 +0100 C++: Remove the std::string Constructor model. commit 8e51b2fed8a14a97da97af6a247cdbae8e145cc5 Author: Rasmus Lerchedahl Petersen Date: Wed Jun 17 16:43:11 2020 +0200 Python: refactor test for global flow commit d565cfc58ea7e49421bf66f3c76c1720f6016afd Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 16 11:27:15 2020 +0100 C++: Add a test of default constructors etc. commit c196ea24b29937fff58d1bf55cba1a9ccac6decf Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Jun 15 23:05:07 2020 +0100 C++: Add taint tests of class constructors and assignment. commit ea9e9a7a263db70b0e514d17d6736651a111704b Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon Jun 15 22:52:35 2020 +0100 C++: Add taint tests of std::string constructors and assignment. commit c1016743a5701d85333b055e2f7011fb68769af1 Author: Dave Bartolomeo Date: Wed Jun 17 10:25:59 2020 -0400 C++: Remove `instructionOrigin()` This noopt predicate is no longer necessary. It's equivalent to `instruction = TRawInstruction(element, tag)`, which is already materialized and has a more favorable column order anyway. commit 71f364eef303afc49f5d40dcae40bded27d13633 Author: Rasmus Lerchedahl Petersen Date: Wed Jun 17 16:24:44 2020 +0200 Python: Implement OutNode Also, fix test for local flow commit e85cc0b0c6b2ad0c55bb7cd52517710834872cec Author: Dave Bartolomeo Date: Wed Jun 17 09:47:48 2020 -0400 C++: Stop caching raw IR construction predicates These predicates are only used within the new single IR stage, so there's no need to cache them beyond that. RA diffs are trivial. Where previously many of the predicate on `Instruction` were inline wrappers around cached predicates from `IRConstruction`, now the predicates from `IRConstruction` get inlined into the `Instruction` predicates, and the `Instruction` predicates get materialized. The net amount of work is the same, but now it's not getting cached unnecessarily. commit d28b5ace63369dc7f5658870bb660f82a807abc3 Author: Anders Schack-Mulligen Date: Wed Jun 17 15:40:11 2020 +0200 Dataflow: Sync. commit 10b64fc47a65871aca751404240408dde3b292e1 Author: Anders Schack-Mulligen Date: Wed Jun 17 15:15:30 2020 +0200 Dataflow: Record content type for stores. commit 01abaf373aedf5c5067bec937b1773068fdca149 Merge: a87ff80ac 7edaade17 Author: Mathias Vorreiter Pedersen Date: Wed Jun 17 14:54:33 2020 +0200 Merge pull request #3728 from geoffw0/memberfunctions C++: Split MemberFunction.qll from Function.qll. commit a87ff80ac0d5aec345fa252ae246379a5f5b1029 Merge: cd111fe35 ef940e815 Author: Jonas Jensen Date: Wed Jun 17 13:27:35 2020 +0200 Merge pull request #3587 from rdmarsh2/ir-this-parameter-2 C++: IR return indirections for `this` commit 7edaade175ac01067cf4e05ce0272659c02fc501 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Jun 17 12:11:42 2020 +0100 C++: Improve QLDoc. commit cd111fe3506cbf185e812fde3c454c4f9613ebbd Merge: ab327b989 23d28967a Author: Erik Krogh Kristensen Date: Wed Jun 17 13:10:56 2020 +0200 Merge pull request #3721 from asger-semmle/js/non-linear-pattern-msg JS: Improve alert message in js/non-linear-pattern commit 0a9ec70c31eaf397daf25df8b339f54d133346cb Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Jun 17 11:54:50 2020 +0100 C++: Autoformat. commit b0be0eb805a5cb42492c5d33b9a7e07197cdf07d Author: Erik Krogh Kristensen Date: Wed Jun 17 11:50:44 2020 +0200 fix qhelp links commit fa0a8c3423f57cf949fddfa839d7ee6a44495a62 Author: Erik Krogh Kristensen Date: Wed Jun 17 11:37:32 2020 +0200 add documentation examples as tests commit b42824640d0b6982d324168262042c98131ddfad Author: Erik Krogh Kristensen Date: Wed Jun 17 11:29:24 2020 +0200 add qhelp for js/exposure-of-private-files commit f3e24963cb9b25b12db2eca0378c0d0ce2f29161 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Jun 17 10:27:34 2020 +0100 C++: Update QLDoc. commit 22cb45beab39796a2654f7e2678c8ad7a822ec39 Merge: 3104f8a37 ab327b989 Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Wed Jun 17 11:13:13 2020 +0200 Merge remote-tracking branch 'upstream/master' commit 345283fe3486649f15a0b449fcc9c93d2c601565 Author: Erik Krogh Kristensen Date: Wed Jun 17 10:48:27 2020 +0200 add change note commit 639907967f27406b417571ee5f38a1fc6514a349 Author: Erik Krogh Kristensen Date: Wed Jun 17 10:46:42 2020 +0200 add home/rootdir as leaking folders commit 6675ddae121c13648a18739481d1d0cd6095b0b5 Author: Erik Krogh Kristensen Date: Wed Jun 17 09:58:32 2020 +0200 add more libraries that serve static files to js/exposure-of-private-files commit e0ba23d2c7e569a317e59e28b1272763d1faa95b Author: Jonas Jensen Date: Tue Jun 16 16:47:33 2020 +0200 C++: @precision high for tainted-format-string* I think these queries have excellent results on lgtm.com. Many of the results come from projects that use `sprintf` like it's a templating engine, trusting that values from `argv` or `getenv` contain the correct number of `%s`. I think we want to flag that. The structure of the change note is modeled after 91af51cf46. commit 52898f16f54c25a3c0492481d8b66db0f6a3b7bf Author: Rasmus Lerchedahl Petersen Date: Wed Jun 17 08:34:45 2020 +0200 Python: update paths after move commit 47f5b04e875ef3358d81f26606140e1552836490 Author: Rasmus Lerchedahl Petersen Date: Wed Jun 17 07:08:46 2020 +0200 Python: fix `identical-files.json` after move also more grouping commit e192b66116276907aed1a9423306b1d1a12b258e Author: Rasmus Lerchedahl Petersen Date: Wed Jun 17 06:46:46 2020 +0200 Python: move shared dataflow to `experimental` commit f40e27a3c5bd9e8ad8a87a5b5a0262c97fcecf15 Author: luchua-bc Date: Wed Jun 17 02:46:02 2020 +0000 Hardcoded AWS credentials commit fb5e13b456a664d04643a2fe63aa87545e17f859 Author: Erik Krogh Kristensen Date: Tue Jun 16 23:45:45 2020 +0200 Apply suggestions from doc review Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com> commit d811518a2eb0f5a659ca944416d7215614b4f612 Author: Erik Krogh Kristensen Date: Tue Jun 16 23:26:22 2020 +0200 fixed from doc review, and add fixed example for js/biased-cryptographic-random using a secure library commit 8e977dc6bf8d27d02b26dfb9a40987fb2c490d32 Author: Dave Bartolomeo Date: Tue Jun 16 16:48:42 2020 -0400 C++/C#: Move overrides of `IRType::getByteSize()` into leaf classes See https://github.com/github/codeql/pull/2272. I've added code comments in all of the places that future me will be tempted to hoist these overrides. commit 24c3110989407cfd76d92e513de93cdf2ef2847a Merge: 89a1fd4b4 e5e373cff Author: Dave Bartolomeo Date: Tue Jun 16 16:37:38 2020 -0400 Merge from `master` commit 210e71cd9388b8ababb97c119c68c68d53534f66 Author: Erik Krogh Kristensen Date: Tue Jun 16 21:52:59 2020 +0200 update expected output commit ef940e815f74388ee80a4cfaebbb5972e1b98088 Author: Robert Marsh Date: Tue Jun 16 11:46:14 2020 -0700 C++: Add comment for false positives in swap tests commit 0c99b3644c871e3a7de797ad7c47e7e93487285c Author: Robert Marsh Date: Tue Jun 16 11:33:26 2020 -0700 C++: remove false negative comments in swap tests commit 1c9b6f0a48ff6c19ea597a585c353626fe5ed2fa Merge: 65f4ef712 ab327b989 Author: Robert Marsh Date: Tue Jun 16 11:28:49 2020 -0700 Merge branch 'master' into ir-this-parameter-2 Accept test changes - dataflow changes are all positive commit 3d75d287a941a8fbe9ec7338f725fd567a0749bc Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue Jun 16 11:48:40 2020 +0100 C++: Split MemberFunction.qll from Function.qll. commit 3104f8a37b2d0e1475557a8098b4505eafce4cb0 Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Tue Jun 16 18:30:00 2020 +0200 Remove Fields in PostMessageEvent commit 68b2a6c8482fd3e64d9ad3de744a61d30914ef18 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Tue Jun 16 18:27:21 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql Co-authored-by: Esben Sparre Andreasen commit 8843522d143bd1dd46d1908b56c4f71e5bc34b51 Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Tue Jun 16 18:26:42 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql Co-authored-by: Esben Sparre Andreasen commit 72dc6510b2a8e55ca6ba4416e2ce4733b6e49d8f Author: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Tue Jun 16 18:22:55 2020 +0200 Update javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql Co-authored-by: Esben Sparre Andreasen commit ab327b989d9bc81fd1fcf8b8fc99264893ca46a6 Merge: e5e373cff c30d1a618 Author: Robert Marsh Date: Tue Jun 16 09:09:46 2020 -0700 Merge pull request #3713 from MathiasVP/flow-diff-test C++: Add test for differences between AST and IR field flow commit ac1a0d992508327f420fe601689cd68b07dbdc5a Merge: b6b838774 cb5b94654 Author: Erik Krogh Kristensen Date: Tue Jun 16 16:28:43 2020 +0200 Merge pull request #3725 from erik-krogh/yargs-changenote JS: add changenote for yargs commit 02c825351c7191a3aae71f9c1eb282461ab2e43c Author: Erik Krogh Kristensen Date: Tue Jun 16 16:25:30 2020 +0200 add change note for js/bad-code-sanitization commit 5ce17bea60227ce13fb7a4a66bf86d31e98ff839 Author: Erik Krogh Kristensen Date: Tue Jun 16 16:23:41 2020 +0200 add qhelp for js/bad-code-sanitization commit e5e373cff2cb9223d0ad1375fa26779fefe6f423 Merge: 07bff646d a38839b44 Author: Jonas Jensen Date: Tue Jun 16 15:43:52 2020 +0200 Merge pull request #3673 from MathiasVP/assign-op-using-swap C++: Add tests for taint through swap commit 0f77403f0e3339ca9c562ae81ebf5778032bf89a Author: Rasmus Lerchedahl Petersen Date: Tue Jun 16 15:36:03 2020 +0200 Python: small start on global flow need to actually have `OutNode`s commit a0951f76b6045ff466bcfb2d90e50f9bdb54f960 Author: Erik Krogh Kristensen Date: Tue Jun 16 14:55:07 2020 +0200 add additional taint steps when type-tracking RemoteFlowSource commit 07bff646d856feca5eb1b7683d5a8288fb4b47f5 Merge: d80a033be c7f74e47e Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Tue Jun 16 13:41:55 2020 +0100 Merge pull request #3641 from asger-semmle/js/pre-call-graph-steps Approved by erik-krogh commit cb5b946546b038cf7525fbcd0ce009fff5deee16 Author: Erik Krogh Kristensen Date: Tue Jun 16 14:37:53 2020 +0200 add changenote for yargs commit 17737cd87226750cfab6a42cb9d9bcdf03842aeb Author: Jonas Jensen Date: Tue Jun 16 14:33:12 2020 +0200 C++: Account for unreachable blocks in guards This restores the code I removed in 4642037dc. commit f3e879a5ab0ba54a6ab13873f5d30382e01966c4 Author: Rasmus Lerchedahl Petersen Date: Tue Jun 16 14:31:22 2020 +0200 Python: small test of local flow commit 696879653a4b3d829f039e4e6ab265d879ea03b5 Author: Erik Krogh Kristensen Date: Tue Jun 16 11:07:43 2020 +0200 add qhelp to js/biased-cryptographic-random commit 2978af34cdda413a4ece8bf3ff1901e0e2992b27 Author: lcartey@github.com Date: Mon May 18 00:31:45 2020 +0100 Java: Add RestTemplate as flow source. commit f2edc5314417cd44a09e840906b9053323c7deec Author: lcartey@github.com Date: Mon May 18 00:30:47 2020 +0100 Java: Add Spring RestTemplate return values to untrusted data types - Also improve unwrapping of lists/arrays/maps etc. commit 9625e82afdf904bc8472cbdff1dafeb408f95248 Author: lcartey@github.com Date: Mon May 18 00:30:14 2020 +0100 Java: Model Spring WebClients/RestTemplates. commit cd6339f5cdb5c8aa1b295295cde5ff760942b7c1 Author: lcartey@github.com Date: Mon May 18 00:25:14 2020 +0100 Java: Add Spring flow out of HttpEntity and HttpHeader commit 93c28d4c03a14893b8fc3b2bb42ced435bb8d349 Author: lcartey@github.com Date: Sun May 17 23:29:13 2020 +0100 Java: Add taint step to flow through Spring tainted user data class getters. commit 8678d5fc6f2e225192b8b7f69a15314c3356d012 Author: lcartey@github.com Date: Sun May 17 23:28:49 2020 +0100 Java: Model untrusted user data types Model the datatypes that may be populated on demand from request parameters. commit 8bd5f748b468509b68040503ede0ed55bb34ba92 Author: lcartey@github.com Date: Sun May 17 22:36:50 2020 +0100 Java: SpringController - handle non-string literal produces values. commit 0db7cead31872b16950cf7e7fa48510892af132b Author: lcartey@github.com Date: Sun May 17 21:47:34 2020 +0100 Java: Model taint flow through ResponseEntity. commit f6b2accabdf745f3c72d81f205cd577fcd9c09d0 Author: lcartey@github.com Date: Sun May 17 21:47:10 2020 +0100 Java: Model ResponseEntity.BodyBuilder commit e2cec582be9f632b7df2fcd5a9dc0f5bfd0b8208 Author: lcartey@github.com Date: Sun May 17 21:45:42 2020 +0100 Java: XSS - ignore Spring sinks when content-type is safe. Methods annotated with a produces field which indicates a safe content-type should not be considered XSS sinks. For example: @RequestMapping(..., produces = "application/json") commit f6a99cb42ee82b73c16a5952f9661828bf11fb80 Author: lcartey@github.com Date: Sun May 17 21:45:17 2020 +0100 Java: Model produces parameter to RequestMapping attribute. commit 8057dff3684201bb5eaf4f5c4598d0b08f5a6a46 Author: lcartey@github.com Date: Sun May 17 17:59:34 2020 +0100 Java: Add Spring XSS sinks Look for Spring request methods which return a String value which may be coerced into a text/html output. commit c59042f9c392c20a4a3a0bd89f2c273d1aac1c39 Author: lcartey@github.com Date: Sun May 17 17:59:06 2020 +0100 Java: Taint tracking through String.replace(all)? commit 7d555a7467d974de1c496f0868bc8e88ec994aff Author: lcartey@github.com Date: Sun May 17 17:58:28 2020 +0100 Java: Track flow through HttpEntity and ResponseEntity - Only track if the body is a String type, as that is the only type at risk of XSS. commit 1d1234093f2a7aec963b84919b901c0189b13b88 Author: lcartey@github.com Date: Sun May 17 17:57:38 2020 +0100 Java: Model Spring @ResponseBody methods. commit fd2cd6025d3d2a4ba6b8f718f17f36b0a114f081 Author: lcartey@github.com Date: Sun May 17 17:57:12 2020 +0100 Java: Modelling of the Spring HTTP classes. commit bfcc06dd0be2d90490a0064ea16c86fb9f903595 Author: lcartey@github.com Date: Sun May 17 14:47:16 2020 +0100 Java: Improve Spring controller modelling - Identify ModelMaps correctly - Add extra not tainted param types (Pageable) - Identify ModelAttributes commit 7c4251deacecb12b49ce62810d23866d4e07a4c7 Author: lcartey@github.com Date: Fri May 15 17:27:07 2020 +0100 Java: Add flow out of Map and List commit 6de2b93f3a03022c25bda20a08b9658cf779edea Author: lcartey@github.com Date: Fri May 15 17:24:02 2020 +0100 Java: Add SpringWebRequest to RemoteTaintedMethod commit 4300bc8088ce2359bb5fc9600ae9f4be8339a341 Author: lcartey@github.com Date: Fri May 15 16:43:04 2020 +0100 Java: Update RemoteFlowSource to use improve Spring request parameter mapping. commit f5dc0337edda85b24f9ffeec9c589648233a8e8a Author: lcartey@github.com Date: Fri May 15 16:41:50 2020 +0100 Java: Improve modelling of Spring request methods - Recognise @Mapping as well as @RequestMapping. - Identify tainted/not tainted parameters of RequestMapping methods. commit c30d1a618e5d371a7ece49ad2d09eceaff36af1d Author: Mathias Vorreiter Pedersen Date: Tue Jun 16 09:55:37 2020 +0200 C++: Add charpred to partial definition node classes in qltest commit d80a033bed070c98ce91b74986098297e5e11ab1 Merge: d7d00bddf 881b3c8e3 Author: Jonas Jensen Date: Tue Jun 16 08:48:35 2020 +0200 Merge pull request #3719 from dbartol/github/codeql-c-analysis-team/69-consistency C++/C#: Fix a couple new consistency failures, and improve consistency messages commit 0abba238cc9f35c6c572858da80ab167935b2b54 Author: Rasmus Lerchedahl Petersen Date: Tue Jun 16 08:21:32 2020 +0200 Python: bit more local flow and fix ql docs commit ad04ec554a9d45c21d1f469c1618eafaecd272b5 Author: Rasmus Lerchedahl Petersen Date: Tue Jun 16 07:30:44 2020 +0200 Python: group related predicates also restore accidentally removed comment commit c2052ed152265ec2476a323bf9da08a42ca2a00e Author: Jonathan Leitschuh Date: Mon Jun 15 22:29:30 2020 -0400 Add .gitignore for VS Code Generated maven project files When VS Code detects a Maven project, it automatically generates a bunch of Eclipse files to describe the project. These are now ignored in order to not pollute the repository commit 5e060fa6a87ffb9c4015929f725d6471a8a48426 Author: Erik Krogh Kristensen Date: Mon Jun 15 23:47:40 2020 +0200 Apply suggestions from code review Co-authored-by: Asger F commit 315faaffee72501f6d8a1a079b612ba37611394f Author: Erik Krogh Kristensen Date: Mon Jun 15 23:40:27 2020 +0200 small corrections in documentation Co-authored-by: Asger F commit 23d28967a7cc8dd1489d26fd1ee2c18968ed78fb Author: Asger Feldthaus Date: Mon Jun 15 20:40:17 2020 +0100 JS: Autoformat commit 3242f5ed94735109448541bb9a39cd3942a07064 Author: Asger Feldthaus Date: Mon Jun 15 17:37:26 2020 +0100 JS: Include qhelp example in test suite commit 824054ba62e9b4bf65950ce81ab47543dbd2e7d5 Author: Asger Feldthaus Date: Mon Jun 15 17:34:36 2020 +0100 JS: Change note and updated help commit 7091a9f704bf00968074edf1a3b0601f19a0e488 Author: Asger Feldthaus Date: Mon Jun 15 17:17:47 2020 +0100 JS: Special-case alert message for type annotations commit c8ab69af110e516234a432eb6cc93cb2441a806e Author: Asger Feldthaus Date: Mon Jun 15 16:57:54 2020 +0100 JS: Avoid duplicate alerts commit f38089812675dde0ffe1067ef402465b500b1eef Author: Asger Feldthaus Date: Mon Jun 15 16:40:37 2020 +0100 JS: Add test showing duplicate alerts commit d7d00bddf6ce3e69aedf019e36fb506036ea2cb2 Merge: f9db197e1 1033d22d1 Author: Aditya Sharad <6874315+adityasharad@users.noreply.github.com> Date: Mon Jun 15 08:39:16 2020 -0700 Merge pull request #3718 from adityasharad/cpp/formatting-function-doc C++: Fix QLDoc on `FormattingFunction` library commit 51d143d6f1f89f371f8fc276bb379aa981be04f5 Author: Asger Feldthaus Date: Mon Jun 15 16:35:36 2020 +0100 JS: Add test with destructuring pattern that looks like type annotations commit 881b3c8e336830201bbf6f4f9d74957dbb75009c Author: Dave Bartolomeo Date: Mon Jun 15 09:13:26 2020 -0400 C#: Fix IR consistency errors We were creating a `TranslatedFunction` even for functions that were not from source code, but then telling the IR package that those functions didn't have IR. This resulted in having prologue/epilogue instructions (e.g. `EnterFunction`, `ExitFunction`) with no enclosing `IRFunction`. commit f9db197e173f69a58cc156387f333e3c42075ea6 Merge: 3728e1afd ab5201067 Author: Owen Mansel-Chan <62447351+owen-mc@users.noreply.github.com> Date: Mon Jun 15 16:25:25 2020 +0100 Merge pull request #3683 from owen-mc/improve-ast-class-reference-for-java Improve ast class reference for java commit 23223fc5fbfa1adccbcd882722759ff90f424875 Author: Erik Krogh Kristensen Date: Mon Jun 15 17:22:11 2020 +0200 change-note commit 3ef5dc74a1ed1641eb16de25c2e709946c36e78c Author: Erik Krogh Kristensen Date: Mon Jun 15 17:10:10 2020 +0200 add backtracking to find division that end up being rounded commit e8db624e749a09777bf383e61e7e3026031e665e Author: Erik Krogh Kristensen Date: Mon Jun 15 16:48:07 2020 +0200 add .jar and .war to the list of sensitive files for js/insecure-download commit fecffab8e78073f0bca433b5ecd2b31cd4278e1e Author: Dave Bartolomeo Date: Sun Jun 14 12:04:40 2020 -0400 C++: Fix consistency error `TTranslatedAllocationSideEffects` wasn't limiting itself to functions that actually have IR, so it was getting used even in template definitions. commit 8cbc7e8654962302d3aca73ca1de3f38afe84f04 Author: Dave Bartolomeo Date: Sun Jun 14 11:54:57 2020 -0400 C++/C#: Improve consistency failure result messages Some of our IR consistency failure query predicates already produced results in the schema as an `@kind problem` query, including `$@` replacements for the enclosing `IRFunction` to make it easier to figure out which function to dump when debugging. This change moves the rest of the query predicates in `IRConsistency.qll` to do the same. In addition, it wraps each call to `getEnclosingIRFunction()` to return an `OptionalIRFunction`, which can be either a real `IRFunction` or a placeholder in case `getEnclosingIRFunction()` returned no results. This exposes a couple new consistency failures in `syntax-zoo`, which will be fixed in a subsequent commit. This change also deals with consistency failures when the enclosing `IRFunction` has more than one `Function` or `Location`. For multiple `Function`s, we concatenate the function names. For multiple `Location`s, we pick the first one in lexicographical order. This changes the number of results produced in the existing tests, but does't change the actual number of problems. commit 3728e1afd30c0b93e1b7b03637a63254bb2e8f61 Merge: 3520f2c73 17010e25a Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Mon Jun 15 15:32:54 2020 +0100 Merge pull request #3715 from asger-semmle/js/returned-functions Approved by erik-krogh, esbena commit 1033d22d1bf009a4fdf23f6783abc8023130d985 Author: Aditya Sharad <6874315+adityasharad@users.noreply.github.com> Date: Mon Jun 15 07:32:53 2020 -0700 C++: Fix QLDoc on `FormattingFunction` library Copy-paste typo from `DataFlowFunction`. commit 3520f2c7374c440ae8f0ce01aa9ca17d25d494e1 Merge: 57c8dd85a 947ccb06c Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Mon Jun 15 15:29:56 2020 +0100 Merge pull request #3714 from shati-patel/name-res-114 QL handbook: Update process for module resolution commit f8eb5839cda350ae6c150519af3802a982c1084c Author: Rasmus Lerchedahl Petersen Date: Mon Jun 15 16:25:41 2020 +0200 Python: start on local flow commit 947ccb06c793d5cb5ca958dc649cf2877ca1f075 Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Mon Jun 15 15:15:44 2020 +0100 Update docs/language/ql-handbook/name-resolution.rst Co-authored-by: Henning Makholm commit e69c946f315ff3823dfddd0e30505125cf3eb5f5 Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Mon Jun 15 14:56:57 2020 +0100 Mention `libraryPathDependencies` commit d2716c532c0248c146045cb92ef101f3018b8e8f Author: Erik Krogh Kristensen Date: Mon Jun 15 14:59:48 2020 +0200 qhelp commit 17010e25a1832b8b32a127108273a306c3c0a1ec Author: Asger Feldthaus Date: Mon Jun 15 13:55:46 2020 +0100 JS: Update another test commit dc09a68eb4f47dddff15fae5d899118c7531a7b2 Author: Erik Krogh Kristensen Date: Mon Jun 15 14:30:34 2020 +0200 add change-note commit 57c8dd85a4a66f668e303e8c5cd86bd3221f5b0d Merge: 0d1fb0f24 872ee13ba Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Mon Jun 15 13:06:22 2020 +0100 Merge pull request #2801 from esbena/js/bulky-route-handler-registration Approved by asgerf commit 868291877903ed44c42359a287adfd806af17c60 Author: Erik Krogh Kristensen Date: Mon Jun 15 13:31:35 2020 +0200 add change note commit fe9aa241a1ce01236d1e395bf364c126d7f94650 Author: Erik Krogh Kristensen Date: Mon Jun 15 13:25:48 2020 +0200 add qhelp commit 4d1920eec13d41ff2186b728cb9cf3d602c72322 Author: Erik Krogh Kristensen Date: Mon Jun 15 12:48:50 2020 +0200 add .js and .py files to js/insecure-download commit 4b3faabcc87c37b720b0bc3a940e28aab0a864be Author: Asger Feldthaus Date: Mon Jun 15 11:16:55 2020 +0100 JS: Autoformat commit c4179eb81d34b16eaabced574eae11d0772bc1b6 Author: Asger Feldthaus Date: Mon Jun 15 11:13:20 2020 +0100 JS: Update test commit c0043eb9db2c0822c883b6ed93e35781fb1cb939 Author: Rasmus Wriedt Larsen Date: Mon Jun 15 11:54:14 2020 +0200 Python: Don't treat re.escape(...) as a regex Fixes https://github.com/github/codeql/issues/3712 commit 6dfb3a5df859b815f48cad80f8efae5afdafc5c9 Author: Rasmus Lerchedahl Petersen Date: Mon Jun 15 11:50:07 2020 +0200 Python: Address QL docs commit 7601bd497e546f217bbc289ed698861b8a8315a8 Author: Rasmus Wriedt Larsen Date: Mon Jun 15 11:34:05 2020 +0200 Python: Add tests for re.escape FP commit b6b838774ed6e807ca409d3c7c6238563112b51a Merge: d844e0025 315f3389d Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Mon Jun 15 09:54:17 2020 +0100 Merge pull request #3704 from asger-semmle/js/cve-serve Approved by esbena commit c7f74e47e28bbbea0b840954a996a3d6d0cb8c64 Author: Asger Feldthaus Date: Mon Jun 15 09:51:42 2020 +0100 JS: Autoformat commit 0d1fb0f2483d8d7f22f5cde80aa957dddd0a126f Merge: cafbe14dc ca531cbb9 Author: Calum Grant <42069085+calumgrant@users.noreply.github.com> Date: Mon Jun 15 09:31:58 2020 +0100 Merge pull request #3509 from hvitved/csharp/html-raw C#: Recognize more calls to `IHtmlHelper.Raw` commit 3dd529035dd517c55f045a714cae99f7d3462ac0 Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Mon Jun 15 08:41:51 2020 +0100 QL reference: Update process for name resolution commit 6748f3887eb6c3973a0b7e5a8f63a7fafc47dcde Author: Mathias Vorreiter Pedersen Date: Mon Jun 15 09:39:15 2020 +0200 C++: Add test demonstrating differences between AST and IR field flow. Also refactored the partial definitions test commit 1af2e568947a3e87355f06efd73edd825fe95772 Author: Rasmus Lerchedahl Petersen Date: Mon Jun 15 08:01:02 2020 +0200 Summary of recent meeting. Perhaps a not-python-specific version of this could go into the shared implementation. commit 89a1fd4b4a68d4d2c462f2cdac97b44b1b8d4b61 Author: Dave Bartolomeo Date: Sat Jun 13 08:22:04 2020 -0400 C++/C#: Fix formatting commit eac3b06c57ca565080ff4fac07457a981bbe12a4 Author: Dave Bartolomeo Date: Fri Jun 12 17:40:27 2020 -0400 C#: Fix up C# IR construction to latest interface commit 73d2e09a8d3e20578b8d9368d24f7d55e5ec2158 Author: Dave Bartolomeo Date: Fri Jun 12 17:36:01 2020 -0400 C++:/C# Remove `opcode` from `TRawInstruction` commit 978275cbd49d0a66513d83c9ca37aeec70701c29 Author: Dave Bartolomeo Date: Fri Jun 12 17:26:45 2020 -0400 C++/C#: Move `irFunc` out of various `TInstruction` branches commit 07c1520b4d8cf5a6a3f96cd5d6b041abf68c43b8 Author: Dave Bartolomeo Date: Fri Jun 12 17:03:02 2020 -0400 C++/C#: Move `ast` out of `TRawInstruction` commit 2aabe431f69968c4abbb66fb9d87bd8e3511e2de Author: Dave Bartolomeo Date: Fri Jun 12 16:22:58 2020 -0400 C++/C#: Stop caching `getOldInstruction()` commit ac169931b3b8fee90b1adcec763eca6d5866c5c1 Author: Dave Bartolomeo Date: Fri Jun 12 16:09:50 2020 -0400 C++/C#: More efficient evaluation of `SSA::hasInstruction()` commit 315f3389d116f3d0407dc930111ac84de6f0d32d Author: Asger Feldthaus Date: Fri Jun 12 19:58:05 2020 +0100 JS: Autoformat test commit d844e0025a10b3862211f347731bc7011ae5f030 Merge: 01c51eea8 678bb7c12 Author: Asger F Date: Fri Jun 12 16:25:22 2020 +0100 Merge pull request #3651 from esbena/js/bad-multicharacter-sanitization JS: initial version of IncompleteMultiCharacterSanitization.ql commit b9cd157c0f0bb75838938699f936d05e060c5534 Author: Asger Feldthaus Date: Fri Jun 12 15:36:02 2020 +0100 JS: Autoformat commit 4331b9b54e61c76a0b465342258af426046e7253 Author: Dave Bartolomeo Date: Fri Jun 12 09:31:19 2020 -0400 C++: Simplify logic to an implication commit 678bb7c128288ff85ee587ca7eff9e1e331b3c2b Author: Esben Sparre Andreasen Date: Fri Jun 12 14:56:08 2020 +0200 JS: simplify loop detection commit eaf6be5feac326b5aa6bcb1f7f042b4f8f0042dd Author: Asger Feldthaus Date: Fri Jun 12 13:29:35 2020 +0100 JS: Fix lazy qldoc commit 91d98c0d009dac7787552dd28ffb6cc168912581 Author: Asger Feldthaus Date: Fri Jun 12 13:12:55 2020 +0100 JS: Change note commit 5548606f219e06087fbb8326e28219886baf005c Author: Asger Feldthaus Date: Fri Jun 12 13:02:33 2020 +0100 JS: Add test commit 01c51eea89a3ea9eaedebcfd5d1974778090ec34 Merge: 2342d3dba f0ec2eb37 Author: Erik Krogh Kristensen Date: Fri Jun 12 14:00:21 2020 +0200 Merge pull request #3680 from erik-krogh/bad-code-sanitizer JS: Add query to detect bad code sanitizers commit 4795b87daabafa974bfa6e207ad52f748f97619e Author: Asger Feldthaus Date: Fri Jun 12 12:44:37 2020 +0100 JS: Add model of Micro commit 230f78afb6a3be6899f7f2e18232754e963af590 Author: Asger Feldthaus Date: Fri Jun 12 12:26:45 2020 +0100 JS: Step through path.{format, parse} commit 2342d3dba3e469bbba881763d1ddb45a67dfa5fe Merge: c9fc1a378 36c480369 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Fri Jun 12 12:18:23 2020 +0100 Merge pull request #3662 from asger-semmle/js/package-export-fixes Approved by esbena commit cafbe14dc868608aca7a62684cce8a6cc8d99006 Merge: 041af3893 07d5ee612 Author: Max Schaefer <54907921+max-schaefer@users.noreply.github.com> Date: Fri Jun 12 11:37:47 2020 +0100 Merge pull request #3703 from shati-patel/mergeback Merge rc/1.24 into master commit 07d5ee612679d72c345e7cd23c84b39e3686e4c3 Merge: 041af3893 c2de54f5c Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Fri Jun 12 11:30:47 2020 +0100 Merge branch 'rc/1.24' into mergeback commit 375da38765564069f475b4a3b6e21f43bdb6f986 Author: Rasmus Lerchedahl Petersen Date: Fri Jun 12 11:48:41 2020 +0200 Python: Minimal compilation of shared dataflow commit f0ec2eb37b857b0dc97040119b48abccc2e1e438 Author: Erik Krogh Kristensen Date: Fri Jun 12 11:47:53 2020 +0200 add missing qldoc commit c9fc1a378d8bb9f1b2d4c7839928cece1adb6a54 Merge: 86b23b239 7c7af8d84 Author: Erik Krogh Kristensen Date: Fri Jun 12 11:32:12 2020 +0200 Merge pull request #3663 from erik-krogh/bad-crypto JS: Introduce query to detect biased random number generators commit 1751fb6c474f208d450110ddf33cb652222ff410 Author: Erik Krogh Kristensen Date: Fri Jun 12 11:30:22 2020 +0200 add missing qldoc commit adabd2daca91ba3b6fb96b37851cc527c7098211 Author: Erik Krogh Kristensen Date: Fri Jun 12 11:26:49 2020 +0200 add qldoc and customizations module commit 4c536dde204f02ab86d45c434a59f11e64d6bc6f Author: Asger Feldthaus Date: Fri Jun 12 10:07:37 2020 +0100 JS: Propagate locally returned functions out of calls commit 908edb39b91bbbb10fa02f4a97a73ae56e35be8c Author: Erik Krogh Kristensen Date: Fri Jun 12 11:02:26 2020 +0200 unsecure -> insecure commit 86b23b239e2edc1f3b4fe5c2878532fb4d9ef409 Merge: 1bdae109c 065cb0420 Author: Erik Krogh Kristensen Date: Fri Jun 12 10:57:24 2020 +0200 Merge pull request #3656 from erik-krogh/destruct-yargs JS: support rest-patterns inside property patterns commit 6531db3ccac6a76de3cc6607d19ddbbc842133fc Author: Asger Feldthaus Date: Fri Jun 12 09:54:53 2020 +0100 JS: Add test commit 57d2226080043175fc2a6cbb70e5944b786b75f3 Author: Erik Krogh Kristensen Date: Fri Jun 12 10:55:29 2020 +0200 typo commit 9780fcf8fe38be04ec023b2a90b92c3a25461f36 Author: Erik Krogh Kristensen Date: Fri Jun 12 10:54:56 2020 +0200 fix ftp protocol regexp commit 3f957103ed0a6bd0799e9454a048c67b63bcda8e Author: Erik Krogh Kristensen Date: Fri Jun 12 10:53:19 2020 +0200 improve alert message - and autoformat commit 056a7e87ff030b48dfa84e4174445a7aa79cd81e Author: Erik Krogh Kristensen Date: Fri Jun 12 10:51:09 2020 +0200 refactor into customizations module - and move curl download to a ClientRequest commit 8225adcaea863549196977143a966dba0633d5be Author: Erik Krogh Kristensen Date: Fri Jun 12 10:28:06 2020 +0200 move TODOs commit 02c4a0477d82005c3317f158d21d229f2f59875a Author: Erik Krogh Kristensen Date: Fri Jun 12 10:21:37 2020 +0200 add tests for js/build-artifact-leak commit 041af38934080609483872afe56967bc8c56a47b Merge: 6f40fc2ea 422b059ae Author: Anders Schack-Mulligen Date: Fri Jun 12 10:04:40 2020 +0200 Merge pull request #3697 from intrigus-lgtm/patch-1 Fix typo commit 6f40fc2eae6f612c4e3d206d16b551fd007defeb Merge: abd05bcff 7cd6dd27a Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Fri Jun 12 08:49:53 2020 +0100 Merge pull request #3678 from Marcono1234/patch-1 Approved by shati-patel commit 421a548e4232a798c1c8661160ccc709db546c91 Author: Anders Schack-Mulligen Date: Fri Jun 12 09:24:37 2020 +0200 Update java/ql/src/semmle/code/java/Expr.qll commit abd05bcff13ec455d7306a0c47c487bc23d95b2b Merge: 035d8ea24 ded5eec76 Author: Jonas Jensen Date: Fri Jun 12 09:08:20 2020 +0200 Merge pull request #3596 from robertbrignull/more-suites Add more code-scanning suites commit 035d8ea24c5e86180e1397bbb7cfdc4ff96deeea Merge: b78c06559 475c631ff Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Fri Jun 12 07:40:58 2020 +0100 Merge pull request #3690 from asger-semmle/js/fix-lgtm-filters-comment Approved by max-schaefer commit 1bdae109c5a85aaaa4218ce7569c8dfb430bdf99 Merge: 5c2f1169d 2e059376f Author: Esben Sparre Andreasen Date: Fri Jun 12 08:40:12 2020 +0200 Merge pull request #3686 from esbena/js/insecure-http-options JS: add query js/disabling-certificate-validation commit 5c2f1169d095c1ee72ffe61cc5c8d588a05855dc Merge: 243e3ad9e 4bb2e8b63 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Fri Jun 12 07:39:26 2020 +0100 Merge pull request #3679 from asger-semmle/js/dom-value-ref-restriction Approved by erik-krogh, esbena commit 243e3ad9e3259b084f35111c0c30373df2b49a8e Merge: df79f2adc 169c8909d Author: Esben Sparre Andreasen Date: Fri Jun 12 08:38:37 2020 +0200 Merge pull request #3672 from esbena/js/server-crashing-route-handler JS: add initial version of ServerCrash.ql commit 65f4ef712e182702ac5c383129e8767f51a32958 Author: Robert Marsh Date: Thu Jun 11 15:27:13 2020 -0700 C++: accept false positive tests after merge The IR false positives are due to the same path length limit as the AST false positives on the same line. commit 5b491313ad526c295f1cc92e5568dcf589002b89 Author: Erik Krogh Kristensen Date: Thu Jun 11 17:03:01 2020 +0200 add simple query for detecting sensitive files downloaded over unsecure connection commit 065cb042029ea3018b7646822e1e4265548aeae9 Author: Erik Krogh Kristensen Date: Thu Jun 11 23:19:03 2020 +0200 make PropNode private again commit ef72c03ca9ddf23bd5a71584afa098fc20e56529 Author: Erik Krogh Kristensen Date: Thu Jun 11 23:16:46 2020 +0200 use simpler taint-step for DestructingPattern commit 7cd6dd27a64fd06dc4ef2a0c63e3b214079892b5 Author: Marcono1234 Date: Thu Jun 11 23:02:59 2020 +0200 Add link to Java regex Pattern documentation to language.rst Co-authored-by: Shati Patel <42641846+shati-patel@users.noreply.github.com> commit 422b059aec22a32f1a008b1326ed4b8118037a06 Author: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> Date: Thu Jun 11 22:54:13 2020 +0200 Fix typo commit a7efa0d6027e58c69e28327cec09ee12612761b5 Merge: 2a96856ca ae46a8d8a Author: Robert Marsh Date: Thu Jun 11 13:21:52 2020 -0700 Merge branch 'master' into ir-this-parameter-2 commit b78c06559efffa6122d6ae6e5511f1c4ce3b981f Merge: ae46a8d8a 91b9b78c4 Author: Mathias Vorreiter Pedersen Date: Thu Jun 11 22:02:45 2020 +0200 Merge pull request #3691 from geoffw0/reftest C++: Add a test case for CWE-114 involving pointers and references. commit fdd7ad23005c59576af9faa216c55fd23fb6d701 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Jun 3 15:02:41 2020 +0100 C++: Add a SideEffectFunction model to 'system'. commit e8b34e07f8725381adb1071395969dc4201deebe Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Jun 3 14:54:20 2020 +0100 C++: Add an AliasFunction model to 'system'. commit 7fee2c239d4340e76c4925106b1dc8646528a642 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Jun 3 14:47:15 2020 +0100 C++: Add an ArrayFunction model to 'system'. commit b38a7a9ffc368997258c580df94e519b18f46422 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed Jun 3 14:36:33 2020 +0100 C++: Fill out ArrayFunction model for 'fgets'. commit ae46a8d8a1014b6f9b46b43ab9892bb533864f66 Merge: 5e021c24c fd88289e4 Author: Robert Marsh Date: Thu Jun 11 09:49:19 2020 -0700 Merge pull request #3692 from igfoo/blockstmt C++: Fix reference to `Block` commit 40c20f27311a0ddafd9c1d0597cd6859006e8ba9 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Jun 11 17:32:44 2020 +0100 C++: Add the test for DefaultTaintTracking as well. commit 2f192f6a0c1fffb7097916caec26f3280aeae782 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu Jun 11 16:49:06 2020 +0100 C++: Add a test of char* -> std::string -> char* taint. commit 41df7000c5a4ef6bbce37d71416e370a95a9dc29 Merge: b116a3e8e 5e021c24c Author: Dave Bartolomeo Date: Thu Jun 11 12:20:46 2020 -0400 Merge from master, including fixing up merge conflicts commit fd88289e46780927101790ef11ca30946bd1802e Author: Ian Lynagh Date: Thu Jun 11 16:50:23 2020 +0100 C++: Fix reference to `Block` We don't call it `BlockStmt`. commit 475c631ff96f2759e4d9def95a8c8d083e5e35ed Author: Asger Feldthaus Date: Thu Jun 11 16:16:51 2020 +0100 JS: Fix a misleading javadoc comment commit b116a3e8eac052d7a0633e49311d361ff88506ac Author: Dave Bartolomeo Date: Thu Jun 11 10:24:01 2020 -0400 C#: Rename IR module references to point to `experimental` commit c961a31789981d5095fc789d66e12b9af8d2cbe2 Author: Anders Schack-Mulligen Date: Thu Jun 11 13:46:12 2020 +0200 Java: Add Expr.getAnEnclosingStmt. commit c2de54f5ca709caf68c5ff4d742618e5576c48d3 Merge: cee248520 287405050 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Thu Jun 11 12:43:20 2020 +0100 Merge pull request #3685 from shati-patel/ast-go-edits Approved by felicitymay, owen-mc commit 169c8909df9646c868829cb61d1217100ec1cef1 Author: Esben Sparre Andreasen Date: Thu Jun 11 13:28:26 2020 +0200 formatting commit bc7f02156b8991d5033268fff0b19d4524963a8c Author: Esben Sparre Andreasen Date: Thu Jun 11 13:20:46 2020 +0200 JS: replace class with two predicates (and improve alert message) commit 7c7af8d84119024de0a83239b9ef089efb0d6172 Author: Erik Krogh Kristensen Date: Thu Jun 11 12:53:24 2020 +0200 less heuristics when flagging division that is rounded commit f1b24ba901eea88e7269f4c211874ff1dec67711 Author: Erik Krogh Kristensen Date: Thu Jun 11 12:34:58 2020 +0200 use type inference to detect string concatenations commit 2e059376fd9025cbf3125e61fdceb81398ef4813 Author: Esben Sparre Andreasen Date: Thu Jun 11 12:25:59 2020 +0200 JS: add query js/disabling-certificate-validation commit f634c62af5ff61f396be9cc4125d5cee9119db48 Author: Erik Krogh Kristensen Date: Thu Jun 11 12:18:41 2020 +0200 remove redundant check commit 2874050503295d8fe6c2f6b19ef81fd801ccf646 Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Thu Jun 11 10:49:19 2020 +0100 CodeQL for Go: Edit AST reference commit a24974b1946ab8e1ed72b02622f460b51d988173 Author: Rasmus Wriedt Larsen Date: Thu Jun 11 11:45:38 2020 +0200 Python: Add missing

to qhelp commit f23eb0432e9bdb57cc149249a740b80af8b2253b Author: Anders Schack-Mulligen Date: Thu Jun 11 11:44:50 2020 +0200 Java: Improve qldoc for JavadocTag. commit 33a9fb6034b3a58bc273abe926d5f30d9667d12b Author: Rasmus Wriedt Larsen Date: Thu Jun 11 11:30:54 2020 +0200 Python: Reorder XSLT qhelp to be valid commit ca531cbb9aa099c8a55507f3268e7e36b508739b Author: Tom Hvitved Date: Tue May 19 15:03:47 2020 +0200 C#: Rename a class commit 8395980fb1318045cd47fa9f86dc1273efee68bc Author: Tom Hvitved Date: Tue May 19 11:52:06 2020 +0200 C#: Recognize more calls to `IHtmlHelper.Raw` Generalize logic by recognizing not only calls to `Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelper.Raw()`, but calls to all `Raw()` methods that implement `Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper.Raw()`. commit c375a0c61111008f5ce371a79c3e60d410de8282 Author: Erik Krogh Kristensen Date: Thu Jun 11 11:16:38 2020 +0200 fix compilation and update expected output commit ab52010674ec3245690061dec231c9f4d84bbcf6 Author: Owen Mansel-Chan Date: Thu Jun 11 09:42:46 2020 +0100 Give general syntax instead of examples for exprs commit 3ca5d34d9b70602a9d1507485ee498f283a15532 Author: Owen Mansel-Chan Date: Thu Jun 11 08:29:45 2020 +0100 Add more links to java AST class reference Using the explicit hyperlink target feature of rst to keep the text in the tables short and put all the URLs at the end of the document commit 84a4630eafdfa3ddd9db11c16a7f62c96fa9980d Author: Owen Mansel-Chan Date: Wed Jun 10 20:12:01 2020 +0100 Move explicit hyperlink targets to the bottom commit 1124816f73df6719661018903a7afaa30f644a26 Author: Erik Krogh Kristensen Date: Thu Jun 11 10:59:56 2020 +0200 fixing FPs in `js/biased-cryptographic-random` commit 5e021c24c17008520f8846b58eeb5052abe7dffd Merge: 60df00c7e 800686637 Author: Calum Grant <42069085+calumgrant@users.noreply.github.com> Date: Thu Jun 11 10:01:50 2020 +0100 Merge pull request #3652 from hvitved/csharp/dataflow/impl-layer C#: Refactor data-flow predicates defined by dispatch commit 4bb2e8b637adf2f54784f837a1e30ca239a6f13b Author: Asger Feldthaus Date: Thu Jun 11 09:53:55 2020 +0100 JS: Update test externs and include array indices commit 60df00c7e35d100fa8dee8e1ec05fd74d7f4e01a Merge: d9d090308 bf1948950 Author: Pavel Avgustinov <54942558+p0@users.noreply.github.com> Date: Thu Jun 11 09:17:11 2020 +0100 Merge pull request #3669 from github/sj-patch-contributing-SLA Update CONTRIBUTING.md to clarify that CLAs are no longer required commit d9d0903084532e3b3539775bf5ec20bf549a9149 Merge: 982fb3880 cee248520 Author: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Thu Jun 11 09:00:57 2020 +0100 Merge pull request #3681 from github/rc/1.24 Merge rc/1.24 into master commit cee248520eeace053b9e509050a9ef99bdd3e41d Merge: 9afbd5b5e d8900448e Author: Max Schaefer <54907921+max-schaefer@users.noreply.github.com> Date: Thu Jun 11 08:05:41 2020 +0100 Merge pull request #3675 from owen-mc/ast-class-reference-for-go AST class reference for go commit b5703cd3f6a1e44e8a9a4d2bbc8f32f98ac1049e Author: Rasmus Lerchedahl Petersen Date: Thu Jun 11 07:14:48 2020 +0200 Python: link to FP report in test file commit 982fb388078cf2b0950b10f5ea462c010e77ae2f Merge: b841cacb8 b48168fc0 Author: Robert Marsh Date: Wed Jun 10 14:31:00 2020 -0700 Merge pull request #3419 from MathiasVP/flat-structs C++: Add reverse reads to IR field flow commit e8b05b70c4273f84ac30b7c0358d20804803218e Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Wed Jun 10 23:11:03 2020 +0200 Added support for detecting unsafe methods used for origin verification commit cf3142e0834df654f01826ce3ecfb50e5fdf1142 Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Wed Jun 10 23:09:35 2020 +0200 Updated qhelp with a third example commit 92f9f320f933f70a06d21e9bb5a180d40a060acb Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Wed Jun 10 23:07:05 2020 +0200 Added new example of an unsafe event.origin verification commit aa3482cbaef6d82292e188a5a2529d845adbb8bc Author: Erik Krogh Kristensen Date: Wed Jun 10 22:58:02 2020 +0200 improve detection of duplicate results with `js/code-injection` commit 51426701381b8ab8779f64592bc5cb7f46f1c406 Author: Erik Krogh Kristensen Date: Wed Jun 10 22:30:45 2020 +0200 don't import AdditionalSinks, refactor sink out in new HeuristicSinks instead commit a38839b4463f428049202b379f30778c1689ba2d Author: Mathias Vorreiter Pedersen Date: Wed Jun 10 22:27:40 2020 +0200 C++: Include copy of IntWrapper class with two data members commit ca20f1770376395d2a19fed63a08ca81a19777f8 Author: Mathias Vorreiter Pedersen Date: Wed Jun 10 22:16:58 2020 +0200 C++: Implement move constructor in terms of swap. I'm haven't found anything online on whether this is good or bad, and the only reason for not doing it might be performance. commit d6ae905eac09ecba361dae8e56cc2a2d53231a9e Author: Esben Sparre Andreasen Date: Wed Jun 10 21:40:12 2020 +0200 JS: remove speculative property access sink from js/server-crash commit b841cacb83cbb2cd6fb5832b05a1447e2ef5c7ba Merge: cd914deef 0f2186c84 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Wed Jun 10 20:02:55 2020 +0100 Merge pull request #3676 from max-schaefer/js/global-access-paths-minor-fixes Approved by erik-krogh commit cd914deeff2bc0808122706dc0ed1c1495e92b31 Merge: 4cdb3c13d 70c3ff36f Author: Calum Grant <42069085+calumgrant@users.noreply.github.com> Date: Wed Jun 10 19:50:37 2020 +0100 Merge pull request #3666 from hvitved/csharp/ir-experimental C#: Move IR code into 'experimental' folder commit 373a437d71a2d4dcde7627ec4b1500da958d6f8f Author: Erik Krogh Kristensen Date: Wed Jun 10 19:40:26 2020 +0200 add query to detect improperly sanitized code commit d8900448ec9f0384797d3b530eb37b4aebaba6e3 Author: Owen Mansel-Chan Date: Wed Jun 10 17:24:40 2020 +0100 Add references to the AST class reference for go commit 48ff00832cad8cd788630c23b504757ea4e76433 Author: Owen Mansel-Chan Date: Wed Jun 10 17:24:40 2020 +0100 Add a reference to the AST class reference for go commit 4cdb3c13df7a782c2fe30b2a83300a691f11d5fa Merge: f7c6b1364 48b2d2cc5 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Wed Jun 10 17:19:49 2020 +0100 Merge pull request #3658 from RasmusWL/python-3.8-dict-ismapping Approved by tausbn commit f7c6b1364b2774f0d05e84a444f64b99ac12ea2a Merge: 5b0d92d72 721713b9e Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Wed Jun 10 17:19:22 2020 +0100 Merge pull request #3640 from RasmusWL/python-handle-3.8-enum-convert Approved by tausbn commit 5c31b9476143b18b1254c4fc0ced864fb123a571 Author: Erik Krogh Kristensen Date: Wed Jun 10 16:13:22 2020 +0200 autoformat and update expected output commit 5d2b911596e0c08e12fbff635b333774e6d084c1 Author: Marcono1234 Date: Wed Jun 10 17:56:57 2020 +0200 Fix incorrect java.util.regex.Pattern name in specification commit 0f2186c8443b337e6bea7ee1b1a49516d4bc2657 Author: Max Schaefer Date: Wed Jun 10 16:44:24 2020 +0100 JavaScript: Fix a few typos. commit 5b2c0fbb04194c920eb3961275c1901e742e93fb Author: Owen Mansel-Chan Date: Wed Jun 10 16:42:03 2020 +0100 AST class reference for go The master copy of this file is in the codeql-go repository commit 1a95095505041dcdb2eb98951e53ce401801b505 Author: Mathias Vorreiter Pedersen Date: Wed Jun 10 17:13:04 2020 +0200 C++: Add default move constructor. Also removed debug comment I forgot to remove earlier. Luckily, that meant that no line numbers changed in .expected files. commit ce1f0a39acd2f764930c0d901eb7f0d0a6189943 Author: Rasmus Wriedt Larsen Date: Wed Jun 10 16:59:40 2020 +0200 Python: Minor fixup of qhelp for XPath injection commit 5abab25c284af4ec780c8fe9ec9badffbc5ebe43 Author: Mathias Vorreiter Pedersen Date: Wed Jun 10 16:51:21 2020 +0200 Update cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp Co-authored-by: Jonas Jensen commit 48b2d2cc5c79a9bddc099c2adace24ce1c7fd27b Author: Rasmus Wriedt Larsen Date: Wed Jun 10 16:43:56 2020 +0200 Python: Make isSequence() and isMapping() tests version specific Since unicode/bytes difference, output can't match between Python 2 and Python 3. commit f23c6030aab56ba62def832e5c03570e1c61b57c Author: Asger Feldthaus Date: Wed Jun 10 15:10:10 2020 +0100 JS: Restrict domValueRef to known DOM property names commit bb2b7fb6fb4cfd11a42ee4742d671ab148e4ae44 Author: Asger Feldthaus Date: Wed Jun 10 15:00:54 2020 +0100 JS: Add test with class stored in global variable commit 721713b9e1e5a61e0214b8e396f1dc1ac3576622 Author: Rasmus Wriedt Larsen Date: Wed Jun 10 16:14:21 2020 +0200 Python: Minor fixes from code review Co-authored-by: Taus commit 5b0d92d72b317367ec868074e8f405ab61b97d97 Merge: da6736df3 712513916 Author: Taus Date: Wed Jun 10 15:47:09 2020 +0200 Merge pull request #3464 from yoff/UnicodeEscape Python: Handle more escapes in regexes commit da6736df376fba6a998907bb376449cb1fe8d8db Merge: 1b8f3c4b8 f73876e6c Author: Taus Date: Wed Jun 10 15:45:07 2020 +0200 Merge pull request #3668 from RasmusWL/python-random-modernisations Python: Two small modernisations commit 91b9b78c48c20b29e5e186dd06e78bd3caeedeb2 Author: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri May 29 20:14:00 2020 +0100 C++: Add a test case for CWE-114 involving pointers and references. commit 36c4803694f250dcb0343c7f47431f4366f9e59c Author: Asger Feldthaus Date: Wed Jun 10 14:08:33 2020 +0100 JS: Add test commit 88dabffd2b27ae6248c001aca9ff84aeacd115e9 Author: Mathias Vorreiter Pedersen Date: Wed Jun 10 15:06:57 2020 +0200 C++: Add tests that demonstrate flow through custom swap functions commit 07e90ff65f71da9aceae26c083343278b12ae6a5 Author: Asger Feldthaus Date: Wed Jun 10 14:03:01 2020 +0100 JS: Autoformat commit df79f2adc56838ca027f86d4e414956b0391de47 Merge: b6e0e6645 034503642 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Wed Jun 10 13:35:22 2020 +0100 Merge pull request #3655 from asger-semmle/js/string-ops-regexp-test-fix Approved by esbena commit 1d396524a38857ec8210ea17ee53caade8e848a8 Author: Esben Sparre Andreasen Date: Wed Jun 10 13:36:03 2020 +0200 JS: add initial version of ServerCrash.ql commit 1b8f3c4b847230e74b64ab960dc8e96f0fa66c86 Merge: 22d50f009 a371205db Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Wed Jun 10 13:22:09 2020 +0100 Merge pull request #3657 from hvitved/dataflow/hidden-nodes Approved by aschackmull, jbj commit c4f61134f1a65b6362df262e122e22383911d6b9 Author: Erik Krogh Kristensen Date: Wed Jun 10 13:32:46 2020 +0200 include the source of cryptographically random number in alert message commit 22d50f009ec7862e0399ac2dadb317f70a7fcbec Merge: 4b3ca13f2 c334d72f1 Author: semmle-qlci <42001189+semmle-qlci@users.noreply.github.com> Date: Wed Jun 10 12:05:42 2020 +0100 Merge pull request #3667 from aschackmull/java/compiletimeconstant-cast-eval Approved by aibaars commit bf19489501504a54b192232c83d8356f15f2bdc9 Author: Bas van Schaik <5082246+sj@users.noreply.github.com> Date: Wed Jun 10 12:02:24 2020 +0100 Update CONTRIBUTING.md commit be48daf0d0b896d261410923ce4a4c244bce08fa Author: Bas van Schaik <5082246+sj@users.noreply.github.com> Date: Wed Jun 10 11:58:38 2020 +0100 Update CONTRIBUTING.md commit 7e8fd803277c677ce7aa9e635e7b673686daba57 Author: Erik Krogh Kristensen Date: Wed Jun 10 12:27:50 2020 +0200 use steps from InsecureRandomness, and use small-steps commit f73876e6ce848e74fb35578f11438e7d508f5f0e Author: Rasmus Wriedt Larsen Date: Wed Jun 10 11:53:11 2020 +0200 Python: Modernise ShouldBeContextManager commit 37cfb5400deb7aa507c5077f1a27e2cc955e7951 Author: Rasmus Wriedt Larsen Date: Wed Jun 10 11:51:41 2020 +0200 Python: Modernise RatioOfDefinitions commit 4b3ca13f25c000fc97601db2b64c7449e10fce26 Merge: 06066f0c5 1fd9c7fde Author: Anders Schack-Mulligen Date: Wed Jun 10 11:02:50 2020 +0200 Merge pull request #3491 from luchua-bc/java-insecure-smtp-ssl Java: CWE-297 insecure JavaMail SSL configuration commit ded5eec76a2b8366067161b17c4957bb2bc62aee Author: Robert Brignull Date: Wed Jun 10 09:59:26 2020 +0100 rename slow-queries.yml to exclude-slow-queries.yml commit c334d72f118ec13ed19ed5a7b381e5bf0635505d Author: Anders Schack-Mulligen Date: Wed Jun 10 10:59:10 2020 +0200 Java: Fix CompileTimeConstantExpr qldoc and add char cast case. commit 9029dbacf54c8a8b0d9bda4598a28534dba9f75c Author: Erik Krogh Kristensen Date: Wed Jun 10 10:55:30 2020 +0200 refactor isAdditionalTaintStep to a utility predicate in InsecureRandomness commit 9189f23403267c3534664ab10ce11c5d0e6344b9 Author: Erik Krogh Kristensen Date: Wed Jun 10 10:39:02 2020 +0200 add support for secure-random commit 16ec405724f2d075a70e181cab63d491bf1b6cc5 Author: Erik Krogh Kristensen Date: Wed Jun 10 10:38:47 2020 +0200 add explanations about modulo by power of 2 commit 111f6d406c4ccf6aa770cc1a3eda0c9317a12ca8 Author: Erik Krogh Kristensen Date: Tue Jun 9 23:08:52 2020 +0200 introduce query to detect biased random number generators commit 70c3ff36f8495c39004c67603fa124a17ce26875 Author: Tom Hvitved Date: Wed Jun 10 09:54:56 2020 +0200 C#: Adjust IR imports commit d5b8c9728c831b319210bf09cecbb8ba5b17fdd3 Author: Tom Hvitved Date: Wed Jun 10 09:40:44 2020 +0200 Update `identifal-files.json` commit 3c8735f43f2c6b1ec60e2fba079282d5b5786d91 Author: Tom Hvitved Date: Wed Jun 10 09:37:30 2020 +0200 C#: Move IR code into 'experimental' folder commit 733e04c1eb7553fec904db2df4c372c5dbd2a9de Author: Erik Krogh Kristensen Date: Tue Jun 9 23:21:04 2020 +0200 Move rest-pattern inside property-pattern step to a taint-step commit 2f9124f754065d116cfdd2681f0c8e5af54b3195 Author: Erik Krogh Kristensen Date: Tue Jun 9 23:32:58 2020 +0200 add missing qldoc commit 1fd9c7fdecb575620b13cf8814ebc7c4df22ebbd Author: luchua-bc Date: Tue Jun 9 20:12:05 2020 +0000 Add all dependent class stubs commit ad401e9f21b7786f9eb8bec378215b265e0b68ff Author: Jonas Jensen Date: Tue Jun 9 20:53:56 2020 +0200 C++: Copy and adjust Java's correctness argumnt Instead of a vague reference to a code comment for another language, the `controlsBlock` predicate now has the whole comment in it directly. I've adjusted the wording so it should be reasonably correct for C/C++. As with the other comments in this file, I don't distinguish between the condition and its block. I think that makes the explanation clearer without losing any detail we care about. To make the code fit the wording of the comment, I changed the `hasBranchEdge/2` predicate into `getBranchSuccessor/1`. commit eb00da5b31de5ed91bc94a87041c39492df0eaf2 Author: Erik Krogh Kristensen Date: Tue Jun 9 20:02:46 2020 +0200 improve readability Co-authored-by: Asger F commit a923a404abd919e35fda52877df4da250de9baaf Author: Asger Feldthaus Date: Tue Jun 9 16:03:20 2020 +0100 JS: Explicitly handle export declarations in PackageExports commit 806c9a372e383258f882f39fa67947c9754bd560 Author: Asger Feldthaus Date: Tue Jun 9 16:03:10 2020 +0100 JS: Resolve package.json main module differently commit b8a9ac39f4e50d227db5a41d6b7b33c1b6c77d70 Author: Erik Krogh Kristensen Date: Tue Jun 9 18:14:07 2020 +0200 add lValueFlowStep for rest-pattern nested inside a property-pattern (and removed old incorrect approach) commit b6e0e6645fd61a9bd151862b5cd5851ded763cf3 Merge: c580ada52 167239e74 Author: Erik Krogh Kristensen Date: Tue Jun 9 17:38:31 2020 +0200 Merge pull request #3645 from erik-krogh/infExposure JS: add query to detect accidential leak of private files commit a7f6f045d282e3d6e31b502d9fc6b4d27c6e49d0 Author: Erik Krogh Kristensen Date: Tue Jun 9 17:16:13 2020 +0200 add taint-steps for copying properties of an object commit 7050d9d7bb7dcfb94dbfb5ea30b36d211f7a349a Author: Erik Krogh Kristensen Date: Tue Jun 9 17:15:55 2020 +0200 remove dead FlowLabel commit 2af8739bb66891f506ffecacf14f1502b355f424 Author: Erik Krogh Kristensen Date: Tue Jun 9 17:15:35 2020 +0200 simplify web.DefinePlugin sink commit 90596167b16a62ff3267b008e516af1459774ef3 Author: Erik Krogh Kristensen Date: Tue Jun 9 17:15:00 2020 +0200 add taint-step for Array.reduce commit 06066f0c5b6d5c00798dff33fd2e008e41cdac0f Merge: f77f486c6 a341912da Author: Mathias Vorreiter Pedersen Date: Tue Jun 9 15:53:19 2020 +0200 Merge pull request #3659 from jbj/getFieldSizeOfClass-perf C++: Performance tweak for 1-field struct loads commit be71ddf7bb5b1c109af6e54a67a233d769332e7b Author: Erik Krogh Kristensen Date: Tue Jun 9 15:27:55 2020 +0200 introduce basic BuildArtifactLeak query commit 896a9b05f678b4e647c3c72311dde6fab00bcf8f Author: Erik Krogh Kristensen Date: Tue Jun 9 15:03:07 2020 +0200 refactor CleartextLogging to allow for reuse commit a341912da952bc5b1f44d8748a563abafebd031a Author: Jonas Jensen Date: Tue Jun 9 14:33:32 2020 +0200 C++: Performance tweak for 1-field struct loads On kamailio/kamailio the `DataFlowUtil::simpleInstructionLocalFlowStep` predicate was slow because of the case for single-field structs, where there was a large tuple-count bulge when joining with `getFieldSizeOfClass`: 3552902 ~2% {2} r1 = SCAN Instruction::CopyInstruction::getSourceValueOperand_dispred#3#ff AS I OUTPUT I.<1>, I.<0> 2065347 ~2% {2} r35 = JOIN r1 WITH Operand::NonPhiMemoryOperand::getAnyDef_dispred#3#ff AS R ON FIRST 1 OUTPUT r1.<1>, R.<1> 2065827 ~2% {3} r36 = JOIN r35 WITH Instruction::Instruction::getResultType_dispred#3#ff AS R ON FIRST 1 OUTPUT R.<1>, r35.<1>, r35.<0> 2065825 ~3% {3} r37 = JOIN r36 WITH Type::Type::getSize_dispred#ff AS R ON FIRST 1 OUTPUT r36.<1>, r36.<2>, R.<1> 2068334 ~2% {4} r38 = JOIN r37 WITH Instruction::Instruction::getResultType_dispred#3#ff AS R ON FIRST 1 OUTPUT R.<1>, r37.<2>, r37.<0>, r37.<1> 314603817 ~0% {3} r39 = JOIN r38 WITH DataFlowUtil::getFieldSizeOfClass#fff_120#join_rhs AS R ON FIRST 2 OUTPUT r38.<3>, R.<2>, r38.<2> 8 ~0% {2} r40 = JOIN r39 WITH Instruction::Instruction::getResultType_dispred#3#ff AS R ON FIRST 2 OUTPUT r39.<2>, r39.<0> That's 314M tuples. Strangely, there is no such bulge on more well-behaved snapshots like mysql/mysql-server. With this commit the explosion is gone: ... 2065825 ~0% {4} r37 = JOIN r36 WITH Type::Type::getSize_dispred#ff AS R ON FIRST 1 OUTPUT r36.<0>, R.<1>, r36.<1>, r36.<2> 1521 ~1% {3} r38 = JOIN r37 WITH DataFlowUtil::getFieldSizeOfClass#fff_021#join_rhs AS R ON FIRST 2 OUTPUT r37.<2>, R.<2>, r37.<3> 8 ~0% {2} r39 = JOIN r38 WITH Instruction::Instruction::getResultType_dispred#3#ff AS R ON FIRST 2 OUTPUT r38.<0>, r38.<2> commit bacd491875cba6856a2819eab5ffca9533bc6a78 Author: Rasmus Wriedt Larsen Date: Tue Jun 9 12:00:29 2020 +0200 Python: Fix isSequence() and isMapping() commit f77f486c6b17ee595d31e72a59cbb2c9f101998a Merge: 398678a28 bab6f3788 Author: Anders Schack-Mulligen Date: Tue Jun 9 14:07:17 2020 +0200 Merge pull request #3438 from artem-smotrakov/unsafe-tls Java: Added a query for unsafe TLS versions commit 846101d295cf5184a86d54364f78e9c9467f9ddf Author: Rasmus Wriedt Larsen Date: Tue Jun 9 14:01:18 2020 +0200 Python: Extend isSequence/isMapping test with custom classes commit a371205db190e0f19d7af6e9a8178032033f597d Author: Tom Hvitved Date: Tue Jun 9 13:55:12 2020 +0200 Data flow: Sync files commit 8c9f85d04f2cbaba9689069562a36935cdef6f3f Author: Tom Hvitved Date: Tue Jun 9 13:53:19 2020 +0200 Data flow: Allow nodes to be hidden from path explanations commit b510e470b11eb06ae003e29bafc4e8de30bede07 Author: Erik Krogh Kristensen Date: Tue Jun 9 13:19:20 2020 +0200 support rest-patterns inside property patterns commit c580ada527824c6009f08764b8098f6924995722 Merge: 1a7570ebb b04d7015a Author: Erik Krogh Kristensen Date: Tue Jun 9 13:17:28 2020 +0200 Merge pull request #3643 from erik-krogh/yargs JS: extend support for yargs for js/indirect-command-line-injection commit 4642037dce0dab44ba82614f9370076c6d433355 Author: Jonas Jensen Date: Tue Jun 9 11:44:08 2020 +0200 C++: Speed up IRGuardCondition::controlsBlock The `controlsBlock` predicate had some dramatic bulges in its tuple counts. To make matters worse, those bulges were in materialized intermediate predicates like `#shared` and `#antijoin_rhs`, not just in the middle of a pipeline. The problem was particularly evident on kamailio/kamailio, where `controlsBlock` was the slowest predicate in the IR libraries: IRGuards::IRGuardCondition::controlsBlock_dispred#fff#shared#4 ........ 58.8s IRGuards::IRGuardCondition::controlsBlock_dispred#fff#antijoin_rhs .... 33.4s IRGuards::IRGuardCondition::controlsBlock_dispred#fff#antijoin_rhs#1 .. 26.7s The first of the above relations had 201M rows, and the others had intermediate bulges of similar size. The bulges could be observed even on small projects although they did not cause measurable performance issues there. The `controlsBlock_dispred#fff#shared#4` relation had 3M rows on git/git, which is a lot for a project with only 1.5M IR instructions. This commit borrows an efficient implementation from Java's `Guards.qll`, tweaking it slightly to fit into `IRGuards`. Performance is now much better: IRGuards::IRGuardCondition::controlsBlock_dispred#fff ................... 6.1s IRGuards::IRGuardCondition::hasDominatingEdgeTo_dispred#ff .............. 616ms IRGuards::IRGuardCondition::hasDominatingEdgeTo_dispred#ff#antijoin_rhs . 540ms After this commit, the biggest bulge in `controlsBlock` is the size of `IRBlock::dominates`. On kamailio/kamailio this is an intermediate tuple count of 18M rows in the calculation of `controlsBlock`, which in the end produces 11M rows. commit 65ce6d27ff9f8ce9130d0e5729548aefaa79db1b Author: Rasmus Wriedt Larsen Date: Tue Jun 9 11:57:00 2020 +0200 Python: Update isSequence() and isMapping() for Python 3.8 commit 958763edc20f48a6302f4cc9d67f548640a17a8f Author: Rasmus Wriedt Larsen Date: Tue Jun 9 11:54:44 2020 +0200 Python: Add test for ClassValue.isSequence() and isMapping() For Python 3.6 commit 800686637029c983e670d76ca67fe5e477e0abd2 Author: Tom Hvitved Date: Tue Jun 9 11:25:07 2020 +0200 C#: Refactor data-flow predicates defined by dispatch commit b04d7015ae86c3d85fe23dfd6d7d0805489f4da4 Author: Erik Krogh Kristensen Date: Tue Jun 9 11:23:46 2020 +0200 fix test commit 03450364203ac87070c1b4f86bc372c96d0bf833 Author: Asger Feldthaus Date: Tue Jun 9 10:02:40 2020 +0100 JS: Fix 'match' call in StringOps::RegExpTest commit cade3a3e23883b1ca5650660c901ed03cc5af74a Author: Jonas Jensen Date: Tue Jun 9 10:33:03 2020 +0200 C++: Use the `hasBranchEdge` helper predicate This tidies up the code, removing unnecessary repetition. commit c2fbcea96fc08bff39672e9cbeb7fd97bef8f5b4 Author: Erik Krogh Kristensen Date: Mon Jun 8 22:28:27 2020 +0200 base the chaining on yargs on the methods that are NOT chained commit 2d2468463b17ca12465af5db1e7fa6f00cff92af Author: Esben Sparre Andreasen Date: Mon Jun 8 10:20:26 2020 +0200 JS: initial version of IncompleteMultiCharacterSanitization.ql commit 167239e74558271d867aaf1f42f2bcf8302d0265 Author: Erik Krogh Kristensen Date: Mon Jun 8 19:54:23 2020 +0200 add query to detect accidential leak of private files commit 3fc02ce24e66b9b47d9d55549e12b108b21d88cc Author: Dave Bartolomeo Date: Mon Jun 8 17:15:43 2020 -0400 C++: Fix join order in virtual dispatch with `unique` The optimizer picked a terrible join order in `VirtualDispatch::DataSensitiveCall::flowsFrom()`. Telling it that `getAnOutNode()` has a unique result convinces it to join first on the `Callable`, rather than on the `ReturnKind`. commit 2a96856ca5586029d33be263f3c5a2e93523f7f8 Author: Robert Marsh Date: Mon Jun 8 12:39:11 2020 -0700 C++/C#: Document IRPositionalParameter commit c511cc3444c5e0035b43f3da5819cdcc52f5f39e Author: Dave Bartolomeo Date: Mon Jun 8 15:37:36 2020 -0400 C++: Better caching for `getPrimaryInstructionForSideEffect()` commit ab65ec40c06671711da6de306242502f56fe880d Author: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Mon Jun 8 20:18:34 2020 +0200 Add Codeql to detect missing 'Message.origin' validation when using postMessage API commit 5acfc52087963607749b65dbf64f405e9d644f72 Author: luchua-bc Date: Mon Jun 8 16:17:40 2020 +0000 Add dependent stub classes for the test case commit 1e4addb20d2fd7af7652171cdef5a88597c9a62e Author: luchua-bc Date: Mon Jun 8 16:17:01 2020 +0000 Add dependent stub classes for the test case commit 0ae98e78a219f0e15450b8b6cdbc86201133c03e Merge: 94c2bba58 398678a28 Author: Dave Bartolomeo Date: Mon Jun 8 11:20:14 2020 -0400 Merge remote-tracking branch 'github/master' into github/codeql-c-analysis-team/69_union commit 0f06f04e322d423400e058c1603fb2d2ae0d26ad Author: Erik Krogh Kristensen Date: Mon Jun 8 16:40:48 2020 +0200 extend support for yargs for js/indirect-command-line-injection commit 53280a6b116ef26f3d8fb2871cdfd7d52926936d Author: Asger Feldthaus Date: Mon Jun 8 13:56:28 2020 +0100 JS: Add test demonstrating new flow commit baa415fec81572be22f618efd50da96e29bbaa25 Author: Rasmus Wriedt Larsen Date: Mon Jun 8 15:03:46 2020 +0200 Python: Add points-to regression for metaclass commit 7c037cd2ab212238820da42bf5ac33e95759a619 Author: Rasmus Wriedt Larsen Date: Mon Jun 8 14:49:58 2020 +0200 Python: Handle Enum._convert in Python 3.8 commit 2d9b9fa584af1d4167d90c7716b12ebd619e5d6d Author: Asger Feldthaus Date: Mon Jun 8 13:16:38 2020 +0100 JS: Use PreCallGraphStep in select array steps commit 3d2bbbd3db59d742b93d061cca3751e0503e8a95 Author: Asger Feldthaus Date: Mon Jun 8 13:10:17 2020 +0100 JS: Add PreCallGraphStep extension point commit 1f2ab605bde170613f7b1cdda0b7c98d5de7d24d Author: Asger Feldthaus Date: Mon Jun 8 12:50:53 2020 +0100 JS: Add store/load steps to AdditionalTypeTrackingStep commit 99aa559ef284a3a7f4c8c6c26fec08308ba55ba3 Author: Bt2018 Date: Mon Jun 8 06:43:00 2020 -0400 Fix auto-formatting issue commit b48168fc0349558f8146e466726a8d207095dae9 Author: Mathias Vorreiter Pedersen Date: Mon Jun 8 12:26:25 2020 +0200 C++: Accept tests commit 431cc5c926d743e6b58da7107f99ccea58a53a35 Author: Mathias Vorreiter Pedersen Date: Mon Jun 8 11:27:09 2020 +0200 C++: Fix inconsistent class name commit 01f3793159b54f1e573a57c9b8cb9816a17754ae Author: Mathias Vorreiter Pedersen Date: Mon Jun 8 11:05:30 2020 +0200 C++: Add ReadSideEffect as a possible end instruction for load chains commit a4388e92587406a27455b452eca1c9bdcd0c15b3 Author: Mathias Vorreiter Pedersen Date: Mon Jun 8 11:03:36 2020 +0200 C++: Add example demonstrating missing flow commit 872ee13ba623aac10a73a5ede6e420bf60f872e6 Author: Esben Sparre Andreasen Date: Mon Jun 8 10:04:37 2020 +0200 JS: formatting commit fa35a6a69494f31bfc612529b90c160157c9d86b Author: Esben Sparre Andreasen Date: Mon Jun 8 08:13:58 2020 +0200 JS: formatting commit 6dd9106301dcb23b6c7d3ed62e78d2819c548f21 Author: porcupineyhairs <61983466+porcupineyhairs@users.noreply.github.com> Date: Mon Jun 8 03:12:23 2020 +0530 Update XSLT.qll commit 424e88d318b1a5fae565bae6a91be5f95b6789f9 Author: Porcupiney Hairs Date: Mon Jun 8 02:52:11 2020 +0530 include sugestions from review commit 1ceb963d4c11c4cbabf3a9e621afd74f011158a7 Author: Porcupiney Hairs Date: Wed May 20 02:03:38 2020 +0530 Python : Add support for detecting XSLT Injection This PR adds support for detecting XSLT injection in Python. I have included the ql files as well as the tests with this. commit cba81eeb977df557145e590d8845d751260aded2 Author: luchua-bc Date: Sat Jun 6 03:56:12 2020 +0000 Fix string/type match and add a test case commit cce99f92a10ff9401637c58bdc4cd84f0d36dbc2 Author: Robert Marsh Date: Fri Jun 5 16:19:02 2020 -0700 C++: exclude conversions in IR field flow tests commit 53a87fa37835ff79a506f950e05ec126c8de7ecb Author: Robert Marsh Date: Fri Jun 5 15:41:10 2020 -0700 C++: accept field flow test changes after merge commit 94c2bba584f81e36da051f5a708b3692a6915ffc Author: Dave Bartolomeo Date: Fri Jun 5 17:14:14 2020 -0400 C++/C#: Fix formatting commit 0d2f8f382586bd3f796be9d6eaf37457827ff13b Merge: f7752b0a0 d4e1ee8aa Author: Robert Marsh Date: Fri Jun 5 13:52:56 2020 -0700 Merge branch 'master' into ir-this-parameter-2 commit 1c32e4cc6875de7a5c861867951f2513e7925f4f Author: Dave Bartolomeo Date: Fri Jun 5 15:41:21 2020 -0400 C++/C#: Do filtering of instructions in cached predicates The four cached predicates used to access common properties of instructions took a `TStageInstruction` as a parameter. This requires the calling code, in `Instruction.qll`, to then join the results with `hasInstruction()` to filter out results for `TRawInstruction`s that were discarded as unreachable. By simply switching the parameter types to `Instruction`, we can force that join to happen in the cached predicate itself. This makes the various accessor predicates on `Instruction` trivially inlinable to the cached predicate, instead of being joins of two huge relations that might have to be recomputed in later stages. commit e62b884b48ccaca9c8e9bc16a22ef760afb57695 Author: Dave Bartolomeo Date: Fri Jun 5 15:17:28 2020 -0400 C++/C#: Cache `Instruction.getResultIRType()` Most of the predicates on `Instruction` are thin wrappers around cached predicates in the `IRConstruction` or `SSAConstruction` modules. However, `getResultIRType()` has to join `Construction::getInstructionResultType()` with `LanguageType::getIRType()`. `getResultIRType()` is called frequently both within the IR code and by IR consumers, and that's a big join to have to repeat in multiple stages. I looked at most of the other predicates in `Instruction.qll`, and didn't see any other predicates that met all of the criteria of "large, commonly called, and not already inline". commit c708ed1fe9c1d538476e2775853c1514cb733aec Author: Dave Bartolomeo Date: Fri Jun 5 14:08:01 2020 -0400 C++: Remove some usage of `Instruction.getResultType()` There were a few places in the IR itself where we use `Instruction.getResultType()`, which returns the C++ `Type` of the result, instead of `Instruction.getResultIRType()`, which returns the language-neutral `IRType` of the result. By removing this usage, we can avoid evaluating `getResultType()` at all. There are still other uses of `Instruction.getResultType()` in other libraries. We should switch those as well. commit 11818489f5facae108ba2b82e3a9c0324e9cdeb9 Author: Dave Bartolomeo Date: Fri Jun 5 14:05:25 2020 -0400 C++/C#: Use `cached` to ensure that IR is evaluated in a single stage Before this change, evaluation of the IR was spread out across about 5 stages. This resulted in a lot of redundant evaluation, especially tuple numbering of large IPA types like `TInstruction`. This change makes two small changes that, when combined, ensure that the IR is evaluated all in one stage: First, we mark `TInstruction` as `cached`. This collapses all of the work to create instructions, across all three IR phases, into a single phase. Second, we make the `SSA` module in `SSAConstruction.qll` just contain aliases to `cached` predicates defined in the `Cached` module. This ensures that all of the `Operand`-related SSA computation happens in the same stage as all of the `Instruction`-related SSA computation. commit 4c44c84ec0ad5d0b2e6365d8ba850c84e0f157c7 Author: Robert Marsh Date: Fri Jun 5 10:45:18 2020 -0700 C++: Add QLdoc in Initializer.qll-Macro.qll commit f70453c54484ed29dc01e9f4690021d4d17aef28 Author: Erik Krogh Kristensen Date: Fri Jun 5 10:10:57 2020 +0200 autoformat commit 58f4f7129eab3162b84bf9f1836859c99531dd66 Author: Erik Krogh Kristensen Date: Thu Jun 4 16:25:26 2020 +0200 change-note commit 5ce2987cb210ea6cfb539444552c04b611243448 Author: Erik Krogh Kristensen Date: Thu Jun 4 16:15:37 2020 +0200 adjust comments to reflect that tainted-path have no array-steps commit ed4e1bbbdfc47a3d1cc0a9d5d4efe4e31040affa Author: Erik Krogh Kristensen Date: Thu Jun 4 16:13:49 2020 +0200 don't have a MembershipTestBarrierGuard in Configuration.qll commit b7a3c4a3d654c68eede920b1f6e2422b575fa901 Author: Erik Krogh Kristensen Date: Thu Jun 4 16:07:28 2020 +0200 autoformat commit f618d430e7274de8ddd5c0140e7009f9856a2668 Author: Esben Sparre Andreasen Date: Thu Jun 4 14:34:52 2020 +0200 JS: simplify HTTP::ContainerCollection, and improve expressivity(!) commit 44ebf84f4cc76c01f0a206d6b51716844b95b5ce Author: Esben Sparre Andreasen Date: Thu Jun 4 14:33:03 2020 +0200 JS: more express tests commit 4b16067af25ad542a86b40afa568ef8dd71a6465 Author: Mathias Vorreiter Pedersen Date: Thu Jun 4 11:02:03 2020 +0200 C++: Fix testcases after merge from master commit 60320a9d78f6eccee329f901ee524ffc271192eb Author: Erik Krogh Kristensen Date: Thu Jun 4 11:00:15 2020 +0200 update TaintedPath to use new consistency checking commit 68ca8e23c0cf86b43abe74b035355315c13ffdd3 Author: Erik Krogh Kristensen Date: Thu Jun 4 11:00:01 2020 +0200 introduce consistency-checking utility predicates commit c7c46ea3d6fad4d3f72aaf716b92964f2bcebf0f Author: Erik Krogh Kristensen Date: Thu Jun 4 10:55:09 2020 +0200 update test comments to be consistent commit 2cf9bcef86c2cd48cb77ad02241f7db354f56ceb Merge: d295e2139 70131e6ac Author: Mathias Vorreiter Pedersen Date: Thu Jun 4 10:52:25 2020 +0200 Merge branch 'master' into flat-structs commit 550c578c3cd96e8167da73f3c094d7491f41551c Author: Erik Krogh Kristensen Date: Thu Jun 4 10:51:08 2020 +0200 use MemberShipTest in TaintedPath commit d513e6c5b5911dbf344d6b18115f15f4d3a7b52b Author: Erik Krogh Kristensen Date: Thu Jun 4 10:40:14 2020 +0200 update comments in TaintedPath tests commit cb2370cc7d1fcd9f60022f2e8b6af4c90cef008e Author: Dave Bartolomeo Date: Thu Jun 4 02:36:51 2020 -0400 C++/C#: Fix formatting commit a409b9d45132690344dffae383f129cd90fec071 Merge: 15f41c010 5cdc29e49 Author: Dave Bartolomeo Date: Wed Jun 3 16:10:22 2020 -0400 Merge remote-tracking branch 'github/master' into github/codeql-c-analysis-team/69_union commit 15f41c0107e000cece74975afbb22d6e27768ad7 Author: Dave Bartolomeo Date: Wed Jun 3 15:42:30 2020 -0400 C++/C#: Remove dead QL code commit 9e7ca2573216ea287b837799f811899cd4a468e7 Author: Tom Hvitved Date: Wed Jun 3 14:19:29 2020 +0200 C#: Add call-sensitivity to data-flow call resolution commit bbadf4b4bb8e2e828fbe6f72e35d7210ab263106 Author: Dave Bartolomeo Date: Wed Jun 3 13:52:19 2020 -0400 C#: Port `TInstruction`-sharing support from C++ This updates C#'s IR to share `TInstruction` across stages the same way C++ does. The only interesting part is that, since we have not yet ported full alias analysis to C#, I stubbed out the required parts of the aliased SSA interface in `AliasedSSAStub.qll`. commit e65a5c921eb428122ebbe46d31c099bf873ba7e4 Author: Dave Bartolomeo Date: Wed Jun 3 13:49:14 2020 -0400 C++: Add missing QLDoc commit f93c2e4e645c6aaf875b8e979a198082bcc213ba Author: Dave Bartolomeo Date: Wed Jun 3 10:11:27 2020 -0400 C++: Remove `resultType` from the IPA constructors for `TInstruction` Making these part of the IPA object identity changes the failure mode for cases where we assign multiple result types to an instruction. Previously, we would just have one instruction with two result types, but now we'd have two instructions, which breaks things worse. This change goes back to how things were before, to avoid any new surprises on real-world code with invalid ASTs or IR. commit d295e2139a433189336c253809e7af283a4e560c Author: Mathias Vorreiter Pedersen Date: Wed Jun 3 15:13:44 2020 +0200 C++: Accept tests after merge from master commit 43a0d4c97de995a557969579c14ee509787725ce Merge: b890b162f 9c50acc0f Author: Mathias Vorreiter Pedersen Date: Wed Jun 3 15:11:14 2020 +0200 Merge branch 'master' into flat-structs commit 8316121a4435538e078ed387f75d3c82b4f5d5a4 Author: Esben Sparre Andreasen Date: Wed Jun 3 15:02:36 2020 +0200 JS: formatting commit 86dd86848f2894bea402b0150a4da4e80fa3ad5d Author: Tom Hvitved Date: Wed Jun 3 13:42:54 2020 +0200 C#: Update call-sensitivity data-flow tests commit a969dbc6ca1cb32f609afc0623ef5263589acbc0 Author: Anders Schack-Mulligen Date: Wed Jun 3 10:49:08 2020 +0200 Java: Fix missing CFG edge for switch expressions. commit b890b162f416542c4dc98f462def7690d1c7b12c Author: Mathias Vorreiter Pedersen Date: Wed Jun 3 09:28:06 2020 +0200 C++: Restrict the side effect of StoreChainEndInstructionSideEffect to be WriteSideEffectInstructions commit afee8642956f7047e3face732611449a53921dbd Author: Esben Sparre Andreasen Date: Tue Apr 28 14:14:52 2020 +0200 JS: make use of the colletions type tracking steps commit 36b7574ac10d17810a884239ff558ad9a7cda2ab Author: Esben Sparre Andreasen Date: Mon Feb 10 12:08:29 2020 +0100 JS: add additional route handler registration tests commit 117f009d175c45f919e5c68c1442d08d6dcb924e Author: Esben Sparre Andreasen Date: Mon Feb 10 10:40:55 2020 +0100 JS: use HTTP::RouteHandlerCandidateContainer in Express commit 9964902c107c7cc6dc17a0d0a59d61b766feef4e Author: Esben Sparre Andreasen Date: Mon Feb 10 10:40:46 2020 +0100 JS: introduce HTTP::RouteHandlerCandidateContainer commit 606f8274c72b9f0b303954cba745f185f2d563a5 Author: Esben Sparre Andreasen Date: Mon Feb 10 10:44:03 2020 +0100 JS: add tests for various route handler registration patterns commit f7752b0a016dff4667122cd50f41a67399aac649 Author: Robert Marsh Date: Tue Jun 2 17:22:10 2020 -0700 C++/C#: add IRParameter subclass of IRVariable commit ce34d91a0761c6cfe1a02788dc269143585d65b8 Author: Mathias Vorreiter Pedersen Date: Tue Jun 2 13:50:00 2020 +0200 C++: Add more QLDoc to StoreNode and LoadNode classes, and related predicates. I also simplified the code a bit by moving common implementations of predicates into shared super classes. Finally, I added a getLocation predicate to StoreNode to match the structure of the LoadNode class. commit a0ee41306ae4dbec36a754ad18d304dc80667f01 Author: Robert Date: Tue Jun 2 09:22:23 2020 +0100 Update cpp/ql/src/codeql-suites/slow-queries.yml Co-authored-by: Robert Marsh commit 9affa157b6db4f1aa1a8c5da601c4be3c8b0ae03 Author: luchua-bc Date: Tue Jun 2 03:21:27 2020 +0000 Add Log4J 2 and a new search string secret commit 53d4a8e3b2634befcf2c54ff97dc298d537575e6 Author: Dave Bartolomeo Date: Mon Jun 1 11:14:41 2020 -0400 C++: Refactor IR construction interface Now that `TInstruction` is shared between IR stages, several of the per-stage IR construction predicates can now be moved into the `Raw` interface exposed only by the initial construction of IR from the ASTs. This also removed a couple predicates that were not used previously at all. commit 1e863ac40bf564a702b47d483eefbffe0b645dbb Author: Dave Bartolomeo Date: Fri May 29 15:49:12 2020 -0400 C++: Share `TInstruction` across IR stages Each stage of the IR reuses the majority of the instructions from previous stages. Previously, we've been wrapping each reused old instruction in a branch of the `TInstruction` type for the next stage. This causes use to create roughly three times as many `TInstruction` objects as we actually need. Now that IPA union types are supported in the compiler, we can share a single `TInstruction` IPA type across stages. We create a single `TInstruction` IPA type, with individual branches of this type for instructions created directly from the AST (`TRawInstruction`) and for instructions added by each stage of SSA construction (`T*PhiInstruction`, `T*ChiInstruction`, `T*UnreachedInstruction`). Each stage then defines a `TStageInstruction` type that is a union of all of the branches that can appear in that particular stage. The public `Instruction` class for each phase extends the `TStageInstruction` type for that stage. The interface that each stage exposes to the pyrameterized modules in the IR is now split into three pieces: - The `Raw` module, exposed only by the original IR construction stage. This module identifies which functions have IR, which `TRawInstruction`s exist, and which `IRVariable`s exist. - The `SSA` module, exposed only by the two SSA construction stages. This identifiers which `Phi`, `Chi`, and `Unreached` instructions exist. - The global module, exposed by all three stages. This module has all of the predicates whose implementation is different for each stage, like gathering definitions of `MemoryOperand`s. Similarly, there is now a single `TIRFunction` IPA type that is shared across all three stages. There is a single `IRFunctionBase` class that exposes the stage-indepdendent predicates; the `IRFunction` class for each stage extends `IRFunctionBase`. Most of the other changes are largely mechanical. commit 6e0552c0745b079e18b50a22283533f835ce08ee Author: Robert Brignull Date: Mon Jun 1 10:57:13 2020 +0100 add more code-scanning suites commit 3d4a5a337de2ee8a60f059ffed500fa9d4a70395 Author: luchua-bc Date: Sat May 30 10:58:16 2020 +0000 Add check for J2EE server directory listing commit 45e555cff0feac58bda2176edd5690ea93c8856a Author: Robert Marsh Date: Fri May 29 14:43:48 2020 -0700 C++: accept inconsistency with unreachable exit block commit 5ee37bcd5a1e5c239a759aa9fdfc3decafeec788 Merge: f8cfcef9c 91da0d556 Author: Robert Marsh Date: Fri May 29 14:40:45 2020 -0700 Merge branch 'master' into ir-this-parameter-2 Bring in fix for duplicate virtual variables for parameter indirections commit f8cfcef9c9ac02a5f31cad1b6a685a052f964e62 Author: Robert Marsh Date: Fri May 29 09:52:03 2020 -0700 C++/C#: document isThisIndirection and sync files commit 3adc10fdb421e48be2f6d9fa466a40b45aa861e4 Author: Mathias Vorreiter Pedersen Date: Fri May 29 15:33:55 2020 +0200 C++: Accept tests commit a0603692cb77834a190678af964404bda3f5792a Author: Mathias Vorreiter Pedersen Date: Fri May 29 13:53:53 2020 +0200 C++: Add LoadChain and StoreChain nodes to handle reverse reads in dataflow commit 335baaef73968df8c2a2ef49053dbed9eef1f8c3 Author: Mathias Vorreiter Pedersen Date: Fri May 29 12:15:39 2020 +0200 C++: Add testcases for partial definitions with long access paths commit a638a08bc5bca805cbec6c64907451ba6c6914d2 Author: Robert Marsh Date: Thu May 28 17:06:14 2020 -0700 C++: autoformat commit a897caec76228f1014f603d945674fabf3b8176e Author: Robert Marsh Date: Thu May 28 13:11:22 2020 -0700 C++: outbound dataflow via `this` indirections commit 7dc30e3fdcd502ae74265b1545050f18e29e4712 Author: Robert Marsh Date: Thu May 28 11:26:30 2020 -0700 C++: add output indirections for `this` commit 104f1c3197d6399880a6a63e8398765690a34a23 Author: luchua-bc Date: Thu May 28 03:34:29 2020 +0000 Add validation query for SSL Engine/Socket and com.rabbitmq.client.ConnectionFactory commit 8c5a97170d98279a3b6944f202b2d8245c626141 Author: Porcupiney Hairs Date: Wed May 13 18:38:08 2020 +0530 Python : Add Xpath injection query This PR adds support for detecting XPATH injection in Python. I have included the ql files as well as the tests with this. commit 21d531f81e5b70920bbaeecc3bb5624f25024325 Author: Rasmus Wriedt Larsen Date: Wed May 27 16:59:18 2020 +0200 Python: Add QLDoc for FunctionValue.getQualifiedName Matching the one for Function.getQualifiedName commit 6cba2fe4f8d4ba674b5fbb44def20c7e5d97b920 Author: Rasmus Wriedt Larsen Date: Tue May 26 16:45:46 2020 +0200 Python: Model Django response sinks that are not vuln to XSS Since HttpResponse is not *only* used for XSS, it is still valuable to know the content is send as part of the response. The *proper* solution to this problem of not all HttpResponses being vulnerable to XSS is probably to define a new abstract class in Http.qll called HttpResponseXSSVulnerableSink (or similar). I would like to model a few more libraries/frameworks before fully comitting to an approach though. commit 6b168de7fc83696b9ea40917fe5b7b6a0206c5db Author: Rasmus Lerchedahl Petersen Date: Tue May 26 11:42:21 2020 +0200 Python: re, handle \Z commit c78ca2616c5950cb4e376bcf677b081df51bd3e9 Merge: 5a18b08d1 6bc9624a4 Author: Rasmus Wriedt Larsen Date: Tue May 26 11:20:04 2020 +0200 Merge branch 'master' into python-keyword-only-args commit 5a18b08d13189986f3558cc7fe86c10c9758a37b Author: Rasmus Wriedt Larsen Date: Tue May 26 11:15:00 2020 +0200 Python: Add comment explaining kw-only default index upgrade commit a616704a56cea661f2a207418ce6af09252ed8c0 Author: Rasmus Wriedt Larsen Date: Tue May 26 11:07:49 2020 +0200 Python: Fix typo Co-authored-by: Taus commit f1efdee194b37616b2eba9aeccc0f64d368132cc Author: Rasmus Lerchedahl Petersen Date: Tue May 26 08:07:13 2020 +0200 Python: re test with \Z commit 712513916c93c2a78850ff444c985e97dda67515 Author: Rasmus Lerchedahl Petersen Date: Mon May 25 07:44:00 2020 +0200 Python: Address review commit 6d1ba3f8997a633af8fe93fe3c6e53e94966b5ef Author: luchua-bc Date: Sun May 24 16:43:15 2020 +0000 Java: CWE-273 Unsafe certificate trust commit 4d6ad32f04cfc568f918916006ddb8cfe57d1c23 Author: Rasmus Lerchedahl Petersen Date: Wed May 20 08:11:03 2020 +0200 Python: Update test expectations. As ar as I can tell, all these are improvements commit 37743109853175bb2587b4d88019c177666303d9 Author: Rasmus Wriedt Larsen Date: Mon May 18 19:13:50 2020 +0200 Python: Reduce FPs in Django due to bad XSS taint-sinks Fixes https://github.com/github/codeql-python-team/issues/38 commit fa08676a1db08a12ba1c97102268adaff1af8209 Author: Rasmus Wriedt Larsen Date: Mon May 18 17:35:31 2020 +0200 Python: Proper redirect taint sinks for Django Also a major restructuring of the code. A bit controversial since it renames/moves classes that are already public. Fixes https://github.com/github/codeql/issues/3466 commit 72ea4ff0dcd4dbe80ca9f3040fe655c7b875d289 Author: Rasmus Wriedt Larsen Date: Mon May 18 16:56:47 2020 +0200 Python: Add more tests of django responses They clearly shouldn't all be XSS sinks commit 8fc803fb9f1c693678d3b4b89b7a27d290e418d1 Merge: f099e0fdc 14664be46 Author: Rasmus Wriedt Larsen Date: Mon May 18 14:44:31 2020 +0200 Merge branch 'master' into python-keyword-only-args commit b56545b236f5a65e76dd379648e8f4804eccda74 Author: Rasmus Lerchedahl Petersen Date: Mon May 18 14:44:11 2020 +0200 Python: Regexp: Handle repetions {n} (with no ,) commit 6c24f36068403ed8140848af96f760d0805c7139 Author: luchua-bc Date: Sun May 17 02:43:26 2020 +0000 Java: CWE-297 insecure JavaMail SSL configuration commit cd9538d0d927b37f24ccdd7ad6841164c5b715c6 Merge: 2c243ad1c 578787173 Author: Tom Hvitved Date: Fri May 15 15:24:05 2020 +0200 Merge remote-tracking branch 'upstream/master' into dataflow/precise-field-types commit 14ce049fc6abbd7e407b4d4291aa5e64d65fe7b3 Author: Grzegorz Golawski Date: Fri May 15 00:12:08 2020 +0200 Add support for Saxon commit 81a5692935741e9eb58bf5716fa2443d77f59e58 Author: Rasmus Lerchedahl Petersen Date: Thu May 14 21:22:21 2020 +0200 Python: handle \uxxxx and refactor commit 2c243ad1cd320be118646904d3b19d010f3835e6 Author: Tom Hvitved Date: Wed May 13 09:05:38 2020 +0200 C#: Add data-flow test commit 2d7470fc3ae1f69c393f28c79669d53e631d2bfc Author: Tom Hvitved Date: Tue May 12 21:15:47 2020 +0200 C++: Follow-up changes commit e608c53c3f6be4c007165b321a5cacad0afbd5c0 Author: Tom Hvitved Date: Tue May 12 21:12:54 2020 +0200 Java: Follow-up changes commit aa83cc14724cb0fde92c9a3841b254c1e26316a2 Author: Tom Hvitved Date: Tue May 12 16:08:25 2020 +0200 Data flow: Sync files commit a0d100485b97d41f4de020bfbbe62a23efe85483 Author: Tom Hvitved Date: Thu May 14 13:59:10 2020 +0200 Data flow: Rename `Content` variables from `f` to `c` commit f1cd53507d3482de760384565ed560760bd9e57d Author: Tom Hvitved Date: Thu May 14 13:48:02 2020 +0200 Data flow: Track precise types during field flow commit c7ddd2c20c4c7a8bcbc7347a16562999ee8a411e Author: Rasmus Lerchedahl Petersen Date: Thu May 14 07:31:03 2020 +0200 Python: make test for unicode names pass commit de50aabd60e054ecdcad75b7be54bf4929c5cbac Author: Rasmus Lerchedahl Petersen Date: Thu May 14 07:30:29 2020 +0200 Python: test for unicode names commit 4c7cf2ac2da7cb76a9fc1a0aaab428a8d07607c6 Author: Rasmus Lerchedahl Petersen Date: Thu May 14 07:06:59 2020 +0200 Python: Make test pass Also checked that the OP's snapshot no longer has alerts from `duplicate_char_in_class` commit f9f52b01057cac7755676b3d809ecf77dba9f3d4 Author: Rasmus Lerchedahl Petersen Date: Wed May 13 18:47:36 2020 +0200 Python: test for unicode in raw strings commit bab6f3788e1cdcf7b23676576e1eeb3c47a49074 Author: Artem Smotrakov Date: Sun May 3 21:58:31 2020 +0200 Java: Added a query for unsafe TLS versions - Added experimental/Security/CWE/CWE-327/UnsafeTlsVersion.ql - Added SslLib.qll - Added a qhelp file with examples - Added tests in java/ql/test/experimental/Security/CWE/CWE-327 commit f099e0fdc6f8b49da15b067dd8f7c4115f3aea63 Merge: f1630983d b2f1008a0 Author: Rasmus Wriedt Larsen Date: Thu May 7 11:27:11 2020 +0200 Merge branch 'master' into python-keyword-only-args commit f1630983d3e2827c62378a92e5f65d67fe36542d Author: Rasmus Wriedt Larsen Date: Wed May 6 09:52:40 2020 +0200 Python: Cleanup default-indexing upgrade script commit 010d5fb7697f4ddebec255a0b5b394b49790f86e Author: Rasmus Wriedt Larsen Date: Wed May 6 09:33:51 2020 +0200 Python: Fix indexes of keyword-only defaults in upgrade script Works like a charm ;) commit a15833d194f010982b90ee9ac675bd843ab3b3c1 Author: Rasmus Wriedt Larsen Date: Wed May 6 09:05:22 2020 +0200 Python: DB upgrade script for default-indexing change Follow this excellent guide: https://github.com/github/codeql-c-extractor-team/blob/master/docs/db-upgrade.md commit f051f46ee9427051d5af3230f0b3971ad36d829f Merge: 908d789f1 78d2ac1ff Author: Raul Garcia (MSFT) Date: Tue May 5 13:37:03 2020 -0700 Merge branch 'master' of https://github.com/semmle/ql commit 16e9d76e223272728f210765acc315acc2c26f79 Merge: c5e14f5c0 a0800cecc Author: Rasmus Wriedt Larsen Date: Mon May 4 11:49:00 2020 +0200 Merge branch 'master' into python-keyword-only-args commit 31a2972ecaa4d8aaf35fa99c1c740de107ef512b Author: Grzegorz Golawski Date: Mon Apr 27 23:32:48 2020 +0200 Remove qlpack.yml as these are not needed commit d590f3fba872f5a5976f90151e446a76f07b6e65 Author: Grzegorz Golawski Date: Mon Apr 27 22:35:35 2020 +0200 CodeQL query to detect XSLT injections commit c5e14f5c0d30f63a9e453e3bd04e9d1795099af8 Author: Rasmus Wriedt Larsen Date: Mon Apr 27 15:36:13 2020 +0200 Python: Handle defaults and annotations for keyword-only arguments This commit is based on a change to the extractor commit 1fcbb6e9f4312b8a705da328a8198e1442606ab7 Author: Rasmus Wriedt Larsen Date: Mon Apr 27 15:24:05 2020 +0200 Python: Better test for Argument.getDefault(i) Default values for positional arugments follow a rule, so if an argument has a default value, later positional arguments must also have default values. The database only stores the actual default values, and nothing about the arguments that doesn't have default values. This turns out to be a major problem for Argument.getKwDefault(i), since default values for keyword-only arguments doesn't have the same rule. So if you know there is one default value, you can't tell if it is associated with `foo` or `bar`, as in the examples below: ``` def a(*, foo=None, bar): pass def b(*, foo, bar=None): pass ``` commit 5f6058363f51ca8b56dd699c3e97883a6ab0e358 Author: Rasmus Wriedt Larsen Date: Mon Apr 27 15:21:48 2020 +0200 Python: Improve QLdoc for Parameter.getPosition commit 8c1cfe52f6cf53f9672225c34f9b317e9bf74eb8 Author: Rasmus Wriedt Larsen Date: Mon Apr 27 15:20:53 2020 +0200 Python: Use `getAKeywordOnlyArg` instead of `getAKwonlyarg` The result is the same, but `getAKeywordOnlyArg` is the method used everywhere else in the code. commit c508e89a0059a0d3b352a3e7d944ab588bb8b78a Author: Rasmus Wriedt Larsen Date: Mon Apr 27 14:57:14 2020 +0200 Python: Handle keyword-only arguments properly commit 4185edc087aca3dbf460706f8b488b2bdfa4a759 Author: Rasmus Wriedt Larsen Date: Mon Apr 27 11:24:59 2020 +0200 Python: Expand parameters/functions test I want to ensure we handle when only _some_ parameters have default/annotations commit 0cc8d4911211b27fa5439069c3130bec01b41193 Author: Rasmus Wriedt Larsen Date: Fri Apr 24 14:48:53 2020 +0200 Python: Add tests for full Python 3 parameters syntax Currently keyword-only parameters are not handled properly :( commit 96b36a7f0f49ce5a62946993512e786cae003519 Author: Rasmus Wriedt Larsen Date: Fri Apr 24 14:28:25 2020 +0200 Python: Clean up some QLdocs commit ce2d7fe04cfeb640303f6cda4cb067758a5497f2 Author: Rasmus Wriedt Larsen Date: Fri Apr 24 12:25:40 2020 +0200 Python: Improve QLDoc for Arguments commit 40fcd4cbe5030ff53583b55628ac53bba85c5e76 Author: Grzegorz Golawski Date: Sun Apr 19 20:49:07 2020 +0200 Fix references commit 457e2eaf594f052af8e89375670fac54437074c8 Author: Grzegorz Golawski Date: Sun Apr 19 20:31:57 2020 +0200 CodeQL query to detect OGNL injections commit 908d789f1b6cadbc44c26c139dd391c3182bf60f Merge: e44229435 5c3c8eb35 Author: Raul Garcia (MSFT) Date: Fri Nov 22 13:25:22 2019 -0800 Merge branch 'master' of https://github.com/semmle/ql commit e44229435ca344a94881e045c0305a855d9e9d27 Merge: c66e5dd13 d501316c7 Author: Raul Garcia <42392023+raulgarciamsft@users.noreply.github.com> Date: Sat Oct 26 19:05:58 2019 -0700 Merge pull request #6 from Semmle/master Merge --- .codeqlmanifest.json | 1 + .devcontainer/devcontainer.json | 2 +- .github/codeql/codeql-config.yml | 11 + .github/workflows/codeql-analysis.yml | 52 + .github/workflows/labeler.yml | 11 + .github/workflows/query-list.yml | 49 + .vscode/extensions.json | 4 +- .vscode/settings.json | 3 + CONTRIBUTING.md | 12 +- README.md | 2 +- change-notes/1.25/analysis-cpp.md | 2 + change-notes/1.25/analysis-csharp.md | 68 +- change-notes/1.25/analysis-java.md | 20 +- change-notes/1.25/analysis-javascript.md | 28 +- change-notes/1.25/analysis-python.md | 25 +- change-notes/1.26/analysis-cpp.md | 30 + change-notes/1.26/analysis-csharp.md | 35 + change-notes/1.26/analysis-java.md | 21 + change-notes/1.26/analysis-javascript.md | 49 + change-notes/1.26/analysis-python.md | 22 + config/identical-files.json | 221 +- config/opcode-qldoc.py | 102 + cpp/autobuilder/.gitignore | 13 + .../BuildScripts.cs | 296 + .../Semmle.Autobuild.Cpp.Tests.csproj | 25 + .../Semmle.Autobuild.Cpp/CppAutobuilder.cs | 23 + .../Semmle.Autobuild.Cpp}/Program.cs | 9 +- .../Properties/AssemblyInfo.cs | 8 +- .../Semmle.Autobuild.Cpp.csproj | 28 + .../2020-09-29-range-analysis-rollup.md | 14 + cpp/ql/examples/qlpack.yml | 3 + cpp/ql/examples/snippets/emptyblock.ql | 2 +- cpp/ql/examples/snippets/emptythen.ql | 2 +- cpp/ql/examples/snippets/singletonblock.ql | 2 +- .../BlockWithTooManyStatements.ql | 4 +- .../Hiding/DeclarationHidesParameter.ql | 19 +- .../Hiding/DeclarationHidesVariable.ql | 4 +- .../Likely Errors/EmptyBlock.ql | 12 +- cpp/ql/src/Critical/DeadCodeGoto.ql | 4 +- cpp/ql/src/Critical/OverflowDestination.ql | 5 +- cpp/ql/src/Critical/SizeCheck2.ql | 7 +- .../src/Critical/aliasAnalysisWarning.qhelp | 11 + cpp/ql/src/Critical/callGraphWarning.qhelp | 12 + cpp/ql/src/Critical/dataFlowWarning.qhelp | 13 + cpp/ql/src/Critical/pointsToWarning.qhelp | 11 + .../src/Documentation/CommentedOutCode.qhelp | 2 +- .../Documentation/CommentedOutCodeQuery.qhelp | 25 + .../LOC-2/Rule 11/SimpleControlFlowJmp.ql | 9 +- .../src/JPL_C/LOC-4/Rule 21/MacroInBlock.ql | 2 +- .../UncheckedReturnValueForTimeFunctions.ql | 18 +- .../Likely Typos/FutileConditional.ql | 8 +- .../Likely Typos/UsingStrcpyAsBoolean.ql | 13 +- .../Likely Typos/inconsistentLoopDirection.ql | 7 +- .../Likely Bugs/RedundantNullCheckSimple.ql | 6 +- .../Dependencies/ExternalDependencies.ql | 1 + .../ExternalDependenciesSourceLinks.ql | 1 + .../CommentedOutCodeMetricOverview.qhelp | 12 + .../Files/CommentedOutCodeReferences.qhelp | 12 + .../Metrics/Files/DuplicationProblems.qhelp | 16 + .../Metrics/Files/FLinesOfDuplicatedCode.ql | 1 + .../Files/FLinesOfDuplicatedCodeCommon.qhelp | 35 + cpp/ql/src/Metrics/Files/FNumberOfTests.ql | 3 + cpp/ql/src/Microsoft/SAL.qll | 76 +- .../src/Power of 10/Rule 4/FunctionTooLong.ql | 2 +- .../src/Power of 10/Rule 4/OneStmtPerLine.ql | 2 +- .../Power of 10/Rule 5/AssertionDensity.ql | 2 +- .../Security/CWE/CWE-022/TaintedPath.qhelp | 2 +- .../CWE/CWE-121/UnterminatedVarargsCall.ql | 2 +- .../CWE/CWE-134/UncontrolledFormatString.ql | 2 +- ...ncontrolledFormatStringThroughGlobalVar.ql | 2 +- .../CWE/CWE-190/TaintedAllocationSize.ql | 2 +- .../CWE/CWE-327/BrokenCryptoAlgorithm.ql | 4 +- .../Security/CWE/CWE-676/DangerousUseOfCin.ql | 5 +- .../CWE-676/PotentiallyDangerousFunction.ql | 7 +- .../CWE/CWE-732/DoNotCreateWorldWritable.ql | 7 +- .../Security/CWE/CWE-732/FilePermissions.qll | 21 +- .../src/codeql-suites/cpp-code-scanning.qls | 2 + cpp/ql/src/codeql-suites/cpp-lgtm-full.qls | 16 +- .../cpp-security-and-quality.qls | 6 + .../codeql-suites/cpp-security-extended.qls | 6 + .../codeql-suites/exclude-slow-queries.yml | 11 + cpp/ql/src/cpp.qll | 1 + .../Likely Bugs/RedundantNullCheckParam.cpp | 11 + .../Likely Bugs/RedundantNullCheckParam.qhelp | 29 + .../Likely Bugs/RedundantNullCheckParam.ql | 56 + .../CWE/CWE-120/MemoryUnsafeFunctionScan.cpp | 25 + .../CWE-120/MemoryUnsafeFunctionScan.qhelp | 25 + .../CWE/CWE-120/MemoryUnsafeFunctionScan.ql | 19 + .../CWE/CWE-359/PrivateCleartextWrite.qhelp | 32 + .../CWE/CWE-359/PrivateCleartextWrite.ql | 21 + .../SimpleRangeAnalysisDefinition.qll | 65 + .../interfaces/SimpleRangeAnalysisExpr.qll | 78 + .../cpp/rangeanalysis/ArrayLengthAnalysis.qll | 2 +- .../semmle/code/cpp/rangeanalysis/Bound.qll | 4 +- .../rangeanalysis/ExtendedRangeAnalysis.qll | 5 + .../rangeanalysis/InBoundsPointerDeref.qll | 2 +- .../code/cpp/rangeanalysis/RangeAnalysis.qll | 16 +- .../code/cpp/rangeanalysis/RangeUtils.qll | 12 +- .../code/cpp/rangeanalysis/SignAnalysis.qll | 14 +- .../ConstantBitwiseAndExprRange.qll | 90 + .../rangeanalysis/extensions/SubtractSelf.qll | 15 + .../cpp/security/PrivateCleartextWrite.qll | 63 + .../semmle/code/cpp/security/PrivateData.qll | 53 + cpp/ql/src/external/CodeDuplication.qll | 2 +- cpp/ql/src/external/DuplicateBlock.ql | 1 + cpp/ql/src/external/DuplicateFunction.ql | 1 + cpp/ql/src/external/MostlyDuplicateClass.ql | 1 + cpp/ql/src/external/MostlyDuplicateFile.ql | 1 + .../src/external/MostlyDuplicateFunction.ql | 1 + cpp/ql/src/external/MostlySimilarFile.ql | 1 + .../src/jsf/4.05 Libraries/AV Rule 24.qhelp | 2 +- .../AV Rule 32.ql | 1 + cpp/ql/src/jsf/4.09 Style/AV Rule 53.ql | 2 +- cpp/ql/src/jsf/4.09 Style/AV Rule 59.ql | 2 +- cpp/ql/src/jsf/4.10 Classes/AV Rule 82.ql | 10 + cpp/ql/src/jsf/4.10 Classes/AV Rule 85.qhelp | 2 +- cpp/ql/src/jsf/4.10 Classes/AV Rule 85.ql | 2 +- cpp/ql/src/jsf/4.12 Templates/AV Rule 104.ql | 4 +- .../src/jsf/4.13 Functions/AV Rule 111.qhelp | 4 +- .../src/jsf/4.13 Functions/AV Rule 114.qhelp | 2 +- .../AV Rule 135.qhelp | 2 +- .../AV Rule 135.ql | 2 +- .../AV Rule 140.qhelp | 2 +- .../jsf/4.16 Initialization/AV Rule 143.ql | 2 +- cpp/ql/src/jsf/4.17 Types/AV Rule 147.qhelp | 2 +- .../jsf/4.18 Constants/AV Rule 151.1.qhelp | 2 +- .../AV Rule 154.qhelp | 2 +- .../src/jsf/4.21 Operators/AV Rule 165.qhelp | 2 +- .../AV Rule 187.ql | 2 +- .../AV Rule 189.qhelp | 2 +- .../AV Rule 191.ql | 2 +- cpp/ql/src/jsf/jsfNote.qhelp | 18 + cpp/ql/src/printAst.ql | 27 + cpp/ql/src/semmle/code/cpp/Class.qll | 30 +- cpp/ql/src/semmle/code/cpp/Declaration.qll | 28 +- cpp/ql/src/semmle/code/cpp/Element.qll | 28 +- cpp/ql/src/semmle/code/cpp/Enum.qll | 10 +- cpp/ql/src/semmle/code/cpp/Field.qll | 4 +- cpp/ql/src/semmle/code/cpp/File.qll | 10 +- cpp/ql/src/semmle/code/cpp/FriendDecl.qll | 2 +- cpp/ql/src/semmle/code/cpp/Function.qll | 505 +- cpp/ql/src/semmle/code/cpp/Include.qll | 2 +- cpp/ql/src/semmle/code/cpp/Initializer.qll | 6 +- cpp/ql/src/semmle/code/cpp/Iteration.qll | 20 +- cpp/ql/src/semmle/code/cpp/Linkage.qll | 4 + cpp/ql/src/semmle/code/cpp/Location.qll | 29 +- cpp/ql/src/semmle/code/cpp/Macro.qll | 11 +- cpp/ql/src/semmle/code/cpp/Member.qll | 4 + cpp/ql/src/semmle/code/cpp/MemberFunction.qll | 499 + cpp/ql/src/semmle/code/cpp/NameQualifiers.qll | 5 + cpp/ql/src/semmle/code/cpp/Namespace.qll | 6 +- cpp/ql/src/semmle/code/cpp/NestedFields.qll | 33 +- cpp/ql/src/semmle/code/cpp/ObjectiveC.qll | 6 +- cpp/ql/src/semmle/code/cpp/Parameter.qll | 13 +- cpp/ql/src/semmle/code/cpp/Preprocessor.qll | 6 +- cpp/ql/src/semmle/code/cpp/PrintAST.qll | 37 +- cpp/ql/src/semmle/code/cpp/Specifier.qll | 14 +- cpp/ql/src/semmle/code/cpp/Struct.qll | 12 +- cpp/ql/src/semmle/code/cpp/TestFile.qll | 5 + cpp/ql/src/semmle/code/cpp/Type.qll | 132 +- cpp/ql/src/semmle/code/cpp/TypedefType.qll | 12 +- cpp/ql/src/semmle/code/cpp/Union.qll | 10 +- cpp/ql/src/semmle/code/cpp/UserType.qll | 13 +- cpp/ql/src/semmle/code/cpp/Variable.qll | 27 +- .../semmle/code/cpp/commons/CommonType.qll | 20 +- .../semmle/code/cpp/commons/Environment.qll | 2 +- cpp/ql/src/semmle/code/cpp/commons/File.qll | 4 + cpp/ql/src/semmle/code/cpp/commons/Printf.qll | 81 +- cpp/ql/src/semmle/code/cpp/commons/Strcat.qll | 17 +- .../code/cpp/commons/StringAnalysis.qll | 4 + .../code/cpp/commons/Synchronization.qll | 44 +- .../semmle/code/cpp/commons/VoidContext.qll | 2 +- .../code/cpp/controlflow/ControlFlowGraph.qll | 12 +- .../semmle/code/cpp/controlflow/IRGuards.qll | 89 +- .../semmle/code/cpp/controlflow/SSAUtils.qll | 14 +- .../code/cpp/controlflow/internal/CFG.qll | 24 +- .../controlflow/internal/ConstantExprs.qll | 75 +- .../cpp/dataflow/internal/AddressFlow.qll | 95 +- .../dataflow/internal/DataFlowDispatch.qll | 25 +- .../cpp/dataflow/internal/DataFlowImpl.qll | 1000 +- .../cpp/dataflow/internal/DataFlowImpl2.qll | 1000 +- .../cpp/dataflow/internal/DataFlowImpl3.qll | 1000 +- .../cpp/dataflow/internal/DataFlowImpl4.qll | 1000 +- .../dataflow/internal/DataFlowImplCommon.qll | 367 +- .../internal/DataFlowImplConsistency.qll | 40 +- .../dataflow/internal/DataFlowImplLocal.qll | 1000 +- .../cpp/dataflow/internal/DataFlowPrivate.qll | 43 +- .../cpp/dataflow/internal/DataFlowUtil.qll | 135 +- .../code/cpp/dataflow/internal/FlowVar.qll | 190 +- .../dataflow/internal/TaintTrackingUtil.qll | 42 +- .../tainttracking1/TaintTrackingImpl.qll | 12 +- .../tainttracking2/TaintTrackingImpl.qll | 12 +- cpp/ql/src/semmle/code/cpp/exprs/Access.qll | 29 +- .../code/cpp/exprs/ArithmeticOperation.qll | 55 +- .../src/semmle/code/cpp/exprs/Assignment.qll | 28 +- .../code/cpp/exprs/BitwiseOperation.qll | 17 +- .../code/cpp/exprs/BuiltInOperations.qll | 121 +- cpp/ql/src/semmle/code/cpp/exprs/Call.qll | 66 +- cpp/ql/src/semmle/code/cpp/exprs/Cast.qll | 64 +- .../code/cpp/exprs/ComparisonOperation.qll | 16 +- cpp/ql/src/semmle/code/cpp/exprs/Expr.qll | 101 +- cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll | 10 +- cpp/ql/src/semmle/code/cpp/exprs/Literal.qll | 25 +- .../code/cpp/exprs/LogicalOperation.qll | 13 +- .../src/semmle/code/cpp/exprs/ObjectiveC.qll | 4 + cpp/ql/src/semmle/code/cpp/ir/IR.qll | 46 +- .../semmle/code/cpp/ir/IRConfiguration.qll | 4 + cpp/ql/src/semmle/code/cpp/ir/PrintIR.qll | 10 + .../cpp/ir/dataflow/DefaultTaintTracking.qll | 7 +- .../ir/dataflow/internal/DataFlowDispatch.qll | 27 +- .../cpp/ir/dataflow/internal/DataFlowImpl.qll | 1000 +- .../ir/dataflow/internal/DataFlowImpl2.qll | 1000 +- .../ir/dataflow/internal/DataFlowImpl3.qll | 1000 +- .../ir/dataflow/internal/DataFlowImpl4.qll | 1000 +- .../dataflow/internal/DataFlowImplCommon.qll | 367 +- .../internal/DataFlowImplConsistency.qll | 40 +- .../ir/dataflow/internal/DataFlowPrivate.qll | 371 +- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 305 +- .../cpp/ir/dataflow/internal/ModelUtil.qll | 27 +- .../ir/dataflow/internal/PrintIRLocalFlow.qll | 152 + .../dataflow/internal/TaintTrackingUtil.qll | 26 +- .../tainttracking1/TaintTrackingImpl.qll | 12 +- .../tainttracking2/TaintTrackingImpl.qll | 12 +- .../code/cpp/ir/implementation/EdgeKind.qll | 14 +- .../cpp/ir/implementation/IRConfiguration.qll | 9 + .../code/cpp/ir/implementation/IRType.qll | 33 +- .../ir/implementation/MemoryAccessKind.qll | 7 + .../code/cpp/ir/implementation/Opcode.qll | 535 +- .../cpp/ir/implementation/TempVariableTag.qll | 1 + .../cpp/ir/implementation/aliased_ssa/IR.qll | 52 +- .../ir/implementation/aliased_ssa/IRBlock.qll | 85 +- .../aliased_ssa/IRConsistency.qll | 346 +- .../implementation/aliased_ssa/IRFunction.qll | 30 +- .../implementation/aliased_ssa/IRVariable.qll | 81 +- .../aliased_ssa/Instruction.qll | 779 +- .../ir/implementation/aliased_ssa/Operand.qll | 43 +- .../ir/implementation/aliased_ssa/PrintIR.qll | 78 +- .../aliased_ssa/internal/AliasAnalysis.qll | 11 +- .../aliased_ssa/internal/AliasedSSA.qll | 12 + .../internal/IRFunctionImports.qll | 1 + .../aliased_ssa/internal/IRInternal.qll | 1 + .../aliased_ssa/internal/SSAConstruction.qll | 305 +- .../internal/SSAConstructionImports.qll | 8 +- .../internal/SSAConstructionInternal.qll | 1 + .../internal/IRFunctionBase.qll | 27 + .../internal/IRFunctionBaseInternal.qll | 2 + .../ir/implementation/internal/OperandTag.qll | 56 +- .../internal/TIRVariableInternal.qll | 2 +- .../implementation/internal/TInstruction.qll | 97 + .../internal/TInstructionImports.qll | 2 + .../internal/TInstructionInternal.qll | 4 + .../code/cpp/ir/implementation/raw/IR.qll | 52 +- .../cpp/ir/implementation/raw/IRBlock.qll | 85 +- .../ir/implementation/raw/IRConsistency.qll | 346 +- .../cpp/ir/implementation/raw/IRFunction.qll | 30 +- .../cpp/ir/implementation/raw/IRVariable.qll | 81 +- .../cpp/ir/implementation/raw/Instruction.qll | 779 +- .../cpp/ir/implementation/raw/Operand.qll | 43 +- .../cpp/ir/implementation/raw/PrintIR.qll | 78 +- .../raw/internal/IRConstruction.qll | 522 +- .../raw/internal/IRFunctionImports.qll | 1 + .../raw/internal/IRInternal.qll | 1 + .../raw/internal/TranslatedElement.qll | 23 +- .../raw/internal/TranslatedExpr.qll | 4 +- .../raw/internal/TranslatedFunction.qll | 72 +- .../raw/internal/TranslatedInitialization.qll | 20 - .../raw/internal/TranslatedStmt.qll | 2 +- .../ir/implementation/unaliased_ssa/IR.qll | 52 +- .../implementation/unaliased_ssa/IRBlock.qll | 85 +- .../unaliased_ssa/IRConsistency.qll | 346 +- .../unaliased_ssa/IRFunction.qll | 30 +- .../unaliased_ssa/IRVariable.qll | 81 +- .../unaliased_ssa/Instruction.qll | 779 +- .../implementation/unaliased_ssa/Operand.qll | 43 +- .../implementation/unaliased_ssa/PrintIR.qll | 78 +- .../unaliased_ssa/internal/AliasAnalysis.qll | 11 +- .../internal/IRFunctionImports.qll | 1 + .../unaliased_ssa/internal/IRInternal.qll | 1 + .../internal/SSAConstruction.qll | 305 +- .../internal/SSAConstructionImports.qll | 8 +- .../internal/SSAConstructionInternal.qll | 2 + .../unaliased_ssa/internal/SimpleSSA.qll | 12 + .../semmle/code/cpp/ir/internal/CppType.qll | 6 +- .../semmle/code/cpp/ir/internal/Overlap.qll | 15 + .../code/cpp/metrics/MetricFunction.qll | 4 +- cpp/ql/src/semmle/code/cpp/models/Models.qll | 7 + .../cpp/models/implementations/Allocation.qll | 2 +- .../models/implementations/Deallocation.qll | 2 +- .../code/cpp/models/implementations/Gets.qll | 27 +- .../implementations/IdentityFunction.qll | 7 +- .../cpp/models/implementations/Iterator.qll | 293 + .../models/implementations/MemberFunction.qll | 92 + .../cpp/models/implementations/Memcpy.qll | 5 + .../cpp/models/implementations/Memset.qll | 5 + .../cpp/models/implementations/Printf.qll | 32 +- .../models/implementations/SmartPointer.qll | 61 + .../models/implementations/StdContainer.qll | 208 + .../cpp/models/implementations/StdMap.qll | 192 + .../cpp/models/implementations/StdPair.qll | 48 + .../cpp/models/implementations/StdSet.qll | 145 + .../cpp/models/implementations/StdString.qll | 598 +- .../cpp/models/implementations/Strcat.qll | 20 + .../cpp/models/implementations/Strcpy.qll | 121 +- .../cpp/models/implementations/Strdup.qll | 5 + .../code/cpp/models/interfaces/Allocation.qll | 2 +- .../code/cpp/models/interfaces/DataFlow.qll | 5 + .../cpp/models/interfaces/Deallocation.qll | 2 +- .../models/interfaces/FormattingFunction.qll | 4 +- .../interfaces/FunctionInputsAndOutputs.qll | 168 +- .../code/cpp/models/interfaces/Iterator.qll | 17 + .../code/cpp/models/interfaces/Taint.qll | 4 + .../code/cpp/rangeanalysis/NanAnalysis.qll | 4 + .../cpp/rangeanalysis/PointlessComparison.qll | 9 + .../cpp/rangeanalysis/RangeAnalysisUtils.qll | 90 +- .../code/cpp/rangeanalysis/RangeSSA.qll | 23 +- .../cpp/rangeanalysis/SimpleRangeAnalysis.qll | 1283 +- .../semmle/code/cpp/security/BufferWrite.qll | 119 +- .../code/cpp/security/CommandExecution.qll | 35 +- .../semmle/code/cpp/security/Encryption.qll | 92 +- .../semmle/code/cpp/security/FileWrite.qll | 34 +- .../cpp/security/FunctionWithWrappers.qll | 20 + .../semmle/code/cpp/security/OutputWrite.qll | 16 +- .../src/semmle/code/cpp/security/Overflow.qll | 36 +- .../semmle/code/cpp/security/PrintfLike.qll | 12 + .../code/cpp/security/SecurityOptions.qll | 6 +- .../code/cpp/security/SensitiveExprs.qll | 18 + .../code/cpp/security/TaintTrackingImpl.qll | 11 +- cpp/ql/src/semmle/code/cpp/stmts/Block.qll | 18 +- cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll | 181 +- cpp/ql/src/semmle/uml/MagicDraw.qll | 11 +- cpp/ql/src/semmlecode.cpp.dbscheme | 46 +- cpp/ql/src/semmlecode.cpp.dbscheme.stats | 4849 ++--- .../TestUtilities/InlineExpectationsTest.qll | 41 +- .../InlineExpectationsTestPrivate.qll | 23 + .../examples/expressions/PrintAST.expected | 96 +- .../rangeanalysis/bitwiseand/bitwiseand.cpp | 59 + .../bitwiseand/bitwiseand.expected | 21 + .../rangeanalysis/bitwiseand/bitwiseand.ql | 8 + .../rangeanalysis/extended/extended.cpp | 9 + .../rangeanalysis/extended/extended.expected | 6 + .../rangeanalysis/extended/extended.ql | 7 + .../extensibility/extensibility.c | 19 + .../extensibility/extensibility.expected | 9 + .../extensibility/extensibility.ql | 80 + .../rangeanalysis/RangeAnalysis.expected | 0 .../rangeanalysis/RangeAnalysis.ql | 2 +- .../rangeanalysis/rangeanalysis/test.cpp | 0 .../signanalysis/SignAnalysis.expected | 0 .../signanalysis/SignAnalysis.ql | 2 +- .../signanalysis/binary_logical_operator.c | 0 .../signanalysis/bounded_bounds.c | 0 .../signanalysis/inline_assembly.c | 0 .../rangeanalysis/signanalysis/minmax.c | 0 .../rangeanalysis/signanalysis/test.c | 0 .../rangeanalysis/signanalysis/test.cpp | 0 .../tests/PrivateCleartextWrite.expected | 21 + .../semmle/tests/PrivateCleartextWrite.qlref | 1 + .../CWE/CWE-359/semmle/tests/test.cpp | 105 + .../semmle/tests/MemoryUnsafeFunctionScan.cpp | 25 + .../tests/MemoryUnsafeFunctionScan.expected | 2 + .../tests/MemoryUnsafeFunctionScan.qlref | 1 + .../deduplication/functions.expected | 2 + .../canAccessMember/canAccessMember.expected | 54 + .../library-tests/complex_numbers/expr.ql | 2 +- .../defaulttainttracking.cpp | 60 + .../stl.cpp | 46 +- .../DefaultTaintTracking/tainted.expected | 90 +- .../DefaultTaintTracking/test_diff.expected | 48 +- .../dataflow-tests/IRDataflowTestCommon.qll | 2 +- .../dataflow/dataflow-tests/clang.cpp | 2 +- .../dataflow-consistency.expected | 70 +- .../dataflow-ir-consistency.expected | 59 +- .../dataflow-tests/localFlow.expected | 4 + .../dataflow/dataflow-tests/ref.cpp | 4 +- .../dataflow/dataflow-tests/test.cpp | 6 +- .../dataflow/dataflow-tests/test.expected | 6 + .../dataflow-tests/test_diff.expected | 10 +- .../dataflow/dataflow-tests/test_ir.expected | 6 + .../test/library-tests/dataflow/fields/A.cpp | 10 +- .../test/library-tests/dataflow/fields/C.cpp | 4 +- .../dataflow/fields/IRConfiguration.qll | 2 +- .../library-tests/dataflow/fields/Nodes.qll | 41 + .../dataflow/fields/aliasing.cpp | 113 + .../library-tests/dataflow/fields/arrays.cpp | 51 + .../dataflow/fields/by_reference.cpp | 14 +- .../library-tests/dataflow/fields/complex.cpp | 13 +- .../dataflow/fields/constructors.cpp | 4 +- .../fields/dataflow-consistency.expected | 126 +- .../fields/dataflow-ir-consistency.expected | 134 +- .../dataflow/fields/flow-diff.expected | 45 + .../dataflow/fields/flow-diff.ql | 31 + .../dataflow/fields/ir-path-flow.expected | 367 +- .../fields/partial-definition-diff.expected | 146 +- .../fields/partial-definition-diff.ql | 35 +- .../fields/partial-definition-ir.expected | 22 + .../fields/partial-definition.expected | 148 +- .../dataflow/fields/path-flow.expected | 376 +- .../dataflow/fields/realistic.cpp | 70 + .../library-tests/dataflow/fields/simple.cpp | 13 +- .../taint-tests/IRTaintTestCommon.qll | 14 +- .../dataflow/taint-tests/arrayassignment.cpp | 147 + .../dataflow/taint-tests/copyableclass.cpp | 69 + .../taint-tests/copyableclass_declonly.cpp | 69 + .../dataflow/taint-tests/format.cpp | 2 +- .../dataflow/taint-tests/localTaint.expected | 6551 ++++++- .../dataflow/taint-tests/map.cpp | 438 + .../dataflow/taint-tests/movableclass.cpp | 67 + .../dataflow/taint-tests/set.cpp | 238 + .../dataflow/taint-tests/smart_pointer.cpp | 68 + .../taint-tests/standalone_iterators.cpp | 55 + .../library-tests/dataflow/taint-tests/stl.h | 589 + .../dataflow/taint-tests/string.cpp | 566 + .../dataflow/taint-tests/stringstream.cpp | 268 + .../dataflow/taint-tests/structlikeclass.cpp | 64 + .../library-tests/dataflow/taint-tests/swap.h | 5 + .../dataflow/taint-tests/swap1.cpp | 146 + .../dataflow/taint-tests/swap2.cpp | 146 + .../dataflow/taint-tests/taint.cpp | 30 +- .../dataflow/taint-tests/taint.expected | 595 +- .../dataflow/taint-tests/test_diff.expected | 404 +- .../dataflow/taint-tests/test_ir.expected | 385 +- .../dataflow/taint-tests/vector.cpp | 401 + .../declaration/IsMember.expected | 2 + .../more/declarationEntry.expected | 3 + .../test/library-tests/fun_decl/test.expected | 1 + .../functions/functions/Functions1.expected | 2 + .../functions/functions/Functions2.expected | 6 +- .../functions/functions/Functions2.ql | 3 - .../qualified_names/unnamed.expected | 1 + .../instantiations/test.expected | 1 + .../library-tests/ir/ir/PrintAST.expected | 456 +- .../ir/ir/aliased_ssa_consistency.expected | 9 +- .../aliased_ssa_consistency_unsound.expected | 9 +- .../ir/ir/raw_consistency.expected | 9 +- .../test/library-tests/ir/ir/raw_ir.expected | 321 +- .../ir/ir/unaliased_ssa_consistency.expected | 9 +- ...unaliased_ssa_consistency_unsound.expected | 9 +- .../ir/ssa/aliased_ssa_consistency.expected | 1 + .../aliased_ssa_consistency_unsound.expected | 1 + .../ir/ssa/aliased_ssa_ir.expected | 44 +- .../ir/ssa/aliased_ssa_ir_unsound.expected | 44 +- cpp/ql/test/library-tests/ir/ssa/ssa.cpp | 4 +- .../ir/ssa/unaliased_ssa_consistency.expected | 1 + ...unaliased_ssa_consistency_unsound.expected | 1 + .../ir/ssa/unaliased_ssa_ir.expected | 44 +- .../ir/ssa/unaliased_ssa_ir_unsound.expected | 44 +- .../lambdas/captures/elements.expected | 34 +- .../inmacroexpansion.expected | 2 + .../macros/macros/affectedbymacroexpansion.ql | 2 +- .../macros/macros/inmacroexpansion.ql | 2 +- .../members/getters/members.expected | 1 + .../test/library-tests/members/this/test.cpp | 129 + .../library-tests/members/this/this.expected | 48 + .../test/library-tests/members/this/this.ql | 6 + .../copy_from_prototype.expected | 12 +- .../SimpleRangeAnalysis/lowerBound.expected | 1143 +- .../SimpleRangeAnalysis/lowerBound.ql | 2 +- .../SimpleRangeAnalysis/ternaryLower.expected | 4 + .../SimpleRangeAnalysis/ternaryUpper.expected | 4 + .../rangeanalysis/SimpleRangeAnalysis/test.c | 237 +- .../SimpleRangeAnalysis/test.cpp | 42 + .../SimpleRangeAnalysis/upperBound.expected | 1143 +- .../SimpleRangeAnalysis/upperBound.ql | 2 +- .../scopes/scopes/Scopes1.expected | 6 + .../scopes/scopes/Scopes3.expected | 32 +- .../scopes/scopes/Scopes4.expected | 6 + .../security/encryption/test.cpp | 12 + .../security/encryption/test.expected | 9 + .../library-tests/security/encryption/test.ql | 14 + .../functions/sideEffects.expected | 4 + .../generated_copy/functions.expected | 8 +- .../test/library-tests/specifiers2/cpp20.cpp | 10 + .../specifiers2/specifiers2.expected | 39 + .../specifiers2/specifiers2pp.cpp | 5 + .../compatible_cpp/compatible.expected | 71 +- .../pointerbasetype.expected | 2 +- cpp/ql/test/library-tests/switch/blocks.ql | 2 +- .../test/library-tests/syntax-zoo/Compare.qll | 148 - .../aliased_ssa_consistency.expected | 589 +- .../syntax-zoo/dataflow-consistency.expected | 75 +- .../dataflow-ir-consistency.expected | 907 +- .../syntax-zoo/raw_consistency.expected | 700 +- .../unaliased_ssa_consistency.expected | 589 +- .../templates/CPP-202/template_args.expected | 4 +- .../templates/decls/decls.expected | 2 +- .../elements.expected | 2 + .../isfromtemplateinstantiation.expected | 2 + .../isfromuninstantiatedtemplate.expected | 2 + .../test/library-tests/typedefs/Typedefs2.ql | 2 +- .../library-tests/unions/Unions1.expected | 2 +- .../library-tests/unnamed/elements.expected | 6 +- .../using-aliases/using-alias.ql | 2 +- .../variables/global/vardecl.expected | 6 + .../library-tests/variables/global/vardecl.ql | 5 + .../variables/global/variables.expected | 3 +- cpp/ql/test/library-tests/vla/blocks.ql | 2 +- .../DeclarationHidesParameter.expected | 5 + .../DeclarationHidesParameter/hiding.cpp | 61 +- .../Hiding/DeclarationHidesParameter/hiding.h | 7 + .../PointlessComparison/PointlessComparison.c | 43 +- .../PointlessComparison.expected | 7 +- .../PointlessComparison/RegressionTests.cpp | 38 +- .../inconsistentLoopDirection.cpp | 41 +- .../inconsistentLoopDirection.expected | 3 + .../MistypedFunctionArguments.expected | 2 - .../CWE/CWE-079/semmle/CgiXss/CgiXss.expected | 14 +- .../UncontrolledProcessOperation.expected | 38 + .../UncontrolledProcessOperation/test.cpp | 39 + .../semmle/tests/UnboundedWrite.expected | 8 + .../CWE-134/semmle/argv/argvLocal.expected | 42 +- ...olledFormatStringThroughGlobalVar.expected | 5 + .../TaintedAllocationSize.expected | 42 +- .../semmle/tainted/ArithmeticTainted.expected | 2 + .../tainted/IntegerOverflowTainted.expected | 10 + .../CWE/CWE-190/semmle/tainted/test2.cpp | 28 + .../CWE/CWE-190/semmle/tainted/test6.cpp | 54 + .../ArithmeticUncontrolled.expected | 36 +- .../semmle/tests/OverrunWrite.expected | 1 + .../CWE/CWE-242/semmle/tests/tests.cpp | 19 + .../block/emptyblock/emptyblock01.ql | 2 +- .../test/successor-tests/dostmt/dostmt04.ql | 2 +- .../forstmt/shortforstmt/shortforstmt04.ql | 2 +- .../ifstmt/ifelsestmt/ifelsestmt04.ql | 2 +- .../ifstmt/ifelsestmt/ifelsestmt06.ql | 2 +- .../successor-tests/ifstmt/ifstmt/ifstmt02.ql | 2 +- .../successor-tests/ifstmt/ifstmt/ifstmt04.ql | 2 +- .../stackvariables/graphable.expected | 1023 +- .../successor-tests/whilestmt/whilestmt04.ql | 2 +- .../old.dbscheme | 2109 +++ .../semmlecode.cpp.dbscheme | 2110 +++ .../static_asserts.ql | 21 + .../upgrade.properties | 4 + .../old.dbscheme | 2110 +++ .../semmlecode.cpp.dbscheme | 2096 +++ .../upgrade.properties | 3 + .../member_function_this_type.ql | 48 + .../old.dbscheme | 2109 +++ .../semmlecode.cpp.dbscheme | 2109 +++ .../upgrade.properties | 3 + .../old.dbscheme | 2096 +++ .../semmlecode.cpp.dbscheme | 2101 +++ .../upgrade.properties | 3 + .../old.dbscheme | 2101 +++ .../semmlecode.cpp.dbscheme | 2123 +++ .../upgrade.properties | 3 + csharp/.editorconfig | 273 + csharp/.gitignore | 3 +- csharp/.vscode/extensions.json | 9 + csharp/.vscode/settings.json | 11 + csharp/.vscode/tasks.json | 53 + csharp/CSharp.sln | 28 +- .../BuildScripts.cs | 1130 ++ .../Semmle.Autobuild.CSharp.Tests.csproj} | 6 +- .../CSharpAutobuilder.cs | 129 + .../DotNetRule.cs | 58 +- .../Semmle.Autobuild.CSharp/Program.cs | 33 + .../Properties/AssemblyInfo.cs | 32 + .../Semmle.Autobuild.CSharp.csproj} | 7 +- .../StandaloneBuildRule.cs | 25 +- .../AutobuildOptions.cs | 66 +- .../Semmle.Autobuild.Shared/Autobuilder.cs | 297 + .../BuildActions.cs | 60 +- .../BuildCommandAutoRule.cs | 22 +- .../BuildCommandRule.cs | 13 +- .../BuildScript.cs | 71 +- .../BuildTools.cs | 35 +- .../CommandBuilder.cs | 52 +- .../Semmle.Autobuild.Shared/Language.cs | 23 + .../MsBuildRule.cs | 88 +- .../Project.cs | 4 +- .../ProjectOrSolution.cs | 8 +- .../Properties/AssemblyInfo.cs | 8 +- .../Semmle.Autobuild.Shared.csproj | 24 + .../Solution.cs | 24 +- .../Semmle.Autobuild.Tests/BuildScripts.cs | 1147 -- .../Semmle.Autobuild/AspBuildRule.cs | 21 - .../Semmle.Autobuild/Autobuilder.cs | 431 - .../autobuilder/Semmle.Autobuild/Language.cs | 21 - .../Semmle.Autobuild/XmlBuildRule.cs | 19 - csharp/codeql-extractor.yml | 18 + .../ExtractorOptions.cs | 188 +- .../InvalidAssemblyException.cs | 7 + .../Semmle.Extraction.CIL.Driver/Program.cs | 26 +- .../Semmle.Extraction.CIL.Driver.csproj | 3 +- .../Semmle.Extraction.CIL/CachedFunction.cs | 35 +- .../Semmle.Extraction.CIL/Context.cs | 63 +- .../Entities/Assembly.cs | 88 +- .../Entities/Attribute.cs | 34 +- .../Semmle.Extraction.CIL/Entities/Event.cs | 28 +- .../Entities/ExceptionRegion.cs | 29 +- .../Semmle.Extraction.CIL/Entities/Field.cs | 66 +- .../Semmle.Extraction.CIL/Entities/File.cs | 37 +- .../Semmle.Extraction.CIL/Entities/Folder.cs | 26 +- .../Entities/Instruction.cs | 89 +- .../Entities/LocalVariable.cs | 10 +- .../Semmle.Extraction.CIL/Entities/Method.cs | 223 +- .../Entities/Namespace.cs | 24 +- .../Entities/Parameter.cs | 12 +- .../Entities/Property.cs | 35 +- .../Entities/SourceLocation.cs | 6 +- .../Semmle.Extraction.CIL/Entities/Type.cs | 461 +- .../ExtractionProduct.cs | 24 +- .../Semmle.Extraction.CIL/Factories.cs | 87 +- .../PDB/MetadataPdbReader.cs | 46 +- .../PDB/NativePdbReader.cs | 71 +- .../Semmle.Extraction.CIL/PDB/PdbReader.cs | 57 +- .../Semmle.Extraction.CIL.csproj | 3 +- .../Semmle.Extraction.CSharp.Driver/Driver.cs | 2 +- .../Semmle.Extraction.CSharp.Driver.csproj | 2 +- .../AssemblyCache.cs | 155 +- .../AssemblyInfo.cs | 140 +- .../AssemblyLoadException.cs | 6 + .../BuildAnalysis.cs | 96 +- .../CsProjFile.cs | 110 +- .../DotNet.cs | 8 +- .../NugetPackages.cs | 24 +- .../Options.cs | 53 +- .../Program.cs | 86 +- .../ProgressMonitor.cs | 12 +- .../Runtime.cs | 35 +- ...Semmle.Extraction.CSharp.Standalone.csproj | 3 +- .../SolutionFile.cs | 31 +- .../Semmle.Extraction.CSharp/Analyser.cs | 224 +- .../CompilerVersion.cs | 14 +- .../Entities/Accessor.cs | 40 +- .../Entities/Attribute.cs | 23 +- .../Entities/CommentBlock.cs | 12 +- .../Entities/CommentLine.cs | 38 +- .../Entities/Compilation.cs | 33 +- .../Entities/Constructor.cs | 48 +- .../Entities/Conversion.cs | 25 +- .../Entities/Destructor.cs | 14 +- .../Entities/Event.cs | 21 +- .../Entities/EventAccessor.cs | 14 +- .../Entities/Expression.cs | 74 +- .../Entities/Expressions/Access.cs | 7 +- .../Entities/Expressions/ArgList.cs | 4 +- .../Entities/Expressions/ArrayCreation.cs | 89 +- .../Entities/Expressions/Assignment.cs | 16 +- .../Entities/Expressions/Await.cs | 4 +- .../Entities/Expressions/Base.cs | 5 +- .../Entities/Expressions/Binary.cs | 8 +- .../Entities/Expressions/Cast.cs | 7 +- .../Entities/Expressions/Checked.cs | 4 +- .../Entities/Expressions/Conditional.cs | 4 +- .../Entities/Expressions/Default.cs | 4 +- .../Entities/Expressions/Discard.cs | 7 +- .../Entities/Expressions/ElementAccess.cs | 46 +- .../Entities/Expressions/Factory.cs | 2 - .../Entities/Expressions/ImplicitCast.cs | 26 +- .../Entities/Expressions/Initializer.cs | 31 +- .../Expressions/InterpolatedString.cs | 4 +- .../Entities/Expressions/Invocation.cs | 59 +- .../Entities/Expressions/IsPattern.cs | 16 +- .../Entities/Expressions/Lambda.cs | 23 +- .../Entities/Expressions/Literal.cs | 9 +- .../Entities/Expressions/MakeRef.cs | 4 +- .../Entities/Expressions/MemberAccess.cs | 18 +- .../Entities/Expressions/Name.cs | 4 +- .../Entities/Expressions/ObjectCreation.cs | 18 +- .../Expressions/PointerMemberAccess.cs | 4 +- .../Entities/Expressions/PostfixUnary.cs | 16 +- .../Entities/Expressions/Query.cs | 33 +- .../Entities/Expressions/RangeExpression.cs | 2 +- .../Entities/Expressions/Ref.cs | 4 +- .../Entities/Expressions/RefType.cs | 4 +- .../Entities/Expressions/RefValue.cs | 4 +- .../Entities/Expressions/Sizeof.cs | 4 +- .../Entities/Expressions/Switch.cs | 13 +- .../Entities/Expressions/This.cs | 4 +- .../Entities/Expressions/Throw.cs | 4 +- .../Entities/Expressions/Tuple.cs | 6 +- .../Entities/Expressions/TypeAccess.cs | 5 +- .../Entities/Expressions/TypeOf.cs | 4 +- .../Entities/Expressions/Unary.cs | 10 +- .../Entities/Expressions/Unchecked.cs | 4 +- .../Entities/Expressions/Unknown.cs | 5 +- .../Expressions/VariableDeclaration.cs | 15 +- .../Entities/Field.cs | 76 +- .../Entities/Indexer.cs | 24 +- .../Entities/LocalFunction.cs | 12 +- .../Entities/LocalVariable.cs | 22 +- .../Entities/Method.cs | 116 +- .../Entities/Modifier.cs | 56 +- .../Entities/Namespace.cs | 14 +- .../Entities/NamespaceDeclaration.cs | 20 +- .../Entities/OrdinaryMethod.cs | 14 +- .../Entities/Parameter.cs | 93 +- .../Entities/Property.cs | 50 +- .../Entities/Statement.cs | 30 +- .../Entities/Statements/Block.cs | 4 +- .../Entities/Statements/Break.cs | 4 +- .../Entities/Statements/Case.cs | 12 +- .../Entities/Statements/Catch.cs | 13 +- .../Entities/Statements/Checked.cs | 4 +- .../Entities/Statements/Continue.cs | 5 +- .../Entities/Statements/Do.cs | 4 +- .../Entities/Statements/Empty.cs | 4 +- .../Statements/ExpressionStatement.cs | 4 +- .../Entities/Statements/Factory.cs | 2 +- .../Entities/Statements/Fixed.cs | 4 +- .../Entities/Statements/For.cs | 6 +- .../Entities/Statements/ForEach.cs | 8 +- .../Entities/Statements/Goto.cs | 6 +- .../Entities/Statements/If.cs | 4 +- .../Entities/Statements/Labeled.cs | 16 +- .../Entities/Statements/LocalDeclaration.cs | 6 +- .../Entities/Statements/LocalFunction.cs | 8 +- .../Entities/Statements/Lock.cs | 4 +- .../Entities/Statements/Return.cs | 4 +- .../Entities/Statements/Switch.cs | 12 +- .../Entities/Statements/Throw.cs | 4 +- .../Entities/Statements/Try.cs | 4 +- .../Entities/Statements/Unchecked.cs | 4 +- .../Entities/Statements/Unsafe.cs | 4 +- .../Entities/Statements/Using.cs | 4 +- .../Entities/Statements/While.cs | 4 +- .../Entities/Statements/Yield.cs | 4 +- .../Entities/Symbol.cs | 51 +- .../Entities/TypeMention.cs | 72 +- .../Entities/Types/ArrayType.cs | 12 +- .../Entities/Types/DynamicType.cs | 10 +- .../Entities/Types/NamedType.cs | 134 +- .../Entities/Types/NullType.cs | 10 +- .../Entities/Types/Nullability.cs | 34 +- .../Entities/Types/PointerType.cs | 10 +- .../Entities/Types/TupleType.cs | 19 +- .../Entities/Types/Type.cs | 91 +- .../Entities/Types/TypeParameter.cs | 37 +- .../Types/TypeParameterConstraints.cs | 2 +- .../Entities/UserOperator.cs | 23 +- .../Entities/UsingDirective.cs | 45 +- .../Semmle.Extraction.CSharp/Extractor.cs | 372 +- .../Semmle.Extraction.CSharp/Options.cs | 28 +- .../Populators/Ast.cs | 16 +- .../Populators/CompilationUnit.cs | 15 +- .../Populators/Locations.cs | 12 +- .../Populators/Methods.cs | 12 +- .../Populators/Symbols.cs | 6 +- .../Semmle.Extraction.CSharp.csproj | 4 +- .../SymbolExtensions.cs | 301 +- .../Semmle.Extraction.Tests/FilePattern.cs | 48 + .../Semmle.Extraction.Tests/Layout.cs | 121 +- .../Semmle.Extraction.Tests/Options.cs | 12 +- .../PathTransformer.cs | 45 + .../Semmle.Extraction.Tests.csproj | 3 +- .../Semmle.Extraction.Tests/TrapWriter.cs | 35 +- .../Semmle.Extraction/CommentProcessing.cs | 94 +- csharp/extractor/Semmle.Extraction/Context.cs | 215 +- .../Semmle.Extraction/Entities/Assembly.cs | 22 +- .../Entities/ExtractionError.cs | 6 +- .../Semmle.Extraction/Entities/File.cs | 107 +- .../Semmle.Extraction/Entities/Folder.cs | 47 +- .../Entities/GeneratedLocation.cs | 16 +- .../Semmle.Extraction/Entities/Location.cs | 8 +- .../Entities/SourceLocation.cs | 14 +- csharp/extractor/Semmle.Extraction/Entity.cs | 68 +- .../Semmle.Extraction/ExtractionScope.cs | 6 +- .../extractor/Semmle.Extraction/Extractor.cs | 35 +- .../Semmle.Extraction/FilePattern.cs | 133 + .../Semmle.Extraction/FreshEntity.cs | 14 +- csharp/extractor/Semmle.Extraction/Id.cs | 42 +- csharp/extractor/Semmle.Extraction/Layout.cs | 102 +- .../Semmle.Extraction/LocationExtensions.cs | 10 +- csharp/extractor/Semmle.Extraction/Message.cs | 10 +- csharp/extractor/Semmle.Extraction/Options.cs | 24 +- .../Semmle.Extraction/PathTransformer.cs | 177 + .../Semmle.Extraction.csproj | 11 +- csharp/extractor/Semmle.Extraction/Symbol.cs | 47 +- .../Semmle.Extraction/TrapExtensions.cs | 24 +- .../extractor/Semmle.Extraction/TrapWriter.cs | 102 +- csharp/extractor/Semmle.Extraction/Tuple.cs | 18 +- csharp/extractor/Semmle.Extraction/Tuples.cs | 2 +- .../extractor/Semmle.Util.Tests/ActionMap.cs | 2 - .../Semmle.Util.Tests/CanonicalPathCache.cs | 32 +- .../extractor/Semmle.Util.Tests/LongPaths.cs | 20 +- .../Semmle.Util.Tests.csproj | 2 +- .../extractor/Semmle.Util.Tests/TextTest.cs | 4 +- csharp/extractor/Semmle.Util/ActionMap.cs | 17 +- .../Semmle.Util/CanonicalPathCache.cs | 141 +- .../Semmle.Util/CommandLineExtensions.cs | 6 +- .../Semmle.Util/CommandLineOptions.cs | 26 +- .../Semmle.Util/DictionaryExtensions.cs | 2 +- csharp/extractor/Semmle.Util/FileRenamer.cs | 4 +- csharp/extractor/Semmle.Util/FileUtils.cs | 16 +- .../extractor/Semmle.Util/FuzzyDictionary.cs | 35 +- .../Semmle.Util/IEnumerableExtensions.cs | 44 +- csharp/extractor/Semmle.Util/LineCounter.cs | 17 +- csharp/extractor/Semmle.Util/Logger.cs | 35 +- csharp/extractor/Semmle.Util/LoggerUtils.cs | 6 +- .../Semmle.Util/ProcessStartInfoExtensions.cs | 19 +- .../extractor/Semmle.Util/Semmle.Util.csproj | 2 +- csharp/extractor/Semmle.Util/StringBuilder.cs | 8 +- .../Semmle.Util/TemporaryDirectory.cs | 3 - csharp/extractor/Semmle.Util/Text.cs | 62 +- csharp/extractor/Semmle.Util/Worklist.cs | 3 +- csharp/ql/examples/qlpack.yml | 3 + .../Comments/CommentedOutCode.qhelp | 2 +- .../Comments/CommentedOutCodeQuery.qhelp | 25 + csharp/ql/src/Concurrency/Concurrency.qll | 34 +- csharp/ql/src/Documentation/Documentation.qll | 16 +- .../ql/src/Language Abuse/ForeachCapture.ql | 12 +- csharp/ql/src/Language Abuse/UselessUpcast.ql | 4 +- csharp/ql/src/Likely Bugs/SelfAssignment.ql | 4 +- csharp/ql/src/Linq/Helpers.qll | 57 +- .../Dependencies/ExternalDependencies.ql | 1 + .../ExternalDependenciesSourceLinks.ql | 1 + .../CommentedOutCodeMetricOverview.qhelp | 12 + .../Files/CommentedOutCodeReferences.qhelp | 12 + .../Metrics/Files/DuplicationProblems.qhelp | 16 + .../Metrics/Files/FLinesOfDuplicatedCode.ql | 1 + csharp/ql/src/Performance/UseTryGetValue.ql | 2 +- .../CWE-020/RuntimeChecksBypass.ql | 1 + .../CWE-022/TaintedPath.qhelp | 2 +- .../Security Features/CWE-022/ZipSlip.qhelp | 2 +- .../CWE-451/MissingXFrameOptions.ql | 2 +- .../CWE-643/XPathInjection.qhelp | 2 +- .../Encryption using ECB.qhelp | 4 +- .../Security Features/InsufficientKeySize.cs | 8 +- .../InsufficientKeySize.qhelp | 2 +- .../Security Features/InsufficientKeySize.ql | 8 +- csharp/ql/src/Stubs/Stubs.qll | 2 +- csharp/ql/src/cil.qll | 4 + .../codeql-suites/csharp-code-scanning.qls | 2 + .../ql/src/codeql-suites/csharp-lgtm-full.qls | 4 + .../csharp-security-and-quality.qls | 6 + .../csharp-security-extended.qls | 6 + .../exclude-dependency-queries.yml | 4 + csharp/ql/src/dotnet.qll | 4 + .../CWE-099/TaintedWebClient.qhelp | 2 +- .../Serialization/DataSetSerialization.qhelp | 23 + .../Serialization/DataSetSerialization.qll | 100 + .../DefiningDatasetRelatedType.qhelp | 5 + .../DefiningDatasetRelatedType.ql | 16 + ...ingPotentiallyUnsafeXmlSerialization.qhelp | 5 + .../DefiningPotentiallyUnsafeXmlSerializer.ql | 20 + ...UnsafeTypeUsedDataContractSerializer.qhelp | 5 + .../UnsafeTypeUsedDataContractSerializer.ql | 43 + .../XmlDeserializationWithDataSet.qhelp | 5 + .../XmlDeserializationWithDataSet.ql | 16 + .../code/csharp => experimental}/ir/IR.qll | 0 .../ir/IRConfiguration.qll | 0 .../ir/IRConsistency.ql | 0 .../csharp => experimental}/ir/PrintIR.ql | 0 .../csharp => experimental}/ir/PrintIR.qll | 0 .../code/csharp => experimental}/ir/Util.qll | 0 .../ir/ValueNumbering.qll | 0 .../ir/implementation/EdgeKind.qll | 14 +- .../ir/implementation/IRConfiguration.qll | 9 + .../ir/implementation/IRType.qll | 33 +- .../ir/implementation/MemoryAccessKind.qll | 7 + .../ir/implementation/Opcode.qll | 535 +- .../ir/implementation/TempVariableTag.qll | 1 + .../implementation/UseSoundEscapeAnalysis.qll | 0 .../internal/AliasedSSAStub.qll | 19 + .../internal/EdgeKindInternal.qll | 1 + .../internal/IRConfigurationInternal.qll | 1 + .../internal/IRFunctionBase.qll | 27 + .../internal/IRFunctionBaseInternal.qll | 2 + .../internal/IRTypeInternal.qll | 1 + .../implementation/internal/OpcodeImports.qll | 1 + .../ir/implementation/internal/OperandTag.qll | 56 +- .../internal/OperandTagInternal.qll | 1 + .../implementation/internal/TIRVariable.qll | 0 .../internal/TIRVariableInternal.qll | 7 + .../implementation/internal/TInstruction.qll | 97 + .../internal/TInstructionImports.qll | 2 + .../internal/TInstructionInternal.qll | 4 + .../internal/TempVariableTagInternal.qll | 6 + .../experimental/ir/implementation/raw/IR.qll | 80 + .../ir/implementation/raw/IRBlock.qll | 85 +- .../ir/implementation/raw/IRConsistency.ql | 0 .../ir/implementation/raw/IRConsistency.qll | 497 + .../ir/implementation/raw}/IRFunction.qll | 30 +- .../ir/implementation/raw/IRVariable.qll | 81 +- .../ir/implementation/raw/Instruction.qll | 779 +- .../ir/implementation/raw}/Operand.qll | 43 +- .../ir/implementation/raw/PrintIR.ql | 0 .../ir/implementation/raw/PrintIR.qll | 78 +- .../raw/constant/ConstantAnalysis.qll | 2 +- .../raw/constant/PrintConstantAnalysis.qll | 2 +- .../internal/ConstantAnalysisInternal.qll | 1 + .../raw/gvn/PrintValueNumbering.qll | 0 .../implementation/raw/gvn/ValueNumbering.qll | 0 .../gvn/internal/ValueNumberingImports.qll | 3 + .../gvn/internal/ValueNumberingInternal.qll | 0 .../raw/internal/IRBlockImports.qll | 1 + .../raw/internal/IRConstruction.qll | 250 +- .../raw/internal/IRFunctionImports.qll | 1 + .../implementation/raw/internal/IRImports.qll | 3 + .../raw/internal/IRInternal.qll | 4 + .../raw/internal/IRVariableImports.qll | 5 + .../raw/internal/InstructionImports.qll | 6 + .../raw/internal/InstructionTag.qll | 2 +- .../raw/internal/OperandImports.qll | 4 + .../raw/internal/PrintIRImports.qll | 1 + .../raw/internal/TranslatedCall.qll | 10 +- .../raw/internal/TranslatedCondition.qll | 8 +- .../raw/internal/TranslatedDeclaration.qll | 8 +- .../raw/internal/TranslatedElement.qll | 27 +- .../raw/internal/TranslatedExpr.qll | 14 +- .../raw/internal/TranslatedFunction.qll | 14 +- .../raw/internal/TranslatedInitialization.qll | 8 +- .../raw/internal/TranslatedStmt.qll | 8 +- .../internal/common/TranslatedCallBase.qll | 16 +- .../common/TranslatedConditionBase.qll | 16 +- .../common/TranslatedDeclarationBase.qll | 18 +- .../internal/common/TranslatedExprBase.qll | 4 +- .../raw/internal/desugar/Common.qll | 20 +- .../raw/internal/desugar/Delegate.qll | 20 +- .../raw/internal/desugar/Foreach.qll | 26 +- .../raw/internal/desugar/Lock.qll | 26 +- .../raw/internal/desugar/Using.qll | 0 .../TranslatedCompilerGeneratedCall.qll | 8 +- .../TranslatedCompilerGeneratedCondition.qll | 6 +- ...TranslatedCompilerGeneratedDeclaration.qll | 16 +- .../TranslatedCompilerGeneratedElement.qll | 4 +- .../TranslatedCompilerGeneratedExpr.qll | 6 +- .../TranslatedCompilerGeneratedStmt.qll | 2 +- .../raw/internal/reachability/Dominance.qll | 0 .../reachability/DominanceInternal.qll | 0 .../internal/reachability/PrintDominance.qll | 0 .../reachability/PrintReachableBlock.qll | 0 .../internal/reachability/ReachableBlock.qll | 0 .../reachability/ReachableBlockInternal.qll | 2 + .../ir/implementation/unaliased_ssa/IR.qll | 80 + .../implementation/unaliased_ssa/IRBlock.qll | 85 +- .../unaliased_ssa/IRConsistency.ql | 0 .../unaliased_ssa/IRConsistency.qll | 497 + .../unaliased_ssa}/IRFunction.qll | 30 +- .../unaliased_ssa/IRVariable.qll | 81 +- .../unaliased_ssa/Instruction.qll | 779 +- .../implementation/unaliased_ssa}/Operand.qll | 43 +- .../implementation/unaliased_ssa/PrintIR.ql | 0 .../implementation/unaliased_ssa/PrintIR.qll | 78 +- .../constant/ConstantAnalysis.qll | 2 +- .../constant/PrintConstantAnalysis.qll | 2 +- .../internal/ConstantAnalysisInternal.qll | 1 + .../unaliased_ssa/gvn/PrintValueNumbering.qll | 0 .../unaliased_ssa/gvn/ValueNumbering.qll | 0 .../gvn/internal/ValueNumberingImports.qll | 3 + .../gvn/internal/ValueNumberingInternal.qll | 0 .../unaliased_ssa/internal/AliasAnalysis.qll | 11 +- .../internal/AliasAnalysisImports.qll | 6 +- .../internal/AliasAnalysisInternal.qll | 3 + .../internal/AliasConfiguration.qll | 0 .../internal/AliasConfigurationImports.qll | 1 + .../unaliased_ssa/internal/IRBlockImports.qll | 1 + .../internal/IRFunctionImports.qll | 1 + .../unaliased_ssa/internal/IRImports.qll | 3 + .../unaliased_ssa/internal/IRInternal.qll | 4 + .../internal/IRVariableImports.qll | 5 + .../internal/InstructionImports.qll | 6 + .../unaliased_ssa/internal/OperandImports.qll | 4 + .../unaliased_ssa/internal/PrintIRImports.qll | 1 + .../unaliased_ssa/internal/PrintSSA.qll | 0 .../unaliased_ssa/internal/SSAConsistency.ql | 0 .../unaliased_ssa/internal/SSAConsistency.qll | 0 .../internal/SSAConstruction.qll | 305 +- .../internal/SSAConstructionImports.qll | 5 + .../internal/SSAConstructionInternal.qll | 8 + .../unaliased_ssa/internal/SimpleSSA.qll | 12 + .../internal/SimpleSSAImports.qll | 4 + .../internal/SimpleSSAPublicImports.qll | 1 + .../internal/reachability/Dominance.qll | 0 .../reachability/DominanceInternal.qll | 0 .../internal/reachability/PrintDominance.qll | 0 .../reachability/PrintReachableBlock.qll | 0 .../internal/reachability/ReachableBlock.qll | 0 .../reachability/ReachableBlockInternal.qll | 2 + .../ir/internal/CSharpType.qll | 2 +- .../ir/internal/IRCSharpLanguage.qll | 0 .../ir/internal/IRGuards.qll | 6 +- .../ir/internal/IRUtilities.qll | 0 .../ir/internal/IntegerConstant.qll | 0 .../ir/internal/IntegerInterval.qll | 0 .../ir/internal/IntegerPartial.qll | 0 .../ir/internal/Overlap.qll | 15 + .../ir/internal/TempVariableTag.qll | 0 .../ir/rangeanalysis/Bound.qll | 4 +- .../ir/rangeanalysis/RangeAnalysis.qll | 8 +- .../ir/rangeanalysis/RangeUtils.qll | 4 +- .../ir/rangeanalysis/SignAnalysis.qll | 6 +- csharp/ql/src/external/CodeDuplication.qll | 25 +- csharp/ql/src/external/DuplicateMethod.ql | 1 + .../ql/src/external/MostlyDuplicateClass.ql | 1 + csharp/ql/src/external/MostlyDuplicateFile.ql | 1 + .../ql/src/external/MostlyDuplicateMethod.ql | 1 + csharp/ql/src/external/MostlySimilarFile.ql | 1 + .../examples/filters/BumpMetricBy10.ql | 11 - .../examples/filters/EditDefectMessage.ql | 11 - .../examples/filters/ExcludeGeneratedCode.ql | 14 - .../external/examples/filters/FromSource.ql | 12 - .../external/tests/DefectFromExternalData.ql | 19 - .../tests/DefectFromExternalDefect.ql | 17 - .../tests/DefectFromExternalMetric.ql | 17 - csharp/ql/src/external/tests/MetricFilter.ql | 13 - .../tests/MetricFromExternalDefect.ql | 21 - .../tests/MetricFromExternalMetric.ql | 27 - csharp/ql/src/printAst.ql | 28 + csharp/ql/src/semmle/code/asp/AspNet.qll | 6 +- csharp/ql/src/semmle/code/cil/Access.qll | 1 + csharp/ql/src/semmle/code/cil/BasicBlock.qll | 20 +- .../ql/src/semmle/code/cil/Instructions.qll | 232 +- .../src/semmle/code/csharp/AnnotatedType.qll | 1 + .../ql/src/semmle/code/csharp/Assignable.qll | 14 +- .../ql/src/semmle/code/csharp/Attribute.qll | 9 +- csharp/ql/src/semmle/code/csharp/Caching.qll | 6 +- csharp/ql/src/semmle/code/csharp/Callable.qll | 233 +- csharp/ql/src/semmle/code/csharp/Comments.qll | 8 +- .../ql/src/semmle/code/csharp/Conversion.qll | 9 +- csharp/ql/src/semmle/code/csharp/Element.qll | 13 + csharp/ql/src/semmle/code/csharp/Event.qll | 15 +- .../semmle/code/csharp/ExprOrStmtParent.qll | 374 +- csharp/ql/src/semmle/code/csharp/Generics.qll | 35 +- .../ql/src/semmle/code/csharp/Implements.qll | 98 +- csharp/ql/src/semmle/code/csharp/Location.qll | 8 +- csharp/ql/src/semmle/code/csharp/Member.qll | 15 +- .../ql/src/semmle/code/csharp/Namespace.qll | 26 +- csharp/ql/src/semmle/code/csharp/PrintAst.ql | 20 + csharp/ql/src/semmle/code/csharp/PrintAst.qll | 647 + csharp/ql/src/semmle/code/csharp/Property.qll | 49 +- csharp/ql/src/semmle/code/csharp/Stmt.qll | 193 +- csharp/ql/src/semmle/code/csharp/Type.qll | 89 +- csharp/ql/src/semmle/code/csharp/TypeRef.qll | 29 + .../ql/src/semmle/code/csharp/Unification.qll | 93 +- csharp/ql/src/semmle/code/csharp/Using.qll | 7 +- csharp/ql/src/semmle/code/csharp/Variable.qll | 57 +- .../semmle/code/csharp/commons/Assertions.qll | 20 +- .../code/csharp/commons/Collections.qll | 4 +- .../code/csharp/commons/ComparisonTest.qll | 5 +- .../semmle/code/csharp/commons/Constants.qll | 2 +- .../semmle/code/csharp/commons/Strings.qll | 2 +- .../code/csharp/commons/TargetFramework.qll | 8 +- .../code/csharp/controlflow/BasicBlocks.qll | 22 +- .../csharp/controlflow/ControlFlowElement.qll | 68 +- .../csharp/controlflow/ControlFlowGraph.qll | 44 +- .../semmle/code/csharp/controlflow/Guards.qll | 263 +- .../controlflow/internal/Completion.qll | 23 +- .../controlflow/internal/NonReturning.qll | 11 +- .../controlflow/internal/PreBasicBlocks.qll | 23 +- .../csharp/controlflow/internal/Splitting.qll | 266 +- .../controlflow/internal/SuccessorType.qll | 20 +- .../src/semmle/code/csharp/dataflow/Bound.qll | 78 + .../code/csharp/dataflow/CallContext.qll | 33 +- .../csharp/dataflow/LibraryTypeDataFlow.qll | 1590 +- .../code/csharp/dataflow/ModulusAnalysis.qll | 302 + .../semmle/code/csharp/dataflow/Nullness.qll | 105 +- .../src/semmle/code/csharp/dataflow/SSA.qll | 136 +- .../code/csharp/dataflow/SignAnalysis.qll | 9 + .../flowsources/PublicCallableParameter.qll | 2 +- .../internal/ControlFlowReachability.qll | 2 +- .../dataflow/internal/DataFlowDispatch.qll | 205 +- .../csharp/dataflow/internal/DataFlowImpl.qll | 1000 +- .../dataflow/internal/DataFlowImpl2.qll | 1000 +- .../dataflow/internal/DataFlowImpl3.qll | 1000 +- .../dataflow/internal/DataFlowImpl4.qll | 1000 +- .../dataflow/internal/DataFlowImpl5.qll | 1000 +- .../dataflow/internal/DataFlowImplCommon.qll | 367 +- .../internal/DataFlowImplConsistency.qll | 40 +- .../dataflow/internal/DataFlowPrivate.qll | 1505 +- .../dataflow/internal/DataFlowPublic.qll | 94 +- .../dataflow/internal/DelegateDataFlow.qll | 66 +- .../code/csharp/dataflow/internal/Steps.qll | 4 +- .../internal/TaintTrackingPrivate.qll | 152 +- .../dataflow/internal/TaintTrackingPublic.qll | 11 +- .../internal/rangeanalysis/BoundSpecific.qll | 21 + .../internal/rangeanalysis/ConstantUtils.qll | 71 + .../rangeanalysis/ModulusAnalysisSpecific.qll | 110 + .../internal/rangeanalysis/RangeUtils.qll | 98 + .../dataflow/internal/rangeanalysis/Sign.qll | 280 + .../rangeanalysis/SignAnalysisCommon.qll | 376 + .../rangeanalysis/SignAnalysisSpecific.qll | 339 + .../rangeanalysis/SsaReadPositionCommon.qll | 57 + .../rangeanalysis/SsaReadPositionSpecific.qll | 16 + .../internal/rangeanalysis/SsaUtils.qll | 42 + .../tainttracking1/TaintTrackingImpl.qll | 12 +- .../tainttracking2/TaintTrackingImpl.qll | 12 +- .../tainttracking3/TaintTrackingImpl.qll | 12 +- .../tainttracking4/TaintTrackingImpl.qll | 12 +- .../tainttracking5/TaintTrackingImpl.qll | 12 +- .../semmle/code/csharp/dispatch/Dispatch.qll | 526 +- .../csharp/dispatch/OverridableCallable.qll | 38 +- .../code/csharp/dispatch/RuntimeCallable.qll | 1 + .../src/semmle/code/csharp/exprs/Access.qll | 91 +- .../code/csharp/exprs/ArithmeticOperation.qll | 26 +- .../semmle/code/csharp/exprs/Assignment.qll | 34 +- .../code/csharp/exprs/BitwiseOperation.qll | 12 + .../ql/src/semmle/code/csharp/exprs/Call.qll | 58 +- .../code/csharp/exprs/ComparisonOperation.qll | 15 + .../src/semmle/code/csharp/exprs/Creation.qll | 68 +- .../src/semmle/code/csharp/exprs/Dynamic.qll | 32 +- .../ql/src/semmle/code/csharp/exprs/Expr.qll | 117 +- .../src/semmle/code/csharp/exprs/Literal.qll | 40 +- .../code/csharp/exprs/LogicalOperation.qll | 14 +- .../csharp/frameworks/EntityFramework.qll | 16 +- .../semmle/code/csharp/frameworks/JsonNET.qll | 6 +- .../code/csharp/frameworks/NHibernate.qll | 5 + .../semmle/code/csharp/frameworks/System.qll | 41 +- .../src/semmle/code/csharp/frameworks/WCF.qll | 14 + .../frameworks/microsoft/AspNetCore.qll | 18 +- .../csharp/frameworks/system/Collections.qll | 10 + .../code/csharp/frameworks/system/Linq.qll | 1 + .../code/csharp/frameworks/system/Xml.qll | 4 +- .../frameworks/system/collections/Generic.qll | 13 + .../csharp/frameworks/system/data/Common.qll | 1 + .../csharp/frameworks/system/data/Entity.qll | 2 + .../frameworks/system/linq/Expressions.qll | 1 + .../system/runtime/CompilerServices.qll | 30 + .../system/text/RegularExpressions.qll | 4 + .../frameworks/system/threading/Tasks.qll | 3 + .../csharp/frameworks/system/xml/XPath.qll | 1 + .../internal/EdgeKindInternal.qll | 1 - .../internal/IRConfigurationInternal.qll | 1 - .../internal/IRTypeInternal.qll | 1 - .../implementation/internal/OpcodeImports.qll | 1 - .../internal/OperandTagInternal.qll | 1 - .../internal/TIRVariableInternal.qll | 7 - .../internal/TempVariableTagInternal.qll | 6 - .../code/csharp/ir/implementation/raw/IR.qll | 30 - .../ir/implementation/raw/IRConsistency.qll | 331 - .../internal/ConstantAnalysisInternal.qll | 1 - .../gvn/internal/ValueNumberingImports.qll | 3 - .../raw/internal/IRBlockImports.qll | 1 - .../implementation/raw/internal/IRImports.qll | 3 - .../raw/internal/IRInternal.qll | 3 - .../raw/internal/IRVariableImports.qll | 5 - .../raw/internal/InstructionImports.qll | 6 - .../raw/internal/OperandImports.qll | 4 - .../raw/internal/PrintIRImports.qll | 1 - .../reachability/ReachableBlockInternal.qll | 2 - .../ir/implementation/unaliased_ssa/IR.qll | 30 - .../unaliased_ssa/IRConsistency.qll | 331 - .../internal/ConstantAnalysisInternal.qll | 1 - .../gvn/internal/ValueNumberingImports.qll | 3 - .../internal/AliasAnalysisInternal.qll | 3 - .../internal/AliasConfigurationImports.qll | 1 - .../unaliased_ssa/internal/IRBlockImports.qll | 1 - .../unaliased_ssa/internal/IRImports.qll | 3 - .../unaliased_ssa/internal/IRInternal.qll | 3 - .../internal/IRVariableImports.qll | 5 - .../internal/InstructionImports.qll | 6 - .../unaliased_ssa/internal/OperandImports.qll | 4 - .../unaliased_ssa/internal/PrintIRImports.qll | 1 - .../internal/SSAConstructionImports.qll | 3 - .../internal/SSAConstructionInternal.qll | 6 - .../internal/SimpleSSAImports.qll | 4 - .../internal/SimpleSSAPublicImports.qll | 1 - .../reachability/ReachableBlockInternal.qll | 2 - .../code/csharp/ir/internal/TIRVariable.qll | 16 - .../semmle/code/csharp/metrics/Coupling.qll | 4 + .../security/dataflow/ConditionalBypass.qll | 4 +- .../security/dataflow/flowsinks/Html.qll | 11 +- .../csharp/serialization/Deserializers.qll | 6 + .../csharp/serialization/Serialization.qll | 22 +- csharp/ql/src/semmle/code/dotnet/Callable.qll | 5 + csharp/ql/src/semmle/code/dotnet/Element.qll | 2 +- csharp/ql/src/semmle/code/dotnet/Variable.qll | 2 + csharp/ql/src/semmlecode.csharp.dbscheme | 2 +- .../DefiningDatasetRelatedType.expected | 2 + .../DefiningDatasetRelatedType.qlref | 1 + ...ingPotentiallyUnsafeXmlSerializer.expected | 2 + ...finingPotentiallyUnsafeXmlSerializer.qlref | 1 + ...afeTypeUsedDataContractSerializer.expected | 2 + ...UnsafeTypeUsedDataContractSerializer.qlref | 1 + .../XmlDeserializationWithDataSet.expected | 1 + .../XmlDeserializationWithDataSet.qlref | 1 + .../Security Features/Serialization/test0.cs | 101 + .../test/experimental/ir/ir/PrintAst.expected | 1151 ++ .../ql/test/experimental/ir/ir/PrintAst.qlref | 1 + .../ir/ir/array.cs | 0 .../ir/ir/assignop.cs | 0 .../ir/ir/casts.cs | 0 .../ir/ir/collections.cs | 0 .../ir/ir/constructor_init.cs | 0 .../ir/ir/crement.cs | 0 .../ir/ir/delegates.cs | 0 .../ir/ir/events.cs | 0 .../ir/ir/foreach.cs | 0 .../ir/ir/func_with_param_call.cs | 0 .../ir/ir/indexers.cs | 0 .../ir/ir/inheritance_polymorphism.cs | 0 .../ir/ir/inoutref.cs | 0 .../ir/ir/isexpr.cs | 0 .../ir/ir/jumps.cs | 0 .../ir/ir/lock.cs | 0 .../ir/ir/obj_creation.cs | 0 .../ir/ir/pointers.cs | 0 .../ir/ir/prop.cs | 0 .../ir/ir/raw_ir.expected | 4 +- .../ql/test/experimental/ir/ir/raw_ir.qlref | 1 + .../ir/ir/raw_ir_consistency.expected | 1 + .../ir/ir/raw_ir_consistency.qlref | 1 + .../ir/ir/simple_call.cs | 0 .../ir/ir/simple_function.cs | 0 .../ir/ir/stmts.cs | 0 .../ir/ir/unaliased_ssa_consistency.expected | 1 + .../ir/ir/unaliased_ssa_consistency.qlref | 1 + .../ir/unaliased_ssa_ssa_consistency.expected | 0 .../ir/ir/unaliased_ssa_ssa_consistency.qlref | 1 + .../ir/ir/using.cs | 0 .../ir/ir/variables.cs | 0 .../ir/offbyone/OffByOneRA.expected | 0 .../ir/offbyone/OffByOneRA.ql | 6 +- .../ir/offbyone/null.cs | 0 .../ir/offbyone/test.cs | 0 .../ir/rangeanalysis/RangeAnalysis.expected | 0 .../ir/rangeanalysis/RangeAnalysis.ql | 8 +- .../ir/rangeanalysis/null.cs | 0 .../ir/rangeanalysis/test.cs | 0 .../library-tests/aliases/aliases1.expected | 2 - .../library-tests/aliases/aliases2.expected | 4 +- .../library-tests/arguments/PrintAst.expected | 211 + .../library-tests/arguments/PrintAst.qlref | 1 + .../assignments/PrintAst.expected | 55 + .../library-tests/assignments/PrintAst.qlref | 1 + .../attributes/PrintAst.expected | 73 + .../library-tests/attributes/PrintAst.qlref | 1 + .../cil/consistency/Handles.expected | 1 + .../library-tests/cil/consistency/Handles.ql | 23 +- .../cil/dataflow/Nullness.expected | 4 + .../constructors/PrintAst.expected | 17 + .../library-tests/constructors/PrintAst.qlref | 1 + .../library-tests/controlflow/graph/Assert.cs | 130 + .../controlflow/graph/BasicBlock.expected | 374 +- .../controlflow/graph/Condition.expected | 546 +- .../controlflow/graph/ConditionalAccess.cs | 10 + .../controlflow/graph/Conditions.cs | 13 +- .../controlflow/graph/Consistency.expected | 74 + .../controlflow/graph/Dominance.expected | 3652 +++- .../graph/EnclosingCallable.expected | 1520 +- .../controlflow/graph/EntryElement.expected | 778 +- .../controlflow/graph/ExitElement.expected | 1035 +- .../controlflow/graph/LoopUnrolling.cs | 55 +- .../controlflow/graph/MultiImplementationA.cs | 38 + .../controlflow/graph/MultiImplementationB.cs | 33 + .../controlflow/graph/NodeGraph.expected | 1204 +- .../controlflow/graph/Nodes.expected | 431 +- .../library-tests/controlflow/graph/Switch.cs | 51 +- .../controlflow/guards/AbstractValue.expected | 72 +- .../guards/BooleanGuardedExpr.expected | 8 +- .../controlflow/guards/Collections.cs | 21 +- .../guards/GuardedControlFlowNode.expected | 44 +- .../controlflow/guards/GuardedExpr.expected | 11 +- .../controlflow/guards/Guards.cs | 7 + .../controlflow/guards/Implications.expected | 65 +- .../guards/NullGuardedExpr.expected | 1 + .../controlflow/guards/Splitting.cs | 1 + .../conversion/nullable/Nullable.cs | 32 +- .../conversion/operator/PrintAst.expected | 17 + .../conversion/operator/PrintAst.qlref | 1 + .../conversion/pointer/Pointer.cs | 28 + .../conversion/pointer/Pointer.expected | 11 + .../conversion/pointer/Pointer.ql | 5 + .../library-tests/csharp6/PrintAst.expected | 236 + .../test/library-tests/csharp6/PrintAst.qlref | 1 + .../library-tests/csharp7.1/PrintAst.expected | 67 + .../library-tests/csharp7.1/PrintAst.qlref | 1 + .../library-tests/csharp7.2/PrintAst.expected | 39 + .../library-tests/csharp7.2/PrintAst.qlref | 1 + .../library-tests/csharp7.3/PrintAst.expected | 80 + .../library-tests/csharp7.3/PrintAst.qlref | 1 + .../ql/test/library-tests/csharp7/CSharp7.cs | 11 +- .../csharp7/CaseCondition.expected | 6 +- .../ConstructedLocalFunctions.expected | 8 +- .../library-tests/csharp7/DefUse.expected | 88 +- .../library-tests/csharp7/Discards.expected | 16 +- .../csharp7/ExpressionBodies.expected | 14 +- .../library-tests/csharp7/ForEach.expected | 12 +- .../library-tests/csharp7/GlobalFlow.expected | 6 +- .../csharp7/GlobalTaintTracking.expected | 8 +- .../library-tests/csharp7/IsFlow.expected | 146 +- .../library-tests/csharp7/IsPatterns.expected | 10 +- .../LocalFunctionCallArguments.expected | 20 +- .../csharp7/LocalFunctionCalls.expected | 20 +- .../csharp7/LocalFunctionParameters.expected | 28 +- .../csharp7/LocalFunctionStmts.expected | 18 +- .../csharp7/LocalFunctions.expected | 38 +- .../csharp7/LocalTaintFlow.expected | 240 +- .../csharp7/LocalVariables.expected | 64 +- .../library-tests/csharp7/PrintAst.expected | 793 + .../test/library-tests/csharp7/PrintAst.qlref | 1 + .../csharp7/RefDelegates.expected | 2 +- .../library-tests/csharp7/RefExprs.expected | 12 +- .../csharp7/RefFunctions.expected | 4 +- .../csharp7/RefVariables.expected | 8 +- .../csharp7/TaintReaches.expected | 22 +- .../csharp7/TupleAccess.expected | 16 +- .../library-tests/csharp7/TupleExpr.expected | 36 +- .../library-tests/csharp7/TupleTypes.expected | 24 +- .../library-tests/csharp7/TypeCase1.expected | 18 +- .../library-tests/csharp7/TypeCase2.expected | 8 +- .../library-tests/csharp7/TypeCase3.expected | 2 +- .../csharp7/UnboundLocalFunctions.expected | 10 +- .../csharp8/NullableRefTypes.expected | 2 +- .../library-tests/csharp8/PrintAst.expected | 1021 ++ .../test/library-tests/csharp8/PrintAst.qlref | 1 + .../ql/test/library-tests/csharp8/ranges.cs | 24 +- .../library-tests/csharp8/ranges.expected | 42 +- .../csharp8/switchCaseExprTypes.expected | 16 + .../csharp8/switchCaseExprTypes.ql | 4 + .../call-sensitivity/CallSensitivityFlow.cs | 22 +- .../CallSensitivityFlow.expected | 22 +- .../dataflow/collections/CollectionFlow.cs | 180 +- .../collections/CollectionFlow.expected | 648 +- .../dataflow/collections/CollectionFlow.ql | 4 +- .../dataflow/delegates/DelegateFlow.cs | 8 + .../dataflow/delegates/DelegateFlow.expected | 4 + .../dataflow/delegates/DelegateFlow.ql | 23 +- .../dataflow/fields/FieldFlow.expected | 223 +- .../test/library-tests/dataflow/fields/I.cs | 46 + .../library-tests/dataflow/global/Common.qll | 3 +- .../dataflow/global/DataFlow.expected | 70 +- .../dataflow/global/DataFlowPath.expected | 735 +- .../dataflow/global/GetAnOutNode.expected | 497 +- .../dataflow/global/GetAnOutNode.ql | 28 +- .../dataflow/global/GlobalDataFlow.cs | 44 + .../dataflow/global/Splitting.cs | 18 + .../dataflow/global/TaintTracking.expected | 92 +- .../global/TaintTrackingPath.expected | 904 +- .../dataflow/library/LibraryTypeDataFlow.cs | 3 + .../library/LibraryTypeDataFlow.expected | 2469 +-- .../dataflow/library/LibraryTypeDataFlow.ql | 22 +- .../dataflow/library/TaintedMember.expected | 1 + .../dataflow/library/TaintedMember.ql | 5 + .../library-tests/dataflow/local/Common.qll | 6 +- .../dataflow/local/DataFlow.expected | 16 +- .../dataflow/local/DataFlowStep.expected | 806 +- .../dataflow/local/LocalDataFlow.cs | 25 +- .../dataflow/local/TaintTracking.expected | 94 +- .../dataflow/local/TaintTrackingStep.expected | 1131 +- .../modulusanalysis/ModulusAnalysis.cs | 84 + .../modulusanalysis/ModulusAnalysis.expected | 138 + .../modulusanalysis/ModulusAnalysis.ql | 7 + .../signanalysis/MissingSign.expected | 0 .../dataflow/signanalysis/MissingSign.ql | 16 + .../dataflow/signanalysis/SignAnalysis.cs | 469 + .../signanalysis/SignAnalysis.expected | 249 + .../dataflow/signanalysis/SignAnalysis.ql | 21 + .../library-tests/dataflow/ssa/Capture.cs | 18 + .../dataflow/ssa/DefAdjacentRead.expected | 2 + .../IsLiveOutRefParameterDefinition.expected | 1 + .../ssa/SsaCapturedVariableDef.expected | 24 +- .../dataflow/ssa/SsaDef.expected | 3 + .../dataflow/ssa/SsaDefElement.expected | 3 + .../dataflow/ssa/SsaDefLastRead.expected | 2 + .../dataflow/ssa/SsaExplicitDef.expected | 3 + .../dataflow/ssa/SsaRead.expected | 2 + .../dataflow/ssa/SsaUltimateDef.expected | 3 + .../library-tests/dataflow/types/Types.cs | 24 + .../dataflow/types/Types.expected | 50 +- .../library-tests/dataflow/types/Types.ql | 2 +- .../definitions/PrintAst.expected | 407 + .../library-tests/definitions/PrintAst.qlref | 1 + .../library-tests/delegates/PrintAst.expected | 190 + .../library-tests/delegates/PrintAst.qlref | 1 + .../dispatch/CallContext.expected | 25 + .../library-tests/dispatch/CallContext.ql | 10 + .../library-tests/dispatch/ViableCallable.cs | 2 +- .../library-tests/dynamic/PrintAst.expected | 252 + .../test/library-tests/dynamic/PrintAst.qlref | 1 + .../test/library-tests/enums/Enums11.expected | 5 + csharp/ql/test/library-tests/enums/Enums11.ql | 12 + .../library-tests/enums/PrintAst.expected | 105 + .../test/library-tests/enums/PrintAst.qlref | 1 + csharp/ql/test/library-tests/enums/enums.cs | 2 +- .../library-tests/events/PrintAst.expected | 149 + .../test/library-tests/events/PrintAst.qlref | 1 + .../exceptions/PrintAst.expected | 503 + .../library-tests/exceptions/PrintAst.qlref | 1 + .../expressions/AnonymousMethod1.expected | 2 +- .../expressions/AnonymousMethod2.expected | 2 +- .../expressions/AnonymousMethod3.expected | 2 +- .../expressions/AnonymousMethod4.expected | 2 +- .../expressions/AnonymousMethod5.expected | 2 +- .../expressions/ArrayCreation11.expected | 27 + .../expressions/ArrayCreation11.ql | 13 + .../expressions/Lambda1.expected | 2 +- .../expressions/Lambda2.expected | 2 +- .../expressions/Lambda3.expected | 2 +- .../expressions/Lambda4.expected | 2 +- .../expressions/Lambda5.expected | 2 +- .../expressions/Lambda6.expected | 2 +- .../expressions/OperatorCall6.expected | 8 +- .../expressions/OperatorCall7.expected | 4 +- .../expressions/PrintAst.expected | 1957 ++ .../library-tests/expressions/PrintAst.qlref | 1 + .../expressions/QualifiableExpr.expected | 8 +- .../expressions/StripCasts.expected | 8 +- .../expressions/Tuples1.expected | 8 +- .../library-tests/expressions/expressions.cs | 12 + .../exprorstmtparent/Callable.expected | 44 + .../exprorstmtparent/Declaration.expected | 39 + .../exprorstmtparent/GetABody.expected | 31 - .../exprorstmtparent/GetABody.ql | 4 - .../exprorstmtparent/Indexer.expected | 3 + .../MultiImplementationsParent.expected | 60 - .../MultiImplementationsParent.ql | 5 - .../exprorstmtparent/Parameter.expected | 3 + .../exprorstmtparent/Property.expected | 6 + .../extractor/tagstack/Bodies.expected | 2 + .../extractor/tagstack/Classes.expected | 1 + .../extractor/tagstack/Methods.expected | 2 + .../library-tests/fields/PrintAst.expected | 185 + .../test/library-tests/fields/PrintAst.qlref | 1 + .../library-tests/generics/PrintAst.expected | 547 + .../library-tests/generics/PrintAst.qlref | 1 + .../test/library-tests/goto/PrintAst.expected | 42 + .../ql/test/library-tests/goto/PrintAst.qlref | 1 + .../indexers/Indexers12.expected | 1 + .../test/library-tests/indexers/Indexers12.ql | 8 + .../library-tests/indexers/PrintAst.expected | 322 + .../library-tests/indexers/PrintAst.qlref | 1 + .../initializers/PrintAst.expected | 58 + .../library-tests/initializers/PrintAst.qlref | 1 + .../ql/test/library-tests/ir/ir/raw_ir.qlref | 1 - .../ir/ir/raw_ir_consistency.qlref | 1 - .../ir/ir/unaliased_ssa_consistency.qlref | 1 - .../ir/ir/unaliased_ssa_ssa_consistency.qlref | 1 - .../test/library-tests/linq/PrintAst.expected | 194 + .../ql/test/library-tests/linq/PrintAst.qlref | 1 + .../library-tests/members/PrintAst.expected | 184 + .../test/library-tests/members/PrintAst.qlref | 1 + .../library-tests/methods/PrintAst.expected | 367 + .../test/library-tests/methods/PrintAst.qlref | 1 + .../namespaces/PrintAst.expected | 37 + .../library-tests/namespaces/PrintAst.qlref | 1 + .../nestedtypes/PrintAst.expected | 77 + .../library-tests/nestedtypes/PrintAst.qlref | 1 + .../library-tests/operators/PrintAst.expected | 129 + .../library-tests/operators/PrintAst.qlref | 1 + .../partial/MethodIsPartial.expected | 7 + .../library-tests/partial/MethodIsPartial.ql | 7 + .../ql/test/library-tests/partial/Partial.cs | 24 +- .../library-tests/partial/Partial1.expected | 9 +- .../library-tests/partial/Partial2.expected | 16 +- .../partial/PartialMethodBody.expected | 3 + .../partial/PartialMethodBody.ql | 7 + .../library-tests/partial/PrintAst.expected | 16 + .../test/library-tests/partial/PrintAst.qlref | 1 + .../properties/PrintAst.expected | 194 + .../library-tests/properties/PrintAst.qlref | 1 + .../test/library-tests/regressions/Program.cs | 26 +- .../regressions/TypeMentions.expected | 18 +- .../statements/PrintAst.expected | 579 + .../library-tests/statements/PrintAst.qlref | 1 + .../library-tests/types/PrintAst.expected | 48 + .../test/library-tests/types/PrintAst.qlref | 1 + .../library-tests/unsafe/PrintAst.expected | 116 + .../test/library-tests/unsafe/PrintAst.qlref | 1 + .../FormatInvalid/FormatInvalid.expected | 4 +- .../UselessCastToSelf/UselessCastToSelf.cs | 9 + .../UselessCastToSelf.expected | 2 + .../Likely Bugs/SelfAssignment/selfassigns.cs | 7 + .../ExternalDependencies.expected | 10 +- .../ExternalDependenciesSourceLinks.expected | 10 +- csharp/ql/test/query-tests/Nullness/Assert.cs | 4 +- csharp/ql/test/query-tests/Nullness/E.cs | 28 +- .../Nullness/EqualityCheck.expected | 4 + .../Nullness/Implications.expected | 42 +- .../query-tests/Nullness/NullAlways.expected | 1 + .../query-tests/Nullness/NullCheck.expected | 18 + .../query-tests/Nullness/NullMaybe.expected | 20 +- .../ReadOnlyContainer/ReadOnlyContainer.cs | 15 + .../ReadOnlyContainer.expected | 3 +- .../CWE-022/ZipSlip/ZipSlip.expected | 38 +- .../CWE-079/StoredXSS/XSS.expected | 13 +- .../CWE-079/XSS/XSS.expected | 11 +- .../CWE-112/MissingXMLValidation.expected | 20 +- .../InsufficientKeySize.cs | 12 +- .../InsufficientKeySize.expected | 4 +- .../CWE-338/InsecureRandomness.expected | 16 +- .../CWE-601/UrlRedirect/UrlRedirect.expected | 16 +- .../CWE-807/ConditionalBypass.expected | 24 +- .../CWE-838/InappropriateEncoding.expected | 4 +- .../Stubs/MinimalStubsFromSource.expected | 2 +- csharp/tools/autobuild.cmd | 4 + csharp/tools/autobuild.sh | 10 + csharp/tools/linux64/compiler-tracing.spec | 9 + csharp/tools/linux64/extract-csharp.sh | 16 + csharp/tools/osx64/compiler-tracing.spec | 24 + csharp/tools/osx64/extract-csharp.sh | 16 + csharp/tools/pre-finalize.cmd | 15 + csharp/tools/pre-finalize.sh | 15 + csharp/tools/win64/compiler-tracing.spec | 9 + .../old.dbscheme | 1889 ++ .../semmlecode.csharp.dbscheme | 1889 ++ .../upgrade.properties | 2 + docs/language/README.rst | 2 +- .../global-sphinx-files/_static/custom.css_t | 358 +- .../global-sphinx-files/_static/primer.css | 14785 ++++++++++++++++ .../_templates/layout.html | 258 +- .../global-sphinx-files/global-conf.py | 11 +- docs/language/images/query-progress.png | Bin 0 -> 1271 bytes .../beginner/crown-the-rightful-heir.rst | 2 +- .../language/learn-ql/cpp/basic-query-cpp.rst | 145 + docs/language/learn-ql/cpp/dataflow.rst | 5 +- .../cpp/private-field-initialization.rst | 6 +- docs/language/learn-ql/cpp/ql-for-cpp.rst | 3 +- .../learn-ql/csharp/basic-query-csharp.rst | 150 + docs/language/learn-ql/csharp/dataflow.rst | 5 +- .../csharp/introduce-libraries-csharp.rst | 2 +- .../learn-ql/csharp/ql-for-csharp.rst | 3 +- .../learn-ql/go/ast-class-reference.rst | 483 + docs/language/learn-ql/go/basic-query-go.rst | 151 + .../learn-ql/go/introduce-libraries-go.rst | 9 +- .../learn-ql/go/library-modeling-go.rst | 122 + docs/language/learn-ql/go/ql-for-go.rst | 10 +- docs/language/learn-ql/index.rst | 2 +- docs/language/learn-ql/intro-to-data-flow.rst | 15 +- docs/language/learn-ql/introduction-to-ql.rst | 6 +- docs/language/learn-ql/java/annotations.rst | 20 +- .../learn-ql/java/ast-class-reference.rst | 417 +- .../learn-ql/java/basic-query-java.rst | 145 + docs/language/learn-ql/java/call-graph.rst | 14 +- docs/language/learn-ql/java/dataflow.rst | 5 +- .../learn-ql/java/expressions-statements.rst | 8 +- .../java/introduce-libraries-java.rst | 50 +- docs/language/learn-ql/java/javadoc.rst | 4 +- docs/language/learn-ql/java/ql-for-java.rst | 3 +- .../learn-ql/java/source-locations.rst | 18 +- .../learn-ql/java/types-class-hierarchy.rst | 14 +- .../javascript/basic-query-javascript.rst | 136 + .../javascript/dataflow-cheat-sheet.rst | 13 +- .../language/learn-ql/javascript/dataflow.rst | 5 +- .../learn-ql/javascript/flow-labels.rst | 5 +- .../javascript/introduce-libraries-ts.rst | 2 +- .../learn-ql/javascript/ql-for-javascript.rst | 3 +- .../learn-ql/javascript/type-tracking.rst | 4 +- .../learn-ql/python/basic-query-python.rst | 144 + .../language/learn-ql/python/control-flow.rst | 2 +- .../learn-ql/python/ql-for-python.rst | 3 +- .../learn-ql/python/taint-tracking.rst | 3 +- .../writing-queries/debugging-queries.rst | 8 +- .../introduction-to-queries.rst | 28 +- .../learn-ql/writing-queries/path-queries.rst | 29 +- .../learn-ql/writing-queries/query-help.rst | 26 +- .../writing-queries/query-metadata.rst | 11 +- .../writing-queries/select-statement.rst | 6 +- .../ql-handbook/about-the-ql-language.rst | 6 +- docs/language/ql-handbook/annotations.rst | 6 +- docs/language/ql-handbook/evaluation.rst | 8 +- docs/language/ql-handbook/expressions.rst | 5 +- docs/language/ql-handbook/formulas.rst | 11 +- docs/language/ql-handbook/language.rst | 46 +- docs/language/ql-handbook/lexical-syntax.rst | 10 +- docs/language/ql-handbook/modules.rst | 11 +- docs/language/ql-handbook/name-resolution.rst | 24 +- docs/language/ql-handbook/predicates.rst | 9 +- docs/language/ql-handbook/queries.rst | 2 +- docs/language/ql-handbook/recursion.rst | 2 +- docs/language/ql-handbook/types.rst | 4 +- docs/language/ql-handbook/variables.rst | 4 +- .../ql-training/java/apache-struts-java.rst | 2 +- .../java/global-data-flow-java.rst | 2 +- .../query-examples/cpp/data-flow-cpp-2.ql | 4 +- .../java/empty-if-java-class.ql | 4 +- .../slide-snippets/abstract-syntax-tree.rst | 6 +- .../codeql-ref-tools-further-reading.rst | 4 +- .../reusables/cpp-further-reading.rst | 4 +- .../reusables/csharp-further-reading.rst | 4 +- .../language/reusables/go-further-reading.rst | 4 +- .../reusables/java-further-reading.rst | 4 +- .../reusables/javascript-further-reading.rst | 4 +- .../reusables/python-further-reading.rst | 4 +- .../language/support/reusables/frameworks.rst | 40 + .../support/reusables/versions-compilers.rst | 2 +- docs/ql-libraries/dataflow/dataflow.md | 478 + docs/ql-style-guide.md | 74 +- docs/qldoc-style-guide.md | 184 + docs/query-metadata-style-guide.md | 2 +- .../2020-09-22-hibernate-sql-sinks.md | 3 + ...-09-23-spring-multipart-request-sources.md | 3 + java/ql/examples/qlpack.yml | 3 + java/ql/examples/snippets/emptyblock.ql | 2 +- java/ql/examples/snippets/emptythen.ql | 2 +- java/ql/examples/snippets/singletonblock.ql | 2 +- .../Statements/OneStatementPerLine.ql | 2 +- .../Complexity/BlockWithTooManyStatements.ql | 2 +- .../Refactoring Opportunities/UnusedBean.ql | 4 +- .../Likely Bugs/Arithmetic/IntMultToLong.ql | 1 - .../Collections/ArrayIndexOutOfBounds.ql | 1 + .../Comparison/MissingInstanceofInEquals.ql | 2 +- .../Comparison/NoAssignInBooleanExprs.ql | 5 +- .../src/Likely Bugs/Statements/EmptyBlock.ql | 6 +- .../src/Likely Bugs/Statements/UseBraces.ql | 18 +- .../Likely Bugs/Termination/SpinOnField.ql | 2 +- .../Callables/StatementNestingDepth.ql | 2 +- .../Dependencies/ExternalDependencies.ql | 1 + .../ExternalDependenciesSourceLinks.ql | 1 + .../CommentedOutCodeMetricOverview.qhelp | 12 + .../Files/CommentedOutCodeReferences.qhelp | 12 + .../Metrics/Files/FCommentRatioCommon.qhelp | 38 + .../Metrics/Files/FLinesOfCodeOverview.qhelp | 32 + .../Files/FLinesOfCodeReferences.qhelp | 10 + .../Metrics/Files/FLinesOfDuplicatedCode.ql | 1 + .../Files/FLinesOfDuplicatedCodeCommon.qhelp | 35 + .../src/Metrics/Files/FLinesOfSimilarCode.ql | 1 + .../src/Performance/InefficientToArray.java | 28 - .../src/Performance/InefficientToArray.qhelp | 61 - java/ql/src/Performance/InefficientToArray.ql | 53 - .../CWE/CWE-020/ExternalAPISinkExample.java | 8 + .../CWE-020/ExternalAPITaintStepExample.java | 12 + .../ExternalAPIsUsedWithUntrustedData.qhelp | 48 + .../ExternalAPIsUsedWithUntrustedData.ql | 18 + .../CWE-020/UntrustedDataToExternalAPI.qhelp | 57 + .../CWE/CWE-020/UntrustedDataToExternalAPI.ql | 21 + .../src/Security/CWE/CWE-022/PathsCommon.qll | 74 - .../Security/CWE/CWE-022/TaintedPath.qhelp | 2 +- .../src/Security/CWE/CWE-022/TaintedPath.ql | 7 +- .../CWE/CWE-022/TaintedPathCommon.qll | 33 + .../Security/CWE/CWE-022/TaintedPathLocal.ql | 9 +- .../ql/src/Security/CWE/CWE-022/ZipSlip.qhelp | 2 +- .../src/Security/CWE/CWE-078/ExecCommon.qll | 7 +- .../src/Security/CWE/CWE-078/ExecTainted.ql | 2 +- .../Security/CWE/CWE-078/ExecTaintedLocal.ql | 9 +- java/ql/src/Security/CWE/CWE-079/XSS.ql | 13 +- java/ql/src/Security/CWE/CWE-079/XSSLocal.ql | 7 +- .../Security/CWE/CWE-089/SqlInjectionLib.qll | 50 +- .../ql/src/Security/CWE/CWE-089/SqlTainted.ql | 1 + .../Security/CWE/CWE-089/SqlTaintedLocal.ql | 5 + .../src/Security/CWE/CWE-089/SqlUnescaped.ql | 3 +- .../Security/CWE/CWE-090/LdapInjectionLib.qll | 393 +- .../Security/CWE/CWE-113/ResponseSplitting.ql | 5 +- .../CWE/CWE-113/ResponseSplitting.qll | 38 - .../CWE/CWE-113/ResponseSplittingLocal.ql | 2 +- .../src/Security/CWE/CWE-129/ArraySizing.qll | 2 +- .../CWE/CWE-209/StackTraceExposure.qhelp | 2 +- .../CWE/CWE-209/StackTraceExposure.ql | 14 +- .../CWE/CWE-327/BrokenCryptoAlgorithm.ql | 4 +- .../CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql | 4 +- .../src/Security/CWE/CWE-601/UrlRedirect.ql | 2 +- .../Security/CWE/CWE-601/UrlRedirectLocal.ql | 2 +- java/ql/src/Security/CWE/CWE-611/XXE.ql | 2 + .../CWE/CWE-798/HardcodedAWSCredentials.java | 10 + .../src/Security/CWE/CWE-798/SensitiveApi.qll | 6 +- .../Comments/CommentedCode.qhelp | 2 +- .../Comments/CommentedOutCodeQuery.qhelp | 25 + .../Dead Code/EmptyFinalize.ql | 2 +- .../legacy/FinallyMayNotComplete.ql | 8 +- java/ql/src/codeql-suites/java-lgtm-full.qls | 6 +- .../java-security-and-quality.qls | 4 + .../codeql-suites/java-security-extended.qls | 4 + .../Security/CWE/CWE-074/XsltInjection.java | 18 + .../Security/CWE/CWE-074/XsltInjection.qhelp | 32 + .../Security/CWE/CWE-074/XsltInjection.ql | 21 + .../Security/CWE/CWE-074/XsltInjectionLib.qll | 288 + .../Security/CWE/CWE-273/UnsafeCertTrust.java | 101 + .../CWE/CWE-273/UnsafeCertTrust.qhelp | 46 + .../Security/CWE/CWE-273/UnsafeCertTrust.ql | 246 + .../CWE/CWE-297/InsecureJavaMail.qhelp | 36 + .../Security/CWE/CWE-297/InsecureJavaMail.ql | 103 + .../Security/CWE/CWE-297/JavaMail.java | 43 + .../Security/CWE/CWE-297/SimpleMail.java | 40 + .../CWE/CWE-299/CustomRevocationChecking.java | 10 + .../CWE-299/DefaultRevocationChecking.java | 5 + .../CWE-299/DisabledRevocationChecking.qhelp | 63 + .../CWE/CWE-299/DisabledRevocationChecking.ql | 20 + .../CWE/CWE-299/NoRevocationChecking.java | 6 + .../CWE/CWE-299/RevocationCheckingLib.qll | 60 + .../Security/CWE/CWE-327/SaferTLSVersion.java | 6 + .../Security/CWE/CWE-327/SslLib.qll | 111 + .../CWE/CWE-327/UnsafeTLSVersion.java | 6 + .../CWE/CWE-327/UnsafeTlsVersion.qhelp | 60 + .../Security/CWE/CWE-327/UnsafeTlsVersion.ql | 20 + .../CWE/CWE-522/InsecureBasicAuth.java | 49 + .../CWE/CWE-522/InsecureBasicAuth.qhelp | 30 + .../Security/CWE/CWE-522/InsecureBasicAuth.ql | 263 + .../CWE}/CWE-532/SensitiveInfoLog.java | 0 .../CWE}/CWE-532/SensitiveInfoLog.qhelp | 0 .../CWE}/CWE-532/SensitiveInfoLog.ql | 11 +- .../CWE/CWE-548/InsecureDirectoryConfig.qhelp | 25 + .../CWE/CWE-548/InsecureDirectoryConfig.ql | 42 + .../experimental/Security/CWE/CWE-548/web.xml | 30 + .../Security/CWE/CWE-643/XPathInjection.qhelp | 2 +- .../Security/CWE/CWE-917/OgnlInjection.java | 17 + .../Security/CWE/CWE-917/OgnlInjection.qhelp | 33 + .../Security/CWE/CWE-917/OgnlInjection.ql | 22 + .../Security/CWE/CWE-917/OgnlInjectionLib.qll | 109 + .../CWE-939/IncorrectURLVerification.java | 0 .../CWE-939/IncorrectURLVerification.qhelp | 0 .../CWE}/CWE-939/IncorrectURLVerification.ql | 0 java/ql/src/external/CodeDuplication.qll | 2 +- java/ql/src/external/DuplicateAnonymous.ql | 1 + java/ql/src/external/DuplicateBlock.ql | 1 + java/ql/src/external/DuplicateMethod.ql | 1 + java/ql/src/external/MostlyDuplicateClass.ql | 1 + java/ql/src/external/MostlyDuplicateFile.ql | 1 + java/ql/src/external/MostlyDuplicateMethod.ql | 1 + java/ql/src/external/MostlySimilarFile.ql | 1 + java/ql/src/java.qll | 1 + java/ql/src/printAst.ql | 28 + java/ql/src/semmle/code/Location.qll | 35 +- java/ql/src/semmle/code/Unit.qll | 10 + java/ql/src/semmle/code/java/Annotation.qll | 2 + .../src/semmle/code/java/CompilationUnit.qll | 2 + .../src/semmle/code/java/ControlFlowGraph.qll | 14 +- java/ql/src/semmle/code/java/Expr.qll | 180 +- java/ql/src/semmle/code/java/Generics.qll | 15 +- java/ql/src/semmle/code/java/Import.qll | 10 + java/ql/src/semmle/code/java/Javadoc.qll | 8 +- java/ql/src/semmle/code/java/Member.qll | 10 +- .../src/semmle/code/java/PrettyPrintAst.qll | 1005 ++ java/ql/src/semmle/code/java/PrintAst.ql | 20 + java/ql/src/semmle/code/java/PrintAst.qll | 1378 +- java/ql/src/semmle/code/java/Statement.qll | 70 +- java/ql/src/semmle/code/java/StringFormat.qll | 13 +- java/ql/src/semmle/code/java/Type.qll | 16 + java/ql/src/semmle/code/java/Variable.qll | 2 + .../code/java/controlflow/Dominance.qll | 2 +- .../src/semmle/code/java/dataflow/Bound.qll | 8 +- .../semmle/code/java/dataflow/FlowSources.qll | 54 +- .../semmle/code/java/dataflow/FlowSteps.qll | 141 + .../code/java/dataflow/ModulusAnalysis.qll | 60 +- .../semmle/code/java/dataflow/Nullness.qll | 2 +- .../code/java/dataflow/RangeAnalysis.qll | 10 + .../semmle/code/java/dataflow/RangeUtils.qll | 58 +- java/ql/src/semmle/code/java/dataflow/SSA.qll | 8 +- .../code/java/dataflow/SignAnalysis.qll | 594 +- .../code/java/dataflow/internal/BaseSSA.qll | 8 +- .../java/dataflow/internal/ContainerFlow.qll | 282 +- .../dataflow/internal/DataFlowDispatch.qll | 114 +- .../java/dataflow/internal/DataFlowImpl.qll | 1000 +- .../java/dataflow/internal/DataFlowImpl2.qll | 1000 +- .../java/dataflow/internal/DataFlowImpl3.qll | 1000 +- .../java/dataflow/internal/DataFlowImpl4.qll | 1000 +- .../java/dataflow/internal/DataFlowImpl5.qll | 1000 +- .../dataflow/internal/DataFlowImplCommon.qll | 367 +- .../internal/DataFlowImplConsistency.qll | 40 +- .../dataflow/internal/DataFlowPrivate.qll | 56 +- .../java/dataflow/internal/DataFlowUtil.qll | 35 +- .../dataflow/internal/TaintTrackingUtil.qll | 326 +- .../internal/rangeanalysis/BoundSpecific.qll | 20 + .../rangeanalysis/ModulusAnalysisSpecific.qll | 119 + .../dataflow/internal/rangeanalysis/Sign.qll | 280 + .../rangeanalysis/SignAnalysisCommon.qll | 376 + .../rangeanalysis/SignAnalysisSpecific.qll | 317 + .../rangeanalysis/SsaReadPositionCommon.qll | 57 + .../rangeanalysis/SsaReadPositionSpecific.qll | 15 + .../tainttracking1/TaintTrackingImpl.qll | 12 +- .../tainttracking2/TaintTrackingImpl.qll | 12 +- .../semmle/code/java/deadcode/DeadCode.qll | 4 +- .../src/semmle/code/java/frameworks/Guice.qll | 7 + .../semmle/code/java/frameworks/Hibernate.qll | 30 +- .../semmle/code/java/frameworks/Protobuf.qll | 17 + .../semmle/code/java/frameworks/SpringWeb.qll | 20 +- .../code/java/frameworks/android/Android.qll | 10 +- .../code/java/frameworks/android/Intent.qll | 5 +- .../code/java/frameworks/android/SQLite.qll | 270 +- .../src/semmle/code/java/frameworks/jOOQ.qll | 23 + .../jackson/JacksonSerializability.qll | 14 +- .../code/java/frameworks/javase/WebSocket.qll | 21 + .../frameworks/spring/SpringController.qll | 224 +- .../java/frameworks/spring/SpringHttp.qll | 40 + .../code/java/frameworks/spring/SpringWeb.qll | 19 + .../frameworks/spring/SpringWebClient.qll | 29 + .../code/java/security/CommandArguments.qll | 194 + .../semmle/code/java/security/Encryption.qll | 90 +- .../code/java/security/ExternalAPIs.qll | 146 + .../code/java/security/FileReadWrite.qll | 16 +- .../code/java/security/LdapInjection.qll | 413 + .../code/java/security/PathCreation.qll | 141 + .../code/java/security/QueryInjection.qll | 94 + .../code/java/security/ResponseSplitting.qll | 49 + .../code/java/security}/UrlRedirect.qll | 15 +- java/ql/src/semmle/code/java/security/XSS.qll | 99 +- .../semmle/code/java/security/XmlParsers.qll | 12 + .../query-tests/security/CWE-016/options | 2 +- .../JndiInjection.expected | 180 + .../JndiInjection.java | 18 + .../JndiInjection.qlref | 0 .../security/CWE-074-JndiInjection/options | 1 + .../security/CWE-074/JndiInjection.expected | 180 - .../security/CWE-074/XsltInjection.expected | 85 + .../security/CWE-074/XsltInjection.java | 127 + .../security/CWE-074/XsltInjection.qlref | 1 + .../query-tests/security/CWE-074/options | 2 +- .../security}/CWE-094/MvelInjection.expected | 0 .../security}/CWE-094/MvelInjection.java | 0 .../security}/CWE-094/MvelInjection.qlref | 0 .../security}/CWE-094/SpelInjection.expected | 0 .../security}/CWE-094/SpelInjection.java | 0 .../security}/CWE-094/SpelInjection.qlref | 0 .../security}/CWE-094/options | 0 .../security/CWE-273/UnsafeCertTrust.expected | 7 + .../security/CWE-273/UnsafeCertTrust.qlref | 1 + .../security/CWE-273/UnsafeCertTrustTest.java | 162 + .../CWE-297/InsecureJavaMail.expected | 2 + .../security/CWE-297/InsecureJavaMail.java | 45 + .../security/CWE-297/InsecureJavaMail.qlref | 1 + .../query-tests/security/CWE-297/options | 1 + .../DisabledRevocationChecking.expected | 17 + .../CWE-299/DisabledRevocationChecking.java | 80 + .../CWE-299/DisabledRevocationChecking.qlref | 1 + .../CWE-327/UnsafeTlsVersion.expected | 150 + .../security/CWE-327/UnsafeTlsVersion.java | 124 + .../security/CWE-327/UnsafeTlsVersion.qlref | 1 + .../CWE-522/InsecureBasicAuth.expected | 43 + .../security/CWE-522/InsecureBasicAuth.java | 164 + .../security/CWE-522/InsecureBasicAuth.qlref | 1 + .../query-tests/security/CWE-522/options | 1 + .../CWE-548/InsecureDirectoryConfig.expected | 1 + .../CWE-548/InsecureDirectoryConfig.qlref | 1 + .../security/CWE-548/insecure-web.xml | 29 + .../security/CWE-917/OgnlInjection.expected | 48 + .../security/CWE-917/OgnlInjection.java | 48 + .../security/CWE-917/OgnlInjection.qlref | 1 + .../query-tests/security/CWE-917/options | 1 + .../net/sf/saxon/Configuration.java | 8 + .../net/sf/saxon/lib/SourceResolver.java | 3 + .../net/sf/saxon/om/NotationSet.java | 3 + .../saxon/s9api/AbstractXsltTransformer.java | 3 + .../net/sf/saxon/s9api/Destination.java | 3 + .../net/sf/saxon/s9api/Processor.java | 9 + .../net/sf/saxon/s9api/QName.java | 3 + .../net/sf/saxon/s9api/SaxonApiException.java | 3 + .../s9api/SaxonApiUncheckedException.java | 3 + .../net/sf/saxon/s9api/XdmItem.java | 3 + .../net/sf/saxon/s9api/XdmValue.java | 8 + .../net/sf/saxon/s9api/Xslt30Transformer.java | 15 + .../net/sf/saxon/s9api/XsltCompiler.java | 11 + .../net/sf/saxon/s9api/XsltExecutable.java | 6 + .../net/sf/saxon/s9api/XsltPackage.java | 5 + .../net/sf/saxon/s9api/XsltTransformer.java | 6 + .../stubs/ognl-3.2.14/ognl/JavaSource.java | 3 + .../stubs/ognl-3.2.14/ognl/Node.java | 6 + .../stubs/ognl-3.2.14/ognl/Ognl.java | 26 + .../stubs/ognl-3.2.14/ognl/OgnlContext.java | 71 + .../stubs/ognl-3.2.14/ognl/OgnlException.java | 3 + .../ldap/core/ContextMapper.java | 4 - .../ldap/core/DirContextOperations.java | 4 - .../ldap/core/LdapTemplate.java | 76 - .../core/NameClassPairCallbackHandler.java | 3 - .../ldap/filter/EqualsFilter.java | 5 - .../springframework/ldap/filter/Filter.java | 4 - .../ldap/filter/HardcodedFilter.java | 7 - .../ldap/query/ConditionCriteria.java | 5 - .../ldap/query/ContainerCriteria.java | 4 - .../springframework/ldap/query/LdapQuery.java | 4 - .../ldap/query/LdapQueryBuilder.java | 14 - .../ldap/support/LdapEncoder.java | 5 - .../ldap/support/LdapNameBuilder.java | 12 - .../ldap/support/LdapUtils.java | 7 - .../opensymphony/xwork2/ognl/OgnlUtil.java | 16 + .../{blacklist.expected => insecure.expected} | 0 .../Encryption/{whitelist.ql => insecure.ql} | 2 +- .../{whitelist.expected => secure.expected} | 0 .../Encryption/{blacklist.ql => secure.ql} | 2 +- .../test/library-tests/JDK/PrintAst.expected | 62 + java/ql/test/library-tests/JDK/PrintAst.qlref | 1 + .../library-tests/arrays/PrintAst.expected | 52 + .../test/library-tests/arrays/PrintAst.qlref | 1 + .../collections/PrintAst.expected | 19 + .../library-tests/collections/PrintAst.qlref | 1 + .../library-tests/comments/PrintAst.expected | 32 + .../library-tests/comments/PrintAst.qlref | 1 + .../library-tests/constants/PrintAst.expected | 514 + .../library-tests/constants/PrintAst.qlref | 1 + .../constructors/PrintAst.expected | 40 + .../library-tests/constructors/PrintAst.qlref | 1 + .../controlflow/dominance/dominanceBad.ql | 2 +- .../library-tests/dataflow/callctx/A.java | 63 + .../dataflow/callctx/test.expected | 15 + .../library-tests/dataflow/callctx/test.ql | 15 + .../dataflow/collections/ContainterTest.java | 228 + .../dataflow/collections/flow.expected | 130 + .../dataflow/collections/flow.ql | 11 +- .../test/library-tests/dataflow/fields/F.java | 38 + .../dataflow/fields/flow.expected | 3 + .../library-tests/dataflow/getter/getter.ql | 2 +- .../local-additional-taint/ArraysTest.java | 23 + .../CollectionsTest.java | 40 + .../dataflow/local-additional-taint/Test.java | 6 +- .../localAdditionalTaintStep.expected | 59 + .../dataflow/local-additional-taint/options | 2 +- .../dataflow/local-flow/ObjectsTest.java | 14 + .../dataflow/local-flow/flow.expected | 7 + .../library-tests/dataflow/local-flow/flow.ql | 21 + .../library-tests/dataflow/local-flow/options | 1 + .../modulus-analysis/ModulusAnalysis.expected | 107 + .../modulus-analysis/ModulusAnalysis.java | 55 + .../modulus-analysis/ModulusAnalysis.ql | 7 + .../dataflow/range-analysis/A.java | 41 + .../range-analysis/RangeAnalysis.expected | 181 + .../dataflow/range-analysis/RangeAnalysis.ql | 12 + .../library-tests/dataflow/records/A.java | 65 + .../library-tests/dataflow/records/options | 1 + .../dataflow/records/test.expected | 9 + .../library-tests/dataflow/records/test.ql | 15 + .../dataflow/sign-analysis/A.java | 17 + .../sign-analysis/SignAnalysis.expected | 5 + .../dataflow/sign-analysis/SignAnalysis.ql | 22 + .../dataflow/taint-format/A.java | 47 + .../dataflow/taint-format/options | 1 + .../dataflow/taint-format/test.expected | 36 + .../dataflow/taint-format/test.ql | 16 + .../test/library-tests/dataflow/taint/B.java | 9 + .../dataflow/taint/test.expected | 3 + .../taintsources/SpringMultiPart.java | 10 + .../dataflow/taintsources/remote.expected | 18 +- .../dependency-counts/PrintAst.expected | 16 + .../dependency-counts/PrintAst.qlref | 1 + .../dependency/PrintAst.expected | 51 + .../library-tests/dependency/PrintAst.qlref | 1 + .../library-tests/fields/PrintAst.expected | 14 + .../test/library-tests/fields/PrintAst.qlref | 1 + .../android/taint-database/FlowSteps.java | 181 + .../android/taint-database/Sinks.java | 359 + .../android/taint-database/flowSteps.expected | 56 + .../android/taint-database/flowSteps.ql | 22 + .../frameworks/android/taint-database/options | 1 + .../android/taint-database/sinks.expected | 88 + .../android/taint-database/sinks.ql | 5 + .../library-tests/generics/PrintAst.expected | 48 + .../library-tests/generics/PrintAst.qlref | 1 + .../library-tests/guards12/PrintAst.expected | 23 + .../library-tests/guards12/PrintAst.qlref | 1 + .../java7/Diamond/PrintAst.expected | 41 + .../java7/Diamond/PrintAst.qlref | 1 + .../java7/MultiCatch/PrintAst.expected | 77 + .../java7/MultiCatch/PrintAst.qlref | 1 + .../library-tests/javadoc/PrintAst.expected | 29 + .../test/library-tests/javadoc/PrintAst.qlref | 1 + .../library-tests/modifiers/PrintAst.expected | 37 + .../library-tests/modifiers/PrintAst.qlref | 1 + .../pathcreation/PathCreation.expected | 25 + .../pathcreation/PathCreation.java | 71 + .../pathcreation/PathCreation.ql | 5 + java/ql/test/library-tests/printAst/A.java | 59 + .../library-tests/printAst/PrintAst.expected | 127 + .../library-tests/printAst/PrintAst.qlref | 1 + java/ql/test/library-tests/printAst/options | 1 + .../reflection/PrintAst.expected | 49 + .../library-tests/reflection/PrintAst.qlref | 1 + .../typeaccesses/PrintAst.expected | 104 + .../library-tests/typeaccesses/PrintAst.qlref | 1 + .../library-tests/varargs/PrintAst.expected | 56 + .../test/library-tests/varargs/PrintAst.qlref | 1 + java/ql/test/query-tests/StringFormat/A.java | 5 + .../StringFormat/MissingFormatArg.expected | 1 + .../StringFormat/UnusedFormatArg.expected | 1 + java/ql/test/query-tests/StringFormat/options | 1 + .../query-tests/maven-dependencies/.gitignore | 6 + .../security/CWE-078/ExecRelative.expected | 1 + .../security/CWE-078/ExecRelative.qlref | 1 + .../CWE-078/ExecTaintedLocal.expected | 27 + .../security/CWE-078/ExecTaintedLocal.qlref | 1 + .../security/CWE-078/ExecUnescaped.expected | 2 + .../security/CWE-078/ExecUnescaped.qlref | 1 + .../query-tests/security/CWE-078/Test.java | 64 + .../CWE-079/semmle/tests/WebsocketXss.java | 27 + .../CWE-089/semmle/examples/Mongo.java | 25 + .../semmle/examples/SqlTaintedLocal.expected | 7 + .../semmle/examples/controlledString.ql | 3 +- .../CWE-089/semmle/examples/endsInQuote.ql | 5 +- .../security/CWE-089/semmle/examples/options | 1 + .../semmle/examples/taintedString.expected | 3 + .../CWE-089/semmle/examples/taintedString.ql | 5 +- .../security/CWE-090/LdapInjection.expected | 454 +- .../security/CWE-090/LdapInjection.java | 59 +- .../semmle/tests/HardcodedAWSCredentials.java | 10 + .../HardcodedCredentialsApiCall.expected | 4 + .../security/CWE-798/semmle/tests/options | 1 + .../stubs/amazon-aws-sdk-1.11.700/LICENSE.txt | 53 + .../com/amazonaws/auth/AWSCredentials.java | 46 + .../amazonaws/auth/BasicAWSCredentials.java | 49 + .../android/content/ContentProvider.java | 17 + .../android/content/ContentResolver.java | 17 + .../android/content/ContentValues.java | 5 + .../android/android/content/Context.java | 5 + .../android/android/database/Cursor.java | 5 + .../android/database/DatabaseUtils.java | 46 + .../database/sqlite/SQLiteDatabase.java | 56 + .../database/sqlite/SQLiteQueryBuilder.java | 57 + .../test/stubs/android/android/net/Uri.java | 5 + .../android/os/CancellationSignal.java | 5 + .../android/os/ParcelFileDescriptor.java | 5 + .../apache-commons-email-1.6.0/LICENSE.txt | 202 + .../commons/mail/DefaultAuthenticator.java | 58 + .../org/apache/commons/mail/Email.java | 805 + .../apache/commons/mail/EmailException.java | 101 + .../org/apache/commons/mail/SimpleEmail.java | 41 + .../org/apache/http/Header.java | 70 + .../org/apache/http/HeaderElement.java | 65 + .../apache/http/HeaderElementIterator.java | 66 + .../org/apache/http/HeaderIterator.java | 64 + .../org/apache/http/HttpEntity.java | 186 + .../http/HttpEntityEnclosingRequest.java | 70 + .../org/apache/http/HttpMessage.java | 196 + .../org/apache/http/HttpRequest.java | 58 + .../org/apache/http/NameValuePair.java | 124 + .../org/apache/http/ParseException.java | 64 + .../org/apache/http/ProtocolVersion.java | 211 + .../org/apache/http/RequestLine.java | 58 + .../HttpEntityEnclosingRequestBase.java | 67 + .../apache/http/client/methods/HttpGet.java | 81 + .../apache/http/client/methods/HttpPost.java | 85 + .../apache/http/client/methods/HttpPut.java | 76 + .../http/client/methods/HttpRequestBase.java | 90 + .../http/message/AbstractHttpMessage.java | 128 + .../BasicHttpEntityEnclosingRequest.java | 79 + .../apache/http/message/BasicHttpRequest.java | 78 + .../apache/http/message/BasicRequestLine.java | 72 + .../org/apache/http/params/HttpParams.java | 176 + .../test/stubs/javamail-api-1.6.2/LICENSE.txt | 759 + .../javax/mail/Authenticator.java | 150 + .../javax/mail/PasswordAuthentication.java | 77 + .../javax/mail/Session.java | 325 + .../com/mongodb/BasicDBObject.java | 7 + .../stubs/mongodbClient/com/mongodb/DB.java | 8 + .../com/mongodb/DBCollection.java | 7 + .../mongodbClient/com/mongodb/DBCursor.java | 4 + .../mongodbClient/com/mongodb/DBObject.java | 4 + .../mongodbClient/com/mongodb/Mongo.java | 10 + .../com/mongodb/MongoClient.java | 6 + .../com/mongodb/ServerAddress.java | 64 + .../mongodbClient/com/mongodb/util/JSON.java | 8 + .../mongodbClient/org/bson/BSONObject.java | 22 + .../ldap/core/AttributesMapper.java | 0 .../ldap/core/DirContextProcessor.java | 0 .../ldap/core/LdapOperations.java | 0 .../ldap/core/LdapTemplate.java | 50 +- .../beans/factory/BeanFactory.java | 0 .../factory/HierarchicalBeanFactory.java | 0 .../beans/factory/InitializingBean.java | 0 .../beans/factory/ListableBeanFactory.java | 0 .../security/servlet/EndpointRequest.java | 0 .../ApplicationContextRequestMatcher.java | 0 .../context/ApplicationContext.java | 0 .../context/ApplicationEventPublisher.java | 0 .../context/MessageSource.java | 0 .../core/env/EnvironmentCapable.java | 0 .../core/io/ResourceLoader.java | 0 .../io/support/ResourcePatternResolver.java | 0 .../springframework/jndi/JndiTemplate.java | 0 .../security/config/Customizer.java | 0 .../AbstractConfiguredSecurityBuilder.java | 0 .../annotation/AbstractSecurityBuilder.java | 0 .../config/annotation/SecurityBuilder.java | 0 .../config/annotation/SecurityConfigurer.java | 0 .../annotation/SecurityConfigurerAdapter.java | 0 .../web/AbstractRequestMatcherRegistry.java | 0 .../annotation/web/HttpSecurityBuilder.java | 0 .../annotation/web/builders/HttpSecurity.java | 0 ...ConfigAttributeRequestMatcherRegistry.java | 0 .../configurers/AbstractHttpConfigurer.java | 0 .../AbstractInterceptUrlConfigurer.java | 0 .../ExpressionUrlAuthorizationConfigurer.java | 0 .../web/DefaultSecurityFilterChain.java | 0 .../security/web/SecurityFilterChain.java | 0 .../web/util/matcher/RequestMatcher.java | 0 .../springframework/stereotype/Component.java | 9 + .../stereotype/Controller.java | 9 + .../springframework/stereotype/Indexed.java | 8 + .../web/bind/annotation/RequestMapping.java} | 4 +- .../web/context/WebApplicationContext.java | 0 .../config/suites/javascript/correctness-core | 1 - .../config/suites/javascript/frameworks-more | 1 - javascript/config/suites/javascript/security | 17 +- .../extractor/lib/typescript/package.json | 5 +- .../extractor/lib/typescript/src/common.ts | 21 +- .../extractor/lib/typescript/src/main.ts | 211 +- .../lib/typescript/src/type_table.ts | 41 +- .../lib/typescript/src/virtual_source_root.ts | 42 +- javascript/extractor/lib/typescript/yarn.lock | 229 +- .../src/com/semmle/jcorn/CustomParser.java | 3 +- .../src/com/semmle/jcorn/Parser.java | 20 +- .../src/com/semmle/jcorn/jsx/JSXParser.java | 17 +- .../src/com/semmle/js/ast/AST2JSON.java | 6 + .../com/semmle/js/ast/DeclarationFlags.java | 20 +- .../src/com/semmle/js/ast/DefaultVisitor.java | 6 + .../src/com/semmle/js/ast/NodeCopier.java | 8 +- .../src/com/semmle/js/ast/Visitor.java | 3 + .../com/semmle/js/ast/jsx/JSXThisExpr.java | 21 + .../semmle/js/dependencies/AsyncFetcher.java | 122 + .../js/dependencies/DependencyResolver.java | 236 + .../com/semmle/js/dependencies/Fetcher.java | 149 + .../com/semmle/js/dependencies/SemVer.java | 106 + .../dependencies/packument/PackageJson.java | 95 + .../js/dependencies/packument/Packument.java | 30 + .../com/semmle/js/extractor/ASTExtractor.java | 83 +- .../com/semmle/js/extractor/AutoBuild.java | 419 +- .../com/semmle/js/extractor/CFGExtractor.java | 23 +- .../DependencyInstallationResult.java | 14 +- .../js/extractor/EnvironmentVariables.java | 14 + .../com/semmle/js/extractor/ExprKinds.java | 16 +- .../semmle/js/extractor/ExtractorConfig.java | 23 +- .../semmle/js/extractor/ExtractorState.java | 32 +- .../semmle/js/extractor/FileExtractor.java | 222 +- .../com/semmle/js/extractor/FileSnippet.java | 44 + .../semmle/js/extractor/HTMLExtractor.java | 80 +- .../com/semmle/js/extractor/JSExtractor.java | 6 +- .../src/com/semmle/js/extractor/Main.java | 69 +- .../semmle/js/extractor/RegExpExtractor.java | 26 +- .../com/semmle/js/extractor/ScopeManager.java | 4 +- .../semmle/js/extractor/ScriptExtractor.java | 82 +- .../semmle/js/extractor/TextualExtractor.java | 29 +- .../js/extractor/TypeScriptExtractor.java | 21 +- .../js/extractor/VirtualSourceRoot.java | 80 + .../js/extractor/test/AutoBuildTests.java | 22 +- .../com/semmle/js/parser/ParsedProject.java | 17 +- .../src/com/semmle/ts/ast/TupleTypeExpr.java | 9 +- .../extractor}/TypeScriptASTConverter.java | 42 +- .../extractor}/TypeScriptParser.java | 67 +- .../extractor}/TypeScriptParserMetadata.java | 2 +- .../tests/cfg/output/trap/classexpr1.js.trap | 24 +- .../tests/cfg/output/trap/classexpr2.js.trap | 28 +- .../tests/cfg/output/trap/classexpr3.js.trap | 50 +- .../tests/cfg/output/trap/classexpr4.js.trap | 54 +- .../tests/cfg/output/trap/fields.js.trap | 112 +- .../tests/cfg/output/trap/seq.js.trap | 36 +- .../cfg/output/trap/short-circuit.js.trap | 44 +- .../tests/cfg/output/trap/ternary.js.trap | 38 +- .../tests/cfg/output/trap/tst.js.trap | 234 +- .../trap/googDotDeclareModuleId.js.trap | 44 +- .../closure/output/trap/googDotModule.js.trap | 64 +- .../output/trap/googDotProvide.js.trap | 48 +- .../output/trap/latin1.js.trap | 12 +- .../tests/e4x/output/trap/regress.js.trap | 20 +- .../tests/e4x/output/trap/tst.js.trap | 236 +- .../encoding/output/trap/surrogates.js.trap | 88 +- .../encoding/output/trap/unicode.js.trap | 8 +- .../tests/encoding/output/trap/zwsp.js.trap | 2 +- .../tests/errors/output/trap/errors.js.trap | 2 +- .../errors/output/trap/incomplete.js.trap | 2 +- .../trap/invalid-assignment-pattern.js.trap | 20 +- .../tests/errors/output/trap/kwident.js.trap | 16 +- .../errors/output/trap/weirdassign.js.trap | 2 +- .../trap/array_pattern_with_default.js.trap | 26 +- .../trap/array_pattern_with_rest.js.trap | 36 +- .../tests/es2015/output/trap/arrowfn.js.trap | 108 +- .../output/trap/class_accessors.js.trap | 90 +- .../es2015/output/trap/class_ctor.js.trap | 44 +- .../es2015/output/trap/class_extends.js.trap | 46 +- .../es2015/output/trap/class_extends2.js.trap | 74 +- .../es2015/output/trap/class_method.js.trap | 48 +- .../es2015/output/trap/class_static.js.trap | 44 +- .../es2015/output/trap/classdecl.js.trap | 20 +- .../es2015/output/trap/classexpr.js.trap | 28 +- .../es2015/output/trap/classexpr2.js.trap | 24 +- .../output/trap/complex_array_pattern.js.trap | 34 +- .../trap/complex_object_pattern.js.trap | 34 +- .../tests/es2015/output/trap/const.js.trap | 14 +- .../es2015/output/trap/defaultargs.js.trap | 18 +- .../output/trap/delegating_yield.js.trap | 26 +- .../es2015/output/trap/destructuring.js.trap | 144 +- .../tests/es2015/output/trap/export1.js.trap | 20 +- .../tests/es2015/output/trap/export10.js.trap | 22 +- .../tests/es2015/output/trap/export11.js.trap | 24 +- .../tests/es2015/output/trap/export2.js.trap | 16 +- .../tests/es2015/output/trap/export3.js.trap | 16 +- .../tests/es2015/output/trap/export4.js.trap | 16 +- .../tests/es2015/output/trap/export5.js.trap | 56 +- .../tests/es2015/output/trap/export6.js.trap | 12 +- .../tests/es2015/output/trap/export7.js.trap | 36 +- .../tests/es2015/output/trap/export8.js.trap | 24 +- .../tests/es2015/output/trap/export9.js.trap | 34 +- .../tests/es2015/output/trap/forof.js.trap | 82 +- .../tests/es2015/output/trap/import1.js.trap | 20 +- .../tests/es2015/output/trap/import2.js.trap | 24 +- .../tests/es2015/output/trap/import3.js.trap | 24 +- .../tests/es2015/output/trap/import4.js.trap | 32 +- .../tests/es2015/output/trap/import5.js.trap | 20 +- .../tests/es2015/output/trap/import6.js.trap | 12 +- .../tests/es2015/output/trap/import7.js.trap | 48 +- .../tests/es2015/output/trap/let.js.trap | 136 +- .../tests/es2015/output/trap/let2.js.trap | 14 +- .../es2015/output/trap/nested_import.js.trap | 70 +- .../es2015/output/trap/new_target.js.trap | 22 +- .../output/trap/no-substitution.js.trap | 6 +- .../es2015/output/trap/nullMethodName.js.trap | 38 +- .../es2015/output/trap/odasa-2593.js.trap | 28 +- .../es2015/output/trap/properties.js.trap | 86 +- .../property_pattern_with_default.js.trap | 16 +- .../es2015/output/trap/restparms.js.trap | 14 +- .../es2015/output/trap/restparms2.js.trap | 2 +- .../es2015/output/trap/spreadelement.js.trap | 38 +- .../es2015/output/trap/super_call.js.trap | 86 +- .../es2015/output/trap/super_ctor.js.trap | 38 +- .../es2015/output/trap/templates.js.trap | 152 +- .../output/trap/unknown_meta_property.js.trap | 16 +- .../tests/es2015/output/trap/yield.js.trap | 52 +- .../tests/es2015/output/trap/yield2.js.trap | 16 +- .../tests/es2016/output/trap/exp.js.trap | 28 +- .../es2016/output/trap/usestrict.js.trap | 22 +- .../es2017/output/trap/async-await.js.trap | 48 +- .../es2017/output/trap/export-async-1.js.trap | 18 +- .../es2017/output/trap/export-async-2.js.trap | 18 +- .../output/trap/invalid-async-fn.js.trap | 20 +- .../output/trap/shorthand-prop-async.js.trap | 18 +- .../es2018/output/trap/asyncIter.js.trap | 138 +- .../es2018/output/trap/templates.js.trap | 220 +- .../es2019/output/trap/json-superset.js.trap | 32 +- .../extractor/tests/es2021/input/assign.js | 9 + .../extractor/tests/es2021/input/numeric.js | 8 + .../extractor/tests/es2021/options.json | 3 + .../tests/es2021/output/trap/assign.js.trap | 633 + .../tests/es2021/output/trap/numeric.js.trap | 435 + .../output/trap/async-generators.js.trap | 46 +- .../trap/catchGuardAndNoBinding.js.trap | 98 +- .../esnext/output/trap/catchNoBinding.js.trap | 26 +- .../esnext/output/trap/dynamic-import.js.trap | 72 +- .../tests/esnext/output/trap/fields.js.trap | 100 +- .../output/trap/nullish-coalescing.js.trap | 102 +- .../output/trap/optional-chaining.js.trap | 138 +- .../trap/optional-chaining_bad1.js.trap | 2 +- .../trap/optional-chaining_bad2.js.trap | 2 +- .../trap/optional-chaining_bad3.js.trap | 2 +- .../trap/optional-chaining_bad4.js.trap | 2 +- .../trap/optional-chaining_bad5.js.trap | 2 +- .../trap/optional-chaining_bad6.js.trap | 2 +- ...optional-chaining_short-circuiting.js.trap | 366 +- .../output/trap/top-level-await.js.trap | 54 +- .../esnext/output/trap/yield-import.js.trap | 26 +- .../tests/excludes/output/trap/a.js.trap | 6 +- .../exprs/output/trap/assignment.js.trap | 168 +- .../tests/exprs/output/trap/binary.js.trap | 214 +- .../exprs/output/trap/comparison.js.trap | 112 +- .../tests/exprs/output/trap/fnnesting.js.trap | 22 +- .../tests/exprs/output/trap/others.js.trap | 50 +- .../tests/exprs/output/trap/parens.js.trap | 14 +- .../tests/exprs/output/trap/primaries.js.trap | 350 +- .../tests/exprs/output/trap/regexp.js.trap | 496 +- .../tests/exprs/output/trap/unary.js.trap | 82 +- .../tests/exprs/output/trap/update.js.trap | 40 +- .../extractor/tests/extensions/input/tst4.cjs | 1 + .../tests/extensions/output/trap/tst.es6.trap | 28 +- .../tests/extensions/output/trap/tst2.es.trap | 28 +- .../extensions/output/trap/tst4.cjs.trap | 148 + .../tests/externs/output/trap/Point.js.trap | 196 +- .../trap/anonFunctionOptionalParm.js.trap | 18 +- .../trap/anonFunctionReturnType.js.trap | 18 +- .../trap/anonFunctionWithoutParens.js.trap | 4 +- .../flow/output/trap/anonIndexer.js.trap | 4 +- .../flow/output/trap/array-types.js.trap | 40 +- .../tests/flow/output/trap/async.js.trap | 22 +- .../trap/boundExplicitTypeParameters.js.trap | 2 +- .../trap/declared-module-imports.js.trap | 4 +- .../trap/explicitTypeParameters.js.trap | 94 +- ...tersForArgumentlessConstructorCall.js.trap | 10 +- .../tests/flow/output/trap/export.js.trap | 32 +- .../flow/output/trap/exportOpaqueType.js.trap | 4 +- .../flow/output/trap/get-set-methods.js.trap | 52 +- .../importNonTypeInDeclaredModule.js.trap | 2 +- .../tests/flow/output/trap/importType.js.trap | 24 +- .../trap/importTypeInDeclaredModule.js.trap | 4 +- .../flow/output/trap/methodTypeParams.js.trap | 36 +- .../trap/notExplicitTypeParameters1.js.trap | 26 +- .../trap/notExplicitTypeParameters2.js.trap | 34 +- .../trap/notExplicitTypeParameters3.js.trap | 28 +- .../tests/flow/output/trap/optParms.js.trap | 38 +- .../output/trap/parmAnonFunctionType.js.trap | 24 +- ...llyAmbigiousExplicitTypeParameters.js.trap | 322 +- .../predicate-function-annotation.js.trap | 52 +- .../tests/flow/output/trap/tst.js.trap | 60 +- .../tests/flow/output/trap/variance.js.trap | 26 +- .../functionbind/output/trap/tst.js.trap | 118 +- .../helloworld/output/trap/hello.js.trap | 16 +- .../tests/html/output/trap/entities.html.trap | 24 +- .../tests/html/output/trap/module.html.trap | 38 +- .../tests/html/output/trap/tst.html.trap | 64 +- .../tests/html/output/trap/tst.xhtml.trap | 6 +- .../tests/html/output/trap/tst2.html.trap | 54 +- .../tests/jscript/output/trap/tst.js.trap | 32 +- .../tests/jsx/output/trap/err1.jsx.trap | 2 +- .../tests/jsx/output/trap/err2.jsx.trap | 2 +- .../tests/jsx/output/trap/err3.jsx.trap | 2 +- .../tests/jsx/output/trap/err4.jsx.trap | 2 +- .../tests/jsx/output/trap/tst.js.trap | 156 +- .../tests/jsx/output/trap/tst2.js.trap | 14 +- .../tests/keywords/output/trap/tst.js.trap | 54 +- .../tests/moduleTypes1/input/package.json | 3 + .../extractor/tests/moduleTypes1/input/tst.js | 0 .../output/trap/package.json.trap | 15 + .../moduleTypes1/output/trap/tst.js.trap | 28 + .../tests/moduleTypes2/input/package.json | 3 + .../tests/moduleTypes2/input/tst2.js | 0 .../output/trap/package.json.trap | 22 + .../moduleTypes2/output/trap/tst2.js.trap | 28 + .../tests/moduleTypes3/input/package.json | 0 .../extractor/tests/moduleTypes3/input/tst.js | 0 .../output/trap/package.json.trap | 15 + .../moduleTypes3/output/trap/tst.js.trap | 28 + .../output/trap/array_comprehensions.js.trap | 158 +- .../tests/mozilla/output/trap/exprfns.js.trap | 50 +- .../tests/mozilla/output/trap/foreach.js.trap | 106 +- .../output/trap/generator_expressions.js.trap | 196 +- .../mozilla/output/trap/guardedCatch.js.trap | 100 +- .../tests/mozilla/output/trap/letExpr.js.trap | 180 +- .../tests/mozilla/output/trap/letStmt.js.trap | 114 +- .../mozilla/output/trap/letStmt2.js.trap | 20 +- .../output/trap/new-with-trailing-arg.js.trap | 36 +- .../mozilla/output/trap/odasa-2593.js.trap | 26 +- .../tests/node/output/trap/constlet.js.trap | 32 +- .../tests/node/output/trap/hello.trap | 28 +- .../tests/node/output/trap/tst.html.trap | 14 +- .../tests/node/output/trap/tst.js.trap | 78 +- .../tests/node/output/trap/tst.mjs.trap | 14 +- .../tests/regexp/output/trap/es2018.js.trap | 62 +- .../regexp/output/trap/nonstandard.js.trap | 8 +- .../regexp/output/trap/odasa-1934.js.trap | 90 +- .../tests/regexp/output/trap/tst.js.trap | Bin 3092 -> 3106 bytes .../tests/restprops/output/trap/tst.js.trap | 20 +- .../tests/shebang/output/trap/tst.html.trap | 2 +- .../tests/shebang/output/trap/tst.js.trap | 20 +- .../trap/typescript-with-shebang.ts.trap | 16 +- .../shebang/output/trap/typescript.ts.trap | 16 +- .../stmts/output/trap/conditionals.js.trap | 42 +- .../stmts/output/trap/forvardefault.js.trap | 48 +- .../tests/stmts/output/trap/functions.js.trap | 86 +- .../tests/stmts/output/trap/loops.js.trap | 174 +- .../tests/stmts/output/trap/others.js.trap | 32 +- .../tests/stmts/output/trap/switch.js.trap | 78 +- .../tests/stmts/output/trap/switch2.js.trap | 40 +- .../stmts/output/trap/trivial-switch.js.trap | 6 +- .../tests/stmts/output/trap/try.js.trap | 44 +- .../strictmode/output/trap/assignargs.js.trap | 32 +- .../tests/strictmode/output/trap/tst.js.trap | 10 +- .../tests/ts/input/importNonStrings.ts | 3 + .../output/trap/arrayBindingPattern.ts.trap | 34 +- .../tests/ts/output/trap/badimport.ts.trap | 2 +- .../ts/output/trap/bindingpattern.ts.trap | 18 +- .../tests/ts/output/trap/bom.ts.trap | 6 +- .../tests/ts/output/trap/classes.ts.trap | 60 +- .../tests/ts/output/trap/comments.ts.trap | 14 +- .../ts/output/trap/conditionalTypes.ts.trap | 2196 +-- .../tests/ts/output/trap/ctordecl.ts.trap | 44 +- .../tests/ts/output/trap/declareClass.ts.trap | 22 +- .../tests/ts/output/trap/decorators.ts.trap | 134 +- .../tests/ts/output/trap/emptydecls.ts.trap | 2 +- .../tests/ts/output/trap/enum.ts.trap | 178 +- .../tests/ts/output/trap/export.ts.trap | 72 +- .../tests/ts/output/trap/export2.ts.trap | 10 +- .../output/trap/exportasnamespace.d.ts.trap | 20 +- .../tests/ts/output/trap/exportassign.ts.trap | 10 +- .../tests/ts/output/trap/exportclass.ts.trap | 22 +- .../tests/ts/output/trap/exprs.ts.trap | 66 +- .../ts/output/trap/externalmodule.ts.trap | 56 +- .../ts/output/trap/functiondecorators.ts.trap | 248 +- .../tests/ts/output/trap/hello.ts.trap | 62 +- .../tests/ts/output/trap/importExport.ts.trap | 40 +- .../ts/output/trap/importNonStrings.ts.trap | 252 + .../tests/ts/output/trap/importassign.ts.trap | 20 +- .../tests/ts/output/trap/interfaces.ts.trap | 78 +- .../trap/invalidModuleSpecifier.ts.trap | 2 +- .../tests/ts/output/trap/let.ts.trap | 42 +- .../tests/ts/output/trap/logicalOr.ts.trap | 44 +- .../output/trap/mappedTypeModifiers.ts.trap | 230 +- .../tests/ts/output/trap/namespaces.ts.trap | 60 +- .../ts/output/trap/nestedNamespace.ts.trap | 72 +- .../tests/ts/output/trap/nobody.ts.trap | 206 +- .../output/trap/objectLiteralAccessor.ts.trap | 50 +- .../tests/ts/output/trap/omitted.ts.trap | 12 +- .../ts/output/trap/optionalChaining.ts.trap | 66 +- .../tests/ts/output/trap/privateField.ts.trap | 44 +- .../tests/ts/output/trap/regexp.ts.trap | 8 +- .../trap/restPatternWithDefault.ts.trap | 2 +- .../tests/ts/output/trap/templates.ts.trap | 34 +- .../ts/output/trap/thisparameter.ts.trap | 110 +- .../tests/ts/output/trap/tryfinally.ts.trap | 34 +- .../tests/ts/output/trap/tsx.tsx.trap | 198 +- .../ts/output/trap/typeannotations.ts.trap | 1080 +- .../tests/ts/output/trap/unicodeId.ts.trap | 14 +- .../trap/uninstantiatedNamespace.ts.trap | 148 +- .../tests/v8/output/trap/tst.js.trap | 150 +- .../tests/variables/output/trap/const.js.trap | 14 +- .../variables/output/trap/finally.js.trap | 34 +- .../variables/output/trap/switch.js.trap | 26 +- .../tests/variables/output/trap/try.js.trap | 24 +- .../variables/output/trap/variables.js.trap | 122 +- javascript/ql/examples/qlpack.yml | 3 + ...rackedNode.ql => StoredXssTypeTracking.ql} | 22 +- .../CommentedOutCodeMetricOverview.qhelp | 12 + .../src/Comments/CommentedOutCodeQuery.qhelp | 25 + .../Comments/CommentedOutCodeReferences.qhelp | 12 + javascript/ql/src/DOM/AmbiguousIdAttribute.ql | 2 +- javascript/ql/src/DOM/TargetBlank.ql | 6 +- .../src/Declarations/ConflictingFunctions.ql | 5 +- .../ql/src/Declarations/DeadStoreOfLocal.ql | 4 +- .../src/Declarations/DeadStoreOfProperty.ql | 258 +- .../ql/src/Declarations/RedeclaredVariable.ql | 4 +- .../ql/src/Declarations/UnusedVariable.ql | 14 +- .../src/Expressions/StringInsteadOfRegex.ql | 2 +- .../src/Expressions/SuspiciousPropAccess.ql | 2 +- .../UnneededDefensiveProgramming.ql | 28 +- .../LanguageFeatures/NonLinearPattern.qhelp | 20 + .../src/LanguageFeatures/NonLinearPattern.ql | 52 +- .../LanguageFeatures/YieldInNonGenerator.ql | 2 +- .../examples/NonLinearPatternTS.ts | 3 + .../examples/NonLinearPatternTSGood.ts | 3 + .../Dependencies/ExternalDependencies.ql | 1 + .../ExternalDependenciesSourceLinks.ql | 1 + .../ql/src/Metrics/DuplicationProblems.qhelp | 16 + .../ql/src/Metrics/FCommentRatioCommon.qhelp | 38 + .../ql/src/Metrics/FLinesOfCodeOverview.qhelp | 32 + .../src/Metrics/FLinesOfCodeReferences.qhelp | 10 + .../ql/src/Metrics/FLinesOfDuplicatedCode.ql | 1 + .../FLinesOfDuplicatedCodeCommon.qhelp | 35 + .../ql/src/Metrics/FLinesOfSimilarCode.ql | 1 + .../Metrics/FLinesOfSimilarCodeCommon.qhelp | 36 + javascript/ql/src/NodeJS/MissingExports.ql | 4 +- javascript/ql/src/NodeJS/UnusedDependency.ql | 2 +- .../ql/src/RegExp/IdentityReplacement.ql | 2 +- .../CWE-020/IncompleteHostnameRegExp.ql | 2 +- .../CWE-020/IncompleteUrlSchemeCheck.ql | 2 +- .../IncompleteUrlSubstringSanitization.ql | 6 +- .../Security/CWE-020/MissingRegExpAnchor.ql | 2 +- .../CWE-020/UselessRegExpCharacterEscape.ql | 2 +- .../ql/src/Security/CWE-022/TaintedPath.qhelp | 2 +- .../ql/src/Security/CWE-022/ZipSlip.qhelp | 2 +- .../CWE-078/UnsafeShellCommandConstruction.ql | 2 +- .../ql/src/Security/CWE-079/ExceptionXss.ql | 14 +- .../Security/CWE-079/UnsafeJQueryPlugin.ql | 3 +- .../ql/src/Security/CWE-079/XssThroughDom.ql | 14 +- .../CWE-094/ImproperCodeSanitization.qhelp | 38 + .../CWE-094/ImproperCodeSanitization.ql | 71 + .../examples/ImproperCodeSanitization.js | 4 + .../examples/ImproperCodeSanitizationFixed.js | 23 + .../ql/src/Security/CWE-116/DoubleEscaping.ql | 2 +- .../IncompleteHtmlAttributeSanitization.qhelp | 10 +- .../IncompleteHtmlAttributeSanitization.ql | 2 +- ...IncompleteMultiCharacterSanitization.qhelp | 8 + .../IncompleteMultiCharacterSanitization.ql | 81 + .../CWE-116/IncompleteSanitization.qhelp | 10 +- .../CWE-116/IncompleteSanitization.ql | 5 +- .../CWE-116/UnsafeHtmlExpansion.qhelp | 13 +- .../UnsafeHtmlExpansion-transformed.html | 2 +- .../CWE-200/PrivateFileExposure.qhelp | 40 + .../Security/CWE-200/PrivateFileExposure.ql | 129 + .../CWE-200/examples/PrivateFileExposure.js | 6 + .../examples/PrivateFileExposureFixed.js | 7 + .../Security/CWE-209/StackTraceExposure.qhelp | 2 +- .../DisablingCertificateValidation.qhelp | 71 + .../CWE-295/DisablingCertificateValidation.ql | 44 + .../DisablingCertificateValidation.js | 14 + .../Security/CWE-312/BuildArtifactLeak.qhelp | 36 + .../src/Security/CWE-312/BuildArtifactLeak.ql | 23 + .../CWE-312/examples/build-leak-fixed.js | 9 + .../Security/CWE-312/examples/build-leak.js | 9 + .../src/Security/CWE-327/BadRandomness.qhelp | 65 + .../ql/src/Security/CWE-327/BadRandomness.ql | 184 + .../CWE-327/examples/bad-random-fixed.js | 3 + .../CWE-327/examples/bad-random-fixed2.js | 10 + .../Security/CWE-327/examples/bad-random.js | 6 + .../Security/CWE-352/MissingCsrfMiddleware.ql | 11 +- .../src/Security/CWE-643/XpathInjection.qhelp | 2 +- .../Security/CWE-829/InsecureDownload.qhelp | 38 + .../src/Security/CWE-829/InsecureDownload.ql | 20 + .../CWE-829/examples/insecure-download.js | 6 + .../CWE-829/examples/secure-download.js | 6 + ...peConfusionThroughParameterTampering.qhelp | 11 +- .../SuspiciousUnusedLoopIterationVariable.ql | 17 + .../codeql-suites/javascript-lgtm-full.qls | 4 + .../javascript-security-and-quality.qls | 4 + .../javascript-security-extended.qls | 4 + .../CWE-020/PostMessageNoOriginCheck.qhelp | 40 + .../CWE-020/PostMessageNoOriginCheck.ql | 64 + .../examples/postMessageInsufficientCheck.js | 14 + .../examples/postMessageNoOriginCheck.js | 9 + .../examples/postMessageWithOriginCheck.js | 9 + .../Security/CWE-090/LdapInjection.qhelp | 50 + .../Security/CWE-090/LdapInjection.ql | 20 + .../Security/CWE-090/LdapInjection.qll | 18 + .../CWE-090/LdapInjectionCustomizations.qll | 85 + .../experimental/Security/CWE-090/Ldapjs.qll | 92 + .../Security/CWE-090/examples/example_bad1.js | 21 + .../Security/CWE-090/examples/example_bad2.js | 16 + .../CWE-090/examples/example_good1.js | 31 + .../CWE-090/examples/example_good2.js | 29 + .../Security/CWE-117/LogInjection.help | 47 + .../Security/CWE-117/LogInjection.ql | 20 + .../Security/CWE-117/LogInjection.qll | 99 + .../CWE-117/examples/logInjectionBad.js | 68 + .../CWE-117/examples/logInjectionGood.js | 51 + ...TMissingSecretOrPublicKeyVerification.help | 30 + ...JWTMissingSecretOrPublicKeyVerification.ql | 21 + ...JWTMissingSecretOrPublicKeyVerification.js | 11 + .../Security/CWE-614/InsecureCookie.qhelp | 26 + .../Security/CWE-614/InsecureCookie.ql | 18 + .../Security/CWE-614/InsecureCookie.qll | 146 + .../ql/src/external/DuplicateFunction.ql | 1 + .../ql/src/external/DuplicateToplevel.ql | 1 + javascript/ql/src/external/SimilarFunction.ql | 1 + javascript/ql/src/external/SimilarToplevel.ql | 1 + javascript/ql/src/filters/ClassifyFiles.qll | 4 +- javascript/ql/src/javascript.qll | 4 + .../ql/src/meta/ApiGraphs/ApiGraphEdges.ql | 15 + .../ql/src/meta/ApiGraphs/ApiGraphNodes.ql | 14 + .../meta/ApiGraphs/ApiGraphPointsToEdges.ql | 14 + .../ql/src/meta/ApiGraphs/ApiGraphRhsNodes.ql | 15 + .../ql/src/meta/ApiGraphs/ApiGraphUseNodes.ql | 14 + javascript/ql/src/meta/MetaMetrics.qll | 32 + .../analysis-quality/CallGraphQuality.qll | 25 +- .../analysis-quality/ResolvableImports.ql | 17 + .../meta/analysis-quality/RouteHandlers.ql | 16 + .../SanitizersReachableFromSource.ql | 22 + .../SinksReachableFromSanitizer.ql | 22 + .../meta/analysis-quality/TaintMetrics.qll | 89 + .../src/meta/analysis-quality/TaintSinks.ql | 14 + .../src/meta/analysis-quality/TaintSources.ql | 14 + .../src/meta/analysis-quality/TaintSteps.ql | 24 + .../src/meta/analysis-quality/TaintedNodes.ql | 27 + javascript/ql/src/meta/types/TypedExprs.ql | 17 + .../src/meta/types/TypesWithQualifiedName.ql | 14 + javascript/ql/src/semmle/javascript/AMD.qll | 12 +- javascript/ql/src/semmle/javascript/AST.qll | 10 +- .../ql/src/semmle/javascript/Aliases.qll | 304 +- .../ql/src/semmle/javascript/ApiGraphs.qll | 880 + .../ql/src/semmle/javascript/Arrays.qll | 105 +- .../src/semmle/javascript/CanonicalNames.qll | 54 +- .../ql/src/semmle/javascript/Classes.qll | 40 +- .../ql/src/semmle/javascript/Closure.qll | 4 +- .../ql/src/semmle/javascript/Collections.qll | 2 +- .../ql/src/semmle/javascript/Comments.qll | 14 +- javascript/ql/src/semmle/javascript/DOM.qll | 35 +- .../ql/src/semmle/javascript/DefUse.qll | 10 +- .../javascript/DefensiveProgramming.qll | 13 +- .../src/semmle/javascript/ES2015Modules.qll | 49 +- .../ql/src/semmle/javascript/Errors.qll | 6 +- javascript/ql/src/semmle/javascript/Expr.qll | 288 +- .../ql/src/semmle/javascript/Extend.qll | 11 +- javascript/ql/src/semmle/javascript/Files.qll | 6 +- .../ql/src/semmle/javascript/Functions.qll | 32 +- .../src/semmle/javascript/GeneratedCode.qll | 5 +- .../ql/src/semmle/javascript/Generators.qll | 37 + .../semmle/javascript/GlobalAccessPaths.qll | 147 +- javascript/ql/src/semmle/javascript/JSX.qll | 10 +- .../semmle/javascript/JsonStringifiers.qll | 34 + .../ql/src/semmle/javascript/Locations.qll | 8 +- .../ql/src/semmle/javascript/Modules.qll | 104 +- .../ql/src/semmle/javascript/NodeJS.qll | 77 +- .../javascript/NodeModuleResolutionImpl.qll | 34 +- .../src/semmle/javascript/PackageExports.qll | 9 +- .../ql/src/semmle/javascript/Promises.qll | 388 +- .../ql/src/semmle/javascript/Regexp.qll | 30 +- javascript/ql/src/semmle/javascript/SSA.qll | 3 + .../src/semmle/javascript/StandardLibrary.qll | 11 +- javascript/ql/src/semmle/javascript/Stmt.qll | 77 +- .../ql/src/semmle/javascript/StringOps.qll | 27 +- .../ql/src/semmle/javascript/Templates.qll | 17 +- .../ql/src/semmle/javascript/TypeScript.qll | 343 +- .../ql/src/semmle/javascript/Variables.qll | 49 +- .../javascript/dataflow/Configuration.qll | 75 +- .../semmle/javascript/dataflow/DataFlow.qll | 54 +- .../src/semmle/javascript/dataflow/Nodes.qll | 42 + .../semmle/javascript/dataflow/Portals.qll | 4 +- .../semmle/javascript/dataflow/Sources.qll | 5 +- .../javascript/dataflow/TaintTracking.qll | 89 +- .../javascript/dataflow/TrackedNodes.qll | 92 +- .../javascript/dataflow/TypeTracking.qll | 19 +- .../internal/BasicExprTypeInference.qll | 2 +- .../dataflow/internal/CallGraphs.qll | 18 + .../dataflow/internal/DataFlowNode.qll | 1 + .../dataflow/internal/FlowSteps.qll | 51 +- .../internal/InterModuleTypeInference.qll | 4 +- .../dataflow/internal/PreCallGraphStep.qll | 134 + .../dataflow/internal/StepSummary.qll | 12 +- .../internal/VariableTypeInference.qll | 2 +- .../javascript/dependencies/Dependencies.qll | 2 +- .../frameworks/AngularJS/AngularJSCore.qll | 14 +- .../AngularJS/DependencyInjections.qll | 14 +- .../AngularJS/ServiceDefinitions.qll | 6 +- .../javascript/frameworks/ClientRequests.qll | 189 + .../semmle/javascript/frameworks/Connect.qll | 10 +- .../javascript/frameworks/CryptoLibraries.qll | 2 +- .../semmle/javascript/frameworks/Express.qll | 95 +- .../semmle/javascript/frameworks/Files.qll | 4 +- .../semmle/javascript/frameworks/Firebase.qll | 2 +- .../src/semmle/javascript/frameworks/HTTP.qll | 220 + .../src/semmle/javascript/frameworks/Hapi.qll | 2 +- .../javascript/frameworks/HttpFrameworks.qll | 1 + .../src/semmle/javascript/frameworks/Koa.qll | 2 +- .../frameworks/LodashUnderscore.qll | 46 + .../semmle/javascript/frameworks/Logging.qll | 48 +- .../semmle/javascript/frameworks/Micro.qll | 114 + .../semmle/javascript/frameworks/NoSQL.qll | 449 +- .../javascript/frameworks/NodeJSLib.qll | 77 +- .../semmle/javascript/frameworks/Restify.qll | 4 +- .../src/semmle/javascript/frameworks/SQL.qll | 276 +- .../javascript/frameworks/ServerLess.qll | 112 + .../frameworks/SystemCommandExecutors.qll | 128 +- .../javascript/frameworks/Templating.qll | 13 +- .../semmle/javascript/frameworks/Testing.qll | 12 +- .../src/semmle/javascript/frameworks/Vue.qll | 138 +- .../semmle/javascript/frameworks/jQuery.qll | 6 +- .../heuristics/AdditionalRouteHandlers.qll | 4 +- .../javascript/heuristics/AdditionalSinks.qll | 28 +- .../heuristics/AdditionalSources.qll | 4 +- .../heuristics/AdditionalTaintSteps.qll | 4 +- .../javascript/heuristics/HeuristicSinks.qll | 35 + .../javascript/internal/StmtContainers.qll | 12 +- .../security/dataflow/BuildArtifactLeak.qll | 45 + .../BuildArtifactLeakCustomizations.qll | 32 + .../security/dataflow/CleartextLogging.qll | 16 +- .../CleartextLoggingCustomizations.qll | 60 +- .../dataflow/ClientSideUrlRedirect.qll | 4 + .../ClientSideUrlRedirectCustomizations.qll | 26 +- .../dataflow/CodeInjectionCustomizations.qll | 3 + .../javascript/security/dataflow/DOM.qll | 19 +- .../security/dataflow/DomBasedXss.qll | 33 +- .../dataflow/ImproperCodeSanitization.qll | 30 + ...ImproperCodeSanitizationCustomizations.qll | 68 + .../dataflow/IndirectCommandArgument.qll | 32 +- ...IndirectCommandInjectionCustomizations.qll | 34 +- .../security/dataflow/InsecureDownload.qll | 31 + .../InsecureDownloadCustomizations.qll | 149 + .../security/dataflow/InsecureRandomness.qll | 11 +- .../InsecureRandomnessCustomizations.qll | 99 +- .../security/dataflow/MissingRateLimiting.qll | 25 +- .../security/dataflow/PostMessageStar.qll | 3 +- .../dataflow/ServerSideUrlRedirect.qll | 3 +- .../ServerSideUrlRedirectCustomizations.qll | 2 +- .../dataflow/TaintedPathCustomizations.qll | 44 +- .../security/dataflow/UnsafeJQueryPlugin.qll | 41 +- .../UnsafeJQueryPluginCustomizations.qll | 35 +- .../UnsafeShellCommandConstruction.qll | 10 + ...ShellCommandConstructionCustomizations.qll | 4 +- .../security/dataflow/UrlConcatenation.qll | 12 + .../javascript/security/dataflow/Xss.qll | 5 +- .../PolynomialReDoSCustomizations.qll | 1 + .../ql/src/semmlecode.javascript.dbscheme | 693 +- .../src/semmlecode.javascript.dbscheme.stats | 554 +- .../ql/test/ApiGraphs/VerifyAssertions.qll | 117 + .../argprops/VerifyAssertions.expected | 0 .../ApiGraphs/argprops/VerifyAssertions.ql | 1 + .../ql/test/ApiGraphs/argprops/index.js | 6 + .../ql/test/ApiGraphs/argprops/package.json | 3 + .../async-await/VerifyAssertions.expected | 0 .../ApiGraphs/async-await/VerifyAssertions.ql | 1 + .../ql/test/ApiGraphs/async-await/index.js | 5 + .../test/ApiGraphs/async-await/package.json | 6 + .../branching-flow/VerifyAssertions.expected | 0 .../branching-flow/VerifyAssertions.ql | 1 + .../ql/test/ApiGraphs/branching-flow/index.js | 7 + .../ApiGraphs/branching-flow/package.json | 3 + .../classes/VerifyAssertions.expected | 0 .../ApiGraphs/classes/VerifyAssertions.ql | 1 + .../ql/test/ApiGraphs/classes/classes.js | 27 + .../ql/test/ApiGraphs/classes/package.json | 4 + .../ctor-arg/VerifyAssertions.expected | 0 .../ApiGraphs/ctor-arg/VerifyAssertions.ql | 1 + .../ql/test/ApiGraphs/ctor-arg/index.js | 5 + .../ql/test/ApiGraphs/ctor-arg/package.json | 3 + .../VerifyAssertions.expected | 0 .../custom-entry-point/VerifyAssertions.ql | 9 + .../ApiGraphs/custom-entry-point/index.js | 1 + .../ApiGraphs/custom-entry-point/package.json | 3 + .../cyclic/VerifyAssertions.expected | 0 .../test/ApiGraphs/cyclic/VerifyAssertions.ql | 1 + javascript/ql/test/ApiGraphs/cyclic/index.js | 4 + .../ql/test/ApiGraphs/cyclic/package.json | 6 + .../VerifyAssertions.expected | 0 .../dynamic-prop-read/VerifyAssertions.ql | 1 + .../test/ApiGraphs/dynamic-prop-read/index.js | 5 + .../ApiGraphs/dynamic-prop-read/package.json | 6 + .../VerifyAssertions.expected | 0 .../imprecise-export/VerifyAssertions.ql | 1 + .../test/ApiGraphs/imprecise-export/index.js | 3 + .../ApiGraphs/imprecise-export/package.json | 3 + .../imprecision/VerifyAssertions.expected | 0 .../ApiGraphs/imprecision/VerifyAssertions.ql | 1 + .../ql/test/ApiGraphs/imprecision/index.js | 11 + .../test/ApiGraphs/imprecision/package.json | 3 + .../VerifyAssertions.expected | 0 .../namespaced-package/VerifyAssertions.ql | 1 + .../ApiGraphs/namespaced-package/index.js | 2 + .../ApiGraphs/namespaced-package/package.json | 6 + .../VerifyAssertions.expected | 0 .../VerifyAssertions.ql | 1 + .../ApiGraphs/nested-property-export/index.js | 7 + .../nested-property-export/package.json | 3 + .../nonlocal/VerifyAssertions.expected | 0 .../ApiGraphs/nonlocal/VerifyAssertions.ql | 1 + .../ql/test/ApiGraphs/nonlocal/index.js | 15 + .../ql/test/ApiGraphs/nonlocal/package.json | 6 + .../partial-invoke/VerifyAssertions.expected | 0 .../partial-invoke/VerifyAssertions.ql | 1 + .../ql/test/ApiGraphs/partial-invoke/index.js | 8 + .../ApiGraphs/partial-invoke/package.json | 3 + .../promises/VerifyAssertions.expected | 0 .../ApiGraphs/promises/VerifyAssertions.ql | 1 + .../ql/test/ApiGraphs/promises/index.js | 21 + .../ql/test/ApiGraphs/promises/package.json | 6 + .../VerifyAssertions.expected | 0 .../VerifyAssertions.ql | 1 + .../property-read-from-argument/index.js | 9 + .../property-read-from-argument/package.json | 3 + .../reexport/VerifyAssertions.expected | 0 .../ApiGraphs/reexport/VerifyAssertions.ql | 1 + .../ql/test/ApiGraphs/reexport/index.js | 8 + .../ql/test/ApiGraphs/reexport/lib/impl.js | 3 + .../ql/test/ApiGraphs/reexport/lib/stuff.js | 5 + .../ql/test/ApiGraphs/reexport/lib/utils.js | 3 + .../ql/test/ApiGraphs/reexport/lib/utils2.js | 5 + .../ql/test/ApiGraphs/reexport/package.json | 3 + .../return-self/VerifyAssertions.expected | 0 .../ApiGraphs/return-self/VerifyAssertions.ql | 1 + .../ql/test/ApiGraphs/return-self/index.js | 6 + .../test/ApiGraphs/return-self/package.json | 3 + .../test/ApiGraphs/typed/NodeOfType.expected | 3 + .../ql/test/ApiGraphs/typed/NodeOfType.ql | 4 + .../ApiGraphs/typed/VerifyAssertions.expected | 0 .../test/ApiGraphs/typed/VerifyAssertions.ql | 1 + javascript/ql/test/ApiGraphs/typed/index.ts | 24 + .../ql/test/ApiGraphs/typed/package.json | 7 + javascript/ql/test/ApiGraphs/typed/shim.d.ts | 13 + .../ql/test/ApiGraphs/typed/tsconfig.json | 6 + .../test/library-tests/AMD/AmdModule.expected | 1 + .../AMD/AmdModuleDefinition.expected | 13 + .../library-tests/AMD/AmdModuleDefinition.ql | 4 + .../AMD/AmdModuleDependencies.expected | 2 + .../AMD/AmdModuleExportedSymbol.expected | 2 + .../library-tests/AMD/AmdModuleExpr.expected | 1 + .../AMD/AmdModuleImportedModule.expected | 2 + .../AMD/AmdModule_exports.expected | 28 +- .../library-tests/AMD/AmdModule_exports.ql | 6 +- javascript/ql/test/library-tests/AMD/tst5.js | 6 + .../CallGraphs/AnnotatedTest/Test.ql | 3 +- .../CallGraphs/AnnotatedTest/reexport/a.js | 4 + .../CallGraphs/AnnotatedTest/reexport/b.js | 7 + .../AnnotatedTest/reexport/import.js | 7 + .../AnnotatedTest/returned-function.js | 32 + .../CallGraphs/FullTest/non-strict.js | 8 + .../CallGraphs/FullTest/strict.js | 10 + .../CallGraphs/FullTest/strict2.js | 12 + .../CallGraphs/FullTest/tests.expected | 31 + .../ClassNode/InstanceMember.expected | 2 +- .../ClassNode/InstanceMethod.expected | 2 +- .../ClassNode/SuperClass.expected | 1 + .../ql/test/library-tests/ClassNode/fields.ts | 12 +- .../ClassNode/getAReceiverNode.expected | 3 +- .../ClassNode/getFieldTypeAnnotation.expected | 4 + .../ClassNode/getFieldTypeAnnotation.ql | 4 + .../library-tests/DOM/Customizations.expected | 5 + .../test/library-tests/DOM/externs/externs.js | 10 + .../ql/test/library-tests/DOM/nameditems.js | 2 + javascript/ql/test/library-tests/DOM/tst.js | 10 + .../DataFlow/basicBlock.expected | 543 + .../test/library-tests/DataFlow/basicBlock.ql | 4 + .../DataFlow/enclosingExpr.expected | 7 + .../library-tests/DataFlow/flowStep.expected | 8 + .../DataFlow/getImmediatePredecessor.expected | 154 + .../DataFlow/getImmediatePredecessor.ql | 4 + .../DataFlow/incomplete.expected | 6 + .../library-tests/DataFlow/sources.expected | 22 + .../ql/test/library-tests/DataFlow/tst.js | 2 + .../ql/test/library-tests/Expr/assignment2.ts | 9 + .../ql/test/library-tests/Expr/tests.expected | 120 + .../ql/test/library-tests/Files/binary.js | Bin 0 -> 80 bytes .../ql/test/library-tests/Functions/getId.qll | 2 +- .../Generators/DataFlow.expected | 0 .../test/library-tests/Generators/DataFlow.ql | 12 + .../library-tests/Generators/generators.js | 53 + .../GlobalAccessPaths.expected | 28 + .../GlobalAccessPaths/GlobalAccessPaths.ql | 4 + .../library-tests/GlobalAccessPaths/test.js | 30 + .../InterProceduralFlow/DataFlow.expected | 9 + .../InterProceduralFlow/DataFlowConfig.qll | 13 +- .../InterProceduralFlow/GermanFlow.expected | 9 + .../TaintTracking.expected | 19 + .../InterProceduralFlow/TaintTracking.ql | 13 +- .../InterProceduralFlow/TrackedNodes.expected | 55 - .../InterProceduralFlow/TrackedNodes.ql | 31 - .../InterProceduralFlow/async.js | 102 + .../library-tests/InterProceduralFlow/tst.js | 3 + .../InterProceduralFlow/underscore.js | 21 + .../library-tests/ModuleTypes/commonjs.cjs | 3 + .../ModuleTypes/commonjsPackage/innermjs.mjs | 1 + .../ModuleTypes/commonjsPackage/package.json | 3 + .../ModuleTypes/commonjsPackage/tst.js | 1 + .../test/library-tests/ModuleTypes/import.js | 5 + .../ql/test/library-tests/ModuleTypes/mjs.mjs | 1 + .../ModuleTypes/modulePackage/package.json | 3 + .../modulePackage/subdir/innercjs.cjs | 1 + .../modulePackage/subdir/subfile.js | 1 + .../ModuleTypes/modulePackage/tst.js | 1 + .../test/library-tests/ModuleTypes/require.js | 7 + .../test/library-tests/ModuleTypes/script.js | 1 + .../library-tests/ModuleTypes/tests.expected | 10 + .../test/library-tests/ModuleTypes/tests.ql | 18 + .../test/library-tests/Modules/tests.expected | 27 +- .../ql/test/library-tests/Modules/tests.ql | 4 +- .../NodeJS/ModuleAccess.expected | 2 + .../Module_getAnExportedSymbol.expected | 3 + .../NodeJS/Module_getAnImport.expected | 1 + .../Module_getAnImportedModule.expected | 1 + .../library-tests/NodeJS/Modules.expected | 2 + .../NodeJS/NodeModule_exports.expected | 15 +- .../NodeJS/NodeModule_exports.ql | 6 +- .../library-tests/NodeJS/Require.expected | 2 + .../NodeJS/RequireImport.expected | 1 + .../NodeJS/mjs-files/createRequire.mjs | 4 + .../test/library-tests/NodeJS/reexport/a.js | 3 + .../test/library-tests/NodeJS/reexport/b.js | 6 + .../PackageExports/absent_main/index.js | 1 + .../PackageExports/absent_main/package.json | 3 + .../PackageExports/esmodules/main.js | 3 + .../PackageExports/esmodules/package.json | 3 + .../library-tests/PackageExports/lib1/baz.js | 5 + .../PackageExports/lib1/reexport/a.js | 3 + .../PackageExports/lib1/reexport/b.js | 6 + .../PackageExports/tests.expected | 19 +- .../library-tests/PackageExports/tests.ql | 4 + .../Portals/PortalEntry.expected | 8 + .../library-tests/Portals/PortalExit.expected | 34 + .../library-tests/Portals/src/m5/index.js | 6 + .../library-tests/Portals/src/m5/package.json | 6 + .../Promises/AdditionalPromises.expected | 2 +- .../ql/test/library-tests/Promises/flow.js | 40 +- .../ql/test/library-tests/Promises/flow2.js | 6 + .../library-tests/Promises/tests.expected | 35 +- .../StringConcatenation/StringOps.expected | 72 + .../StringConcatenation/StringOps.ql | 5 + .../library-tests/StringConcatenation/tst.js | 6 + .../StringOps/RegExpTest/RegExpTest.expected | 20 +- .../library-tests/StringOps/RegExpTest/tst.js | 17 +- .../TaintTracking/BasicTaintTracking.expected | 21 +- .../TaintTracking/DataFlowTracking.expected | 1 - .../library-tests/TaintTracking/exceptions.js | 4 +- .../TaintTracking/json-stringify.js | 19 + .../TaintTracking/static-capture-groups.js | 45 + .../QualifiedNames.expected | 1 + .../TypeScript/ArrayTypes/ArrayTypes.expected | 15 - .../ArrayTypes/NumberIndexTypes.expected | 15 - .../TypeScript/ArrayTypes/TupleTypes.expected | 1 - .../TypeScript/BaseTypes/BaseTypes.expected | 1 - .../TypeScript/BaseTypes/SelfTypes.expected | 4 - .../CallSignatureTypes/test.expected | 27 - .../TypeScript/EmbeddedInScript/Test.expected | 26 + .../TypeScript/EmbeddedInScript/Test.ql | 9 + .../TypeScript/EmbeddedInScript/htmlfile.html | 8 + .../TypeScript/EmbeddedInScript/other.ts | 5 + .../TypeScript/EmbeddedInScript/test.vue | 6 + .../TypeScript/EmbeddedInScript/tsconfig.json | 3 + .../ExpansiveTypes/ExpansiveTypes.expected | 23 - .../ExpansiveTypes/ExpansiveTypes.ql | 11 - .../ExpansiveTypes/NonExpansiveTypes.expected | 31 - .../ExpansiveTypes/NonExpansiveTypes.ql | 5 - .../TypeScript/ExpansiveTypes/Types.expected | 77 + .../TypeScript/ExpansiveTypes/Types.ql | 4 + .../GlobalQualifiedNames.expected | 4 - .../TypeScript/ExternalTypes/Types.expected | 4 - .../HasQualifiedNameFallback/Test.expected | 14 + .../HasQualifiedNameFallback/Test.ql | 13 + .../HasQualifiedNameFallback/relative.ts | 4 + .../HasQualifiedNameFallback/tst.ts | 16 + .../LexicalTypes/TypeReferences.expected | 8 - .../TypeScript/Namespaces/CheckBindings.ql | 5 +- .../Namespaces.expected | 1 - .../RegressionTests/EmptyName/test.expected | 6 - .../PartialFunctionArgs/Test.expected | 1 + .../PartialFunctionArgs/Test.ql | 4 + .../PartialFunctionArgs/tsconfig.json | 3 + .../PartialFunctionArgs/tst.ts | 1 + .../SemicolonInName/test.expected | 2 - .../TypeAnnotations/TupleTypeExpr.qll | 4 + .../TypeScript/TypeAnnotations/tests.expected | 35 + .../TypeScript/TypeAnnotations/tst.ts | 42 + .../LexicalTypeVariables.expected | 1 - .../SignatureTypeParameters.expected | 12 - .../TypeScript/Types/GetExprType.expected | 9 +- .../TypeScript/Types/GetTypeExprType.expected | 1 + .../TypeScript/Types/UnknownType.expected | 2 + .../library-tests/TypeScript/Types/tst.ts | 8 + .../TypeTracking/ClassStyle.expected | 2 + .../TypeTracking/PredicateStyle.expected | 7 + .../TypeTracking/PredicateStyle.ql | 12 + .../TypeTracking/TypeTracking.expected | 0 .../TypeTracking/TypeTracking.ql | 43 + .../library-tests/TypeTracking/client2.js | 3 + .../library-tests/TypeTracking/deprecated.js | 5 + .../library-tests/TypeTracking/reexport/a.js | 3 + .../library-tests/TypeTracking/reexport/b.js | 6 + .../TypeTracking/reexport/test.js | 4 + .../dependencies/DependencyKinds.expected | 1 + .../dependencies/dependency-kinds.js | 4 + .../ClientRequests/ClientRequests.expected | 20 + .../frameworks/ClientRequests/tst.js | 27 + .../frameworks/Concepts/tst-file-names.js | 2 +- .../Electron/BrowserObject.expected | 1 + .../frameworks/Express/RouteHandler.qll | 4 +- .../Express/RouteHandlerContainer.expected | 0 .../Express/RouteHandlerContainer.qll | 8 + .../src/advanced-routehandler-registration.js | 163 + .../controllers/handler-in-bulk-require.js | 1 + .../controllers/handler-in-dynamic-require.js | 1 + .../Express/src/controllers/index.js | 4 + .../Express/src/route-collection.js | 4 + .../frameworks/Express/tests.expected | 1416 ++ .../library-tests/frameworks/Express/tests.ql | 1 + .../AdditionalRouteHandlers.expected | 2 + .../HTTP-heuristics/RouteHandler.expected | 3 + .../RouteHandlerCandidate.expected | 2 + .../UnpromotedRouteHandlerCandidate.expected | 5 +- .../frameworks/Logging/LoggerCall.expected | 18 + .../library-tests/frameworks/Logging/tst.js | 13 + .../frameworks/Micro/TestMicro.expected | 19 + .../frameworks/Micro/TestMicro.ql | 17 + .../library-tests/frameworks/Micro/tst.js | 19 + .../frameworks/NodeJSLib/createServer.js | 11 + .../frameworks/NodeJSLib/src/http.js | 6 + .../frameworks/NodeJSLib/src/indirect.js | 36 + .../frameworks/NodeJSLib/src/indirect2.js | 18 + .../frameworks/NodeJSLib/tests.expected | 95 + .../frameworks/ReactJS/ReactName.qll | 17 + .../frameworks/ReactJS/tests.expected | 34 + .../library-tests/frameworks/ReactJS/tests.ql | 1 + .../frameworks/ReactJS/thisAccesses.js | 11 + .../frameworks/SQL/Credentials.expected | 2 + .../frameworks/SQL/SqlString.expected | 3 + .../library-tests/frameworks/SQL/mssql2.js | 13 +- .../library-tests/frameworks/SQL/mysql1a.js | 24 + .../frameworks/SQL/sqliteArray.js | 7 + .../frameworks/ServerLess/test.expected | 5 + .../frameworks/ServerLess/test.ql | 3 + .../ServerLess/tst1/backend/src/mylibrary.js | 3 + .../frameworks/ServerLess/tst1/template.yml | 19 + .../ServerLess/tst2/nodejs/index.js | 3 + .../frameworks/ServerLess/tst2/template.yml | 18 + .../ServerLess/tst3/function/index.js | 3 + .../frameworks/ServerLess/tst3/template.yml | 10 + .../frameworks/ServerLess/tst4/app.js | 3 + .../frameworks/ServerLess/tst4/template.yml | 12 + .../frameworks/ServerLess/tst5/app.js | 3 + .../frameworks/ServerLess/tst5/template.yml | 11 + .../frameworks/Vue/Instance.expected | 2 + .../Vue/Instance_getAPropertyValue.expected | 4 + .../Vue/Instance_getOption.expected | 1 + .../frameworks/Vue/TemplateElement.expected | 8 + .../frameworks/Vue/VHtmlSourceWrite.expected | 2 + .../frameworks/Vue/XssSink.expected | 2 + .../Vue/single-file-component-4.vue | 20 + .../Vue/single-file-component-5.vue | 18 + .../frameworks/connect/src/test.js | 4 + .../frameworks/connect/tests.expected | 9 + .../frameworks/hapi/tests.expected | 1 + .../DOM/TargetBlank/TargetBlank.expected | 1 + .../test/query-tests/DOM/TargetBlank/tst.html | 8 + .../test/query-tests/DOM/TargetBlank/tst.js | 5 + .../DeadStoreOfProperty.expected | 2 + .../DeadStoreOfProperty/exports.js | 3 + .../DeadStoreOfProperty/fieldInit.ts | 6 + .../Declarations/DeadStoreOfProperty/tst.js | 12 +- .../UnusedVariable/ts/tsconfig.json | 6 + .../UnusedVariable/ts/usesreact.tsx | 5 + .../UnneededDefensiveProgramming.expected | 2 + .../regression.js | 15 + .../UnneededDefensiveProgramming/tst2.js | 8 + .../NonLinearPattern.expected | 5 + .../NonLinearPattern/NonLinearPatternTS.ts | 3 + .../NonLinearPatternTSGood.ts | 3 + .../NonLinearPattern/ts-test.ts | 24 + .../MissingExports/MissingExports.expected | 2 +- .../ReDoS/PolynomialBackTracking.expected | 1 + .../ReDoS/PolynomialReDoS.expected | 5 + .../Performance/ReDoS/polynomial-redos.js | 2 +- ...ncompleteUrlSubstringSanitization.expected | 3 + .../tst-IncompleteUrlSubstringSanitization.js | 7 +- .../CWE-022/TaintedPath/Consistency.expected | 4 - .../CWE-022/TaintedPath/Consistency.ql | 31 +- .../CWE-022/TaintedPath/TaintedPath.expected | 7120 +++++--- .../CWE-022/TaintedPath/TaintedPath.js | 25 +- .../CWE-022/TaintedPath/normalizedPaths.js | 2 +- .../CWE-022/TaintedPath/other-fs-libraries.js | 4 +- .../TaintedPath/tainted-access-paths.js | 34 + .../TaintedPath/tainted-array-steps.js | 7 +- .../TaintedPath/tainted-string-steps.js | 6 +- .../CWE-022/TaintedPath/typescript.ts | 34 + .../CWE-078/CommandInjection.expected | 170 +- .../Security/CWE-078/Consistency.expected | 0 .../Security/CWE-078/Consistency.ql | 22 + .../CWE-078/IndirectCommandInjection.expected | 104 + .../UnsafeShellCommandConstruction.expected | 143 +- .../Security/CWE-078/UselessUseOfCat.expected | 12 +- .../Security/CWE-078/UselessUseOfCat.ql | 16 - .../Security/CWE-078/child_process-test.js | 26 +- ...ommand-line-parameter-command-injection.js | 43 +- .../query-tests/Security/CWE-078/exec-sh.js | 21 + .../query-tests/Security/CWE-078/exec-sh2.js | 16 + .../Security/CWE-078/execSeries.js | 4 +- .../query-tests/Security/CWE-078/lib/lib.js | 45 +- .../Security/CWE-078/lib/subLib/index.js | 4 + .../Security/CWE-078/lib/subLib/package.json | 2 +- .../query-tests/Security/CWE-078/other.js | 10 +- .../Security/CWE-078/uselesscat.js | 4 +- .../Security/CWE-079/Consistency.expected | 0 .../Security/CWE-079/Consistency.ql | 8 + .../Security/CWE-079/ExceptionXss.expected | 72 +- .../Security/CWE-079/ReflectedXss.expected | 9 + .../Security/CWE-079/ReflectedXss.js | 10 +- .../Security/CWE-079/ReflectedXssGood3.js | 2 +- .../ReflectedXssWithCustomSanitizer.expected | 1 + .../CWE-079/UnsafeJQueryPlugin.expected | 53 +- .../query-tests/Security/CWE-079/Xss.expected | 1065 +- .../Security/CWE-079/XssThroughDom.expected | 30 +- .../CWE-079/XssWithAdditionalSources.expected | 941 +- .../Security/CWE-079/exception-xss.js | 6 +- .../query-tests/Security/CWE-079/externs.js | 20 +- .../query-tests/Security/CWE-079/partial.js | 2 +- .../query-tests/Security/CWE-079/sanitiser.js | 2 +- .../test/query-tests/Security/CWE-079/tst.js | 69 +- .../query-tests/Security/CWE-079/typeahead.js | 2 +- .../Security/CWE-079/unsafe-jquery-plugin.js | 6 +- .../CWE-089/untyped/Consistency.expected | 0 .../Security/CWE-089/untyped/Consistency.ql | 4 + .../CWE-089/untyped/DatabaseAccesses.expected | 28 +- .../CWE-089/untyped/SqlInjection.expected | 231 +- .../Security/CWE-089/untyped/mongodb.js | 28 + .../Security/CWE-089/untyped/mongoose.js | 15 +- .../Security/CWE-089/untyped/tst3.js | 3 +- .../CodeInjection/CodeInjection.expected | 40 + .../HeuristicSourceCodeInjection.expected | 37 + .../ImproperCodeSanitization.expected | 75 + .../ImproperCodeSanitization.qlref | 1 + .../CodeInjection/NoSQLCodeInjection.js | 8 +- .../CodeInjection/bad-code-sanitization.js | 92 + .../query-tests/Security/CWE-094/tmp.html | 9 + ...ompleteMultiCharacterSanitization.expected | 33 + ...IncompleteMultiCharacterSanitization.qlref | 1 + .../tst-multi-character-sanitization.js | 116 + .../CWE-200/PrivateFileExposure.expected | 21 + .../CWE-200/PrivateFileExposure.qlref | 1 + .../Security/CWE-200/lib/package.json | 6 + .../query-tests/Security/CWE-200/lib/tst.js | 11 + .../Security/CWE-200/private-file-exposure.js | 62 + .../DisablingCertificateValidation.expected | 9 + .../DisablingCertificateValidation.qlref | 1 + .../test/query-tests/Security/CWE-295/tst.js | 70 + .../CWE-312/BuildArtifactLeak.expected | 57 + .../Security/CWE-312/BuildArtifactLeak.qlref | 1 + .../Security/CWE-312/build-leaks.js | 42 + .../query-tests/Security/CWE-312/passwords.js | 12 +- .../Security/CWE-327/BadRandomness.expected | 18 + .../Security/CWE-327/BadRandomness.qlref | 1 + .../Security/CWE-327/bad-random.js | 129 + .../test/query-tests/Security/CWE-338/tst.js | 20 +- .../test/query-tests/Security/CWE-346/tst.js | 2 +- .../CWE-352/MissingCsrfMiddleware.expected | 3 + .../CWE-352/MissingCsrfMiddlewareBad.js | 48 +- .../test/query-tests/Security/CWE-506/tst.js | 2 +- .../ClientSideUrlRedirect.expected | 175 + .../ClientSideUrlRedirect/sanitizer.js | 43 + .../CWE-601/ClientSideUrlRedirect/tst.js | 16 + .../CWE-601/ClientSideUrlRedirect/tst13.js | 55 + .../CWE-601/ClientSideUrlRedirect/tst14.js | 10 + .../ServerSideUrlRedirect.expected | 114 +- .../CWE-601/ServerSideUrlRedirect/express.js | 9 +- .../CWE-601/ServerSideUrlRedirect/node.js | 3 +- .../query-tests/Security/CWE-611/Xxe.expected | 42 +- .../Security/CWE-611/libxml.noent.js | 13 + .../Security/CWE-611/libxml.sax.js | 3 +- .../Security/CWE-611/libxml.saxpush.js | 3 +- .../Security/CWE-614/InsecureCookies.expected | 9 + .../Security/CWE-614/InsecureCookies.qlref | 1 + .../Security/CWE-614/test_cookie-session.js | 28 + .../Security/CWE-614/test_express-session.js | 33 + .../Security/CWE-614/test_httpserver.js | 22 + .../Security/CWE-614/test_jscookie.js | 3 + .../Security/CWE-614/test_responseCookie.js | 33 + .../Security/CWE-730/RegExpInjection.js | 2 +- .../CWE-754/UnsafeDynamicMethodAccess.js | 8 +- .../test/query-tests/Security/CWE-754/tst.js | 4 +- .../query-tests/Security/CWE-770/rateLimit.ts | 5 + .../test/query-tests/Security/CWE-770/tst2.ts | 8 + .../Security/CWE-776/XmlBomb.expected | 30 +- .../query-tests/Security/CWE-776/expat.js | 3 +- .../Security/CWE-776/libxml.sax.js | 3 +- .../Security/CWE-776/libxml.saxpush.js | 3 +- .../Security/CWE-798/HardcodedCredentials.js | 62 +- .../CWE-807/ConditionalBypass.expected | 214 +- .../DifferentKindsComparisonBypass.expected | 6 +- .../test/query-tests/Security/CWE-807/tst.js | 39 +- .../CWE-829/InsecureDownload.expected | 48 + .../Security/CWE-829/InsecureDownload.qlref | 1 + .../Security/CWE-829/insecure-download.js | 59 + .../Security/CWE-834/LoopBoundInjectionBad.js | 4 +- .../CWE-834/LoopBoundInjectionExitBad.js | 4 +- .../test/query-tests/Security/CWE-843/tst.js | 2 +- .../test/query-tests/Security/CWE-918/tst.js | 6 +- ...iciousUnusedLoopIterationVariable.expected | 3 + .../tst.js | 17 + .../filters/ClassifyFiles/MyComponent.vue | 6 + .../testUtilities/ConsistencyChecking.qll | 177 + .../query15.qll | 11 +- .../old.dbscheme | 1190 ++ .../semmlecode.javascript.dbscheme | 1193 ++ .../upgrade.properties | 2 + .../old.dbscheme | 1193 ++ .../semmlecode.javascript.dbscheme | 1193 ++ .../upgrade.properties | 94 + .../generate-code-scanning-query-list.py | 157 + .../suite-helpers/code-scanning-selectors.yml | 2 + misc/suite-helpers/lgtm-selectors.yml | 2 + .../security-and-quality-selectors.yml | 21 + .../security-extended-selectors.yml | 26 + python/ql/examples/qlpack.yml | 3 + .../ql/examples/snippets/catch_exception.ql | 4 +- .../snippets/conditional_expression.ql | 6 +- python/ql/examples/snippets/emptythen.ql | 8 +- python/ql/examples/snippets/extend_class.ql | 4 +- python/ql/examples/snippets/method_call.ql | 4 +- python/ql/examples/snippets/new_instance.ql | 4 +- .../ql/examples/snippets/override_method.ql | 4 +- python/ql/examples/snippets/print.ql | 10 +- python/ql/examples/snippets/private_access.ql | 8 +- .../ql/examples/snippets/raise_exception.ql | 4 +- python/ql/examples/snippets/store_none.ql | 4 +- python/ql/examples/snippets/tryfinally.ql | 4 +- python/ql/src/Classes/ClassAttributes.qll | 240 +- .../ConflictingAttributesInBaseClasses.ql | 66 +- .../DefineEqualsWhenAddingAttributes.ql | 48 +- python/ql/src/Classes/Equality.qll | 102 +- python/ql/src/Classes/EqualsOrHash.ql | 54 +- python/ql/src/Classes/EqualsOrNotEquals.ql | 30 +- python/ql/src/Classes/IncompleteOrdering.ql | 72 +- python/ql/src/Classes/InconsistentMRO.ql | 14 +- .../ql/src/Classes/InitCallsSubclassMethod.ql | 24 +- .../Classes/MaybeUndefinedClassAttribute.ql | 38 +- python/ql/src/Classes/MethodCallOrder.qll | 84 +- python/ql/src/Classes/MissingCallToDel.ql | 12 +- python/ql/src/Classes/MissingCallToInit.ql | 20 +- python/ql/src/Classes/MutatingDescriptor.ql | 24 +- .../OverwritingAttributeInSuperClass.ql | 114 +- .../ql/src/Classes/PropertyInOldStyleClass.ql | 4 +- .../ql/src/Classes/ShouldBeContextManager.ql | 8 +- python/ql/src/Classes/SubclassShadowing.ql | 34 +- python/ql/src/Classes/SuperInOldStyleClass.ql | 14 +- .../SuperclassDelCalledMultipleTimes.ql | 20 +- .../SuperclassInitCalledMultipleTimes.ql | 22 +- .../ql/src/Classes/UndefinedClassAttribute.ql | 18 +- python/ql/src/Classes/UselessClass.ql | 106 +- ...rongNameForArgumentInClassInstantiation.ql | 6 +- ...rongNumberArgumentsInClassInstantiation.ql | 22 +- .../src/Exceptions/CatchingBaseException.ql | 10 +- python/ql/src/Exceptions/EmptyExcept.ql | 104 +- .../Exceptions/IllegalExceptionHandlerType.ql | 22 +- python/ql/src/Exceptions/IllegalRaise.ql | 10 +- .../ql/src/Exceptions/IncorrectExceptOrder.ql | 20 +- python/ql/src/Exceptions/NotImplemented.qll | 10 +- python/ql/src/Exceptions/Raising.qll | 14 +- python/ql/src/Exceptions/RaisingTuple.ql | 10 +- .../Exceptions/UnguardedNextInGenerator.ql | 42 +- python/ql/src/Expressions/CallArgs.qll | 302 +- .../src/Expressions/CallToSuperWrongClass.ql | 18 +- python/ql/src/Expressions/CompareConstants.ql | 8 +- .../Comparisons/UselessComparisonTest.ql | 26 +- .../src/Expressions/ContainsNonContainer.ql | 26 +- .../DuplicateKeyInDictionaryLiteral.ql | 42 +- .../ExpectedMappingForFormatString.ql | 16 +- .../ql/src/Expressions/ExplicitCallToDel.ql | 26 +- .../Formatting/AdvancedFormatting.qll | 185 +- .../Formatting/UnusedArgumentIn3101Format.ql | 14 +- .../UnusedNamedArgumentIn3101Format.ql | 26 +- .../WrongNameInArgumentsFor3101Format.ql | 12 +- .../WrongNumberArgumentsFor3101Format.ql | 20 +- python/ql/src/Expressions/HashedButNoHash.ql | 60 +- .../Expressions/IncorrectComparisonUsingIs.ql | 18 +- python/ql/src/Expressions/IsComparisons.qll | 190 +- .../ql/src/Expressions/NonCallableCalled.ql | 16 +- .../NonPortableComparisonUsingIs.ql | 14 +- .../src/Expressions/RedundantComparison.qll | 67 +- .../src/Expressions/Regex/BackspaceEscape.ql | 6 +- .../Regex/DuplicateCharacterInSet.ql | 42 +- .../src/Expressions/Regex/UnmatchableCaret.ql | 10 +- .../Expressions/Regex/UnmatchableDollar.ql | 10 +- .../ql/src/Expressions/TruncatedDivision.ql | 36 +- ...nintentionalImplicitStringConcatenation.ql | 24 +- .../ql/src/Expressions/UnnecessaryLambda.ql | 68 +- python/ql/src/Expressions/UseofInput.ql | 8 +- .../Expressions/WrongNameForArgumentInCall.ql | 12 +- .../WrongNumberArgumentsForFormat.qhelp | 4 +- .../WrongNumberArgumentsForFormat.ql | 42 +- .../Expressions/WrongNumberArgumentsInCall.ql | 19 +- python/ql/src/Filters/ClassifyFiles.ql | 6 +- python/ql/src/Functions/ConsistentReturns.ql | 20 +- .../ql/src/Functions/DeprecatedSliceMethod.ql | 10 +- .../ql/src/Functions/ExplicitReturnInInit.ql | 12 +- .../IncorrectRaiseInSpecialMethod.ql | 212 +- .../Functions/IncorrectlyOverriddenMethod.ql | 26 +- .../IncorrectlySpecifiedOverriddenMethod.ql | 40 +- python/ql/src/Functions/InitIsGenerator.ql | 4 +- .../src/Functions/IterReturnsNonIterator.ql | 12 +- python/ql/src/Functions/IterReturnsNonSelf.ql | 12 +- .../ModificationOfParameterWithDefault.ql | 104 +- python/ql/src/Functions/NonCls.ql | 44 +- python/ql/src/Functions/NonSelf.ql | 58 +- .../src/Functions/OverlyComplexDelMethod.ql | 8 +- .../Functions/ReturnConsistentTupleSizes.ql | 20 +- python/ql/src/Functions/ReturnValueIgnored.ql | 92 +- .../Functions/SignatureOverriddenMethod.ql | 32 +- .../src/Functions/SignatureSpecialMethods.ql | 330 +- .../Functions/UseImplicitNoneReturnValue.ql | 36 +- python/ql/src/Imports/Cyclic.qll | 132 +- python/ql/src/Imports/CyclicImport.ql | 14 +- python/ql/src/Imports/DeprecatedModule.ql | 110 +- .../Imports/FromImportOfMutableAttribute.ql | 30 +- .../ql/src/Imports/ImportShadowedByLoopVar.ql | 10 +- python/ql/src/Imports/ImportandImportFrom.ql | 12 +- python/ql/src/Imports/ModuleImportsItself.ql | 16 +- .../ql/src/Imports/ModuleLevelCyclicImport.ql | 8 +- python/ql/src/Imports/MultipleImports.ql | 46 +- python/ql/src/Imports/UnintentionalImport.ql | 18 +- python/ql/src/Imports/UnusedImport.ql | 160 +- python/ql/src/Lexical/CommentedOutCode.qll | 434 +- .../CommentedOutCodeMetricOverview.qhelp | 12 + .../src/Lexical/CommentedOutCodeQuery.qhelp | 25 + .../Lexical/CommentedOutCodeReferences.qhelp | 12 + python/ql/src/Lexical/OldOctalLiteral.ql | 20 +- python/ql/src/Metrics/CommentRatio.ql | 2 +- .../Dependencies/ExternalDependencies.ql | 15 +- .../ExternalDependenciesSourceLinks.ql | 11 +- python/ql/src/Metrics/DocStringRatio.ql | 4 +- .../ql/src/Metrics/DuplicationProblems.qhelp | 1 - python/ql/src/Metrics/FLinesOfComments.ql | 2 +- .../ql/src/Metrics/FLinesOfDuplicatedCode.ql | 15 +- .../FLinesOfDuplicatedCodeCommon.qhelp | 35 + python/ql/src/Metrics/FLinesOfSimilarCode.ql | 15 +- python/ql/src/Metrics/History/HChurn.ql | 14 +- python/ql/src/Metrics/History/HLinesAdded.ql | 14 +- .../ql/src/Metrics/History/HLinesDeleted.ql | 14 +- .../src/Metrics/History/HNumberOfCoCommits.ql | 10 +- .../src/Metrics/History/HNumberOfReCommits.ql | 24 +- .../Metrics/History/HNumberOfRecentAuthors.ql | 14 +- .../History/HNumberOfRecentChangedFiles.ql | 8 +- python/ql/src/Metrics/Internal/Extents.qll | 34 +- python/ql/src/Numerics/Pythagorean.ql | 34 +- .../ql/src/Resources/FileNotAlwaysClosed.ql | 78 +- python/ql/src/Resources/FileOpen.qll | 202 +- .../CVE-2018-1281/BindToAllInterfaces.ql | 22 +- .../CWE-020/IncompleteHostnameRegExp.qhelp | 2 +- .../CWE-020/IncompleteHostnameRegExp.ql | 26 +- .../IncompleteUrlSubstringSanitization.qhelp | 4 +- .../IncompleteUrlSubstringSanitization.ql | 44 +- .../IncompleteUrlSubstringSanitization.py | 6 +- .../src/Security/CWE-022/PathInjection.qhelp | 4 +- .../ql/src/Security/CWE-022/PathInjection.ql | 26 +- python/ql/src/Security/CWE-022/TarSlip.qhelp | 2 +- python/ql/src/Security/CWE-022/TarSlip.ql | 222 +- .../Security/CWE-078/CommandInjection.qhelp | 2 +- .../src/Security/CWE-078/CommandInjection.ql | 22 +- .../CWE-078/examples/command_injection.py | 2 +- .../Security/CWE-079/Jinja2WithoutEscaping.ql | 26 +- .../ql/src/Security/CWE-079/ReflectedXss.ql | 17 +- .../ql/src/Security/CWE-089/SqlInjection.ql | 22 +- .../ql/src/Security/CWE-094/CodeInjection.ql | 12 +- .../Security/CWE-209/StackTraceExposure.qhelp | 2 +- .../Security/CWE-209/StackTraceExposure.ql | 8 +- python/ql/src/Security/CWE-215/FlaskDebug.ql | 8 +- .../CWE-295/MissingHostKeyValidation.ql | 20 +- .../CWE-295/RequestWithoutValidation.ql | 8 +- .../src/Security/CWE-312/CleartextLogging.ql | 18 +- .../src/Security/CWE-312/CleartextStorage.ql | 18 +- python/ql/src/Security/CWE-326/WeakCrypto.ql | 94 +- .../CWE-327/BrokenCryptoAlgorithm.qhelp | 2 +- .../Security/CWE-327/BrokenCryptoAlgorithm.ql | 12 +- .../CWE-327/InsecureDefaultProtocol.ql | 20 +- .../src/Security/CWE-327/InsecureProtocol.ql | 94 +- .../CWE-327/examples/broken_crypto.py | 4 +- .../Security/CWE-377/InsecureTemporaryFile.ql | 20 +- .../Security/CWE-502/UnsafeDeserialization.ql | 10 +- python/ql/src/Security/CWE-601/UrlRedirect.ql | 20 +- .../Security/CWE-732/WeakFilePermissions.ql | 28 +- .../Security/CWE-798/HardcodedCredentials.ql | 144 +- .../src/Statements/AssertLiteralConstant.ql | 22 +- python/ql/src/Statements/AssertOnTuple.ql | 16 +- .../src/Statements/BreakOrReturnInFinally.ql | 16 +- .../ql/src/Statements/C_StyleParentheses.ql | 34 +- .../src/Statements/ConstantInConditional.ql | 24 +- python/ql/src/Statements/DocStrings.ql | 40 +- python/ql/src/Statements/ExecUsed.ql | 8 +- .../Statements/IterableStringOrSequence.ql | 32 +- .../MismatchInMultipleAssignment.ql | 68 +- .../ql/src/Statements/ModificationOfLocals.ql | 24 +- .../src/Statements/NestedLoopsSameVariable.ql | 14 +- .../NestedLoopsSameVariableWithReuse.ql | 24 +- .../ql/src/Statements/NonIteratorInForLoop.ql | 14 +- .../ql/src/Statements/RedundantAssignment.ql | 82 +- .../ReturnOrYieldOutsideFunction.ql | 16 +- .../src/Statements/ShouldUseWithStatement.ql | 24 +- .../ql/src/Statements/SideEffectInAssert.ql | 50 +- python/ql/src/Statements/StatementNoEffect.ql | 132 +- .../Statements/StringConcatenationInLoop.ql | 16 +- python/ql/src/Statements/TopLevelPrint.ql | 32 +- python/ql/src/Statements/UnnecessaryDelete.ql | 26 +- .../src/Statements/UnnecessaryElseClause.ql | 14 +- python/ql/src/Statements/UnnecessaryPass.ql | 18 +- python/ql/src/Statements/UnreachableCode.ql | 56 +- .../src/Statements/UnusedExceptionObject.ql | 6 +- python/ql/src/Statements/UseOfExit.ql | 4 +- python/ql/src/Testing/ImpreciseAssert.ql | 130 +- python/ql/src/Testing/Mox.qll | 20 +- python/ql/src/Variables/Definition.qll | 218 +- .../src/Variables/LeakingListComprehension.ql | 26 +- python/ql/src/Variables/Loop.qll | 40 +- .../ql/src/Variables/LoopVariableCapture.ql | 42 +- python/ql/src/Variables/MonkeyPatched.qll | 40 +- python/ql/src/Variables/MultiplyDefined.ql | 62 +- python/ql/src/Variables/ShadowBuiltin.ql | 76 +- python/ql/src/Variables/ShadowGlobal.ql | 64 +- python/ql/src/Variables/Shadowing.qll | 8 +- .../SuspiciousUnusedLoopIterationVariable.ql | 126 +- python/ql/src/Variables/Undefined.qll | 154 +- python/ql/src/Variables/UndefinedExport.ql | 76 +- python/ql/src/Variables/UndefinedGlobal.ql | 148 +- .../ql/src/Variables/UndefinedPlaceHolder.ql | 28 +- python/ql/src/Variables/UninitializedLocal.ql | 22 +- .../ql/src/Variables/UnusedLocalVariable.ql | 24 +- .../ql/src/Variables/UnusedModuleVariable.ql | 72 +- python/ql/src/Variables/UnusedParameter.ql | 26 +- python/ql/src/analysis/AlertSuppression.ql | 130 +- python/ql/src/analysis/CallGraphEfficiency.ql | 26 +- .../analysis/CallGraphMarginalEfficiency.ql | 34 +- python/ql/src/analysis/Consistency.ql | 298 + python/ql/src/analysis/ContextEfficiency.ql | 28 +- .../src/analysis/ContextMarginalEfficiency.ql | 28 +- .../src/analysis/CrossProjectDefinitions.qll | 144 +- python/ql/src/analysis/DefinitionTracking.qll | 541 +- python/ql/src/analysis/Definitions.ql | 2 +- python/ql/src/analysis/Efficiency.ql | 38 +- python/ql/src/analysis/ImportFailure.ql | 98 +- python/ql/src/analysis/KeyPointsToFailure.ql | 14 +- python/ql/src/analysis/LocalDefinitions.ql | 9 +- python/ql/src/analysis/LocalReferences.ql | 7 +- python/ql/src/analysis/RatioOfDefinitions.ql | 26 +- python/ql/src/analysis/Sanity.ql | 298 - python/ql/src/analysis/Summary.ql | 68 +- .../ql/src/analysis/TypeInferenceFailure.ql | 4 +- .../ql/src/codeql-suites/python-lgtm-full.qls | 4 + .../python-security-and-quality.qls | 4 + .../python-security-extended.qls | 4 + python/ql/src/experimental/Customizations.qll | 20 + .../CWE-078/CommandInjection.ql | 65 + .../CWE-094/CodeInjection.ql | 35 + .../CWE-502/UnsafeDeserialization.ql | 36 + .../Security-new-dataflow/promote.sh | 13 + .../experimental/Security/CWE-074/JinjaBad.py | 19 + .../Security/CWE-074/JinjaGood.py | 20 + .../Security/CWE-074/TemplateInjection.qhelp | 24 + .../Security/CWE-074/TemplateInjection.ql | 34 + .../experimental/Security/CWE-091/Xslt.qhelp | 18 + .../src/experimental/Security/CWE-091/Xslt.ql | 35 + .../src/experimental/Security/CWE-091/xslt.py | 14 + .../experimental/Security/CWE-643/xpath.qhelp | 30 + .../experimental/Security/CWE-643/xpath.ql | 36 + .../experimental/Security/CWE-643/xpathBad.py | 18 + .../Security/CWE-643/xpathGood.py | 18 + .../ql/src/experimental/dataflow/DataFlow.qll | 26 + .../src/experimental/dataflow/DataFlow2.qll | 26 + .../dataflow/RemoteFlowSources.qll | 34 + .../experimental/dataflow/TaintTracking.qll | 19 + .../src/experimental/dataflow/TypeTracker.qll | 299 + .../dataflow/internal/Attributes.qll | 244 + .../dataflow/internal/DataFlowImpl.qll | 3110 ++++ .../dataflow/internal/DataFlowImpl2.qll | 3110 ++++ .../dataflow/internal/DataFlowImplCommon.qll | 822 + .../internal/DataFlowImplConsistency.qll | 175 + .../internal/DataFlowImplSpecific.qll | 12 + .../dataflow/internal/DataFlowPrivate.qll | 1127 ++ .../dataflow/internal/DataFlowPublic.qll | 421 + .../dataflow/internal/DataFlowUtil.qll | 72 + .../internal/TaintTrackingPrivate.qll | 227 + .../dataflow/internal/TaintTrackingPublic.qll | 59 + .../experimental/dataflow/internal/readme.md | 138 + .../tainttracking1/TaintTrackingImpl.qll | 115 + .../tainttracking1/TaintTrackingParameter.qll | 6 + .../experimental/semmle/python/Concepts.qll | 186 + .../experimental/semmle/python/Frameworks.qll | 10 + .../semmle/python/frameworks/Dill.qll | 58 + .../semmle/python/frameworks/Django.qll | 10 + .../semmle/python/frameworks/Flask.qll | 311 + .../semmle/python/frameworks/Invoke.qll | 149 + .../semmle/python/frameworks/Stdlib.qll | 683 + .../semmle/python/frameworks/Werkzeug.qll | 75 + .../semmle/python/frameworks/Yaml.qll | 98 + .../semmle/python/security/injection/XSLT.qll | 115 + .../python/security/injection/Xpath.qll | 115 + .../semmle/python/templates/Airspeed.qll | 27 + .../semmle/python/templates/Bottle.qll | 46 + .../semmle/python/templates/Chameleon.qll | 27 + .../semmle/python/templates/Cheetah.qll | 37 + .../semmle/python/templates/Chevron.qll | 36 + .../python/templates/DjangoTemplate.qll | 35 + .../semmle/python/templates/FlaskTemplate.qll | 26 + .../semmle/python/templates/Genshi.qll | 51 + .../semmle/python/templates/Jinja.qll | 49 + .../semmle/python/templates/Mako.qll | 27 + .../semmle/python/templates/SSTISink.qll | 7 + .../semmle/python/templates/Ssti.qll | 13 + .../semmle/python/templates/TRender.qll | 27 + python/ql/src/external/CodeDuplication.qll | 290 +- python/ql/src/external/DefectFilter.qll | 83 +- python/ql/src/external/DuplicateBlock.ql | 16 +- python/ql/src/external/DuplicateFunction.ql | 11 +- python/ql/src/external/ExternalArtifact.qll | 87 +- .../ql/src/external/MostlyDuplicateClass.ql | 7 +- python/ql/src/external/MostlyDuplicateFile.ql | 1 + python/ql/src/external/MostlySimilarFile.ql | 1 + python/ql/src/external/SimilarFunction.ql | 13 +- python/ql/src/external/Thrift.qll | 219 +- python/ql/src/external/VCS.qll | 85 +- python/ql/src/meta/MetaMetrics.qll | 26 + .../analysis-quality/CallGraphQuality.qll | 65 + .../PointsToResolvableCallRatio.ql | 15 + .../PointsToResolvableCalls.ql | 14 + .../PointsToResolvableCallsRelevantTarget.ql | 14 + .../ResolvableCallCandidates.ql | 14 + python/ql/src/semmle/crypto/Crypto.qll | 232 +- python/ql/src/semmle/python/AstExtended.qll | 180 +- python/ql/src/semmle/python/AstGenerated.qll | 1645 +- python/ql/src/semmle/python/Class.qll | 267 +- python/ql/src/semmle/python/Comment.qll | 145 +- python/ql/src/semmle/python/Comparisons.qll | 816 +- .../ql/src/semmle/python/Comprehensions.qll | 158 +- python/ql/src/semmle/python/Constants.qll | 32 +- python/ql/src/semmle/python/Exprs.qll | 953 +- python/ql/src/semmle/python/Files.qll | 820 +- python/ql/src/semmle/python/Flow.qll | 2003 +-- python/ql/src/semmle/python/Function.qll | 604 +- .../src/semmle/python/GuardedControlFlow.qll | 120 +- python/ql/src/semmle/python/Import.qll | 422 +- python/ql/src/semmle/python/Keywords.qll | 56 +- python/ql/src/semmle/python/Metrics.qll | 596 +- python/ql/src/semmle/python/Module.qll | 410 +- python/ql/src/semmle/python/Operations.qll | 156 +- python/ql/src/semmle/python/SSA.qll | 349 +- python/ql/src/semmle/python/Scope.qll | 282 +- python/ql/src/semmle/python/SelfAttribute.qll | 100 +- .../ql/src/semmle/python/SpecialMethods.qll | 117 + python/ql/src/semmle/python/Stmts.qll | 605 +- python/ql/src/semmle/python/TestUtils.qll | 22 +- python/ql/src/semmle/python/Variables.qll | 129 +- .../semmle/python/dataflow/Configuration.qll | 266 +- .../ql/src/semmle/python/dataflow/Files.qll | 16 +- .../semmle/python/dataflow/Implementation.qll | 1733 +- .../ql/src/semmle/python/dataflow/Legacy.qll | 100 +- .../semmle/python/dataflow/StateTracking.qll | 296 +- .../semmle/python/dataflow/TaintTracking.qll | 882 +- .../python/dependencies/Dependencies.qll | 226 +- .../python/dependencies/DependencyKind.qll | 20 +- .../python/dependencies/TechInventory.qll | 150 +- .../ql/src/semmle/python/essa/Definitions.qll | 569 +- python/ql/src/semmle/python/essa/Essa.qll | 1079 +- .../ql/src/semmle/python/essa/SsaCompute.qll | 582 +- .../src/semmle/python/essa/SsaDefinitions.qll | 250 +- .../semmle/python/filters/GeneratedCode.qll | 246 +- python/ql/src/semmle/python/filters/Tests.qll | 46 +- .../ql/src/semmle/python/libraries/Zope.qll | 62 +- .../src/semmle/python/objects/Callables.qll | 742 +- .../ql/src/semmle/python/objects/Classes.qll | 531 +- .../src/semmle/python/objects/Constants.qll | 364 +- .../src/semmle/python/objects/Descriptors.qll | 498 +- .../src/semmle/python/objects/Instances.qll | 735 +- .../ql/src/semmle/python/objects/Modules.qll | 588 +- .../src/semmle/python/objects/ObjectAPI.qll | 1719 +- .../semmle/python/objects/ObjectInternal.qll | 868 +- .../src/semmle/python/objects/Sequences.qll | 397 +- .../ql/src/semmle/python/objects/TObject.qll | 809 +- python/ql/src/semmle/python/pointsto/Base.qll | 413 +- .../src/semmle/python/pointsto/CallGraph.qll | 85 +- .../ql/src/semmle/python/pointsto/Filters.qll | 48 +- python/ql/src/semmle/python/pointsto/MRO.qll | 712 +- .../src/semmle/python/pointsto/PointsTo.qll | 5255 +++--- .../python/pointsto/PointsToContext.qll | 315 +- python/ql/src/semmle/python/regex.qll | 1353 +- .../src/semmle/python/security/ClearText.qll | 80 +- .../ql/src/semmle/python/security/Crypto.qll | 180 +- .../src/semmle/python/security/Exceptions.qll | 84 +- .../ql/src/semmle/python/security/Paths.qll | 18 +- .../semmle/python/security/SensitiveData.qll | 218 +- .../semmle/python/security/flow/AnyCall.qll | 4 +- .../python/security/injection/Command.qll | 344 +- .../security/injection/Deserialization.qll | 4 +- .../semmle/python/security/injection/Exec.qll | 18 +- .../python/security/injection/Marshal.qll | 16 +- .../semmle/python/security/injection/Path.qll | 84 +- .../python/security/injection/Pickle.qll | 26 +- .../semmle/python/security/injection/Sql.qll | 64 +- .../semmle/python/security/injection/Xml.qll | 42 +- .../semmle/python/security/injection/Yaml.qll | 16 +- .../semmle/python/security/strings/Basic.qll | 166 +- .../semmle/python/security/strings/Common.qll | 16 +- .../python/security/strings/External.qll | 472 +- .../python/security/strings/Untrusted.qll | 2 +- python/ql/src/semmle/python/strings.qll | 38 +- .../src/semmle/python/templates/PyxlTags.qll | 78 +- .../src/semmle/python/templates/Templates.qll | 12 +- .../ql/src/semmle/python/types/Builtins.qll | 229 +- .../src/semmle/python/types/ClassObject.qll | 676 +- .../src/semmle/python/types/Descriptors.qll | 30 +- .../ql/src/semmle/python/types/Exceptions.qll | 838 +- .../ql/src/semmle/python/types/Extensions.qll | 234 +- .../semmle/python/types/FunctionObject.qll | 550 +- .../ql/src/semmle/python/types/ImportTime.qll | 42 +- .../ql/src/semmle/python/types/ModuleKind.qll | 52 +- .../src/semmle/python/types/ModuleObject.qll | 374 +- python/ql/src/semmle/python/types/Object.qll | 638 +- .../ql/src/semmle/python/types/Properties.qll | 128 +- python/ql/src/semmle/python/types/Version.qll | 14 +- .../semmle/python/values/StringAttributes.qll | 108 +- python/ql/src/semmle/python/web/Http.qll | 139 +- .../src/semmle/python/web/HttpConstants.qll | 14 +- .../src/semmle/python/web/bottle/General.qll | 48 +- .../src/semmle/python/web/bottle/Redirect.qll | 16 +- .../src/semmle/python/web/bottle/Request.qll | 86 +- .../src/semmle/python/web/bottle/Response.qll | 46 +- .../semmle/python/web/cherrypy/General.qll | 60 +- .../semmle/python/web/cherrypy/Request.qll | 56 +- .../semmle/python/web/cherrypy/Response.qll | 16 +- .../src/semmle/python/web/client/Requests.qll | 18 +- .../src/semmle/python/web/client/StdLib.qll | 88 +- python/ql/src/semmle/python/web/django/Db.qll | 34 +- .../src/semmle/python/web/django/General.qll | 178 +- .../ql/src/semmle/python/web/django/Model.qll | 102 +- .../src/semmle/python/web/django/Redirect.qll | 28 +- .../src/semmle/python/web/django/Request.qll | 90 +- .../src/semmle/python/web/django/Response.qll | 109 +- .../src/semmle/python/web/django/Shared.qll | 86 +- .../src/semmle/python/web/falcon/General.qll | 38 +- .../src/semmle/python/web/falcon/Request.qll | 58 +- .../src/semmle/python/web/falcon/Response.qll | 22 +- .../src/semmle/python/web/flask/General.qll | 102 +- .../src/semmle/python/web/flask/Redirect.qll | 14 +- .../src/semmle/python/web/flask/Request.qll | 86 +- .../src/semmle/python/web/flask/Response.qll | 66 +- .../semmle/python/web/pyramid/Redirect.qll | 26 +- .../src/semmle/python/web/pyramid/Request.qll | 20 +- .../semmle/python/web/pyramid/Response.qll | 34 +- .../ql/src/semmle/python/web/pyramid/View.qll | 2 +- .../src/semmle/python/web/stdlib/Request.qll | 182 +- .../src/semmle/python/web/stdlib/Response.qll | 46 +- .../semmle/python/web/tornado/Redirect.qll | 18 +- .../src/semmle/python/web/tornado/Request.qll | 96 +- .../semmle/python/web/tornado/Response.qll | 48 +- .../src/semmle/python/web/tornado/Tornado.qll | 50 +- .../semmle/python/web/turbogears/Request.qll | 30 +- .../semmle/python/web/turbogears/Response.qll | 32 +- .../python/web/turbogears/TurboGears.qll | 40 +- .../src/semmle/python/web/twisted/Request.qll | 40 +- .../semmle/python/web/twisted/Response.qll | 48 +- .../src/semmle/python/web/twisted/Twisted.qll | 50 +- .../src/semmle/python/web/webob/Request.qll | 52 +- python/ql/src/semmlecode.python.dbscheme | 23 +- .../ControlFlow/Exceptions/Likely.ql | 4 +- .../class_properties/ClassValues.expected | 12 + .../PointsTo/class_properties/ClassValues.ql | 20 + .../PointsTo/class_properties/options | 1 + .../PointsTo/class_properties/test.py | 50 + .../PointsTo/import_time/Pruned.ql | 10 +- .../library-tests/PointsTo/imports/Runtime.ql | 10 +- .../PointsTo/origin_uniqueness/Origin.ql | 8 +- .../library-tests/classes/attr/class_attr.ql | 8 +- .../classes/attr/class_has_attr.ql | 8 +- .../2/library-tests/classes/attr/list_attr.ql | 10 +- .../ql/test/2/library-tests/classes/mro/C3.ql | 2 +- .../test/2/library-tests/classes/mro/mro.ql | 4 +- ...eck.expected => ConsistencyCheck.expected} | 0 .../{SanityCheck.ql => ConsistencyCheck.ql} | 4 +- .../locations/general/AllLocations.ql | 6 +- .../modules/general/import_test.ql | 8 +- .../test/2/library-tests/objects/Literals.ql | 6 +- .../ql/test/2/library-tests/six/pointsto.ql | 6 +- .../library-tests/types/classes/new_style.ql | 6 +- .../library-tests/types/exceptions/Raises.ql | 14 +- .../types/properties/BuiltinProperties.ql | 6 +- .../ControlFlow/Exceptions/Likely.ql | 4 +- .../PointsTo/attributes/TestWithType.ql | 2 +- .../class_properties/ClassValues.expected | 13 + .../PointsTo/class_properties/ClassValues.ql | 20 + .../PointsTo/class_properties/options | 1 + .../PointsTo/class_properties/test.py | 50 + .../PointsTo/consts/BooleanConstants.ql | 6 +- .../PointsTo/import_time/Pruned.ql | 6 +- .../subprocess-assert/ClassValue.ql | 10 +- .../PointsTo/typehints/Values.ql | 4 +- .../library-tests/classes/attr/class_attr.ql | 8 +- .../classes/attr/class_has_attr.ql | 8 +- .../test/3/library-tests/classes/mro/mro.ql | 4 +- .../3/library-tests/classes/mro/mro_index.ql | 4 +- .../functions/Function.getAChildNode.expected | 16 + .../functions/Function.getAChildNode.ql | 4 + .../functions/Function.getArg.expected | 5 + .../functions/Function.getArg.ql | 4 + .../functions/Function.getArgByName.expected | 9 + .../functions/Function.getArgByName.ql | 4 + .../FunctionExpr.getASubExpression.expected | 13 + .../FunctionExpr.getASubExpression.ql | 4 + ...unctionExpr.getArgs.getAnnotation.expected | 3 + .../FunctionExpr.getArgs.getAnnotation.ql | 4 + .../FunctionExpr.getArgs.getDefault.expected | 4 + .../FunctionExpr.getArgs.getDefault.ql | 4 + ...ctionExpr.getArgs.getKwAnnotation.expected | 2 + .../FunctionExpr.getArgs.getKwAnnotation.ql | 4 + ...FunctionExpr.getArgs.getKwDefault.expected | 2 + .../FunctionExpr.getArgs.getKwDefault.ql | 4 + .../ql/test/3/library-tests/functions/test.py | 43 + .../locations/general/AllLocations.ql | 6 +- .../modules/general/import_test.ql | 8 +- .../parameters/Annotations.expected | 7 + .../3/library-tests/parameters/Annotations.ql | 4 + .../parameters/Defaults.expected | 6 + .../3/library-tests/parameters/Defaults.ql | 4 + .../library-tests/parameters/Special.expected | 11 + .../3/library-tests/parameters/Special.ql | 10 + .../test/3/library-tests/parameters/test.py | 43 + .../ql/test/3/library-tests/six/pointsto.ql | 6 +- .../3/library-tests/taint/strings/Taint.qll | 44 + .../taint/strings/TestTaint.expected | 1 + .../library-tests/taint/strings/TestTaint.ql | 33 + .../3/library-tests/taint/strings/test.py | 5 + .../3/library-tests/taint/unpacking/Taint.qll | 18 +- .../taint/unpacking/TestTaint.ql | 22 +- .../library-tests/types/exceptions/Raises.ql | 14 +- .../library-tests/types/exceptions/Viable.ql | 2 +- .../types/namespaces/NameSpace.ql | 22 +- .../types/properties/BuiltinProperties.ql | 6 +- .../TestUtilities/InlineExpectationsTest.qll | 290 + .../InlineExpectationsTestPrivate.qll | 7 + .../dataflow/basic/allFlowsConfig.qll | 13 + .../dataflow/basic/callGraph.expected | 3 + .../experimental/dataflow/basic/callGraph.ql | 5 + .../dataflow/basic/callGraphSinks.expected | 2 + .../dataflow/basic/callGraphSinks.ql | 5 + .../dataflow/basic/callGraphSources.expected | 2 + .../dataflow/basic/callGraphSources.ql | 5 + .../dataflow/basic/global.expected | 58 + .../experimental/dataflow/basic/global.ql | 7 + .../dataflow/basic/globalStep.expected | 80 + .../experimental/dataflow/basic/globalStep.ql | 5 + .../dataflow/basic/local.expected | 48 + .../test/experimental/dataflow/basic/local.ql | 5 + .../dataflow/basic/localStep.expected | 10 + .../experimental/dataflow/basic/localStep.ql | 5 + .../dataflow/basic/maximalFlows.expected | 8 + .../dataflow/basic/maximalFlows.ql | 7 + .../dataflow/basic/maximalFlowsConfig.qll | 24 + .../dataflow/basic/sinks.expected | 26 + .../test/experimental/dataflow/basic/sinks.ql | 5 + .../dataflow/basic/sources.expected | 26 + .../experimental/dataflow/basic/sources.ql | 5 + .../test/experimental/dataflow/basic/test.py | 7 + .../experimental/dataflow/callGraphConfig.qll | 22 + .../consistency/dataflow-consistency.expected | 18 + .../consistency/dataflow-consistency.ql | 1 + .../dataflow/consistency/module.py | 10 + .../experimental/dataflow/consistency/test.py | 237 + .../dataflow/coverage/argumentPassing.py | 211 + .../coverage/argumentRouting1.expected | 34 + .../dataflow/coverage/argumentRouting1.ql | 35 + .../coverage/argumentRouting2.expected | 25 + .../dataflow/coverage/argumentRouting2.ql | 27 + .../coverage/argumentRouting3.expected | 8 + .../dataflow/coverage/argumentRouting3.ql | 27 + .../coverage/argumentRouting4.expected | 0 .../dataflow/coverage/argumentRouting4.ql | 27 + .../experimental/dataflow/coverage/classes.py | 1605 ++ .../coverage/classesCallGraph.expected | 39 + .../dataflow/coverage/classesCallGraph.ql | 37 + .../dataflow/coverage/dataflow.expected | 454 + .../dataflow/coverage/dataflow.ql | 11 + .../dataflow/coverage/datamodel.py | 159 + .../dataflow/coverage/localFlow.expected | 15 + .../dataflow/coverage/localFlow.ql | 8 + .../experimental/dataflow/coverage/test.py | 582 + .../experimental/dataflow/coverage/testlib.py | 27 + .../dataflow/coverage/validTest.py | 55 + .../dataflow/fieldflow/allLocalFlow.expected | 159 + .../dataflow/fieldflow/allLocalFlow.ql | 8 + .../dataflow/fieldflow/dataflow.expected | 137 + .../dataflow/fieldflow/dataflow.ql | 10 + .../dataflow/fieldflow/examples.py | 59 + .../dataflow/fieldflow/globalStep.expected | 1075 ++ .../dataflow/fieldflow/globalStep.ql | 7 + .../dataflow/fieldflow/localFlow.expected | 12 + .../dataflow/fieldflow/localFlow.ql | 8 + .../dataflow/fieldflow/postupdates.expected | 80 + .../dataflow/fieldflow/postupdates.ql | 4 + .../experimental/dataflow/fieldflow/test.py | 97 + .../dataflow/global-flow/accesses.expected | 0 .../dataflow/global-flow/accesses.ql | 36 + .../dataflow/global-flow/known.py | 1 + .../experimental/dataflow/global-flow/test.py | 121 + .../import-helper/ImportHelper.expected | 27 + .../dataflow/import-helper/ImportHelper.ql | 4 + .../dataflow/import-helper/README.md | 1 + .../dataflow/import-helper/mypkg/__init__.py | 1 + .../dataflow/import-helper/mypkg/bar.py | 1 + .../dataflow/import-helper/mypkg/foo.py | 1 + .../dataflow/import-helper/test1.py | 6 + .../dataflow/import-helper/test2.py | 3 + .../dataflow/import-helper/test3.py | 4 + .../dataflow/import-helper/test4.py | 4 + .../dataflow/import-helper/test5.py | 10 + .../dataflow/import-helper/test6.py | 6 + .../dataflow/import-helper/test7.py | 10 + python/ql/test/experimental/dataflow/options | 1 + .../regression/custom_dataflow.expected | 1 + .../dataflow/regression/custom_dataflow.ql | 30 + .../dataflow/regression/dataflow.expected | 19 + .../dataflow/regression/dataflow.ql | 13 + .../dataflow/regression/module.py | 10 + .../experimental/dataflow/regression/test.py | 214 + .../dataflow/strange-essaflow/test.py | 11 + .../strange-essaflow/testFlow.expected | 6 + .../dataflow/strange-essaflow/testFlow.ql | 37 + .../dataflow/tainttracking/TestTaintLib.qll | 74 + .../basic/GlobalTaintTracking.expected | 2 + .../basic/GlobalTaintTracking.ql | 22 + .../basic/LocalTaintStep.expected | 5 + .../tainttracking/basic/LocalTaintStep.ql | 7 + .../dataflow/tainttracking/basic/test.py | 8 + .../customSanitizer/TestTaint.expected | 11 + .../customSanitizer/TestTaint.ql | 33 + .../tainttracking/customSanitizer/test.py | 58 + .../TestTaint.expected | 34 + .../TestTaint.ql | 1 + .../defaultAdditionalTaintStep-py3/options | 1 + .../test_collections.py | 32 + .../test_pathlib.py | 60 + .../test_string.py | 55 + .../test_unpacking.py | 46 + .../TestTaint.expected | 176 + .../defaultAdditionalTaintStep/TestTaint.ql | 1 + .../test_collections.py | 254 + .../defaultAdditionalTaintStep/test_json.py | 64 + .../defaultAdditionalTaintStep/test_string.py | 173 + .../test_unpacking.py | 75 + .../defaultSanitizer/TestTaint.expected | 37 + .../defaultSanitizer/TestTaint.ql | 1 + .../defaultSanitizer/test_logical.py | 138 + .../defaultSanitizer/test_string_eq.py | 56 + .../dataflow/tainttracking/taintlib.py | 17 + .../unwanted-global-flow/test.py | 54 + .../unwanted-global-flow/testTaint.expected | 6 + .../unwanted-global-flow/testTaint.ql | 1 + .../test/experimental/dataflow/testConfig.qll | 48 + .../dataflow/typetracking/attribute_tests.py | 101 + .../dataflow/typetracking/import_as_attr.py | 9 + .../typetracking/import_as_attr_dotted.py | 9 + .../dataflow/typetracking/moduleattr.expected | 10 + .../dataflow/typetracking/moduleattr.ql | 23 + .../dataflow/typetracking/mymodule.py | 4 + .../dataflow/typetracking/test.py | 70 + .../dataflow/typetracking/tracked.expected | 0 .../dataflow/typetracking/tracked.ql | 75 + .../CallGraph-implicit-init/PointsTo.expected | 6 + .../CallGraph-implicit-init/PointsTo.qlref | 1 + .../CallGraph-implicit-init/Relative.expected | 6 + .../CallGraph-implicit-init/Relative.qlref | 1 + .../TypeTracker.expected | 7 + .../CallGraph-implicit-init/TypeTracker.qlref | 1 + .../CallGraph-implicit-init/example.py | 22 + .../CallGraph-implicit-init/foo/bar/a.py | 4 + .../foo_explicit/__init__.py | 0 .../foo_explicit/bar/__init__.py | 0 .../foo_explicit/bar/a.py | 4 + .../CallGraph-implicit-init/options | 1 + .../CallGraph-xfail/PointsTo.expected | 18 + .../CallGraph-xfail/PointsTo.qlref | 1 + .../library-tests/CallGraph-xfail/README.md | 1 + .../CallGraph-xfail/annotation_xfail.py | 21 + .../CallGraph-xfail/call_edge_xfail.py | 43 + .../library-tests/CallGraph/CallGraphTest.qll | 147 + .../library-tests/CallGraph/PointsTo.expected | 6 + .../library-tests/CallGraph/PointsTo.ql | 10 + .../library-tests/CallGraph/README.md | 38 + .../library-tests/CallGraph/Relative.expected | 20 + .../library-tests/CallGraph/Relative.ql | 14 + .../CallGraph/TypeTracker.expected | 21 + .../library-tests/CallGraph/TypeTracker.ql | 10 + .../library-tests/CallGraph/code/__init__.py | 0 .../CallGraph/code/class_advanced.py | 40 + .../CallGraph/code/class_simple.py | 37 + .../CallGraph/code/runtime_decision.py | 30 + .../library-tests/CallGraph/code/simple.py | 27 + .../code/underscore_prefix_func_name.py | 28 + .../library-tests/CallGraph/test.py | 3 + .../frameworks/dill/ConceptsTest.expected | 0 .../frameworks/dill/ConceptsTest.ql | 2 + .../library-tests/frameworks/dill/Decoding.py | 3 + .../frameworks/flask/ConceptsTest.expected | 0 .../frameworks/flask/ConceptsTest.ql | 2 + .../frameworks/flask/TestTaint.expected | 98 + .../frameworks/flask/TestTaint.ql | 6 + .../frameworks/flask/old_test.py | 67 + .../frameworks/flask/routing_test.py | 31 + .../frameworks/flask/taint_test.py | 273 + .../frameworks/invoke/ConceptsTest.expected | 0 .../frameworks/invoke/ConceptsTest.ql | 2 + .../frameworks/invoke/invoke_test.py | 39 + .../modeling-example/NaiveModel.expected | 35 + .../frameworks/modeling-example/NaiveModel.ql | 24 + .../modeling-example/ProperModel.expected | 67 + .../modeling-example/ProperModel.ql | 26 + .../frameworks/modeling-example/README.md | 29 + .../modeling-example/SharedCode.qll | 36 + .../frameworks/modeling-example/test.py | 108 + .../frameworks/stdlib-py2/CodeExecution.py | 2 + .../stdlib-py2/ConceptsTest.expected | 0 .../frameworks/stdlib-py2/ConceptsTest.ql | 2 + .../stdlib-py2/SystemCommandExecution.py | 36 + .../frameworks/stdlib-py2/options | 1 + .../frameworks/stdlib-py3/CodeExecution.py | 4 + .../stdlib-py3/ConceptsTest.expected | 0 .../frameworks/stdlib-py3/ConceptsTest.ql | 2 + .../frameworks/stdlib-py3/options | 1 + .../frameworks/stdlib/CodeExecution.py | 39 + .../stdlib/CodeExecutionPossibleFP1.py | 11 + .../stdlib/CodeExecutionPossibleFP2.py | 13 + .../stdlib/CodeExecutionPossibleFP3.py | 19 + .../frameworks/stdlib/ConceptsTest.expected | 0 .../frameworks/stdlib/ConceptsTest.ql | 2 + .../frameworks/stdlib/Decoding.py | 5 + .../stdlib/SystemCommandExecution.py | 141 + .../frameworks/stdlib/TestTaint.expected | 4 + .../frameworks/stdlib/TestTaint.ql | 2 + .../frameworks/yaml/ConceptsTest.expected | 0 .../frameworks/yaml/ConceptsTest.ql | 2 + .../library-tests/frameworks/yaml/Decoding.py | 6 + .../test/experimental/library-tests/options | 1 + .../test/experimental/meta/ConceptsTest.qll | 127 + .../test/experimental/meta/debug/dataflow.qll | 18 + .../CWE-078-py2/CommandInjection.expected | 31 + .../CWE-078-py2/CommandInjection.qlref | 1 + .../CWE-078-py2/command_injection.py | 29 + .../Security-new-dataflow/CWE-078-py2/options | 1 + .../CWE-078/CommandInjection.expected | 42 + .../CWE-078/CommandInjection.qlref | 1 + .../CWE-078/command_injection.py | 57 + .../CWE-094/CodeInjection.expected | 13 + .../CWE-094/CodeInjection.qlref | 1 + .../CWE-094/code_injection.py | 10 + .../CWE-502/UnsafeDeserialization.expected | 16 + .../CWE-502/UnsafeDeserialization.qlref | 1 + .../CWE-502/unsafe_deserialization.py | 21 + .../Security/CWE-074/AirspeedSsti.py | 11 + .../Security/CWE-074/BottleSsti.py | 20 + .../query-tests/Security/CWE-074/Chameleon.py | 10 + .../Security/CWE-074/ChevronSsti.py | 24 + .../Security/CWE-074/DjangoTemplates.py | 41 + .../Security/CWE-074/FlaskTemplate.py | 22 + .../query-tests/Security/CWE-074/Genshi.py | 18 + .../query-tests/Security/CWE-074/JinjaSsti.py | 30 + .../query-tests/Security/CWE-074/MakoSsti.py | 15 + .../query-tests/Security/CWE-074/TRender.py | 12 + .../CWE-074/TemplateInjection.expected | 60 + .../Security/CWE-074/TemplateInjection.qlref | 1 + .../query-tests/Security/CWE-074/options | 1 + .../Security/CWE-091/Xslt.expected | 47 + .../query-tests/Security/CWE-091/Xslt.qlref | 1 + .../Security/CWE-091/XsltSinks.expected | 12 + .../query-tests/Security/CWE-091/XsltSinks.ql | 6 + .../query-tests/Security/CWE-091/options | 1 + .../query-tests/Security/CWE-091/xslt.py | 14 + .../Security/CWE-091/xsltInjection.py | 79 + .../query-tests/Security/CWE-091/xsltSinks.py | 56 + .../query-tests/Security/CWE-643/options | 1 + .../Security/CWE-643/xpath.expected | 38 + .../query-tests/Security/CWE-643/xpath.py | 40 + .../query-tests/Security/CWE-643/xpath.qlref | 1 + .../query-tests/Security/CWE-643/xpathBad.py | 18 + .../query-tests/Security/CWE-643/xpathFlow.py | 49 + .../query-tests/Security/CWE-643/xpathGood.py | 18 + .../Security/CWE-643/xpathSinks.expected | 12 + .../Security/CWE-643/xpathSinks.ql | 7 + .../ql/test/experimental/query-tests/options | 1 + .../semmle/python/templates/Airspeed.py | 10 + .../templates/AirspeedSSTISinks.expected | 1 + .../python/templates/AirspeedSSTISinks.ql | 5 + .../semmle/python/templates/Bottle.py | 17 + .../python/templates/BottleSSTISinks.expected | 2 + .../python/templates/BottleSSTISinks.ql | 5 + .../semmle/python/templates/Chameleon.py | 5 + .../templates/ChameleonSSTISinks.expected | 1 + .../python/templates/ChameleonSSTISinks.ql | 5 + .../templates/CheetahSSTISinks.expected | 2 + .../python/templates/CheetahSSTISinks.ql | 5 + .../semmle/python/templates/CheetahSinks.py | 20 + .../templates/ChevronSSTISinks.expected | 1 + .../python/templates/ChevronSSTISinks.ql | 5 + .../semmle/python/templates/ChevronSinks.py | 22 + .../python/templates/DjangoSSTISinks.expected | 1 + .../python/templates/DjangoSSTISinks.ql | 5 + .../python/templates/DjangoTemplates.py | 39 + .../semmle/python/templates/Genshi.py | 10 + .../python/templates/GenshiSSTISinks.expected | 2 + .../python/templates/GenshiSSTISinks.ql | 5 + .../python/templates/Jinja2Templates.py | 17 + .../python/templates/JinjaSSTISinks.expected | 3 + .../semmle/python/templates/JinjaSSTISinks.ql | 5 + .../semmle/python/templates/Mako.py | 5 + .../python/templates/MakoSSTISinks.expected | 1 + .../semmle/python/templates/MakoSSTISinks.ql | 5 + .../semmle/python/templates/TRender.py | 6 + .../templates/TRenderSSTISinks.expected | 1 + .../python/templates/TRenderSSTISinks.ql | 5 + .../semmle/python/templates/options | 1 + .../PointsToSupport/UseFromDefinition.ql | 12 +- .../ControlFlow/augassign/AugAssignFlow.ql | 6 +- .../ControlFlow/augassign/Kind.ql | 14 +- .../ControlFlow/comparison/Compare.ql | 12 +- .../library-tests/ControlFlow/delete/test.ql | 2 +- ...expected => DominatesConsistency.expected} | 0 .../dominators/DominatesConsistency.ql | 8 + .../ControlFlow/dominators/DominatesSanity.ql | 8 - .../ControlFlow/dominators/idom.ql | 4 +- .../general/ImmediateDominatorCheck.ql | 20 +- .../ControlFlow/general/Lines.ql | 6 +- .../ControlFlow/general/Reaches.ql | 8 +- .../ControlFlow/raising_stmts/RaisingFlow.ql | 10 +- .../ControlFlow/splitting/NodeCount.ql | 12 +- .../ControlFlow/splitting/SuccessorCount.ql | 6 +- .../ControlFlow/ssa/defns/test.ql | 2 +- .../ControlFlow/ssa/deletions/test.ql | 16 +- .../ssa/phi-nodes/phi_input_test.ql | 2 +- .../ControlFlow/ssa/phi-nodes/test.ql | 2 +- .../ControlFlow/ssa/uses/test.ql | 2 +- .../ControlFlow/successors/Successors.ql | 22 +- .../truefalse/ExceptionalSuccessors.ql | 8 +- .../truefalse/TrueFalseSuccessors.ql | 8 +- .../library-tests/ControlFlow/try/test_ssa.ql | 2 +- .../library-tests/DuplicateCode/Duplicate.ql | 14 +- .../DuplicateCode/DuplicateStatements.ql | 20 +- .../library-tests/DuplicateCode/Similar.ql | 12 +- .../library-tests/PointsTo/api/ClassValue.ql | 18 +- .../library-tests/PointsTo/api/Constants.ql | 20 +- .../PointsTo/api/QualifedNames.ql | 20 +- .../test/library-tests/PointsTo/api/Value.ql | 16 +- .../PointsTo/calls/getArgumentForCall.ql | 2 +- .../PointsTo/calls/getNamedArgumentForCall.ql | 2 +- .../PointsTo/comparisons/PointsTo.ql | 6 +- .../library-tests/PointsTo/customise/test.ql | 40 +- .../library-tests/PointsTo/decorators/Test.ql | 6 +- .../PointsTo/decorators/Values.ql | 4 +- .../PointsTo/extensions/Extend.ql | 74 +- .../library-tests/PointsTo/functions/Calls.ql | 12 +- .../library-tests/PointsTo/functions/test.ql | 4 +- .../PointsTo/general/GlobalPointsTo.ql | 6 +- .../PointsTo/general/LocalPointsTo.ql | 4 +- .../PointsTo/general/LocalPointsToType.ql | 4 +- .../library-tests/PointsTo/general/Util.qll | 12 +- .../PointsTo/general/interesting.qll | 16 +- .../library-tests/PointsTo/global/Global.ql | 4 +- .../PointsTo/guarded/PointsTo.ql | 6 +- .../PointsTo/guarded/PointsToWithType.ql | 6 +- .../PointsTo/import_star/Values.expected | 2 +- .../library-tests/PointsTo/imports/Runtime.ql | 8 +- .../PointsTo/imports/RuntimeWithType.ql | 10 +- .../library-tests/PointsTo/indexing/Test.ql | 4 +- .../PointsTo/indexing/TestWithType.ql | 6 +- .../PointsTo/inheritance/BaseTypes.ql | 4 +- .../PointsTo/inheritance/MetaClass.ql | 4 +- .../library-tests/PointsTo/inheritance/Mro.ql | 2 +- .../PointsTo/inheritance/SuperTypes.ql | 4 +- .../PointsTo/local/LocalPointsTo.ql | 4 +- .../library-tests/PointsTo/lookup/Lookup.ql | 16 +- .../PointsTo/metaclass/Failed.ql | 4 +- .../library-tests/PointsTo/metaclass/Mro.ql | 2 +- .../library-tests/PointsTo/metaclass/Style.ql | 12 +- .../library-tests/PointsTo/metaclass/test.ql | 2 +- .../library-tests/PointsTo/new/ClassMethod.ql | 2 +- .../PointsTo/new/Consistency.expected | 0 .../library-tests/PointsTo/new/Consistency.ql | 146 + .../library-tests/PointsTo/new/Dataflow.ql | 2 +- .../test/library-tests/PointsTo/new/Live.ql | 6 +- .../library-tests/PointsTo/new/NameSpace.ql | 22 +- .../PointsTo/new/PointsToMissing.ql | 26 +- .../PointsTo/new/PointsToWithContext.ql | 2 +- .../PointsTo/new/PointsToWithType.ql | 2 +- .../library-tests/PointsTo/new/Precedes.ql | 2 +- .../library-tests/PointsTo/new/SSA.expected | 2 +- .../ql/test/library-tests/PointsTo/new/SSA.ql | 8 +- .../test/library-tests/PointsTo/new/Sanity.ql | 146 - .../PointsTo/new/SourceNodeDefinitions.ql | 12 +- .../library-tests/PointsTo/new/SsaAttr.ql | 6 +- .../PointsTo/new/TestEvaluate.ql | 22 +- .../test/library-tests/PointsTo/new/Util.qll | 68 +- .../test/library-tests/PointsTo/new/Values.ql | 2 +- .../library-tests/PointsTo/new/VarUses.ql | 4 +- .../PointsTo/new/code/b_condition.py | 2 +- .../PointsTo/new/code/c_tests.py | 2 +- .../PointsTo/properties/Values.ql | 8 +- .../missing/if-urlsplit-access/Test.ql | 10 +- .../missing/metaclass/getACall.expected | 1 + .../regressions/missing/metaclass/getACall.ql | 4 + .../regressions/missing/metaclass/test.py | 25 + .../regressions/missing/re-compile/Test.ql | 10 +- .../missing/uncalled-function/Test.ql | 10 +- .../regressions/wrong/classmethod/Test.ql | 10 +- .../PointsTo/subclass/TestEvaluate.ql | 8 +- .../PointsTo/super/SuperMethodCall.ql | 6 +- .../library-tests/attributes/SelfAttribute.ql | 6 +- .../classes/abstract/Abstract.ql | 4 +- .../library-tests/classes/attr/class_attr.ql | 8 +- .../classes/attr/class_defined_attr.ql | 8 +- .../classes/attr/class_defines_attr.ql | 8 +- .../classes/attr/class_has_attr.ql | 8 +- .../test/library-tests/classes/attr/hash.ql | 10 +- .../ql/test/library-tests/comments/length.ql | 4 +- .../library-tests/comparisons/Compare2.ql | 12 +- .../comparisons/CompareControls.ql | 2 +- .../dependencies/Dependencies.ql | 2 +- .../library-tests/descriptors/Descriptors.ql | 8 +- .../test/library-tests/descriptors/Methods.ql | 6 +- .../library-tests/descriptors/Properties.ql | 10 +- .../library-tests/encoding/CheckEncoding.ql | 6 +- .../examples/custom-sanitizer/Taint.qll | 80 +- .../examples/custom-sanitizer/TestTaint.ql | 44 +- .../ql/test/library-tests/exceptions/Legal.ql | 10 +- .../test/library-tests/exprs/ast/AstParent.ql | 2 +- .../library-tests/filters/generated/Filter.ql | 6 +- .../formatting/FormatArguments.ql | 6 +- .../jump_to_defn/Consistency.expected | 0 .../library-tests/jump_to_defn/Consistency.ql | 21 + .../test/library-tests/jump_to_defn/Remote.ql | 6 +- .../test/library-tests/jump_to_defn/Sanity.ql | 21 - .../test/library-tests/jump_to_defn/test.ql | 4 +- .../implicit_concatenation/part_locations.ql | 4 +- .../locations/implicit_concatenation/parts.ql | 2 +- .../locations/implicit_concatenation/test.ql | 10 +- .../locations/negative_numbers/negative.ql | 4 +- .../modules/usage/ModuleUsage.ql | 22 +- .../ql/test/library-tests/objects/Literals.ql | 6 +- python/ql/test/library-tests/objects/Name.ql | 32 +- .../overrides/FunctionOverrides.ql | 4 +- .../test/library-tests/parameters/Special.ql | 10 +- .../test/library-tests/regex/Alternation.ql | 2 +- .../library-tests/regex/Characters.expected | 1 - .../library-tests/regex/FirstLast.expected | 2 + .../ql/test/library-tests/regex/FirstLast.ql | 6 +- .../test/library-tests/regex/GroupContents.ql | 2 +- .../library-tests/regex/Qualified.expected | 1 + .../test/library-tests/regex/Regex.expected | 2 +- python/ql/test/library-tests/regex/Regex.ql | 30 +- python/ql/test/library-tests/regex/test.py | 4 + .../security/fabric-v1-execute/Taint.qll | 18 +- .../security/fabric-v1-execute/TestTaint.ql | 45 +- .../test/library-tests/state_tracking/Lib.qll | 10 +- .../test/library-tests/state_tracking/Test.ql | 12 +- .../state_tracking/Violations.ql | 12 +- .../library-tests/stmts/general/AstParent.ql | 2 +- .../stmts/general/SubExpressions.ql | 2 +- .../library-tests/stmts/raise_stmt/AST.ql | 2 +- .../test/library-tests/stmts/try_stmt/AST.ql | 2 +- .../test/library-tests/stmts/with_stmt/AST.ql | 2 +- .../library-tests/taint/collections/Taint.qll | 18 +- .../taint/collections/TestStep.ql | 8 +- .../taint/collections/TestTaint.ql | 22 +- .../taint/config/RockPaperScissors.ql | 2 +- .../test/library-tests/taint/config/Simple.ql | 2 +- .../library-tests/taint/config/TaintLib.qll | 294 +- .../taint/config/TaintedArgument.ql | 8 +- .../library-tests/taint/config/TestNode.ql | 2 +- .../library-tests/taint/config/TestSource.ql | 2 +- .../library-tests/taint/config/TestStep.ql | 4 +- .../library-tests/taint/dataflow/Config.qll | 16 +- .../library-tests/taint/dataflow/TestNode.ql | 2 +- .../taint/example/DilbertConfig.qll | 52 +- .../test/library-tests/taint/example/Edges.ql | 40 +- .../taint/example/ExampleConfig.ql | 2 +- .../test/library-tests/taint/example/Nodes.ql | 2 +- .../taint/exception_traceback/TestSource.ql | 4 +- .../taint/exception_traceback/TestStep.ql | 10 +- .../taint/extensions/ExtensionsLib.qll | 92 +- .../taint/extensions/TestNode.ql | 2 +- .../taint/extensions/TestStep.expected | 2 +- .../taint/extensions/TestStep.ql | 4 +- .../taint/flowpath_regression/Config.qll | 44 +- .../taint/general/Contexts.expected | 2 +- .../library-tests/taint/general/Contexts.ql | 4 +- .../taint/general/ParamSource.ql | 36 +- .../taint/general/TaintConsistency.expected | 0 .../taint/general/TaintConsistency.ql | 29 + .../library-tests/taint/general/TaintLib.qll | 340 +- .../taint/general/TaintSanity.ql | 29 - .../library-tests/taint/general/TestDefn.ql | 2 +- .../library-tests/taint/general/TestSink.ql | 2 +- .../library-tests/taint/general/TestStep.ql | 2 +- .../library-tests/taint/general/TestTaint.ql | 22 +- .../library-tests/taint/general/TestVar.ql | 2 +- .../library-tests/taint/namedtuple/Taint.qll | 42 +- .../taint/namedtuple/TestTaint.ql | 22 +- .../library-tests/taint/strings/Taint.qll | 30 +- .../library-tests/taint/strings/TestStep.ql | 8 +- .../library-tests/taint/strings/TestTaint.ql | 22 +- .../library-tests/taint/unpacking/Taint.qll | 18 +- .../library-tests/taint/unpacking/TestStep.ql | 8 +- .../taint/unpacking/TestTaint.ql | 22 +- .../ql/test/library-tests/thrift/Function.ql | 10 +- .../library-tests/types/attributes/Test.ql | 2 +- .../types/classattr/ClassAttribute.ql | 14 +- .../types/classattr/ClassMember.ql | 14 +- .../types/classattr/SpecialAttribute.ql | 16 +- .../types/exceptions/Impossible.ql | 28 +- .../types/exceptions/LineRaises.ql | 14 +- .../library-tests/types/exceptions/Raises.ql | 14 +- .../library-tests/types/exceptions/Viable.ql | 2 +- .../library-tests/variables/scopes/free.ql | 6 +- .../library-tests/variables/scopes/locals.ql | 6 +- .../library-tests/variables/scopes/lookup.ql | 26 +- .../web/django/HttpRedirectSinks.expected | 6 +- .../web/django/HttpResponseSinks.expected | 8 + .../test/library-tests/web/django/views_1x.py | 30 +- .../library-tests/web/django/views_2x_3x.py | 40 +- .../library-tests/web/stdlib/HttpSources.ql | 4 +- .../library-tests/web/stdlib/TestTaint.ql | 44 +- python/ql/test/library-tests/web/zope/Test.ql | 8 +- .../Regex/DuplicateCharacterInSet.expected | 6 +- .../Regex/UnmatchableCaret.expected | 2 +- .../Regex/UnmatchableDollar.expected | 2 +- .../query-tests/Expressions/Regex/test.py | 24 +- .../Imports/general/ImportStarUsed.expected | 1 + .../Imports/general/imports_test.py | 2 + .../query-tests/Metrics/ratios/CodeRatio.ql | 2 +- .../ql/test/query-tests/Resources/Dataflow.ql | 16 +- .../query-tests/Security/CWE-020/hosttest.py | 4 + .../query-tests/Security/CWE-020/urltest.py | 6 +- .../CWE-078/CommandInjection.expected | 10 +- .../Security/CWE-078/command_injection.py | 2 +- .../test/query-tests/Security/lib/airspeed.py | 3 + .../Security/lib/cheetah/Template/__init__.py | 2 + .../test/query-tests/Security/lib/chevron.py | 6 + .../Security/lib/django/http/__init__.py | 2 +- .../Security/lib/django/http/response.py | 48 +- .../Security/lib/flask/__init__.py | 3 + .../test/query-tests/Security/lib/jinja2.py | 3 + .../Security/lib/libxml2/__init__.py | 10 + .../query-tests/Security/lib/lxml/__init__.py | 0 .../query-tests/Security/lib/lxml/etree.py | 37 + .../analysis/Consistency/Consistency.expected | 0 .../analysis/Consistency/Consistency.qlref | 1 + .../package/__init__.py | 0 .../analysis/{Sanity => Consistency}/test.py | 0 .../query-tests/analysis/Sanity/Sanity.qlref | 1 - .../tools/recorded-call-graph-metrics/.flake8 | 6 + .../recorded-call-graph-metrics/.gitignore | 13 + .../recorded-call-graph-metrics/.isort.cfg | 6 + .../recorded-call-graph-metrics/README.md | 116 + .../example/simple.py | 10 + .../example/simple.xml | 137 + .../recorded-call-graph-metrics/helper.sh | 191 + .../recorded-call-graph-metrics/projects.json | 28 + .../ql/lib/BytecodeExpr.qll | 73 + .../ql/lib/RecordedCalls.qll | 269 + .../recorded-call-graph-metrics/ql/qlpack.yml | 4 + .../ql/query/InternalMetrics.ql | 17 + .../ql/query/Metrics.ql | 56 + .../ql/query/PointsToFound.ql | 4 + .../ql/query/PointsToNotFound.ql | 5 + .../ql/query/UnidentifiedRecordedCalls.ql | 23 + .../ql/query/UnknownOpcode.ql | 9 + .../requirements.txt | 5 + .../recorded-call-graph-metrics/setup.py | 14 + .../src/cg_trace/__init__.py | 15 + .../src/cg_trace/__main__.py | 5 + .../src/cg_trace/bytecode_reconstructor.py | 275 + .../src/cg_trace/cmdline.py | 22 + .../src/cg_trace/exporter.py | 46 + .../cg_trace/generate_bytecode_expr_qll.py | 46 + .../src/cg_trace/main.py | 118 + .../src/cg_trace/settings.py | 6 + .../src/cg_trace/tracer.py | 333 + .../src/cg_trace/utils.py | 20 + .../tests/create-test-db.sh | 32 + .../tests/python-src/BUILD_LIST.py | 9 + .../tests/python-src/BUILD_TUPLE.py | 9 + .../tests/python-src/CALL_FUNCTION_EX.py | 15 + .../tests/python-src/__getitem__.py | 7 + .../tests/python-src/builtins.py | 9 + .../tests/python-src/class-simple.py | 44 + .../tests/python-src/dict-get.py | 3 + .../tests/python-src/getsockname.py | 4 + .../tests/python-src/io-builtin.py | 4 + .../tests/python-src/iteration.py | 7 + .../tests/python-src/multiple-on-one-line.py | 37 + .../tests/python-src/problem-1.py | 26 + .../tests/python-src/problem-2.py | 25 + .../tests/python-src/simple.py | 10 + .../tests/python-src/with-exit.py | 5 + .../old.dbscheme | 988 ++ .../py_exprs.ql | 161 + .../semmlecode.python.dbscheme | 999 ++ .../upgrade.properties | 3 + 4182 files changed, 251309 insertions(+), 82502 deletions(-) create mode 100644 .github/codeql/codeql-config.yml create mode 100644 .github/workflows/codeql-analysis.yml create mode 100644 .github/workflows/labeler.yml create mode 100644 .github/workflows/query-list.yml create mode 100644 .vscode/settings.json create mode 100644 change-notes/1.26/analysis-cpp.md create mode 100644 change-notes/1.26/analysis-csharp.md create mode 100644 change-notes/1.26/analysis-java.md create mode 100644 change-notes/1.26/analysis-javascript.md create mode 100644 change-notes/1.26/analysis-python.md create mode 100644 config/opcode-qldoc.py create mode 100644 cpp/autobuilder/.gitignore create mode 100644 cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/BuildScripts.cs create mode 100644 cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/Semmle.Autobuild.Cpp.Tests.csproj create mode 100644 cpp/autobuilder/Semmle.Autobuild.Cpp/CppAutobuilder.cs rename {csharp/autobuilder/Semmle.Autobuild => cpp/autobuilder/Semmle.Autobuild.Cpp}/Program.cs (72%) rename {csharp/autobuilder/Semmle.Autobuild.Tests => cpp/autobuilder/Semmle.Autobuild.Cpp}/Properties/AssemblyInfo.cs (83%) create mode 100644 cpp/autobuilder/Semmle.Autobuild.Cpp/Semmle.Autobuild.Cpp.csproj create mode 100644 cpp/change-notes/2020-09-29-range-analysis-rollup.md create mode 100644 cpp/ql/examples/qlpack.yml create mode 100644 cpp/ql/src/Critical/aliasAnalysisWarning.qhelp create mode 100644 cpp/ql/src/Critical/callGraphWarning.qhelp create mode 100644 cpp/ql/src/Critical/dataFlowWarning.qhelp create mode 100644 cpp/ql/src/Critical/pointsToWarning.qhelp create mode 100644 cpp/ql/src/Documentation/CommentedOutCodeQuery.qhelp create mode 100644 cpp/ql/src/Metrics/Files/CommentedOutCodeMetricOverview.qhelp create mode 100644 cpp/ql/src/Metrics/Files/CommentedOutCodeReferences.qhelp create mode 100644 cpp/ql/src/Metrics/Files/DuplicationProblems.qhelp create mode 100644 cpp/ql/src/Metrics/Files/FLinesOfDuplicatedCodeCommon.qhelp create mode 100644 cpp/ql/src/codeql-suites/cpp-security-and-quality.qls create mode 100644 cpp/ql/src/codeql-suites/cpp-security-extended.qls create mode 100644 cpp/ql/src/codeql-suites/exclude-slow-queries.yml create mode 100644 cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.cpp create mode 100644 cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.qhelp create mode 100644 cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql create mode 100644 cpp/ql/src/experimental/Security/CWE/CWE-120/MemoryUnsafeFunctionScan.cpp create mode 100644 cpp/ql/src/experimental/Security/CWE/CWE-120/MemoryUnsafeFunctionScan.qhelp create mode 100644 cpp/ql/src/experimental/Security/CWE/CWE-120/MemoryUnsafeFunctionScan.ql create mode 100644 cpp/ql/src/experimental/Security/CWE/CWE-359/PrivateCleartextWrite.qhelp create mode 100644 cpp/ql/src/experimental/Security/CWE/CWE-359/PrivateCleartextWrite.ql create mode 100644 cpp/ql/src/experimental/semmle/code/cpp/models/interfaces/SimpleRangeAnalysisDefinition.qll create mode 100644 cpp/ql/src/experimental/semmle/code/cpp/models/interfaces/SimpleRangeAnalysisExpr.qll rename cpp/ql/src/{ => experimental}/semmle/code/cpp/rangeanalysis/Bound.qll (95%) create mode 100644 cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/ExtendedRangeAnalysis.qll rename cpp/ql/src/{ => experimental}/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll (97%) rename cpp/ql/src/{ => experimental}/semmle/code/cpp/rangeanalysis/RangeUtils.qll (90%) rename cpp/ql/src/{ => experimental}/semmle/code/cpp/rangeanalysis/SignAnalysis.qll (97%) create mode 100644 cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/extensions/ConstantBitwiseAndExprRange.qll create mode 100644 cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/extensions/SubtractSelf.qll create mode 100644 cpp/ql/src/experimental/semmle/code/cpp/security/PrivateCleartextWrite.qll create mode 100644 cpp/ql/src/experimental/semmle/code/cpp/security/PrivateData.qll create mode 100644 cpp/ql/src/jsf/jsfNote.qhelp create mode 100644 cpp/ql/src/printAst.ql create mode 100644 cpp/ql/src/semmle/code/cpp/MemberFunction.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/PrintIRLocalFlow.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRFunctionImports.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBase.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBaseInternal.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstructionImports.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstructionInternal.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRFunctionImports.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll create mode 100644 cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll create mode 100644 cpp/ql/src/semmle/code/cpp/models/implementations/MemberFunction.qll create mode 100644 cpp/ql/src/semmle/code/cpp/models/implementations/SmartPointer.qll create mode 100644 cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll create mode 100644 cpp/ql/src/semmle/code/cpp/models/implementations/StdMap.qll create mode 100644 cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll create mode 100644 cpp/ql/src/semmle/code/cpp/models/implementations/StdSet.qll create mode 100644 cpp/ql/src/semmle/code/cpp/models/interfaces/Iterator.qll create mode 100644 cpp/ql/test/TestUtilities/InlineExpectationsTestPrivate.qll create mode 100644 cpp/ql/test/experimental/library-tests/rangeanalysis/bitwiseand/bitwiseand.cpp create mode 100644 cpp/ql/test/experimental/library-tests/rangeanalysis/bitwiseand/bitwiseand.expected create mode 100644 cpp/ql/test/experimental/library-tests/rangeanalysis/bitwiseand/bitwiseand.ql create mode 100644 cpp/ql/test/experimental/library-tests/rangeanalysis/extended/extended.cpp create mode 100644 cpp/ql/test/experimental/library-tests/rangeanalysis/extended/extended.expected create mode 100644 cpp/ql/test/experimental/library-tests/rangeanalysis/extended/extended.ql create mode 100644 cpp/ql/test/experimental/library-tests/rangeanalysis/extensibility/extensibility.c create mode 100644 cpp/ql/test/experimental/library-tests/rangeanalysis/extensibility/extensibility.expected create mode 100644 cpp/ql/test/experimental/library-tests/rangeanalysis/extensibility/extensibility.ql rename cpp/ql/test/{ => experimental}/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected (100%) rename cpp/ql/test/{ => experimental}/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.ql (91%) rename cpp/ql/test/{ => experimental}/library-tests/rangeanalysis/rangeanalysis/test.cpp (100%) rename cpp/ql/test/{ => experimental}/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected (100%) rename cpp/ql/test/{ => experimental}/library-tests/rangeanalysis/signanalysis/SignAnalysis.ql (86%) rename cpp/ql/test/{ => experimental}/library-tests/rangeanalysis/signanalysis/binary_logical_operator.c (100%) rename cpp/ql/test/{ => experimental}/library-tests/rangeanalysis/signanalysis/bounded_bounds.c (100%) rename cpp/ql/test/{ => experimental}/library-tests/rangeanalysis/signanalysis/inline_assembly.c (100%) rename cpp/ql/test/{ => experimental}/library-tests/rangeanalysis/signanalysis/minmax.c (100%) rename cpp/ql/test/{ => experimental}/library-tests/rangeanalysis/signanalysis/test.c (100%) rename cpp/ql/test/{ => experimental}/library-tests/rangeanalysis/signanalysis/test.cpp (100%) create mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-359/semmle/tests/PrivateCleartextWrite.expected create mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-359/semmle/tests/PrivateCleartextWrite.qlref create mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-359/semmle/tests/test.cpp create mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/semmle/tests/MemoryUnsafeFunctionScan.cpp create mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/semmle/tests/MemoryUnsafeFunctionScan.expected create mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/semmle/tests/MemoryUnsafeFunctionScan.qlref rename cpp/ql/test/library-tests/dataflow/{taint-tests => DefaultTaintTracking}/stl.cpp (79%) create mode 100644 cpp/ql/test/library-tests/dataflow/fields/Nodes.qll create mode 100644 cpp/ql/test/library-tests/dataflow/fields/arrays.cpp create mode 100644 cpp/ql/test/library-tests/dataflow/fields/flow-diff.expected create mode 100644 cpp/ql/test/library-tests/dataflow/fields/flow-diff.ql create mode 100644 cpp/ql/test/library-tests/dataflow/fields/realistic.cpp create mode 100644 cpp/ql/test/library-tests/dataflow/taint-tests/arrayassignment.cpp create mode 100644 cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass.cpp create mode 100644 cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass_declonly.cpp create mode 100644 cpp/ql/test/library-tests/dataflow/taint-tests/map.cpp create mode 100644 cpp/ql/test/library-tests/dataflow/taint-tests/movableclass.cpp create mode 100644 cpp/ql/test/library-tests/dataflow/taint-tests/set.cpp create mode 100644 cpp/ql/test/library-tests/dataflow/taint-tests/smart_pointer.cpp create mode 100644 cpp/ql/test/library-tests/dataflow/taint-tests/standalone_iterators.cpp create mode 100644 cpp/ql/test/library-tests/dataflow/taint-tests/stl.h create mode 100644 cpp/ql/test/library-tests/dataflow/taint-tests/string.cpp create mode 100644 cpp/ql/test/library-tests/dataflow/taint-tests/stringstream.cpp create mode 100644 cpp/ql/test/library-tests/dataflow/taint-tests/structlikeclass.cpp create mode 100644 cpp/ql/test/library-tests/dataflow/taint-tests/swap.h create mode 100644 cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp create mode 100644 cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp create mode 100644 cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp create mode 100644 cpp/ql/test/library-tests/members/this/test.cpp create mode 100644 cpp/ql/test/library-tests/members/this/this.expected create mode 100644 cpp/ql/test/library-tests/members/this/this.ql create mode 100644 cpp/ql/test/library-tests/security/encryption/test.cpp create mode 100644 cpp/ql/test/library-tests/security/encryption/test.expected create mode 100644 cpp/ql/test/library-tests/security/encryption/test.ql create mode 100644 cpp/ql/test/library-tests/specifiers2/cpp20.cpp delete mode 100644 cpp/ql/test/library-tests/syntax-zoo/Compare.qll create mode 100644 cpp/ql/test/library-tests/variables/global/vardecl.expected create mode 100644 cpp/ql/test/library-tests/variables/global/vardecl.ql create mode 100644 cpp/ql/test/query-tests/Best Practices/Hiding/DeclarationHidesParameter/hiding.h create mode 100644 cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/test2.cpp create mode 100644 cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/test6.cpp create mode 100644 cpp/upgrades/025827d85c3f44a7fd52d4fad636e9a4141f12dd/old.dbscheme create mode 100644 cpp/upgrades/025827d85c3f44a7fd52d4fad636e9a4141f12dd/semmlecode.cpp.dbscheme create mode 100644 cpp/upgrades/025827d85c3f44a7fd52d4fad636e9a4141f12dd/static_asserts.ql create mode 100644 cpp/upgrades/025827d85c3f44a7fd52d4fad636e9a4141f12dd/upgrade.properties create mode 100644 cpp/upgrades/098850d25c4e9d417eb74c1bef9deb2f9d2dc417/old.dbscheme create mode 100644 cpp/upgrades/098850d25c4e9d417eb74c1bef9deb2f9d2dc417/semmlecode.cpp.dbscheme create mode 100644 cpp/upgrades/098850d25c4e9d417eb74c1bef9deb2f9d2dc417/upgrade.properties create mode 100644 cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/member_function_this_type.ql create mode 100644 cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/old.dbscheme create mode 100644 cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/semmlecode.cpp.dbscheme create mode 100644 cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/upgrade.properties create mode 100644 cpp/upgrades/75da61c94e19ae80a142f03a877ab9d0728752bc/old.dbscheme create mode 100644 cpp/upgrades/75da61c94e19ae80a142f03a877ab9d0728752bc/semmlecode.cpp.dbscheme create mode 100644 cpp/upgrades/75da61c94e19ae80a142f03a877ab9d0728752bc/upgrade.properties create mode 100644 cpp/upgrades/b5fa4fb0283c4accf2d85d559aeb2bba914c102b/old.dbscheme create mode 100644 cpp/upgrades/b5fa4fb0283c4accf2d85d559aeb2bba914c102b/semmlecode.cpp.dbscheme create mode 100644 cpp/upgrades/b5fa4fb0283c4accf2d85d559aeb2bba914c102b/upgrade.properties create mode 100644 csharp/.editorconfig create mode 100644 csharp/.vscode/extensions.json create mode 100644 csharp/.vscode/settings.json create mode 100644 csharp/.vscode/tasks.json create mode 100644 csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs rename csharp/autobuilder/{Semmle.Autobuild.Tests/Semmle.Autobuild.Tests.csproj => Semmle.Autobuild.CSharp.Tests/Semmle.Autobuild.CSharp.Tests.csproj} (76%) create mode 100644 csharp/autobuilder/Semmle.Autobuild.CSharp/CSharpAutobuilder.cs rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.CSharp}/DotNetRule.cs (83%) create mode 100644 csharp/autobuilder/Semmle.Autobuild.CSharp/Program.cs create mode 100644 csharp/autobuilder/Semmle.Autobuild.CSharp/Properties/AssemblyInfo.cs rename csharp/autobuilder/{Semmle.Autobuild/Semmle.Autobuild.csproj => Semmle.Autobuild.CSharp/Semmle.Autobuild.CSharp.csproj} (74%) rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.CSharp}/StandaloneBuildRule.cs (60%) rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.Shared}/AutobuildOptions.cs (65%) create mode 100644 csharp/autobuilder/Semmle.Autobuild.Shared/Autobuilder.cs rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.Shared}/BuildActions.cs (77%) rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.Shared}/BuildCommandAutoRule.cs (72%) rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.Shared}/BuildCommandRule.cs (74%) rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.Shared}/BuildScript.cs (84%) rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.Shared}/BuildTools.cs (83%) rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.Shared}/CommandBuilder.cs (83%) create mode 100644 csharp/autobuilder/Semmle.Autobuild.Shared/Language.cs rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.Shared}/MsBuildRule.cs (54%) rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.Shared}/Project.cs (97%) rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.Shared}/ProjectOrSolution.cs (90%) rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.Shared}/Properties/AssemblyInfo.cs (85%) create mode 100644 csharp/autobuilder/Semmle.Autobuild.Shared/Semmle.Autobuild.Shared.csproj rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.Shared}/Solution.cs (77%) delete mode 100644 csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs delete mode 100644 csharp/autobuilder/Semmle.Autobuild/AspBuildRule.cs delete mode 100644 csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs delete mode 100644 csharp/autobuilder/Semmle.Autobuild/Language.cs delete mode 100644 csharp/autobuilder/Semmle.Autobuild/XmlBuildRule.cs create mode 100644 csharp/codeql-extractor.yml create mode 100644 csharp/extractor/Semmle.Extraction.CIL.Driver/InvalidAssemblyException.cs create mode 100644 csharp/extractor/Semmle.Extraction.CSharp.Standalone/AssemblyLoadException.cs create mode 100644 csharp/extractor/Semmle.Extraction.Tests/FilePattern.cs create mode 100644 csharp/extractor/Semmle.Extraction.Tests/PathTransformer.cs create mode 100644 csharp/extractor/Semmle.Extraction/FilePattern.cs create mode 100644 csharp/extractor/Semmle.Extraction/PathTransformer.cs create mode 100644 csharp/ql/examples/qlpack.yml create mode 100644 csharp/ql/src/Bad Practices/Comments/CommentedOutCodeQuery.qhelp create mode 100644 csharp/ql/src/Metrics/Files/CommentedOutCodeMetricOverview.qhelp create mode 100644 csharp/ql/src/Metrics/Files/CommentedOutCodeReferences.qhelp create mode 100644 csharp/ql/src/Metrics/Files/DuplicationProblems.qhelp create mode 100644 csharp/ql/src/codeql-suites/csharp-security-and-quality.qls create mode 100644 csharp/ql/src/codeql-suites/csharp-security-extended.qls create mode 100644 csharp/ql/src/codeql-suites/exclude-dependency-queries.yml create mode 100644 csharp/ql/src/experimental/Security Features/Serialization/DataSetSerialization.qhelp create mode 100644 csharp/ql/src/experimental/Security Features/Serialization/DataSetSerialization.qll create mode 100644 csharp/ql/src/experimental/Security Features/Serialization/DefiningDatasetRelatedType.qhelp create mode 100644 csharp/ql/src/experimental/Security Features/Serialization/DefiningDatasetRelatedType.ql create mode 100644 csharp/ql/src/experimental/Security Features/Serialization/DefiningPotentiallyUnsafeXmlSerialization.qhelp create mode 100644 csharp/ql/src/experimental/Security Features/Serialization/DefiningPotentiallyUnsafeXmlSerializer.ql create mode 100644 csharp/ql/src/experimental/Security Features/Serialization/UnsafeTypeUsedDataContractSerializer.qhelp create mode 100644 csharp/ql/src/experimental/Security Features/Serialization/UnsafeTypeUsedDataContractSerializer.ql create mode 100644 csharp/ql/src/experimental/Security Features/Serialization/XmlDeserializationWithDataSet.qhelp create mode 100644 csharp/ql/src/experimental/Security Features/Serialization/XmlDeserializationWithDataSet.ql rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/IR.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/IRConfiguration.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/IRConsistency.ql (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/PrintIR.ql (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/PrintIR.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/Util.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/ValueNumbering.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/EdgeKind.qll (89%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/IRConfiguration.qll (70%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/IRType.qll (89%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/MemoryAccessKind.qll (93%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/Opcode.qll (59%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/TempVariableTag.qll (92%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/UseSoundEscapeAnalysis.qll (100%) create mode 100644 csharp/ql/src/experimental/ir/implementation/internal/AliasedSSAStub.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/internal/EdgeKindInternal.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/internal/IRConfigurationInternal.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBase.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBaseInternal.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/internal/IRTypeInternal.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/internal/OpcodeImports.qll rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/internal/OperandTag.qll (82%) create mode 100644 csharp/ql/src/experimental/ir/implementation/internal/OperandTagInternal.qll rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/internal/TIRVariable.qll (100%) create mode 100644 csharp/ql/src/experimental/ir/implementation/internal/TIRVariableInternal.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/internal/TInstructionImports.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/internal/TInstructionInternal.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/internal/TempVariableTagInternal.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/raw/IR.qll rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/IRBlock.qll (75%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/IRConsistency.ql (100%) create mode 100644 csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.qll rename csharp/ql/src/{semmle/code/csharp/ir/implementation/unaliased_ssa => experimental/ir/implementation/raw}/IRFunction.qll (70%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/IRVariable.qll (78%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/Instruction.qll (59%) rename csharp/ql/src/{semmle/code/csharp/ir/implementation/unaliased_ssa => experimental/ir/implementation/raw}/Operand.qll (91%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/PrintIR.ql (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/PrintIR.qll (73%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/constant/ConstantAnalysis.qll (97%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/constant/PrintConstantAnalysis.qll (84%) create mode 100644 csharp/ql/src/experimental/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/gvn/PrintValueNumbering.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/gvn/ValueNumbering.qll (100%) create mode 100644 csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll (100%) create mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/IRBlockImports.qll rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/IRConstruction.qll (84%) create mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/IRFunctionImports.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/IRImports.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/IRInternal.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/IRVariableImports.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionImports.qll rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/InstructionTag.qll (99%) create mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/OperandImports.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/PrintIRImports.qll rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/TranslatedCall.qll (91%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/TranslatedCondition.qll (95%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/TranslatedDeclaration.qll (89%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/TranslatedElement.qll (96%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/TranslatedExpr.qll (99%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/TranslatedFunction.qll (96%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/TranslatedInitialization.qll (98%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/TranslatedStmt.qll (99%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/common/TranslatedCallBase.qll (90%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/common/TranslatedConditionBase.qll (80%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll (81%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/common/TranslatedExprBase.qll (68%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/desugar/Common.qll (90%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/desugar/Delegate.qll (81%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/desugar/Foreach.qll (94%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/desugar/Lock.qll (93%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/desugar/Using.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll (55%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll (63%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll (81%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll (81%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll (65%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll (84%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/reachability/Dominance.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/reachability/DominanceInternal.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/reachability/PrintDominance.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/reachability/PrintReachableBlock.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/reachability/ReachableBlock.qll (100%) create mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/IRBlock.qll (75%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/IRConsistency.ql (100%) create mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.qll rename csharp/ql/src/{semmle/code/csharp/ir/implementation/raw => experimental/ir/implementation/unaliased_ssa}/IRFunction.qll (70%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/IRVariable.qll (78%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/Instruction.qll (59%) rename csharp/ql/src/{semmle/code/csharp/ir/implementation/raw => experimental/ir/implementation/unaliased_ssa}/Operand.qll (91%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/PrintIR.ql (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/PrintIR.qll (73%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll (96%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll (84%) create mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll (100%) create mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll (97%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll (91%) create mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll (100%) create mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRImports.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRInternal.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/InstructionImports.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandImports.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/PrintSSA.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll (84%) create mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll (85%) create mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/reachability/DominanceInternal.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/reachability/PrintReachableBlock.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll (100%) create mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/internal/CSharpType.qll (99%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/internal/IRCSharpLanguage.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/internal/IRGuards.qll (99%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/internal/IRUtilities.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/internal/IntegerConstant.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/internal/IntegerInterval.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/internal/IntegerPartial.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/internal/Overlap.qll (56%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/internal/TempVariableTag.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/rangeanalysis/Bound.qll (96%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/rangeanalysis/RangeAnalysis.qll (99%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/rangeanalysis/RangeUtils.qll (96%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/rangeanalysis/SignAnalysis.qll (99%) delete mode 100644 csharp/ql/src/external/examples/filters/BumpMetricBy10.ql delete mode 100644 csharp/ql/src/external/examples/filters/EditDefectMessage.ql delete mode 100644 csharp/ql/src/external/examples/filters/ExcludeGeneratedCode.ql delete mode 100644 csharp/ql/src/external/examples/filters/FromSource.ql delete mode 100644 csharp/ql/src/external/tests/DefectFromExternalData.ql delete mode 100644 csharp/ql/src/external/tests/DefectFromExternalDefect.ql delete mode 100644 csharp/ql/src/external/tests/DefectFromExternalMetric.ql delete mode 100644 csharp/ql/src/external/tests/MetricFilter.ql delete mode 100644 csharp/ql/src/external/tests/MetricFromExternalDefect.ql delete mode 100644 csharp/ql/src/external/tests/MetricFromExternalMetric.ql create mode 100644 csharp/ql/src/printAst.ql create mode 100644 csharp/ql/src/semmle/code/csharp/PrintAst.ql create mode 100644 csharp/ql/src/semmle/code/csharp/PrintAst.qll create mode 100644 csharp/ql/src/semmle/code/csharp/TypeRef.qll create mode 100644 csharp/ql/src/semmle/code/csharp/dataflow/Bound.qll create mode 100644 csharp/ql/src/semmle/code/csharp/dataflow/ModulusAnalysis.qll create mode 100644 csharp/ql/src/semmle/code/csharp/dataflow/SignAnalysis.qll create mode 100644 csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/BoundSpecific.qll create mode 100644 csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/ConstantUtils.qll create mode 100644 csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/ModulusAnalysisSpecific.qll create mode 100644 csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll create mode 100644 csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/Sign.qll create mode 100644 csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll create mode 100644 csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll create mode 100644 csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll create mode 100644 csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionSpecific.qll create mode 100644 csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaUtils.qll create mode 100644 csharp/ql/src/semmle/code/csharp/frameworks/system/runtime/CompilerServices.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/internal/EdgeKindInternal.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRConfigurationInternal.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRTypeInternal.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OpcodeImports.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTagInternal.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariableInternal.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TempVariableTagInternal.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IR.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRBlockImports.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRInternal.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/PrintIRImports.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IR.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRInternal.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/internal/TIRVariable.qll create mode 100644 csharp/ql/test/experimental/Security Features/Serialization/DefiningDatasetRelatedType.expected create mode 100644 csharp/ql/test/experimental/Security Features/Serialization/DefiningDatasetRelatedType.qlref create mode 100644 csharp/ql/test/experimental/Security Features/Serialization/DefiningPotentiallyUnsafeXmlSerializer.expected create mode 100644 csharp/ql/test/experimental/Security Features/Serialization/DefiningPotentiallyUnsafeXmlSerializer.qlref create mode 100644 csharp/ql/test/experimental/Security Features/Serialization/UnsafeTypeUsedDataContractSerializer.expected create mode 100644 csharp/ql/test/experimental/Security Features/Serialization/UnsafeTypeUsedDataContractSerializer.qlref create mode 100644 csharp/ql/test/experimental/Security Features/Serialization/XmlDeserializationWithDataSet.expected create mode 100644 csharp/ql/test/experimental/Security Features/Serialization/XmlDeserializationWithDataSet.qlref create mode 100644 csharp/ql/test/experimental/Security Features/Serialization/test0.cs create mode 100644 csharp/ql/test/experimental/ir/ir/PrintAst.expected create mode 100644 csharp/ql/test/experimental/ir/ir/PrintAst.qlref rename csharp/ql/test/{library-tests => experimental}/ir/ir/array.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/assignop.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/casts.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/collections.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/constructor_init.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/crement.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/delegates.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/events.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/foreach.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/func_with_param_call.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/indexers.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/inheritance_polymorphism.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/inoutref.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/isexpr.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/jumps.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/lock.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/obj_creation.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/pointers.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/prop.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/raw_ir.expected (99%) create mode 100644 csharp/ql/test/experimental/ir/ir/raw_ir.qlref rename csharp/ql/test/{library-tests => experimental}/ir/ir/raw_ir_consistency.expected (95%) create mode 100644 csharp/ql/test/experimental/ir/ir/raw_ir_consistency.qlref rename csharp/ql/test/{library-tests => experimental}/ir/ir/simple_call.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/simple_function.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/stmts.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/unaliased_ssa_consistency.expected (95%) create mode 100644 csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.qlref rename csharp/ql/test/{library-tests => experimental}/ir/ir/unaliased_ssa_ssa_consistency.expected (100%) create mode 100644 csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.qlref rename csharp/ql/test/{library-tests => experimental}/ir/ir/using.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/variables.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/offbyone/OffByOneRA.expected (100%) rename csharp/ql/test/{library-tests => experimental}/ir/offbyone/OffByOneRA.ql (91%) rename csharp/ql/test/{library-tests => experimental}/ir/offbyone/null.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/offbyone/test.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/rangeanalysis/RangeAnalysis.expected (100%) rename csharp/ql/test/{library-tests => experimental}/ir/rangeanalysis/RangeAnalysis.ql (79%) rename csharp/ql/test/{library-tests => experimental}/ir/rangeanalysis/null.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/rangeanalysis/test.cs (100%) create mode 100644 csharp/ql/test/library-tests/arguments/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/arguments/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/assignments/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/assignments/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/attributes/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/attributes/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/constructors/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/constructors/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/controlflow/graph/Assert.cs create mode 100644 csharp/ql/test/library-tests/controlflow/graph/MultiImplementationA.cs create mode 100644 csharp/ql/test/library-tests/controlflow/graph/MultiImplementationB.cs create mode 100644 csharp/ql/test/library-tests/conversion/operator/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/conversion/operator/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/conversion/pointer/Pointer.cs create mode 100644 csharp/ql/test/library-tests/conversion/pointer/Pointer.expected create mode 100644 csharp/ql/test/library-tests/conversion/pointer/Pointer.ql create mode 100644 csharp/ql/test/library-tests/csharp6/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/csharp6/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/csharp7.1/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/csharp7.1/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/csharp7.2/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/csharp7.2/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/csharp7.3/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/csharp7.3/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/csharp7/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/csharp7/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/csharp8/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/csharp8/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/csharp8/switchCaseExprTypes.expected create mode 100644 csharp/ql/test/library-tests/csharp8/switchCaseExprTypes.ql create mode 100644 csharp/ql/test/library-tests/dataflow/fields/I.cs create mode 100644 csharp/ql/test/library-tests/dataflow/library/TaintedMember.expected create mode 100644 csharp/ql/test/library-tests/dataflow/library/TaintedMember.ql create mode 100644 csharp/ql/test/library-tests/dataflow/modulusanalysis/ModulusAnalysis.cs create mode 100644 csharp/ql/test/library-tests/dataflow/modulusanalysis/ModulusAnalysis.expected create mode 100644 csharp/ql/test/library-tests/dataflow/modulusanalysis/ModulusAnalysis.ql rename docs/language/global-sphinx-files/_static/.gitkeep => csharp/ql/test/library-tests/dataflow/signanalysis/MissingSign.expected (100%) create mode 100644 csharp/ql/test/library-tests/dataflow/signanalysis/MissingSign.ql create mode 100644 csharp/ql/test/library-tests/dataflow/signanalysis/SignAnalysis.cs create mode 100644 csharp/ql/test/library-tests/dataflow/signanalysis/SignAnalysis.expected create mode 100644 csharp/ql/test/library-tests/dataflow/signanalysis/SignAnalysis.ql create mode 100644 csharp/ql/test/library-tests/definitions/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/definitions/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/delegates/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/delegates/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/dispatch/CallContext.expected create mode 100644 csharp/ql/test/library-tests/dispatch/CallContext.ql create mode 100644 csharp/ql/test/library-tests/dynamic/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/dynamic/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/enums/Enums11.expected create mode 100644 csharp/ql/test/library-tests/enums/Enums11.ql create mode 100644 csharp/ql/test/library-tests/enums/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/enums/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/events/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/events/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/exceptions/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/exceptions/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/expressions/ArrayCreation11.expected create mode 100644 csharp/ql/test/library-tests/expressions/ArrayCreation11.ql create mode 100644 csharp/ql/test/library-tests/expressions/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/expressions/PrintAst.qlref delete mode 100644 csharp/ql/test/library-tests/exprorstmtparent/GetABody.expected delete mode 100644 csharp/ql/test/library-tests/exprorstmtparent/GetABody.ql delete mode 100644 csharp/ql/test/library-tests/exprorstmtparent/MultiImplementationsParent.expected delete mode 100644 csharp/ql/test/library-tests/exprorstmtparent/MultiImplementationsParent.ql create mode 100644 csharp/ql/test/library-tests/fields/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/fields/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/generics/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/generics/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/goto/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/goto/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/indexers/Indexers12.expected create mode 100644 csharp/ql/test/library-tests/indexers/Indexers12.ql create mode 100644 csharp/ql/test/library-tests/indexers/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/indexers/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/initializers/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/initializers/PrintAst.qlref delete mode 100644 csharp/ql/test/library-tests/ir/ir/raw_ir.qlref delete mode 100644 csharp/ql/test/library-tests/ir/ir/raw_ir_consistency.qlref delete mode 100644 csharp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.qlref delete mode 100644 csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.qlref create mode 100644 csharp/ql/test/library-tests/linq/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/linq/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/members/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/members/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/methods/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/methods/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/namespaces/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/namespaces/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/nestedtypes/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/nestedtypes/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/operators/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/operators/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/partial/MethodIsPartial.expected create mode 100644 csharp/ql/test/library-tests/partial/MethodIsPartial.ql create mode 100644 csharp/ql/test/library-tests/partial/PartialMethodBody.expected create mode 100644 csharp/ql/test/library-tests/partial/PartialMethodBody.ql create mode 100644 csharp/ql/test/library-tests/partial/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/partial/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/properties/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/properties/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/statements/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/statements/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/types/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/types/PrintAst.qlref create mode 100644 csharp/ql/test/library-tests/unsafe/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/unsafe/PrintAst.qlref create mode 100644 csharp/tools/autobuild.cmd create mode 100755 csharp/tools/autobuild.sh create mode 100644 csharp/tools/linux64/compiler-tracing.spec create mode 100755 csharp/tools/linux64/extract-csharp.sh create mode 100644 csharp/tools/osx64/compiler-tracing.spec create mode 100755 csharp/tools/osx64/extract-csharp.sh create mode 100644 csharp/tools/pre-finalize.cmd create mode 100755 csharp/tools/pre-finalize.sh create mode 100644 csharp/tools/win64/compiler-tracing.spec create mode 100644 csharp/upgrades/f2aa2d4ac31309bd83ab633d0f40e8a442767bd1/old.dbscheme create mode 100644 csharp/upgrades/f2aa2d4ac31309bd83ab633d0f40e8a442767bd1/semmlecode.csharp.dbscheme create mode 100644 csharp/upgrades/f2aa2d4ac31309bd83ab633d0f40e8a442767bd1/upgrade.properties create mode 100644 docs/language/global-sphinx-files/_static/primer.css create mode 100644 docs/language/images/query-progress.png create mode 100644 docs/language/learn-ql/cpp/basic-query-cpp.rst create mode 100644 docs/language/learn-ql/csharp/basic-query-csharp.rst create mode 100644 docs/language/learn-ql/go/ast-class-reference.rst create mode 100644 docs/language/learn-ql/go/basic-query-go.rst create mode 100644 docs/language/learn-ql/go/library-modeling-go.rst create mode 100644 docs/language/learn-ql/java/basic-query-java.rst create mode 100644 docs/language/learn-ql/javascript/basic-query-javascript.rst create mode 100644 docs/language/learn-ql/python/basic-query-python.rst create mode 100644 docs/ql-libraries/dataflow/dataflow.md create mode 100644 docs/qldoc-style-guide.md create mode 100644 java/change-notes/2020-09-22-hibernate-sql-sinks.md create mode 100644 java/change-notes/2020-09-23-spring-multipart-request-sources.md create mode 100644 java/ql/examples/qlpack.yml create mode 100644 java/ql/src/Metrics/Files/CommentedOutCodeMetricOverview.qhelp create mode 100644 java/ql/src/Metrics/Files/CommentedOutCodeReferences.qhelp create mode 100644 java/ql/src/Metrics/Files/FCommentRatioCommon.qhelp create mode 100644 java/ql/src/Metrics/Files/FLinesOfCodeOverview.qhelp create mode 100644 java/ql/src/Metrics/Files/FLinesOfCodeReferences.qhelp create mode 100644 java/ql/src/Metrics/Files/FLinesOfDuplicatedCodeCommon.qhelp delete mode 100644 java/ql/src/Performance/InefficientToArray.java delete mode 100644 java/ql/src/Performance/InefficientToArray.qhelp delete mode 100644 java/ql/src/Performance/InefficientToArray.ql create mode 100644 java/ql/src/Security/CWE/CWE-020/ExternalAPISinkExample.java create mode 100644 java/ql/src/Security/CWE/CWE-020/ExternalAPITaintStepExample.java create mode 100644 java/ql/src/Security/CWE/CWE-020/ExternalAPIsUsedWithUntrustedData.qhelp create mode 100644 java/ql/src/Security/CWE/CWE-020/ExternalAPIsUsedWithUntrustedData.ql create mode 100644 java/ql/src/Security/CWE/CWE-020/UntrustedDataToExternalAPI.qhelp create mode 100644 java/ql/src/Security/CWE/CWE-020/UntrustedDataToExternalAPI.ql delete mode 100644 java/ql/src/Security/CWE/CWE-022/PathsCommon.qll create mode 100644 java/ql/src/Security/CWE/CWE-022/TaintedPathCommon.qll delete mode 100644 java/ql/src/Security/CWE/CWE-113/ResponseSplitting.qll create mode 100644 java/ql/src/Security/CWE/CWE-798/HardcodedAWSCredentials.java create mode 100644 java/ql/src/Violations of Best Practice/Comments/CommentedOutCodeQuery.qhelp create mode 100644 java/ql/src/codeql-suites/java-security-and-quality.qls create mode 100644 java/ql/src/codeql-suites/java-security-extended.qls create mode 100644 java/ql/src/experimental/Security/CWE/CWE-074/XsltInjection.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-074/XsltInjection.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-074/XsltInjection.ql create mode 100644 java/ql/src/experimental/Security/CWE/CWE-074/XsltInjectionLib.qll create mode 100644 java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.ql create mode 100644 java/ql/src/experimental/Security/CWE/CWE-297/InsecureJavaMail.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-297/InsecureJavaMail.ql create mode 100644 java/ql/src/experimental/Security/CWE/CWE-297/JavaMail.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-297/SimpleMail.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-299/CustomRevocationChecking.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-299/DefaultRevocationChecking.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.ql create mode 100644 java/ql/src/experimental/Security/CWE/CWE-299/NoRevocationChecking.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-299/RevocationCheckingLib.qll create mode 100644 java/ql/src/experimental/Security/CWE/CWE-327/SaferTLSVersion.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-327/SslLib.qll create mode 100644 java/ql/src/experimental/Security/CWE/CWE-327/UnsafeTLSVersion.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.ql create mode 100644 java/ql/src/experimental/Security/CWE/CWE-522/InsecureBasicAuth.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-522/InsecureBasicAuth.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-522/InsecureBasicAuth.ql rename java/ql/src/experimental/{ => Security/CWE}/CWE-532/SensitiveInfoLog.java (100%) rename java/ql/src/experimental/{ => Security/CWE}/CWE-532/SensitiveInfoLog.qhelp (100%) rename java/ql/src/experimental/{ => Security/CWE}/CWE-532/SensitiveInfoLog.ql (77%) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.ql create mode 100644 java/ql/src/experimental/Security/CWE/CWE-548/web.xml create mode 100644 java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.ql create mode 100644 java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjectionLib.qll rename java/ql/src/experimental/{ => Security/CWE}/CWE-939/IncorrectURLVerification.java (100%) rename java/ql/src/experimental/{ => Security/CWE}/CWE-939/IncorrectURLVerification.qhelp (100%) rename java/ql/src/experimental/{ => Security/CWE}/CWE-939/IncorrectURLVerification.ql (100%) create mode 100644 java/ql/src/printAst.ql create mode 100644 java/ql/src/semmle/code/Unit.qll create mode 100644 java/ql/src/semmle/code/java/PrettyPrintAst.qll create mode 100644 java/ql/src/semmle/code/java/PrintAst.ql create mode 100644 java/ql/src/semmle/code/java/dataflow/FlowSteps.qll create mode 100644 java/ql/src/semmle/code/java/dataflow/internal/rangeanalysis/BoundSpecific.qll create mode 100644 java/ql/src/semmle/code/java/dataflow/internal/rangeanalysis/ModulusAnalysisSpecific.qll create mode 100644 java/ql/src/semmle/code/java/dataflow/internal/rangeanalysis/Sign.qll create mode 100644 java/ql/src/semmle/code/java/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll create mode 100644 java/ql/src/semmle/code/java/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll create mode 100644 java/ql/src/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll create mode 100644 java/ql/src/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionSpecific.qll create mode 100644 java/ql/src/semmle/code/java/frameworks/jOOQ.qll create mode 100644 java/ql/src/semmle/code/java/frameworks/javase/WebSocket.qll create mode 100644 java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll create mode 100644 java/ql/src/semmle/code/java/frameworks/spring/SpringWeb.qll create mode 100644 java/ql/src/semmle/code/java/frameworks/spring/SpringWebClient.qll create mode 100644 java/ql/src/semmle/code/java/security/CommandArguments.qll create mode 100644 java/ql/src/semmle/code/java/security/ExternalAPIs.qll create mode 100644 java/ql/src/semmle/code/java/security/LdapInjection.qll create mode 100644 java/ql/src/semmle/code/java/security/PathCreation.qll create mode 100644 java/ql/src/semmle/code/java/security/QueryInjection.qll create mode 100644 java/ql/src/semmle/code/java/security/ResponseSplitting.qll rename java/ql/src/{Security/CWE/CWE-601 => semmle/code/java/security}/UrlRedirect.qll (65%) create mode 100644 java/ql/test/experimental/query-tests/security/CWE-074-JndiInjection/JndiInjection.expected rename java/ql/test/experimental/query-tests/security/{CWE-074 => CWE-074-JndiInjection}/JndiInjection.java (94%) rename java/ql/test/experimental/query-tests/security/{CWE-074 => CWE-074-JndiInjection}/JndiInjection.qlref (100%) create mode 100644 java/ql/test/experimental/query-tests/security/CWE-074-JndiInjection/options delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-074/XsltInjection.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-074/XsltInjection.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-074/XsltInjection.qlref rename java/ql/test/experimental/{Security/CWE => query-tests/security}/CWE-094/MvelInjection.expected (100%) rename java/ql/test/experimental/{Security/CWE => query-tests/security}/CWE-094/MvelInjection.java (100%) rename java/ql/test/experimental/{Security/CWE => query-tests/security}/CWE-094/MvelInjection.qlref (100%) rename java/ql/test/experimental/{Security/CWE => query-tests/security}/CWE-094/SpelInjection.expected (100%) rename java/ql/test/experimental/{Security/CWE => query-tests/security}/CWE-094/SpelInjection.java (100%) rename java/ql/test/experimental/{Security/CWE => query-tests/security}/CWE-094/SpelInjection.qlref (100%) rename java/ql/test/experimental/{Security/CWE => query-tests/security}/CWE-094/options (100%) create mode 100644 java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrust.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrust.qlref create mode 100644 java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrustTest.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.qlref create mode 100644 java/ql/test/experimental/query-tests/security/CWE-297/options create mode 100644 java/ql/test/experimental/query-tests/security/CWE-299/DisabledRevocationChecking.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-299/DisabledRevocationChecking.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-299/DisabledRevocationChecking.qlref create mode 100644 java/ql/test/experimental/query-tests/security/CWE-327/UnsafeTlsVersion.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-327/UnsafeTlsVersion.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-327/UnsafeTlsVersion.qlref create mode 100644 java/ql/test/experimental/query-tests/security/CWE-522/InsecureBasicAuth.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-522/InsecureBasicAuth.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-522/InsecureBasicAuth.qlref create mode 100644 java/ql/test/experimental/query-tests/security/CWE-522/options create mode 100644 java/ql/test/experimental/query-tests/security/CWE-548/InsecureDirectoryConfig.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-548/InsecureDirectoryConfig.qlref create mode 100644 java/ql/test/experimental/query-tests/security/CWE-548/insecure-web.xml create mode 100644 java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.qlref create mode 100644 java/ql/test/experimental/query-tests/security/CWE-917/options create mode 100644 java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/Configuration.java create mode 100644 java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/lib/SourceResolver.java create mode 100644 java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/om/NotationSet.java create mode 100644 java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/AbstractXsltTransformer.java create mode 100644 java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/Destination.java create mode 100644 java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/Processor.java create mode 100644 java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/QName.java create mode 100644 java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/SaxonApiException.java create mode 100644 java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/SaxonApiUncheckedException.java create mode 100644 java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XdmItem.java create mode 100644 java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XdmValue.java create mode 100644 java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/Xslt30Transformer.java create mode 100644 java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XsltCompiler.java create mode 100644 java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XsltExecutable.java create mode 100644 java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XsltPackage.java create mode 100644 java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XsltTransformer.java create mode 100644 java/ql/test/experimental/stubs/ognl-3.2.14/ognl/JavaSource.java create mode 100644 java/ql/test/experimental/stubs/ognl-3.2.14/ognl/Node.java create mode 100644 java/ql/test/experimental/stubs/ognl-3.2.14/ognl/Ognl.java create mode 100644 java/ql/test/experimental/stubs/ognl-3.2.14/ognl/OgnlContext.java create mode 100644 java/ql/test/experimental/stubs/ognl-3.2.14/ognl/OgnlException.java delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/ContextMapper.java delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/DirContextOperations.java delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapTemplate.java delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/NameClassPairCallbackHandler.java delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/EqualsFilter.java delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/Filter.java delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/HardcodedFilter.java delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/ConditionCriteria.java delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/ContainerCriteria.java delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/LdapQuery.java delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/LdapQueryBuilder.java delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapEncoder.java delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapNameBuilder.java delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapUtils.java create mode 100644 java/ql/test/experimental/stubs/struts2-core-2.5.22/com/opensymphony/xwork2/ognl/OgnlUtil.java rename java/ql/test/library-tests/Encryption/{blacklist.expected => insecure.expected} (100%) rename java/ql/test/library-tests/Encryption/{whitelist.ql => insecure.ql} (59%) rename java/ql/test/library-tests/Encryption/{whitelist.expected => secure.expected} (100%) rename java/ql/test/library-tests/Encryption/{blacklist.ql => secure.ql} (60%) create mode 100644 java/ql/test/library-tests/JDK/PrintAst.expected create mode 100644 java/ql/test/library-tests/JDK/PrintAst.qlref create mode 100644 java/ql/test/library-tests/arrays/PrintAst.expected create mode 100644 java/ql/test/library-tests/arrays/PrintAst.qlref create mode 100644 java/ql/test/library-tests/collections/PrintAst.expected create mode 100644 java/ql/test/library-tests/collections/PrintAst.qlref create mode 100644 java/ql/test/library-tests/comments/PrintAst.expected create mode 100644 java/ql/test/library-tests/comments/PrintAst.qlref create mode 100644 java/ql/test/library-tests/constants/PrintAst.expected create mode 100644 java/ql/test/library-tests/constants/PrintAst.qlref create mode 100644 java/ql/test/library-tests/constructors/PrintAst.expected create mode 100644 java/ql/test/library-tests/constructors/PrintAst.qlref create mode 100644 java/ql/test/library-tests/dataflow/callctx/A.java create mode 100644 java/ql/test/library-tests/dataflow/callctx/test.expected create mode 100644 java/ql/test/library-tests/dataflow/callctx/test.ql create mode 100644 java/ql/test/library-tests/dataflow/collections/ContainterTest.java create mode 100644 java/ql/test/library-tests/dataflow/fields/F.java create mode 100644 java/ql/test/library-tests/dataflow/local-additional-taint/ArraysTest.java create mode 100644 java/ql/test/library-tests/dataflow/local-additional-taint/CollectionsTest.java create mode 100644 java/ql/test/library-tests/dataflow/local-flow/ObjectsTest.java create mode 100644 java/ql/test/library-tests/dataflow/local-flow/flow.expected create mode 100644 java/ql/test/library-tests/dataflow/local-flow/flow.ql create mode 100644 java/ql/test/library-tests/dataflow/local-flow/options create mode 100644 java/ql/test/library-tests/dataflow/modulus-analysis/ModulusAnalysis.expected create mode 100644 java/ql/test/library-tests/dataflow/modulus-analysis/ModulusAnalysis.java create mode 100644 java/ql/test/library-tests/dataflow/modulus-analysis/ModulusAnalysis.ql create mode 100644 java/ql/test/library-tests/dataflow/range-analysis/A.java create mode 100644 java/ql/test/library-tests/dataflow/range-analysis/RangeAnalysis.expected create mode 100644 java/ql/test/library-tests/dataflow/range-analysis/RangeAnalysis.ql create mode 100644 java/ql/test/library-tests/dataflow/records/A.java create mode 100644 java/ql/test/library-tests/dataflow/records/options create mode 100644 java/ql/test/library-tests/dataflow/records/test.expected create mode 100644 java/ql/test/library-tests/dataflow/records/test.ql create mode 100644 java/ql/test/library-tests/dataflow/sign-analysis/A.java create mode 100644 java/ql/test/library-tests/dataflow/sign-analysis/SignAnalysis.expected create mode 100644 java/ql/test/library-tests/dataflow/sign-analysis/SignAnalysis.ql create mode 100644 java/ql/test/library-tests/dataflow/taint-format/A.java create mode 100644 java/ql/test/library-tests/dataflow/taint-format/options create mode 100644 java/ql/test/library-tests/dataflow/taint-format/test.expected create mode 100644 java/ql/test/library-tests/dataflow/taint-format/test.ql create mode 100644 java/ql/test/library-tests/dependency-counts/PrintAst.expected create mode 100644 java/ql/test/library-tests/dependency-counts/PrintAst.qlref create mode 100644 java/ql/test/library-tests/dependency/PrintAst.expected create mode 100644 java/ql/test/library-tests/dependency/PrintAst.qlref create mode 100644 java/ql/test/library-tests/fields/PrintAst.expected create mode 100644 java/ql/test/library-tests/fields/PrintAst.qlref create mode 100644 java/ql/test/library-tests/frameworks/android/taint-database/FlowSteps.java create mode 100644 java/ql/test/library-tests/frameworks/android/taint-database/Sinks.java create mode 100644 java/ql/test/library-tests/frameworks/android/taint-database/flowSteps.expected create mode 100644 java/ql/test/library-tests/frameworks/android/taint-database/flowSteps.ql create mode 100644 java/ql/test/library-tests/frameworks/android/taint-database/options create mode 100644 java/ql/test/library-tests/frameworks/android/taint-database/sinks.expected create mode 100644 java/ql/test/library-tests/frameworks/android/taint-database/sinks.ql create mode 100644 java/ql/test/library-tests/generics/PrintAst.expected create mode 100644 java/ql/test/library-tests/generics/PrintAst.qlref create mode 100644 java/ql/test/library-tests/guards12/PrintAst.expected create mode 100644 java/ql/test/library-tests/guards12/PrintAst.qlref create mode 100644 java/ql/test/library-tests/java7/Diamond/PrintAst.expected create mode 100644 java/ql/test/library-tests/java7/Diamond/PrintAst.qlref create mode 100644 java/ql/test/library-tests/java7/MultiCatch/PrintAst.expected create mode 100644 java/ql/test/library-tests/java7/MultiCatch/PrintAst.qlref create mode 100644 java/ql/test/library-tests/javadoc/PrintAst.expected create mode 100644 java/ql/test/library-tests/javadoc/PrintAst.qlref create mode 100644 java/ql/test/library-tests/modifiers/PrintAst.expected create mode 100644 java/ql/test/library-tests/modifiers/PrintAst.qlref create mode 100644 java/ql/test/library-tests/pathcreation/PathCreation.expected create mode 100644 java/ql/test/library-tests/pathcreation/PathCreation.java create mode 100644 java/ql/test/library-tests/pathcreation/PathCreation.ql create mode 100644 java/ql/test/library-tests/printAst/A.java create mode 100644 java/ql/test/library-tests/printAst/PrintAst.expected create mode 100644 java/ql/test/library-tests/printAst/PrintAst.qlref create mode 100644 java/ql/test/library-tests/printAst/options create mode 100644 java/ql/test/library-tests/reflection/PrintAst.expected create mode 100644 java/ql/test/library-tests/reflection/PrintAst.qlref create mode 100644 java/ql/test/library-tests/typeaccesses/PrintAst.expected create mode 100644 java/ql/test/library-tests/typeaccesses/PrintAst.qlref create mode 100644 java/ql/test/library-tests/varargs/PrintAst.expected create mode 100644 java/ql/test/library-tests/varargs/PrintAst.qlref create mode 100644 java/ql/test/query-tests/StringFormat/options create mode 100644 java/ql/test/query-tests/maven-dependencies/.gitignore create mode 100644 java/ql/test/query-tests/security/CWE-078/ExecRelative.expected create mode 100644 java/ql/test/query-tests/security/CWE-078/ExecRelative.qlref create mode 100644 java/ql/test/query-tests/security/CWE-078/ExecTaintedLocal.expected create mode 100644 java/ql/test/query-tests/security/CWE-078/ExecTaintedLocal.qlref create mode 100644 java/ql/test/query-tests/security/CWE-078/ExecUnescaped.expected create mode 100644 java/ql/test/query-tests/security/CWE-078/ExecUnescaped.qlref create mode 100644 java/ql/test/query-tests/security/CWE-078/Test.java create mode 100644 java/ql/test/query-tests/security/CWE-079/semmle/tests/WebsocketXss.java create mode 100644 java/ql/test/query-tests/security/CWE-089/semmle/examples/Mongo.java create mode 100644 java/ql/test/query-tests/security/CWE-089/semmle/examples/options create mode 100644 java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedAWSCredentials.java create mode 100644 java/ql/test/query-tests/security/CWE-798/semmle/tests/options create mode 100644 java/ql/test/stubs/amazon-aws-sdk-1.11.700/LICENSE.txt create mode 100644 java/ql/test/stubs/amazon-aws-sdk-1.11.700/com/amazonaws/auth/AWSCredentials.java create mode 100644 java/ql/test/stubs/amazon-aws-sdk-1.11.700/com/amazonaws/auth/BasicAWSCredentials.java create mode 100644 java/ql/test/stubs/android/android/content/ContentProvider.java create mode 100644 java/ql/test/stubs/android/android/content/ContentResolver.java create mode 100644 java/ql/test/stubs/android/android/content/ContentValues.java create mode 100644 java/ql/test/stubs/android/android/content/Context.java create mode 100644 java/ql/test/stubs/android/android/database/Cursor.java create mode 100644 java/ql/test/stubs/android/android/database/DatabaseUtils.java create mode 100644 java/ql/test/stubs/android/android/database/sqlite/SQLiteDatabase.java create mode 100644 java/ql/test/stubs/android/android/database/sqlite/SQLiteQueryBuilder.java create mode 100644 java/ql/test/stubs/android/android/net/Uri.java create mode 100644 java/ql/test/stubs/android/android/os/CancellationSignal.java create mode 100644 java/ql/test/stubs/android/android/os/ParcelFileDescriptor.java create mode 100644 java/ql/test/stubs/apache-commons-email-1.6.0/LICENSE.txt create mode 100644 java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/DefaultAuthenticator.java create mode 100644 java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/Email.java create mode 100644 java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/EmailException.java create mode 100644 java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/SimpleEmail.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/Header.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/HeaderElement.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/HeaderElementIterator.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/HeaderIterator.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/HttpEntity.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/HttpEntityEnclosingRequest.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/HttpMessage.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/HttpRequest.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/NameValuePair.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/ParseException.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/ProtocolVersion.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/RequestLine.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/client/methods/HttpEntityEnclosingRequestBase.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/client/methods/HttpGet.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/client/methods/HttpPost.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/client/methods/HttpPut.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/client/methods/HttpRequestBase.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/message/AbstractHttpMessage.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/message/BasicHttpEntityEnclosingRequest.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/message/BasicHttpRequest.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/message/BasicRequestLine.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/params/HttpParams.java create mode 100644 java/ql/test/stubs/javamail-api-1.6.2/LICENSE.txt create mode 100644 java/ql/test/stubs/javamail-api-1.6.2/javax/mail/Authenticator.java create mode 100644 java/ql/test/stubs/javamail-api-1.6.2/javax/mail/PasswordAuthentication.java create mode 100644 java/ql/test/stubs/javamail-api-1.6.2/javax/mail/Session.java create mode 100644 java/ql/test/stubs/mongodbClient/com/mongodb/BasicDBObject.java create mode 100644 java/ql/test/stubs/mongodbClient/com/mongodb/DB.java create mode 100644 java/ql/test/stubs/mongodbClient/com/mongodb/DBCollection.java create mode 100644 java/ql/test/stubs/mongodbClient/com/mongodb/DBCursor.java create mode 100644 java/ql/test/stubs/mongodbClient/com/mongodb/DBObject.java create mode 100644 java/ql/test/stubs/mongodbClient/com/mongodb/Mongo.java create mode 100644 java/ql/test/stubs/mongodbClient/com/mongodb/MongoClient.java create mode 100644 java/ql/test/stubs/mongodbClient/com/mongodb/ServerAddress.java create mode 100644 java/ql/test/stubs/mongodbClient/com/mongodb/util/JSON.java create mode 100644 java/ql/test/stubs/mongodbClient/org/bson/BSONObject.java rename java/ql/test/{experimental => }/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/AttributesMapper.java (100%) rename java/ql/test/{experimental => }/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/DirContextProcessor.java (100%) rename java/ql/test/{experimental => }/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapOperations.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/beans/factory/BeanFactory.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/beans/factory/HierarchicalBeanFactory.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/beans/factory/InitializingBean.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/beans/factory/ListableBeanFactory.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/boot/security/servlet/ApplicationContextRequestMatcher.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/context/ApplicationContext.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/context/ApplicationEventPublisher.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/context/MessageSource.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/core/env/EnvironmentCapable.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/core/io/ResourceLoader.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/core/io/support/ResourcePatternResolver.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/jndi/JndiTemplate.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/config/Customizer.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractConfiguredSecurityBuilder.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractSecurityBuilder.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityBuilder.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurer.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurerAdapter.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/HttpSecurityBuilder.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/builders/HttpSecurity.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractConfigAttributeRequestMatcherRegistry.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractHttpConfigurer.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractInterceptUrlConfigurer.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/web/DefaultSecurityFilterChain.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/web/SecurityFilterChain.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/web/util/matcher/RequestMatcher.java (100%) create mode 100644 java/ql/test/stubs/springframework-5.2.3/org/springframework/stereotype/Component.java create mode 100644 java/ql/test/stubs/springframework-5.2.3/org/springframework/stereotype/Controller.java create mode 100644 java/ql/test/stubs/springframework-5.2.3/org/springframework/stereotype/Indexed.java rename java/ql/test/{experimental/stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestParam.java => stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestMapping.java} (60%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/web/context/WebApplicationContext.java (100%) create mode 100644 javascript/extractor/src/com/semmle/js/ast/jsx/JSXThisExpr.java create mode 100644 javascript/extractor/src/com/semmle/js/dependencies/AsyncFetcher.java create mode 100644 javascript/extractor/src/com/semmle/js/dependencies/DependencyResolver.java create mode 100644 javascript/extractor/src/com/semmle/js/dependencies/Fetcher.java create mode 100644 javascript/extractor/src/com/semmle/js/dependencies/SemVer.java create mode 100644 javascript/extractor/src/com/semmle/js/dependencies/packument/PackageJson.java create mode 100644 javascript/extractor/src/com/semmle/js/dependencies/packument/Packument.java create mode 100644 javascript/extractor/src/com/semmle/js/extractor/FileSnippet.java create mode 100644 javascript/extractor/src/com/semmle/js/extractor/VirtualSourceRoot.java rename javascript/extractor/src/com/semmle/{js/parser => ts/extractor}/TypeScriptASTConverter.java (98%) rename javascript/extractor/src/com/semmle/{js/parser => ts/extractor}/TypeScriptParser.java (91%) rename javascript/extractor/src/com/semmle/{js/parser => ts/extractor}/TypeScriptParserMetadata.java (98%) create mode 100644 javascript/extractor/tests/es2021/input/assign.js create mode 100644 javascript/extractor/tests/es2021/input/numeric.js create mode 100644 javascript/extractor/tests/es2021/options.json create mode 100644 javascript/extractor/tests/es2021/output/trap/assign.js.trap create mode 100644 javascript/extractor/tests/es2021/output/trap/numeric.js.trap create mode 100644 javascript/extractor/tests/extensions/input/tst4.cjs create mode 100644 javascript/extractor/tests/extensions/output/trap/tst4.cjs.trap create mode 100644 javascript/extractor/tests/moduleTypes1/input/package.json rename python/ql/test/library-tests/PointsTo/new/Sanity.expected => javascript/extractor/tests/moduleTypes1/input/tst.js (100%) create mode 100644 javascript/extractor/tests/moduleTypes1/output/trap/package.json.trap create mode 100644 javascript/extractor/tests/moduleTypes1/output/trap/tst.js.trap create mode 100644 javascript/extractor/tests/moduleTypes2/input/package.json rename python/ql/test/library-tests/jump_to_defn/Sanity.expected => javascript/extractor/tests/moduleTypes2/input/tst2.js (100%) create mode 100644 javascript/extractor/tests/moduleTypes2/output/trap/package.json.trap create mode 100644 javascript/extractor/tests/moduleTypes2/output/trap/tst2.js.trap rename python/ql/test/library-tests/taint/general/TaintSanity.expected => javascript/extractor/tests/moduleTypes3/input/package.json (100%) rename python/ql/test/query-tests/analysis/Sanity/Sanity.expected => javascript/extractor/tests/moduleTypes3/input/tst.js (100%) create mode 100644 javascript/extractor/tests/moduleTypes3/output/trap/package.json.trap create mode 100644 javascript/extractor/tests/moduleTypes3/output/trap/tst.js.trap create mode 100644 javascript/extractor/tests/ts/input/importNonStrings.ts create mode 100644 javascript/extractor/tests/ts/output/trap/importNonStrings.ts.trap create mode 100644 javascript/ql/examples/qlpack.yml rename javascript/ql/examples/queries/dataflow/StoredXss/{StoredXssTrackedNode.ql => StoredXssTypeTracking.ql} (66%) create mode 100644 javascript/ql/src/Comments/CommentedOutCodeMetricOverview.qhelp create mode 100644 javascript/ql/src/Comments/CommentedOutCodeQuery.qhelp create mode 100644 javascript/ql/src/Comments/CommentedOutCodeReferences.qhelp create mode 100644 javascript/ql/src/LanguageFeatures/examples/NonLinearPatternTS.ts create mode 100644 javascript/ql/src/LanguageFeatures/examples/NonLinearPatternTSGood.ts create mode 100644 javascript/ql/src/Metrics/DuplicationProblems.qhelp create mode 100644 javascript/ql/src/Metrics/FCommentRatioCommon.qhelp create mode 100644 javascript/ql/src/Metrics/FLinesOfCodeOverview.qhelp create mode 100644 javascript/ql/src/Metrics/FLinesOfCodeReferences.qhelp create mode 100644 javascript/ql/src/Metrics/FLinesOfDuplicatedCodeCommon.qhelp create mode 100644 javascript/ql/src/Metrics/FLinesOfSimilarCodeCommon.qhelp create mode 100644 javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.qhelp create mode 100644 javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.ql create mode 100644 javascript/ql/src/Security/CWE-094/examples/ImproperCodeSanitization.js create mode 100644 javascript/ql/src/Security/CWE-094/examples/ImproperCodeSanitizationFixed.js create mode 100644 javascript/ql/src/Security/CWE-116/IncompleteMultiCharacterSanitization.qhelp create mode 100644 javascript/ql/src/Security/CWE-116/IncompleteMultiCharacterSanitization.ql create mode 100644 javascript/ql/src/Security/CWE-200/PrivateFileExposure.qhelp create mode 100644 javascript/ql/src/Security/CWE-200/PrivateFileExposure.ql create mode 100644 javascript/ql/src/Security/CWE-200/examples/PrivateFileExposure.js create mode 100644 javascript/ql/src/Security/CWE-200/examples/PrivateFileExposureFixed.js create mode 100644 javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.qhelp create mode 100644 javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.ql create mode 100644 javascript/ql/src/Security/CWE-295/examples/DisablingCertificateValidation.js create mode 100644 javascript/ql/src/Security/CWE-312/BuildArtifactLeak.qhelp create mode 100644 javascript/ql/src/Security/CWE-312/BuildArtifactLeak.ql create mode 100644 javascript/ql/src/Security/CWE-312/examples/build-leak-fixed.js create mode 100644 javascript/ql/src/Security/CWE-312/examples/build-leak.js create mode 100644 javascript/ql/src/Security/CWE-327/BadRandomness.qhelp create mode 100644 javascript/ql/src/Security/CWE-327/BadRandomness.ql create mode 100644 javascript/ql/src/Security/CWE-327/examples/bad-random-fixed.js create mode 100644 javascript/ql/src/Security/CWE-327/examples/bad-random-fixed2.js create mode 100644 javascript/ql/src/Security/CWE-327/examples/bad-random.js create mode 100644 javascript/ql/src/Security/CWE-829/InsecureDownload.qhelp create mode 100644 javascript/ql/src/Security/CWE-829/InsecureDownload.ql create mode 100644 javascript/ql/src/Security/CWE-829/examples/insecure-download.js create mode 100644 javascript/ql/src/Security/CWE-829/examples/secure-download.js create mode 100644 javascript/ql/src/codeql-suites/javascript-security-and-quality.qls create mode 100644 javascript/ql/src/codeql-suites/javascript-security-extended.qls create mode 100644 javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp create mode 100644 javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql create mode 100644 javascript/ql/src/experimental/Security/CWE-020/examples/postMessageInsufficientCheck.js create mode 100644 javascript/ql/src/experimental/Security/CWE-020/examples/postMessageNoOriginCheck.js create mode 100644 javascript/ql/src/experimental/Security/CWE-020/examples/postMessageWithOriginCheck.js create mode 100644 javascript/ql/src/experimental/Security/CWE-090/LdapInjection.qhelp create mode 100644 javascript/ql/src/experimental/Security/CWE-090/LdapInjection.ql create mode 100644 javascript/ql/src/experimental/Security/CWE-090/LdapInjection.qll create mode 100644 javascript/ql/src/experimental/Security/CWE-090/LdapInjectionCustomizations.qll create mode 100644 javascript/ql/src/experimental/Security/CWE-090/Ldapjs.qll create mode 100644 javascript/ql/src/experimental/Security/CWE-090/examples/example_bad1.js create mode 100644 javascript/ql/src/experimental/Security/CWE-090/examples/example_bad2.js create mode 100644 javascript/ql/src/experimental/Security/CWE-090/examples/example_good1.js create mode 100644 javascript/ql/src/experimental/Security/CWE-090/examples/example_good2.js create mode 100644 javascript/ql/src/experimental/Security/CWE-117/LogInjection.help create mode 100644 javascript/ql/src/experimental/Security/CWE-117/LogInjection.ql create mode 100644 javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll create mode 100644 javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionBad.js create mode 100644 javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionGood.js create mode 100644 javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.help create mode 100644 javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql create mode 100644 javascript/ql/src/experimental/Security/CWE-347/examples/JWTMissingSecretOrPublicKeyVerification.js create mode 100644 javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp create mode 100644 javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql create mode 100644 javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll create mode 100644 javascript/ql/src/meta/ApiGraphs/ApiGraphEdges.ql create mode 100644 javascript/ql/src/meta/ApiGraphs/ApiGraphNodes.ql create mode 100644 javascript/ql/src/meta/ApiGraphs/ApiGraphPointsToEdges.ql create mode 100644 javascript/ql/src/meta/ApiGraphs/ApiGraphRhsNodes.ql create mode 100644 javascript/ql/src/meta/ApiGraphs/ApiGraphUseNodes.ql create mode 100644 javascript/ql/src/meta/MetaMetrics.qll create mode 100644 javascript/ql/src/meta/analysis-quality/ResolvableImports.ql create mode 100644 javascript/ql/src/meta/analysis-quality/RouteHandlers.ql create mode 100644 javascript/ql/src/meta/analysis-quality/SanitizersReachableFromSource.ql create mode 100644 javascript/ql/src/meta/analysis-quality/SinksReachableFromSanitizer.ql create mode 100644 javascript/ql/src/meta/analysis-quality/TaintMetrics.qll create mode 100644 javascript/ql/src/meta/analysis-quality/TaintSinks.ql create mode 100644 javascript/ql/src/meta/analysis-quality/TaintSources.ql create mode 100644 javascript/ql/src/meta/analysis-quality/TaintSteps.ql create mode 100644 javascript/ql/src/meta/analysis-quality/TaintedNodes.ql create mode 100644 javascript/ql/src/meta/types/TypedExprs.ql create mode 100644 javascript/ql/src/meta/types/TypesWithQualifiedName.ql create mode 100644 javascript/ql/src/semmle/javascript/ApiGraphs.qll create mode 100644 javascript/ql/src/semmle/javascript/Generators.qll create mode 100644 javascript/ql/src/semmle/javascript/JsonStringifiers.qll create mode 100644 javascript/ql/src/semmle/javascript/dataflow/internal/PreCallGraphStep.qll create mode 100644 javascript/ql/src/semmle/javascript/frameworks/Micro.qll create mode 100644 javascript/ql/src/semmle/javascript/frameworks/ServerLess.qll create mode 100644 javascript/ql/src/semmle/javascript/heuristics/HeuristicSinks.qll create mode 100644 javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeak.qll create mode 100644 javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeakCustomizations.qll create mode 100644 javascript/ql/src/semmle/javascript/security/dataflow/ImproperCodeSanitization.qll create mode 100644 javascript/ql/src/semmle/javascript/security/dataflow/ImproperCodeSanitizationCustomizations.qll create mode 100644 javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownload.qll create mode 100644 javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll create mode 100644 javascript/ql/test/ApiGraphs/VerifyAssertions.qll create mode 100644 javascript/ql/test/ApiGraphs/argprops/VerifyAssertions.expected create mode 100644 javascript/ql/test/ApiGraphs/argprops/VerifyAssertions.ql create mode 100644 javascript/ql/test/ApiGraphs/argprops/index.js create mode 100644 javascript/ql/test/ApiGraphs/argprops/package.json create mode 100644 javascript/ql/test/ApiGraphs/async-await/VerifyAssertions.expected create mode 100644 javascript/ql/test/ApiGraphs/async-await/VerifyAssertions.ql create mode 100644 javascript/ql/test/ApiGraphs/async-await/index.js create mode 100644 javascript/ql/test/ApiGraphs/async-await/package.json create mode 100644 javascript/ql/test/ApiGraphs/branching-flow/VerifyAssertions.expected create mode 100644 javascript/ql/test/ApiGraphs/branching-flow/VerifyAssertions.ql create mode 100644 javascript/ql/test/ApiGraphs/branching-flow/index.js create mode 100644 javascript/ql/test/ApiGraphs/branching-flow/package.json create mode 100644 javascript/ql/test/ApiGraphs/classes/VerifyAssertions.expected create mode 100644 javascript/ql/test/ApiGraphs/classes/VerifyAssertions.ql create mode 100644 javascript/ql/test/ApiGraphs/classes/classes.js create mode 100644 javascript/ql/test/ApiGraphs/classes/package.json create mode 100644 javascript/ql/test/ApiGraphs/ctor-arg/VerifyAssertions.expected create mode 100644 javascript/ql/test/ApiGraphs/ctor-arg/VerifyAssertions.ql create mode 100644 javascript/ql/test/ApiGraphs/ctor-arg/index.js create mode 100644 javascript/ql/test/ApiGraphs/ctor-arg/package.json create mode 100644 javascript/ql/test/ApiGraphs/custom-entry-point/VerifyAssertions.expected create mode 100644 javascript/ql/test/ApiGraphs/custom-entry-point/VerifyAssertions.ql create mode 100644 javascript/ql/test/ApiGraphs/custom-entry-point/index.js create mode 100644 javascript/ql/test/ApiGraphs/custom-entry-point/package.json create mode 100644 javascript/ql/test/ApiGraphs/cyclic/VerifyAssertions.expected create mode 100644 javascript/ql/test/ApiGraphs/cyclic/VerifyAssertions.ql create mode 100644 javascript/ql/test/ApiGraphs/cyclic/index.js create mode 100644 javascript/ql/test/ApiGraphs/cyclic/package.json create mode 100644 javascript/ql/test/ApiGraphs/dynamic-prop-read/VerifyAssertions.expected create mode 100644 javascript/ql/test/ApiGraphs/dynamic-prop-read/VerifyAssertions.ql create mode 100644 javascript/ql/test/ApiGraphs/dynamic-prop-read/index.js create mode 100644 javascript/ql/test/ApiGraphs/dynamic-prop-read/package.json create mode 100644 javascript/ql/test/ApiGraphs/imprecise-export/VerifyAssertions.expected create mode 100644 javascript/ql/test/ApiGraphs/imprecise-export/VerifyAssertions.ql create mode 100644 javascript/ql/test/ApiGraphs/imprecise-export/index.js create mode 100644 javascript/ql/test/ApiGraphs/imprecise-export/package.json create mode 100644 javascript/ql/test/ApiGraphs/imprecision/VerifyAssertions.expected create mode 100644 javascript/ql/test/ApiGraphs/imprecision/VerifyAssertions.ql create mode 100644 javascript/ql/test/ApiGraphs/imprecision/index.js create mode 100644 javascript/ql/test/ApiGraphs/imprecision/package.json create mode 100644 javascript/ql/test/ApiGraphs/namespaced-package/VerifyAssertions.expected create mode 100644 javascript/ql/test/ApiGraphs/namespaced-package/VerifyAssertions.ql create mode 100644 javascript/ql/test/ApiGraphs/namespaced-package/index.js create mode 100644 javascript/ql/test/ApiGraphs/namespaced-package/package.json create mode 100644 javascript/ql/test/ApiGraphs/nested-property-export/VerifyAssertions.expected create mode 100644 javascript/ql/test/ApiGraphs/nested-property-export/VerifyAssertions.ql create mode 100644 javascript/ql/test/ApiGraphs/nested-property-export/index.js create mode 100644 javascript/ql/test/ApiGraphs/nested-property-export/package.json create mode 100644 javascript/ql/test/ApiGraphs/nonlocal/VerifyAssertions.expected create mode 100644 javascript/ql/test/ApiGraphs/nonlocal/VerifyAssertions.ql create mode 100644 javascript/ql/test/ApiGraphs/nonlocal/index.js create mode 100644 javascript/ql/test/ApiGraphs/nonlocal/package.json create mode 100644 javascript/ql/test/ApiGraphs/partial-invoke/VerifyAssertions.expected create mode 100644 javascript/ql/test/ApiGraphs/partial-invoke/VerifyAssertions.ql create mode 100644 javascript/ql/test/ApiGraphs/partial-invoke/index.js create mode 100644 javascript/ql/test/ApiGraphs/partial-invoke/package.json create mode 100644 javascript/ql/test/ApiGraphs/promises/VerifyAssertions.expected create mode 100644 javascript/ql/test/ApiGraphs/promises/VerifyAssertions.ql create mode 100644 javascript/ql/test/ApiGraphs/promises/index.js create mode 100644 javascript/ql/test/ApiGraphs/promises/package.json create mode 100644 javascript/ql/test/ApiGraphs/property-read-from-argument/VerifyAssertions.expected create mode 100644 javascript/ql/test/ApiGraphs/property-read-from-argument/VerifyAssertions.ql create mode 100644 javascript/ql/test/ApiGraphs/property-read-from-argument/index.js create mode 100644 javascript/ql/test/ApiGraphs/property-read-from-argument/package.json create mode 100644 javascript/ql/test/ApiGraphs/reexport/VerifyAssertions.expected create mode 100644 javascript/ql/test/ApiGraphs/reexport/VerifyAssertions.ql create mode 100644 javascript/ql/test/ApiGraphs/reexport/index.js create mode 100644 javascript/ql/test/ApiGraphs/reexport/lib/impl.js create mode 100644 javascript/ql/test/ApiGraphs/reexport/lib/stuff.js create mode 100644 javascript/ql/test/ApiGraphs/reexport/lib/utils.js create mode 100644 javascript/ql/test/ApiGraphs/reexport/lib/utils2.js create mode 100644 javascript/ql/test/ApiGraphs/reexport/package.json create mode 100644 javascript/ql/test/ApiGraphs/return-self/VerifyAssertions.expected create mode 100644 javascript/ql/test/ApiGraphs/return-self/VerifyAssertions.ql create mode 100644 javascript/ql/test/ApiGraphs/return-self/index.js create mode 100644 javascript/ql/test/ApiGraphs/return-self/package.json create mode 100644 javascript/ql/test/ApiGraphs/typed/NodeOfType.expected create mode 100644 javascript/ql/test/ApiGraphs/typed/NodeOfType.ql create mode 100644 javascript/ql/test/ApiGraphs/typed/VerifyAssertions.expected create mode 100644 javascript/ql/test/ApiGraphs/typed/VerifyAssertions.ql create mode 100644 javascript/ql/test/ApiGraphs/typed/index.ts create mode 100644 javascript/ql/test/ApiGraphs/typed/package.json create mode 100644 javascript/ql/test/ApiGraphs/typed/shim.d.ts create mode 100644 javascript/ql/test/ApiGraphs/typed/tsconfig.json create mode 100644 javascript/ql/test/library-tests/AMD/tst5.js create mode 100644 javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/reexport/a.js create mode 100644 javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/reexport/b.js create mode 100644 javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/reexport/import.js create mode 100644 javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/returned-function.js create mode 100644 javascript/ql/test/library-tests/CallGraphs/FullTest/non-strict.js create mode 100644 javascript/ql/test/library-tests/CallGraphs/FullTest/strict.js create mode 100644 javascript/ql/test/library-tests/CallGraphs/FullTest/strict2.js create mode 100644 javascript/ql/test/library-tests/ClassNode/getFieldTypeAnnotation.expected create mode 100644 javascript/ql/test/library-tests/ClassNode/getFieldTypeAnnotation.ql create mode 100644 javascript/ql/test/library-tests/DOM/externs/externs.js create mode 100644 javascript/ql/test/library-tests/DOM/nameditems.js create mode 100644 javascript/ql/test/library-tests/DataFlow/basicBlock.expected create mode 100644 javascript/ql/test/library-tests/DataFlow/basicBlock.ql create mode 100644 javascript/ql/test/library-tests/DataFlow/getImmediatePredecessor.expected create mode 100644 javascript/ql/test/library-tests/DataFlow/getImmediatePredecessor.ql create mode 100644 javascript/ql/test/library-tests/Expr/assignment2.ts create mode 100644 javascript/ql/test/library-tests/Files/binary.js create mode 100644 javascript/ql/test/library-tests/Generators/DataFlow.expected create mode 100644 javascript/ql/test/library-tests/Generators/DataFlow.ql create mode 100644 javascript/ql/test/library-tests/Generators/generators.js delete mode 100644 javascript/ql/test/library-tests/InterProceduralFlow/TrackedNodes.expected delete mode 100644 javascript/ql/test/library-tests/InterProceduralFlow/TrackedNodes.ql create mode 100644 javascript/ql/test/library-tests/InterProceduralFlow/async.js create mode 100644 javascript/ql/test/library-tests/InterProceduralFlow/underscore.js create mode 100644 javascript/ql/test/library-tests/ModuleTypes/commonjs.cjs create mode 100644 javascript/ql/test/library-tests/ModuleTypes/commonjsPackage/innermjs.mjs create mode 100644 javascript/ql/test/library-tests/ModuleTypes/commonjsPackage/package.json create mode 100644 javascript/ql/test/library-tests/ModuleTypes/commonjsPackage/tst.js create mode 100644 javascript/ql/test/library-tests/ModuleTypes/import.js create mode 100644 javascript/ql/test/library-tests/ModuleTypes/mjs.mjs create mode 100644 javascript/ql/test/library-tests/ModuleTypes/modulePackage/package.json create mode 100644 javascript/ql/test/library-tests/ModuleTypes/modulePackage/subdir/innercjs.cjs create mode 100644 javascript/ql/test/library-tests/ModuleTypes/modulePackage/subdir/subfile.js create mode 100644 javascript/ql/test/library-tests/ModuleTypes/modulePackage/tst.js create mode 100644 javascript/ql/test/library-tests/ModuleTypes/require.js create mode 100644 javascript/ql/test/library-tests/ModuleTypes/script.js create mode 100644 javascript/ql/test/library-tests/ModuleTypes/tests.expected create mode 100644 javascript/ql/test/library-tests/ModuleTypes/tests.ql create mode 100644 javascript/ql/test/library-tests/NodeJS/mjs-files/createRequire.mjs create mode 100644 javascript/ql/test/library-tests/NodeJS/reexport/a.js create mode 100644 javascript/ql/test/library-tests/NodeJS/reexport/b.js create mode 100644 javascript/ql/test/library-tests/PackageExports/absent_main/index.js create mode 100644 javascript/ql/test/library-tests/PackageExports/absent_main/package.json create mode 100644 javascript/ql/test/library-tests/PackageExports/esmodules/main.js create mode 100644 javascript/ql/test/library-tests/PackageExports/esmodules/package.json create mode 100644 javascript/ql/test/library-tests/PackageExports/lib1/baz.js create mode 100644 javascript/ql/test/library-tests/PackageExports/lib1/reexport/a.js create mode 100644 javascript/ql/test/library-tests/PackageExports/lib1/reexport/b.js create mode 100644 javascript/ql/test/library-tests/Portals/src/m5/index.js create mode 100644 javascript/ql/test/library-tests/Portals/src/m5/package.json create mode 100644 javascript/ql/test/library-tests/TaintTracking/json-stringify.js create mode 100644 javascript/ql/test/library-tests/TaintTracking/static-capture-groups.js create mode 100644 javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/Test.expected create mode 100644 javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/Test.ql create mode 100644 javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/htmlfile.html create mode 100644 javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/other.ts create mode 100644 javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/test.vue create mode 100644 javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/tsconfig.json delete mode 100644 javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/ExpansiveTypes.expected delete mode 100644 javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/ExpansiveTypes.ql delete mode 100644 javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/NonExpansiveTypes.expected delete mode 100644 javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/NonExpansiveTypes.ql create mode 100644 javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/Types.expected create mode 100644 javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/Types.ql create mode 100644 javascript/ql/test/library-tests/TypeScript/HasQualifiedNameFallback/Test.expected create mode 100644 javascript/ql/test/library-tests/TypeScript/HasQualifiedNameFallback/Test.ql create mode 100644 javascript/ql/test/library-tests/TypeScript/HasQualifiedNameFallback/relative.ts create mode 100644 javascript/ql/test/library-tests/TypeScript/HasQualifiedNameFallback/tst.ts create mode 100644 javascript/ql/test/library-tests/TypeScript/RegressionTests/PartialFunctionArgs/Test.expected create mode 100644 javascript/ql/test/library-tests/TypeScript/RegressionTests/PartialFunctionArgs/Test.ql create mode 100644 javascript/ql/test/library-tests/TypeScript/RegressionTests/PartialFunctionArgs/tsconfig.json create mode 100644 javascript/ql/test/library-tests/TypeScript/RegressionTests/PartialFunctionArgs/tst.ts create mode 100644 javascript/ql/test/library-tests/TypeTracking/TypeTracking.expected create mode 100644 javascript/ql/test/library-tests/TypeTracking/TypeTracking.ql create mode 100644 javascript/ql/test/library-tests/TypeTracking/client2.js create mode 100644 javascript/ql/test/library-tests/TypeTracking/deprecated.js create mode 100644 javascript/ql/test/library-tests/TypeTracking/reexport/a.js create mode 100644 javascript/ql/test/library-tests/TypeTracking/reexport/b.js create mode 100644 javascript/ql/test/library-tests/TypeTracking/reexport/test.js create mode 100644 javascript/ql/test/library-tests/frameworks/Express/RouteHandlerContainer.expected create mode 100644 javascript/ql/test/library-tests/frameworks/Express/RouteHandlerContainer.qll create mode 100644 javascript/ql/test/library-tests/frameworks/Express/src/advanced-routehandler-registration.js create mode 100644 javascript/ql/test/library-tests/frameworks/Express/src/controllers/handler-in-bulk-require.js create mode 100644 javascript/ql/test/library-tests/frameworks/Express/src/controllers/handler-in-dynamic-require.js create mode 100644 javascript/ql/test/library-tests/frameworks/Express/src/controllers/index.js create mode 100644 javascript/ql/test/library-tests/frameworks/Express/src/route-collection.js create mode 100644 javascript/ql/test/library-tests/frameworks/Micro/TestMicro.expected create mode 100644 javascript/ql/test/library-tests/frameworks/Micro/TestMicro.ql create mode 100644 javascript/ql/test/library-tests/frameworks/Micro/tst.js create mode 100644 javascript/ql/test/library-tests/frameworks/NodeJSLib/src/indirect.js create mode 100644 javascript/ql/test/library-tests/frameworks/NodeJSLib/src/indirect2.js create mode 100644 javascript/ql/test/library-tests/frameworks/ReactJS/ReactName.qll create mode 100644 javascript/ql/test/library-tests/frameworks/SQL/mysql1a.js create mode 100644 javascript/ql/test/library-tests/frameworks/SQL/sqliteArray.js create mode 100644 javascript/ql/test/library-tests/frameworks/ServerLess/test.expected create mode 100644 javascript/ql/test/library-tests/frameworks/ServerLess/test.ql create mode 100644 javascript/ql/test/library-tests/frameworks/ServerLess/tst1/backend/src/mylibrary.js create mode 100644 javascript/ql/test/library-tests/frameworks/ServerLess/tst1/template.yml create mode 100644 javascript/ql/test/library-tests/frameworks/ServerLess/tst2/nodejs/index.js create mode 100644 javascript/ql/test/library-tests/frameworks/ServerLess/tst2/template.yml create mode 100644 javascript/ql/test/library-tests/frameworks/ServerLess/tst3/function/index.js create mode 100644 javascript/ql/test/library-tests/frameworks/ServerLess/tst3/template.yml create mode 100644 javascript/ql/test/library-tests/frameworks/ServerLess/tst4/app.js create mode 100644 javascript/ql/test/library-tests/frameworks/ServerLess/tst4/template.yml create mode 100644 javascript/ql/test/library-tests/frameworks/ServerLess/tst5/app.js create mode 100644 javascript/ql/test/library-tests/frameworks/ServerLess/tst5/template.yml create mode 100644 javascript/ql/test/library-tests/frameworks/Vue/single-file-component-4.vue create mode 100644 javascript/ql/test/library-tests/frameworks/Vue/single-file-component-5.vue create mode 100644 javascript/ql/test/query-tests/Declarations/DeadStoreOfProperty/exports.js create mode 100644 javascript/ql/test/query-tests/Declarations/UnusedVariable/ts/tsconfig.json create mode 100644 javascript/ql/test/query-tests/Declarations/UnusedVariable/ts/usesreact.tsx create mode 100644 javascript/ql/test/query-tests/Expressions/UnneededDefensiveProgramming/regression.js create mode 100644 javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPatternTS.ts create mode 100644 javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPatternTSGood.ts create mode 100644 javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-access-paths.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/typescript.ts create mode 100644 javascript/ql/test/query-tests/Security/CWE-078/Consistency.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-078/Consistency.ql create mode 100644 javascript/ql/test/query-tests/Security/CWE-078/exec-sh.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-078/exec-sh2.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-079/Consistency.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-079/Consistency.ql create mode 100644 javascript/ql/test/query-tests/Security/CWE-089/untyped/Consistency.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-089/untyped/Consistency.ql create mode 100644 javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/ImproperCodeSanitization.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/ImproperCodeSanitization.qlref create mode 100644 javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/bad-code-sanitization.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-094/tmp.html create mode 100644 javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteMultiCharacterSanitization.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteMultiCharacterSanitization.qlref create mode 100644 javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/tst-multi-character-sanitization.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-200/PrivateFileExposure.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-200/PrivateFileExposure.qlref create mode 100644 javascript/ql/test/query-tests/Security/CWE-200/lib/package.json create mode 100644 javascript/ql/test/query-tests/Security/CWE-200/lib/tst.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-200/private-file-exposure.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-295/DisablingCertificateValidation.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-295/DisablingCertificateValidation.qlref create mode 100644 javascript/ql/test/query-tests/Security/CWE-295/tst.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-312/BuildArtifactLeak.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-312/BuildArtifactLeak.qlref create mode 100644 javascript/ql/test/query-tests/Security/CWE-312/build-leaks.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.qlref create mode 100644 javascript/ql/test/query-tests/Security/CWE-327/bad-random.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/sanitizer.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/tst13.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/tst14.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-614/InsecureCookies.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-614/InsecureCookies.qlref create mode 100644 javascript/ql/test/query-tests/Security/CWE-614/test_cookie-session.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-614/test_express-session.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-614/test_httpserver.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-614/test_jscookie.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-614/test_responseCookie.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-770/rateLimit.ts create mode 100644 javascript/ql/test/query-tests/Security/CWE-770/tst2.ts create mode 100644 javascript/ql/test/query-tests/Security/CWE-829/InsecureDownload.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-829/InsecureDownload.qlref create mode 100644 javascript/ql/test/query-tests/Security/CWE-829/insecure-download.js create mode 100644 javascript/ql/test/query-tests/filters/ClassifyFiles/MyComponent.vue create mode 100644 javascript/ql/test/testUtilities/ConsistencyChecking.qll create mode 100644 javascript/upgrades/2dc7a0389827d235763a3748aba73c2d4a677b15/old.dbscheme create mode 100644 javascript/upgrades/2dc7a0389827d235763a3748aba73c2d4a677b15/semmlecode.javascript.dbscheme create mode 100644 javascript/upgrades/2dc7a0389827d235763a3748aba73c2d4a677b15/upgrade.properties create mode 100644 javascript/upgrades/c73fbfca57f3d593b9ff50c6aa3a886d6888efec/old.dbscheme create mode 100644 javascript/upgrades/c73fbfca57f3d593b9ff50c6aa3a886d6888efec/semmlecode.javascript.dbscheme create mode 100644 javascript/upgrades/c73fbfca57f3d593b9ff50c6aa3a886d6888efec/upgrade.properties create mode 100644 misc/scripts/generate-code-scanning-query-list.py create mode 100644 misc/suite-helpers/security-and-quality-selectors.yml create mode 100644 misc/suite-helpers/security-extended-selectors.yml create mode 100644 python/ql/examples/qlpack.yml create mode 100644 python/ql/src/Lexical/CommentedOutCodeMetricOverview.qhelp create mode 100644 python/ql/src/Lexical/CommentedOutCodeQuery.qhelp create mode 100644 python/ql/src/Lexical/CommentedOutCodeReferences.qhelp create mode 100644 python/ql/src/Metrics/FLinesOfDuplicatedCodeCommon.qhelp create mode 100644 python/ql/src/analysis/Consistency.ql delete mode 100644 python/ql/src/analysis/Sanity.ql create mode 100644 python/ql/src/codeql-suites/python-security-and-quality.qls create mode 100644 python/ql/src/codeql-suites/python-security-extended.qls create mode 100644 python/ql/src/experimental/Customizations.qll create mode 100755 python/ql/src/experimental/Security-new-dataflow/CWE-078/CommandInjection.ql create mode 100644 python/ql/src/experimental/Security-new-dataflow/CWE-094/CodeInjection.ql create mode 100644 python/ql/src/experimental/Security-new-dataflow/CWE-502/UnsafeDeserialization.ql create mode 100755 python/ql/src/experimental/Security-new-dataflow/promote.sh create mode 100644 python/ql/src/experimental/Security/CWE-074/JinjaBad.py create mode 100644 python/ql/src/experimental/Security/CWE-074/JinjaGood.py create mode 100644 python/ql/src/experimental/Security/CWE-074/TemplateInjection.qhelp create mode 100644 python/ql/src/experimental/Security/CWE-074/TemplateInjection.ql create mode 100644 python/ql/src/experimental/Security/CWE-091/Xslt.qhelp create mode 100644 python/ql/src/experimental/Security/CWE-091/Xslt.ql create mode 100644 python/ql/src/experimental/Security/CWE-091/xslt.py create mode 100644 python/ql/src/experimental/Security/CWE-643/xpath.qhelp create mode 100644 python/ql/src/experimental/Security/CWE-643/xpath.ql create mode 100644 python/ql/src/experimental/Security/CWE-643/xpathBad.py create mode 100644 python/ql/src/experimental/Security/CWE-643/xpathGood.py create mode 100644 python/ql/src/experimental/dataflow/DataFlow.qll create mode 100644 python/ql/src/experimental/dataflow/DataFlow2.qll create mode 100644 python/ql/src/experimental/dataflow/RemoteFlowSources.qll create mode 100644 python/ql/src/experimental/dataflow/TaintTracking.qll create mode 100644 python/ql/src/experimental/dataflow/TypeTracker.qll create mode 100644 python/ql/src/experimental/dataflow/internal/Attributes.qll create mode 100644 python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll create mode 100644 python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll create mode 100644 python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll create mode 100644 python/ql/src/experimental/dataflow/internal/DataFlowImplConsistency.qll create mode 100644 python/ql/src/experimental/dataflow/internal/DataFlowImplSpecific.qll create mode 100644 python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll create mode 100644 python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll create mode 100644 python/ql/src/experimental/dataflow/internal/DataFlowUtil.qll create mode 100644 python/ql/src/experimental/dataflow/internal/TaintTrackingPrivate.qll create mode 100644 python/ql/src/experimental/dataflow/internal/TaintTrackingPublic.qll create mode 100644 python/ql/src/experimental/dataflow/internal/readme.md create mode 100644 python/ql/src/experimental/dataflow/internal/tainttracking1/TaintTrackingImpl.qll create mode 100644 python/ql/src/experimental/dataflow/internal/tainttracking1/TaintTrackingParameter.qll create mode 100644 python/ql/src/experimental/semmle/python/Concepts.qll create mode 100644 python/ql/src/experimental/semmle/python/Frameworks.qll create mode 100644 python/ql/src/experimental/semmle/python/frameworks/Dill.qll create mode 100644 python/ql/src/experimental/semmle/python/frameworks/Django.qll create mode 100644 python/ql/src/experimental/semmle/python/frameworks/Flask.qll create mode 100644 python/ql/src/experimental/semmle/python/frameworks/Invoke.qll create mode 100644 python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll create mode 100644 python/ql/src/experimental/semmle/python/frameworks/Werkzeug.qll create mode 100644 python/ql/src/experimental/semmle/python/frameworks/Yaml.qll create mode 100644 python/ql/src/experimental/semmle/python/security/injection/XSLT.qll create mode 100644 python/ql/src/experimental/semmle/python/security/injection/Xpath.qll create mode 100644 python/ql/src/experimental/semmle/python/templates/Airspeed.qll create mode 100644 python/ql/src/experimental/semmle/python/templates/Bottle.qll create mode 100644 python/ql/src/experimental/semmle/python/templates/Chameleon.qll create mode 100644 python/ql/src/experimental/semmle/python/templates/Cheetah.qll create mode 100644 python/ql/src/experimental/semmle/python/templates/Chevron.qll create mode 100644 python/ql/src/experimental/semmle/python/templates/DjangoTemplate.qll create mode 100644 python/ql/src/experimental/semmle/python/templates/FlaskTemplate.qll create mode 100644 python/ql/src/experimental/semmle/python/templates/Genshi.qll create mode 100644 python/ql/src/experimental/semmle/python/templates/Jinja.qll create mode 100644 python/ql/src/experimental/semmle/python/templates/Mako.qll create mode 100644 python/ql/src/experimental/semmle/python/templates/SSTISink.qll create mode 100644 python/ql/src/experimental/semmle/python/templates/Ssti.qll create mode 100644 python/ql/src/experimental/semmle/python/templates/TRender.qll create mode 100644 python/ql/src/meta/MetaMetrics.qll create mode 100644 python/ql/src/meta/analysis-quality/CallGraphQuality.qll create mode 100644 python/ql/src/meta/analysis-quality/PointsToResolvableCallRatio.ql create mode 100644 python/ql/src/meta/analysis-quality/PointsToResolvableCalls.ql create mode 100644 python/ql/src/meta/analysis-quality/PointsToResolvableCallsRelevantTarget.ql create mode 100644 python/ql/src/meta/analysis-quality/ResolvableCallCandidates.ql create mode 100644 python/ql/src/semmle/python/SpecialMethods.qll create mode 100644 python/ql/test/2/library-tests/PointsTo/class_properties/ClassValues.expected create mode 100644 python/ql/test/2/library-tests/PointsTo/class_properties/ClassValues.ql create mode 100644 python/ql/test/2/library-tests/PointsTo/class_properties/options create mode 100644 python/ql/test/2/library-tests/PointsTo/class_properties/test.py rename python/ql/test/2/library-tests/comprehensions/{SanityCheck.expected => ConsistencyCheck.expected} (100%) rename python/ql/test/2/library-tests/comprehensions/{SanityCheck.ql => ConsistencyCheck.ql} (60%) create mode 100644 python/ql/test/3/library-tests/PointsTo/class_properties/ClassValues.expected create mode 100644 python/ql/test/3/library-tests/PointsTo/class_properties/ClassValues.ql create mode 100644 python/ql/test/3/library-tests/PointsTo/class_properties/options create mode 100644 python/ql/test/3/library-tests/PointsTo/class_properties/test.py create mode 100644 python/ql/test/3/library-tests/functions/Function.getAChildNode.expected create mode 100644 python/ql/test/3/library-tests/functions/Function.getAChildNode.ql create mode 100644 python/ql/test/3/library-tests/functions/Function.getArg.expected create mode 100644 python/ql/test/3/library-tests/functions/Function.getArg.ql create mode 100644 python/ql/test/3/library-tests/functions/Function.getArgByName.expected create mode 100644 python/ql/test/3/library-tests/functions/Function.getArgByName.ql create mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getASubExpression.expected create mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getASubExpression.ql create mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAnnotation.expected create mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAnnotation.ql create mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getDefault.expected create mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getDefault.ql create mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getKwAnnotation.expected create mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getKwAnnotation.ql create mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getKwDefault.expected create mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getKwDefault.ql create mode 100644 python/ql/test/3/library-tests/functions/test.py create mode 100644 python/ql/test/3/library-tests/parameters/Annotations.expected create mode 100644 python/ql/test/3/library-tests/parameters/Annotations.ql create mode 100644 python/ql/test/3/library-tests/parameters/Defaults.expected create mode 100644 python/ql/test/3/library-tests/parameters/Defaults.ql create mode 100644 python/ql/test/3/library-tests/parameters/Special.expected create mode 100644 python/ql/test/3/library-tests/parameters/Special.ql create mode 100644 python/ql/test/3/library-tests/parameters/test.py create mode 100644 python/ql/test/3/library-tests/taint/strings/Taint.qll create mode 100644 python/ql/test/3/library-tests/taint/strings/TestTaint.expected create mode 100644 python/ql/test/3/library-tests/taint/strings/TestTaint.ql create mode 100644 python/ql/test/3/library-tests/taint/strings/test.py create mode 100644 python/ql/test/TestUtilities/InlineExpectationsTest.qll create mode 100644 python/ql/test/TestUtilities/InlineExpectationsTestPrivate.qll create mode 100644 python/ql/test/experimental/dataflow/basic/allFlowsConfig.qll create mode 100644 python/ql/test/experimental/dataflow/basic/callGraph.expected create mode 100644 python/ql/test/experimental/dataflow/basic/callGraph.ql create mode 100644 python/ql/test/experimental/dataflow/basic/callGraphSinks.expected create mode 100644 python/ql/test/experimental/dataflow/basic/callGraphSinks.ql create mode 100644 python/ql/test/experimental/dataflow/basic/callGraphSources.expected create mode 100644 python/ql/test/experimental/dataflow/basic/callGraphSources.ql create mode 100644 python/ql/test/experimental/dataflow/basic/global.expected create mode 100644 python/ql/test/experimental/dataflow/basic/global.ql create mode 100644 python/ql/test/experimental/dataflow/basic/globalStep.expected create mode 100644 python/ql/test/experimental/dataflow/basic/globalStep.ql create mode 100644 python/ql/test/experimental/dataflow/basic/local.expected create mode 100644 python/ql/test/experimental/dataflow/basic/local.ql create mode 100644 python/ql/test/experimental/dataflow/basic/localStep.expected create mode 100644 python/ql/test/experimental/dataflow/basic/localStep.ql create mode 100644 python/ql/test/experimental/dataflow/basic/maximalFlows.expected create mode 100644 python/ql/test/experimental/dataflow/basic/maximalFlows.ql create mode 100644 python/ql/test/experimental/dataflow/basic/maximalFlowsConfig.qll create mode 100644 python/ql/test/experimental/dataflow/basic/sinks.expected create mode 100644 python/ql/test/experimental/dataflow/basic/sinks.ql create mode 100644 python/ql/test/experimental/dataflow/basic/sources.expected create mode 100644 python/ql/test/experimental/dataflow/basic/sources.ql create mode 100644 python/ql/test/experimental/dataflow/basic/test.py create mode 100644 python/ql/test/experimental/dataflow/callGraphConfig.qll create mode 100644 python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected create mode 100644 python/ql/test/experimental/dataflow/consistency/dataflow-consistency.ql create mode 100644 python/ql/test/experimental/dataflow/consistency/module.py create mode 100644 python/ql/test/experimental/dataflow/consistency/test.py create mode 100644 python/ql/test/experimental/dataflow/coverage/argumentPassing.py create mode 100644 python/ql/test/experimental/dataflow/coverage/argumentRouting1.expected create mode 100644 python/ql/test/experimental/dataflow/coverage/argumentRouting1.ql create mode 100644 python/ql/test/experimental/dataflow/coverage/argumentRouting2.expected create mode 100644 python/ql/test/experimental/dataflow/coverage/argumentRouting2.ql create mode 100644 python/ql/test/experimental/dataflow/coverage/argumentRouting3.expected create mode 100644 python/ql/test/experimental/dataflow/coverage/argumentRouting3.ql create mode 100644 python/ql/test/experimental/dataflow/coverage/argumentRouting4.expected create mode 100644 python/ql/test/experimental/dataflow/coverage/argumentRouting4.ql create mode 100644 python/ql/test/experimental/dataflow/coverage/classes.py create mode 100644 python/ql/test/experimental/dataflow/coverage/classesCallGraph.expected create mode 100644 python/ql/test/experimental/dataflow/coverage/classesCallGraph.ql create mode 100644 python/ql/test/experimental/dataflow/coverage/dataflow.expected create mode 100644 python/ql/test/experimental/dataflow/coverage/dataflow.ql create mode 100644 python/ql/test/experimental/dataflow/coverage/datamodel.py create mode 100644 python/ql/test/experimental/dataflow/coverage/localFlow.expected create mode 100644 python/ql/test/experimental/dataflow/coverage/localFlow.ql create mode 100644 python/ql/test/experimental/dataflow/coverage/test.py create mode 100644 python/ql/test/experimental/dataflow/coverage/testlib.py create mode 100644 python/ql/test/experimental/dataflow/coverage/validTest.py create mode 100644 python/ql/test/experimental/dataflow/fieldflow/allLocalFlow.expected create mode 100644 python/ql/test/experimental/dataflow/fieldflow/allLocalFlow.ql create mode 100644 python/ql/test/experimental/dataflow/fieldflow/dataflow.expected create mode 100644 python/ql/test/experimental/dataflow/fieldflow/dataflow.ql create mode 100644 python/ql/test/experimental/dataflow/fieldflow/examples.py create mode 100644 python/ql/test/experimental/dataflow/fieldflow/globalStep.expected create mode 100644 python/ql/test/experimental/dataflow/fieldflow/globalStep.ql create mode 100644 python/ql/test/experimental/dataflow/fieldflow/localFlow.expected create mode 100644 python/ql/test/experimental/dataflow/fieldflow/localFlow.ql create mode 100644 python/ql/test/experimental/dataflow/fieldflow/postupdates.expected create mode 100644 python/ql/test/experimental/dataflow/fieldflow/postupdates.ql create mode 100644 python/ql/test/experimental/dataflow/fieldflow/test.py create mode 100644 python/ql/test/experimental/dataflow/global-flow/accesses.expected create mode 100644 python/ql/test/experimental/dataflow/global-flow/accesses.ql create mode 100644 python/ql/test/experimental/dataflow/global-flow/known.py create mode 100644 python/ql/test/experimental/dataflow/global-flow/test.py create mode 100644 python/ql/test/experimental/dataflow/import-helper/ImportHelper.expected create mode 100644 python/ql/test/experimental/dataflow/import-helper/ImportHelper.ql create mode 100644 python/ql/test/experimental/dataflow/import-helper/README.md create mode 100644 python/ql/test/experimental/dataflow/import-helper/mypkg/__init__.py create mode 100644 python/ql/test/experimental/dataflow/import-helper/mypkg/bar.py create mode 100644 python/ql/test/experimental/dataflow/import-helper/mypkg/foo.py create mode 100644 python/ql/test/experimental/dataflow/import-helper/test1.py create mode 100644 python/ql/test/experimental/dataflow/import-helper/test2.py create mode 100644 python/ql/test/experimental/dataflow/import-helper/test3.py create mode 100644 python/ql/test/experimental/dataflow/import-helper/test4.py create mode 100644 python/ql/test/experimental/dataflow/import-helper/test5.py create mode 100644 python/ql/test/experimental/dataflow/import-helper/test6.py create mode 100644 python/ql/test/experimental/dataflow/import-helper/test7.py create mode 100644 python/ql/test/experimental/dataflow/options create mode 100644 python/ql/test/experimental/dataflow/regression/custom_dataflow.expected create mode 100644 python/ql/test/experimental/dataflow/regression/custom_dataflow.ql create mode 100644 python/ql/test/experimental/dataflow/regression/dataflow.expected create mode 100644 python/ql/test/experimental/dataflow/regression/dataflow.ql create mode 100644 python/ql/test/experimental/dataflow/regression/module.py create mode 100644 python/ql/test/experimental/dataflow/regression/test.py create mode 100644 python/ql/test/experimental/dataflow/strange-essaflow/test.py create mode 100644 python/ql/test/experimental/dataflow/strange-essaflow/testFlow.expected create mode 100644 python/ql/test/experimental/dataflow/strange-essaflow/testFlow.ql create mode 100644 python/ql/test/experimental/dataflow/tainttracking/TestTaintLib.qll create mode 100644 python/ql/test/experimental/dataflow/tainttracking/basic/GlobalTaintTracking.expected create mode 100644 python/ql/test/experimental/dataflow/tainttracking/basic/GlobalTaintTracking.ql create mode 100644 python/ql/test/experimental/dataflow/tainttracking/basic/LocalTaintStep.expected create mode 100644 python/ql/test/experimental/dataflow/tainttracking/basic/LocalTaintStep.ql create mode 100644 python/ql/test/experimental/dataflow/tainttracking/basic/test.py create mode 100644 python/ql/test/experimental/dataflow/tainttracking/customSanitizer/TestTaint.expected create mode 100644 python/ql/test/experimental/dataflow/tainttracking/customSanitizer/TestTaint.ql create mode 100644 python/ql/test/experimental/dataflow/tainttracking/customSanitizer/test.py create mode 100644 python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep-py3/TestTaint.expected create mode 100644 python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep-py3/TestTaint.ql create mode 100644 python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep-py3/options create mode 100644 python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep-py3/test_collections.py create mode 100644 python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep-py3/test_pathlib.py create mode 100644 python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep-py3/test_string.py create mode 100644 python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep-py3/test_unpacking.py create mode 100644 python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep/TestTaint.expected create mode 100644 python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep/TestTaint.ql create mode 100644 python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep/test_collections.py create mode 100644 python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep/test_json.py create mode 100644 python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep/test_string.py create mode 100644 python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep/test_unpacking.py create mode 100644 python/ql/test/experimental/dataflow/tainttracking/defaultSanitizer/TestTaint.expected create mode 100644 python/ql/test/experimental/dataflow/tainttracking/defaultSanitizer/TestTaint.ql create mode 100644 python/ql/test/experimental/dataflow/tainttracking/defaultSanitizer/test_logical.py create mode 100644 python/ql/test/experimental/dataflow/tainttracking/defaultSanitizer/test_string_eq.py create mode 100644 python/ql/test/experimental/dataflow/tainttracking/taintlib.py create mode 100644 python/ql/test/experimental/dataflow/tainttracking/unwanted-global-flow/test.py create mode 100644 python/ql/test/experimental/dataflow/tainttracking/unwanted-global-flow/testTaint.expected create mode 100644 python/ql/test/experimental/dataflow/tainttracking/unwanted-global-flow/testTaint.ql create mode 100644 python/ql/test/experimental/dataflow/testConfig.qll create mode 100644 python/ql/test/experimental/dataflow/typetracking/attribute_tests.py create mode 100644 python/ql/test/experimental/dataflow/typetracking/import_as_attr.py create mode 100644 python/ql/test/experimental/dataflow/typetracking/import_as_attr_dotted.py create mode 100644 python/ql/test/experimental/dataflow/typetracking/moduleattr.expected create mode 100644 python/ql/test/experimental/dataflow/typetracking/moduleattr.ql create mode 100644 python/ql/test/experimental/dataflow/typetracking/mymodule.py create mode 100644 python/ql/test/experimental/dataflow/typetracking/test.py create mode 100644 python/ql/test/experimental/dataflow/typetracking/tracked.expected create mode 100644 python/ql/test/experimental/dataflow/typetracking/tracked.ql create mode 100644 python/ql/test/experimental/library-tests/CallGraph-implicit-init/PointsTo.expected create mode 100644 python/ql/test/experimental/library-tests/CallGraph-implicit-init/PointsTo.qlref create mode 100644 python/ql/test/experimental/library-tests/CallGraph-implicit-init/Relative.expected create mode 100644 python/ql/test/experimental/library-tests/CallGraph-implicit-init/Relative.qlref create mode 100644 python/ql/test/experimental/library-tests/CallGraph-implicit-init/TypeTracker.expected create mode 100644 python/ql/test/experimental/library-tests/CallGraph-implicit-init/TypeTracker.qlref create mode 100644 python/ql/test/experimental/library-tests/CallGraph-implicit-init/example.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph-implicit-init/foo/bar/a.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph-implicit-init/foo_explicit/__init__.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph-implicit-init/foo_explicit/bar/__init__.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph-implicit-init/foo_explicit/bar/a.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph-implicit-init/options create mode 100644 python/ql/test/experimental/library-tests/CallGraph-xfail/PointsTo.expected create mode 100644 python/ql/test/experimental/library-tests/CallGraph-xfail/PointsTo.qlref create mode 100644 python/ql/test/experimental/library-tests/CallGraph-xfail/README.md create mode 100644 python/ql/test/experimental/library-tests/CallGraph-xfail/annotation_xfail.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph-xfail/call_edge_xfail.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/CallGraphTest.qll create mode 100644 python/ql/test/experimental/library-tests/CallGraph/PointsTo.expected create mode 100644 python/ql/test/experimental/library-tests/CallGraph/PointsTo.ql create mode 100644 python/ql/test/experimental/library-tests/CallGraph/README.md create mode 100644 python/ql/test/experimental/library-tests/CallGraph/Relative.expected create mode 100644 python/ql/test/experimental/library-tests/CallGraph/Relative.ql create mode 100644 python/ql/test/experimental/library-tests/CallGraph/TypeTracker.expected create mode 100644 python/ql/test/experimental/library-tests/CallGraph/TypeTracker.ql create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/__init__.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/class_advanced.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/class_simple.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/runtime_decision.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/simple.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/underscore_prefix_func_name.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/test.py create mode 100644 python/ql/test/experimental/library-tests/frameworks/dill/ConceptsTest.expected create mode 100644 python/ql/test/experimental/library-tests/frameworks/dill/ConceptsTest.ql create mode 100644 python/ql/test/experimental/library-tests/frameworks/dill/Decoding.py create mode 100644 python/ql/test/experimental/library-tests/frameworks/flask/ConceptsTest.expected create mode 100644 python/ql/test/experimental/library-tests/frameworks/flask/ConceptsTest.ql create mode 100644 python/ql/test/experimental/library-tests/frameworks/flask/TestTaint.expected create mode 100644 python/ql/test/experimental/library-tests/frameworks/flask/TestTaint.ql create mode 100644 python/ql/test/experimental/library-tests/frameworks/flask/old_test.py create mode 100644 python/ql/test/experimental/library-tests/frameworks/flask/routing_test.py create mode 100644 python/ql/test/experimental/library-tests/frameworks/flask/taint_test.py create mode 100644 python/ql/test/experimental/library-tests/frameworks/invoke/ConceptsTest.expected create mode 100644 python/ql/test/experimental/library-tests/frameworks/invoke/ConceptsTest.ql create mode 100644 python/ql/test/experimental/library-tests/frameworks/invoke/invoke_test.py create mode 100644 python/ql/test/experimental/library-tests/frameworks/modeling-example/NaiveModel.expected create mode 100644 python/ql/test/experimental/library-tests/frameworks/modeling-example/NaiveModel.ql create mode 100644 python/ql/test/experimental/library-tests/frameworks/modeling-example/ProperModel.expected create mode 100644 python/ql/test/experimental/library-tests/frameworks/modeling-example/ProperModel.ql create mode 100644 python/ql/test/experimental/library-tests/frameworks/modeling-example/README.md create mode 100644 python/ql/test/experimental/library-tests/frameworks/modeling-example/SharedCode.qll create mode 100644 python/ql/test/experimental/library-tests/frameworks/modeling-example/test.py create mode 100644 python/ql/test/experimental/library-tests/frameworks/stdlib-py2/CodeExecution.py create mode 100644 python/ql/test/experimental/library-tests/frameworks/stdlib-py2/ConceptsTest.expected create mode 100644 python/ql/test/experimental/library-tests/frameworks/stdlib-py2/ConceptsTest.ql create mode 100644 python/ql/test/experimental/library-tests/frameworks/stdlib-py2/SystemCommandExecution.py create mode 100644 python/ql/test/experimental/library-tests/frameworks/stdlib-py2/options create mode 100644 python/ql/test/experimental/library-tests/frameworks/stdlib-py3/CodeExecution.py create mode 100644 python/ql/test/experimental/library-tests/frameworks/stdlib-py3/ConceptsTest.expected create mode 100644 python/ql/test/experimental/library-tests/frameworks/stdlib-py3/ConceptsTest.ql create mode 100644 python/ql/test/experimental/library-tests/frameworks/stdlib-py3/options create mode 100644 python/ql/test/experimental/library-tests/frameworks/stdlib/CodeExecution.py create mode 100644 python/ql/test/experimental/library-tests/frameworks/stdlib/CodeExecutionPossibleFP1.py create mode 100644 python/ql/test/experimental/library-tests/frameworks/stdlib/CodeExecutionPossibleFP2.py create mode 100644 python/ql/test/experimental/library-tests/frameworks/stdlib/CodeExecutionPossibleFP3.py create mode 100644 python/ql/test/experimental/library-tests/frameworks/stdlib/ConceptsTest.expected create mode 100644 python/ql/test/experimental/library-tests/frameworks/stdlib/ConceptsTest.ql create mode 100644 python/ql/test/experimental/library-tests/frameworks/stdlib/Decoding.py create mode 100644 python/ql/test/experimental/library-tests/frameworks/stdlib/SystemCommandExecution.py create mode 100644 python/ql/test/experimental/library-tests/frameworks/stdlib/TestTaint.expected create mode 100644 python/ql/test/experimental/library-tests/frameworks/stdlib/TestTaint.ql create mode 100644 python/ql/test/experimental/library-tests/frameworks/yaml/ConceptsTest.expected create mode 100644 python/ql/test/experimental/library-tests/frameworks/yaml/ConceptsTest.ql create mode 100644 python/ql/test/experimental/library-tests/frameworks/yaml/Decoding.py create mode 100644 python/ql/test/experimental/library-tests/options create mode 100644 python/ql/test/experimental/meta/ConceptsTest.qll create mode 100644 python/ql/test/experimental/meta/debug/dataflow.qll create mode 100644 python/ql/test/experimental/query-tests/Security-new-dataflow/CWE-078-py2/CommandInjection.expected create mode 100644 python/ql/test/experimental/query-tests/Security-new-dataflow/CWE-078-py2/CommandInjection.qlref create mode 100644 python/ql/test/experimental/query-tests/Security-new-dataflow/CWE-078-py2/command_injection.py create mode 100644 python/ql/test/experimental/query-tests/Security-new-dataflow/CWE-078-py2/options create mode 100644 python/ql/test/experimental/query-tests/Security-new-dataflow/CWE-078/CommandInjection.expected create mode 100644 python/ql/test/experimental/query-tests/Security-new-dataflow/CWE-078/CommandInjection.qlref create mode 100644 python/ql/test/experimental/query-tests/Security-new-dataflow/CWE-078/command_injection.py create mode 100644 python/ql/test/experimental/query-tests/Security-new-dataflow/CWE-094/CodeInjection.expected create mode 100644 python/ql/test/experimental/query-tests/Security-new-dataflow/CWE-094/CodeInjection.qlref create mode 100644 python/ql/test/experimental/query-tests/Security-new-dataflow/CWE-094/code_injection.py create mode 100644 python/ql/test/experimental/query-tests/Security-new-dataflow/CWE-502/UnsafeDeserialization.expected create mode 100644 python/ql/test/experimental/query-tests/Security-new-dataflow/CWE-502/UnsafeDeserialization.qlref create mode 100644 python/ql/test/experimental/query-tests/Security-new-dataflow/CWE-502/unsafe_deserialization.py create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-074/AirspeedSsti.py create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-074/BottleSsti.py create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-074/Chameleon.py create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-074/ChevronSsti.py create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-074/DjangoTemplates.py create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-074/FlaskTemplate.py create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-074/Genshi.py create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-074/JinjaSsti.py create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-074/MakoSsti.py create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-074/TRender.py create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-074/TemplateInjection.expected create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-074/TemplateInjection.qlref create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-074/options create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-091/Xslt.expected create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-091/Xslt.qlref create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-091/XsltSinks.expected create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-091/XsltSinks.ql create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-091/options create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-091/xslt.py create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-091/xsltInjection.py create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-091/xsltSinks.py create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-643/options create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-643/xpath.expected create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-643/xpath.py create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-643/xpath.qlref create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-643/xpathBad.py create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-643/xpathFlow.py create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-643/xpathGood.py create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-643/xpathSinks.expected create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-643/xpathSinks.ql create mode 100644 python/ql/test/experimental/query-tests/options create mode 100644 python/ql/test/experimental/semmle/python/templates/Airspeed.py create mode 100644 python/ql/test/experimental/semmle/python/templates/AirspeedSSTISinks.expected create mode 100644 python/ql/test/experimental/semmle/python/templates/AirspeedSSTISinks.ql create mode 100644 python/ql/test/experimental/semmle/python/templates/Bottle.py create mode 100644 python/ql/test/experimental/semmle/python/templates/BottleSSTISinks.expected create mode 100644 python/ql/test/experimental/semmle/python/templates/BottleSSTISinks.ql create mode 100644 python/ql/test/experimental/semmle/python/templates/Chameleon.py create mode 100644 python/ql/test/experimental/semmle/python/templates/ChameleonSSTISinks.expected create mode 100644 python/ql/test/experimental/semmle/python/templates/ChameleonSSTISinks.ql create mode 100644 python/ql/test/experimental/semmle/python/templates/CheetahSSTISinks.expected create mode 100644 python/ql/test/experimental/semmle/python/templates/CheetahSSTISinks.ql create mode 100644 python/ql/test/experimental/semmle/python/templates/CheetahSinks.py create mode 100644 python/ql/test/experimental/semmle/python/templates/ChevronSSTISinks.expected create mode 100644 python/ql/test/experimental/semmle/python/templates/ChevronSSTISinks.ql create mode 100644 python/ql/test/experimental/semmle/python/templates/ChevronSinks.py create mode 100644 python/ql/test/experimental/semmle/python/templates/DjangoSSTISinks.expected create mode 100644 python/ql/test/experimental/semmle/python/templates/DjangoSSTISinks.ql create mode 100644 python/ql/test/experimental/semmle/python/templates/DjangoTemplates.py create mode 100644 python/ql/test/experimental/semmle/python/templates/Genshi.py create mode 100644 python/ql/test/experimental/semmle/python/templates/GenshiSSTISinks.expected create mode 100644 python/ql/test/experimental/semmle/python/templates/GenshiSSTISinks.ql create mode 100644 python/ql/test/experimental/semmle/python/templates/Jinja2Templates.py create mode 100644 python/ql/test/experimental/semmle/python/templates/JinjaSSTISinks.expected create mode 100644 python/ql/test/experimental/semmle/python/templates/JinjaSSTISinks.ql create mode 100644 python/ql/test/experimental/semmle/python/templates/Mako.py create mode 100644 python/ql/test/experimental/semmle/python/templates/MakoSSTISinks.expected create mode 100644 python/ql/test/experimental/semmle/python/templates/MakoSSTISinks.ql create mode 100644 python/ql/test/experimental/semmle/python/templates/TRender.py create mode 100644 python/ql/test/experimental/semmle/python/templates/TRenderSSTISinks.expected create mode 100644 python/ql/test/experimental/semmle/python/templates/TRenderSSTISinks.ql create mode 100644 python/ql/test/experimental/semmle/python/templates/options rename python/ql/test/library-tests/ControlFlow/dominators/{DominatesSanity.expected => DominatesConsistency.expected} (100%) create mode 100644 python/ql/test/library-tests/ControlFlow/dominators/DominatesConsistency.ql delete mode 100644 python/ql/test/library-tests/ControlFlow/dominators/DominatesSanity.ql create mode 100644 python/ql/test/library-tests/PointsTo/new/Consistency.expected create mode 100644 python/ql/test/library-tests/PointsTo/new/Consistency.ql delete mode 100644 python/ql/test/library-tests/PointsTo/new/Sanity.ql create mode 100644 python/ql/test/library-tests/PointsTo/regressions/missing/metaclass/getACall.expected create mode 100644 python/ql/test/library-tests/PointsTo/regressions/missing/metaclass/getACall.ql create mode 100644 python/ql/test/library-tests/PointsTo/regressions/missing/metaclass/test.py create mode 100644 python/ql/test/library-tests/jump_to_defn/Consistency.expected create mode 100644 python/ql/test/library-tests/jump_to_defn/Consistency.ql delete mode 100644 python/ql/test/library-tests/jump_to_defn/Sanity.ql create mode 100644 python/ql/test/library-tests/taint/general/TaintConsistency.expected create mode 100644 python/ql/test/library-tests/taint/general/TaintConsistency.ql delete mode 100644 python/ql/test/library-tests/taint/general/TaintSanity.ql create mode 100644 python/ql/test/query-tests/Security/lib/airspeed.py create mode 100644 python/ql/test/query-tests/Security/lib/cheetah/Template/__init__.py create mode 100644 python/ql/test/query-tests/Security/lib/chevron.py create mode 100644 python/ql/test/query-tests/Security/lib/libxml2/__init__.py create mode 100644 python/ql/test/query-tests/Security/lib/lxml/__init__.py create mode 100644 python/ql/test/query-tests/Security/lib/lxml/etree.py create mode 100644 python/ql/test/query-tests/analysis/Consistency/Consistency.expected create mode 100644 python/ql/test/query-tests/analysis/Consistency/Consistency.qlref rename python/ql/test/query-tests/analysis/{Sanity => Consistency}/package/__init__.py (100%) rename python/ql/test/query-tests/analysis/{Sanity => Consistency}/test.py (100%) delete mode 100644 python/ql/test/query-tests/analysis/Sanity/Sanity.qlref create mode 100644 python/tools/recorded-call-graph-metrics/.flake8 create mode 100644 python/tools/recorded-call-graph-metrics/.gitignore create mode 100644 python/tools/recorded-call-graph-metrics/.isort.cfg create mode 100644 python/tools/recorded-call-graph-metrics/README.md create mode 100644 python/tools/recorded-call-graph-metrics/example/simple.py create mode 100644 python/tools/recorded-call-graph-metrics/example/simple.xml create mode 100755 python/tools/recorded-call-graph-metrics/helper.sh create mode 100644 python/tools/recorded-call-graph-metrics/projects.json create mode 100644 python/tools/recorded-call-graph-metrics/ql/lib/BytecodeExpr.qll create mode 100644 python/tools/recorded-call-graph-metrics/ql/lib/RecordedCalls.qll create mode 100644 python/tools/recorded-call-graph-metrics/ql/qlpack.yml create mode 100644 python/tools/recorded-call-graph-metrics/ql/query/InternalMetrics.ql create mode 100644 python/tools/recorded-call-graph-metrics/ql/query/Metrics.ql create mode 100644 python/tools/recorded-call-graph-metrics/ql/query/PointsToFound.ql create mode 100644 python/tools/recorded-call-graph-metrics/ql/query/PointsToNotFound.ql create mode 100644 python/tools/recorded-call-graph-metrics/ql/query/UnidentifiedRecordedCalls.ql create mode 100644 python/tools/recorded-call-graph-metrics/ql/query/UnknownOpcode.ql create mode 100644 python/tools/recorded-call-graph-metrics/requirements.txt create mode 100644 python/tools/recorded-call-graph-metrics/setup.py create mode 100644 python/tools/recorded-call-graph-metrics/src/cg_trace/__init__.py create mode 100644 python/tools/recorded-call-graph-metrics/src/cg_trace/__main__.py create mode 100644 python/tools/recorded-call-graph-metrics/src/cg_trace/bytecode_reconstructor.py create mode 100644 python/tools/recorded-call-graph-metrics/src/cg_trace/cmdline.py create mode 100644 python/tools/recorded-call-graph-metrics/src/cg_trace/exporter.py create mode 100644 python/tools/recorded-call-graph-metrics/src/cg_trace/generate_bytecode_expr_qll.py create mode 100644 python/tools/recorded-call-graph-metrics/src/cg_trace/main.py create mode 100644 python/tools/recorded-call-graph-metrics/src/cg_trace/settings.py create mode 100644 python/tools/recorded-call-graph-metrics/src/cg_trace/tracer.py create mode 100644 python/tools/recorded-call-graph-metrics/src/cg_trace/utils.py create mode 100755 python/tools/recorded-call-graph-metrics/tests/create-test-db.sh create mode 100644 python/tools/recorded-call-graph-metrics/tests/python-src/BUILD_LIST.py create mode 100644 python/tools/recorded-call-graph-metrics/tests/python-src/BUILD_TUPLE.py create mode 100644 python/tools/recorded-call-graph-metrics/tests/python-src/CALL_FUNCTION_EX.py create mode 100644 python/tools/recorded-call-graph-metrics/tests/python-src/__getitem__.py create mode 100644 python/tools/recorded-call-graph-metrics/tests/python-src/builtins.py create mode 100644 python/tools/recorded-call-graph-metrics/tests/python-src/class-simple.py create mode 100644 python/tools/recorded-call-graph-metrics/tests/python-src/dict-get.py create mode 100644 python/tools/recorded-call-graph-metrics/tests/python-src/getsockname.py create mode 100644 python/tools/recorded-call-graph-metrics/tests/python-src/io-builtin.py create mode 100644 python/tools/recorded-call-graph-metrics/tests/python-src/iteration.py create mode 100644 python/tools/recorded-call-graph-metrics/tests/python-src/multiple-on-one-line.py create mode 100644 python/tools/recorded-call-graph-metrics/tests/python-src/problem-1.py create mode 100644 python/tools/recorded-call-graph-metrics/tests/python-src/problem-2.py create mode 100644 python/tools/recorded-call-graph-metrics/tests/python-src/simple.py create mode 100644 python/tools/recorded-call-graph-metrics/tests/python-src/with-exit.py create mode 100644 python/upgrades/f635b392038a494915307f913657cd3058f9b476/old.dbscheme create mode 100644 python/upgrades/f635b392038a494915307f913657cd3058f9b476/py_exprs.ql create mode 100644 python/upgrades/f635b392038a494915307f913657cd3058f9b476/semmlecode.python.dbscheme create mode 100644 python/upgrades/f635b392038a494915307f913657cd3058f9b476/upgrade.properties diff --git a/.codeqlmanifest.json b/.codeqlmanifest.json index 020c9ce92449..30efc842b00f 100644 --- a/.codeqlmanifest.json +++ b/.codeqlmanifest.json @@ -1,5 +1,6 @@ { "provide": [ "*/ql/src/qlpack.yml", "*/ql/test/qlpack.yml", + "*/ql/examples/qlpack.yml", "*/upgrades/qlpack.yml", "misc/legacy-support/*/qlpack.yml", "misc/suite-helpers/qlpack.yml" ] } diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index eef634fae2a3..8f9ffdde4de4 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -4,6 +4,6 @@ "slevesque.vscode-zipexplorer" ], "settings": { - "codeQL.experimentalBqrsParsing": true + "codeQL.runningQueries.memory": 2048 } } diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml new file mode 100644 index 000000000000..cbd1f33a7f66 --- /dev/null +++ b/.github/codeql/codeql-config.yml @@ -0,0 +1,11 @@ +name: "CodeQL config" + +queries: + - uses: security-and-quality + +paths-ignore: + - '/cpp/' + - '/java/' + - '/python/' + - '/javascript/ql/test' + - '/javascript/extractor/tests' diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 000000000000..f1844da86cff --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,52 @@ +name: "Code scanning - action" + +on: + push: + pull_request: + schedule: + - cron: '0 9 * * 1' + +jobs: + CodeQL-Build: + + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + with: + # We must fetch at least the immediate parents so that if this is + # a pull request then we can checkout the head. + fetch-depth: 2 + + # If this run was triggered by a pull request event, then checkout + # the head of the pull request instead of the merge commit. + - run: git checkout HEAD^2 + if: ${{ github.event_name == 'pull_request' }} + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + # Override language selection by uncommenting this and choosing your languages + with: + languages: csharp + config-file: ./.github/codeql/codeql-config.yml + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 000000000000..3606bd75cc55 --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,11 @@ +name: "Pull Request Labeler" +on: +- pull_request_target + +jobs: + triage: + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@v2 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/query-list.yml b/.github/workflows/query-list.yml new file mode 100644 index 000000000000..a9f24b8c9c7c --- /dev/null +++ b/.github/workflows/query-list.yml @@ -0,0 +1,49 @@ +name: Build code scanning query list + +on: + push: + branches: + - main + - 'rc/**' + pull_request: + paths: + - '.github/workflows/query-list.yml' + - 'misc/scripts/generate-code-scanning-query-list.py' + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - name: Clone self (github/codeql) + uses: actions/checkout@v2 + with: + path: codeql + - name: Clone github/codeql-go + uses: actions/checkout@v2 + with: + repository: 'github/codeql-go' + path: codeql-go + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Download CodeQL CLI + uses: dsaltares/fetch-gh-release-asset@aa37ae5c44d3c9820bc12fe675e8670ecd93bd1c + with: + repo: "github/codeql-cli-binaries" + version: "latest" + file: "codeql-linux64.zip" + token: ${{ secrets.GITHUB_TOKEN }} + - name: Unzip CodeQL CLI + run: unzip -d codeql-cli codeql-linux64.zip + - name: Build code scanning query list + run: | + PATH="$PATH:codeql-cli/codeql" python codeql/misc/scripts/generate-code-scanning-query-list.py > code-scanning-query-list.csv + - name: Upload code scanning query list + uses: actions/upload-artifact@v2 + with: + name: code-scanning-query-list + path: code-scanning-query-list.csv + diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 8465a7c2f866..8eec4887a1e0 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -3,8 +3,8 @@ // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp // List of extensions which should be recommended for users of this workspace. "recommendations": [ - "github.vscode-codeql" + "GitHub.vscode-codeql" ], // List of extensions recommended by VS Code that should not be recommended for users of this workspace. "unwantedRecommendations": [] -} \ No newline at end of file +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000000..b467b469f224 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "omnisharp.autoStart": false +} \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f23df3b4e8bc..fa88395e5d09 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -53,14 +53,6 @@ After the experimental query is merged, we welcome pull requests to improve it. ## Using your personal data -If you contribute to this project, we will record your name and email -address (as provided by you with your contributions) as part of the code -repositories, which are public. We might also use this information -to contact you in relation to your contributions, as well as in the -normal course of software development. We also store records of your -CLA agreements. Under GDPR legislation, we do this -on the basis of our legitimate interest in creating the CodeQL product. - -Please do get in touch (privacy@github.com) if you have any questions about -this or our data protection policies. +If you contribute to this project, we will record your name and email address (as provided by you with your contributions) as part of the code repositories, which are public. We might also use this information to contact you in relation to your contributions, as well as in the normal course of software development. We also store records of CLA agreements signed in the past, but no longer require contributors to sign a CLA. Under GDPR legislation, we do this on the basis of our legitimate interest in creating the CodeQL product. +Please do get in touch (privacy@github.com) if you have any questions about this or our data protection policies. diff --git a/README.md b/README.md index 08e572a02463..9012e83f10da 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ You can use the [interactive query console](https://lgtm.com/help/lgtm/using-que ## Contributing -We welcome contributions to our standard library and standard checks. Do you have an idea for a new check, or how to improve an existing query? Then please go ahead and open a pull request! Before you do, though, please take the time to read our [contributing guidelines](CONTRIBUTING.md). You can also consult our [style guides](https://github.com/github/codeql/tree/master/docs) to learn how to format your code for consistency and clarity, how to write query metadata, and how to write query help documentation for your query. +We welcome contributions to our standard library and standard checks. Do you have an idea for a new check, or how to improve an existing query? Then please go ahead and open a pull request! Before you do, though, please take the time to read our [contributing guidelines](CONTRIBUTING.md). You can also consult our [style guides](https://github.com/github/codeql/tree/main/docs) to learn how to format your code for consistency and clarity, how to write query metadata, and how to write query help documentation for your query. ## License diff --git a/change-notes/1.25/analysis-cpp.md b/change-notes/1.25/analysis-cpp.md index 7ab98ffe859a..47997f070527 100644 --- a/change-notes/1.25/analysis-cpp.md +++ b/change-notes/1.25/analysis-cpp.md @@ -13,6 +13,8 @@ The following changes in version 1.25 affect C/C++ analysis in all applications. | **Query** | **Expected impact** | **Change** | |----------------------------|------------------------|------------------------------------------------------------------| +| Uncontrolled format string (`cpp/tainted-format-string`) | | This query is now displayed by default on LGTM. | +| Uncontrolled format string (through global variable) (`cpp/tainted-format-string-through-global`) | | This query is now displayed by default on LGTM. | ## Changes to libraries diff --git a/change-notes/1.25/analysis-csharp.md b/change-notes/1.25/analysis-csharp.md index de4761c92489..10684aca4809 100644 --- a/change-notes/1.25/analysis-csharp.md +++ b/change-notes/1.25/analysis-csharp.md @@ -28,27 +28,51 @@ The following changes in version 1.25 affect C# analysis in all applications. such as `A.B`, no longer are considered unbound generics. (Such nested types do, however, still have relevant `.getSourceDeclaration()`s, for example `A<>.B`.) * The data-flow library has been improved, which affects most security queries by potentially - adding more results. Flow through methods now takes nested field reads/writes into account. - For example, the library is able to track flow from `"taint"` to `Sink()` via the method - `GetF2F1()` in - ```csharp - class C1 - { - string F1; - } - - class C2 - { - C1 F2; - - string GetF2F1() => F2.F1; // Nested field read - - void M() - { - F2 = new C1() { F1 = "taint" }; - Sink(GetF2F1()); // NEW: "taint" reaches here - } - } - ``` + adding more results: + - Flow through methods now takes nested field reads/writes into account. + For example, the library is able to track flow from `"taint"` to `Sink()` via the method + `GetF2F1()` in + ```csharp + class C1 + { + string F1; + } + + class C2 + { + C1 F2; + + string GetF2F1() => F2.F1; // Nested field read + + void M() + { + F2 = new C1() { F1 = "taint" }; + Sink(GetF2F1()); // NEW: "taint" reaches here + } + } + ``` + - Flow through collections is now modeled precisely. For example, instead of modeling an array + store `a[i] = x` as a taint-step from `x` to `a`, we now model it as a data-flow step that + stores `x` into `a`. To get the value back out, a matching read step must be taken. + + For source-code based data-flow analysis, the following constructs are modeled as stores into + collections: + - Direct array assignments, `a[i] = x`. + - Array initializers, `new [] { x }`. + - C# 6-style array initializers, `new C() { Array = { [i] = x } }`. + - Call arguments that match a `params` parameter, where the C# compiler creates an array under-the-hood. + - `yield return` statements. + + The following source-code constructs read from a collection: + - Direct array reads, `a[i]`. + - `foreach` statements. + + For calls out to library code, existing flow summaries have been refined to precisely + capture how they interact with collection contents. For example, a call to + `System.Collections.Generic.List.Add(T)` stores the value of the argument into the + qualifier, and a call to `System.Collections.Generic.List.get_Item(int)` (that is, an + indexer call) reads contents out of the qualifier. Moreover, the effect of + collection-clearing methods such as `System.Collections.Generic.List.Clear()` is now + also modeled. ## Changes to autobuilder diff --git a/change-notes/1.25/analysis-java.md b/change-notes/1.25/analysis-java.md index 7cdd9e491a2b..ab11e5aaaf1e 100644 --- a/change-notes/1.25/analysis-java.md +++ b/change-notes/1.25/analysis-java.md @@ -4,20 +4,26 @@ The following changes in version 1.25 affect Java analysis in all applications. ## General improvements -## New queries - -| **Query** | **Tags** | **Purpose** | -|-----------------------------|-----------|--------------------------------------------------------------------| - +The Java autobuilder has been improved to detect more Gradle Java versions. ## Changes to existing queries | **Query** | **Expected impact** | **Change** | |------------------------------|------------------------|-----------------------------------| - +| Hard-coded credential in API call (`java/hardcoded-credential-api-call`) | More results | The query now recognizes the `BasicAWSCredentials` class of the Amazon client SDK library with hardcoded access key/secret key. | +| Deserialization of user-controlled data (`java/unsafe-deserialization`) | Fewer false positive results | The query no longer reports results using `org.apache.commons.io.serialization.ValidatingObjectInputStream`. | +| Use of a broken or risky cryptographic algorithm (`java/weak-cryptographic-algorithm`) | More results | The query now recognizes the `MessageDigest.getInstance` method. | +| Use of a potentially broken or risky cryptographic algorithm (`java/potentially-weak-cryptographic-algorithm`) | More results | The query now recognizes the `MessageDigest.getInstance` method. | +| Reading from a world writable file (`java/world-writable-file-read`) | More results | The query now recognizes more JDK file operations. | ## Changes to libraries +* The data-flow library has been improved with more taint flow modeling for the + Collections framework and other classes of the JDK. This affects all security + queries using data flow and can yield additional results. +* The data-flow library has been improved with more taint flow modeling for the + Spring framework. This affects all security queries using data flow and can + yield additional results on project that rely on the Spring framework. * The data-flow library has been improved, which affects most security queries by potentially adding more results. Flow through methods now takes nested field reads/writes into account. For example, the library is able to track flow from `"taint"` to `sink()` via the method @@ -39,3 +45,5 @@ The following changes in version 1.25 affect Java analysis in all applications. } } ``` +* The library has been extended with more support for Java 14 features + (`switch` expressions and pattern-matching for `instanceof`). diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 2aada0cbd86a..9491ecb657fc 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -6,22 +6,33 @@ - [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) - [bluebird](http://bluebirdjs.com/) - [express](https://www.npmjs.com/package/express) + - [execa](https://www.npmjs.com/package/execa) + - [fancy-log](https://www.npmjs.com/package/fancy-log) - [fastify](https://www.npmjs.com/package/fastify) + - [foreground-child](https://www.npmjs.com/package/foreground-child) - [fstream](https://www.npmjs.com/package/fstream) - [jGrowl](https://github.com/stanlemon/jGrowl) - [jQuery](https://jquery.com/) - [marsdb](https://www.npmjs.com/package/marsdb) + - [micro](https://www.npmjs.com/package/micro/) - [minimongo](https://www.npmjs.com/package/minimongo/) - [mssql](https://www.npmjs.com/package/mssql) - [mysql](https://www.npmjs.com/package/mysql) + - [npmlog](https://www.npmjs.com/package/npmlog) + - [opener](https://www.npmjs.com/package/opener) - [pg](https://www.npmjs.com/package/pg) - [sequelize](https://www.npmjs.com/package/sequelize) - [spanner](https://www.npmjs.com/package/spanner) - [sqlite](https://www.npmjs.com/package/sqlite) - [ssh2-streams](https://www.npmjs.com/package/ssh2-streams) - [ssh2](https://www.npmjs.com/package/ssh2) + - [vue](https://www.npmjs.com/package/vue) + - [yargs](https://www.npmjs.com/package/yargs) + - [webpack-dev-server](https://www.npmjs.com/package/webpack-dev-server) -* TypeScript 3.9 is now supported. +* TypeScript 4.0 is now supported. + +* TypeScript code embedded in HTML and Vue files is now extracted and analyzed. * The analysis of sanitizers has improved, leading to more accurate results from the security queries. @@ -30,10 +41,17 @@ | **Query** | **Tags** | **Purpose** | |---------------------------------------------------------------------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Cross-site scripting through DOM (`js/xss-through-dom`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities where existing text from the DOM is used as HTML. Results are not shown on LGTM by default. | +| DOM text reinterpreted as HTML (`js/xss-through-dom`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities where existing text from the DOM is used as HTML. Results are shown on LGTM by default. | | Incomplete HTML attribute sanitization (`js/incomplete-html-attribute-sanitization`) | security, external/cwe/cwe-20, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities due to incomplete sanitization of HTML meta-characters. Results are shown on LGTM by default. | | Unsafe expansion of self-closing HTML tag (`js/unsafe-html-expansion`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities caused by unsafe expansion of self-closing HTML tags. | | Unsafe shell command constructed from library input (`js/shell-command-constructed-from-input`) | correctness, security, external/cwe/cwe-078, external/cwe/cwe-088 | Highlights potential command injections due to a shell command being constructed from library inputs. Results are shown on LGTM by default. | +| Download of sensitive file through insecure connection (`js/insecure-download`) | security, external/cwe/cwe-829 | Highlights downloads of sensitive files through an unencrypted protocol. Results are shown on LGTM by default. | +| Exposure of private files (`js/exposure-of-private-files`) | security, external/cwe/cwe-200 | Highlights servers that serve private files. Results are shown on LGTM by default. | +| Creating biased random numbers from a cryptographically secure source (`js/biased-cryptographic-random`) | security, external/cwe/cwe-327 | Highlights mathematical operations on cryptographically secure numbers that can create biased results. Results are shown on LGTM by default. | +| Storage of sensitive information in build artifact (`js/build-artifact-leak`) | security, external/cwe/cwe-312 | Highlights storage of sensitive information in build artifacts. Results are shown on LGTM by default. | +| Improper code sanitization (`js/bad-code-sanitization`) | security, external/cwe/cwe-094, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights string concatenation where code is constructed without proper sanitization. Results are shown on LGTM by default. | +| Disabling certificate validation (`js/disabling-certificate-validation`) | security, external/cwe-295 | Highlights locations where SSL certificate validation is disabled. Results are shown on LGTM by default. | +| Incomplete multi-character sanitization (`js/incomplete-multi-character-sanitization`) | correctness, security, external/cwe/cwe-20, external/cwe/cwe-116 | Highlights sanitizers that fail to remove dangerous substrings completely. Results are shown on LGTM by default. | ## Changes to existing queries @@ -42,14 +60,19 @@ | Client-side cross-site scripting (`js/xss`) | Fewer results | This query now recognizes additional safe patterns of constructing HTML. | | Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Fewer results | This query now recognizes additional safe patterns of doing URL redirects. | | Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. | +| Exception text reinterpreted as HTML (`js/exception-xss`) | Rephrased and changed visibility | Rephrased name and alert message. Severity lowered from error to warning. Results are now shown on LGTM by default. | | Expression has no effect (`js/useless-expression`) | Fewer results | This query no longer flags an expression when that expression is the only content of the containing file. | | Hard-coded credentials (`js/hardcoded-credentials`) | More results | This query now recognizes hard-coded credentials sent via HTTP authorization headers. | | Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional url scheme checks. | +| Insecure randomness (`js/insecure-randomness`) | Fewer results | This query now recognizes when an insecure random value is used as a fallback when secure random values are unsupported. | | Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. | +| Non-linear pattern (`js/non-linear-pattern`) | Fewer duplicates and message changed | This query now generates fewer duplicate alerts and has a clearer explanation in case of type annotations used in a pattern. | | Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes additional utility functions as vulnerable to prototype polution. | | Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. | | Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. | +| Uncontrolled data used in path expression (`js/path-injection`) | Fewer results | This query no longer flags paths that have been checked to be part of a collection. | | Unknown directive (`js/unknown-directive`) | Fewer results | This query no longer flags directives generated by the Babel compiler. | +| Unneeded defensive code (`js/unneeded-defensive-code`) | Fewer false-positive results | This query now recognizes checks meant to handle the `document.all` object. | | Unused property (`js/unused-property`) | Fewer results | This query no longer flags properties of objects that are operands of `yield` expressions. | | Zip Slip (`js/zipslip`) | More results | This query now recognizes additional vulnerabilities. | @@ -85,3 +108,4 @@ The following low-precision queries are no longer run by default on LGTM (their - `ParameterNode.asExpr()` and `.getAstNode()` now gets the parameter's AST node, whereas previously it had no result. - `Expr.flow()` now has a more meaningful result for destructuring patterns. Previously this node was disconnected from the data flow graph. Now it represents the values being destructured by the pattern. * The global data-flow and taint-tracking libraries now model indirect parameter accesses through the `arguments` object in some cases, which may lead to additional results from some of the security queries, particularly "Prototype pollution in utility function". +* The predicates `Type.getProperty()` and variants of `Type.getMethod()` have been deprecated due to lack of use-cases. Looking up a named property of a static type is no longer supported, favoring faster extraction times instead. diff --git a/change-notes/1.25/analysis-python.md b/change-notes/1.25/analysis-python.md index 5d0fc69ec808..ed3496bc7349 100644 --- a/change-notes/1.25/analysis-python.md +++ b/change-notes/1.25/analysis-python.md @@ -1,22 +1,9 @@ # Improvements to Python analysis -The following changes in version 1.25 affect Python analysis in all applications. - -## General improvements - - -## New queries - -| **Query** | **Tags** | **Purpose** | -|-----------------------------|-----------|--------------------------------------------------------------------| - - -## Changes to existing queries - -| **Query** | **Expected impact** | **Change** | -|----------------------------|------------------------|------------------------------------------------------------------| - - -## Changes to libraries - * Importing `semmle.python.web.HttpRequest` will no longer import `UntrustedStringKind` transitively. `UntrustedStringKind` is the most commonly used non-abstract subclass of `ExternalStringKind`. If not imported (by one mean or another), taint-tracking queries that concern `ExternalStringKind` will not produce any results. Please ensure such queries contain an explicit import (`import semmle.python.security.strings.Untrusted`). +* Added model of taint sources for HTTP servers using `http.server`. +* Added taint modeling of routed parameters in Flask. +* Improved modeling of built-in methods on strings for taint tracking. +* Improved classification of test files. +* New class `BoundMethodValue` represents a bound method during runtime. +* The query `py/command-line-injection` now recognizes command execution with the `fabric` and `invoke` Python libraries. diff --git a/change-notes/1.26/analysis-cpp.md b/change-notes/1.26/analysis-cpp.md new file mode 100644 index 000000000000..6b31cf76050f --- /dev/null +++ b/change-notes/1.26/analysis-cpp.md @@ -0,0 +1,30 @@ +# Improvements to C/C++ analysis + +The following changes in version 1.26 affect C/C++ analysis in all applications. + +## General improvements + +## New queries + +| **Query** | **Tags** | **Purpose** | +|-----------------------------|-----------|--------------------------------------------------------------------| + +## Changes to existing queries + +| **Query** | **Expected impact** | **Change** | +|----------------------------|------------------------|------------------------------------------------------------------| +| Declaration hides parameter (`cpp/declaration-hides-parameter`) | Fewer false positive results | False positives involving template functions have been fixed. | +| Inconsistent direction of for loop (`cpp/inconsistent-loop-direction`) | Fewer false positive results | The query now accounts for intentional wrapping of an unsigned loop counter. | +| Overflow in uncontrolled allocation size (`cpp/uncontrolled-allocation-size`) | | The precision of this query has been decreased from "high" to "medium". As a result, the query is still run but results are no longer displayed on LGTM by default. | +| Comparison result is always the same (`cpp/constant-comparison`) | More correct results | Bounds on expressions involving multiplication can now be determined in more cases. | + +## Changes to libraries + +* The QL class `Block`, denoting the `{ ... }` statement, is renamed to `BlockStmt`. +* The models library now models many taint flows through `std::array`, `std::vector`, `std::deque`, `std::list` and `std::forward_list`. +* The models library now models many more taint flows through `std::string`. +* The models library now models many taint flows through `std::istream` and `std::ostream`. +* The models library now models some taint flows through `std::shared_ptr`, `std::unique_ptr`, `std::make_shared` and `std::make_unique`. +* The models library now models many taint flows through `std::pair`, `std::map`, `std::unordered_map`, `std::set` and `std::unordered_set`. +* The `SimpleRangeAnalysis` library now supports multiplications of the form + `e1 * e2` and `x *= e2` when `e1` and `e2` are unsigned or constant. diff --git a/change-notes/1.26/analysis-csharp.md b/change-notes/1.26/analysis-csharp.md new file mode 100644 index 000000000000..3d17e00ab704 --- /dev/null +++ b/change-notes/1.26/analysis-csharp.md @@ -0,0 +1,35 @@ +# Improvements to C# analysis + +The following changes in version 1.26 affect C# analysis in all applications. + +## New queries + +| **Query** | **Tags** | **Purpose** | +|-----------------------------|-----------|--------------------------------------------------------------------| + + +## Changes to existing queries + +| **Query** | **Expected impact** | **Change** | +|------------------------------|------------------------|-----------------------------------| +| Weak encryption: Insufficient key size (`cs/insufficient-key-size`) | More results | The required key size has been increased from 1024 to 2048. | + +## Removal of old queries + +## Changes to code extraction + +* Partial method bodies are extracted. Previously, partial method bodies were skipped completely. +* Inferring the lengths of implicitely sized arrays is fixed. Previously, multidimensional arrays were always extracted with the same length for +each dimension. With the fix, the array sizes `2` and `1` are extracted for `new int[,]{{1},{2}}`. Previously `2` and `2` were extracted. +* The extractor is now assembly-insensitive by default. This means that two entities with the same + fully-qualified name are now mapped to the same entity in the resulting database, regardless of + whether they belong to different assemblies. Assembly sensitivity can be reenabled by passing + `--assemblysensitivetrap` to the extractor. + +## Changes to libraries + +## Changes to autobuilder + +## Changes to tooling support + +* The Abstract Syntax Tree of C# files can be printed in Visual Studio Code. diff --git a/change-notes/1.26/analysis-java.md b/change-notes/1.26/analysis-java.md new file mode 100644 index 000000000000..cf87be2d8b85 --- /dev/null +++ b/change-notes/1.26/analysis-java.md @@ -0,0 +1,21 @@ +# Improvements to Java analysis + +The following changes in version 1.26 affect Java analysis in all applications. + +## General improvements + +## New queries + +| **Query** | **Tags** | **Purpose** | +|-----------------------------|-----------|--------------------------------------------------------------------| + + +## Changes to existing queries + +| **Query** | **Expected impact** | **Change** | +|------------------------------|------------------------|-----------------------------------| + + +## Changes to libraries + +* The QL class `Block`, denoting the `{ ... }` statement, is renamed to `BlockStmt`. diff --git a/change-notes/1.26/analysis-javascript.md b/change-notes/1.26/analysis-javascript.md new file mode 100644 index 000000000000..01d35a12c2dc --- /dev/null +++ b/change-notes/1.26/analysis-javascript.md @@ -0,0 +1,49 @@ +# Improvements to JavaScript analysis + +## General improvements + +* Support for the following frameworks and libraries has been improved: + - [AWS Serverless](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html) + - [Alibaba Serverless](https://www.alibabacloud.com/help/doc-detail/156876.htm) + - [bluebird](https://www.npmjs.com/package/bluebird) + - [express](https://www.npmjs.com/package/express) + - [fast-json-stable-stringify](https://www.npmjs.com/package/fast-json-stable-stringify) + - [fast-safe-stringify](https://www.npmjs.com/package/fast-safe-stringify) + - [http](https://nodejs.org/api/http.html) + - [javascript-stringify](https://www.npmjs.com/package/javascript-stringify) + - [js-stringify](https://www.npmjs.com/package/js-stringify) + - [json-stable-stringify](https://www.npmjs.com/package/json-stable-stringify) + - [json-stringify-safe](https://www.npmjs.com/package/json-stringify-safe) + - [json3](https://www.npmjs.com/package/json3) + - [lodash](https://www.npmjs.com/package/lodash) + - [needle](https://www.npmjs.com/package/needle) + - [object-inspect](https://www.npmjs.com/package/object-inspect) + - [pretty-format](https://www.npmjs.com/package/pretty-format) + - [stringify-object](https://www.npmjs.com/package/stringify-object) + - [underscore](https://www.npmjs.com/package/underscore) + +* Analyzing files with the ".cjs" extension is now supported. +* ES2021 features are now supported. + +## New queries + +| **Query** | **Tags** | **Purpose** | +|---------------------------------------------------------------------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| + + +## Changes to existing queries + +| **Query** | **Expected impact** | **Change** | +|--------------------------------|------------------------------|---------------------------------------------------------------------------| +| Potentially unsafe external link (`js/unsafe-external-link`) | Fewer results | This query no longer flags URLs constructed using a template system where only the hash or query part of the URL is dynamic. | +| Incomplete URL substring sanitization (`js/incomplete-url-substring-sanitization`) | More results | This query now recognizes additional URLs when the substring check is an inclusion check. | +| Ambiguous HTML id attribute (`js/duplicate-html-id`) | Results no longer shown | Precision tag reduced to "low". The query is no longer run by default. | +| Unused loop iteration variable (`js/unused-loop-variable`) | Fewer results | This query no longer flags variables in a destructuring array assignment that are not the last variable in the destructed array. | +| Unsafe shell command constructed from library input (`js/shell-command-constructed-from-input`) | More results | This query now recognizes more commands where colon, dash, and underscore are used. | +| Unsafe jQuery plugin (`js/unsafe-jquery-plugin`) | More results | This query now detects more unsafe uses of nested option properties. | +| Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | More results | This query now recognizes some unsafe uses of `importScripts()` inside WebWorkers. | +| Missing CSRF middleware (`js/missing-token-validation`) | More results | This query now recognizes writes to cookie and session variables as potentially vulnerable to CSRF attacks. | + + +## Changes to libraries +* The predicate `TypeAnnotation.hasQualifiedName` now works in more cases when the imported library was not present during extraction. diff --git a/change-notes/1.26/analysis-python.md b/change-notes/1.26/analysis-python.md new file mode 100644 index 000000000000..f60eb6b4354d --- /dev/null +++ b/change-notes/1.26/analysis-python.md @@ -0,0 +1,22 @@ +# Improvements to Python analysis + +The following changes in version 1.26 affect Python analysis in all applications. + +## General improvements + + +## New queries + +| **Query** | **Tags** | **Purpose** | +|-----------------------------|-----------|--------------------------------------------------------------------| + + +## Changes to existing queries + +| **Query** | **Expected impact** | **Change** | +|----------------------------|------------------------|------------------------------------------------------------------| + + +## Changes to libraries + +* Added taint tracking support for string formatting through f-strings. diff --git a/config/identical-files.json b/config/identical-files.json index 1a1324687a0d..9be5c0d0dd2d 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -1,5 +1,5 @@ { - "DataFlow Java/C++/C#": [ + "DataFlow Java/C++/C#/Python": [ "java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll", "java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll", "java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll", @@ -18,15 +18,18 @@ "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll", "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll", "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll", - "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll" + "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll", + "python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll", + "python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll" ], - "DataFlow Java/C++/C# Common": [ + "DataFlow Java/C++/C#/Python Common": [ "java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll", "cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll", "cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll", - "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll" + "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll", + "python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll" ], - "TaintTracking::Configuration Java/C++/C#": [ + "TaintTracking::Configuration Java/C++/C#/Python": [ "cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll", "cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll", "cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll", @@ -37,13 +40,35 @@ "csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll", "csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll", "java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll", - "java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll" + "java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll", + "python/ql/src/experimental/dataflow/internal/tainttracking1/TaintTrackingImpl.qll" ], - "DataFlow Java/C++/C# Consistency checks": [ + "DataFlow Java/C++/C#/Python Consistency checks": [ "java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll", "cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll", "cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll", - "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll" + "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll", + "python/ql/src/experimental/dataflow/internal/DataFlowImplConsistency.qll" + ], + "SsaReadPosition Java/C#": [ + "java/ql/src/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll", + "csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll" + ], + "Sign Java/C#": [ + "java/ql/src/semmle/code/java/dataflow/internal/rangeanalysis/Sign.qll", + "csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/Sign.qll" + ], + "SignAnalysis Java/C#": [ + "java/ql/src/semmle/code/java/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll", + "csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll" + ], + "Bound Java/C#": [ + "java/ql/src/semmle/code/java/dataflow/Bound.qll", + "csharp/ql/src/semmle/code/csharp/dataflow/Bound.qll" + ], + "ModulusAnalysis Java/C#": [ + "java/ql/src/semmle/code/java/dataflow/ModulusAnalysis.qll", + "csharp/ql/src/semmle/code/csharp/dataflow/ModulusAnalysis.qll" ], "C++ SubBasicBlocks": [ "cpp/ql/src/semmle/code/cpp/controlflow/SubBasicBlocks.qll", @@ -53,114 +78,122 @@ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll" + "csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll" ], "IR IRBlock": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRBlock.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRBlock.qll" + "csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll" ], "IR IRVariable": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll" + "csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll" ], "IR IRFunction": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll" + "csharp/ql/src/experimental/ir/implementation/raw/IRFunction.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRFunction.qll" ], "IR Operand": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll" + "csharp/ql/src/experimental/ir/implementation/raw/Operand.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll" ], "IR IRType": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll" + "csharp/ql/src/experimental/ir/implementation/IRType.qll" ], "IR IRConfiguration": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/IRConfiguration.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/IRConfiguration.qll" + "csharp/ql/src/experimental/ir/implementation/IRConfiguration.qll" ], "IR UseSoundEscapeAnalysis": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/UseSoundEscapeAnalysis.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/UseSoundEscapeAnalysis.qll" + "csharp/ql/src/experimental/ir/implementation/UseSoundEscapeAnalysis.qll" + ], + "IR IRFunctionBase": [ + "cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBase.qll", + "csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBase.qll" ], "IR Operand Tag": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll" + "csharp/ql/src/experimental/ir/implementation/internal/OperandTag.qll" ], - "IR TIRVariable":[ + "IR TInstruction": [ + "cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll", + "csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll" + ], + "IR TIRVariable": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariable.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariable.qll" + "csharp/ql/src/experimental/ir/implementation/internal/TIRVariable.qll" ], "IR IR": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IR.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IR.qll" + "csharp/ql/src/experimental/ir/implementation/raw/IR.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll" ], "IR IRConsistency": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll" + "csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.qll" ], "IR PrintIR": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/PrintIR.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.qll" + "csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll" ], "IR IntegerConstant": [ "cpp/ql/src/semmle/code/cpp/ir/internal/IntegerConstant.qll", - "csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll" + "csharp/ql/src/experimental/ir/internal/IntegerConstant.qll" ], "IR IntegerInteval": [ "cpp/ql/src/semmle/code/cpp/ir/internal/IntegerInterval.qll", - "csharp/ql/src/semmle/code/csharp/ir/internal/IntegerInterval.qll" + "csharp/ql/src/experimental/ir/internal/IntegerInterval.qll" ], "IR IntegerPartial": [ "cpp/ql/src/semmle/code/cpp/ir/internal/IntegerPartial.qll", - "csharp/ql/src/semmle/code/csharp/ir/internal/IntegerPartial.qll" + "csharp/ql/src/experimental/ir/internal/IntegerPartial.qll" ], "IR Overlap": [ "cpp/ql/src/semmle/code/cpp/ir/internal/Overlap.qll", - "csharp/ql/src/semmle/code/csharp/ir/internal/Overlap.qll" + "csharp/ql/src/experimental/ir/internal/Overlap.qll" ], "IR EdgeKind": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll" + "csharp/ql/src/experimental/ir/implementation/EdgeKind.qll" ], "IR MemoryAccessKind": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/MemoryAccessKind.qll" + "csharp/ql/src/experimental/ir/implementation/MemoryAccessKind.qll" ], "IR TempVariableTag": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/TempVariableTag.qll" + "csharp/ql/src/experimental/ir/implementation/TempVariableTag.qll" ], "IR Opcode": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll" + "csharp/ql/src/experimental/ir/implementation/Opcode.qll" ], "IR SSAConsistency": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll" + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll" ], "C++ IR InstructionImports": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionImports.qll", @@ -177,6 +210,11 @@ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRBlockImports.qll" ], + "C++ IR IRFunctionImports": [ + "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRFunctionImports.qll", + "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll", + "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRFunctionImports.qll" + ], "C++ IR IRVariableImports": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRVariableImports.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll", @@ -199,7 +237,7 @@ "SSA AliasAnalysis": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll" + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll" ], "C++ SSA AliasAnalysisImports": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll", @@ -212,42 +250,42 @@ ], "IR SSA SimpleSSA": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll" + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll" ], "IR AliasConfiguration (unaliased_ssa)": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll" + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll" ], "IR SSA SSAConstruction": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll" + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll" ], "IR SSA PrintSSA": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll" + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintSSA.qll" ], "IR ValueNumberInternal": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll" + "csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll" ], "C++ IR ValueNumber": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll" + "csharp/ql/src/experimental/ir/implementation/raw/gvn/ValueNumbering.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll" ], "C++ IR PrintValueNumbering": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/PrintValueNumbering.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/PrintValueNumbering.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/PrintValueNumbering.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll" + "csharp/ql/src/experimental/ir/implementation/raw/gvn/PrintValueNumbering.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll" ], "C++ IR ConstantAnalysis": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/constant/ConstantAnalysis.qll", @@ -276,32 +314,40 @@ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll" ], "C# IR InstructionImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll" + "csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionImports.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/InstructionImports.qll" ], "C# IR IRImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll" + "csharp/ql/src/experimental/ir/implementation/raw/internal/IRImports.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRImports.qll" ], "C# IR IRBlockImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRBlockImports.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll" + "csharp/ql/src/experimental/ir/implementation/raw/internal/IRBlockImports.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll" + ], + "C# IR IRFunctionImports": [ + "csharp/ql/src/experimental/ir/implementation/raw/internal/IRFunctionImports.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll" ], "C# IR IRVariableImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll" + "csharp/ql/src/experimental/ir/implementation/raw/internal/IRVariableImports.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll" ], "C# IR OperandImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll" + "csharp/ql/src/experimental/ir/implementation/raw/internal/OperandImports.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandImports.qll" ], "C# IR PrintIRImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/PrintIRImports.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll" + "csharp/ql/src/experimental/ir/implementation/raw/internal/PrintIRImports.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll" ], "C# IR ValueNumberingImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll" + "csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll" + ], + "Inline Test Expectations": [ + "cpp/ql/test/TestUtilities/InlineExpectationsTest.qll", + "python/ql/test/TestUtilities/InlineExpectationsTest.qll" ], "XML": [ "cpp/ql/src/semmle/code/cpp/XML.qll", @@ -309,5 +355,50 @@ "java/ql/src/semmle/code/xml/XML.qll", "javascript/ql/src/semmle/javascript/XML.qll", "python/ql/src/semmle/python/xml/XML.qll" + ], + "DuplicationProblems.qhelp": [ + "cpp/ql/src/Metrics/Files/DuplicationProblems.qhelp", + "csharp/ql/src/Metrics/Files/DuplicationProblems.qhelp", + "javascript/ql/src/Metrics/DuplicationProblems.qhelp", + "python/ql/src/Metrics/DuplicationProblems.qhelp" + ], + "CommentedOutCodeQuery.qhelp": [ + "cpp/ql/src/Documentation/CommentedOutCodeQuery.qhelp", + "python/ql/src/Lexical/CommentedOutCodeQuery.qhelp", + "csharp/ql/src/Bad Practices/Comments/CommentedOutCodeQuery.qhelp", + "java/ql/src/Violations of Best Practice/Comments/CommentedOutCodeQuery.qhelp", + "javascript/ql/src/Comments/CommentedOutCodeQuery.qhelp" + ], + "FLinesOfCodeReferences.qhelp": [ + "java/ql/src/Metrics/Files/FLinesOfCodeReferences.qhelp", + "javascript/ql/src/Metrics/FLinesOfCodeReferences.qhelp" + ], + "FCommentRatioCommon.qhelp": [ + "java/ql/src/Metrics/Files/FCommentRatioCommon.qhelp", + "javascript/ql/src/Metrics/FCommentRatioCommon.qhelp" + ], + "FLinesOfCodeOverview.qhelp": [ + "java/ql/src/Metrics/Files/FLinesOfCodeOverview.qhelp", + "javascript/ql/src/Metrics/FLinesOfCodeOverview.qhelp" + ], + "CommentedOutCodeMetricOverview.qhelp": [ + "cpp/ql/src/Metrics/Files/CommentedOutCodeMetricOverview.qhelp", + "csharp/ql/src/Metrics/Files/CommentedOutCodeMetricOverview.qhelp", + "java/ql/src/Metrics/Files/CommentedOutCodeMetricOverview.qhelp", + "javascript/ql/src/Comments/CommentedOutCodeMetricOverview.qhelp", + "python/ql/src/Lexical/CommentedOutCodeMetricOverview.qhelp" + ], + "FLinesOfDuplicatedCodeCommon.qhelp": [ + "cpp/ql/src/Metrics/Files/FLinesOfDuplicatedCodeCommon.qhelp", + "java/ql/src/Metrics/Files/FLinesOfDuplicatedCodeCommon.qhelp", + "javascript/ql/src/Metrics/FLinesOfDuplicatedCodeCommon.qhelp", + "python/ql/src/Metrics/FLinesOfDuplicatedCodeCommon.qhelp" + ], + "CommentedOutCodeReferences.qhelp": [ + "cpp/ql/src/Metrics/Files/CommentedOutCodeReferences.qhelp", + "csharp/ql/src/Metrics/Files/CommentedOutCodeReferences.qhelp", + "java/ql/src/Metrics/Files/CommentedOutCodeReferences.qhelp", + "javascript/ql/src/Comments/CommentedOutCodeReferences.qhelp", + "python/ql/src/Lexical/CommentedOutCodeReferences.qhelp" ] -} +} \ No newline at end of file diff --git a/config/opcode-qldoc.py b/config/opcode-qldoc.py new file mode 100644 index 000000000000..e379e6a3ea96 --- /dev/null +++ b/config/opcode-qldoc.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 + +import os +import re +path = os.path + +needs_an_re = re.compile(r'^(?!Unary)[AEIOU]') # Name requiring "an" instead of "a". +start_qldoc_re = re.compile(r'^\s*/\*\*') # Start of a QLDoc comment +end_qldoc_re = re.compile(r'\*/\s*$') # End of a QLDoc comment +blank_qldoc_line_re = re.compile(r'^\s*\*\s*$') # A line in a QLDoc comment with only the '*' +instruction_class_re = re.compile(r'^class (?P[A-aa-z0-9]+)Instruction\s') # Declaration of an `Instruction` class +opcode_base_class_re = re.compile(r'^abstract class (?P[A-aa-z0-9]+)Opcode\s') # Declaration of an `Opcode` base class +opcode_class_re = re.compile(r'^ class (?P[A-aa-z0-9]+)\s') # Declaration of an `Opcode` class + +script_dir = path.realpath(path.dirname(__file__)) +instruction_path = path.realpath(path.join(script_dir, '../cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll')) +opcode_path = path.realpath(path.join(script_dir, '../cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll')) + +# Scan `Instruction.qll`, keeping track of the QLDoc comment attached to each declaration of a class +# whose name ends with `Instruction`. +instruction_comments = {} +in_qldoc = False +saw_blank_line_in_qldoc = False +qldoc_lines = [] +with open(instruction_path, 'r', encoding='utf-8') as instr: + for line in instr: + if in_qldoc: + if end_qldoc_re.search(line): + qldoc_lines.append(line) + in_qldoc = False + elif blank_qldoc_line_re.search(line): + # We're going to skip any lines after the first blank line, to avoid duplicating all + # of the verbose description. + saw_blank_line_in_qldoc = True + elif not saw_blank_line_in_qldoc: + qldoc_lines.append(line) + else: + if start_qldoc_re.search(line): + # Starting a new QLDoc comment. + saw_blank_line_in_qldoc = False + qldoc_lines.append(line) + if not end_qldoc_re.search(line): + in_qldoc = True + else: + instruction_match = instruction_class_re.search(line) + if instruction_match: + # Found the declaration of an `Instruction` class. Record the QLDoc comments. + instruction_comments[instruction_match.group('name')] = qldoc_lines + qldoc_lines = [] + +# Scan `Opcode.qll`. Whenever we see the declaration of an `Opcode` class for which we have a +# corresponding `Instruction` class, we'll attach a copy of the `Instruction`'s QLDoc comment. +in_qldoc = False +qldoc_lines = [] +output_lines = [] +with open(opcode_path, 'r', encoding='utf-8') as opcode: + for line in opcode: + if in_qldoc: + qldoc_lines.append(line) + if end_qldoc_re.search(line): + in_qldoc = False + else: + if start_qldoc_re.search(line): + qldoc_lines.append(line) + if not end_qldoc_re.search(line): + in_qldoc = True + else: + name_without_suffix = None + name = None + indent = '' + opcode_base_match = opcode_base_class_re.search(line) + if opcode_base_match: + name_without_suffix = opcode_base_match.group('name') + name = name_without_suffix + 'Opcode' + else: + opcode_match = opcode_class_re.search(line) + if opcode_match: + name_without_suffix = opcode_match.group('name') + name = name_without_suffix + # Indent by two additional spaces, since opcodes are declared in the + # `Opcode` module. + indent = ' ' + + if name_without_suffix: + # Found an `Opcode` that matches a known `Instruction`. Replace the QLDoc with + # a copy of the one from the `Instruction`. + if instruction_comments.get(name_without_suffix): + article = 'an' if needs_an_re.search(name_without_suffix) else 'a' + qldoc_lines = [ + indent + '/**\n', + indent + ' * The `Opcode` for ' + article + ' `' + name_without_suffix + 'Instruction`.\n', + indent + ' *\n', + indent + ' * See the `' + name_without_suffix + 'Instruction` documentation for more details.\n', + indent + ' */\n' + ] + output_lines.extend(qldoc_lines) + qldoc_lines = [] + output_lines.append(line) + +# Write out the updated `Opcode.qll` +with open(opcode_path, 'w', encoding='utf-8') as opcode: + opcode.writelines(output_lines) diff --git a/cpp/autobuilder/.gitignore b/cpp/autobuilder/.gitignore new file mode 100644 index 000000000000..f81ecc73dffa --- /dev/null +++ b/cpp/autobuilder/.gitignore @@ -0,0 +1,13 @@ +obj/ +TestResults/ +*.manifest +*.pdb +*.suo +*.mdb +*.vsmdi +csharp.log +**/bin/Debug +**/bin/Release +*.tlog +.vs +*.user \ No newline at end of file diff --git a/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/BuildScripts.cs b/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/BuildScripts.cs new file mode 100644 index 000000000000..87390b7bf8fe --- /dev/null +++ b/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/BuildScripts.cs @@ -0,0 +1,296 @@ +using Xunit; +using Semmle.Autobuild.Shared; +using System.Collections.Generic; +using System; +using System.Linq; +using Microsoft.Build.Construction; +using System.Xml; + +namespace Semmle.Autobuild.Cpp.Tests +{ + ///

+ /// Test class to script Autobuilder scenarios. + /// For most methods, it uses two fields: + /// - an IList to capture the the arguments passed to it + /// - an IDictionary of possible return values. + /// + class TestActions : IBuildActions + { + /// + /// List of strings passed to FileDelete. + /// + public IList FileDeleteIn = new List(); + + void IBuildActions.FileDelete(string file) + { + FileDeleteIn.Add(file); + } + + public IList FileExistsIn = new List(); + public IDictionary FileExists = new Dictionary(); + + bool IBuildActions.FileExists(string file) + { + FileExistsIn.Add(file); + if (FileExists.TryGetValue(file, out var ret)) + return ret; + if (FileExists.TryGetValue(System.IO.Path.GetFileName(file), out ret)) + return ret; + throw new ArgumentException("Missing FileExists " + file); + } + + public IList RunProcessIn = new List(); + public IDictionary RunProcess = new Dictionary(); + public IDictionary RunProcessOut = new Dictionary(); + public IDictionary RunProcessWorkingDirectory = new Dictionary(); + + int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary? env, out IList stdOut) + { + var pattern = cmd + " " + args; + RunProcessIn.Add(pattern); + if (RunProcessOut.TryGetValue(pattern, out var str)) + stdOut = str.Split("\n"); + else + throw new ArgumentException("Missing RunProcessOut " + pattern); + RunProcessWorkingDirectory.TryGetValue(pattern, out var wd); + if (wd != workingDirectory) + throw new ArgumentException("Missing RunProcessWorkingDirectory " + pattern); + if (RunProcess.TryGetValue(pattern, out var ret)) + return ret; + throw new ArgumentException("Missing RunProcess " + pattern); + } + + int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary? env) + { + var pattern = cmd + " " + args; + RunProcessIn.Add(pattern); + RunProcessWorkingDirectory.TryGetValue(pattern, out var wd); + if (wd != workingDirectory) + throw new ArgumentException("Missing RunProcessWorkingDirectory " + pattern); + if (RunProcess.TryGetValue(pattern, out var ret)) + return ret; + throw new ArgumentException("Missing RunProcess " + pattern); + } + + public IList DirectoryDeleteIn = new List(); + + void IBuildActions.DirectoryDelete(string dir, bool recursive) + { + DirectoryDeleteIn.Add(dir); + } + + public IDictionary DirectoryExists = new Dictionary(); + public IList DirectoryExistsIn = new List(); + + bool IBuildActions.DirectoryExists(string dir) + { + DirectoryExistsIn.Add(dir); + if (DirectoryExists.TryGetValue(dir, out var ret)) + return ret; + throw new ArgumentException("Missing DirectoryExists " + dir); + } + + public IDictionary GetEnvironmentVariable = new Dictionary(); + + string? IBuildActions.GetEnvironmentVariable(string name) + { + if (GetEnvironmentVariable.TryGetValue(name, out var ret)) + return ret; + throw new ArgumentException("Missing GetEnvironmentVariable " + name); + } + + public string GetCurrentDirectory = ""; + + string IBuildActions.GetCurrentDirectory() + { + return GetCurrentDirectory; + } + + public IDictionary EnumerateFiles = new Dictionary(); + + IEnumerable IBuildActions.EnumerateFiles(string dir) + { + if (EnumerateFiles.TryGetValue(dir, out var str)) + return str.Split("\n"); + throw new ArgumentException("Missing EnumerateFiles " + dir); + } + + public IDictionary EnumerateDirectories = new Dictionary(); + + IEnumerable IBuildActions.EnumerateDirectories(string dir) + { + if (EnumerateDirectories.TryGetValue(dir, out var str)) + return string.IsNullOrEmpty(str) ? Enumerable.Empty() : str.Split("\n"); + throw new ArgumentException("Missing EnumerateDirectories " + dir); + } + + public bool IsWindows; + + bool IBuildActions.IsWindows() => IsWindows; + + string IBuildActions.PathCombine(params string[] parts) + { + return string.Join(IsWindows ? '\\' : '/', parts.Where(p => !string.IsNullOrWhiteSpace(p))); + } + + string IBuildActions.GetFullPath(string path) => path; + + void IBuildActions.WriteAllText(string filename, string contents) + { + } + + public IDictionary LoadXml = new Dictionary(); + XmlDocument IBuildActions.LoadXml(string filename) + { + if (LoadXml.TryGetValue(filename, out var xml)) + return xml; + throw new ArgumentException("Missing LoadXml " + filename); + } + + public string EnvironmentExpandEnvironmentVariables(string s) + { + foreach (var kvp in GetEnvironmentVariable) + s = s.Replace($"%{kvp.Key}%", kvp.Value); + return s; + } + } + + /// + /// A fake solution to build. + /// + class TestSolution : ISolution + { + public IEnumerable Configurations => throw new NotImplementedException(); + + public string DefaultConfigurationName => "Release"; + + public string DefaultPlatformName => "x86"; + + public string FullPath { get; set; } + + public Version ToolsVersion => new Version("14.0"); + + public IEnumerable IncludedProjects => throw new NotImplementedException(); + + public TestSolution(string path) + { + FullPath = path; + } + } + + public class BuildScriptTests + { + TestActions Actions = new TestActions(); + + // Records the arguments passed to StartCallback. + IList StartCallbackIn = new List(); + + void StartCallback(string s, bool silent) + { + StartCallbackIn.Add(s); + } + + // Records the arguments passed to EndCallback + IList EndCallbackIn = new List(); + IList EndCallbackReturn = new List(); + + void EndCallback(int ret, string s, bool silent) + { + EndCallbackReturn.Add(ret); + EndCallbackIn.Add(s); + } + + CppAutobuilder CreateAutoBuilder(bool isWindows, + string? buildless = null, string? solution = null, string? buildCommand = null, string? ignoreErrors = null, + string? msBuildArguments = null, string? msBuildPlatform = null, string? msBuildConfiguration = null, string? msBuildTarget = null, + string? dotnetArguments = null, string? dotnetVersion = null, string? vsToolsVersion = null, + string? nugetRestore = null, string? allSolutions = null, + string cwd = @"C:\Project") + { + string codeqlUpperLanguage = Language.Cpp.UpperCaseName; + Actions.GetEnvironmentVariable[$"CODEQL_AUTOBUILDER_{codeqlUpperLanguage}_NO_INDEXING"] = "false"; + Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_TRAP_DIR"] = ""; + Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_SOURCE_ARCHIVE_DIR"] = ""; + Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_ROOT"] = $@"C:\codeql\{codeqlUpperLanguage.ToLowerInvariant()}"; + Actions.GetEnvironmentVariable["CODEQL_JAVA_HOME"] = @"C:\codeql\tools\java"; + Actions.GetEnvironmentVariable["SEMMLE_DIST"] = @"C:\odasa"; + Actions.GetEnvironmentVariable["SEMMLE_JAVA_HOME"] = @"C:\odasa\tools\java"; + Actions.GetEnvironmentVariable["SEMMLE_PLATFORM_TOOLS"] = @"C:\odasa\tools"; + Actions.GetEnvironmentVariable["LGTM_INDEX_VSTOOLS_VERSION"] = vsToolsVersion; + Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_ARGUMENTS"] = msBuildArguments; + Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_PLATFORM"] = msBuildPlatform; + Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_CONFIGURATION"] = msBuildConfiguration; + Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_TARGET"] = msBuildTarget; + Actions.GetEnvironmentVariable["LGTM_INDEX_DOTNET_ARGUMENTS"] = dotnetArguments; + Actions.GetEnvironmentVariable["LGTM_INDEX_DOTNET_VERSION"] = dotnetVersion; + Actions.GetEnvironmentVariable["LGTM_INDEX_BUILD_COMMAND"] = buildCommand; + Actions.GetEnvironmentVariable["LGTM_INDEX_SOLUTION"] = solution; + Actions.GetEnvironmentVariable["LGTM_INDEX_IGNORE_ERRORS"] = ignoreErrors; + Actions.GetEnvironmentVariable["LGTM_INDEX_BUILDLESS"] = buildless; + Actions.GetEnvironmentVariable["LGTM_INDEX_ALL_SOLUTIONS"] = allSolutions; + Actions.GetEnvironmentVariable["LGTM_INDEX_NUGET_RESTORE"] = nugetRestore; + Actions.GetEnvironmentVariable["ProgramFiles(x86)"] = isWindows ? @"C:\Program Files (x86)" : null; + Actions.GetCurrentDirectory = cwd; + Actions.IsWindows = isWindows; + + var options = new AutobuildOptions(Actions, Language.Cpp); + return new CppAutobuilder(Actions, options); + } + + void TestAutobuilderScript(Autobuilder autobuilder, int expectedOutput, int commandsRun) + { + Assert.Equal(expectedOutput, autobuilder.GetBuildScript().Run(Actions, StartCallback, EndCallback)); + + // Check expected commands actually ran + Assert.Equal(commandsRun, StartCallbackIn.Count); + Assert.Equal(commandsRun, EndCallbackIn.Count); + Assert.Equal(commandsRun, EndCallbackReturn.Count); + + var action = Actions.RunProcess.GetEnumerator(); + for (int cmd = 0; cmd < commandsRun; ++cmd) + { + Assert.True(action.MoveNext()); + + Assert.Equal(action.Current.Key, StartCallbackIn[cmd]); + Assert.Equal(action.Current.Value, EndCallbackReturn[cmd]); + } + } + + + [Fact] + public void TestDefaultCppAutobuilder() + { + Actions.EnumerateFiles[@"C:\Project"] = ""; + Actions.EnumerateDirectories[@"C:\Project"] = ""; + + var autobuilder = CreateAutoBuilder(true); + var script = autobuilder.GetBuildScript(); + + // Fails due to no solutions present. + Assert.NotEqual(0, script.Run(Actions, StartCallback, EndCallback)); + } + + [Fact] + public void TestCppAutobuilderSuccess() + { + Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\csharp\nuget\nuget.exe restore C:\Project\test.sln"] = 1; + Actions.RunProcess[@"cmd.exe /C CALL ^""C:\Program Files ^(x86^)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat^"" && set Platform=&& type NUL && C:\odasa\tools\odasa index --auto msbuild C:\Project\test.sln /p:UseSharedCompilation=false /t:rebuild /p:Platform=""x86"" /p:Configuration=""Release"" /p:MvcBuildViews=true"] = 0; + Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = ""; + Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = 1; + Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = 0; + Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = ""; + Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = true; + Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = true; + Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = true; + Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = true; + Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = true; + Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.slx"; + Actions.EnumerateDirectories[@"C:\Project"] = ""; + + var autobuilder = CreateAutoBuilder(true); + var solution = new TestSolution(@"C:\Project\test.sln"); + autobuilder.ProjectsOrSolutionsToBuild.Add(solution); + TestAutobuilderScript(autobuilder, 0, 2); + } + } +} diff --git a/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/Semmle.Autobuild.Cpp.Tests.csproj b/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/Semmle.Autobuild.Cpp.Tests.csproj new file mode 100644 index 000000000000..7de677b56100 --- /dev/null +++ b/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/Semmle.Autobuild.Cpp.Tests.csproj @@ -0,0 +1,25 @@ + + + + Exe + netcoreapp3.1 + false + win-x64;linux-x64;osx-x64 + enable + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + + + + diff --git a/cpp/autobuilder/Semmle.Autobuild.Cpp/CppAutobuilder.cs b/cpp/autobuilder/Semmle.Autobuild.Cpp/CppAutobuilder.cs new file mode 100644 index 000000000000..44c34656a2a8 --- /dev/null +++ b/cpp/autobuilder/Semmle.Autobuild.Cpp/CppAutobuilder.cs @@ -0,0 +1,23 @@ +using Semmle.Autobuild.Shared; + +namespace Semmle.Autobuild.Cpp +{ + public class CppAutobuilder : Autobuilder + { + public CppAutobuilder(IBuildActions actions, AutobuildOptions options) : base(actions, options) { } + + public override BuildScript GetBuildScript() + { + if (Options.BuildCommand != null) + return new BuildCommandRule((_, f) => f(null)).Analyse(this, false); + + return + // First try MSBuild + new MsBuildRule().Analyse(this, true) | + // Then look for a script that might be a build script + (() => new BuildCommandAutoRule((_, f) => f(null)).Analyse(this, true)) | + // All attempts failed: print message + AutobuildFailure(); + } + } +} diff --git a/csharp/autobuilder/Semmle.Autobuild/Program.cs b/cpp/autobuilder/Semmle.Autobuild.Cpp/Program.cs similarity index 72% rename from csharp/autobuilder/Semmle.Autobuild/Program.cs rename to cpp/autobuilder/Semmle.Autobuild.Cpp/Program.cs index e4bccb0e626e..3f4627c53d54 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Program.cs +++ b/cpp/autobuilder/Semmle.Autobuild.Cpp/Program.cs @@ -1,6 +1,7 @@ using System; +using Semmle.Autobuild.Shared; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Cpp { class Program { @@ -10,11 +11,11 @@ static int Main() try { var actions = SystemBuildActions.Instance; - var options = new AutobuildOptions(actions); + var options = new AutobuildOptions(actions, Language.Cpp); try { - Console.WriteLine($"Semmle autobuilder for {options.Language}"); - var builder = new Autobuilder(actions, options); + Console.WriteLine("CodeQL C++ autobuilder"); + var builder = new CppAutobuilder(actions, options); return builder.AttemptBuild(); } catch(InvalidEnvironmentException ex) diff --git a/csharp/autobuilder/Semmle.Autobuild.Tests/Properties/AssemblyInfo.cs b/cpp/autobuilder/Semmle.Autobuild.Cpp/Properties/AssemblyInfo.cs similarity index 83% rename from csharp/autobuilder/Semmle.Autobuild.Tests/Properties/AssemblyInfo.cs rename to cpp/autobuilder/Semmle.Autobuild.Cpp/Properties/AssemblyInfo.cs index 778d6305fc5d..2d14b0e909d6 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Tests/Properties/AssemblyInfo.cs +++ b/cpp/autobuilder/Semmle.Autobuild.Cpp/Properties/AssemblyInfo.cs @@ -4,12 +4,12 @@ // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("Semmle.Autobuild.Tests")] +[assembly: AssemblyTitle("Semmle.Autobuild.Cpp")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Semmle.Extraction.Tests")] -[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyCompany("GitHub")] +[assembly: AssemblyProduct("CodeQL autobuilder for C++")] +[assembly: AssemblyCopyright("Copyright © GitHub 2020")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/cpp/autobuilder/Semmle.Autobuild.Cpp/Semmle.Autobuild.Cpp.csproj b/cpp/autobuilder/Semmle.Autobuild.Cpp/Semmle.Autobuild.Cpp.csproj new file mode 100644 index 000000000000..aadcc07568df --- /dev/null +++ b/cpp/autobuilder/Semmle.Autobuild.Cpp/Semmle.Autobuild.Cpp.csproj @@ -0,0 +1,28 @@ + + + + netcoreapp3.1 + Semmle.Autobuild.Cpp + Semmle.Autobuild.Cpp + + Exe + + false + win-x64;linux-x64;osx-x64 + enable + + + + + + + + + + + + + + + + diff --git a/cpp/change-notes/2020-09-29-range-analysis-rollup.md b/cpp/change-notes/2020-09-29-range-analysis-rollup.md new file mode 100644 index 000000000000..d5b2c729bcbc --- /dev/null +++ b/cpp/change-notes/2020-09-29-range-analysis-rollup.md @@ -0,0 +1,14 @@ +lgtm,codescanning +* The `SimpleRangeAnalysis` library has gained support for several language + constructs it did not support previously. These improvements primarily affect + the queries `cpp/constant-comparison`, `cpp/comparison-with-wider-type`, and + `cpp/integer-multiplication-cast-to-long`. The newly supported language + features are: + * Multiplication of unsigned numbers. + * Multiplication by a constant. + * Reference-typed function parameters. + * Comparing a variable not equal to an endpoint of its range, thus narrowing the range by one. + * Using `if (x)` or `if (!x)` or similar to test for equality to zero. +* The `SimpleRangeAnalysis` library can now be extended with custom rules. See + examples in + `cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/extensions/`. diff --git a/cpp/ql/examples/qlpack.yml b/cpp/ql/examples/qlpack.yml new file mode 100644 index 000000000000..67289f8e360c --- /dev/null +++ b/cpp/ql/examples/qlpack.yml @@ -0,0 +1,3 @@ +name: codeql-cpp-examples +version: 0.0.0 +libraryPathDependencies: codeql-cpp diff --git a/cpp/ql/examples/snippets/emptyblock.ql b/cpp/ql/examples/snippets/emptyblock.ql index 2f1e198fc595..46ee35a68644 100644 --- a/cpp/ql/examples/snippets/emptyblock.ql +++ b/cpp/ql/examples/snippets/emptyblock.ql @@ -9,6 +9,6 @@ import cpp -from Block blk +from BlockStmt blk where blk.getNumStmt() = 0 select blk diff --git a/cpp/ql/examples/snippets/emptythen.ql b/cpp/ql/examples/snippets/emptythen.ql index 0ae060838d26..7e31ac7e4e18 100644 --- a/cpp/ql/examples/snippets/emptythen.ql +++ b/cpp/ql/examples/snippets/emptythen.ql @@ -13,5 +13,5 @@ import cpp from IfStmt i -where i.getThen().(Block).getNumStmt() = 0 +where i.getThen().(BlockStmt).getNumStmt() = 0 select i diff --git a/cpp/ql/examples/snippets/singletonblock.ql b/cpp/ql/examples/snippets/singletonblock.ql index a265d84a0da3..265bc85927c8 100644 --- a/cpp/ql/examples/snippets/singletonblock.ql +++ b/cpp/ql/examples/snippets/singletonblock.ql @@ -8,6 +8,6 @@ import cpp -from Block b +from BlockStmt b where b.getNumStmt() = 1 select b diff --git a/cpp/ql/src/Best Practices/BlockWithTooManyStatements.ql b/cpp/ql/src/Best Practices/BlockWithTooManyStatements.ql index cfa197109347..97481bc8b038 100644 --- a/cpp/ql/src/Best Practices/BlockWithTooManyStatements.ql +++ b/cpp/ql/src/Best Practices/BlockWithTooManyStatements.ql @@ -14,7 +14,7 @@ import cpp class ComplexStmt extends Stmt { ComplexStmt() { - exists(Block body | + exists(BlockStmt body | body = this.(Loop).getStmt() or body = this.(SwitchStmt).getStmt() | @@ -24,7 +24,7 @@ class ComplexStmt extends Stmt { } } -from Block b, int n, ComplexStmt complexStmt +from BlockStmt b, int n, ComplexStmt complexStmt where n = strictcount(ComplexStmt s | s = b.getAStmt()) and n > 3 and diff --git a/cpp/ql/src/Best Practices/Hiding/DeclarationHidesParameter.ql b/cpp/ql/src/Best Practices/Hiding/DeclarationHidesParameter.ql index 91317c53af85..64e5760ed2b4 100644 --- a/cpp/ql/src/Best Practices/Hiding/DeclarationHidesParameter.ql +++ b/cpp/ql/src/Best Practices/Hiding/DeclarationHidesParameter.ql @@ -11,6 +11,17 @@ import cpp +/** + * Gets the template that a function `f` is constructed from, or just `f` if it + * is not from a template instantiation. + */ +Function getConstructedFrom(Function f) { + f.isConstructedFrom(result) + or + not f.isConstructedFrom(_) and + result = f +} + /** * Gets the parameter of `f` with name `name`, which has to come from the * _definition_ of `f` and not a prototype declaration. @@ -18,13 +29,17 @@ import cpp * This should not happen in a single application but since we * have a system wide view it is likely to happen for instance for * the main function. + * + * Note: we use `getConstructedFrom` to ensure that we look at template + * functions rather than their instantiations. We get better results this way + * as the instantiation is artificial and may have inherited parameter names + * from the declaration rather than the definition. */ ParameterDeclarationEntry functionParameterNames(Function f, string name) { exists(FunctionDeclarationEntry fe | result.getFunctionDeclarationEntry() = fe and - fe.getFunction() = f and + getConstructedFrom(f).getDefinition() = fe and fe.getLocation() = f.getDefinitionLocation() and - result.getFile() = fe.getFile() and // Work around CPP-331 strictcount(f.getDefinitionLocation()) = 1 and result.getName() = name ) diff --git a/cpp/ql/src/Best Practices/Hiding/DeclarationHidesVariable.ql b/cpp/ql/src/Best Practices/Hiding/DeclarationHidesVariable.ql index 675fd7178d8a..d10d346c5135 100644 --- a/cpp/ql/src/Best Practices/Hiding/DeclarationHidesVariable.ql +++ b/cpp/ql/src/Best Practices/Hiding/DeclarationHidesVariable.ql @@ -17,7 +17,7 @@ where shadowing(lv1, lv2) and not lv1.isCompilerGenerated() and not lv2.isCompilerGenerated() and - not lv1.getParentScope().(Block).isInMacroExpansion() and - not lv2.getParentScope().(Block).isInMacroExpansion() + not lv1.getParentScope().(BlockStmt).isInMacroExpansion() and + not lv2.getParentScope().(BlockStmt).isInMacroExpansion() select lv1, "Variable " + lv1.getName() + " hides another variable of the same name (on $@).", lv2, "line " + lv2.getLocation().getStartLine().toString() diff --git a/cpp/ql/src/Best Practices/Likely Errors/EmptyBlock.ql b/cpp/ql/src/Best Practices/Likely Errors/EmptyBlock.ql index 9880a3ae2a0a..9fa8c4e5e3fb 100644 --- a/cpp/ql/src/Best Practices/Likely Errors/EmptyBlock.ql +++ b/cpp/ql/src/Best Practices/Likely Errors/EmptyBlock.ql @@ -14,7 +14,7 @@ import cpp -predicate emptyBlock(ControlStructure s, Block b) { +predicate emptyBlock(ControlStructure s, BlockStmt b) { b = s.getAChild() and not exists(b.getAChild()) and not b.isInMacroExpansion() and @@ -23,7 +23,7 @@ predicate emptyBlock(ControlStructure s, Block b) { class AffectedFile extends File { AffectedFile() { - exists(Block b | + exists(BlockStmt b | emptyBlock(_, b) and this = b.getFile() ) @@ -37,7 +37,7 @@ class AffectedFile extends File { class BlockOrNonChild extends Element { BlockOrNonChild() { ( - this instanceof Block + this instanceof BlockStmt or this instanceof Comment or @@ -78,7 +78,7 @@ class BlockOrNonChild extends Element { /** * A block that contains a non-child element. */ -predicate emptyBlockContainsNonchild(Block b) { +predicate emptyBlockContainsNonchild(BlockStmt b) { emptyBlock(_, b) and exists(BlockOrNonChild c, AffectedFile file | c.(BlockOrNonChild).getStartRankIn(file) = 1 + b.(BlockOrNonChild).getStartRankIn(file) and @@ -91,7 +91,7 @@ predicate emptyBlockContainsNonchild(Block b) { * A block that is entirely on one line, which also contains a comment. Chances * are the comment is intended to refer to the block. */ -predicate lineComment(Block b) { +predicate lineComment(BlockStmt b) { emptyBlock(_, b) and exists(Location bLocation, File f, int line | bLocation = b.getLocation() and @@ -106,7 +106,7 @@ predicate lineComment(Block b) { ) } -from ControlStructure s, Block eb +from ControlStructure s, BlockStmt eb where emptyBlock(s, eb) and not emptyBlockContainsNonchild(eb) and diff --git a/cpp/ql/src/Critical/DeadCodeGoto.ql b/cpp/ql/src/Critical/DeadCodeGoto.ql index 4e16325f943d..a2f8db771b07 100644 --- a/cpp/ql/src/Critical/DeadCodeGoto.ql +++ b/cpp/ql/src/Critical/DeadCodeGoto.ql @@ -12,7 +12,7 @@ import cpp import semmle.code.cpp.commons.Exclusions -Stmt getNextRealStmt(Block b, int i) { +Stmt getNextRealStmt(BlockStmt b, int i) { result = b.getStmt(i + 1) and not result instanceof EmptyStmt or @@ -20,7 +20,7 @@ Stmt getNextRealStmt(Block b, int i) { result = getNextRealStmt(b, i + 1) } -from JumpStmt js, Block b, int i, Stmt s +from JumpStmt js, BlockStmt b, int i, Stmt s where b.getStmt(i) = js and s = getNextRealStmt(b, i) and diff --git a/cpp/ql/src/Critical/OverflowDestination.ql b/cpp/ql/src/Critical/OverflowDestination.ql index ad925daed628..bff3cac9326c 100644 --- a/cpp/ql/src/Critical/OverflowDestination.ql +++ b/cpp/ql/src/Critical/OverflowDestination.ql @@ -23,10 +23,7 @@ import semmle.code.cpp.security.TaintTracking * ``` */ predicate sourceSized(FunctionCall fc, Expr src) { - exists(string name | - (name = "strncpy" or name = "strncat" or name = "memcpy" or name = "memmove") and - fc.getTarget().hasGlobalOrStdName(name) - ) and + fc.getTarget().hasGlobalOrStdName(["strncpy", "strncat", "memcpy", "memmove"]) and exists(Expr dest, Expr size, Variable v | fc.getArgument(0) = dest and fc.getArgument(1) = src and diff --git a/cpp/ql/src/Critical/SizeCheck2.ql b/cpp/ql/src/Critical/SizeCheck2.ql index 1b716d79d49e..1b7e1347c308 100644 --- a/cpp/ql/src/Critical/SizeCheck2.ql +++ b/cpp/ql/src/Critical/SizeCheck2.ql @@ -15,12 +15,7 @@ import cpp class Allocation extends FunctionCall { - Allocation() { - exists(string name | - this.getTarget().hasGlobalOrStdName(name) and - (name = "malloc" or name = "calloc" or name = "realloc") - ) - } + Allocation() { this.getTarget().hasGlobalOrStdName(["malloc", "calloc", "realloc"]) } private string getName() { this.getTarget().hasGlobalOrStdName(result) } diff --git a/cpp/ql/src/Critical/aliasAnalysisWarning.qhelp b/cpp/ql/src/Critical/aliasAnalysisWarning.qhelp new file mode 100644 index 000000000000..77d395c7da53 --- /dev/null +++ b/cpp/ql/src/Critical/aliasAnalysisWarning.qhelp @@ -0,0 +1,11 @@ + + + + +This check is an approximation, so some results may not be actual defects in the program. +It is not possible in general to compute the exact value of the variable without running the program with all possible input data. + + + diff --git a/cpp/ql/src/Critical/callGraphWarning.qhelp b/cpp/ql/src/Critical/callGraphWarning.qhelp new file mode 100644 index 000000000000..1e408db15270 --- /dev/null +++ b/cpp/ql/src/Critical/callGraphWarning.qhelp @@ -0,0 +1,12 @@ + + + + +This check is an approximation, so some results may not be actual defects in the program. +It is not possible in general to compute which function is actually called in a virtual call, +or a call through a pointer, without running the program with all possible input data. + + + diff --git a/cpp/ql/src/Critical/dataFlowWarning.qhelp b/cpp/ql/src/Critical/dataFlowWarning.qhelp new file mode 100644 index 000000000000..f96c82226c21 --- /dev/null +++ b/cpp/ql/src/Critical/dataFlowWarning.qhelp @@ -0,0 +1,13 @@ + + + + +This check is an approximation, so some results may not be actual defects in the program. +It is not possible in general to compute the actual branch taken in conditional statements such +as "if" without running the program with all possible input data. This means that it is not possible +to determine if a particular statement is going to be executed. + + + diff --git a/cpp/ql/src/Critical/pointsToWarning.qhelp b/cpp/ql/src/Critical/pointsToWarning.qhelp new file mode 100644 index 000000000000..2fa777ebfe97 --- /dev/null +++ b/cpp/ql/src/Critical/pointsToWarning.qhelp @@ -0,0 +1,11 @@ + + + + +This check is an approximation, so some results may not be actual defects in the program. It is not possible +in general to compute the values of pointers without running the program with all input data. + + + diff --git a/cpp/ql/src/Documentation/CommentedOutCode.qhelp b/cpp/ql/src/Documentation/CommentedOutCode.qhelp index 4ce0ee029b62..ba056ab73f77 100644 --- a/cpp/ql/src/Documentation/CommentedOutCode.qhelp +++ b/cpp/ql/src/Documentation/CommentedOutCode.qhelp @@ -3,5 +3,5 @@ "qhelp.dtd"> - + diff --git a/cpp/ql/src/Documentation/CommentedOutCodeQuery.qhelp b/cpp/ql/src/Documentation/CommentedOutCodeQuery.qhelp new file mode 100644 index 000000000000..eb40ecdb7088 --- /dev/null +++ b/cpp/ql/src/Documentation/CommentedOutCodeQuery.qhelp @@ -0,0 +1,25 @@ + + + + +

+Commented-out code is distracting and confusing for developers who read the surrounding code, +and its significance is often unclear. It will not get compiled or tested when the code around +it changes, so it's likely to break over time. For these reasons, commented-out code should be +avoided. +

+ +
+ + + +

+Remove or reinstate the commented-out code. If you want to include a snippet of example code +in a comment, consider enclosing it in quotes or marking it up as appropriate for the source +language. +

+ +
+
diff --git a/cpp/ql/src/JPL_C/LOC-2/Rule 11/SimpleControlFlowJmp.ql b/cpp/ql/src/JPL_C/LOC-2/Rule 11/SimpleControlFlowJmp.ql index 7468b6e71748..0623036a5924 100644 --- a/cpp/ql/src/JPL_C/LOC-2/Rule 11/SimpleControlFlowJmp.ql +++ b/cpp/ql/src/JPL_C/LOC-2/Rule 11/SimpleControlFlowJmp.ql @@ -13,14 +13,7 @@ import cpp class ForbiddenFunction extends Function { - ForbiddenFunction() { - exists(string name | name = this.getName() | - name = "setjmp" or - name = "longjmp" or - name = "sigsetjmp" or - name = "siglongjmp" - ) - } + ForbiddenFunction() { this.getName() = ["setjmp", "longjmp", "sigsetjmp", "siglongjmp"] } } from FunctionCall call diff --git a/cpp/ql/src/JPL_C/LOC-4/Rule 21/MacroInBlock.ql b/cpp/ql/src/JPL_C/LOC-4/Rule 21/MacroInBlock.ql index 602be971763b..9ed5675e7955 100644 --- a/cpp/ql/src/JPL_C/LOC-4/Rule 21/MacroInBlock.ql +++ b/cpp/ql/src/JPL_C/LOC-4/Rule 21/MacroInBlock.ql @@ -12,7 +12,7 @@ import cpp int lineInBlock(File f) { - exists(Block block, Location blockLocation | + exists(BlockStmt block, Location blockLocation | block.getFile() = f and blockLocation = block.getLocation() | result in [blockLocation.getStartLine() .. blockLocation.getEndLine()] diff --git a/cpp/ql/src/Likely Bugs/Leap Year/UncheckedReturnValueForTimeFunctions.ql b/cpp/ql/src/Likely Bugs/Leap Year/UncheckedReturnValueForTimeFunctions.ql index 31af5b3ce794..ca36e6d1ce2e 100644 --- a/cpp/ql/src/Likely Bugs/Leap Year/UncheckedReturnValueForTimeFunctions.ql +++ b/cpp/ql/src/Likely Bugs/Leap Year/UncheckedReturnValueForTimeFunctions.ql @@ -40,9 +40,7 @@ class DateStructModifiedFieldAccess extends LeapYearFieldAccess { */ class SafeTimeGatheringFunction extends Function { SafeTimeGatheringFunction() { - this.getQualifiedName() = "GetFileTime" or - this.getQualifiedName() = "GetSystemTime" or - this.getQualifiedName() = "NtQuerySystemTime" + this.getQualifiedName() = ["GetFileTime", "GetSystemTime", "NtQuerySystemTime"] } } @@ -51,15 +49,11 @@ class SafeTimeGatheringFunction extends Function { */ class TimeConversionFunction extends Function { TimeConversionFunction() { - this.getQualifiedName() = "FileTimeToSystemTime" or - this.getQualifiedName() = "SystemTimeToFileTime" or - this.getQualifiedName() = "SystemTimeToTzSpecificLocalTime" or - this.getQualifiedName() = "SystemTimeToTzSpecificLocalTimeEx" or - this.getQualifiedName() = "TzSpecificLocalTimeToSystemTime" or - this.getQualifiedName() = "TzSpecificLocalTimeToSystemTimeEx" or - this.getQualifiedName() = "RtlLocalTimeToSystemTime" or - this.getQualifiedName() = "RtlTimeToSecondsSince1970" or - this.getQualifiedName() = "_mkgmtime" + this.getQualifiedName() = + ["FileTimeToSystemTime", "SystemTimeToFileTime", "SystemTimeToTzSpecificLocalTime", + "SystemTimeToTzSpecificLocalTimeEx", "TzSpecificLocalTimeToSystemTime", + "TzSpecificLocalTimeToSystemTimeEx", "RtlLocalTimeToSystemTime", + "RtlTimeToSecondsSince1970", "_mkgmtime"] } } diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/FutileConditional.ql b/cpp/ql/src/Likely Bugs/Likely Typos/FutileConditional.ql index 4f23ed50b365..bf724de3d70c 100644 --- a/cpp/ql/src/Likely Bugs/Likely Typos/FutileConditional.ql +++ b/cpp/ql/src/Likely Bugs/Likely Typos/FutileConditional.ql @@ -27,11 +27,11 @@ predicate macroUseLocation(File f, int start, int end) { } pragma[noopt] -predicate emptyIf(IfStmt s, Block b, File f, int start, int end) { +predicate emptyIf(IfStmt s, BlockStmt b, File f, int start, int end) { s instanceof IfStmt and not exists(s.getElse()) and b = s.getThen() and - b instanceof Block and + b instanceof BlockStmt and not exists(b.getAChild()) and f = b.getFile() and exists(Location l | @@ -42,7 +42,7 @@ predicate emptyIf(IfStmt s, Block b, File f, int start, int end) { } pragma[noopt] -predicate query(IfStmt s, Block b) { +predicate query(IfStmt s, BlockStmt b) { exists(File f, int blockStart, int blockEnd | emptyIf(s, b, f, blockStart, blockEnd) and not exists(int macroStart, int macroEnd | @@ -53,7 +53,7 @@ predicate query(IfStmt s, Block b) { ) } -from IfStmt s, Block b +from IfStmt s, BlockStmt b where query(s, b) and not b.isInMacroExpansion() diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean.ql b/cpp/ql/src/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean.ql index b53cb1d50b32..074c82bc03b1 100644 --- a/cpp/ql/src/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean.ql +++ b/cpp/ql/src/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean.ql @@ -15,6 +15,15 @@ import cpp import semmle.code.cpp.models.implementations.Strcpy import semmle.code.cpp.dataflow.DataFlow +/** + * A string copy function that returns a string, rather than an error code (for + * example, `strcpy` returns a string, whereas `strcpy_s` returns an error + * code). + */ +class InterestingStrcpyFunction extends StrcpyFunction { + InterestingStrcpyFunction() { getType().getUnspecifiedType() instanceof PointerType } +} + predicate isBoolean(Expr e1) { exists(Type t1 | t1 = e1.getType() and @@ -25,12 +34,12 @@ predicate isBoolean(Expr e1) { predicate isStringCopyCastedAsBoolean(FunctionCall func, Expr expr1, string msg) { DataFlow::localExprFlow(func, expr1) and isBoolean(expr1.getConversion*()) and - func.getTarget() instanceof StrcpyFunction and + func.getTarget() instanceof InterestingStrcpyFunction and msg = "Return value of " + func.getTarget().getName() + " used as a Boolean." } predicate isStringCopyUsedInLogicalOperationOrCondition(FunctionCall func, Expr expr1, string msg) { - func.getTarget() instanceof StrcpyFunction and + func.getTarget() instanceof InterestingStrcpyFunction and ( ( // it is being used in an equality or logical operation diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/inconsistentLoopDirection.ql b/cpp/ql/src/Likely Bugs/Likely Typos/inconsistentLoopDirection.ql index aaf52883e059..5e3af3478214 100644 --- a/cpp/ql/src/Likely Bugs/Likely Typos/inconsistentLoopDirection.ql +++ b/cpp/ql/src/Likely Bugs/Likely Typos/inconsistentLoopDirection.ql @@ -50,7 +50,12 @@ predicate illDefinedDecrForStmt( DataFlow::localFlowStep(DataFlow::exprNode(initialCondition), DataFlow::exprNode(lesserOperand)) and // `initialCondition` < `terminalCondition` ( - upperBound(initialCondition) < lowerBound(terminalCondition) + upperBound(initialCondition) < lowerBound(terminalCondition) and + ( + // exclude cases where the loop counter is `unsigned` (where wrapping behaviour can be used deliberately) + v.getUnspecifiedType().(IntegralType).isSigned() or + initialCondition.getValue().toInt() = 0 + ) or (forstmt.conditionAlwaysFalse() or forstmt.conditionAlwaysTrue()) ) diff --git a/cpp/ql/src/Likely Bugs/RedundantNullCheckSimple.ql b/cpp/ql/src/Likely Bugs/RedundantNullCheckSimple.ql index 6ba835acbdc8..65ba665dff29 100644 --- a/cpp/ql/src/Likely Bugs/RedundantNullCheckSimple.ql +++ b/cpp/ql/src/Likely Bugs/RedundantNullCheckSimple.ql @@ -23,7 +23,7 @@ import semmle.code.cpp.ir.ValueNumbering class NullInstruction extends ConstantValueInstruction { NullInstruction() { this.getValue() = "0" and - this.getResultType().getUnspecifiedType() instanceof PointerType + this.getResultIRType() instanceof IRAddressType } } @@ -44,8 +44,8 @@ predicate explicitNullTestOfInstruction(Instruction checked, Instruction bool) { bool = any(ConvertInstruction convert | checked = convert.getUnary() and - convert.getResultType() instanceof BoolType and - checked.getResultType() instanceof PointerType + convert.getResultIRType() instanceof IRBooleanType and + checked.getResultIRType() instanceof IRAddressType ) } diff --git a/cpp/ql/src/Metrics/Dependencies/ExternalDependencies.ql b/cpp/ql/src/Metrics/Dependencies/ExternalDependencies.ql index 7062911ca4df..47ddb9d1f1e6 100644 --- a/cpp/ql/src/Metrics/Dependencies/ExternalDependencies.ql +++ b/cpp/ql/src/Metrics/Dependencies/ExternalDependencies.ql @@ -1,4 +1,5 @@ /** + * @deprecated * @name External dependencies * @description Count the number of dependencies a C/C++ source file has on external libraries. * @kind treemap diff --git a/cpp/ql/src/Metrics/Dependencies/ExternalDependenciesSourceLinks.ql b/cpp/ql/src/Metrics/Dependencies/ExternalDependenciesSourceLinks.ql index f2c110a0ac19..cf305ab0aeaf 100644 --- a/cpp/ql/src/Metrics/Dependencies/ExternalDependenciesSourceLinks.ql +++ b/cpp/ql/src/Metrics/Dependencies/ExternalDependenciesSourceLinks.ql @@ -1,4 +1,5 @@ /** + * @deprecated * @name External dependency source links * @kind source-link * @metricType externalDependency diff --git a/cpp/ql/src/Metrics/Files/CommentedOutCodeMetricOverview.qhelp b/cpp/ql/src/Metrics/Files/CommentedOutCodeMetricOverview.qhelp new file mode 100644 index 000000000000..217b6d175295 --- /dev/null +++ b/cpp/ql/src/Metrics/Files/CommentedOutCodeMetricOverview.qhelp @@ -0,0 +1,12 @@ + + + +

+This metric counts the number of lines of commented-out code in each file. Large amounts of +commented-out code often indicate poorly maintained code. +

+ +
+
diff --git a/cpp/ql/src/Metrics/Files/CommentedOutCodeReferences.qhelp b/cpp/ql/src/Metrics/Files/CommentedOutCodeReferences.qhelp new file mode 100644 index 000000000000..462eb7795f91 --- /dev/null +++ b/cpp/ql/src/Metrics/Files/CommentedOutCodeReferences.qhelp @@ -0,0 +1,12 @@ + + + + +
  • Mark Needham: The danger of commenting out code.
  • +
  • Los Techies: Commented Code == Technical Debt.
  • +
  • High Integrity C++ Coding Standard: 2.3.2 Do not comment out code.
  • + +
    +
    diff --git a/cpp/ql/src/Metrics/Files/DuplicationProblems.qhelp b/cpp/ql/src/Metrics/Files/DuplicationProblems.qhelp new file mode 100644 index 000000000000..54397da6c994 --- /dev/null +++ b/cpp/ql/src/Metrics/Files/DuplicationProblems.qhelp @@ -0,0 +1,16 @@ + + + +

    +Duplicated code increases overall code size, making the code base +harder to maintain and harder to understand. It also becomes harder to fix bugs, +since a programmer applying a fix to one copy has to always remember to update +other copies accordingly. Finally, code duplication is generally an indication of +a poorly designed or hastily written code base, which typically suffers from other +problems as well. +

    + +
    +
    diff --git a/cpp/ql/src/Metrics/Files/FLinesOfDuplicatedCode.ql b/cpp/ql/src/Metrics/Files/FLinesOfDuplicatedCode.ql index 3a11eb3575a1..ab9317ea316e 100644 --- a/cpp/ql/src/Metrics/Files/FLinesOfDuplicatedCode.ql +++ b/cpp/ql/src/Metrics/Files/FLinesOfDuplicatedCode.ql @@ -1,4 +1,5 @@ /** + * @deprecated * @name Duplicated lines in files * @description The number of lines in a file, including code, comment * and whitespace lines, which are duplicated in at least diff --git a/cpp/ql/src/Metrics/Files/FLinesOfDuplicatedCodeCommon.qhelp b/cpp/ql/src/Metrics/Files/FLinesOfDuplicatedCodeCommon.qhelp new file mode 100644 index 000000000000..17171fb75871 --- /dev/null +++ b/cpp/ql/src/Metrics/Files/FLinesOfDuplicatedCodeCommon.qhelp @@ -0,0 +1,35 @@ + + + + +

    +This metric measures the number of lines in a file that are contained within a block that is duplicated elsewhere. These lines may include code, comments and whitespace, and the duplicate block may be in this file or in another file. +

    + +

    +A file that contains many lines that are duplicated within the code base is problematic +for a number of reasons. +

    + +
    + + + + +

    +Refactor files with lots of duplicated code to extract the common code into +a shared library or module. +

    + +
    + + + +
  • Wikipedia: Duplicate code.
  • +
  • M. Fowler, Refactoring. Addison-Wesley, 1999.
  • + + +
    +
    diff --git a/cpp/ql/src/Metrics/Files/FNumberOfTests.ql b/cpp/ql/src/Metrics/Files/FNumberOfTests.ql index a474b9862037..421fc2baba1f 100644 --- a/cpp/ql/src/Metrics/Files/FNumberOfTests.ql +++ b/cpp/ql/src/Metrics/Files/FNumberOfTests.ql @@ -18,6 +18,9 @@ Expr getTest() { or // boost tests; http://www.boost.org/ result.(FunctionCall).getTarget().hasQualifiedName("boost::unit_test", "make_test_case") + or + // googletest tests; https://github.com/google/googletest/ + result.(FunctionCall).getTarget().hasQualifiedName("testing::internal", "MakeAndRegisterTestInfo") } from File f, int n diff --git a/cpp/ql/src/Microsoft/SAL.qll b/cpp/ql/src/Microsoft/SAL.qll index 04ea9a9c5fa8..46fedbb5d80c 100644 --- a/cpp/ql/src/Microsoft/SAL.qll +++ b/cpp/ql/src/Microsoft/SAL.qll @@ -1,14 +1,17 @@ +/** + * Provides classes for identifying and reasoning about Microsoft source code + * annotation language (SAL) macros. + */ + import cpp +/** + * A SAL macro defined in `sal.h` or a similar header file. + */ class SALMacro extends Macro { SALMacro() { - exists(string filename | filename = this.getFile().getBaseName() | - filename = "sal.h" or - filename = "specstrings_strict.h" or - filename = "specstrings.h" or - filename = "w32p.h" or - filename = "minwindef.h" - ) and + this.getFile().getBaseName() = + ["sal.h", "specstrings_strict.h", "specstrings.h", "w32p.h", "minwindef.h"] and ( // Dialect for Windows 8 and above this.getName().matches("\\_%\\_") @@ -20,36 +23,44 @@ class SALMacro extends Macro { } pragma[noinline] -predicate isTopLevelMacroAccess(MacroAccess ma) { not exists(ma.getParentInvocation()) } +private predicate isTopLevelMacroAccess(MacroAccess ma) { not exists(ma.getParentInvocation()) } +/** + * An invocation of a SAL macro (excluding invocations inside other macros). + */ class SALAnnotation extends MacroInvocation { SALAnnotation() { this.getMacro() instanceof SALMacro and isTopLevelMacroAccess(this) } - /** Returns the `Declaration` annotated by `this`. */ + /** Gets the `Declaration` annotated by `this`. */ Declaration getDeclaration() { annotatesAt(this, result.getADeclarationEntry(), _, _) and not result instanceof Type // exclude typedefs } - /** Returns the `DeclarationEntry` annotated by `this`. */ + /** Gets the `DeclarationEntry` annotated by `this`. */ DeclarationEntry getDeclarationEntry() { annotatesAt(this, result, _, _) and not result instanceof TypeDeclarationEntry // exclude typedefs } } +/** + * A SAL macro indicating that the return value of a function should always be + * checked. + */ class SALCheckReturn extends SALAnnotation { SALCheckReturn() { - exists(SALMacro m | m = this.getMacro() | - m.getName() = "_Check_return_" or - m.getName() = "_Must_inspect_result_" - ) + this.getMacro().(SALMacro).getName() = ["_Check_return_", "_Must_inspect_result_"] } } +/** + * A SAL macro indicating that a pointer variable or return value should not be + * `NULL`. + */ class SALNotNull extends SALAnnotation { SALNotNull() { exists(SALMacro m | m = this.getMacro() | @@ -69,6 +80,9 @@ class SALNotNull extends SALAnnotation { } } +/** + * A SAL macro indicating that a value may be `NULL`. + */ class SALMaybeNull extends SALAnnotation { SALMaybeNull() { exists(SALMacro m | m = this.getMacro() | @@ -79,13 +93,29 @@ class SALMaybeNull extends SALAnnotation { } } +/** + * A parameter annotated by one or more SAL annotations. + */ +class SALParameter extends Parameter { + /** One of this parameter's annotations. */ + SALAnnotation a; + + SALParameter() { annotatesAt(a, this.getADeclarationEntry(), _, _) } + + predicate isIn() { a.getMacroName().toLowerCase().matches("%\\_in%") } + + predicate isOut() { a.getMacroName().toLowerCase().matches("%\\_out%") } + + predicate isInOut() { a.getMacroName().toLowerCase().matches("%\\_inout%") } +} + /////////////////////////////////////////////////////////////////////////////// // Implementation details /** * Holds if `a` annotates the declaration entry `d` and * its start position is the `idx`th position in `file` that holds a SAL element. */ -predicate annotatesAt(SALAnnotation a, DeclarationEntry d, File file, int idx) { +private predicate annotatesAt(SALAnnotation a, DeclarationEntry d, File file, int idx) { annotatesAtPosition(a.(SALElement).getStartPosition(), d, file, idx) } @@ -109,22 +139,6 @@ private predicate annotatesAtPosition(SALPosition pos, DeclarationEntry d, File ) } -/** - * A parameter annotated by one or more SAL annotations. - */ -class SALParameter extends Parameter { - /** One of this parameter's annotations. */ - SALAnnotation a; - - SALParameter() { annotatesAt(a, this.getADeclarationEntry(), _, _) } - - predicate isIn() { a.getMacroName().toLowerCase().matches("%\\_in%") } - - predicate isOut() { a.getMacroName().toLowerCase().matches("%\\_out%") } - - predicate isInOut() { a.getMacroName().toLowerCase().matches("%\\_inout%") } -} - /** * A SAL element, that is, a SAL annotation or a declaration entry * that may have SAL annotations. diff --git a/cpp/ql/src/Power of 10/Rule 4/FunctionTooLong.ql b/cpp/ql/src/Power of 10/Rule 4/FunctionTooLong.ql index 2b26a8356830..701d56e6ce24 100644 --- a/cpp/ql/src/Power of 10/Rule 4/FunctionTooLong.ql +++ b/cpp/ql/src/Power of 10/Rule 4/FunctionTooLong.ql @@ -27,7 +27,7 @@ int logicalLength(FunctionDeclarationEntry f) { count(Stmt s | s.getEnclosingFunction() = f.getFunction() and s.getFile() = f.getFile() and - not s instanceof Block and + not s instanceof BlockStmt and not s instanceof EmptyStmt and not exists(ForStmt for | s = for.getInitialization()) and not s.isAffectedByMacro() diff --git a/cpp/ql/src/Power of 10/Rule 4/OneStmtPerLine.ql b/cpp/ql/src/Power of 10/Rule 4/OneStmtPerLine.ql index c3936e1ed89d..7c66cdd41f40 100644 --- a/cpp/ql/src/Power of 10/Rule 4/OneStmtPerLine.ql +++ b/cpp/ql/src/Power of 10/Rule 4/OneStmtPerLine.ql @@ -14,7 +14,7 @@ import cpp class OneLineStmt extends Stmt { OneLineStmt() { this.getLocation().getStartLine() = this.getLocation().getEndLine() and - not this instanceof Block and + not this instanceof BlockStmt and not exists(ForStmt for | this = for.getInitialization()) and ( // Either this statement is not touched by a macro at all... diff --git a/cpp/ql/src/Power of 10/Rule 5/AssertionDensity.ql b/cpp/ql/src/Power of 10/Rule 5/AssertionDensity.ql index 1fbbaf99b58d..3bb926b8a649 100644 --- a/cpp/ql/src/Power of 10/Rule 5/AssertionDensity.ql +++ b/cpp/ql/src/Power of 10/Rule 5/AssertionDensity.ql @@ -27,7 +27,7 @@ int logicalLength(FunctionDeclarationEntry f) { count(Stmt s | s.getEnclosingFunction() = f.getFunction() and s.getFile() = f.getFile() and - not s instanceof Block and + not s instanceof BlockStmt and not s instanceof EmptyStmt and not exists(ForStmt for | s = for.getInitialization()) and not s.isAffectedByMacro() diff --git a/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.qhelp b/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.qhelp index d7432369f0e8..eba2ede58f52 100644 --- a/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.qhelp +++ b/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.qhelp @@ -39,7 +39,7 @@ access all the system's passwords.

  • OWASP: -Path Traversal. +Path Traversal.
  • diff --git a/cpp/ql/src/Security/CWE/CWE-121/UnterminatedVarargsCall.ql b/cpp/ql/src/Security/CWE/CWE-121/UnterminatedVarargsCall.ql index 473f0f72f122..bfb3a2fbb816 100644 --- a/cpp/ql/src/Security/CWE/CWE-121/UnterminatedVarargsCall.ql +++ b/cpp/ql/src/Security/CWE/CWE-121/UnterminatedVarargsCall.ql @@ -56,7 +56,7 @@ class VarargsFunction extends Function { } string normalTerminator(int cnt) { - (result = "0" or result = "-1") and + result = ["0", "-1"] and cnt = trailingArgValueCount(result) and 2 * cnt > totalCount() and not exists(FunctionCall fc, int index | diff --git a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql index 91ccc5c4d400..b64091263e09 100644 --- a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql +++ b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql @@ -5,7 +5,7 @@ * or data representation problems. * @kind path-problem * @problem.severity warning - * @precision medium + * @precision high * @id cpp/tainted-format-string * @tags reliability * security diff --git a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql index 96cffdb024bf..d38f3eb24c2f 100644 --- a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql +++ b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql @@ -5,7 +5,7 @@ * or data representation problems. * @kind path-problem * @problem.severity warning - * @precision medium + * @precision high * @id cpp/tainted-format-string-through-global * @tags reliability * security diff --git a/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql b/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql index 54c6d1e7a966..cc2d52385c77 100644 --- a/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql +++ b/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql @@ -4,7 +4,7 @@ * user can result in integer overflow. * @kind path-problem * @problem.severity error - * @precision high + * @precision medium * @id cpp/uncontrolled-allocation-size * @tags reliability * security diff --git a/cpp/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql b/cpp/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql index 3f6ff63635e0..af64a1789c3b 100644 --- a/cpp/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql +++ b/cpp/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql @@ -18,7 +18,7 @@ abstract class InsecureCryptoSpec extends Locatable { } Function getAnInsecureFunction() { - result.getName().regexpMatch(algorithmBlacklistRegex()) and + result.getName().regexpMatch(getInsecureAlgorithmRegex()) and exists(result.getACallToThisFunction()) } @@ -33,7 +33,7 @@ class InsecureFunctionCall extends InsecureCryptoSpec, FunctionCall { } Macro getAnInsecureMacro() { - result.getName().regexpMatch(algorithmBlacklistRegex()) and + result.getName().regexpMatch(getInsecureAlgorithmRegex()) and exists(result.getAnInvocation()) } diff --git a/cpp/ql/src/Security/CWE/CWE-676/DangerousUseOfCin.ql b/cpp/ql/src/Security/CWE/CWE-676/DangerousUseOfCin.ql index fc47d04c2c51..32bdfbaf1007 100644 --- a/cpp/ql/src/Security/CWE/CWE-676/DangerousUseOfCin.ql +++ b/cpp/ql/src/Security/CWE/CWE-676/DangerousUseOfCin.ql @@ -66,10 +66,7 @@ class IFStream extends Type { */ class CinVariable extends NamespaceVariable { CinVariable() { - ( - getName() = "cin" or - getName() = "wcin" - ) and + getName() = ["cin", "wcin"] and getNamespace().getName() = "std" } } diff --git a/cpp/ql/src/Security/CWE/CWE-676/PotentiallyDangerousFunction.ql b/cpp/ql/src/Security/CWE/CWE-676/PotentiallyDangerousFunction.ql index 71601ec2181c..4316fe229b26 100644 --- a/cpp/ql/src/Security/CWE/CWE-676/PotentiallyDangerousFunction.ql +++ b/cpp/ql/src/Security/CWE/CWE-676/PotentiallyDangerousFunction.ql @@ -14,12 +14,7 @@ import cpp predicate potentiallyDangerousFunction(Function f, string message) { exists(string name | f.hasGlobalName(name) | - ( - name = "gmtime" or - name = "localtime" or - name = "ctime" or - name = "asctime" - ) and + name = ["gmtime", "localtime", "ctime", "asctime"] and message = "Call to " + name + " is potentially dangerous" ) } diff --git a/cpp/ql/src/Security/CWE/CWE-732/DoNotCreateWorldWritable.ql b/cpp/ql/src/Security/CWE/CWE-732/DoNotCreateWorldWritable.ql index 269e7e33b59e..95790298347d 100644 --- a/cpp/ql/src/Security/CWE/CWE-732/DoNotCreateWorldWritable.ql +++ b/cpp/ql/src/Security/CWE/CWE-732/DoNotCreateWorldWritable.ql @@ -19,12 +19,7 @@ predicate worldWritableCreation(FileCreationExpr fc, int mode) { } predicate setWorldWritable(FunctionCall fc, int mode) { - exists(string name | fc.getTarget().getName() = name | - name = "chmod" or - name = "fchmod" or - name = "_chmod" or - name = "_wchmod" - ) and + fc.getTarget().getName() = ["chmod", "fchmod", "_chmod", "_wchmod"] and mode = fc.getArgument(1).getValue().toInt() and sets(mode, s_iwoth()) } diff --git a/cpp/ql/src/Security/CWE/CWE-732/FilePermissions.qll b/cpp/ql/src/Security/CWE/CWE-732/FilePermissions.qll index bb9c5b12f986..d62f3e6a6daa 100644 --- a/cpp/ql/src/Security/CWE/CWE-732/FilePermissions.qll +++ b/cpp/ql/src/Security/CWE/CWE-732/FilePermissions.qll @@ -31,11 +31,7 @@ predicate sets(int mask, int fields) { mask.bitAnd(fields) != 0 } * one of the `umask` family of functions. */ private int umask(FunctionCall fc) { - exists(string name | name = fc.getTarget().getName() | - name = "umask" or - name = "_umask" or - name = "_umask_s" - ) and + fc.getTarget().getName() = ["umask", "_umask", "_umask_s"] and result = fc.getArgument(0).getValue().toInt() } @@ -89,11 +85,7 @@ abstract class FileCreationExpr extends FunctionCall { class OpenCreationExpr extends FileCreationExpr { OpenCreationExpr() { - exists(string name | name = this.getTarget().getName() | - name = "open" or - name = "_open" or - name = "_wopen" - ) and + this.getTarget().getName() = ["open", "_open", "_wopen"] and sets(this.getArgument(1).getValue().toInt(), o_creat()) } @@ -134,14 +126,9 @@ private int fopenMode() { class FopenCreationExpr extends FileCreationExpr { FopenCreationExpr() { - exists(string name | name = this.getTarget().getName() | - name = "fopen" or - name = "_wfopen" or - name = "fsopen" or - name = "_wfsopen" - ) and + this.getTarget().getName() = ["fopen", "_wfopen", "fsopen", "_wfsopen"] and exists(string mode | - (mode = "w" or mode = "a") and + mode = ["w", "a"] and this.getArgument(1).getValue().matches(mode + "%") ) } diff --git a/cpp/ql/src/codeql-suites/cpp-code-scanning.qls b/cpp/ql/src/codeql-suites/cpp-code-scanning.qls index 27bff98ea5d0..f811010a26a7 100644 --- a/cpp/ql/src/codeql-suites/cpp-code-scanning.qls +++ b/cpp/ql/src/codeql-suites/cpp-code-scanning.qls @@ -2,3 +2,5 @@ - qlpack: codeql-cpp - apply: code-scanning-selectors.yml from: codeql-suite-helpers +- apply: codeql-suites/exclude-slow-queries.yml + from: codeql-cpp diff --git a/cpp/ql/src/codeql-suites/cpp-lgtm-full.qls b/cpp/ql/src/codeql-suites/cpp-lgtm-full.qls index e9fda1cdb9e8..b6775597c30a 100644 --- a/cpp/ql/src/codeql-suites/cpp-lgtm-full.qls +++ b/cpp/ql/src/codeql-suites/cpp-lgtm-full.qls @@ -2,18 +2,14 @@ - qlpack: codeql-cpp - apply: lgtm-selectors.yml from: codeql-suite-helpers -# These queries are infeasible to compute on large projects: -- exclude: - query path: - - Security/CWE/CWE-497/ExposedSystemData.ql - - Critical/DescriptorMayNotBeClosed.ql - - Critical/DescriptorNeverClosed.ql - - Critical/FileMayNotBeClosed.ql - - Critical/FileNeverClosed.ql - - Critical/MemoryMayNotBeFreed.ql - - Critical/MemoryNeverFreed.ql +- apply: codeql-suites/exclude-slow-queries.yml + from: codeql-cpp # These are only for IDE use. - exclude: tags contain: - ide-contextual-queries/local-definitions - ide-contextual-queries/local-references +- query: Metrics/Files/FLinesOfCode.ql +- query: Metrics/Files/FLinesOfCommentedOutCode.ql +- query: Metrics/Files/FLinesOfComments.ql +- query: Metrics/Files/FNumberOfTests.ql diff --git a/cpp/ql/src/codeql-suites/cpp-security-and-quality.qls b/cpp/ql/src/codeql-suites/cpp-security-and-quality.qls new file mode 100644 index 000000000000..297f46bc7522 --- /dev/null +++ b/cpp/ql/src/codeql-suites/cpp-security-and-quality.qls @@ -0,0 +1,6 @@ +- description: Security-and-quality queries for C and C++ +- qlpack: codeql-cpp +- apply: security-and-quality-selectors.yml + from: codeql-suite-helpers +- apply: codeql-suites/exclude-slow-queries.yml + from: codeql-cpp diff --git a/cpp/ql/src/codeql-suites/cpp-security-extended.qls b/cpp/ql/src/codeql-suites/cpp-security-extended.qls new file mode 100644 index 000000000000..fa69559add0b --- /dev/null +++ b/cpp/ql/src/codeql-suites/cpp-security-extended.qls @@ -0,0 +1,6 @@ +- description: Security-extended queries for C and C++ +- qlpack: codeql-cpp +- apply: security-extended-selectors.yml + from: codeql-suite-helpers +- apply: codeql-suites/exclude-slow-queries.yml + from: codeql-cpp diff --git a/cpp/ql/src/codeql-suites/exclude-slow-queries.yml b/cpp/ql/src/codeql-suites/exclude-slow-queries.yml new file mode 100644 index 000000000000..a1a4ced9c7db --- /dev/null +++ b/cpp/ql/src/codeql-suites/exclude-slow-queries.yml @@ -0,0 +1,11 @@ +- description: C/C++ queries which are infeasible to compute on large projects +# These queries are infeasible to compute on large projects: +- exclude: + query path: + - Security/CWE/CWE-497/ExposedSystemData.ql + - Critical/DescriptorMayNotBeClosed.ql + - Critical/DescriptorNeverClosed.ql + - Critical/FileMayNotBeClosed.ql + - Critical/FileNeverClosed.ql + - Critical/MemoryMayNotBeFreed.ql + - Critical/MemoryNeverFreed.ql diff --git a/cpp/ql/src/cpp.qll b/cpp/ql/src/cpp.qll index 78fde101a42f..a989c9a6c9d4 100644 --- a/cpp/ql/src/cpp.qll +++ b/cpp/ql/src/cpp.qll @@ -32,6 +32,7 @@ import semmle.code.cpp.Enum import semmle.code.cpp.Member import semmle.code.cpp.Field import semmle.code.cpp.Function +import semmle.code.cpp.MemberFunction import semmle.code.cpp.Parameter import semmle.code.cpp.Variable import semmle.code.cpp.Initializer diff --git a/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.cpp b/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.cpp new file mode 100644 index 000000000000..3765d0b14d40 --- /dev/null +++ b/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.cpp @@ -0,0 +1,11 @@ +void test(char *arg1, int *arg2) { + if (arg1[0] == 'A') { + if (arg2 != NULL) { //maybe redundant + *arg2 = 42; + } + } + if (arg1[1] == 'B') + { + *arg2 = 54; //dereferenced without checking first + } +} diff --git a/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.qhelp b/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.qhelp new file mode 100644 index 000000000000..25cbeff355ec --- /dev/null +++ b/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.qhelp @@ -0,0 +1,29 @@ + + + + +

    This rule finds comparisons of a function parameter to null that occur when in another path the parameter is dereferenced without a guard check. It's +likely either the check is not required and can be removed, or it should be added before the dereference +so that a null pointer dereference does not occur.

    +
    + + +

    A check should be added to before the dereference, in a way that prevents a null pointer value from +being dereferenced. If it's clear that the pointer cannot be null, consider removing the check instead.

    +
    + + + + + + +
  • + + Null Dereference + +
  • +
    + +
    diff --git a/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql b/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql new file mode 100644 index 000000000000..f1a3663bb960 --- /dev/null +++ b/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql @@ -0,0 +1,56 @@ +/** + * @name Redundant null check or missing null check of parameter + * @description Checking a parameter for nullness in one path, + * and not in another is likely to be a sign that either + * the check can be removed, or added in the other case. + * @kind problem + * @id cpp/redundant-null-check-param + * @problem.severity recommendation + * @tags reliability + * security + * external/cwe/cwe-476 + */ + +import cpp + +predicate blockDominates(BlockStmt check, BlockStmt access) { + check.getLocation().getStartLine() <= access.getLocation().getStartLine() and + check.getLocation().getEndLine() >= access.getLocation().getEndLine() +} + +predicate isCheckedInstruction(VariableAccess unchecked, VariableAccess checked) { + checked = any(VariableAccess va | va.getTarget() = unchecked.getTarget()) and + //Simple test if the first access in this code path is dereferenced + not dereferenced(checked) and + blockDominates(checked.getEnclosingBlock(), unchecked.getEnclosingBlock()) +} + +predicate candidateResultUnchecked(VariableAccess unchecked) { + not isCheckedInstruction(unchecked, _) +} + +predicate candidateResultChecked(VariableAccess check, EqualityOperation eqop) { + //not dereferenced to check against pointer, not its pointed value + not dereferenced(check) and + //assert macros are not taken into account + not check.isInMacroExpansion() and + // is part of a comparison against some constant NULL + eqop.getAnOperand() = check and + eqop.getAnOperand() instanceof NullValue +} + +from VariableAccess unchecked, VariableAccess check, EqualityOperation eqop, Parameter param +where + // a dereference + dereferenced(unchecked) and + // for a function parameter + unchecked.getTarget() = param and + // this function parameter is not overwritten + count(param.getAnAssignment()) = 0 and + check.getTarget() = param and + // which is once checked + candidateResultChecked(check, eqop) and + // and which has not been checked before in this code path + candidateResultUnchecked(unchecked) +select check, "This null check is redundant or there is a missing null check before $@ ", unchecked, + "where dereferencing happens" diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-120/MemoryUnsafeFunctionScan.cpp b/cpp/ql/src/experimental/Security/CWE/CWE-120/MemoryUnsafeFunctionScan.cpp new file mode 100644 index 000000000000..001f4da6028d --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-120/MemoryUnsafeFunctionScan.cpp @@ -0,0 +1,25 @@ +///// Library routines ///// + +int scanf(const char *format, ...); +int sscanf(const char *str, const char *format, ...); +int fscanf(const char *str, const char *format, ...); + +///// EXAMPLES ///// + +int main(int argc, char **argv) +{ + + // BAD, do not use scanf without specifying a length first + char buf1[10]; + scanf("%s", buf1); + + // GOOD, length is specified. The length should be one less than the size of the buffer, since the last character is the NULL terminator. + char buf2[10]; + sscanf(buf2, "%9s"); + + // BAD, do not use scanf without specifying a length first + char file[10]; + fscanf(file, "%s", buf2); + + return 0; +} diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-120/MemoryUnsafeFunctionScan.qhelp b/cpp/ql/src/experimental/Security/CWE/CWE-120/MemoryUnsafeFunctionScan.qhelp new file mode 100644 index 000000000000..c3561a6c17f6 --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-120/MemoryUnsafeFunctionScan.qhelp @@ -0,0 +1,25 @@ + + + +

    It is bad practice to use any of the scanf functions without including a specified length within the format parameter, as it will be vulnerable to buffer overflows.

    + +
    + + + +

    Specify a length within the format string parameter, and make this length one less than the size of the buffer, since the last character should be reserved for the NULL terminator.

    + +
    + + +

    The following example demonstrates safe and unsafe uses of scanf type functions.

    + + +
    + + + + +
    diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-120/MemoryUnsafeFunctionScan.ql b/cpp/ql/src/experimental/Security/CWE/CWE-120/MemoryUnsafeFunctionScan.ql new file mode 100644 index 000000000000..dd5c389fdafc --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-120/MemoryUnsafeFunctionScan.ql @@ -0,0 +1,19 @@ +/** + * @name Scanf function without a specified length + * @description Use of one of the scanf functions without a specified length. + * @kind problem + * @problem.severity warning + * @id cpp/memory-unsafe-function-scan + * @tags reliability + * security + * external/cwe/cwe-120 + */ + +import cpp +import semmle.code.cpp.commons.Scanf + +from FunctionCall call, ScanfFunction sff +where + call.getTarget() = sff and + call.getArgument(sff.getFormatParameterIndex()).getValue().regexpMatch(".*%l?s.*") +select call, "Dangerous use of one of the scanf functions" diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-359/PrivateCleartextWrite.qhelp b/cpp/ql/src/experimental/Security/CWE/CWE-359/PrivateCleartextWrite.qhelp new file mode 100644 index 000000000000..5403f030b52e --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-359/PrivateCleartextWrite.qhelp @@ -0,0 +1,32 @@ + + + +

    Private data that is stored in a file or buffer unencrypted is accessible to an attacker who gains access to the +storage.

    + +
    + + +

    Ensure that private data is always encrypted before being stored. +It may be wise to encrypt information before it is put into a buffer that may be readable in memory.

    + +

    In general, decrypt private data only at the point where it is necessary for it to be used in +cleartext.

    + +
    + + + +
  • OWASP Sensitive_Data_Exposure
  • +
  • M. Dowd, J. McDonald and J. Schuhm, The Art of Software Security Assessment, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.
  • +
  • M. Howard and D. LeBlanc, Writing Secure Code, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.
  • + + + + + +
    +
    diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-359/PrivateCleartextWrite.ql b/cpp/ql/src/experimental/Security/CWE/CWE-359/PrivateCleartextWrite.ql new file mode 100644 index 000000000000..60b13525aff4 --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-359/PrivateCleartextWrite.ql @@ -0,0 +1,21 @@ +/** + * @name Exposure of private information + * @description If private information is written to an external location, it may be accessible by + * unauthorized persons. + * @kind path-problem + * @problem.severity error + * @id cpp/private-cleartext-write + * @tags security + * external/cwe/cwe-359 + */ + +import cpp +import experimental.semmle.code.cpp.security.PrivateCleartextWrite +import experimental.semmle.code.cpp.security.PrivateCleartextWrite::PrivateCleartextWrite +import DataFlow::PathGraph + +from WriteConfig b, DataFlow::PathNode source, DataFlow::PathNode sink +where b.hasFlowPath(source, sink) +select sink.getNode(), + "This write into the external location '" + sink + "' may contain unencrypted data from $@", + source, "this source." diff --git a/cpp/ql/src/experimental/semmle/code/cpp/models/interfaces/SimpleRangeAnalysisDefinition.qll b/cpp/ql/src/experimental/semmle/code/cpp/models/interfaces/SimpleRangeAnalysisDefinition.qll new file mode 100644 index 000000000000..0cf570a72b43 --- /dev/null +++ b/cpp/ql/src/experimental/semmle/code/cpp/models/interfaces/SimpleRangeAnalysisDefinition.qll @@ -0,0 +1,65 @@ +/** + * EXPERIMENTAL: The API of this module may change without notice. + * + * Provides a class for modeling `RangeSsaDefinition`s with a restricted range. + */ + +import cpp +import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis + +/** + * EXPERIMENTAL: The API of this class may change without notice. + * + * An SSA definition for which a range can be deduced. As with + * `RangeSsaDefinition` and `SsaDefinition`, instances of this class + * correspond to points in the program where one or more variables are defined + * or have their value constrained in some way. + * + * Extend this class to add functionality to the range analysis library. + */ +abstract class SimpleRangeAnalysisDefinition extends RangeSsaDefinition { + /** + * Holds if this `SimpleRangeAnalysisDefinition` adds range information for + * `v`. Because a `SimpleRangeAnalysisDefinition` is just a point in the + * program, it's possible that more than one variable might be defined at + * this point. This predicate clarifies which variable(s) should get range + * information from `this`. + * + * This predicate **must be overridden** to hold for any `v` that can show + * up in the other members of `SimpleRangeAnalysisDefinition`. Conversely, + * the other members **must be accurate** for any `v` in this predicate. + */ + abstract predicate hasRangeInformationFor(StackVariable v); + + /** + * Holds if `(this, v)` depends on the range of the unconverted expression + * `e`. This information is used to inform the range analysis about cyclic + * dependencies. Without this information, range analysis might work for + * simple cases but will go into infinite loops on complex code. + * + * For example, when modelling the definition by reference in a call to an + * overloaded `operator=`, written as `v = e`, the definition of `(this, v)` + * depends on `e`. + */ + abstract predicate dependsOnExpr(StackVariable v, Expr e); + + /** + * Gets the lower bound of the variable `v` defined by this definition. + * + * Implementations of this predicate should use + * `getFullyConvertedLowerBounds` and `getFullyConvertedUpperBounds` for + * recursive calls to get the bounds of their dependencies. + */ + abstract float getLowerBounds(StackVariable v); + + /** + * Gets the upper bound of the variable `v` defined by this definition. + * + * Implementations of this predicate should use + * `getFullyConvertedLowerBounds` and `getFullyConvertedUpperBounds` for + * recursive calls to get the bounds of their dependencies. + */ + abstract float getUpperBounds(StackVariable v); +} + +import SimpleRangeAnalysisInternal diff --git a/cpp/ql/src/experimental/semmle/code/cpp/models/interfaces/SimpleRangeAnalysisExpr.qll b/cpp/ql/src/experimental/semmle/code/cpp/models/interfaces/SimpleRangeAnalysisExpr.qll new file mode 100644 index 000000000000..c8c1110b3af8 --- /dev/null +++ b/cpp/ql/src/experimental/semmle/code/cpp/models/interfaces/SimpleRangeAnalysisExpr.qll @@ -0,0 +1,78 @@ +/** + * EXPERIMENTAL: The API of this module may change without notice. + * + * Provides a class for modeling `Expr`s with a restricted range. + */ + +import cpp +import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis + +/** + * EXPERIMENTAL: The API of this class may change without notice. + * + * An expression for which a range can be deduced. Extend this class to add + * functionality to the range analysis library. + */ +abstract class SimpleRangeAnalysisExpr extends Expr { + /** + * Gets the lower bound of the expression. + * + * Implementations of this predicate should use + * `getFullyConvertedLowerBounds` and `getFullyConvertedUpperBounds` for + * recursive calls to get the bounds of their children. + */ + abstract float getLowerBounds(); + + /** + * Gets the upper bound of the expression. + * + * Implementations of this predicate should use + * `getFullyConvertedLowerBounds` and `getFullyConvertedUpperBounds` for + * recursive calls to get the bounds of their children. + */ + abstract float getUpperBounds(); + + /** + * Holds if the range this expression depends on the definition `srcDef` for + * StackVariable `srcVar`. + * + * Because this predicate cannot be recursive, most implementations should + * override `dependsOnChild` instead. + */ + predicate dependsOnDef(RangeSsaDefinition srcDef, StackVariable srcVar) { none() } + + /** + * Holds if this expression depends on the range of its unconverted + * subexpression `child`. This information is used to inform the range + * analysis about cyclic dependencies. Without this information, range + * analysis might work for simple cases but will go into infinite loops on + * complex code. + * + * For example, when modeling a function call whose return value depends on + * all of its arguments, implement this predicate as + * `child = this.getAnArgument()`. + */ + abstract predicate dependsOnChild(Expr child); +} + +import SimpleRangeAnalysisInternal + +/** + * This class exists to prevent the QL front end from emitting compile errors + * inside `SimpleRangeAnalysis.qll` about certain conjuncts being empty + * because the overrides of `SimpleRangeAnalysisExpr` that happen to be in + * scope do not make use of every feature it offers. + */ +private class Empty extends SimpleRangeAnalysisExpr { + Empty() { + // This predicate is complicated enough that the QL type checker doesn't + // see it as empty but simple enough that the optimizer should. + this = this and none() + } + + override float getLowerBounds() { none() } + + override float getUpperBounds() { none() } + + override predicate dependsOnChild(Expr child) { none() } +} diff --git a/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/ArrayLengthAnalysis.qll b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/ArrayLengthAnalysis.qll index 8388511932e7..39db446e3d30 100644 --- a/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/ArrayLengthAnalysis.qll +++ b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/ArrayLengthAnalysis.qll @@ -20,7 +20,7 @@ import semmle.code.cpp.ir.IR private import semmle.code.cpp.ir.ValueNumbering private import semmle.code.cpp.ir.internal.CppType private import semmle.code.cpp.models.interfaces.Allocation -private import semmle.code.cpp.rangeanalysis.RangeUtils +private import experimental.semmle.code.cpp.rangeanalysis.RangeUtils private newtype TLength = TZeroLength() or diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/Bound.qll b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/Bound.qll similarity index 95% rename from cpp/ql/src/semmle/code/cpp/rangeanalysis/Bound.qll rename to cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/Bound.qll index 9e56794233fe..bdd0e39f9b7e 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/Bound.qll +++ b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/Bound.qll @@ -8,8 +8,8 @@ private newtype TBound = exists(Instruction i | vn.getAnInstruction() = i and ( - i.getResultType() instanceof IntegralType or - i.getResultType() instanceof PointerType + i.getResultIRType() instanceof IRIntegerType or + i.getResultIRType() instanceof IRAddressType ) and not vn.getAnInstruction() instanceof ConstantInstruction | diff --git a/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/ExtendedRangeAnalysis.qll b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/ExtendedRangeAnalysis.qll new file mode 100644 index 000000000000..bc63d740c321 --- /dev/null +++ b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/ExtendedRangeAnalysis.qll @@ -0,0 +1,5 @@ +import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis +// +// Import each extension we want to enable +import extensions.SubtractSelf +import extensions.ConstantBitwiseAndExprRange diff --git a/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/InBoundsPointerDeref.qll b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/InBoundsPointerDeref.qll index 94227a5a8acd..a7375f66b669 100644 --- a/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/InBoundsPointerDeref.qll +++ b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/InBoundsPointerDeref.qll @@ -13,7 +13,7 @@ import cpp private import experimental.semmle.code.cpp.rangeanalysis.ArrayLengthAnalysis -private import semmle.code.cpp.rangeanalysis.RangeAnalysis +private import experimental.semmle.code.cpp.rangeanalysis.RangeAnalysis /** * Gets the instruction that computes the address of memory that `i` accesses. diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll similarity index 97% rename from cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll rename to cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll index a79df3c37d75..4a5bef36b200 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll +++ b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll @@ -244,14 +244,14 @@ class CondReason extends Reason, TCondReason { /** * Holds if `typ` is a small integral type with the given lower and upper bounds. */ -private predicate typeBound(IntegralType typ, int lowerbound, int upperbound) { - typ.isSigned() and typ.getSize() = 1 and lowerbound = -128 and upperbound = 127 +private predicate typeBound(IRIntegerType typ, int lowerbound, int upperbound) { + typ.isSigned() and typ.getByteSize() = 1 and lowerbound = -128 and upperbound = 127 or - typ.isUnsigned() and typ.getSize() = 1 and lowerbound = 0 and upperbound = 255 + typ.isUnsigned() and typ.getByteSize() = 1 and lowerbound = 0 and upperbound = 255 or - typ.isSigned() and typ.getSize() = 2 and lowerbound = -32768 and upperbound = 32767 + typ.isSigned() and typ.getByteSize() = 2 and lowerbound = -32768 and upperbound = 32767 or - typ.isUnsigned() and typ.getSize() = 2 and lowerbound = 0 and upperbound = 65535 + typ.isUnsigned() and typ.getByteSize() = 2 and lowerbound = 0 and upperbound = 65535 } /** @@ -260,14 +260,14 @@ private predicate typeBound(IntegralType typ, int lowerbound, int upperbound) { private class NarrowingCastInstruction extends ConvertInstruction { NarrowingCastInstruction() { not this instanceof SafeCastInstruction and - typeBound(getResultType(), _, _) + typeBound(getResultIRType(), _, _) } /** Gets the lower bound of the resulting type. */ - int getLowerBound() { typeBound(getResultType(), result, _) } + int getLowerBound() { typeBound(getResultIRType(), result, _) } /** Gets the upper bound of the resulting type. */ - int getUpperBound() { typeBound(getResultType(), _, result) } + int getUpperBound() { typeBound(getResultIRType(), _, result) } } /** diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeUtils.qll b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/RangeUtils.qll similarity index 90% rename from cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeUtils.qll rename to cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/RangeUtils.qll index ee790404559e..bffd08fbe527 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeUtils.qll +++ b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/RangeUtils.qll @@ -86,15 +86,15 @@ predicate backEdge(PhiInstruction phi, PhiInputOperand op) { * range analysis. */ pragma[inline] -private predicate safeCast(IntegralType fromtyp, IntegralType totyp) { - fromtyp.getSize() < totyp.getSize() and +private predicate safeCast(IRIntegerType fromtyp, IRIntegerType totyp) { + fromtyp.getByteSize() < totyp.getByteSize() and ( fromtyp.isUnsigned() or totyp.isSigned() ) or - fromtyp.getSize() <= totyp.getSize() and + fromtyp.getByteSize() <= totyp.getByteSize() and ( fromtyp.isSigned() and totyp.isSigned() @@ -109,8 +109,8 @@ private predicate safeCast(IntegralType fromtyp, IntegralType totyp) { */ class PtrToPtrCastInstruction extends ConvertInstruction { PtrToPtrCastInstruction() { - getResultType() instanceof PointerType and - getUnary().getResultType() instanceof PointerType + getResultIRType() instanceof IRAddressType and + getUnary().getResultIRType() instanceof IRAddressType } } @@ -119,7 +119,7 @@ class PtrToPtrCastInstruction extends ConvertInstruction { * that cannot overflow or underflow. */ class SafeIntCastInstruction extends ConvertInstruction { - SafeIntCastInstruction() { safeCast(getUnary().getResultType(), getResultType()) } + SafeIntCastInstruction() { safeCast(getUnary().getResultIRType(), getResultIRType()) } } /** diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SignAnalysis.qll b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/SignAnalysis.qll similarity index 97% rename from cpp/ql/src/semmle/code/cpp/rangeanalysis/SignAnalysis.qll rename to cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/SignAnalysis.qll index 37e2ac463861..0bd73105cc5f 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SignAnalysis.qll +++ b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/SignAnalysis.qll @@ -469,7 +469,7 @@ module SignAnalysisCached { not exists(certainInstructionSign(i)) and not ( result = TNeg() and - i.getResultType().(IntegralType).isUnsigned() + i.getResultIRType().(IRIntegerType).isUnsigned() ) and ( unknownSign(i) @@ -477,9 +477,13 @@ module SignAnalysisCached { exists(ConvertInstruction ci, Instruction prior, boolean fromSigned, boolean toSigned | i = ci and prior = ci.getUnary() and - (if ci.getResultType().(IntegralType).isSigned() then toSigned = true else toSigned = false) and ( - if prior.getResultType().(IntegralType).isSigned() + if ci.getResultIRType().(IRIntegerType).isSigned() + then toSigned = true + else toSigned = false + ) and + ( + if prior.getResultIRType().(IRIntegerType).isSigned() then fromSigned = true else fromSigned = false ) and @@ -512,11 +516,11 @@ module SignAnalysisCached { i instanceof ShiftLeftInstruction and result = s1.lshift(s2) or i instanceof ShiftRightInstruction and - i.getResultType().(IntegralType).isSigned() and + i.getResultIRType().(IRIntegerType).isSigned() and result = s1.rshift(s2) or i instanceof ShiftRightInstruction and - not i.getResultType().(IntegralType).isSigned() and + not i.getResultIRType().(IRIntegerType).isSigned() and result = s1.urshift(s2) ) or diff --git a/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/extensions/ConstantBitwiseAndExprRange.qll b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/extensions/ConstantBitwiseAndExprRange.qll new file mode 100644 index 000000000000..33776bd81050 --- /dev/null +++ b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/extensions/ConstantBitwiseAndExprRange.qll @@ -0,0 +1,90 @@ +private import cpp +private import experimental.semmle.code.cpp.models.interfaces.SimpleRangeAnalysisExpr +private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils + +/** + * Holds if `e` is a constant or if it is a variable with a constant value + */ +float evaluateConstantExpr(Expr e) { + result = e.getValue().toFloat() + or + exists(SsaDefinition defn, StackVariable sv | + defn.getAUse(sv) = e and + result = defn.getDefiningValue(sv).getValue().toFloat() + ) +} + +/** + * The current implementation for `BitwiseAndExpr` only handles cases where both operands are + * either unsigned or non-negative constants. This class not only covers these cases, but also + * adds support for `&` expressions between a signed integer with a non-negative range and a + * non-negative constant. It also adds support for `&=` for the same set of cases as `&`. + */ +private class ConstantBitwiseAndExprRange extends SimpleRangeAnalysisExpr { + ConstantBitwiseAndExprRange() { + exists(Expr l, Expr r | + l = this.(BitwiseAndExpr).getLeftOperand() and + r = this.(BitwiseAndExpr).getRightOperand() + or + l = this.(AssignAndExpr).getLValue() and + r = this.(AssignAndExpr).getRValue() + | + // No operands can be negative constants + not (evaluateConstantExpr(l) < 0 or evaluateConstantExpr(r) < 0) and + // At least one operand must be a non-negative constant + (evaluateConstantExpr(l) >= 0 or evaluateConstantExpr(r) >= 0) + ) + } + + Expr getLeftOperand() { + result = this.(BitwiseAndExpr).getLeftOperand() or + result = this.(AssignAndExpr).getLValue() + } + + Expr getRightOperand() { + result = this.(BitwiseAndExpr).getRightOperand() or + result = this.(AssignAndExpr).getRValue() + } + + override float getLowerBounds() { + // If an operand can have negative values, the lower bound is unconstrained. + // Otherwise, the lower bound is zero. + exists(float lLower, float rLower | + lLower = getFullyConvertedLowerBounds(getLeftOperand()) and + rLower = getFullyConvertedLowerBounds(getRightOperand()) and + ( + (lLower < 0 or rLower < 0) and + result = exprMinVal(this) + or + // This technically results in two lowerBounds when an operand range is negative, but + // that's fine since `exprMinVal(x) <= 0`. We can't use an if statement here without + // non-monotonic recursion issues + result = 0 + ) + ) + } + + override float getUpperBounds() { + // If an operand can have negative values, the upper bound is unconstrained. + // Otherwise, the upper bound is the minimum of the upper bounds of the operands + exists(float lLower, float lUpper, float rLower, float rUpper | + lLower = getFullyConvertedLowerBounds(getLeftOperand()) and + lUpper = getFullyConvertedUpperBounds(getLeftOperand()) and + rLower = getFullyConvertedLowerBounds(getRightOperand()) and + rUpper = getFullyConvertedUpperBounds(getRightOperand()) and + ( + (lLower < 0 or rLower < 0) and + result = exprMaxVal(this) + or + // This technically results in two upperBounds when an operand range is negative, but + // that's fine since `exprMaxVal(b) >= result`. We can't use an if statement here without + // non-monotonic recursion issues + result = rUpper.minimum(lUpper) + ) + ) + } + + override predicate dependsOnChild(Expr child) { + child = getLeftOperand() or child = getRightOperand() + } +} diff --git a/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/extensions/SubtractSelf.qll b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/extensions/SubtractSelf.qll new file mode 100644 index 000000000000..ff716d02d6f6 --- /dev/null +++ b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/extensions/SubtractSelf.qll @@ -0,0 +1,15 @@ +import experimental.semmle.code.cpp.models.interfaces.SimpleRangeAnalysisExpr + +private class SelfSub extends SimpleRangeAnalysisExpr, SubExpr { + SelfSub() { + // Match `x - x` but not `myInt - (unsigned char)myInt`. + getLeftOperand().getExplicitlyConverted().(VariableAccess).getTarget() = + getRightOperand().getExplicitlyConverted().(VariableAccess).getTarget() + } + + override float getLowerBounds() { result = 0 } + + override float getUpperBounds() { result = 0 } + + override predicate dependsOnChild(Expr child) { none() } +} diff --git a/cpp/ql/src/experimental/semmle/code/cpp/security/PrivateCleartextWrite.qll b/cpp/ql/src/experimental/semmle/code/cpp/security/PrivateCleartextWrite.qll new file mode 100644 index 000000000000..b495412f5a21 --- /dev/null +++ b/cpp/ql/src/experimental/semmle/code/cpp/security/PrivateCleartextWrite.qll @@ -0,0 +1,63 @@ +/** + * Provides a taint-tracking configuration for reasoning about private information flowing unencrypted to an external location. + */ + +import cpp +import semmle.code.cpp.dataflow.TaintTracking +import experimental.semmle.code.cpp.security.PrivateData +import semmle.code.cpp.security.FileWrite +import semmle.code.cpp.security.BufferWrite +import semmle.code.cpp.dataflow.TaintTracking + +module PrivateCleartextWrite { + /** + * A data flow source for private information flowing unencrypted to an external location. + */ + abstract class Source extends DataFlow::ExprNode { } + + /** + * A data flow sink for private information flowing unencrypted to an external location. + */ + abstract class Sink extends DataFlow::ExprNode { } + + /** + * A sanitizer for private information flowing unencrypted to an external location. + */ + abstract class Sanitizer extends DataFlow::ExprNode { } + + /** A call to any method whose name suggests that it encodes or encrypts the parameter. */ + class ProtectSanitizer extends Sanitizer { + ProtectSanitizer() { + exists(Function m, string s | + this.getExpr().(FunctionCall).getTarget() = m and + m.getName().regexpMatch("(?i).*" + s + ".*") + | + s = "protect" or s = "encode" or s = "encrypt" + ) + } + } + + class WriteConfig extends TaintTracking::Configuration { + WriteConfig() { this = "Write configuration" } + + override predicate isSource(DataFlow::Node source) { source instanceof Source } + + override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer } + } + + class PrivateDataSource extends Source { + PrivateDataSource() { this.getExpr() instanceof PrivateDataExpr } + } + + class WriteSink extends Sink { + WriteSink() { + exists(FileWrite f, BufferWrite b | + this.asExpr() = f.getASource() + or + this.asExpr() = b.getAChild() + ) + } + } +} diff --git a/cpp/ql/src/experimental/semmle/code/cpp/security/PrivateData.qll b/cpp/ql/src/experimental/semmle/code/cpp/security/PrivateData.qll new file mode 100644 index 000000000000..621e8aad707b --- /dev/null +++ b/cpp/ql/src/experimental/semmle/code/cpp/security/PrivateData.qll @@ -0,0 +1,53 @@ +/** + * Provides classes and predicates for identifying private data and functions for security. + * + * 'Private' data in general is anything that would compromise user privacy if exposed. This + * library tries to guess where private data may either be stored in a variable or produced by a + * function. + * + * This library is not concerned with credentials. See `SensitiveActions` for expressions related + * to credentials. + */ + +import cpp + +/** A string for `match` that identifies strings that look like they represent private data. */ +private string privateNames() { + // Inspired by the list on https://cwe.mitre.org/data/definitions/359.html + // Government identifiers, such as Social Security Numbers + result = "%social%security%number%" or + // Contact information, such as home addresses and telephone numbers + result = "%postcode%" or + result = "%zipcode%" or + // result = "%telephone%" or + // Geographic location - where the user is (or was) + result = "%latitude%" or + result = "%longitude%" or + // Financial data - such as credit card numbers, salary, bank accounts, and debts + result = "%creditcard%" or + result = "%salary%" or + result = "%bankaccount%" or + // Communications - e-mail addresses, private e-mail messages, SMS text messages, chat logs, etc. + // result = "%email%" or + // result = "%mobile%" or + result = "%employer%" or + // Health - medical conditions, insurance status, prescription records + result = "%medical%" +} + +/** An expression that might contain private data. */ +abstract class PrivateDataExpr extends Expr { } + +/** A functiond call that might produce private data. */ +class PrivateFunctionCall extends PrivateDataExpr, FunctionCall { + PrivateFunctionCall() { + exists(string s | this.getTarget().getName().toLowerCase() = s | s.matches(privateNames())) + } +} + +/** An access to a variable that might contain private data. */ +class PrivateVariableAccess extends PrivateDataExpr, VariableAccess { + PrivateVariableAccess() { + exists(string s | this.getTarget().getName().toLowerCase() = s | s.matches(privateNames())) + } +} diff --git a/cpp/ql/src/external/CodeDuplication.qll b/cpp/ql/src/external/CodeDuplication.qll index 4548e0be85ed..8cc56d12e190 100644 --- a/cpp/ql/src/external/CodeDuplication.qll +++ b/cpp/ql/src/external/CodeDuplication.qll @@ -117,7 +117,7 @@ private predicate blockCoversStatement(int equivClass, int first, int last, Stmt private Stmt statementInMethod(FunctionDeclarationEntry m) { result.getParent+() = m.getBlock() and not result.getLocation() instanceof UnknownStmtLocation and - not result instanceof Block + not result instanceof BlockStmt } private predicate duplicateStatement( diff --git a/cpp/ql/src/external/DuplicateBlock.ql b/cpp/ql/src/external/DuplicateBlock.ql index 90070ed6a7df..3fdef9b510d4 100644 --- a/cpp/ql/src/external/DuplicateBlock.ql +++ b/cpp/ql/src/external/DuplicateBlock.ql @@ -1,4 +1,5 @@ /** + * @deprecated * @name Duplicate code * @description This block of code is duplicated elsewhere. If possible, the shared code should be refactored so there is only one occurrence left. It may not always be possible to address these issues; other duplicate code checks (such as duplicate function, duplicate class) give subsets of the results with higher confidence. * @kind problem diff --git a/cpp/ql/src/external/DuplicateFunction.ql b/cpp/ql/src/external/DuplicateFunction.ql index ca749315bbfd..1a861867fcbc 100644 --- a/cpp/ql/src/external/DuplicateFunction.ql +++ b/cpp/ql/src/external/DuplicateFunction.ql @@ -1,4 +1,5 @@ /** + * @deprecated * @name Duplicate function * @description There is another identical implementation of this function. Extract the code to a common file or superclass or delegate to improve sharing. * @kind problem diff --git a/cpp/ql/src/external/MostlyDuplicateClass.ql b/cpp/ql/src/external/MostlyDuplicateClass.ql index a7d6cc605a63..20b9f39214ed 100644 --- a/cpp/ql/src/external/MostlyDuplicateClass.ql +++ b/cpp/ql/src/external/MostlyDuplicateClass.ql @@ -1,4 +1,5 @@ /** + * @deprecated * @name Mostly duplicate class * @description More than 80% of the methods in this class are duplicated in another class. Create a common supertype to improve code sharing. * @kind problem diff --git a/cpp/ql/src/external/MostlyDuplicateFile.ql b/cpp/ql/src/external/MostlyDuplicateFile.ql index 13ad0707ce8e..8cb23a432d24 100644 --- a/cpp/ql/src/external/MostlyDuplicateFile.ql +++ b/cpp/ql/src/external/MostlyDuplicateFile.ql @@ -1,4 +1,5 @@ /** + * @deprecated * @name Mostly duplicate file * @description There is another file that shares a lot of the code with this file. Merge the two files to improve maintainability. * @kind problem diff --git a/cpp/ql/src/external/MostlyDuplicateFunction.ql b/cpp/ql/src/external/MostlyDuplicateFunction.ql index 1ec592a65680..8a7454e4c97f 100644 --- a/cpp/ql/src/external/MostlyDuplicateFunction.ql +++ b/cpp/ql/src/external/MostlyDuplicateFunction.ql @@ -1,4 +1,5 @@ /** + * @deprecated * @name Mostly duplicate function * @description There is another function that shares a lot of the code with this one. Extract the code to a common file/superclass or delegate to improve sharing. * @kind problem diff --git a/cpp/ql/src/external/MostlySimilarFile.ql b/cpp/ql/src/external/MostlySimilarFile.ql index 27830a5c9515..81a6ed02d6cc 100644 --- a/cpp/ql/src/external/MostlySimilarFile.ql +++ b/cpp/ql/src/external/MostlySimilarFile.ql @@ -1,4 +1,5 @@ /** + * @deprecated * @name Mostly similar file * @description There is another file that shares a lot of the code with this file. Notice that names of variables and types may have been changed. Merge the two files to improve maintainability. * @kind problem diff --git a/cpp/ql/src/jsf/4.05 Libraries/AV Rule 24.qhelp b/cpp/ql/src/jsf/4.05 Libraries/AV Rule 24.qhelp index 7513d84d5267..70c8460c8355 100644 --- a/cpp/ql/src/jsf/4.05 Libraries/AV Rule 24.qhelp +++ b/cpp/ql/src/jsf/4.05 Libraries/AV Rule 24.qhelp @@ -7,7 +7,7 @@ - +

    This query highlights calls to the standard library functions abort, exit, getenv and system. diff --git a/cpp/ql/src/jsf/4.06 Pre-Processing Directives/AV Rule 32.ql b/cpp/ql/src/jsf/4.06 Pre-Processing Directives/AV Rule 32.ql index d78bc0ee2a70..dedd5658bdf2 100644 --- a/cpp/ql/src/jsf/4.06 Pre-Processing Directives/AV Rule 32.ql +++ b/cpp/ql/src/jsf/4.06 Pre-Processing Directives/AV Rule 32.ql @@ -18,6 +18,7 @@ from Include i, File f, string extension where f = i.getIncludedFile() and extension = f.getExtension().toLowerCase() and + extension != "inc" and extension != "inl" and extension != "tcc" and extension != "tpp" and diff --git a/cpp/ql/src/jsf/4.09 Style/AV Rule 53.ql b/cpp/ql/src/jsf/4.09 Style/AV Rule 53.ql index db8ad52e1f3c..a01e0c16bd4e 100644 --- a/cpp/ql/src/jsf/4.09 Style/AV Rule 53.ql +++ b/cpp/ql/src/jsf/4.09 Style/AV Rule 53.ql @@ -18,6 +18,6 @@ import cpp from File f where - (f.getExtension().toLowerCase() = "h" or f.getExtension().toLowerCase() = "hpp") and + f.getExtension().toLowerCase() = ["h", "hpp"] and f.getExtension() != "h" select f, "AV Rule 53: Header files will always have a file name extension of .h." diff --git a/cpp/ql/src/jsf/4.09 Style/AV Rule 59.ql b/cpp/ql/src/jsf/4.09 Style/AV Rule 59.ql index 2a5681093c7b..63e318125dc6 100644 --- a/cpp/ql/src/jsf/4.09 Style/AV Rule 59.ql +++ b/cpp/ql/src/jsf/4.09 Style/AV Rule 59.ql @@ -13,7 +13,7 @@ import cpp from Stmt parent, Stmt child where - not child instanceof Block and + not child instanceof BlockStmt and ( child = parent.(IfStmt).getThen() or diff --git a/cpp/ql/src/jsf/4.10 Classes/AV Rule 82.ql b/cpp/ql/src/jsf/4.10 Classes/AV Rule 82.ql index 02220f3d4d3a..67559557c3cc 100644 --- a/cpp/ql/src/jsf/4.10 Classes/AV Rule 82.ql +++ b/cpp/ql/src/jsf/4.10 Classes/AV Rule 82.ql @@ -45,6 +45,16 @@ predicate dereferenceThis(Expr e) { or // `*this = ...` (where `=` is not overloaded, so an `AssignExpr`) dereferenceThis(e.(AssignExpr).getLValue()) + or + // `e ? ... : ... ` + exists(ConditionalExpr cond | + cond = e and + dereferenceThis(cond.getThen()) and + dereferenceThis(cond.getElse()) + ) + or + // `..., ... ` + dereferenceThis(e.(CommaExpr).getRightOperand()) } /** diff --git a/cpp/ql/src/jsf/4.10 Classes/AV Rule 85.qhelp b/cpp/ql/src/jsf/4.10 Classes/AV Rule 85.qhelp index 61275fedefab..69cc5322ad5f 100644 --- a/cpp/ql/src/jsf/4.10 Classes/AV Rule 85.qhelp +++ b/cpp/ql/src/jsf/4.10 Classes/AV Rule 85.qhelp @@ -7,7 +7,7 @@ - +

    This query ensures that all operators with opposites (e.g. == and !=) are both defined, and diff --git a/cpp/ql/src/jsf/4.10 Classes/AV Rule 85.ql b/cpp/ql/src/jsf/4.10 Classes/AV Rule 85.ql index dcfaf06f49ba..26a56faab5c0 100644 --- a/cpp/ql/src/jsf/4.10 Classes/AV Rule 85.ql +++ b/cpp/ql/src/jsf/4.10 Classes/AV Rule 85.ql @@ -28,7 +28,7 @@ predicate oppositeOperators(string op1, string op2) { * `!op2(_, _)`. */ predicate implementedAsNegationOf(Operator op1, Operator op2) { - exists(Block b, ReturnStmt r, NotExpr n, Expr o | + exists(BlockStmt b, ReturnStmt r, NotExpr n, Expr o | b = op1.getBlock() and b.getNumStmt() = 1 and r = b.getStmt(0) and diff --git a/cpp/ql/src/jsf/4.12 Templates/AV Rule 104.ql b/cpp/ql/src/jsf/4.12 Templates/AV Rule 104.ql index bc1ebf8c1d91..0a608f1dbe9c 100644 --- a/cpp/ql/src/jsf/4.12 Templates/AV Rule 104.ql +++ b/cpp/ql/src/jsf/4.12 Templates/AV Rule 104.ql @@ -21,8 +21,8 @@ import cpp */ class WarningLateTemplateSpecialization extends CompilerWarning { WarningLateTemplateSpecialization() { - this.getTag() = "partial_spec_after_instantiation" or - this.getTag() = "partial_spec_after_instantiation_ambiguous" + this.getTag() = + ["partial_spec_after_instantiation", "partial_spec_after_instantiation_ambiguous"] } } diff --git a/cpp/ql/src/jsf/4.13 Functions/AV Rule 111.qhelp b/cpp/ql/src/jsf/4.13 Functions/AV Rule 111.qhelp index 7dbbb12dba31..614fe4711fd1 100644 --- a/cpp/ql/src/jsf/4.13 Functions/AV Rule 111.qhelp +++ b/cpp/ql/src/jsf/4.13 Functions/AV Rule 111.qhelp @@ -7,7 +7,7 @@ - +

    This query highlights return statements that return pointers to an object allocated on the stack. The lifetime @@ -18,7 +18,7 @@ memory after the function has already returned will have undefined results. - + diff --git a/cpp/ql/src/jsf/4.13 Functions/AV Rule 114.qhelp b/cpp/ql/src/jsf/4.13 Functions/AV Rule 114.qhelp index e47368f5d664..086d1ea1fb60 100644 --- a/cpp/ql/src/jsf/4.13 Functions/AV Rule 114.qhelp +++ b/cpp/ql/src/jsf/4.13 Functions/AV Rule 114.qhelp @@ -12,7 +12,7 @@ calling convention for x86, it would be whatever value was in the AX/EAX registe assuming the function had a non-float return type that can fit in a machine word.

    - + diff --git a/cpp/ql/src/jsf/4.15 Declarations and Definitions/AV Rule 135.qhelp b/cpp/ql/src/jsf/4.15 Declarations and Definitions/AV Rule 135.qhelp index 6729583ff772..d67d84c5e064 100644 --- a/cpp/ql/src/jsf/4.15 Declarations and Definitions/AV Rule 135.qhelp +++ b/cpp/ql/src/jsf/4.15 Declarations and Definitions/AV Rule 135.qhelp @@ -7,7 +7,7 @@ - +

    This query highlights identifiers in an inner scope that hide (have the same name as) an identifier in an outer scope. diff --git a/cpp/ql/src/jsf/4.15 Declarations and Definitions/AV Rule 135.ql b/cpp/ql/src/jsf/4.15 Declarations and Definitions/AV Rule 135.ql index 0b3572af97e5..d3e23c9a7f6b 100644 --- a/cpp/ql/src/jsf/4.15 Declarations and Definitions/AV Rule 135.ql +++ b/cpp/ql/src/jsf/4.15 Declarations and Definitions/AV Rule 135.ql @@ -29,7 +29,7 @@ predicate localShadowsParameter(LocalVariable lv, Parameter p) { from Variable v, Variable shadowed where - not v.getParentScope().(Block).isInMacroExpansion() and + not v.getParentScope().(BlockStmt).isInMacroExpansion() and ( v.(LocalVariableOrParameter).shadowsGlobal(shadowed.(GlobalVariable)) or localShadowsParameter(v, shadowed) or diff --git a/cpp/ql/src/jsf/4.15 Declarations and Definitions/AV Rule 140.qhelp b/cpp/ql/src/jsf/4.15 Declarations and Definitions/AV Rule 140.qhelp index e184b9edd6f7..73e66f0b0067 100644 --- a/cpp/ql/src/jsf/4.15 Declarations and Definitions/AV Rule 140.qhelp +++ b/cpp/ql/src/jsf/4.15 Declarations and Definitions/AV Rule 140.qhelp @@ -7,7 +7,7 @@ - +

    This query highlights variables with the register storage class specifier. Modern compilers are now capable of diff --git a/cpp/ql/src/jsf/4.16 Initialization/AV Rule 143.ql b/cpp/ql/src/jsf/4.16 Initialization/AV Rule 143.ql index 973cb0165795..1f7fe79fd77b 100644 --- a/cpp/ql/src/jsf/4.16 Initialization/AV Rule 143.ql +++ b/cpp/ql/src/jsf/4.16 Initialization/AV Rule 143.ql @@ -38,7 +38,7 @@ predicate noDefUsePath(LocalVariable lv, ControlFlowNode n) { } predicate neighbouringStmts(Stmt s1, Stmt s2) { - exists(Block b, int i | + exists(BlockStmt b, int i | i in [0 .. b.getNumStmt() - 2] and s1 = b.getStmt(i) and s2 = b.getStmt(i + 1) diff --git a/cpp/ql/src/jsf/4.17 Types/AV Rule 147.qhelp b/cpp/ql/src/jsf/4.17 Types/AV Rule 147.qhelp index 75c4f03e9800..1633cb2a8674 100644 --- a/cpp/ql/src/jsf/4.17 Types/AV Rule 147.qhelp +++ b/cpp/ql/src/jsf/4.17 Types/AV Rule 147.qhelp @@ -7,7 +7,7 @@ - +

    This query highlights portions of code that can expose the floating point implementation of the underlying diff --git a/cpp/ql/src/jsf/4.18 Constants/AV Rule 151.1.qhelp b/cpp/ql/src/jsf/4.18 Constants/AV Rule 151.1.qhelp index 9c6c369cfed9..b30e828428c9 100644 --- a/cpp/ql/src/jsf/4.18 Constants/AV Rule 151.1.qhelp +++ b/cpp/ql/src/jsf/4.18 Constants/AV Rule 151.1.qhelp @@ -7,7 +7,7 @@ - +

    This query highlights string literals that are assigned to a non-const variable. String literals diff --git a/cpp/ql/src/jsf/4.20 Unions and Bit Fields/AV Rule 154.qhelp b/cpp/ql/src/jsf/4.20 Unions and Bit Fields/AV Rule 154.qhelp index 3c502a249285..946e0873ab0d 100644 --- a/cpp/ql/src/jsf/4.20 Unions and Bit Fields/AV Rule 154.qhelp +++ b/cpp/ql/src/jsf/4.20 Unions and Bit Fields/AV Rule 154.qhelp @@ -7,7 +7,7 @@ - +

    This query finds bit fields with members that are not explicitly declared to be unsigned. diff --git a/cpp/ql/src/jsf/4.21 Operators/AV Rule 165.qhelp b/cpp/ql/src/jsf/4.21 Operators/AV Rule 165.qhelp index 5961991fcdc1..1beb8b94f35b 100644 --- a/cpp/ql/src/jsf/4.21 Operators/AV Rule 165.qhelp +++ b/cpp/ql/src/jsf/4.21 Operators/AV Rule 165.qhelp @@ -7,7 +7,7 @@ - +

    This query finds unsigned values that are being negated. Behavior is undefined in such cases. diff --git a/cpp/ql/src/jsf/4.24 Control Flow Structures/AV Rule 187.ql b/cpp/ql/src/jsf/4.24 Control Flow Structures/AV Rule 187.ql index 7a8919faf896..5893f3f35a39 100644 --- a/cpp/ql/src/jsf/4.24 Control Flow Structures/AV Rule 187.ql +++ b/cpp/ql/src/jsf/4.24 Control Flow Structures/AV Rule 187.ql @@ -22,6 +22,6 @@ where not s instanceof ControlStructure and // Exclude blocks; if a child of the block violates the rule that will still // be picked up so there is no point in blaming the block as well - not s instanceof Block and + not s instanceof BlockStmt and s.isPure() select s, "AV Rule 187: All non-null statements shall potentially have a side-effect." diff --git a/cpp/ql/src/jsf/4.24 Control Flow Structures/AV Rule 189.qhelp b/cpp/ql/src/jsf/4.24 Control Flow Structures/AV Rule 189.qhelp index e65f5b8dfb42..85db1463d56b 100644 --- a/cpp/ql/src/jsf/4.24 Control Flow Structures/AV Rule 189.qhelp +++ b/cpp/ql/src/jsf/4.24 Control Flow Structures/AV Rule 189.qhelp @@ -6,7 +6,7 @@ - +

    Use of goto statements makes code more difficult to understand and maintain. Consequently, the use of goto statements is deprecated except as a mechanism for breaking out of multiple nested loops. diff --git a/cpp/ql/src/jsf/4.24 Control Flow Structures/AV Rule 191.ql b/cpp/ql/src/jsf/4.24 Control Flow Structures/AV Rule 191.ql index 579a615c27fd..2e730b666549 100644 --- a/cpp/ql/src/jsf/4.24 Control Flow Structures/AV Rule 191.ql +++ b/cpp/ql/src/jsf/4.24 Control Flow Structures/AV Rule 191.ql @@ -18,7 +18,7 @@ import cpp // whether t is the last statement of s, possibly peeling off blocks predicate isTerminatingStmt(Stmt s, Stmt t) { - s = t or isTerminatingStmt(s.(Block).getLastStmt(), t) + s = t or isTerminatingStmt(s.(BlockStmt).getLastStmt(), t) } from BreakStmt s diff --git a/cpp/ql/src/jsf/jsfNote.qhelp b/cpp/ql/src/jsf/jsfNote.qhelp new file mode 100644 index 000000000000..4a05d0c6e344 --- /dev/null +++ b/cpp/ql/src/jsf/jsfNote.qhelp @@ -0,0 +1,18 @@ + + + +

    +This query is part of a suite that tests code against +the Joint Strike Fighter Air Vehicle C++ Coding Standard (JSF). +Alerts reported by this query highlight code that may break the +JSF rule listed in the References section. +

    + +

    +The JSF rule this query tests is likely to be too strict for projects +that do not follow the JSF standard. +

    + + diff --git a/cpp/ql/src/printAst.ql b/cpp/ql/src/printAst.ql new file mode 100644 index 000000000000..622e5812be13 --- /dev/null +++ b/cpp/ql/src/printAst.ql @@ -0,0 +1,27 @@ +/** + * @name Print AST + * @description Outputs a representation of a file's Abstract Syntax Tree. This + * query is used by the VS Code extension. + * @id cpp/print-ast + * @kind graph + * @tags ide-contextual-queries/print-ast + */ + +import cpp +import semmle.code.cpp.PrintAST +import definitions + +/** + * The source file to generate an AST from. + */ +external string selectedSourceFile(); + +class Cfg extends PrintASTConfiguration { + /** + * Holds if the AST for `func` should be printed. + * Print All functions from the selected file. + */ + override predicate shouldPrintFunction(Function func) { + func.getFile() = getEncodedFile(selectedSourceFile()) + } +} diff --git a/cpp/ql/src/semmle/code/cpp/Class.qll b/cpp/ql/src/semmle/code/cpp/Class.qll index 11ebef3e5ff2..f81f00064d7d 100644 --- a/cpp/ql/src/semmle/code/cpp/Class.qll +++ b/cpp/ql/src/semmle/code/cpp/Class.qll @@ -33,7 +33,7 @@ private import semmle.code.cpp.internal.ResolveClass class Class extends UserType { Class() { isClass(underlyingElement(this)) } - override string getCanonicalQLClass() { result = "Class" } + override string getAPrimaryQlClass() { result = "Class" } /** Gets a child declaration of this class, struct or union. */ override Declaration getADeclaration() { result = this.getAMember() } @@ -768,7 +768,7 @@ class ClassDerivation extends Locatable, @derivation { */ Class getBaseClass() { result = getBaseType().getUnderlyingType() } - override string getCanonicalQLClass() { result = "ClassDerivation" } + override string getAPrimaryQlClass() { result = "ClassDerivation" } /** * Gets the type from which we are deriving, without resolving any @@ -849,9 +849,7 @@ class ClassDerivation extends Locatable, @derivation { class LocalClass extends Class { LocalClass() { isLocal() } - override string getCanonicalQLClass() { - not this instanceof LocalStruct and result = "LocalClass" - } + override string getAPrimaryQlClass() { not this instanceof LocalStruct and result = "LocalClass" } override Function getEnclosingAccessHolder() { result = this.getEnclosingFunction() } } @@ -872,7 +870,7 @@ class LocalClass extends Class { class NestedClass extends Class { NestedClass() { this.isMember() } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not this instanceof NestedStruct and result = "NestedClass" } @@ -893,7 +891,7 @@ class NestedClass extends Class { class AbstractClass extends Class { AbstractClass() { exists(PureVirtualFunction f | this.getAMemberFunction() = f) } - override string getCanonicalQLClass() { result = "AbstractClass" } + override string getAPrimaryQlClass() { result = "AbstractClass" } } /** @@ -934,7 +932,7 @@ class TemplateClass extends Class { exists(result.getATemplateArgument()) } - override string getCanonicalQLClass() { result = "TemplateClass" } + override string getAPrimaryQlClass() { result = "TemplateClass" } } /** @@ -955,7 +953,7 @@ class ClassTemplateInstantiation extends Class { ClassTemplateInstantiation() { tc.getAnInstantiation() = this } - override string getCanonicalQLClass() { result = "ClassTemplateInstantiation" } + override string getAPrimaryQlClass() { result = "ClassTemplateInstantiation" } /** * Gets the class template from which this instantiation was instantiated. @@ -996,7 +994,7 @@ abstract class ClassTemplateSpecialization extends Class { count(int i | exists(result.getTemplateArgument(i))) } - override string getCanonicalQLClass() { result = "ClassTemplateSpecialization" } + override string getAPrimaryQlClass() { result = "ClassTemplateSpecialization" } } /** @@ -1025,7 +1023,7 @@ class FullClassTemplateSpecialization extends ClassTemplateSpecialization { not this instanceof ClassTemplateInstantiation } - override string getCanonicalQLClass() { result = "FullClassTemplateSpecialization" } + override string getAPrimaryQlClass() { result = "FullClassTemplateSpecialization" } } /** @@ -1064,7 +1062,7 @@ class PartialClassTemplateSpecialization extends ClassTemplateSpecialization { count(int i | exists(getTemplateArgument(i))) } - override string getCanonicalQLClass() { result = "PartialClassTemplateSpecialization" } + override string getAPrimaryQlClass() { result = "PartialClassTemplateSpecialization" } } /** @@ -1089,7 +1087,7 @@ deprecated class Interface extends Class { ) } - override string getCanonicalQLClass() { result = "Interface" } + override string getAPrimaryQlClass() { result = "Interface" } } /** @@ -1104,7 +1102,7 @@ deprecated class Interface extends Class { class VirtualClassDerivation extends ClassDerivation { VirtualClassDerivation() { hasSpecifier("virtual") } - override string getCanonicalQLClass() { result = "VirtualClassDerivation" } + override string getAPrimaryQlClass() { result = "VirtualClassDerivation" } } /** @@ -1124,7 +1122,7 @@ class VirtualClassDerivation extends ClassDerivation { class VirtualBaseClass extends Class { VirtualBaseClass() { exists(VirtualClassDerivation cd | cd.getBaseClass() = this) } - override string getCanonicalQLClass() { result = "VirtualBaseClass" } + override string getAPrimaryQlClass() { result = "VirtualBaseClass" } /** A virtual class derivation of which this class/struct is the base. */ VirtualClassDerivation getAVirtualDerivation() { result.getBaseClass() = this } @@ -1146,7 +1144,7 @@ class VirtualBaseClass extends Class { class ProxyClass extends UserType { ProxyClass() { usertypes(underlyingElement(this), _, 9) } - override string getCanonicalQLClass() { result = "ProxyClass" } + override string getAPrimaryQlClass() { result = "ProxyClass" } /** Gets the location of the proxy class. */ override Location getLocation() { result = getTemplateParameter().getDefinitionLocation() } diff --git a/cpp/ql/src/semmle/code/cpp/Declaration.qll b/cpp/ql/src/semmle/code/cpp/Declaration.qll index 6245005fd410..e5d3d83326ba 100644 --- a/cpp/ql/src/semmle/code/cpp/Declaration.qll +++ b/cpp/ql/src/semmle/code/cpp/Declaration.qll @@ -124,7 +124,7 @@ class Declaration extends Locatable, @declaration { * To test whether this declaration has a particular name in the global * namespace, use `hasGlobalName`. */ - abstract string getName(); + string getName() { none() } // overridden in subclasses /** Holds if this declaration has the given name. */ predicate hasName(string name) { name = this.getName() } @@ -140,7 +140,7 @@ class Declaration extends Locatable, @declaration { } /** Gets a specifier of this declaration. */ - abstract Specifier getASpecifier(); + Specifier getASpecifier() { none() } // overridden in subclasses /** Holds if this declaration has a specifier with the given name. */ predicate hasSpecifier(string name) { this.getASpecifier().hasName(name) } @@ -156,7 +156,7 @@ class Declaration extends Locatable, @declaration { * Gets the location of a declaration entry corresponding to this * declaration. */ - abstract Location getADeclarationLocation(); + Location getADeclarationLocation() { none() } // overridden in subclasses /** * Gets the declaration entry corresponding to this declaration that is a @@ -165,7 +165,7 @@ class Declaration extends Locatable, @declaration { DeclarationEntry getDefinition() { none() } /** Gets the location of the definition, if any. */ - abstract Location getDefinitionLocation(); + Location getDefinitionLocation() { none() } // overridden in subclasses /** Holds if the declaration has a definition. */ predicate hasDefinition() { exists(this.getDefinition()) } @@ -289,6 +289,8 @@ class Declaration extends Locatable, @declaration { } } +private class TDeclarationEntry = @var_decl or @type_decl or @fun_decl; + /** * A C/C++ declaration entry. For example the following code contains five * declaration entries: @@ -304,9 +306,9 @@ class Declaration extends Locatable, @declaration { * See the comment above `Declaration` for an explanation of the relationship * between `Declaration` and `DeclarationEntry`. */ -abstract class DeclarationEntry extends Locatable { +class DeclarationEntry extends Locatable, TDeclarationEntry { /** Gets a specifier associated with this declaration entry. */ - abstract string getASpecifier(); + string getASpecifier() { none() } // overridden in subclasses /** * Gets the name associated with the corresponding definition (where @@ -329,10 +331,10 @@ abstract class DeclarationEntry extends Locatable { * `I.getADeclarationEntry()` returns `D` * but `D.getDeclaration()` only returns `C` */ - abstract Declaration getDeclaration(); + Declaration getDeclaration() { none() } // overridden in subclasses /** Gets the name associated with this declaration entry, if any. */ - abstract string getName(); + string getName() { none() } // overridden in subclasses /** * Gets the type associated with this declaration entry. @@ -341,7 +343,7 @@ abstract class DeclarationEntry extends Locatable { * For function declarations, get the return type of the function. * For type declarations, get the type being declared. */ - abstract Type getType(); + Type getType() { none() } // overridden in subclasses /** * Gets the type associated with this declaration entry after specifiers @@ -359,7 +361,7 @@ abstract class DeclarationEntry extends Locatable { predicate hasSpecifier(string specifier) { getASpecifier() = specifier } /** Holds if this declaration entry is a definition. */ - abstract predicate isDefinition(); + predicate isDefinition() { none() } // overridden in subclasses override string toString() { if isDefinition() @@ -371,6 +373,8 @@ abstract class DeclarationEntry extends Locatable { } } +private class TAccessHolder = @function or @usertype; + /** * A declaration that can potentially have more C++ access rights than its * enclosing element. This comprises `Class` (they have access to their own @@ -392,7 +396,7 @@ abstract class DeclarationEntry extends Locatable { * the informal phrase "_R_ occurs in a member or friend of class C", where * `AccessHolder` corresponds to this _R_. */ -abstract class AccessHolder extends Declaration { +class AccessHolder extends Declaration, TAccessHolder { /** * Holds if `this` can access private members of class `c`. * @@ -410,7 +414,7 @@ abstract class AccessHolder extends Declaration { /** * Gets the nearest enclosing `AccessHolder`. */ - abstract AccessHolder getEnclosingAccessHolder(); + AccessHolder getEnclosingAccessHolder() { none() } // overridden in subclasses /** * Holds if a base class `base` of `derived` _is accessible at_ `this` (N4140 diff --git a/cpp/ql/src/semmle/code/cpp/Element.qll b/cpp/ql/src/semmle/code/cpp/Element.qll index 50b72037ff77..c7cc4a65b368 100644 --- a/cpp/ql/src/semmle/code/cpp/Element.qll +++ b/cpp/ql/src/semmle/code/cpp/Element.qll @@ -55,12 +55,21 @@ class ElementBase extends @element { cached string toString() { none() } + /** DEPRECATED: use `getAPrimaryQlClass` instead. */ + deprecated string getCanonicalQLClass() { result = this.getAPrimaryQlClass() } + /** - * Canonical QL class corresponding to this element. + * Gets the name of a primary CodeQL class to which this element belongs. + * + * For most elements, this is simply the most precise syntactic category to + * which they belong; for example, `AddExpr` is a primary class, but + * `BinaryOperation` is not. * - * ElementBase is the root class for this predicate. + * This predicate always has a result. If no primary class can be + * determined, the result is `"???"`. If multiple primary classes match, + * this predicate can have multiple results. */ - string getCanonicalQLClass() { result = "???" } + string getAPrimaryQlClass() { result = "???" } } /** @@ -119,7 +128,7 @@ class Element extends ElementBase { /** * Gets the parent scope of this `Element`, if any. - * A scope is a `Type` (`Class` / `Enum`), a `Namespace`, a `Block`, a `Function`, + * A scope is a `Type` (`Class` / `Enum`), a `Namespace`, a `BlockStmt`, a `Function`, * or certain kinds of `Statement`. */ Element getParentScope() { @@ -152,7 +161,7 @@ class Element extends ElementBase { exists(EnumConstant e | this = e and result = e.getDeclaringEnum()) or // result instanceof block|function - exists(Block b | this = b and blockscope(unresolveElement(b), unresolveElement(result))) + exists(BlockStmt b | this = b and blockscope(unresolveElement(b), unresolveElement(result))) or exists(TemplateFunction tf | this = tf.getATemplateArgument() and result = tf) or @@ -188,7 +197,8 @@ class Element extends ElementBase { initialisers(underlyingElement(this), unresolveElement(result), _, _) or exprconv(unresolveElement(result), underlyingElement(this)) or param_decl_bind(underlyingElement(this), _, unresolveElement(result)) or - using_container(unresolveElement(result), underlyingElement(this)) + using_container(unresolveElement(result), underlyingElement(this)) or + static_asserts(unresolveElement(this), _, _, _, underlyingElement(result)) } /** Gets the closest `Element` enclosing this one. */ @@ -269,12 +279,12 @@ class StaticAssert extends Locatable, @static_assert { /** * Gets the expression which this static assertion ensures is true. */ - Expr getCondition() { static_asserts(underlyingElement(this), unresolveElement(result), _, _) } + Expr getCondition() { static_asserts(underlyingElement(this), unresolveElement(result), _, _, _) } /** * Gets the message which will be reported by the compiler if this static assertion fails. */ - string getMessage() { static_asserts(underlyingElement(this), _, result, _) } + string getMessage() { static_asserts(underlyingElement(this), _, result, _, _) } - override Location getLocation() { static_asserts(underlyingElement(this), _, _, result) } + override Location getLocation() { static_asserts(underlyingElement(this), _, _, result, _) } } diff --git a/cpp/ql/src/semmle/code/cpp/Enum.qll b/cpp/ql/src/semmle/code/cpp/Enum.qll index 2c51a5228d98..9cddeb78f9b1 100644 --- a/cpp/ql/src/semmle/code/cpp/Enum.qll +++ b/cpp/ql/src/semmle/code/cpp/Enum.qll @@ -38,7 +38,7 @@ class Enum extends UserType, IntegralOrEnumType { enumconstants(unresolveElement(result), underlyingElement(this), index, _, _, _) } - override string getCanonicalQLClass() { result = "Enum" } + override string getAPrimaryQlClass() { result = "Enum" } /** * Gets a descriptive string for the enum. This method is only intended to @@ -87,7 +87,7 @@ class Enum extends UserType, IntegralOrEnumType { class LocalEnum extends Enum { LocalEnum() { isLocal() } - override string getCanonicalQLClass() { result = "LocalEnum" } + override string getAPrimaryQlClass() { result = "LocalEnum" } } /** @@ -105,7 +105,7 @@ class LocalEnum extends Enum { class NestedEnum extends Enum { NestedEnum() { this.isMember() } - override string getCanonicalQLClass() { result = "NestedEnum" } + override string getAPrimaryQlClass() { result = "NestedEnum" } /** Holds if this member is private. */ predicate isPrivate() { this.hasSpecifier("private") } @@ -130,7 +130,7 @@ class NestedEnum extends Enum { class ScopedEnum extends Enum { ScopedEnum() { usertypes(underlyingElement(this), _, 13) } - override string getCanonicalQLClass() { result = "ScopedEnum" } + override string getAPrimaryQlClass() { result = "ScopedEnum" } } /** @@ -153,7 +153,7 @@ class EnumConstant extends Declaration, @enumconstant { enumconstants(underlyingElement(this), unresolveElement(result), _, _, _, _) } - override string getCanonicalQLClass() { result = "EnumConstant" } + override string getAPrimaryQlClass() { result = "EnumConstant" } override Class getDeclaringType() { result = this.getDeclaringEnum().getDeclaringType() } diff --git a/cpp/ql/src/semmle/code/cpp/Field.qll b/cpp/ql/src/semmle/code/cpp/Field.qll index 79c9b58dfea1..5ed5e8e4b4bc 100644 --- a/cpp/ql/src/semmle/code/cpp/Field.qll +++ b/cpp/ql/src/semmle/code/cpp/Field.qll @@ -23,7 +23,7 @@ import semmle.code.cpp.exprs.Access class Field extends MemberVariable { Field() { fieldoffsets(underlyingElement(this), _, _) } - override string getCanonicalQLClass() { result = "Field" } + override string getAPrimaryQlClass() { result = "Field" } /** * Gets the offset of this field in bytes from the start of its declaring @@ -90,7 +90,7 @@ class Field extends MemberVariable { class BitField extends Field { BitField() { bitfield(underlyingElement(this), _, _) } - override string getCanonicalQLClass() { result = "BitField" } + override string getAPrimaryQlClass() { result = "BitField" } /** * Gets the size of this bitfield in bits (on the machine where facts diff --git a/cpp/ql/src/semmle/code/cpp/File.qll b/cpp/ql/src/semmle/code/cpp/File.qll index 061e79c7d452..1887f43b70cb 100644 --- a/cpp/ql/src/semmle/code/cpp/File.qll +++ b/cpp/ql/src/semmle/code/cpp/File.qll @@ -178,7 +178,7 @@ class Folder extends Container, @folder { result.hasLocationInfo(_, 0, 0, 0, 0) } - override string getCanonicalQLClass() { result = "Folder" } + override string getAPrimaryQlClass() { result = "Folder" } /** * DEPRECATED: Use `getLocation` instead. @@ -246,7 +246,7 @@ class File extends Container, @file { override string toString() { result = Container.super.toString() } - override string getCanonicalQLClass() { result = "File" } + override string getAPrimaryQlClass() { result = "File" } override Location getLocation() { result.getContainer() = this and @@ -382,7 +382,7 @@ class HeaderFile extends File { exists(Include i | i.getIncludedFile() = this) } - override string getCanonicalQLClass() { result = "HeaderFile" } + override string getAPrimaryQlClass() { result = "HeaderFile" } /** * Holds if this header file does not contain any declaration entries or top level @@ -408,7 +408,7 @@ class HeaderFile extends File { class CFile extends File { CFile() { exists(string ext | ext = this.getExtension().toLowerCase() | ext = "c" or ext = "i") } - override string getCanonicalQLClass() { result = "CFile" } + override string getAPrimaryQlClass() { result = "CFile" } } /** @@ -436,7 +436,7 @@ class CppFile extends File { ) } - override string getCanonicalQLClass() { result = "CppFile" } + override string getAPrimaryQlClass() { result = "CppFile" } } /** diff --git a/cpp/ql/src/semmle/code/cpp/FriendDecl.qll b/cpp/ql/src/semmle/code/cpp/FriendDecl.qll index e0a6b04b1fcd..9a35f7527d52 100644 --- a/cpp/ql/src/semmle/code/cpp/FriendDecl.qll +++ b/cpp/ql/src/semmle/code/cpp/FriendDecl.qll @@ -27,7 +27,7 @@ class FriendDecl extends Declaration, @frienddecl { */ override Location getADeclarationLocation() { result = this.getLocation() } - override string getCanonicalQLClass() { result = "FriendDecl" } + override string getAPrimaryQlClass() { result = "FriendDecl" } /** * Implements the abstract method `Declaration.getDefinitionLocation`. A diff --git a/cpp/ql/src/semmle/code/cpp/Function.qll b/cpp/ql/src/semmle/code/cpp/Function.qll index 20abef21d7b8..2c45fa184cf6 100644 --- a/cpp/ql/src/semmle/code/cpp/Function.qll +++ b/cpp/ql/src/semmle/code/cpp/Function.qll @@ -1,10 +1,8 @@ /** - * Provides classes for working with functions, including C++ constructors, destructors, - * user-defined operators, and template functions. + * Provides classes for working with functions, including template functions. */ import semmle.code.cpp.Location -import semmle.code.cpp.Member import semmle.code.cpp.Class import semmle.code.cpp.Parameter import semmle.code.cpp.exprs.Call @@ -270,7 +268,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function { * block, this gives the block guarded by the try statement. See * `FunctionTryStmt` for further information. */ - Block getBlock() { result.getParentScope() = this } + BlockStmt getBlock() { result.getParentScope() = this } /** Holds if this function has an entry point. */ predicate hasEntryPoint() { exists(getEntryPoint()) } @@ -278,7 +276,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function { /** * Gets the first node in this function's control flow graph. * - * For most functions, this first node will be the `Block` returned by + * For most functions, this first node will be the `BlockStmt` returned by * `getBlock`. However in C++, the first node can also be a * `FunctionTryStmt`. */ @@ -515,7 +513,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl { /** Gets the function which is being declared or defined. */ override Function getDeclaration() { result = getFunction() } - override string getCanonicalQLClass() { result = "FunctionDeclarationEntry" } + override string getAPrimaryQlClass() { result = "FunctionDeclarationEntry" } /** Gets the function which is being declared or defined. */ Function getFunction() { fun_decls(underlyingElement(this), unresolveElement(result), _, _, _) } @@ -566,7 +564,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl { * If this is a function definition, get the block containing the * function body. */ - Block getBlock() { + BlockStmt getBlock() { this.isDefinition() and result = getFunction().getBlock() and result.getFile() = this.getFile() @@ -578,7 +576,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl { */ pragma[noopt] int getNumberOfLines() { - exists(Block b, Location l, int start, int end, int diff | b = getBlock() | + exists(BlockStmt b, Location l, int start, int end, int diff | b = getBlock() | l = b.getLocation() and start = l.getStartLine() and end = l.getEndLine() and @@ -700,430 +698,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl { class TopLevelFunction extends Function { TopLevelFunction() { not this.isMember() } - override string getCanonicalQLClass() { result = "TopLevelFunction" } -} - -/** - * A C++ function declared as a member of a class [N4140 9.3]. This includes - * static member functions. For example the functions `MyStaticMemberFunction` - * and `MyMemberFunction` in: - * ``` - * class MyClass { - * public: - * void MyMemberFunction() { - * DoSomething(); - * } - * - * static void MyStaticMemberFunction() { - * DoSomething(); - * } - * }; - * ``` - */ -class MemberFunction extends Function { - MemberFunction() { this.isMember() } - - override string getCanonicalQLClass() { - not this instanceof CopyAssignmentOperator and - not this instanceof MoveAssignmentOperator and - result = "MemberFunction" - } - - /** - * Gets the number of parameters of this function, including any implicit - * `this` parameter. - */ - override int getEffectiveNumberOfParameters() { - if isStatic() then result = getNumberOfParameters() else result = getNumberOfParameters() + 1 - } - - /** Holds if this member is private. */ - predicate isPrivate() { this.hasSpecifier("private") } - - /** Holds if this member is protected. */ - predicate isProtected() { this.hasSpecifier("protected") } - - /** Holds if this member is public. */ - predicate isPublic() { this.hasSpecifier("public") } - - /** Holds if this function overrides that function. */ - predicate overrides(MemberFunction that) { - overrides(underlyingElement(this), unresolveElement(that)) - } - - /** Gets a directly overridden function. */ - MemberFunction getAnOverriddenFunction() { this.overrides(result) } - - /** Gets a directly overriding function. */ - MemberFunction getAnOverridingFunction() { result.overrides(this) } - - /** - * Gets the declaration entry for this member function that is within the - * class body. - */ - FunctionDeclarationEntry getClassBodyDeclarationEntry() { - if strictcount(getADeclarationEntry()) = 1 - then result = getDefinition() - else ( - result = getADeclarationEntry() and result != getDefinition() - ) - } -} - -/** - * A C++ virtual function. For example the two functions called - * `myVirtualFunction` in the following code are each a - * `VirtualFunction`: - * ``` - * class A { - * public: - * virtual void myVirtualFunction() = 0; - * }; - * - * class B: public A { - * public: - * virtual void myVirtualFunction() { - * doSomething(); - * } - * }; - * ``` - */ -class VirtualFunction extends MemberFunction { - VirtualFunction() { this.hasSpecifier("virtual") or purefunctions(underlyingElement(this)) } - - override string getCanonicalQLClass() { result = "VirtualFunction" } - - /** Holds if this virtual function is pure. */ - predicate isPure() { this instanceof PureVirtualFunction } - - /** - * Holds if this function was declared with the `override` specifier - * [N4140 10.3]. - */ - predicate isOverrideExplicit() { this.hasSpecifier("override") } -} - -/** - * A C++ pure virtual function [N4140 10.4]. For example the first function - * called `myVirtualFunction` in the following code: - * ``` - * class A { - * public: - * virtual void myVirtualFunction() = 0; - * }; - * - * class B: public A { - * public: - * virtual void myVirtualFunction() { - * doSomething(); - * } - * }; - * ``` - */ -class PureVirtualFunction extends VirtualFunction { - PureVirtualFunction() { purefunctions(underlyingElement(this)) } - - override string getCanonicalQLClass() { result = "PureVirtualFunction" } -} - -/** - * A const C++ member function [N4140 9.3.1/4]. A const function has the - * `const` specifier and does not modify the state of its class. For example - * the member function `day` in the following code: - * ``` - * class MyClass { - * ... - * - * int day() const { - * return d; - * } - * - * ... - * }; - * ``` - */ -class ConstMemberFunction extends MemberFunction { - ConstMemberFunction() { this.hasSpecifier("const") } - - override string getCanonicalQLClass() { result = "ConstMemberFunction" } -} - -/** - * A C++ constructor [N4140 12.1]. For example the function `MyClass` in the - * following code is a constructor: - * ``` - * class MyClass { - * public: - * MyClass() { - * ... - * } - * }; - * ``` - */ -class Constructor extends MemberFunction { - Constructor() { functions(underlyingElement(this), _, 2) } - - override string getCanonicalQLClass() { result = "Constructor" } - - /** - * Holds if this constructor serves as a default constructor. - * - * This holds for constructors with zero formal parameters. It also holds - * for constructors which have a non-zero number of formal parameters, - * provided that every parameter has a default value. - */ - predicate isDefault() { forall(Parameter p | p = this.getAParameter() | p.hasInitializer()) } - - /** - * Gets an entry in the constructor's initializer list, or a - * compiler-generated action which initializes a base class or member - * variable. - */ - ConstructorInit getAnInitializer() { result = getInitializer(_) } - - /** - * Gets an entry in the constructor's initializer list, or a - * compiler-generated action which initializes a base class or member - * variable. The index specifies the order in which the initializer is - * to be evaluated. - */ - ConstructorInit getInitializer(int i) { - exprparents(unresolveElement(result), i, underlyingElement(this)) - } -} - -/** - * A function that defines an implicit conversion. - */ -abstract class ImplicitConversionFunction extends MemberFunction { - /** Gets the type this `ImplicitConversionFunction` takes as input. */ - abstract Type getSourceType(); - - /** Gets the type this `ImplicitConversionFunction` converts to. */ - abstract Type getDestType(); -} - -/** - * A C++ constructor that also defines an implicit conversion. For example the - * function `MyClass` in the following code is a `ConversionConstructor`: - * ``` - * class MyClass { - * public: - * MyClass(const MyOtherClass &from) { - * ... - * } - * }; - * ``` - */ -class ConversionConstructor extends Constructor, ImplicitConversionFunction { - ConversionConstructor() { - strictcount(Parameter p | p = getAParameter() and not p.hasInitializer()) = 1 and - not hasSpecifier("explicit") and - not this instanceof CopyConstructor - } - - override string getCanonicalQLClass() { - not this instanceof MoveConstructor and result = "ConversionConstructor" - } - - /** Gets the type this `ConversionConstructor` takes as input. */ - override Type getSourceType() { result = this.getParameter(0).getType() } - - /** Gets the type this `ConversionConstructor` is a constructor of. */ - override Type getDestType() { result = this.getDeclaringType() } -} - -private predicate hasCopySignature(MemberFunction f) { - f.getParameter(0).getUnspecifiedType().(LValueReferenceType).getBaseType() = f.getDeclaringType() -} - -private predicate hasMoveSignature(MemberFunction f) { - f.getParameter(0).getUnspecifiedType().(RValueReferenceType).getBaseType() = f.getDeclaringType() -} - -/** - * A C++ copy constructor [N4140 12.8]. For example the function `MyClass` in - * the following code is a `CopyConstructor`: - * ``` - * class MyClass { - * public: - * MyClass(const MyClass &from) { - * ... - * } - * }; - * ``` - * - * As per the standard, a copy constructor of class `T` is a non-template - * constructor whose first parameter has type `T&`, `const T&`, `volatile - * T&`, or `const volatile T&`, and either there are no other parameters, - * or the rest of the parameters all have default values. - * - * For template classes, it can generally not be determined until instantiation - * whether a constructor is a copy constructor. For such classes, `CopyConstructor` - * over-approximates the set of copy constructors; if an under-approximation is - * desired instead, see the member predicate - * `mayNotBeCopyConstructorInInstantiation`. - */ -class CopyConstructor extends Constructor { - CopyConstructor() { - hasCopySignature(this) and - ( - // The rest of the parameters all have default values - forall(int i | i > 0 and exists(getParameter(i)) | getParameter(i).hasInitializer()) - or - // or this is a template class, in which case the default values have - // not been extracted even if they exist. In that case, we assume that - // there are default values present since that is the most common case - // in real-world code. - getDeclaringType() instanceof TemplateClass - ) and - not exists(getATemplateArgument()) - } - - override string getCanonicalQLClass() { result = "CopyConstructor" } - - /** - * Holds if we cannot determine that this constructor will become a copy - * constructor in all instantiations. Depending on template parameters of the - * enclosing class, this may become an ordinary constructor or a copy - * constructor. - */ - predicate mayNotBeCopyConstructorInInstantiation() { - // In general, default arguments of template classes can only be - // type-checked for each template instantiation; if an argument in an - // instantiation fails to type-check then the corresponding parameter has - // no default argument in the instantiation. - getDeclaringType() instanceof TemplateClass and - getNumberOfParameters() > 1 - } -} - -/** - * A C++ move constructor [N4140 12.8]. For example the function `MyClass` in - * the following code is a `MoveConstructor`: - * ``` - * class MyClass { - * public: - * MyClass(MyClass &&from) { - * ... - * } - * }; - * ``` - * - * As per the standard, a move constructor of class `T` is a non-template - * constructor whose first parameter is `T&&`, `const T&&`, `volatile T&&`, - * or `const volatile T&&`, and either there are no other parameters, or - * the rest of the parameters all have default values. - * - * For template classes, it can generally not be determined until instantiation - * whether a constructor is a move constructor. For such classes, `MoveConstructor` - * over-approximates the set of move constructors; if an under-approximation is - * desired instead, see the member predicate - * `mayNotBeMoveConstructorInInstantiation`. - */ -class MoveConstructor extends Constructor { - MoveConstructor() { - hasMoveSignature(this) and - ( - // The rest of the parameters all have default values - forall(int i | i > 0 and exists(getParameter(i)) | getParameter(i).hasInitializer()) - or - // or this is a template class, in which case the default values have - // not been extracted even if they exist. In that case, we assume that - // there are default values present since that is the most common case - // in real-world code. - getDeclaringType() instanceof TemplateClass - ) and - not exists(getATemplateArgument()) - } - - override string getCanonicalQLClass() { result = "MoveConstructor" } - - /** - * Holds if we cannot determine that this constructor will become a move - * constructor in all instantiations. Depending on template parameters of the - * enclosing class, this may become an ordinary constructor or a move - * constructor. - */ - predicate mayNotBeMoveConstructorInInstantiation() { - // In general, default arguments of template classes can only be - // type-checked for each template instantiation; if an argument in an - // instantiation fails to type-check then the corresponding parameter has - // no default argument in the instantiation. - getDeclaringType() instanceof TemplateClass and - getNumberOfParameters() > 1 - } -} - -/** - * A C++ constructor that takes no arguments ('default' constructor). This - * is the constructor that is invoked when no initializer is given. For - * example the function `MyClass` in the following code is a - * `NoArgConstructor`: - * ``` - * class MyClass { - * public: - * MyClass() { - * ... - * } - * }; - * ``` - */ -class NoArgConstructor extends Constructor { - NoArgConstructor() { this.getNumberOfParameters() = 0 } -} - -/** - * A C++ destructor [N4140 12.4]. For example the function `~MyClass` in the - * following code is a destructor: - * ``` - * class MyClass { - * public: - * ~MyClass() { - * ... - * } - * }; - * ``` - */ -class Destructor extends MemberFunction { - Destructor() { functions(underlyingElement(this), _, 3) } - - override string getCanonicalQLClass() { result = "Destructor" } - - /** - * Gets a compiler-generated action which destructs a base class or member - * variable. - */ - DestructorDestruction getADestruction() { result = getDestruction(_) } - - /** - * Gets a compiler-generated action which destructs a base class or member - * variable. The index specifies the order in which the destruction should - * be evaluated. - */ - DestructorDestruction getDestruction(int i) { - exprparents(unresolveElement(result), i, underlyingElement(this)) - } -} - -/** - * A C++ conversion operator [N4140 12.3.2]. For example the function - * `operator int` in the following code is a `ConversionOperator`: - * ``` - * class MyClass { - * public: - * operator int(); - * }; - * ``` - */ -class ConversionOperator extends MemberFunction, ImplicitConversionFunction { - ConversionOperator() { functions(underlyingElement(this), _, 4) } - - override string getCanonicalQLClass() { result = "ConversionOperator" } - - override Type getSourceType() { result = this.getDeclaringType() } - - override Type getDestType() { result = this.getType() } + override string getAPrimaryQlClass() { result = "TopLevelFunction" } } /** @@ -1132,69 +707,11 @@ class ConversionOperator extends MemberFunction, ImplicitConversionFunction { class Operator extends Function { Operator() { functions(underlyingElement(this), _, 5) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not this instanceof MemberFunction and result = "Operator" } } -/** - * A C++ copy assignment operator [N4140 12.8]. For example the function - * `operator=` in the following code is a `CopyAssignmentOperator`: - * ``` - * class MyClass { - * public: - * MyClass &operator=(const MyClass &other); - * }; - * ``` - * - * As per the standard, a copy assignment operator of class `T` is a - * non-template non-static member function with the name `operator=` that - * takes exactly one parameter of type `T`, `T&`, `const T&`, `volatile - * T&`, or `const volatile T&`. - */ -class CopyAssignmentOperator extends Operator { - CopyAssignmentOperator() { - hasName("operator=") and - ( - hasCopySignature(this) - or - // Unlike CopyConstructor, this member allows a non-reference - // parameter. - getParameter(0).getUnspecifiedType() = getDeclaringType() - ) and - not exists(this.getParameter(1)) and - not exists(getATemplateArgument()) - } - - override string getCanonicalQLClass() { result = "CopyAssignmentOperator" } -} - -/** - * A C++ move assignment operator [N4140 12.8]. For example the function - * `operator=` in the following code is a `MoveAssignmentOperator`: - * ``` - * class MyClass { - * public: - * MyClass &operator=(MyClass &&other); - * }; - * ``` - * - * As per the standard, a move assignment operator of class `T` is a - * non-template non-static member function with the name `operator=` that - * takes exactly one parameter of type `T&&`, `const T&&`, `volatile T&&`, - * or `const volatile T&&`. - */ -class MoveAssignmentOperator extends Operator { - MoveAssignmentOperator() { - hasName("operator=") and - hasMoveSignature(this) and - not exists(this.getParameter(1)) and - not exists(getATemplateArgument()) - } - - override string getCanonicalQLClass() { result = "MoveAssignmentOperator" } -} - /** * A C++ function which has a non-empty template argument list. For example * the function `myTemplateFunction` in the following code: @@ -1221,7 +738,7 @@ class TemplateFunction extends Function { is_function_template(underlyingElement(this)) and exists(getATemplateArgument()) } - override string getCanonicalQLClass() { result = "TemplateFunction" } + override string getAPrimaryQlClass() { result = "TemplateFunction" } /** * Gets a compiler-generated instantiation of this function template. @@ -1261,7 +778,7 @@ class FunctionTemplateInstantiation extends Function { FunctionTemplateInstantiation() { tf.getAnInstantiation() = this } - override string getCanonicalQLClass() { result = "FunctionTemplateInstantiation" } + override string getAPrimaryQlClass() { result = "FunctionTemplateInstantiation" } /** * Gets the function template from which this instantiation was instantiated. @@ -1306,7 +823,7 @@ class FunctionTemplateInstantiation extends Function { class FunctionTemplateSpecialization extends Function { FunctionTemplateSpecialization() { this.isSpecialization() } - override string getCanonicalQLClass() { result = "FunctionTemplateSpecialization" } + override string getAPrimaryQlClass() { result = "FunctionTemplateSpecialization" } /** * Gets the primary template for the specialization (the function template diff --git a/cpp/ql/src/semmle/code/cpp/Include.qll b/cpp/ql/src/semmle/code/cpp/Include.qll index 11702ce1bf69..f21edb2651d9 100644 --- a/cpp/ql/src/semmle/code/cpp/Include.qll +++ b/cpp/ql/src/semmle/code/cpp/Include.qll @@ -21,7 +21,7 @@ class Include extends PreprocessorDirective, @ppd_include { /** * Gets the token which occurs after `#include`, for example `"filename"` - * or `<filename>`. + * or ``. */ string getIncludeText() { result = getHead() } diff --git a/cpp/ql/src/semmle/code/cpp/Initializer.qll b/cpp/ql/src/semmle/code/cpp/Initializer.qll index 80601f659da8..643a880ddf2c 100644 --- a/cpp/ql/src/semmle/code/cpp/Initializer.qll +++ b/cpp/ql/src/semmle/code/cpp/Initializer.qll @@ -1,3 +1,7 @@ +/** + * Provides the `Initializer` class, representing C/C++ declaration initializers. + */ + import semmle.code.cpp.controlflow.ControlFlowGraph /** @@ -18,7 +22,7 @@ import semmle.code.cpp.controlflow.ControlFlowGraph class Initializer extends ControlFlowNode, @initialiser { override Location getLocation() { initialisers(underlyingElement(this), _, _, result) } - override string getCanonicalQLClass() { result = "Initializer" } + override string getAPrimaryQlClass() { result = "Initializer" } /** Holds if this initializer is explicit in the source. */ override predicate fromSource() { not this.getLocation() instanceof UnknownLocation } diff --git a/cpp/ql/src/semmle/code/cpp/Iteration.qll b/cpp/ql/src/semmle/code/cpp/Iteration.qll index fd7ba60ea194..d87306c4babe 100644 --- a/cpp/ql/src/semmle/code/cpp/Iteration.qll +++ b/cpp/ql/src/semmle/code/cpp/Iteration.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for loop iteration variables. + */ + import semmle.code.cpp.Variable /** @@ -7,14 +11,18 @@ import semmle.code.cpp.Variable class LoopCounter extends Variable { LoopCounter() { exists(ForStmt f | f.getAnIterationVariable() = this) } - // Gets an access of this variable within loop `f`. + /** + * Gets an access of this variable within loop `f`. + */ VariableAccess getVariableAccessInLoop(ForStmt f) { this.getALoop() = f and result.getEnclosingStmt().getParent*() = f and this = result.getTarget() } - // Gets a loop which uses this variable as its counter. + /** + * Gets a loop which uses this variable as its counter. + */ ForStmt getALoop() { result.getAnIterationVariable() = this } } @@ -25,14 +33,18 @@ class LoopCounter extends Variable { class LoopControlVariable extends Variable { LoopControlVariable() { this = loopControlVariable(_) } - // Gets an access of this variable within loop `f`. + /** + * Gets an access of this variable within loop `f`. + */ VariableAccess getVariableAccessInLoop(ForStmt f) { this.getALoop() = f and result.getEnclosingStmt().getParent*() = f and this = result.getTarget() } - // Gets a loop which uses this variable as its control variable. + /** + * Gets a loop which uses this variable as its control variable. + */ ForStmt getALoop() { this = loopControlVariable(result) } } diff --git a/cpp/ql/src/semmle/code/cpp/Linkage.qll b/cpp/ql/src/semmle/code/cpp/Linkage.qll index 7912c9e25e1b..54a6099eaef2 100644 --- a/cpp/ql/src/semmle/code/cpp/Linkage.qll +++ b/cpp/ql/src/semmle/code/cpp/Linkage.qll @@ -1,3 +1,7 @@ +/** + * Proivdes the `LinkTarget` class representing linker invocations during the build process. + */ + import semmle.code.cpp.Class import semmle.code.cpp.File import semmle.code.cpp.Function diff --git a/cpp/ql/src/semmle/code/cpp/Location.qll b/cpp/ql/src/semmle/code/cpp/Location.qll index 129ffba0f748..dc37d4009c05 100644 --- a/cpp/ql/src/semmle/code/cpp/Location.qll +++ b/cpp/ql/src/semmle/code/cpp/Location.qll @@ -1,3 +1,7 @@ +/** + * Provides classes and predicates for locations in the source code. + */ + import semmle.code.cpp.Element import semmle.code.cpp.File @@ -11,16 +15,16 @@ class Location extends @location { /** Gets the file corresponding to this location, if any. */ File getFile() { result = this.getContainer() } - /** Gets the start line of this location. */ + /** Gets the 1-based line number (inclusive) where this location starts. */ int getStartLine() { this.fullLocationInfo(_, result, _, _, _) } - /** Gets the start column of this location. */ + /** Gets the 1-based column number (inclusive) where this location starts. */ int getStartColumn() { this.fullLocationInfo(_, _, result, _, _) } - /** Gets the end line of this location. */ + /** Gets the 1-based line number (inclusive) where this location ends. */ int getEndLine() { this.fullLocationInfo(_, _, _, result, _) } - /** Gets the end column of this location. */ + /** Gets the 1-based column number (inclusive) where this location ends. */ int getEndColumn() { this.fullLocationInfo(_, _, _, _, result) } /** @@ -101,16 +105,23 @@ class Location extends @location { } /** + * DEPRECATED: Use `Location` instead. * A location of an element. Not used for expressions or statements, which * instead use LocationExpr and LocationStmt respectively. */ -library class LocationDefault extends Location, @location_default { } +deprecated library class LocationDefault extends Location, @location_default { } -/** A location of a statement. */ -library class LocationStmt extends Location, @location_stmt { } +/** + * DEPRECATED: Use `Location` instead. + * A location of a statement. + */ +deprecated library class LocationStmt extends Location, @location_stmt { } -/** A location of an expression. */ -library class LocationExpr extends Location, @location_expr { } +/** + * DEPRECATED: Use `Location` instead. + * A location of an expression. + */ +deprecated library class LocationExpr extends Location, @location_expr { } /** * Gets the length of the longest line in file `f`. diff --git a/cpp/ql/src/semmle/code/cpp/Macro.qll b/cpp/ql/src/semmle/code/cpp/Macro.qll index 389634912b7d..aa4b8d419990 100644 --- a/cpp/ql/src/semmle/code/cpp/Macro.qll +++ b/cpp/ql/src/semmle/code/cpp/Macro.qll @@ -13,7 +13,7 @@ class Macro extends PreprocessorDirective, @ppd_define { */ override string getHead() { preproctext(underlyingElement(this), result, _) } - override string getCanonicalQLClass() { result = "Macro" } + override string getAPrimaryQlClass() { result = "Macro" } /** * Gets the body of this macro. For example, `(((x)>(y))?(x):(y))` in @@ -74,7 +74,7 @@ class MacroAccess extends Locatable, @macroinvocation { */ override Location getLocation() { result = this.getOutermostMacroAccess().getActualLocation() } - override string getCanonicalQLClass() { result = "MacroAccess" } + override string getAPrimaryQlClass() { result = "MacroAccess" } /** * Gets the location of this macro access. For a nested access, where @@ -147,7 +147,7 @@ class MacroAccess extends Locatable, @macroinvocation { class MacroInvocation extends MacroAccess { MacroInvocation() { macroinvocations(underlyingElement(this), _, _, 1) } - override string getCanonicalQLClass() { result = "MacroInvocation" } + override string getAPrimaryQlClass() { result = "MacroInvocation" } /** * Gets an element that occurs in this macro invocation or a nested macro @@ -179,6 +179,11 @@ class MacroInvocation extends MacroAccess { result.(Stmt).getGeneratingMacro() = this } + /** + * Gets a function that includes an expression that is affected by this macro + * invocation. If the macro expansion includes the end of one function and + * the beginning of another, this predicate will get both. + */ Function getEnclosingFunction() { result = this.getAnAffectedElement().(Expr).getEnclosingFunction() } diff --git a/cpp/ql/src/semmle/code/cpp/Member.qll b/cpp/ql/src/semmle/code/cpp/Member.qll index 92769486ae98..f47edbddeba0 100644 --- a/cpp/ql/src/semmle/code/cpp/Member.qll +++ b/cpp/ql/src/semmle/code/cpp/Member.qll @@ -1,2 +1,6 @@ +/** + * DEPRECATED: import `semmle.code.cpp.Element` and/or `semmle.code.cpp.Type` directly as required. + */ + import semmle.code.cpp.Element import semmle.code.cpp.Type diff --git a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll new file mode 100644 index 000000000000..0a692f755ed7 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll @@ -0,0 +1,499 @@ +/** + * Provides classes for working with C++ member functions, constructors, destructors, + * and user-defined operators. + */ + +import cpp + +/** + * A C++ function declared as a member of a class [N4140 9.3]. This includes + * static member functions. For example the functions `MyStaticMemberFunction` + * and `MyMemberFunction` in: + * ``` + * class MyClass { + * public: + * void MyMemberFunction() { + * DoSomething(); + * } + * + * static void MyStaticMemberFunction() { + * DoSomething(); + * } + * }; + * ``` + */ +class MemberFunction extends Function { + MemberFunction() { this.isMember() } + + override string getAPrimaryQlClass() { + not this instanceof CopyAssignmentOperator and + not this instanceof MoveAssignmentOperator and + result = "MemberFunction" + } + + /** + * Gets the number of parameters of this function, including any implicit + * `this` parameter. + */ + override int getEffectiveNumberOfParameters() { + if isStatic() then result = getNumberOfParameters() else result = getNumberOfParameters() + 1 + } + + /** Holds if this member is private. */ + predicate isPrivate() { this.hasSpecifier("private") } + + /** Holds if this member is protected. */ + predicate isProtected() { this.hasSpecifier("protected") } + + /** Holds if this member is public. */ + predicate isPublic() { this.hasSpecifier("public") } + + /** Holds if this function overrides that function. */ + predicate overrides(MemberFunction that) { + overrides(underlyingElement(this), unresolveElement(that)) + } + + /** Gets a directly overridden function. */ + MemberFunction getAnOverriddenFunction() { this.overrides(result) } + + /** Gets a directly overriding function. */ + MemberFunction getAnOverridingFunction() { result.overrides(this) } + + /** + * Gets the declaration entry for this member function that is within the + * class body. + */ + FunctionDeclarationEntry getClassBodyDeclarationEntry() { + if strictcount(getADeclarationEntry()) = 1 + then result = getDefinition() + else ( + result = getADeclarationEntry() and result != getDefinition() + ) + } + + /** + * Gets the type of the `this` parameter associated with this member function, if any. The type + * may have `const` and/or `volatile` qualifiers, matching the function declaration. + */ + PointerType getTypeOfThis() { + member_function_this_type(underlyingElement(this), unresolveElement(result)) + } +} + +/** + * A C++ virtual function. For example the two functions called + * `myVirtualFunction` in the following code are each a + * `VirtualFunction`: + * ``` + * class A { + * public: + * virtual void myVirtualFunction() = 0; + * }; + * + * class B: public A { + * public: + * virtual void myVirtualFunction() { + * doSomething(); + * } + * }; + * ``` + */ +class VirtualFunction extends MemberFunction { + VirtualFunction() { this.hasSpecifier("virtual") or purefunctions(underlyingElement(this)) } + + override string getAPrimaryQlClass() { result = "VirtualFunction" } + + /** Holds if this virtual function is pure. */ + predicate isPure() { this instanceof PureVirtualFunction } + + /** + * Holds if this function was declared with the `override` specifier + * [N4140 10.3]. + */ + predicate isOverrideExplicit() { this.hasSpecifier("override") } +} + +/** + * A C++ pure virtual function [N4140 10.4]. For example the first function + * called `myVirtualFunction` in the following code: + * ``` + * class A { + * public: + * virtual void myVirtualFunction() = 0; + * }; + * + * class B: public A { + * public: + * virtual void myVirtualFunction() { + * doSomething(); + * } + * }; + * ``` + */ +class PureVirtualFunction extends VirtualFunction { + PureVirtualFunction() { purefunctions(underlyingElement(this)) } + + override string getAPrimaryQlClass() { result = "PureVirtualFunction" } +} + +/** + * A const C++ member function [N4140 9.3.1/4]. A const function has the + * `const` specifier and does not modify the state of its class. For example + * the member function `day` in the following code: + * ``` + * class MyClass { + * ... + * + * int day() const { + * return d; + * } + * + * ... + * }; + * ``` + */ +class ConstMemberFunction extends MemberFunction { + ConstMemberFunction() { this.hasSpecifier("const") } + + override string getAPrimaryQlClass() { result = "ConstMemberFunction" } +} + +/** + * A C++ constructor [N4140 12.1]. For example the function `MyClass` in the + * following code is a constructor: + * ``` + * class MyClass { + * public: + * MyClass() { + * ... + * } + * }; + * ``` + */ +class Constructor extends MemberFunction { + Constructor() { functions(underlyingElement(this), _, 2) } + + override string getAPrimaryQlClass() { result = "Constructor" } + + /** + * Holds if this constructor serves as a default constructor. + * + * This holds for constructors with zero formal parameters. It also holds + * for constructors which have a non-zero number of formal parameters, + * provided that every parameter has a default value. + */ + predicate isDefault() { forall(Parameter p | p = this.getAParameter() | p.hasInitializer()) } + + /** + * Gets an entry in the constructor's initializer list, or a + * compiler-generated action which initializes a base class or member + * variable. + */ + ConstructorInit getAnInitializer() { result = getInitializer(_) } + + /** + * Gets an entry in the constructor's initializer list, or a + * compiler-generated action which initializes a base class or member + * variable. The index specifies the order in which the initializer is + * to be evaluated. + */ + ConstructorInit getInitializer(int i) { + exprparents(unresolveElement(result), i, underlyingElement(this)) + } +} + +/** + * A function that defines an implicit conversion. + */ +abstract class ImplicitConversionFunction extends MemberFunction { + /** Gets the type this `ImplicitConversionFunction` takes as input. */ + abstract Type getSourceType(); + + /** Gets the type this `ImplicitConversionFunction` converts to. */ + abstract Type getDestType(); +} + +/** + * DEPRECATED: as of C++11 this class does not correspond perfectly with the + * language definition of a converting constructor. + * + * A C++ constructor that also defines an implicit conversion. For example the + * function `MyClass` in the following code is a `ConversionConstructor`: + * ``` + * class MyClass { + * public: + * MyClass(const MyOtherClass &from) { + * ... + * } + * }; + * ``` + */ +deprecated class ConversionConstructor extends Constructor, ImplicitConversionFunction { + ConversionConstructor() { + strictcount(Parameter p | p = getAParameter() and not p.hasInitializer()) = 1 and + not hasSpecifier("explicit") + } + + override string getAPrimaryQlClass() { + not this instanceof CopyConstructor and + not this instanceof MoveConstructor and + result = "ConversionConstructor" + } + + /** Gets the type this `ConversionConstructor` takes as input. */ + override Type getSourceType() { result = this.getParameter(0).getType() } + + /** Gets the type this `ConversionConstructor` is a constructor of. */ + override Type getDestType() { result = this.getDeclaringType() } +} + +private predicate hasCopySignature(MemberFunction f) { + f.getParameter(0).getUnspecifiedType().(LValueReferenceType).getBaseType() = f.getDeclaringType() +} + +private predicate hasMoveSignature(MemberFunction f) { + f.getParameter(0).getUnspecifiedType().(RValueReferenceType).getBaseType() = f.getDeclaringType() +} + +/** + * A C++ copy constructor [N4140 12.8]. For example the function `MyClass` in + * the following code is a `CopyConstructor`: + * ``` + * class MyClass { + * public: + * MyClass(const MyClass &from) { + * ... + * } + * }; + * ``` + * + * As per the standard, a copy constructor of class `T` is a non-template + * constructor whose first parameter has type `T&`, `const T&`, `volatile + * T&`, or `const volatile T&`, and either there are no other parameters, + * or the rest of the parameters all have default values. + * + * For template classes, it can generally not be determined until instantiation + * whether a constructor is a copy constructor. For such classes, `CopyConstructor` + * over-approximates the set of copy constructors; if an under-approximation is + * desired instead, see the member predicate + * `mayNotBeCopyConstructorInInstantiation`. + */ +class CopyConstructor extends Constructor { + CopyConstructor() { + hasCopySignature(this) and + ( + // The rest of the parameters all have default values + forall(int i | i > 0 and exists(getParameter(i)) | getParameter(i).hasInitializer()) + or + // or this is a template class, in which case the default values have + // not been extracted even if they exist. In that case, we assume that + // there are default values present since that is the most common case + // in real-world code. + getDeclaringType() instanceof TemplateClass + ) and + not exists(getATemplateArgument()) + } + + override string getAPrimaryQlClass() { result = "CopyConstructor" } + + /** + * Holds if we cannot determine that this constructor will become a copy + * constructor in all instantiations. Depending on template parameters of the + * enclosing class, this may become an ordinary constructor or a copy + * constructor. + */ + predicate mayNotBeCopyConstructorInInstantiation() { + // In general, default arguments of template classes can only be + // type-checked for each template instantiation; if an argument in an + // instantiation fails to type-check then the corresponding parameter has + // no default argument in the instantiation. + getDeclaringType() instanceof TemplateClass and + getNumberOfParameters() > 1 + } +} + +/** + * A C++ move constructor [N4140 12.8]. For example the function `MyClass` in + * the following code is a `MoveConstructor`: + * ``` + * class MyClass { + * public: + * MyClass(MyClass &&from) { + * ... + * } + * }; + * ``` + * + * As per the standard, a move constructor of class `T` is a non-template + * constructor whose first parameter is `T&&`, `const T&&`, `volatile T&&`, + * or `const volatile T&&`, and either there are no other parameters, or + * the rest of the parameters all have default values. + * + * For template classes, it can generally not be determined until instantiation + * whether a constructor is a move constructor. For such classes, `MoveConstructor` + * over-approximates the set of move constructors; if an under-approximation is + * desired instead, see the member predicate + * `mayNotBeMoveConstructorInInstantiation`. + */ +class MoveConstructor extends Constructor { + MoveConstructor() { + hasMoveSignature(this) and + ( + // The rest of the parameters all have default values + forall(int i | i > 0 and exists(getParameter(i)) | getParameter(i).hasInitializer()) + or + // or this is a template class, in which case the default values have + // not been extracted even if they exist. In that case, we assume that + // there are default values present since that is the most common case + // in real-world code. + getDeclaringType() instanceof TemplateClass + ) and + not exists(getATemplateArgument()) + } + + override string getAPrimaryQlClass() { result = "MoveConstructor" } + + /** + * Holds if we cannot determine that this constructor will become a move + * constructor in all instantiations. Depending on template parameters of the + * enclosing class, this may become an ordinary constructor or a move + * constructor. + */ + predicate mayNotBeMoveConstructorInInstantiation() { + // In general, default arguments of template classes can only be + // type-checked for each template instantiation; if an argument in an + // instantiation fails to type-check then the corresponding parameter has + // no default argument in the instantiation. + getDeclaringType() instanceof TemplateClass and + getNumberOfParameters() > 1 + } +} + +/** + * A C++ constructor that takes no arguments ('default' constructor). This + * is the constructor that is invoked when no initializer is given. For + * example the function `MyClass` in the following code is a + * `NoArgConstructor`: + * ``` + * class MyClass { + * public: + * MyClass() { + * ... + * } + * }; + * ``` + */ +class NoArgConstructor extends Constructor { + NoArgConstructor() { this.getNumberOfParameters() = 0 } +} + +/** + * A C++ destructor [N4140 12.4]. For example the function `~MyClass` in the + * following code is a destructor: + * ``` + * class MyClass { + * public: + * ~MyClass() { + * ... + * } + * }; + * ``` + */ +class Destructor extends MemberFunction { + Destructor() { functions(underlyingElement(this), _, 3) } + + override string getAPrimaryQlClass() { result = "Destructor" } + + /** + * Gets a compiler-generated action which destructs a base class or member + * variable. + */ + DestructorDestruction getADestruction() { result = getDestruction(_) } + + /** + * Gets a compiler-generated action which destructs a base class or member + * variable. The index specifies the order in which the destruction should + * be evaluated. + */ + DestructorDestruction getDestruction(int i) { + exprparents(unresolveElement(result), i, underlyingElement(this)) + } +} + +/** + * A C++ conversion operator [N4140 12.3.2]. For example the function + * `operator int` in the following code is a `ConversionOperator`: + * ``` + * class MyClass { + * public: + * operator int(); + * }; + * ``` + */ +class ConversionOperator extends MemberFunction, ImplicitConversionFunction { + ConversionOperator() { functions(underlyingElement(this), _, 4) } + + override string getAPrimaryQlClass() { result = "ConversionOperator" } + + override Type getSourceType() { result = this.getDeclaringType() } + + override Type getDestType() { result = this.getType() } +} + +/** + * A C++ copy assignment operator [N4140 12.8]. For example the function + * `operator=` in the following code is a `CopyAssignmentOperator`: + * ``` + * class MyClass { + * public: + * MyClass &operator=(const MyClass &other); + * }; + * ``` + * + * As per the standard, a copy assignment operator of class `T` is a + * non-template non-static member function with the name `operator=` that + * takes exactly one parameter of type `T`, `T&`, `const T&`, `volatile + * T&`, or `const volatile T&`. + */ +class CopyAssignmentOperator extends Operator { + CopyAssignmentOperator() { + hasName("operator=") and + ( + hasCopySignature(this) + or + // Unlike CopyConstructor, this member allows a non-reference + // parameter. + getParameter(0).getUnspecifiedType() = getDeclaringType() + ) and + not exists(this.getParameter(1)) and + not exists(getATemplateArgument()) + } + + override string getAPrimaryQlClass() { result = "CopyAssignmentOperator" } +} + +/** + * A C++ move assignment operator [N4140 12.8]. For example the function + * `operator=` in the following code is a `MoveAssignmentOperator`: + * ``` + * class MyClass { + * public: + * MyClass &operator=(MyClass &&other); + * }; + * ``` + * + * As per the standard, a move assignment operator of class `T` is a + * non-template non-static member function with the name `operator=` that + * takes exactly one parameter of type `T&&`, `const T&&`, `volatile T&&`, + * or `const volatile T&&`. + */ +class MoveAssignmentOperator extends Operator { + MoveAssignmentOperator() { + hasName("operator=") and + hasMoveSignature(this) and + not exists(this.getParameter(1)) and + not exists(getATemplateArgument()) + } + + override string getAPrimaryQlClass() { result = "MoveAssignmentOperator" } +} diff --git a/cpp/ql/src/semmle/code/cpp/NameQualifiers.qll b/cpp/ql/src/semmle/code/cpp/NameQualifiers.qll index eff2c9205bf9..042ee10700ad 100644 --- a/cpp/ql/src/semmle/code/cpp/NameQualifiers.qll +++ b/cpp/ql/src/semmle/code/cpp/NameQualifiers.qll @@ -1,3 +1,8 @@ +/** + * Provides classes for working with name qualifiers such as the `N::` in + * `N::f()`. + */ + import cpp /** diff --git a/cpp/ql/src/semmle/code/cpp/Namespace.qll b/cpp/ql/src/semmle/code/cpp/Namespace.qll index 9b9b12aaef06..6172c3af50ca 100644 --- a/cpp/ql/src/semmle/code/cpp/Namespace.qll +++ b/cpp/ql/src/semmle/code/cpp/Namespace.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for modeling namespaces, `using` directives and `using` declarations. + */ + import semmle.code.cpp.Element import semmle.code.cpp.Type import semmle.code.cpp.metrics.MetricNamespace @@ -127,7 +131,7 @@ class NamespaceDeclarationEntry extends Locatable, @namespace_decl { */ Location getBodyLocation() { namespace_decls(underlyingElement(this), _, _, result) } - override string getCanonicalQLClass() { result = "NamespaceDeclarationEntry" } + override string getAPrimaryQlClass() { result = "NamespaceDeclarationEntry" } } /** diff --git a/cpp/ql/src/semmle/code/cpp/NestedFields.qll b/cpp/ql/src/semmle/code/cpp/NestedFields.qll index c4be8b8b9ffd..ce67719a7e21 100644 --- a/cpp/ql/src/semmle/code/cpp/NestedFields.qll +++ b/cpp/ql/src/semmle/code/cpp/NestedFields.qll @@ -1,3 +1,8 @@ +/** + * Provides a class for reasoning about nested field accesses, for example + * the access `myLine.start.x`. + */ + import cpp /** @@ -25,7 +30,7 @@ private Expr getUltimateQualifier(FieldAccess fa) { } /** - * Accesses to nested fields. + * A nested field access, for example the access `myLine.start.x`. */ class NestedFieldAccess extends FieldAccess { Expr ultimateQualifier; @@ -35,6 +40,30 @@ class NestedFieldAccess extends FieldAccess { getTarget() = getANestedField(ultimateQualifier.getType().stripType()) } - /** Gets the ultimate qualifier of this nested field access. */ + /** + * Gets the outermost qualifier of this nested field access. In the + * following example, the access to `myLine.start.x` has outermost qualifier + * `myLine`: + * ``` + * struct Point + * { + * float x, y; + * }; + * + * struct Line + * { + * Point start, end; + * }; + * + * void init() + * { + * Line myLine; + * + * myLine.start.x = 0.0f; + * + * // ... + * } + * ``` + */ Expr getUltimateQualifier() { result = ultimateQualifier } } diff --git a/cpp/ql/src/semmle/code/cpp/ObjectiveC.qll b/cpp/ql/src/semmle/code/cpp/ObjectiveC.qll index 5c99a47e6747..17da273d5a73 100644 --- a/cpp/ql/src/semmle/code/cpp/ObjectiveC.qll +++ b/cpp/ql/src/semmle/code/cpp/ObjectiveC.qll @@ -1,3 +1,7 @@ +/** + * DEPRECATED: Objective-C is no longer supported. + */ + import semmle.code.cpp.Class private import semmle.code.cpp.internal.ResolveClass @@ -132,7 +136,7 @@ deprecated class ObjcTryStmt extends TryStmt { * DEPRECATED: Objective-C is no longer supported. * An Objective C `@finally` block. */ -deprecated class FinallyBlock extends Block { +deprecated class FinallyBlock extends BlockStmt { FinallyBlock() { none() } /** Gets the try statement corresponding to this finally block. */ diff --git a/cpp/ql/src/semmle/code/cpp/Parameter.qll b/cpp/ql/src/semmle/code/cpp/Parameter.qll index 1fbd8b0f071c..040b738591c4 100644 --- a/cpp/ql/src/semmle/code/cpp/Parameter.qll +++ b/cpp/ql/src/semmle/code/cpp/Parameter.qll @@ -1,3 +1,7 @@ +/** + * Provides a class that models parameters to functions. + */ + import semmle.code.cpp.Location import semmle.code.cpp.Declaration private import semmle.code.cpp.internal.ResolveClass @@ -45,7 +49,7 @@ class Parameter extends LocalScopeVariable, @parameter { result = "p#" + this.getIndex().toString() } - override string getCanonicalQLClass() { result = "Parameter" } + override string getAPrimaryQlClass() { result = "Parameter" } /** * Gets the name of this parameter, including it's type. @@ -94,7 +98,7 @@ class Parameter extends LocalScopeVariable, @parameter { * DEPRECATED: this method was used in a previous implementation of * getName, but is no longer in use. */ - deprecated string getNameInBlock(Block b) { + deprecated string getNameInBlock(BlockStmt b) { exists(ParameterDeclarationEntry pde | pde.getFunctionDeclarationEntry().getBlock() = b and this.getFunction().getBlock() = b and @@ -123,7 +127,7 @@ class Parameter extends LocalScopeVariable, @parameter { * Gets the catch block to which this parameter belongs, if it is a catch * block parameter. */ - Block getCatchBlock() { params(underlyingElement(this), unresolveElement(result), _, _) } + BlockStmt getCatchBlock() { params(underlyingElement(this), unresolveElement(result), _, _) } /** * Gets the zero-based index of this parameter. @@ -165,6 +169,7 @@ class Parameter extends LocalScopeVariable, @parameter { class ParameterIndex extends int { ParameterIndex() { exists(Parameter p | this = p.getIndex()) or - exists(Call c | exists(c.getArgument(this))) // permit indexing varargs + exists(Call c | exists(c.getArgument(this))) or // permit indexing varargs + this = -1 // used for `this` } } diff --git a/cpp/ql/src/semmle/code/cpp/Preprocessor.qll b/cpp/ql/src/semmle/code/cpp/Preprocessor.qll index d0104900d605..a9609922b74d 100644 --- a/cpp/ql/src/semmle/code/cpp/Preprocessor.qll +++ b/cpp/ql/src/semmle/code/cpp/Preprocessor.qll @@ -33,11 +33,13 @@ class PreprocessorDirective extends Locatable, @preprocdirect { } } +private class TPreprocessorBranchDirective = @ppd_branch or @ppd_else or @ppd_endif; + /** * A C/C++ preprocessor branch related directive: `#if`, `#ifdef`, * `#ifndef`, `#elif`, `#else` or `#endif`. */ -abstract class PreprocessorBranchDirective extends PreprocessorDirective { +class PreprocessorBranchDirective extends PreprocessorDirective, TPreprocessorBranchDirective { /** * Gets the `#if`, `#ifdef` or `#ifndef` directive which matches this * branching directive. @@ -152,7 +154,7 @@ class PreprocessorIf extends PreprocessorBranch, @ppd_if { class PreprocessorIfdef extends PreprocessorBranch, @ppd_ifdef { override string toString() { result = "#ifdef " + this.getHead() } - override string getCanonicalQLClass() { result = "PreprocessorIfdef" } + override string getAPrimaryQlClass() { result = "PreprocessorIfdef" } } /** diff --git a/cpp/ql/src/semmle/code/cpp/PrintAST.qll b/cpp/ql/src/semmle/code/cpp/PrintAST.qll index 9f69d5644575..fb5232b3008a 100644 --- a/cpp/ql/src/semmle/code/cpp/PrintAST.qll +++ b/cpp/ql/src/semmle/code/cpp/PrintAST.qll @@ -1,3 +1,11 @@ +/** + * Provides queries to pretty-print a C++ AST as a graph. + * + * By default, this will print the AST for all functions in the database. To change this behavior, + * extend `PrintASTConfiguration` and override `shouldPrintFunction` to hold for only the functions + * you wish to view the AST for. + */ + import cpp private import semmle.code.cpp.Print @@ -7,6 +15,9 @@ private newtype TPrintASTConfiguration = MkPrintASTConfiguration() * The query can extend this class to control which functions are printed. */ class PrintASTConfiguration extends TPrintASTConfiguration { + /** + * Gets a textual representation of this `PrintASTConfiguration`. + */ string toString() { result = "PrintASTConfiguration" } /** @@ -96,6 +107,9 @@ private newtype TPrintASTNode = * A node in the output tree. */ class PrintASTNode extends TPrintASTNode { + /** + * Gets a textual representation of this node in the PrintAST output tree. + */ abstract string toString(); /** @@ -155,7 +169,7 @@ class PrintASTNode extends TPrintASTNode { * Retrieves the canonical QL class(es) for entity `el` */ private string qlClass(ElementBase el) { - result = "[" + concat(el.getCanonicalQLClass(), ",") + "] " + result = "[" + concat(el.getAPrimaryQlClass(), ",") + "] " // Alternative implementation -- do not delete. It is useful for QL class discovery. //result = "["+ concat(el.getAQlClass(), ",") + "] " } @@ -208,6 +222,9 @@ class ExprNode extends ASTNode { result = expr.getValueCategoryString() } + /** + * Gets the value of this expression, if it is a constant. + */ string getValue() { result = expr.getValue() } } @@ -373,6 +390,9 @@ class ParametersNode extends PrintASTNode, TParametersNode { override ASTNode getChild(int childIndex) { result.getAST() = func.getParameter(childIndex) } + /** + * Gets the `Function` for which this node represents the parameters. + */ final Function getFunction() { result = func } } @@ -392,6 +412,9 @@ class ConstructorInitializersNode extends PrintASTNode, TConstructorInitializers result.getAST() = ctor.getInitializer(childIndex) } + /** + * Gets the `Constructor` for which this node represents the initializer list. + */ final Constructor getConstructor() { result = ctor } } @@ -411,6 +434,9 @@ class DestructorDestructionsNode extends PrintASTNode, TDestructorDestructionsNo result.getAST() = dtor.getDestruction(childIndex) } + /** + * Gets the `Destructor` for which this node represents the destruction list. + */ final Destructor getDestructor() { result = dtor } } @@ -464,6 +490,9 @@ class FunctionNode extends ASTNode { key = "semmle.order" and result = getOrder().toString() } + /** + * Gets the `Function` this node represents. + */ final Function getFunction() { result = func } } @@ -499,11 +528,16 @@ class ArrayAggregateLiteralNode extends ExprNode { } } +/** Holds if `node` belongs to the output tree, and its property `key` has the given `value`. */ query predicate nodes(PrintASTNode node, string key, string value) { node.shouldPrint() and value = node.getProperty(key) } +/** + * Holds if `target` is a child of `source` in the AST, and property `key` of the edge has the + * given `value`. + */ query predicate edges(PrintASTNode source, PrintASTNode target, string key, string value) { exists(int childIndex | source.shouldPrint() and @@ -517,6 +551,7 @@ query predicate edges(PrintASTNode source, PrintASTNode target, string key, stri ) } +/** Holds if property `key` of the graph has the given `value`. */ query predicate graphProperties(string key, string value) { key = "semmle.graphKind" and value = "tree" } diff --git a/cpp/ql/src/semmle/code/cpp/Specifier.qll b/cpp/ql/src/semmle/code/cpp/Specifier.qll index f58f060623dd..3d68fb374f12 100644 --- a/cpp/ql/src/semmle/code/cpp/Specifier.qll +++ b/cpp/ql/src/semmle/code/cpp/Specifier.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for modeling specifiers and attributes. + */ + import semmle.code.cpp.Element private import semmle.code.cpp.internal.ResolveClass @@ -12,7 +16,7 @@ class Specifier extends Element, @specifier { result instanceof UnknownDefaultLocation } - override string getCanonicalQLClass() { result = "Specifier" } + override string getAPrimaryQlClass() { result = "Specifier" } /** Gets the name of this specifier. */ string getName() { specifiers(underlyingElement(this), result) } @@ -33,7 +37,7 @@ class FunctionSpecifier extends Specifier { this.hasName("explicit") } - override string getCanonicalQLClass() { result = "FunctionSpecifier)" } + override string getAPrimaryQlClass() { result = "FunctionSpecifier)" } } /** @@ -49,7 +53,7 @@ class StorageClassSpecifier extends Specifier { this.hasName("mutable") } - override string getCanonicalQLClass() { result = "StorageClassSpecifier" } + override string getAPrimaryQlClass() { result = "StorageClassSpecifier" } } /** @@ -104,7 +108,7 @@ class AccessSpecifier extends Specifier { ) } - override string getCanonicalQLClass() { result = "AccessSpecifier" } + override string getAPrimaryQlClass() { result = "AccessSpecifier" } } /** @@ -234,7 +238,7 @@ class FormatAttribute extends GnuAttribute { ) } - override string getCanonicalQLClass() { result = "FormatAttribute" } + override string getAPrimaryQlClass() { result = "FormatAttribute" } } /** diff --git a/cpp/ql/src/semmle/code/cpp/Struct.qll b/cpp/ql/src/semmle/code/cpp/Struct.qll index 6b95cdba1bd5..50a208894b43 100644 --- a/cpp/ql/src/semmle/code/cpp/Struct.qll +++ b/cpp/ql/src/semmle/code/cpp/Struct.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for modeling `struct`s. + */ + import semmle.code.cpp.Type import semmle.code.cpp.Class @@ -18,7 +22,7 @@ import semmle.code.cpp.Class class Struct extends Class { Struct() { usertypes(underlyingElement(this), _, 1) or usertypes(underlyingElement(this), _, 3) } - override string getCanonicalQLClass() { result = "Struct" } + override string getAPrimaryQlClass() { result = "Struct" } override string explain() { result = "struct " + this.getName() } @@ -39,9 +43,7 @@ class Struct extends Class { class LocalStruct extends Struct { LocalStruct() { isLocal() } - override string getCanonicalQLClass() { - not this instanceof LocalUnion and result = "LocalStruct" - } + override string getAPrimaryQlClass() { not this instanceof LocalUnion and result = "LocalStruct" } } /** @@ -58,7 +60,7 @@ class LocalStruct extends Struct { class NestedStruct extends Struct { NestedStruct() { this.isMember() } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not this instanceof NestedUnion and result = "NestedStruct" } diff --git a/cpp/ql/src/semmle/code/cpp/TestFile.qll b/cpp/ql/src/semmle/code/cpp/TestFile.qll index 4348bddf59c0..b9e3fe3a614f 100644 --- a/cpp/ql/src/semmle/code/cpp/TestFile.qll +++ b/cpp/ql/src/semmle/code/cpp/TestFile.qll @@ -1,3 +1,8 @@ +/** + * Provides classes for identifying files that contain test cases. It is often + * desirable to exclude these files from analysis. + */ + import semmle.code.cpp.File /** diff --git a/cpp/ql/src/semmle/code/cpp/Type.qll b/cpp/ql/src/semmle/code/cpp/Type.qll index 55eb4f27d3dc..8273d0440d5c 100644 --- a/cpp/ql/src/semmle/code/cpp/Type.qll +++ b/cpp/ql/src/semmle/code/cpp/Type.qll @@ -1,5 +1,8 @@ +/** + * Provides a hierarchy of classes for modeling C/C++ types. + */ + import semmle.code.cpp.Element -import semmle.code.cpp.Member import semmle.code.cpp.Function private import semmle.code.cpp.internal.ResolveClass @@ -322,7 +325,7 @@ class BuiltInType extends Type, @builtintype { class ErroneousType extends BuiltInType { ErroneousType() { builtintypes(underlyingElement(this), _, 1, _, _, _) } - override string getCanonicalQLClass() { result = "ErroneousType" } + override string getAPrimaryQlClass() { result = "ErroneousType" } } /** @@ -342,7 +345,7 @@ class ErroneousType extends BuiltInType { class UnknownType extends BuiltInType { UnknownType() { builtintypes(underlyingElement(this), _, 2, _, _, _) } - override string getCanonicalQLClass() { result = "UnknownType" } + override string getAPrimaryQlClass() { result = "UnknownType" } } private predicate isArithmeticType(@builtintype type, int kind) { @@ -361,7 +364,7 @@ private predicate isArithmeticType(@builtintype type, int kind) { class ArithmeticType extends BuiltInType { ArithmeticType() { isArithmeticType(underlyingElement(this), _) } - override string getCanonicalQLClass() { result = "ArithmeticType" } + override string getAPrimaryQlClass() { result = "ArithmeticType" } } private predicate isIntegralType(@builtintype type, int kind) { @@ -561,7 +564,7 @@ class IntegralType extends ArithmeticType, IntegralOrEnumType { class BoolType extends IntegralType { BoolType() { builtintypes(underlyingElement(this), _, 4, _, _, _) } - override string getCanonicalQLClass() { result = "BoolType" } + override string getAPrimaryQlClass() { result = "BoolType" } } /** @@ -586,7 +589,7 @@ abstract class CharType extends IntegralType { } class PlainCharType extends CharType { PlainCharType() { builtintypes(underlyingElement(this), _, 5, _, _, _) } - override string getCanonicalQLClass() { result = "PlainCharType" } + override string getAPrimaryQlClass() { result = "PlainCharType" } } /** @@ -599,7 +602,7 @@ class PlainCharType extends CharType { class UnsignedCharType extends CharType { UnsignedCharType() { builtintypes(underlyingElement(this), _, 6, _, _, _) } - override string getCanonicalQLClass() { result = "UnsignedCharType" } + override string getAPrimaryQlClass() { result = "UnsignedCharType" } } /** @@ -612,7 +615,7 @@ class UnsignedCharType extends CharType { class SignedCharType extends CharType { SignedCharType() { builtintypes(underlyingElement(this), _, 7, _, _, _) } - override string getCanonicalQLClass() { result = "SignedCharType" } + override string getAPrimaryQlClass() { result = "SignedCharType" } } /** @@ -629,7 +632,7 @@ class ShortType extends IntegralType { builtintypes(underlyingElement(this), _, 10, _, _, _) } - override string getCanonicalQLClass() { result = "ShortType" } + override string getAPrimaryQlClass() { result = "ShortType" } } /** @@ -646,7 +649,7 @@ class IntType extends IntegralType { builtintypes(underlyingElement(this), _, 13, _, _, _) } - override string getCanonicalQLClass() { result = "IntType" } + override string getAPrimaryQlClass() { result = "IntType" } } /** @@ -663,7 +666,7 @@ class LongType extends IntegralType { builtintypes(underlyingElement(this), _, 16, _, _, _) } - override string getCanonicalQLClass() { result = "LongType" } + override string getAPrimaryQlClass() { result = "LongType" } } /** @@ -680,7 +683,7 @@ class LongLongType extends IntegralType { builtintypes(underlyingElement(this), _, 19, _, _, _) } - override string getCanonicalQLClass() { result = "LongLongType" } + override string getAPrimaryQlClass() { result = "LongLongType" } } /** @@ -698,7 +701,7 @@ class Int128Type extends IntegralType { builtintypes(underlyingElement(this), _, 37, _, _, _) } - override string getCanonicalQLClass() { result = "Int128Type" } + override string getAPrimaryQlClass() { result = "Int128Type" } } private newtype TTypeDomain = @@ -894,7 +897,7 @@ class DecimalFloatingPointType extends FloatingPointType { class FloatType extends RealNumberType, BinaryFloatingPointType { FloatType() { builtintypes(underlyingElement(this), _, 24, _, _, _) } - override string getCanonicalQLClass() { result = "FloatType" } + override string getAPrimaryQlClass() { result = "FloatType" } } /** @@ -906,7 +909,7 @@ class FloatType extends RealNumberType, BinaryFloatingPointType { class DoubleType extends RealNumberType, BinaryFloatingPointType { DoubleType() { builtintypes(underlyingElement(this), _, 25, _, _, _) } - override string getCanonicalQLClass() { result = "DoubleType" } + override string getAPrimaryQlClass() { result = "DoubleType" } } /** @@ -918,7 +921,7 @@ class DoubleType extends RealNumberType, BinaryFloatingPointType { class LongDoubleType extends RealNumberType, BinaryFloatingPointType { LongDoubleType() { builtintypes(underlyingElement(this), _, 26, _, _, _) } - override string getCanonicalQLClass() { result = "LongDoubleType" } + override string getAPrimaryQlClass() { result = "LongDoubleType" } } /** @@ -930,7 +933,7 @@ class LongDoubleType extends RealNumberType, BinaryFloatingPointType { class Float128Type extends RealNumberType, BinaryFloatingPointType { Float128Type() { builtintypes(underlyingElement(this), _, 38, _, _, _) } - override string getCanonicalQLClass() { result = "Float128Type" } + override string getAPrimaryQlClass() { result = "Float128Type" } } /** @@ -942,7 +945,7 @@ class Float128Type extends RealNumberType, BinaryFloatingPointType { class Decimal32Type extends RealNumberType, DecimalFloatingPointType { Decimal32Type() { builtintypes(underlyingElement(this), _, 40, _, _, _) } - override string getCanonicalQLClass() { result = "Decimal32Type" } + override string getAPrimaryQlClass() { result = "Decimal32Type" } } /** @@ -954,7 +957,7 @@ class Decimal32Type extends RealNumberType, DecimalFloatingPointType { class Decimal64Type extends RealNumberType, DecimalFloatingPointType { Decimal64Type() { builtintypes(underlyingElement(this), _, 41, _, _, _) } - override string getCanonicalQLClass() { result = "Decimal64Type" } + override string getAPrimaryQlClass() { result = "Decimal64Type" } } /** @@ -966,7 +969,7 @@ class Decimal64Type extends RealNumberType, DecimalFloatingPointType { class Decimal128Type extends RealNumberType, DecimalFloatingPointType { Decimal128Type() { builtintypes(underlyingElement(this), _, 42, _, _, _) } - override string getCanonicalQLClass() { result = "Decimal128Type" } + override string getAPrimaryQlClass() { result = "Decimal128Type" } } /** @@ -978,7 +981,7 @@ class Decimal128Type extends RealNumberType, DecimalFloatingPointType { class VoidType extends BuiltInType { VoidType() { builtintypes(underlyingElement(this), _, 3, _, _, _) } - override string getCanonicalQLClass() { result = "VoidType" } + override string getAPrimaryQlClass() { result = "VoidType" } } /** @@ -994,7 +997,7 @@ class VoidType extends BuiltInType { class WideCharType extends IntegralType { WideCharType() { builtintypes(underlyingElement(this), _, 33, _, _, _) } - override string getCanonicalQLClass() { result = "WideCharType" } + override string getAPrimaryQlClass() { result = "WideCharType" } } /** @@ -1006,7 +1009,7 @@ class WideCharType extends IntegralType { class Char8Type extends IntegralType { Char8Type() { builtintypes(underlyingElement(this), _, 51, _, _, _) } - override string getCanonicalQLClass() { result = "Char8Type" } + override string getAPrimaryQlClass() { result = "Char8Type" } } /** @@ -1018,7 +1021,7 @@ class Char8Type extends IntegralType { class Char16Type extends IntegralType { Char16Type() { builtintypes(underlyingElement(this), _, 43, _, _, _) } - override string getCanonicalQLClass() { result = "Char16Type" } + override string getAPrimaryQlClass() { result = "Char16Type" } } /** @@ -1030,7 +1033,7 @@ class Char16Type extends IntegralType { class Char32Type extends IntegralType { Char32Type() { builtintypes(underlyingElement(this), _, 44, _, _, _) } - override string getCanonicalQLClass() { result = "Char32Type" } + override string getAPrimaryQlClass() { result = "Char32Type" } } /** @@ -1045,7 +1048,7 @@ class Char32Type extends IntegralType { class NullPointerType extends BuiltInType { NullPointerType() { builtintypes(underlyingElement(this), _, 34, _, _, _) } - override string getCanonicalQLClass() { result = "NullPointerType" } + override string getAPrimaryQlClass() { result = "NullPointerType" } } /** @@ -1080,22 +1083,46 @@ class DerivedType extends Type, @derivedtype { override Type stripType() { result = getBaseType().stripType() } - predicate isAutoReleasing() { + /** + * Holds if this type has the `__autoreleasing` specifier or if it points to + * a type with the `__autoreleasing` specifier. + * + * DEPRECATED: use `hasSpecifier` directly instead. + */ + deprecated predicate isAutoReleasing() { this.hasSpecifier("__autoreleasing") or this.(PointerType).getBaseType().hasSpecifier("__autoreleasing") } - predicate isStrong() { + /** + * Holds if this type has the `__strong` specifier or if it points to + * a type with the `__strong` specifier. + * + * DEPRECATED: use `hasSpecifier` directly instead. + */ + deprecated predicate isStrong() { this.hasSpecifier("__strong") or this.(PointerType).getBaseType().hasSpecifier("__strong") } - predicate isUnsafeRetained() { + /** + * Holds if this type has the `__unsafe_unretained` specifier or if it points + * to a type with the `__unsafe_unretained` specifier. + * + * DEPRECATED: use `hasSpecifier` directly instead. + */ + deprecated predicate isUnsafeRetained() { this.hasSpecifier("__unsafe_unretained") or this.(PointerType).getBaseType().hasSpecifier("__unsafe_unretained") } - predicate isWeak() { + /** + * Holds if this type has the `__weak` specifier or if it points to + * a type with the `__weak` specifier. + * + * DEPRECATED: use `hasSpecifier` directly instead. + */ + deprecated predicate isWeak() { this.hasSpecifier("__weak") or this.(PointerType).getBaseType().hasSpecifier("__weak") } @@ -1109,7 +1136,7 @@ class DerivedType extends Type, @derivedtype { * ``` */ class Decltype extends Type, @decltype { - override string getCanonicalQLClass() { result = "Decltype" } + override string getAPrimaryQlClass() { result = "Decltype" } /** * The expression whose type is being obtained by this decltype. @@ -1182,7 +1209,7 @@ class Decltype extends Type, @decltype { class PointerType extends DerivedType { PointerType() { derivedtypes(underlyingElement(this), _, 1, _) } - override string getCanonicalQLClass() { result = "PointerType" } + override string getAPrimaryQlClass() { result = "PointerType" } override int getPointerIndirectionLevel() { result = 1 + this.getBaseType().getPointerIndirectionLevel() @@ -1208,7 +1235,7 @@ class ReferenceType extends DerivedType { derivedtypes(underlyingElement(this), _, 2, _) or derivedtypes(underlyingElement(this), _, 8, _) } - override string getCanonicalQLClass() { result = "ReferenceType" } + override string getAPrimaryQlClass() { result = "ReferenceType" } override int getPointerIndirectionLevel() { result = getBaseType().getPointerIndirectionLevel() } @@ -1235,7 +1262,7 @@ class ReferenceType extends DerivedType { class LValueReferenceType extends ReferenceType { LValueReferenceType() { derivedtypes(underlyingElement(this), _, 2, _) } - override string getCanonicalQLClass() { result = "LValueReferenceType" } + override string getAPrimaryQlClass() { result = "LValueReferenceType" } } /** @@ -1251,7 +1278,7 @@ class LValueReferenceType extends ReferenceType { class RValueReferenceType extends ReferenceType { RValueReferenceType() { derivedtypes(underlyingElement(this), _, 8, _) } - override string getCanonicalQLClass() { result = "RValueReferenceType" } + override string getAPrimaryQlClass() { result = "RValueReferenceType" } override string explain() { result = "rvalue " + super.explain() } } @@ -1266,7 +1293,7 @@ class RValueReferenceType extends ReferenceType { class SpecifiedType extends DerivedType { SpecifiedType() { derivedtypes(underlyingElement(this), _, 3, _) } - override string getCanonicalQLClass() { result = "SpecifiedType" } + override string getAPrimaryQlClass() { result = "SpecifiedType" } override int getSize() { result = this.getBaseType().getSize() } @@ -1314,8 +1341,12 @@ class SpecifiedType extends DerivedType { class ArrayType extends DerivedType { ArrayType() { derivedtypes(underlyingElement(this), _, 4, _) } - override string getCanonicalQLClass() { result = "ArrayType" } + override string getAPrimaryQlClass() { result = "ArrayType" } + /** + * Holds if this array is declared to be of a constant size. See + * `getArraySize` and `getByteSize` to get the size of the array. + */ predicate hasArraySize() { arraysizes(underlyingElement(this), _, _, _) } /** @@ -1381,7 +1412,7 @@ class GNUVectorType extends DerivedType { */ int getNumElements() { arraysizes(underlyingElement(this), result, _, _) } - override string getCanonicalQLClass() { result = "GNUVectorType" } + override string getAPrimaryQlClass() { result = "GNUVectorType" } /** * Gets the size, in bytes, of this vector type. @@ -1412,7 +1443,7 @@ class GNUVectorType extends DerivedType { class FunctionPointerType extends FunctionPointerIshType { FunctionPointerType() { derivedtypes(underlyingElement(this), _, 6, _) } - override string getCanonicalQLClass() { result = "FunctionPointerType" } + override string getAPrimaryQlClass() { result = "FunctionPointerType" } override int getPointerIndirectionLevel() { result = 1 } @@ -1430,7 +1461,7 @@ class FunctionPointerType extends FunctionPointerIshType { class FunctionReferenceType extends FunctionPointerIshType { FunctionReferenceType() { derivedtypes(underlyingElement(this), _, 7, _) } - override string getCanonicalQLClass() { result = "FunctionReferenceType" } + override string getAPrimaryQlClass() { result = "FunctionReferenceType" } override int getPointerIndirectionLevel() { result = getBaseType().getPointerIndirectionLevel() } @@ -1519,7 +1550,7 @@ class PointerToMemberType extends Type, @ptrtomember { /** a printable representation of this named element */ override string toString() { result = this.getName() } - override string getCanonicalQLClass() { result = "PointerToMemberType" } + override string getAPrimaryQlClass() { result = "PointerToMemberType" } /** the name of this type */ override string getName() { result = "..:: *" } @@ -1564,16 +1595,25 @@ class RoutineType extends Type, @routinetype { /** a printable representation of this named element */ override string toString() { result = this.getName() } - override string getCanonicalQLClass() { result = "RoutineType" } + override string getAPrimaryQlClass() { result = "RoutineType" } override string getName() { result = "..()(..)" } + /** + * Gets the type of the `n`th parameter to this routine. + */ Type getParameterType(int n) { routinetypeargs(underlyingElement(this), n, unresolveElement(result)) } + /** + * Gets the type of a parameter to this routine. + */ Type getAParameterType() { routinetypeargs(underlyingElement(this), _, unresolveElement(result)) } + /** + * Gets the return type of this routine. + */ Type getReturnType() { routinetypes(underlyingElement(this), unresolveElement(result)) } override string explain() { @@ -1632,7 +1672,7 @@ class TemplateParameter extends UserType { usertypes(underlyingElement(this), _, 7) or usertypes(underlyingElement(this), _, 8) } - override string getCanonicalQLClass() { result = "TemplateParameter" } + override string getAPrimaryQlClass() { result = "TemplateParameter" } override predicate involvesTemplateParameter() { any() } } @@ -1650,7 +1690,7 @@ class TemplateParameter extends UserType { class TemplateTemplateParameter extends TemplateParameter { TemplateTemplateParameter() { usertypes(underlyingElement(this), _, 8) } - override string getCanonicalQLClass() { result = "TemplateTemplateParameter" } + override string getAPrimaryQlClass() { result = "TemplateTemplateParameter" } } /** @@ -1662,7 +1702,7 @@ class TemplateTemplateParameter extends TemplateParameter { class AutoType extends TemplateParameter { AutoType() { usertypes(underlyingElement(this), "auto", 7) } - override string getCanonicalQLClass() { result = "AutoType" } + override string getAPrimaryQlClass() { result = "AutoType" } override Location getLocation() { suppressUnusedThis(this) and @@ -1698,7 +1738,7 @@ private predicate suppressUnusedThis(Type t) { any() } class TypeMention extends Locatable, @type_mention { override string toString() { result = "type mention" } - override string getCanonicalQLClass() { result = "TypeMention" } + override string getAPrimaryQlClass() { result = "TypeMention" } /** * Gets the type being referenced by this type mention. diff --git a/cpp/ql/src/semmle/code/cpp/TypedefType.qll b/cpp/ql/src/semmle/code/cpp/TypedefType.qll index 504333aeedcc..aaf452ce4bb2 100644 --- a/cpp/ql/src/semmle/code/cpp/TypedefType.qll +++ b/cpp/ql/src/semmle/code/cpp/TypedefType.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for modeling typedefs and type aliases. + */ + import semmle.code.cpp.Type private import semmle.code.cpp.internal.ResolveClass @@ -55,7 +59,7 @@ class TypedefType extends UserType { class CTypedefType extends TypedefType { CTypedefType() { usertypes(underlyingElement(this), _, 5) } - override string getCanonicalQLClass() { result = "CTypedefType" } + override string getAPrimaryQlClass() { result = "CTypedefType" } override string explain() { result = "typedef {" + this.getBaseType().explain() + "} as \"" + this.getName() + "\"" @@ -71,7 +75,7 @@ class CTypedefType extends TypedefType { class UsingAliasTypedefType extends TypedefType { UsingAliasTypedefType() { usertypes(underlyingElement(this), _, 14) } - override string getCanonicalQLClass() { result = "UsingAliasTypedefType" } + override string getAPrimaryQlClass() { result = "UsingAliasTypedefType" } override string explain() { result = "using {" + this.getBaseType().explain() + "} as \"" + this.getName() + "\"" @@ -88,7 +92,7 @@ class UsingAliasTypedefType extends TypedefType { class LocalTypedefType extends TypedefType { LocalTypedefType() { isLocal() } - override string getCanonicalQLClass() { result = "LocalTypedefType" } + override string getAPrimaryQlClass() { result = "LocalTypedefType" } } /** @@ -101,7 +105,7 @@ class LocalTypedefType extends TypedefType { class NestedTypedefType extends TypedefType { NestedTypedefType() { this.isMember() } - override string getCanonicalQLClass() { result = "NestedTypedefType" } + override string getAPrimaryQlClass() { result = "NestedTypedefType" } /** * DEPRECATED: use `.hasSpecifier("private")` instead. diff --git a/cpp/ql/src/semmle/code/cpp/Union.qll b/cpp/ql/src/semmle/code/cpp/Union.qll index f1c033438ba5..6dcb2f0796c8 100644 --- a/cpp/ql/src/semmle/code/cpp/Union.qll +++ b/cpp/ql/src/semmle/code/cpp/Union.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for modeling `union`s. + */ + import semmle.code.cpp.Type import semmle.code.cpp.Struct @@ -13,7 +17,7 @@ import semmle.code.cpp.Struct class Union extends Struct { Union() { usertypes(underlyingElement(this), _, 3) } - override string getCanonicalQLClass() { result = "Union" } + override string getAPrimaryQlClass() { result = "Union" } override string explain() { result = "union " + this.getName() } @@ -35,7 +39,7 @@ class Union extends Struct { class LocalUnion extends Union { LocalUnion() { isLocal() } - override string getCanonicalQLClass() { result = "LocalUnion" } + override string getAPrimaryQlClass() { result = "LocalUnion" } } /** @@ -53,7 +57,7 @@ class LocalUnion extends Union { class NestedUnion extends Union { NestedUnion() { this.isMember() } - override string getCanonicalQLClass() { result = "NestedUnion" } + override string getAPrimaryQlClass() { result = "NestedUnion" } /** Holds if this member is private. */ predicate isPrivate() { this.hasSpecifier("private") } diff --git a/cpp/ql/src/semmle/code/cpp/UserType.qll b/cpp/ql/src/semmle/code/cpp/UserType.qll index 4484cde84deb..2ab0603f06cc 100644 --- a/cpp/ql/src/semmle/code/cpp/UserType.qll +++ b/cpp/ql/src/semmle/code/cpp/UserType.qll @@ -1,6 +1,10 @@ +/** + * Provides classes for modeling user-defined types such as classes, typedefs + * and enums. + */ + import semmle.code.cpp.Declaration import semmle.code.cpp.Type -import semmle.code.cpp.Member import semmle.code.cpp.Function private import semmle.code.cpp.internal.ResolveClass @@ -20,7 +24,7 @@ class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @ */ override string getName() { usertypes(underlyingElement(this), result, _) } - override string getCanonicalQLClass() { result = "UserType" } + override string getAPrimaryQlClass() { result = "UserType" } /** * Gets the simple name of this type, without any template parameters. For example @@ -84,6 +88,9 @@ class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @ * type exactly - but this is not apparent from its subclasses */ + /** + * Gets a child declaration within this user-defined type. + */ Declaration getADeclaration() { none() } override string explain() { result = this.getName() } @@ -104,7 +111,7 @@ class TypeDeclarationEntry extends DeclarationEntry, @type_decl { override string getName() { result = getType().getName() } - override string getCanonicalQLClass() { result = "TypeDeclarationEntry" } + override string getAPrimaryQlClass() { result = "TypeDeclarationEntry" } /** * The type which is being declared or defined. diff --git a/cpp/ql/src/semmle/code/cpp/Variable.qll b/cpp/ql/src/semmle/code/cpp/Variable.qll index 54f39ab2bb6f..527d8879b96d 100644 --- a/cpp/ql/src/semmle/code/cpp/Variable.qll +++ b/cpp/ql/src/semmle/code/cpp/Variable.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for modeling variables and their declarations. + */ + import semmle.code.cpp.Element import semmle.code.cpp.exprs.Access import semmle.code.cpp.Initializer @@ -28,7 +32,7 @@ private import semmle.code.cpp.internal.ResolveClass * can have multiple declarations. */ class Variable extends Declaration, @variable { - override string getCanonicalQLClass() { result = "Variable" } + override string getAPrimaryQlClass() { result = "Variable" } /** Gets the initializer of this variable, if any. */ Initializer getInitializer() { result.getDeclaration() = this } @@ -140,6 +144,11 @@ class Variable extends Declaration, @variable { */ predicate isConstexpr() { this.hasSpecifier("is_constexpr") } + /** + * Holds if this variable is declared `constinit`. + */ + predicate isConstinit() { this.hasSpecifier("declared_constinit") } + /** * Holds if this variable is `thread_local`. */ @@ -186,7 +195,7 @@ class Variable extends Declaration, @variable { class VariableDeclarationEntry extends DeclarationEntry, @var_decl { override Variable getDeclaration() { result = getVariable() } - override string getCanonicalQLClass() { result = "VariableDeclarationEntry" } + override string getAPrimaryQlClass() { result = "VariableDeclarationEntry" } /** * Gets the variable which is being declared or defined. @@ -245,7 +254,7 @@ class VariableDeclarationEntry extends DeclarationEntry, @var_decl { class ParameterDeclarationEntry extends VariableDeclarationEntry { ParameterDeclarationEntry() { param_decl_bind(underlyingElement(this), _, _) } - override string getCanonicalQLClass() { result = "ParameterDeclarationEntry" } + override string getAPrimaryQlClass() { result = "ParameterDeclarationEntry" } /** * Gets the function declaration or definition which this parameter @@ -321,7 +330,7 @@ class ParameterDeclarationEntry extends VariableDeclarationEntry { */ class LocalScopeVariable extends Variable, @localscopevariable { /** Gets the function to which this variable belongs. */ - /*abstract*/ Function getFunction() { none() } + Function getFunction() { none() } // overridden in subclasses } /** @@ -359,7 +368,7 @@ class StackVariable extends LocalScopeVariable { * A local variable can be declared by a `DeclStmt` or a `ConditionDeclExpr`. */ class LocalVariable extends LocalScopeVariable, @localvariable { - override string getCanonicalQLClass() { result = "LocalVariable" } + override string getAPrimaryQlClass() { result = "LocalVariable" } override string getName() { localvariables(underlyingElement(this), _, result) } @@ -460,7 +469,7 @@ class NamespaceVariable extends GlobalOrNamespaceVariable { exists(Namespace n | namespacembrs(unresolveElement(n), underlyingElement(this))) } - override string getCanonicalQLClass() { result = "NamespaceVariable" } + override string getAPrimaryQlClass() { result = "NamespaceVariable" } } /** @@ -481,7 +490,7 @@ class NamespaceVariable extends GlobalOrNamespaceVariable { class GlobalVariable extends GlobalOrNamespaceVariable { GlobalVariable() { not this instanceof NamespaceVariable } - override string getCanonicalQLClass() { result = "GlobalVariable" } + override string getAPrimaryQlClass() { result = "GlobalVariable" } } /** @@ -501,7 +510,7 @@ class GlobalVariable extends GlobalOrNamespaceVariable { class MemberVariable extends Variable, @membervariable { MemberVariable() { this.isMember() } - override string getCanonicalQLClass() { result = "MemberVariable" } + override string getAPrimaryQlClass() { result = "MemberVariable" } /** Holds if this member is private. */ predicate isPrivate() { this.hasSpecifier("private") } @@ -578,7 +587,7 @@ class TemplateVariable extends Variable { * float a; * } * - * template + * template * void myTemplateFunction() { * T b; * } diff --git a/cpp/ql/src/semmle/code/cpp/commons/CommonType.qll b/cpp/ql/src/semmle/code/cpp/commons/CommonType.qll index f584a8e48027..253a27670774 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/CommonType.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/CommonType.qll @@ -6,7 +6,7 @@ import semmle.code.cpp.Type class CharPointerType extends PointerType { CharPointerType() { this.getBaseType() instanceof CharType } - override string getCanonicalQLClass() { result = "CharPointerType" } + override string getAPrimaryQlClass() { result = "CharPointerType" } } /** @@ -15,7 +15,7 @@ class CharPointerType extends PointerType { class IntPointerType extends PointerType { IntPointerType() { this.getBaseType() instanceof IntType } - override string getCanonicalQLClass() { result = "IntPointerType" } + override string getAPrimaryQlClass() { result = "IntPointerType" } } /** @@ -24,7 +24,7 @@ class IntPointerType extends PointerType { class VoidPointerType extends PointerType { VoidPointerType() { this.getBaseType() instanceof VoidType } - override string getCanonicalQLClass() { result = "VoidPointerType" } + override string getAPrimaryQlClass() { result = "VoidPointerType" } } /** @@ -36,7 +36,7 @@ class Size_t extends Type { this.hasName("size_t") } - override string getCanonicalQLClass() { result = "Size_t" } + override string getAPrimaryQlClass() { result = "Size_t" } } /** @@ -48,7 +48,7 @@ class Ssize_t extends Type { this.hasName("ssize_t") } - override string getCanonicalQLClass() { result = "Ssize_t" } + override string getAPrimaryQlClass() { result = "Ssize_t" } } /** @@ -60,7 +60,7 @@ class Ptrdiff_t extends Type { this.hasName("ptrdiff_t") } - override string getCanonicalQLClass() { result = "Ptrdiff_t" } + override string getAPrimaryQlClass() { result = "Ptrdiff_t" } } /** @@ -72,7 +72,7 @@ class Intmax_t extends Type { this.hasName("intmax_t") } - override string getCanonicalQLClass() { result = "Intmax_t" } + override string getAPrimaryQlClass() { result = "Intmax_t" } } /** @@ -84,7 +84,7 @@ class Uintmax_t extends Type { this.hasName("uintmax_t") } - override string getCanonicalQLClass() { result = "Uintmax_t" } + override string getAPrimaryQlClass() { result = "Uintmax_t" } } /** @@ -100,7 +100,7 @@ class Wchar_t extends Type { this.hasName("wchar_t") } - override string getCanonicalQLClass() { result = "Wchar_t" } + override string getAPrimaryQlClass() { result = "Wchar_t" } } /** @@ -176,5 +176,5 @@ class MicrosoftInt64Type extends IntegralType { class BuiltInVarArgsList extends Type { BuiltInVarArgsList() { this.hasName("__builtin_va_list") } - override string getCanonicalQLClass() { result = "BuiltInVarArgsList" } + override string getAPrimaryQlClass() { result = "BuiltInVarArgsList" } } diff --git a/cpp/ql/src/semmle/code/cpp/commons/Environment.qll b/cpp/ql/src/semmle/code/cpp/commons/Environment.qll index f3f1759dd5c0..3da19977f338 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/Environment.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/Environment.qll @@ -29,7 +29,7 @@ private predicate readsEnvironment(Expr read, string sourceDescription) { exists(FunctionCall call, string name | read = call and call.getTarget().hasGlobalOrStdName(name) and - (name = "getenv" or name = "secure_getenv" or name = "_wgetenv") and + name = ["getenv", "secure_getenv", "_wgetenv"] and sourceDescription = name ) } diff --git a/cpp/ql/src/semmle/code/cpp/commons/File.qll b/cpp/ql/src/semmle/code/cpp/commons/File.qll index 5808d704e385..acc5893d8106 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/File.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/File.qll @@ -1,3 +1,7 @@ +/** + * Provides predicates for identifying function calls that open or close a file. + */ + import cpp /** diff --git a/cpp/ql/src/semmle/code/cpp/commons/Printf.qll b/cpp/ql/src/semmle/code/cpp/commons/Printf.qll index 32cea249214f..e441dd66adcc 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/Printf.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/Printf.qll @@ -9,10 +9,7 @@ import semmle.code.cpp.models.interfaces.FormattingFunction import semmle.code.cpp.models.implementations.Printf class PrintfFormatAttribute extends FormatAttribute { - PrintfFormatAttribute() { - getArchetype() = "printf" or - getArchetype() = "__printf__" - } + PrintfFormatAttribute() { getArchetype() = ["printf", "__printf__"] } } /** @@ -20,7 +17,7 @@ class PrintfFormatAttribute extends FormatAttribute { * function by its use of the GNU `format` attribute. */ class AttributeFormattingFunction extends FormattingFunction { - override string getCanonicalQLClass() { result = "AttributeFormattingFunction" } + override string getAPrimaryQlClass() { result = "AttributeFormattingFunction" } AttributeFormattingFunction() { exists(PrintfFormatAttribute printf_attrib | @@ -49,6 +46,18 @@ predicate primitiveVariadicFormatter(TopLevelFunction f, int formatParamIndex) { ) } +/** + * A standard function such as `vsprintf` that has an output parameter + * and a variable argument list of type `va_arg`. + */ +private predicate primitiveVariadicFormatterOutput(TopLevelFunction f, int outputParamIndex) { + // note: this might look like the regular expression in `primitiveVariadicFormatter`, but + // there is one important difference: the [fs] part is not optional, as these classify + // the `printf` variants that write to a buffer. + // Conveniently, these buffer parameters are all at index 0. + f.getName().regexpMatch("_?_?va?[fs]n?w?printf(_s)?(_p)?(_l)?") and outputParamIndex = 0 +} + private predicate callsVariadicFormatter(Function f, int formatParamIndex) { exists(FunctionCall fc, int i | variadicFormatter(fc.getTarget(), i) and @@ -57,6 +66,26 @@ private predicate callsVariadicFormatter(Function f, int formatParamIndex) { ) } +private predicate callsVariadicFormatterOutput(Function f, int outputParamIndex) { + exists(FunctionCall fc, int i | + fc.getEnclosingFunction() = f and + variadicFormatterOutput(fc.getTarget(), i) and + fc.getArgument(i) = f.getParameter(outputParamIndex).getAnAccess() + ) +} + +/** + * Holds if `f` is a function such as `vprintf` that takes variable argument list + * of type `va_arg` and writes formatted output to a buffer given as a parameter at + * index `outputParamIndex`, if any. + */ +private predicate variadicFormatterOutput(Function f, int outputParamIndex) { + primitiveVariadicFormatterOutput(f, outputParamIndex) + or + not f.isVarargs() and + callsVariadicFormatterOutput(f, outputParamIndex) +} + /** * Holds if `f` is a function such as `vprintf` that has a format parameter * (at `formatParamIndex`) and a variable argument list of type `va_arg`. @@ -73,11 +102,13 @@ predicate variadicFormatter(Function f, int formatParamIndex) { * string and a variable number of arguments. */ class UserDefinedFormattingFunction extends FormattingFunction { - override string getCanonicalQLClass() { result = "UserDefinedFormattingFunction" } + override string getAPrimaryQlClass() { result = "UserDefinedFormattingFunction" } UserDefinedFormattingFunction() { isVarargs() and callsVariadicFormatter(this, _) } override int getFormatParameterIndex() { callsVariadicFormatter(this, result) } + + override int getOutputParameterIndex() { callsVariadicFormatterOutput(this, result) } } /** @@ -86,7 +117,7 @@ class UserDefinedFormattingFunction extends FormattingFunction { class FormattingFunctionCall extends Expr { FormattingFunctionCall() { this.(Call).getTarget() instanceof FormattingFunction } - override string getCanonicalQLClass() { result = "FormattingFunctionCall" } + override string getAPrimaryQlClass() { result = "FormattingFunctionCall" } /** * Gets the formatting function being called. @@ -567,12 +598,12 @@ class FormatLiteral extends Literal { or len = "l" and result = this.getLongType() or - (len = "ll" or len = "L" or len = "q") and + len = ["ll", "L", "q"] and result instanceof LongLongType or len = "j" and result = this.getIntmax_t() or - (len = "z" or len = "Z") and + len = ["z", "Z"] and (result = this.getSize_t() or result = this.getSsize_t()) or len = "t" and result = this.getPtrdiff_t() @@ -605,12 +636,12 @@ class FormatLiteral extends Literal { or len = "l" and result = this.getLongType() or - (len = "ll" or len = "L" or len = "q") and + len = ["ll", "L", "q"] and result instanceof LongLongType or len = "j" and result = this.getIntmax_t() or - (len = "z" or len = "Z") and + len = ["z", "Z"] and (result = this.getSize_t() or result = this.getSsize_t()) or len = "t" and result = this.getPtrdiff_t() @@ -636,9 +667,7 @@ class FormatLiteral extends Literal { FloatingPointType getFloatingPointConversion(int n) { exists(string len | len = this.getLength(n) and - if len = "L" or len = "ll" - then result instanceof LongDoubleType - else result instanceof DoubleType + if len = ["L", "ll"] then result instanceof LongDoubleType else result instanceof DoubleType ) } @@ -655,7 +684,7 @@ class FormatLiteral extends Literal { or len = "l" and base = this.getLongType() or - (len = "ll" or len = "L") and + len = ["ll", "L"] and base instanceof LongLongType or len = "q" and base instanceof LongLongType @@ -702,12 +731,12 @@ class FormatLiteral extends Literal { exists(string len, string conv | this.parseConvSpec(n, _, _, _, _, _, len, conv) and ( - (conv = "c" or conv = "C") and + conv = ["c", "C"] and len = "h" and result instanceof PlainCharType or - (conv = "c" or conv = "C") and - (len = "l" or len = "w") and + conv = ["c", "C"] and + len = ["l", "w"] and result = getWideCharType() or conv = "c" and @@ -747,12 +776,12 @@ class FormatLiteral extends Literal { exists(string len, string conv | this.parseConvSpec(n, _, _, _, _, _, len, conv) and ( - (conv = "s" or conv = "S") and + conv = ["s", "S"] and len = "h" and result.(PointerType).getBaseType() instanceof PlainCharType or - (conv = "s" or conv = "S") and - (len = "l" or len = "w") and + conv = ["s", "S"] and + len = ["l", "w"] and result.(PointerType).getBaseType() = getWideCharType() or conv = "s" and @@ -789,10 +818,7 @@ class FormatLiteral extends Literal { private Type getConversionType9(int n) { this.getConversionChar(n) = "Z" and - ( - this.getLength(n) = "l" or - this.getLength(n) = "w" - ) and + this.getLength(n) = ["l", "w"] and exists(Type t | t.getName() = "UNICODE_STRING" and result.(PointerType).getBaseType() = t @@ -945,10 +971,7 @@ class FormatLiteral extends Literal { len = (afterdot.maximum(1) + 6).maximum(1 + 1 + dot + afterdot + 1 + 1 + 3) ) // (e.g. "-1.59203e-319") or - ( - this.getConversionChar(n).toLowerCase() = "d" or - this.getConversionChar(n).toLowerCase() = "i" - ) and + this.getConversionChar(n).toLowerCase() = ["d", "i"] and // e.g. -2^31 = "-2147483648" exists(int sizeBits | sizeBits = diff --git a/cpp/ql/src/semmle/code/cpp/commons/Strcat.qll b/cpp/ql/src/semmle/code/cpp/commons/Strcat.qll index dce086bdd4ba..28408b82ffa6 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/Strcat.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/Strcat.qll @@ -8,14 +8,13 @@ import cpp */ class StrcatFunction extends Function { StrcatFunction() { - exists(string name | name = getName() | - name = "strcat" or // strcat(dst, src) - name = "strncat" or // strncat(dst, src, max_amount) - name = "wcscat" or // wcscat(dst, src) - name = "_mbscat" or // _mbscat(dst, src) - name = "wcsncat" or // wcsncat(dst, src, max_amount) - name = "_mbsncat" or // _mbsncat(dst, src, max_amount) - name = "_mbsncat_l" // _mbsncat_l(dst, src, max_amount, locale) - ) + getName() = + ["strcat", // strcat(dst, src) + "strncat", // strncat(dst, src, max_amount) + "wcscat", // wcscat(dst, src) + "_mbscat", // _mbscat(dst, src) + "wcsncat", // wcsncat(dst, src, max_amount) + "_mbsncat", // _mbsncat(dst, src, max_amount) + "_mbsncat_l"] // _mbsncat_l(dst, src, max_amount, locale) } } diff --git a/cpp/ql/src/semmle/code/cpp/commons/StringAnalysis.qll b/cpp/ql/src/semmle/code/cpp/commons/StringAnalysis.qll index 92c09a3e6667..b54ff6d66e30 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/StringAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/StringAnalysis.qll @@ -1,3 +1,7 @@ +/** + * Provides a class for calculating the possible length of string expressions. + */ + import semmle.code.cpp.exprs.Expr import semmle.code.cpp.controlflow.SSA diff --git a/cpp/ql/src/semmle/code/cpp/commons/Synchronization.qll b/cpp/ql/src/semmle/code/cpp/commons/Synchronization.qll index c680cfb073e8..c76413853939 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/Synchronization.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/Synchronization.qll @@ -23,8 +23,7 @@ abstract class MutexType extends Type { abstract predicate trylockAccess(FunctionCall fc, Expr arg); /** - * Holds if `fc` is a call that unlocks mutex `arg` - * of this type. + * Holds if `fc` is a call that unlocks mutex `arg` of this type. */ abstract predicate unlockAccess(FunctionCall fc, Expr arg); @@ -38,8 +37,7 @@ abstract class MutexType extends Type { } /** - * Holds if `fc` is a call that locks or tries to lock any - * mutex of this type. + * Gets a call that locks or tries to lock any mutex of this type. */ FunctionCall getLockAccess() { result = getMustlockAccess() or @@ -47,44 +45,44 @@ abstract class MutexType extends Type { } /** - * Holds if `fc` is a call that always locks any mutex of this type. + * Gets a call that always locks any mutex of this type. */ FunctionCall getMustlockAccess() { this.mustlockAccess(result, _) } /** - * Holds if `fc` is a call that tries to lock any mutex of this type, + * Gets a call that tries to lock any mutex of this type, * by may return without success. */ FunctionCall getTrylockAccess() { this.trylockAccess(result, _) } /** - * Holds if `fc` is a call that unlocks any mutex of this type. + * Gets a call that unlocks any mutex of this type. */ FunctionCall getUnlockAccess() { this.unlockAccess(result, _) } /** - * DEPRECATED: use mustlockAccess(fc, arg) instead + * DEPRECATED: use mustlockAccess(fc, arg) instead. */ deprecated Function getMustlockFunction() { result = getMustlockAccess().getTarget() } /** - * DEPRECATED: use trylockAccess(fc, arg) instead + * DEPRECATED: use trylockAccess(fc, arg) instead. */ deprecated Function getTrylockFunction() { result = getTrylockAccess().getTarget() } /** - * DEPRECATED: use lockAccess(fc, arg) instead + * DEPRECATED: use lockAccess(fc, arg) instead. */ deprecated Function getLockFunction() { result = getLockAccess().getTarget() } /** - * DEPRECATED: use unlockAccess(fc, arg) instead + * DEPRECATED: use unlockAccess(fc, arg) instead. */ deprecated Function getUnlockFunction() { result = getUnlockAccess().getTarget() } } /** - * A function that looks like a lock function. + * Gets a function that looks like a lock function. */ private Function mustlockCandidate() { exists(string name | name = result.getName() | @@ -94,7 +92,7 @@ private Function mustlockCandidate() { } /** - * A function that looks like a try-lock function. + * Gets a function that looks like a try-lock function. */ private Function trylockCandidate() { exists(string name | name = result.getName() | @@ -104,7 +102,7 @@ private Function trylockCandidate() { } /** - * A function that looks like an unlock function. + * Gets a function that looks like an unlock function. */ private Function unlockCandidate() { exists(string name | name = result.getName() | @@ -171,7 +169,10 @@ class DefaultMutexType extends MutexType { } } -/** Get the mutex argument of a call to lock or unlock. */ +/** + * Holds if `arg` is the mutex argument of a call to lock or unlock and + * `argType` is the type of the mutex. + */ private predicate lockArg(Expr arg, MutexType argType, FunctionCall call) { argType = arg.getUnderlyingType().stripType() and ( @@ -184,18 +185,31 @@ private predicate lockArg(Expr arg, MutexType argType, FunctionCall call) { // `MutexType.mustlockAccess`. } +/** + * Holds if `call` is a call that locks or tries to lock its argument `arg`. + */ predicate lockCall(Expr arg, FunctionCall call) { exists(MutexType t | lockArg(arg, t, call) and call = t.getLockAccess()) } +/** + * Holds if `call` is a call that always locks its argument `arg`. + */ predicate mustlockCall(Expr arg, FunctionCall call) { exists(MutexType t | lockArg(arg, t, call) and call = t.getMustlockAccess()) } +/** + * Holds if `call` is a call that tries to lock its argument `arg`, but may + * return without success. + */ predicate trylockCall(Expr arg, FunctionCall call) { exists(MutexType t | lockArg(arg, t, call) and call = t.getTrylockAccess()) } +/** + * Holds if `call` is a call that unlocks its argument `arg`. + */ predicate unlockCall(Expr arg, FunctionCall call) { exists(MutexType t | lockArg(arg, t, call) and call = t.getUnlockAccess()) } diff --git a/cpp/ql/src/semmle/code/cpp/commons/VoidContext.qll b/cpp/ql/src/semmle/code/cpp/commons/VoidContext.qll index 4b0b1299fd86..0a325442cf5a 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/VoidContext.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/VoidContext.qll @@ -25,7 +25,7 @@ private predicate exprInVoidContext(Expr e) { ( exists(ExprStmt s | s = e.getParent() and - not exists(StmtExpr se | s = se.getStmt().(Block).getLastStmt()) + not exists(StmtExpr se | s = se.getStmt().(BlockStmt).getLastStmt()) ) or exists(ConditionalExpr c | c.getThen() = e and c instanceof ExprInVoidContext) diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll b/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll index 1f79d6c5bc20..bac051f64746 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll @@ -65,7 +65,7 @@ class ControlFlowNode extends Locatable, ControlFlowNodeBase { * taken when this expression is true. */ ControlFlowNode getATrueSuccessor() { - truecond_base(this, result) and + qlCFGTrueSuccessor(this, result) and result = getASuccessor() } @@ -74,7 +74,7 @@ class ControlFlowNode extends Locatable, ControlFlowNodeBase { * taken when this expression is false. */ ControlFlowNode getAFalseSuccessor() { - falsecond_base(this, result) and + qlCFGFalseSuccessor(this, result) and result = getASuccessor() } @@ -95,18 +95,20 @@ import ControlFlowGraphPublic class ControlFlowNodeBase extends ElementBase, @cfgnode { } /** + * DEPRECATED: Use `ControlFlowNode.getATrueSuccessor()` instead. * Holds when `n2` is a control-flow node such that the control-flow * edge `(n1, n2)` may be taken when `n1` is an expression that is true. */ -predicate truecond_base(ControlFlowNodeBase n1, ControlFlowNodeBase n2) { +deprecated predicate truecond_base(ControlFlowNodeBase n1, ControlFlowNodeBase n2) { qlCFGTrueSuccessor(n1, n2) } /** + * DEPRECATED: Use `ControlFlowNode.getAFalseSuccessor()` instead. * Holds when `n2` is a control-flow node such that the control-flow * edge `(n1, n2)` may be taken when `n1` is an expression that is false. */ -predicate falsecond_base(ControlFlowNodeBase n1, ControlFlowNodeBase n2) { +deprecated predicate falsecond_base(ControlFlowNodeBase n1, ControlFlowNodeBase n2) { qlCFGFalseSuccessor(n1, n2) } @@ -134,7 +136,7 @@ abstract class AdditionalControlFlowEdge extends ControlFlowNodeBase { /** * Holds if there is a control-flow edge from `source` to `target` in either * the extractor-generated control-flow graph or in a subclass of - * `AdditionalControlFlowEdge`. Use this relation instead of `successors`. + * `AdditionalControlFlowEdge`. Use this relation instead of `qlCFGSuccessor`. */ predicate successors_extended(ControlFlowNodeBase source, ControlFlowNodeBase target) { qlCFGSuccessor(source, target) diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll b/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll index 75211c631feb..656496325af2 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll @@ -13,6 +13,7 @@ import semmle.code.cpp.ir.IR * has the AST for the `Function` itself, which tends to confuse mapping between the AST `BasicBlock` * and the `IRBlock`. */ +pragma[noinline] private predicate isUnreachedBlock(IRBlock block) { block.getFirstInstruction() instanceof UnreachedInstruction } @@ -304,13 +305,13 @@ class IRGuardCondition extends Instruction { pred.getASuccessor() = succ and controls(pred, testIsTrue) or - hasBranchEdge(succ, testIsTrue) and + succ = getBranchSuccessor(testIsTrue) and branch.getCondition() = this and branch.getBlock() = pred } /** - * Holds if `branch` jumps directly to `succ` when this condition is `testIsTrue`. + * Gets the block to which `branch` jumps directly when this condition is `testIsTrue`. * * This predicate is intended to help with situations in which an inference can only be made * based on an edge between a block with multiple successors and a block with multiple @@ -324,14 +325,14 @@ class IRGuardCondition extends Instruction { * return x; * ``` */ - private predicate hasBranchEdge(IRBlock succ, boolean testIsTrue) { + private IRBlock getBranchSuccessor(boolean testIsTrue) { branch.getCondition() = this and ( testIsTrue = true and - succ.getFirstInstruction() = branch.getTrueSuccessor() + result.getFirstInstruction() = branch.getTrueSuccessor() or testIsTrue = false and - succ.getFirstInstruction() = branch.getFalseSuccessor() + result.getFirstInstruction() = branch.getFalseSuccessor() ) } @@ -405,20 +406,78 @@ class IRGuardCondition extends Instruction { */ private predicate controlsBlock(IRBlock controlled, boolean testIsTrue) { not isUnreachedBlock(controlled) and - exists(IRBlock branchBlock | branchBlock.getAnInstruction() = branch | - exists(IRBlock succ | - testIsTrue = true and succ.getFirstInstruction() = branch.getTrueSuccessor() + // + // For this block to control the block `controlled` with `testIsTrue` the + // following must hold: Execution must have passed through the test; that + // is, `this` must strictly dominate `controlled`. Execution must have + // passed through the `testIsTrue` edge leaving `this`. + // + // Although "passed through the true edge" implies that + // `getBranchSuccessor(true)` dominates `controlled`, the reverse is not + // true, as flow may have passed through another edge to get to + // `getBranchSuccessor(true)`, so we need to assert that + // `getBranchSuccessor(true)` dominates `controlled` *and* that all + // predecessors of `getBranchSuccessor(true)` are either `this` or + // dominated by `getBranchSuccessor(true)`. + // + // For example, in the following snippet: + // + // if (x) + // controlled; + // false_successor; + // uncontrolled; + // + // `false_successor` dominates `uncontrolled`, but not all of its + // predecessors are `this` (`if (x)`) or dominated by itself. Whereas in + // the following code: + // + // if (x) + // while (controlled) + // also_controlled; + // false_successor; + // uncontrolled; + // + // the block `while (controlled)` is controlled because all of its + // predecessors are `this` (`if (x)`) or (in the case of `also_controlled`) + // dominated by itself. + // + // The additional constraint on the predecessors of the test successor implies + // that `this` strictly dominates `controlled` so that isn't necessary to check + // directly. + exists(IRBlock succ | + succ = this.getBranchSuccessor(testIsTrue) and + this.hasDominatingEdgeTo(succ) and + succ.dominates(controlled) + ) + } + + /** + * Holds if `(this, succ)` is an edge that dominates `succ`, that is, all other + * predecessors of `succ` are dominated by `succ`. This implies that `this` is the + * immediate dominator of `succ`. + * + * This is a necessary and sufficient condition for an edge to dominate anything, + * and in particular `bb1.hasDominatingEdgeTo(bb2) and bb2.dominates(bb3)` means + * that the edge `(bb1, bb2)` dominates `bb3`. + */ + private predicate hasDominatingEdgeTo(IRBlock succ) { + exists(IRBlock branchBlock | branchBlock = this.getBranchBlock() | + branchBlock.immediatelyDominates(succ) and + branchBlock.getASuccessor() = succ and + forall(IRBlock pred | pred = succ.getAPredecessor() and pred != branchBlock | + succ.dominates(pred) or - testIsTrue = false and succ.getFirstInstruction() = branch.getFalseSuccessor() - | - branch.getCondition() = this and - succ.dominates(controlled) and - forall(IRBlock pred | pred.getASuccessor() = succ | - pred = branchBlock or succ.dominates(pred) or not pred.isReachableFromFunctionEntry() - ) + // An unreachable `pred` is vacuously dominated by `succ` since all + // paths from the entry to `pred` go through `succ`. Such vacuous + // dominance is not included in the `dominates` predicate since that + // could cause quadratic blow-up. + not pred.isReachableFromFunctionEntry() ) ) } + + pragma[noinline] + private IRBlock getBranchBlock() { result = branch.getBlock() } } private ConditionalBranchInstruction get_branch_for_condition(Instruction guard) { diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/SSAUtils.qll b/cpp/ql/src/semmle/code/cpp/controlflow/SSAUtils.qll index 3ae1ed11e6d9..caae23c3bbd9 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/SSAUtils.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/SSAUtils.qll @@ -73,8 +73,20 @@ private predicate addressTakenVariable(StackVariable var) { ) } +/** + * Holds if `v` is a stack-allocated reference-typed local variable. We don't + * build SSA for such variables since they are likely to change values even + * when not syntactically mentioned. For the same reason, + * `addressTakenVariable` is used to prevent tracking variables that may be + * aliased by such a reference. + * + * Reference-typed parameters are treated as if they weren't references. + * That's because it's in practice highly unlikely that they alias other data + * accessible from the function body. + */ private predicate isReferenceVar(StackVariable v) { - v.getUnspecifiedType() instanceof ReferenceType + v.getUnspecifiedType() instanceof ReferenceType and + not v instanceof Parameter } /** diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/internal/CFG.qll b/cpp/ql/src/semmle/code/cpp/controlflow/internal/CFG.qll index b2cfc903a662..b47618de2e92 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/internal/CFG.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/internal/CFG.qll @@ -118,7 +118,7 @@ private predicate excludeNodeAndNodesBelow(Expr e) { or // Constructor init lists should be evaluated, and we can change this in // the future, but it would mean that a `Function` entry point is not - // always a `Block` or `FunctionTryStmt`. + // always a `BlockStmt` or `FunctionTryStmt`. e instanceof ConstructorInit or // Destructor field destructions should also be hooked into the CFG @@ -408,10 +408,10 @@ private Node getControlOrderChildSparse(Node n, int i) { // in-line in the block containing their corresponding DeclStmt but should // not be evaluated in the order implied by their position in the block. We // do the following. - // - Block skips all the VlaDeclStmt and VlaDimensionStmt children. + // - BlockStmt skips all the VlaDeclStmt and VlaDimensionStmt children. // - VlaDeclStmt is inserted as a child of DeclStmt // - VlaDimensionStmt is inserted as a child of VlaDeclStmt - result = n.(Block).getChild(i) and + result = n.(BlockStmt).getChild(i) and not result instanceof VlaDeclStmt and not result instanceof VlaDimensionStmt or @@ -557,7 +557,7 @@ private class Spec extends Pos { */ private predicate straightLineSparse(Node scope, int i, Node ni, Spec spec) { scope = - any(Block b | + any(BlockStmt b | i = -1 and ni = b and spec.isAt() or if exists(getLastControlOrderChild(b)) @@ -734,7 +734,7 @@ private predicate straightLineSparse(Node scope, int i, Node ni, Spec spec) { 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().(Block) and spec.isAt() + i = 1 and ni = s.getStmt().(BlockStmt) and spec.isAt() or i = 2 and ni = s.getASwitchCase() and spec.isBefore() or @@ -1010,7 +1010,7 @@ private predicate subEdgeIncludingDestructors(Pos p1, Node n1, Node n2, Pos p2) * The exact placement of that call in the CFG depends on the type of * `node` as follows: * - * - `Block`: after ordinary control flow falls off the end of the block + * - `BlockStmt`: after ordinary control flow falls off the end of the block * without jumps or exceptions. * - `ReturnStmt`: After the statement itself or after its operand (if * present). @@ -1376,8 +1376,6 @@ private module Cached { /** * Holds if `n2` is a successor of `n1` in the CFG. This includes also * true-successors and false-successors. - * - * This corresponds to the old `successors` dbscheme relation. */ cached predicate qlCFGSuccessor(Node n1, Node n2) { @@ -1390,9 +1388,8 @@ private module Cached { } /** - * Holds if `n2` is a true-successor of `n1` in the CFG. - * - * This corresponds to the old `truecond` dbscheme relation. + * Holds if `n2` is a control-flow node such that the control-flow + * edge `(n1, n2)` may be taken when `n1` is an expression that is true. */ cached predicate qlCFGTrueSuccessor(Node n1, Node n2) { @@ -1401,9 +1398,8 @@ private module Cached { } /** - * Holds if `n2` is a false-successor of `n1` in the CFG. - * - * This corresponds to the old `falsecond` dbscheme relation. + * Holds if `n2` is a control-flow node such that the control-flow + * edge `(n1, n2)` may be taken when `n1` is an expression that is false. */ cached predicate qlCFGFalseSuccessor(Node n1, Node n2) { diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/internal/ConstantExprs.qll b/cpp/ql/src/semmle/code/cpp/controlflow/internal/ConstantExprs.qll index c473f1560882..77e0f05ed020 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/internal/ConstantExprs.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/internal/ConstantExprs.qll @@ -1,5 +1,6 @@ import cpp private import PrimitiveBasicBlocks +private import semmle.code.cpp.controlflow.internal.CFG private class Node = ControlFlowNodeBase; @@ -153,8 +154,8 @@ private predicate nonAnalyzableFunction(Function f) { */ private predicate impossibleFalseEdge(Expr condition, Node succ) { conditionAlwaysTrue(condition) and - falsecond_base(condition, succ) and - not truecond_base(condition, succ) + qlCFGFalseSuccessor(condition, succ) and + not qlCFGTrueSuccessor(condition, succ) } /** @@ -162,8 +163,8 @@ private predicate impossibleFalseEdge(Expr condition, Node succ) { */ private predicate impossibleTrueEdge(Expr condition, Node succ) { conditionAlwaysFalse(condition) and - truecond_base(condition, succ) and - not falsecond_base(condition, succ) + qlCFGTrueSuccessor(condition, succ) and + not qlCFGFalseSuccessor(condition, succ) } /** @@ -181,7 +182,7 @@ private int switchCaseRangeEnd(SwitchCase sc) { * body `switchBlock`. There may be several such expressions: for example, if * the condition is `(x ? y : z)` then the result is {`y`, `z`}. */ -private Node getASwitchExpr(SwitchStmt switch, Block switchBlock) { +private Node getASwitchExpr(SwitchStmt switch, BlockStmt switchBlock) { switch.getStmt() = switchBlock and successors_extended(result, switchBlock) } @@ -191,7 +192,7 @@ private Node getASwitchExpr(SwitchStmt switch, Block switchBlock) { * from `switchBlock` to `sc` is impossible. This considers only non-`default` * switch cases. */ -private predicate impossibleSwitchEdge(Block switchBlock, SwitchCase sc) { +private predicate impossibleSwitchEdge(BlockStmt switchBlock, SwitchCase sc) { not sc instanceof DefaultCase and exists(SwitchStmt switch | switch = sc.getSwitchStmt() and @@ -214,7 +215,7 @@ private predicate impossibleSwitchEdge(Block switchBlock, SwitchCase sc) { * If a switch provably always chooses a non-default case, then the edge to * the default case is impossible. */ -private predicate impossibleDefaultSwitchEdge(Block switchBlock, DefaultCase dc) { +private predicate impossibleDefaultSwitchEdge(BlockStmt switchBlock, DefaultCase dc) { exists(SwitchStmt switch | switch = dc.getSwitchStmt() and switch.getStmt() = switchBlock and @@ -278,20 +279,62 @@ private predicate reachableRecursive(ControlFlowNode n) { reachableRecursive(n.getAPredecessor()) } +/** Holds if `e` is a compile time constant with integer value `val`. */ private predicate compileTimeConstantInt(Expr e, int val) { - val = e.getFullyConverted().getValue().toInt() and - not e instanceof StringLiteral and - not exists(Expr e1 | e1.getConversion() = e) // only values for fully converted expressions + ( + // If we have an integer value then we are done. + if exists(e.getValue().toInt()) + then val = e.getValue().toInt() + else + // Otherwise, if we are a conversion of another expression with an + // integer value, and that value can be converted into our type, + // then we have that value. + exists(Expr x, int valx | + x.getConversion() = e and + compileTimeConstantInt(x, valx) and + val = convertIntToType(valx, e.getType().getUnspecifiedType()) + ) + ) and + // If our unconverted expression is a string literal `"123"`, then we + // do not have integer value `123`. + not e.getUnconverted() instanceof StringLiteral } -library class CompileTimeConstantInt extends Expr { - CompileTimeConstantInt() { compileTimeConstantInt(this, _) } +/** + * Get `val` represented as type `t`, if that is possible without + * overflow or underflows. + */ +bindingset[val, t] +private int convertIntToType(int val, IntegralType t) { + if t instanceof BoolType + then if val = 0 then result = 0 else result = 1 + else + if t.isUnsigned() + then if val >= 0 and val.bitShiftRight(t.getSize() * 8) = 0 then result = val else none() + else + if val >= 0 and val.bitShiftRight(t.getSize() * 8 - 1) = 0 + then result = val + else + if (-(val + 1)).bitShiftRight(t.getSize() * 8 - 1) = 0 + then result = val + else none() +} + +/** + * INTERNAL: Do not use. + * An expression that has been found to have an integer value at compile + * time. + */ +class CompileTimeConstantInt extends Expr { + int val; + + CompileTimeConstantInt() { compileTimeConstantInt(this.getFullyConverted(), val) } - int getIntValue() { compileTimeConstantInt(this, result) } + int getIntValue() { result = val } } library class CompileTimeVariableExpr extends Expr { - CompileTimeVariableExpr() { not compileTimeConstantInt(this, _) } + CompileTimeVariableExpr() { not this instanceof CompileTimeConstantInt } } /** A helper class for evaluation of expressions. */ @@ -863,9 +906,9 @@ library class ConditionEvaluator extends ExprEvaluator { ConditionEvaluator() { this = 0 } override predicate interesting(Expr e) { - falsecond_base(e, _) + qlCFGFalseSuccessor(e, _) or - truecond_base(e, _) + qlCFGTrueSuccessor(e, _) } } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll index b3f8cd02828b..f9677a0654b7 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll @@ -29,7 +29,7 @@ private predicate stdIdentityFunction(Function f) { f.hasQualifiedName("std", [" */ private predicate stdAddressOf(Function f) { f.hasQualifiedName("std", "addressof") } -private predicate lvalueToLvalueStep(Expr lvalueIn, Expr lvalueOut) { +private predicate lvalueToLvalueStepPure(Expr lvalueIn, Expr lvalueOut) { lvalueIn.getConversion() = lvalueOut.(ParenthesisExpr) or // When an object is implicitly converted to a reference to one of its base @@ -42,6 +42,10 @@ private predicate lvalueToLvalueStep(Expr lvalueIn, Expr lvalueOut) { // such casts. lvalueIn.getConversion() = lvalueOut and lvalueOut.(CStyleCast).isImplicit() +} + +private predicate lvalueToLvalueStep(Expr lvalueIn, Expr lvalueOut) { + lvalueToLvalueStepPure(lvalueIn, lvalueOut) or // C++ only lvalueIn = lvalueOut.(PrefixCrementOperation).getOperand().getFullyConverted() @@ -214,6 +218,69 @@ private predicate referenceToUpdate(Expr reference, Expr outer, ControlFlowNode ) } +private predicate lvalueFromVariableAccess(VariableAccess va, Expr lvalue) { + // Base case for non-reference types. + lvalue = va and + not va.getConversion() instanceof ReferenceDereferenceExpr + or + // Base case for reference types where we pretend that they are + // non-reference types. The type of the target of `va` can be `ReferenceType` + // or `FunctionReferenceType`. + lvalue = va.getConversion().(ReferenceDereferenceExpr) + or + // lvalue -> lvalue + exists(Expr prev | + lvalueFromVariableAccess(va, prev) and + lvalueToLvalueStep(prev, lvalue) + ) + or + // pointer -> lvalue + exists(Expr prev | + pointerFromVariableAccess(va, prev) and + pointerToLvalueStep(prev, lvalue) + ) + or + // reference -> lvalue + exists(Expr prev | + referenceFromVariableAccess(va, prev) and + referenceToLvalueStep(prev, lvalue) + ) +} + +private predicate pointerFromVariableAccess(VariableAccess va, Expr pointer) { + // pointer -> pointer + exists(Expr prev | + pointerFromVariableAccess(va, prev) and + pointerToPointerStep(prev, pointer) + ) + or + // reference -> pointer + exists(Expr prev | + referenceFromVariableAccess(va, prev) and + referenceToPointerStep(prev, pointer) + ) + or + // lvalue -> pointer + exists(Expr prev | + lvalueFromVariableAccess(va, prev) and + lvalueToPointerStep(prev, pointer) + ) +} + +private predicate referenceFromVariableAccess(VariableAccess va, Expr reference) { + // reference -> reference + exists(Expr prev | + referenceFromVariableAccess(va, prev) and + referenceToReferenceStep(prev, reference) + ) + or + // lvalue -> reference + exists(Expr prev | + lvalueFromVariableAccess(va, prev) and + lvalueToReferenceStep(prev, reference) + ) +} + /** * Holds if `node` is a control-flow node that may modify `inner` (or what it * points to) through `outer`. The two expressions may be `Conversion`s. Plain @@ -236,7 +303,7 @@ predicate valueToUpdate(Expr inner, Expr outer, ControlFlowNode node) { ( inner instanceof VariableAccess and // Don't track non-field assignments - (assignmentTo(outer, _) implies inner instanceof FieldAccess) + not (assignmentTo(outer, _) and outer.(VariableAccess).getTarget() instanceof StackVariable) or inner instanceof ThisExpr or @@ -245,3 +312,27 @@ predicate valueToUpdate(Expr inner, Expr outer, ControlFlowNode node) { // can't do anything useful with those at the moment. ) } + +/** + * Holds if `e` is a fully-converted expression that evaluates to an lvalue + * derived from `va` and is used for reading from or assigning to. This is in + * contrast with a variable access that is used for taking an address (`&x`) + * or simply discarding its value (`x;`). + * + * This analysis does not propagate across assignments or calls, and unlike + * `variableAccessedAsValue` in `semmle.code.cpp.dataflow.EscapesTree` it + * propagates through array accesses but not field accesses. The analysis is + * also not concerned with whether the lvalue `e` is converted to an rvalue -- + * to examine that, use the relevant member predicates on `Expr`. + * + * If `va` has reference type, the analysis concerns the value pointed to by + * the reference rather than the reference itself. The expression `e` may be a + * `Conversion`. + */ +predicate variablePartiallyAccessed(VariableAccess va, Expr e) { + lvalueFromVariableAccess(va, e) and + not lvalueToLvalueStepPure(e, _) and + not lvalueToPointerStep(e, _) and + not lvalueToReferenceStep(e, _) and + not e = any(ExprInVoidContext eivc | e = eivc.getConversion*()) +} diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowDispatch.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowDispatch.qll index 154430794d4a..e57af3b8d317 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowDispatch.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowDispatch.qll @@ -53,26 +53,13 @@ private predicate functionSignature(Function f, string qualifiedName, int nparam } /** - * Holds if the call context `ctx` reduces the set of viable dispatch - * targets of `ma` in `c`. + * Holds if the set of viable implementations that can be called by `call` + * might be improved by knowing the call context. */ -predicate reducedViableImplInCallContext(Call call, Function f, Call ctx) { none() } +predicate mayBenefitFromCallContext(Call call, Function f) { none() } /** - * Gets a viable dispatch target of `ma` in the context `ctx`. This is - * restricted to those `ma`s for which the context makes a difference. + * Gets a viable dispatch target of `call` in the context `ctx`. This is + * restricted to those `call`s for which a context might make a difference. */ -Function prunedViableImplInCallContext(Call call, Call ctx) { none() } - -/** - * Holds if flow returning from `m` to `ma` might return further and if - * this path restricts the set of call sites that can be returned to. - */ -predicate reducedViableImplInReturn(Function f, Call call) { none() } - -/** - * Gets a viable dispatch target of `ma` in the context `ctx`. This is - * restricted to those `ma`s and results for which the return flow from the - * result to `ma` restricts the possible context `ctx`. - */ -Function prunedViableImplInCallContextReverse(Call call, Call ctx) { none() } +Function viableImplInCallContext(Call call, Call ctx) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index f876c04d6c66..8bc3d75ff86e 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -286,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -318,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -417,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -447,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -566,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -748,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -781,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -896,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -930,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1046,11 +1051,22 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1058,9 +1074,9 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1074,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1108,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1122,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1154,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1183,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1197,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1223,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1261,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } +pragma[nomagic] +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + pragma[nomagic] private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1385,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1417,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1497,24 +1523,24 @@ private predicate flowCandIsReturned( ) } -private newtype TAccessPath = +private newtype TAccessPathApprox = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two - * elements of the list and its length are tracked. If data flows from a source to - * a given node with a given `AccessPath`, this indicates the sequence 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. + * Conceptually a list of `TypedContent`s followed by a `DataFlowType`, but only + * the first two elements of the list and its length are tracked. If data flows + * from a source to a given node with a given `AccessPathApprox`, this indicates + * the sequence 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 { +abstract private class AccessPathApprox extends TAccessPathApprox { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1522,20 +1548,18 @@ abstract private class AccessPath extends TAccessPath { abstract AccessPathFront getFront(); - /** - * Holds if this access path has `head` at the front and may be followed by `tail`. - */ - abstract predicate pop(Content head, AccessPath tail); + /** Gets the access path obtained by popping `head` from this path, if any. */ + abstract AccessPathApprox pop(TypedContent head); } -private class AccessPathNil extends AccessPath, TNil { +private class AccessPathApproxNil extends AccessPathApprox, TNil { private DataFlowType t; - AccessPathNil() { this = TNil(t) } + AccessPathApproxNil() { this = TNil(t) } override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1543,258 +1567,285 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override AccessPathApprox pop(TypedContent head) { none() } } -abstract private class AccessPathCons extends AccessPath { } +abstract private class AccessPathApproxCons extends AccessPathApprox { } -private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; +private class AccessPathApproxConsNil extends AccessPathApproxCons, TConsNil { + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathApproxConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override AccessPathApprox pop(TypedContent head) { head = tc and result = TNil(t) } } -private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; +private class AccessPathApproxConsCons extends AccessPathApproxCons, TConsCons { + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathApproxConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override AccessPathApprox pop(TypedContent head) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + result = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + result = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPathApprox pop(TypedContent tc, AccessPathApprox apa) { result = apa.pop(tc) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPathApprox push(TypedContent tc, AccessPathApprox apa) { apa = pop(tc, result) } -private newtype TAccessPathOption = - TAccessPathNone() or - TAccessPathSome(AccessPath ap) +private newtype TAccessPathApproxOption = + TAccessPathApproxNone() or + TAccessPathApproxSome(AccessPathApprox apa) -private class AccessPathOption extends TAccessPathOption { +private class AccessPathApproxOption extends TAccessPathApproxOption { string toString() { - this = TAccessPathNone() and result = "" + this = TAccessPathApproxNone() and result = "" or - this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + this = TAccessPathApproxSome(any(AccessPathApprox apa | result = apa.toString())) } } /** - * Holds if `node` is reachable with access path `ap` from a source in - * the configuration `config`. + * Holds if `node` is reachable with approximate access path `apa` from a source + * in the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an - * argument in a call, and if so, `argAp` records the access path of that - * argument. + * The call context `cc` records whether the node is reached through an + * argument in a call, and if so, `argApa` records the approximate access path + * of that argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argApa, apf, apa, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, apf, apa, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and - apf = ap.(AccessPathNil).getFront() + exists(Node mid, AccessPathApproxNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and + apf = apa.(AccessPathApproxNil).getFront() ) or exists(Node mid | - flowFwd(mid, _, _, apf, ap, config) and + flowFwd(mid, _, _, apf, apa, config) and jumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | + exists(Node mid, AccessPathApproxNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, apa), apf, cc, argApa, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, apa), apf, cc, argApa, config) and + flowFwdConsCand(tc, apf, apa, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, _, cc, _, apf, apa, config) and if flowCand(node, true, _, apf, config) - then argAp = TAccessPathSome(ap) - else argAp = TAccessPathNone() + then argApa = TAccessPathApproxSome(apa) + else argApa = TAccessPathApproxNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argApa, apf, apa, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or - exists(AccessPath argAp0 | - flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + exists(AccessPathApprox argApa0 | + flowFwdOutFromArg(call, node, argApa0, apf, apa, config) and + flowFwdIsEntered(call, cc, argApa, argApa0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argApa, apf, apa, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - AccessPathOption argAp, Configuration config + Node node, TypedContent tc, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwd(mid, cc, argApa, apf0, apa0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPathApprox apa0, Node node2, + CallContext cc, AccessPathApproxOption argApa, Configuration config +) { + flowFwd(node1, cc, argApa, apf0, apa0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + pragma[nomagic] private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config + Node node, AccessPathFrontHead apf0, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, apa0, node, cc, argApa, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(Node n | - flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwd(n, _, _, apf, apa, config) and + flowFwdStore0(n, tc, _, apf, _, config) ) } pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argApa, apf, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argApa, apf, apa, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOutFromArg( - DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + DataFlowCall call, Node node, AccessPathApprox argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathApproxSome(argApa), apf, apa, + config) } /** @@ -1802,166 +1853,174 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathApproxOption argApa, AccessPathApprox apa, + Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argApa, apf, apa, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if `node` with access path `ap` is part of a path from a source to - * a sink in the configuration `config`. + * Holds if `node` with approximate access path `apa` is part of a path from a + * source to a sink in the configuration `config`. * * The Boolean `toReturn` records whether the node must be returned from - * the enclosing callable in order to reach a sink, and if so, `returnAp` - * records the access path of the returned value. + * the enclosing callable in order to reach a sink, and if so, `returnApa` + * records the approximate access path of the returned value. */ private predicate flow( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flow0(node, toReturn, returnAp, ap, config) and - flowFwd(node, _, _, _, ap, config) + flow0(node, toReturn, returnApa, apa, config) and + flowFwd(node, _, _, _, apa, config) } private predicate flow0( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flowFwd(node, _, _, _, ap, config) and + flowFwd(node, _, _, _, apa, config) and config.isSink(node) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil or exists(Node mid | localFlowBigStep(node, mid, true, _, config, _) and - flow(mid, toReturn, returnAp, ap, config) + flow(mid, toReturn, returnApa, apa, config) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and localFlowBigStep(node, mid, false, _, config, _) and - flow(mid, toReturn, returnAp, nil, config) and - ap instanceof AccessPathNil + flow(mid, toReturn, returnApa, nil, config) and + apa instanceof AccessPathApproxNil ) or exists(Node mid | jumpStep(node, mid, config) and - flow(mid, _, _, ap, config) and + flow(mid, _, _, apa, config) and toReturn = false and - returnAp = TAccessPathNone() + returnApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and additionalJumpStep(node, mid, config) and flow(mid, _, _, nil, config) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnApa, apa, config) and + flowConsCand(tc, apa, config) ) or // read - exists(Node mid, AccessPath ap0 | - readFlowFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + readFlowFwd(node, _, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) or // flow into a callable exists(DataFlowCall call | - flowIn(call, node, toReturn, returnAp, ap, config) and + flowIn(call, node, toReturn, returnApa, apa, config) and toReturn = false or - exists(AccessPath returnAp0 | - flowInToReturn(call, node, returnAp0, ap, config) and - flowIsReturned(call, toReturn, returnAp, returnAp0, config) + exists(AccessPathApprox returnApa0 | + flowInToReturn(call, node, returnApa0, apa, config) and + flowIsReturned(call, toReturn, returnApa, returnApa0, config) ) ) or // flow out of a callable - flowOut(_, node, _, _, ap, config) and + flowOut(_, node, _, _, apa, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) - then returnAp = TAccessPathSome(ap) - else returnAp = TAccessPathNone() + if flowFwd(node, any(CallContextCall ccc), TAccessPathApproxSome(_), _, apa, config) + then returnApa = TAccessPathApproxSome(apa) + else returnApa = TAccessPathApproxNone() } pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, apa, _, _, _, config) and + apa0 = push(tc, apa) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { - exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + storeFlowFwd(node, tc, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, apa, _, _, _, config) and + apa0 = pop(tc, apa) and + flowFwdConsCand(tc, _, apa0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPathApprox apa, Configuration config) { exists(Node n, Node mid | - flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + flow(mid, _, _, apa, config) and + readFlowFwd(n, tc, mid, _, apa, config) ) } pragma[nomagic] private predicate flowOut( - DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(Node out, boolean allowsFieldFlow | - flow(out, toReturn, returnAp, ap, config) and + flow(out, toReturn, returnApa, apa, config) and flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowIn( - DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(ParameterNode p, boolean allowsFieldFlow | - flow(p, toReturn, returnAp, ap, config) and + flow(p, toReturn, returnApa, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowInToReturn( - DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config + DataFlowCall call, ArgumentNode arg, AccessPathApprox returnApa, AccessPathApprox apa, + Configuration config ) { - flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) + flowIn(call, arg, true, TAccessPathApproxSome(returnApa), apa, config) } /** @@ -1969,12 +2028,13 @@ private predicate flowInToReturn( */ pragma[nomagic] private predicate flowIsReturned( - DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + DataFlowCall call, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, Configuration config ) { - exists(ReturnNodeExt ret | - flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + exists(ReturnNodeExt ret, CallContextCall ccc | + flowOut(call, ret, toReturn, returnApa, apa, config) and + flowFwd(ret, ccc, TAccessPathApproxSome(_), _, apa, config) and + ccc.matchesCall(call) ) } @@ -1985,21 +2045,23 @@ private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) pragma[noinline] private predicate parameterFlow( - ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config + ParameterNode p, AccessPathApprox apa, DataFlowCallable c, Configuration config ) { - flow(p, true, _, ap, config) and + flow(p, true, _, apa, config) and c = p.getEnclosingCallable() } +private predicate parameterMayFlowThrough(ParameterNode p, AccessPathApprox apa) { + exists(ReturnNodeExt ret, Configuration config, AccessPathApprox apa0 | + parameterFlow(p, apa, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathApproxSome(_), apa0, config) and + flowFwd(ret, any(CallContextCall ccc), TAccessPathApproxSome(apa), _, apa0, config) + ) +} + private newtype TSummaryCtx = TSummaryCtxNone() or - TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | - parameterFlow(p, ap, ret.getEnclosingCallable(), config) and - flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) - ) - } + TSummaryCtxSome(ParameterNode p, AccessPath ap) { parameterMayFlowThrough(p, ap.getApprox()) } /** * A context for generating flow summaries. This represents flow entry through @@ -2034,6 +2096,10 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { } } +private newtype TAccessPath = + TAccessPathNil(DataFlowType t) or + TAccessPathCons(TypedContent head, AccessPath tail) { flowConsCand(head, tail.getApprox(), _) } + private newtype TPathNode = TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) { // A PathNode is introduced by a source ... @@ -2041,13 +2107,13 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(node, _, _, ap, unbind(config)) + flow(node, _, _, ap.getApprox(), unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2059,12 +2125,99 @@ private newtype TPathNode = or // ... or a sink that can be reached from a source exists(PathNodeMid mid | - pathStep(mid, node, _, _, any(AccessPathNil nil)) and + pathStep(mid, node, _, _, TAccessPathNil(_)) and config = unbind(mid.getConfiguration()) ) ) } +/** + * A list of `TypedContent`s followed by a `DataFlowType`. If data flows from a + * source to a given node with a given `AccessPath`, this indicates the sequence + * 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 { + /** Gets the head of this access path, if any. */ + abstract TypedContent getHead(); + + /** Gets the tail of this access path, if any. */ + abstract AccessPath getTail(); + + /** Gets the front of this access path. */ + abstract AccessPathFront getFront(); + + /** Gets the approximation of this access path. */ + abstract AccessPathApprox getApprox(); + + /** Gets the length of this access path. */ + abstract int length(); + + /** Gets a textual representation of this access path. */ + abstract string toString(); + + /** Gets the access path obtained by popping `tc` from this access path, if any. */ + final AccessPath pop(TypedContent tc) { + result = this.getTail() and + tc = this.getHead() + } + + /** Gets the access path obtained by pushing `tc` onto this access path. */ + final AccessPath push(TypedContent tc) { this = result.pop(tc) } +} + +private class AccessPathNil extends AccessPath, TAccessPathNil { + private DataFlowType t; + + AccessPathNil() { this = TAccessPathNil(t) } + + DataFlowType getType() { result = t } + + override TypedContent getHead() { none() } + + override AccessPath getTail() { none() } + + override AccessPathFrontNil getFront() { result = TFrontNil(t) } + + override AccessPathApproxNil getApprox() { result = TNil(t) } + + override int length() { result = 0 } + + override string toString() { result = concat(": " + ppReprType(t)) } +} + +private class AccessPathCons extends AccessPath, TAccessPathCons { + private TypedContent head; + private AccessPath tail; + + AccessPathCons() { this = TAccessPathCons(head, tail) } + + override TypedContent getHead() { result = head } + + override AccessPath getTail() { result = tail } + + override AccessPathFrontHead getFront() { result = TFrontHead(head) } + + override AccessPathApproxCons getApprox() { + result = TConsNil(head, tail.(AccessPathNil).getType()) + or + result = TConsCons(head, tail.getHead(), this.length()) + } + + override int length() { result = 1 + tail.length() } + + private string toStringImpl() { + exists(DataFlowType t | + tail = TAccessPathNil(t) and + result = head.toString() + "]" + concat(" : " + ppReprType(t)) + ) + or + result = head + ", " + tail.(AccessPathCons).toStringImpl() + } + + override string toString() { result = "[" + this.toStringImpl() } +} + /** * A `Node` augmented with a call context (except for sinks), an access path, and a configuration. * Only those `PathNode`s that are reachable from a source are generated. @@ -2098,14 +2251,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2350,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2387,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2251,12 +2421,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2267,50 +2437,53 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } private predicate pathOutOfCallable0( - PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPath ap, Configuration config + PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa, + Configuration config ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and - ap = mid.getAp() and + innercc instanceof CallContextNoCall and + apa = mid.getAp().getApprox() and config = mid.getConfiguration() } pragma[nomagic] private predicate pathOutOfCallable1( - PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPath ap, + PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPathApprox apa, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | - pathOutOfCallable0(mid, pos, innercc, ap, config) and + pathOutOfCallable0(mid, pos, innercc, apa, config) and c = pos.getCallable() and kind = pos.getKind() and resolveReturn(innercc, c, call) @@ -2321,10 +2494,10 @@ private predicate pathOutOfCallable1( pragma[noinline] private Node getAnOutNodeFlow( - ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config + ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ) { result = kind.getAnOutNode(call) and - flow(result, _, _, ap, config) + flow(result, _, _, apa, config) } /** @@ -2333,10 +2506,9 @@ private Node getAnOutNodeFlow( */ pragma[noinline] private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { - exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | - pathOutOfCallable1(mid, call, kind, cc, ap, config) - | - out = getAnOutNodeFlow(kind, call, ap, config) + exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config | + pathOutOfCallable1(mid, call, kind, cc, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -2345,22 +2517,23 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa ) { exists(ArgumentNode arg | arg = mid.getNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and - ap = mid.getAp() + ap = mid.getAp() and + apa = ap.getApprox() ) } pragma[noinline] private predicate parameterCand( - DataFlowCallable callable, int i, AccessPath ap, Configuration config + DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { exists(ParameterNode p | - flow(p, _, _, ap, config) and + flow(p, _, _, apa, config) and p.isParameterOf(callable, i) ) } @@ -2370,9 +2543,11 @@ private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, AccessPath ap ) { - pathIntoArg(mid, i, outercc, call, ap) and - callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), ap, mid.getConfiguration()) + exists(AccessPathApprox apa | + pathIntoArg(mid, i, outercc, call, ap, apa) and + callable = resolveCall(call, outercc) and + parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + ) } /** @@ -2403,7 +2578,8 @@ private predicate pathIntoCallable( /** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */ pragma[nomagic] private predicate paramFlowsThrough( - ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config + ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(PathNodeMid mid, ReturnNodeExt ret, int pos | mid.getNode() = ret and @@ -2412,6 +2588,7 @@ private predicate paramFlowsThrough( sc = mid.getSummaryCtx() and config = mid.getConfiguration() and ap = mid.getAp() and + apa = ap.getApprox() and pos = sc.getParameterPos() and not kind.(ParamUpdateReturnKind).getPosition() = pos ) @@ -2419,11 +2596,12 @@ private predicate paramFlowsThrough( pragma[nomagic] private predicate pathThroughCallable0( - DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap + DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, + AccessPathApprox apa ) { exists(CallContext innercc, SummaryCtx sc | pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, unbind(mid.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration())) ) } @@ -2433,9 +2611,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind | - pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | + pathThroughCallable0(call, mid, kind, cc, ap, apa) and + out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration())) ) } @@ -2521,10 +2699,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2533,7 +2711,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2544,7 +2722,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2562,15 +2740,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2591,7 +2769,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2608,7 +2786,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2721,7 +2899,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2737,7 +2915,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2746,11 +2924,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2769,35 +2948,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( @@ -2806,7 +2992,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index f876c04d6c66..8bc3d75ff86e 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -286,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -318,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -417,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -447,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -566,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -748,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -781,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -896,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -930,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1046,11 +1051,22 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1058,9 +1074,9 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1074,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1108,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1122,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1154,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1183,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1197,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1223,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1261,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } +pragma[nomagic] +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + pragma[nomagic] private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1385,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1417,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1497,24 +1523,24 @@ private predicate flowCandIsReturned( ) } -private newtype TAccessPath = +private newtype TAccessPathApprox = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two - * elements of the list and its length are tracked. If data flows from a source to - * a given node with a given `AccessPath`, this indicates the sequence 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. + * Conceptually a list of `TypedContent`s followed by a `DataFlowType`, but only + * the first two elements of the list and its length are tracked. If data flows + * from a source to a given node with a given `AccessPathApprox`, this indicates + * the sequence 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 { +abstract private class AccessPathApprox extends TAccessPathApprox { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1522,20 +1548,18 @@ abstract private class AccessPath extends TAccessPath { abstract AccessPathFront getFront(); - /** - * Holds if this access path has `head` at the front and may be followed by `tail`. - */ - abstract predicate pop(Content head, AccessPath tail); + /** Gets the access path obtained by popping `head` from this path, if any. */ + abstract AccessPathApprox pop(TypedContent head); } -private class AccessPathNil extends AccessPath, TNil { +private class AccessPathApproxNil extends AccessPathApprox, TNil { private DataFlowType t; - AccessPathNil() { this = TNil(t) } + AccessPathApproxNil() { this = TNil(t) } override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1543,258 +1567,285 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override AccessPathApprox pop(TypedContent head) { none() } } -abstract private class AccessPathCons extends AccessPath { } +abstract private class AccessPathApproxCons extends AccessPathApprox { } -private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; +private class AccessPathApproxConsNil extends AccessPathApproxCons, TConsNil { + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathApproxConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override AccessPathApprox pop(TypedContent head) { head = tc and result = TNil(t) } } -private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; +private class AccessPathApproxConsCons extends AccessPathApproxCons, TConsCons { + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathApproxConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override AccessPathApprox pop(TypedContent head) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + result = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + result = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPathApprox pop(TypedContent tc, AccessPathApprox apa) { result = apa.pop(tc) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPathApprox push(TypedContent tc, AccessPathApprox apa) { apa = pop(tc, result) } -private newtype TAccessPathOption = - TAccessPathNone() or - TAccessPathSome(AccessPath ap) +private newtype TAccessPathApproxOption = + TAccessPathApproxNone() or + TAccessPathApproxSome(AccessPathApprox apa) -private class AccessPathOption extends TAccessPathOption { +private class AccessPathApproxOption extends TAccessPathApproxOption { string toString() { - this = TAccessPathNone() and result = "" + this = TAccessPathApproxNone() and result = "" or - this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + this = TAccessPathApproxSome(any(AccessPathApprox apa | result = apa.toString())) } } /** - * Holds if `node` is reachable with access path `ap` from a source in - * the configuration `config`. + * Holds if `node` is reachable with approximate access path `apa` from a source + * in the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an - * argument in a call, and if so, `argAp` records the access path of that - * argument. + * The call context `cc` records whether the node is reached through an + * argument in a call, and if so, `argApa` records the approximate access path + * of that argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argApa, apf, apa, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, apf, apa, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and - apf = ap.(AccessPathNil).getFront() + exists(Node mid, AccessPathApproxNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and + apf = apa.(AccessPathApproxNil).getFront() ) or exists(Node mid | - flowFwd(mid, _, _, apf, ap, config) and + flowFwd(mid, _, _, apf, apa, config) and jumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | + exists(Node mid, AccessPathApproxNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, apa), apf, cc, argApa, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, apa), apf, cc, argApa, config) and + flowFwdConsCand(tc, apf, apa, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, _, cc, _, apf, apa, config) and if flowCand(node, true, _, apf, config) - then argAp = TAccessPathSome(ap) - else argAp = TAccessPathNone() + then argApa = TAccessPathApproxSome(apa) + else argApa = TAccessPathApproxNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argApa, apf, apa, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or - exists(AccessPath argAp0 | - flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + exists(AccessPathApprox argApa0 | + flowFwdOutFromArg(call, node, argApa0, apf, apa, config) and + flowFwdIsEntered(call, cc, argApa, argApa0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argApa, apf, apa, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - AccessPathOption argAp, Configuration config + Node node, TypedContent tc, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwd(mid, cc, argApa, apf0, apa0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPathApprox apa0, Node node2, + CallContext cc, AccessPathApproxOption argApa, Configuration config +) { + flowFwd(node1, cc, argApa, apf0, apa0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + pragma[nomagic] private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config + Node node, AccessPathFrontHead apf0, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, apa0, node, cc, argApa, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(Node n | - flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwd(n, _, _, apf, apa, config) and + flowFwdStore0(n, tc, _, apf, _, config) ) } pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argApa, apf, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argApa, apf, apa, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOutFromArg( - DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + DataFlowCall call, Node node, AccessPathApprox argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathApproxSome(argApa), apf, apa, + config) } /** @@ -1802,166 +1853,174 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathApproxOption argApa, AccessPathApprox apa, + Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argApa, apf, apa, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if `node` with access path `ap` is part of a path from a source to - * a sink in the configuration `config`. + * Holds if `node` with approximate access path `apa` is part of a path from a + * source to a sink in the configuration `config`. * * The Boolean `toReturn` records whether the node must be returned from - * the enclosing callable in order to reach a sink, and if so, `returnAp` - * records the access path of the returned value. + * the enclosing callable in order to reach a sink, and if so, `returnApa` + * records the approximate access path of the returned value. */ private predicate flow( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flow0(node, toReturn, returnAp, ap, config) and - flowFwd(node, _, _, _, ap, config) + flow0(node, toReturn, returnApa, apa, config) and + flowFwd(node, _, _, _, apa, config) } private predicate flow0( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flowFwd(node, _, _, _, ap, config) and + flowFwd(node, _, _, _, apa, config) and config.isSink(node) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil or exists(Node mid | localFlowBigStep(node, mid, true, _, config, _) and - flow(mid, toReturn, returnAp, ap, config) + flow(mid, toReturn, returnApa, apa, config) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and localFlowBigStep(node, mid, false, _, config, _) and - flow(mid, toReturn, returnAp, nil, config) and - ap instanceof AccessPathNil + flow(mid, toReturn, returnApa, nil, config) and + apa instanceof AccessPathApproxNil ) or exists(Node mid | jumpStep(node, mid, config) and - flow(mid, _, _, ap, config) and + flow(mid, _, _, apa, config) and toReturn = false and - returnAp = TAccessPathNone() + returnApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and additionalJumpStep(node, mid, config) and flow(mid, _, _, nil, config) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnApa, apa, config) and + flowConsCand(tc, apa, config) ) or // read - exists(Node mid, AccessPath ap0 | - readFlowFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + readFlowFwd(node, _, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) or // flow into a callable exists(DataFlowCall call | - flowIn(call, node, toReturn, returnAp, ap, config) and + flowIn(call, node, toReturn, returnApa, apa, config) and toReturn = false or - exists(AccessPath returnAp0 | - flowInToReturn(call, node, returnAp0, ap, config) and - flowIsReturned(call, toReturn, returnAp, returnAp0, config) + exists(AccessPathApprox returnApa0 | + flowInToReturn(call, node, returnApa0, apa, config) and + flowIsReturned(call, toReturn, returnApa, returnApa0, config) ) ) or // flow out of a callable - flowOut(_, node, _, _, ap, config) and + flowOut(_, node, _, _, apa, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) - then returnAp = TAccessPathSome(ap) - else returnAp = TAccessPathNone() + if flowFwd(node, any(CallContextCall ccc), TAccessPathApproxSome(_), _, apa, config) + then returnApa = TAccessPathApproxSome(apa) + else returnApa = TAccessPathApproxNone() } pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, apa, _, _, _, config) and + apa0 = push(tc, apa) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { - exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + storeFlowFwd(node, tc, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, apa, _, _, _, config) and + apa0 = pop(tc, apa) and + flowFwdConsCand(tc, _, apa0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPathApprox apa, Configuration config) { exists(Node n, Node mid | - flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + flow(mid, _, _, apa, config) and + readFlowFwd(n, tc, mid, _, apa, config) ) } pragma[nomagic] private predicate flowOut( - DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(Node out, boolean allowsFieldFlow | - flow(out, toReturn, returnAp, ap, config) and + flow(out, toReturn, returnApa, apa, config) and flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowIn( - DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(ParameterNode p, boolean allowsFieldFlow | - flow(p, toReturn, returnAp, ap, config) and + flow(p, toReturn, returnApa, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowInToReturn( - DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config + DataFlowCall call, ArgumentNode arg, AccessPathApprox returnApa, AccessPathApprox apa, + Configuration config ) { - flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) + flowIn(call, arg, true, TAccessPathApproxSome(returnApa), apa, config) } /** @@ -1969,12 +2028,13 @@ private predicate flowInToReturn( */ pragma[nomagic] private predicate flowIsReturned( - DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + DataFlowCall call, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, Configuration config ) { - exists(ReturnNodeExt ret | - flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + exists(ReturnNodeExt ret, CallContextCall ccc | + flowOut(call, ret, toReturn, returnApa, apa, config) and + flowFwd(ret, ccc, TAccessPathApproxSome(_), _, apa, config) and + ccc.matchesCall(call) ) } @@ -1985,21 +2045,23 @@ private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) pragma[noinline] private predicate parameterFlow( - ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config + ParameterNode p, AccessPathApprox apa, DataFlowCallable c, Configuration config ) { - flow(p, true, _, ap, config) and + flow(p, true, _, apa, config) and c = p.getEnclosingCallable() } +private predicate parameterMayFlowThrough(ParameterNode p, AccessPathApprox apa) { + exists(ReturnNodeExt ret, Configuration config, AccessPathApprox apa0 | + parameterFlow(p, apa, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathApproxSome(_), apa0, config) and + flowFwd(ret, any(CallContextCall ccc), TAccessPathApproxSome(apa), _, apa0, config) + ) +} + private newtype TSummaryCtx = TSummaryCtxNone() or - TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | - parameterFlow(p, ap, ret.getEnclosingCallable(), config) and - flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) - ) - } + TSummaryCtxSome(ParameterNode p, AccessPath ap) { parameterMayFlowThrough(p, ap.getApprox()) } /** * A context for generating flow summaries. This represents flow entry through @@ -2034,6 +2096,10 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { } } +private newtype TAccessPath = + TAccessPathNil(DataFlowType t) or + TAccessPathCons(TypedContent head, AccessPath tail) { flowConsCand(head, tail.getApprox(), _) } + private newtype TPathNode = TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) { // A PathNode is introduced by a source ... @@ -2041,13 +2107,13 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(node, _, _, ap, unbind(config)) + flow(node, _, _, ap.getApprox(), unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2059,12 +2125,99 @@ private newtype TPathNode = or // ... or a sink that can be reached from a source exists(PathNodeMid mid | - pathStep(mid, node, _, _, any(AccessPathNil nil)) and + pathStep(mid, node, _, _, TAccessPathNil(_)) and config = unbind(mid.getConfiguration()) ) ) } +/** + * A list of `TypedContent`s followed by a `DataFlowType`. If data flows from a + * source to a given node with a given `AccessPath`, this indicates the sequence + * 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 { + /** Gets the head of this access path, if any. */ + abstract TypedContent getHead(); + + /** Gets the tail of this access path, if any. */ + abstract AccessPath getTail(); + + /** Gets the front of this access path. */ + abstract AccessPathFront getFront(); + + /** Gets the approximation of this access path. */ + abstract AccessPathApprox getApprox(); + + /** Gets the length of this access path. */ + abstract int length(); + + /** Gets a textual representation of this access path. */ + abstract string toString(); + + /** Gets the access path obtained by popping `tc` from this access path, if any. */ + final AccessPath pop(TypedContent tc) { + result = this.getTail() and + tc = this.getHead() + } + + /** Gets the access path obtained by pushing `tc` onto this access path. */ + final AccessPath push(TypedContent tc) { this = result.pop(tc) } +} + +private class AccessPathNil extends AccessPath, TAccessPathNil { + private DataFlowType t; + + AccessPathNil() { this = TAccessPathNil(t) } + + DataFlowType getType() { result = t } + + override TypedContent getHead() { none() } + + override AccessPath getTail() { none() } + + override AccessPathFrontNil getFront() { result = TFrontNil(t) } + + override AccessPathApproxNil getApprox() { result = TNil(t) } + + override int length() { result = 0 } + + override string toString() { result = concat(": " + ppReprType(t)) } +} + +private class AccessPathCons extends AccessPath, TAccessPathCons { + private TypedContent head; + private AccessPath tail; + + AccessPathCons() { this = TAccessPathCons(head, tail) } + + override TypedContent getHead() { result = head } + + override AccessPath getTail() { result = tail } + + override AccessPathFrontHead getFront() { result = TFrontHead(head) } + + override AccessPathApproxCons getApprox() { + result = TConsNil(head, tail.(AccessPathNil).getType()) + or + result = TConsCons(head, tail.getHead(), this.length()) + } + + override int length() { result = 1 + tail.length() } + + private string toStringImpl() { + exists(DataFlowType t | + tail = TAccessPathNil(t) and + result = head.toString() + "]" + concat(" : " + ppReprType(t)) + ) + or + result = head + ", " + tail.(AccessPathCons).toStringImpl() + } + + override string toString() { result = "[" + this.toStringImpl() } +} + /** * A `Node` augmented with a call context (except for sinks), an access path, and a configuration. * Only those `PathNode`s that are reachable from a source are generated. @@ -2098,14 +2251,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2350,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2387,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2251,12 +2421,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2267,50 +2437,53 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } private predicate pathOutOfCallable0( - PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPath ap, Configuration config + PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa, + Configuration config ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and - ap = mid.getAp() and + innercc instanceof CallContextNoCall and + apa = mid.getAp().getApprox() and config = mid.getConfiguration() } pragma[nomagic] private predicate pathOutOfCallable1( - PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPath ap, + PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPathApprox apa, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | - pathOutOfCallable0(mid, pos, innercc, ap, config) and + pathOutOfCallable0(mid, pos, innercc, apa, config) and c = pos.getCallable() and kind = pos.getKind() and resolveReturn(innercc, c, call) @@ -2321,10 +2494,10 @@ private predicate pathOutOfCallable1( pragma[noinline] private Node getAnOutNodeFlow( - ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config + ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ) { result = kind.getAnOutNode(call) and - flow(result, _, _, ap, config) + flow(result, _, _, apa, config) } /** @@ -2333,10 +2506,9 @@ private Node getAnOutNodeFlow( */ pragma[noinline] private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { - exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | - pathOutOfCallable1(mid, call, kind, cc, ap, config) - | - out = getAnOutNodeFlow(kind, call, ap, config) + exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config | + pathOutOfCallable1(mid, call, kind, cc, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -2345,22 +2517,23 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa ) { exists(ArgumentNode arg | arg = mid.getNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and - ap = mid.getAp() + ap = mid.getAp() and + apa = ap.getApprox() ) } pragma[noinline] private predicate parameterCand( - DataFlowCallable callable, int i, AccessPath ap, Configuration config + DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { exists(ParameterNode p | - flow(p, _, _, ap, config) and + flow(p, _, _, apa, config) and p.isParameterOf(callable, i) ) } @@ -2370,9 +2543,11 @@ private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, AccessPath ap ) { - pathIntoArg(mid, i, outercc, call, ap) and - callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), ap, mid.getConfiguration()) + exists(AccessPathApprox apa | + pathIntoArg(mid, i, outercc, call, ap, apa) and + callable = resolveCall(call, outercc) and + parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + ) } /** @@ -2403,7 +2578,8 @@ private predicate pathIntoCallable( /** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */ pragma[nomagic] private predicate paramFlowsThrough( - ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config + ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(PathNodeMid mid, ReturnNodeExt ret, int pos | mid.getNode() = ret and @@ -2412,6 +2588,7 @@ private predicate paramFlowsThrough( sc = mid.getSummaryCtx() and config = mid.getConfiguration() and ap = mid.getAp() and + apa = ap.getApprox() and pos = sc.getParameterPos() and not kind.(ParamUpdateReturnKind).getPosition() = pos ) @@ -2419,11 +2596,12 @@ private predicate paramFlowsThrough( pragma[nomagic] private predicate pathThroughCallable0( - DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap + DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, + AccessPathApprox apa ) { exists(CallContext innercc, SummaryCtx sc | pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, unbind(mid.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration())) ) } @@ -2433,9 +2611,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind | - pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | + pathThroughCallable0(call, mid, kind, cc, ap, apa) and + out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration())) ) } @@ -2521,10 +2699,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2533,7 +2711,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2544,7 +2722,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2562,15 +2740,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2591,7 +2769,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2608,7 +2786,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2721,7 +2899,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2737,7 +2915,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2746,11 +2924,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2769,35 +2948,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( @@ -2806,7 +2992,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index f876c04d6c66..8bc3d75ff86e 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -286,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -318,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -417,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -447,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -566,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -748,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -781,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -896,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -930,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1046,11 +1051,22 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1058,9 +1074,9 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1074,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1108,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1122,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1154,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1183,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1197,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1223,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1261,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } +pragma[nomagic] +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + pragma[nomagic] private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1385,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1417,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1497,24 +1523,24 @@ private predicate flowCandIsReturned( ) } -private newtype TAccessPath = +private newtype TAccessPathApprox = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two - * elements of the list and its length are tracked. If data flows from a source to - * a given node with a given `AccessPath`, this indicates the sequence 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. + * Conceptually a list of `TypedContent`s followed by a `DataFlowType`, but only + * the first two elements of the list and its length are tracked. If data flows + * from a source to a given node with a given `AccessPathApprox`, this indicates + * the sequence 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 { +abstract private class AccessPathApprox extends TAccessPathApprox { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1522,20 +1548,18 @@ abstract private class AccessPath extends TAccessPath { abstract AccessPathFront getFront(); - /** - * Holds if this access path has `head` at the front and may be followed by `tail`. - */ - abstract predicate pop(Content head, AccessPath tail); + /** Gets the access path obtained by popping `head` from this path, if any. */ + abstract AccessPathApprox pop(TypedContent head); } -private class AccessPathNil extends AccessPath, TNil { +private class AccessPathApproxNil extends AccessPathApprox, TNil { private DataFlowType t; - AccessPathNil() { this = TNil(t) } + AccessPathApproxNil() { this = TNil(t) } override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1543,258 +1567,285 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override AccessPathApprox pop(TypedContent head) { none() } } -abstract private class AccessPathCons extends AccessPath { } +abstract private class AccessPathApproxCons extends AccessPathApprox { } -private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; +private class AccessPathApproxConsNil extends AccessPathApproxCons, TConsNil { + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathApproxConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override AccessPathApprox pop(TypedContent head) { head = tc and result = TNil(t) } } -private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; +private class AccessPathApproxConsCons extends AccessPathApproxCons, TConsCons { + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathApproxConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override AccessPathApprox pop(TypedContent head) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + result = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + result = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPathApprox pop(TypedContent tc, AccessPathApprox apa) { result = apa.pop(tc) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPathApprox push(TypedContent tc, AccessPathApprox apa) { apa = pop(tc, result) } -private newtype TAccessPathOption = - TAccessPathNone() or - TAccessPathSome(AccessPath ap) +private newtype TAccessPathApproxOption = + TAccessPathApproxNone() or + TAccessPathApproxSome(AccessPathApprox apa) -private class AccessPathOption extends TAccessPathOption { +private class AccessPathApproxOption extends TAccessPathApproxOption { string toString() { - this = TAccessPathNone() and result = "" + this = TAccessPathApproxNone() and result = "" or - this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + this = TAccessPathApproxSome(any(AccessPathApprox apa | result = apa.toString())) } } /** - * Holds if `node` is reachable with access path `ap` from a source in - * the configuration `config`. + * Holds if `node` is reachable with approximate access path `apa` from a source + * in the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an - * argument in a call, and if so, `argAp` records the access path of that - * argument. + * The call context `cc` records whether the node is reached through an + * argument in a call, and if so, `argApa` records the approximate access path + * of that argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argApa, apf, apa, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, apf, apa, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and - apf = ap.(AccessPathNil).getFront() + exists(Node mid, AccessPathApproxNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and + apf = apa.(AccessPathApproxNil).getFront() ) or exists(Node mid | - flowFwd(mid, _, _, apf, ap, config) and + flowFwd(mid, _, _, apf, apa, config) and jumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | + exists(Node mid, AccessPathApproxNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, apa), apf, cc, argApa, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, apa), apf, cc, argApa, config) and + flowFwdConsCand(tc, apf, apa, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, _, cc, _, apf, apa, config) and if flowCand(node, true, _, apf, config) - then argAp = TAccessPathSome(ap) - else argAp = TAccessPathNone() + then argApa = TAccessPathApproxSome(apa) + else argApa = TAccessPathApproxNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argApa, apf, apa, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or - exists(AccessPath argAp0 | - flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + exists(AccessPathApprox argApa0 | + flowFwdOutFromArg(call, node, argApa0, apf, apa, config) and + flowFwdIsEntered(call, cc, argApa, argApa0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argApa, apf, apa, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - AccessPathOption argAp, Configuration config + Node node, TypedContent tc, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwd(mid, cc, argApa, apf0, apa0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPathApprox apa0, Node node2, + CallContext cc, AccessPathApproxOption argApa, Configuration config +) { + flowFwd(node1, cc, argApa, apf0, apa0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + pragma[nomagic] private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config + Node node, AccessPathFrontHead apf0, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, apa0, node, cc, argApa, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(Node n | - flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwd(n, _, _, apf, apa, config) and + flowFwdStore0(n, tc, _, apf, _, config) ) } pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argApa, apf, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argApa, apf, apa, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOutFromArg( - DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + DataFlowCall call, Node node, AccessPathApprox argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathApproxSome(argApa), apf, apa, + config) } /** @@ -1802,166 +1853,174 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathApproxOption argApa, AccessPathApprox apa, + Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argApa, apf, apa, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if `node` with access path `ap` is part of a path from a source to - * a sink in the configuration `config`. + * Holds if `node` with approximate access path `apa` is part of a path from a + * source to a sink in the configuration `config`. * * The Boolean `toReturn` records whether the node must be returned from - * the enclosing callable in order to reach a sink, and if so, `returnAp` - * records the access path of the returned value. + * the enclosing callable in order to reach a sink, and if so, `returnApa` + * records the approximate access path of the returned value. */ private predicate flow( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flow0(node, toReturn, returnAp, ap, config) and - flowFwd(node, _, _, _, ap, config) + flow0(node, toReturn, returnApa, apa, config) and + flowFwd(node, _, _, _, apa, config) } private predicate flow0( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flowFwd(node, _, _, _, ap, config) and + flowFwd(node, _, _, _, apa, config) and config.isSink(node) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil or exists(Node mid | localFlowBigStep(node, mid, true, _, config, _) and - flow(mid, toReturn, returnAp, ap, config) + flow(mid, toReturn, returnApa, apa, config) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and localFlowBigStep(node, mid, false, _, config, _) and - flow(mid, toReturn, returnAp, nil, config) and - ap instanceof AccessPathNil + flow(mid, toReturn, returnApa, nil, config) and + apa instanceof AccessPathApproxNil ) or exists(Node mid | jumpStep(node, mid, config) and - flow(mid, _, _, ap, config) and + flow(mid, _, _, apa, config) and toReturn = false and - returnAp = TAccessPathNone() + returnApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and additionalJumpStep(node, mid, config) and flow(mid, _, _, nil, config) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnApa, apa, config) and + flowConsCand(tc, apa, config) ) or // read - exists(Node mid, AccessPath ap0 | - readFlowFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + readFlowFwd(node, _, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) or // flow into a callable exists(DataFlowCall call | - flowIn(call, node, toReturn, returnAp, ap, config) and + flowIn(call, node, toReturn, returnApa, apa, config) and toReturn = false or - exists(AccessPath returnAp0 | - flowInToReturn(call, node, returnAp0, ap, config) and - flowIsReturned(call, toReturn, returnAp, returnAp0, config) + exists(AccessPathApprox returnApa0 | + flowInToReturn(call, node, returnApa0, apa, config) and + flowIsReturned(call, toReturn, returnApa, returnApa0, config) ) ) or // flow out of a callable - flowOut(_, node, _, _, ap, config) and + flowOut(_, node, _, _, apa, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) - then returnAp = TAccessPathSome(ap) - else returnAp = TAccessPathNone() + if flowFwd(node, any(CallContextCall ccc), TAccessPathApproxSome(_), _, apa, config) + then returnApa = TAccessPathApproxSome(apa) + else returnApa = TAccessPathApproxNone() } pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, apa, _, _, _, config) and + apa0 = push(tc, apa) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { - exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + storeFlowFwd(node, tc, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, apa, _, _, _, config) and + apa0 = pop(tc, apa) and + flowFwdConsCand(tc, _, apa0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPathApprox apa, Configuration config) { exists(Node n, Node mid | - flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + flow(mid, _, _, apa, config) and + readFlowFwd(n, tc, mid, _, apa, config) ) } pragma[nomagic] private predicate flowOut( - DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(Node out, boolean allowsFieldFlow | - flow(out, toReturn, returnAp, ap, config) and + flow(out, toReturn, returnApa, apa, config) and flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowIn( - DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(ParameterNode p, boolean allowsFieldFlow | - flow(p, toReturn, returnAp, ap, config) and + flow(p, toReturn, returnApa, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowInToReturn( - DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config + DataFlowCall call, ArgumentNode arg, AccessPathApprox returnApa, AccessPathApprox apa, + Configuration config ) { - flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) + flowIn(call, arg, true, TAccessPathApproxSome(returnApa), apa, config) } /** @@ -1969,12 +2028,13 @@ private predicate flowInToReturn( */ pragma[nomagic] private predicate flowIsReturned( - DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + DataFlowCall call, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, Configuration config ) { - exists(ReturnNodeExt ret | - flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + exists(ReturnNodeExt ret, CallContextCall ccc | + flowOut(call, ret, toReturn, returnApa, apa, config) and + flowFwd(ret, ccc, TAccessPathApproxSome(_), _, apa, config) and + ccc.matchesCall(call) ) } @@ -1985,21 +2045,23 @@ private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) pragma[noinline] private predicate parameterFlow( - ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config + ParameterNode p, AccessPathApprox apa, DataFlowCallable c, Configuration config ) { - flow(p, true, _, ap, config) and + flow(p, true, _, apa, config) and c = p.getEnclosingCallable() } +private predicate parameterMayFlowThrough(ParameterNode p, AccessPathApprox apa) { + exists(ReturnNodeExt ret, Configuration config, AccessPathApprox apa0 | + parameterFlow(p, apa, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathApproxSome(_), apa0, config) and + flowFwd(ret, any(CallContextCall ccc), TAccessPathApproxSome(apa), _, apa0, config) + ) +} + private newtype TSummaryCtx = TSummaryCtxNone() or - TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | - parameterFlow(p, ap, ret.getEnclosingCallable(), config) and - flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) - ) - } + TSummaryCtxSome(ParameterNode p, AccessPath ap) { parameterMayFlowThrough(p, ap.getApprox()) } /** * A context for generating flow summaries. This represents flow entry through @@ -2034,6 +2096,10 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { } } +private newtype TAccessPath = + TAccessPathNil(DataFlowType t) or + TAccessPathCons(TypedContent head, AccessPath tail) { flowConsCand(head, tail.getApprox(), _) } + private newtype TPathNode = TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) { // A PathNode is introduced by a source ... @@ -2041,13 +2107,13 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(node, _, _, ap, unbind(config)) + flow(node, _, _, ap.getApprox(), unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2059,12 +2125,99 @@ private newtype TPathNode = or // ... or a sink that can be reached from a source exists(PathNodeMid mid | - pathStep(mid, node, _, _, any(AccessPathNil nil)) and + pathStep(mid, node, _, _, TAccessPathNil(_)) and config = unbind(mid.getConfiguration()) ) ) } +/** + * A list of `TypedContent`s followed by a `DataFlowType`. If data flows from a + * source to a given node with a given `AccessPath`, this indicates the sequence + * 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 { + /** Gets the head of this access path, if any. */ + abstract TypedContent getHead(); + + /** Gets the tail of this access path, if any. */ + abstract AccessPath getTail(); + + /** Gets the front of this access path. */ + abstract AccessPathFront getFront(); + + /** Gets the approximation of this access path. */ + abstract AccessPathApprox getApprox(); + + /** Gets the length of this access path. */ + abstract int length(); + + /** Gets a textual representation of this access path. */ + abstract string toString(); + + /** Gets the access path obtained by popping `tc` from this access path, if any. */ + final AccessPath pop(TypedContent tc) { + result = this.getTail() and + tc = this.getHead() + } + + /** Gets the access path obtained by pushing `tc` onto this access path. */ + final AccessPath push(TypedContent tc) { this = result.pop(tc) } +} + +private class AccessPathNil extends AccessPath, TAccessPathNil { + private DataFlowType t; + + AccessPathNil() { this = TAccessPathNil(t) } + + DataFlowType getType() { result = t } + + override TypedContent getHead() { none() } + + override AccessPath getTail() { none() } + + override AccessPathFrontNil getFront() { result = TFrontNil(t) } + + override AccessPathApproxNil getApprox() { result = TNil(t) } + + override int length() { result = 0 } + + override string toString() { result = concat(": " + ppReprType(t)) } +} + +private class AccessPathCons extends AccessPath, TAccessPathCons { + private TypedContent head; + private AccessPath tail; + + AccessPathCons() { this = TAccessPathCons(head, tail) } + + override TypedContent getHead() { result = head } + + override AccessPath getTail() { result = tail } + + override AccessPathFrontHead getFront() { result = TFrontHead(head) } + + override AccessPathApproxCons getApprox() { + result = TConsNil(head, tail.(AccessPathNil).getType()) + or + result = TConsCons(head, tail.getHead(), this.length()) + } + + override int length() { result = 1 + tail.length() } + + private string toStringImpl() { + exists(DataFlowType t | + tail = TAccessPathNil(t) and + result = head.toString() + "]" + concat(" : " + ppReprType(t)) + ) + or + result = head + ", " + tail.(AccessPathCons).toStringImpl() + } + + override string toString() { result = "[" + this.toStringImpl() } +} + /** * A `Node` augmented with a call context (except for sinks), an access path, and a configuration. * Only those `PathNode`s that are reachable from a source are generated. @@ -2098,14 +2251,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2350,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2387,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2251,12 +2421,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2267,50 +2437,53 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } private predicate pathOutOfCallable0( - PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPath ap, Configuration config + PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa, + Configuration config ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and - ap = mid.getAp() and + innercc instanceof CallContextNoCall and + apa = mid.getAp().getApprox() and config = mid.getConfiguration() } pragma[nomagic] private predicate pathOutOfCallable1( - PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPath ap, + PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPathApprox apa, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | - pathOutOfCallable0(mid, pos, innercc, ap, config) and + pathOutOfCallable0(mid, pos, innercc, apa, config) and c = pos.getCallable() and kind = pos.getKind() and resolveReturn(innercc, c, call) @@ -2321,10 +2494,10 @@ private predicate pathOutOfCallable1( pragma[noinline] private Node getAnOutNodeFlow( - ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config + ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ) { result = kind.getAnOutNode(call) and - flow(result, _, _, ap, config) + flow(result, _, _, apa, config) } /** @@ -2333,10 +2506,9 @@ private Node getAnOutNodeFlow( */ pragma[noinline] private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { - exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | - pathOutOfCallable1(mid, call, kind, cc, ap, config) - | - out = getAnOutNodeFlow(kind, call, ap, config) + exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config | + pathOutOfCallable1(mid, call, kind, cc, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -2345,22 +2517,23 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa ) { exists(ArgumentNode arg | arg = mid.getNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and - ap = mid.getAp() + ap = mid.getAp() and + apa = ap.getApprox() ) } pragma[noinline] private predicate parameterCand( - DataFlowCallable callable, int i, AccessPath ap, Configuration config + DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { exists(ParameterNode p | - flow(p, _, _, ap, config) and + flow(p, _, _, apa, config) and p.isParameterOf(callable, i) ) } @@ -2370,9 +2543,11 @@ private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, AccessPath ap ) { - pathIntoArg(mid, i, outercc, call, ap) and - callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), ap, mid.getConfiguration()) + exists(AccessPathApprox apa | + pathIntoArg(mid, i, outercc, call, ap, apa) and + callable = resolveCall(call, outercc) and + parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + ) } /** @@ -2403,7 +2578,8 @@ private predicate pathIntoCallable( /** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */ pragma[nomagic] private predicate paramFlowsThrough( - ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config + ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(PathNodeMid mid, ReturnNodeExt ret, int pos | mid.getNode() = ret and @@ -2412,6 +2588,7 @@ private predicate paramFlowsThrough( sc = mid.getSummaryCtx() and config = mid.getConfiguration() and ap = mid.getAp() and + apa = ap.getApprox() and pos = sc.getParameterPos() and not kind.(ParamUpdateReturnKind).getPosition() = pos ) @@ -2419,11 +2596,12 @@ private predicate paramFlowsThrough( pragma[nomagic] private predicate pathThroughCallable0( - DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap + DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, + AccessPathApprox apa ) { exists(CallContext innercc, SummaryCtx sc | pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, unbind(mid.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration())) ) } @@ -2433,9 +2611,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind | - pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | + pathThroughCallable0(call, mid, kind, cc, ap, apa) and + out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration())) ) } @@ -2521,10 +2699,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2533,7 +2711,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2544,7 +2722,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2562,15 +2740,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2591,7 +2769,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2608,7 +2786,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2721,7 +2899,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2737,7 +2915,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2746,11 +2924,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2769,35 +2948,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( @@ -2806,7 +2992,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index f876c04d6c66..8bc3d75ff86e 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -286,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -318,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -417,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -447,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -566,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -748,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -781,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -896,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -930,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1046,11 +1051,22 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1058,9 +1074,9 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1074,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1108,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1122,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1154,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1183,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1197,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1223,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1261,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } +pragma[nomagic] +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + pragma[nomagic] private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1385,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1417,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1497,24 +1523,24 @@ private predicate flowCandIsReturned( ) } -private newtype TAccessPath = +private newtype TAccessPathApprox = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two - * elements of the list and its length are tracked. If data flows from a source to - * a given node with a given `AccessPath`, this indicates the sequence 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. + * Conceptually a list of `TypedContent`s followed by a `DataFlowType`, but only + * the first two elements of the list and its length are tracked. If data flows + * from a source to a given node with a given `AccessPathApprox`, this indicates + * the sequence 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 { +abstract private class AccessPathApprox extends TAccessPathApprox { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1522,20 +1548,18 @@ abstract private class AccessPath extends TAccessPath { abstract AccessPathFront getFront(); - /** - * Holds if this access path has `head` at the front and may be followed by `tail`. - */ - abstract predicate pop(Content head, AccessPath tail); + /** Gets the access path obtained by popping `head` from this path, if any. */ + abstract AccessPathApprox pop(TypedContent head); } -private class AccessPathNil extends AccessPath, TNil { +private class AccessPathApproxNil extends AccessPathApprox, TNil { private DataFlowType t; - AccessPathNil() { this = TNil(t) } + AccessPathApproxNil() { this = TNil(t) } override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1543,258 +1567,285 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override AccessPathApprox pop(TypedContent head) { none() } } -abstract private class AccessPathCons extends AccessPath { } +abstract private class AccessPathApproxCons extends AccessPathApprox { } -private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; +private class AccessPathApproxConsNil extends AccessPathApproxCons, TConsNil { + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathApproxConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override AccessPathApprox pop(TypedContent head) { head = tc and result = TNil(t) } } -private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; +private class AccessPathApproxConsCons extends AccessPathApproxCons, TConsCons { + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathApproxConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override AccessPathApprox pop(TypedContent head) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + result = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + result = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPathApprox pop(TypedContent tc, AccessPathApprox apa) { result = apa.pop(tc) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPathApprox push(TypedContent tc, AccessPathApprox apa) { apa = pop(tc, result) } -private newtype TAccessPathOption = - TAccessPathNone() or - TAccessPathSome(AccessPath ap) +private newtype TAccessPathApproxOption = + TAccessPathApproxNone() or + TAccessPathApproxSome(AccessPathApprox apa) -private class AccessPathOption extends TAccessPathOption { +private class AccessPathApproxOption extends TAccessPathApproxOption { string toString() { - this = TAccessPathNone() and result = "" + this = TAccessPathApproxNone() and result = "" or - this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + this = TAccessPathApproxSome(any(AccessPathApprox apa | result = apa.toString())) } } /** - * Holds if `node` is reachable with access path `ap` from a source in - * the configuration `config`. + * Holds if `node` is reachable with approximate access path `apa` from a source + * in the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an - * argument in a call, and if so, `argAp` records the access path of that - * argument. + * The call context `cc` records whether the node is reached through an + * argument in a call, and if so, `argApa` records the approximate access path + * of that argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argApa, apf, apa, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, apf, apa, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and - apf = ap.(AccessPathNil).getFront() + exists(Node mid, AccessPathApproxNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and + apf = apa.(AccessPathApproxNil).getFront() ) or exists(Node mid | - flowFwd(mid, _, _, apf, ap, config) and + flowFwd(mid, _, _, apf, apa, config) and jumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | + exists(Node mid, AccessPathApproxNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, apa), apf, cc, argApa, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, apa), apf, cc, argApa, config) and + flowFwdConsCand(tc, apf, apa, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, _, cc, _, apf, apa, config) and if flowCand(node, true, _, apf, config) - then argAp = TAccessPathSome(ap) - else argAp = TAccessPathNone() + then argApa = TAccessPathApproxSome(apa) + else argApa = TAccessPathApproxNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argApa, apf, apa, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or - exists(AccessPath argAp0 | - flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + exists(AccessPathApprox argApa0 | + flowFwdOutFromArg(call, node, argApa0, apf, apa, config) and + flowFwdIsEntered(call, cc, argApa, argApa0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argApa, apf, apa, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - AccessPathOption argAp, Configuration config + Node node, TypedContent tc, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwd(mid, cc, argApa, apf0, apa0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPathApprox apa0, Node node2, + CallContext cc, AccessPathApproxOption argApa, Configuration config +) { + flowFwd(node1, cc, argApa, apf0, apa0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + pragma[nomagic] private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config + Node node, AccessPathFrontHead apf0, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, apa0, node, cc, argApa, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(Node n | - flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwd(n, _, _, apf, apa, config) and + flowFwdStore0(n, tc, _, apf, _, config) ) } pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argApa, apf, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argApa, apf, apa, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOutFromArg( - DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + DataFlowCall call, Node node, AccessPathApprox argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathApproxSome(argApa), apf, apa, + config) } /** @@ -1802,166 +1853,174 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathApproxOption argApa, AccessPathApprox apa, + Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argApa, apf, apa, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if `node` with access path `ap` is part of a path from a source to - * a sink in the configuration `config`. + * Holds if `node` with approximate access path `apa` is part of a path from a + * source to a sink in the configuration `config`. * * The Boolean `toReturn` records whether the node must be returned from - * the enclosing callable in order to reach a sink, and if so, `returnAp` - * records the access path of the returned value. + * the enclosing callable in order to reach a sink, and if so, `returnApa` + * records the approximate access path of the returned value. */ private predicate flow( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flow0(node, toReturn, returnAp, ap, config) and - flowFwd(node, _, _, _, ap, config) + flow0(node, toReturn, returnApa, apa, config) and + flowFwd(node, _, _, _, apa, config) } private predicate flow0( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flowFwd(node, _, _, _, ap, config) and + flowFwd(node, _, _, _, apa, config) and config.isSink(node) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil or exists(Node mid | localFlowBigStep(node, mid, true, _, config, _) and - flow(mid, toReturn, returnAp, ap, config) + flow(mid, toReturn, returnApa, apa, config) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and localFlowBigStep(node, mid, false, _, config, _) and - flow(mid, toReturn, returnAp, nil, config) and - ap instanceof AccessPathNil + flow(mid, toReturn, returnApa, nil, config) and + apa instanceof AccessPathApproxNil ) or exists(Node mid | jumpStep(node, mid, config) and - flow(mid, _, _, ap, config) and + flow(mid, _, _, apa, config) and toReturn = false and - returnAp = TAccessPathNone() + returnApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and additionalJumpStep(node, mid, config) and flow(mid, _, _, nil, config) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnApa, apa, config) and + flowConsCand(tc, apa, config) ) or // read - exists(Node mid, AccessPath ap0 | - readFlowFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + readFlowFwd(node, _, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) or // flow into a callable exists(DataFlowCall call | - flowIn(call, node, toReturn, returnAp, ap, config) and + flowIn(call, node, toReturn, returnApa, apa, config) and toReturn = false or - exists(AccessPath returnAp0 | - flowInToReturn(call, node, returnAp0, ap, config) and - flowIsReturned(call, toReturn, returnAp, returnAp0, config) + exists(AccessPathApprox returnApa0 | + flowInToReturn(call, node, returnApa0, apa, config) and + flowIsReturned(call, toReturn, returnApa, returnApa0, config) ) ) or // flow out of a callable - flowOut(_, node, _, _, ap, config) and + flowOut(_, node, _, _, apa, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) - then returnAp = TAccessPathSome(ap) - else returnAp = TAccessPathNone() + if flowFwd(node, any(CallContextCall ccc), TAccessPathApproxSome(_), _, apa, config) + then returnApa = TAccessPathApproxSome(apa) + else returnApa = TAccessPathApproxNone() } pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, apa, _, _, _, config) and + apa0 = push(tc, apa) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { - exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + storeFlowFwd(node, tc, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, apa, _, _, _, config) and + apa0 = pop(tc, apa) and + flowFwdConsCand(tc, _, apa0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPathApprox apa, Configuration config) { exists(Node n, Node mid | - flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + flow(mid, _, _, apa, config) and + readFlowFwd(n, tc, mid, _, apa, config) ) } pragma[nomagic] private predicate flowOut( - DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(Node out, boolean allowsFieldFlow | - flow(out, toReturn, returnAp, ap, config) and + flow(out, toReturn, returnApa, apa, config) and flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowIn( - DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(ParameterNode p, boolean allowsFieldFlow | - flow(p, toReturn, returnAp, ap, config) and + flow(p, toReturn, returnApa, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowInToReturn( - DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config + DataFlowCall call, ArgumentNode arg, AccessPathApprox returnApa, AccessPathApprox apa, + Configuration config ) { - flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) + flowIn(call, arg, true, TAccessPathApproxSome(returnApa), apa, config) } /** @@ -1969,12 +2028,13 @@ private predicate flowInToReturn( */ pragma[nomagic] private predicate flowIsReturned( - DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + DataFlowCall call, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, Configuration config ) { - exists(ReturnNodeExt ret | - flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + exists(ReturnNodeExt ret, CallContextCall ccc | + flowOut(call, ret, toReturn, returnApa, apa, config) and + flowFwd(ret, ccc, TAccessPathApproxSome(_), _, apa, config) and + ccc.matchesCall(call) ) } @@ -1985,21 +2045,23 @@ private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) pragma[noinline] private predicate parameterFlow( - ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config + ParameterNode p, AccessPathApprox apa, DataFlowCallable c, Configuration config ) { - flow(p, true, _, ap, config) and + flow(p, true, _, apa, config) and c = p.getEnclosingCallable() } +private predicate parameterMayFlowThrough(ParameterNode p, AccessPathApprox apa) { + exists(ReturnNodeExt ret, Configuration config, AccessPathApprox apa0 | + parameterFlow(p, apa, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathApproxSome(_), apa0, config) and + flowFwd(ret, any(CallContextCall ccc), TAccessPathApproxSome(apa), _, apa0, config) + ) +} + private newtype TSummaryCtx = TSummaryCtxNone() or - TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | - parameterFlow(p, ap, ret.getEnclosingCallable(), config) and - flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) - ) - } + TSummaryCtxSome(ParameterNode p, AccessPath ap) { parameterMayFlowThrough(p, ap.getApprox()) } /** * A context for generating flow summaries. This represents flow entry through @@ -2034,6 +2096,10 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { } } +private newtype TAccessPath = + TAccessPathNil(DataFlowType t) or + TAccessPathCons(TypedContent head, AccessPath tail) { flowConsCand(head, tail.getApprox(), _) } + private newtype TPathNode = TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) { // A PathNode is introduced by a source ... @@ -2041,13 +2107,13 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(node, _, _, ap, unbind(config)) + flow(node, _, _, ap.getApprox(), unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2059,12 +2125,99 @@ private newtype TPathNode = or // ... or a sink that can be reached from a source exists(PathNodeMid mid | - pathStep(mid, node, _, _, any(AccessPathNil nil)) and + pathStep(mid, node, _, _, TAccessPathNil(_)) and config = unbind(mid.getConfiguration()) ) ) } +/** + * A list of `TypedContent`s followed by a `DataFlowType`. If data flows from a + * source to a given node with a given `AccessPath`, this indicates the sequence + * 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 { + /** Gets the head of this access path, if any. */ + abstract TypedContent getHead(); + + /** Gets the tail of this access path, if any. */ + abstract AccessPath getTail(); + + /** Gets the front of this access path. */ + abstract AccessPathFront getFront(); + + /** Gets the approximation of this access path. */ + abstract AccessPathApprox getApprox(); + + /** Gets the length of this access path. */ + abstract int length(); + + /** Gets a textual representation of this access path. */ + abstract string toString(); + + /** Gets the access path obtained by popping `tc` from this access path, if any. */ + final AccessPath pop(TypedContent tc) { + result = this.getTail() and + tc = this.getHead() + } + + /** Gets the access path obtained by pushing `tc` onto this access path. */ + final AccessPath push(TypedContent tc) { this = result.pop(tc) } +} + +private class AccessPathNil extends AccessPath, TAccessPathNil { + private DataFlowType t; + + AccessPathNil() { this = TAccessPathNil(t) } + + DataFlowType getType() { result = t } + + override TypedContent getHead() { none() } + + override AccessPath getTail() { none() } + + override AccessPathFrontNil getFront() { result = TFrontNil(t) } + + override AccessPathApproxNil getApprox() { result = TNil(t) } + + override int length() { result = 0 } + + override string toString() { result = concat(": " + ppReprType(t)) } +} + +private class AccessPathCons extends AccessPath, TAccessPathCons { + private TypedContent head; + private AccessPath tail; + + AccessPathCons() { this = TAccessPathCons(head, tail) } + + override TypedContent getHead() { result = head } + + override AccessPath getTail() { result = tail } + + override AccessPathFrontHead getFront() { result = TFrontHead(head) } + + override AccessPathApproxCons getApprox() { + result = TConsNil(head, tail.(AccessPathNil).getType()) + or + result = TConsCons(head, tail.getHead(), this.length()) + } + + override int length() { result = 1 + tail.length() } + + private string toStringImpl() { + exists(DataFlowType t | + tail = TAccessPathNil(t) and + result = head.toString() + "]" + concat(" : " + ppReprType(t)) + ) + or + result = head + ", " + tail.(AccessPathCons).toStringImpl() + } + + override string toString() { result = "[" + this.toStringImpl() } +} + /** * A `Node` augmented with a call context (except for sinks), an access path, and a configuration. * Only those `PathNode`s that are reachable from a source are generated. @@ -2098,14 +2251,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2350,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2387,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2251,12 +2421,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2267,50 +2437,53 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } private predicate pathOutOfCallable0( - PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPath ap, Configuration config + PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa, + Configuration config ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and - ap = mid.getAp() and + innercc instanceof CallContextNoCall and + apa = mid.getAp().getApprox() and config = mid.getConfiguration() } pragma[nomagic] private predicate pathOutOfCallable1( - PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPath ap, + PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPathApprox apa, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | - pathOutOfCallable0(mid, pos, innercc, ap, config) and + pathOutOfCallable0(mid, pos, innercc, apa, config) and c = pos.getCallable() and kind = pos.getKind() and resolveReturn(innercc, c, call) @@ -2321,10 +2494,10 @@ private predicate pathOutOfCallable1( pragma[noinline] private Node getAnOutNodeFlow( - ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config + ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ) { result = kind.getAnOutNode(call) and - flow(result, _, _, ap, config) + flow(result, _, _, apa, config) } /** @@ -2333,10 +2506,9 @@ private Node getAnOutNodeFlow( */ pragma[noinline] private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { - exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | - pathOutOfCallable1(mid, call, kind, cc, ap, config) - | - out = getAnOutNodeFlow(kind, call, ap, config) + exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config | + pathOutOfCallable1(mid, call, kind, cc, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -2345,22 +2517,23 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa ) { exists(ArgumentNode arg | arg = mid.getNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and - ap = mid.getAp() + ap = mid.getAp() and + apa = ap.getApprox() ) } pragma[noinline] private predicate parameterCand( - DataFlowCallable callable, int i, AccessPath ap, Configuration config + DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { exists(ParameterNode p | - flow(p, _, _, ap, config) and + flow(p, _, _, apa, config) and p.isParameterOf(callable, i) ) } @@ -2370,9 +2543,11 @@ private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, AccessPath ap ) { - pathIntoArg(mid, i, outercc, call, ap) and - callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), ap, mid.getConfiguration()) + exists(AccessPathApprox apa | + pathIntoArg(mid, i, outercc, call, ap, apa) and + callable = resolveCall(call, outercc) and + parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + ) } /** @@ -2403,7 +2578,8 @@ private predicate pathIntoCallable( /** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */ pragma[nomagic] private predicate paramFlowsThrough( - ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config + ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(PathNodeMid mid, ReturnNodeExt ret, int pos | mid.getNode() = ret and @@ -2412,6 +2588,7 @@ private predicate paramFlowsThrough( sc = mid.getSummaryCtx() and config = mid.getConfiguration() and ap = mid.getAp() and + apa = ap.getApprox() and pos = sc.getParameterPos() and not kind.(ParamUpdateReturnKind).getPosition() = pos ) @@ -2419,11 +2596,12 @@ private predicate paramFlowsThrough( pragma[nomagic] private predicate pathThroughCallable0( - DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap + DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, + AccessPathApprox apa ) { exists(CallContext innercc, SummaryCtx sc | pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, unbind(mid.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration())) ) } @@ -2433,9 +2611,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind | - pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | + pathThroughCallable0(call, mid, kind, cc, ap, apa) and + out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration())) ) } @@ -2521,10 +2699,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2533,7 +2711,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2544,7 +2722,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2562,15 +2740,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2591,7 +2769,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2608,7 +2786,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2721,7 +2899,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2737,7 +2915,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2746,11 +2924,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2769,35 +2948,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( @@ -2806,7 +2992,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll index 852f54974e24..892250f44bb8 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll @@ -22,7 +22,7 @@ private module Cached { exists(int i | viableParam(call, i, p) and arg.argumentOf(call, i) and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(p)) + compatibleTypes(getNodeType(arg), getNodeType(p)) ) } @@ -147,174 +147,140 @@ private module Cached { } } - private module LocalFlowBigStep { - private predicate localFlowEntry(Node n) { - Cand::cand(_, n) and - ( - n instanceof ParameterNode or - n instanceof OutNode or - readStep(_, _, n) or - n instanceof CastNode - ) - } - - private predicate localFlowExit(Node n) { - Cand::cand(_, n) and - ( - n instanceof ArgumentNode - or - n instanceof ReturnNode - or - readStep(n, _, _) - or - n instanceof CastNode - or - n = - any(PostUpdateNode pun | Cand::parameterValueFlowsToPreUpdateCand(_, pun)) - .getPreUpdateNode() - ) - } - - pragma[nomagic] - private predicate localFlowStepPlus(Node node1, Node node2) { - localFlowEntry(node1) and - simpleLocalFlowStep(node1, node2) and - node1 != node2 - or - exists(Node mid | - localFlowStepPlus(node1, mid) and - simpleLocalFlowStep(mid, node2) and - not mid instanceof CastNode - ) - } - - pragma[nomagic] - predicate localFlowBigStep(Node node1, Node node2) { - localFlowStepPlus(node1, node2) and - localFlowExit(node2) - } - } - /** * The final flow-through calculation: * - * - Input access paths are abstracted with a `ContentOption` parameter - * that represents the head of the access path. `TContentNone()` means that - * the access path is unrestricted. + * - Calculated flow is either value-preserving (`read = TReadStepTypesNone()`) + * or summarized as a single read step with before and after types recorded + * in the `ReadStepTypesOption` parameter. * - Types are checked using the `compatibleTypes()` relation. */ private module Final { /** * Holds if `p` can flow to `node` in the same callable using only - * value-preserving steps, not taking call contexts into account. + * value-preserving steps and possibly a single read step, not taking + * call contexts into account. * - * `contentIn` describes the content of `p` that can flow to `node` - * (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ - predicate parameterValueFlow(ParameterNode p, Node node, ContentOption contentIn) { - parameterValueFlow0(p, node, contentIn) and + predicate parameterValueFlow(ParameterNode p, Node node, ReadStepTypesOption read) { + parameterValueFlow0(p, node, read) and if node instanceof CastingNode then // normal flow through - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) + read = TReadStepTypesNone() and + compatibleTypes(getNodeType(p), getNodeType(node)) or // getter - exists(Content fIn | - contentIn.getContent() = fIn and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(node)) - ) + compatibleTypes(read.getContentType(), getNodeType(node)) else any() } pragma[nomagic] - private predicate parameterValueFlow0(ParameterNode p, Node node, ContentOption contentIn) { + private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() + read = TReadStepTypesNone() or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn) and - LocalFlowBigStep::localFlowBigStep(mid, node) + parameterValueFlow(p, mid, read) and + simpleLocalFlowStep(mid, node) ) or // read - exists(Node mid, Content f | - parameterValueFlow(p, mid, TContentNone()) and - readStep(mid, f, node) and - contentIn.getContent() = f and + exists(Node mid | + parameterValueFlow(p, mid, TReadStepTypesNone()) and + readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, + read.getContentType()) and Cand::parameterValueFlowReturnCand(p, _, true) and - compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) + compatibleTypes(getNodeType(p), read.getContainerType()) ) or + parameterValueFlow0_0(TReadStepTypesNone(), p, node, read) + } + + pragma[nomagic] + private predicate parameterValueFlow0_0( + ReadStepTypesOption mustBeNone, ParameterNode p, Node node, ReadStepTypesOption read + ) { // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, TContentNone()) and - argumentValueFlowsThrough(arg, contentIn, node) + parameterValueFlowArg(p, arg, mustBeNone) and + argumentValueFlowsThrough(arg, read, node) ) or // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, contentIn) and - argumentValueFlowsThrough(arg, TContentNone(), node) + parameterValueFlowArg(p, arg, read) and + argumentValueFlowsThrough(arg, mustBeNone, node) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn + ParameterNode p, ArgumentNode arg, ReadStepTypesOption read ) { - parameterValueFlow(p, arg, contentIn) and + parameterValueFlow(p, arg, read) and Cand::argumentValueFlowsThroughCand(arg, _, _) } pragma[nomagic] private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn + DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, kind, contentIn) + parameterValueFlowReturn(param, kind, read) ) } /** - * Holds if `arg` flows to `out` through a call using only value-preserving steps, - * not taking call contexts into account. + * Holds if `arg` flows to `out` through a call using only + * value-preserving steps and possibly a single read step, not taking + * call contexts into account. * - * `contentIn` describes the content of `arg` that can flow to `out` (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ pragma[nomagic] - predicate argumentValueFlowsThrough(ArgumentNode arg, ContentOption contentIn, Node out) { + predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) { exists(DataFlowCall call, ReturnKind kind | - argumentValueFlowsThrough0(call, arg, kind, contentIn) and + argumentValueFlowsThrough0(call, arg, kind, read) and out = getAnOutNode(call, kind) | // normal flow through - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) + read = TReadStepTypesNone() and + compatibleTypes(getNodeType(arg), getNodeType(out)) or // getter - exists(Content fIn | - contentIn.getContent() = fIn and - compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(out)) - ) + compatibleTypes(getNodeType(arg), read.getContainerType()) and + compatibleTypes(read.getContentType(), getNodeType(out)) ) } + /** + * Holds if `arg` flows to `out` through a call using only + * value-preserving steps and a single read step, not taking call + * contexts into account, thus representing a getter-step. + */ + predicate getterStep(ArgumentNode arg, Content c, Node out) { + argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out) + } + /** * Holds if `p` can flow to a return node of kind `kind` in the same - * callable using only value-preserving steps. + * callable using only value-preserving steps and possibly a single read + * step. * - * `contentIn` describes the content of `p` that can flow to the return - * node (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ private predicate parameterValueFlowReturn( - ParameterNode p, ReturnKind kind, ContentOption contentIn + ParameterNode p, ReturnKind kind, ReadStepTypesOption read ) { exists(ReturnNode ret | - parameterValueFlow(p, ret, contentIn) and + parameterValueFlow(p, ret, read) and kind = ret.getKind() ) } @@ -323,37 +289,107 @@ private module Cached { import Final } + import FlowThrough + + cached + private module DispatchWithCallContext { + /** + * Holds if the call context `ctx` reduces the set of viable run-time + * dispatch targets of call `call` in `c`. + */ + cached + predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) { + exists(int tgts, int ctxtgts | + mayBenefitFromCallContext(call, c) and + c = viableCallable(ctx) and + ctxtgts = count(viableImplInCallContext(call, ctx)) and + tgts = strictcount(viableCallable(call)) and + ctxtgts < tgts + ) + } + + /** + * Gets a viable run-time dispatch target for the call `call` in the + * context `ctx`. This is restricted to those calls for which a context + * makes a difference. + */ + cached + DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) and + reducedViableImplInCallContext(call, _, ctx) + } + + /** + * Holds if flow returning from callable `c` to call `call` might return + * further and if this path restricts the set of call sites that can be + * returned to. + */ + cached + predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { + exists(int tgts, int ctxtgts | + mayBenefitFromCallContext(call, _) and + c = viableCallable(call) and + ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and + tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and + ctxtgts < tgts + ) + } + + /** + * Gets a viable run-time dispatch target for the call `call` in the + * context `ctx`. This is restricted to those calls and results for which + * the return flow from the result to `call` restricts the possible context + * `ctx`. + */ + cached + DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) and + reducedViableImplInReturn(result, call) + } + } + + import DispatchWithCallContext + /** * Holds if `p` can flow to the pre-update node associated with post-update * node `n`, in the same callable, using only value-preserving steps. */ cached predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone()) + parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone()) } - /** - * Holds if data can flow from `node1` to `node2` via a direct assignment to - * `f`. - * - * This includes reverse steps through reads when the result of the read has - * been stored into, in order to handle cases like `x.f1.f2 = y`. - */ - cached - predicate store(Node node1, Content f, Node node2) { - storeStep(node1, f, node2) and readStep(_, f, _) + private predicate store( + Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType + ) { + storeStep(node1, c, node2) and + readStep(_, c, _) and + contentType = getNodeType(node1) and + containerType = getNodeType(node2) or exists(Node n1, Node n2 | n1 = node1.(PostUpdateNode).getPreUpdateNode() and n2 = node2.(PostUpdateNode).getPreUpdateNode() | - argumentValueFlowsThrough(n2, TContentSome(f), n1) + argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1) or - readStep(n2, f, n1) + readStep(n2, c, n1) and + contentType = getNodeType(n1) and + containerType = getNodeType(n2) ) } - import FlowThrough + /** + * Holds if data can flow from `node1` to `node2` via a direct assignment to + * `f`. + * + * This includes reverse steps through reads when the result of the read has + * been stored into, in order to handle cases like `x.f1.f2 = y`. + */ + cached + predicate store(Node node1, TypedContent tc, Node node2, DataFlowType contentType) { + store(node1, tc.getContent(), node2, contentType, tc.getContainerType()) + } /** * Holds if the call context `call` either improves virtual dispatch in @@ -397,10 +433,13 @@ private module Cached { TBooleanNone() or TBooleanSome(boolean b) { b = true or b = false } + cached + newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } + cached newtype TAccessPathFront = TFrontNil(DataFlowType t) or - TFrontHead(Content f) + TFrontHead(TypedContent tc) cached newtype TAccessPathFrontOption = @@ -415,25 +454,38 @@ class CastingNode extends Node { CastingNode() { this instanceof ParameterNode or this instanceof CastNode or - this instanceof OutNodeExt + this instanceof OutNodeExt or + // For reads, `x.f`, we want to check that the tracked type after the read (which + // is obtained by popping the head of the access path stack) is compatible with + // the type of `x.f`. + readStep(_, _, this) } } -newtype TContentOption = - TContentNone() or - TContentSome(Content f) +private predicate readStepWithTypes( + Node n1, DataFlowType container, Content c, Node n2, DataFlowType content +) { + readStep(n1, c, n2) and + container = getNodeType(n1) and + content = getNodeType(n2) +} -private class ContentOption extends TContentOption { - Content getContent() { this = TContentSome(result) } +private newtype TReadStepTypesOption = + TReadStepTypesNone() or + TReadStepTypesSome(DataFlowType container, Content c, DataFlowType content) { + readStepWithTypes(_, container, c, _, content) + } - predicate hasContent() { exists(this.getContent()) } +private class ReadStepTypesOption extends TReadStepTypesOption { + predicate isSome() { this instanceof TReadStepTypesSome } - string toString() { - result = this.getContent().toString() - or - not this.hasContent() and - result = "" - } + DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) } + + Content getContent() { this = TReadStepTypesSome(_, result, _) } + + DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) } + + string toString() { if this.isSome() then result = "Some(..)" else result = "None()" } } /** @@ -460,13 +512,19 @@ abstract class CallContext extends TCallContext { abstract predicate relevantFor(DataFlowCallable callable); } -class CallContextAny extends CallContext, TAnyCallContext { +abstract class CallContextNoCall extends CallContext { } + +class CallContextAny extends CallContextNoCall, TAnyCallContext { override string toString() { result = "CcAny" } override predicate relevantFor(DataFlowCallable callable) { any() } } -abstract class CallContextCall extends CallContext { } +abstract class CallContextCall extends CallContext { + /** Holds if this call context may be `call`. */ + bindingset[call] + abstract predicate matchesCall(DataFlowCall call); +} class CallContextSpecificCall extends CallContextCall, TSpecificCall { override string toString() { @@ -477,6 +535,8 @@ class CallContextSpecificCall extends CallContextCall, TSpecificCall { recordDataFlowCallSite(getCall(), callable) } + override predicate matchesCall(DataFlowCall call) { call = this.getCall() } + DataFlowCall getCall() { this = TSpecificCall(result) } } @@ -486,9 +546,11 @@ class CallContextSomeCall extends CallContextCall, TSomeCall { override predicate relevantFor(DataFlowCallable callable) { exists(ParameterNode p | p.getEnclosingCallable() = callable) } + + override predicate matchesCall(DataFlowCall call) { any() } } -class CallContextReturn extends CallContext, TReturn { +class CallContextReturn extends CallContextNoCall, TReturn { override string toString() { exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")") } @@ -678,9 +740,6 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { result = viableCallable(call) and cc instanceof CallContextReturn } -pragma[noinline] -DataFlowType getErasedNodeTypeBound(Node n) { result = getErasedRepr(n.getTypeBound()) } - predicate read = readStep/3; /** An optional Boolean value. */ @@ -692,6 +751,23 @@ class BooleanOption extends TBooleanOption { } } +/** Content tagged with the type of a containing object. */ +class TypedContent extends MkTypedContent { + private Content c; + private DataFlowType t; + + TypedContent() { this = MkTypedContent(c, t) } + + /** Gets the content. */ + Content getContent() { result = c } + + /** Gets the container type. */ + DataFlowType getContainerType() { result = t } + + /** Gets a textual representation of this content. */ + string toString() { result = c.toString() } +} + /** * The front of an access path. This is either a head or a nil. */ @@ -702,25 +778,36 @@ abstract class AccessPathFront extends TAccessPathFront { abstract boolean toBoolNonEmpty(); - predicate headUsesContent(Content f) { this = TFrontHead(f) } + predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) } + + predicate isClearedAt(Node n) { + exists(TypedContent tc | + this.headUsesContent(tc) and + clearsContent(n, tc.getContent()) + ) + } } class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } + private DataFlowType t; + + AccessPathFrontNil() { this = TFrontNil(t) } + + override string toString() { result = ppReprType(t) } - override DataFlowType getType() { this = TFrontNil(result) } + override DataFlowType getType() { result = t } override boolean toBoolNonEmpty() { result = false } } class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } + private TypedContent tc; - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } + AccessPathFrontHead() { this = TFrontHead(tc) } + + override string toString() { result = tc.toString() } + + override DataFlowType getType() { result = tc.getContainerType() } override boolean toBoolNonEmpty() { result = true } } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll index 0dc3b8eff450..4e1cd281488f 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll @@ -37,21 +37,12 @@ module Consistency { ) } - query predicate uniqueTypeBound(Node n, string msg) { + query predicate uniqueType(Node n, string msg) { exists(int c | n instanceof RelevantNode and - c = count(n.getTypeBound()) and + c = count(getNodeType(n)) and c != 1 and - msg = "Node should have one type bound but has " + c + "." - ) - } - - query predicate uniqueTypeRepr(Node n, string msg) { - exists(int c | - n instanceof RelevantNode and - c = count(getErasedRepr(n.getTypeBound())) and - c != 1 and - msg = "Node should have one type representation but has " + c + "." + msg = "Node should have one type but has " + c + "." ) } @@ -104,7 +95,7 @@ module Consistency { msg = "Local flow step does not preserve enclosing callable." } - private DataFlowType typeRepr() { result = getErasedRepr(any(Node n).getTypeBound()) } + private DataFlowType typeRepr() { result = getNodeType(_) } query predicate compatibleTypesReflexive(DataFlowType t, string msg) { t = typeRepr() and @@ -132,8 +123,18 @@ module Consistency { n.getEnclosingCallable() != call.getEnclosingCallable() } + // This predicate helps the compiler forget that in some languages + // it is impossible for a result of `getPreUpdateNode` to be an + // instance of `PostUpdateNode`. + private Node getPre(PostUpdateNode n) { + result = n.getPreUpdateNode() + or + none() + } + query predicate postIsNotPre(PostUpdateNode n, string msg) { - n.getPreUpdateNode() = n and msg = "PostUpdateNode should not equal its pre-update node." + getPre(n) = n and + msg = "PostUpdateNode should not equal its pre-update node." } query predicate postHasUniquePre(PostUpdateNode n, string msg) { @@ -161,15 +162,14 @@ module Consistency { msg = "Origin of readStep is missing a PostUpdateNode." } - query predicate storeIsPostUpdate(Node n, string msg) { - storeStep(_, _, n) and - not n instanceof PostUpdateNode and - msg = "Store targets should be PostUpdateNodes." - } - query predicate argHasPostUpdate(ArgumentNode n, string msg) { not hasPost(n) and not isImmutableOrUnobservable(n) and msg = "ArgumentNode is missing PostUpdateNode." } + + query predicate postWithInFlow(PostUpdateNode n, string msg) { + simpleLocalFlowStep(_, n) and + msg = "PostUpdateNode should not be the target of local flow." + } } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index f876c04d6c66..8bc3d75ff86e 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -286,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -318,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -417,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -447,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -566,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -748,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -781,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -896,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -930,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1046,11 +1051,22 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1058,9 +1074,9 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1074,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1108,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1122,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1154,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1183,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1197,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1223,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1261,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } +pragma[nomagic] +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + pragma[nomagic] private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1385,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1417,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1497,24 +1523,24 @@ private predicate flowCandIsReturned( ) } -private newtype TAccessPath = +private newtype TAccessPathApprox = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two - * elements of the list and its length are tracked. If data flows from a source to - * a given node with a given `AccessPath`, this indicates the sequence 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. + * Conceptually a list of `TypedContent`s followed by a `DataFlowType`, but only + * the first two elements of the list and its length are tracked. If data flows + * from a source to a given node with a given `AccessPathApprox`, this indicates + * the sequence 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 { +abstract private class AccessPathApprox extends TAccessPathApprox { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1522,20 +1548,18 @@ abstract private class AccessPath extends TAccessPath { abstract AccessPathFront getFront(); - /** - * Holds if this access path has `head` at the front and may be followed by `tail`. - */ - abstract predicate pop(Content head, AccessPath tail); + /** Gets the access path obtained by popping `head` from this path, if any. */ + abstract AccessPathApprox pop(TypedContent head); } -private class AccessPathNil extends AccessPath, TNil { +private class AccessPathApproxNil extends AccessPathApprox, TNil { private DataFlowType t; - AccessPathNil() { this = TNil(t) } + AccessPathApproxNil() { this = TNil(t) } override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1543,258 +1567,285 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override AccessPathApprox pop(TypedContent head) { none() } } -abstract private class AccessPathCons extends AccessPath { } +abstract private class AccessPathApproxCons extends AccessPathApprox { } -private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; +private class AccessPathApproxConsNil extends AccessPathApproxCons, TConsNil { + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathApproxConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override AccessPathApprox pop(TypedContent head) { head = tc and result = TNil(t) } } -private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; +private class AccessPathApproxConsCons extends AccessPathApproxCons, TConsCons { + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathApproxConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override AccessPathApprox pop(TypedContent head) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + result = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + result = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPathApprox pop(TypedContent tc, AccessPathApprox apa) { result = apa.pop(tc) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPathApprox push(TypedContent tc, AccessPathApprox apa) { apa = pop(tc, result) } -private newtype TAccessPathOption = - TAccessPathNone() or - TAccessPathSome(AccessPath ap) +private newtype TAccessPathApproxOption = + TAccessPathApproxNone() or + TAccessPathApproxSome(AccessPathApprox apa) -private class AccessPathOption extends TAccessPathOption { +private class AccessPathApproxOption extends TAccessPathApproxOption { string toString() { - this = TAccessPathNone() and result = "" + this = TAccessPathApproxNone() and result = "" or - this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + this = TAccessPathApproxSome(any(AccessPathApprox apa | result = apa.toString())) } } /** - * Holds if `node` is reachable with access path `ap` from a source in - * the configuration `config`. + * Holds if `node` is reachable with approximate access path `apa` from a source + * in the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an - * argument in a call, and if so, `argAp` records the access path of that - * argument. + * The call context `cc` records whether the node is reached through an + * argument in a call, and if so, `argApa` records the approximate access path + * of that argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argApa, apf, apa, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, apf, apa, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and - apf = ap.(AccessPathNil).getFront() + exists(Node mid, AccessPathApproxNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and + apf = apa.(AccessPathApproxNil).getFront() ) or exists(Node mid | - flowFwd(mid, _, _, apf, ap, config) and + flowFwd(mid, _, _, apf, apa, config) and jumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | + exists(Node mid, AccessPathApproxNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, apa), apf, cc, argApa, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, apa), apf, cc, argApa, config) and + flowFwdConsCand(tc, apf, apa, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, _, cc, _, apf, apa, config) and if flowCand(node, true, _, apf, config) - then argAp = TAccessPathSome(ap) - else argAp = TAccessPathNone() + then argApa = TAccessPathApproxSome(apa) + else argApa = TAccessPathApproxNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argApa, apf, apa, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or - exists(AccessPath argAp0 | - flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + exists(AccessPathApprox argApa0 | + flowFwdOutFromArg(call, node, argApa0, apf, apa, config) and + flowFwdIsEntered(call, cc, argApa, argApa0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argApa, apf, apa, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - AccessPathOption argAp, Configuration config + Node node, TypedContent tc, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwd(mid, cc, argApa, apf0, apa0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPathApprox apa0, Node node2, + CallContext cc, AccessPathApproxOption argApa, Configuration config +) { + flowFwd(node1, cc, argApa, apf0, apa0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + pragma[nomagic] private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config + Node node, AccessPathFrontHead apf0, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, apa0, node, cc, argApa, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(Node n | - flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwd(n, _, _, apf, apa, config) and + flowFwdStore0(n, tc, _, apf, _, config) ) } pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argApa, apf, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argApa, apf, apa, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOutFromArg( - DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + DataFlowCall call, Node node, AccessPathApprox argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathApproxSome(argApa), apf, apa, + config) } /** @@ -1802,166 +1853,174 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathApproxOption argApa, AccessPathApprox apa, + Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argApa, apf, apa, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if `node` with access path `ap` is part of a path from a source to - * a sink in the configuration `config`. + * Holds if `node` with approximate access path `apa` is part of a path from a + * source to a sink in the configuration `config`. * * The Boolean `toReturn` records whether the node must be returned from - * the enclosing callable in order to reach a sink, and if so, `returnAp` - * records the access path of the returned value. + * the enclosing callable in order to reach a sink, and if so, `returnApa` + * records the approximate access path of the returned value. */ private predicate flow( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flow0(node, toReturn, returnAp, ap, config) and - flowFwd(node, _, _, _, ap, config) + flow0(node, toReturn, returnApa, apa, config) and + flowFwd(node, _, _, _, apa, config) } private predicate flow0( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flowFwd(node, _, _, _, ap, config) and + flowFwd(node, _, _, _, apa, config) and config.isSink(node) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil or exists(Node mid | localFlowBigStep(node, mid, true, _, config, _) and - flow(mid, toReturn, returnAp, ap, config) + flow(mid, toReturn, returnApa, apa, config) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and localFlowBigStep(node, mid, false, _, config, _) and - flow(mid, toReturn, returnAp, nil, config) and - ap instanceof AccessPathNil + flow(mid, toReturn, returnApa, nil, config) and + apa instanceof AccessPathApproxNil ) or exists(Node mid | jumpStep(node, mid, config) and - flow(mid, _, _, ap, config) and + flow(mid, _, _, apa, config) and toReturn = false and - returnAp = TAccessPathNone() + returnApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and additionalJumpStep(node, mid, config) and flow(mid, _, _, nil, config) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnApa, apa, config) and + flowConsCand(tc, apa, config) ) or // read - exists(Node mid, AccessPath ap0 | - readFlowFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + readFlowFwd(node, _, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) or // flow into a callable exists(DataFlowCall call | - flowIn(call, node, toReturn, returnAp, ap, config) and + flowIn(call, node, toReturn, returnApa, apa, config) and toReturn = false or - exists(AccessPath returnAp0 | - flowInToReturn(call, node, returnAp0, ap, config) and - flowIsReturned(call, toReturn, returnAp, returnAp0, config) + exists(AccessPathApprox returnApa0 | + flowInToReturn(call, node, returnApa0, apa, config) and + flowIsReturned(call, toReturn, returnApa, returnApa0, config) ) ) or // flow out of a callable - flowOut(_, node, _, _, ap, config) and + flowOut(_, node, _, _, apa, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) - then returnAp = TAccessPathSome(ap) - else returnAp = TAccessPathNone() + if flowFwd(node, any(CallContextCall ccc), TAccessPathApproxSome(_), _, apa, config) + then returnApa = TAccessPathApproxSome(apa) + else returnApa = TAccessPathApproxNone() } pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, apa, _, _, _, config) and + apa0 = push(tc, apa) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { - exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + storeFlowFwd(node, tc, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, apa, _, _, _, config) and + apa0 = pop(tc, apa) and + flowFwdConsCand(tc, _, apa0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPathApprox apa, Configuration config) { exists(Node n, Node mid | - flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + flow(mid, _, _, apa, config) and + readFlowFwd(n, tc, mid, _, apa, config) ) } pragma[nomagic] private predicate flowOut( - DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(Node out, boolean allowsFieldFlow | - flow(out, toReturn, returnAp, ap, config) and + flow(out, toReturn, returnApa, apa, config) and flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowIn( - DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(ParameterNode p, boolean allowsFieldFlow | - flow(p, toReturn, returnAp, ap, config) and + flow(p, toReturn, returnApa, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowInToReturn( - DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config + DataFlowCall call, ArgumentNode arg, AccessPathApprox returnApa, AccessPathApprox apa, + Configuration config ) { - flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) + flowIn(call, arg, true, TAccessPathApproxSome(returnApa), apa, config) } /** @@ -1969,12 +2028,13 @@ private predicate flowInToReturn( */ pragma[nomagic] private predicate flowIsReturned( - DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + DataFlowCall call, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, Configuration config ) { - exists(ReturnNodeExt ret | - flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + exists(ReturnNodeExt ret, CallContextCall ccc | + flowOut(call, ret, toReturn, returnApa, apa, config) and + flowFwd(ret, ccc, TAccessPathApproxSome(_), _, apa, config) and + ccc.matchesCall(call) ) } @@ -1985,21 +2045,23 @@ private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) pragma[noinline] private predicate parameterFlow( - ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config + ParameterNode p, AccessPathApprox apa, DataFlowCallable c, Configuration config ) { - flow(p, true, _, ap, config) and + flow(p, true, _, apa, config) and c = p.getEnclosingCallable() } +private predicate parameterMayFlowThrough(ParameterNode p, AccessPathApprox apa) { + exists(ReturnNodeExt ret, Configuration config, AccessPathApprox apa0 | + parameterFlow(p, apa, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathApproxSome(_), apa0, config) and + flowFwd(ret, any(CallContextCall ccc), TAccessPathApproxSome(apa), _, apa0, config) + ) +} + private newtype TSummaryCtx = TSummaryCtxNone() or - TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | - parameterFlow(p, ap, ret.getEnclosingCallable(), config) and - flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) - ) - } + TSummaryCtxSome(ParameterNode p, AccessPath ap) { parameterMayFlowThrough(p, ap.getApprox()) } /** * A context for generating flow summaries. This represents flow entry through @@ -2034,6 +2096,10 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { } } +private newtype TAccessPath = + TAccessPathNil(DataFlowType t) or + TAccessPathCons(TypedContent head, AccessPath tail) { flowConsCand(head, tail.getApprox(), _) } + private newtype TPathNode = TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) { // A PathNode is introduced by a source ... @@ -2041,13 +2107,13 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(node, _, _, ap, unbind(config)) + flow(node, _, _, ap.getApprox(), unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2059,12 +2125,99 @@ private newtype TPathNode = or // ... or a sink that can be reached from a source exists(PathNodeMid mid | - pathStep(mid, node, _, _, any(AccessPathNil nil)) and + pathStep(mid, node, _, _, TAccessPathNil(_)) and config = unbind(mid.getConfiguration()) ) ) } +/** + * A list of `TypedContent`s followed by a `DataFlowType`. If data flows from a + * source to a given node with a given `AccessPath`, this indicates the sequence + * 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 { + /** Gets the head of this access path, if any. */ + abstract TypedContent getHead(); + + /** Gets the tail of this access path, if any. */ + abstract AccessPath getTail(); + + /** Gets the front of this access path. */ + abstract AccessPathFront getFront(); + + /** Gets the approximation of this access path. */ + abstract AccessPathApprox getApprox(); + + /** Gets the length of this access path. */ + abstract int length(); + + /** Gets a textual representation of this access path. */ + abstract string toString(); + + /** Gets the access path obtained by popping `tc` from this access path, if any. */ + final AccessPath pop(TypedContent tc) { + result = this.getTail() and + tc = this.getHead() + } + + /** Gets the access path obtained by pushing `tc` onto this access path. */ + final AccessPath push(TypedContent tc) { this = result.pop(tc) } +} + +private class AccessPathNil extends AccessPath, TAccessPathNil { + private DataFlowType t; + + AccessPathNil() { this = TAccessPathNil(t) } + + DataFlowType getType() { result = t } + + override TypedContent getHead() { none() } + + override AccessPath getTail() { none() } + + override AccessPathFrontNil getFront() { result = TFrontNil(t) } + + override AccessPathApproxNil getApprox() { result = TNil(t) } + + override int length() { result = 0 } + + override string toString() { result = concat(": " + ppReprType(t)) } +} + +private class AccessPathCons extends AccessPath, TAccessPathCons { + private TypedContent head; + private AccessPath tail; + + AccessPathCons() { this = TAccessPathCons(head, tail) } + + override TypedContent getHead() { result = head } + + override AccessPath getTail() { result = tail } + + override AccessPathFrontHead getFront() { result = TFrontHead(head) } + + override AccessPathApproxCons getApprox() { + result = TConsNil(head, tail.(AccessPathNil).getType()) + or + result = TConsCons(head, tail.getHead(), this.length()) + } + + override int length() { result = 1 + tail.length() } + + private string toStringImpl() { + exists(DataFlowType t | + tail = TAccessPathNil(t) and + result = head.toString() + "]" + concat(" : " + ppReprType(t)) + ) + or + result = head + ", " + tail.(AccessPathCons).toStringImpl() + } + + override string toString() { result = "[" + this.toStringImpl() } +} + /** * A `Node` augmented with a call context (except for sinks), an access path, and a configuration. * Only those `PathNode`s that are reachable from a source are generated. @@ -2098,14 +2251,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2350,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2387,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2251,12 +2421,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2267,50 +2437,53 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } private predicate pathOutOfCallable0( - PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPath ap, Configuration config + PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa, + Configuration config ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and - ap = mid.getAp() and + innercc instanceof CallContextNoCall and + apa = mid.getAp().getApprox() and config = mid.getConfiguration() } pragma[nomagic] private predicate pathOutOfCallable1( - PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPath ap, + PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPathApprox apa, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | - pathOutOfCallable0(mid, pos, innercc, ap, config) and + pathOutOfCallable0(mid, pos, innercc, apa, config) and c = pos.getCallable() and kind = pos.getKind() and resolveReturn(innercc, c, call) @@ -2321,10 +2494,10 @@ private predicate pathOutOfCallable1( pragma[noinline] private Node getAnOutNodeFlow( - ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config + ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ) { result = kind.getAnOutNode(call) and - flow(result, _, _, ap, config) + flow(result, _, _, apa, config) } /** @@ -2333,10 +2506,9 @@ private Node getAnOutNodeFlow( */ pragma[noinline] private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { - exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | - pathOutOfCallable1(mid, call, kind, cc, ap, config) - | - out = getAnOutNodeFlow(kind, call, ap, config) + exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config | + pathOutOfCallable1(mid, call, kind, cc, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -2345,22 +2517,23 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa ) { exists(ArgumentNode arg | arg = mid.getNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and - ap = mid.getAp() + ap = mid.getAp() and + apa = ap.getApprox() ) } pragma[noinline] private predicate parameterCand( - DataFlowCallable callable, int i, AccessPath ap, Configuration config + DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { exists(ParameterNode p | - flow(p, _, _, ap, config) and + flow(p, _, _, apa, config) and p.isParameterOf(callable, i) ) } @@ -2370,9 +2543,11 @@ private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, AccessPath ap ) { - pathIntoArg(mid, i, outercc, call, ap) and - callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), ap, mid.getConfiguration()) + exists(AccessPathApprox apa | + pathIntoArg(mid, i, outercc, call, ap, apa) and + callable = resolveCall(call, outercc) and + parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + ) } /** @@ -2403,7 +2578,8 @@ private predicate pathIntoCallable( /** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */ pragma[nomagic] private predicate paramFlowsThrough( - ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config + ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(PathNodeMid mid, ReturnNodeExt ret, int pos | mid.getNode() = ret and @@ -2412,6 +2588,7 @@ private predicate paramFlowsThrough( sc = mid.getSummaryCtx() and config = mid.getConfiguration() and ap = mid.getAp() and + apa = ap.getApprox() and pos = sc.getParameterPos() and not kind.(ParamUpdateReturnKind).getPosition() = pos ) @@ -2419,11 +2596,12 @@ private predicate paramFlowsThrough( pragma[nomagic] private predicate pathThroughCallable0( - DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap + DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, + AccessPathApprox apa ) { exists(CallContext innercc, SummaryCtx sc | pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, unbind(mid.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration())) ) } @@ -2433,9 +2611,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind | - pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | + pathThroughCallable0(call, mid, kind, cc, ap, apa) and + out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration())) ) } @@ -2521,10 +2699,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2533,7 +2711,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2544,7 +2722,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2562,15 +2740,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2591,7 +2769,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2608,7 +2786,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2721,7 +2899,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2737,7 +2915,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2746,11 +2924,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2769,35 +2948,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( @@ -2806,7 +2992,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll index 43359fb329be..4562eb3fd194 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll @@ -1,6 +1,7 @@ private import cpp private import DataFlowUtil private import DataFlowDispatch +private import FlowVar /** Gets the instance argument of a non-static call. */ private Node getInstanceArgument(Call call) { @@ -106,7 +107,7 @@ private class ExprOutNode extends OutNode, ExprNode { override DataFlowCall getCall() { result = this.getExpr() } } -private class RefOutNode extends OutNode, DefinitionByReferenceNode { +private class RefOutNode extends OutNode, DefinitionByReferenceOrIteratorNode { /** Gets the underlying call. */ override DataFlowCall getCall() { result = this.getArgument().getParent() } } @@ -120,7 +121,7 @@ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { kind = TNormalReturnKind() or exists(int i | - result.asDefiningArgument() = call.getArgument(i) and + result.(DefinitionByReferenceOrIteratorNode).getArgument() = call.getArgument(i) and kind = TRefReturnKind(i) ) } @@ -148,12 +149,6 @@ class Content extends TContent { predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { path = "" and sl = 0 and sc = 0 and el = 0 and ec = 0 } - - /** Gets the type of the object containing this content. */ - abstract Type getContainerType(); - - /** Gets the type of this content. */ - abstract Type getType(); } private class FieldContent extends Content, TFieldContent { @@ -168,26 +163,14 @@ private class FieldContent extends Content, TFieldContent { override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { f.getLocation().hasLocationInfo(path, sl, sc, el, ec) } - - override Type getContainerType() { result = f.getDeclaringType() } - - override Type getType() { result = f.getType() } } private class CollectionContent extends Content, TCollectionContent { override string toString() { result = "collection" } - - override Type getContainerType() { none() } - - override Type getType() { none() } } private class ArrayContent extends Content, TArrayContent { override string toString() { result = "array" } - - override Type getContainerType() { none() } - - override Type getType() { none() } } /** @@ -235,16 +218,19 @@ predicate readStep(Node node1, Content f, Node node2) { } /** - * Gets a representative (boxed) type for `t` for the purpose of pruning - * possible flow. A single type is used for all numeric types to account for - * numeric conversions, and otherwise the erasure is used. + * Holds if values stored inside content `c` are cleared at node `n`. */ -Type getErasedRepr(Type t) { - suppressUnusedType(t) and +predicate clearsContent(Node n, Content c) { + none() // stub implementation +} + +/** Gets the type of `n` used for type pruning. */ +Type getNodeType(Node n) { + suppressUnusedNode(n) and result instanceof VoidType // stub implementation } -/** Gets a string representation of a type returned by `getErasedRepr`. */ +/** Gets a string representation of a type returned by `getNodeType`. */ string ppReprType(Type t) { none() } // stub implementation /** @@ -256,7 +242,7 @@ predicate compatibleTypes(Type t1, Type t2) { any() // stub implementation } -private predicate suppressUnusedType(Type t) { any() } +private predicate suppressUnusedNode(Node n) { any() } ////////////////////////////////////////////////////////////////////////////// // Java QL library compatibility wrappers @@ -314,3 +300,6 @@ predicate isImmutableOrUnobservable(Node n) { // The above list of cases isn't exhaustive, but it narrows down the // consistency alerts enough that most of them are interesting. } + +/** Holds if `n` should be hidden from path explanations. */ +predicate nodeIsHidden(Node n) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll index 47da6ca6e540..09409eb30f2a 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll @@ -6,6 +6,7 @@ private import cpp private import semmle.code.cpp.dataflow.internal.FlowVar private import semmle.code.cpp.models.interfaces.DataFlow private import semmle.code.cpp.controlflow.Guards +private import semmle.code.cpp.dataflow.internal.AddressFlow cached private newtype TNode = @@ -50,13 +51,25 @@ class Node extends TNode { /** Gets the type of this node. */ Type getType() { none() } // overridden in subclasses - /** Gets the expression corresponding to this node, if any. */ + /** + * Gets the expression corresponding to this node, if any. This predicate + * only has a result on nodes that represent the value of evaluating the + * expression. For data flowing _out of_ an expression, like when an + * argument is passed by reference, use `asDefiningArgument` instead of + * `asExpr`. + */ Expr asExpr() { result = this.(ExprNode).getExpr() } /** Gets the parameter corresponding to this node, if any. */ Parameter asParameter() { result = this.(ExplicitParameterNode).getParameter() } - /** Gets the argument that defines this `DefinitionByReferenceNode`, if any. */ + /** + * Gets the argument that defines this `DefinitionByReferenceNode`, if any. + * This predicate should be used instead of `asExpr` when referring to the + * value of a reference argument _after_ the call has returned. For example, + * in `f(&x)`, this predicate will have `&x` as its result for the `Node` + * that represents the new value of `x`. + */ Expr asDefiningArgument() { result = this.(DefinitionByReferenceNode).getArgument() } /** @@ -170,28 +183,29 @@ class ImplicitParameterNode extends ParameterNode, TInstanceParameterNode { } /** - * A node that represents the value of a variable after a function call that - * may have changed the variable because it's passed by reference. + * INTERNAL: do not use. * - * A typical example would be a call `f(&x)`. Firstly, there will be flow into - * `x` from previous definitions of `x`. Secondly, there will be a - * `DefinitionByReferenceNode` to represent the value of `x` after the call has - * returned. This node will have its `getArgument()` equal to `&x`. + * A node that represents the value of a variable after a function call that + * may have changed the variable because it's passed by reference or because an + * iterator for it was passed by value or by reference. */ -class DefinitionByReferenceNode extends PartialDefinitionNode { +class DefinitionByReferenceOrIteratorNode extends PartialDefinitionNode { Expr inner; Expr argument; - DefinitionByReferenceNode() { - this.getPartialDefinition().(DefinitionByReference).definesExpressions(inner, argument) + DefinitionByReferenceOrIteratorNode() { + this.getPartialDefinition().definesExpressions(inner, argument) and + ( + this.getPartialDefinition() instanceof DefinitionByReference + or + this.getPartialDefinition() instanceof DefinitionByIterator + ) } override Function getFunction() { result = inner.getEnclosingFunction() } override Type getType() { result = inner.getType() } - override string toString() { result = "ref arg " + argument.toString() } - override Location getLocation() { result = argument.getLocation() } override ExprNode getPreUpdateNode() { result.getExpr() = argument } @@ -208,6 +222,21 @@ class DefinitionByReferenceNode extends PartialDefinitionNode { } } +/** + * A node that represents the value of a variable after a function call that + * may have changed the variable because it's passed by reference. + * + * A typical example would be a call `f(&x)`. Firstly, there will be flow into + * `x` from previous definitions of `x`. Secondly, there will be a + * `DefinitionByReferenceNode` to represent the value of `x` after the call has + * returned. This node will have its `getArgument()` equal to `&x`. + */ +class DefinitionByReferenceNode extends DefinitionByReferenceOrIteratorNode { + override VariablePartialDefinition pd; + + override string toString() { result = "ref arg " + argument.toString() } +} + /** * The value of an uninitialized local variable, viewed as a node in a data * flow graph. @@ -271,13 +300,11 @@ abstract class PostUpdateNode extends Node { override Location getLocation() { result = getPreUpdateNode().getLocation() } } -private class PartialDefinitionNode extends PostUpdateNode, TPartialDefinitionNode { +abstract private class PartialDefinitionNode extends PostUpdateNode, TPartialDefinitionNode { PartialDefinition pd; PartialDefinitionNode() { this = TPartialDefinitionNode(pd) } - override Node getPreUpdateNode() { pd.definesExpressions(_, result.asExpr()) } - override Location getLocation() { result = pd.getActualLocation() } PartialDefinition getPartialDefinition() { result = pd } @@ -285,6 +312,24 @@ private class PartialDefinitionNode extends PostUpdateNode, TPartialDefinitionNo override string toString() { result = getPreUpdateNode().toString() + " [post update]" } } +private class VariablePartialDefinitionNode extends PartialDefinitionNode { + override VariablePartialDefinition pd; + + override Node getPreUpdateNode() { pd.definesExpressions(_, result.asExpr()) } +} + +/** + * INTERNAL: do not use. + * + * A synthetic data flow node used for flow into a collection when an iterator + * write occurs in a callee. + */ +class IteratorPartialDefinitionNode extends PartialDefinitionNode { + override IteratorPartialDefinition pd; + + override Node getPreUpdateNode() { pd.definesExpressions(_, result.asExpr()) } +} + /** * A post-update node on the `e->f` in `f(&e->f)` (and other forms). */ @@ -383,7 +428,9 @@ class PreConstructorInitThis extends Node, TPreConstructorInitThis { } /** - * Gets the `Node` corresponding to `e`. + * Gets the `Node` corresponding to the value of evaluating `e`. For data + * flowing _out of_ an expression, like when an argument is passed by + * reference, use `definitionByReferenceNodeFromArgument` instead. */ ExprNode exprNode(Expr e) { result.getExpr() = e } @@ -484,6 +531,17 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { // Expr -> Expr exprToExprStep_nocfg(nodeFrom.asExpr(), nodeTo.asExpr()) or + // Assignment -> LValue post-update node + // + // This is used for assignments whose left-hand side is not a variable + // assignment or a storeStep but is still modeled by other means. It could be + // a call to `operator*` or `operator[]` where taint should flow to the + // post-update node of the qualifier. + exists(AssignExpr assign | + nodeFrom.asExpr() = assign and + nodeTo.(PostUpdateNode).getPreUpdateNode().asExpr() = assign.getLValue() + ) + or // Node -> FlowVar -> VariableAccess exists(FlowVar var | ( @@ -514,6 +572,19 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { inner = nodeTo.(InnerPartialDefinitionNode).getPreUpdateNode().asExpr() and outer = nodeFrom.(PartialDefinitionNode).getPreUpdateNode().asExpr() ) + or + // Reverse flow: data that flows from the post-update node of a reference + // returned by a function call, back into the qualifier of that function. + // This allows data to flow 'in' through references returned by a modeled + // function such as `operator[]`. + exists(DataFlowFunction f, Call call, FunctionInput inModel, FunctionOutput outModel | + call.getTarget() = f and + inModel.isReturnValueDeref() and + outModel.isQualifierObject() and + f.hasDataFlow(inModel, outModel) and + nodeFrom.(PostUpdateNode).getPreUpdateNode().asExpr() = call and + nodeTo.asDefiningArgument() = call.getQualifier() + ) } /** @@ -572,6 +643,15 @@ private predicate exprToExprStep_nocfg(Expr fromExpr, Expr toExpr) { or toExpr.(AddressOfExpr).getOperand() = fromExpr or + // This rule enables flow from an array to its elements. Example: `a` to + // `a[i]` or `*a`, where `a` is an array type. It does not enable flow from a + // pointer to its indirection as in `p[i]` where `p` is a pointer type. + exists(Expr toConverted | + variablePartiallyAccessed(fromExpr, toConverted) and + toExpr = toConverted.getUnconverted() and + not toExpr = fromExpr + ) + or toExpr.(BuiltInOperationBuiltInAddressOf).getOperand() = fromExpr or // The following case is needed to track the qualifier object for flow @@ -591,14 +671,25 @@ private predicate exprToExprStep_nocfg(Expr fromExpr, Expr toExpr) { // `ClassAggregateLiteral` (`{ capture1, ..., captureN }`). toExpr.(LambdaExpression).getInitializer() = fromExpr or + // Data flow through a function model. toExpr = any(Call call | - exists(DataFlowFunction f, FunctionInput inModel, FunctionOutput outModel, int iIn | - call.getTarget() = f and + exists(DataFlowFunction f, FunctionInput inModel, FunctionOutput outModel | f.hasDataFlow(inModel, outModel) and - outModel.isReturnValue() and - inModel.isParameter(iIn) and - fromExpr = call.getArgument(iIn) + ( + exists(int iIn | + inModel.isParameter(iIn) and + fromExpr = call.getArgument(iIn) + ) + or + inModel.isQualifierObject() and + fromExpr = call.getQualifier() + or + inModel.isQualifierAddress() and + fromExpr = call.getQualifier() + ) and + call.getTarget() = f and + outModel.isReturnValue() ) ) } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll index 72033b0f72df..50395dbaafc0 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll @@ -6,6 +6,7 @@ import cpp private import semmle.code.cpp.controlflow.SSA private import semmle.code.cpp.dataflow.internal.SubBasicBlocks private import semmle.code.cpp.dataflow.internal.AddressFlow +private import semmle.code.cpp.models.implementations.Iterator /** * A conceptual variable that is assigned only once, like an SSA variable. This @@ -108,27 +109,26 @@ class FlowVar extends TFlowVar { * ``` */ private module PartialDefinitions { - class PartialDefinition extends Expr { - Expr innerDefinedExpr; + abstract class PartialDefinition extends Expr { ControlFlowNode node; - PartialDefinition() { - exists(Expr convertedInner | - valueToUpdate(convertedInner, this.getFullyConverted(), node) and - innerDefinedExpr = convertedInner.getUnconverted() and - not this instanceof Conversion - ) - } - - predicate partiallyDefines(Variable v) { innerDefinedExpr = v.getAnAccess() } + abstract deprecated predicate partiallyDefines(Variable v); - predicate partiallyDefinesThis(ThisExpr e) { innerDefinedExpr = e } + abstract deprecated predicate partiallyDefinesThis(ThisExpr e); /** * Gets the subBasicBlock where this `PartialDefinition` is defined. */ ControlFlowNode getSubBasicBlockStart() { result = node } + /** + * Holds if this `PartialDefinition` defines variable `v` at control-flow + * node `cfn`. + */ + // does this work with a dispred? + pragma[noinline] + abstract predicate partiallyDefinesVariableAt(Variable v, ControlFlowNode cfn); + /** * Holds if this partial definition may modify `inner` (or what it points * to) through `outer`. These expressions will never be `Conversion`s. @@ -137,10 +137,7 @@ private module PartialDefinitions { * - `inner` = `... .x`, `outer` = `&...` * - `inner` = `a`, `outer` = `*` */ - predicate definesExpressions(Expr inner, Expr outer) { - inner = innerDefinedExpr and - outer = this - } + abstract predicate definesExpressions(Expr inner, Expr outer); /** * Gets the location of this element, adjusted to avoid unknown locations @@ -156,10 +153,107 @@ private module PartialDefinitions { } } + class IteratorPartialDefinition extends PartialDefinition { + Variable collection; + Expr innerDefinedExpr; + + IteratorPartialDefinition() { + exists(Expr convertedInner | + not this instanceof Conversion and + valueToUpdate(convertedInner, this.getFullyConverted(), node) and + innerDefinedExpr = convertedInner.getUnconverted() and + ( + innerDefinedExpr.(Call).getQualifier() = getAnIteratorAccess(collection) + or + innerDefinedExpr.(Call).getQualifier() = collection.getAnAccess() and + collection instanceof IteratorParameter + ) and + innerDefinedExpr.(Call).getTarget() instanceof IteratorPointerDereferenceMemberOperator + ) + or + // iterators passed by value without a copy constructor + exists(Call call | + call = node and + call.getAnArgument() = innerDefinedExpr and + innerDefinedExpr = this and + this = getAnIteratorAccess(collection) and + not call.getTarget() instanceof IteratorPointerDereferenceMemberOperator + ) + or + // iterators passed by value with a copy constructor + exists(Call call, ConstructorCall copy | + copy.getTarget() instanceof CopyConstructor and + call = node and + call.getAnArgument() = copy and + copy.getArgument(0) = getAnIteratorAccess(collection) and + innerDefinedExpr = this and + this = copy and + not call.getTarget() instanceof IteratorPointerDereferenceMemberOperator + ) + } + + deprecated override predicate partiallyDefines(Variable v) { v = collection } + + deprecated override predicate partiallyDefinesThis(ThisExpr e) { none() } + + override predicate definesExpressions(Expr inner, Expr outer) { + inner = innerDefinedExpr and + outer = this + } + + override predicate partiallyDefinesVariableAt(Variable v, ControlFlowNode cfn) { + v = collection and + cfn = node + } + } + + class VariablePartialDefinition extends PartialDefinition { + Expr innerDefinedExpr; + + VariablePartialDefinition() { + not this instanceof Conversion and + exists(Expr convertedInner | + valueToUpdate(convertedInner, this.getFullyConverted(), node) and + innerDefinedExpr = convertedInner.getUnconverted() + ) + } + + deprecated override predicate partiallyDefines(Variable v) { + innerDefinedExpr = v.getAnAccess() + } + + deprecated override predicate partiallyDefinesThis(ThisExpr e) { innerDefinedExpr = e } + + /** + * Holds if this partial definition may modify `inner` (or what it points + * to) through `outer`. These expressions will never be `Conversion`s. + * + * For example, in `f(& (*a).x)`, there are two results: + * - `inner` = `... .x`, `outer` = `&...` + * - `inner` = `a`, `outer` = `*` + */ + override predicate definesExpressions(Expr inner, Expr outer) { + inner = innerDefinedExpr and + outer = this + } + + override predicate partiallyDefinesVariableAt(Variable v, ControlFlowNode cfn) { + innerDefinedExpr = v.getAnAccess() and + cfn = node + } + } + + /** + * A partial definition that's a definition via an output iterator. + */ + class DefinitionByIterator extends IteratorPartialDefinition { + DefinitionByIterator() { exists(Call c | this = c.getAnArgument() or this = c.getQualifier()) } + } + /** * A partial definition that's a definition by reference. */ - class DefinitionByReference extends PartialDefinition { + class DefinitionByReference extends VariablePartialDefinition { DefinitionByReference() { exists(Call c | this = c.getAnArgument() or this = c.getQualifier()) } } } @@ -188,7 +282,7 @@ module FlowVar_internal { predicate fullySupportedSsaVariable(Variable v) { v = any(SsaDefinition def).getAVariable() and // A partially-defined variable is handled using the partial definitions logic. - not any(PartialDefinition p).partiallyDefines(v) and + not any(PartialDefinition p).partiallyDefinesVariableAt(v, _) and // SSA variables do not exist before their first assignment, but one // feature of this data flow library is to track where uninitialized data // ends up. @@ -201,7 +295,8 @@ module FlowVar_internal { // The SSA library has a theoretically accurate treatment of reference types, // treating them as immutable, but for data flow it gives better results in // practice to make the variable synonymous with its contents. - not v.getUnspecifiedType() instanceof ReferenceType + not v.getUnspecifiedType() instanceof ReferenceType and + not v instanceof IteratorParameter } /** @@ -230,9 +325,9 @@ module FlowVar_internal { ( initializer(v, sbb.getANode()) or - assignmentLikeOperation(sbb, v, _, _) + assignmentLikeOperation(sbb, v, _) or - sbb = any(PartialDefinition p | p.partiallyDefines(v)).getSubBasicBlockStart() + exists(PartialDefinition p | p.partiallyDefinesVariableAt(v, sbb)) or blockVarDefinedByVariable(sbb, v) ) @@ -349,7 +444,7 @@ module FlowVar_internal { } override predicate definedByExpr(Expr e, ControlFlowNode node) { - assignmentLikeOperation(node, v, _, e) and + assignmentLikeOperation(node, v, e) and node = sbb or // We pick the defining `ControlFlowNode` of an `Initializer` to be its @@ -363,8 +458,7 @@ module FlowVar_internal { override predicate definedPartiallyAt(Expr e) { exists(PartialDefinition p | - p.partiallyDefines(v) and - sbb = p.getSubBasicBlockStart() and + p.partiallyDefinesVariableAt(v, sbb) and p.definesExpressions(_, e) ) } @@ -427,7 +521,7 @@ module FlowVar_internal { /** * Gets a variable that is assigned in this loop and read outside the loop. */ - private Variable getARelevantVariable() { + Variable getARelevantVariable() { result = this.getAVariableAssignedInLoop() and exists(VariableAccess va | va.getTarget() = result and @@ -440,7 +534,7 @@ module FlowVar_internal { pragma[noinline] private Variable getAVariableAssignedInLoop() { exists(BasicBlock bbAssign | - assignmentLikeOperation(bbAssign.getANode(), result, _, _) and + assignmentLikeOperation(bbAssign.getANode(), result, _) and this.bbInLoop(bbAssign) ) } @@ -472,10 +566,16 @@ module FlowVar_internal { reachesWithoutAssignment(bb.getAPredecessor(), v) and this.bbInLoop(bb) ) and - not assignmentLikeOperation(bb.getANode(), v, _, _) + not assignsToVar(bb, v) } } + pragma[noinline] + private predicate assignsToVar(BasicBlock bb, Variable v) { + assignmentLikeOperation(bb.getANode(), v, _) and + exists(AlwaysTrueUponEntryLoop loop | v = loop.getARelevantVariable()) + } + /** * Holds if `loop` always assigns to `v` before leaving through an edge * from `bbInside` in its condition to `bbOutside` outside the loop. Also, @@ -509,7 +609,7 @@ module FlowVar_internal { result = mid.getASuccessor() and variableLiveInSBB(result, v) and forall(AlwaysTrueUponEntryLoop loop | skipLoop(mid, result, v, loop) | loop.sbbInLoop(sbbDef)) and - not assignmentLikeOperation(result, v, _, _) + not assignmentLikeOperation(result, v, _) ) } @@ -545,13 +645,15 @@ module FlowVar_internal { refType = p.getUnderlyingType() and not refType.getBaseType().isConst() ) + or + p instanceof IteratorParameter } /** * Holds if liveness of `v` should stop propagating backwards from `sbb`. */ private predicate variableNotLiveBefore(SubBasicBlock sbb, Variable v) { - assignmentLikeOperation(sbb, v, _, _) + assignmentLikeOperation(sbb, v, _) or // Liveness of `v` is killed when going backwards from a block that declares it exists(DeclStmt ds | ds.getADeclaration().(LocalVariable) = v and sbb.contains(ds)) @@ -671,21 +773,17 @@ module FlowVar_internal { * `node instanceof Initializer` is covered by `initializer` instead of this * predicate. */ - predicate assignmentLikeOperation( - ControlFlowNode node, Variable v, VariableAccess va, Expr assignedExpr - ) { + predicate assignmentLikeOperation(ControlFlowNode node, Variable v, Expr assignedExpr) { // Together, the two following cases cover `Assignment` node = any(AssignExpr ae | - va = ae.getLValue() and - v = va.getTarget() and + v.getAnAccess() = ae.getLValue() and assignedExpr = ae.getRValue() ) or node = any(AssignOperation ao | - va = ao.getLValue() and - v = va.getTarget() and + v.getAnAccess() = ao.getLValue() and // Here and in the `PrefixCrementOperation` case, we say that the assigned // expression is the operation itself. For example, we say that `x += 1` // assigns `x += 1` to `x`. The justification is that after this operation, @@ -697,12 +795,24 @@ module FlowVar_internal { // `PrefixCrementOperation` is itself a source node = any(CrementOperation op | - va = op.getOperand() and - v = va.getTarget() and + v.getAnAccess() = op.getOperand() and assignedExpr = op ) } + Expr getAnIteratorAccess(Variable collection) { + exists(Call c, SsaDefinition def, Variable iterator | + c.getQualifier() = collection.getAnAccess() and + c.getTarget() instanceof BeginOrEndFunction and + def.getAnUltimateDefiningValue(iterator) = c and + result = def.getAUse(iterator) + ) + } + + class IteratorParameter extends Parameter { + IteratorParameter() { this.getUnspecifiedType() instanceof Iterator } + } + /** * Holds if `v` is initialized to have value `assignedExpr`. */ @@ -734,9 +844,9 @@ module FlowVar_internal { class DataFlowSubBasicBlockCutNode extends SubBasicBlockCutNode { DataFlowSubBasicBlockCutNode() { exists(Variable v | not fullySupportedSsaVariable(v) | - assignmentLikeOperation(this, v, _, _) + assignmentLikeOperation(this, v, _) or - this = any(PartialDefinition p | p.partiallyDefines(v)).getSubBasicBlockStart() + exists(PartialDefinition p | p.partiallyDefinesVariableAt(v, this)) // It is not necessary to cut the basic blocks at `Initializer` nodes // because the affected variable can have no _other_ value before its // initializer. It is not necessary to cut basic blocks at procedure diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/TaintTrackingUtil.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/TaintTrackingUtil.qll index 1812e3ffe7f9..1ef340c4f213 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/TaintTrackingUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/TaintTrackingUtil.qll @@ -10,6 +10,7 @@ private import semmle.code.cpp.models.interfaces.DataFlow private import semmle.code.cpp.models.interfaces.Taint +private import semmle.code.cpp.models.interfaces.Iterator private module DataFlow { import semmle.code.cpp.dataflow.internal.DataFlowUtil @@ -33,10 +34,10 @@ predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) { } /** - * Holds if `node` should be a barrier in all global taint flow configurations + * Holds if `node` should be a sanitizer in all global taint flow configurations * but not in local taint. */ -predicate defaultTaintBarrier(DataFlow::Node node) { none() } +predicate defaultTaintSanitizer(DataFlow::Node node) { none() } /** * Holds if taint can flow in one local step from `nodeFrom` to `nodeTo` excluding @@ -65,6 +66,15 @@ predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeT // tracking. The flow from expression `x` into `x++` etc. is handled in the // case above. exprTo = DataFlow::getAnAccessToAssignedVariable(exprFrom.(PostfixCrementOperation)) + or + // In `for (char c : s) { ... c ... }`, this rule propagates taint from `s` + // to `c`. + exists(RangeBasedForStmt rbf | + exprFrom = rbf.getRange() and + // It's guaranteed up to at least C++20 that the range-based for loop + // desugars to a variable with an initializer. + exprTo = rbf.getVariable().getInitializer().getExpr() + ) ) or // Taint can flow through modeled functions @@ -73,6 +83,26 @@ predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeT exprToDefinitionByReferenceStep(nodeFrom.asExpr(), nodeTo.asDefiningArgument()) or exprToPartialDefinitionStep(nodeFrom.asExpr(), nodeTo.asPartialDefinition()) + or + // Reverse taint: taint that flows from the post-update node of a reference + // returned by a function call, back into the qualifier of that function. + // This allows taint to flow 'in' through references returned by a modeled + // function such as `operator[]`. + exists(TaintFunction f, Call call, FunctionInput inModel, FunctionOutput outModel | + call.getTarget() = f and + inModel.isReturnValueDeref() and + nodeFrom.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr() = call and + f.hasTaintFlow(inModel, outModel) and + ( + outModel.isQualifierObject() and + nodeTo.asDefiningArgument() = call.getQualifier() + or + exists(int argOutIndex | + outModel.isParameterDeref(argOutIndex) and + nodeTo.asDefiningArgument() = call.getArgument(argOutIndex) + ) + ) + ) } /** @@ -226,4 +256,12 @@ private predicate exprToPartialDefinitionStep(Expr exprIn, Expr exprOut) { exprIn = call.getArgument(argInIndex) ) ) + or + exists(Assignment a | + iteratorDereference(exprOut) and + a.getLValue() = exprOut and + a.getRValue() = exprIn + ) } + +private predicate iteratorDereference(Call c) { c.getTarget() instanceof IteratorReferenceFunction } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll index 0f0607662e90..b509fad9cd20 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * To create a configuration, extend this class with a subclass whose * characteristic predicate is a unique singleton string. For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends TaintTracking::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -76,20 +76,20 @@ abstract class Configuration extends DataFlow::Configuration { final override predicate isBarrier(DataFlow::Node node) { isSanitizer(node) or - defaultTaintBarrier(node) + defaultTaintSanitizer(node) } - /** Holds if data flow into `node` is prohibited. */ + /** Holds if taint propagation into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) } - /** Holds if data flow out of `node` is prohibited. */ + /** Holds if taint propagation out of `node` is prohibited. */ predicate isSanitizerOut(DataFlow::Node node) { none() } final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) } - /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + /** Holds if taint propagation through nodes guarded by `guard` is prohibited. */ predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() } final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll index 0f0607662e90..b509fad9cd20 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * To create a configuration, extend this class with a subclass whose * characteristic predicate is a unique singleton string. For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends TaintTracking::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -76,20 +76,20 @@ abstract class Configuration extends DataFlow::Configuration { final override predicate isBarrier(DataFlow::Node node) { isSanitizer(node) or - defaultTaintBarrier(node) + defaultTaintSanitizer(node) } - /** Holds if data flow into `node` is prohibited. */ + /** Holds if taint propagation into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) } - /** Holds if data flow out of `node` is prohibited. */ + /** Holds if taint propagation out of `node` is prohibited. */ predicate isSanitizerOut(DataFlow::Node node) { none() } final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) } - /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + /** Holds if taint propagation through nodes guarded by `guard` is prohibited. */ predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() } final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Access.qll b/cpp/ql/src/semmle/code/cpp/exprs/Access.qll index fe467be6fe4c..681fb41fa678 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Access.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Access.qll @@ -1,3 +1,8 @@ +/** + * Provides classes for modeling accesses including variable accesses, enum + * constant accesses and function accesses. + */ + import semmle.code.cpp.exprs.Expr import semmle.code.cpp.Variable import semmle.code.cpp.Enum @@ -36,7 +41,7 @@ class Access extends Expr, NameQualifiableElement, @access { * ``` */ class EnumConstantAccess extends Access, @varaccess { - override string getCanonicalQLClass() { result = "EnumConstantAccess" } + override string getAPrimaryQlClass() { result = "EnumConstantAccess" } EnumConstantAccess() { exists(EnumConstant c | varbind(underlyingElement(this), unresolveElement(c))) @@ -61,7 +66,7 @@ class EnumConstantAccess extends Access, @varaccess { * ``` */ class VariableAccess extends Access, @varaccess { - override string getCanonicalQLClass() { result = "VariableAccess" } + override string getAPrimaryQlClass() { result = "VariableAccess" } VariableAccess() { not exists(EnumConstant c | varbind(underlyingElement(this), unresolveElement(c))) @@ -166,7 +171,7 @@ class VariableAccess extends Access, @varaccess { * ``` */ class FieldAccess extends VariableAccess { - override string getCanonicalQLClass() { result = "FieldAccess" } + override string getAPrimaryQlClass() { result = "FieldAccess" } FieldAccess() { exists(Field f | varbind(underlyingElement(this), unresolveElement(f))) } @@ -194,7 +199,7 @@ class FieldAccess extends VariableAccess { * ``` */ class PointerFieldAccess extends FieldAccess { - override string getCanonicalQLClass() { result = "PointerFieldAccess" } + override string getAPrimaryQlClass() { result = "PointerFieldAccess" } PointerFieldAccess() { exists(PointerType t | @@ -211,7 +216,7 @@ class PointerFieldAccess extends FieldAccess { * distinguish whether or not the type of `obj` is a reference type. */ class DotFieldAccess extends FieldAccess { - override string getCanonicalQLClass() { result = "DotFieldAccess" } + override string getAPrimaryQlClass() { result = "DotFieldAccess" } DotFieldAccess() { exists(Class c | c = getQualifier().getFullyConverted().getUnspecifiedType()) } } @@ -232,7 +237,7 @@ class DotFieldAccess extends FieldAccess { * ``` */ class ReferenceFieldAccess extends DotFieldAccess { - override string getCanonicalQLClass() { result = "ReferenceFieldAccess" } + override string getAPrimaryQlClass() { result = "ReferenceFieldAccess" } ReferenceFieldAccess() { exprHasReferenceConversion(this.getQualifier()) } } @@ -253,7 +258,7 @@ class ReferenceFieldAccess extends DotFieldAccess { * ``` */ class ValueFieldAccess extends DotFieldAccess { - override string getCanonicalQLClass() { result = "ValueFieldAccess" } + override string getAPrimaryQlClass() { result = "ValueFieldAccess" } ValueFieldAccess() { not exprHasReferenceConversion(this.getQualifier()) } } @@ -307,7 +312,7 @@ private predicate exprHasReferenceConversion(Expr e) { referenceConversion(e.get * `ImplicitThisFieldAccess`. */ class ImplicitThisFieldAccess extends FieldAccess { - override string getCanonicalQLClass() { result = "ImplicitThisFieldAccess" } + override string getAPrimaryQlClass() { result = "ImplicitThisFieldAccess" } ImplicitThisFieldAccess() { not exists(this.getQualifier()) } } @@ -332,7 +337,7 @@ class PointerToFieldLiteral extends ImplicitThisFieldAccess { override predicate isConstant() { any() } - override string getCanonicalQLClass() { result = "PointerToFieldLiteral" } + override string getAPrimaryQlClass() { result = "PointerToFieldLiteral" } } /** @@ -349,7 +354,7 @@ class PointerToFieldLiteral extends ImplicitThisFieldAccess { class FunctionAccess extends Access, @routineexpr { FunctionAccess() { not iscall(underlyingElement(this), _) } - override string getCanonicalQLClass() { result = "FunctionAccess" } + override string getAPrimaryQlClass() { result = "FunctionAccess" } /** Gets the accessed function. */ override Function getTarget() { funbind(underlyingElement(this), unresolveElement(result)) } @@ -399,7 +404,7 @@ class ParamAccessForType extends Expr, @param_ref { * ``` */ class TypeName extends Expr, @type_operand { - override string getCanonicalQLClass() { result = "TypeName" } + override string getAPrimaryQlClass() { result = "TypeName" } override string toString() { result = this.getType().getName() } } @@ -418,7 +423,7 @@ class TypeName extends Expr, @type_operand { * `OverloadedArrayExpr`. */ class ArrayExpr extends Expr, @subscriptexpr { - override string getCanonicalQLClass() { result = "ArrayExpr" } + override string getAPrimaryQlClass() { result = "ArrayExpr" } /** * Gets the array or pointer expression being subscripted. diff --git a/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll b/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll index 278db89b41ef..b94c9cee724b 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll @@ -1,3 +1,8 @@ +/** + * Provides classes for modeling arithmetic operations such as `+`, `-`, `*` + * and `++`. + */ + import semmle.code.cpp.exprs.Expr /** @@ -14,7 +19,7 @@ class UnaryArithmeticOperation extends UnaryOperation, @un_arith_op_expr { } class UnaryMinusExpr extends UnaryArithmeticOperation, @arithnegexpr { override string getOperator() { result = "-" } - override string getCanonicalQLClass() { result = "UnaryMinusExpr" } + override string getAPrimaryQlClass() { result = "UnaryMinusExpr" } override int getPrecedence() { result = 16 } } @@ -28,7 +33,7 @@ class UnaryMinusExpr extends UnaryArithmeticOperation, @arithnegexpr { class UnaryPlusExpr extends UnaryArithmeticOperation, @unaryplusexpr { override string getOperator() { result = "+" } - override string getCanonicalQLClass() { result = "UnaryPlusExpr" } + override string getAPrimaryQlClass() { result = "UnaryPlusExpr" } override int getPrecedence() { result = 16 } } @@ -45,7 +50,7 @@ class UnaryPlusExpr extends UnaryArithmeticOperation, @unaryplusexpr { class ConjugationExpr extends UnaryArithmeticOperation, @conjugation { override string getOperator() { result = "~" } - override string getCanonicalQLClass() { result = "ConjugationExpr" } + override string getAPrimaryQlClass() { result = "ConjugationExpr" } } /** @@ -107,7 +112,7 @@ class PostfixCrementOperation extends CrementOperation, @postfix_crement_expr { class PrefixIncrExpr extends IncrementOperation, PrefixCrementOperation, @preincrexpr { override string getOperator() { result = "++" } - override string getCanonicalQLClass() { result = "PrefixIncrExpr" } + override string getAPrimaryQlClass() { result = "PrefixIncrExpr" } override int getPrecedence() { result = 16 } } @@ -123,7 +128,7 @@ class PrefixIncrExpr extends IncrementOperation, PrefixCrementOperation, @preinc class PrefixDecrExpr extends DecrementOperation, PrefixCrementOperation, @predecrexpr { override string getOperator() { result = "--" } - override string getCanonicalQLClass() { result = "PrefixDecrExpr" } + override string getAPrimaryQlClass() { result = "PrefixDecrExpr" } override int getPrecedence() { result = 16 } } @@ -139,7 +144,7 @@ class PrefixDecrExpr extends DecrementOperation, PrefixCrementOperation, @predec class PostfixIncrExpr extends IncrementOperation, PostfixCrementOperation, @postincrexpr { override string getOperator() { result = "++" } - override string getCanonicalQLClass() { result = "PostfixIncrExpr" } + override string getAPrimaryQlClass() { result = "PostfixIncrExpr" } override int getPrecedence() { result = 17 } @@ -157,7 +162,7 @@ class PostfixIncrExpr extends IncrementOperation, PostfixCrementOperation, @post class PostfixDecrExpr extends DecrementOperation, PostfixCrementOperation, @postdecrexpr { override string getOperator() { result = "--" } - override string getCanonicalQLClass() { result = "PostfixDecrExpr" } + override string getAPrimaryQlClass() { result = "PostfixDecrExpr" } override int getPrecedence() { result = 17 } @@ -175,7 +180,7 @@ class PostfixDecrExpr extends DecrementOperation, PostfixCrementOperation, @post class RealPartExpr extends UnaryArithmeticOperation, @realpartexpr { override string getOperator() { result = "__real" } - override string getCanonicalQLClass() { result = "RealPartExpr" } + override string getAPrimaryQlClass() { result = "RealPartExpr" } } /** @@ -189,7 +194,7 @@ class RealPartExpr extends UnaryArithmeticOperation, @realpartexpr { class ImaginaryPartExpr extends UnaryArithmeticOperation, @imagpartexpr { override string getOperator() { result = "__imag" } - override string getCanonicalQLClass() { result = "ImaginaryPartExpr" } + override string getAPrimaryQlClass() { result = "ImaginaryPartExpr" } } /** @@ -208,7 +213,7 @@ class BinaryArithmeticOperation extends BinaryOperation, @bin_arith_op_expr { } class AddExpr extends BinaryArithmeticOperation, @addexpr { override string getOperator() { result = "+" } - override string getCanonicalQLClass() { result = "AddExpr" } + override string getAPrimaryQlClass() { result = "AddExpr" } override int getPrecedence() { result = 13 } } @@ -222,7 +227,7 @@ class AddExpr extends BinaryArithmeticOperation, @addexpr { class SubExpr extends BinaryArithmeticOperation, @subexpr { override string getOperator() { result = "-" } - override string getCanonicalQLClass() { result = "SubExpr" } + override string getAPrimaryQlClass() { result = "SubExpr" } override int getPrecedence() { result = 13 } } @@ -236,7 +241,7 @@ class SubExpr extends BinaryArithmeticOperation, @subexpr { class MulExpr extends BinaryArithmeticOperation, @mulexpr { override string getOperator() { result = "*" } - override string getCanonicalQLClass() { result = "MulExpr" } + override string getAPrimaryQlClass() { result = "MulExpr" } override int getPrecedence() { result = 14 } } @@ -250,7 +255,7 @@ class MulExpr extends BinaryArithmeticOperation, @mulexpr { class DivExpr extends BinaryArithmeticOperation, @divexpr { override string getOperator() { result = "/" } - override string getCanonicalQLClass() { result = "DivExpr" } + override string getAPrimaryQlClass() { result = "DivExpr" } override int getPrecedence() { result = 14 } } @@ -264,7 +269,7 @@ class DivExpr extends BinaryArithmeticOperation, @divexpr { class RemExpr extends BinaryArithmeticOperation, @remexpr { override string getOperator() { result = "%" } - override string getCanonicalQLClass() { result = "RemExpr" } + override string getAPrimaryQlClass() { result = "RemExpr" } override int getPrecedence() { result = 14 } } @@ -281,7 +286,7 @@ class RemExpr extends BinaryArithmeticOperation, @remexpr { class ImaginaryMulExpr extends BinaryArithmeticOperation, @jmulexpr { override string getOperator() { result = "*" } - override string getCanonicalQLClass() { result = "ImaginaryMulExpr" } + override string getAPrimaryQlClass() { result = "ImaginaryMulExpr" } override int getPrecedence() { result = 14 } } @@ -298,7 +303,7 @@ class ImaginaryMulExpr extends BinaryArithmeticOperation, @jmulexpr { class ImaginaryDivExpr extends BinaryArithmeticOperation, @jdivexpr { override string getOperator() { result = "/" } - override string getCanonicalQLClass() { result = "ImaginaryDivExpr" } + override string getAPrimaryQlClass() { result = "ImaginaryDivExpr" } override int getPrecedence() { result = 14 } } @@ -316,7 +321,7 @@ class ImaginaryDivExpr extends BinaryArithmeticOperation, @jdivexpr { class RealImaginaryAddExpr extends BinaryArithmeticOperation, @fjaddexpr { override string getOperator() { result = "+" } - override string getCanonicalQLClass() { result = "RealImaginaryAddExpr" } + override string getAPrimaryQlClass() { result = "RealImaginaryAddExpr" } override int getPrecedence() { result = 13 } } @@ -334,7 +339,7 @@ class RealImaginaryAddExpr extends BinaryArithmeticOperation, @fjaddexpr { class ImaginaryRealAddExpr extends BinaryArithmeticOperation, @jfaddexpr { override string getOperator() { result = "+" } - override string getCanonicalQLClass() { result = "ImaginaryRealAddExpr" } + override string getAPrimaryQlClass() { result = "ImaginaryRealAddExpr" } override int getPrecedence() { result = 13 } } @@ -352,7 +357,7 @@ class ImaginaryRealAddExpr extends BinaryArithmeticOperation, @jfaddexpr { class RealImaginarySubExpr extends BinaryArithmeticOperation, @fjsubexpr { override string getOperator() { result = "-" } - override string getCanonicalQLClass() { result = "RealImaginarySubExpr" } + override string getAPrimaryQlClass() { result = "RealImaginarySubExpr" } override int getPrecedence() { result = 13 } } @@ -370,7 +375,7 @@ class RealImaginarySubExpr extends BinaryArithmeticOperation, @fjsubexpr { class ImaginaryRealSubExpr extends BinaryArithmeticOperation, @jfsubexpr { override string getOperator() { result = "-" } - override string getCanonicalQLClass() { result = "ImaginaryRealSubExpr" } + override string getAPrimaryQlClass() { result = "ImaginaryRealSubExpr" } override int getPrecedence() { result = 13 } } @@ -384,7 +389,7 @@ class ImaginaryRealSubExpr extends BinaryArithmeticOperation, @jfsubexpr { class MinExpr extends BinaryArithmeticOperation, @minexpr { override string getOperator() { result = "?" } - override string getCanonicalQLClass() { result = "MaxExpr" } + override string getAPrimaryQlClass() { result = "MaxExpr" } } /** @@ -414,7 +419,7 @@ class PointerArithmeticOperation extends BinaryArithmeticOperation, @p_arith_op_ class PointerAddExpr extends PointerArithmeticOperation, @paddexpr { override string getOperator() { result = "+" } - override string getCanonicalQLClass() { result = "PointerAddExpr" } + override string getAPrimaryQlClass() { result = "PointerAddExpr" } override int getPrecedence() { result = 13 } } @@ -429,7 +434,7 @@ class PointerAddExpr extends PointerArithmeticOperation, @paddexpr { class PointerSubExpr extends PointerArithmeticOperation, @psubexpr { override string getOperator() { result = "-" } - override string getCanonicalQLClass() { result = "PointerSubExpr" } + override string getAPrimaryQlClass() { result = "PointerSubExpr" } override int getPrecedence() { result = 13 } } @@ -444,7 +449,7 @@ class PointerSubExpr extends PointerArithmeticOperation, @psubexpr { class PointerDiffExpr extends PointerArithmeticOperation, @pdiffexpr { override string getOperator() { result = "-" } - override string getCanonicalQLClass() { result = "PointerDiffExpr" } + override string getAPrimaryQlClass() { result = "PointerDiffExpr" } override int getPrecedence() { result = 13 } } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Assignment.qll b/cpp/ql/src/semmle/code/cpp/exprs/Assignment.qll index 4d2f61f1b6d8..0c56d9a4d51f 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Assignment.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Assignment.qll @@ -38,7 +38,7 @@ class Assignment extends Operation, @assign_expr { class AssignExpr extends Assignment, @assignexpr { override string getOperator() { result = "=" } - override string getCanonicalQLClass() { result = "AssignExpr" } + override string getAPrimaryQlClass() { result = "AssignExpr" } /** Gets a textual representation of this assignment. */ override string toString() { result = "... = ..." } @@ -64,7 +64,7 @@ class AssignArithmeticOperation extends AssignOperation, @assign_arith_expr { } * ``` */ class AssignAddExpr extends AssignArithmeticOperation, @assignaddexpr { - override string getCanonicalQLClass() { result = "AssignAddExpr" } + override string getAPrimaryQlClass() { result = "AssignAddExpr" } override string getOperator() { result = "+=" } } @@ -76,7 +76,7 @@ class AssignAddExpr extends AssignArithmeticOperation, @assignaddexpr { * ``` */ class AssignSubExpr extends AssignArithmeticOperation, @assignsubexpr { - override string getCanonicalQLClass() { result = "AssignSubExpr" } + override string getAPrimaryQlClass() { result = "AssignSubExpr" } override string getOperator() { result = "-=" } } @@ -88,7 +88,7 @@ class AssignSubExpr extends AssignArithmeticOperation, @assignsubexpr { * ``` */ class AssignMulExpr extends AssignArithmeticOperation, @assignmulexpr { - override string getCanonicalQLClass() { result = "AssignMulExpr" } + override string getAPrimaryQlClass() { result = "AssignMulExpr" } override string getOperator() { result = "*=" } } @@ -100,7 +100,7 @@ class AssignMulExpr extends AssignArithmeticOperation, @assignmulexpr { * ``` */ class AssignDivExpr extends AssignArithmeticOperation, @assigndivexpr { - override string getCanonicalQLClass() { result = "AssignDivExpr" } + override string getAPrimaryQlClass() { result = "AssignDivExpr" } override string getOperator() { result = "/=" } } @@ -112,7 +112,7 @@ class AssignDivExpr extends AssignArithmeticOperation, @assigndivexpr { * ``` */ class AssignRemExpr extends AssignArithmeticOperation, @assignremexpr { - override string getCanonicalQLClass() { result = "AssignRemExpr" } + override string getAPrimaryQlClass() { result = "AssignRemExpr" } override string getOperator() { result = "%=" } } @@ -130,7 +130,7 @@ class AssignBitwiseOperation extends AssignOperation, @assign_bitwise_expr { } * ``` */ class AssignAndExpr extends AssignBitwiseOperation, @assignandexpr { - override string getCanonicalQLClass() { result = "AssignAndExpr" } + override string getAPrimaryQlClass() { result = "AssignAndExpr" } override string getOperator() { result = "&=" } } @@ -142,7 +142,7 @@ class AssignAndExpr extends AssignBitwiseOperation, @assignandexpr { * ``` */ class AssignOrExpr extends AssignBitwiseOperation, @assignorexpr { - override string getCanonicalQLClass() { result = "AssignOrExpr" } + override string getAPrimaryQlClass() { result = "AssignOrExpr" } override string getOperator() { result = "|=" } } @@ -154,7 +154,7 @@ class AssignOrExpr extends AssignBitwiseOperation, @assignorexpr { * ``` */ class AssignXorExpr extends AssignBitwiseOperation, @assignxorexpr { - override string getCanonicalQLClass() { result = "AssignXorExpr" } + override string getAPrimaryQlClass() { result = "AssignXorExpr" } override string getOperator() { result = "^=" } } @@ -166,7 +166,7 @@ class AssignXorExpr extends AssignBitwiseOperation, @assignxorexpr { * ``` */ class AssignLShiftExpr extends AssignBitwiseOperation, @assignlshiftexpr { - override string getCanonicalQLClass() { result = "AssignLShiftExpr" } + override string getAPrimaryQlClass() { result = "AssignLShiftExpr" } override string getOperator() { result = "<<=" } } @@ -178,7 +178,7 @@ class AssignLShiftExpr extends AssignBitwiseOperation, @assignlshiftexpr { * ``` */ class AssignRShiftExpr extends AssignBitwiseOperation, @assignrshiftexpr { - override string getCanonicalQLClass() { result = "AssignRShiftExpr" } + override string getAPrimaryQlClass() { result = "AssignRShiftExpr" } override string getOperator() { result = ">>=" } } @@ -190,7 +190,7 @@ class AssignRShiftExpr extends AssignBitwiseOperation, @assignrshiftexpr { * ``` */ class AssignPointerAddExpr extends AssignOperation, @assignpaddexpr { - override string getCanonicalQLClass() { result = "AssignPointerAddExpr" } + override string getAPrimaryQlClass() { result = "AssignPointerAddExpr" } override string getOperator() { result = "+=" } } @@ -202,7 +202,7 @@ class AssignPointerAddExpr extends AssignOperation, @assignpaddexpr { * ``` */ class AssignPointerSubExpr extends AssignOperation, @assignpsubexpr { - override string getCanonicalQLClass() { result = "AssignPointerSubExpr" } + override string getAPrimaryQlClass() { result = "AssignPointerSubExpr" } override string getOperator() { result = "-=" } } @@ -227,7 +227,7 @@ class ConditionDeclExpr extends Expr, @condition_decl { */ deprecated Expr getExpr() { result = this.getChild(0) } - override string getCanonicalQLClass() { result = "ConditionDeclExpr" } + override string getAPrimaryQlClass() { result = "ConditionDeclExpr" } /** * Gets the compiler-generated variable access that conceptually occurs after diff --git a/cpp/ql/src/semmle/code/cpp/exprs/BitwiseOperation.qll b/cpp/ql/src/semmle/code/cpp/exprs/BitwiseOperation.qll index 2d0b6cda0d6e..3a4f14d9ab81 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/BitwiseOperation.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/BitwiseOperation.qll @@ -1,3 +1,8 @@ +/** + * Provides classes for modeling bitwise operations such as `~`, `<<`, `&` and + * `|`. + */ + import semmle.code.cpp.exprs.Expr /** @@ -16,7 +21,7 @@ class ComplementExpr extends UnaryBitwiseOperation, @complementexpr { override int getPrecedence() { result = 16 } - override string getCanonicalQLClass() { result = "ComplementExpr" } + override string getAPrimaryQlClass() { result = "ComplementExpr" } } /** @@ -35,7 +40,7 @@ class LShiftExpr extends BinaryBitwiseOperation, @lshiftexpr { override int getPrecedence() { result = 12 } - override string getCanonicalQLClass() { result = "LShiftExpr" } + override string getAPrimaryQlClass() { result = "LShiftExpr" } } /** @@ -49,7 +54,7 @@ class RShiftExpr extends BinaryBitwiseOperation, @rshiftexpr { override int getPrecedence() { result = 12 } - override string getCanonicalQLClass() { result = "RShiftExpr" } + override string getAPrimaryQlClass() { result = "RShiftExpr" } } /** @@ -63,7 +68,7 @@ class BitwiseAndExpr extends BinaryBitwiseOperation, @andexpr { override int getPrecedence() { result = 8 } - override string getCanonicalQLClass() { result = "BitwiseAndExpr" } + override string getAPrimaryQlClass() { result = "BitwiseAndExpr" } } /** @@ -77,7 +82,7 @@ class BitwiseOrExpr extends BinaryBitwiseOperation, @orexpr { override int getPrecedence() { result = 6 } - override string getCanonicalQLClass() { result = "BitwiseOrExpr" } + override string getAPrimaryQlClass() { result = "BitwiseOrExpr" } } /** @@ -91,5 +96,5 @@ class BitwiseXorExpr extends BinaryBitwiseOperation, @xorexpr { override int getPrecedence() { result = 7 } - override string getCanonicalQLClass() { result = "BitwiseXorExpr" } + override string getAPrimaryQlClass() { result = "BitwiseXorExpr" } } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll b/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll index 5729a49086b4..3c627d712b44 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll @@ -1,11 +1,16 @@ +/** + * Provides classes for modeling built-in operations. Built-in operations are + * typically compiler specific and are used by libraries and generated code. + */ + import semmle.code.cpp.exprs.Expr /** - * A C/C++ builtin operation. This is the root QL class encompassing + * A C/C++ built-in operation. This is the root QL class encompassing * built-in functionality. */ class BuiltInOperation extends Expr, @builtin_op { - override string getCanonicalQLClass() { result = "BuiltInOperation" } + override string getAPrimaryQlClass() { result = "BuiltInOperation" } } /** @@ -25,7 +30,7 @@ class VarArgsExpr extends BuiltInOperation, @var_args_expr { } class BuiltInVarArgsStart extends BuiltInOperation, @vastartexpr { override string toString() { result = "__builtin_va_start" } - override string getCanonicalQLClass() { result = "BuiltInVarArgsStart" } + override string getAPrimaryQlClass() { result = "BuiltInVarArgsStart" } /** * Gets the `va_list` argument. @@ -50,7 +55,7 @@ class BuiltInVarArgsStart extends BuiltInOperation, @vastartexpr { class BuiltInVarArgsEnd extends BuiltInOperation, @vaendexpr { override string toString() { result = "__builtin_va_end" } - override string getCanonicalQLClass() { result = "BuiltInVarArgsEnd" } + override string getAPrimaryQlClass() { result = "BuiltInVarArgsEnd" } /** * Gets the `va_list` argument. @@ -68,7 +73,7 @@ class BuiltInVarArgsEnd extends BuiltInOperation, @vaendexpr { class BuiltInVarArg extends BuiltInOperation, @vaargexpr { override string toString() { result = "__builtin_va_arg" } - override string getCanonicalQLClass() { result = "BuiltInVarArg" } + override string getAPrimaryQlClass() { result = "BuiltInVarArg" } /** * Gets the `va_list` argument. @@ -88,7 +93,7 @@ class BuiltInVarArg extends BuiltInOperation, @vaargexpr { class BuiltInVarArgCopy extends BuiltInOperation, @vacopyexpr { override string toString() { result = "__builtin_va_copy" } - override string getCanonicalQLClass() { result = "BuiltInVarArgCopy" } + override string getAPrimaryQlClass() { result = "BuiltInVarArgCopy" } /** * Gets the destination `va_list` argument. @@ -110,7 +115,7 @@ class BuiltInVarArgCopy extends BuiltInOperation, @vacopyexpr { class BuiltInNoOp extends BuiltInOperation, @noopexpr { override string toString() { result = "__noop" } - override string getCanonicalQLClass() { result = "BuiltInNoOp" } + override string getAPrimaryQlClass() { result = "BuiltInNoOp" } } /** @@ -132,7 +137,7 @@ deprecated class BuiltInOperationOffsetOf = BuiltInOperationBuiltInOffsetOf; class BuiltInOperationBuiltInOffsetOf extends BuiltInOperation, @offsetofexpr { override string toString() { result = "__builtin_offsetof" } - override string getCanonicalQLClass() { result = "BuiltInOperationBuiltInOffsetOf" } + override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInOffsetOf" } } /** @@ -149,7 +154,7 @@ class BuiltInOperationBuiltInOffsetOf extends BuiltInOperation, @offsetofexpr { class BuiltInIntAddr extends BuiltInOperation, @intaddrexpr { override string toString() { result = "__INTADDR__" } - override string getCanonicalQLClass() { result = "BuiltInIntAddr" } + override string getAPrimaryQlClass() { result = "BuiltInIntAddr" } } /** @@ -164,7 +169,7 @@ class BuiltInIntAddr extends BuiltInOperation, @intaddrexpr { class BuiltInOperationHasAssign extends BuiltInOperation, @hasassignexpr { override string toString() { result = "__has_assign" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasAssign" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasAssign" } } /** @@ -179,7 +184,7 @@ class BuiltInOperationHasAssign extends BuiltInOperation, @hasassignexpr { class BuiltInOperationHasCopy extends BuiltInOperation, @hascopyexpr { override string toString() { result = "__has_copy" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasCopy" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasCopy" } } /** @@ -195,7 +200,7 @@ class BuiltInOperationHasCopy extends BuiltInOperation, @hascopyexpr { class BuiltInOperationHasNoThrowAssign extends BuiltInOperation, @hasnothrowassign { override string toString() { result = "__has_nothrow_assign" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasNoThrowAssign" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasNoThrowAssign" } } /** @@ -211,7 +216,7 @@ class BuiltInOperationHasNoThrowAssign extends BuiltInOperation, @hasnothrowassi class BuiltInOperationHasNoThrowConstructor extends BuiltInOperation, @hasnothrowconstr { override string toString() { result = "__has_nothrow_constructor" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasNoThrowConstructor" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasNoThrowConstructor" } } /** @@ -226,7 +231,7 @@ class BuiltInOperationHasNoThrowConstructor extends BuiltInOperation, @hasnothro class BuiltInOperationHasNoThrowCopy extends BuiltInOperation, @hasnothrowcopy { override string toString() { result = "__has_nothrow_copy" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasNoThrowCopy" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasNoThrowCopy" } } /** @@ -242,7 +247,7 @@ class BuiltInOperationHasNoThrowCopy extends BuiltInOperation, @hasnothrowcopy { class BuiltInOperationHasTrivialAssign extends BuiltInOperation, @hastrivialassign { override string toString() { result = "__has_trivial_assign" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasTrivialAssign" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialAssign" } } /** @@ -257,7 +262,7 @@ class BuiltInOperationHasTrivialAssign extends BuiltInOperation, @hastrivialassi class BuiltInOperationHasTrivialConstructor extends BuiltInOperation, @hastrivialconstr { override string toString() { result = "__has_trivial_constructor" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasTrivialConstructor" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialConstructor" } } /** @@ -272,7 +277,7 @@ class BuiltInOperationHasTrivialConstructor extends BuiltInOperation, @hastrivia class BuiltInOperationHasTrivialCopy extends BuiltInOperation, @hastrivialcopy { override string toString() { result = "__has_trivial_copy" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasTrivialCopy" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialCopy" } } /** @@ -287,7 +292,7 @@ class BuiltInOperationHasTrivialCopy extends BuiltInOperation, @hastrivialcopy { class BuiltInOperationHasTrivialDestructor extends BuiltInOperation, @hastrivialdestructor { override string toString() { result = "__has_trivial_destructor" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasTrivialDestructor" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialDestructor" } } /** @@ -302,7 +307,7 @@ class BuiltInOperationHasTrivialDestructor extends BuiltInOperation, @hastrivial class BuiltInOperationHasUserDestructor extends BuiltInOperation, @hasuserdestr { override string toString() { result = "__has_user_destructor" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasUserDestructor" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasUserDestructor" } } /** @@ -320,7 +325,7 @@ class BuiltInOperationHasUserDestructor extends BuiltInOperation, @hasuserdestr class BuiltInOperationHasVirtualDestructor extends BuiltInOperation, @hasvirtualdestr { override string toString() { result = "__has_virtual_destructor" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasVirtualDestructor" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasVirtualDestructor" } } /** @@ -335,7 +340,7 @@ class BuiltInOperationHasVirtualDestructor extends BuiltInOperation, @hasvirtual class BuiltInOperationIsAbstract extends BuiltInOperation, @isabstractexpr { override string toString() { result = "__is_abstract" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsAbstract" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsAbstract" } } /** @@ -350,7 +355,7 @@ class BuiltInOperationIsAbstract extends BuiltInOperation, @isabstractexpr { class BuiltInOperationIsBaseOf extends BuiltInOperation, @isbaseofexpr { override string toString() { result = "__is_base_of" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsBaseOf" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsBaseOf" } } /** @@ -365,7 +370,7 @@ class BuiltInOperationIsBaseOf extends BuiltInOperation, @isbaseofexpr { class BuiltInOperationIsClass extends BuiltInOperation, @isclassexpr { override string toString() { result = "__is_class" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsClass" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsClass" } } /** @@ -380,7 +385,7 @@ class BuiltInOperationIsClass extends BuiltInOperation, @isclassexpr { class BuiltInOperationIsConvertibleTo extends BuiltInOperation, @isconvtoexpr { override string toString() { result = "__is_convertible_to" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsConvertibleTo" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsConvertibleTo" } } /** @@ -395,7 +400,7 @@ class BuiltInOperationIsConvertibleTo extends BuiltInOperation, @isconvtoexpr { class BuiltInOperationIsEmpty extends BuiltInOperation, @isemptyexpr { override string toString() { result = "__is_empty" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsEmpty" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsEmpty" } } /** @@ -410,7 +415,7 @@ class BuiltInOperationIsEmpty extends BuiltInOperation, @isemptyexpr { class BuiltInOperationIsEnum extends BuiltInOperation, @isenumexpr { override string toString() { result = "__is_enum" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsEnum" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsEnum" } } /** @@ -427,7 +432,7 @@ class BuiltInOperationIsEnum extends BuiltInOperation, @isenumexpr { class BuiltInOperationIsPod extends BuiltInOperation, @ispodexpr { override string toString() { result = "__is_pod" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsPod" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsPod" } } /** @@ -442,7 +447,7 @@ class BuiltInOperationIsPod extends BuiltInOperation, @ispodexpr { class BuiltInOperationIsPolymorphic extends BuiltInOperation, @ispolyexpr { override string toString() { result = "__is_polymorphic" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsPolymorphic" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsPolymorphic" } } /** @@ -457,7 +462,7 @@ class BuiltInOperationIsPolymorphic extends BuiltInOperation, @ispolyexpr { class BuiltInOperationIsUnion extends BuiltInOperation, @isunionexpr { override string toString() { result = "__is_union" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsUnion" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsUnion" } } /** @@ -496,7 +501,7 @@ class BuiltInOperationBuiltInTypesCompatibleP extends BuiltInOperation, @typesco class BuiltInOperationBuiltInShuffleVector extends BuiltInOperation, @builtinshufflevector { override string toString() { result = "__builtin_shufflevector" } - override string getCanonicalQLClass() { result = "BuiltInOperationBuiltInShuffleVector" } + override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInShuffleVector" } } /** @@ -516,7 +521,7 @@ class BuiltInOperationBuiltInShuffleVector extends BuiltInOperation, @builtinshu class BuiltInOperationBuiltInConvertVector extends BuiltInOperation, @builtinconvertvector { override string toString() { result = "__builtin_convertvector" } - override string getCanonicalQLClass() { result = "BuiltInOperationBuiltInConvertVector" } + override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInConvertVector" } } /** @@ -538,7 +543,7 @@ class BuiltInOperationBuiltInAddressOf extends UnaryOperation, BuiltInOperation, result = this.getOperand().(ReferenceDereferenceExpr).getChild(0).(Access).getTarget() } - override string getCanonicalQLClass() { result = "BuiltInOperationBuiltInAddressOf" } + override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInAddressOf" } override string getOperator() { result = "__builtin_addressof" } } @@ -560,7 +565,7 @@ class BuiltInOperationIsTriviallyConstructible extends BuiltInOperation, @istriviallyconstructibleexpr { override string toString() { result = "__is_trivially_constructible" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsTriviallyConstructible" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyConstructible" } } /** @@ -577,7 +582,7 @@ class BuiltInOperationIsTriviallyConstructible extends BuiltInOperation, class BuiltInOperationIsDestructible extends BuiltInOperation, @isdestructibleexpr { override string toString() { result = "__is_destructible" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsDestructible" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsDestructible" } } /** @@ -594,7 +599,7 @@ class BuiltInOperationIsDestructible extends BuiltInOperation, @isdestructibleex class BuiltInOperationIsNothrowDestructible extends BuiltInOperation, @isnothrowdestructibleexpr { override string toString() { result = "__is_nothrow_destructible" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsNothrowDestructible" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsNothrowDestructible" } } /** @@ -610,7 +615,7 @@ class BuiltInOperationIsNothrowDestructible extends BuiltInOperation, @isnothrow class BuiltInOperationIsTriviallyDestructible extends BuiltInOperation, @istriviallydestructibleexpr { override string toString() { result = "__is_trivially_destructible" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsTriviallyDestructible" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyDestructible" } } /** @@ -629,7 +634,7 @@ class BuiltInOperationIsTriviallyDestructible extends BuiltInOperation, @istrivi class BuiltInOperationIsTriviallyAssignable extends BuiltInOperation, @istriviallyassignableexpr { override string toString() { result = "__is_trivially_assignable" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsTriviallyAssignable" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyAssignable" } } /** @@ -645,7 +650,7 @@ class BuiltInOperationIsTriviallyAssignable extends BuiltInOperation, @istrivial class BuiltInOperationIsNothrowAssignable extends BuiltInOperation, @isnothrowassignableexpr { override string toString() { result = "__is_nothrow_assignable" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsNothrowAssignable" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsNothrowAssignable" } } /** @@ -665,7 +670,7 @@ class BuiltInOperationIsNothrowAssignable extends BuiltInOperation, @isnothrowas class BuiltInOperationIsStandardLayout extends BuiltInOperation, @isstandardlayoutexpr { override string toString() { result = "__is_standard_layout" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsStandardLayout" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsStandardLayout" } } /** @@ -679,7 +684,7 @@ class BuiltInOperationIsStandardLayout extends BuiltInOperation, @isstandardlayo class BuiltInOperationIsTriviallyCopyable extends BuiltInOperation, @istriviallycopyableexpr { override string toString() { result = "__is_trivially_copyable" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsTriviallyCopyable" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyCopyable" } } /** @@ -699,7 +704,7 @@ class BuiltInOperationIsTriviallyCopyable extends BuiltInOperation, @istrivially class BuiltInOperationIsLiteralType extends BuiltInOperation, @isliteraltypeexpr { override string toString() { result = "__is_literal_type" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsLiteralType" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsLiteralType" } } /** @@ -717,7 +722,7 @@ class BuiltInOperationHasTrivialMoveConstructor extends BuiltInOperation, @hastrivialmoveconstructorexpr { override string toString() { result = "__has_trivial_move_constructor" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasTrivialMoveConstructor" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialMoveConstructor" } } /** @@ -735,7 +740,7 @@ class BuiltInOperationHasTrivialMoveConstructor extends BuiltInOperation, class BuiltInOperationHasTrivialMoveAssign extends BuiltInOperation, @hastrivialmoveassignexpr { override string toString() { result = "__has_trivial_move_assign" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasTrivialMoveAssign" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialMoveAssign" } } /** @@ -751,7 +756,7 @@ class BuiltInOperationHasTrivialMoveAssign extends BuiltInOperation, @hastrivial class BuiltInOperationHasNothrowMoveAssign extends BuiltInOperation, @hasnothrowmoveassignexpr { override string toString() { result = "__has_nothrow_move_assign" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasNothrowMoveAssign" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasNothrowMoveAssign" } } /** @@ -770,7 +775,7 @@ class BuiltInOperationHasNothrowMoveAssign extends BuiltInOperation, @hasnothrow class BuiltInOperationIsConstructible extends BuiltInOperation, @isconstructibleexpr { override string toString() { result = "__is_constructible" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsConstructible" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsConstructible" } } /** @@ -786,7 +791,7 @@ class BuiltInOperationIsConstructible extends BuiltInOperation, @isconstructible class BuiltInOperationIsNothrowConstructible extends BuiltInOperation, @isnothrowconstructibleexpr { override string toString() { result = "__is_nothrow_constructible" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsNothrowConstructible" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsNothrowConstructible" } } /** @@ -801,7 +806,7 @@ class BuiltInOperationIsNothrowConstructible extends BuiltInOperation, @isnothro class BuiltInOperationHasFinalizer extends BuiltInOperation, @hasfinalizerexpr { override string toString() { result = "__has_finalizer" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasFinalizer" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasFinalizer" } } /** @@ -815,7 +820,7 @@ class BuiltInOperationHasFinalizer extends BuiltInOperation, @hasfinalizerexpr { class BuiltInOperationIsDelegate extends BuiltInOperation, @isdelegateexpr { override string toString() { result = "__is_delegate" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsDelegate" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsDelegate" } } /** @@ -828,7 +833,7 @@ class BuiltInOperationIsDelegate extends BuiltInOperation, @isdelegateexpr { class BuiltInOperationIsInterfaceClass extends BuiltInOperation, @isinterfaceclassexpr { override string toString() { result = "__is_interface_class" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsInterfaceClass" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsInterfaceClass" } } /** @@ -845,7 +850,7 @@ class BuiltInOperationIsInterfaceClass extends BuiltInOperation, @isinterfacecla class BuiltInOperationIsRefArray extends BuiltInOperation, @isrefarrayexpr { override string toString() { result = "__is_ref_array" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsRefArray" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsRefArray" } } /** @@ -862,7 +867,7 @@ class BuiltInOperationIsRefArray extends BuiltInOperation, @isrefarrayexpr { class BuiltInOperationIsRefClass extends BuiltInOperation, @isrefclassexpr { override string toString() { result = "__is_ref_class" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsRefClass" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsRefClass" } } /** @@ -880,7 +885,7 @@ class BuiltInOperationIsRefClass extends BuiltInOperation, @isrefclassexpr { class BuiltInOperationIsSealed extends BuiltInOperation, @issealedexpr { override string toString() { result = "__is_sealed" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsSealed" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsSealed" } } /** @@ -899,7 +904,7 @@ class BuiltInOperationIsSealed extends BuiltInOperation, @issealedexpr { class BuiltInOperationIsSimpleValueClass extends BuiltInOperation, @issimplevalueclassexpr { override string toString() { result = "__is_simple_value_class" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsSimpleValueClass" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsSimpleValueClass" } } /** @@ -916,7 +921,7 @@ class BuiltInOperationIsSimpleValueClass extends BuiltInOperation, @issimplevalu class BuiltInOperationIsValueClass extends BuiltInOperation, @isvalueclassexpr { override string toString() { result = "__is_value_class" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsValueClass" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsValueClass" } } /** @@ -934,7 +939,7 @@ class BuiltInOperationIsValueClass extends BuiltInOperation, @isvalueclassexpr { class BuiltInOperationIsFinal extends BuiltInOperation, @isfinalexpr { override string toString() { result = "__is_final" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsFinal" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsFinal" } } /** @@ -949,7 +954,7 @@ class BuiltInOperationIsFinal extends BuiltInOperation, @isfinalexpr { class BuiltInChooseExpr extends BuiltInOperation, @builtinchooseexpr { override string toString() { result = "__builtin_choose_expr" } - override string getCanonicalQLClass() { result = "BuiltInChooseExpr" } + override string getAPrimaryQlClass() { result = "BuiltInChooseExpr" } } /** @@ -966,7 +971,7 @@ class BuiltInChooseExpr extends BuiltInOperation, @builtinchooseexpr { class VectorFillOperation extends UnaryOperation, @vec_fill { override string getOperator() { result = "(vector fill)" } - override string getCanonicalQLClass() { result = "VectorFillOperation" } + override string getAPrimaryQlClass() { result = "VectorFillOperation" } } /** @@ -975,7 +980,7 @@ class VectorFillOperation extends UnaryOperation, @vec_fill { class BuiltInComplexOperation extends BuiltInOperation, @builtincomplex { override string toString() { result = "__builtin_complex" } - override string getCanonicalQLClass() { result = "BuiltInComplexOperation" } + override string getAPrimaryQlClass() { result = "BuiltInComplexOperation" } /** Gets the operand corresponding to the real part of the complex number. */ Expr getRealOperand() { this.hasChild(result, 0) } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Call.qll b/cpp/ql/src/semmle/code/cpp/exprs/Call.qll index abb26002091c..2f1c29be8bc9 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Call.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Call.qll @@ -1,13 +1,29 @@ +/** + * Provides classes for modeling call expressions including direct calls to + * functions, constructor and destructor calls, and calls made through function + * pointers. + */ + import semmle.code.cpp.exprs.Expr import semmle.code.cpp.Function private import semmle.code.cpp.dataflow.EscapesTree +private class TCall = @funbindexpr or @callexpr; + /** * A C/C++ call. - * - * This is the abstract root QL class for all types of calls. */ -abstract class Call extends Expr, NameQualifiableElement { +class Call extends Expr, NameQualifiableElement, TCall { + // `@funbindexpr` (which is the dbscheme type for FunctionCall) is a union type that includes + // `@routineexpr. This dbscheme type includes accesses to functions that are not necessarily calls to + // that function. That's why the charpred for `FunctionCall` requires: + // ``` + // iscall(underlyingElement(this), _) + // ``` + // So for the charpred for `Call` we include the requirement that if this is an instance of + // `@funbindexpr` it must be a _call_ to the function. + Call() { this instanceof @callexpr or iscall(underlyingElement(this), _) } + /** * Gets the number of arguments (actual parameters) of this call. The count * does _not_ include the qualifier of the call, if any. @@ -74,7 +90,7 @@ abstract class Call extends Expr, NameQualifiableElement { * method, and it might not exist. * - For a variable call, it never exists. */ - abstract Function getTarget(); + Function getTarget() { none() } // overridden in subclasses override int getPrecedence() { result = 17 } @@ -148,7 +164,7 @@ abstract class Call extends Expr, NameQualifiableElement { class FunctionCall extends Call, @funbindexpr { FunctionCall() { iscall(underlyingElement(this), _) } - override string getCanonicalQLClass() { result = "FunctionCall" } + override string getAPrimaryQlClass() { result = "FunctionCall" } /** Gets an explicit template argument for this call. */ Locatable getAnExplicitTemplateArgument() { result = getExplicitTemplateArgument(_) } @@ -297,7 +313,7 @@ class OverloadedPointerDereferenceExpr extends FunctionCall { getTarget().getEffectiveNumberOfParameters() = 1 } - override string getCanonicalQLClass() { result = "OverloadedPointerDereferenceExpr" } + override string getAPrimaryQlClass() { result = "OverloadedPointerDereferenceExpr" } /** * Gets the expression this operator * applies to. @@ -345,7 +361,7 @@ class OverloadedPointerDereferenceExpr extends FunctionCall { class OverloadedArrayExpr extends FunctionCall { OverloadedArrayExpr() { getTarget().hasName("operator[]") } - override string getCanonicalQLClass() { result = "OverloadedArrayExpr" } + override string getAPrimaryQlClass() { result = "OverloadedArrayExpr" } /** * Gets the expression being subscripted. @@ -377,7 +393,7 @@ class ExprCall extends Call, @callexpr { */ Expr getExpr() { result = this.getChild(0) } - override string getCanonicalQLClass() { result = "ExprCall" } + override string getAPrimaryQlClass() { result = "ExprCall" } override Expr getAnArgument() { exists(int i | result = this.getChild(i) and i >= 1) } @@ -401,7 +417,7 @@ class ExprCall extends Call, @callexpr { class VariableCall extends ExprCall { VariableCall() { this.getExpr() instanceof VariableAccess } - override string getCanonicalQLClass() { result = "VariableCall" } + override string getAPrimaryQlClass() { result = "VariableCall" } /** * Gets the variable which yields the function pointer to call. @@ -419,7 +435,7 @@ class VariableCall extends ExprCall { class ConstructorCall extends FunctionCall { ConstructorCall() { super.getTarget() instanceof Constructor } - override string getCanonicalQLClass() { result = "ConstructorCall" } + override string getAPrimaryQlClass() { result = "ConstructorCall" } /** Gets the constructor being called. */ override Constructor getTarget() { result = super.getTarget() } @@ -438,7 +454,7 @@ class ThrowExpr extends Expr, @throw_expr { */ Expr getExpr() { result = this.getChild(0) } - override string getCanonicalQLClass() { result = "ThrowExpr" } + override string getAPrimaryQlClass() { result = "ThrowExpr" } override string toString() { result = "throw ..." } @@ -454,7 +470,7 @@ class ThrowExpr extends Expr, @throw_expr { class ReThrowExpr extends ThrowExpr { ReThrowExpr() { this.getType() instanceof VoidType } - override string getCanonicalQLClass() { result = "ReThrowExpr" } + override string getAPrimaryQlClass() { result = "ReThrowExpr" } override string toString() { result = "re-throw exception " } } @@ -469,7 +485,7 @@ class ReThrowExpr extends ThrowExpr { class DestructorCall extends FunctionCall { DestructorCall() { super.getTarget() instanceof Destructor } - override string getCanonicalQLClass() { result = "DestructorCall" } + override string getAPrimaryQlClass() { result = "DestructorCall" } /** Gets the destructor being called. */ override Destructor getTarget() { result = super.getTarget() } @@ -493,7 +509,7 @@ class VacuousDestructorCall extends Expr, @vacuous_destructor_call { */ Expr getQualifier() { result = this.getChild(0) } - override string getCanonicalQLClass() { result = "VacuousDestructorCall" } + override string getAPrimaryQlClass() { result = "VacuousDestructorCall" } override string toString() { result = "(vacuous destructor call)" } } @@ -506,7 +522,7 @@ class VacuousDestructorCall extends Expr, @vacuous_destructor_call { * initializations. */ class ConstructorInit extends Expr, @ctorinit { - override string getCanonicalQLClass() { result = "ConstructorInit" } + override string getAPrimaryQlClass() { result = "ConstructorInit" } } /** @@ -514,7 +530,7 @@ class ConstructorInit extends Expr, @ctorinit { * initializer list or compiler-generated actions. */ class ConstructorBaseInit extends ConstructorInit, ConstructorCall { - override string getCanonicalQLClass() { result = "ConstructorBaseInit" } + override string getAPrimaryQlClass() { result = "ConstructorBaseInit" } } /** @@ -531,7 +547,7 @@ class ConstructorBaseInit extends ConstructorInit, ConstructorCall { * ``` */ class ConstructorDirectInit extends ConstructorBaseInit, @ctordirectinit { - override string getCanonicalQLClass() { result = "ConstructorDirectInit" } + override string getAPrimaryQlClass() { result = "ConstructorDirectInit" } } /** @@ -551,7 +567,7 @@ class ConstructorDirectInit extends ConstructorBaseInit, @ctordirectinit { * ``` */ class ConstructorVirtualInit extends ConstructorBaseInit, @ctorvirtualinit { - override string getCanonicalQLClass() { result = "ConstructorVirtualInit" } + override string getAPrimaryQlClass() { result = "ConstructorVirtualInit" } } /** @@ -566,7 +582,7 @@ class ConstructorVirtualInit extends ConstructorBaseInit, @ctorvirtualinit { * ``` */ class ConstructorDelegationInit extends ConstructorBaseInit, @ctordelegatinginit { - override string getCanonicalQLClass() { result = "ConstructorDelegationInit" } + override string getAPrimaryQlClass() { result = "ConstructorDelegationInit" } } /** @@ -585,7 +601,7 @@ class ConstructorFieldInit extends ConstructorInit, @ctorfieldinit { /** Gets the field being initialized. */ Field getTarget() { varbind(underlyingElement(this), unresolveElement(result)) } - override string getCanonicalQLClass() { result = "ConstructorFieldInit" } + override string getAPrimaryQlClass() { result = "ConstructorFieldInit" } /** * Gets the expression to which the field is initialized. @@ -607,7 +623,7 @@ class ConstructorFieldInit extends ConstructorInit, @ctorfieldinit { * compiler-generated actions. */ class DestructorDestruction extends Expr, @dtordestruct { - override string getCanonicalQLClass() { result = "DestructorDestruction" } + override string getAPrimaryQlClass() { result = "DestructorDestruction" } } /** @@ -615,7 +631,7 @@ class DestructorDestruction extends Expr, @dtordestruct { * compiler-generated actions. */ class DestructorBaseDestruction extends DestructorCall, DestructorDestruction { - override string getCanonicalQLClass() { result = "DestructorBaseDestruction" } + override string getAPrimaryQlClass() { result = "DestructorBaseDestruction" } } /** @@ -629,7 +645,7 @@ class DestructorBaseDestruction extends DestructorCall, DestructorDestruction { * ``` */ class DestructorDirectDestruction extends DestructorBaseDestruction, @dtordirectdestruct { - override string getCanonicalQLClass() { result = "DestructorDirectDestruction" } + override string getAPrimaryQlClass() { result = "DestructorDirectDestruction" } } /** @@ -646,7 +662,7 @@ class DestructorDirectDestruction extends DestructorBaseDestruction, @dtordirect * ``` */ class DestructorVirtualDestruction extends DestructorBaseDestruction, @dtorvirtualdestruct { - override string getCanonicalQLClass() { result = "DestructorVirtualDestruction" } + override string getAPrimaryQlClass() { result = "DestructorVirtualDestruction" } } /** @@ -664,7 +680,7 @@ class DestructorFieldDestruction extends DestructorDestruction, @dtorfielddestru /** Gets the field being destructed. */ Field getTarget() { varbind(underlyingElement(this), unresolveElement(result)) } - override string getCanonicalQLClass() { result = "DestructorFieldDestruction" } + override string getAPrimaryQlClass() { result = "DestructorFieldDestruction" } /** Gets the compiler-generated call to the variable's destructor. */ DestructorCall getExpr() { result = this.getChild(0) } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll b/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll index a00014b9af75..e06ed095d401 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll @@ -1,3 +1,8 @@ +/** + * Provides classes for modeling C/C++ casts and conversions, as well as some + * type-related operators such as `sizeof` and `alignof`. + */ + import semmle.code.cpp.exprs.Expr private import semmle.code.cpp.internal.ResolveClass @@ -92,7 +97,7 @@ module CastConsistency { class CStyleCast extends Cast, @c_style_cast { override string toString() { result = "(" + this.getType().getName() + ")..." } - override string getCanonicalQLClass() { result = "CStyleCast" } + override string getAPrimaryQlClass() { result = "CStyleCast" } override int getPrecedence() { result = 16 } } @@ -111,7 +116,7 @@ class CStyleCast extends Cast, @c_style_cast { class StaticCast extends Cast, @static_cast { override string toString() { result = "static_cast<" + this.getType().getName() + ">..." } - override string getCanonicalQLClass() { result = "StaticCast" } + override string getAPrimaryQlClass() { result = "StaticCast" } override int getPrecedence() { result = 17 } } @@ -129,7 +134,7 @@ class StaticCast extends Cast, @static_cast { class ConstCast extends Cast, @const_cast { override string toString() { result = "const_cast<" + this.getType().getName() + ">..." } - override string getCanonicalQLClass() { result = "ConstCast" } + override string getAPrimaryQlClass() { result = "ConstCast" } override int getPrecedence() { result = 17 } } @@ -147,7 +152,7 @@ class ConstCast extends Cast, @const_cast { class ReinterpretCast extends Cast, @reinterpret_cast { override string toString() { result = "reinterpret_cast<" + this.getType().getName() + ">..." } - override string getCanonicalQLClass() { result = "ReinterpretCast" } + override string getAPrimaryQlClass() { result = "ReinterpretCast" } override int getPrecedence() { result = 17 } } @@ -203,7 +208,7 @@ class IntegralConversion extends ArithmeticConversion { isIntegralOrEnum(getExpr().getUnspecifiedType()) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "IntegralConversion" } @@ -223,7 +228,7 @@ class FloatingPointConversion extends ArithmeticConversion { getExpr().getUnspecifiedType() instanceof FloatingPointType } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "FloatingPointConversion" } @@ -243,7 +248,7 @@ class FloatingPointToIntegralConversion extends ArithmeticConversion { getExpr().getUnspecifiedType() instanceof FloatingPointType } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "FloatingPointToIntegralConversion" } @@ -263,7 +268,7 @@ class IntegralToFloatingPointConversion extends ArithmeticConversion { isIntegralOrEnum(getExpr().getUnspecifiedType()) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "IntegralToFloatingPointConversion" } @@ -289,9 +294,7 @@ class PointerConversion extends Cast { isPointerOrNullPointer(getExpr().getUnspecifiedType()) } - override string getCanonicalQLClass() { - not exists(qlCast(this)) and result = "PointerConversion" - } + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PointerConversion" } override string getSemanticConversionString() { result = "pointer conversion" } } @@ -325,7 +328,7 @@ class PointerToMemberConversion extends Cast { ) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PointerToMemberConversion" } @@ -346,7 +349,7 @@ class PointerToIntegralConversion extends Cast { isPointerOrNullPointer(getExpr().getUnspecifiedType()) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PointerToIntegralConversion" } @@ -367,7 +370,7 @@ class IntegralToPointerConversion extends Cast { isIntegralOrEnum(getExpr().getUnspecifiedType()) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "IntegralToPointerConversion" } @@ -385,7 +388,7 @@ class IntegralToPointerConversion extends Cast { class BoolConversion extends Cast { BoolConversion() { conversionkinds(underlyingElement(this), 1) } - override string getCanonicalQLClass() { not exists(qlCast(this)) and result = "BoolConversion" } + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "BoolConversion" } override string getSemanticConversionString() { result = "conversion to bool" } } @@ -403,7 +406,7 @@ class VoidConversion extends Cast { getUnspecifiedType() instanceof VoidType } - override string getCanonicalQLClass() { not exists(qlCast(this)) and result = "VoidConversion" } + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "VoidConversion" } override string getSemanticConversionString() { result = "conversion to void" } } @@ -479,7 +482,7 @@ private Class getConversionClass(Expr expr) { class BaseClassConversion extends InheritanceConversion { BaseClassConversion() { conversionkinds(underlyingElement(this), 2) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "BaseClassConversion" } @@ -506,7 +509,7 @@ class BaseClassConversion extends InheritanceConversion { class DerivedClassConversion extends InheritanceConversion { DerivedClassConversion() { conversionkinds(underlyingElement(this), 3) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "DerivedClassConversion" } @@ -528,7 +531,7 @@ class DerivedClassConversion extends InheritanceConversion { class PointerToMemberBaseClassConversion extends Cast { PointerToMemberBaseClassConversion() { conversionkinds(underlyingElement(this), 4) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PointerToMemberBaseClassConversion" } @@ -548,7 +551,7 @@ class PointerToMemberBaseClassConversion extends Cast { class PointerToMemberDerivedClassConversion extends Cast { PointerToMemberDerivedClassConversion() { conversionkinds(underlyingElement(this), 5) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PointerToMemberDerivedClassConversion" } @@ -569,9 +572,7 @@ class PointerToMemberDerivedClassConversion extends Cast { class GlvalueConversion extends Cast { GlvalueConversion() { conversionkinds(underlyingElement(this), 6) } - override string getCanonicalQLClass() { - not exists(qlCast(this)) and result = "GlvalueConversion" - } + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "GlvalueConversion" } override string getSemanticConversionString() { result = "glvalue conversion" } } @@ -597,7 +598,7 @@ class GlvalueConversion extends Cast { class PrvalueAdjustmentConversion extends Cast { PrvalueAdjustmentConversion() { conversionkinds(underlyingElement(this), 7) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PrvalueAdjustmentConversion" } @@ -620,7 +621,7 @@ class DynamicCast extends Cast, @dynamic_cast { override int getPrecedence() { result = 17 } - override string getCanonicalQLClass() { result = "DynamicCast" } + override string getAPrimaryQlClass() { result = "DynamicCast" } override string getSemanticConversionString() { result = "dynamic_cast" } } @@ -660,6 +661,9 @@ class UuidofOperator extends Expr, @uuidof { * ``` */ class TypeidOperator extends Expr, @type_id { + /** + * Gets the type that is returned by this typeid expression. + */ Type getResultType() { typeid_bind(underlyingElement(this), unresolveElement(result)) } /** @@ -669,7 +673,7 @@ class TypeidOperator extends Expr, @type_id { */ deprecated Type getSpecifiedType() { result = this.getResultType() } - override string getCanonicalQLClass() { result = "TypeidOperator" } + override string getAPrimaryQlClass() { result = "TypeidOperator" } /** * Gets the contained expression, if any (if this typeid contains @@ -699,7 +703,7 @@ class TypeidOperator extends Expr, @type_id { class SizeofPackOperator extends Expr, @sizeof_pack { override string toString() { result = "sizeof...(...)" } - override string getCanonicalQLClass() { result = "SizeofPackOperator" } + override string getAPrimaryQlClass() { result = "SizeofPackOperator" } override predicate mayBeImpure() { none() } @@ -722,7 +726,7 @@ class SizeofOperator extends Expr, @runtime_sizeof { class SizeofExprOperator extends SizeofOperator { SizeofExprOperator() { exists(Expr e | this.getChild(0) = e) } - override string getCanonicalQLClass() { result = "SizeofExprOperator" } + override string getAPrimaryQlClass() { result = "SizeofExprOperator" } /** Gets the contained expression. */ Expr getExprOperand() { result = this.getChild(0) } @@ -750,7 +754,7 @@ class SizeofExprOperator extends SizeofOperator { class SizeofTypeOperator extends SizeofOperator { SizeofTypeOperator() { sizeof_bind(underlyingElement(this), _) } - override string getCanonicalQLClass() { result = "SizeofTypeOperator" } + override string getAPrimaryQlClass() { result = "SizeofTypeOperator" } /** Gets the contained type. */ Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) } @@ -829,7 +833,7 @@ class ArrayToPointerConversion extends Conversion, @array_to_pointer { /** Gets a textual representation of this conversion. */ override string toString() { result = "array to pointer conversion" } - override string getCanonicalQLClass() { result = "ArrayToPointerConversion" } + override string getAPrimaryQlClass() { result = "ArrayToPointerConversion" } override predicate mayBeImpure() { none() } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/ComparisonOperation.qll b/cpp/ql/src/semmle/code/cpp/exprs/ComparisonOperation.qll index a0688890a23b..0c84e07f5533 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/ComparisonOperation.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/ComparisonOperation.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for modeling comparisons such as `==`, `!=` and `<`. + */ + import semmle.code.cpp.exprs.Expr /** @@ -21,7 +25,7 @@ class EqualityOperation extends ComparisonOperation, @eq_op_expr { * ``` */ class EQExpr extends EqualityOperation, @eqexpr { - override string getCanonicalQLClass() { result = "EQExpr" } + override string getAPrimaryQlClass() { result = "EQExpr" } override string getOperator() { result = "==" } } @@ -33,7 +37,7 @@ class EQExpr extends EqualityOperation, @eqexpr { * ``` */ class NEExpr extends EqualityOperation, @neexpr { - override string getCanonicalQLClass() { result = "NEExpr" } + override string getAPrimaryQlClass() { result = "NEExpr" } override string getOperator() { result = "!=" } } @@ -78,7 +82,7 @@ class RelationalOperation extends ComparisonOperation, @rel_op_expr { * ``` */ class GTExpr extends RelationalOperation, @gtexpr { - override string getCanonicalQLClass() { result = "GTExpr" } + override string getAPrimaryQlClass() { result = "GTExpr" } override string getOperator() { result = ">" } @@ -94,7 +98,7 @@ class GTExpr extends RelationalOperation, @gtexpr { * ``` */ class LTExpr extends RelationalOperation, @ltexpr { - override string getCanonicalQLClass() { result = "LTExpr" } + override string getAPrimaryQlClass() { result = "LTExpr" } override string getOperator() { result = "<" } @@ -110,7 +114,7 @@ class LTExpr extends RelationalOperation, @ltexpr { * ``` */ class GEExpr extends RelationalOperation, @geexpr { - override string getCanonicalQLClass() { result = "GEExpr" } + override string getAPrimaryQlClass() { result = "GEExpr" } override string getOperator() { result = ">=" } @@ -126,7 +130,7 @@ class GEExpr extends RelationalOperation, @geexpr { * ``` */ class LEExpr extends RelationalOperation, @leexpr { - override string getCanonicalQLClass() { result = "LEExpr" } + override string getAPrimaryQlClass() { result = "LEExpr" } override string getOperator() { result = "<=" } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll b/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll index fd15a22fbd22..a39b215b54a2 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll @@ -1,3 +1,7 @@ +/** + * Provides classes modeling C/C++ expressions. + */ + import semmle.code.cpp.Element private import semmle.code.cpp.Enclosing private import semmle.code.cpp.internal.ResolveClass @@ -23,7 +27,7 @@ class Expr extends StmtParent, @expr { Function getEnclosingFunction() { result = exprEnclosingElement(this) } /** Gets the nearest enclosing set of curly braces around this expression in the source, if any. */ - Block getEnclosingBlock() { result = getEnclosingStmt().getEnclosingBlock() } + BlockStmt getEnclosingBlock() { result = getEnclosingStmt().getEnclosingBlock() } override Stmt getEnclosingStmt() { result = this.getParent().(Expr).getEnclosingStmt() @@ -398,7 +402,7 @@ class Expr extends StmtParent, @expr { */ predicate hasImplicitConversion() { exists(Expr e | - exprconv(underlyingElement(this), unresolveElement(e)) and e.(Cast).isImplicit() + exprconv(underlyingElement(this), unresolveElement(e)) and e.(Conversion).isImplicit() ) } @@ -410,7 +414,7 @@ class Expr extends StmtParent, @expr { */ predicate hasExplicitConversion() { exists(Expr e | - exprconv(underlyingElement(this), unresolveElement(e)) and not e.(Cast).isImplicit() + exprconv(underlyingElement(this), unresolveElement(e)) and not e.(Conversion).isImplicit() ) } @@ -449,12 +453,14 @@ class Expr extends StmtParent, @expr { * cast from B to C. Only (1) and (2) would be included. */ Expr getExplicitlyConverted() { - // result is this or one of its conversions - result = this.getConversion*() and - // result is not an implicit conversion - it's either the expr or an explicit cast - (result = this or not result.(Cast).isImplicit()) and - // there is no further explicit conversion after result - not exists(Cast other | other = result.getConversion+() and not other.isImplicit()) + // For performance, we avoid a full transitive closure over `getConversion`. + // Since there can be several implicit conversions before and after an + // explicit conversion, use `getImplicitlyConverted` to step over them + // cheaply. Then, if there is an explicit conversion following the implict + // conversion sequence, recurse to handle multiple explicit conversions. + if this.getImplicitlyConverted().hasExplicitConversion() + then result = this.getImplicitlyConverted().getConversion().getExplicitlyConverted() + else result = this } /** @@ -535,6 +541,17 @@ class BinaryOperation extends Operation, @bin_op_expr { /** Gets the right operand of this binary operation. */ Expr getRightOperand() { this.hasChild(result, 1) } + /** + * Holds if `e1` and `e2` (in either order) are the two operands of this + * binary operation. + */ + predicate hasOperands(Expr e1, Expr e2) { + exists(int i | i in [0, 1] | + this.hasChild(e1, i) and + this.hasChild(e2, 1 - i) + ) + } + override string toString() { result = "... " + this.getOperator() + " ..." } override predicate mayBeImpure() { @@ -565,7 +582,7 @@ class BinaryOperation extends Operation, @bin_op_expr { class ParenthesizedBracedInitializerList extends Expr, @braced_init_list { override string toString() { result = "({...})" } - override string getCanonicalQLClass() { result = "ParenthesizedBracedInitializerList" } + override string getAPrimaryQlClass() { result = "ParenthesizedBracedInitializerList" } } /** @@ -580,7 +597,7 @@ class ParenthesizedBracedInitializerList extends Expr, @braced_init_list { class ParenthesisExpr extends Conversion, @parexpr { override string toString() { result = "(...)" } - override string getCanonicalQLClass() { result = "ParenthesisExpr" } + override string getAPrimaryQlClass() { result = "ParenthesisExpr" } } /** @@ -591,7 +608,7 @@ class ParenthesisExpr extends Conversion, @parexpr { class ErrorExpr extends Expr, @errorexpr { override string toString() { result = "" } - override string getCanonicalQLClass() { result = "ErrorExpr" } + override string getAPrimaryQlClass() { result = "ErrorExpr" } } /** @@ -606,7 +623,7 @@ class ErrorExpr extends Expr, @errorexpr { class AssumeExpr extends Expr, @assume { override string toString() { result = "__assume(...)" } - override string getCanonicalQLClass() { result = "AssumeExpr" } + override string getAPrimaryQlClass() { result = "AssumeExpr" } /** * Gets the operand of the `__assume` expressions. @@ -621,7 +638,7 @@ class AssumeExpr extends Expr, @assume { * ``` */ class CommaExpr extends Expr, @commaexpr { - override string getCanonicalQLClass() { result = "CommaExpr" } + override string getAPrimaryQlClass() { result = "CommaExpr" } /** * Gets the left operand, which is the one whose value is discarded. @@ -656,7 +673,7 @@ class CommaExpr extends Expr, @commaexpr { * ``` */ class AddressOfExpr extends UnaryOperation, @address_of { - override string getCanonicalQLClass() { result = "AddressOfExpr" } + override string getAPrimaryQlClass() { result = "AddressOfExpr" } /** Gets the function or variable whose address is taken. */ Declaration getAddressable() { @@ -688,7 +705,7 @@ class AddressOfExpr extends UnaryOperation, @address_of { class ReferenceToExpr extends Conversion, @reference_to { override string toString() { result = "(reference to)" } - override string getCanonicalQLClass() { result = "ReferenceToExpr" } + override string getAPrimaryQlClass() { result = "ReferenceToExpr" } override int getPrecedence() { result = 16 } } @@ -702,7 +719,7 @@ class ReferenceToExpr extends Conversion, @reference_to { * ``` */ class PointerDereferenceExpr extends UnaryOperation, @indirect { - override string getCanonicalQLClass() { result = "PointerDereferenceExpr" } + override string getAPrimaryQlClass() { result = "PointerDereferenceExpr" } /** * DEPRECATED: Use getOperand() instead. @@ -740,7 +757,7 @@ class PointerDereferenceExpr extends UnaryOperation, @indirect { class ReferenceDereferenceExpr extends Conversion, @ref_indirect { override string toString() { result = "(reference dereference)" } - override string getCanonicalQLClass() { result = "ReferenceDereferenceExpr" } + override string getAPrimaryQlClass() { result = "ReferenceDereferenceExpr" } } /** @@ -846,7 +863,7 @@ class NewOrNewArrayExpr extends Expr, @any_new_expr { class NewExpr extends NewOrNewArrayExpr, @new_expr { override string toString() { result = "new" } - override string getCanonicalQLClass() { result = "NewExpr" } + override string getAPrimaryQlClass() { result = "NewExpr" } /** * Gets the type that is being allocated. @@ -876,7 +893,7 @@ class NewExpr extends NewOrNewArrayExpr, @new_expr { class NewArrayExpr extends NewOrNewArrayExpr, @new_array_expr { override string toString() { result = "new[]" } - override string getCanonicalQLClass() { result = "NewArrayExpr" } + override string getAPrimaryQlClass() { result = "NewArrayExpr" } /** * Gets the type that is being allocated. @@ -924,7 +941,7 @@ class NewArrayExpr extends NewOrNewArrayExpr, @new_array_expr { class DeleteExpr extends Expr, @delete_expr { override string toString() { result = "delete" } - override string getCanonicalQLClass() { result = "DeleteExpr" } + override string getAPrimaryQlClass() { result = "DeleteExpr" } override int getPrecedence() { result = 16 } @@ -998,7 +1015,7 @@ class DeleteExpr extends Expr, @delete_expr { class DeleteArrayExpr extends Expr, @delete_array_expr { override string toString() { result = "delete[]" } - override string getCanonicalQLClass() { result = "DeleteArrayExpr" } + override string getAPrimaryQlClass() { result = "DeleteArrayExpr" } override int getPrecedence() { result = 16 } @@ -1078,7 +1095,7 @@ class StmtExpr extends Expr, @expr_stmt { */ Stmt getStmt() { result.getParent() = this } - override string getCanonicalQLClass() { result = "StmtExpr" } + override string getAPrimaryQlClass() { result = "StmtExpr" } /** * Gets the result expression of the enclosed statement. For example, @@ -1094,7 +1111,7 @@ class StmtExpr extends Expr, @expr_stmt { /** Get the result expression of a statement. (Helper function for StmtExpr.) */ private Expr getStmtResultExpr(Stmt stmt) { result = stmt.(ExprStmt).getExpr() or - result = getStmtResultExpr(stmt.(Block).getLastStmt()) + result = getStmtResultExpr(stmt.(BlockStmt).getLastStmt()) } /** @@ -1103,7 +1120,7 @@ private Expr getStmtResultExpr(Stmt stmt) { class ThisExpr extends Expr, @thisaccess { override string toString() { result = "this" } - override string getCanonicalQLClass() { result = "ThisExpr" } + override string getAPrimaryQlClass() { result = "ThisExpr" } override predicate mayBeImpure() { none() } @@ -1139,7 +1156,7 @@ class BlockExpr extends Literal { class NoExceptExpr extends Expr, @noexceptexpr { override string toString() { result = "noexcept(...)" } - override string getCanonicalQLClass() { result = "NoExceptExpr" } + override string getAPrimaryQlClass() { result = "NoExceptExpr" } /** * Gets the expression inside this noexcept expression. @@ -1171,7 +1188,7 @@ class FoldExpr extends Expr, @foldexpr { ) } - override string getCanonicalQLClass() { result = "FoldExpr" } + override string getAPrimaryQlClass() { result = "FoldExpr" } /** Gets the binary operator used in this fold expression, as a string. */ string getOperatorString() { fold(underlyingElement(this), result, _) } @@ -1247,9 +1264,37 @@ private predicate constantTemplateLiteral(Expr e) { * ``` */ class SpaceshipExpr extends BinaryOperation, @spaceshipexpr { - override string getCanonicalQLClass() { result = "SpaceshipExpr" } + override string getAPrimaryQlClass() { result = "SpaceshipExpr" } override int getPrecedence() { result = 11 } override string getOperator() { result = "<=>" } } + +/** + * A C/C++ `co_await` expression. + * ``` + * co_await foo(); + * ``` + */ +class CoAwaitExpr extends UnaryOperation, @co_await { + override string getAPrimaryQlClass() { result = "CoAwaitExpr" } + + override string getOperator() { result = "co_await" } + + override int getPrecedence() { result = 16 } +} + +/** + * A C/C++ `co_yield` expression. + * ``` + * co_yield 1; + * ``` + */ +class CoYieldExpr extends UnaryOperation, @co_yield { + override string getAPrimaryQlClass() { result = "CoYieldExpr" } + + override string getOperator() { result = "co_yield" } + + override int getPrecedence() { result = 2 } +} diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll b/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll index 4a5b1b21c8dd..8a51001f4d5e 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for modeling lambda expressions and their captures. + */ + import semmle.code.cpp.exprs.Expr import semmle.code.cpp.Class @@ -15,7 +19,7 @@ import semmle.code.cpp.Class class LambdaExpression extends Expr, @lambdaexpr { override string toString() { result = "[...](...){...}" } - override string getCanonicalQLClass() { result = "LambdaExpression" } + override string getAPrimaryQlClass() { result = "LambdaExpression" } /** * Gets an implicitly or explicitly captured value of this lambda expression. @@ -75,7 +79,7 @@ class LambdaExpression extends Expr, @lambdaexpr { class Closure extends Class { Closure() { exists(LambdaExpression e | this = e.getType()) } - override string getCanonicalQLClass() { result = "Closure" } + override string getAPrimaryQlClass() { result = "Closure" } /** Gets the lambda expression of which this is the type. */ LambdaExpression getLambdaExpression() { result.getType() = this } @@ -101,7 +105,7 @@ class Closure extends Class { class LambdaCapture extends Locatable, @lambdacapture { override string toString() { result = getField().getName() } - override string getCanonicalQLClass() { result = "LambdaCapture" } + override string getAPrimaryQlClass() { result = "LambdaCapture" } /** * Holds if this capture was made implicitly. diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll b/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll index 3360be330c26..9ab944d2cc33 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll @@ -1,3 +1,8 @@ +/** + * Provides classes for modeling literals in the source code such as `0`, `'c'` + * or `"string"`. + */ + import semmle.code.cpp.exprs.Expr /** @@ -14,7 +19,7 @@ class Literal extends Expr, @literal { result = "Unknown literal" } - override string getCanonicalQLClass() { result = "Literal" } + override string getAPrimaryQlClass() { result = "Literal" } override predicate mayBeImpure() { none() } @@ -35,7 +40,7 @@ class Literal extends Expr, @literal { class LabelLiteral extends Literal { LabelLiteral() { jumpinfo(underlyingElement(this), _, _) } - override string getCanonicalQLClass() { result = "LabelLiteral" } + override string getAPrimaryQlClass() { result = "LabelLiteral" } /** Gets the corresponding label statement. */ LabelStmt getLabel() { jumpinfo(underlyingElement(this), _, unresolveElement(result)) } @@ -93,7 +98,7 @@ abstract class TextLiteral extends Literal { class CharLiteral extends TextLiteral { CharLiteral() { this.getValueText().regexpMatch("(?s)\\s*L?'.*") } - override string getCanonicalQLClass() { result = "CharLiteral" } + override string getAPrimaryQlClass() { result = "CharLiteral" } /** * Gets the character of this literal. For example `L'a'` has character `"a"`. @@ -115,7 +120,7 @@ class StringLiteral extends TextLiteral { // @aggregateliteral rather than @literal. } - override string getCanonicalQLClass() { result = "StringLiteral" } + override string getAPrimaryQlClass() { result = "StringLiteral" } } /** @@ -128,7 +133,7 @@ class StringLiteral extends TextLiteral { class OctalLiteral extends Literal { OctalLiteral() { super.getValueText().regexpMatch("\\s*0[0-7]+[uUlL]*\\s*") } - override string getCanonicalQLClass() { result = "OctalLiteral" } + override string getAPrimaryQlClass() { result = "OctalLiteral" } } /** @@ -140,14 +145,14 @@ class OctalLiteral extends Literal { class HexLiteral extends Literal { HexLiteral() { super.getValueText().regexpMatch("\\s*0[xX][0-9a-fA-F]+[uUlL]*\\s*") } - override string getCanonicalQLClass() { result = "HexLiteral" } + override string getAPrimaryQlClass() { result = "HexLiteral" } } /** * A C/C++ aggregate literal. */ class AggregateLiteral extends Expr, @aggregateliteral { - override string getCanonicalQLClass() { result = "AggregateLiteral" } + override string getAPrimaryQlClass() { result = "AggregateLiteral" } /** * DEPRECATED: Use ClassAggregateLiteral.getFieldExpr() instead. @@ -179,7 +184,7 @@ class ClassAggregateLiteral extends AggregateLiteral { ClassAggregateLiteral() { classType = this.getUnspecifiedType() } - override string getCanonicalQLClass() { result = "ClassAggregateLiteral" } + override string getAPrimaryQlClass() { result = "ClassAggregateLiteral" } /** * Gets the expression within the aggregate literal that is used to initialize @@ -299,7 +304,7 @@ class ArrayAggregateLiteral extends ArrayOrVectorAggregateLiteral { ArrayAggregateLiteral() { arrayType = this.getUnspecifiedType() } - override string getCanonicalQLClass() { result = "ArrayAggregateLiteral" } + override string getAPrimaryQlClass() { result = "ArrayAggregateLiteral" } override int getArraySize() { result = arrayType.getArraySize() } @@ -323,7 +328,7 @@ class VectorAggregateLiteral extends ArrayOrVectorAggregateLiteral { VectorAggregateLiteral() { vectorType = this.getUnspecifiedType() } - override string getCanonicalQLClass() { result = "VectorAggregateLiteral" } + override string getAPrimaryQlClass() { result = "VectorAggregateLiteral" } override int getArraySize() { result = vectorType.getNumElements() } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/LogicalOperation.qll b/cpp/ql/src/semmle/code/cpp/exprs/LogicalOperation.qll index fa55c1e91eb4..d0e207f7b31d 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/LogicalOperation.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/LogicalOperation.qll @@ -1,3 +1,8 @@ +/** + * Provides classes for modeling logical operations such as `!`, `&&`, `||`, and + * the ternary `? :` expression. + */ + import semmle.code.cpp.exprs.Expr /** @@ -14,7 +19,7 @@ class UnaryLogicalOperation extends UnaryOperation, @un_log_op_expr { } class NotExpr extends UnaryLogicalOperation, @notexpr { override string getOperator() { result = "!" } - override string getCanonicalQLClass() { result = "NotExpr" } + override string getAPrimaryQlClass() { result = "NotExpr" } override int getPrecedence() { result = 16 } } @@ -46,7 +51,7 @@ class BinaryLogicalOperation extends BinaryOperation, @bin_log_op_expr { class LogicalAndExpr extends BinaryLogicalOperation, @andlogicalexpr { override string getOperator() { result = "&&" } - override string getCanonicalQLClass() { result = "LogicalAndExpr" } + override string getAPrimaryQlClass() { result = "LogicalAndExpr" } override int getPrecedence() { result = 5 } @@ -67,7 +72,7 @@ class LogicalAndExpr extends BinaryLogicalOperation, @andlogicalexpr { class LogicalOrExpr extends BinaryLogicalOperation, @orlogicalexpr { override string getOperator() { result = "||" } - override string getCanonicalQLClass() { result = "LogicalOrExpr" } + override string getAPrimaryQlClass() { result = "LogicalOrExpr" } override int getPrecedence() { result = 4 } @@ -89,7 +94,7 @@ class ConditionalExpr extends Operation, @conditionalexpr { /** Gets the condition of this conditional expression. */ Expr getCondition() { expr_cond_guard(underlyingElement(this), unresolveElement(result)) } - override string getCanonicalQLClass() { result = "ConditionalExpr" } + override string getAPrimaryQlClass() { result = "ConditionalExpr" } /** Gets the 'then' expression of this conditional expression. */ Expr getThen() { diff --git a/cpp/ql/src/semmle/code/cpp/exprs/ObjectiveC.qll b/cpp/ql/src/semmle/code/cpp/exprs/ObjectiveC.qll index 61699023f8f1..c651ae9b1534 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/ObjectiveC.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/ObjectiveC.qll @@ -1,3 +1,7 @@ +/** + * DEPRECATED: Objective-C is no longer supported. + */ + import semmle.code.cpp.exprs.Expr import semmle.code.cpp.Class import semmle.code.cpp.ObjectiveC diff --git a/cpp/ql/src/semmle/code/cpp/ir/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/IR.qll index f019f20b6a83..381adad5e418 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/IR.qll @@ -1,3 +1,47 @@ +/** + * Provides classes that describe the Intermediate Representation (IR) of the program. + * + * The IR is a representation of the semantics of the program, with very little dependence on the + * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, + * and `++i` all have the same semantic effect, but appear in the AST as three different types of + * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental + * operations similar to: + * + * ``` + * r1(int*) = VariableAddress[i] // Compute the address of variable `i` + * r2(int) = Load &:r1, m0 // Load the value of `i` + * r3(int) = Constant[1] // An integer constant with the value `1` + * r4(int) = Add r2, r3 // Add `1` to the value of `i` + * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` + * ``` + * + * This allows IR-based analysis to focus on the fundamental operations, rather than having to be + * concerned with the various ways of expressing those operations in source code. + * + * The key classes in the IR are: + * + * - `IRFunction` - Contains the IR for an entire function definition, including all of that + * function's `Instruction`s, `IRBlock`s, and `IRVariables`. + * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be + * performed, the operands that produce the inputs to that operation, and the type of the result + * of the operation. Control flows from an `Instruction` to one of a set of successor + * `Instruction`s. + * - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly + * represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has + * a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction` + * that produces its value (its "definition"). + * - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is + * created for each variable directly accessed by the function. In addition, `IRVariable`s are + * created to represent certain temporary storage locations that do not have explicitly declared + * variables in the source code, such as the return value of the function. + * - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a + * sequence of instructions such that control flow can only enter the block at the first + * instruction, and can only leave the block from the last instruction. + * - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType` + * is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all + * be represented as the `IRType` `uint4`, a four-byte unsigned integer. + */ + // Most queries should operate on the aliased SSA IR, so that's what we expose -// publically as the "IR". +// publicly as the "IR". import implementation.aliased_ssa.IR diff --git a/cpp/ql/src/semmle/code/cpp/ir/IRConfiguration.qll b/cpp/ql/src/semmle/code/cpp/ir/IRConfiguration.qll index b5b7d7de7c24..b8abef8a5474 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/IRConfiguration.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/IRConfiguration.qll @@ -1 +1,5 @@ +/** + * Module used to configure the IR generation process. + */ + import implementation.IRConfiguration diff --git a/cpp/ql/src/semmle/code/cpp/ir/PrintIR.qll b/cpp/ql/src/semmle/code/cpp/ir/PrintIR.qll index 3ff802376357..c4ebf2f1eba2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/PrintIR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/PrintIR.qll @@ -1 +1,11 @@ +/** + * Outputs a representation of the IR as a control flow graph. + * + * This file contains the actual implementation of `PrintIR.ql`. For test cases and very small + * databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintIR.qll`, extends + * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to + * dump. + */ + import implementation.aliased_ssa.PrintIR diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll index ddf43651727c..d735c8422480 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -70,7 +70,7 @@ private DataFlow::Node getNodeForSource(Expr source) { // // This case goes together with the similar (but not identical) rule in // `nodeIsBarrierIn`. - result = DataFlow::definitionByReferenceNode(source) and + result = DataFlow::definitionByReferenceNodeFromArgument(source) and not argv(source.(VariableAccess).getTarget()) ) } @@ -210,7 +210,7 @@ private predicate nodeIsBarrierIn(DataFlow::Node node) { or // This case goes together with the similar (but not identical) rule in // `getNodeForSource`. - node = DataFlow::definitionByReferenceNode(source) + node = DataFlow::definitionByReferenceNodeFromArgument(source) ) } @@ -264,9 +264,6 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) { t instanceof Union or t instanceof ArrayType - or - // Buffers of unknown size - t instanceof UnknownType ) or exists(BinaryInstruction bin | diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll index d8904625e0ea..e927634fec23 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll @@ -226,28 +226,13 @@ private predicate functionSignature(Function f, string qualifiedName, int nparam } /** - * Holds if the call context `ctx` reduces the set of viable dispatch - * targets of `ma` in `c`. + * Holds if the set of viable implementations that can be called by `call` + * might be improved by knowing the call context. */ -predicate reducedViableImplInCallContext(CallInstruction call, Function f, CallInstruction ctx) { - none() -} - -/** - * Gets a viable dispatch target of `ma` in the context `ctx`. This is - * restricted to those `ma`s for which the context makes a difference. - */ -Function prunedViableImplInCallContext(CallInstruction call, CallInstruction ctx) { none() } - -/** - * Holds if flow returning from `m` to `ma` might return further and if - * this path restricts the set of call sites that can be returned to. - */ -predicate reducedViableImplInReturn(Function f, CallInstruction call) { none() } +predicate mayBenefitFromCallContext(CallInstruction call, Function f) { none() } /** - * Gets a viable dispatch target of `ma` in the context `ctx`. This is - * restricted to those `ma`s and results for which the return flow from the - * result to `ma` restricts the possible context `ctx`. + * Gets a viable dispatch target of `call` in the context `ctx`. This is + * restricted to those `call`s for which a context might make a difference. */ -Function prunedViableImplInCallContextReverse(CallInstruction call, CallInstruction ctx) { none() } +Function viableImplInCallContext(CallInstruction call, CallInstruction ctx) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index f876c04d6c66..8bc3d75ff86e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -286,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -318,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -417,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -447,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -566,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -748,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -781,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -896,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -930,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1046,11 +1051,22 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1058,9 +1074,9 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1074,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1108,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1122,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1154,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1183,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1197,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1223,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1261,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } +pragma[nomagic] +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + pragma[nomagic] private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1385,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1417,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1497,24 +1523,24 @@ private predicate flowCandIsReturned( ) } -private newtype TAccessPath = +private newtype TAccessPathApprox = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two - * elements of the list and its length are tracked. If data flows from a source to - * a given node with a given `AccessPath`, this indicates the sequence 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. + * Conceptually a list of `TypedContent`s followed by a `DataFlowType`, but only + * the first two elements of the list and its length are tracked. If data flows + * from a source to a given node with a given `AccessPathApprox`, this indicates + * the sequence 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 { +abstract private class AccessPathApprox extends TAccessPathApprox { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1522,20 +1548,18 @@ abstract private class AccessPath extends TAccessPath { abstract AccessPathFront getFront(); - /** - * Holds if this access path has `head` at the front and may be followed by `tail`. - */ - abstract predicate pop(Content head, AccessPath tail); + /** Gets the access path obtained by popping `head` from this path, if any. */ + abstract AccessPathApprox pop(TypedContent head); } -private class AccessPathNil extends AccessPath, TNil { +private class AccessPathApproxNil extends AccessPathApprox, TNil { private DataFlowType t; - AccessPathNil() { this = TNil(t) } + AccessPathApproxNil() { this = TNil(t) } override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1543,258 +1567,285 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override AccessPathApprox pop(TypedContent head) { none() } } -abstract private class AccessPathCons extends AccessPath { } +abstract private class AccessPathApproxCons extends AccessPathApprox { } -private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; +private class AccessPathApproxConsNil extends AccessPathApproxCons, TConsNil { + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathApproxConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override AccessPathApprox pop(TypedContent head) { head = tc and result = TNil(t) } } -private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; +private class AccessPathApproxConsCons extends AccessPathApproxCons, TConsCons { + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathApproxConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override AccessPathApprox pop(TypedContent head) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + result = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + result = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPathApprox pop(TypedContent tc, AccessPathApprox apa) { result = apa.pop(tc) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPathApprox push(TypedContent tc, AccessPathApprox apa) { apa = pop(tc, result) } -private newtype TAccessPathOption = - TAccessPathNone() or - TAccessPathSome(AccessPath ap) +private newtype TAccessPathApproxOption = + TAccessPathApproxNone() or + TAccessPathApproxSome(AccessPathApprox apa) -private class AccessPathOption extends TAccessPathOption { +private class AccessPathApproxOption extends TAccessPathApproxOption { string toString() { - this = TAccessPathNone() and result = "" + this = TAccessPathApproxNone() and result = "" or - this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + this = TAccessPathApproxSome(any(AccessPathApprox apa | result = apa.toString())) } } /** - * Holds if `node` is reachable with access path `ap` from a source in - * the configuration `config`. + * Holds if `node` is reachable with approximate access path `apa` from a source + * in the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an - * argument in a call, and if so, `argAp` records the access path of that - * argument. + * The call context `cc` records whether the node is reached through an + * argument in a call, and if so, `argApa` records the approximate access path + * of that argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argApa, apf, apa, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, apf, apa, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and - apf = ap.(AccessPathNil).getFront() + exists(Node mid, AccessPathApproxNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and + apf = apa.(AccessPathApproxNil).getFront() ) or exists(Node mid | - flowFwd(mid, _, _, apf, ap, config) and + flowFwd(mid, _, _, apf, apa, config) and jumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | + exists(Node mid, AccessPathApproxNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, apa), apf, cc, argApa, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, apa), apf, cc, argApa, config) and + flowFwdConsCand(tc, apf, apa, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, _, cc, _, apf, apa, config) and if flowCand(node, true, _, apf, config) - then argAp = TAccessPathSome(ap) - else argAp = TAccessPathNone() + then argApa = TAccessPathApproxSome(apa) + else argApa = TAccessPathApproxNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argApa, apf, apa, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or - exists(AccessPath argAp0 | - flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + exists(AccessPathApprox argApa0 | + flowFwdOutFromArg(call, node, argApa0, apf, apa, config) and + flowFwdIsEntered(call, cc, argApa, argApa0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argApa, apf, apa, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - AccessPathOption argAp, Configuration config + Node node, TypedContent tc, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwd(mid, cc, argApa, apf0, apa0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPathApprox apa0, Node node2, + CallContext cc, AccessPathApproxOption argApa, Configuration config +) { + flowFwd(node1, cc, argApa, apf0, apa0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + pragma[nomagic] private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config + Node node, AccessPathFrontHead apf0, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, apa0, node, cc, argApa, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(Node n | - flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwd(n, _, _, apf, apa, config) and + flowFwdStore0(n, tc, _, apf, _, config) ) } pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argApa, apf, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argApa, apf, apa, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOutFromArg( - DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + DataFlowCall call, Node node, AccessPathApprox argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathApproxSome(argApa), apf, apa, + config) } /** @@ -1802,166 +1853,174 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathApproxOption argApa, AccessPathApprox apa, + Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argApa, apf, apa, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if `node` with access path `ap` is part of a path from a source to - * a sink in the configuration `config`. + * Holds if `node` with approximate access path `apa` is part of a path from a + * source to a sink in the configuration `config`. * * The Boolean `toReturn` records whether the node must be returned from - * the enclosing callable in order to reach a sink, and if so, `returnAp` - * records the access path of the returned value. + * the enclosing callable in order to reach a sink, and if so, `returnApa` + * records the approximate access path of the returned value. */ private predicate flow( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flow0(node, toReturn, returnAp, ap, config) and - flowFwd(node, _, _, _, ap, config) + flow0(node, toReturn, returnApa, apa, config) and + flowFwd(node, _, _, _, apa, config) } private predicate flow0( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flowFwd(node, _, _, _, ap, config) and + flowFwd(node, _, _, _, apa, config) and config.isSink(node) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil or exists(Node mid | localFlowBigStep(node, mid, true, _, config, _) and - flow(mid, toReturn, returnAp, ap, config) + flow(mid, toReturn, returnApa, apa, config) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and localFlowBigStep(node, mid, false, _, config, _) and - flow(mid, toReturn, returnAp, nil, config) and - ap instanceof AccessPathNil + flow(mid, toReturn, returnApa, nil, config) and + apa instanceof AccessPathApproxNil ) or exists(Node mid | jumpStep(node, mid, config) and - flow(mid, _, _, ap, config) and + flow(mid, _, _, apa, config) and toReturn = false and - returnAp = TAccessPathNone() + returnApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and additionalJumpStep(node, mid, config) and flow(mid, _, _, nil, config) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnApa, apa, config) and + flowConsCand(tc, apa, config) ) or // read - exists(Node mid, AccessPath ap0 | - readFlowFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + readFlowFwd(node, _, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) or // flow into a callable exists(DataFlowCall call | - flowIn(call, node, toReturn, returnAp, ap, config) and + flowIn(call, node, toReturn, returnApa, apa, config) and toReturn = false or - exists(AccessPath returnAp0 | - flowInToReturn(call, node, returnAp0, ap, config) and - flowIsReturned(call, toReturn, returnAp, returnAp0, config) + exists(AccessPathApprox returnApa0 | + flowInToReturn(call, node, returnApa0, apa, config) and + flowIsReturned(call, toReturn, returnApa, returnApa0, config) ) ) or // flow out of a callable - flowOut(_, node, _, _, ap, config) and + flowOut(_, node, _, _, apa, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) - then returnAp = TAccessPathSome(ap) - else returnAp = TAccessPathNone() + if flowFwd(node, any(CallContextCall ccc), TAccessPathApproxSome(_), _, apa, config) + then returnApa = TAccessPathApproxSome(apa) + else returnApa = TAccessPathApproxNone() } pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, apa, _, _, _, config) and + apa0 = push(tc, apa) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { - exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + storeFlowFwd(node, tc, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, apa, _, _, _, config) and + apa0 = pop(tc, apa) and + flowFwdConsCand(tc, _, apa0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPathApprox apa, Configuration config) { exists(Node n, Node mid | - flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + flow(mid, _, _, apa, config) and + readFlowFwd(n, tc, mid, _, apa, config) ) } pragma[nomagic] private predicate flowOut( - DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(Node out, boolean allowsFieldFlow | - flow(out, toReturn, returnAp, ap, config) and + flow(out, toReturn, returnApa, apa, config) and flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowIn( - DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(ParameterNode p, boolean allowsFieldFlow | - flow(p, toReturn, returnAp, ap, config) and + flow(p, toReturn, returnApa, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowInToReturn( - DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config + DataFlowCall call, ArgumentNode arg, AccessPathApprox returnApa, AccessPathApprox apa, + Configuration config ) { - flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) + flowIn(call, arg, true, TAccessPathApproxSome(returnApa), apa, config) } /** @@ -1969,12 +2028,13 @@ private predicate flowInToReturn( */ pragma[nomagic] private predicate flowIsReturned( - DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + DataFlowCall call, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, Configuration config ) { - exists(ReturnNodeExt ret | - flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + exists(ReturnNodeExt ret, CallContextCall ccc | + flowOut(call, ret, toReturn, returnApa, apa, config) and + flowFwd(ret, ccc, TAccessPathApproxSome(_), _, apa, config) and + ccc.matchesCall(call) ) } @@ -1985,21 +2045,23 @@ private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) pragma[noinline] private predicate parameterFlow( - ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config + ParameterNode p, AccessPathApprox apa, DataFlowCallable c, Configuration config ) { - flow(p, true, _, ap, config) and + flow(p, true, _, apa, config) and c = p.getEnclosingCallable() } +private predicate parameterMayFlowThrough(ParameterNode p, AccessPathApprox apa) { + exists(ReturnNodeExt ret, Configuration config, AccessPathApprox apa0 | + parameterFlow(p, apa, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathApproxSome(_), apa0, config) and + flowFwd(ret, any(CallContextCall ccc), TAccessPathApproxSome(apa), _, apa0, config) + ) +} + private newtype TSummaryCtx = TSummaryCtxNone() or - TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | - parameterFlow(p, ap, ret.getEnclosingCallable(), config) and - flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) - ) - } + TSummaryCtxSome(ParameterNode p, AccessPath ap) { parameterMayFlowThrough(p, ap.getApprox()) } /** * A context for generating flow summaries. This represents flow entry through @@ -2034,6 +2096,10 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { } } +private newtype TAccessPath = + TAccessPathNil(DataFlowType t) or + TAccessPathCons(TypedContent head, AccessPath tail) { flowConsCand(head, tail.getApprox(), _) } + private newtype TPathNode = TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) { // A PathNode is introduced by a source ... @@ -2041,13 +2107,13 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(node, _, _, ap, unbind(config)) + flow(node, _, _, ap.getApprox(), unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2059,12 +2125,99 @@ private newtype TPathNode = or // ... or a sink that can be reached from a source exists(PathNodeMid mid | - pathStep(mid, node, _, _, any(AccessPathNil nil)) and + pathStep(mid, node, _, _, TAccessPathNil(_)) and config = unbind(mid.getConfiguration()) ) ) } +/** + * A list of `TypedContent`s followed by a `DataFlowType`. If data flows from a + * source to a given node with a given `AccessPath`, this indicates the sequence + * 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 { + /** Gets the head of this access path, if any. */ + abstract TypedContent getHead(); + + /** Gets the tail of this access path, if any. */ + abstract AccessPath getTail(); + + /** Gets the front of this access path. */ + abstract AccessPathFront getFront(); + + /** Gets the approximation of this access path. */ + abstract AccessPathApprox getApprox(); + + /** Gets the length of this access path. */ + abstract int length(); + + /** Gets a textual representation of this access path. */ + abstract string toString(); + + /** Gets the access path obtained by popping `tc` from this access path, if any. */ + final AccessPath pop(TypedContent tc) { + result = this.getTail() and + tc = this.getHead() + } + + /** Gets the access path obtained by pushing `tc` onto this access path. */ + final AccessPath push(TypedContent tc) { this = result.pop(tc) } +} + +private class AccessPathNil extends AccessPath, TAccessPathNil { + private DataFlowType t; + + AccessPathNil() { this = TAccessPathNil(t) } + + DataFlowType getType() { result = t } + + override TypedContent getHead() { none() } + + override AccessPath getTail() { none() } + + override AccessPathFrontNil getFront() { result = TFrontNil(t) } + + override AccessPathApproxNil getApprox() { result = TNil(t) } + + override int length() { result = 0 } + + override string toString() { result = concat(": " + ppReprType(t)) } +} + +private class AccessPathCons extends AccessPath, TAccessPathCons { + private TypedContent head; + private AccessPath tail; + + AccessPathCons() { this = TAccessPathCons(head, tail) } + + override TypedContent getHead() { result = head } + + override AccessPath getTail() { result = tail } + + override AccessPathFrontHead getFront() { result = TFrontHead(head) } + + override AccessPathApproxCons getApprox() { + result = TConsNil(head, tail.(AccessPathNil).getType()) + or + result = TConsCons(head, tail.getHead(), this.length()) + } + + override int length() { result = 1 + tail.length() } + + private string toStringImpl() { + exists(DataFlowType t | + tail = TAccessPathNil(t) and + result = head.toString() + "]" + concat(" : " + ppReprType(t)) + ) + or + result = head + ", " + tail.(AccessPathCons).toStringImpl() + } + + override string toString() { result = "[" + this.toStringImpl() } +} + /** * A `Node` augmented with a call context (except for sinks), an access path, and a configuration. * Only those `PathNode`s that are reachable from a source are generated. @@ -2098,14 +2251,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2350,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2387,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2251,12 +2421,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2267,50 +2437,53 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } private predicate pathOutOfCallable0( - PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPath ap, Configuration config + PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa, + Configuration config ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and - ap = mid.getAp() and + innercc instanceof CallContextNoCall and + apa = mid.getAp().getApprox() and config = mid.getConfiguration() } pragma[nomagic] private predicate pathOutOfCallable1( - PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPath ap, + PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPathApprox apa, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | - pathOutOfCallable0(mid, pos, innercc, ap, config) and + pathOutOfCallable0(mid, pos, innercc, apa, config) and c = pos.getCallable() and kind = pos.getKind() and resolveReturn(innercc, c, call) @@ -2321,10 +2494,10 @@ private predicate pathOutOfCallable1( pragma[noinline] private Node getAnOutNodeFlow( - ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config + ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ) { result = kind.getAnOutNode(call) and - flow(result, _, _, ap, config) + flow(result, _, _, apa, config) } /** @@ -2333,10 +2506,9 @@ private Node getAnOutNodeFlow( */ pragma[noinline] private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { - exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | - pathOutOfCallable1(mid, call, kind, cc, ap, config) - | - out = getAnOutNodeFlow(kind, call, ap, config) + exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config | + pathOutOfCallable1(mid, call, kind, cc, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -2345,22 +2517,23 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa ) { exists(ArgumentNode arg | arg = mid.getNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and - ap = mid.getAp() + ap = mid.getAp() and + apa = ap.getApprox() ) } pragma[noinline] private predicate parameterCand( - DataFlowCallable callable, int i, AccessPath ap, Configuration config + DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { exists(ParameterNode p | - flow(p, _, _, ap, config) and + flow(p, _, _, apa, config) and p.isParameterOf(callable, i) ) } @@ -2370,9 +2543,11 @@ private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, AccessPath ap ) { - pathIntoArg(mid, i, outercc, call, ap) and - callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), ap, mid.getConfiguration()) + exists(AccessPathApprox apa | + pathIntoArg(mid, i, outercc, call, ap, apa) and + callable = resolveCall(call, outercc) and + parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + ) } /** @@ -2403,7 +2578,8 @@ private predicate pathIntoCallable( /** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */ pragma[nomagic] private predicate paramFlowsThrough( - ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config + ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(PathNodeMid mid, ReturnNodeExt ret, int pos | mid.getNode() = ret and @@ -2412,6 +2588,7 @@ private predicate paramFlowsThrough( sc = mid.getSummaryCtx() and config = mid.getConfiguration() and ap = mid.getAp() and + apa = ap.getApprox() and pos = sc.getParameterPos() and not kind.(ParamUpdateReturnKind).getPosition() = pos ) @@ -2419,11 +2596,12 @@ private predicate paramFlowsThrough( pragma[nomagic] private predicate pathThroughCallable0( - DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap + DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, + AccessPathApprox apa ) { exists(CallContext innercc, SummaryCtx sc | pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, unbind(mid.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration())) ) } @@ -2433,9 +2611,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind | - pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | + pathThroughCallable0(call, mid, kind, cc, ap, apa) and + out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration())) ) } @@ -2521,10 +2699,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2533,7 +2711,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2544,7 +2722,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2562,15 +2740,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2591,7 +2769,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2608,7 +2786,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2721,7 +2899,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2737,7 +2915,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2746,11 +2924,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2769,35 +2948,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( @@ -2806,7 +2992,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index f876c04d6c66..8bc3d75ff86e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -286,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -318,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -417,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -447,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -566,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -748,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -781,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -896,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -930,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1046,11 +1051,22 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1058,9 +1074,9 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1074,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1108,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1122,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1154,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1183,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1197,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1223,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1261,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } +pragma[nomagic] +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + pragma[nomagic] private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1385,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1417,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1497,24 +1523,24 @@ private predicate flowCandIsReturned( ) } -private newtype TAccessPath = +private newtype TAccessPathApprox = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two - * elements of the list and its length are tracked. If data flows from a source to - * a given node with a given `AccessPath`, this indicates the sequence 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. + * Conceptually a list of `TypedContent`s followed by a `DataFlowType`, but only + * the first two elements of the list and its length are tracked. If data flows + * from a source to a given node with a given `AccessPathApprox`, this indicates + * the sequence 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 { +abstract private class AccessPathApprox extends TAccessPathApprox { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1522,20 +1548,18 @@ abstract private class AccessPath extends TAccessPath { abstract AccessPathFront getFront(); - /** - * Holds if this access path has `head` at the front and may be followed by `tail`. - */ - abstract predicate pop(Content head, AccessPath tail); + /** Gets the access path obtained by popping `head` from this path, if any. */ + abstract AccessPathApprox pop(TypedContent head); } -private class AccessPathNil extends AccessPath, TNil { +private class AccessPathApproxNil extends AccessPathApprox, TNil { private DataFlowType t; - AccessPathNil() { this = TNil(t) } + AccessPathApproxNil() { this = TNil(t) } override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1543,258 +1567,285 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override AccessPathApprox pop(TypedContent head) { none() } } -abstract private class AccessPathCons extends AccessPath { } +abstract private class AccessPathApproxCons extends AccessPathApprox { } -private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; +private class AccessPathApproxConsNil extends AccessPathApproxCons, TConsNil { + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathApproxConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override AccessPathApprox pop(TypedContent head) { head = tc and result = TNil(t) } } -private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; +private class AccessPathApproxConsCons extends AccessPathApproxCons, TConsCons { + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathApproxConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override AccessPathApprox pop(TypedContent head) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + result = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + result = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPathApprox pop(TypedContent tc, AccessPathApprox apa) { result = apa.pop(tc) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPathApprox push(TypedContent tc, AccessPathApprox apa) { apa = pop(tc, result) } -private newtype TAccessPathOption = - TAccessPathNone() or - TAccessPathSome(AccessPath ap) +private newtype TAccessPathApproxOption = + TAccessPathApproxNone() or + TAccessPathApproxSome(AccessPathApprox apa) -private class AccessPathOption extends TAccessPathOption { +private class AccessPathApproxOption extends TAccessPathApproxOption { string toString() { - this = TAccessPathNone() and result = "" + this = TAccessPathApproxNone() and result = "" or - this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + this = TAccessPathApproxSome(any(AccessPathApprox apa | result = apa.toString())) } } /** - * Holds if `node` is reachable with access path `ap` from a source in - * the configuration `config`. + * Holds if `node` is reachable with approximate access path `apa` from a source + * in the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an - * argument in a call, and if so, `argAp` records the access path of that - * argument. + * The call context `cc` records whether the node is reached through an + * argument in a call, and if so, `argApa` records the approximate access path + * of that argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argApa, apf, apa, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, apf, apa, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and - apf = ap.(AccessPathNil).getFront() + exists(Node mid, AccessPathApproxNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and + apf = apa.(AccessPathApproxNil).getFront() ) or exists(Node mid | - flowFwd(mid, _, _, apf, ap, config) and + flowFwd(mid, _, _, apf, apa, config) and jumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | + exists(Node mid, AccessPathApproxNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, apa), apf, cc, argApa, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, apa), apf, cc, argApa, config) and + flowFwdConsCand(tc, apf, apa, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, _, cc, _, apf, apa, config) and if flowCand(node, true, _, apf, config) - then argAp = TAccessPathSome(ap) - else argAp = TAccessPathNone() + then argApa = TAccessPathApproxSome(apa) + else argApa = TAccessPathApproxNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argApa, apf, apa, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or - exists(AccessPath argAp0 | - flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + exists(AccessPathApprox argApa0 | + flowFwdOutFromArg(call, node, argApa0, apf, apa, config) and + flowFwdIsEntered(call, cc, argApa, argApa0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argApa, apf, apa, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - AccessPathOption argAp, Configuration config + Node node, TypedContent tc, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwd(mid, cc, argApa, apf0, apa0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPathApprox apa0, Node node2, + CallContext cc, AccessPathApproxOption argApa, Configuration config +) { + flowFwd(node1, cc, argApa, apf0, apa0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + pragma[nomagic] private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config + Node node, AccessPathFrontHead apf0, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, apa0, node, cc, argApa, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(Node n | - flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwd(n, _, _, apf, apa, config) and + flowFwdStore0(n, tc, _, apf, _, config) ) } pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argApa, apf, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argApa, apf, apa, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOutFromArg( - DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + DataFlowCall call, Node node, AccessPathApprox argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathApproxSome(argApa), apf, apa, + config) } /** @@ -1802,166 +1853,174 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathApproxOption argApa, AccessPathApprox apa, + Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argApa, apf, apa, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if `node` with access path `ap` is part of a path from a source to - * a sink in the configuration `config`. + * Holds if `node` with approximate access path `apa` is part of a path from a + * source to a sink in the configuration `config`. * * The Boolean `toReturn` records whether the node must be returned from - * the enclosing callable in order to reach a sink, and if so, `returnAp` - * records the access path of the returned value. + * the enclosing callable in order to reach a sink, and if so, `returnApa` + * records the approximate access path of the returned value. */ private predicate flow( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flow0(node, toReturn, returnAp, ap, config) and - flowFwd(node, _, _, _, ap, config) + flow0(node, toReturn, returnApa, apa, config) and + flowFwd(node, _, _, _, apa, config) } private predicate flow0( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flowFwd(node, _, _, _, ap, config) and + flowFwd(node, _, _, _, apa, config) and config.isSink(node) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil or exists(Node mid | localFlowBigStep(node, mid, true, _, config, _) and - flow(mid, toReturn, returnAp, ap, config) + flow(mid, toReturn, returnApa, apa, config) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and localFlowBigStep(node, mid, false, _, config, _) and - flow(mid, toReturn, returnAp, nil, config) and - ap instanceof AccessPathNil + flow(mid, toReturn, returnApa, nil, config) and + apa instanceof AccessPathApproxNil ) or exists(Node mid | jumpStep(node, mid, config) and - flow(mid, _, _, ap, config) and + flow(mid, _, _, apa, config) and toReturn = false and - returnAp = TAccessPathNone() + returnApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and additionalJumpStep(node, mid, config) and flow(mid, _, _, nil, config) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnApa, apa, config) and + flowConsCand(tc, apa, config) ) or // read - exists(Node mid, AccessPath ap0 | - readFlowFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + readFlowFwd(node, _, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) or // flow into a callable exists(DataFlowCall call | - flowIn(call, node, toReturn, returnAp, ap, config) and + flowIn(call, node, toReturn, returnApa, apa, config) and toReturn = false or - exists(AccessPath returnAp0 | - flowInToReturn(call, node, returnAp0, ap, config) and - flowIsReturned(call, toReturn, returnAp, returnAp0, config) + exists(AccessPathApprox returnApa0 | + flowInToReturn(call, node, returnApa0, apa, config) and + flowIsReturned(call, toReturn, returnApa, returnApa0, config) ) ) or // flow out of a callable - flowOut(_, node, _, _, ap, config) and + flowOut(_, node, _, _, apa, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) - then returnAp = TAccessPathSome(ap) - else returnAp = TAccessPathNone() + if flowFwd(node, any(CallContextCall ccc), TAccessPathApproxSome(_), _, apa, config) + then returnApa = TAccessPathApproxSome(apa) + else returnApa = TAccessPathApproxNone() } pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, apa, _, _, _, config) and + apa0 = push(tc, apa) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { - exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + storeFlowFwd(node, tc, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, apa, _, _, _, config) and + apa0 = pop(tc, apa) and + flowFwdConsCand(tc, _, apa0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPathApprox apa, Configuration config) { exists(Node n, Node mid | - flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + flow(mid, _, _, apa, config) and + readFlowFwd(n, tc, mid, _, apa, config) ) } pragma[nomagic] private predicate flowOut( - DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(Node out, boolean allowsFieldFlow | - flow(out, toReturn, returnAp, ap, config) and + flow(out, toReturn, returnApa, apa, config) and flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowIn( - DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(ParameterNode p, boolean allowsFieldFlow | - flow(p, toReturn, returnAp, ap, config) and + flow(p, toReturn, returnApa, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowInToReturn( - DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config + DataFlowCall call, ArgumentNode arg, AccessPathApprox returnApa, AccessPathApprox apa, + Configuration config ) { - flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) + flowIn(call, arg, true, TAccessPathApproxSome(returnApa), apa, config) } /** @@ -1969,12 +2028,13 @@ private predicate flowInToReturn( */ pragma[nomagic] private predicate flowIsReturned( - DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + DataFlowCall call, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, Configuration config ) { - exists(ReturnNodeExt ret | - flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + exists(ReturnNodeExt ret, CallContextCall ccc | + flowOut(call, ret, toReturn, returnApa, apa, config) and + flowFwd(ret, ccc, TAccessPathApproxSome(_), _, apa, config) and + ccc.matchesCall(call) ) } @@ -1985,21 +2045,23 @@ private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) pragma[noinline] private predicate parameterFlow( - ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config + ParameterNode p, AccessPathApprox apa, DataFlowCallable c, Configuration config ) { - flow(p, true, _, ap, config) and + flow(p, true, _, apa, config) and c = p.getEnclosingCallable() } +private predicate parameterMayFlowThrough(ParameterNode p, AccessPathApprox apa) { + exists(ReturnNodeExt ret, Configuration config, AccessPathApprox apa0 | + parameterFlow(p, apa, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathApproxSome(_), apa0, config) and + flowFwd(ret, any(CallContextCall ccc), TAccessPathApproxSome(apa), _, apa0, config) + ) +} + private newtype TSummaryCtx = TSummaryCtxNone() or - TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | - parameterFlow(p, ap, ret.getEnclosingCallable(), config) and - flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) - ) - } + TSummaryCtxSome(ParameterNode p, AccessPath ap) { parameterMayFlowThrough(p, ap.getApprox()) } /** * A context for generating flow summaries. This represents flow entry through @@ -2034,6 +2096,10 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { } } +private newtype TAccessPath = + TAccessPathNil(DataFlowType t) or + TAccessPathCons(TypedContent head, AccessPath tail) { flowConsCand(head, tail.getApprox(), _) } + private newtype TPathNode = TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) { // A PathNode is introduced by a source ... @@ -2041,13 +2107,13 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(node, _, _, ap, unbind(config)) + flow(node, _, _, ap.getApprox(), unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2059,12 +2125,99 @@ private newtype TPathNode = or // ... or a sink that can be reached from a source exists(PathNodeMid mid | - pathStep(mid, node, _, _, any(AccessPathNil nil)) and + pathStep(mid, node, _, _, TAccessPathNil(_)) and config = unbind(mid.getConfiguration()) ) ) } +/** + * A list of `TypedContent`s followed by a `DataFlowType`. If data flows from a + * source to a given node with a given `AccessPath`, this indicates the sequence + * 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 { + /** Gets the head of this access path, if any. */ + abstract TypedContent getHead(); + + /** Gets the tail of this access path, if any. */ + abstract AccessPath getTail(); + + /** Gets the front of this access path. */ + abstract AccessPathFront getFront(); + + /** Gets the approximation of this access path. */ + abstract AccessPathApprox getApprox(); + + /** Gets the length of this access path. */ + abstract int length(); + + /** Gets a textual representation of this access path. */ + abstract string toString(); + + /** Gets the access path obtained by popping `tc` from this access path, if any. */ + final AccessPath pop(TypedContent tc) { + result = this.getTail() and + tc = this.getHead() + } + + /** Gets the access path obtained by pushing `tc` onto this access path. */ + final AccessPath push(TypedContent tc) { this = result.pop(tc) } +} + +private class AccessPathNil extends AccessPath, TAccessPathNil { + private DataFlowType t; + + AccessPathNil() { this = TAccessPathNil(t) } + + DataFlowType getType() { result = t } + + override TypedContent getHead() { none() } + + override AccessPath getTail() { none() } + + override AccessPathFrontNil getFront() { result = TFrontNil(t) } + + override AccessPathApproxNil getApprox() { result = TNil(t) } + + override int length() { result = 0 } + + override string toString() { result = concat(": " + ppReprType(t)) } +} + +private class AccessPathCons extends AccessPath, TAccessPathCons { + private TypedContent head; + private AccessPath tail; + + AccessPathCons() { this = TAccessPathCons(head, tail) } + + override TypedContent getHead() { result = head } + + override AccessPath getTail() { result = tail } + + override AccessPathFrontHead getFront() { result = TFrontHead(head) } + + override AccessPathApproxCons getApprox() { + result = TConsNil(head, tail.(AccessPathNil).getType()) + or + result = TConsCons(head, tail.getHead(), this.length()) + } + + override int length() { result = 1 + tail.length() } + + private string toStringImpl() { + exists(DataFlowType t | + tail = TAccessPathNil(t) and + result = head.toString() + "]" + concat(" : " + ppReprType(t)) + ) + or + result = head + ", " + tail.(AccessPathCons).toStringImpl() + } + + override string toString() { result = "[" + this.toStringImpl() } +} + /** * A `Node` augmented with a call context (except for sinks), an access path, and a configuration. * Only those `PathNode`s that are reachable from a source are generated. @@ -2098,14 +2251,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2350,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2387,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2251,12 +2421,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2267,50 +2437,53 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } private predicate pathOutOfCallable0( - PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPath ap, Configuration config + PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa, + Configuration config ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and - ap = mid.getAp() and + innercc instanceof CallContextNoCall and + apa = mid.getAp().getApprox() and config = mid.getConfiguration() } pragma[nomagic] private predicate pathOutOfCallable1( - PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPath ap, + PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPathApprox apa, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | - pathOutOfCallable0(mid, pos, innercc, ap, config) and + pathOutOfCallable0(mid, pos, innercc, apa, config) and c = pos.getCallable() and kind = pos.getKind() and resolveReturn(innercc, c, call) @@ -2321,10 +2494,10 @@ private predicate pathOutOfCallable1( pragma[noinline] private Node getAnOutNodeFlow( - ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config + ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ) { result = kind.getAnOutNode(call) and - flow(result, _, _, ap, config) + flow(result, _, _, apa, config) } /** @@ -2333,10 +2506,9 @@ private Node getAnOutNodeFlow( */ pragma[noinline] private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { - exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | - pathOutOfCallable1(mid, call, kind, cc, ap, config) - | - out = getAnOutNodeFlow(kind, call, ap, config) + exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config | + pathOutOfCallable1(mid, call, kind, cc, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -2345,22 +2517,23 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa ) { exists(ArgumentNode arg | arg = mid.getNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and - ap = mid.getAp() + ap = mid.getAp() and + apa = ap.getApprox() ) } pragma[noinline] private predicate parameterCand( - DataFlowCallable callable, int i, AccessPath ap, Configuration config + DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { exists(ParameterNode p | - flow(p, _, _, ap, config) and + flow(p, _, _, apa, config) and p.isParameterOf(callable, i) ) } @@ -2370,9 +2543,11 @@ private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, AccessPath ap ) { - pathIntoArg(mid, i, outercc, call, ap) and - callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), ap, mid.getConfiguration()) + exists(AccessPathApprox apa | + pathIntoArg(mid, i, outercc, call, ap, apa) and + callable = resolveCall(call, outercc) and + parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + ) } /** @@ -2403,7 +2578,8 @@ private predicate pathIntoCallable( /** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */ pragma[nomagic] private predicate paramFlowsThrough( - ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config + ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(PathNodeMid mid, ReturnNodeExt ret, int pos | mid.getNode() = ret and @@ -2412,6 +2588,7 @@ private predicate paramFlowsThrough( sc = mid.getSummaryCtx() and config = mid.getConfiguration() and ap = mid.getAp() and + apa = ap.getApprox() and pos = sc.getParameterPos() and not kind.(ParamUpdateReturnKind).getPosition() = pos ) @@ -2419,11 +2596,12 @@ private predicate paramFlowsThrough( pragma[nomagic] private predicate pathThroughCallable0( - DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap + DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, + AccessPathApprox apa ) { exists(CallContext innercc, SummaryCtx sc | pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, unbind(mid.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration())) ) } @@ -2433,9 +2611,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind | - pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | + pathThroughCallable0(call, mid, kind, cc, ap, apa) and + out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration())) ) } @@ -2521,10 +2699,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2533,7 +2711,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2544,7 +2722,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2562,15 +2740,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2591,7 +2769,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2608,7 +2786,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2721,7 +2899,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2737,7 +2915,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2746,11 +2924,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2769,35 +2948,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( @@ -2806,7 +2992,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index f876c04d6c66..8bc3d75ff86e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -286,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -318,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -417,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -447,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -566,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -748,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -781,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -896,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -930,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1046,11 +1051,22 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1058,9 +1074,9 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1074,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1108,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1122,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1154,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1183,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1197,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1223,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1261,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } +pragma[nomagic] +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + pragma[nomagic] private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1385,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1417,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1497,24 +1523,24 @@ private predicate flowCandIsReturned( ) } -private newtype TAccessPath = +private newtype TAccessPathApprox = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two - * elements of the list and its length are tracked. If data flows from a source to - * a given node with a given `AccessPath`, this indicates the sequence 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. + * Conceptually a list of `TypedContent`s followed by a `DataFlowType`, but only + * the first two elements of the list and its length are tracked. If data flows + * from a source to a given node with a given `AccessPathApprox`, this indicates + * the sequence 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 { +abstract private class AccessPathApprox extends TAccessPathApprox { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1522,20 +1548,18 @@ abstract private class AccessPath extends TAccessPath { abstract AccessPathFront getFront(); - /** - * Holds if this access path has `head` at the front and may be followed by `tail`. - */ - abstract predicate pop(Content head, AccessPath tail); + /** Gets the access path obtained by popping `head` from this path, if any. */ + abstract AccessPathApprox pop(TypedContent head); } -private class AccessPathNil extends AccessPath, TNil { +private class AccessPathApproxNil extends AccessPathApprox, TNil { private DataFlowType t; - AccessPathNil() { this = TNil(t) } + AccessPathApproxNil() { this = TNil(t) } override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1543,258 +1567,285 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override AccessPathApprox pop(TypedContent head) { none() } } -abstract private class AccessPathCons extends AccessPath { } +abstract private class AccessPathApproxCons extends AccessPathApprox { } -private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; +private class AccessPathApproxConsNil extends AccessPathApproxCons, TConsNil { + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathApproxConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override AccessPathApprox pop(TypedContent head) { head = tc and result = TNil(t) } } -private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; +private class AccessPathApproxConsCons extends AccessPathApproxCons, TConsCons { + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathApproxConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override AccessPathApprox pop(TypedContent head) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + result = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + result = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPathApprox pop(TypedContent tc, AccessPathApprox apa) { result = apa.pop(tc) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPathApprox push(TypedContent tc, AccessPathApprox apa) { apa = pop(tc, result) } -private newtype TAccessPathOption = - TAccessPathNone() or - TAccessPathSome(AccessPath ap) +private newtype TAccessPathApproxOption = + TAccessPathApproxNone() or + TAccessPathApproxSome(AccessPathApprox apa) -private class AccessPathOption extends TAccessPathOption { +private class AccessPathApproxOption extends TAccessPathApproxOption { string toString() { - this = TAccessPathNone() and result = "" + this = TAccessPathApproxNone() and result = "" or - this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + this = TAccessPathApproxSome(any(AccessPathApprox apa | result = apa.toString())) } } /** - * Holds if `node` is reachable with access path `ap` from a source in - * the configuration `config`. + * Holds if `node` is reachable with approximate access path `apa` from a source + * in the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an - * argument in a call, and if so, `argAp` records the access path of that - * argument. + * The call context `cc` records whether the node is reached through an + * argument in a call, and if so, `argApa` records the approximate access path + * of that argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argApa, apf, apa, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, apf, apa, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and - apf = ap.(AccessPathNil).getFront() + exists(Node mid, AccessPathApproxNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and + apf = apa.(AccessPathApproxNil).getFront() ) or exists(Node mid | - flowFwd(mid, _, _, apf, ap, config) and + flowFwd(mid, _, _, apf, apa, config) and jumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | + exists(Node mid, AccessPathApproxNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, apa), apf, cc, argApa, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, apa), apf, cc, argApa, config) and + flowFwdConsCand(tc, apf, apa, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, _, cc, _, apf, apa, config) and if flowCand(node, true, _, apf, config) - then argAp = TAccessPathSome(ap) - else argAp = TAccessPathNone() + then argApa = TAccessPathApproxSome(apa) + else argApa = TAccessPathApproxNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argApa, apf, apa, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or - exists(AccessPath argAp0 | - flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + exists(AccessPathApprox argApa0 | + flowFwdOutFromArg(call, node, argApa0, apf, apa, config) and + flowFwdIsEntered(call, cc, argApa, argApa0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argApa, apf, apa, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - AccessPathOption argAp, Configuration config + Node node, TypedContent tc, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwd(mid, cc, argApa, apf0, apa0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPathApprox apa0, Node node2, + CallContext cc, AccessPathApproxOption argApa, Configuration config +) { + flowFwd(node1, cc, argApa, apf0, apa0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + pragma[nomagic] private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config + Node node, AccessPathFrontHead apf0, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, apa0, node, cc, argApa, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(Node n | - flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwd(n, _, _, apf, apa, config) and + flowFwdStore0(n, tc, _, apf, _, config) ) } pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argApa, apf, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argApa, apf, apa, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOutFromArg( - DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + DataFlowCall call, Node node, AccessPathApprox argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathApproxSome(argApa), apf, apa, + config) } /** @@ -1802,166 +1853,174 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathApproxOption argApa, AccessPathApprox apa, + Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argApa, apf, apa, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if `node` with access path `ap` is part of a path from a source to - * a sink in the configuration `config`. + * Holds if `node` with approximate access path `apa` is part of a path from a + * source to a sink in the configuration `config`. * * The Boolean `toReturn` records whether the node must be returned from - * the enclosing callable in order to reach a sink, and if so, `returnAp` - * records the access path of the returned value. + * the enclosing callable in order to reach a sink, and if so, `returnApa` + * records the approximate access path of the returned value. */ private predicate flow( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flow0(node, toReturn, returnAp, ap, config) and - flowFwd(node, _, _, _, ap, config) + flow0(node, toReturn, returnApa, apa, config) and + flowFwd(node, _, _, _, apa, config) } private predicate flow0( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flowFwd(node, _, _, _, ap, config) and + flowFwd(node, _, _, _, apa, config) and config.isSink(node) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil or exists(Node mid | localFlowBigStep(node, mid, true, _, config, _) and - flow(mid, toReturn, returnAp, ap, config) + flow(mid, toReturn, returnApa, apa, config) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and localFlowBigStep(node, mid, false, _, config, _) and - flow(mid, toReturn, returnAp, nil, config) and - ap instanceof AccessPathNil + flow(mid, toReturn, returnApa, nil, config) and + apa instanceof AccessPathApproxNil ) or exists(Node mid | jumpStep(node, mid, config) and - flow(mid, _, _, ap, config) and + flow(mid, _, _, apa, config) and toReturn = false and - returnAp = TAccessPathNone() + returnApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and additionalJumpStep(node, mid, config) and flow(mid, _, _, nil, config) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnApa, apa, config) and + flowConsCand(tc, apa, config) ) or // read - exists(Node mid, AccessPath ap0 | - readFlowFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + readFlowFwd(node, _, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) or // flow into a callable exists(DataFlowCall call | - flowIn(call, node, toReturn, returnAp, ap, config) and + flowIn(call, node, toReturn, returnApa, apa, config) and toReturn = false or - exists(AccessPath returnAp0 | - flowInToReturn(call, node, returnAp0, ap, config) and - flowIsReturned(call, toReturn, returnAp, returnAp0, config) + exists(AccessPathApprox returnApa0 | + flowInToReturn(call, node, returnApa0, apa, config) and + flowIsReturned(call, toReturn, returnApa, returnApa0, config) ) ) or // flow out of a callable - flowOut(_, node, _, _, ap, config) and + flowOut(_, node, _, _, apa, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) - then returnAp = TAccessPathSome(ap) - else returnAp = TAccessPathNone() + if flowFwd(node, any(CallContextCall ccc), TAccessPathApproxSome(_), _, apa, config) + then returnApa = TAccessPathApproxSome(apa) + else returnApa = TAccessPathApproxNone() } pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, apa, _, _, _, config) and + apa0 = push(tc, apa) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { - exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + storeFlowFwd(node, tc, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, apa, _, _, _, config) and + apa0 = pop(tc, apa) and + flowFwdConsCand(tc, _, apa0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPathApprox apa, Configuration config) { exists(Node n, Node mid | - flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + flow(mid, _, _, apa, config) and + readFlowFwd(n, tc, mid, _, apa, config) ) } pragma[nomagic] private predicate flowOut( - DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(Node out, boolean allowsFieldFlow | - flow(out, toReturn, returnAp, ap, config) and + flow(out, toReturn, returnApa, apa, config) and flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowIn( - DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(ParameterNode p, boolean allowsFieldFlow | - flow(p, toReturn, returnAp, ap, config) and + flow(p, toReturn, returnApa, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowInToReturn( - DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config + DataFlowCall call, ArgumentNode arg, AccessPathApprox returnApa, AccessPathApprox apa, + Configuration config ) { - flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) + flowIn(call, arg, true, TAccessPathApproxSome(returnApa), apa, config) } /** @@ -1969,12 +2028,13 @@ private predicate flowInToReturn( */ pragma[nomagic] private predicate flowIsReturned( - DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + DataFlowCall call, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, Configuration config ) { - exists(ReturnNodeExt ret | - flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + exists(ReturnNodeExt ret, CallContextCall ccc | + flowOut(call, ret, toReturn, returnApa, apa, config) and + flowFwd(ret, ccc, TAccessPathApproxSome(_), _, apa, config) and + ccc.matchesCall(call) ) } @@ -1985,21 +2045,23 @@ private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) pragma[noinline] private predicate parameterFlow( - ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config + ParameterNode p, AccessPathApprox apa, DataFlowCallable c, Configuration config ) { - flow(p, true, _, ap, config) and + flow(p, true, _, apa, config) and c = p.getEnclosingCallable() } +private predicate parameterMayFlowThrough(ParameterNode p, AccessPathApprox apa) { + exists(ReturnNodeExt ret, Configuration config, AccessPathApprox apa0 | + parameterFlow(p, apa, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathApproxSome(_), apa0, config) and + flowFwd(ret, any(CallContextCall ccc), TAccessPathApproxSome(apa), _, apa0, config) + ) +} + private newtype TSummaryCtx = TSummaryCtxNone() or - TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | - parameterFlow(p, ap, ret.getEnclosingCallable(), config) and - flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) - ) - } + TSummaryCtxSome(ParameterNode p, AccessPath ap) { parameterMayFlowThrough(p, ap.getApprox()) } /** * A context for generating flow summaries. This represents flow entry through @@ -2034,6 +2096,10 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { } } +private newtype TAccessPath = + TAccessPathNil(DataFlowType t) or + TAccessPathCons(TypedContent head, AccessPath tail) { flowConsCand(head, tail.getApprox(), _) } + private newtype TPathNode = TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) { // A PathNode is introduced by a source ... @@ -2041,13 +2107,13 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(node, _, _, ap, unbind(config)) + flow(node, _, _, ap.getApprox(), unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2059,12 +2125,99 @@ private newtype TPathNode = or // ... or a sink that can be reached from a source exists(PathNodeMid mid | - pathStep(mid, node, _, _, any(AccessPathNil nil)) and + pathStep(mid, node, _, _, TAccessPathNil(_)) and config = unbind(mid.getConfiguration()) ) ) } +/** + * A list of `TypedContent`s followed by a `DataFlowType`. If data flows from a + * source to a given node with a given `AccessPath`, this indicates the sequence + * 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 { + /** Gets the head of this access path, if any. */ + abstract TypedContent getHead(); + + /** Gets the tail of this access path, if any. */ + abstract AccessPath getTail(); + + /** Gets the front of this access path. */ + abstract AccessPathFront getFront(); + + /** Gets the approximation of this access path. */ + abstract AccessPathApprox getApprox(); + + /** Gets the length of this access path. */ + abstract int length(); + + /** Gets a textual representation of this access path. */ + abstract string toString(); + + /** Gets the access path obtained by popping `tc` from this access path, if any. */ + final AccessPath pop(TypedContent tc) { + result = this.getTail() and + tc = this.getHead() + } + + /** Gets the access path obtained by pushing `tc` onto this access path. */ + final AccessPath push(TypedContent tc) { this = result.pop(tc) } +} + +private class AccessPathNil extends AccessPath, TAccessPathNil { + private DataFlowType t; + + AccessPathNil() { this = TAccessPathNil(t) } + + DataFlowType getType() { result = t } + + override TypedContent getHead() { none() } + + override AccessPath getTail() { none() } + + override AccessPathFrontNil getFront() { result = TFrontNil(t) } + + override AccessPathApproxNil getApprox() { result = TNil(t) } + + override int length() { result = 0 } + + override string toString() { result = concat(": " + ppReprType(t)) } +} + +private class AccessPathCons extends AccessPath, TAccessPathCons { + private TypedContent head; + private AccessPath tail; + + AccessPathCons() { this = TAccessPathCons(head, tail) } + + override TypedContent getHead() { result = head } + + override AccessPath getTail() { result = tail } + + override AccessPathFrontHead getFront() { result = TFrontHead(head) } + + override AccessPathApproxCons getApprox() { + result = TConsNil(head, tail.(AccessPathNil).getType()) + or + result = TConsCons(head, tail.getHead(), this.length()) + } + + override int length() { result = 1 + tail.length() } + + private string toStringImpl() { + exists(DataFlowType t | + tail = TAccessPathNil(t) and + result = head.toString() + "]" + concat(" : " + ppReprType(t)) + ) + or + result = head + ", " + tail.(AccessPathCons).toStringImpl() + } + + override string toString() { result = "[" + this.toStringImpl() } +} + /** * A `Node` augmented with a call context (except for sinks), an access path, and a configuration. * Only those `PathNode`s that are reachable from a source are generated. @@ -2098,14 +2251,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2350,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2387,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2251,12 +2421,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2267,50 +2437,53 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } private predicate pathOutOfCallable0( - PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPath ap, Configuration config + PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa, + Configuration config ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and - ap = mid.getAp() and + innercc instanceof CallContextNoCall and + apa = mid.getAp().getApprox() and config = mid.getConfiguration() } pragma[nomagic] private predicate pathOutOfCallable1( - PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPath ap, + PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPathApprox apa, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | - pathOutOfCallable0(mid, pos, innercc, ap, config) and + pathOutOfCallable0(mid, pos, innercc, apa, config) and c = pos.getCallable() and kind = pos.getKind() and resolveReturn(innercc, c, call) @@ -2321,10 +2494,10 @@ private predicate pathOutOfCallable1( pragma[noinline] private Node getAnOutNodeFlow( - ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config + ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ) { result = kind.getAnOutNode(call) and - flow(result, _, _, ap, config) + flow(result, _, _, apa, config) } /** @@ -2333,10 +2506,9 @@ private Node getAnOutNodeFlow( */ pragma[noinline] private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { - exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | - pathOutOfCallable1(mid, call, kind, cc, ap, config) - | - out = getAnOutNodeFlow(kind, call, ap, config) + exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config | + pathOutOfCallable1(mid, call, kind, cc, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -2345,22 +2517,23 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa ) { exists(ArgumentNode arg | arg = mid.getNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and - ap = mid.getAp() + ap = mid.getAp() and + apa = ap.getApprox() ) } pragma[noinline] private predicate parameterCand( - DataFlowCallable callable, int i, AccessPath ap, Configuration config + DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { exists(ParameterNode p | - flow(p, _, _, ap, config) and + flow(p, _, _, apa, config) and p.isParameterOf(callable, i) ) } @@ -2370,9 +2543,11 @@ private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, AccessPath ap ) { - pathIntoArg(mid, i, outercc, call, ap) and - callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), ap, mid.getConfiguration()) + exists(AccessPathApprox apa | + pathIntoArg(mid, i, outercc, call, ap, apa) and + callable = resolveCall(call, outercc) and + parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + ) } /** @@ -2403,7 +2578,8 @@ private predicate pathIntoCallable( /** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */ pragma[nomagic] private predicate paramFlowsThrough( - ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config + ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(PathNodeMid mid, ReturnNodeExt ret, int pos | mid.getNode() = ret and @@ -2412,6 +2588,7 @@ private predicate paramFlowsThrough( sc = mid.getSummaryCtx() and config = mid.getConfiguration() and ap = mid.getAp() and + apa = ap.getApprox() and pos = sc.getParameterPos() and not kind.(ParamUpdateReturnKind).getPosition() = pos ) @@ -2419,11 +2596,12 @@ private predicate paramFlowsThrough( pragma[nomagic] private predicate pathThroughCallable0( - DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap + DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, + AccessPathApprox apa ) { exists(CallContext innercc, SummaryCtx sc | pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, unbind(mid.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration())) ) } @@ -2433,9 +2611,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind | - pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | + pathThroughCallable0(call, mid, kind, cc, ap, apa) and + out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration())) ) } @@ -2521,10 +2699,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2533,7 +2711,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2544,7 +2722,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2562,15 +2740,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2591,7 +2769,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2608,7 +2786,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2721,7 +2899,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2737,7 +2915,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2746,11 +2924,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2769,35 +2948,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( @@ -2806,7 +2992,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index f876c04d6c66..8bc3d75ff86e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -286,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -318,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -417,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -447,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -566,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -748,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -781,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -896,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -930,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1046,11 +1051,22 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1058,9 +1074,9 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1074,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1108,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1122,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1154,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1183,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1197,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1223,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1261,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } +pragma[nomagic] +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + pragma[nomagic] private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1385,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1417,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1497,24 +1523,24 @@ private predicate flowCandIsReturned( ) } -private newtype TAccessPath = +private newtype TAccessPathApprox = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two - * elements of the list and its length are tracked. If data flows from a source to - * a given node with a given `AccessPath`, this indicates the sequence 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. + * Conceptually a list of `TypedContent`s followed by a `DataFlowType`, but only + * the first two elements of the list and its length are tracked. If data flows + * from a source to a given node with a given `AccessPathApprox`, this indicates + * the sequence 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 { +abstract private class AccessPathApprox extends TAccessPathApprox { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1522,20 +1548,18 @@ abstract private class AccessPath extends TAccessPath { abstract AccessPathFront getFront(); - /** - * Holds if this access path has `head` at the front and may be followed by `tail`. - */ - abstract predicate pop(Content head, AccessPath tail); + /** Gets the access path obtained by popping `head` from this path, if any. */ + abstract AccessPathApprox pop(TypedContent head); } -private class AccessPathNil extends AccessPath, TNil { +private class AccessPathApproxNil extends AccessPathApprox, TNil { private DataFlowType t; - AccessPathNil() { this = TNil(t) } + AccessPathApproxNil() { this = TNil(t) } override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1543,258 +1567,285 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override AccessPathApprox pop(TypedContent head) { none() } } -abstract private class AccessPathCons extends AccessPath { } +abstract private class AccessPathApproxCons extends AccessPathApprox { } -private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; +private class AccessPathApproxConsNil extends AccessPathApproxCons, TConsNil { + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathApproxConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override AccessPathApprox pop(TypedContent head) { head = tc and result = TNil(t) } } -private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; +private class AccessPathApproxConsCons extends AccessPathApproxCons, TConsCons { + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathApproxConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override AccessPathApprox pop(TypedContent head) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + result = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + result = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPathApprox pop(TypedContent tc, AccessPathApprox apa) { result = apa.pop(tc) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPathApprox push(TypedContent tc, AccessPathApprox apa) { apa = pop(tc, result) } -private newtype TAccessPathOption = - TAccessPathNone() or - TAccessPathSome(AccessPath ap) +private newtype TAccessPathApproxOption = + TAccessPathApproxNone() or + TAccessPathApproxSome(AccessPathApprox apa) -private class AccessPathOption extends TAccessPathOption { +private class AccessPathApproxOption extends TAccessPathApproxOption { string toString() { - this = TAccessPathNone() and result = "" + this = TAccessPathApproxNone() and result = "" or - this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + this = TAccessPathApproxSome(any(AccessPathApprox apa | result = apa.toString())) } } /** - * Holds if `node` is reachable with access path `ap` from a source in - * the configuration `config`. + * Holds if `node` is reachable with approximate access path `apa` from a source + * in the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an - * argument in a call, and if so, `argAp` records the access path of that - * argument. + * The call context `cc` records whether the node is reached through an + * argument in a call, and if so, `argApa` records the approximate access path + * of that argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argApa, apf, apa, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, apf, apa, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and - apf = ap.(AccessPathNil).getFront() + exists(Node mid, AccessPathApproxNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and + apf = apa.(AccessPathApproxNil).getFront() ) or exists(Node mid | - flowFwd(mid, _, _, apf, ap, config) and + flowFwd(mid, _, _, apf, apa, config) and jumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | + exists(Node mid, AccessPathApproxNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, apa), apf, cc, argApa, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, apa), apf, cc, argApa, config) and + flowFwdConsCand(tc, apf, apa, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, _, cc, _, apf, apa, config) and if flowCand(node, true, _, apf, config) - then argAp = TAccessPathSome(ap) - else argAp = TAccessPathNone() + then argApa = TAccessPathApproxSome(apa) + else argApa = TAccessPathApproxNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argApa, apf, apa, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or - exists(AccessPath argAp0 | - flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + exists(AccessPathApprox argApa0 | + flowFwdOutFromArg(call, node, argApa0, apf, apa, config) and + flowFwdIsEntered(call, cc, argApa, argApa0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argApa, apf, apa, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - AccessPathOption argAp, Configuration config + Node node, TypedContent tc, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwd(mid, cc, argApa, apf0, apa0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPathApprox apa0, Node node2, + CallContext cc, AccessPathApproxOption argApa, Configuration config +) { + flowFwd(node1, cc, argApa, apf0, apa0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + pragma[nomagic] private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config + Node node, AccessPathFrontHead apf0, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, apa0, node, cc, argApa, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(Node n | - flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwd(n, _, _, apf, apa, config) and + flowFwdStore0(n, tc, _, apf, _, config) ) } pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argApa, apf, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argApa, apf, apa, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOutFromArg( - DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + DataFlowCall call, Node node, AccessPathApprox argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathApproxSome(argApa), apf, apa, + config) } /** @@ -1802,166 +1853,174 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathApproxOption argApa, AccessPathApprox apa, + Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argApa, apf, apa, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if `node` with access path `ap` is part of a path from a source to - * a sink in the configuration `config`. + * Holds if `node` with approximate access path `apa` is part of a path from a + * source to a sink in the configuration `config`. * * The Boolean `toReturn` records whether the node must be returned from - * the enclosing callable in order to reach a sink, and if so, `returnAp` - * records the access path of the returned value. + * the enclosing callable in order to reach a sink, and if so, `returnApa` + * records the approximate access path of the returned value. */ private predicate flow( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flow0(node, toReturn, returnAp, ap, config) and - flowFwd(node, _, _, _, ap, config) + flow0(node, toReturn, returnApa, apa, config) and + flowFwd(node, _, _, _, apa, config) } private predicate flow0( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flowFwd(node, _, _, _, ap, config) and + flowFwd(node, _, _, _, apa, config) and config.isSink(node) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil or exists(Node mid | localFlowBigStep(node, mid, true, _, config, _) and - flow(mid, toReturn, returnAp, ap, config) + flow(mid, toReturn, returnApa, apa, config) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and localFlowBigStep(node, mid, false, _, config, _) and - flow(mid, toReturn, returnAp, nil, config) and - ap instanceof AccessPathNil + flow(mid, toReturn, returnApa, nil, config) and + apa instanceof AccessPathApproxNil ) or exists(Node mid | jumpStep(node, mid, config) and - flow(mid, _, _, ap, config) and + flow(mid, _, _, apa, config) and toReturn = false and - returnAp = TAccessPathNone() + returnApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and additionalJumpStep(node, mid, config) and flow(mid, _, _, nil, config) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnApa, apa, config) and + flowConsCand(tc, apa, config) ) or // read - exists(Node mid, AccessPath ap0 | - readFlowFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + readFlowFwd(node, _, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) or // flow into a callable exists(DataFlowCall call | - flowIn(call, node, toReturn, returnAp, ap, config) and + flowIn(call, node, toReturn, returnApa, apa, config) and toReturn = false or - exists(AccessPath returnAp0 | - flowInToReturn(call, node, returnAp0, ap, config) and - flowIsReturned(call, toReturn, returnAp, returnAp0, config) + exists(AccessPathApprox returnApa0 | + flowInToReturn(call, node, returnApa0, apa, config) and + flowIsReturned(call, toReturn, returnApa, returnApa0, config) ) ) or // flow out of a callable - flowOut(_, node, _, _, ap, config) and + flowOut(_, node, _, _, apa, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) - then returnAp = TAccessPathSome(ap) - else returnAp = TAccessPathNone() + if flowFwd(node, any(CallContextCall ccc), TAccessPathApproxSome(_), _, apa, config) + then returnApa = TAccessPathApproxSome(apa) + else returnApa = TAccessPathApproxNone() } pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, apa, _, _, _, config) and + apa0 = push(tc, apa) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { - exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + storeFlowFwd(node, tc, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, apa, _, _, _, config) and + apa0 = pop(tc, apa) and + flowFwdConsCand(tc, _, apa0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPathApprox apa, Configuration config) { exists(Node n, Node mid | - flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + flow(mid, _, _, apa, config) and + readFlowFwd(n, tc, mid, _, apa, config) ) } pragma[nomagic] private predicate flowOut( - DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(Node out, boolean allowsFieldFlow | - flow(out, toReturn, returnAp, ap, config) and + flow(out, toReturn, returnApa, apa, config) and flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowIn( - DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(ParameterNode p, boolean allowsFieldFlow | - flow(p, toReturn, returnAp, ap, config) and + flow(p, toReturn, returnApa, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowInToReturn( - DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config + DataFlowCall call, ArgumentNode arg, AccessPathApprox returnApa, AccessPathApprox apa, + Configuration config ) { - flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) + flowIn(call, arg, true, TAccessPathApproxSome(returnApa), apa, config) } /** @@ -1969,12 +2028,13 @@ private predicate flowInToReturn( */ pragma[nomagic] private predicate flowIsReturned( - DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + DataFlowCall call, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, Configuration config ) { - exists(ReturnNodeExt ret | - flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + exists(ReturnNodeExt ret, CallContextCall ccc | + flowOut(call, ret, toReturn, returnApa, apa, config) and + flowFwd(ret, ccc, TAccessPathApproxSome(_), _, apa, config) and + ccc.matchesCall(call) ) } @@ -1985,21 +2045,23 @@ private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) pragma[noinline] private predicate parameterFlow( - ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config + ParameterNode p, AccessPathApprox apa, DataFlowCallable c, Configuration config ) { - flow(p, true, _, ap, config) and + flow(p, true, _, apa, config) and c = p.getEnclosingCallable() } +private predicate parameterMayFlowThrough(ParameterNode p, AccessPathApprox apa) { + exists(ReturnNodeExt ret, Configuration config, AccessPathApprox apa0 | + parameterFlow(p, apa, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathApproxSome(_), apa0, config) and + flowFwd(ret, any(CallContextCall ccc), TAccessPathApproxSome(apa), _, apa0, config) + ) +} + private newtype TSummaryCtx = TSummaryCtxNone() or - TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | - parameterFlow(p, ap, ret.getEnclosingCallable(), config) and - flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) - ) - } + TSummaryCtxSome(ParameterNode p, AccessPath ap) { parameterMayFlowThrough(p, ap.getApprox()) } /** * A context for generating flow summaries. This represents flow entry through @@ -2034,6 +2096,10 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { } } +private newtype TAccessPath = + TAccessPathNil(DataFlowType t) or + TAccessPathCons(TypedContent head, AccessPath tail) { flowConsCand(head, tail.getApprox(), _) } + private newtype TPathNode = TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) { // A PathNode is introduced by a source ... @@ -2041,13 +2107,13 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(node, _, _, ap, unbind(config)) + flow(node, _, _, ap.getApprox(), unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2059,12 +2125,99 @@ private newtype TPathNode = or // ... or a sink that can be reached from a source exists(PathNodeMid mid | - pathStep(mid, node, _, _, any(AccessPathNil nil)) and + pathStep(mid, node, _, _, TAccessPathNil(_)) and config = unbind(mid.getConfiguration()) ) ) } +/** + * A list of `TypedContent`s followed by a `DataFlowType`. If data flows from a + * source to a given node with a given `AccessPath`, this indicates the sequence + * 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 { + /** Gets the head of this access path, if any. */ + abstract TypedContent getHead(); + + /** Gets the tail of this access path, if any. */ + abstract AccessPath getTail(); + + /** Gets the front of this access path. */ + abstract AccessPathFront getFront(); + + /** Gets the approximation of this access path. */ + abstract AccessPathApprox getApprox(); + + /** Gets the length of this access path. */ + abstract int length(); + + /** Gets a textual representation of this access path. */ + abstract string toString(); + + /** Gets the access path obtained by popping `tc` from this access path, if any. */ + final AccessPath pop(TypedContent tc) { + result = this.getTail() and + tc = this.getHead() + } + + /** Gets the access path obtained by pushing `tc` onto this access path. */ + final AccessPath push(TypedContent tc) { this = result.pop(tc) } +} + +private class AccessPathNil extends AccessPath, TAccessPathNil { + private DataFlowType t; + + AccessPathNil() { this = TAccessPathNil(t) } + + DataFlowType getType() { result = t } + + override TypedContent getHead() { none() } + + override AccessPath getTail() { none() } + + override AccessPathFrontNil getFront() { result = TFrontNil(t) } + + override AccessPathApproxNil getApprox() { result = TNil(t) } + + override int length() { result = 0 } + + override string toString() { result = concat(": " + ppReprType(t)) } +} + +private class AccessPathCons extends AccessPath, TAccessPathCons { + private TypedContent head; + private AccessPath tail; + + AccessPathCons() { this = TAccessPathCons(head, tail) } + + override TypedContent getHead() { result = head } + + override AccessPath getTail() { result = tail } + + override AccessPathFrontHead getFront() { result = TFrontHead(head) } + + override AccessPathApproxCons getApprox() { + result = TConsNil(head, tail.(AccessPathNil).getType()) + or + result = TConsCons(head, tail.getHead(), this.length()) + } + + override int length() { result = 1 + tail.length() } + + private string toStringImpl() { + exists(DataFlowType t | + tail = TAccessPathNil(t) and + result = head.toString() + "]" + concat(" : " + ppReprType(t)) + ) + or + result = head + ", " + tail.(AccessPathCons).toStringImpl() + } + + override string toString() { result = "[" + this.toStringImpl() } +} + /** * A `Node` augmented with a call context (except for sinks), an access path, and a configuration. * Only those `PathNode`s that are reachable from a source are generated. @@ -2098,14 +2251,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2350,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2387,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2251,12 +2421,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2267,50 +2437,53 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } private predicate pathOutOfCallable0( - PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPath ap, Configuration config + PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa, + Configuration config ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and - ap = mid.getAp() and + innercc instanceof CallContextNoCall and + apa = mid.getAp().getApprox() and config = mid.getConfiguration() } pragma[nomagic] private predicate pathOutOfCallable1( - PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPath ap, + PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPathApprox apa, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | - pathOutOfCallable0(mid, pos, innercc, ap, config) and + pathOutOfCallable0(mid, pos, innercc, apa, config) and c = pos.getCallable() and kind = pos.getKind() and resolveReturn(innercc, c, call) @@ -2321,10 +2494,10 @@ private predicate pathOutOfCallable1( pragma[noinline] private Node getAnOutNodeFlow( - ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config + ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ) { result = kind.getAnOutNode(call) and - flow(result, _, _, ap, config) + flow(result, _, _, apa, config) } /** @@ -2333,10 +2506,9 @@ private Node getAnOutNodeFlow( */ pragma[noinline] private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { - exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | - pathOutOfCallable1(mid, call, kind, cc, ap, config) - | - out = getAnOutNodeFlow(kind, call, ap, config) + exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config | + pathOutOfCallable1(mid, call, kind, cc, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -2345,22 +2517,23 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa ) { exists(ArgumentNode arg | arg = mid.getNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and - ap = mid.getAp() + ap = mid.getAp() and + apa = ap.getApprox() ) } pragma[noinline] private predicate parameterCand( - DataFlowCallable callable, int i, AccessPath ap, Configuration config + DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { exists(ParameterNode p | - flow(p, _, _, ap, config) and + flow(p, _, _, apa, config) and p.isParameterOf(callable, i) ) } @@ -2370,9 +2543,11 @@ private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, AccessPath ap ) { - pathIntoArg(mid, i, outercc, call, ap) and - callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), ap, mid.getConfiguration()) + exists(AccessPathApprox apa | + pathIntoArg(mid, i, outercc, call, ap, apa) and + callable = resolveCall(call, outercc) and + parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + ) } /** @@ -2403,7 +2578,8 @@ private predicate pathIntoCallable( /** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */ pragma[nomagic] private predicate paramFlowsThrough( - ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config + ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(PathNodeMid mid, ReturnNodeExt ret, int pos | mid.getNode() = ret and @@ -2412,6 +2588,7 @@ private predicate paramFlowsThrough( sc = mid.getSummaryCtx() and config = mid.getConfiguration() and ap = mid.getAp() and + apa = ap.getApprox() and pos = sc.getParameterPos() and not kind.(ParamUpdateReturnKind).getPosition() = pos ) @@ -2419,11 +2596,12 @@ private predicate paramFlowsThrough( pragma[nomagic] private predicate pathThroughCallable0( - DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap + DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, + AccessPathApprox apa ) { exists(CallContext innercc, SummaryCtx sc | pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, unbind(mid.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration())) ) } @@ -2433,9 +2611,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind | - pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | + pathThroughCallable0(call, mid, kind, cc, ap, apa) and + out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration())) ) } @@ -2521,10 +2699,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2533,7 +2711,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2544,7 +2722,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2562,15 +2740,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2591,7 +2769,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2608,7 +2786,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2721,7 +2899,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2737,7 +2915,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2746,11 +2924,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2769,35 +2948,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( @@ -2806,7 +2992,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll index 852f54974e24..892250f44bb8 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll @@ -22,7 +22,7 @@ private module Cached { exists(int i | viableParam(call, i, p) and arg.argumentOf(call, i) and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(p)) + compatibleTypes(getNodeType(arg), getNodeType(p)) ) } @@ -147,174 +147,140 @@ private module Cached { } } - private module LocalFlowBigStep { - private predicate localFlowEntry(Node n) { - Cand::cand(_, n) and - ( - n instanceof ParameterNode or - n instanceof OutNode or - readStep(_, _, n) or - n instanceof CastNode - ) - } - - private predicate localFlowExit(Node n) { - Cand::cand(_, n) and - ( - n instanceof ArgumentNode - or - n instanceof ReturnNode - or - readStep(n, _, _) - or - n instanceof CastNode - or - n = - any(PostUpdateNode pun | Cand::parameterValueFlowsToPreUpdateCand(_, pun)) - .getPreUpdateNode() - ) - } - - pragma[nomagic] - private predicate localFlowStepPlus(Node node1, Node node2) { - localFlowEntry(node1) and - simpleLocalFlowStep(node1, node2) and - node1 != node2 - or - exists(Node mid | - localFlowStepPlus(node1, mid) and - simpleLocalFlowStep(mid, node2) and - not mid instanceof CastNode - ) - } - - pragma[nomagic] - predicate localFlowBigStep(Node node1, Node node2) { - localFlowStepPlus(node1, node2) and - localFlowExit(node2) - } - } - /** * The final flow-through calculation: * - * - Input access paths are abstracted with a `ContentOption` parameter - * that represents the head of the access path. `TContentNone()` means that - * the access path is unrestricted. + * - Calculated flow is either value-preserving (`read = TReadStepTypesNone()`) + * or summarized as a single read step with before and after types recorded + * in the `ReadStepTypesOption` parameter. * - Types are checked using the `compatibleTypes()` relation. */ private module Final { /** * Holds if `p` can flow to `node` in the same callable using only - * value-preserving steps, not taking call contexts into account. + * value-preserving steps and possibly a single read step, not taking + * call contexts into account. * - * `contentIn` describes the content of `p` that can flow to `node` - * (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ - predicate parameterValueFlow(ParameterNode p, Node node, ContentOption contentIn) { - parameterValueFlow0(p, node, contentIn) and + predicate parameterValueFlow(ParameterNode p, Node node, ReadStepTypesOption read) { + parameterValueFlow0(p, node, read) and if node instanceof CastingNode then // normal flow through - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) + read = TReadStepTypesNone() and + compatibleTypes(getNodeType(p), getNodeType(node)) or // getter - exists(Content fIn | - contentIn.getContent() = fIn and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(node)) - ) + compatibleTypes(read.getContentType(), getNodeType(node)) else any() } pragma[nomagic] - private predicate parameterValueFlow0(ParameterNode p, Node node, ContentOption contentIn) { + private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() + read = TReadStepTypesNone() or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn) and - LocalFlowBigStep::localFlowBigStep(mid, node) + parameterValueFlow(p, mid, read) and + simpleLocalFlowStep(mid, node) ) or // read - exists(Node mid, Content f | - parameterValueFlow(p, mid, TContentNone()) and - readStep(mid, f, node) and - contentIn.getContent() = f and + exists(Node mid | + parameterValueFlow(p, mid, TReadStepTypesNone()) and + readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, + read.getContentType()) and Cand::parameterValueFlowReturnCand(p, _, true) and - compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) + compatibleTypes(getNodeType(p), read.getContainerType()) ) or + parameterValueFlow0_0(TReadStepTypesNone(), p, node, read) + } + + pragma[nomagic] + private predicate parameterValueFlow0_0( + ReadStepTypesOption mustBeNone, ParameterNode p, Node node, ReadStepTypesOption read + ) { // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, TContentNone()) and - argumentValueFlowsThrough(arg, contentIn, node) + parameterValueFlowArg(p, arg, mustBeNone) and + argumentValueFlowsThrough(arg, read, node) ) or // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, contentIn) and - argumentValueFlowsThrough(arg, TContentNone(), node) + parameterValueFlowArg(p, arg, read) and + argumentValueFlowsThrough(arg, mustBeNone, node) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn + ParameterNode p, ArgumentNode arg, ReadStepTypesOption read ) { - parameterValueFlow(p, arg, contentIn) and + parameterValueFlow(p, arg, read) and Cand::argumentValueFlowsThroughCand(arg, _, _) } pragma[nomagic] private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn + DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, kind, contentIn) + parameterValueFlowReturn(param, kind, read) ) } /** - * Holds if `arg` flows to `out` through a call using only value-preserving steps, - * not taking call contexts into account. + * Holds if `arg` flows to `out` through a call using only + * value-preserving steps and possibly a single read step, not taking + * call contexts into account. * - * `contentIn` describes the content of `arg` that can flow to `out` (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ pragma[nomagic] - predicate argumentValueFlowsThrough(ArgumentNode arg, ContentOption contentIn, Node out) { + predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) { exists(DataFlowCall call, ReturnKind kind | - argumentValueFlowsThrough0(call, arg, kind, contentIn) and + argumentValueFlowsThrough0(call, arg, kind, read) and out = getAnOutNode(call, kind) | // normal flow through - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) + read = TReadStepTypesNone() and + compatibleTypes(getNodeType(arg), getNodeType(out)) or // getter - exists(Content fIn | - contentIn.getContent() = fIn and - compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(out)) - ) + compatibleTypes(getNodeType(arg), read.getContainerType()) and + compatibleTypes(read.getContentType(), getNodeType(out)) ) } + /** + * Holds if `arg` flows to `out` through a call using only + * value-preserving steps and a single read step, not taking call + * contexts into account, thus representing a getter-step. + */ + predicate getterStep(ArgumentNode arg, Content c, Node out) { + argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out) + } + /** * Holds if `p` can flow to a return node of kind `kind` in the same - * callable using only value-preserving steps. + * callable using only value-preserving steps and possibly a single read + * step. * - * `contentIn` describes the content of `p` that can flow to the return - * node (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ private predicate parameterValueFlowReturn( - ParameterNode p, ReturnKind kind, ContentOption contentIn + ParameterNode p, ReturnKind kind, ReadStepTypesOption read ) { exists(ReturnNode ret | - parameterValueFlow(p, ret, contentIn) and + parameterValueFlow(p, ret, read) and kind = ret.getKind() ) } @@ -323,37 +289,107 @@ private module Cached { import Final } + import FlowThrough + + cached + private module DispatchWithCallContext { + /** + * Holds if the call context `ctx` reduces the set of viable run-time + * dispatch targets of call `call` in `c`. + */ + cached + predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) { + exists(int tgts, int ctxtgts | + mayBenefitFromCallContext(call, c) and + c = viableCallable(ctx) and + ctxtgts = count(viableImplInCallContext(call, ctx)) and + tgts = strictcount(viableCallable(call)) and + ctxtgts < tgts + ) + } + + /** + * Gets a viable run-time dispatch target for the call `call` in the + * context `ctx`. This is restricted to those calls for which a context + * makes a difference. + */ + cached + DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) and + reducedViableImplInCallContext(call, _, ctx) + } + + /** + * Holds if flow returning from callable `c` to call `call` might return + * further and if this path restricts the set of call sites that can be + * returned to. + */ + cached + predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { + exists(int tgts, int ctxtgts | + mayBenefitFromCallContext(call, _) and + c = viableCallable(call) and + ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and + tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and + ctxtgts < tgts + ) + } + + /** + * Gets a viable run-time dispatch target for the call `call` in the + * context `ctx`. This is restricted to those calls and results for which + * the return flow from the result to `call` restricts the possible context + * `ctx`. + */ + cached + DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) and + reducedViableImplInReturn(result, call) + } + } + + import DispatchWithCallContext + /** * Holds if `p` can flow to the pre-update node associated with post-update * node `n`, in the same callable, using only value-preserving steps. */ cached predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone()) + parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone()) } - /** - * Holds if data can flow from `node1` to `node2` via a direct assignment to - * `f`. - * - * This includes reverse steps through reads when the result of the read has - * been stored into, in order to handle cases like `x.f1.f2 = y`. - */ - cached - predicate store(Node node1, Content f, Node node2) { - storeStep(node1, f, node2) and readStep(_, f, _) + private predicate store( + Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType + ) { + storeStep(node1, c, node2) and + readStep(_, c, _) and + contentType = getNodeType(node1) and + containerType = getNodeType(node2) or exists(Node n1, Node n2 | n1 = node1.(PostUpdateNode).getPreUpdateNode() and n2 = node2.(PostUpdateNode).getPreUpdateNode() | - argumentValueFlowsThrough(n2, TContentSome(f), n1) + argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1) or - readStep(n2, f, n1) + readStep(n2, c, n1) and + contentType = getNodeType(n1) and + containerType = getNodeType(n2) ) } - import FlowThrough + /** + * Holds if data can flow from `node1` to `node2` via a direct assignment to + * `f`. + * + * This includes reverse steps through reads when the result of the read has + * been stored into, in order to handle cases like `x.f1.f2 = y`. + */ + cached + predicate store(Node node1, TypedContent tc, Node node2, DataFlowType contentType) { + store(node1, tc.getContent(), node2, contentType, tc.getContainerType()) + } /** * Holds if the call context `call` either improves virtual dispatch in @@ -397,10 +433,13 @@ private module Cached { TBooleanNone() or TBooleanSome(boolean b) { b = true or b = false } + cached + newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } + cached newtype TAccessPathFront = TFrontNil(DataFlowType t) or - TFrontHead(Content f) + TFrontHead(TypedContent tc) cached newtype TAccessPathFrontOption = @@ -415,25 +454,38 @@ class CastingNode extends Node { CastingNode() { this instanceof ParameterNode or this instanceof CastNode or - this instanceof OutNodeExt + this instanceof OutNodeExt or + // For reads, `x.f`, we want to check that the tracked type after the read (which + // is obtained by popping the head of the access path stack) is compatible with + // the type of `x.f`. + readStep(_, _, this) } } -newtype TContentOption = - TContentNone() or - TContentSome(Content f) +private predicate readStepWithTypes( + Node n1, DataFlowType container, Content c, Node n2, DataFlowType content +) { + readStep(n1, c, n2) and + container = getNodeType(n1) and + content = getNodeType(n2) +} -private class ContentOption extends TContentOption { - Content getContent() { this = TContentSome(result) } +private newtype TReadStepTypesOption = + TReadStepTypesNone() or + TReadStepTypesSome(DataFlowType container, Content c, DataFlowType content) { + readStepWithTypes(_, container, c, _, content) + } - predicate hasContent() { exists(this.getContent()) } +private class ReadStepTypesOption extends TReadStepTypesOption { + predicate isSome() { this instanceof TReadStepTypesSome } - string toString() { - result = this.getContent().toString() - or - not this.hasContent() and - result = "" - } + DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) } + + Content getContent() { this = TReadStepTypesSome(_, result, _) } + + DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) } + + string toString() { if this.isSome() then result = "Some(..)" else result = "None()" } } /** @@ -460,13 +512,19 @@ abstract class CallContext extends TCallContext { abstract predicate relevantFor(DataFlowCallable callable); } -class CallContextAny extends CallContext, TAnyCallContext { +abstract class CallContextNoCall extends CallContext { } + +class CallContextAny extends CallContextNoCall, TAnyCallContext { override string toString() { result = "CcAny" } override predicate relevantFor(DataFlowCallable callable) { any() } } -abstract class CallContextCall extends CallContext { } +abstract class CallContextCall extends CallContext { + /** Holds if this call context may be `call`. */ + bindingset[call] + abstract predicate matchesCall(DataFlowCall call); +} class CallContextSpecificCall extends CallContextCall, TSpecificCall { override string toString() { @@ -477,6 +535,8 @@ class CallContextSpecificCall extends CallContextCall, TSpecificCall { recordDataFlowCallSite(getCall(), callable) } + override predicate matchesCall(DataFlowCall call) { call = this.getCall() } + DataFlowCall getCall() { this = TSpecificCall(result) } } @@ -486,9 +546,11 @@ class CallContextSomeCall extends CallContextCall, TSomeCall { override predicate relevantFor(DataFlowCallable callable) { exists(ParameterNode p | p.getEnclosingCallable() = callable) } + + override predicate matchesCall(DataFlowCall call) { any() } } -class CallContextReturn extends CallContext, TReturn { +class CallContextReturn extends CallContextNoCall, TReturn { override string toString() { exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")") } @@ -678,9 +740,6 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { result = viableCallable(call) and cc instanceof CallContextReturn } -pragma[noinline] -DataFlowType getErasedNodeTypeBound(Node n) { result = getErasedRepr(n.getTypeBound()) } - predicate read = readStep/3; /** An optional Boolean value. */ @@ -692,6 +751,23 @@ class BooleanOption extends TBooleanOption { } } +/** Content tagged with the type of a containing object. */ +class TypedContent extends MkTypedContent { + private Content c; + private DataFlowType t; + + TypedContent() { this = MkTypedContent(c, t) } + + /** Gets the content. */ + Content getContent() { result = c } + + /** Gets the container type. */ + DataFlowType getContainerType() { result = t } + + /** Gets a textual representation of this content. */ + string toString() { result = c.toString() } +} + /** * The front of an access path. This is either a head or a nil. */ @@ -702,25 +778,36 @@ abstract class AccessPathFront extends TAccessPathFront { abstract boolean toBoolNonEmpty(); - predicate headUsesContent(Content f) { this = TFrontHead(f) } + predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) } + + predicate isClearedAt(Node n) { + exists(TypedContent tc | + this.headUsesContent(tc) and + clearsContent(n, tc.getContent()) + ) + } } class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } + private DataFlowType t; + + AccessPathFrontNil() { this = TFrontNil(t) } + + override string toString() { result = ppReprType(t) } - override DataFlowType getType() { this = TFrontNil(result) } + override DataFlowType getType() { result = t } override boolean toBoolNonEmpty() { result = false } } class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } + private TypedContent tc; - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } + AccessPathFrontHead() { this = TFrontHead(tc) } + + override string toString() { result = tc.toString() } + + override DataFlowType getType() { result = tc.getContainerType() } override boolean toBoolNonEmpty() { result = true } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll index 0dc3b8eff450..4e1cd281488f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll @@ -37,21 +37,12 @@ module Consistency { ) } - query predicate uniqueTypeBound(Node n, string msg) { + query predicate uniqueType(Node n, string msg) { exists(int c | n instanceof RelevantNode and - c = count(n.getTypeBound()) and + c = count(getNodeType(n)) and c != 1 and - msg = "Node should have one type bound but has " + c + "." - ) - } - - query predicate uniqueTypeRepr(Node n, string msg) { - exists(int c | - n instanceof RelevantNode and - c = count(getErasedRepr(n.getTypeBound())) and - c != 1 and - msg = "Node should have one type representation but has " + c + "." + msg = "Node should have one type but has " + c + "." ) } @@ -104,7 +95,7 @@ module Consistency { msg = "Local flow step does not preserve enclosing callable." } - private DataFlowType typeRepr() { result = getErasedRepr(any(Node n).getTypeBound()) } + private DataFlowType typeRepr() { result = getNodeType(_) } query predicate compatibleTypesReflexive(DataFlowType t, string msg) { t = typeRepr() and @@ -132,8 +123,18 @@ module Consistency { n.getEnclosingCallable() != call.getEnclosingCallable() } + // This predicate helps the compiler forget that in some languages + // it is impossible for a result of `getPreUpdateNode` to be an + // instance of `PostUpdateNode`. + private Node getPre(PostUpdateNode n) { + result = n.getPreUpdateNode() + or + none() + } + query predicate postIsNotPre(PostUpdateNode n, string msg) { - n.getPreUpdateNode() = n and msg = "PostUpdateNode should not equal its pre-update node." + getPre(n) = n and + msg = "PostUpdateNode should not equal its pre-update node." } query predicate postHasUniquePre(PostUpdateNode n, string msg) { @@ -161,15 +162,14 @@ module Consistency { msg = "Origin of readStep is missing a PostUpdateNode." } - query predicate storeIsPostUpdate(Node n, string msg) { - storeStep(_, _, n) and - not n instanceof PostUpdateNode and - msg = "Store targets should be PostUpdateNodes." - } - query predicate argHasPostUpdate(ArgumentNode n, string msg) { not hasPost(n) and not isImmutableOrUnobservable(n) and msg = "ArgumentNode is missing PostUpdateNode." } + + query predicate postWithInFlow(PostUpdateNode n, string msg) { + simpleLocalFlowStep(_, n) and + msg = "PostUpdateNode should not be the target of local flow." + } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 97118da117c8..e780c5c7eb36 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -5,35 +5,58 @@ private import DataFlowDispatch /** * A data flow node that occurs as the argument of a call and is passed as-is - * to the callable. Instance arguments (`this` pointer) are also included. + * to the callable. Instance arguments (`this` pointer) and read side effects + * on parameters are also included. */ -class ArgumentNode extends InstructionNode { - ArgumentNode() { - exists(CallInstruction call | - instr = call.getAnArgument() - or - instr.(ReadSideEffectInstruction).getPrimaryInstruction() = call - ) - } - +abstract class ArgumentNode extends OperandNode { /** * Holds if this argument occurs at the given position in the given call. * The instance argument is considered to have index `-1`. */ - predicate argumentOf(DataFlowCall call, int pos) { - instr = call.getPositionalArgument(pos) + abstract predicate argumentOf(DataFlowCall call, int pos); + + /** Gets the call in which this node is an argument. */ + DataFlowCall getCall() { this.argumentOf(result, _) } +} + +/** + * A data flow node that occurs as the argument to a call, or an + * implicit `this` pointer argument. + */ +private class PrimaryArgumentNode extends ArgumentNode { + override ArgumentOperand op; + + PrimaryArgumentNode() { exists(CallInstruction call | op = call.getAnArgumentOperand()) } + + override predicate argumentOf(DataFlowCall call, int pos) { + op = call.getPositionalArgumentOperand(pos) or - instr = call.getThisArgument() and pos = -1 + op = call.getThisArgumentOperand() and pos = -1 + } + + override string toString() { + result = "Argument " + op.(PositionalArgumentOperand).getIndex() or - exists(ReadSideEffectInstruction read | - read = instr and - read.getPrimaryInstruction() = call and - pos = getArgumentPosOfSideEffect(read.getIndex()) - ) + op instanceof ThisArgumentOperand and result = "This argument" } +} - /** Gets the call in which this node is an argument. */ - DataFlowCall getCall() { this.argumentOf(result, _) } +/** + * A data flow node representing the read side effect of a call on a + * specific parameter. + */ +private class SideEffectArgumentNode extends ArgumentNode { + override SideEffectOperand op; + ReadSideEffectInstruction read; + + SideEffectArgumentNode() { op = read.getSideEffectOperand() } + + override predicate argumentOf(DataFlowCall call, int pos) { + read.getPrimaryInstruction() = call and + pos = getArgumentPosOfSideEffect(read.getIndex()) + } + + override string toString() { result = "Argument " + read.getIndex() + " indirection" } } private newtype TReturnKind = @@ -86,7 +109,12 @@ class ReturnValueNode extends ReturnNode { class ReturnIndirectionNode extends ReturnNode { override ReturnIndirectionInstruction primary; - override ReturnKind getKind() { result = TIndirectReturnKind(primary.getParameter().getIndex()) } + override ReturnKind getKind() { + result = TIndirectReturnKind(-1) and + primary.isThisIndirection() + or + result = TIndirectReturnKind(primary.getParameter().getIndex()) + } } /** A data flow node that represents the output of a call. */ @@ -123,8 +151,13 @@ private class SideEffectOutNode extends OutNode { * `kind`. */ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { - result.getCall() = call and - result.getReturnKind() = kind + // There should be only one `OutNode` for a given `(call, kind)` pair. Showing the optimizer that + // this is true helps it make better decisions downstream, especially in virtual dispatch. + result = + unique(OutNode outNode | + outNode.getCall() = call and + outNode.getReturnKind() = kind + ) } /** @@ -134,8 +167,23 @@ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { */ predicate jumpStep(Node n1, Node n2) { none() } +/** + * Gets a field corresponding to the bit range `[startBit..endBit)` of class `c`, if any. + */ +private Field getAField(Class c, int startBit, int endBit) { + result.getDeclaringType() = c and + startBit = 8 * result.getByteOffset() and + endBit = 8 * result.getType().getSize() + startBit + or + exists(Field f, Class cInner | + f = c.getAField() and + cInner = f.getUnderlyingType() and + result = getAField(cInner, startBit - 8 * f.getByteOffset(), endBit - 8 * f.getByteOffset()) + ) +} + private newtype TContent = - TFieldContent(Field f) or + TFieldContent(Class c, int startBit, int endBit) { exists(getAField(c, startBit, endBit)) } or TCollectionContent() or TArrayContent() @@ -150,63 +198,92 @@ class Content extends TContent { predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { path = "" and sl = 0 and sc = 0 and el = 0 and ec = 0 } - - /** Gets the type of the object containing this content. */ - abstract Type getContainerType(); - - /** Gets the type of this content. */ - abstract Type getType(); } private class FieldContent extends Content, TFieldContent { - Field f; - - FieldContent() { this = TFieldContent(f) } + Class c; + int startBit; + int endBit; - Field getField() { result = f } + FieldContent() { this = TFieldContent(c, startBit, endBit) } - override string toString() { result = f.toString() } + // Ensure that there's just 1 result for `toString`. + override string toString() { result = min(Field f | f = getAField() | f.toString()) } - override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { - f.getLocation().hasLocationInfo(path, sl, sc, el, ec) - } - - override Type getContainerType() { result = f.getDeclaringType() } + predicate hasOffset(Class cl, int start, int end) { cl = c and start = startBit and end = endBit } - override Type getType() { result = f.getType() } + Field getAField() { result = getAField(c, startBit, endBit) } } private class CollectionContent extends Content, TCollectionContent { override string toString() { result = "collection" } - - override Type getContainerType() { none() } - - override Type getType() { none() } } private class ArrayContent extends Content, TArrayContent { - override string toString() { result = "array" } - - override Type getContainerType() { none() } + ArrayContent() { this = TArrayContent() } - override Type getType() { none() } + override string toString() { result = "array content" } } -private predicate storeStepNoChi(Node node1, Content f, PostUpdateNode node2) { - exists(FieldAddressInstruction fa, StoreInstruction store | +private predicate fieldStoreStepNoChi(Node node1, FieldContent f, PostUpdateNode node2) { + exists(StoreInstruction store, Class c | store = node2.asInstruction() and - store.getDestinationAddress() = fa and store.getSourceValue() = node1.asInstruction() and - f.(FieldContent).getField() = fa.getField() + getWrittenField(store, f.(FieldContent).getAField(), c) and + f.hasOffset(c, _, _) + ) +} + +private FieldAddressInstruction getFieldInstruction(Instruction instr) { + result = instr or + result = instr.(CopyValueInstruction).getUnary() +} + +pragma[noinline] +private predicate getWrittenField(Instruction instr, Field f, Class c) { + exists(FieldAddressInstruction fa | + fa = + getFieldInstruction([instr.(StoreInstruction).getDestinationAddress(), + instr.(WriteSideEffectInstruction).getDestinationAddress()]) and + f = fa.getField() and + c = f.getDeclaringType() + ) +} + +private predicate fieldStoreStepChi(Node node1, FieldContent f, PostUpdateNode node2) { + exists(StoreInstruction store, ChiInstruction chi | + node1.asInstruction() = store and + node2.asInstruction() = chi and + chi.getPartial() = store and + exists(Class c | + c = chi.getResultType() and + exists(int startBit, int endBit | + chi.getUpdatedInterval(startBit, endBit) and + f.hasOffset(c, startBit, endBit) + ) + or + getWrittenField(store, f.getAField(), c) and + f.hasOffset(c, _, _) + ) ) } -private predicate storeStepChi(Node node1, Content f, PostUpdateNode node2) { - exists(FieldAddressInstruction fa, StoreInstruction store | +private predicate arrayStoreStepChi(Node node1, ArrayContent a, PostUpdateNode node2) { + a = TArrayContent() and + exists(StoreInstruction store | node1.asInstruction() = store and - store.getDestinationAddress() = fa and - node2.asInstruction().(ChiInstruction).getPartial() = store and - f.(FieldContent).getField() = fa.getField() + ( + // `x[i] = taint()` + // This matches the characteristic predicate in `ArrayStoreNode`. + store.getDestinationAddress() instanceof PointerAddInstruction + or + // `*p = taint()` + // This matches the characteristic predicate in `PointerStoreNode`. + store.getDestinationAddress().(CopyValueInstruction).getUnary() instanceof LoadInstruction + ) and + // This `ChiInstruction` will always have a non-conflated result because both `ArrayStoreNode` + // and `PointerStoreNode` require it in their characteristic predicates. + node2.asInstruction().(ChiInstruction).getPartial() = store ) } @@ -216,8 +293,37 @@ private predicate storeStepChi(Node node1, Content f, PostUpdateNode node2) { * value of `node1`. */ predicate storeStep(Node node1, Content f, PostUpdateNode node2) { - storeStepNoChi(node1, f, node2) or - storeStepChi(node1, f, node2) + fieldStoreStepNoChi(node1, f, node2) or + fieldStoreStepChi(node1, f, node2) or + arrayStoreStepChi(node1, f, node2) or + fieldStoreStepAfterArraySuppression(node1, f, node2) +} + +// This predicate pushes the correct `FieldContent` onto the access path when the +// `suppressArrayRead` predicate has popped off an `ArrayContent`. +private predicate fieldStoreStepAfterArraySuppression( + Node node1, FieldContent f, PostUpdateNode node2 +) { + exists(BufferMayWriteSideEffectInstruction write, ChiInstruction chi, Class c | + not chi.isResultConflated() and + node1.asInstruction() = chi and + node2.asInstruction() = chi and + chi.getPartial() = write and + getWrittenField(write, f.getAField(), c) and + f.hasOffset(c, _, _) + ) +} + +bindingset[result, i] +private int unbindInt(int i) { i <= result and i >= result } + +pragma[noinline] +private predicate getLoadedField(LoadInstruction load, Field f, Class c) { + exists(FieldAddressInstruction fa | + fa = load.getSourceAddress() and + f = fa.getField() and + c = f.getDeclaringType() + ) } /** @@ -225,38 +331,148 @@ predicate storeStep(Node node1, Content f, PostUpdateNode node2) { * Thus, `node1` references an object with a field `f` whose value ends up in * `node2`. */ -predicate readStep(Node node1, Content f, Node node2) { - exists(FieldAddressInstruction fa, LoadInstruction load | - load.getSourceAddress() = fa and +private predicate fieldReadStep(Node node1, FieldContent f, Node node2) { + exists(LoadInstruction load | + node2.asInstruction() = load and + node1.asInstruction() = load.getSourceValueOperand().getAnyDef() and + exists(Class c | + c = load.getSourceValueOperand().getAnyDef().getResultType() and + exists(int startBit, int endBit | + load.getSourceValueOperand().getUsedInterval(unbindInt(startBit), unbindInt(endBit)) and + f.hasOffset(c, startBit, endBit) + ) + or + getLoadedField(load, f.getAField(), c) and + f.hasOffset(c, _, _) + ) + ) +} + +/** + * When a store step happens in a function that looks like an array write such as: + * ```cpp + * void f(int* pa) { + * pa = source(); + * } + * ``` + * it can be a write to an array, but it can also happen that `f` is called as `f(&a.x)`. If that is + * the case, the `ArrayContent` that was written by the call to `f` should be popped off the access + * path, and a `FieldContent` containing `x` should be pushed instead. + * So this case pops `ArrayContent` off the access path, and the `fieldStoreStepAfterArraySuppression` + * predicate in `storeStep` ensures that we push the right `FieldContent` onto the access path. + */ +predicate suppressArrayRead(Node node1, ArrayContent a, Node node2) { + a = TArrayContent() and + exists(BufferMayWriteSideEffectInstruction write, ChiInstruction chi | + node1.asInstruction() = write and + node2.asInstruction() = chi and + chi.getPartial() = write and + getWrittenField(write, _, _) + ) +} + +private class ArrayToPointerConvertInstruction extends ConvertInstruction { + ArrayToPointerConvertInstruction() { + this.getUnary().getResultType() instanceof ArrayType and + this.getResultType() instanceof PointerType + } +} + +private Instruction skipOneCopyValueInstructionRec(CopyValueInstruction copy) { + copy.getUnary() = result and not result instanceof CopyValueInstruction + or + result = skipOneCopyValueInstructionRec(copy.getUnary()) +} + +private Instruction skipCopyValueInstructions(Instruction instr) { + not result instanceof CopyValueInstruction and result = instr + or + result = skipOneCopyValueInstructionRec(instr) +} + +private predicate arrayReadStep(Node node1, ArrayContent a, Node node2) { + a = TArrayContent() and + // Explicit dereferences such as `*p` or `p[i]` where `p` is a pointer or array. + exists(LoadInstruction load, Instruction address | + load.getSourceValueOperand().isDefinitionInexact() and node1.asInstruction() = load.getSourceValueOperand().getAnyDef() and - fa.getField() = f.(FieldContent).getField() and - load = node2.asInstruction() + load = node2.asInstruction() and + address = skipCopyValueInstructions(load.getSourceAddress()) and + ( + address instanceof LoadInstruction or + address instanceof ArrayToPointerConvertInstruction or + address instanceof PointerOffsetInstruction + ) + ) +} + +/** + * In cases such as: + * ```cpp + * void f(int* pa) { + * *pa = source(); + * } + * ... + * int x; + * f(&x); + * use(x); + * ``` + * the load on `x` in `use(x)` will exactly overlap with its definition (in this case the definition + * is a `BufferMayWriteSideEffect`). This predicate pops the `ArrayContent` (pushed by the store in `f`) + * from the access path. + */ +private predicate exactReadStep(Node node1, ArrayContent a, Node node2) { + a = TArrayContent() and + exists(BufferMayWriteSideEffectInstruction write, ChiInstruction chi | + not chi.isResultConflated() and + chi.getPartial() = write and + node1.asInstruction() = write and + node2.asInstruction() = chi and + // To distinquish this case from the `arrayReadStep` case we require that the entire variable was + // overwritten by the `BufferMayWriteSideEffectInstruction` (i.e., there is a load that reads the + // entire variable). + exists(LoadInstruction load | load.getSourceValue() = chi) ) } /** - * Gets a representative (boxed) type for `t` for the purpose of pruning - * possible flow. A single type is used for all numeric types to account for - * numeric conversions, and otherwise the erasure is used. + * Holds if data can flow from `node1` to `node2` via a read of `f`. + * Thus, `node1` references an object with a field `f` whose value ends up in + * `node2`. + */ +predicate readStep(Node node1, Content f, Node node2) { + fieldReadStep(node1, f, node2) or + arrayReadStep(node1, f, node2) or + exactReadStep(node1, f, node2) or + suppressArrayRead(node1, f, node2) +} + +/** + * Holds if values stored inside content `c` are cleared at node `n`. */ -Type getErasedRepr(Type t) { - suppressUnusedType(t) and - result instanceof VoidType // stub implementation +predicate clearsContent(Node n, Content c) { + none() // stub implementation } -/** Gets a string representation of a type returned by `getErasedRepr`. */ -string ppReprType(Type t) { none() } // stub implementation +/** Gets the type of `n` used for type pruning. */ +IRType getNodeType(Node n) { + suppressUnusedNode(n) and + result instanceof IRVoidType // stub implementation +} + +/** Gets a string representation of a type returned by `getNodeType`. */ +string ppReprType(IRType t) { none() } // stub implementation /** * Holds if `t1` and `t2` are compatible, that is, whether data can flow from * a node of type `t1` to a node of type `t2`. */ pragma[inline] -predicate compatibleTypes(Type t1, Type t2) { +predicate compatibleTypes(IRType t1, IRType t2) { any() // stub implementation } -private predicate suppressUnusedType(Type t) { any() } +private predicate suppressUnusedNode(Node n) { any() } ////////////////////////////////////////////////////////////////////////////// // Java QL library compatibility wrappers @@ -276,7 +492,7 @@ class DataFlowCallable = Declaration; class DataFlowExpr = Expr; -class DataFlowType = Type; +class DataFlowType = IRType; /** A function call relevant for data flow. */ class DataFlowCall extends CallInstruction { @@ -306,3 +522,6 @@ predicate isImmutableOrUnobservable(Node n) { // complex to model here. any() } + +/** Holds if `n` should be hidden from path explanations. */ +predicate nodeIsHidden(Node n) { n instanceof OperandNode } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index beb3c8d954d1..1270b8d67da5 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -11,8 +11,10 @@ private import semmle.code.cpp.ir.IR private import semmle.code.cpp.controlflow.IRGuards private import semmle.code.cpp.models.interfaces.DataFlow +cached private newtype TIRDataFlowNode = TInstructionNode(Instruction i) or + TOperandNode(Operand op) or TVariableNode(Variable var) /** @@ -32,15 +34,23 @@ class Node extends TIRDataFlowNode { Function getFunction() { none() } // overridden in subclasses /** Gets the type of this node. */ - Type getType() { none() } // overridden in subclasses + IRType getType() { none() } // overridden in subclasses /** Gets the instruction corresponding to this node, if any. */ Instruction asInstruction() { result = this.(InstructionNode).getInstruction() } + /** Gets the operands corresponding to this node, if any. */ + Operand asOperand() { result = this.(OperandNode).getOperand() } + /** - * Gets the non-conversion expression corresponding to this node, if any. If - * this node strictly (in the sense of `asConvertedExpr`) corresponds to a - * `Conversion`, then the result is that `Conversion`'s non-`Conversion` base + * Gets the non-conversion expression corresponding to this node, if any. + * This predicate only has a result on nodes that represent the value of + * evaluating the expression. For data flowing _out of_ an expression, like + * when an argument is passed by reference, use `asDefiningArgument` instead + * of `asExpr`. + * + * If this node strictly (in the sense of `asConvertedExpr`) corresponds to + * a `Conversion`, then the result is the underlying non-`Conversion` base * expression. */ Expr asExpr() { result = this.(ExprNode).getExpr() } @@ -51,7 +61,13 @@ class Node extends TIRDataFlowNode { */ Expr asConvertedExpr() { result = this.(ExprNode).getConvertedExpr() } - /** Gets the argument that defines this `DefinitionByReferenceNode`, if any. */ + /** + * Gets the argument that defines this `DefinitionByReferenceNode`, if any. + * This predicate should be used instead of `asExpr` when referring to the + * value of a reference argument _after_ the call has returned. For example, + * in `f(&x)`, this predicate will have `&x` as its result for the `Node` + * that represents the new value of `x`. + */ Expr asDefiningArgument() { result = this.(DefinitionByReferenceNode).getArgument() } /** Gets the positional parameter corresponding to this node, if any. */ @@ -59,7 +75,7 @@ class Node extends TIRDataFlowNode { /** * Gets the variable corresponding to this node, if any. This can be used for - * modelling flow in and out of global variables. + * modeling flow in and out of global variables. */ Variable asVariable() { result = this.(VariableNode).getVariable() } @@ -84,7 +100,7 @@ class Node extends TIRDataFlowNode { /** * Gets an upper bound on the type of this node. */ - Type getTypeBound() { result = getType() } + IRType getTypeBound() { result = getType() } /** Gets the location of this element. */ Location getLocation() { none() } // overridden by subclasses @@ -121,7 +137,7 @@ class InstructionNode extends Node, TInstructionNode { override Function getFunction() { result = instr.getEnclosingFunction() } - override Type getType() { result = instr.getResultType() } + override IRType getType() { result = instr.getResultIRType() } override Location getLocation() { result = instr.getLocation() } @@ -132,6 +148,28 @@ class InstructionNode extends Node, TInstructionNode { } } +/** + * An operand, viewed as a node in a data flow graph. + */ +class OperandNode extends Node, TOperandNode { + Operand op; + + OperandNode() { this = TOperandNode(op) } + + /** Gets the operand corresponding to this node. */ + Operand getOperand() { result = op } + + override Declaration getEnclosingCallable() { result = this.getFunction() } + + override Function getFunction() { result = op.getUse().getEnclosingFunction() } + + override IRType getType() { result = op.getIRType() } + + override Location getLocation() { result = op.getLocation() } + + override string toString() { result = this.getOperand().toString() } +} + /** * An expression, viewed as a node in a data flow graph. */ @@ -291,29 +329,36 @@ abstract class PostUpdateNode extends InstructionNode { * setY(&x); // a partial definition of the object `x`. * ``` */ -abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { +abstract private class PartialDefinitionNode extends PostUpdateNode { abstract Expr getDefinedExpr(); } private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { override ChiInstruction instr; - FieldAddressInstruction field; + StoreInstruction store; ExplicitFieldStoreQualifierNode() { not instr.isResultConflated() and - exists(StoreInstruction store | - instr.getPartial() = store and field = store.getDestinationAddress() + instr.getPartial() = store and + ( + instr.getUpdatedInterval(_, _) or + store.getDestinationAddress() instanceof FieldAddressInstruction ) } - // There might be multiple `ChiInstructions` that has a particular instruction as - // the total operand - so this definition gives consistency errors in - // DataFlowImplConsistency::Consistency. However, it's not clear what (if any) implications - // this consistency failure has. - override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() } + // By using an operand as the result of this predicate we avoid the dataflow inconsistency errors + // caused by having multiple nodes sharing the same pre update node. This inconsistency error can cause + // a tuple explosion in the big step dataflow relation since it can make many nodes be the entry node + // into a big step. + override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() } override Expr getDefinedExpr() { - result = field.getObjectAddress().getUnconvertedResultExpression() + result = + store + .getDestinationAddress() + .(FieldAddressInstruction) + .getObjectAddress() + .getUnconvertedResultExpression() } } @@ -325,20 +370,93 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { */ private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNode { override StoreInstruction instr; - FieldAddressInstruction field; ExplicitSingleFieldStoreQualifierNode() { - field = instr.getDestinationAddress() and - not exists(ChiInstruction chi | chi.getPartial() = instr) + not exists(ChiInstruction chi | chi.getPartial() = instr) and + // Without this condition any store would create a `PostUpdateNode`. + instr.getDestinationAddress() instanceof FieldAddressInstruction } override Node getPreUpdateNode() { none() } + override Expr getDefinedExpr() { + result = + instr + .getDestinationAddress() + .(FieldAddressInstruction) + .getObjectAddress() + .getUnconvertedResultExpression() + } +} + +private FieldAddressInstruction getFieldInstruction(Instruction instr) { + result = instr or + result = instr.(CopyValueInstruction).getUnary() +} + +/** + * The target of a `fieldStoreStepAfterArraySuppression` store step, which is used to convert + * an `ArrayContent` to a `FieldContent` when the `BufferMayWriteSideEffect` instruction stores + * into a field. See the QLDoc for `suppressArrayRead` for an example of where such a conversion + * is inserted. + */ +private class BufferMayWriteSideEffectFieldStoreQualifierNode extends PartialDefinitionNode { + override ChiInstruction instr; + BufferMayWriteSideEffectInstruction write; + FieldAddressInstruction field; + + BufferMayWriteSideEffectFieldStoreQualifierNode() { + not instr.isResultConflated() and + instr.getPartial() = write and + field = getFieldInstruction(write.getDestinationAddress()) + } + + override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() } + override Expr getDefinedExpr() { result = field.getObjectAddress().getUnconvertedResultExpression() } } +/** + * The `PostUpdateNode` that is the target of a `arrayStoreStepChi` store step. The overriden + * `ChiInstruction` corresponds to the instruction represented by `node2` in `arrayStoreStepChi`. + */ +private class ArrayStoreNode extends PartialDefinitionNode { + override ChiInstruction instr; + PointerAddInstruction add; + + ArrayStoreNode() { + not instr.isResultConflated() and + exists(StoreInstruction store | + instr.getPartial() = store and + add = store.getDestinationAddress() + ) + } + + override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() } + + override Expr getDefinedExpr() { result = add.getLeft().getUnconvertedResultExpression() } +} + +/** + * The `PostUpdateNode` that is the target of a `arrayStoreStepChi` store step. The overriden + * `ChiInstruction` corresponds to the instruction represented by `node2` in `arrayStoreStepChi`. + */ +private class PointerStoreNode extends PostUpdateNode { + override ChiInstruction instr; + + PointerStoreNode() { + not instr.isResultConflated() and + exists(StoreInstruction store | + instr.getPartial() = store and + store.getDestinationAddress().(CopyValueInstruction).getUnary() instanceof LoadInstruction + ) + } + + override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() } +} + /** * A node that represents the value of a variable after a function call that * may have changed the variable because it's passed by reference. @@ -352,7 +470,7 @@ private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNod class DefinitionByReferenceNode extends InstructionNode { override WriteSideEffectInstruction instr; - /** Gets the argument corresponding to this node. */ + /** Gets the unconverted argument corresponding to this node. */ Expr getArgument() { result = instr @@ -387,22 +505,10 @@ class DefinitionByReferenceNode extends InstructionNode { } } -/** - * A node representing the memory pointed to by a function argument. - * - * This class exists only in order to override `toString`, which would - * otherwise be the default implementation inherited from `InstructionNode`. - */ -private class ArgumentIndirectionNode extends InstructionNode { - override ReadSideEffectInstruction instr; - - override string toString() { result = "Argument " + instr.getIndex() + " indirection" } -} - /** * A `Node` corresponding to a variable in the program, as opposed to the * value of that variable at some particular point. This can be used for - * modelling flow in and out of global variables. + * modeling flow in and out of global variables. */ class VariableNode extends Node, TVariableNode { Variable v; @@ -423,7 +529,7 @@ class VariableNode extends Node, TVariableNode { result = v } - override Type getType() { result = v.getType() } + override IRType getType() { result.getCanonicalLanguageType().hasUnspecifiedType(v.getType(), _) } override Location getLocation() { result = v.getLocation() } @@ -436,20 +542,26 @@ class VariableNode extends Node, TVariableNode { InstructionNode instructionNode(Instruction instr) { result.getInstruction() = instr } /** + * DEPRECATED: use `definitionByReferenceNodeFromArgument` instead. + * * Gets the `Node` corresponding to a definition by reference of the variable * that is passed as `argument` of a call. */ -DefinitionByReferenceNode definitionByReferenceNode(Expr e) { result.getArgument() = e } +deprecated DefinitionByReferenceNode definitionByReferenceNode(Expr e) { result.getArgument() = e } /** - * Gets a `Node` corresponding to `e` or any of its conversions. There is no - * result if `e` is a `Conversion`. + * Gets the `Node` corresponding to the value of evaluating `e` or any of its + * conversions. There is no result if `e` is a `Conversion`. For data flowing + * _out of_ an expression, like when an argument is passed by reference, use + * `definitionByReferenceNodeFromArgument` instead. */ ExprNode exprNode(Expr e) { result.getExpr() = e } /** - * Gets the `Node` corresponding to `e`, if any. Here, `e` may be a - * `Conversion`. + * Gets the `Node` corresponding to the value of evaluating `e`. Here, `e` may + * be a `Conversion`. For data flowing _out of_ an expression, like when an + * argument is passed by reference, use + * `definitionByReferenceNodeFromArgument` instead. */ ExprNode convertedExprNode(Expr e) { result.getConvertedExpr() = e } @@ -458,6 +570,14 @@ ExprNode convertedExprNode(Expr e) { result.getConvertedExpr() = e } */ ExplicitParameterNode parameterNode(Parameter p) { result.getParameter() = p } +/** + * Gets the `Node` corresponding to a definition by reference of the variable + * that is passed as unconverted `argument` of a call. + */ +DefinitionByReferenceNode definitionByReferenceNodeFromArgument(Expr argument) { + result.getArgument() = argument +} + /** Gets the `VariableNode` corresponding to the variable `v`. */ VariableNode variableNode(Variable v) { result.getVariable() = v } @@ -481,29 +601,39 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFr * This is the local flow predicate that's used as a building block in global * data flow. It may have less flow than the `localFlowStep` predicate. */ +cached predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { - simpleInstructionLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asInstruction()) + // Operand -> Instruction flow + simpleInstructionLocalFlowStep(nodeFrom.asOperand(), nodeTo.asInstruction()) + or + // Instruction -> Operand flow + simpleOperandLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asOperand()) } pragma[noinline] private predicate getFieldSizeOfClass(Class c, Type type, int size) { exists(Field f | f.getDeclaringType() = c and - f.getType() = type and + f.getUnderlyingType() = type and type.getSize() = size ) } -cached -private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction iTo) { - iTo.(CopyInstruction).getSourceValue() = iFrom - or - iTo.(PhiInstruction).getAnOperand().getDef() = iFrom +private predicate isSingleFieldClass(Type type, Operand op) { + exists(int size, Class c | + c = op.getType().getUnderlyingType() and + c.getSize() = size and + getFieldSizeOfClass(c, type, size) + ) +} + +private predicate simpleOperandLocalFlowStep(Instruction iFrom, Operand opTo) { + // Propagate flow from an instruction to its exact uses. + opTo.getDef() = iFrom or - // A read side effect is almost never exact since we don't know exactly how - // much memory the callee will read. - iTo.(ReadSideEffectInstruction).getSideEffectOperand().getAnyDef() = iFrom and - not iFrom.isResultConflated() + opTo = any(ReadSideEffectInstruction read).getSideEffectOperand() and + not iFrom.isResultConflated() and + iFrom = opTo.getAnyDef() or // Loading a single `int` from an `int *` parameter is not an exact load since // the parameter may point to an entire array rather than a single `int`. The @@ -517,20 +647,33 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction // leads to a phi node. exists(InitializeIndirectionInstruction init | iFrom = init and - iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = init and + opTo.(LoadOperand).getAnyDef() = init and // Check that the types match. Otherwise we can get flow from an object to // its fields, which leads to field conflation when there's flow from other // fields to the object elsewhere. init.getParameter().getType().getUnspecifiedType().(DerivedType).getBaseType() = - iTo.getResultType().getUnspecifiedType() + opTo.getType().getUnspecifiedType() ) or + // Flow from stores to structs with a single field to a load of that field. + exists(LoadInstruction load | + load.getSourceValueOperand() = opTo and + opTo.getAnyDef() = iFrom and + isSingleFieldClass(iFrom.getResultType(), opTo) + ) +} + +private predicate simpleInstructionLocalFlowStep(Operand opFrom, Instruction iTo) { + iTo.(CopyInstruction).getSourceValueOperand() = opFrom + or + iTo.(PhiInstruction).getAnInputOperand() = opFrom + or // Treat all conversions as flow, even conversions between different numeric types. - iTo.(ConvertInstruction).getUnary() = iFrom + iTo.(ConvertInstruction).getUnaryOperand() = opFrom or - iTo.(CheckedConvertOrNullInstruction).getUnary() = iFrom + iTo.(CheckedConvertOrNullInstruction).getUnaryOperand() = opFrom or - iTo.(InheritanceConversionInstruction).getUnary() = iFrom + iTo.(InheritanceConversionInstruction).getUnaryOperand() = opFrom or // A chi instruction represents a point where a new value (the _partial_ // operand) may overwrite an old value (the _total_ operand), but the alias @@ -543,7 +686,7 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction // // Flow through the partial operand belongs in the taint-tracking libraries // for now. - iTo.getAnOperand().(ChiTotalOperand).getDef() = iFrom + iTo.getAnOperand().(ChiTotalOperand) = opFrom or // Add flow from write side-effects to non-conflated chi instructions through their // partial operands. From there, a `readStep` will find subsequent reads of that field. @@ -558,23 +701,16 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction // Here, a `WriteSideEffectInstruction` will provide a new definition for `p->x` after the call to // `setX`, which will be melded into `p` through a chi instruction. exists(ChiInstruction chi | chi = iTo | - chi.getPartialOperand().getDef() = iFrom.(WriteSideEffectInstruction) and + opFrom.getAnyDef() instanceof WriteSideEffectInstruction and + chi.getPartialOperand() = opFrom and not chi.isResultConflated() ) or - // Flow from stores to structs with a single field to a load of that field. - iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = iFrom and - exists(int size, Type type | - type = iFrom.getResultType() and - iTo.getResultType().getSize() = size and - getFieldSizeOfClass(iTo.getResultType(), type, size) - ) - or // Flow through modeled functions - modelFlow(iFrom, iTo) + modelFlow(opFrom, iTo) } -private predicate modelFlow(Instruction iFrom, Instruction iTo) { +private predicate modelFlow(Operand opFrom, Instruction iTo) { exists( CallInstruction call, DataFlowFunction func, FunctionInput modelIn, FunctionOutput modelOut | @@ -594,23 +730,33 @@ private predicate modelFlow(Instruction iFrom, Instruction iTo) { iTo = outNode and outNode = getSideEffectFor(call, index) ) - // TODO: add write side effects for qualifiers + or + exists(WriteSideEffectInstruction outNode | + modelOut.isQualifierObject() and + iTo = outNode and + outNode = getSideEffectFor(call, -1) + ) ) and ( exists(int index | modelIn.isParameter(index) and - iFrom = call.getPositionalArgument(index) + opFrom = call.getPositionalArgumentOperand(index) ) or exists(int index, ReadSideEffectInstruction read | modelIn.isParameterDeref(index) and read = getSideEffectFor(call, index) and - iFrom = read.getSideEffectOperand().getAnyDef() + opFrom = read.getSideEffectOperand() ) or modelIn.isQualifierAddress() and - iFrom = call.getThisArgument() - // TODO: add read side effects for qualifiers + opFrom = call.getThisArgumentOperand() + or + exists(ReadSideEffectInstruction read | + modelIn.isQualifierObject() and + read = getSideEffectFor(call, -1) and + opFrom = read.getSideEffectOperand() + ) ) ) } @@ -658,13 +804,20 @@ predicate localExprFlow(Expr e1, Expr e2) { localFlow(exprNode(e1), exprNode(e2) */ class BarrierGuard extends IRGuardCondition { /** Override this predicate to hold if this guard validates `instr` upon evaluating to `b`. */ - abstract predicate checks(Instruction instr, boolean b); + predicate checksInstr(Instruction instr, boolean b) { none() } + + /** Override this predicate to hold if this guard validates `expr` upon evaluating to `b`. */ + predicate checks(Expr e, boolean b) { none() } /** Gets a node guarded by this guard. */ final Node getAGuardedNode() { exists(ValueNumber value, boolean edge | + ( + this.checksInstr(value.getAnInstruction(), edge) + or + this.checks(value.getAnInstruction().getConvertedResultExpression(), edge) + ) and result.asInstruction() = value.getAnInstruction() and - this.checks(value.getAnInstruction(), edge) and this.controls(result.asInstruction().getBlock(), edge) ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/ModelUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/ModelUtil.qll index d1cafb28f1c1..93d74519ca5c 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/ModelUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/ModelUtil.qll @@ -9,24 +9,31 @@ private import semmle.code.cpp.ir.dataflow.DataFlow /** * Gets the instruction that goes into `input` for `call`. */ -Instruction callInput(CallInstruction call, FunctionInput input) { +DataFlow::Node callInput(CallInstruction call, FunctionInput input) { // A positional argument exists(int index | - result = call.getPositionalArgument(index) and + result.asInstruction() = call.getPositionalArgument(index) and input.isParameter(index) ) or // A value pointed to by a positional argument exists(ReadSideEffectInstruction read | - result = read and + result.asOperand() = read.getSideEffectOperand() and read.getPrimaryInstruction() = call and input.isParameterDeref(read.getIndex()) ) or // The qualifier pointer - result = call.getThisArgument() and + result.asInstruction() = call.getThisArgument() and input.isQualifierAddress() - //TODO: qualifier deref + or + // The qualifier object + exists(ReadSideEffectInstruction read | + result.asOperand() = read.getSideEffectOperand() and + read.getPrimaryInstruction() = call and + read.getIndex() = -1 and + input.isQualifierObject() + ) } /** @@ -43,5 +50,13 @@ Instruction callOutput(CallInstruction call, FunctionOutput output) { effect.getPrimaryInstruction() = call and output.isParameterDeref(effect.getIndex()) ) - // TODO: qualifiers, return value dereference + or + // The side effect of a call on the qualifier object + exists(WriteSideEffectInstruction effect | + result = effect and + effect.getPrimaryInstruction() = call and + effect.getIndex() = -1 and + output.isQualifierObject() + ) + // TODO: return value dereference } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/PrintIRLocalFlow.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/PrintIRLocalFlow.qll new file mode 100644 index 000000000000..edbb11db2f37 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/PrintIRLocalFlow.qll @@ -0,0 +1,152 @@ +private import cpp +// The `ValueNumbering` library has to be imported right after `cpp` to ensure +// that the cached IR gets the same checksum here as it does in queries that use +// `ValueNumbering` without `DataFlow`. +private import semmle.code.cpp.ir.ValueNumbering +private import semmle.code.cpp.ir.IR +private import semmle.code.cpp.ir.dataflow.DataFlow +private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil + +/** + * Gets a short ID for an IR dataflow node. + * - For `Instruction`s, this is just the result ID of the instruction (e.g. `m128`). + * - For `Operand`s, this is the label of the operand, prefixed with the result ID of the + * instruction and a dot (e.g. `m128.left`). + * - For `Variable`s, this is the qualified name of the variable. + */ +private string nodeId(DataFlow::Node node, int order1, int order2) { + exists(Instruction instruction | instruction = node.asInstruction() | + result = instruction.getResultId() and + order1 = instruction.getBlock().getDisplayIndex() and + order2 = instruction.getDisplayIndexInBlock() + ) + or + exists(Operand operand, Instruction instruction | + operand = node.asOperand() and + instruction = operand.getUse() + | + result = instruction.getResultId() + "." + operand.getDumpId() and + order1 = instruction.getBlock().getDisplayIndex() and + order2 = instruction.getDisplayIndexInBlock() + ) + or + result = "var(" + node.asVariable().getQualifiedName() + ")" and + order1 = 1000000 and + order2 = 0 +} + +/** + * Gets the local dataflow from other nodes in the same function to this node. + */ +private string getFromFlow(DataFlow::Node useNode, int order1, int order2) { + exists(DataFlow::Node defNode, string prefix | + ( + simpleLocalFlowStep(defNode, useNode) and prefix = "" + or + any(DataFlow::Configuration cfg).isAdditionalFlowStep(defNode, useNode) and + defNode.getEnclosingCallable() = useNode.getEnclosingCallable() and + prefix = "+" + ) and + if defNode.asInstruction() = useNode.asOperand().getAnyDef() + then + // Shorthand for flow from the def of this operand. + result = prefix + "def" and + order1 = -1 and + order2 = 0 + else + if defNode.asOperand().getUse() = useNode.asInstruction() + then + // Shorthand for flow from an operand of this instruction + result = prefix + defNode.asOperand().getDumpId() and + order1 = -1 and + order2 = defNode.asOperand().getDumpSortOrder() + else result = prefix + nodeId(defNode, order1, order2) + ) +} + +/** + * Gets the local dataflow from this node to other nodes in the same function. + */ +private string getToFlow(DataFlow::Node defNode, int order1, int order2) { + exists(DataFlow::Node useNode, string prefix | + ( + simpleLocalFlowStep(defNode, useNode) and prefix = "" + or + any(DataFlow::Configuration cfg).isAdditionalFlowStep(defNode, useNode) and + defNode.getEnclosingCallable() = useNode.getEnclosingCallable() and + prefix = "+" + ) and + if useNode.asInstruction() = defNode.asOperand().getUse() + then + // Shorthand for flow to this operand's instruction. + result = prefix + "result" and + order1 = -1 and + order2 = 0 + else result = prefix + nodeId(useNode, order1, order2) + ) +} + +/** + * Gets the properties of the dataflow node `node`. + */ +private string getNodeProperty(DataFlow::Node node, string key) { + // List dataflow into and out of this node. Flow into this node is printed as `src->@`, and flow + // out of this node is printed as `@->dest`. + key = "flow" and + result = + strictconcat(string flow, boolean to, int order1, int order2 | + flow = getFromFlow(node, order1, order2) + "->@" and to = false + or + flow = "@->" + getToFlow(node, order1, order2) and to = true + | + flow, ", " order by to, order1, order2, flow + ) + or + // Is this node a dataflow sink? + key = "sink" and + any(DataFlow::Configuration cfg).isSink(node) and + result = "true" + or + // Is this node a dataflow source? + key = "source" and + any(DataFlow::Configuration cfg).isSource(node) and + result = "true" + or + // Is this node a dataflow barrier, and if so, what kind? + key = "barrier" and + result = + strictconcat(string kind | + any(DataFlow::Configuration cfg).isBarrier(node) and kind = "full" + or + any(DataFlow::Configuration cfg).isBarrierIn(node) and kind = "in" + or + any(DataFlow::Configuration cfg).isBarrierOut(node) and kind = "out" + or + exists(DataFlow::BarrierGuard guard | + any(DataFlow::Configuration cfg).isBarrierGuard(guard) and + node = guard.getAGuardedNode() and + kind = "guard(" + guard.getResultId() + ")" + ) + | + kind, ", " + ) +} + +/** + * Property provider for local IR dataflow. + */ +class LocalFlowPropertyProvider extends IRPropertyProvider { + override string getOperandProperty(Operand operand, string key) { + exists(DataFlow::Node node | + operand = node.asOperand() and + result = getNodeProperty(node, key) + ) + } + + override string getInstructionProperty(Instruction instruction, string key) { + exists(DataFlow::Node node | + instruction = node.asInstruction() and + result = getNodeProperty(node, key) + ) + } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll index 2290bab05713..202d3f1c14ef 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll @@ -19,8 +19,11 @@ predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { * local data flow steps. That is, `nodeFrom` and `nodeTo` are likely to represent * different objects. */ +cached predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { localInstructionTaintStep(nodeFrom.asInstruction(), nodeTo.asInstruction()) + or + modeledTaintStep(nodeFrom, nodeTo) } /** @@ -49,8 +52,6 @@ private predicate localInstructionTaintStep(Instruction nodeFrom, Instruction no or nodeTo.(LoadInstruction).getSourceAddress() = nodeFrom or - modeledInstructionTaintStep(nodeFrom, nodeTo) - or // Flow through partial reads of arrays and unions nodeTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = nodeFrom and not nodeFrom.isResultConflated() and @@ -100,19 +101,26 @@ predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) { } /** - * Holds if `node` should be a barrier in all global taint flow configurations + * Holds if `node` should be a sanitizer in all global taint flow configurations * but not in local taint. */ -predicate defaultTaintBarrier(DataFlow::Node node) { none() } +predicate defaultTaintSanitizer(DataFlow::Node node) { none() } /** * Holds if taint can flow from `instrIn` to `instrOut` through a call to a * modeled function. */ -predicate modeledInstructionTaintStep(Instruction instrIn, Instruction instrOut) { +predicate modeledTaintStep(DataFlow::Node nodeIn, DataFlow::Node nodeOut) { exists(CallInstruction call, TaintFunction func, FunctionInput modelIn, FunctionOutput modelOut | - instrIn = callInput(call, modelIn) and - instrOut = callOutput(call, modelOut) and + ( + nodeIn = callInput(call, modelIn) + or + exists(int n | + modelIn.isParameterDeref(n) and + nodeIn = callInput(call, any(InParameter inParam | inParam.getIndex() = n)) + ) + ) and + nodeOut.asInstruction() = callOutput(call, modelOut) and call.getStaticCallTarget() = func and func.hasTaintFlow(modelIn, modelOut) ) @@ -126,8 +134,8 @@ predicate modeledInstructionTaintStep(Instruction instrIn, Instruction instrOut) CallInstruction call, Function func, FunctionInput modelIn, OutParameterDeref modelMidOut, int indexMid, InParameter modelMidIn, OutReturnValue modelOut | - instrIn = callInput(call, modelIn) and - instrOut = callOutput(call, modelOut) and + nodeIn = callInput(call, modelIn) and + nodeOut.asInstruction() = callOutput(call, modelOut) and call.getStaticCallTarget() = func and func.(TaintFunction).hasTaintFlow(modelIn, modelMidOut) and func.(DataFlowFunction).hasDataFlow(modelMidIn, modelOut) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll index 0f0607662e90..b509fad9cd20 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * To create a configuration, extend this class with a subclass whose * characteristic predicate is a unique singleton string. For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends TaintTracking::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -76,20 +76,20 @@ abstract class Configuration extends DataFlow::Configuration { final override predicate isBarrier(DataFlow::Node node) { isSanitizer(node) or - defaultTaintBarrier(node) + defaultTaintSanitizer(node) } - /** Holds if data flow into `node` is prohibited. */ + /** Holds if taint propagation into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) } - /** Holds if data flow out of `node` is prohibited. */ + /** Holds if taint propagation out of `node` is prohibited. */ predicate isSanitizerOut(DataFlow::Node node) { none() } final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) } - /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + /** Holds if taint propagation through nodes guarded by `guard` is prohibited. */ predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() } final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll index 0f0607662e90..b509fad9cd20 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * To create a configuration, extend this class with a subclass whose * characteristic predicate is a unique singleton string. For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends TaintTracking::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -76,20 +76,20 @@ abstract class Configuration extends DataFlow::Configuration { final override predicate isBarrier(DataFlow::Node node) { isSanitizer(node) or - defaultTaintBarrier(node) + defaultTaintSanitizer(node) } - /** Holds if data flow into `node` is prohibited. */ + /** Holds if taint propagation into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) } - /** Holds if data flow out of `node` is prohibited. */ + /** Holds if taint propagation out of `node` is prohibited. */ predicate isSanitizerOut(DataFlow::Node node) { none() } final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) } - /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + /** Holds if taint propagation through nodes guarded by `guard` is prohibited. */ predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() } final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll index 54059fb5b82f..32e36bb67876 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that specify the conditions under which control flows along a given edge. + */ + private import internal.EdgeKindInternal private newtype TEdgeKind = @@ -77,9 +81,15 @@ class CaseEdge extends EdgeKind, TCaseEdge { else result = "Case[" + minValue + ".." + maxValue + "]" } - string getMinValue() { result = minValue } + /** + * Gets the smallest value of the switch expression for which control will flow along this edge. + */ + final string getMinValue() { result = minValue } - string getMaxValue() { result = maxValue } + /** + * Gets the largest value of the switch expression for which control will flow along this edge. + */ + final string getMaxValue() { result = maxValue } } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRConfiguration.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRConfiguration.qll index 71bc8ec2b0f2..37ac2fccdd94 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRConfiguration.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRConfiguration.qll @@ -10,6 +10,7 @@ private newtype TIRConfiguration = MkIRConfiguration() * The query can extend this class to control which functions have IR generated for them. */ class IRConfiguration extends TIRConfiguration { + /** Gets a textual representation of this element. */ string toString() { result = "IRConfiguration" } /** @@ -17,6 +18,13 @@ class IRConfiguration extends TIRConfiguration { */ predicate shouldCreateIRForFunction(Language::Function func) { any() } + /** + * Holds if the strings used as part of an IR dump should be generated for function `func`. + * + * This predicate is overridden in `PrintIR.qll` to avoid the expense of generating a large number + * of debug strings for IR that will not be dumped. We still generate the actual IR for these + * functions, however, to preserve the results of any interprocedural analysis. + */ predicate shouldEvaluateDebugStringsForFunction(Language::Function func) { any() } } @@ -26,6 +34,7 @@ private newtype TIREscapeAnalysisConfiguration = MkIREscapeAnalysisConfiguration * The query can extend this class to control what escape analysis is used when generating SSA. */ class IREscapeAnalysisConfiguration extends TIREscapeAnalysisConfiguration { + /** Gets a textual representation of this element. */ string toString() { result = "IREscapeAnalysisConfiguration" } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll index d196cdce0ab2..3bf3bf2e2766 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll @@ -32,6 +32,7 @@ private newtype TIRType = * all pointer types map to the same instance of `IRAddressType`. */ class IRType extends TIRType { + /** Gets a textual representation of this type. */ string toString() { none() } /** @@ -111,6 +112,8 @@ private class IRSizedType extends IRType { this = TIRFunctionAddressType(byteSize) or this = TIROpaqueType(_, byteSize) } + // Don't override `getByteSize()` here. The optimizer seems to generate better code when this is + // overridden only in the leaf classes. } /** @@ -128,7 +131,7 @@ class IRBooleanType extends IRSizedType, TIRBooleanType { } /** - * A numberic type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and + * A numeric type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and * `IRFloatingPointType`. */ class IRNumericType extends IRSizedType { @@ -137,13 +140,33 @@ class IRNumericType extends IRSizedType { this = TIRUnsignedIntegerType(byteSize) or this = TIRFloatingPointType(byteSize, _, _) } + // Don't override `getByteSize()` here. The optimizer seems to generate better code when this is + // overridden only in the leaf classes. +} + +/** + * An integer type. This includes `IRSignedIntegerType` and `IRUnsignedIntegerType`. + */ +class IRIntegerType extends IRNumericType { + IRIntegerType() { + this = TIRSignedIntegerType(byteSize) or + this = TIRUnsignedIntegerType(byteSize) + } + + /** Holds if this integer type is signed. */ + predicate isSigned() { none() } + + /** Holds if this integer type is unsigned. */ + predicate isUnsigned() { none() } + // Don't override `getByteSize()` here. The optimizer seems to generate better code when this is + // overridden only in the leaf classes. } /** * A signed two's-complement integer. Also used to represent enums whose underlying type is a signed * integer, as well as character types whose representation is signed. */ -class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType { +class IRSignedIntegerType extends IRIntegerType, TIRSignedIntegerType { final override string toString() { result = "int" + byteSize.toString() } final override Language::LanguageType getCanonicalLanguageType() { @@ -152,13 +175,15 @@ class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType { pragma[noinline] final override int getByteSize() { result = byteSize } + + override predicate isSigned() { any() } } /** * An unsigned two's-complement integer. Also used to represent enums whose underlying type is an * unsigned integer, as well as character types whose representation is unsigned. */ -class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType { +class IRUnsignedIntegerType extends IRIntegerType, TIRUnsignedIntegerType { final override string toString() { result = "uint" + byteSize.toString() } final override Language::LanguageType getCanonicalLanguageType() { @@ -167,6 +192,8 @@ class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType { pragma[noinline] final override int getByteSize() { result = byteSize } + + override predicate isUnsigned() { any() } } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll index 6852a9654017..5e11a310e2fb 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll @@ -1,3 +1,9 @@ +/** + * Provides classes that describe how a particular `Instruction` or its operands access memory. + */ + +private import IRConfiguration + private newtype TMemoryAccessKind = TIndirectMemoryAccess() or TBufferMemoryAccess() or @@ -14,6 +20,7 @@ private newtype TMemoryAccessKind = * memory result. */ class MemoryAccessKind extends TMemoryAccessKind { + /** Gets a textual representation of this access kind. */ string toString() { none() } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll index c0b8adbe56be..c4134d240aba 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll @@ -1,3 +1,8 @@ +/** + * Provides `Opcode`s that specify the operation performed by an `Instruction`, as well as metadata + * about those opcodes, such as operand kinds and memory accesses. + */ + private import internal.OpcodeImports as Imports private import internal.OperandTag import Imports::MemoryAccessKind @@ -45,7 +50,7 @@ private newtype TOpcode = TConvertToDerived() or TCheckedConvertOrNull() or TCheckedConvertOrThrow() or - TDynamicCastToVoid() or + TCompleteObjectAddress() or TVariableAddress() or TFieldAddress() or TFunctionAddress() or @@ -86,7 +91,11 @@ private newtype TOpcode = TUnreached() or TNewObj() +/** + * An opcode that specifies the operation performed by an `Instruction`. + */ class Opcode extends TOpcode { + /** Gets a textual representation of this element. */ string toString() { result = "UnknownOpcode" } /** @@ -139,10 +148,20 @@ class Opcode extends TOpcode { predicate hasOperandInternal(OperandTag tag) { none() } } +/** + * The `Opcode` for a `UnaryInstruction`. + * + * See the `UnaryInstruction` documentation for more details. + */ abstract class UnaryOpcode extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof UnaryOperandTag } } +/** + * The `Opcode` for a `BinaryInstruction`. + * + * See the `BinaryInstruction` documentation for more details. + */ abstract class BinaryOpcode extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof LeftOperandTag or @@ -150,44 +169,127 @@ abstract class BinaryOpcode extends Opcode { } } +/** + * The `Opcode` for a `PointerArithmeticInstruction`. + * + * See the `PointerArithmeticInstruction` documentation for more details. + */ abstract class PointerArithmeticOpcode extends BinaryOpcode { } +/** + * The `Opcode` for a `PointerOffsetInstruction`. + * + * See the `PointerOffsetInstruction` documentation for more details. + */ abstract class PointerOffsetOpcode extends PointerArithmeticOpcode { } +/** + * The `Opcode` for an `ArithmeticInstruction`. + * + * See the `ArithmeticInstruction` documentation for more details. + */ abstract class ArithmeticOpcode extends Opcode { } +/** + * The `Opcode` for a `BinaryArithmeticInstruction`. + * + * See the `BinaryArithmeticInstruction` documentation for more details. + */ abstract class BinaryArithmeticOpcode extends BinaryOpcode, ArithmeticOpcode { } +/** + * The `Opcode` for a `UnaryArithmeticInstruction`. + * + * See the `UnaryArithmeticInstruction` documentation for more details. + */ abstract class UnaryArithmeticOpcode extends UnaryOpcode, ArithmeticOpcode { } +/** + * The `Opcode` for a `BitwiseInstruction`. + * + * See the `BitwiseInstruction` documentation for more details. + */ abstract class BitwiseOpcode extends Opcode { } +/** + * The `Opcode` for a `BinaryBitwiseInstruction`. + * + * See the `BinaryBitwiseInstruction` documentation for more details. + */ abstract class BinaryBitwiseOpcode extends BinaryOpcode, BitwiseOpcode { } +/** + * The `Opcode` for a `UnaryBitwiseInstruction`. + * + * See the `UnaryBitwiseInstruction` documentation for more details. + */ abstract class UnaryBitwiseOpcode extends UnaryOpcode, BitwiseOpcode { } +/** + * The `Opcode` for a `CompareInstruction`. + * + * See the `CompareInstruction` documentation for more details. + */ abstract class CompareOpcode extends BinaryOpcode { } +/** + * The `Opcode` for a `RelationalInstruction`. + * + * See the `RelationalInstruction` documentation for more details. + */ abstract class RelationalOpcode extends CompareOpcode { } +/** + * The `Opcode` for a `CopyInstruction`. + * + * See the `CopyInstruction` documentation for more details. + */ abstract class CopyOpcode extends Opcode { } +/** + * The `Opcode` for a `ConvertToBaseInstruction`. + * + * See the `ConvertToBaseInstruction` documentation for more details. + */ abstract class ConvertToBaseOpcode extends UnaryOpcode { } -abstract class MemoryAccessOpcode extends Opcode { } - +/** + * The `Opcode` for a `ReturnInstruction`. + * + * See the `ReturnInstruction` documentation for more details. + */ abstract class ReturnOpcode extends Opcode { } +/** + * The `Opcode` for a `ThrowInstruction`. + * + * See the `ThrowInstruction` documentation for more details. + */ abstract class ThrowOpcode extends Opcode { } +/** + * The `Opcode` for a `CatchInstruction`. + * + * See the `CatchInstruction` documentation for more details. + */ abstract class CatchOpcode extends Opcode { } -abstract class OpcodeWithCondition extends Opcode { +abstract private class OpcodeWithCondition extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof ConditionOperandTag } } +/** + * The `Opcode` for a `BuiltInOperationInstruction`. + * + * See the `BuiltInOperationInstruction` documentation for more details. + */ abstract class BuiltInOperationOpcode extends Opcode { } +/** + * The `Opcode` for a `SideEffectInstruction`. + * + * See the `SideEffectInstruction` documentation for more details. + */ abstract class SideEffectOpcode extends Opcode { } /** @@ -323,7 +425,9 @@ abstract class OpcodeWithLoad extends IndirectReadOpcode { } /** - * An opcode that reads from a set of memory locations as a side effect. + * The `Opcode` for a `ReadSideEffectInstruction`. + * + * See the `ReadSideEffectInstruction` documentation for more details. */ abstract class ReadSideEffectOpcode extends SideEffectOpcode { final override predicate hasOperandInternal(OperandTag tag) { @@ -332,51 +436,111 @@ abstract class ReadSideEffectOpcode extends SideEffectOpcode { } /** - * An opcode that writes to a set of memory locations as a side effect. + * The `Opcode` for a `WriteSideEffectInstruction`. + * + * See the `WriteSideEffectInstruction` documentation for more details. */ abstract class WriteSideEffectOpcode extends SideEffectOpcode { } +/** + * Provides `Opcode`s that specify the operation performed by an `Instruction`. + */ module Opcode { + /** + * The `Opcode` for a `NoOpInstruction`. + * + * See the `NoOpInstruction` documentation for more details. + */ class NoOp extends Opcode, TNoOp { final override string toString() { result = "NoOp" } } + /** + * The `Opcode` for an `UninitializedInstruction`. + * + * See the `UninitializedInstruction` documentation for more details. + */ class Uninitialized extends IndirectWriteOpcode, TUninitialized { final override string toString() { result = "Uninitialized" } } + /** + * The `Opcode` for an `ErrorInstruction`. + * + * See the `ErrorInstruction` documentation for more details. + */ class Error extends Opcode, TError { final override string toString() { result = "Error" } } + /** + * The `Opcode` for an `InitializeParameterInstruction`. + * + * See the `InitializeParameterInstruction` documentation for more details. + */ class InitializeParameter extends IndirectWriteOpcode, TInitializeParameter { final override string toString() { result = "InitializeParameter" } } + /** + * The `Opcode` for an `InitializeIndirectionInstruction`. + * + * See the `InitializeIndirectionInstruction` documentation for more details. + */ class InitializeIndirection extends EntireAllocationWriteOpcode, TInitializeIndirection { final override string toString() { result = "InitializeIndirection" } } + /** + * The `Opcode` for an `InitializeThisInstruction`. + * + * See the `InitializeThisInstruction` documentation for more details. + */ class InitializeThis extends Opcode, TInitializeThis { final override string toString() { result = "InitializeThis" } } + /** + * The `Opcode` for an `EnterFunctionInstruction`. + * + * See the `EnterFunctionInstruction` documentation for more details. + */ class EnterFunction extends Opcode, TEnterFunction { final override string toString() { result = "EnterFunction" } } + /** + * The `Opcode` for an `ExitFunctionInstruction`. + * + * See the `ExitFunctionInstruction` documentation for more details. + */ class ExitFunction extends Opcode, TExitFunction { final override string toString() { result = "ExitFunction" } } + /** + * The `Opcode` for a `ReturnValueInstruction`. + * + * See the `ReturnValueInstruction` documentation for more details. + */ class ReturnValue extends ReturnOpcode, OpcodeWithLoad, TReturnValue { final override string toString() { result = "ReturnValue" } } + /** + * The `Opcode` for a `ReturnVoidInstruction`. + * + * See the `ReturnVoidInstruction` documentation for more details. + */ class ReturnVoid extends ReturnOpcode, TReturnVoid { final override string toString() { result = "ReturnVoid" } } + /** + * The `Opcode` for a `ReturnIndirectionInstruction`. + * + * See the `ReturnIndirectionInstruction` documentation for more details. + */ class ReturnIndirection extends EntireAllocationReadOpcode, TReturnIndirection { final override string toString() { result = "ReturnIndirection" } @@ -385,14 +549,29 @@ module Opcode { } } + /** + * The `Opcode` for a `CopyValueInstruction`. + * + * See the `CopyValueInstruction` documentation for more details. + */ class CopyValue extends UnaryOpcode, CopyOpcode, TCopyValue { final override string toString() { result = "CopyValue" } } + /** + * The `Opcode` for a `LoadInstruction`. + * + * See the `LoadInstruction` documentation for more details. + */ class Load extends CopyOpcode, OpcodeWithLoad, TLoad { final override string toString() { result = "Load" } } + /** + * The `Opcode` for a `StoreInstruction`. + * + * See the `StoreInstruction` documentation for more details. + */ class Store extends CopyOpcode, IndirectWriteOpcode, TStore { final override string toString() { result = "Store" } @@ -401,154 +580,344 @@ module Opcode { } } + /** + * The `Opcode` for an `AddInstruction`. + * + * See the `AddInstruction` documentation for more details. + */ class Add extends BinaryArithmeticOpcode, TAdd { final override string toString() { result = "Add" } } + /** + * The `Opcode` for a `SubInstruction`. + * + * See the `SubInstruction` documentation for more details. + */ class Sub extends BinaryArithmeticOpcode, TSub { final override string toString() { result = "Sub" } } + /** + * The `Opcode` for a `MulInstruction`. + * + * See the `MulInstruction` documentation for more details. + */ class Mul extends BinaryArithmeticOpcode, TMul { final override string toString() { result = "Mul" } } + /** + * The `Opcode` for a `DivInstruction`. + * + * See the `DivInstruction` documentation for more details. + */ class Div extends BinaryArithmeticOpcode, TDiv { final override string toString() { result = "Div" } } + /** + * The `Opcode` for a `RemInstruction`. + * + * See the `RemInstruction` documentation for more details. + */ class Rem extends BinaryArithmeticOpcode, TRem { final override string toString() { result = "Rem" } } + /** + * The `Opcode` for a `NegateInstruction`. + * + * See the `NegateInstruction` documentation for more details. + */ class Negate extends UnaryArithmeticOpcode, TNegate { final override string toString() { result = "Negate" } } + /** + * The `Opcode` for a `ShiftLeftInstruction`. + * + * See the `ShiftLeftInstruction` documentation for more details. + */ class ShiftLeft extends BinaryBitwiseOpcode, TShiftLeft { final override string toString() { result = "ShiftLeft" } } + /** + * The `Opcode` for a `ShiftRightInstruction`. + * + * See the `ShiftRightInstruction` documentation for more details. + */ class ShiftRight extends BinaryBitwiseOpcode, TShiftRight { final override string toString() { result = "ShiftRight" } } + /** + * The `Opcode` for a `BitAndInstruction`. + * + * See the `BitAndInstruction` documentation for more details. + */ class BitAnd extends BinaryBitwiseOpcode, TBitAnd { final override string toString() { result = "BitAnd" } } + /** + * The `Opcode` for a `BitOrInstruction`. + * + * See the `BitOrInstruction` documentation for more details. + */ class BitOr extends BinaryBitwiseOpcode, TBitOr { final override string toString() { result = "BitOr" } } + /** + * The `Opcode` for a `BitXorInstruction`. + * + * See the `BitXorInstruction` documentation for more details. + */ class BitXor extends BinaryBitwiseOpcode, TBitXor { final override string toString() { result = "BitXor" } } + /** + * The `Opcode` for a `BitComplementInstruction`. + * + * See the `BitComplementInstruction` documentation for more details. + */ class BitComplement extends UnaryBitwiseOpcode, TBitComplement { final override string toString() { result = "BitComplement" } } + /** + * The `Opcode` for a `LogicalNotInstruction`. + * + * See the `LogicalNotInstruction` documentation for more details. + */ class LogicalNot extends UnaryOpcode, TLogicalNot { final override string toString() { result = "LogicalNot" } } + /** + * The `Opcode` for a `CompareEQInstruction`. + * + * See the `CompareEQInstruction` documentation for more details. + */ class CompareEQ extends CompareOpcode, TCompareEQ { final override string toString() { result = "CompareEQ" } } + /** + * The `Opcode` for a `CompareNEInstruction`. + * + * See the `CompareNEInstruction` documentation for more details. + */ class CompareNE extends CompareOpcode, TCompareNE { final override string toString() { result = "CompareNE" } } + /** + * The `Opcode` for a `CompareLTInstruction`. + * + * See the `CompareLTInstruction` documentation for more details. + */ class CompareLT extends RelationalOpcode, TCompareLT { final override string toString() { result = "CompareLT" } } + /** + * The `Opcode` for a `CompareGTInstruction`. + * + * See the `CompareGTInstruction` documentation for more details. + */ class CompareGT extends RelationalOpcode, TCompareGT { final override string toString() { result = "CompareGT" } } + /** + * The `Opcode` for a `CompareLEInstruction`. + * + * See the `CompareLEInstruction` documentation for more details. + */ class CompareLE extends RelationalOpcode, TCompareLE { final override string toString() { result = "CompareLE" } } + /** + * The `Opcode` for a `CompareGEInstruction`. + * + * See the `CompareGEInstruction` documentation for more details. + */ class CompareGE extends RelationalOpcode, TCompareGE { final override string toString() { result = "CompareGE" } } + /** + * The `Opcode` for a `PointerAddInstruction`. + * + * See the `PointerAddInstruction` documentation for more details. + */ class PointerAdd extends PointerOffsetOpcode, TPointerAdd { final override string toString() { result = "PointerAdd" } } + /** + * The `Opcode` for a `PointerSubInstruction`. + * + * See the `PointerSubInstruction` documentation for more details. + */ class PointerSub extends PointerOffsetOpcode, TPointerSub { final override string toString() { result = "PointerSub" } } + /** + * The `Opcode` for a `PointerDiffInstruction`. + * + * See the `PointerDiffInstruction` documentation for more details. + */ class PointerDiff extends PointerArithmeticOpcode, TPointerDiff { final override string toString() { result = "PointerDiff" } } + /** + * The `Opcode` for a `ConvertInstruction`. + * + * See the `ConvertInstruction` documentation for more details. + */ class Convert extends UnaryOpcode, TConvert { final override string toString() { result = "Convert" } } + /** + * The `Opcode` for a `ConvertToNonVirtualBaseInstruction`. + * + * See the `ConvertToNonVirtualBaseInstruction` documentation for more details. + */ class ConvertToNonVirtualBase extends ConvertToBaseOpcode, TConvertToNonVirtualBase { final override string toString() { result = "ConvertToNonVirtualBase" } } + /** + * The `Opcode` for a `ConvertToVirtualBaseInstruction`. + * + * See the `ConvertToVirtualBaseInstruction` documentation for more details. + */ class ConvertToVirtualBase extends ConvertToBaseOpcode, TConvertToVirtualBase { final override string toString() { result = "ConvertToVirtualBase" } } + /** + * The `Opcode` for a `ConvertToDerivedInstruction`. + * + * See the `ConvertToDerivedInstruction` documentation for more details. + */ class ConvertToDerived extends UnaryOpcode, TConvertToDerived { final override string toString() { result = "ConvertToDerived" } } + /** + * The `Opcode` for a `CheckedConvertOrNullInstruction`. + * + * See the `CheckedConvertOrNullInstruction` documentation for more details. + */ class CheckedConvertOrNull extends UnaryOpcode, TCheckedConvertOrNull { final override string toString() { result = "CheckedConvertOrNull" } } + /** + * The `Opcode` for a `CheckedConvertOrThrowInstruction`. + * + * See the `CheckedConvertOrThrowInstruction` documentation for more details. + */ class CheckedConvertOrThrow extends UnaryOpcode, TCheckedConvertOrThrow { final override string toString() { result = "CheckedConvertOrThrow" } } - class DynamicCastToVoid extends UnaryOpcode, TDynamicCastToVoid { - final override string toString() { result = "DynamicCastToVoid" } + /** + * The `Opcode` for a `CompleteObjectAddressInstruction`. + * + * See the `CompleteObjectAddressInstruction` documentation for more details. + */ + class CompleteObjectAddress extends UnaryOpcode, TCompleteObjectAddress { + final override string toString() { result = "CompleteObjectAddress" } } + /** + * The `Opcode` for a `VariableAddressInstruction`. + * + * See the `VariableAddressInstruction` documentation for more details. + */ class VariableAddress extends Opcode, TVariableAddress { final override string toString() { result = "VariableAddress" } } + /** + * The `Opcode` for a `FieldAddressInstruction`. + * + * See the `FieldAddressInstruction` documentation for more details. + */ class FieldAddress extends UnaryOpcode, TFieldAddress { final override string toString() { result = "FieldAddress" } } + /** + * The `Opcode` for an `ElementsAddressInstruction`. + * + * See the `ElementsAddressInstruction` documentation for more details. + */ class ElementsAddress extends UnaryOpcode, TElementsAddress { final override string toString() { result = "ElementsAddress" } } + /** + * The `Opcode` for a `FunctionAddressInstruction`. + * + * See the `FunctionAddressInstruction` documentation for more details. + */ class FunctionAddress extends Opcode, TFunctionAddress { final override string toString() { result = "FunctionAddress" } } + /** + * The `Opcode` for a `ConstantInstruction`. + * + * See the `ConstantInstruction` documentation for more details. + */ class Constant extends Opcode, TConstant { final override string toString() { result = "Constant" } } + /** + * The `Opcode` for a `StringConstantInstruction`. + * + * See the `StringConstantInstruction` documentation for more details. + */ class StringConstant extends Opcode, TStringConstant { final override string toString() { result = "StringConstant" } } + /** + * The `Opcode` for a `ConditionalBranchInstruction`. + * + * See the `ConditionalBranchInstruction` documentation for more details. + */ class ConditionalBranch extends OpcodeWithCondition, TConditionalBranch { final override string toString() { result = "ConditionalBranch" } } + /** + * The `Opcode` for a `SwitchInstruction`. + * + * See the `SwitchInstruction` documentation for more details. + */ class Switch extends OpcodeWithCondition, TSwitch { final override string toString() { result = "Switch" } } + /** + * The `Opcode` for a `CallInstruction`. + * + * See the `CallInstruction` documentation for more details. + */ class Call extends Opcode, TCall { final override string toString() { result = "Call" } @@ -557,32 +926,67 @@ module Opcode { } } + /** + * The `Opcode` for a `CatchByTypeInstruction`. + * + * See the `CatchByTypeInstruction` documentation for more details. + */ class CatchByType extends CatchOpcode, TCatchByType { final override string toString() { result = "CatchByType" } } + /** + * The `Opcode` for a `CatchAnyInstruction`. + * + * See the `CatchAnyInstruction` documentation for more details. + */ class CatchAny extends CatchOpcode, TCatchAny { final override string toString() { result = "CatchAny" } } + /** + * The `Opcode` for a `ThrowValueInstruction`. + * + * See the `ThrowValueInstruction` documentation for more details. + */ class ThrowValue extends ThrowOpcode, OpcodeWithLoad, TThrowValue { final override string toString() { result = "ThrowValue" } } + /** + * The `Opcode` for a `ReThrowInstruction`. + * + * See the `ReThrowInstruction` documentation for more details. + */ class ReThrow extends ThrowOpcode, TReThrow { final override string toString() { result = "ReThrow" } } + /** + * The `Opcode` for an `UnwindInstruction`. + * + * See the `UnwindInstruction` documentation for more details. + */ class Unwind extends Opcode, TUnwind { final override string toString() { result = "Unwind" } } + /** + * The `Opcode` for an `AliasedDefinitionInstruction`. + * + * See the `AliasedDefinitionInstruction` documentation for more details. + */ class AliasedDefinition extends Opcode, TAliasedDefinition { final override string toString() { result = "AliasedDefinition" } final override MemoryAccessKind getWriteMemoryAccess() { result instanceof EscapedMemoryAccess } } + /** + * The `Opcode` for an `InitializeNonLocalInstruction`. + * + * See the `InitializeNonLocalInstruction` documentation for more details. + */ class InitializeNonLocal extends Opcode, TInitializeNonLocal { final override string toString() { result = "InitializeNonLocal" } @@ -591,6 +995,11 @@ module Opcode { } } + /** + * The `Opcode` for an `AliasedUseInstruction`. + * + * See the `AliasedUseInstruction` documentation for more details. + */ class AliasedUse extends Opcode, TAliasedUse { final override string toString() { result = "AliasedUse" } @@ -601,92 +1010,187 @@ module Opcode { } } + /** + * The `Opcode` for a `PhiInstruction`. + * + * See the `PhiInstruction` documentation for more details. + */ class Phi extends Opcode, TPhi { final override string toString() { result = "Phi" } final override MemoryAccessKind getWriteMemoryAccess() { result instanceof PhiMemoryAccess } } + /** + * The `Opcode` for a `BuiltInInstruction`. + * + * See the `BuiltInInstruction` documentation for more details. + */ class BuiltIn extends BuiltInOperationOpcode, TBuiltIn { final override string toString() { result = "BuiltIn" } } + /** + * The `Opcode` for a `VarArgsStartInstruction`. + * + * See the `VarArgsStartInstruction` documentation for more details. + */ class VarArgsStart extends UnaryOpcode, TVarArgsStart { final override string toString() { result = "VarArgsStart" } } + /** + * The `Opcode` for a `VarArgsEndInstruction`. + * + * See the `VarArgsEndInstruction` documentation for more details. + */ class VarArgsEnd extends UnaryOpcode, TVarArgsEnd { final override string toString() { result = "VarArgsEnd" } } + /** + * The `Opcode` for a `VarArgInstruction`. + * + * See the `VarArgInstruction` documentation for more details. + */ class VarArg extends UnaryOpcode, TVarArg { final override string toString() { result = "VarArg" } } + /** + * The `Opcode` for a `NextVarArgInstruction`. + * + * See the `NextVarArgInstruction` documentation for more details. + */ class NextVarArg extends UnaryOpcode, TNextVarArg { final override string toString() { result = "NextVarArg" } } + /** + * The `Opcode` for a `CallSideEffectInstruction`. + * + * See the `CallSideEffectInstruction` documentation for more details. + */ class CallSideEffect extends WriteSideEffectOpcode, EscapedWriteOpcode, MayWriteOpcode, ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallSideEffect { final override string toString() { result = "CallSideEffect" } } + /** + * The `Opcode` for a `CallReadSideEffectInstruction`. + * + * See the `CallReadSideEffectInstruction` documentation for more details. + */ class CallReadSideEffect extends ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallReadSideEffect { final override string toString() { result = "CallReadSideEffect" } } + /** + * The `Opcode` for an `IndirectReadSideEffectInstruction`. + * + * See the `IndirectReadSideEffectInstruction` documentation for more details. + */ class IndirectReadSideEffect extends ReadSideEffectOpcode, IndirectReadOpcode, TIndirectReadSideEffect { final override string toString() { result = "IndirectReadSideEffect" } } + /** + * The `Opcode` for an `IndirectMustWriteSideEffectInstruction`. + * + * See the `IndirectMustWriteSideEffectInstruction` documentation for more details. + */ class IndirectMustWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode, TIndirectMustWriteSideEffect { final override string toString() { result = "IndirectMustWriteSideEffect" } } + /** + * The `Opcode` for an `IndirectMayWriteSideEffectInstruction`. + * + * See the `IndirectMayWriteSideEffectInstruction` documentation for more details. + */ class IndirectMayWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode, MayWriteOpcode, TIndirectMayWriteSideEffect { final override string toString() { result = "IndirectMayWriteSideEffect" } } + /** + * The `Opcode` for a `BufferReadSideEffectInstruction`. + * + * See the `BufferReadSideEffectInstruction` documentation for more details. + */ class BufferReadSideEffect extends ReadSideEffectOpcode, UnsizedBufferReadOpcode, TBufferReadSideEffect { final override string toString() { result = "BufferReadSideEffect" } } + /** + * The `Opcode` for a `BufferMustWriteSideEffectInstruction`. + * + * See the `BufferMustWriteSideEffectInstruction` documentation for more details. + */ class BufferMustWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode, TBufferMustWriteSideEffect { final override string toString() { result = "BufferMustWriteSideEffect" } } + /** + * The `Opcode` for a `BufferMayWriteSideEffectInstruction`. + * + * See the `BufferMayWriteSideEffectInstruction` documentation for more details. + */ class BufferMayWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode, MayWriteOpcode, TBufferMayWriteSideEffect { final override string toString() { result = "BufferMayWriteSideEffect" } } + /** + * The `Opcode` for a `SizedBufferReadSideEffectInstruction`. + * + * See the `SizedBufferReadSideEffectInstruction` documentation for more details. + */ class SizedBufferReadSideEffect extends ReadSideEffectOpcode, SizedBufferReadOpcode, TSizedBufferReadSideEffect { final override string toString() { result = "SizedBufferReadSideEffect" } } + /** + * The `Opcode` for a `SizedBufferMustWriteSideEffectInstruction`. + * + * See the `SizedBufferMustWriteSideEffectInstruction` documentation for more details. + */ class SizedBufferMustWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode, TSizedBufferMustWriteSideEffect { final override string toString() { result = "SizedBufferMustWriteSideEffect" } } + /** + * The `Opcode` for a `SizedBufferMayWriteSideEffectInstruction`. + * + * See the `SizedBufferMayWriteSideEffectInstruction` documentation for more details. + */ class SizedBufferMayWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode, MayWriteOpcode, TSizedBufferMayWriteSideEffect { final override string toString() { result = "SizedBufferMayWriteSideEffect" } } + /** + * The `Opcode` for an `InitializeDynamicAllocationInstruction`. + * + * See the `InitializeDynamicAllocationInstruction` documentation for more details. + */ class InitializeDynamicAllocation extends SideEffectOpcode, EntireAllocationWriteOpcode, TInitializeDynamicAllocation { final override string toString() { result = "InitializeDynamicAllocation" } } + /** + * The `Opcode` for a `ChiInstruction`. + * + * See the `ChiInstruction` documentation for more details. + */ class Chi extends Opcode, TChi { final override string toString() { result = "Chi" } @@ -701,6 +1205,11 @@ module Opcode { } } + /** + * The `Opcode` for an `InlineAsmInstruction`. + * + * See the `InlineAsmInstruction` documentation for more details. + */ class InlineAsm extends Opcode, EscapedWriteOpcode, MayWriteOpcode, EscapedReadOpcode, MayReadOpcode, TInlineAsm { final override string toString() { result = "InlineAsm" } @@ -710,10 +1219,20 @@ module Opcode { } } + /** + * The `Opcode` for an `UnreachedInstruction`. + * + * See the `UnreachedInstruction` documentation for more details. + */ class Unreached extends Opcode, TUnreached { final override string toString() { result = "Unreached" } } + /** + * The `Opcode` for a `NewObjInstruction`. + * + * See the `NewObjInstruction` documentation for more details. + */ class NewObj extends Opcode, TNewObj { final override string toString() { result = "NewObj" } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll index a0c0ca675307..5f230de560d6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll @@ -12,5 +12,6 @@ private import Imports::TempVariableTag * computed on each branch. The set of possible `TempVariableTag`s is language-dependent. */ class TempVariableTag extends TTempVariableTag { + /** Gets a textual representation of this tag. */ string toString() { result = getTempVariableTagId(this) } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll index badd48552a5f..c96783fe6e81 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll @@ -1,3 +1,47 @@ +/** + * Provides classes that describe the Intermediate Representation (IR) of the program. + * + * The IR is a representation of the semantics of the program, with very little dependence on the + * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, + * and `++i` all have the same semantic effect, but appear in the AST as three different types of + * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental + * operations similar to: + * + * ``` + * r1(int*) = VariableAddress[i] // Compute the address of variable `i` + * r2(int) = Load &:r1, m0 // Load the value of `i` + * r3(int) = Constant[1] // An integer constant with the value `1` + * r4(int) = Add r2, r3 // Add `1` to the value of `i` + * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` + * ``` + * + * This allows IR-based analysis to focus on the fundamental operations, rather than having to be + * concerned with the various ways of expressing those operations in source code. + * + * The key classes in the IR are: + * + * - `IRFunction` - Contains the IR for an entire function definition, including all of that + * function's `Instruction`s, `IRBlock`s, and `IRVariables`. + * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be + * performed, the operands that produce the inputs to that operation, and the type of the result + * of the operation. Control flows from an `Instruction` to one of a set of successor + * `Instruction`s. + * - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly + * represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has + * a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction` + * that produces its value (its "definition"). + * - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is + * created for each variable directly accessed by the function. In addition, `IRVariable`s are + * created to represent certain temporary storage locations that do not have explicitly declared + * variables in the source code, such as the return value of the function. + * - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a + * sequence of instructions such that control flow can only enter the block at the first + * instruction, and can only leave the block from the last instruction. + * - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType` + * is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all + * be represented as the `IRType` `uint4`, a four-byte unsigned integer. + */ + import IRFunction import Instruction import IRBlock @@ -11,11 +55,12 @@ import Imports::MemoryAccessKind private newtype TIRPropertyProvider = MkIRPropertyProvider() /** - * Class that provides additional properties to be dumped for IR instructions and blocks when using + * A class that provides additional properties to be dumped for IR instructions and blocks when using * the PrintIR module. Libraries that compute additional facts about IR elements can extend the * single instance of this class to specify the additional properties computed by the library. */ class IRPropertyProvider extends TIRPropertyProvider { + /** Gets a textual representation of this element. */ string toString() { result = "IRPropertyProvider" } /** @@ -27,4 +72,9 @@ class IRPropertyProvider extends TIRPropertyProvider { * Gets the value of the property named `key` for the specified block. */ string getBlockProperty(IRBlock block, string key) { none() } + + /** + * Gets the value of the property named `key` for the specified operand. + */ + string getOperandProperty(Operand operand, string key) { none() } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll index 94ef73b27692..d827ed3cf82d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll @@ -1,3 +1,7 @@ +/** + * Provides classes describing basic blocks in the IR of a function. + */ + private import internal.IRInternal import Instruction private import internal.IRBlockImports as Imports @@ -16,15 +20,27 @@ private import Cached * Most consumers should use the class `IRBlock`. */ class IRBlockBase extends TIRBlock { + /** Gets a textual representation of this block. */ final string toString() { result = getFirstInstruction(this).toString() } + /** Gets the source location of the first non-`Phi` instruction in this block. */ final Language::Location getLocation() { result = getFirstInstruction().getLocation() } + /** + * INTERNAL: Do not use. + * + * Gets a string that uniquely identifies this block within its enclosing function. + * + * This predicate is used by debugging and printing code only. + */ final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() } /** - * Gets the zero-based index of the block within its function. This is used - * by debugging and printing code only. + * INTERNAL: Do not use. + * + * Gets the zero-based index of the block within its function. + * + * This predicate is used by debugging and printing code only. */ int getDisplayIndex() { exists(IRConfiguration::IRConfiguration config | @@ -42,27 +58,51 @@ class IRBlockBase extends TIRBlock { ) } + /** + * Gets the `index`th non-`Phi` instruction in this block. + */ final Instruction getInstruction(int index) { result = getInstruction(this, index) } + /** + * Get the `Phi` instructions that appear at the start of this block. + */ final PhiInstruction getAPhiInstruction() { Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() } + /** + * Gets an instruction in this block. This includes `Phi` instructions. + */ final Instruction getAnInstruction() { result = getInstruction(_) or result = getAPhiInstruction() } + /** + * Gets the first non-`Phi` instruction in this block. + */ final Instruction getFirstInstruction() { result = getFirstInstruction(this) } + /** + * Gets the last instruction in this block. + */ final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) } + /** + * Gets the number of non-`Phi` instructions in this block. + */ final int getInstructionCount() { result = getInstructionCount(this) } + /** + * Gets the `IRFunction` that contains this block. + */ final IRFunction getEnclosingIRFunction() { result = getFirstInstruction(this).getEnclosingIRFunction() } + /** + * Gets the `Function` that contains this block. + */ final Language::Function getEnclosingFunction() { result = getFirstInstruction(this).getEnclosingFunction() } @@ -74,20 +114,57 @@ class IRBlockBase extends TIRBlock { * instruction of another block. */ class IRBlock extends IRBlockBase { + /** + * Gets a block to which control flows directly from this block. + */ final IRBlock getASuccessor() { blockSuccessor(this, result) } + /** + * Gets a block from which control flows directly to this block. + */ final IRBlock getAPredecessor() { blockSuccessor(result, this) } + /** + * Gets the block to which control flows directly from this block along an edge of kind `kind`. + */ final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } + /** + * Gets the block to which control flows directly from this block along a back edge of kind + * `kind`. + */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } + /** + * Holds if this block immediately dominates `block`. + * + * Block `A` immediate dominates block `B` if block `A` strictly dominates block `B` and block `B` + * is a direct successor of block `A`. + */ final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) } + /** + * Holds if this block strictly dominates `block`. + * + * Block `A` strictly dominates block `B` if block `A` dominates block `B` and blocks `A` and `B` + * are not the same block. + */ final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) } + /** + * Holds if this block dominates `block`. + * + * Block `A` dominates block `B` if any control flow path from the entry block of the function to + * block `B` must pass through block `A`. A block always dominates itself. + */ final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } + /** + * Gets a block on the dominance frontier of this block. + * + * The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not + * dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`. + */ pragma[noinline] final IRBlock dominanceFrontier() { dominates(result.getAPredecessor()) and @@ -95,7 +172,7 @@ class IRBlock extends IRBlockBase { } /** - * Holds if this block is reachable from the entry point of its function + * Holds if this block is reachable from the entry block of its function. */ final predicate isReachableFromFunctionEntry() { this = getEnclosingIRFunction().getEntryBlock() or @@ -210,4 +287,4 @@ private module Cached { idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block) } -Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } +private Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll index 65af34942b6b..6a87b9b4b5fd 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll @@ -8,10 +8,79 @@ module InstructionConsistency { private import Imports::Overlap private import internal.IRInternal + private newtype TOptionalIRFunction = + TPresentIRFunction(IRFunction irFunc) or + TMissingIRFunction() + + /** + * An `IRFunction` that might not exist. This is used so that we can produce consistency failures + * for IR that also incorrectly lacks a `getEnclosingIRFunction()`. + */ + abstract private class OptionalIRFunction extends TOptionalIRFunction { + abstract string toString(); + + abstract Language::Location getLocation(); + } + + private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction { + private IRFunction irFunc; + + PresentIRFunction() { this = TPresentIRFunction(irFunc) } + + override string toString() { + result = concat(Language::getIdentityString(irFunc.getFunction()), "; ") + } + + override Language::Location getLocation() { + // To avoid an overwhelming number of results when the extractor merges functions with the + // same name, just pick a single location. + result = + rank[1](Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString()) + } + } + + private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction { + override string toString() { result = "" } + + override Language::Location getLocation() { result instanceof Language::UnknownDefaultLocation } + } + + private OptionalIRFunction getInstructionIRFunction(Instruction instr) { + result = TPresentIRFunction(instr.getEnclosingIRFunction()) + or + not exists(instr.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getInstructionIRFunction(Instruction instr, string irFuncText) { + result = getInstructionIRFunction(instr) and + irFuncText = result.toString() + } + + private OptionalIRFunction getOperandIRFunction(Operand operand) { + result = TPresentIRFunction(operand.getEnclosingIRFunction()) + or + not exists(operand.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getOperandIRFunction(Operand operand, string irFuncText) { + result = getOperandIRFunction(operand) and + irFuncText = result.toString() + } + + private OptionalIRFunction getBlockIRFunction(IRBlock block) { + result = TPresentIRFunction(block.getEnclosingIRFunction()) + or + not exists(block.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + /** * Holds if instruction `instr` is missing an expected operand with tag `tag`. */ - query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) { + query predicate missingOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { exists(OperandTag tag | instr.getOpcode().hasOperand(tag) and not exists(NonPhiOperand operand | @@ -21,32 +90,39 @@ module InstructionConsistency { message = "Instruction '" + instr.getOpcode().toString() + "' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getInstructionIRFunction(instr, irFuncText) ) } /** * Holds if instruction `instr` has an unexpected operand with tag `tag`. */ - query predicate unexpectedOperand(Instruction instr, OperandTag tag) { - exists(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and - not instr.getOpcode().hasOperand(tag) and - not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and - not ( - instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag - ) and - not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag) + query predicate unexpectedOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(OperandTag tag | + exists(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + not instr.getOpcode().hasOperand(tag) and + not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and + not ( + instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag + ) and + not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag) and + message = + "Instruction '" + instr.toString() + "' has unexpected operand '" + tag.toString() + + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } /** * Holds if instruction `instr` has multiple operands with tag `tag`. */ query predicate duplicateOperand( - Instruction instr, string message, IRFunction func, string funcText + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(OperandTag tag, int operandCount | operandCount = @@ -58,8 +134,7 @@ module InstructionConsistency { message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + " in function '$@'." and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getInstructionIRFunction(instr, irFuncText) ) } @@ -67,100 +142,136 @@ module InstructionConsistency { * Holds if `Phi` instruction `instr` is missing an operand corresponding to * the predecessor block `pred`. */ - query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) { - pred = instr.getBlock().getAPredecessor() and - not exists(PhiInputOperand operand | - operand = instr.getAnOperand() and - operand.getPredecessorBlock() = pred + query predicate missingPhiOperand( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRBlock pred | + pred = instr.getBlock().getAPredecessor() and + not exists(PhiInputOperand operand | + operand = instr.getAnOperand() and + operand.getPredecessorBlock() = pred + ) and + message = + "Instruction '" + instr.toString() + "' is missing an operand for predecessor block '" + + pred.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) ) } - query predicate missingOperandType(Operand operand, string message) { - exists(Language::Function func, Instruction use | + query predicate missingOperandType( + Operand operand, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Instruction use | not exists(operand.getType()) and use = operand.getUse() and - func = use.getEnclosingFunction() and message = "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() + - "' missing type in function '" + Language::getIdentityString(func) + "'." + "' is missing a type in function '$@'." and + irFunc = getOperandIRFunction(operand, irFuncText) ) } query predicate duplicateChiOperand( - ChiInstruction chi, string message, IRFunction func, string funcText + ChiInstruction chi, string message, OptionalIRFunction irFunc, string irFuncText ) { chi.getTotal() = chi.getPartial() and message = "Chi instruction for " + chi.getPartial().toString() + - " has duplicate operands in function $@" and - func = chi.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + " has duplicate operands in function '$@'." and + irFunc = getInstructionIRFunction(chi, irFuncText) } query predicate sideEffectWithoutPrimary( - SideEffectInstruction instr, string message, IRFunction func, string funcText + SideEffectInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText ) { not exists(instr.getPrimaryInstruction()) and - message = "Side effect instruction missing primary instruction in function $@" and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + message = + "Side effect instruction '" + instr + "' is missing a primary instruction in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } /** * Holds if an instruction, other than `ExitFunction`, has no successors. */ - query predicate instructionWithoutSuccessor(Instruction instr) { + query predicate instructionWithoutSuccessor( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { not exists(instr.getASuccessor()) and not instr instanceof ExitFunctionInstruction and // Phi instructions aren't linked into the instruction-level flow graph. not instr instanceof PhiInstruction and - not instr instanceof UnreachedInstruction + not instr instanceof UnreachedInstruction and + message = "Instruction '" + instr.toString() + "' has no successors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } /** - * Holds if there are multiple (`n`) edges of kind `kind` from `source`, - * where `target` is among the targets of those edges. + * Holds if there are multiple edges of the same kind from `source`. */ - query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) { - n = strictcount(Instruction t | source.getSuccessor(kind) = t) and - n > 1 and - source.getSuccessor(kind) = target + query predicate ambiguousSuccessors( + Instruction source, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(EdgeKind kind, int n | + n = strictcount(Instruction t | source.getSuccessor(kind) = t) and + n > 1 and + message = + "Instruction '" + source.toString() + "' has " + n.toString() + " successors of kind '" + + kind.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(source, irFuncText) + ) } /** - * Holds if `instr` in `f` is part of a loop even though the AST of `f` + * Holds if `instr` is part of a loop even though the AST of `instr`'s enclosing function * contains no element that can cause loops. */ - query predicate unexplainedLoop(Language::Function f, Instruction instr) { - exists(IRBlock block | - instr.getBlock() = block and - block.getEnclosingFunction() = f and - block.getASuccessor+() = block - ) and - not Language::hasPotentialLoop(f) + query predicate unexplainedLoop( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Language::Function f | + exists(IRBlock block | + instr.getBlock() = block and + block.getEnclosingFunction() = f and + block.getASuccessor+() = block + ) and + not Language::hasPotentialLoop(f) and + message = + "Instruction '" + instr.toString() + "' is part of an unexplained loop in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } /** * Holds if a `Phi` instruction is present in a block with fewer than two * predecessors. */ - query predicate unnecessaryPhiInstruction(PhiInstruction instr) { - count(instr.getBlock().getAPredecessor()) < 2 + query predicate unnecessaryPhiInstruction( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int n | + n = count(instr.getBlock().getAPredecessor()) and + n < 2 and + message = + "Instruction '" + instr.toString() + "' is in a block with only " + n.toString() + + " predecessors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } /** * Holds if a memory operand is connected to a definition with an unmodeled result. */ query predicate memoryOperandDefinitionIsUnmodeled( - Instruction instr, string message, IRFunction func, string funcText + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(MemoryOperand operand, Instruction def | operand = instr.getAnOperand() and def = operand.getAnyDef() and not def.isResultModeled() and - message = "Memory operand definition has unmodeled result in function '$@'" and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + message = + "Memory operand definition on instruction '" + instr.toString() + + "' has unmodeled result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) ) } @@ -168,18 +279,37 @@ module InstructionConsistency { * Holds if operand `operand` consumes a value that was defined in * a different function. */ - query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) { - operand.getUse() = instr and - operand.getAnyDef() = defInstr and - instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction() + query predicate operandAcrossFunctions( + Operand operand, string message, OptionalIRFunction useIRFunc, string useIRFuncText, + OptionalIRFunction defIRFunc, string defIRFuncText + ) { + exists(Instruction useInstr, Instruction defInstr | + operand.getUse() = useInstr and + operand.getAnyDef() = defInstr and + useIRFunc = getInstructionIRFunction(useInstr, useIRFuncText) and + defIRFunc = getInstructionIRFunction(defInstr, defIRFuncText) and + useIRFunc != defIRFunc and + message = + "Operand '" + operand.toString() + "' is used on instruction '" + useInstr.toString() + + "' in function '$@', but is defined on instruction '" + defInstr.toString() + + "' in function '$@'." + ) } /** * Holds if instruction `instr` is not in exactly one block. */ - query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) { - blockCount = count(instr.getBlock()) and - blockCount != 1 + query predicate instructionWithoutUniqueBlock( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int blockCount | + blockCount = count(instr.getBlock()) and + blockCount != 1 and + message = + "Instruction '" + instr.toString() + "' is a member of " + blockCount.toString() + + " blocks in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } private predicate forwardEdge(IRBlock b1, IRBlock b2) { @@ -192,10 +322,11 @@ module InstructionConsistency { * * This check ensures we don't have too _few_ back edges. */ - query predicate containsLoopOfForwardEdges(IRFunction f) { + query predicate containsLoopOfForwardEdges(IRFunction f, string message) { exists(IRBlock block | forwardEdge+(block, block) and - block.getEnclosingIRFunction() = f + block.getEnclosingIRFunction() = f and + message = "Function contains a loop consisting of only forward edges." ) } @@ -207,12 +338,19 @@ module InstructionConsistency { * * This check ensures we don't have too _many_ back edges. */ - query predicate lostReachability(IRBlock block) { + query predicate lostReachability( + IRBlock block, string message, OptionalIRFunction irFunc, string irFuncText + ) { exists(IRFunction f, IRBlock entry | entry = f.getEntryBlock() and entry.getASuccessor+() = block and not forwardEdge+(entry, block) and - not Language::hasGoto(f.getFunction()) + not Language::hasGoto(f.getFunction()) and + message = + "Block '" + block.toString() + + "' is not reachable by traversing only forward edges in function '$@'." and + irFunc = TPresentIRFunction(f) and + irFuncText = irFunc.toString() ) } @@ -220,16 +358,22 @@ module InstructionConsistency { * Holds if the number of back edges differs between the `Instruction` graph * and the `IRBlock` graph. */ - query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) { - fromInstr = - count(Instruction i1, Instruction i2 | - i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2 - ) and - fromBlock = - count(IRBlock b1, IRBlock b2 | - b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2 - ) and - fromInstr != fromBlock + query predicate backEdgeCountMismatch(OptionalIRFunction irFunc, string message) { + exists(int fromInstr, int fromBlock | + fromInstr = + count(Instruction i1, Instruction i2 | + getInstructionIRFunction(i1) = irFunc and i1.getBackEdgeSuccessor(_) = i2 + ) and + fromBlock = + count(IRBlock b1, IRBlock b2 | + getBlockIRFunction(b1) = irFunc and b1.getBackEdgeSuccessor(_) = b2 + ) and + fromInstr != fromBlock and + message = + "The instruction graph for function '" + irFunc.toString() + "' contains " + + fromInstr.toString() + " back edges, but the block graph contains " + fromBlock.toString() + + " back edges." + ) } /** @@ -251,7 +395,7 @@ module InstructionConsistency { * Holds if `useOperand` has a definition that does not dominate the use. */ query predicate useNotDominatedByDefinition( - Operand useOperand, string message, IRFunction func, string funcText + Operand useOperand, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | pointOfEvaluation(useOperand, useBlock, useIndex) and @@ -272,19 +416,17 @@ module InstructionConsistency { message = "Operand '" + useOperand.toString() + "' is not dominated by its definition in function '$@'." and - func = useOperand.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getOperandIRFunction(useOperand, irFuncText) ) } query predicate switchInstructionWithoutDefaultEdge( - SwitchInstruction switchInstr, string message, IRFunction func, string funcText + SwitchInstruction switchInstr, string message, OptionalIRFunction irFunc, string irFuncText ) { not exists(switchInstr.getDefaultSuccessor()) and message = "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and - func = switchInstr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getInstructionIRFunction(switchInstr, irFuncText) } /** @@ -305,18 +447,30 @@ module InstructionConsistency { instr.getOpcode() instanceof Opcode::InitializeNonLocal } - query predicate notMarkedAsConflated(Instruction instr) { + query predicate notMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { shouldBeConflated(instr) and - not instr.isResultConflated() + not instr.isResultConflated() and + message = + "Instruction '" + instr.toString() + + "' should be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } - query predicate wronglyMarkedAsConflated(Instruction instr) { + query predicate wronglyMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { instr.isResultConflated() and - not shouldBeConflated(instr) + not shouldBeConflated(instr) and + message = + "Instruction '" + instr.toString() + + "' should not be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } query predicate invalidOverlap( - MemoryOperand useOperand, string message, IRFunction func, string funcText + MemoryOperand useOperand, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(Overlap overlap | overlap = useOperand.getDefinitionOverlap() and @@ -324,8 +478,20 @@ module InstructionConsistency { message = "MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" + overlap.toString() + "'." and - func = useOperand.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getOperandIRFunction(useOperand, irFuncText) + ) + } + + query predicate nonUniqueEnclosingIRFunction( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int irFuncCount | + irFuncCount = count(instr.getEnclosingIRFunction()) and + irFuncCount != 1 and + message = + "Instruction '" + instr.toString() + "' has " + irFuncCount.toString() + + " results for `getEnclosingIRFunction()` in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) ) } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll index 9aea3e00d666..5968e58f90bf 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll @@ -1,29 +1,17 @@ +/** + * Provides the class `IRFunction`, which represents the Intermediate Representation for the + * definition of a function. + */ + private import internal.IRInternal +private import internal.IRFunctionImports as Imports +import Imports::IRFunctionBase import Instruction -private newtype TIRFunction = - MkIRFunction(Language::Function func) { Construction::functionHasIR(func) } - /** - * Represents the IR for a function. + * The IR for a function. */ -class IRFunction extends TIRFunction { - Language::Function func; - - IRFunction() { this = MkIRFunction(func) } - - final string toString() { result = "IR: " + func.toString() } - - /** - * Gets the function whose IR is represented. - */ - final Language::Function getFunction() { result = func } - - /** - * Gets the location of the function. - */ - final Language::Location getLocation() { result = func.getLocation() } - +class IRFunction extends IRFunctionBase { /** * Gets the entry point for this function. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll index 9f2a0d4ea281..146fc2707383 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent variables accessed by the IR. + */ + private import internal.IRInternal import IRFunction private import internal.IRVariableImports as Imports @@ -7,15 +11,11 @@ private import Imports::TTempVariableTag private import Imports::TIRVariable private import Imports::IRType -IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { - result.getVariable() = var and - result.getEnclosingFunction() = func -} - /** - * A variable referenced by the IR for a function. The variable may be a user-declared variable - * (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation - * (`IRTempVariable`). + * A variable referenced by the IR for a function. + * + * The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated + * by the AST-to-IR translation (`IRTempVariable`). */ class IRVariable extends TIRVariable { Language::Function func; @@ -27,6 +27,7 @@ class IRVariable extends TIRVariable { this = TIRDynamicInitializationFlag(func, _, _) } + /** Gets a textual representation of this element. */ string toString() { none() } /** @@ -162,20 +163,30 @@ class IRGeneratedVariable extends IRVariable { override string getUniqueId() { none() } + /** + * INTERNAL: Do not use. + * + * Gets a string containing the source code location of the AST that generated this variable. + * + * This is used by debugging and printing code only. + */ final string getLocationString() { result = ast.getLocation().getStartLine().toString() + ":" + ast.getLocation().getStartColumn().toString() } + /** + * INTERNAL: Do not use. + * + * Gets the string that is combined with the location of the variable to generate the string + * representation of this variable. + * + * This is used by debugging and printing code only. + */ string getBaseString() { none() } } -IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { - result.getAST() = ast and - result.getTag() = tag -} - /** * A temporary variable introduced by IR construction. The most common examples are the variable * generated to hold the return value of a function, or the variable generated to hold the result of @@ -190,6 +201,10 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa result = "Temp: " + Construction::getTempVariableUniqueId(this) } + /** + * Gets the "tag" object that differentiates this temporary variable from other temporary + * variables generated for the same AST. + */ final TempVariableTag getTag() { result = tag } override string getBaseString() { result = "#temp" } @@ -217,19 +232,23 @@ class IRThrowVariable extends IRTempVariable { * A temporary variable generated to hold the contents of all arguments passed to the `...` of a * function that accepts a variable number of arguments. */ -class IREllipsisVariable extends IRTempVariable { +class IREllipsisVariable extends IRTempVariable, IRParameter { IREllipsisVariable() { tag = EllipsisTempVar() } final override string toString() { result = "#ellipsis" } + + final override int getIndex() { result = func.getNumberOfParameters() } } /** * A temporary variable generated to hold the `this` pointer. */ -class IRThisVariable extends IRTempVariable { +class IRThisVariable extends IRTempVariable, IRParameter { IRThisVariable() { tag = ThisTempVar() } final override string toString() { result = "#this" } + + final override int getIndex() { result = -1 } } /** @@ -249,6 +268,9 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { final override string getBaseString() { result = "#string" } + /** + * Gets the AST of the string literal represented by this `IRStringLiteral`. + */ final Language::StringLiteral getLiteral() { result = literal } } @@ -266,6 +288,9 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string toString() { result = var.toString() + "#init" } + /** + * Gets variable whose initialization is guarded by this flag. + */ final Language::Variable getVariable() { result = var } final override string getUniqueId() { @@ -274,3 +299,29 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string getBaseString() { result = "#init:" + var.toString() + ":" } } + +/** + * An IR variable which acts like a function parameter, including positional parameters and the + * temporary variables generated for `this` and ellipsis parameters. + */ +class IRParameter extends IRAutomaticVariable { + IRParameter() { + this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter + or + this = TIRTempVariable(_, _, ThisTempVar(), _) + or + this = TIRTempVariable(_, _, EllipsisTempVar(), _) + } + + /** + * Gets the zero-based index of this parameter. The `this` parameter has index -1. + */ + int getIndex() { none() } +} + +/** + * An IR variable representing a positional parameter. + */ +class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable { + final override int getIndex() { result = getVariable().(Language::Parameter).getIndex() } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 9c83a3d99f0c..620b23b942e0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the individual instructions in the IR for a function. + */ + private import internal.IRInternal import IRFunction import IRBlock @@ -27,9 +31,16 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil } /** - * Represents a single operation in the IR. + * A single instruction in the IR. */ -class Instruction extends Construction::TInstruction { +class Instruction extends Construction::TStageInstruction { + Instruction() { + // The base `TStageInstruction` type is a superset of the actual instructions appearing in this + // stage. This call lets the stage filter out the ones that are not reused from raw IR. + Construction::hasInstruction(this) + } + + /** Gets a textual representation of this element. */ final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } /** @@ -194,16 +205,25 @@ class Instruction extends Construction::TInstruction { * conversion. */ final Language::Expr getConvertedResultExpression() { - result = Construction::getInstructionConvertedResultExpression(this) + result = Raw::getInstructionConvertedResultExpression(this) } /** * Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any. */ final Language::Expr getUnconvertedResultExpression() { - result = Construction::getInstructionUnconvertedResultExpression(this) + result = Raw::getInstructionUnconvertedResultExpression(this) } + /** + * Gets the language-specific type of the result produced by this instruction. + * + * Most consumers of the IR should use `getResultIRType()` instead. `getResultIRType()` uses a + * less complex, language-neutral type system in which all semantically equivalent types share the + * same `IRType` instance. For example, in C++, four different `Instruction`s might have three + * different values for `getResultLanguageType()`: `unsigned int`, `char32_t`, and `wchar_t`, + * whereas all four instructions would have the same value for `getResultIRType()`, `uint4`. + */ final Language::LanguageType getResultLanguageType() { result = Construction::getInstructionResultType(this) } @@ -212,6 +232,7 @@ class Instruction extends Construction::TInstruction { * Gets the type of the result produced by this instruction. If the instruction does not produce * a result, its result type will be `IRVoidType`. */ + cached final IRType getResultIRType() { result = getResultLanguageType().getIRType() } /** @@ -240,17 +261,19 @@ class Instruction extends Construction::TInstruction { * given by `getResultType()`. * * For example, the statement `y = x;` generates the following IR: + * ``` * r1_0(glval: int) = VariableAddress[x] * r1_1(int) = Load r1_0, mu0_1 * r1_2(glval: int) = VariableAddress[y] * mu1_3(int) = Store r1_2, r1_1 + * ``` * * The result of each `VariableAddress` instruction is a glvalue of type * `int`, representing the address of the corresponding integer variable. The * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) } + final predicate isGLValue() { getResultLanguageType().hasType(_, true) } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -259,7 +282,7 @@ class Instruction extends Construction::TInstruction { * If `this.isGLValue()` holds for this instruction, the value of * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() } + final int getResultSize() { result = getResultLanguageType().getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. @@ -392,13 +415,27 @@ class Instruction extends Construction::TInstruction { final Instruction getAPredecessor() { result = getPredecessor(_) } } +/** + * An instruction that refers to a variable. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * variable. For example, it is used for `VariableAddress`, which returns the address of a specific + * variable, and `InitializeParameter`, which returns the value that was passed to the specified + * parameter by the caller. `VariableInstruction` is not used for `Load` or `Store` instructions + * that happen to load from or store to a particular variable; in those cases, the memory location + * being accessed is specified by the `AddressOperand` on the instruction, which may or may not be + * defined by the result of a `VariableAddress` instruction. + */ class VariableInstruction extends Instruction { IRVariable var; - VariableInstruction() { var = Construction::getInstructionVariable(this) } + VariableInstruction() { var = Raw::getInstructionVariable(this) } override string getImmediateString() { result = var.toString() } + /** + * Gets the variable that this instruction references. + */ final IRVariable getIRVariable() { result = var } /** @@ -407,63 +444,156 @@ class VariableInstruction extends Instruction { final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that refers to a field of a class, struct, or union. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * field. For example, it is used for `FieldAddress`, which computes the address of a specific + * field on an object. `FieldInstruction` is not used for `Load` or `Store` instructions that happen + * to load from or store to a particular field; in those cases, the memory location being accessed + * is specified by the `AddressOperand` on the instruction, which may or may not be defined by the + * result of a `FieldAddress` instruction. + */ class FieldInstruction extends Instruction { Language::Field field; - FieldInstruction() { field = Construction::getInstructionField(this) } + FieldInstruction() { field = Raw::getInstructionField(this) } final override string getImmediateString() { result = field.toString() } + /** + * Gets the field that this instruction references. + */ final Language::Field getField() { result = field } } +/** + * An instruction that refers to a function. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * function. For example, it is used for `FunctionAddress`, which returns the address of a specific + * function. `FunctionInstruction` is not used for `Call` instructions that happen to call a + * particular function; in that case, the function being called is specified by the + * `CallTargetOperand` on the instruction, which may or may not be defined by the result of a + * `FunctionAddress` instruction. + */ class FunctionInstruction extends Instruction { Language::Function funcSymbol; - FunctionInstruction() { funcSymbol = Construction::getInstructionFunction(this) } + FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) } final override string getImmediateString() { result = funcSymbol.toString() } + /** + * Gets the function that this instruction references. + */ final Language::Function getFunctionSymbol() { result = funcSymbol } } +/** + * An instruction whose result is a compile-time constant value. + */ class ConstantValueInstruction extends Instruction { string value; - ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) } + ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) } final override string getImmediateString() { result = value } + /** + * Gets the constant value of this instruction's result. + */ final string getValue() { result = value } } +/** + * An instruction that refers to an argument of a `Call` instruction. + * + * This instruction is used for side effects of a `Call` instruction that read or write memory + * pointed to by one of the arguments of the call. + */ class IndexedInstruction extends Instruction { int index; - IndexedInstruction() { index = Construction::getInstructionIndex(this) } + IndexedInstruction() { index = Raw::getInstructionIndex(this) } final override string getImmediateString() { result = index.toString() } + /** + * Gets the zero-based index of the argument that this instruction references. + */ final int getIndex() { result = index } } +/** + * An instruction representing the entry point to a function. + * + * Each `IRFunction` has exactly one `EnterFunction` instruction. Execution of the function begins + * at this instruction. This instruction has no predecessors. + */ class EnterFunctionInstruction extends Instruction { EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction } } +/** + * An instruction that returns the address of a variable. + * + * This instruction returns the address of a local variable, parameter, static field, + * namespace-scope variable, or global variable. For the address of a non-static field of a class, + * struct, or union, see `FieldAddressInstruction`. + */ class VariableAddressInstruction extends VariableInstruction { VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } } +/** + * An instruction that returns the address of a function. + * + * This instruction returns the address of a function, including non-member functions, static member + * functions, and non-static member functions. + * + * The result has an `IRFunctionAddress` type. + */ +class FunctionAddressInstruction extends FunctionInstruction { + FunctionAddressInstruction() { getOpcode() instanceof Opcode::FunctionAddress } +} + +/** + * An instruction that initializes a parameter of the enclosing function with the value of the + * corresponding argument passed by the caller. + * + * Each parameter of a function will have exactly one `InitializeParameter` instruction that + * initializes that parameter. + */ class InitializeParameterInstruction extends VariableInstruction { InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that initializes all memory that existed before this function was called. + * + * This instruction provides a definition for memory that, because it was actually allocated and + * initialized elsewhere, would not otherwise have a definition in this function. + */ +class InitializeNonLocalInstruction extends Instruction { + InitializeNonLocalInstruction() { getOpcode() instanceof Opcode::InitializeNonLocal } +} + +/** + * An instruction that initializes the memory pointed to by a parameter of the enclosing function + * with the value of that memory on entry to the function. + */ class InitializeIndirectionInstruction extends VariableInstruction { InitializeIndirectionInstruction() { getOpcode() instanceof Opcode::InitializeIndirection } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } @@ -474,14 +604,42 @@ class InitializeThisInstruction extends Instruction { InitializeThisInstruction() { getOpcode() instanceof Opcode::InitializeThis } } +/** + * An instruction that computes the address of a non-static field of an object. + */ class FieldAddressInstruction extends FieldInstruction { FieldAddressInstruction() { getOpcode() instanceof Opcode::FieldAddress } + /** + * Gets the operand that provides the address of the object containing the field. + */ final UnaryOperand getObjectAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the object containing the field. + */ final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } } +/** + * An instruction that computes the address of the first element of a managed array. + * + * This instruction is used for element access to C# arrays. + */ +class ElementsAddressInstruction extends UnaryInstruction { + ElementsAddressInstruction() { getOpcode() instanceof Opcode::ElementsAddress } + + /** + * Gets the operand that provides the address of the array object. + */ + final UnaryOperand getArrayObjectAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the array object. + */ + final Instruction getArrayObjectAddress() { result = getArrayObjectAddressOperand().getDef() } +} + /** * An instruction that produces a well-defined but unknown result and has * unknown side effects, including side effects that are not conservatively @@ -496,6 +654,12 @@ class ErrorInstruction extends Instruction { ErrorInstruction() { getOpcode() instanceof Opcode::Error } } +/** + * An instruction that returns an uninitialized value. + * + * This instruction is used to provide an initial definition for a stack variable that does not have + * an initializer, or whose initializer only partially initializes the variable. + */ class UninitializedInstruction extends VariableInstruction { UninitializedInstruction() { getOpcode() instanceof Opcode::Uninitialized } @@ -505,35 +669,94 @@ class UninitializedInstruction extends VariableInstruction { final Language::Variable getLocalVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that has no effect. + * + * This instruction is typically inserted to ensure that a particular AST is associated with at + * least one instruction, even when the AST has no semantic effect. + */ class NoOpInstruction extends Instruction { NoOpInstruction() { getOpcode() instanceof Opcode::NoOp } } +/** + * An instruction that returns control to the caller of the function. + * + * This instruction represents the normal (non-exception) return from a function, either from an + * explicit `return` statement or from control flow reaching the end of the function's body. + * + * Each function has exactly one `ReturnInstruction`. Each `return` statement in a function is + * represented as an initialization of the temporary variable that holds the return value, with + * control then flowing to the common `ReturnInstruction` for that function. Exception: A function + * that never returns will not have a `ReturnInstruction`. + * + * The `ReturnInstruction` for a function will have a control-flow successor edge to a block + * containing the `ExitFunction` instruction for that function. + * + * There are two differet return instructions: `ReturnValueInstruction`, for returning a value from + * a non-`void`-returning function, and `ReturnVoidInstruction`, for returning from a + * `void`-returning function. + */ class ReturnInstruction extends Instruction { ReturnInstruction() { getOpcode() instanceof ReturnOpcode } } +/** + * An instruction that returns control to the caller of the function, without returning a value. + */ class ReturnVoidInstruction extends ReturnInstruction { ReturnVoidInstruction() { getOpcode() instanceof Opcode::ReturnVoid } } +/** + * An instruction that returns control to the caller of the function, including a return value. + */ class ReturnValueInstruction extends ReturnInstruction { ReturnValueInstruction() { getOpcode() instanceof Opcode::ReturnValue } + /** + * Gets the operand that provides the value being returned by the function. + */ final LoadOperand getReturnValueOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value being returned by the function, if an + * exact definition is available. + */ final Instruction getReturnValue() { result = getReturnValueOperand().getDef() } } +/** + * An instruction that represents the use of the value pointed to by a parameter of the function + * after the function returns control to its caller. + * + * This instruction does not itself return control to the caller. It merely represents the potential + * for a caller to use the memory pointed to by the parameter sometime after the call returns. This + * is the counterpart to the `InitializeIndirection` instruction, which represents the possibility + * that the caller initialized the memory pointed to by the parameter before the call. + */ class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } + /** + * Gets the operand that provides the value of the pointed-to memory. + */ final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the pointed-to memory, if an exact + * definition is available. + */ final Instruction getSideEffect() { result = getSideEffectOperand().getDef() } + /** + * Gets the operand that provides the address of the pointed-to memory. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the pointed-to memory. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } /** @@ -541,87 +764,191 @@ class ReturnIndirectionInstruction extends VariableInstruction { * function. */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } + + /** + * Holds if this instruction is the return indirection for `this`. + */ + final predicate isThisIndirection() { var instanceof IRThisVariable } } +/** + * An instruction that returns a copy of its operand. + * + * There are several different copy instructions, depending on the source and destination of the + * copy operation: + * - `CopyInstruction` - Copies a register operand to a register result. + * - `LoadInstruction` - Copies a memory operand to a register result. + * - `StoreInstruction` - Copies a register operand to a memory result. + */ class CopyInstruction extends Instruction { CopyInstruction() { getOpcode() instanceof CopyOpcode } + /** + * Gets the operand that provides the input value of the copy. + */ Operand getSourceValueOperand() { none() } + /** + * Gets the instruction whose result provides the input value of the copy, if an exact definition + * is available. + */ final Instruction getSourceValue() { result = getSourceValueOperand().getDef() } } +/** + * An instruction that returns a register result containing a copy of its register operand. + */ class CopyValueInstruction extends CopyInstruction, UnaryInstruction { CopyValueInstruction() { getOpcode() instanceof Opcode::CopyValue } final override UnaryOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a register result containing a copy of its memory operand. + */ class LoadInstruction extends CopyInstruction { LoadInstruction() { getOpcode() instanceof Opcode::Load } + /** + * Gets the operand that provides the address of the value being loaded. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the value being loaded. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } final override LoadOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a memory result containing a copy of its register operand. + */ class StoreInstruction extends CopyInstruction { StoreInstruction() { getOpcode() instanceof Opcode::Store } + /** + * Gets the operand that provides the address of the location to which the value will be stored. + */ final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the location to which the value will + * be stored, if an exact definition is available. + */ final Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } final override StoreValueOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that branches to one of two successor instructions based on the value of a Boolean + * operand. + */ class ConditionalBranchInstruction extends Instruction { ConditionalBranchInstruction() { getOpcode() instanceof Opcode::ConditionalBranch } + /** + * Gets the operand that provides the Boolean condition controlling the branch. + */ final ConditionOperand getConditionOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the Boolean condition controlling the branch. + */ final Instruction getCondition() { result = getConditionOperand().getDef() } + /** + * Gets the instruction to which control will flow if the condition is true. + */ final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } + /** + * Gets the instruction to which control will flow if the condition is false. + */ final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } } +/** + * An instruction representing the exit point of a function. + * + * Each `IRFunction` has exactly one `ExitFunction` instruction, unless the function neither returns + * nor throws an exception. Control flows to the `ExitFunction` instruction from both normal returns + * (`ReturnVoid`, `ReturnValue`) and propagated exceptions (`Unwind`). This instruction has no + * successors. + */ class ExitFunctionInstruction extends Instruction { ExitFunctionInstruction() { getOpcode() instanceof Opcode::ExitFunction } } +/** + * An instruction whose result is a constant value. + */ class ConstantInstruction extends ConstantValueInstruction { ConstantInstruction() { getOpcode() instanceof Opcode::Constant } } +/** + * An instruction whose result is a constant value of integer or Boolean type. + */ class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType } + IntegerConstantInstruction() { + exists(IRType resultType | + resultType = getResultIRType() and + (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType) + ) + } } +/** + * An instruction whose result is a constant value of floating-point type. + */ class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } + FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } +/** + * An instruction whose result is the address of a string literal. + */ class StringConstantInstruction extends VariableInstruction { override IRStringLiteral var; final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) } + /** + * Gets the string literal whose address is returned by this instruction. + */ final Language::StringLiteral getValue() { result = var.getLiteral() } } +/** + * An instruction whose result is computed from two operands. + */ class BinaryInstruction extends Instruction { BinaryInstruction() { getOpcode() instanceof BinaryOpcode } + /** + * Gets the left operand of this binary instruction. + */ final LeftOperand getLeftOperand() { result = getAnOperand() } + /** + * Gets the right operand of this binary instruction. + */ final RightOperand getRightOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the left operand of this binary + * instruction. + */ final Instruction getLeft() { result = getLeftOperand().getDef() } + /** + * Gets the instruction whose result provides the value of the right operand of this binary + * instruction. + */ final Instruction getRight() { result = getRightOperand().getDef() } /** @@ -634,121 +961,301 @@ class BinaryInstruction extends Instruction { } } +/** + * An instruction that computes the result of an arithmetic operation. + */ class ArithmeticInstruction extends Instruction { ArithmeticInstruction() { getOpcode() instanceof ArithmeticOpcode } } +/** + * An instruction that performs an arithmetic operation on two numeric operands. + */ class BinaryArithmeticInstruction extends ArithmeticInstruction, BinaryInstruction { } +/** + * An instruction whose result is computed by performing an arithmetic operation on a single + * numeric operand. + */ class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction { } +/** + * An instruction that computes the sum of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point addition is + * performed according to IEEE-754. + */ class AddInstruction extends BinaryArithmeticInstruction { AddInstruction() { getOpcode() instanceof Opcode::Add } } +/** + * An instruction that computes the difference of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point subtraction is performed + * according to IEEE-754. + */ class SubInstruction extends BinaryArithmeticInstruction { SubInstruction() { getOpcode() instanceof Opcode::Sub } } +/** + * An instruction that computes the product of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point multiplication is + * performed according to IEEE-754. + */ class MulInstruction extends BinaryArithmeticInstruction { MulInstruction() { getOpcode() instanceof Opcode::Mul } } +/** + * An instruction that computes the quotient of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. Floating-point division is performed according + * to IEEE-754. + */ class DivInstruction extends BinaryArithmeticInstruction { DivInstruction() { getOpcode() instanceof Opcode::Div } } +/** + * An instruction that computes the remainder of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. + */ class RemInstruction extends BinaryArithmeticInstruction { RemInstruction() { getOpcode() instanceof Opcode::Rem } } +/** + * An instruction that negates a single numeric operand. + * + * The operand must have a numeric type, which will also be the result type. The result of integer + * negation uses two's complement, and is computed modulo 2^n. The result of floating-point negation + * is performed according to IEEE-754. + */ class NegateInstruction extends UnaryArithmeticInstruction { NegateInstruction() { getOpcode() instanceof Opcode::Negate } } +/** + * An instruction that computes the result of a bitwise operation. + */ class BitwiseInstruction extends Instruction { BitwiseInstruction() { getOpcode() instanceof BitwiseOpcode } } +/** + * An instruction that performs a bitwise operation on two integer operands. + */ class BinaryBitwiseInstruction extends BitwiseInstruction, BinaryInstruction { } +/** + * An instruction that performs a bitwise operation on a single integer operand. + */ class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } +/** + * An instruction that computes the bitwise "and" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitAndInstruction extends BinaryBitwiseInstruction { BitAndInstruction() { getOpcode() instanceof Opcode::BitAnd } } +/** + * An instruction that computes the bitwise "or" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitOrInstruction extends BinaryBitwiseInstruction { BitOrInstruction() { getOpcode() instanceof Opcode::BitOr } } +/** + * An instruction that computes the bitwise "xor" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitXorInstruction extends BinaryBitwiseInstruction { BitXorInstruction() { getOpcode() instanceof Opcode::BitXor } } +/** + * An instruction that shifts its left operand to the left by the number of bits specified by its + * right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. The + * rightmost bits are zero-filled. + */ class ShiftLeftInstruction extends BinaryBitwiseInstruction { ShiftLeftInstruction() { getOpcode() instanceof Opcode::ShiftLeft } } +/** + * An instruction that shifts its left operand to the right by the number of bits specified by its + * right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. If the + * left operand has an unsigned integer type, the leftmost bits are zero-filled. If the left operand + * has a signed integer type, the leftmost bits are filled by duplicating the most significant bit + * of the left operand. + */ class ShiftRightInstruction extends BinaryBitwiseInstruction { ShiftRightInstruction() { getOpcode() instanceof Opcode::ShiftRight } } +/** + * An instruction that performs a binary arithmetic operation involving at least one pointer + * operand. + */ class PointerArithmeticInstruction extends BinaryInstruction { int elementSize; PointerArithmeticInstruction() { getOpcode() instanceof PointerArithmeticOpcode and - elementSize = Construction::getInstructionElementSize(this) + elementSize = Raw::getInstructionElementSize(this) } final override string getImmediateString() { result = elementSize.toString() } + /** + * Gets the size of the elements pointed to by the pointer operands, in bytes. + * + * When adding an integer offset to a pointer (`PointerAddInstruction`) or subtracting an integer + * offset from a pointer (`PointerSubInstruction`), the integer offset is multiplied by the + * element size to compute the actual number of bytes added to or subtracted from the pointer + * address. When computing the integer difference between two pointers (`PointerDiffInstruction`), + * the result is computed by computing the difference between the two pointer byte addresses, then + * dividing that byte count by the element size. + */ final int getElementSize() { result = elementSize } } +/** + * An instruction that adds or subtracts an integer offset from a pointer. + */ class PointerOffsetInstruction extends PointerArithmeticInstruction { PointerOffsetInstruction() { getOpcode() instanceof PointerOffsetOpcode } } +/** + * An instruction that adds an integer offset to a pointer. + * + * The result is the byte address computed by adding the value of the right (integer) operand, + * multiplied by the element size, to the value of the left (pointer) operand. The result of pointer + * overflow is undefined. + */ class PointerAddInstruction extends PointerOffsetInstruction { PointerAddInstruction() { getOpcode() instanceof Opcode::PointerAdd } } +/** + * An instruction that subtracts an integer offset from a pointer. + * + * The result is the byte address computed by subtracting the value of the right (integer) operand, + * multiplied by the element size, from the value of the left (pointer) operand. The result of + * pointer underflow is undefined. + */ class PointerSubInstruction extends PointerOffsetInstruction { PointerSubInstruction() { getOpcode() instanceof Opcode::PointerSub } } +/** + * An instruction that computes the difference between two pointers. + * + * Both operands must have the same pointer type. The result must have an integer type whose size is + * the same as that of the pointer operands. The result is computed by subtracting the byte address + * in the right operand from the byte address in the left operand, and dividing by the element size. + * If the difference in byte addresses is not divisible by the element size, the result is + * undefined. + */ class PointerDiffInstruction extends PointerArithmeticInstruction { PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff } } +/** + * An instruction whose result is computed from a single operand. + */ class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } + /** + * Gets the sole operand of this instruction. + */ final UnaryOperand getUnaryOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the sole operand of this instruction. + */ final Instruction getUnary() { result = getUnaryOperand().getDef() } } +/** + * An instruction that converts the value of its operand to a value of a different type. + */ class ConvertInstruction extends UnaryInstruction { ConvertInstruction() { getOpcode() instanceof Opcode::Convert } } +/** + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, returning a null address if the dynamic type of the + * object is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a pointer type, or a C# `is` or + * `as` expression. + */ class CheckedConvertOrNullInstruction extends UnaryInstruction { CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull } } /** - * Represents an instruction that converts between two addresses - * related by inheritance. + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, throwing an exception if the dynamic type of the object + * is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a reference type, or a C# cast + * expression. + */ +class CheckedConvertOrThrowInstruction extends UnaryInstruction { + CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } +} + +/** + * An instruction that returns the address of the complete object that contains the subobject + * pointed to by its operand. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent `dyanmic_cast` in C++, which returns the pointer to + * the most-derived object. + */ +class CompleteObjectAddressInstruction extends UnaryInstruction { + CompleteObjectAddressInstruction() { getOpcode() instanceof Opcode::CompleteObjectAddress } +} + +/** + * An instruction that converts the address of an object to the address of a different subobject of + * the same object, without any type checking at runtime. */ class InheritanceConversionInstruction extends UnaryInstruction { Language::Class baseClass; Language::Class derivedClass; InheritanceConversionInstruction() { - Construction::getInstructionInheritance(this, baseClass, derivedClass) + Raw::getInstructionInheritance(this, baseClass, derivedClass) } final override string getImmediateString() { @@ -778,59 +1285,91 @@ class InheritanceConversionInstruction extends UnaryInstruction { } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a base class. + * An instruction that converts from the address of a derived class to the address of a base class. */ class ConvertToBaseInstruction extends InheritanceConversionInstruction { ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a direct non-virtual base class. + * An instruction that converts from the address of a derived class to the address of a direct + * non-virtual base class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToNonVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToNonVirtualBase } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a virtual base class. + * An instruction that converts from the address of a derived class to the address of a virtual base + * class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToVirtualBase } } /** - * Represents an instruction that converts from the address of a base class - * to the address of a direct non-virtual derived class. + * An instruction that converts from the address of a base class to the address of a direct + * non-virtual derived class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToDerivedInstruction extends InheritanceConversionInstruction { ConvertToDerivedInstruction() { getOpcode() instanceof Opcode::ConvertToDerived } } +/** + * An instruction that computes the bitwise complement of its operand. + * + * The operand must have an integer type, which will also be the result type. + */ class BitComplementInstruction extends UnaryBitwiseInstruction { BitComplementInstruction() { getOpcode() instanceof Opcode::BitComplement } } +/** + * An instruction that computes the logical complement of its operand. + * + * The operand must have a Boolean type, which will also be the result type. + */ class LogicalNotInstruction extends UnaryInstruction { LogicalNotInstruction() { getOpcode() instanceof Opcode::LogicalNot } } +/** + * An instruction that compares two numeric operands. + */ class CompareInstruction extends BinaryInstruction { CompareInstruction() { getOpcode() instanceof CompareOpcode } } +/** + * An instruction that returns a `true` result if its operands are equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left == right`, and `false` if `left != right` or the two operands are + * unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareEQInstruction extends CompareInstruction { CompareEQInstruction() { getOpcode() instanceof Opcode::CompareEQ } } +/** + * An instruction that returns a `true` result if its operands are not equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left != right` or if the two operands are unordered, and `false` if + * `left == right`. Floating-point comparison is performed according to IEEE-754. + */ class CompareNEInstruction extends CompareInstruction { CompareNEInstruction() { getOpcode() instanceof Opcode::CompareNE } } /** - * Represents an instruction that does a relative comparison of two values, such as `<` or `>=`. + * An instruction that does a relative comparison of two values, such as `<` or `>=`. */ class RelationalInstruction extends CompareInstruction { RelationalInstruction() { getOpcode() instanceof RelationalOpcode } @@ -857,6 +1396,13 @@ class RelationalInstruction extends CompareInstruction { predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is less than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left < right`, and `false` if `left >= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLTInstruction extends RelationalInstruction { CompareLTInstruction() { getOpcode() instanceof Opcode::CompareLT } @@ -867,6 +1413,13 @@ class CompareLTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is greater than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left > right`, and `false` if `left <= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGTInstruction extends RelationalInstruction { CompareGTInstruction() { getOpcode() instanceof Opcode::CompareGT } @@ -877,6 +1430,14 @@ class CompareGTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is less than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left <= right`, and `false` if `left > right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLEInstruction extends RelationalInstruction { CompareLEInstruction() { getOpcode() instanceof Opcode::CompareLE } @@ -887,6 +1448,14 @@ class CompareLEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is greater than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left >= right`, and `false` if `left < right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGEInstruction extends RelationalInstruction { CompareGEInstruction() { getOpcode() instanceof Opcode::CompareGE } @@ -897,15 +1466,32 @@ class CompareGEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that branches to one of multiple successor instructions based on the value of an + * integer operand. + * + * This instruction will have zero or more successors whose edge kind is `CaseEdge`, each + * representing the branch that will be taken if the controlling expression is within the range + * specified for that case edge. The range of a case edge must be disjoint from the range of each + * other case edge. + * + * The instruction may optionally have a successor edge whose edge kind is `DefaultEdge`, + * representing the branch that will be taken if the controlling expression is not within the range + * of any case edge. + */ class SwitchInstruction extends Instruction { SwitchInstruction() { getOpcode() instanceof Opcode::Switch } + /** Gets the operand that provides the integer value controlling the switch. */ final ConditionOperand getExpressionOperand() { result = getAnOperand() } + /** Gets the instruction whose result provides the integer value controlling the switch. */ final Instruction getExpression() { result = getExpressionOperand().getDef() } + /** Gets the successor instructions along the case edges of the switch. */ final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } + /** Gets the successor instruction along the default edge of the switch, if any. */ final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } } @@ -936,7 +1522,7 @@ class CallInstruction extends Instruction { * Gets the `Function` that the call targets, if this is statically known. */ final Language::Function getStaticCallTarget() { - result = getCallTarget().(FunctionInstruction).getFunctionSymbol() + result = getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() } /** @@ -981,6 +1567,9 @@ class CallInstruction extends Instruction { class SideEffectInstruction extends Instruction { SideEffectInstruction() { getOpcode() instanceof SideEffectOpcode } + /** + * Gets the instruction whose execution causes this side effect. + */ final Instruction getPrimaryInstruction() { result = Construction::getPrimaryInstructionForSideEffect(this) } @@ -996,9 +1585,10 @@ class CallSideEffectInstruction extends SideEffectInstruction { /** * An instruction representing the side effect of a function call on any memory - * that might be read by that call. This instruction is emitted instead of - * `CallSideEffectInstruction` when it's certain that the call target cannot - * write to escaped memory. + * that might be read by that call. + * + * This instruction is emitted instead of `CallSideEffectInstruction` when it is certain that the + * call target cannot write to escaped memory. */ class CallReadSideEffectInstruction extends SideEffectInstruction { CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect } @@ -1046,7 +1636,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { getOpcode() instanceof Opcode::SizedBufferReadSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes read from the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes read from the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1056,7 +1654,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } + /** + * Get the operand that holds the address of the memory to be written. + */ + final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the memory to be written. + */ + Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } } /** @@ -1087,11 +1693,20 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** * An instruction representing the potential write of an indirect parameter within a function call. + * * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. * written. */ @@ -1103,6 +1718,7 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1111,6 +1727,7 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1118,11 +1735,19 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** - * An instruction representing the initial value of newly allocated memory, e.g. the result of a + * An instruction representing the initial value of newly allocated memory, such as the result of a * call to `malloc`. */ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { @@ -1211,7 +1836,7 @@ class CatchByTypeInstruction extends CatchInstruction { CatchByTypeInstruction() { getOpcode() instanceof Opcode::CatchByType and - exceptionType = Construction::getInstructionExceptionType(this) + exceptionType = Raw::getInstructionExceptionType(this) } final override string getImmediateString() { result = exceptionType.toString() } @@ -1337,29 +1962,43 @@ class ChiInstruction extends Instruction { * Gets the operand that represents the new value written by the memory write. */ final Instruction getPartial() { result = getPartialOperand().getDef() } + + /** + * Gets the bit range `[startBit, endBit)` updated by the partial operand of this `ChiInstruction`, relative to the start address of the total operand. + */ + final predicate getUpdatedInterval(int startBit, int endBit) { + Construction::getIntervalUpdatedByChi(this, startBit, endBit) + } } /** - * An instruction representing unreachable code. Inserted in place of the original target - * instruction of a `ConditionalBranch` or `Switch` instruction where that particular edge is - * infeasible. + * An instruction representing unreachable code. + * + * This instruction is inserted in place of the original target instruction of a `ConditionalBranch` + * or `Switch` instruction where that particular edge is infeasible. */ class UnreachedInstruction extends Instruction { UnreachedInstruction() { getOpcode() instanceof Opcode::Unreached } } /** - * An instruction representing a built-in operation. This is used to represent - * operations such as access to variable argument lists. + * An instruction representing a built-in operation. + * + * This is used to represent a variety of intrinsic operations provided by the compiler + * implementation, such as vector arithmetic. */ class BuiltInOperationInstruction extends Instruction { Language::BuiltInOperation operation; BuiltInOperationInstruction() { getOpcode() instanceof BuiltInOperationOpcode and - operation = Construction::getInstructionBuiltInOperation(this) + operation = Raw::getInstructionBuiltInOperation(this) } + /** + * Gets the language-specific `BuiltInOperation` object that specifies the operation that is + * performed by this instruction. + */ final Language::BuiltInOperation getBuiltInOperation() { result = operation } } @@ -1372,3 +2011,59 @@ class BuiltInInstruction extends BuiltInOperationInstruction { final override string getImmediateString() { result = getBuiltInOperation().toString() } } + +/** + * An instruction that returns a `va_list` to access the arguments passed to the `...` parameter. + * + * The operand specifies the address of the `IREllipsisVariable` used to represent the `...` + * parameter. The result is a `va_list` that initially refers to the first argument that was passed + * to the `...` parameter. + */ +class VarArgsStartInstruction extends UnaryInstruction { + VarArgsStartInstruction() { getOpcode() instanceof Opcode::VarArgsStart } +} + +/** + * An instruction that cleans up a `va_list` after it is no longer in use. + * + * The operand specifies the address of the `va_list` to clean up. This instruction does not return + * a result. + */ +class VarArgsEndInstruction extends UnaryInstruction { + VarArgsEndInstruction() { getOpcode() instanceof Opcode::VarArgsEnd } +} + +/** + * An instruction that returns the address of the argument currently pointed to by a `va_list`. + * + * The operand is the `va_list` that points to the argument. The result is the address of the + * argument. + */ +class VarArgInstruction extends UnaryInstruction { + VarArgInstruction() { getOpcode() instanceof Opcode::VarArg } +} + +/** + * An instruction that modifies a `va_list` to point to the next argument that was passed to the + * `...` parameter. + * + * The operand is the current `va_list`. The result is an updated `va_list` that points to the next + * argument of the `...` parameter. + */ +class NextVarArgInstruction extends UnaryInstruction { + NextVarArgInstruction() { getOpcode() instanceof Opcode::NextVarArg } +} + +/** + * An instruction that allocates a new object on the managed heap. + * + * This instruction is used to represent the allocation of a new object in C# using the `new` + * expression. This instruction does not invoke a constructor for the object. Instead, there will be + * a subsequent `Call` instruction to invoke the appropriate constructor directory, passing the + * result of the `NewObj` as the `this` argument. + * + * The result is the address of the newly allocated object. + */ +class NewObjInstruction extends Instruction { + NewObjInstruction() { getOpcode() instanceof Opcode::NewObj } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll index f82704094c8e..a12e35d471b8 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the input values of IR instructions. + */ + private import internal.IRInternal private import Instruction private import IRBlock @@ -75,13 +79,21 @@ private PhiOperandBase phiOperand( } /** - * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. + * An operand of an `Instruction`. The operand represents a use of the result of one instruction + * (the defining instruction) in another instruction (the use instruction) */ class Operand extends TOperand { + /** Gets a textual representation of this element. */ string toString() { result = "Operand" } + /** + * Gets the location of the source code for this operand. + */ final Language::Location getLocation() { result = getUse().getLocation() } + /** + * Gets the function that contains this operand. + */ final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() } /** @@ -139,6 +151,11 @@ class Operand extends TOperand { */ string getDumpLabel() { result = "" } + /** + * Gets a string that uniquely identifies this operand on its use instruction. + */ + string getDumpId() { result = "" } + /** * Gets a string describing this operand, suitable for display in IR dumps. This consists of the * result ID of the instruction consumed by the operand, plus a label identifying the operand @@ -268,8 +285,13 @@ class NonPhiOperand extends Operand { final override string getDumpLabel() { result = tag.getLabel() } + final override string getDumpId() { result = tag.getId() } + final override int getDumpSortOrder() { result = tag.getSortOrder() } + /** + * Gets the `OperandTag` that specifies how this operand is used by its `Instruction`. + */ final OperandTag getOperandTag() { result = tag } } @@ -292,6 +314,9 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { } } +/** + * A memory operand other than the operand of a `Phi` instruction. + */ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; @@ -311,8 +336,19 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper not Construction::isInCycle(useInstr) and strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 } + + /** + * Holds if the operand totally overlaps with its definition and consumes the + * bit range `[startBitOffset, endBitOffset)` relative to the start address of the definition. + */ + predicate getUsedInterval(int startBitOffset, int endBitOffset) { + Construction::getUsedInterval(this, startBitOffset, endBitOffset) + } } +/** + * A memory operand whose type may be different from the type of the result of its definition. + */ class TypedOperand extends NonPhiMemoryOperand { override TypedOperandTag tag; @@ -416,6 +452,9 @@ class PositionalArgumentOperand extends ArgumentOperand { final int getIndex() { result = tag.getArgIndex() } } +/** + * An operand representing memory read as a side effect of evaluating another instruction. + */ class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; } @@ -445,6 +484,8 @@ class PhiInputOperand extends MemoryOperand, PhiOperandBase { result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":" } + final override string getDumpId() { result = getPredecessorBlock().getDisplayIndex().toString() } + /** * Gets the predecessor block from which this value comes. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll index d9c0df44e12e..59dadee71545 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll @@ -1,3 +1,13 @@ +/** + * Outputs a representation of the IR as a control flow graph. + * + * This file contains the actual implementation of `PrintIR.ql`. For test cases and very small + * databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintIR.qll`, extends + * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to + * dump. + */ + private import internal.IRInternal private import IR private import internal.PrintIRImports as Imports @@ -9,6 +19,7 @@ private newtype TPrintIRConfiguration = MkPrintIRConfiguration() * The query can extend this class to control which functions are printed. */ class PrintIRConfiguration extends TPrintIRConfiguration { + /** Gets a textual representation of this configuration. */ string toString() { result = "PrintIRConfiguration" } /** @@ -39,6 +50,37 @@ private string getAdditionalBlockProperty(IRBlock block, string key) { exists(IRPropertyProvider provider | result = provider.getBlockProperty(block, key)) } +/** + * Gets the properties of an operand from any active property providers. + */ +private string getAdditionalOperandProperty(Operand operand, string key) { + exists(IRPropertyProvider provider | result = provider.getOperandProperty(operand, key)) +} + +/** + * Gets a string listing the properties of the operand and their corresponding values. If the + * operand has no properties, this predicate has no result. + */ +private string getOperandPropertyListString(Operand operand) { + result = + strictconcat(string key, string value | + value = getAdditionalOperandProperty(operand, key) + | + key + ":" + value, ", " + ) +} + +/** + * Gets a string listing the properties of the operand and their corresponding values. The list is + * surrounded by curly braces. If the operand has no properties, this predicate returns an empty + * string. + */ +private string getOperandPropertyString(Operand operand) { + result = "{" + getOperandPropertyListString(operand) + "}" + or + not exists(getOperandPropertyListString(operand)) and result = "" +} + private newtype TPrintableIRNode = TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or @@ -47,7 +89,7 @@ private newtype TPrintableIRNode = /** * A node to be emitted in the IR graph. */ -abstract class PrintableIRNode extends TPrintableIRNode { +abstract private class PrintableIRNode extends TPrintableIRNode { abstract string toString(); /** @@ -98,7 +140,7 @@ abstract class PrintableIRNode extends TPrintableIRNode { /** * An IR graph node representing a `IRFunction` object. */ -class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { +private class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { IRFunction irFunc; PrintableIRFunction() { this = TPrintableIRFunction(irFunc) } @@ -129,7 +171,7 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { /** * An IR graph node representing an `IRBlock` object. */ -class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { +private class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { IRBlock block; PrintableIRBlock() { this = TPrintableIRBlock(block) } @@ -161,7 +203,7 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { /** * An IR graph node representing an `Instruction`. */ -class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { +private class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { Instruction instr; PrintableInstruction() { this = TPrintableInstruction(instr) } @@ -179,7 +221,7 @@ class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { | resultString = instr.getResultString() and operationString = instr.getOperationString() and - operandsString = instr.getOperandsString() and + operandsString = getOperandsString() and columnWidths(block, resultWidth, operationWidth) and result = resultString + getPaddingString(resultWidth - resultString.length()) + " = " + @@ -199,6 +241,22 @@ class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { result = PrintableIRNode.super.getProperty(key) or result = getAdditionalInstructionProperty(instr, key) } + + /** + * Gets the string representation of the operand list. This is the same as + * `Instruction::getOperandsString()`, except that each operand is annotated with any properties + * provided by active `IRPropertyProvider` instances. + */ + private string getOperandsString() { + result = + concat(Operand operand | + operand = instr.getAnOperand() + | + operand.getDumpString() + getOperandPropertyString(operand), ", " + order by + operand.getDumpSortOrder() + ) + } } private predicate columnWidths(IRBlock block, int resultWidth, int operationWidth) { @@ -224,6 +282,9 @@ private string getPaddingString(int n) { n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " " } +/** + * Holds if `node` belongs to the output graph, and its property `key` has the given `value`. + */ query predicate nodes(PrintableIRNode node, string key, string value) { value = node.getProperty(key) } @@ -237,6 +298,10 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) { ) } +/** + * Holds if the output graph contains an edge from `pred` to `succ`, and that edge's property `key` + * has the given `value`. + */ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | predBlock = pred.getBlock() and @@ -256,6 +321,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, ) } +/** + * Holds if `parent` is the parent node of `child` in the output graph. + */ query predicate parents(PrintableIRNode child, PrintableIRNode parent) { parent = child.getParent() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll index 1612e0065b77..19fb0490f808 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll @@ -196,16 +196,17 @@ private predicate operandReturned(Operand operand, IntValue bitOffset) { bitOffset = Ints::unknown() } -private predicate isArgumentForParameter(CallInstruction ci, Operand operand, Instruction init) { +private predicate isArgumentForParameter( + CallInstruction ci, Operand operand, InitializeParameterInstruction init +) { exists(Language::Function f | ci = operand.getUse() and f = ci.getStaticCallTarget() and ( - init.(InitializeParameterInstruction).getParameter() = - f.getParameter(operand.(PositionalArgumentOperand).getIndex()) + init.getParameter() = f.getParameter(operand.(PositionalArgumentOperand).getIndex()) or - init.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable and - init.getEnclosingFunction() = f and + init.getIRVariable() instanceof IRThisVariable and + unique( | | init.getEnclosingFunction()) = f and operand instanceof ThisArgumentOperand ) and not Language::isFunctionVirtual(f) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasedSSA.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasedSSA.qll index 9cd0384f924c..1e034051f05e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasedSSA.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasedSSA.qll @@ -133,6 +133,12 @@ abstract class MemoryLocation extends TMemoryLocation { predicate isAlwaysAllocatedOnStack() { none() } } +/** + * Represents a set of `MemoryLocation`s that cannot overlap with + * `MemoryLocation`s outside of the set. The `VirtualVariable` will be + * represented by a `MemoryLocation` that totally overlaps all other + * `MemoryLocations` in the set. + */ abstract class VirtualVariable extends MemoryLocation { } abstract class AllocationMemoryLocation extends MemoryLocation { @@ -617,3 +623,9 @@ MemoryLocation getOperandMemoryLocation(MemoryOperand operand) { ) ) } + +/** Gets the start bit offset of a `MemoryLocation`, if any. */ +int getStartBitOffset(VariableMemoryLocation location) { result = location.getStartBitOffset() } + +/** Gets the end bit offset of a `MemoryLocation`, if any. */ +int getEndBitOffset(VariableMemoryLocation location) { result = location.getEndBitOffset() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRFunctionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRFunctionImports.qll new file mode 100644 index 000000000000..8ec63b7c1cbd --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRFunctionImports.qll @@ -0,0 +1 @@ +import semmle.code.cpp.ir.implementation.internal.IRFunctionBase as IRFunctionBase diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRInternal.qll index 4cc52d3bbf99..3a7a08accc0d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRInternal.qll @@ -1,3 +1,4 @@ import semmle.code.cpp.ir.internal.IRCppLanguage as Language import SSAConstruction as Construction import semmle.code.cpp.ir.implementation.IRConfiguration as IRConfiguration +import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction::Raw as Raw diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index 30414bb5db3a..a6cb78b2b3a7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -1,5 +1,11 @@ import SSAConstructionInternal -private import SSAConstructionImports +private import SSAConstructionImports as Imports +private import Imports::Opcode +private import Imports::OperandTag +private import Imports::Overlap +private import Imports::TInstruction +private import Imports::RawIR as RawIR +private import SSAInstructions private import NewIR private class OldBlock = Reachability::ReachableBlock; @@ -10,52 +16,45 @@ import Cached cached private module Cached { - private IRBlock getNewBlock(OldBlock oldBlock) { - result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction()) + cached + predicate hasPhiInstructionCached( + OldInstruction blockStartInstr, Alias::MemoryLocation defLocation + ) { + exists(OldBlock oldBlock | + definitionHasPhiNode(defLocation, oldBlock) and + blockStartInstr = oldBlock.getFirstInstruction() + ) } cached - predicate functionHasIR(Language::Function func) { - exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func) + predicate hasChiInstructionCached(OldInstruction primaryInstruction) { + hasChiNode(_, primaryInstruction) } cached - OldInstruction getOldInstruction(Instruction instr) { instr = WrappedInstruction(result) } - - private IRVariable getNewIRVariable(OldIR::IRVariable var) { - // This is just a type cast. Both classes derive from the same newtype. - result = var + predicate hasUnreachedInstructionCached(IRFunction irFunc) { + exists(OldInstruction oldInstruction | + irFunc = oldInstruction.getEnclosingIRFunction() and + Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) + ) } - cached - newtype TInstruction = - WrappedInstruction(OldInstruction oldInstruction) { - not oldInstruction instanceof OldIR::PhiInstruction - } or - Phi(OldBlock block, Alias::MemoryLocation defLocation) { - definitionHasPhiNode(defLocation, block) - } or - Chi(OldInstruction oldInstruction) { - not oldInstruction instanceof OldIR::PhiInstruction and - hasChiNode(_, oldInstruction) - } or - Unreached(Language::Function function) { - exists(OldInstruction oldInstruction | - function = oldInstruction.getEnclosingFunction() and - Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) - ) - } + class TStageInstruction = + TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction; cached - predicate hasTempVariable( - Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type - ) { - exists(OldIR::IRTempVariable var | - var.getEnclosingFunction() = func and - var.getAST() = ast and - var.getTag() = tag and - var.getLanguageType() = type - ) + predicate hasInstruction(TStageInstruction instr) { + instr instanceof TRawInstruction and instr instanceof OldInstruction + or + instr instanceof TPhiInstruction + or + instr instanceof TChiInstruction + or + instr instanceof TUnreachedInstruction + } + + private IRBlock getNewBlock(OldBlock oldBlock) { + result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction()) } cached @@ -73,7 +72,7 @@ private module Cached { or // Chi instructions track virtual variables, and therefore a chi instruction is // conflated if it's associated with the aliased virtual variable. - exists(OldInstruction oldInstruction | instruction = Chi(oldInstruction) | + exists(OldInstruction oldInstruction | instruction = getChi(oldInstruction) | Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof Alias::AliasedVirtualVariable ) @@ -81,7 +80,7 @@ private module Cached { // Phi instructions track locations, and therefore a phi instruction is // conflated if it's associated with a conflated location. exists(Alias::MemoryLocation location | - instruction = Phi(_, location) and + instruction = getPhi(_, location) and not exists(location.getAllocation()) ) } @@ -128,7 +127,7 @@ private module Cached { hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result) ) or - instruction = Chi(getOldInstruction(result)) and + instruction = getChi(getOldInstruction(result)) and tag instanceof ChiPartialOperandTag and overlap instanceof MustExactlyOverlap or @@ -150,6 +149,34 @@ private module Cached { ) } + /** + * Holds if the partial operand of this `ChiInstruction` updates the bit range + * `[startBitOffset, endBitOffset)` of the total operand. + */ + cached + predicate getIntervalUpdatedByChi(ChiInstruction chi, int startBitOffset, int endBitOffset) { + exists(Alias::MemoryLocation location, OldInstruction oldInstruction | + oldInstruction = getOldInstruction(chi.getPartial()) and + location = Alias::getResultMemoryLocation(oldInstruction) and + startBitOffset = Alias::getStartBitOffset(location) and + endBitOffset = Alias::getEndBitOffset(location) + ) + } + + /** + * Holds if `operand` totally overlaps with its definition and consumes the bit range + * `[startBitOffset, endBitOffset)`. + */ + cached + predicate getUsedInterval(NonPhiMemoryOperand operand, int startBitOffset, int endBitOffset) { + exists(Alias::MemoryLocation location, OldIR::NonPhiMemoryOperand oldOperand | + oldOperand = operand.getUse().(OldInstruction).getAnOperand() and + location = Alias::getOperandMemoryLocation(oldOperand) and + startBitOffset = Alias::getStartBitOffset(location) and + endBitOffset = Alias::getEndBitOffset(location) + ) + } + /** * Holds if `instr` is part of a cycle in the operand graph that doesn't go * through a phi instruction and therefore should be impossible. @@ -172,13 +199,15 @@ private module Cached { pragma[noopt] cached - Instruction getPhiOperandDefinition(Phi instr, IRBlock newPredecessorBlock, Overlap overlap) { + Instruction getPhiOperandDefinition( + PhiInstruction instr, IRBlock newPredecessorBlock, Overlap overlap + ) { exists( Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock, OldBlock predBlock, OldBlock defBlock, int defOffset, Alias::MemoryLocation actualDefLocation | hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset) and - instr = Phi(phiBlock, useLocation) and + instr = getPhi(phiBlock, useLocation) and newPredecessorBlock = getNewBlock(predBlock) and result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and overlap = Alias::getOverlap(actualDefLocation, useLocation) @@ -191,7 +220,7 @@ private module Cached { Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation, OldBlock defBlock, int defRank, int defOffset, OldBlock useBlock, int useRank | - chiInstr = Chi(oldInstr) and + chiInstr = getChi(oldInstr) and vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and hasUseAtRank(vvar, useBlock, useRank, oldInstr) and @@ -203,21 +232,11 @@ private module Cached { cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) { exists(OldBlock oldBlock | - instr = Phi(oldBlock, _) and + instr = getPhi(oldBlock, _) and result = getNewInstruction(oldBlock.getFirstInstruction()) ) } - cached - Language::Expr getInstructionConvertedResultExpression(Instruction instruction) { - result = getOldInstruction(instruction).getConvertedResultExpression() - } - - cached - Language::Expr getInstructionUnconvertedResultExpression(Instruction instruction) { - result = getOldInstruction(instruction).getUnconvertedResultExpression() - } - /* * This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node, * that node is its successor in the new successor relation, and the Chi node's successors are @@ -228,20 +247,20 @@ private module Cached { Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) { if hasChiNode(_, getOldInstruction(instruction)) then - result = Chi(getOldInstruction(instruction)) and + result = getChi(getOldInstruction(instruction)) and kind instanceof GotoEdge else ( exists(OldInstruction oldInstruction | oldInstruction = getOldInstruction(instruction) and ( if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind) - then result = Unreached(instruction.getEnclosingFunction()) + then result = unreachedInstruction(instruction.getEnclosingIRFunction()) else result = getNewInstruction(oldInstruction.getSuccessor(kind)) ) ) or exists(OldInstruction oldInstruction | - instruction = Chi(oldInstruction) and + instruction = getChi(oldInstruction) and result = getNewInstruction(oldInstruction.getSuccessor(kind)) ) ) @@ -260,137 +279,73 @@ private module Cached { // `oldInstruction`, in which case the back edge should come out of the // chi node instead. if hasChiNode(_, oldInstruction) - then instruction = Chi(oldInstruction) + then instruction = getChi(oldInstruction) else instruction = getNewInstruction(oldInstruction) ) } cached - Language::AST getInstructionAST(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) - or - instruction = Chi(oldInstruction) - | - result = oldInstruction.getAST() + Language::AST getInstructionAST(Instruction instr) { + result = getOldInstruction(instr).getAST() + or + exists(RawIR::Instruction blockStartInstr | + instr = phiInstruction(blockStartInstr, _) and + result = blockStartInstr.getAST() ) or - exists(OldBlock block | - instruction = Phi(block, _) and - result = block.getFirstInstruction().getAST() + exists(RawIR::Instruction primaryInstr | + instr = chiInstruction(primaryInstr) and + result = primaryInstr.getAST() ) or - instruction = Unreached(result) + exists(IRFunctionBase irFunc | + instr = unreachedInstruction(irFunc) and result = irFunc.getFunction() + ) } cached - Language::LanguageType getInstructionResultType(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) and - result = oldInstruction.getResultLanguageType() - ) + Language::LanguageType getInstructionResultType(Instruction instr) { + result = instr.(RawIR::Instruction).getResultLanguageType() or - exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar | - instruction = Chi(oldInstruction) and - hasChiNode(vvar, oldInstruction) and - result = vvar.getType() + exists(Alias::MemoryLocation defLocation | + instr = phiInstruction(_, defLocation) and + result = defLocation.getType() ) or - exists(Alias::MemoryLocation location | - instruction = Phi(_, location) and - result = location.getType() + exists(Instruction primaryInstr, Alias::VirtualVariable vvar | + instr = chiInstruction(primaryInstr) and + hasChiNode(vvar, primaryInstr) and + result = vvar.getType() ) or - instruction = Unreached(_) and - result = Language::getVoidType() + instr = unreachedInstruction(_) and result = Language::getVoidType() } cached - Opcode getInstructionOpcode(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) and - result = oldInstruction.getOpcode() - ) + Opcode getInstructionOpcode(Instruction instr) { + result = getOldInstruction(instr).getOpcode() or - instruction instanceof Chi and - result instanceof Opcode::Chi + instr = phiInstruction(_, _) and result instanceof Opcode::Phi or - instruction instanceof Phi and - result instanceof Opcode::Phi + instr = chiInstruction(_) and result instanceof Opcode::Chi or - instruction instanceof Unreached and - result instanceof Opcode::Unreached + instr = unreachedInstruction(_) and result instanceof Opcode::Unreached } cached - IRFunction getInstructionEnclosingIRFunction(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) - or - instruction = Chi(oldInstruction) - | - result.getFunction() = oldInstruction.getEnclosingFunction() - ) + IRFunctionBase getInstructionEnclosingIRFunction(Instruction instr) { + result = getOldInstruction(instr).getEnclosingIRFunction() or - exists(OldBlock block | - instruction = Phi(block, _) and - result.getFunction() = block.getEnclosingFunction() + exists(OldInstruction blockStartInstr | + instr = phiInstruction(blockStartInstr, _) and + result = blockStartInstr.getEnclosingIRFunction() ) or - instruction = Unreached(result.getFunction()) - } - - cached - IRVariable getInstructionVariable(Instruction instruction) { - result = - getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getIRVariable()) - } - - cached - Language::Field getInstructionField(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField() - } - - cached - int getInstructionIndex(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::IndexedInstruction).getIndex() - } - - cached - Language::Function getInstructionFunction(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol() - } - - cached - string getInstructionConstantValue(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue() - } - - cached - Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) { - result = - getOldInstruction(instruction).(OldIR::BuiltInOperationInstruction).getBuiltInOperation() - } - - cached - Language::LanguageType getInstructionExceptionType(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType() - } - - cached - int getInstructionElementSize(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::PointerArithmeticInstruction).getElementSize() - } - - cached - predicate getInstructionInheritance( - Instruction instruction, Language::Class baseClass, Language::Class derivedClass - ) { - exists(OldIR::InheritanceConversionInstruction oldInstr | - oldInstr = getOldInstruction(instruction) and - baseClass = oldInstr.getBaseClass() and - derivedClass = oldInstr.getDerivedClass() + exists(OldInstruction primaryInstr | + instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction() ) + or + instr = unreachedInstruction(result) } cached @@ -401,7 +356,7 @@ private module Cached { ) or exists(OldIR::Instruction oldInstruction | - instruction = Chi(oldInstruction) and + instruction = getChi(oldInstruction) and result = getNewInstruction(oldInstruction) ) } @@ -409,6 +364,14 @@ private module Cached { private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr } +private OldInstruction getOldInstruction(Instruction instr) { instr = result } + +private ChiInstruction getChi(OldInstruction primaryInstr) { result = chiInstruction(primaryInstr) } + +private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) { + result = phiInstruction(defBlock.getFirstInstruction(), defLocation) +} + /** * Holds if instruction `def` needs to have a `Chi` instruction inserted after it, to account for a partial definition * of a virtual variable. The `Chi` instruction provides a definition of the entire virtual variable of which the @@ -588,7 +551,7 @@ module DefUse { | // An odd offset corresponds to the `Chi` instruction. defOffset = oldOffset * 2 + 1 and - result = Chi(oldInstr) and + result = getChi(oldInstr) and ( defLocation = Alias::getResultMemoryLocation(oldInstr) or defLocation = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() @@ -607,7 +570,7 @@ module DefUse { or defOffset = -1 and hasDefinition(_, defLocation, defBlock, defOffset) and - result = Phi(defBlock, defLocation) and + result = getPhi(defBlock, defLocation) and actualDefLocation = defLocation } @@ -891,7 +854,7 @@ private module CachedForDebugging { ) or exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity | - instr = Phi(phiBlock, location) and + instr = getPhi(phiBlock, location) and result = "Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " + location.getUniqueId() and if location instanceof Alias::VirtualVariable @@ -901,7 +864,7 @@ private module CachedForDebugging { else specificity = "s" ) or - instr = Unreached(_) and + instr = unreachedInstruction(_) and result = "Unreached" } @@ -961,3 +924,19 @@ module SSAConsistency { ) } } + +/** + * Provides the portion of the parameterized IR interface that is used to construct the SSA stages + * of the IR. The raw stage of the IR does not expose these predicates. + * These predicates are all just aliases for predicates defined in the `Cached` module. This ensures + * that all of SSA construction will be evaluated in the same stage. + */ +module SSA { + class MemoryLocation = Alias::MemoryLocation; + + predicate hasPhiInstruction = Cached::hasPhiInstructionCached/2; + + predicate hasChiInstruction = Cached::hasChiInstructionCached/1; + + predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1; +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll index 00f12020a29d..f347df86ba1e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll @@ -1,3 +1,5 @@ -import semmle.code.cpp.ir.implementation.Opcode -import semmle.code.cpp.ir.implementation.internal.OperandTag -import semmle.code.cpp.ir.internal.Overlap +import semmle.code.cpp.ir.implementation.Opcode as Opcode +import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag +import semmle.code.cpp.ir.internal.Overlap as Overlap +import semmle.code.cpp.ir.implementation.internal.TInstruction as TInstruction +import semmle.code.cpp.ir.implementation.raw.IR as RawIR diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll index c0922aff8917..bb068bdd489c 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll @@ -2,5 +2,6 @@ import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as OldIR import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.ReachableBlock as Reachability import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.Dominance as Dominance import semmle.code.cpp.ir.implementation.aliased_ssa.IR as NewIR +import semmle.code.cpp.ir.implementation.internal.TInstruction::AliasedSSAInstructions as SSAInstructions import semmle.code.cpp.ir.internal.IRCppLanguage as Language import AliasedSSA as Alias diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBase.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBase.qll new file mode 100644 index 000000000000..60895ce3d266 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBase.qll @@ -0,0 +1,27 @@ +/** + * Provides a base class, `IRFunctionBase`, for the stage-independent portions of `IRFunction`. + */ + +private import IRFunctionBaseInternal + +private newtype TIRFunction = + MkIRFunction(Language::Function func) { IRConstruction::Raw::functionHasIR(func) } + +/** + * The IR for a function. This base class contains only the predicates that are the same between all + * phases of the IR. Each instantiation of `IRFunction` extends this class. + */ +class IRFunctionBase extends TIRFunction { + Language::Function func; + + IRFunctionBase() { this = MkIRFunction(func) } + + /** Gets a textual representation of this element. */ + final string toString() { result = "IR: " + func.toString() } + + /** Gets the function whose IR is represented. */ + final Language::Function getFunction() { result = func } + + /** Gets the location of the function. */ + final Language::Location getLocation() { result = func.getLocation() } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBaseInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBaseInternal.qll new file mode 100644 index 000000000000..cc1bdb6444b6 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBaseInternal.qll @@ -0,0 +1,2 @@ +import semmle.code.cpp.ir.internal.IRCppLanguage as Language +import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll index ac284440648d..21dfedd95cd4 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll @@ -40,7 +40,17 @@ abstract class OperandTag extends TOperandTag { /** * Gets a label that will appear before the operand when the IR is printed. */ - string getLabel() { result = "" } + final string getLabel() { if alwaysPrintLabel() then result = getId() + ":" else result = "" } + + /** + * Gets an identifier that uniquely identifies this operand within its instruction. + */ + abstract string getId(); + + /** + * Holds if the operand should always be prefixed with its label in the dump of its instruction. + */ + predicate alwaysPrintLabel() { none() } } /** @@ -69,7 +79,9 @@ class AddressOperandTag extends RegisterOperandTag, TAddressOperand { final override int getSortOrder() { result = 0 } - final override string getLabel() { result = "&:" } + final override predicate alwaysPrintLabel() { any() } + + final override string getId() { result = "&" } } AddressOperandTag addressOperand() { result = TAddressOperand() } @@ -82,6 +94,8 @@ class BufferSizeOperandTag extends RegisterOperandTag, TBufferSizeOperand { final override string toString() { result = "BufferSize" } final override int getSortOrder() { result = 1 } + + final override string getId() { result = "size" } } BufferSizeOperandTag bufferSizeOperand() { result = TBufferSizeOperand() } @@ -93,6 +107,8 @@ class SideEffectOperandTag extends TypedOperandTag, TSideEffectOperand { final override string toString() { result = "SideEffect" } final override int getSortOrder() { result = 2 } + + final override string getId() { result = "side_effect" } } SideEffectOperandTag sideEffectOperand() { result = TSideEffectOperand() } @@ -105,6 +121,8 @@ class LoadOperandTag extends TypedOperandTag, TLoadOperand { final override string toString() { result = "Load" } final override int getSortOrder() { result = 3 } + + final override string getId() { result = "load" } } LoadOperandTag loadOperand() { result = TLoadOperand() } @@ -116,6 +134,8 @@ class StoreValueOperandTag extends RegisterOperandTag, TStoreValueOperand { final override string toString() { result = "StoreValue" } final override int getSortOrder() { result = 4 } + + final override string getId() { result = "store" } } StoreValueOperandTag storeValueOperand() { result = TStoreValueOperand() } @@ -127,6 +147,8 @@ class UnaryOperandTag extends RegisterOperandTag, TUnaryOperand { final override string toString() { result = "Unary" } final override int getSortOrder() { result = 5 } + + final override string getId() { result = "unary" } } UnaryOperandTag unaryOperand() { result = TUnaryOperand() } @@ -138,6 +160,8 @@ class LeftOperandTag extends RegisterOperandTag, TLeftOperand { final override string toString() { result = "Left" } final override int getSortOrder() { result = 6 } + + final override string getId() { result = "left" } } LeftOperandTag leftOperand() { result = TLeftOperand() } @@ -149,6 +173,8 @@ class RightOperandTag extends RegisterOperandTag, TRightOperand { final override string toString() { result = "Right" } final override int getSortOrder() { result = 7 } + + final override string getId() { result = "right" } } RightOperandTag rightOperand() { result = TRightOperand() } @@ -160,6 +186,8 @@ class ConditionOperandTag extends RegisterOperandTag, TConditionOperand { final override string toString() { result = "Condition" } final override int getSortOrder() { result = 8 } + + final override string getId() { result = "cond" } } ConditionOperandTag conditionOperand() { result = TConditionOperand() } @@ -172,7 +200,9 @@ class CallTargetOperandTag extends RegisterOperandTag, TCallTargetOperand { final override int getSortOrder() { result = 10 } - final override string getLabel() { result = "func:" } + final override predicate alwaysPrintLabel() { any() } + + final override string getId() { result = "func" } } CallTargetOperandTag callTargetOperand() { result = TCallTargetOperand() } @@ -195,7 +225,9 @@ class ThisArgumentOperandTag extends ArgumentOperandTag, TThisArgumentOperand { final override int getSortOrder() { result = 11 } - final override string getLabel() { result = "this:" } + final override predicate alwaysPrintLabel() { any() } + + final override string getId() { result = "this" } } ThisArgumentOperandTag thisArgumentOperand() { result = TThisArgumentOperand() } @@ -212,9 +244,11 @@ class PositionalArgumentOperandTag extends ArgumentOperandTag, TPositionalArgume final override int getSortOrder() { result = 12 + argIndex } - final override string getLabel() { result = argIndex.toString() + ":" } + final override predicate alwaysPrintLabel() { any() } final int getArgIndex() { result = argIndex } + + final override string getId() { result = argIndex.toString() } } PositionalArgumentOperandTag positionalArgumentOperand(int argIndex) { @@ -228,7 +262,9 @@ class ChiTotalOperandTag extends ChiOperandTag, TChiTotalOperand { final override int getSortOrder() { result = 13 } - final override string getLabel() { result = "total:" } + final override predicate alwaysPrintLabel() { any() } + + final override string getId() { result = "total" } } ChiTotalOperandTag chiTotalOperand() { result = TChiTotalOperand() } @@ -238,7 +274,9 @@ class ChiPartialOperandTag extends ChiOperandTag, TChiPartialOperand { final override int getSortOrder() { result = 14 } - final override string getLabel() { result = "partial:" } + final override predicate alwaysPrintLabel() { any() } + + final override string getId() { result = "partial" } } ChiPartialOperandTag chiPartialOperand() { result = TChiPartialOperand() } @@ -252,7 +290,9 @@ class AsmOperandTag extends RegisterOperandTag, TAsmOperand { final override int getSortOrder() { result = 15 + index } - final override string getLabel() { result = index.toString() + ":" } + final override predicate alwaysPrintLabel() { any() } + + final override string getId() { result = index.toString() } } AsmOperandTag asmOperand(int index) { result = TAsmOperand(index) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariableInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariableInternal.qll index 362274f387c0..7984c4883fd5 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariableInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariableInternal.qll @@ -1,5 +1,5 @@ import semmle.code.cpp.ir.internal.IRCppLanguage as Language -import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as Construction +import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction::Raw as Construction private import semmle.code.cpp.ir.implementation.TempVariableTag as TempVariableTag_ module Imports { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll new file mode 100644 index 000000000000..e16b71733b5a --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll @@ -0,0 +1,97 @@ +private import TInstructionInternal +private import IRFunctionBase +private import TInstructionImports as Imports +private import Imports::IRType +private import Imports::Opcode + +/** + * An IR instruction. `TInstruction` is shared across all phases of the IR. There are individual + * branches of this type for instructions created directly from the AST (`TRawInstruction`) and for + * instructions added by each stage of SSA construction (`T*PhiInstruction`, `T*ChiInstruction`, + * `T*UnreachedInstruction`). Each stage then defines a `TStageInstruction` type that is a union of + * all of the branches that can appear in that particular stage. The public `Instruction` class for + * each phase extends the `TStageInstruction` type for that stage. + */ +cached +newtype TInstruction = + TRawInstruction( + IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2 + ) { + IRConstruction::Raw::hasInstruction(tag1, tag2) + } or + TUnaliasedSSAPhiInstruction( + TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation + ) { + UnaliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation) + } or + TUnaliasedSSAChiInstruction(TRawInstruction primaryInstruction) { none() } or + TUnaliasedSSAUnreachedInstruction(IRFunctionBase irFunc) { + UnaliasedSSA::SSA::hasUnreachedInstruction(irFunc) + } or + TAliasedSSAPhiInstruction( + TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation + ) { + AliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation) + } or + TAliasedSSAChiInstruction(TRawInstruction primaryInstruction) { + AliasedSSA::SSA::hasChiInstruction(primaryInstruction) + } or + TAliasedSSAUnreachedInstruction(IRFunctionBase irFunc) { + AliasedSSA::SSA::hasUnreachedInstruction(irFunc) + } + +/** + * Provides wrappers for the constructors of each branch of `TInstruction` that is used by the + * unaliased SSA stage. + * These wrappers are not parameterized because it is not possible to invoke an IPA constructor via + * a class alias. + */ +module UnaliasedSSAInstructions { + class TPhiInstruction = TUnaliasedSSAPhiInstruction; + + TPhiInstruction phiInstruction( + TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation + ) { + result = TUnaliasedSSAPhiInstruction(blockStartInstr, memoryLocation) + } + + class TChiInstruction = TUnaliasedSSAChiInstruction; + + TChiInstruction chiInstruction(TRawInstruction primaryInstruction) { + result = TUnaliasedSSAChiInstruction(primaryInstruction) + } + + class TUnreachedInstruction = TUnaliasedSSAUnreachedInstruction; + + TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) { + result = TUnaliasedSSAUnreachedInstruction(irFunc) + } +} + +/** + * Provides wrappers for the constructors of each branch of `TInstruction` that is used by the + * aliased SSA stage. + * These wrappers are not parameterized because it is not possible to invoke an IPA constructor via + * a class alias. + */ +module AliasedSSAInstructions { + class TPhiInstruction = TAliasedSSAPhiInstruction; + + TPhiInstruction phiInstruction( + TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation + ) { + result = TAliasedSSAPhiInstruction(blockStartInstr, memoryLocation) + } + + class TChiInstruction = TAliasedSSAChiInstruction; + + TChiInstruction chiInstruction(TRawInstruction primaryInstruction) { + result = TAliasedSSAChiInstruction(primaryInstruction) + } + + class TUnreachedInstruction = TAliasedSSAUnreachedInstruction; + + TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) { + result = TAliasedSSAUnreachedInstruction(irFunc) + } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstructionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstructionImports.qll new file mode 100644 index 000000000000..e008ce7d8d34 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstructionImports.qll @@ -0,0 +1,2 @@ +import semmle.code.cpp.ir.implementation.IRType as IRType +import semmle.code.cpp.ir.implementation.Opcode as Opcode diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstructionInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstructionInternal.qll new file mode 100644 index 000000000000..adaaaca9cd82 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstructionInternal.qll @@ -0,0 +1,4 @@ +import semmle.code.cpp.ir.internal.IRCppLanguage as Language +import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction +import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedSSA +import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConstruction as AliasedSSA diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll index badd48552a5f..c96783fe6e81 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll @@ -1,3 +1,47 @@ +/** + * Provides classes that describe the Intermediate Representation (IR) of the program. + * + * The IR is a representation of the semantics of the program, with very little dependence on the + * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, + * and `++i` all have the same semantic effect, but appear in the AST as three different types of + * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental + * operations similar to: + * + * ``` + * r1(int*) = VariableAddress[i] // Compute the address of variable `i` + * r2(int) = Load &:r1, m0 // Load the value of `i` + * r3(int) = Constant[1] // An integer constant with the value `1` + * r4(int) = Add r2, r3 // Add `1` to the value of `i` + * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` + * ``` + * + * This allows IR-based analysis to focus on the fundamental operations, rather than having to be + * concerned with the various ways of expressing those operations in source code. + * + * The key classes in the IR are: + * + * - `IRFunction` - Contains the IR for an entire function definition, including all of that + * function's `Instruction`s, `IRBlock`s, and `IRVariables`. + * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be + * performed, the operands that produce the inputs to that operation, and the type of the result + * of the operation. Control flows from an `Instruction` to one of a set of successor + * `Instruction`s. + * - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly + * represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has + * a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction` + * that produces its value (its "definition"). + * - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is + * created for each variable directly accessed by the function. In addition, `IRVariable`s are + * created to represent certain temporary storage locations that do not have explicitly declared + * variables in the source code, such as the return value of the function. + * - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a + * sequence of instructions such that control flow can only enter the block at the first + * instruction, and can only leave the block from the last instruction. + * - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType` + * is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all + * be represented as the `IRType` `uint4`, a four-byte unsigned integer. + */ + import IRFunction import Instruction import IRBlock @@ -11,11 +55,12 @@ import Imports::MemoryAccessKind private newtype TIRPropertyProvider = MkIRPropertyProvider() /** - * Class that provides additional properties to be dumped for IR instructions and blocks when using + * A class that provides additional properties to be dumped for IR instructions and blocks when using * the PrintIR module. Libraries that compute additional facts about IR elements can extend the * single instance of this class to specify the additional properties computed by the library. */ class IRPropertyProvider extends TIRPropertyProvider { + /** Gets a textual representation of this element. */ string toString() { result = "IRPropertyProvider" } /** @@ -27,4 +72,9 @@ class IRPropertyProvider extends TIRPropertyProvider { * Gets the value of the property named `key` for the specified block. */ string getBlockProperty(IRBlock block, string key) { none() } + + /** + * Gets the value of the property named `key` for the specified operand. + */ + string getOperandProperty(Operand operand, string key) { none() } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll index 94ef73b27692..d827ed3cf82d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll @@ -1,3 +1,7 @@ +/** + * Provides classes describing basic blocks in the IR of a function. + */ + private import internal.IRInternal import Instruction private import internal.IRBlockImports as Imports @@ -16,15 +20,27 @@ private import Cached * Most consumers should use the class `IRBlock`. */ class IRBlockBase extends TIRBlock { + /** Gets a textual representation of this block. */ final string toString() { result = getFirstInstruction(this).toString() } + /** Gets the source location of the first non-`Phi` instruction in this block. */ final Language::Location getLocation() { result = getFirstInstruction().getLocation() } + /** + * INTERNAL: Do not use. + * + * Gets a string that uniquely identifies this block within its enclosing function. + * + * This predicate is used by debugging and printing code only. + */ final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() } /** - * Gets the zero-based index of the block within its function. This is used - * by debugging and printing code only. + * INTERNAL: Do not use. + * + * Gets the zero-based index of the block within its function. + * + * This predicate is used by debugging and printing code only. */ int getDisplayIndex() { exists(IRConfiguration::IRConfiguration config | @@ -42,27 +58,51 @@ class IRBlockBase extends TIRBlock { ) } + /** + * Gets the `index`th non-`Phi` instruction in this block. + */ final Instruction getInstruction(int index) { result = getInstruction(this, index) } + /** + * Get the `Phi` instructions that appear at the start of this block. + */ final PhiInstruction getAPhiInstruction() { Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() } + /** + * Gets an instruction in this block. This includes `Phi` instructions. + */ final Instruction getAnInstruction() { result = getInstruction(_) or result = getAPhiInstruction() } + /** + * Gets the first non-`Phi` instruction in this block. + */ final Instruction getFirstInstruction() { result = getFirstInstruction(this) } + /** + * Gets the last instruction in this block. + */ final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) } + /** + * Gets the number of non-`Phi` instructions in this block. + */ final int getInstructionCount() { result = getInstructionCount(this) } + /** + * Gets the `IRFunction` that contains this block. + */ final IRFunction getEnclosingIRFunction() { result = getFirstInstruction(this).getEnclosingIRFunction() } + /** + * Gets the `Function` that contains this block. + */ final Language::Function getEnclosingFunction() { result = getFirstInstruction(this).getEnclosingFunction() } @@ -74,20 +114,57 @@ class IRBlockBase extends TIRBlock { * instruction of another block. */ class IRBlock extends IRBlockBase { + /** + * Gets a block to which control flows directly from this block. + */ final IRBlock getASuccessor() { blockSuccessor(this, result) } + /** + * Gets a block from which control flows directly to this block. + */ final IRBlock getAPredecessor() { blockSuccessor(result, this) } + /** + * Gets the block to which control flows directly from this block along an edge of kind `kind`. + */ final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } + /** + * Gets the block to which control flows directly from this block along a back edge of kind + * `kind`. + */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } + /** + * Holds if this block immediately dominates `block`. + * + * Block `A` immediate dominates block `B` if block `A` strictly dominates block `B` and block `B` + * is a direct successor of block `A`. + */ final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) } + /** + * Holds if this block strictly dominates `block`. + * + * Block `A` strictly dominates block `B` if block `A` dominates block `B` and blocks `A` and `B` + * are not the same block. + */ final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) } + /** + * Holds if this block dominates `block`. + * + * Block `A` dominates block `B` if any control flow path from the entry block of the function to + * block `B` must pass through block `A`. A block always dominates itself. + */ final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } + /** + * Gets a block on the dominance frontier of this block. + * + * The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not + * dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`. + */ pragma[noinline] final IRBlock dominanceFrontier() { dominates(result.getAPredecessor()) and @@ -95,7 +172,7 @@ class IRBlock extends IRBlockBase { } /** - * Holds if this block is reachable from the entry point of its function + * Holds if this block is reachable from the entry block of its function. */ final predicate isReachableFromFunctionEntry() { this = getEnclosingIRFunction().getEntryBlock() or @@ -210,4 +287,4 @@ private module Cached { idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block) } -Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } +private Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll index 65af34942b6b..6a87b9b4b5fd 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll @@ -8,10 +8,79 @@ module InstructionConsistency { private import Imports::Overlap private import internal.IRInternal + private newtype TOptionalIRFunction = + TPresentIRFunction(IRFunction irFunc) or + TMissingIRFunction() + + /** + * An `IRFunction` that might not exist. This is used so that we can produce consistency failures + * for IR that also incorrectly lacks a `getEnclosingIRFunction()`. + */ + abstract private class OptionalIRFunction extends TOptionalIRFunction { + abstract string toString(); + + abstract Language::Location getLocation(); + } + + private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction { + private IRFunction irFunc; + + PresentIRFunction() { this = TPresentIRFunction(irFunc) } + + override string toString() { + result = concat(Language::getIdentityString(irFunc.getFunction()), "; ") + } + + override Language::Location getLocation() { + // To avoid an overwhelming number of results when the extractor merges functions with the + // same name, just pick a single location. + result = + rank[1](Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString()) + } + } + + private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction { + override string toString() { result = "" } + + override Language::Location getLocation() { result instanceof Language::UnknownDefaultLocation } + } + + private OptionalIRFunction getInstructionIRFunction(Instruction instr) { + result = TPresentIRFunction(instr.getEnclosingIRFunction()) + or + not exists(instr.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getInstructionIRFunction(Instruction instr, string irFuncText) { + result = getInstructionIRFunction(instr) and + irFuncText = result.toString() + } + + private OptionalIRFunction getOperandIRFunction(Operand operand) { + result = TPresentIRFunction(operand.getEnclosingIRFunction()) + or + not exists(operand.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getOperandIRFunction(Operand operand, string irFuncText) { + result = getOperandIRFunction(operand) and + irFuncText = result.toString() + } + + private OptionalIRFunction getBlockIRFunction(IRBlock block) { + result = TPresentIRFunction(block.getEnclosingIRFunction()) + or + not exists(block.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + /** * Holds if instruction `instr` is missing an expected operand with tag `tag`. */ - query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) { + query predicate missingOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { exists(OperandTag tag | instr.getOpcode().hasOperand(tag) and not exists(NonPhiOperand operand | @@ -21,32 +90,39 @@ module InstructionConsistency { message = "Instruction '" + instr.getOpcode().toString() + "' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getInstructionIRFunction(instr, irFuncText) ) } /** * Holds if instruction `instr` has an unexpected operand with tag `tag`. */ - query predicate unexpectedOperand(Instruction instr, OperandTag tag) { - exists(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and - not instr.getOpcode().hasOperand(tag) and - not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and - not ( - instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag - ) and - not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag) + query predicate unexpectedOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(OperandTag tag | + exists(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + not instr.getOpcode().hasOperand(tag) and + not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and + not ( + instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag + ) and + not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag) and + message = + "Instruction '" + instr.toString() + "' has unexpected operand '" + tag.toString() + + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } /** * Holds if instruction `instr` has multiple operands with tag `tag`. */ query predicate duplicateOperand( - Instruction instr, string message, IRFunction func, string funcText + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(OperandTag tag, int operandCount | operandCount = @@ -58,8 +134,7 @@ module InstructionConsistency { message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + " in function '$@'." and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getInstructionIRFunction(instr, irFuncText) ) } @@ -67,100 +142,136 @@ module InstructionConsistency { * Holds if `Phi` instruction `instr` is missing an operand corresponding to * the predecessor block `pred`. */ - query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) { - pred = instr.getBlock().getAPredecessor() and - not exists(PhiInputOperand operand | - operand = instr.getAnOperand() and - operand.getPredecessorBlock() = pred + query predicate missingPhiOperand( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRBlock pred | + pred = instr.getBlock().getAPredecessor() and + not exists(PhiInputOperand operand | + operand = instr.getAnOperand() and + operand.getPredecessorBlock() = pred + ) and + message = + "Instruction '" + instr.toString() + "' is missing an operand for predecessor block '" + + pred.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) ) } - query predicate missingOperandType(Operand operand, string message) { - exists(Language::Function func, Instruction use | + query predicate missingOperandType( + Operand operand, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Instruction use | not exists(operand.getType()) and use = operand.getUse() and - func = use.getEnclosingFunction() and message = "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() + - "' missing type in function '" + Language::getIdentityString(func) + "'." + "' is missing a type in function '$@'." and + irFunc = getOperandIRFunction(operand, irFuncText) ) } query predicate duplicateChiOperand( - ChiInstruction chi, string message, IRFunction func, string funcText + ChiInstruction chi, string message, OptionalIRFunction irFunc, string irFuncText ) { chi.getTotal() = chi.getPartial() and message = "Chi instruction for " + chi.getPartial().toString() + - " has duplicate operands in function $@" and - func = chi.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + " has duplicate operands in function '$@'." and + irFunc = getInstructionIRFunction(chi, irFuncText) } query predicate sideEffectWithoutPrimary( - SideEffectInstruction instr, string message, IRFunction func, string funcText + SideEffectInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText ) { not exists(instr.getPrimaryInstruction()) and - message = "Side effect instruction missing primary instruction in function $@" and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + message = + "Side effect instruction '" + instr + "' is missing a primary instruction in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } /** * Holds if an instruction, other than `ExitFunction`, has no successors. */ - query predicate instructionWithoutSuccessor(Instruction instr) { + query predicate instructionWithoutSuccessor( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { not exists(instr.getASuccessor()) and not instr instanceof ExitFunctionInstruction and // Phi instructions aren't linked into the instruction-level flow graph. not instr instanceof PhiInstruction and - not instr instanceof UnreachedInstruction + not instr instanceof UnreachedInstruction and + message = "Instruction '" + instr.toString() + "' has no successors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } /** - * Holds if there are multiple (`n`) edges of kind `kind` from `source`, - * where `target` is among the targets of those edges. + * Holds if there are multiple edges of the same kind from `source`. */ - query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) { - n = strictcount(Instruction t | source.getSuccessor(kind) = t) and - n > 1 and - source.getSuccessor(kind) = target + query predicate ambiguousSuccessors( + Instruction source, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(EdgeKind kind, int n | + n = strictcount(Instruction t | source.getSuccessor(kind) = t) and + n > 1 and + message = + "Instruction '" + source.toString() + "' has " + n.toString() + " successors of kind '" + + kind.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(source, irFuncText) + ) } /** - * Holds if `instr` in `f` is part of a loop even though the AST of `f` + * Holds if `instr` is part of a loop even though the AST of `instr`'s enclosing function * contains no element that can cause loops. */ - query predicate unexplainedLoop(Language::Function f, Instruction instr) { - exists(IRBlock block | - instr.getBlock() = block and - block.getEnclosingFunction() = f and - block.getASuccessor+() = block - ) and - not Language::hasPotentialLoop(f) + query predicate unexplainedLoop( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Language::Function f | + exists(IRBlock block | + instr.getBlock() = block and + block.getEnclosingFunction() = f and + block.getASuccessor+() = block + ) and + not Language::hasPotentialLoop(f) and + message = + "Instruction '" + instr.toString() + "' is part of an unexplained loop in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } /** * Holds if a `Phi` instruction is present in a block with fewer than two * predecessors. */ - query predicate unnecessaryPhiInstruction(PhiInstruction instr) { - count(instr.getBlock().getAPredecessor()) < 2 + query predicate unnecessaryPhiInstruction( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int n | + n = count(instr.getBlock().getAPredecessor()) and + n < 2 and + message = + "Instruction '" + instr.toString() + "' is in a block with only " + n.toString() + + " predecessors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } /** * Holds if a memory operand is connected to a definition with an unmodeled result. */ query predicate memoryOperandDefinitionIsUnmodeled( - Instruction instr, string message, IRFunction func, string funcText + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(MemoryOperand operand, Instruction def | operand = instr.getAnOperand() and def = operand.getAnyDef() and not def.isResultModeled() and - message = "Memory operand definition has unmodeled result in function '$@'" and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + message = + "Memory operand definition on instruction '" + instr.toString() + + "' has unmodeled result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) ) } @@ -168,18 +279,37 @@ module InstructionConsistency { * Holds if operand `operand` consumes a value that was defined in * a different function. */ - query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) { - operand.getUse() = instr and - operand.getAnyDef() = defInstr and - instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction() + query predicate operandAcrossFunctions( + Operand operand, string message, OptionalIRFunction useIRFunc, string useIRFuncText, + OptionalIRFunction defIRFunc, string defIRFuncText + ) { + exists(Instruction useInstr, Instruction defInstr | + operand.getUse() = useInstr and + operand.getAnyDef() = defInstr and + useIRFunc = getInstructionIRFunction(useInstr, useIRFuncText) and + defIRFunc = getInstructionIRFunction(defInstr, defIRFuncText) and + useIRFunc != defIRFunc and + message = + "Operand '" + operand.toString() + "' is used on instruction '" + useInstr.toString() + + "' in function '$@', but is defined on instruction '" + defInstr.toString() + + "' in function '$@'." + ) } /** * Holds if instruction `instr` is not in exactly one block. */ - query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) { - blockCount = count(instr.getBlock()) and - blockCount != 1 + query predicate instructionWithoutUniqueBlock( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int blockCount | + blockCount = count(instr.getBlock()) and + blockCount != 1 and + message = + "Instruction '" + instr.toString() + "' is a member of " + blockCount.toString() + + " blocks in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } private predicate forwardEdge(IRBlock b1, IRBlock b2) { @@ -192,10 +322,11 @@ module InstructionConsistency { * * This check ensures we don't have too _few_ back edges. */ - query predicate containsLoopOfForwardEdges(IRFunction f) { + query predicate containsLoopOfForwardEdges(IRFunction f, string message) { exists(IRBlock block | forwardEdge+(block, block) and - block.getEnclosingIRFunction() = f + block.getEnclosingIRFunction() = f and + message = "Function contains a loop consisting of only forward edges." ) } @@ -207,12 +338,19 @@ module InstructionConsistency { * * This check ensures we don't have too _many_ back edges. */ - query predicate lostReachability(IRBlock block) { + query predicate lostReachability( + IRBlock block, string message, OptionalIRFunction irFunc, string irFuncText + ) { exists(IRFunction f, IRBlock entry | entry = f.getEntryBlock() and entry.getASuccessor+() = block and not forwardEdge+(entry, block) and - not Language::hasGoto(f.getFunction()) + not Language::hasGoto(f.getFunction()) and + message = + "Block '" + block.toString() + + "' is not reachable by traversing only forward edges in function '$@'." and + irFunc = TPresentIRFunction(f) and + irFuncText = irFunc.toString() ) } @@ -220,16 +358,22 @@ module InstructionConsistency { * Holds if the number of back edges differs between the `Instruction` graph * and the `IRBlock` graph. */ - query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) { - fromInstr = - count(Instruction i1, Instruction i2 | - i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2 - ) and - fromBlock = - count(IRBlock b1, IRBlock b2 | - b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2 - ) and - fromInstr != fromBlock + query predicate backEdgeCountMismatch(OptionalIRFunction irFunc, string message) { + exists(int fromInstr, int fromBlock | + fromInstr = + count(Instruction i1, Instruction i2 | + getInstructionIRFunction(i1) = irFunc and i1.getBackEdgeSuccessor(_) = i2 + ) and + fromBlock = + count(IRBlock b1, IRBlock b2 | + getBlockIRFunction(b1) = irFunc and b1.getBackEdgeSuccessor(_) = b2 + ) and + fromInstr != fromBlock and + message = + "The instruction graph for function '" + irFunc.toString() + "' contains " + + fromInstr.toString() + " back edges, but the block graph contains " + fromBlock.toString() + + " back edges." + ) } /** @@ -251,7 +395,7 @@ module InstructionConsistency { * Holds if `useOperand` has a definition that does not dominate the use. */ query predicate useNotDominatedByDefinition( - Operand useOperand, string message, IRFunction func, string funcText + Operand useOperand, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | pointOfEvaluation(useOperand, useBlock, useIndex) and @@ -272,19 +416,17 @@ module InstructionConsistency { message = "Operand '" + useOperand.toString() + "' is not dominated by its definition in function '$@'." and - func = useOperand.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getOperandIRFunction(useOperand, irFuncText) ) } query predicate switchInstructionWithoutDefaultEdge( - SwitchInstruction switchInstr, string message, IRFunction func, string funcText + SwitchInstruction switchInstr, string message, OptionalIRFunction irFunc, string irFuncText ) { not exists(switchInstr.getDefaultSuccessor()) and message = "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and - func = switchInstr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getInstructionIRFunction(switchInstr, irFuncText) } /** @@ -305,18 +447,30 @@ module InstructionConsistency { instr.getOpcode() instanceof Opcode::InitializeNonLocal } - query predicate notMarkedAsConflated(Instruction instr) { + query predicate notMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { shouldBeConflated(instr) and - not instr.isResultConflated() + not instr.isResultConflated() and + message = + "Instruction '" + instr.toString() + + "' should be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } - query predicate wronglyMarkedAsConflated(Instruction instr) { + query predicate wronglyMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { instr.isResultConflated() and - not shouldBeConflated(instr) + not shouldBeConflated(instr) and + message = + "Instruction '" + instr.toString() + + "' should not be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } query predicate invalidOverlap( - MemoryOperand useOperand, string message, IRFunction func, string funcText + MemoryOperand useOperand, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(Overlap overlap | overlap = useOperand.getDefinitionOverlap() and @@ -324,8 +478,20 @@ module InstructionConsistency { message = "MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" + overlap.toString() + "'." and - func = useOperand.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getOperandIRFunction(useOperand, irFuncText) + ) + } + + query predicate nonUniqueEnclosingIRFunction( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int irFuncCount | + irFuncCount = count(instr.getEnclosingIRFunction()) and + irFuncCount != 1 and + message = + "Instruction '" + instr.toString() + "' has " + irFuncCount.toString() + + " results for `getEnclosingIRFunction()` in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) ) } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll index 9aea3e00d666..5968e58f90bf 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll @@ -1,29 +1,17 @@ +/** + * Provides the class `IRFunction`, which represents the Intermediate Representation for the + * definition of a function. + */ + private import internal.IRInternal +private import internal.IRFunctionImports as Imports +import Imports::IRFunctionBase import Instruction -private newtype TIRFunction = - MkIRFunction(Language::Function func) { Construction::functionHasIR(func) } - /** - * Represents the IR for a function. + * The IR for a function. */ -class IRFunction extends TIRFunction { - Language::Function func; - - IRFunction() { this = MkIRFunction(func) } - - final string toString() { result = "IR: " + func.toString() } - - /** - * Gets the function whose IR is represented. - */ - final Language::Function getFunction() { result = func } - - /** - * Gets the location of the function. - */ - final Language::Location getLocation() { result = func.getLocation() } - +class IRFunction extends IRFunctionBase { /** * Gets the entry point for this function. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll index 9f2a0d4ea281..146fc2707383 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent variables accessed by the IR. + */ + private import internal.IRInternal import IRFunction private import internal.IRVariableImports as Imports @@ -7,15 +11,11 @@ private import Imports::TTempVariableTag private import Imports::TIRVariable private import Imports::IRType -IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { - result.getVariable() = var and - result.getEnclosingFunction() = func -} - /** - * A variable referenced by the IR for a function. The variable may be a user-declared variable - * (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation - * (`IRTempVariable`). + * A variable referenced by the IR for a function. + * + * The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated + * by the AST-to-IR translation (`IRTempVariable`). */ class IRVariable extends TIRVariable { Language::Function func; @@ -27,6 +27,7 @@ class IRVariable extends TIRVariable { this = TIRDynamicInitializationFlag(func, _, _) } + /** Gets a textual representation of this element. */ string toString() { none() } /** @@ -162,20 +163,30 @@ class IRGeneratedVariable extends IRVariable { override string getUniqueId() { none() } + /** + * INTERNAL: Do not use. + * + * Gets a string containing the source code location of the AST that generated this variable. + * + * This is used by debugging and printing code only. + */ final string getLocationString() { result = ast.getLocation().getStartLine().toString() + ":" + ast.getLocation().getStartColumn().toString() } + /** + * INTERNAL: Do not use. + * + * Gets the string that is combined with the location of the variable to generate the string + * representation of this variable. + * + * This is used by debugging and printing code only. + */ string getBaseString() { none() } } -IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { - result.getAST() = ast and - result.getTag() = tag -} - /** * A temporary variable introduced by IR construction. The most common examples are the variable * generated to hold the return value of a function, or the variable generated to hold the result of @@ -190,6 +201,10 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa result = "Temp: " + Construction::getTempVariableUniqueId(this) } + /** + * Gets the "tag" object that differentiates this temporary variable from other temporary + * variables generated for the same AST. + */ final TempVariableTag getTag() { result = tag } override string getBaseString() { result = "#temp" } @@ -217,19 +232,23 @@ class IRThrowVariable extends IRTempVariable { * A temporary variable generated to hold the contents of all arguments passed to the `...` of a * function that accepts a variable number of arguments. */ -class IREllipsisVariable extends IRTempVariable { +class IREllipsisVariable extends IRTempVariable, IRParameter { IREllipsisVariable() { tag = EllipsisTempVar() } final override string toString() { result = "#ellipsis" } + + final override int getIndex() { result = func.getNumberOfParameters() } } /** * A temporary variable generated to hold the `this` pointer. */ -class IRThisVariable extends IRTempVariable { +class IRThisVariable extends IRTempVariable, IRParameter { IRThisVariable() { tag = ThisTempVar() } final override string toString() { result = "#this" } + + final override int getIndex() { result = -1 } } /** @@ -249,6 +268,9 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { final override string getBaseString() { result = "#string" } + /** + * Gets the AST of the string literal represented by this `IRStringLiteral`. + */ final Language::StringLiteral getLiteral() { result = literal } } @@ -266,6 +288,9 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string toString() { result = var.toString() + "#init" } + /** + * Gets variable whose initialization is guarded by this flag. + */ final Language::Variable getVariable() { result = var } final override string getUniqueId() { @@ -274,3 +299,29 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string getBaseString() { result = "#init:" + var.toString() + ":" } } + +/** + * An IR variable which acts like a function parameter, including positional parameters and the + * temporary variables generated for `this` and ellipsis parameters. + */ +class IRParameter extends IRAutomaticVariable { + IRParameter() { + this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter + or + this = TIRTempVariable(_, _, ThisTempVar(), _) + or + this = TIRTempVariable(_, _, EllipsisTempVar(), _) + } + + /** + * Gets the zero-based index of this parameter. The `this` parameter has index -1. + */ + int getIndex() { none() } +} + +/** + * An IR variable representing a positional parameter. + */ +class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable { + final override int getIndex() { result = getVariable().(Language::Parameter).getIndex() } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 9c83a3d99f0c..620b23b942e0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the individual instructions in the IR for a function. + */ + private import internal.IRInternal import IRFunction import IRBlock @@ -27,9 +31,16 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil } /** - * Represents a single operation in the IR. + * A single instruction in the IR. */ -class Instruction extends Construction::TInstruction { +class Instruction extends Construction::TStageInstruction { + Instruction() { + // The base `TStageInstruction` type is a superset of the actual instructions appearing in this + // stage. This call lets the stage filter out the ones that are not reused from raw IR. + Construction::hasInstruction(this) + } + + /** Gets a textual representation of this element. */ final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } /** @@ -194,16 +205,25 @@ class Instruction extends Construction::TInstruction { * conversion. */ final Language::Expr getConvertedResultExpression() { - result = Construction::getInstructionConvertedResultExpression(this) + result = Raw::getInstructionConvertedResultExpression(this) } /** * Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any. */ final Language::Expr getUnconvertedResultExpression() { - result = Construction::getInstructionUnconvertedResultExpression(this) + result = Raw::getInstructionUnconvertedResultExpression(this) } + /** + * Gets the language-specific type of the result produced by this instruction. + * + * Most consumers of the IR should use `getResultIRType()` instead. `getResultIRType()` uses a + * less complex, language-neutral type system in which all semantically equivalent types share the + * same `IRType` instance. For example, in C++, four different `Instruction`s might have three + * different values for `getResultLanguageType()`: `unsigned int`, `char32_t`, and `wchar_t`, + * whereas all four instructions would have the same value for `getResultIRType()`, `uint4`. + */ final Language::LanguageType getResultLanguageType() { result = Construction::getInstructionResultType(this) } @@ -212,6 +232,7 @@ class Instruction extends Construction::TInstruction { * Gets the type of the result produced by this instruction. If the instruction does not produce * a result, its result type will be `IRVoidType`. */ + cached final IRType getResultIRType() { result = getResultLanguageType().getIRType() } /** @@ -240,17 +261,19 @@ class Instruction extends Construction::TInstruction { * given by `getResultType()`. * * For example, the statement `y = x;` generates the following IR: + * ``` * r1_0(glval: int) = VariableAddress[x] * r1_1(int) = Load r1_0, mu0_1 * r1_2(glval: int) = VariableAddress[y] * mu1_3(int) = Store r1_2, r1_1 + * ``` * * The result of each `VariableAddress` instruction is a glvalue of type * `int`, representing the address of the corresponding integer variable. The * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) } + final predicate isGLValue() { getResultLanguageType().hasType(_, true) } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -259,7 +282,7 @@ class Instruction extends Construction::TInstruction { * If `this.isGLValue()` holds for this instruction, the value of * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() } + final int getResultSize() { result = getResultLanguageType().getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. @@ -392,13 +415,27 @@ class Instruction extends Construction::TInstruction { final Instruction getAPredecessor() { result = getPredecessor(_) } } +/** + * An instruction that refers to a variable. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * variable. For example, it is used for `VariableAddress`, which returns the address of a specific + * variable, and `InitializeParameter`, which returns the value that was passed to the specified + * parameter by the caller. `VariableInstruction` is not used for `Load` or `Store` instructions + * that happen to load from or store to a particular variable; in those cases, the memory location + * being accessed is specified by the `AddressOperand` on the instruction, which may or may not be + * defined by the result of a `VariableAddress` instruction. + */ class VariableInstruction extends Instruction { IRVariable var; - VariableInstruction() { var = Construction::getInstructionVariable(this) } + VariableInstruction() { var = Raw::getInstructionVariable(this) } override string getImmediateString() { result = var.toString() } + /** + * Gets the variable that this instruction references. + */ final IRVariable getIRVariable() { result = var } /** @@ -407,63 +444,156 @@ class VariableInstruction extends Instruction { final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that refers to a field of a class, struct, or union. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * field. For example, it is used for `FieldAddress`, which computes the address of a specific + * field on an object. `FieldInstruction` is not used for `Load` or `Store` instructions that happen + * to load from or store to a particular field; in those cases, the memory location being accessed + * is specified by the `AddressOperand` on the instruction, which may or may not be defined by the + * result of a `FieldAddress` instruction. + */ class FieldInstruction extends Instruction { Language::Field field; - FieldInstruction() { field = Construction::getInstructionField(this) } + FieldInstruction() { field = Raw::getInstructionField(this) } final override string getImmediateString() { result = field.toString() } + /** + * Gets the field that this instruction references. + */ final Language::Field getField() { result = field } } +/** + * An instruction that refers to a function. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * function. For example, it is used for `FunctionAddress`, which returns the address of a specific + * function. `FunctionInstruction` is not used for `Call` instructions that happen to call a + * particular function; in that case, the function being called is specified by the + * `CallTargetOperand` on the instruction, which may or may not be defined by the result of a + * `FunctionAddress` instruction. + */ class FunctionInstruction extends Instruction { Language::Function funcSymbol; - FunctionInstruction() { funcSymbol = Construction::getInstructionFunction(this) } + FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) } final override string getImmediateString() { result = funcSymbol.toString() } + /** + * Gets the function that this instruction references. + */ final Language::Function getFunctionSymbol() { result = funcSymbol } } +/** + * An instruction whose result is a compile-time constant value. + */ class ConstantValueInstruction extends Instruction { string value; - ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) } + ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) } final override string getImmediateString() { result = value } + /** + * Gets the constant value of this instruction's result. + */ final string getValue() { result = value } } +/** + * An instruction that refers to an argument of a `Call` instruction. + * + * This instruction is used for side effects of a `Call` instruction that read or write memory + * pointed to by one of the arguments of the call. + */ class IndexedInstruction extends Instruction { int index; - IndexedInstruction() { index = Construction::getInstructionIndex(this) } + IndexedInstruction() { index = Raw::getInstructionIndex(this) } final override string getImmediateString() { result = index.toString() } + /** + * Gets the zero-based index of the argument that this instruction references. + */ final int getIndex() { result = index } } +/** + * An instruction representing the entry point to a function. + * + * Each `IRFunction` has exactly one `EnterFunction` instruction. Execution of the function begins + * at this instruction. This instruction has no predecessors. + */ class EnterFunctionInstruction extends Instruction { EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction } } +/** + * An instruction that returns the address of a variable. + * + * This instruction returns the address of a local variable, parameter, static field, + * namespace-scope variable, or global variable. For the address of a non-static field of a class, + * struct, or union, see `FieldAddressInstruction`. + */ class VariableAddressInstruction extends VariableInstruction { VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } } +/** + * An instruction that returns the address of a function. + * + * This instruction returns the address of a function, including non-member functions, static member + * functions, and non-static member functions. + * + * The result has an `IRFunctionAddress` type. + */ +class FunctionAddressInstruction extends FunctionInstruction { + FunctionAddressInstruction() { getOpcode() instanceof Opcode::FunctionAddress } +} + +/** + * An instruction that initializes a parameter of the enclosing function with the value of the + * corresponding argument passed by the caller. + * + * Each parameter of a function will have exactly one `InitializeParameter` instruction that + * initializes that parameter. + */ class InitializeParameterInstruction extends VariableInstruction { InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that initializes all memory that existed before this function was called. + * + * This instruction provides a definition for memory that, because it was actually allocated and + * initialized elsewhere, would not otherwise have a definition in this function. + */ +class InitializeNonLocalInstruction extends Instruction { + InitializeNonLocalInstruction() { getOpcode() instanceof Opcode::InitializeNonLocal } +} + +/** + * An instruction that initializes the memory pointed to by a parameter of the enclosing function + * with the value of that memory on entry to the function. + */ class InitializeIndirectionInstruction extends VariableInstruction { InitializeIndirectionInstruction() { getOpcode() instanceof Opcode::InitializeIndirection } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } @@ -474,14 +604,42 @@ class InitializeThisInstruction extends Instruction { InitializeThisInstruction() { getOpcode() instanceof Opcode::InitializeThis } } +/** + * An instruction that computes the address of a non-static field of an object. + */ class FieldAddressInstruction extends FieldInstruction { FieldAddressInstruction() { getOpcode() instanceof Opcode::FieldAddress } + /** + * Gets the operand that provides the address of the object containing the field. + */ final UnaryOperand getObjectAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the object containing the field. + */ final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } } +/** + * An instruction that computes the address of the first element of a managed array. + * + * This instruction is used for element access to C# arrays. + */ +class ElementsAddressInstruction extends UnaryInstruction { + ElementsAddressInstruction() { getOpcode() instanceof Opcode::ElementsAddress } + + /** + * Gets the operand that provides the address of the array object. + */ + final UnaryOperand getArrayObjectAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the array object. + */ + final Instruction getArrayObjectAddress() { result = getArrayObjectAddressOperand().getDef() } +} + /** * An instruction that produces a well-defined but unknown result and has * unknown side effects, including side effects that are not conservatively @@ -496,6 +654,12 @@ class ErrorInstruction extends Instruction { ErrorInstruction() { getOpcode() instanceof Opcode::Error } } +/** + * An instruction that returns an uninitialized value. + * + * This instruction is used to provide an initial definition for a stack variable that does not have + * an initializer, or whose initializer only partially initializes the variable. + */ class UninitializedInstruction extends VariableInstruction { UninitializedInstruction() { getOpcode() instanceof Opcode::Uninitialized } @@ -505,35 +669,94 @@ class UninitializedInstruction extends VariableInstruction { final Language::Variable getLocalVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that has no effect. + * + * This instruction is typically inserted to ensure that a particular AST is associated with at + * least one instruction, even when the AST has no semantic effect. + */ class NoOpInstruction extends Instruction { NoOpInstruction() { getOpcode() instanceof Opcode::NoOp } } +/** + * An instruction that returns control to the caller of the function. + * + * This instruction represents the normal (non-exception) return from a function, either from an + * explicit `return` statement or from control flow reaching the end of the function's body. + * + * Each function has exactly one `ReturnInstruction`. Each `return` statement in a function is + * represented as an initialization of the temporary variable that holds the return value, with + * control then flowing to the common `ReturnInstruction` for that function. Exception: A function + * that never returns will not have a `ReturnInstruction`. + * + * The `ReturnInstruction` for a function will have a control-flow successor edge to a block + * containing the `ExitFunction` instruction for that function. + * + * There are two differet return instructions: `ReturnValueInstruction`, for returning a value from + * a non-`void`-returning function, and `ReturnVoidInstruction`, for returning from a + * `void`-returning function. + */ class ReturnInstruction extends Instruction { ReturnInstruction() { getOpcode() instanceof ReturnOpcode } } +/** + * An instruction that returns control to the caller of the function, without returning a value. + */ class ReturnVoidInstruction extends ReturnInstruction { ReturnVoidInstruction() { getOpcode() instanceof Opcode::ReturnVoid } } +/** + * An instruction that returns control to the caller of the function, including a return value. + */ class ReturnValueInstruction extends ReturnInstruction { ReturnValueInstruction() { getOpcode() instanceof Opcode::ReturnValue } + /** + * Gets the operand that provides the value being returned by the function. + */ final LoadOperand getReturnValueOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value being returned by the function, if an + * exact definition is available. + */ final Instruction getReturnValue() { result = getReturnValueOperand().getDef() } } +/** + * An instruction that represents the use of the value pointed to by a parameter of the function + * after the function returns control to its caller. + * + * This instruction does not itself return control to the caller. It merely represents the potential + * for a caller to use the memory pointed to by the parameter sometime after the call returns. This + * is the counterpart to the `InitializeIndirection` instruction, which represents the possibility + * that the caller initialized the memory pointed to by the parameter before the call. + */ class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } + /** + * Gets the operand that provides the value of the pointed-to memory. + */ final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the pointed-to memory, if an exact + * definition is available. + */ final Instruction getSideEffect() { result = getSideEffectOperand().getDef() } + /** + * Gets the operand that provides the address of the pointed-to memory. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the pointed-to memory. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } /** @@ -541,87 +764,191 @@ class ReturnIndirectionInstruction extends VariableInstruction { * function. */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } + + /** + * Holds if this instruction is the return indirection for `this`. + */ + final predicate isThisIndirection() { var instanceof IRThisVariable } } +/** + * An instruction that returns a copy of its operand. + * + * There are several different copy instructions, depending on the source and destination of the + * copy operation: + * - `CopyInstruction` - Copies a register operand to a register result. + * - `LoadInstruction` - Copies a memory operand to a register result. + * - `StoreInstruction` - Copies a register operand to a memory result. + */ class CopyInstruction extends Instruction { CopyInstruction() { getOpcode() instanceof CopyOpcode } + /** + * Gets the operand that provides the input value of the copy. + */ Operand getSourceValueOperand() { none() } + /** + * Gets the instruction whose result provides the input value of the copy, if an exact definition + * is available. + */ final Instruction getSourceValue() { result = getSourceValueOperand().getDef() } } +/** + * An instruction that returns a register result containing a copy of its register operand. + */ class CopyValueInstruction extends CopyInstruction, UnaryInstruction { CopyValueInstruction() { getOpcode() instanceof Opcode::CopyValue } final override UnaryOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a register result containing a copy of its memory operand. + */ class LoadInstruction extends CopyInstruction { LoadInstruction() { getOpcode() instanceof Opcode::Load } + /** + * Gets the operand that provides the address of the value being loaded. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the value being loaded. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } final override LoadOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a memory result containing a copy of its register operand. + */ class StoreInstruction extends CopyInstruction { StoreInstruction() { getOpcode() instanceof Opcode::Store } + /** + * Gets the operand that provides the address of the location to which the value will be stored. + */ final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the location to which the value will + * be stored, if an exact definition is available. + */ final Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } final override StoreValueOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that branches to one of two successor instructions based on the value of a Boolean + * operand. + */ class ConditionalBranchInstruction extends Instruction { ConditionalBranchInstruction() { getOpcode() instanceof Opcode::ConditionalBranch } + /** + * Gets the operand that provides the Boolean condition controlling the branch. + */ final ConditionOperand getConditionOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the Boolean condition controlling the branch. + */ final Instruction getCondition() { result = getConditionOperand().getDef() } + /** + * Gets the instruction to which control will flow if the condition is true. + */ final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } + /** + * Gets the instruction to which control will flow if the condition is false. + */ final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } } +/** + * An instruction representing the exit point of a function. + * + * Each `IRFunction` has exactly one `ExitFunction` instruction, unless the function neither returns + * nor throws an exception. Control flows to the `ExitFunction` instruction from both normal returns + * (`ReturnVoid`, `ReturnValue`) and propagated exceptions (`Unwind`). This instruction has no + * successors. + */ class ExitFunctionInstruction extends Instruction { ExitFunctionInstruction() { getOpcode() instanceof Opcode::ExitFunction } } +/** + * An instruction whose result is a constant value. + */ class ConstantInstruction extends ConstantValueInstruction { ConstantInstruction() { getOpcode() instanceof Opcode::Constant } } +/** + * An instruction whose result is a constant value of integer or Boolean type. + */ class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType } + IntegerConstantInstruction() { + exists(IRType resultType | + resultType = getResultIRType() and + (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType) + ) + } } +/** + * An instruction whose result is a constant value of floating-point type. + */ class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } + FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } +/** + * An instruction whose result is the address of a string literal. + */ class StringConstantInstruction extends VariableInstruction { override IRStringLiteral var; final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) } + /** + * Gets the string literal whose address is returned by this instruction. + */ final Language::StringLiteral getValue() { result = var.getLiteral() } } +/** + * An instruction whose result is computed from two operands. + */ class BinaryInstruction extends Instruction { BinaryInstruction() { getOpcode() instanceof BinaryOpcode } + /** + * Gets the left operand of this binary instruction. + */ final LeftOperand getLeftOperand() { result = getAnOperand() } + /** + * Gets the right operand of this binary instruction. + */ final RightOperand getRightOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the left operand of this binary + * instruction. + */ final Instruction getLeft() { result = getLeftOperand().getDef() } + /** + * Gets the instruction whose result provides the value of the right operand of this binary + * instruction. + */ final Instruction getRight() { result = getRightOperand().getDef() } /** @@ -634,121 +961,301 @@ class BinaryInstruction extends Instruction { } } +/** + * An instruction that computes the result of an arithmetic operation. + */ class ArithmeticInstruction extends Instruction { ArithmeticInstruction() { getOpcode() instanceof ArithmeticOpcode } } +/** + * An instruction that performs an arithmetic operation on two numeric operands. + */ class BinaryArithmeticInstruction extends ArithmeticInstruction, BinaryInstruction { } +/** + * An instruction whose result is computed by performing an arithmetic operation on a single + * numeric operand. + */ class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction { } +/** + * An instruction that computes the sum of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point addition is + * performed according to IEEE-754. + */ class AddInstruction extends BinaryArithmeticInstruction { AddInstruction() { getOpcode() instanceof Opcode::Add } } +/** + * An instruction that computes the difference of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point subtraction is performed + * according to IEEE-754. + */ class SubInstruction extends BinaryArithmeticInstruction { SubInstruction() { getOpcode() instanceof Opcode::Sub } } +/** + * An instruction that computes the product of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point multiplication is + * performed according to IEEE-754. + */ class MulInstruction extends BinaryArithmeticInstruction { MulInstruction() { getOpcode() instanceof Opcode::Mul } } +/** + * An instruction that computes the quotient of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. Floating-point division is performed according + * to IEEE-754. + */ class DivInstruction extends BinaryArithmeticInstruction { DivInstruction() { getOpcode() instanceof Opcode::Div } } +/** + * An instruction that computes the remainder of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. + */ class RemInstruction extends BinaryArithmeticInstruction { RemInstruction() { getOpcode() instanceof Opcode::Rem } } +/** + * An instruction that negates a single numeric operand. + * + * The operand must have a numeric type, which will also be the result type. The result of integer + * negation uses two's complement, and is computed modulo 2^n. The result of floating-point negation + * is performed according to IEEE-754. + */ class NegateInstruction extends UnaryArithmeticInstruction { NegateInstruction() { getOpcode() instanceof Opcode::Negate } } +/** + * An instruction that computes the result of a bitwise operation. + */ class BitwiseInstruction extends Instruction { BitwiseInstruction() { getOpcode() instanceof BitwiseOpcode } } +/** + * An instruction that performs a bitwise operation on two integer operands. + */ class BinaryBitwiseInstruction extends BitwiseInstruction, BinaryInstruction { } +/** + * An instruction that performs a bitwise operation on a single integer operand. + */ class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } +/** + * An instruction that computes the bitwise "and" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitAndInstruction extends BinaryBitwiseInstruction { BitAndInstruction() { getOpcode() instanceof Opcode::BitAnd } } +/** + * An instruction that computes the bitwise "or" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitOrInstruction extends BinaryBitwiseInstruction { BitOrInstruction() { getOpcode() instanceof Opcode::BitOr } } +/** + * An instruction that computes the bitwise "xor" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitXorInstruction extends BinaryBitwiseInstruction { BitXorInstruction() { getOpcode() instanceof Opcode::BitXor } } +/** + * An instruction that shifts its left operand to the left by the number of bits specified by its + * right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. The + * rightmost bits are zero-filled. + */ class ShiftLeftInstruction extends BinaryBitwiseInstruction { ShiftLeftInstruction() { getOpcode() instanceof Opcode::ShiftLeft } } +/** + * An instruction that shifts its left operand to the right by the number of bits specified by its + * right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. If the + * left operand has an unsigned integer type, the leftmost bits are zero-filled. If the left operand + * has a signed integer type, the leftmost bits are filled by duplicating the most significant bit + * of the left operand. + */ class ShiftRightInstruction extends BinaryBitwiseInstruction { ShiftRightInstruction() { getOpcode() instanceof Opcode::ShiftRight } } +/** + * An instruction that performs a binary arithmetic operation involving at least one pointer + * operand. + */ class PointerArithmeticInstruction extends BinaryInstruction { int elementSize; PointerArithmeticInstruction() { getOpcode() instanceof PointerArithmeticOpcode and - elementSize = Construction::getInstructionElementSize(this) + elementSize = Raw::getInstructionElementSize(this) } final override string getImmediateString() { result = elementSize.toString() } + /** + * Gets the size of the elements pointed to by the pointer operands, in bytes. + * + * When adding an integer offset to a pointer (`PointerAddInstruction`) or subtracting an integer + * offset from a pointer (`PointerSubInstruction`), the integer offset is multiplied by the + * element size to compute the actual number of bytes added to or subtracted from the pointer + * address. When computing the integer difference between two pointers (`PointerDiffInstruction`), + * the result is computed by computing the difference between the two pointer byte addresses, then + * dividing that byte count by the element size. + */ final int getElementSize() { result = elementSize } } +/** + * An instruction that adds or subtracts an integer offset from a pointer. + */ class PointerOffsetInstruction extends PointerArithmeticInstruction { PointerOffsetInstruction() { getOpcode() instanceof PointerOffsetOpcode } } +/** + * An instruction that adds an integer offset to a pointer. + * + * The result is the byte address computed by adding the value of the right (integer) operand, + * multiplied by the element size, to the value of the left (pointer) operand. The result of pointer + * overflow is undefined. + */ class PointerAddInstruction extends PointerOffsetInstruction { PointerAddInstruction() { getOpcode() instanceof Opcode::PointerAdd } } +/** + * An instruction that subtracts an integer offset from a pointer. + * + * The result is the byte address computed by subtracting the value of the right (integer) operand, + * multiplied by the element size, from the value of the left (pointer) operand. The result of + * pointer underflow is undefined. + */ class PointerSubInstruction extends PointerOffsetInstruction { PointerSubInstruction() { getOpcode() instanceof Opcode::PointerSub } } +/** + * An instruction that computes the difference between two pointers. + * + * Both operands must have the same pointer type. The result must have an integer type whose size is + * the same as that of the pointer operands. The result is computed by subtracting the byte address + * in the right operand from the byte address in the left operand, and dividing by the element size. + * If the difference in byte addresses is not divisible by the element size, the result is + * undefined. + */ class PointerDiffInstruction extends PointerArithmeticInstruction { PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff } } +/** + * An instruction whose result is computed from a single operand. + */ class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } + /** + * Gets the sole operand of this instruction. + */ final UnaryOperand getUnaryOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the sole operand of this instruction. + */ final Instruction getUnary() { result = getUnaryOperand().getDef() } } +/** + * An instruction that converts the value of its operand to a value of a different type. + */ class ConvertInstruction extends UnaryInstruction { ConvertInstruction() { getOpcode() instanceof Opcode::Convert } } +/** + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, returning a null address if the dynamic type of the + * object is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a pointer type, or a C# `is` or + * `as` expression. + */ class CheckedConvertOrNullInstruction extends UnaryInstruction { CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull } } /** - * Represents an instruction that converts between two addresses - * related by inheritance. + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, throwing an exception if the dynamic type of the object + * is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a reference type, or a C# cast + * expression. + */ +class CheckedConvertOrThrowInstruction extends UnaryInstruction { + CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } +} + +/** + * An instruction that returns the address of the complete object that contains the subobject + * pointed to by its operand. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent `dyanmic_cast` in C++, which returns the pointer to + * the most-derived object. + */ +class CompleteObjectAddressInstruction extends UnaryInstruction { + CompleteObjectAddressInstruction() { getOpcode() instanceof Opcode::CompleteObjectAddress } +} + +/** + * An instruction that converts the address of an object to the address of a different subobject of + * the same object, without any type checking at runtime. */ class InheritanceConversionInstruction extends UnaryInstruction { Language::Class baseClass; Language::Class derivedClass; InheritanceConversionInstruction() { - Construction::getInstructionInheritance(this, baseClass, derivedClass) + Raw::getInstructionInheritance(this, baseClass, derivedClass) } final override string getImmediateString() { @@ -778,59 +1285,91 @@ class InheritanceConversionInstruction extends UnaryInstruction { } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a base class. + * An instruction that converts from the address of a derived class to the address of a base class. */ class ConvertToBaseInstruction extends InheritanceConversionInstruction { ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a direct non-virtual base class. + * An instruction that converts from the address of a derived class to the address of a direct + * non-virtual base class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToNonVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToNonVirtualBase } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a virtual base class. + * An instruction that converts from the address of a derived class to the address of a virtual base + * class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToVirtualBase } } /** - * Represents an instruction that converts from the address of a base class - * to the address of a direct non-virtual derived class. + * An instruction that converts from the address of a base class to the address of a direct + * non-virtual derived class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToDerivedInstruction extends InheritanceConversionInstruction { ConvertToDerivedInstruction() { getOpcode() instanceof Opcode::ConvertToDerived } } +/** + * An instruction that computes the bitwise complement of its operand. + * + * The operand must have an integer type, which will also be the result type. + */ class BitComplementInstruction extends UnaryBitwiseInstruction { BitComplementInstruction() { getOpcode() instanceof Opcode::BitComplement } } +/** + * An instruction that computes the logical complement of its operand. + * + * The operand must have a Boolean type, which will also be the result type. + */ class LogicalNotInstruction extends UnaryInstruction { LogicalNotInstruction() { getOpcode() instanceof Opcode::LogicalNot } } +/** + * An instruction that compares two numeric operands. + */ class CompareInstruction extends BinaryInstruction { CompareInstruction() { getOpcode() instanceof CompareOpcode } } +/** + * An instruction that returns a `true` result if its operands are equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left == right`, and `false` if `left != right` or the two operands are + * unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareEQInstruction extends CompareInstruction { CompareEQInstruction() { getOpcode() instanceof Opcode::CompareEQ } } +/** + * An instruction that returns a `true` result if its operands are not equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left != right` or if the two operands are unordered, and `false` if + * `left == right`. Floating-point comparison is performed according to IEEE-754. + */ class CompareNEInstruction extends CompareInstruction { CompareNEInstruction() { getOpcode() instanceof Opcode::CompareNE } } /** - * Represents an instruction that does a relative comparison of two values, such as `<` or `>=`. + * An instruction that does a relative comparison of two values, such as `<` or `>=`. */ class RelationalInstruction extends CompareInstruction { RelationalInstruction() { getOpcode() instanceof RelationalOpcode } @@ -857,6 +1396,13 @@ class RelationalInstruction extends CompareInstruction { predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is less than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left < right`, and `false` if `left >= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLTInstruction extends RelationalInstruction { CompareLTInstruction() { getOpcode() instanceof Opcode::CompareLT } @@ -867,6 +1413,13 @@ class CompareLTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is greater than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left > right`, and `false` if `left <= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGTInstruction extends RelationalInstruction { CompareGTInstruction() { getOpcode() instanceof Opcode::CompareGT } @@ -877,6 +1430,14 @@ class CompareGTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is less than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left <= right`, and `false` if `left > right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLEInstruction extends RelationalInstruction { CompareLEInstruction() { getOpcode() instanceof Opcode::CompareLE } @@ -887,6 +1448,14 @@ class CompareLEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is greater than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left >= right`, and `false` if `left < right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGEInstruction extends RelationalInstruction { CompareGEInstruction() { getOpcode() instanceof Opcode::CompareGE } @@ -897,15 +1466,32 @@ class CompareGEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that branches to one of multiple successor instructions based on the value of an + * integer operand. + * + * This instruction will have zero or more successors whose edge kind is `CaseEdge`, each + * representing the branch that will be taken if the controlling expression is within the range + * specified for that case edge. The range of a case edge must be disjoint from the range of each + * other case edge. + * + * The instruction may optionally have a successor edge whose edge kind is `DefaultEdge`, + * representing the branch that will be taken if the controlling expression is not within the range + * of any case edge. + */ class SwitchInstruction extends Instruction { SwitchInstruction() { getOpcode() instanceof Opcode::Switch } + /** Gets the operand that provides the integer value controlling the switch. */ final ConditionOperand getExpressionOperand() { result = getAnOperand() } + /** Gets the instruction whose result provides the integer value controlling the switch. */ final Instruction getExpression() { result = getExpressionOperand().getDef() } + /** Gets the successor instructions along the case edges of the switch. */ final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } + /** Gets the successor instruction along the default edge of the switch, if any. */ final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } } @@ -936,7 +1522,7 @@ class CallInstruction extends Instruction { * Gets the `Function` that the call targets, if this is statically known. */ final Language::Function getStaticCallTarget() { - result = getCallTarget().(FunctionInstruction).getFunctionSymbol() + result = getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() } /** @@ -981,6 +1567,9 @@ class CallInstruction extends Instruction { class SideEffectInstruction extends Instruction { SideEffectInstruction() { getOpcode() instanceof SideEffectOpcode } + /** + * Gets the instruction whose execution causes this side effect. + */ final Instruction getPrimaryInstruction() { result = Construction::getPrimaryInstructionForSideEffect(this) } @@ -996,9 +1585,10 @@ class CallSideEffectInstruction extends SideEffectInstruction { /** * An instruction representing the side effect of a function call on any memory - * that might be read by that call. This instruction is emitted instead of - * `CallSideEffectInstruction` when it's certain that the call target cannot - * write to escaped memory. + * that might be read by that call. + * + * This instruction is emitted instead of `CallSideEffectInstruction` when it is certain that the + * call target cannot write to escaped memory. */ class CallReadSideEffectInstruction extends SideEffectInstruction { CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect } @@ -1046,7 +1636,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { getOpcode() instanceof Opcode::SizedBufferReadSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes read from the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes read from the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1056,7 +1654,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } + /** + * Get the operand that holds the address of the memory to be written. + */ + final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the memory to be written. + */ + Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } } /** @@ -1087,11 +1693,20 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** * An instruction representing the potential write of an indirect parameter within a function call. + * * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. * written. */ @@ -1103,6 +1718,7 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1111,6 +1727,7 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1118,11 +1735,19 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** - * An instruction representing the initial value of newly allocated memory, e.g. the result of a + * An instruction representing the initial value of newly allocated memory, such as the result of a * call to `malloc`. */ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { @@ -1211,7 +1836,7 @@ class CatchByTypeInstruction extends CatchInstruction { CatchByTypeInstruction() { getOpcode() instanceof Opcode::CatchByType and - exceptionType = Construction::getInstructionExceptionType(this) + exceptionType = Raw::getInstructionExceptionType(this) } final override string getImmediateString() { result = exceptionType.toString() } @@ -1337,29 +1962,43 @@ class ChiInstruction extends Instruction { * Gets the operand that represents the new value written by the memory write. */ final Instruction getPartial() { result = getPartialOperand().getDef() } + + /** + * Gets the bit range `[startBit, endBit)` updated by the partial operand of this `ChiInstruction`, relative to the start address of the total operand. + */ + final predicate getUpdatedInterval(int startBit, int endBit) { + Construction::getIntervalUpdatedByChi(this, startBit, endBit) + } } /** - * An instruction representing unreachable code. Inserted in place of the original target - * instruction of a `ConditionalBranch` or `Switch` instruction where that particular edge is - * infeasible. + * An instruction representing unreachable code. + * + * This instruction is inserted in place of the original target instruction of a `ConditionalBranch` + * or `Switch` instruction where that particular edge is infeasible. */ class UnreachedInstruction extends Instruction { UnreachedInstruction() { getOpcode() instanceof Opcode::Unreached } } /** - * An instruction representing a built-in operation. This is used to represent - * operations such as access to variable argument lists. + * An instruction representing a built-in operation. + * + * This is used to represent a variety of intrinsic operations provided by the compiler + * implementation, such as vector arithmetic. */ class BuiltInOperationInstruction extends Instruction { Language::BuiltInOperation operation; BuiltInOperationInstruction() { getOpcode() instanceof BuiltInOperationOpcode and - operation = Construction::getInstructionBuiltInOperation(this) + operation = Raw::getInstructionBuiltInOperation(this) } + /** + * Gets the language-specific `BuiltInOperation` object that specifies the operation that is + * performed by this instruction. + */ final Language::BuiltInOperation getBuiltInOperation() { result = operation } } @@ -1372,3 +2011,59 @@ class BuiltInInstruction extends BuiltInOperationInstruction { final override string getImmediateString() { result = getBuiltInOperation().toString() } } + +/** + * An instruction that returns a `va_list` to access the arguments passed to the `...` parameter. + * + * The operand specifies the address of the `IREllipsisVariable` used to represent the `...` + * parameter. The result is a `va_list` that initially refers to the first argument that was passed + * to the `...` parameter. + */ +class VarArgsStartInstruction extends UnaryInstruction { + VarArgsStartInstruction() { getOpcode() instanceof Opcode::VarArgsStart } +} + +/** + * An instruction that cleans up a `va_list` after it is no longer in use. + * + * The operand specifies the address of the `va_list` to clean up. This instruction does not return + * a result. + */ +class VarArgsEndInstruction extends UnaryInstruction { + VarArgsEndInstruction() { getOpcode() instanceof Opcode::VarArgsEnd } +} + +/** + * An instruction that returns the address of the argument currently pointed to by a `va_list`. + * + * The operand is the `va_list` that points to the argument. The result is the address of the + * argument. + */ +class VarArgInstruction extends UnaryInstruction { + VarArgInstruction() { getOpcode() instanceof Opcode::VarArg } +} + +/** + * An instruction that modifies a `va_list` to point to the next argument that was passed to the + * `...` parameter. + * + * The operand is the current `va_list`. The result is an updated `va_list` that points to the next + * argument of the `...` parameter. + */ +class NextVarArgInstruction extends UnaryInstruction { + NextVarArgInstruction() { getOpcode() instanceof Opcode::NextVarArg } +} + +/** + * An instruction that allocates a new object on the managed heap. + * + * This instruction is used to represent the allocation of a new object in C# using the `new` + * expression. This instruction does not invoke a constructor for the object. Instead, there will be + * a subsequent `Call` instruction to invoke the appropriate constructor directory, passing the + * result of the `NewObj` as the `this` argument. + * + * The result is the address of the newly allocated object. + */ +class NewObjInstruction extends Instruction { + NewObjInstruction() { getOpcode() instanceof Opcode::NewObj } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll index f82704094c8e..a12e35d471b8 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the input values of IR instructions. + */ + private import internal.IRInternal private import Instruction private import IRBlock @@ -75,13 +79,21 @@ private PhiOperandBase phiOperand( } /** - * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. + * An operand of an `Instruction`. The operand represents a use of the result of one instruction + * (the defining instruction) in another instruction (the use instruction) */ class Operand extends TOperand { + /** Gets a textual representation of this element. */ string toString() { result = "Operand" } + /** + * Gets the location of the source code for this operand. + */ final Language::Location getLocation() { result = getUse().getLocation() } + /** + * Gets the function that contains this operand. + */ final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() } /** @@ -139,6 +151,11 @@ class Operand extends TOperand { */ string getDumpLabel() { result = "" } + /** + * Gets a string that uniquely identifies this operand on its use instruction. + */ + string getDumpId() { result = "" } + /** * Gets a string describing this operand, suitable for display in IR dumps. This consists of the * result ID of the instruction consumed by the operand, plus a label identifying the operand @@ -268,8 +285,13 @@ class NonPhiOperand extends Operand { final override string getDumpLabel() { result = tag.getLabel() } + final override string getDumpId() { result = tag.getId() } + final override int getDumpSortOrder() { result = tag.getSortOrder() } + /** + * Gets the `OperandTag` that specifies how this operand is used by its `Instruction`. + */ final OperandTag getOperandTag() { result = tag } } @@ -292,6 +314,9 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { } } +/** + * A memory operand other than the operand of a `Phi` instruction. + */ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; @@ -311,8 +336,19 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper not Construction::isInCycle(useInstr) and strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 } + + /** + * Holds if the operand totally overlaps with its definition and consumes the + * bit range `[startBitOffset, endBitOffset)` relative to the start address of the definition. + */ + predicate getUsedInterval(int startBitOffset, int endBitOffset) { + Construction::getUsedInterval(this, startBitOffset, endBitOffset) + } } +/** + * A memory operand whose type may be different from the type of the result of its definition. + */ class TypedOperand extends NonPhiMemoryOperand { override TypedOperandTag tag; @@ -416,6 +452,9 @@ class PositionalArgumentOperand extends ArgumentOperand { final int getIndex() { result = tag.getArgIndex() } } +/** + * An operand representing memory read as a side effect of evaluating another instruction. + */ class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; } @@ -445,6 +484,8 @@ class PhiInputOperand extends MemoryOperand, PhiOperandBase { result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":" } + final override string getDumpId() { result = getPredecessorBlock().getDisplayIndex().toString() } + /** * Gets the predecessor block from which this value comes. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll index d9c0df44e12e..59dadee71545 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll @@ -1,3 +1,13 @@ +/** + * Outputs a representation of the IR as a control flow graph. + * + * This file contains the actual implementation of `PrintIR.ql`. For test cases and very small + * databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintIR.qll`, extends + * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to + * dump. + */ + private import internal.IRInternal private import IR private import internal.PrintIRImports as Imports @@ -9,6 +19,7 @@ private newtype TPrintIRConfiguration = MkPrintIRConfiguration() * The query can extend this class to control which functions are printed. */ class PrintIRConfiguration extends TPrintIRConfiguration { + /** Gets a textual representation of this configuration. */ string toString() { result = "PrintIRConfiguration" } /** @@ -39,6 +50,37 @@ private string getAdditionalBlockProperty(IRBlock block, string key) { exists(IRPropertyProvider provider | result = provider.getBlockProperty(block, key)) } +/** + * Gets the properties of an operand from any active property providers. + */ +private string getAdditionalOperandProperty(Operand operand, string key) { + exists(IRPropertyProvider provider | result = provider.getOperandProperty(operand, key)) +} + +/** + * Gets a string listing the properties of the operand and their corresponding values. If the + * operand has no properties, this predicate has no result. + */ +private string getOperandPropertyListString(Operand operand) { + result = + strictconcat(string key, string value | + value = getAdditionalOperandProperty(operand, key) + | + key + ":" + value, ", " + ) +} + +/** + * Gets a string listing the properties of the operand and their corresponding values. The list is + * surrounded by curly braces. If the operand has no properties, this predicate returns an empty + * string. + */ +private string getOperandPropertyString(Operand operand) { + result = "{" + getOperandPropertyListString(operand) + "}" + or + not exists(getOperandPropertyListString(operand)) and result = "" +} + private newtype TPrintableIRNode = TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or @@ -47,7 +89,7 @@ private newtype TPrintableIRNode = /** * A node to be emitted in the IR graph. */ -abstract class PrintableIRNode extends TPrintableIRNode { +abstract private class PrintableIRNode extends TPrintableIRNode { abstract string toString(); /** @@ -98,7 +140,7 @@ abstract class PrintableIRNode extends TPrintableIRNode { /** * An IR graph node representing a `IRFunction` object. */ -class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { +private class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { IRFunction irFunc; PrintableIRFunction() { this = TPrintableIRFunction(irFunc) } @@ -129,7 +171,7 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { /** * An IR graph node representing an `IRBlock` object. */ -class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { +private class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { IRBlock block; PrintableIRBlock() { this = TPrintableIRBlock(block) } @@ -161,7 +203,7 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { /** * An IR graph node representing an `Instruction`. */ -class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { +private class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { Instruction instr; PrintableInstruction() { this = TPrintableInstruction(instr) } @@ -179,7 +221,7 @@ class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { | resultString = instr.getResultString() and operationString = instr.getOperationString() and - operandsString = instr.getOperandsString() and + operandsString = getOperandsString() and columnWidths(block, resultWidth, operationWidth) and result = resultString + getPaddingString(resultWidth - resultString.length()) + " = " + @@ -199,6 +241,22 @@ class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { result = PrintableIRNode.super.getProperty(key) or result = getAdditionalInstructionProperty(instr, key) } + + /** + * Gets the string representation of the operand list. This is the same as + * `Instruction::getOperandsString()`, except that each operand is annotated with any properties + * provided by active `IRPropertyProvider` instances. + */ + private string getOperandsString() { + result = + concat(Operand operand | + operand = instr.getAnOperand() + | + operand.getDumpString() + getOperandPropertyString(operand), ", " + order by + operand.getDumpSortOrder() + ) + } } private predicate columnWidths(IRBlock block, int resultWidth, int operationWidth) { @@ -224,6 +282,9 @@ private string getPaddingString(int n) { n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " " } +/** + * Holds if `node` belongs to the output graph, and its property `key` has the given `value`. + */ query predicate nodes(PrintableIRNode node, string key, string value) { value = node.getProperty(key) } @@ -237,6 +298,10 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) { ) } +/** + * Holds if the output graph contains an edge from `pred` to `succ`, and that edge's property `key` + * has the given `value`. + */ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | predBlock = pred.getBlock() and @@ -256,6 +321,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, ) } +/** + * Holds if `parent` is the parent node of `child` in the output graph. + */ query predicate parents(PrintableIRNode child, PrintableIRNode parent) { parent = child.getParent() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll index 5200da91a55c..f6e27e080f7d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll @@ -1,6 +1,9 @@ private import cpp import semmle.code.cpp.ir.implementation.raw.IR private import semmle.code.cpp.ir.implementation.internal.OperandTag +private import semmle.code.cpp.ir.implementation.internal.IRFunctionBase +private import semmle.code.cpp.ir.implementation.internal.TInstruction +private import semmle.code.cpp.ir.implementation.internal.TIRVariable private import semmle.code.cpp.ir.internal.CppType private import semmle.code.cpp.ir.internal.Overlap private import semmle.code.cpp.ir.internal.TempVariableTag @@ -12,34 +15,36 @@ private import TranslatedStmt private import TranslatedFunction TranslatedElement getInstructionTranslatedElement(Instruction instruction) { - instruction = MkInstruction(result, _) + instruction = TRawInstruction(result, _) } -InstructionTag getInstructionTag(Instruction instruction) { instruction = MkInstruction(_, result) } - -import Cached +InstructionTag getInstructionTag(Instruction instruction) { + instruction = TRawInstruction(_, result) +} +/** + * Provides the portion of the parameterized IR interface that is used to construct the initial + * "raw" stage of the IR. The other stages of the IR do not expose these predicates. + */ cached -private module Cached { +module Raw { + class InstructionTag1 = TranslatedElement; + + class InstructionTag2 = InstructionTag; + cached predicate functionHasIR(Function func) { exists(getTranslatedFunction(func)) } cached - newtype TInstruction = - MkInstruction(TranslatedElement element, InstructionTag tag) { - element.hasInstruction(_, tag, _) - } + predicate hasInstruction(TranslatedElement element, InstructionTag tag) { + element.hasInstruction(_, tag, _) + } cached predicate hasUserVariable(Function func, Variable var, CppType type) { getTranslatedFunction(func).hasUserVariable(var, type) } - cached - predicate hasThisVariable(Function func, CppType type) { - type = getTypeForGLValue(getTranslatedFunction(func).getThisType()) - } - cached predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, CppType type) { exists(TranslatedElement element | @@ -64,232 +69,7 @@ private module Cached { } cached - predicate hasModeledMemoryResult(Instruction instruction) { none() } - - cached - predicate hasConflatedMemoryResult(Instruction instruction) { - instruction instanceof AliasedDefinitionInstruction - or - instruction.getOpcode() instanceof Opcode::InitializeNonLocal - } - - cached - Expr getInstructionConvertedResultExpression(Instruction instruction) { - exists(TranslatedExpr translatedExpr | - translatedExpr = getTranslatedExpr(result) and - instruction = translatedExpr.getResult() and - // Only associate `instruction` with this expression if the translated - // expression actually produced the instruction; not if it merely - // forwarded the result of another translated expression. - instruction = translatedExpr.getInstruction(_) - ) - } - - cached - Expr getInstructionUnconvertedResultExpression(Instruction instruction) { - result = getInstructionConvertedResultExpression(instruction).getUnconverted() - } - - cached - Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) { - result = - getInstructionTranslatedElement(instruction) - .getInstructionRegisterOperand(getInstructionTag(instruction), tag) - } - - cached - Instruction getMemoryOperandDefinition( - Instruction instruction, MemoryOperandTag tag, Overlap overlap - ) { - none() - } - - /** Gets a non-phi instruction that defines an operand of `instr`. */ - private Instruction getNonPhiOperandDef(Instruction instr) { - result = getRegisterOperandDefinition(instr, _) - or - result = getMemoryOperandDefinition(instr, _, _) - } - - /** - * Gets a non-phi instruction that defines an operand of `instr` but only if - * both `instr` and the result have neighbor on the other side of the edge - * between them. This is a necessary condition for being in a cycle, and it - * removes about two thirds of the tuples that would otherwise be in this - * predicate. - */ - private Instruction getNonPhiOperandDefOfIntermediate(Instruction instr) { - result = getNonPhiOperandDef(instr) and - exists(getNonPhiOperandDef(result)) and - instr = getNonPhiOperandDef(_) - } - - /** - * Holds if `instr` is part of a cycle in the operand graph that doesn't go - * through a phi instruction and therefore should be impossible. - * - * If such cycles are present, either due to a programming error in the IR - * generation or due to a malformed database, it can cause infinite loops in - * analyses that assume a cycle-free graph of non-phi operands. Therefore it's - * better to remove these operands than to leave cycles in the operand graph. - */ - pragma[noopt] - cached - predicate isInCycle(Instruction instr) { - instr instanceof Instruction and - getNonPhiOperandDefOfIntermediate+(instr) = instr - } - - cached - CppType getInstructionOperandType(Instruction instruction, TypedOperandTag tag) { - // For all `LoadInstruction`s, the operand type of the `LoadOperand` is the same as - // the result type of the load. - tag instanceof LoadOperandTag and - result = instruction.(LoadInstruction).getResultLanguageType() - or - not instruction instanceof LoadInstruction and - result = - getInstructionTranslatedElement(instruction) - .getInstructionMemoryOperandType(getInstructionTag(instruction), tag) - } - - cached - Instruction getPhiOperandDefinition( - PhiInstruction instruction, IRBlock predecessorBlock, Overlap overlap - ) { - none() - } - - cached - Instruction getPhiInstructionBlockStart(PhiInstruction instr) { none() } - - cached - Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) { - result = - getInstructionTranslatedElement(instruction) - .getInstructionSuccessor(getInstructionTag(instruction), kind) - } - - /** - * Holds if the CFG edge (`sourceElement`, `sourceTag`) ---`kind`--> - * `targetInstruction` is a back edge under the condition that - * `requiredAncestor` is an ancestor of `sourceElement`. - */ - private predicate backEdgeCandidate( - TranslatedElement sourceElement, InstructionTag sourceTag, TranslatedElement requiredAncestor, - Instruction targetInstruction, EdgeKind kind - ) { - // While loop: - // Any edge from within the body of the loop to the condition of the loop - // is a back edge. This includes edges from `continue` and the fall-through - // edge(s) after the last instruction(s) in the body. - exists(TranslatedWhileStmt s | - targetInstruction = s.getFirstConditionInstruction() and - targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and - requiredAncestor = s.getBody() - ) - or - // Do-while loop: - // The back edge should be the edge(s) from the condition to the - // body. This ensures that it's the back edge that will be pruned in a `do - // { ... } while (0)` statement. Note that all `continue` statements in a - // do-while loop produce forward edges. - exists(TranslatedDoStmt s | - targetInstruction = s.getBody().getFirstInstruction() and - targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and - requiredAncestor = s.getCondition() - ) - or - // For loop: - // Any edge from within the body or update of the loop to the condition of - // the loop is a back edge. When there is no loop update expression, this - // includes edges from `continue` and the fall-through edge(s) after the - // last instruction(s) in the body. A for loop may not have a condition, in - // which case `getFirstConditionInstruction` returns the body instead. - exists(TranslatedForStmt s | - targetInstruction = s.getFirstConditionInstruction() and - targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and - ( - requiredAncestor = s.getUpdate() - or - not exists(s.getUpdate()) and - requiredAncestor = s.getBody() - ) - ) - or - // Range-based for loop: - // Any edge from within the update of the loop to the condition of - // the loop is a back edge. - exists(TranslatedRangeBasedForStmt s | - targetInstruction = s.getCondition().getFirstInstruction() and - targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and - requiredAncestor = s.getUpdate() - ) - } - - private predicate jumpSourceHasAncestor(TranslatedElement jumpSource, TranslatedElement ancestor) { - backEdgeCandidate(jumpSource, _, _, _, _) and - ancestor = jumpSource - or - // For performance, we don't want a fastTC here - jumpSourceHasAncestor(jumpSource, ancestor.getAChild()) - } - - cached - Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) { - exists( - TranslatedElement sourceElement, InstructionTag sourceTag, TranslatedElement requiredAncestor - | - backEdgeCandidate(sourceElement, sourceTag, requiredAncestor, result, kind) and - jumpSourceHasAncestor(sourceElement, requiredAncestor) and - instruction = sourceElement.getInstruction(sourceTag) - ) - or - // Goto statement: - // As a conservative approximation, any edge out of `goto` is a back edge - // unless it goes strictly forward in the program text. A `goto` whose - // source and target are both inside a macro will be seen as having the - // same location for source and target, so we conservatively assume that - // such a `goto` creates a back edge. - exists(TranslatedElement s, GotoStmt goto | - not isStrictlyForwardGoto(goto) and - goto = s.getAST() and - exists(InstructionTag tag | - result = s.getInstructionSuccessor(tag, kind) and - instruction = s.getInstruction(tag) - ) - ) - } - - /** Holds if `goto` jumps strictly forward in the program text. */ - private predicate isStrictlyForwardGoto(GotoStmt goto) { - goto.getLocation().isBefore(goto.getTarget().getLocation()) - } - - cached - Locatable getInstructionAST(Instruction instruction) { - result = getInstructionTranslatedElement(instruction).getAST() - } - - cached - CppType getInstructionResultType(Instruction instruction) { - getInstructionTranslatedElement(instruction) - .hasInstruction(_, getInstructionTag(instruction), result) - } - - cached - Opcode getInstructionOpcode(Instruction instruction) { - getInstructionTranslatedElement(instruction) - .hasInstruction(result, getInstructionTag(instruction), _) - } - - cached - IRFunction getInstructionEnclosingIRFunction(Instruction instruction) { - result.getFunction() = getInstructionTranslatedElement(instruction).getFunction() - } - - cached - IRVariable getInstructionVariable(Instruction instruction) { + TIRVariable getInstructionVariable(Instruction instruction) { exists(TranslatedElement element, InstructionTag tag | element = getInstructionTranslatedElement(instruction) and tag = getInstructionTag(instruction) and @@ -302,10 +82,9 @@ private module Cached { cached Field getInstructionField(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and - result = element.getInstructionField(tag) - ) + result = + getInstructionTranslatedElement(instruction) + .getInstructionField(getInstructionTag(instruction)) } cached @@ -324,10 +103,9 @@ private module Cached { cached int getInstructionIndex(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and - result = element.getInstructionIndex(tag) - ) + result = + getInstructionTranslatedElement(instruction) + .getInstructionIndex(getInstructionTag(instruction)) } cached @@ -350,20 +128,11 @@ private module Cached { .getInstructionInheritance(getInstructionTag(instruction), baseClass, derivedClass) } - pragma[noinline] - private predicate instructionOrigin( - Instruction instruction, TranslatedElement element, InstructionTag tag - ) { - element = getInstructionTranslatedElement(instruction) and - tag = getInstructionTag(instruction) - } - cached int getInstructionElementSize(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and - result = element.getInstructionElementSize(tag) - ) + result = + getInstructionTranslatedElement(instruction) + .getInstructionElementSize(getInstructionTag(instruction)) } cached @@ -372,22 +141,237 @@ private module Cached { } cached - int getInstructionResultSize(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and - result = element.getInstructionResultSize(tag) + Expr getInstructionConvertedResultExpression(Instruction instruction) { + exists(TranslatedExpr translatedExpr | + translatedExpr = getTranslatedExpr(result) and + instruction = translatedExpr.getResult() and + // Only associate `instruction` with this expression if the translated + // expression actually produced the instruction; not if it merely + // forwarded the result of another translated expression. + instruction = translatedExpr.getInstruction(_) ) } cached - Instruction getPrimaryInstructionForSideEffect(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and - result = element.getPrimaryInstructionForSideEffect(tag) - ) + Expr getInstructionUnconvertedResultExpression(Instruction instruction) { + result = getInstructionConvertedResultExpression(instruction).getUnconverted() } } +class TStageInstruction = TRawInstruction; + +predicate hasInstruction(TRawInstruction instr) { any() } + +predicate hasModeledMemoryResult(Instruction instruction) { none() } + +predicate hasConflatedMemoryResult(Instruction instruction) { + instruction instanceof AliasedDefinitionInstruction + or + instruction.getOpcode() instanceof Opcode::InitializeNonLocal +} + +Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) { + result = + getInstructionTranslatedElement(instruction) + .getInstructionRegisterOperand(getInstructionTag(instruction), tag) +} + +Instruction getMemoryOperandDefinition( + Instruction instruction, MemoryOperandTag tag, Overlap overlap +) { + none() +} + +/** + * Holds if the partial operand of this `ChiInstruction` updates the bit range + * `[startBitOffset, endBitOffset)` of the total operand. + */ +predicate getIntervalUpdatedByChi(ChiInstruction chi, int startBit, int endBit) { none() } + +/** + * Holds if the operand totally overlaps with its definition and consumes the + * bit range `[startBitOffset, endBitOffset)`. + */ +predicate getUsedInterval(Operand operand, int startBit, int endBit) { none() } + +/** Gets a non-phi instruction that defines an operand of `instr`. */ +private Instruction getNonPhiOperandDef(Instruction instr) { + result = getRegisterOperandDefinition(instr, _) + or + result = getMemoryOperandDefinition(instr, _, _) +} + +/** + * Gets a non-phi instruction that defines an operand of `instr` but only if + * both `instr` and the result have neighbor on the other side of the edge + * between them. This is a necessary condition for being in a cycle, and it + * removes about two thirds of the tuples that would otherwise be in this + * predicate. + */ +private Instruction getNonPhiOperandDefOfIntermediate(Instruction instr) { + result = getNonPhiOperandDef(instr) and + exists(getNonPhiOperandDef(result)) and + instr = getNonPhiOperandDef(_) +} + +/** + * Holds if `instr` is part of a cycle in the operand graph that doesn't go + * through a phi instruction and therefore should be impossible. + * + * If such cycles are present, either due to a programming error in the IR + * generation or due to a malformed database, it can cause infinite loops in + * analyses that assume a cycle-free graph of non-phi operands. Therefore it's + * better to remove these operands than to leave cycles in the operand graph. + */ +pragma[noopt] +predicate isInCycle(Instruction instr) { + instr instanceof Instruction and + getNonPhiOperandDefOfIntermediate+(instr) = instr +} + +CppType getInstructionOperandType(Instruction instruction, TypedOperandTag tag) { + // For all `LoadInstruction`s, the operand type of the `LoadOperand` is the same as + // the result type of the load. + tag instanceof LoadOperandTag and + result = instruction.(LoadInstruction).getResultLanguageType() + or + not instruction instanceof LoadInstruction and + result = + getInstructionTranslatedElement(instruction) + .getInstructionMemoryOperandType(getInstructionTag(instruction), tag) +} + +Instruction getPhiOperandDefinition( + PhiInstruction instruction, IRBlock predecessorBlock, Overlap overlap +) { + none() +} + +Instruction getPhiInstructionBlockStart(PhiInstruction instr) { none() } + +Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) { + result = + getInstructionTranslatedElement(instruction) + .getInstructionSuccessor(getInstructionTag(instruction), kind) +} + +/** + * Holds if the CFG edge (`sourceElement`, `sourceTag`) ---`kind`--> + * `targetInstruction` is a back edge under the condition that + * `requiredAncestor` is an ancestor of `sourceElement`. + */ +private predicate backEdgeCandidate( + TranslatedElement sourceElement, InstructionTag sourceTag, TranslatedElement requiredAncestor, + Instruction targetInstruction, EdgeKind kind +) { + // While loop: + // Any edge from within the body of the loop to the condition of the loop + // is a back edge. This includes edges from `continue` and the fall-through + // edge(s) after the last instruction(s) in the body. + exists(TranslatedWhileStmt s | + targetInstruction = s.getFirstConditionInstruction() and + targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and + requiredAncestor = s.getBody() + ) + or + // Do-while loop: + // The back edge should be the edge(s) from the condition to the + // body. This ensures that it's the back edge that will be pruned in a `do + // { ... } while (0)` statement. Note that all `continue` statements in a + // do-while loop produce forward edges. + exists(TranslatedDoStmt s | + targetInstruction = s.getBody().getFirstInstruction() and + targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and + requiredAncestor = s.getCondition() + ) + or + // For loop: + // Any edge from within the body or update of the loop to the condition of + // the loop is a back edge. When there is no loop update expression, this + // includes edges from `continue` and the fall-through edge(s) after the + // last instruction(s) in the body. A for loop may not have a condition, in + // which case `getFirstConditionInstruction` returns the body instead. + exists(TranslatedForStmt s | + targetInstruction = s.getFirstConditionInstruction() and + targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and + ( + requiredAncestor = s.getUpdate() + or + not exists(s.getUpdate()) and + requiredAncestor = s.getBody() + ) + ) + or + // Range-based for loop: + // Any edge from within the update of the loop to the condition of + // the loop is a back edge. + exists(TranslatedRangeBasedForStmt s | + targetInstruction = s.getCondition().getFirstInstruction() and + targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and + requiredAncestor = s.getUpdate() + ) +} + +private predicate jumpSourceHasAncestor(TranslatedElement jumpSource, TranslatedElement ancestor) { + backEdgeCandidate(jumpSource, _, _, _, _) and + ancestor = jumpSource + or + // For performance, we don't want a fastTC here + jumpSourceHasAncestor(jumpSource, ancestor.getAChild()) +} + +Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) { + exists( + TranslatedElement sourceElement, InstructionTag sourceTag, TranslatedElement requiredAncestor + | + backEdgeCandidate(sourceElement, sourceTag, requiredAncestor, result, kind) and + jumpSourceHasAncestor(sourceElement, requiredAncestor) and + instruction = sourceElement.getInstruction(sourceTag) + ) + or + // Goto statement: + // As a conservative approximation, any edge out of `goto` is a back edge + // unless it goes strictly forward in the program text. A `goto` whose + // source and target are both inside a macro will be seen as having the + // same location for source and target, so we conservatively assume that + // such a `goto` creates a back edge. + exists(TranslatedElement s, GotoStmt goto | + not isStrictlyForwardGoto(goto) and + goto = s.getAST() and + exists(InstructionTag tag | + result = s.getInstructionSuccessor(tag, kind) and + instruction = s.getInstruction(tag) + ) + ) +} + +/** Holds if `goto` jumps strictly forward in the program text. */ +private predicate isStrictlyForwardGoto(GotoStmt goto) { + goto.getLocation().isBefore(goto.getTarget().getLocation()) +} + +Locatable getInstructionAST(TStageInstruction instr) { + result = getInstructionTranslatedElement(instr).getAST() +} + +CppType getInstructionResultType(TStageInstruction instr) { + getInstructionTranslatedElement(instr).hasInstruction(_, getInstructionTag(instr), result) +} + +Opcode getInstructionOpcode(TStageInstruction instr) { + getInstructionTranslatedElement(instr).hasInstruction(result, getInstructionTag(instr), _) +} + +IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) { + result.getFunction() = getInstructionTranslatedElement(instr).getFunction() +} + +Instruction getPrimaryInstructionForSideEffect(SideEffectInstruction instruction) { + result = + getInstructionTranslatedElement(instruction) + .getPrimaryInstructionForSideEffect(getInstructionTag(instruction)) +} + import CachedForDebugging cached diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRFunctionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRFunctionImports.qll new file mode 100644 index 000000000000..8ec63b7c1cbd --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRFunctionImports.qll @@ -0,0 +1 @@ +import semmle.code.cpp.ir.implementation.internal.IRFunctionBase as IRFunctionBase diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRInternal.qll index 8fd2f662f346..82cc38ac0927 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRInternal.qll @@ -1,3 +1,4 @@ import semmle.code.cpp.ir.internal.IRCppLanguage as Language import IRConstruction as Construction import semmle.code.cpp.ir.implementation.IRConfiguration as IRConfiguration +import IRConstruction::Raw as Raw diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll index 15bb66940ea1..f3c8816c19d6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll @@ -24,6 +24,16 @@ private Element getRealParent(Expr expr) { result.(Destructor).getADestruction() = expr } +IRUserVariable getIRUserVariable(Function func, Variable var) { + result.getVariable() = var and + result.getEnclosingFunction() = func +} + +IRTempVariable getIRTempVariable(Locatable ast, TempVariableTag tag) { + result.getAST() = ast and + result.getTag() = tag +} + /** * Holds if `expr` is a constant of a type that can be replaced directly with * its value in the IR. This does not include address constants as we have no @@ -415,8 +425,11 @@ newtype TTranslatedElement = } or TTranslatedEllipsisParameter(Function func) { translateFunction(func) and func.isVarargs() } or TTranslatedReadEffects(Function func) { translateFunction(func) } or + TTranslatedThisReadEffect(Function func) { + translateFunction(func) and func.isMember() and not func.isStatic() + } or // The read side effects in a function's return block - TTranslatedReadEffect(Parameter param) { + TTranslatedParameterReadEffect(Parameter param) { translateFunction(param.getFunction()) and exists(Type t | t = param.getUnspecifiedType() | t instanceof ArrayType or @@ -463,7 +476,7 @@ newtype TTranslatedElement = ) } or // The side effects of an allocation, i.e. `new`, `new[]` or `malloc` - TTranslatedAllocationSideEffects(AllocationExpr expr) or + TTranslatedAllocationSideEffects(AllocationExpr expr) { not ignoreExpr(expr) } or // A precise side effect of an argument to a `Call` TTranslatedArgumentSideEffect(Call call, Expr expr, int n, boolean isWrite) { ( @@ -702,12 +715,8 @@ abstract class TranslatedElement extends TTranslatedElement { int getInstructionElementSize(InstructionTag tag) { none() } /** - * If the instruction specified by `tag` has a result of type `UnknownType`, - * gets the size of the result in bytes. If the result does not have a knonwn - * constant size, this predicate does not hold. + * Holds if the generated IR refers to an opaque type with size `byteSize`. */ - int getInstructionResultSize(InstructionTag tag) { none() } - predicate needsUnknownOpaqueType(int byteSize) { none() } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll index 75e70d1986f4..6da9193fd580 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -1011,7 +1011,7 @@ class TranslatedDynamicCast extends TranslatedSingleInstructionConversion { if resultType instanceof PointerType then if resultType.(PointerType).getBaseType() instanceof VoidType - then result instanceof Opcode::DynamicCastToVoid + then result instanceof Opcode::CompleteObjectAddress else result instanceof Opcode::CheckedConvertOrNull else result instanceof Opcode::CheckedConvertOrThrow ) @@ -2905,7 +2905,7 @@ predicate exprNeedsCopyIfNotLoaded(Expr expr) { private predicate exprImmediatelyDiscarded(Expr expr) { exists(ExprStmt s | s = expr.getParent() and - not exists(StmtExpr se | s = se.getStmt().(Block).getLastStmt()) + not exists(StmtExpr se | s = se.getStmt().(BlockStmt).getLastStmt()) ) or exists(CommaExpr c | c.getLeftOperand() = expr) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll index 6d34830a0bd4..f55d661b202e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll @@ -676,14 +676,17 @@ class TranslatedReadEffects extends TranslatedElement, TTranslatedReadEffects { override string toString() { result = "read effects: " + func.toString() } override TranslatedElement getChild(int id) { - result = getTranslatedReadEffect(func.getParameter(id)) + result = getTranslatedThisReadEffect(func) and + id = -1 + or + result = getTranslatedParameterReadEffect(func.getParameter(id)) } override Instruction getFirstInstruction() { if exists(getAChild()) then result = - min(TranslatedReadEffect child, int id | child = getChild(id) | child order by id) + min(TranslatedElement child, int id | child = getChild(id) | child order by id) .getFirstInstruction() else result = getParent().getChildSuccessor(this) } @@ -709,17 +712,15 @@ class TranslatedReadEffects extends TranslatedElement, TTranslatedReadEffects { override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } } -private TranslatedReadEffect getTranslatedReadEffect(Parameter param) { result.getAST() = param } - -class TranslatedReadEffect extends TranslatedElement, TTranslatedReadEffect { - Parameter param; - - TranslatedReadEffect() { this = TTranslatedReadEffect(param) } - - override Locatable getAST() { result = param } +private TranslatedThisReadEffect getTranslatedThisReadEffect(Function func) { + result.getAST() = func +} - override string toString() { result = "read effect: " + param.toString() } +private TranslatedParameterReadEffect getTranslatedParameterReadEffect(Parameter param) { + result.getAST() = param +} +abstract class TranslatedReadEffect extends TranslatedElement { override TranslatedElement getChild(int id) { none() } override Instruction getChildSuccessor(TranslatedElement child) { none() } @@ -732,20 +733,12 @@ class TranslatedReadEffect extends TranslatedElement, TTranslatedReadEffect { override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) } - override Function getFunction() { result = param.getFunction() } - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { opcode instanceof Opcode::ReturnIndirection and tag = OnlyInstructionTag() and resultType = getVoidType() } - final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { - tag = OnlyInstructionTag() and - operandTag = addressOperand() and - result = getTranslatedParameter(param).getInstruction(InitializerIndirectAddressTag()) - } - final override CppType getInstructionMemoryOperandType( InstructionTag tag, TypedOperandTag operandTag ) { @@ -753,6 +746,47 @@ class TranslatedReadEffect extends TranslatedElement, TTranslatedReadEffect { operandTag = sideEffectOperand() and result = getUnknownType() } +} + +class TranslatedThisReadEffect extends TranslatedReadEffect, TTranslatedThisReadEffect { + Function func; + + TranslatedThisReadEffect() { this = TTranslatedThisReadEffect(func) } + + override Locatable getAST() { result = func } + + override Function getFunction() { result = func } + + override string toString() { result = "read effect: this" } + + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { + tag = OnlyInstructionTag() and + operandTag = addressOperand() and + result = getTranslatedThisParameter(func).getInstruction(InitializerIndirectAddressTag()) + } + + final override IRVariable getInstructionVariable(InstructionTag tag) { + tag = OnlyInstructionTag() and + result = getTranslatedFunction(func).getThisVariable() + } +} + +class TranslatedParameterReadEffect extends TranslatedReadEffect, TTranslatedParameterReadEffect { + Parameter param; + + TranslatedParameterReadEffect() { this = TTranslatedParameterReadEffect(param) } + + override Locatable getAST() { result = param } + + override string toString() { result = "read effect: " + param.toString() } + + override Function getFunction() { result = param.getFunction() } + + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { + tag = OnlyInstructionTag() and + operandTag = addressOperand() and + result = getTranslatedParameter(param).getInstruction(InitializerIndirectAddressTag()) + } final override IRVariable getInstructionVariable(InstructionTag tag) { tag = OnlyInstructionTag() and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll index 8e2947d709f0..4b6538654db8 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll @@ -415,17 +415,6 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati ) } - override int getInstructionResultSize(InstructionTag tag) { - exists(int elementCount | - zeroInitRange(_, elementCount) and - ( - tag = ZeroPadStringConstantTag() or - tag = ZeroPadStringStoreTag() - ) and - result = elementCount * getElementType().getSize() - ) - } - private Type getElementType() { result = getContext().getTargetType().getUnspecifiedType().(ArrayType).getBaseType() } @@ -772,15 +761,6 @@ class TranslatedElementValueInitialization extends TranslatedElementInitializati result = getZeroValue(getElementType()) } - override int getInstructionResultSize(InstructionTag tag) { - elementCount > 1 and - ( - tag = getElementDefaultValueTag() or - tag = getElementDefaultValueStoreTag() - ) and - result = elementCount * getElementType().getSize() - } - override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { result = TranslatedElementInitialization.super.getInstructionRegisterOperand(tag, operandTag) or diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll index 3339046d3915..ce08fc9367fc 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll @@ -290,7 +290,7 @@ class TranslatedTryStmt extends TranslatedStmt { } class TranslatedBlock extends TranslatedStmt { - override Block stmt; + override BlockStmt stmt; override TranslatedElement getChild(int id) { result = getStmt(id) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll index badd48552a5f..c96783fe6e81 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll @@ -1,3 +1,47 @@ +/** + * Provides classes that describe the Intermediate Representation (IR) of the program. + * + * The IR is a representation of the semantics of the program, with very little dependence on the + * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, + * and `++i` all have the same semantic effect, but appear in the AST as three different types of + * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental + * operations similar to: + * + * ``` + * r1(int*) = VariableAddress[i] // Compute the address of variable `i` + * r2(int) = Load &:r1, m0 // Load the value of `i` + * r3(int) = Constant[1] // An integer constant with the value `1` + * r4(int) = Add r2, r3 // Add `1` to the value of `i` + * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` + * ``` + * + * This allows IR-based analysis to focus on the fundamental operations, rather than having to be + * concerned with the various ways of expressing those operations in source code. + * + * The key classes in the IR are: + * + * - `IRFunction` - Contains the IR for an entire function definition, including all of that + * function's `Instruction`s, `IRBlock`s, and `IRVariables`. + * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be + * performed, the operands that produce the inputs to that operation, and the type of the result + * of the operation. Control flows from an `Instruction` to one of a set of successor + * `Instruction`s. + * - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly + * represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has + * a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction` + * that produces its value (its "definition"). + * - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is + * created for each variable directly accessed by the function. In addition, `IRVariable`s are + * created to represent certain temporary storage locations that do not have explicitly declared + * variables in the source code, such as the return value of the function. + * - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a + * sequence of instructions such that control flow can only enter the block at the first + * instruction, and can only leave the block from the last instruction. + * - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType` + * is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all + * be represented as the `IRType` `uint4`, a four-byte unsigned integer. + */ + import IRFunction import Instruction import IRBlock @@ -11,11 +55,12 @@ import Imports::MemoryAccessKind private newtype TIRPropertyProvider = MkIRPropertyProvider() /** - * Class that provides additional properties to be dumped for IR instructions and blocks when using + * A class that provides additional properties to be dumped for IR instructions and blocks when using * the PrintIR module. Libraries that compute additional facts about IR elements can extend the * single instance of this class to specify the additional properties computed by the library. */ class IRPropertyProvider extends TIRPropertyProvider { + /** Gets a textual representation of this element. */ string toString() { result = "IRPropertyProvider" } /** @@ -27,4 +72,9 @@ class IRPropertyProvider extends TIRPropertyProvider { * Gets the value of the property named `key` for the specified block. */ string getBlockProperty(IRBlock block, string key) { none() } + + /** + * Gets the value of the property named `key` for the specified operand. + */ + string getOperandProperty(Operand operand, string key) { none() } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll index 94ef73b27692..d827ed3cf82d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll @@ -1,3 +1,7 @@ +/** + * Provides classes describing basic blocks in the IR of a function. + */ + private import internal.IRInternal import Instruction private import internal.IRBlockImports as Imports @@ -16,15 +20,27 @@ private import Cached * Most consumers should use the class `IRBlock`. */ class IRBlockBase extends TIRBlock { + /** Gets a textual representation of this block. */ final string toString() { result = getFirstInstruction(this).toString() } + /** Gets the source location of the first non-`Phi` instruction in this block. */ final Language::Location getLocation() { result = getFirstInstruction().getLocation() } + /** + * INTERNAL: Do not use. + * + * Gets a string that uniquely identifies this block within its enclosing function. + * + * This predicate is used by debugging and printing code only. + */ final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() } /** - * Gets the zero-based index of the block within its function. This is used - * by debugging and printing code only. + * INTERNAL: Do not use. + * + * Gets the zero-based index of the block within its function. + * + * This predicate is used by debugging and printing code only. */ int getDisplayIndex() { exists(IRConfiguration::IRConfiguration config | @@ -42,27 +58,51 @@ class IRBlockBase extends TIRBlock { ) } + /** + * Gets the `index`th non-`Phi` instruction in this block. + */ final Instruction getInstruction(int index) { result = getInstruction(this, index) } + /** + * Get the `Phi` instructions that appear at the start of this block. + */ final PhiInstruction getAPhiInstruction() { Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() } + /** + * Gets an instruction in this block. This includes `Phi` instructions. + */ final Instruction getAnInstruction() { result = getInstruction(_) or result = getAPhiInstruction() } + /** + * Gets the first non-`Phi` instruction in this block. + */ final Instruction getFirstInstruction() { result = getFirstInstruction(this) } + /** + * Gets the last instruction in this block. + */ final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) } + /** + * Gets the number of non-`Phi` instructions in this block. + */ final int getInstructionCount() { result = getInstructionCount(this) } + /** + * Gets the `IRFunction` that contains this block. + */ final IRFunction getEnclosingIRFunction() { result = getFirstInstruction(this).getEnclosingIRFunction() } + /** + * Gets the `Function` that contains this block. + */ final Language::Function getEnclosingFunction() { result = getFirstInstruction(this).getEnclosingFunction() } @@ -74,20 +114,57 @@ class IRBlockBase extends TIRBlock { * instruction of another block. */ class IRBlock extends IRBlockBase { + /** + * Gets a block to which control flows directly from this block. + */ final IRBlock getASuccessor() { blockSuccessor(this, result) } + /** + * Gets a block from which control flows directly to this block. + */ final IRBlock getAPredecessor() { blockSuccessor(result, this) } + /** + * Gets the block to which control flows directly from this block along an edge of kind `kind`. + */ final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } + /** + * Gets the block to which control flows directly from this block along a back edge of kind + * `kind`. + */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } + /** + * Holds if this block immediately dominates `block`. + * + * Block `A` immediate dominates block `B` if block `A` strictly dominates block `B` and block `B` + * is a direct successor of block `A`. + */ final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) } + /** + * Holds if this block strictly dominates `block`. + * + * Block `A` strictly dominates block `B` if block `A` dominates block `B` and blocks `A` and `B` + * are not the same block. + */ final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) } + /** + * Holds if this block dominates `block`. + * + * Block `A` dominates block `B` if any control flow path from the entry block of the function to + * block `B` must pass through block `A`. A block always dominates itself. + */ final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } + /** + * Gets a block on the dominance frontier of this block. + * + * The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not + * dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`. + */ pragma[noinline] final IRBlock dominanceFrontier() { dominates(result.getAPredecessor()) and @@ -95,7 +172,7 @@ class IRBlock extends IRBlockBase { } /** - * Holds if this block is reachable from the entry point of its function + * Holds if this block is reachable from the entry block of its function. */ final predicate isReachableFromFunctionEntry() { this = getEnclosingIRFunction().getEntryBlock() or @@ -210,4 +287,4 @@ private module Cached { idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block) } -Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } +private Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll index 65af34942b6b..6a87b9b4b5fd 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll @@ -8,10 +8,79 @@ module InstructionConsistency { private import Imports::Overlap private import internal.IRInternal + private newtype TOptionalIRFunction = + TPresentIRFunction(IRFunction irFunc) or + TMissingIRFunction() + + /** + * An `IRFunction` that might not exist. This is used so that we can produce consistency failures + * for IR that also incorrectly lacks a `getEnclosingIRFunction()`. + */ + abstract private class OptionalIRFunction extends TOptionalIRFunction { + abstract string toString(); + + abstract Language::Location getLocation(); + } + + private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction { + private IRFunction irFunc; + + PresentIRFunction() { this = TPresentIRFunction(irFunc) } + + override string toString() { + result = concat(Language::getIdentityString(irFunc.getFunction()), "; ") + } + + override Language::Location getLocation() { + // To avoid an overwhelming number of results when the extractor merges functions with the + // same name, just pick a single location. + result = + rank[1](Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString()) + } + } + + private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction { + override string toString() { result = "" } + + override Language::Location getLocation() { result instanceof Language::UnknownDefaultLocation } + } + + private OptionalIRFunction getInstructionIRFunction(Instruction instr) { + result = TPresentIRFunction(instr.getEnclosingIRFunction()) + or + not exists(instr.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getInstructionIRFunction(Instruction instr, string irFuncText) { + result = getInstructionIRFunction(instr) and + irFuncText = result.toString() + } + + private OptionalIRFunction getOperandIRFunction(Operand operand) { + result = TPresentIRFunction(operand.getEnclosingIRFunction()) + or + not exists(operand.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getOperandIRFunction(Operand operand, string irFuncText) { + result = getOperandIRFunction(operand) and + irFuncText = result.toString() + } + + private OptionalIRFunction getBlockIRFunction(IRBlock block) { + result = TPresentIRFunction(block.getEnclosingIRFunction()) + or + not exists(block.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + /** * Holds if instruction `instr` is missing an expected operand with tag `tag`. */ - query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) { + query predicate missingOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { exists(OperandTag tag | instr.getOpcode().hasOperand(tag) and not exists(NonPhiOperand operand | @@ -21,32 +90,39 @@ module InstructionConsistency { message = "Instruction '" + instr.getOpcode().toString() + "' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getInstructionIRFunction(instr, irFuncText) ) } /** * Holds if instruction `instr` has an unexpected operand with tag `tag`. */ - query predicate unexpectedOperand(Instruction instr, OperandTag tag) { - exists(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and - not instr.getOpcode().hasOperand(tag) and - not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and - not ( - instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag - ) and - not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag) + query predicate unexpectedOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(OperandTag tag | + exists(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + not instr.getOpcode().hasOperand(tag) and + not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and + not ( + instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag + ) and + not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag) and + message = + "Instruction '" + instr.toString() + "' has unexpected operand '" + tag.toString() + + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } /** * Holds if instruction `instr` has multiple operands with tag `tag`. */ query predicate duplicateOperand( - Instruction instr, string message, IRFunction func, string funcText + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(OperandTag tag, int operandCount | operandCount = @@ -58,8 +134,7 @@ module InstructionConsistency { message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + " in function '$@'." and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getInstructionIRFunction(instr, irFuncText) ) } @@ -67,100 +142,136 @@ module InstructionConsistency { * Holds if `Phi` instruction `instr` is missing an operand corresponding to * the predecessor block `pred`. */ - query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) { - pred = instr.getBlock().getAPredecessor() and - not exists(PhiInputOperand operand | - operand = instr.getAnOperand() and - operand.getPredecessorBlock() = pred + query predicate missingPhiOperand( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRBlock pred | + pred = instr.getBlock().getAPredecessor() and + not exists(PhiInputOperand operand | + operand = instr.getAnOperand() and + operand.getPredecessorBlock() = pred + ) and + message = + "Instruction '" + instr.toString() + "' is missing an operand for predecessor block '" + + pred.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) ) } - query predicate missingOperandType(Operand operand, string message) { - exists(Language::Function func, Instruction use | + query predicate missingOperandType( + Operand operand, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Instruction use | not exists(operand.getType()) and use = operand.getUse() and - func = use.getEnclosingFunction() and message = "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() + - "' missing type in function '" + Language::getIdentityString(func) + "'." + "' is missing a type in function '$@'." and + irFunc = getOperandIRFunction(operand, irFuncText) ) } query predicate duplicateChiOperand( - ChiInstruction chi, string message, IRFunction func, string funcText + ChiInstruction chi, string message, OptionalIRFunction irFunc, string irFuncText ) { chi.getTotal() = chi.getPartial() and message = "Chi instruction for " + chi.getPartial().toString() + - " has duplicate operands in function $@" and - func = chi.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + " has duplicate operands in function '$@'." and + irFunc = getInstructionIRFunction(chi, irFuncText) } query predicate sideEffectWithoutPrimary( - SideEffectInstruction instr, string message, IRFunction func, string funcText + SideEffectInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText ) { not exists(instr.getPrimaryInstruction()) and - message = "Side effect instruction missing primary instruction in function $@" and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + message = + "Side effect instruction '" + instr + "' is missing a primary instruction in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } /** * Holds if an instruction, other than `ExitFunction`, has no successors. */ - query predicate instructionWithoutSuccessor(Instruction instr) { + query predicate instructionWithoutSuccessor( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { not exists(instr.getASuccessor()) and not instr instanceof ExitFunctionInstruction and // Phi instructions aren't linked into the instruction-level flow graph. not instr instanceof PhiInstruction and - not instr instanceof UnreachedInstruction + not instr instanceof UnreachedInstruction and + message = "Instruction '" + instr.toString() + "' has no successors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } /** - * Holds if there are multiple (`n`) edges of kind `kind` from `source`, - * where `target` is among the targets of those edges. + * Holds if there are multiple edges of the same kind from `source`. */ - query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) { - n = strictcount(Instruction t | source.getSuccessor(kind) = t) and - n > 1 and - source.getSuccessor(kind) = target + query predicate ambiguousSuccessors( + Instruction source, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(EdgeKind kind, int n | + n = strictcount(Instruction t | source.getSuccessor(kind) = t) and + n > 1 and + message = + "Instruction '" + source.toString() + "' has " + n.toString() + " successors of kind '" + + kind.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(source, irFuncText) + ) } /** - * Holds if `instr` in `f` is part of a loop even though the AST of `f` + * Holds if `instr` is part of a loop even though the AST of `instr`'s enclosing function * contains no element that can cause loops. */ - query predicate unexplainedLoop(Language::Function f, Instruction instr) { - exists(IRBlock block | - instr.getBlock() = block and - block.getEnclosingFunction() = f and - block.getASuccessor+() = block - ) and - not Language::hasPotentialLoop(f) + query predicate unexplainedLoop( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Language::Function f | + exists(IRBlock block | + instr.getBlock() = block and + block.getEnclosingFunction() = f and + block.getASuccessor+() = block + ) and + not Language::hasPotentialLoop(f) and + message = + "Instruction '" + instr.toString() + "' is part of an unexplained loop in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } /** * Holds if a `Phi` instruction is present in a block with fewer than two * predecessors. */ - query predicate unnecessaryPhiInstruction(PhiInstruction instr) { - count(instr.getBlock().getAPredecessor()) < 2 + query predicate unnecessaryPhiInstruction( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int n | + n = count(instr.getBlock().getAPredecessor()) and + n < 2 and + message = + "Instruction '" + instr.toString() + "' is in a block with only " + n.toString() + + " predecessors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } /** * Holds if a memory operand is connected to a definition with an unmodeled result. */ query predicate memoryOperandDefinitionIsUnmodeled( - Instruction instr, string message, IRFunction func, string funcText + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(MemoryOperand operand, Instruction def | operand = instr.getAnOperand() and def = operand.getAnyDef() and not def.isResultModeled() and - message = "Memory operand definition has unmodeled result in function '$@'" and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + message = + "Memory operand definition on instruction '" + instr.toString() + + "' has unmodeled result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) ) } @@ -168,18 +279,37 @@ module InstructionConsistency { * Holds if operand `operand` consumes a value that was defined in * a different function. */ - query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) { - operand.getUse() = instr and - operand.getAnyDef() = defInstr and - instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction() + query predicate operandAcrossFunctions( + Operand operand, string message, OptionalIRFunction useIRFunc, string useIRFuncText, + OptionalIRFunction defIRFunc, string defIRFuncText + ) { + exists(Instruction useInstr, Instruction defInstr | + operand.getUse() = useInstr and + operand.getAnyDef() = defInstr and + useIRFunc = getInstructionIRFunction(useInstr, useIRFuncText) and + defIRFunc = getInstructionIRFunction(defInstr, defIRFuncText) and + useIRFunc != defIRFunc and + message = + "Operand '" + operand.toString() + "' is used on instruction '" + useInstr.toString() + + "' in function '$@', but is defined on instruction '" + defInstr.toString() + + "' in function '$@'." + ) } /** * Holds if instruction `instr` is not in exactly one block. */ - query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) { - blockCount = count(instr.getBlock()) and - blockCount != 1 + query predicate instructionWithoutUniqueBlock( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int blockCount | + blockCount = count(instr.getBlock()) and + blockCount != 1 and + message = + "Instruction '" + instr.toString() + "' is a member of " + blockCount.toString() + + " blocks in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } private predicate forwardEdge(IRBlock b1, IRBlock b2) { @@ -192,10 +322,11 @@ module InstructionConsistency { * * This check ensures we don't have too _few_ back edges. */ - query predicate containsLoopOfForwardEdges(IRFunction f) { + query predicate containsLoopOfForwardEdges(IRFunction f, string message) { exists(IRBlock block | forwardEdge+(block, block) and - block.getEnclosingIRFunction() = f + block.getEnclosingIRFunction() = f and + message = "Function contains a loop consisting of only forward edges." ) } @@ -207,12 +338,19 @@ module InstructionConsistency { * * This check ensures we don't have too _many_ back edges. */ - query predicate lostReachability(IRBlock block) { + query predicate lostReachability( + IRBlock block, string message, OptionalIRFunction irFunc, string irFuncText + ) { exists(IRFunction f, IRBlock entry | entry = f.getEntryBlock() and entry.getASuccessor+() = block and not forwardEdge+(entry, block) and - not Language::hasGoto(f.getFunction()) + not Language::hasGoto(f.getFunction()) and + message = + "Block '" + block.toString() + + "' is not reachable by traversing only forward edges in function '$@'." and + irFunc = TPresentIRFunction(f) and + irFuncText = irFunc.toString() ) } @@ -220,16 +358,22 @@ module InstructionConsistency { * Holds if the number of back edges differs between the `Instruction` graph * and the `IRBlock` graph. */ - query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) { - fromInstr = - count(Instruction i1, Instruction i2 | - i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2 - ) and - fromBlock = - count(IRBlock b1, IRBlock b2 | - b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2 - ) and - fromInstr != fromBlock + query predicate backEdgeCountMismatch(OptionalIRFunction irFunc, string message) { + exists(int fromInstr, int fromBlock | + fromInstr = + count(Instruction i1, Instruction i2 | + getInstructionIRFunction(i1) = irFunc and i1.getBackEdgeSuccessor(_) = i2 + ) and + fromBlock = + count(IRBlock b1, IRBlock b2 | + getBlockIRFunction(b1) = irFunc and b1.getBackEdgeSuccessor(_) = b2 + ) and + fromInstr != fromBlock and + message = + "The instruction graph for function '" + irFunc.toString() + "' contains " + + fromInstr.toString() + " back edges, but the block graph contains " + fromBlock.toString() + + " back edges." + ) } /** @@ -251,7 +395,7 @@ module InstructionConsistency { * Holds if `useOperand` has a definition that does not dominate the use. */ query predicate useNotDominatedByDefinition( - Operand useOperand, string message, IRFunction func, string funcText + Operand useOperand, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | pointOfEvaluation(useOperand, useBlock, useIndex) and @@ -272,19 +416,17 @@ module InstructionConsistency { message = "Operand '" + useOperand.toString() + "' is not dominated by its definition in function '$@'." and - func = useOperand.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getOperandIRFunction(useOperand, irFuncText) ) } query predicate switchInstructionWithoutDefaultEdge( - SwitchInstruction switchInstr, string message, IRFunction func, string funcText + SwitchInstruction switchInstr, string message, OptionalIRFunction irFunc, string irFuncText ) { not exists(switchInstr.getDefaultSuccessor()) and message = "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and - func = switchInstr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getInstructionIRFunction(switchInstr, irFuncText) } /** @@ -305,18 +447,30 @@ module InstructionConsistency { instr.getOpcode() instanceof Opcode::InitializeNonLocal } - query predicate notMarkedAsConflated(Instruction instr) { + query predicate notMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { shouldBeConflated(instr) and - not instr.isResultConflated() + not instr.isResultConflated() and + message = + "Instruction '" + instr.toString() + + "' should be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } - query predicate wronglyMarkedAsConflated(Instruction instr) { + query predicate wronglyMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { instr.isResultConflated() and - not shouldBeConflated(instr) + not shouldBeConflated(instr) and + message = + "Instruction '" + instr.toString() + + "' should not be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } query predicate invalidOverlap( - MemoryOperand useOperand, string message, IRFunction func, string funcText + MemoryOperand useOperand, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(Overlap overlap | overlap = useOperand.getDefinitionOverlap() and @@ -324,8 +478,20 @@ module InstructionConsistency { message = "MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" + overlap.toString() + "'." and - func = useOperand.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getOperandIRFunction(useOperand, irFuncText) + ) + } + + query predicate nonUniqueEnclosingIRFunction( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int irFuncCount | + irFuncCount = count(instr.getEnclosingIRFunction()) and + irFuncCount != 1 and + message = + "Instruction '" + instr.toString() + "' has " + irFuncCount.toString() + + " results for `getEnclosingIRFunction()` in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) ) } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll index 9aea3e00d666..5968e58f90bf 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll @@ -1,29 +1,17 @@ +/** + * Provides the class `IRFunction`, which represents the Intermediate Representation for the + * definition of a function. + */ + private import internal.IRInternal +private import internal.IRFunctionImports as Imports +import Imports::IRFunctionBase import Instruction -private newtype TIRFunction = - MkIRFunction(Language::Function func) { Construction::functionHasIR(func) } - /** - * Represents the IR for a function. + * The IR for a function. */ -class IRFunction extends TIRFunction { - Language::Function func; - - IRFunction() { this = MkIRFunction(func) } - - final string toString() { result = "IR: " + func.toString() } - - /** - * Gets the function whose IR is represented. - */ - final Language::Function getFunction() { result = func } - - /** - * Gets the location of the function. - */ - final Language::Location getLocation() { result = func.getLocation() } - +class IRFunction extends IRFunctionBase { /** * Gets the entry point for this function. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll index 9f2a0d4ea281..146fc2707383 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent variables accessed by the IR. + */ + private import internal.IRInternal import IRFunction private import internal.IRVariableImports as Imports @@ -7,15 +11,11 @@ private import Imports::TTempVariableTag private import Imports::TIRVariable private import Imports::IRType -IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { - result.getVariable() = var and - result.getEnclosingFunction() = func -} - /** - * A variable referenced by the IR for a function. The variable may be a user-declared variable - * (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation - * (`IRTempVariable`). + * A variable referenced by the IR for a function. + * + * The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated + * by the AST-to-IR translation (`IRTempVariable`). */ class IRVariable extends TIRVariable { Language::Function func; @@ -27,6 +27,7 @@ class IRVariable extends TIRVariable { this = TIRDynamicInitializationFlag(func, _, _) } + /** Gets a textual representation of this element. */ string toString() { none() } /** @@ -162,20 +163,30 @@ class IRGeneratedVariable extends IRVariable { override string getUniqueId() { none() } + /** + * INTERNAL: Do not use. + * + * Gets a string containing the source code location of the AST that generated this variable. + * + * This is used by debugging and printing code only. + */ final string getLocationString() { result = ast.getLocation().getStartLine().toString() + ":" + ast.getLocation().getStartColumn().toString() } + /** + * INTERNAL: Do not use. + * + * Gets the string that is combined with the location of the variable to generate the string + * representation of this variable. + * + * This is used by debugging and printing code only. + */ string getBaseString() { none() } } -IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { - result.getAST() = ast and - result.getTag() = tag -} - /** * A temporary variable introduced by IR construction. The most common examples are the variable * generated to hold the return value of a function, or the variable generated to hold the result of @@ -190,6 +201,10 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa result = "Temp: " + Construction::getTempVariableUniqueId(this) } + /** + * Gets the "tag" object that differentiates this temporary variable from other temporary + * variables generated for the same AST. + */ final TempVariableTag getTag() { result = tag } override string getBaseString() { result = "#temp" } @@ -217,19 +232,23 @@ class IRThrowVariable extends IRTempVariable { * A temporary variable generated to hold the contents of all arguments passed to the `...` of a * function that accepts a variable number of arguments. */ -class IREllipsisVariable extends IRTempVariable { +class IREllipsisVariable extends IRTempVariable, IRParameter { IREllipsisVariable() { tag = EllipsisTempVar() } final override string toString() { result = "#ellipsis" } + + final override int getIndex() { result = func.getNumberOfParameters() } } /** * A temporary variable generated to hold the `this` pointer. */ -class IRThisVariable extends IRTempVariable { +class IRThisVariable extends IRTempVariable, IRParameter { IRThisVariable() { tag = ThisTempVar() } final override string toString() { result = "#this" } + + final override int getIndex() { result = -1 } } /** @@ -249,6 +268,9 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { final override string getBaseString() { result = "#string" } + /** + * Gets the AST of the string literal represented by this `IRStringLiteral`. + */ final Language::StringLiteral getLiteral() { result = literal } } @@ -266,6 +288,9 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string toString() { result = var.toString() + "#init" } + /** + * Gets variable whose initialization is guarded by this flag. + */ final Language::Variable getVariable() { result = var } final override string getUniqueId() { @@ -274,3 +299,29 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string getBaseString() { result = "#init:" + var.toString() + ":" } } + +/** + * An IR variable which acts like a function parameter, including positional parameters and the + * temporary variables generated for `this` and ellipsis parameters. + */ +class IRParameter extends IRAutomaticVariable { + IRParameter() { + this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter + or + this = TIRTempVariable(_, _, ThisTempVar(), _) + or + this = TIRTempVariable(_, _, EllipsisTempVar(), _) + } + + /** + * Gets the zero-based index of this parameter. The `this` parameter has index -1. + */ + int getIndex() { none() } +} + +/** + * An IR variable representing a positional parameter. + */ +class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable { + final override int getIndex() { result = getVariable().(Language::Parameter).getIndex() } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 9c83a3d99f0c..620b23b942e0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the individual instructions in the IR for a function. + */ + private import internal.IRInternal import IRFunction import IRBlock @@ -27,9 +31,16 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil } /** - * Represents a single operation in the IR. + * A single instruction in the IR. */ -class Instruction extends Construction::TInstruction { +class Instruction extends Construction::TStageInstruction { + Instruction() { + // The base `TStageInstruction` type is a superset of the actual instructions appearing in this + // stage. This call lets the stage filter out the ones that are not reused from raw IR. + Construction::hasInstruction(this) + } + + /** Gets a textual representation of this element. */ final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } /** @@ -194,16 +205,25 @@ class Instruction extends Construction::TInstruction { * conversion. */ final Language::Expr getConvertedResultExpression() { - result = Construction::getInstructionConvertedResultExpression(this) + result = Raw::getInstructionConvertedResultExpression(this) } /** * Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any. */ final Language::Expr getUnconvertedResultExpression() { - result = Construction::getInstructionUnconvertedResultExpression(this) + result = Raw::getInstructionUnconvertedResultExpression(this) } + /** + * Gets the language-specific type of the result produced by this instruction. + * + * Most consumers of the IR should use `getResultIRType()` instead. `getResultIRType()` uses a + * less complex, language-neutral type system in which all semantically equivalent types share the + * same `IRType` instance. For example, in C++, four different `Instruction`s might have three + * different values for `getResultLanguageType()`: `unsigned int`, `char32_t`, and `wchar_t`, + * whereas all four instructions would have the same value for `getResultIRType()`, `uint4`. + */ final Language::LanguageType getResultLanguageType() { result = Construction::getInstructionResultType(this) } @@ -212,6 +232,7 @@ class Instruction extends Construction::TInstruction { * Gets the type of the result produced by this instruction. If the instruction does not produce * a result, its result type will be `IRVoidType`. */ + cached final IRType getResultIRType() { result = getResultLanguageType().getIRType() } /** @@ -240,17 +261,19 @@ class Instruction extends Construction::TInstruction { * given by `getResultType()`. * * For example, the statement `y = x;` generates the following IR: + * ``` * r1_0(glval: int) = VariableAddress[x] * r1_1(int) = Load r1_0, mu0_1 * r1_2(glval: int) = VariableAddress[y] * mu1_3(int) = Store r1_2, r1_1 + * ``` * * The result of each `VariableAddress` instruction is a glvalue of type * `int`, representing the address of the corresponding integer variable. The * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) } + final predicate isGLValue() { getResultLanguageType().hasType(_, true) } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -259,7 +282,7 @@ class Instruction extends Construction::TInstruction { * If `this.isGLValue()` holds for this instruction, the value of * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() } + final int getResultSize() { result = getResultLanguageType().getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. @@ -392,13 +415,27 @@ class Instruction extends Construction::TInstruction { final Instruction getAPredecessor() { result = getPredecessor(_) } } +/** + * An instruction that refers to a variable. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * variable. For example, it is used for `VariableAddress`, which returns the address of a specific + * variable, and `InitializeParameter`, which returns the value that was passed to the specified + * parameter by the caller. `VariableInstruction` is not used for `Load` or `Store` instructions + * that happen to load from or store to a particular variable; in those cases, the memory location + * being accessed is specified by the `AddressOperand` on the instruction, which may or may not be + * defined by the result of a `VariableAddress` instruction. + */ class VariableInstruction extends Instruction { IRVariable var; - VariableInstruction() { var = Construction::getInstructionVariable(this) } + VariableInstruction() { var = Raw::getInstructionVariable(this) } override string getImmediateString() { result = var.toString() } + /** + * Gets the variable that this instruction references. + */ final IRVariable getIRVariable() { result = var } /** @@ -407,63 +444,156 @@ class VariableInstruction extends Instruction { final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that refers to a field of a class, struct, or union. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * field. For example, it is used for `FieldAddress`, which computes the address of a specific + * field on an object. `FieldInstruction` is not used for `Load` or `Store` instructions that happen + * to load from or store to a particular field; in those cases, the memory location being accessed + * is specified by the `AddressOperand` on the instruction, which may or may not be defined by the + * result of a `FieldAddress` instruction. + */ class FieldInstruction extends Instruction { Language::Field field; - FieldInstruction() { field = Construction::getInstructionField(this) } + FieldInstruction() { field = Raw::getInstructionField(this) } final override string getImmediateString() { result = field.toString() } + /** + * Gets the field that this instruction references. + */ final Language::Field getField() { result = field } } +/** + * An instruction that refers to a function. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * function. For example, it is used for `FunctionAddress`, which returns the address of a specific + * function. `FunctionInstruction` is not used for `Call` instructions that happen to call a + * particular function; in that case, the function being called is specified by the + * `CallTargetOperand` on the instruction, which may or may not be defined by the result of a + * `FunctionAddress` instruction. + */ class FunctionInstruction extends Instruction { Language::Function funcSymbol; - FunctionInstruction() { funcSymbol = Construction::getInstructionFunction(this) } + FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) } final override string getImmediateString() { result = funcSymbol.toString() } + /** + * Gets the function that this instruction references. + */ final Language::Function getFunctionSymbol() { result = funcSymbol } } +/** + * An instruction whose result is a compile-time constant value. + */ class ConstantValueInstruction extends Instruction { string value; - ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) } + ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) } final override string getImmediateString() { result = value } + /** + * Gets the constant value of this instruction's result. + */ final string getValue() { result = value } } +/** + * An instruction that refers to an argument of a `Call` instruction. + * + * This instruction is used for side effects of a `Call` instruction that read or write memory + * pointed to by one of the arguments of the call. + */ class IndexedInstruction extends Instruction { int index; - IndexedInstruction() { index = Construction::getInstructionIndex(this) } + IndexedInstruction() { index = Raw::getInstructionIndex(this) } final override string getImmediateString() { result = index.toString() } + /** + * Gets the zero-based index of the argument that this instruction references. + */ final int getIndex() { result = index } } +/** + * An instruction representing the entry point to a function. + * + * Each `IRFunction` has exactly one `EnterFunction` instruction. Execution of the function begins + * at this instruction. This instruction has no predecessors. + */ class EnterFunctionInstruction extends Instruction { EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction } } +/** + * An instruction that returns the address of a variable. + * + * This instruction returns the address of a local variable, parameter, static field, + * namespace-scope variable, or global variable. For the address of a non-static field of a class, + * struct, or union, see `FieldAddressInstruction`. + */ class VariableAddressInstruction extends VariableInstruction { VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } } +/** + * An instruction that returns the address of a function. + * + * This instruction returns the address of a function, including non-member functions, static member + * functions, and non-static member functions. + * + * The result has an `IRFunctionAddress` type. + */ +class FunctionAddressInstruction extends FunctionInstruction { + FunctionAddressInstruction() { getOpcode() instanceof Opcode::FunctionAddress } +} + +/** + * An instruction that initializes a parameter of the enclosing function with the value of the + * corresponding argument passed by the caller. + * + * Each parameter of a function will have exactly one `InitializeParameter` instruction that + * initializes that parameter. + */ class InitializeParameterInstruction extends VariableInstruction { InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that initializes all memory that existed before this function was called. + * + * This instruction provides a definition for memory that, because it was actually allocated and + * initialized elsewhere, would not otherwise have a definition in this function. + */ +class InitializeNonLocalInstruction extends Instruction { + InitializeNonLocalInstruction() { getOpcode() instanceof Opcode::InitializeNonLocal } +} + +/** + * An instruction that initializes the memory pointed to by a parameter of the enclosing function + * with the value of that memory on entry to the function. + */ class InitializeIndirectionInstruction extends VariableInstruction { InitializeIndirectionInstruction() { getOpcode() instanceof Opcode::InitializeIndirection } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } @@ -474,14 +604,42 @@ class InitializeThisInstruction extends Instruction { InitializeThisInstruction() { getOpcode() instanceof Opcode::InitializeThis } } +/** + * An instruction that computes the address of a non-static field of an object. + */ class FieldAddressInstruction extends FieldInstruction { FieldAddressInstruction() { getOpcode() instanceof Opcode::FieldAddress } + /** + * Gets the operand that provides the address of the object containing the field. + */ final UnaryOperand getObjectAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the object containing the field. + */ final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } } +/** + * An instruction that computes the address of the first element of a managed array. + * + * This instruction is used for element access to C# arrays. + */ +class ElementsAddressInstruction extends UnaryInstruction { + ElementsAddressInstruction() { getOpcode() instanceof Opcode::ElementsAddress } + + /** + * Gets the operand that provides the address of the array object. + */ + final UnaryOperand getArrayObjectAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the array object. + */ + final Instruction getArrayObjectAddress() { result = getArrayObjectAddressOperand().getDef() } +} + /** * An instruction that produces a well-defined but unknown result and has * unknown side effects, including side effects that are not conservatively @@ -496,6 +654,12 @@ class ErrorInstruction extends Instruction { ErrorInstruction() { getOpcode() instanceof Opcode::Error } } +/** + * An instruction that returns an uninitialized value. + * + * This instruction is used to provide an initial definition for a stack variable that does not have + * an initializer, or whose initializer only partially initializes the variable. + */ class UninitializedInstruction extends VariableInstruction { UninitializedInstruction() { getOpcode() instanceof Opcode::Uninitialized } @@ -505,35 +669,94 @@ class UninitializedInstruction extends VariableInstruction { final Language::Variable getLocalVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that has no effect. + * + * This instruction is typically inserted to ensure that a particular AST is associated with at + * least one instruction, even when the AST has no semantic effect. + */ class NoOpInstruction extends Instruction { NoOpInstruction() { getOpcode() instanceof Opcode::NoOp } } +/** + * An instruction that returns control to the caller of the function. + * + * This instruction represents the normal (non-exception) return from a function, either from an + * explicit `return` statement or from control flow reaching the end of the function's body. + * + * Each function has exactly one `ReturnInstruction`. Each `return` statement in a function is + * represented as an initialization of the temporary variable that holds the return value, with + * control then flowing to the common `ReturnInstruction` for that function. Exception: A function + * that never returns will not have a `ReturnInstruction`. + * + * The `ReturnInstruction` for a function will have a control-flow successor edge to a block + * containing the `ExitFunction` instruction for that function. + * + * There are two differet return instructions: `ReturnValueInstruction`, for returning a value from + * a non-`void`-returning function, and `ReturnVoidInstruction`, for returning from a + * `void`-returning function. + */ class ReturnInstruction extends Instruction { ReturnInstruction() { getOpcode() instanceof ReturnOpcode } } +/** + * An instruction that returns control to the caller of the function, without returning a value. + */ class ReturnVoidInstruction extends ReturnInstruction { ReturnVoidInstruction() { getOpcode() instanceof Opcode::ReturnVoid } } +/** + * An instruction that returns control to the caller of the function, including a return value. + */ class ReturnValueInstruction extends ReturnInstruction { ReturnValueInstruction() { getOpcode() instanceof Opcode::ReturnValue } + /** + * Gets the operand that provides the value being returned by the function. + */ final LoadOperand getReturnValueOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value being returned by the function, if an + * exact definition is available. + */ final Instruction getReturnValue() { result = getReturnValueOperand().getDef() } } +/** + * An instruction that represents the use of the value pointed to by a parameter of the function + * after the function returns control to its caller. + * + * This instruction does not itself return control to the caller. It merely represents the potential + * for a caller to use the memory pointed to by the parameter sometime after the call returns. This + * is the counterpart to the `InitializeIndirection` instruction, which represents the possibility + * that the caller initialized the memory pointed to by the parameter before the call. + */ class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } + /** + * Gets the operand that provides the value of the pointed-to memory. + */ final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the pointed-to memory, if an exact + * definition is available. + */ final Instruction getSideEffect() { result = getSideEffectOperand().getDef() } + /** + * Gets the operand that provides the address of the pointed-to memory. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the pointed-to memory. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } /** @@ -541,87 +764,191 @@ class ReturnIndirectionInstruction extends VariableInstruction { * function. */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } + + /** + * Holds if this instruction is the return indirection for `this`. + */ + final predicate isThisIndirection() { var instanceof IRThisVariable } } +/** + * An instruction that returns a copy of its operand. + * + * There are several different copy instructions, depending on the source and destination of the + * copy operation: + * - `CopyInstruction` - Copies a register operand to a register result. + * - `LoadInstruction` - Copies a memory operand to a register result. + * - `StoreInstruction` - Copies a register operand to a memory result. + */ class CopyInstruction extends Instruction { CopyInstruction() { getOpcode() instanceof CopyOpcode } + /** + * Gets the operand that provides the input value of the copy. + */ Operand getSourceValueOperand() { none() } + /** + * Gets the instruction whose result provides the input value of the copy, if an exact definition + * is available. + */ final Instruction getSourceValue() { result = getSourceValueOperand().getDef() } } +/** + * An instruction that returns a register result containing a copy of its register operand. + */ class CopyValueInstruction extends CopyInstruction, UnaryInstruction { CopyValueInstruction() { getOpcode() instanceof Opcode::CopyValue } final override UnaryOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a register result containing a copy of its memory operand. + */ class LoadInstruction extends CopyInstruction { LoadInstruction() { getOpcode() instanceof Opcode::Load } + /** + * Gets the operand that provides the address of the value being loaded. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the value being loaded. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } final override LoadOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a memory result containing a copy of its register operand. + */ class StoreInstruction extends CopyInstruction { StoreInstruction() { getOpcode() instanceof Opcode::Store } + /** + * Gets the operand that provides the address of the location to which the value will be stored. + */ final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the location to which the value will + * be stored, if an exact definition is available. + */ final Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } final override StoreValueOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that branches to one of two successor instructions based on the value of a Boolean + * operand. + */ class ConditionalBranchInstruction extends Instruction { ConditionalBranchInstruction() { getOpcode() instanceof Opcode::ConditionalBranch } + /** + * Gets the operand that provides the Boolean condition controlling the branch. + */ final ConditionOperand getConditionOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the Boolean condition controlling the branch. + */ final Instruction getCondition() { result = getConditionOperand().getDef() } + /** + * Gets the instruction to which control will flow if the condition is true. + */ final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } + /** + * Gets the instruction to which control will flow if the condition is false. + */ final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } } +/** + * An instruction representing the exit point of a function. + * + * Each `IRFunction` has exactly one `ExitFunction` instruction, unless the function neither returns + * nor throws an exception. Control flows to the `ExitFunction` instruction from both normal returns + * (`ReturnVoid`, `ReturnValue`) and propagated exceptions (`Unwind`). This instruction has no + * successors. + */ class ExitFunctionInstruction extends Instruction { ExitFunctionInstruction() { getOpcode() instanceof Opcode::ExitFunction } } +/** + * An instruction whose result is a constant value. + */ class ConstantInstruction extends ConstantValueInstruction { ConstantInstruction() { getOpcode() instanceof Opcode::Constant } } +/** + * An instruction whose result is a constant value of integer or Boolean type. + */ class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType } + IntegerConstantInstruction() { + exists(IRType resultType | + resultType = getResultIRType() and + (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType) + ) + } } +/** + * An instruction whose result is a constant value of floating-point type. + */ class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } + FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } +/** + * An instruction whose result is the address of a string literal. + */ class StringConstantInstruction extends VariableInstruction { override IRStringLiteral var; final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) } + /** + * Gets the string literal whose address is returned by this instruction. + */ final Language::StringLiteral getValue() { result = var.getLiteral() } } +/** + * An instruction whose result is computed from two operands. + */ class BinaryInstruction extends Instruction { BinaryInstruction() { getOpcode() instanceof BinaryOpcode } + /** + * Gets the left operand of this binary instruction. + */ final LeftOperand getLeftOperand() { result = getAnOperand() } + /** + * Gets the right operand of this binary instruction. + */ final RightOperand getRightOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the left operand of this binary + * instruction. + */ final Instruction getLeft() { result = getLeftOperand().getDef() } + /** + * Gets the instruction whose result provides the value of the right operand of this binary + * instruction. + */ final Instruction getRight() { result = getRightOperand().getDef() } /** @@ -634,121 +961,301 @@ class BinaryInstruction extends Instruction { } } +/** + * An instruction that computes the result of an arithmetic operation. + */ class ArithmeticInstruction extends Instruction { ArithmeticInstruction() { getOpcode() instanceof ArithmeticOpcode } } +/** + * An instruction that performs an arithmetic operation on two numeric operands. + */ class BinaryArithmeticInstruction extends ArithmeticInstruction, BinaryInstruction { } +/** + * An instruction whose result is computed by performing an arithmetic operation on a single + * numeric operand. + */ class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction { } +/** + * An instruction that computes the sum of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point addition is + * performed according to IEEE-754. + */ class AddInstruction extends BinaryArithmeticInstruction { AddInstruction() { getOpcode() instanceof Opcode::Add } } +/** + * An instruction that computes the difference of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point subtraction is performed + * according to IEEE-754. + */ class SubInstruction extends BinaryArithmeticInstruction { SubInstruction() { getOpcode() instanceof Opcode::Sub } } +/** + * An instruction that computes the product of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point multiplication is + * performed according to IEEE-754. + */ class MulInstruction extends BinaryArithmeticInstruction { MulInstruction() { getOpcode() instanceof Opcode::Mul } } +/** + * An instruction that computes the quotient of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. Floating-point division is performed according + * to IEEE-754. + */ class DivInstruction extends BinaryArithmeticInstruction { DivInstruction() { getOpcode() instanceof Opcode::Div } } +/** + * An instruction that computes the remainder of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. + */ class RemInstruction extends BinaryArithmeticInstruction { RemInstruction() { getOpcode() instanceof Opcode::Rem } } +/** + * An instruction that negates a single numeric operand. + * + * The operand must have a numeric type, which will also be the result type. The result of integer + * negation uses two's complement, and is computed modulo 2^n. The result of floating-point negation + * is performed according to IEEE-754. + */ class NegateInstruction extends UnaryArithmeticInstruction { NegateInstruction() { getOpcode() instanceof Opcode::Negate } } +/** + * An instruction that computes the result of a bitwise operation. + */ class BitwiseInstruction extends Instruction { BitwiseInstruction() { getOpcode() instanceof BitwiseOpcode } } +/** + * An instruction that performs a bitwise operation on two integer operands. + */ class BinaryBitwiseInstruction extends BitwiseInstruction, BinaryInstruction { } +/** + * An instruction that performs a bitwise operation on a single integer operand. + */ class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } +/** + * An instruction that computes the bitwise "and" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitAndInstruction extends BinaryBitwiseInstruction { BitAndInstruction() { getOpcode() instanceof Opcode::BitAnd } } +/** + * An instruction that computes the bitwise "or" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitOrInstruction extends BinaryBitwiseInstruction { BitOrInstruction() { getOpcode() instanceof Opcode::BitOr } } +/** + * An instruction that computes the bitwise "xor" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitXorInstruction extends BinaryBitwiseInstruction { BitXorInstruction() { getOpcode() instanceof Opcode::BitXor } } +/** + * An instruction that shifts its left operand to the left by the number of bits specified by its + * right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. The + * rightmost bits are zero-filled. + */ class ShiftLeftInstruction extends BinaryBitwiseInstruction { ShiftLeftInstruction() { getOpcode() instanceof Opcode::ShiftLeft } } +/** + * An instruction that shifts its left operand to the right by the number of bits specified by its + * right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. If the + * left operand has an unsigned integer type, the leftmost bits are zero-filled. If the left operand + * has a signed integer type, the leftmost bits are filled by duplicating the most significant bit + * of the left operand. + */ class ShiftRightInstruction extends BinaryBitwiseInstruction { ShiftRightInstruction() { getOpcode() instanceof Opcode::ShiftRight } } +/** + * An instruction that performs a binary arithmetic operation involving at least one pointer + * operand. + */ class PointerArithmeticInstruction extends BinaryInstruction { int elementSize; PointerArithmeticInstruction() { getOpcode() instanceof PointerArithmeticOpcode and - elementSize = Construction::getInstructionElementSize(this) + elementSize = Raw::getInstructionElementSize(this) } final override string getImmediateString() { result = elementSize.toString() } + /** + * Gets the size of the elements pointed to by the pointer operands, in bytes. + * + * When adding an integer offset to a pointer (`PointerAddInstruction`) or subtracting an integer + * offset from a pointer (`PointerSubInstruction`), the integer offset is multiplied by the + * element size to compute the actual number of bytes added to or subtracted from the pointer + * address. When computing the integer difference between two pointers (`PointerDiffInstruction`), + * the result is computed by computing the difference between the two pointer byte addresses, then + * dividing that byte count by the element size. + */ final int getElementSize() { result = elementSize } } +/** + * An instruction that adds or subtracts an integer offset from a pointer. + */ class PointerOffsetInstruction extends PointerArithmeticInstruction { PointerOffsetInstruction() { getOpcode() instanceof PointerOffsetOpcode } } +/** + * An instruction that adds an integer offset to a pointer. + * + * The result is the byte address computed by adding the value of the right (integer) operand, + * multiplied by the element size, to the value of the left (pointer) operand. The result of pointer + * overflow is undefined. + */ class PointerAddInstruction extends PointerOffsetInstruction { PointerAddInstruction() { getOpcode() instanceof Opcode::PointerAdd } } +/** + * An instruction that subtracts an integer offset from a pointer. + * + * The result is the byte address computed by subtracting the value of the right (integer) operand, + * multiplied by the element size, from the value of the left (pointer) operand. The result of + * pointer underflow is undefined. + */ class PointerSubInstruction extends PointerOffsetInstruction { PointerSubInstruction() { getOpcode() instanceof Opcode::PointerSub } } +/** + * An instruction that computes the difference between two pointers. + * + * Both operands must have the same pointer type. The result must have an integer type whose size is + * the same as that of the pointer operands. The result is computed by subtracting the byte address + * in the right operand from the byte address in the left operand, and dividing by the element size. + * If the difference in byte addresses is not divisible by the element size, the result is + * undefined. + */ class PointerDiffInstruction extends PointerArithmeticInstruction { PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff } } +/** + * An instruction whose result is computed from a single operand. + */ class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } + /** + * Gets the sole operand of this instruction. + */ final UnaryOperand getUnaryOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the sole operand of this instruction. + */ final Instruction getUnary() { result = getUnaryOperand().getDef() } } +/** + * An instruction that converts the value of its operand to a value of a different type. + */ class ConvertInstruction extends UnaryInstruction { ConvertInstruction() { getOpcode() instanceof Opcode::Convert } } +/** + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, returning a null address if the dynamic type of the + * object is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a pointer type, or a C# `is` or + * `as` expression. + */ class CheckedConvertOrNullInstruction extends UnaryInstruction { CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull } } /** - * Represents an instruction that converts between two addresses - * related by inheritance. + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, throwing an exception if the dynamic type of the object + * is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a reference type, or a C# cast + * expression. + */ +class CheckedConvertOrThrowInstruction extends UnaryInstruction { + CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } +} + +/** + * An instruction that returns the address of the complete object that contains the subobject + * pointed to by its operand. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent `dyanmic_cast` in C++, which returns the pointer to + * the most-derived object. + */ +class CompleteObjectAddressInstruction extends UnaryInstruction { + CompleteObjectAddressInstruction() { getOpcode() instanceof Opcode::CompleteObjectAddress } +} + +/** + * An instruction that converts the address of an object to the address of a different subobject of + * the same object, without any type checking at runtime. */ class InheritanceConversionInstruction extends UnaryInstruction { Language::Class baseClass; Language::Class derivedClass; InheritanceConversionInstruction() { - Construction::getInstructionInheritance(this, baseClass, derivedClass) + Raw::getInstructionInheritance(this, baseClass, derivedClass) } final override string getImmediateString() { @@ -778,59 +1285,91 @@ class InheritanceConversionInstruction extends UnaryInstruction { } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a base class. + * An instruction that converts from the address of a derived class to the address of a base class. */ class ConvertToBaseInstruction extends InheritanceConversionInstruction { ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a direct non-virtual base class. + * An instruction that converts from the address of a derived class to the address of a direct + * non-virtual base class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToNonVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToNonVirtualBase } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a virtual base class. + * An instruction that converts from the address of a derived class to the address of a virtual base + * class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToVirtualBase } } /** - * Represents an instruction that converts from the address of a base class - * to the address of a direct non-virtual derived class. + * An instruction that converts from the address of a base class to the address of a direct + * non-virtual derived class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToDerivedInstruction extends InheritanceConversionInstruction { ConvertToDerivedInstruction() { getOpcode() instanceof Opcode::ConvertToDerived } } +/** + * An instruction that computes the bitwise complement of its operand. + * + * The operand must have an integer type, which will also be the result type. + */ class BitComplementInstruction extends UnaryBitwiseInstruction { BitComplementInstruction() { getOpcode() instanceof Opcode::BitComplement } } +/** + * An instruction that computes the logical complement of its operand. + * + * The operand must have a Boolean type, which will also be the result type. + */ class LogicalNotInstruction extends UnaryInstruction { LogicalNotInstruction() { getOpcode() instanceof Opcode::LogicalNot } } +/** + * An instruction that compares two numeric operands. + */ class CompareInstruction extends BinaryInstruction { CompareInstruction() { getOpcode() instanceof CompareOpcode } } +/** + * An instruction that returns a `true` result if its operands are equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left == right`, and `false` if `left != right` or the two operands are + * unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareEQInstruction extends CompareInstruction { CompareEQInstruction() { getOpcode() instanceof Opcode::CompareEQ } } +/** + * An instruction that returns a `true` result if its operands are not equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left != right` or if the two operands are unordered, and `false` if + * `left == right`. Floating-point comparison is performed according to IEEE-754. + */ class CompareNEInstruction extends CompareInstruction { CompareNEInstruction() { getOpcode() instanceof Opcode::CompareNE } } /** - * Represents an instruction that does a relative comparison of two values, such as `<` or `>=`. + * An instruction that does a relative comparison of two values, such as `<` or `>=`. */ class RelationalInstruction extends CompareInstruction { RelationalInstruction() { getOpcode() instanceof RelationalOpcode } @@ -857,6 +1396,13 @@ class RelationalInstruction extends CompareInstruction { predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is less than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left < right`, and `false` if `left >= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLTInstruction extends RelationalInstruction { CompareLTInstruction() { getOpcode() instanceof Opcode::CompareLT } @@ -867,6 +1413,13 @@ class CompareLTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is greater than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left > right`, and `false` if `left <= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGTInstruction extends RelationalInstruction { CompareGTInstruction() { getOpcode() instanceof Opcode::CompareGT } @@ -877,6 +1430,14 @@ class CompareGTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is less than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left <= right`, and `false` if `left > right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLEInstruction extends RelationalInstruction { CompareLEInstruction() { getOpcode() instanceof Opcode::CompareLE } @@ -887,6 +1448,14 @@ class CompareLEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is greater than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left >= right`, and `false` if `left < right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGEInstruction extends RelationalInstruction { CompareGEInstruction() { getOpcode() instanceof Opcode::CompareGE } @@ -897,15 +1466,32 @@ class CompareGEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that branches to one of multiple successor instructions based on the value of an + * integer operand. + * + * This instruction will have zero or more successors whose edge kind is `CaseEdge`, each + * representing the branch that will be taken if the controlling expression is within the range + * specified for that case edge. The range of a case edge must be disjoint from the range of each + * other case edge. + * + * The instruction may optionally have a successor edge whose edge kind is `DefaultEdge`, + * representing the branch that will be taken if the controlling expression is not within the range + * of any case edge. + */ class SwitchInstruction extends Instruction { SwitchInstruction() { getOpcode() instanceof Opcode::Switch } + /** Gets the operand that provides the integer value controlling the switch. */ final ConditionOperand getExpressionOperand() { result = getAnOperand() } + /** Gets the instruction whose result provides the integer value controlling the switch. */ final Instruction getExpression() { result = getExpressionOperand().getDef() } + /** Gets the successor instructions along the case edges of the switch. */ final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } + /** Gets the successor instruction along the default edge of the switch, if any. */ final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } } @@ -936,7 +1522,7 @@ class CallInstruction extends Instruction { * Gets the `Function` that the call targets, if this is statically known. */ final Language::Function getStaticCallTarget() { - result = getCallTarget().(FunctionInstruction).getFunctionSymbol() + result = getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() } /** @@ -981,6 +1567,9 @@ class CallInstruction extends Instruction { class SideEffectInstruction extends Instruction { SideEffectInstruction() { getOpcode() instanceof SideEffectOpcode } + /** + * Gets the instruction whose execution causes this side effect. + */ final Instruction getPrimaryInstruction() { result = Construction::getPrimaryInstructionForSideEffect(this) } @@ -996,9 +1585,10 @@ class CallSideEffectInstruction extends SideEffectInstruction { /** * An instruction representing the side effect of a function call on any memory - * that might be read by that call. This instruction is emitted instead of - * `CallSideEffectInstruction` when it's certain that the call target cannot - * write to escaped memory. + * that might be read by that call. + * + * This instruction is emitted instead of `CallSideEffectInstruction` when it is certain that the + * call target cannot write to escaped memory. */ class CallReadSideEffectInstruction extends SideEffectInstruction { CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect } @@ -1046,7 +1636,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { getOpcode() instanceof Opcode::SizedBufferReadSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes read from the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes read from the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1056,7 +1654,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } + /** + * Get the operand that holds the address of the memory to be written. + */ + final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the memory to be written. + */ + Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } } /** @@ -1087,11 +1693,20 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** * An instruction representing the potential write of an indirect parameter within a function call. + * * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. * written. */ @@ -1103,6 +1718,7 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1111,6 +1727,7 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1118,11 +1735,19 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** - * An instruction representing the initial value of newly allocated memory, e.g. the result of a + * An instruction representing the initial value of newly allocated memory, such as the result of a * call to `malloc`. */ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { @@ -1211,7 +1836,7 @@ class CatchByTypeInstruction extends CatchInstruction { CatchByTypeInstruction() { getOpcode() instanceof Opcode::CatchByType and - exceptionType = Construction::getInstructionExceptionType(this) + exceptionType = Raw::getInstructionExceptionType(this) } final override string getImmediateString() { result = exceptionType.toString() } @@ -1337,29 +1962,43 @@ class ChiInstruction extends Instruction { * Gets the operand that represents the new value written by the memory write. */ final Instruction getPartial() { result = getPartialOperand().getDef() } + + /** + * Gets the bit range `[startBit, endBit)` updated by the partial operand of this `ChiInstruction`, relative to the start address of the total operand. + */ + final predicate getUpdatedInterval(int startBit, int endBit) { + Construction::getIntervalUpdatedByChi(this, startBit, endBit) + } } /** - * An instruction representing unreachable code. Inserted in place of the original target - * instruction of a `ConditionalBranch` or `Switch` instruction where that particular edge is - * infeasible. + * An instruction representing unreachable code. + * + * This instruction is inserted in place of the original target instruction of a `ConditionalBranch` + * or `Switch` instruction where that particular edge is infeasible. */ class UnreachedInstruction extends Instruction { UnreachedInstruction() { getOpcode() instanceof Opcode::Unreached } } /** - * An instruction representing a built-in operation. This is used to represent - * operations such as access to variable argument lists. + * An instruction representing a built-in operation. + * + * This is used to represent a variety of intrinsic operations provided by the compiler + * implementation, such as vector arithmetic. */ class BuiltInOperationInstruction extends Instruction { Language::BuiltInOperation operation; BuiltInOperationInstruction() { getOpcode() instanceof BuiltInOperationOpcode and - operation = Construction::getInstructionBuiltInOperation(this) + operation = Raw::getInstructionBuiltInOperation(this) } + /** + * Gets the language-specific `BuiltInOperation` object that specifies the operation that is + * performed by this instruction. + */ final Language::BuiltInOperation getBuiltInOperation() { result = operation } } @@ -1372,3 +2011,59 @@ class BuiltInInstruction extends BuiltInOperationInstruction { final override string getImmediateString() { result = getBuiltInOperation().toString() } } + +/** + * An instruction that returns a `va_list` to access the arguments passed to the `...` parameter. + * + * The operand specifies the address of the `IREllipsisVariable` used to represent the `...` + * parameter. The result is a `va_list` that initially refers to the first argument that was passed + * to the `...` parameter. + */ +class VarArgsStartInstruction extends UnaryInstruction { + VarArgsStartInstruction() { getOpcode() instanceof Opcode::VarArgsStart } +} + +/** + * An instruction that cleans up a `va_list` after it is no longer in use. + * + * The operand specifies the address of the `va_list` to clean up. This instruction does not return + * a result. + */ +class VarArgsEndInstruction extends UnaryInstruction { + VarArgsEndInstruction() { getOpcode() instanceof Opcode::VarArgsEnd } +} + +/** + * An instruction that returns the address of the argument currently pointed to by a `va_list`. + * + * The operand is the `va_list` that points to the argument. The result is the address of the + * argument. + */ +class VarArgInstruction extends UnaryInstruction { + VarArgInstruction() { getOpcode() instanceof Opcode::VarArg } +} + +/** + * An instruction that modifies a `va_list` to point to the next argument that was passed to the + * `...` parameter. + * + * The operand is the current `va_list`. The result is an updated `va_list` that points to the next + * argument of the `...` parameter. + */ +class NextVarArgInstruction extends UnaryInstruction { + NextVarArgInstruction() { getOpcode() instanceof Opcode::NextVarArg } +} + +/** + * An instruction that allocates a new object on the managed heap. + * + * This instruction is used to represent the allocation of a new object in C# using the `new` + * expression. This instruction does not invoke a constructor for the object. Instead, there will be + * a subsequent `Call` instruction to invoke the appropriate constructor directory, passing the + * result of the `NewObj` as the `this` argument. + * + * The result is the address of the newly allocated object. + */ +class NewObjInstruction extends Instruction { + NewObjInstruction() { getOpcode() instanceof Opcode::NewObj } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll index f82704094c8e..a12e35d471b8 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the input values of IR instructions. + */ + private import internal.IRInternal private import Instruction private import IRBlock @@ -75,13 +79,21 @@ private PhiOperandBase phiOperand( } /** - * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. + * An operand of an `Instruction`. The operand represents a use of the result of one instruction + * (the defining instruction) in another instruction (the use instruction) */ class Operand extends TOperand { + /** Gets a textual representation of this element. */ string toString() { result = "Operand" } + /** + * Gets the location of the source code for this operand. + */ final Language::Location getLocation() { result = getUse().getLocation() } + /** + * Gets the function that contains this operand. + */ final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() } /** @@ -139,6 +151,11 @@ class Operand extends TOperand { */ string getDumpLabel() { result = "" } + /** + * Gets a string that uniquely identifies this operand on its use instruction. + */ + string getDumpId() { result = "" } + /** * Gets a string describing this operand, suitable for display in IR dumps. This consists of the * result ID of the instruction consumed by the operand, plus a label identifying the operand @@ -268,8 +285,13 @@ class NonPhiOperand extends Operand { final override string getDumpLabel() { result = tag.getLabel() } + final override string getDumpId() { result = tag.getId() } + final override int getDumpSortOrder() { result = tag.getSortOrder() } + /** + * Gets the `OperandTag` that specifies how this operand is used by its `Instruction`. + */ final OperandTag getOperandTag() { result = tag } } @@ -292,6 +314,9 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { } } +/** + * A memory operand other than the operand of a `Phi` instruction. + */ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; @@ -311,8 +336,19 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper not Construction::isInCycle(useInstr) and strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 } + + /** + * Holds if the operand totally overlaps with its definition and consumes the + * bit range `[startBitOffset, endBitOffset)` relative to the start address of the definition. + */ + predicate getUsedInterval(int startBitOffset, int endBitOffset) { + Construction::getUsedInterval(this, startBitOffset, endBitOffset) + } } +/** + * A memory operand whose type may be different from the type of the result of its definition. + */ class TypedOperand extends NonPhiMemoryOperand { override TypedOperandTag tag; @@ -416,6 +452,9 @@ class PositionalArgumentOperand extends ArgumentOperand { final int getIndex() { result = tag.getArgIndex() } } +/** + * An operand representing memory read as a side effect of evaluating another instruction. + */ class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; } @@ -445,6 +484,8 @@ class PhiInputOperand extends MemoryOperand, PhiOperandBase { result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":" } + final override string getDumpId() { result = getPredecessorBlock().getDisplayIndex().toString() } + /** * Gets the predecessor block from which this value comes. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll index d9c0df44e12e..59dadee71545 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll @@ -1,3 +1,13 @@ +/** + * Outputs a representation of the IR as a control flow graph. + * + * This file contains the actual implementation of `PrintIR.ql`. For test cases and very small + * databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintIR.qll`, extends + * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to + * dump. + */ + private import internal.IRInternal private import IR private import internal.PrintIRImports as Imports @@ -9,6 +19,7 @@ private newtype TPrintIRConfiguration = MkPrintIRConfiguration() * The query can extend this class to control which functions are printed. */ class PrintIRConfiguration extends TPrintIRConfiguration { + /** Gets a textual representation of this configuration. */ string toString() { result = "PrintIRConfiguration" } /** @@ -39,6 +50,37 @@ private string getAdditionalBlockProperty(IRBlock block, string key) { exists(IRPropertyProvider provider | result = provider.getBlockProperty(block, key)) } +/** + * Gets the properties of an operand from any active property providers. + */ +private string getAdditionalOperandProperty(Operand operand, string key) { + exists(IRPropertyProvider provider | result = provider.getOperandProperty(operand, key)) +} + +/** + * Gets a string listing the properties of the operand and their corresponding values. If the + * operand has no properties, this predicate has no result. + */ +private string getOperandPropertyListString(Operand operand) { + result = + strictconcat(string key, string value | + value = getAdditionalOperandProperty(operand, key) + | + key + ":" + value, ", " + ) +} + +/** + * Gets a string listing the properties of the operand and their corresponding values. The list is + * surrounded by curly braces. If the operand has no properties, this predicate returns an empty + * string. + */ +private string getOperandPropertyString(Operand operand) { + result = "{" + getOperandPropertyListString(operand) + "}" + or + not exists(getOperandPropertyListString(operand)) and result = "" +} + private newtype TPrintableIRNode = TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or @@ -47,7 +89,7 @@ private newtype TPrintableIRNode = /** * A node to be emitted in the IR graph. */ -abstract class PrintableIRNode extends TPrintableIRNode { +abstract private class PrintableIRNode extends TPrintableIRNode { abstract string toString(); /** @@ -98,7 +140,7 @@ abstract class PrintableIRNode extends TPrintableIRNode { /** * An IR graph node representing a `IRFunction` object. */ -class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { +private class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { IRFunction irFunc; PrintableIRFunction() { this = TPrintableIRFunction(irFunc) } @@ -129,7 +171,7 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { /** * An IR graph node representing an `IRBlock` object. */ -class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { +private class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { IRBlock block; PrintableIRBlock() { this = TPrintableIRBlock(block) } @@ -161,7 +203,7 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { /** * An IR graph node representing an `Instruction`. */ -class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { +private class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { Instruction instr; PrintableInstruction() { this = TPrintableInstruction(instr) } @@ -179,7 +221,7 @@ class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { | resultString = instr.getResultString() and operationString = instr.getOperationString() and - operandsString = instr.getOperandsString() and + operandsString = getOperandsString() and columnWidths(block, resultWidth, operationWidth) and result = resultString + getPaddingString(resultWidth - resultString.length()) + " = " + @@ -199,6 +241,22 @@ class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { result = PrintableIRNode.super.getProperty(key) or result = getAdditionalInstructionProperty(instr, key) } + + /** + * Gets the string representation of the operand list. This is the same as + * `Instruction::getOperandsString()`, except that each operand is annotated with any properties + * provided by active `IRPropertyProvider` instances. + */ + private string getOperandsString() { + result = + concat(Operand operand | + operand = instr.getAnOperand() + | + operand.getDumpString() + getOperandPropertyString(operand), ", " + order by + operand.getDumpSortOrder() + ) + } } private predicate columnWidths(IRBlock block, int resultWidth, int operationWidth) { @@ -224,6 +282,9 @@ private string getPaddingString(int n) { n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " " } +/** + * Holds if `node` belongs to the output graph, and its property `key` has the given `value`. + */ query predicate nodes(PrintableIRNode node, string key, string value) { value = node.getProperty(key) } @@ -237,6 +298,10 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) { ) } +/** + * Holds if the output graph contains an edge from `pred` to `succ`, and that edge's property `key` + * has the given `value`. + */ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | predBlock = pred.getBlock() and @@ -256,6 +321,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, ) } +/** + * Holds if `parent` is the parent node of `child` in the output graph. + */ query predicate parents(PrintableIRNode child, PrintableIRNode parent) { parent = child.getParent() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll index 1612e0065b77..19fb0490f808 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll @@ -196,16 +196,17 @@ private predicate operandReturned(Operand operand, IntValue bitOffset) { bitOffset = Ints::unknown() } -private predicate isArgumentForParameter(CallInstruction ci, Operand operand, Instruction init) { +private predicate isArgumentForParameter( + CallInstruction ci, Operand operand, InitializeParameterInstruction init +) { exists(Language::Function f | ci = operand.getUse() and f = ci.getStaticCallTarget() and ( - init.(InitializeParameterInstruction).getParameter() = - f.getParameter(operand.(PositionalArgumentOperand).getIndex()) + init.getParameter() = f.getParameter(operand.(PositionalArgumentOperand).getIndex()) or - init.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable and - init.getEnclosingFunction() = f and + init.getIRVariable() instanceof IRThisVariable and + unique( | | init.getEnclosingFunction()) = f and operand instanceof ThisArgumentOperand ) and not Language::isFunctionVirtual(f) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll new file mode 100644 index 000000000000..8ec63b7c1cbd --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll @@ -0,0 +1 @@ +import semmle.code.cpp.ir.implementation.internal.IRFunctionBase as IRFunctionBase diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRInternal.qll index 4cc52d3bbf99..3a7a08accc0d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRInternal.qll @@ -1,3 +1,4 @@ import semmle.code.cpp.ir.internal.IRCppLanguage as Language import SSAConstruction as Construction import semmle.code.cpp.ir.implementation.IRConfiguration as IRConfiguration +import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction::Raw as Raw diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 30414bb5db3a..a6cb78b2b3a7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -1,5 +1,11 @@ import SSAConstructionInternal -private import SSAConstructionImports +private import SSAConstructionImports as Imports +private import Imports::Opcode +private import Imports::OperandTag +private import Imports::Overlap +private import Imports::TInstruction +private import Imports::RawIR as RawIR +private import SSAInstructions private import NewIR private class OldBlock = Reachability::ReachableBlock; @@ -10,52 +16,45 @@ import Cached cached private module Cached { - private IRBlock getNewBlock(OldBlock oldBlock) { - result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction()) + cached + predicate hasPhiInstructionCached( + OldInstruction blockStartInstr, Alias::MemoryLocation defLocation + ) { + exists(OldBlock oldBlock | + definitionHasPhiNode(defLocation, oldBlock) and + blockStartInstr = oldBlock.getFirstInstruction() + ) } cached - predicate functionHasIR(Language::Function func) { - exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func) + predicate hasChiInstructionCached(OldInstruction primaryInstruction) { + hasChiNode(_, primaryInstruction) } cached - OldInstruction getOldInstruction(Instruction instr) { instr = WrappedInstruction(result) } - - private IRVariable getNewIRVariable(OldIR::IRVariable var) { - // This is just a type cast. Both classes derive from the same newtype. - result = var + predicate hasUnreachedInstructionCached(IRFunction irFunc) { + exists(OldInstruction oldInstruction | + irFunc = oldInstruction.getEnclosingIRFunction() and + Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) + ) } - cached - newtype TInstruction = - WrappedInstruction(OldInstruction oldInstruction) { - not oldInstruction instanceof OldIR::PhiInstruction - } or - Phi(OldBlock block, Alias::MemoryLocation defLocation) { - definitionHasPhiNode(defLocation, block) - } or - Chi(OldInstruction oldInstruction) { - not oldInstruction instanceof OldIR::PhiInstruction and - hasChiNode(_, oldInstruction) - } or - Unreached(Language::Function function) { - exists(OldInstruction oldInstruction | - function = oldInstruction.getEnclosingFunction() and - Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) - ) - } + class TStageInstruction = + TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction; cached - predicate hasTempVariable( - Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type - ) { - exists(OldIR::IRTempVariable var | - var.getEnclosingFunction() = func and - var.getAST() = ast and - var.getTag() = tag and - var.getLanguageType() = type - ) + predicate hasInstruction(TStageInstruction instr) { + instr instanceof TRawInstruction and instr instanceof OldInstruction + or + instr instanceof TPhiInstruction + or + instr instanceof TChiInstruction + or + instr instanceof TUnreachedInstruction + } + + private IRBlock getNewBlock(OldBlock oldBlock) { + result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction()) } cached @@ -73,7 +72,7 @@ private module Cached { or // Chi instructions track virtual variables, and therefore a chi instruction is // conflated if it's associated with the aliased virtual variable. - exists(OldInstruction oldInstruction | instruction = Chi(oldInstruction) | + exists(OldInstruction oldInstruction | instruction = getChi(oldInstruction) | Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof Alias::AliasedVirtualVariable ) @@ -81,7 +80,7 @@ private module Cached { // Phi instructions track locations, and therefore a phi instruction is // conflated if it's associated with a conflated location. exists(Alias::MemoryLocation location | - instruction = Phi(_, location) and + instruction = getPhi(_, location) and not exists(location.getAllocation()) ) } @@ -128,7 +127,7 @@ private module Cached { hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result) ) or - instruction = Chi(getOldInstruction(result)) and + instruction = getChi(getOldInstruction(result)) and tag instanceof ChiPartialOperandTag and overlap instanceof MustExactlyOverlap or @@ -150,6 +149,34 @@ private module Cached { ) } + /** + * Holds if the partial operand of this `ChiInstruction` updates the bit range + * `[startBitOffset, endBitOffset)` of the total operand. + */ + cached + predicate getIntervalUpdatedByChi(ChiInstruction chi, int startBitOffset, int endBitOffset) { + exists(Alias::MemoryLocation location, OldInstruction oldInstruction | + oldInstruction = getOldInstruction(chi.getPartial()) and + location = Alias::getResultMemoryLocation(oldInstruction) and + startBitOffset = Alias::getStartBitOffset(location) and + endBitOffset = Alias::getEndBitOffset(location) + ) + } + + /** + * Holds if `operand` totally overlaps with its definition and consumes the bit range + * `[startBitOffset, endBitOffset)`. + */ + cached + predicate getUsedInterval(NonPhiMemoryOperand operand, int startBitOffset, int endBitOffset) { + exists(Alias::MemoryLocation location, OldIR::NonPhiMemoryOperand oldOperand | + oldOperand = operand.getUse().(OldInstruction).getAnOperand() and + location = Alias::getOperandMemoryLocation(oldOperand) and + startBitOffset = Alias::getStartBitOffset(location) and + endBitOffset = Alias::getEndBitOffset(location) + ) + } + /** * Holds if `instr` is part of a cycle in the operand graph that doesn't go * through a phi instruction and therefore should be impossible. @@ -172,13 +199,15 @@ private module Cached { pragma[noopt] cached - Instruction getPhiOperandDefinition(Phi instr, IRBlock newPredecessorBlock, Overlap overlap) { + Instruction getPhiOperandDefinition( + PhiInstruction instr, IRBlock newPredecessorBlock, Overlap overlap + ) { exists( Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock, OldBlock predBlock, OldBlock defBlock, int defOffset, Alias::MemoryLocation actualDefLocation | hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset) and - instr = Phi(phiBlock, useLocation) and + instr = getPhi(phiBlock, useLocation) and newPredecessorBlock = getNewBlock(predBlock) and result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and overlap = Alias::getOverlap(actualDefLocation, useLocation) @@ -191,7 +220,7 @@ private module Cached { Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation, OldBlock defBlock, int defRank, int defOffset, OldBlock useBlock, int useRank | - chiInstr = Chi(oldInstr) and + chiInstr = getChi(oldInstr) and vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and hasUseAtRank(vvar, useBlock, useRank, oldInstr) and @@ -203,21 +232,11 @@ private module Cached { cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) { exists(OldBlock oldBlock | - instr = Phi(oldBlock, _) and + instr = getPhi(oldBlock, _) and result = getNewInstruction(oldBlock.getFirstInstruction()) ) } - cached - Language::Expr getInstructionConvertedResultExpression(Instruction instruction) { - result = getOldInstruction(instruction).getConvertedResultExpression() - } - - cached - Language::Expr getInstructionUnconvertedResultExpression(Instruction instruction) { - result = getOldInstruction(instruction).getUnconvertedResultExpression() - } - /* * This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node, * that node is its successor in the new successor relation, and the Chi node's successors are @@ -228,20 +247,20 @@ private module Cached { Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) { if hasChiNode(_, getOldInstruction(instruction)) then - result = Chi(getOldInstruction(instruction)) and + result = getChi(getOldInstruction(instruction)) and kind instanceof GotoEdge else ( exists(OldInstruction oldInstruction | oldInstruction = getOldInstruction(instruction) and ( if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind) - then result = Unreached(instruction.getEnclosingFunction()) + then result = unreachedInstruction(instruction.getEnclosingIRFunction()) else result = getNewInstruction(oldInstruction.getSuccessor(kind)) ) ) or exists(OldInstruction oldInstruction | - instruction = Chi(oldInstruction) and + instruction = getChi(oldInstruction) and result = getNewInstruction(oldInstruction.getSuccessor(kind)) ) ) @@ -260,137 +279,73 @@ private module Cached { // `oldInstruction`, in which case the back edge should come out of the // chi node instead. if hasChiNode(_, oldInstruction) - then instruction = Chi(oldInstruction) + then instruction = getChi(oldInstruction) else instruction = getNewInstruction(oldInstruction) ) } cached - Language::AST getInstructionAST(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) - or - instruction = Chi(oldInstruction) - | - result = oldInstruction.getAST() + Language::AST getInstructionAST(Instruction instr) { + result = getOldInstruction(instr).getAST() + or + exists(RawIR::Instruction blockStartInstr | + instr = phiInstruction(blockStartInstr, _) and + result = blockStartInstr.getAST() ) or - exists(OldBlock block | - instruction = Phi(block, _) and - result = block.getFirstInstruction().getAST() + exists(RawIR::Instruction primaryInstr | + instr = chiInstruction(primaryInstr) and + result = primaryInstr.getAST() ) or - instruction = Unreached(result) + exists(IRFunctionBase irFunc | + instr = unreachedInstruction(irFunc) and result = irFunc.getFunction() + ) } cached - Language::LanguageType getInstructionResultType(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) and - result = oldInstruction.getResultLanguageType() - ) + Language::LanguageType getInstructionResultType(Instruction instr) { + result = instr.(RawIR::Instruction).getResultLanguageType() or - exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar | - instruction = Chi(oldInstruction) and - hasChiNode(vvar, oldInstruction) and - result = vvar.getType() + exists(Alias::MemoryLocation defLocation | + instr = phiInstruction(_, defLocation) and + result = defLocation.getType() ) or - exists(Alias::MemoryLocation location | - instruction = Phi(_, location) and - result = location.getType() + exists(Instruction primaryInstr, Alias::VirtualVariable vvar | + instr = chiInstruction(primaryInstr) and + hasChiNode(vvar, primaryInstr) and + result = vvar.getType() ) or - instruction = Unreached(_) and - result = Language::getVoidType() + instr = unreachedInstruction(_) and result = Language::getVoidType() } cached - Opcode getInstructionOpcode(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) and - result = oldInstruction.getOpcode() - ) + Opcode getInstructionOpcode(Instruction instr) { + result = getOldInstruction(instr).getOpcode() or - instruction instanceof Chi and - result instanceof Opcode::Chi + instr = phiInstruction(_, _) and result instanceof Opcode::Phi or - instruction instanceof Phi and - result instanceof Opcode::Phi + instr = chiInstruction(_) and result instanceof Opcode::Chi or - instruction instanceof Unreached and - result instanceof Opcode::Unreached + instr = unreachedInstruction(_) and result instanceof Opcode::Unreached } cached - IRFunction getInstructionEnclosingIRFunction(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) - or - instruction = Chi(oldInstruction) - | - result.getFunction() = oldInstruction.getEnclosingFunction() - ) + IRFunctionBase getInstructionEnclosingIRFunction(Instruction instr) { + result = getOldInstruction(instr).getEnclosingIRFunction() or - exists(OldBlock block | - instruction = Phi(block, _) and - result.getFunction() = block.getEnclosingFunction() + exists(OldInstruction blockStartInstr | + instr = phiInstruction(blockStartInstr, _) and + result = blockStartInstr.getEnclosingIRFunction() ) or - instruction = Unreached(result.getFunction()) - } - - cached - IRVariable getInstructionVariable(Instruction instruction) { - result = - getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getIRVariable()) - } - - cached - Language::Field getInstructionField(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField() - } - - cached - int getInstructionIndex(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::IndexedInstruction).getIndex() - } - - cached - Language::Function getInstructionFunction(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol() - } - - cached - string getInstructionConstantValue(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue() - } - - cached - Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) { - result = - getOldInstruction(instruction).(OldIR::BuiltInOperationInstruction).getBuiltInOperation() - } - - cached - Language::LanguageType getInstructionExceptionType(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType() - } - - cached - int getInstructionElementSize(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::PointerArithmeticInstruction).getElementSize() - } - - cached - predicate getInstructionInheritance( - Instruction instruction, Language::Class baseClass, Language::Class derivedClass - ) { - exists(OldIR::InheritanceConversionInstruction oldInstr | - oldInstr = getOldInstruction(instruction) and - baseClass = oldInstr.getBaseClass() and - derivedClass = oldInstr.getDerivedClass() + exists(OldInstruction primaryInstr | + instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction() ) + or + instr = unreachedInstruction(result) } cached @@ -401,7 +356,7 @@ private module Cached { ) or exists(OldIR::Instruction oldInstruction | - instruction = Chi(oldInstruction) and + instruction = getChi(oldInstruction) and result = getNewInstruction(oldInstruction) ) } @@ -409,6 +364,14 @@ private module Cached { private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr } +private OldInstruction getOldInstruction(Instruction instr) { instr = result } + +private ChiInstruction getChi(OldInstruction primaryInstr) { result = chiInstruction(primaryInstr) } + +private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) { + result = phiInstruction(defBlock.getFirstInstruction(), defLocation) +} + /** * Holds if instruction `def` needs to have a `Chi` instruction inserted after it, to account for a partial definition * of a virtual variable. The `Chi` instruction provides a definition of the entire virtual variable of which the @@ -588,7 +551,7 @@ module DefUse { | // An odd offset corresponds to the `Chi` instruction. defOffset = oldOffset * 2 + 1 and - result = Chi(oldInstr) and + result = getChi(oldInstr) and ( defLocation = Alias::getResultMemoryLocation(oldInstr) or defLocation = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() @@ -607,7 +570,7 @@ module DefUse { or defOffset = -1 and hasDefinition(_, defLocation, defBlock, defOffset) and - result = Phi(defBlock, defLocation) and + result = getPhi(defBlock, defLocation) and actualDefLocation = defLocation } @@ -891,7 +854,7 @@ private module CachedForDebugging { ) or exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity | - instr = Phi(phiBlock, location) and + instr = getPhi(phiBlock, location) and result = "Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " + location.getUniqueId() and if location instanceof Alias::VirtualVariable @@ -901,7 +864,7 @@ private module CachedForDebugging { else specificity = "s" ) or - instr = Unreached(_) and + instr = unreachedInstruction(_) and result = "Unreached" } @@ -961,3 +924,19 @@ module SSAConsistency { ) } } + +/** + * Provides the portion of the parameterized IR interface that is used to construct the SSA stages + * of the IR. The raw stage of the IR does not expose these predicates. + * These predicates are all just aliases for predicates defined in the `Cached` module. This ensures + * that all of SSA construction will be evaluated in the same stage. + */ +module SSA { + class MemoryLocation = Alias::MemoryLocation; + + predicate hasPhiInstruction = Cached::hasPhiInstructionCached/2; + + predicate hasChiInstruction = Cached::hasChiInstructionCached/1; + + predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1; +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll index 00f12020a29d..f347df86ba1e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll @@ -1,3 +1,5 @@ -import semmle.code.cpp.ir.implementation.Opcode -import semmle.code.cpp.ir.implementation.internal.OperandTag -import semmle.code.cpp.ir.internal.Overlap +import semmle.code.cpp.ir.implementation.Opcode as Opcode +import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag +import semmle.code.cpp.ir.internal.Overlap as Overlap +import semmle.code.cpp.ir.implementation.internal.TInstruction as TInstruction +import semmle.code.cpp.ir.implementation.raw.IR as RawIR diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll index 4cfbdfe831e1..73b08d1286b5 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll @@ -2,5 +2,7 @@ import semmle.code.cpp.ir.implementation.raw.IR as OldIR import semmle.code.cpp.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability import semmle.code.cpp.ir.implementation.raw.internal.reachability.Dominance as Dominance import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as NewIR +import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as RawStage +import semmle.code.cpp.ir.implementation.internal.TInstruction::UnaliasedSSAInstructions as SSAInstructions import semmle.code.cpp.ir.internal.IRCppLanguage as Language import SimpleSSA as Alias diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll index aee4959513ed..a7b9160bdc75 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll @@ -59,6 +59,12 @@ class MemoryLocation extends TMemoryLocation { final string getUniqueId() { result = var.getUniqueId() } } +/** + * Represents a set of `MemoryLocation`s that cannot overlap with + * `MemoryLocation`s outside of the set. The `VirtualVariable` will be + * represented by a `MemoryLocation` that totally overlaps all other + * `MemoryLocations` in the set. + */ class VirtualVariable extends MemoryLocation { } /** A virtual variable that groups all escaped memory within a function. */ @@ -79,3 +85,9 @@ MemoryLocation getResultMemoryLocation(Instruction instr) { MemoryLocation getOperandMemoryLocation(MemoryOperand operand) { result = getMemoryLocation(getAddressOperandAllocation(operand.getAddressOperand())) } + +/** Gets the start bit offset of a `MemoryLocation`, if any. */ +int getStartBitOffset(MemoryLocation location) { none() } + +/** Gets the end bit offset of a `MemoryLocation`, if any. */ +int getEndBitOffset(MemoryLocation location) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll index f8c4ceaf9049..2ce23f098a2d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll @@ -1,7 +1,7 @@ private import cpp private import semmle.code.cpp.Print private import semmle.code.cpp.ir.implementation.IRType -private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction +private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction::Raw as Raw private int getPointerSize() { result = max(any(NullPointerType t).getSize()) } @@ -143,7 +143,7 @@ private predicate isOpaqueType(Type type) { predicate hasOpaqueType(Type tag, int byteSize) { isOpaqueType(tag) and byteSize = getTypeSize(tag) or - tag instanceof UnknownType and IRConstruction::needsUnknownOpaqueType(byteSize) + tag instanceof UnknownType and Raw::needsUnknownOpaqueType(byteSize) } /** @@ -191,7 +191,7 @@ private newtype TCppType = TPRValueType(Type type) { exists(getIRTypeForPRValue(type)) } or TFunctionGLValueType() or TGLValueAddressType(Type type) or - TUnknownOpaqueType(int byteSize) { IRConstruction::needsUnknownOpaqueType(byteSize) } or + TUnknownOpaqueType(int byteSize) { Raw::needsUnknownOpaqueType(byteSize) } or TUnknownType() /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/Overlap.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/Overlap.qll index 8ce0549b2b4d..f9a0c574f8c3 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/Overlap.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/Overlap.qll @@ -3,18 +3,33 @@ private newtype TOverlap = TMustTotallyOverlap() or TMustExactlyOverlap() +/** + * Represents a possible overlap between two memory ranges. + */ abstract class Overlap extends TOverlap { abstract string toString(); } +/** + * Represents a partial overlap between two memory ranges, which may or may not + * actually occur in practice. + */ class MayPartiallyOverlap extends Overlap, TMayPartiallyOverlap { final override string toString() { result = "MayPartiallyOverlap" } } +/** + * Represents an overlap in which the first memory range is known to include all + * bits of the second memory range, but may be larger or have a different type. + */ class MustTotallyOverlap extends Overlap, TMustTotallyOverlap { final override string toString() { result = "MustTotallyOverlap" } } +/** + * Represents an overlap between two memory ranges that have the same extent and + * the same type. + */ class MustExactlyOverlap extends Overlap, TMustExactlyOverlap { final override string toString() { result = "MustExactlyOverlap" } } diff --git a/cpp/ql/src/semmle/code/cpp/metrics/MetricFunction.qll b/cpp/ql/src/semmle/code/cpp/metrics/MetricFunction.qll index 3dbb290d71a7..45036cfddf33 100644 --- a/cpp/ql/src/semmle/code/cpp/metrics/MetricFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/metrics/MetricFunction.qll @@ -334,7 +334,7 @@ private predicate branchingExpr(Expr expr) { * Gets the number of branching statements and expressions in a block. This is * for computing cyclomatic complexity. */ -int cyclomaticComplexityBranches(Block b) { +int cyclomaticComplexityBranches(BlockStmt b) { result = count(Stmt stmt | branchingStmt(stmt) and @@ -373,7 +373,7 @@ private predicate skipParent(Stmt s) { exists(Stmt parent | parent = s.getParentStmt() | s instanceof IfStmt and parent.(IfStmt).getElse() = s or - parent instanceof Block + parent instanceof BlockStmt or exists(File f, int startLine, int startCol | startsAt(s, f, startLine, startCol) and diff --git a/cpp/ql/src/semmle/code/cpp/models/Models.qll b/cpp/ql/src/semmle/code/cpp/models/Models.qll index 82ae1fdc4f0a..75e81fdc318e 100644 --- a/cpp/ql/src/semmle/code/cpp/models/Models.qll +++ b/cpp/ql/src/semmle/code/cpp/models/Models.qll @@ -4,6 +4,8 @@ private import implementations.Fread private import implementations.Gets private import implementations.IdentityFunction private import implementations.Inet +private import implementations.Iterator +private import implementations.MemberFunction private import implementations.Memcpy private import implementations.Memset private import implementations.Printf @@ -12,6 +14,11 @@ private import implementations.Strcat private import implementations.Strcpy private import implementations.Strdup private import implementations.Strftime +private import implementations.StdContainer +private import implementations.StdPair +private import implementations.StdMap +private import implementations.StdSet private import implementations.StdString private import implementations.Swap private import implementations.GetDelim +private import implementations.SmartPointer diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll index 782800d0fa24..1f82b90bff42 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll @@ -1,5 +1,5 @@ /** - * Provides implementation classes modelling various methods of allocation + * Provides implementation classes modeling various methods of allocation * (`malloc`, `new` etc). See `semmle.code.cpp.models.interfaces.Allocation` * for usage information. */ diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll index 2ef355bf3982..4f0341b673ee 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll @@ -1,5 +1,5 @@ /** - * Provides implementation classes modelling various methods of deallocation + * Provides implementation classes modeling various methods of deallocation * (`free`, `delete` etc). See `semmle.code.cpp.models.interfaces.Deallocation` * for usage information. */ diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll index e5e45729e0dc..d22f2f376806 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll @@ -1,3 +1,8 @@ +/** + * Provides implementation classes modeling `gets` and various similar + * functions. See `semmle.code.cpp.models.Models` for usage information. + */ + import semmle.code.cpp.models.interfaces.DataFlow import semmle.code.cpp.models.interfaces.Taint import semmle.code.cpp.models.interfaces.ArrayFunction @@ -11,11 +16,10 @@ import semmle.code.cpp.models.interfaces.FlowSource class GetsFunction extends DataFlowFunction, TaintFunction, ArrayFunction, AliasFunction, SideEffectFunction, RemoteFlowFunction { GetsFunction() { - exists(string name | hasGlobalOrStdName(name) | - name = "gets" or // gets(str) - name = "fgets" or // fgets(str, num, stream) - name = "fgetws" // fgetws(wstr, num, stream) - ) + // gets(str) + // fgets(str, num, stream) + // fgetws(wstr, num, stream) + hasGlobalOrStdName(["gets", "fgets", "fgetws"]) } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { @@ -48,4 +52,17 @@ class GetsFunction extends DataFlowFunction, TaintFunction, ArrayFunction, Alias output.isParameterDeref(0) and description = "String read by " + this.getName() } + + override predicate hasArrayWithVariableSize(int bufParam, int countParam) { + not hasGlobalOrStdName("gets") and + bufParam = 0 and + countParam = 1 + } + + override predicate hasArrayWithUnknownSize(int bufParam) { + hasGlobalOrStdName("gets") and + bufParam = 0 + } + + override predicate hasArrayOutput(int bufParam) { bufParam = 0 } } diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/IdentityFunction.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/IdentityFunction.qll index 865a74b55717..f9eab7aba939 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/IdentityFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/IdentityFunction.qll @@ -4,16 +4,13 @@ import semmle.code.cpp.models.interfaces.DataFlow import semmle.code.cpp.models.interfaces.SideEffect /** - * The standard function templates `std::move` and `std::identity` + * The standard function templates `std::move` and `std::forward`. */ class IdentityFunction extends DataFlowFunction, SideEffectFunction, AliasFunction { IdentityFunction() { this.getNamespace().getParentNamespace() instanceof GlobalNamespace and this.getNamespace().getName() = "std" and - ( - this.getName() = "move" or - this.getName() = "forward" - ) + this.getName() = ["move", "forward"] } override predicate hasOnlySpecificReadSideEffects() { any() } diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll new file mode 100644 index 000000000000..71453467d8a7 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll @@ -0,0 +1,293 @@ +/** + * Provides implementation classes modeling C++ iterators, including + * `std::iterator`, `std::iterator_traits`, and types meeting the + * `LegacyIterator` named requirement. See `semmle.code.cpp.models.Models` for + * usage information. + */ + +import cpp +import semmle.code.cpp.models.interfaces.Taint +import semmle.code.cpp.models.interfaces.DataFlow +import semmle.code.cpp.models.interfaces.Iterator + +/** + * An instantiation of the `std::iterator_traits` template. + */ +class IteratorTraits extends Class { + IteratorTraits() { + this.hasQualifiedName("std", "iterator_traits") and + not this instanceof TemplateClass and + exists(TypedefType t | + this.getAMember() = t and + t.getName() = "iterator_category" + ) + } + + Type getIteratorType() { result = this.getTemplateArgument(0) } +} + +/** + * A type which has the typedefs expected for an iterator. + */ +class IteratorByTypedefs extends Class { + IteratorByTypedefs() { + this.getAMember().(TypedefType).hasName("difference_type") and + this.getAMember().(TypedefType).hasName("value_type") and + this.getAMember().(TypedefType).hasName("pointer") and + this.getAMember().(TypedefType).hasName("reference") and + this.getAMember().(TypedefType).hasName("iterator_category") and + not this.hasQualifiedName("std", "iterator_traits") + } +} + +/** + * The `std::iterator` class. + */ +class StdIterator extends Class { + StdIterator() { this.hasQualifiedName("std", "iterator") } +} + +/** + * A type which can be used as an iterator + */ +class Iterator extends Type { + Iterator() { + this instanceof IteratorByTypedefs or + exists(IteratorTraits it | it.getIteratorType() = this) or + this instanceof StdIterator + } +} + +private FunctionInput getIteratorArgumentInput(Operator op, int index) { + exists(Type t | + t = + op + .getACallToThisFunction() + .getArgument(index) + .getExplicitlyConverted() + .getType() + .stripTopLevelSpecifiers() + | + ( + t instanceof Iterator or + t.(ReferenceType).getBaseType() instanceof Iterator + ) and + if op.getParameter(index).getUnspecifiedType() instanceof ReferenceType + then result.isParameterDeref(index) + else result.isParameter(index) + ) +} + +/** + * A non-member prefix `operator*` function for an iterator type. + */ +class IteratorPointerDereferenceOperator extends Operator, TaintFunction, IteratorReferenceFunction { + FunctionInput iteratorInput; + + IteratorPointerDereferenceOperator() { + this.hasName("operator*") and + iteratorInput = getIteratorArgumentInput(this, 0) + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + input = iteratorInput and + output.isReturnValue() + } +} + +/** + * A non-member `operator++` or `operator--` function for an iterator type. + */ +class IteratorCrementOperator extends Operator, DataFlowFunction { + FunctionInput iteratorInput; + + IteratorCrementOperator() { + this.hasName(["operator++", "operator--"]) and + iteratorInput = getIteratorArgumentInput(this, 0) + } + + override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { + input = iteratorInput and + output.isReturnValue() + } +} + +/** + * A non-member `operator+` function for an iterator type. + */ +class IteratorAddOperator extends Operator, TaintFunction { + FunctionInput iteratorInput; + + IteratorAddOperator() { + this.hasName("operator+") and + iteratorInput = getIteratorArgumentInput(this, [0, 1]) + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + input = iteratorInput and + output.isReturnValue() + } +} + +/** + * A non-member `operator-` function that takes a pointer difference type as its second argument. + */ +class IteratorSubOperator extends Operator, TaintFunction { + FunctionInput iteratorInput; + + IteratorSubOperator() { + this.hasName("operator-") and + iteratorInput = getIteratorArgumentInput(this, 0) and + this.getParameter(1).getUnspecifiedType() instanceof IntegralType // not an iterator difference + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + input = iteratorInput and + output.isReturnValue() + } +} + +/** + * A non-member `operator+=` or `operator-=` function for an iterator type. + */ +class IteratorAssignArithmeticOperator extends Operator, DataFlowFunction, TaintFunction { + IteratorAssignArithmeticOperator() { + this.hasName(["operator+=", "operator-="]) and + this.getDeclaringType() instanceof Iterator + } + + override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { + input.isParameter(0) and + output.isReturnValue() + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + input.isParameterDeref(1) and + output.isParameterDeref(0) + } +} + +/** + * A prefix `operator*` member function for an iterator type. + */ +class IteratorPointerDereferenceMemberOperator extends MemberFunction, TaintFunction, + IteratorReferenceFunction { + IteratorPointerDereferenceMemberOperator() { + this.hasName("operator*") and + this.getDeclaringType() instanceof Iterator + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + input.isQualifierObject() and + output.isReturnValue() + } +} + +/** + * An `operator++` or `operator--` member function for an iterator type. + */ +class IteratorCrementMemberOperator extends MemberFunction, DataFlowFunction, TaintFunction { + IteratorCrementMemberOperator() { + this.hasName(["operator++", "operator--"]) and + this.getDeclaringType() instanceof Iterator + } + + override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { + input.isQualifierAddress() and + output.isReturnValue() + or + input.isReturnValueDeref() and + output.isQualifierObject() + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + input.isQualifierObject() and + output.isReturnValueDeref() + } +} + +/** + * A member `operator->` function for an iterator type. + */ +class IteratorFieldMemberOperator extends Operator, TaintFunction { + IteratorFieldMemberOperator() { + this.hasName("operator->") and + this.getDeclaringType() instanceof Iterator + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + input.isQualifierObject() and + output.isReturnValue() + } +} + +/** + * An `operator+` or `operator-` member function of an iterator class. + */ +class IteratorBinaryArithmeticMemberOperator extends MemberFunction, TaintFunction { + IteratorBinaryArithmeticMemberOperator() { + this.hasName(["operator+", "operator-"]) and + this.getDeclaringType() instanceof Iterator + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + input.isQualifierObject() and + output.isReturnValue() + } +} + +/** + * An `operator+=` or `operator-=` member function of an iterator class. + */ +class IteratorAssignArithmeticMemberOperator extends MemberFunction, DataFlowFunction, TaintFunction { + IteratorAssignArithmeticMemberOperator() { + this.hasName(["operator+=", "operator-="]) and + this.getDeclaringType() instanceof Iterator + } + + override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { + input.isQualifierAddress() and + output.isReturnValue() + or + input.isReturnValueDeref() and + output.isQualifierObject() + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + input.isQualifierObject() and + output.isReturnValueDeref() + } +} + +/** + * An `operator[]` member function of an iterator class. + */ +class IteratorArrayMemberOperator extends MemberFunction, TaintFunction, IteratorReferenceFunction { + IteratorArrayMemberOperator() { + this.hasName("operator[]") and + this.getDeclaringType() instanceof Iterator + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + input.isQualifierObject() and + output.isReturnValue() + } +} + +/** + * A `begin` or `end` member function, or a related member function, that + * returns an iterator. + */ +class BeginOrEndFunction extends MemberFunction, TaintFunction { + BeginOrEndFunction() { + this + .hasName(["begin", "cbegin", "rbegin", "crbegin", "end", "cend", "rend", "crend", + "before_begin", "cbefore_begin"]) and + this.getType().getUnspecifiedType() instanceof Iterator + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + input.isQualifierObject() and + output.isReturnValue() + } +} diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/MemberFunction.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/MemberFunction.qll new file mode 100644 index 000000000000..0e4812cc25cc --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/MemberFunction.qll @@ -0,0 +1,92 @@ +/** + * Provides models for C++ constructors and user-defined operators. + */ + +import cpp +import semmle.code.cpp.models.interfaces.DataFlow +import semmle.code.cpp.models.interfaces.Taint + +/** + * Model for C++ conversion constructors. As of C++11 this does not correspond + * perfectly with the language definition of a converting constructor, however, + * it does correspond with the constructors we are confident taint should flow + * through. + */ +class ConversionConstructorModel extends Constructor, TaintFunction { + ConversionConstructorModel() { + strictcount(Parameter p | p = getAParameter() and not p.hasInitializer()) = 1 and + not hasSpecifier("explicit") + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // taint flow from the first constructor argument to the returned object + input.isParameter(0) and + ( + output.isReturnValue() + or + output.isQualifierObject() + ) + } +} + +/** + * Model for C++ copy constructors. + */ +class CopyConstructorModel extends CopyConstructor, DataFlowFunction { + override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { + // data flow from the first constructor argument to the returned object + input.isParameter(0) and + ( + output.isReturnValue() + or + output.isQualifierObject() + ) + } +} + +/** + * Model for C++ move constructors. + */ +class MoveConstructorModel extends MoveConstructor, DataFlowFunction { + override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { + // data flow from the first constructor argument to the returned object + input.isParameter(0) and + ( + output.isReturnValue() + or + output.isQualifierObject() + ) + } +} + +/** + * Model for C++ copy assignment operators. + */ +class CopyAssignmentOperatorModel extends CopyAssignmentOperator, TaintFunction { + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // taint flow from argument to self + input.isParameterDeref(0) and + output.isQualifierObject() + or + // taint flow from argument to return value + input.isParameterDeref(0) and + output.isReturnValueDeref() + // TODO: it would be more accurate to model copy assignment as data flow + } +} + +/** + * Model for C++ move assignment operators. + */ +class MoveAssignmentOperatorModel extends MoveAssignmentOperator, TaintFunction { + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // taint flow from argument to self + input.isParameterDeref(0) and + output.isQualifierObject() + or + // taint flow from argument to return value + input.isParameterDeref(0) and + output.isReturnValueDeref() + // TODO: it would be more accurate to model move assignment as data flow + } +} diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll index 0951daea11b7..ef4aa8b7290e 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll @@ -1,3 +1,8 @@ +/** + * Provides implementation classes modeling `memcpy` and various similar + * functions. See `semmle.code.cpp.models.Models` for usage information. + */ + import semmle.code.cpp.Function import semmle.code.cpp.models.interfaces.ArrayFunction import semmle.code.cpp.models.interfaces.DataFlow diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll index 7fc7fbfc9e5b..2c34369aee44 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll @@ -1,3 +1,8 @@ +/** + * Provides implementation classes modeling `memset` and various similar + * functions. See `semmle.code.cpp.models.Models` for usage information. + */ + import semmle.code.cpp.Function import semmle.code.cpp.models.interfaces.ArrayFunction import semmle.code.cpp.models.interfaces.DataFlow diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll index b5047c25e854..61dd3bc50b9d 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll @@ -1,3 +1,10 @@ +/** + * Provides implementation classes modeling various standard formatting + * functions (`printf`, `snprintf` etc). + * See `semmle.code.cpp.models.interfaces.FormattingFunction` for usage + * information. + */ + import semmle.code.cpp.models.interfaces.FormattingFunction import semmle.code.cpp.models.interfaces.Alias @@ -59,12 +66,25 @@ class Sprintf extends FormattingFunction { Sprintf() { this instanceof TopLevelFunction and ( - hasGlobalOrStdName("sprintf") or - hasGlobalName("_sprintf_l") or - hasGlobalName("__swprintf_l") or - hasGlobalOrStdName("wsprintf") or - hasGlobalName("g_strdup_printf") or - hasGlobalName("g_sprintf") or + // sprintf(dst, format, args...) + hasGlobalOrStdName("sprintf") + or + // _sprintf_l(dst, format, locale, args...) + hasGlobalName("_sprintf_l") + or + // __swprintf_l(dst, format, locale, args...) + hasGlobalName("__swprintf_l") + or + // wsprintf(dst, format, args...) + hasGlobalOrStdName("wsprintf") + or + // g_strdup_printf(format, ...) + hasGlobalName("g_strdup_printf") + or + // g_sprintf(dst, format, ...) + hasGlobalName("g_sprintf") + or + // __builtin___sprintf_chk(dst, flag, os, format, ...) hasGlobalName("__builtin___sprintf_chk") ) and not exists(getDefinition().getFile().getRelativePath()) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/SmartPointer.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/SmartPointer.qll new file mode 100644 index 000000000000..7dde921bfa1f --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/SmartPointer.qll @@ -0,0 +1,61 @@ +import semmle.code.cpp.models.interfaces.Taint + +/** + * The `std::shared_ptr` and `std::unique_ptr` template classes. + */ +class UniqueOrSharedPtr extends Class { + UniqueOrSharedPtr() { this.hasQualifiedName("std", ["shared_ptr", "unique_ptr"]) } +} + +/** + * The `std::make_shared` and `std::make_unique` template functions. + */ +class MakeUniqueOrShared extends TaintFunction { + MakeUniqueOrShared() { this.hasQualifiedName("std", ["make_shared", "make_unique"]) } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // Exclude the specializations of `std::make_shared` and `std::make_unique` that allocate arrays + // since these just take a size argument, which we don't want to propagate taint through. + not this.isArray() and + input.isParameter(_) and + output.isReturnValue() + } + + /** + * Holds if the function returns a `shared_ptr` (or `unique_ptr`) where `T` is an + * array type (i.e., `U[]` for some type `U`). + */ + predicate isArray() { + this.getTemplateArgument(0).(Type).getUnderlyingType() instanceof ArrayType + } +} + +/** + * A prefix `operator*` member function for a `shared_ptr` or `unique_ptr` type. + */ +class UniqueOrSharedDereferenceMemberOperator extends MemberFunction, TaintFunction { + UniqueOrSharedDereferenceMemberOperator() { + this.hasName("operator*") and + this.getDeclaringType() instanceof UniqueOrSharedPtr + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + input.isQualifierObject() and + output.isReturnValueDeref() + } +} + +/** + * The `std::shared_ptr` or `std::unique_ptr` function `get`. + */ +class UniqueOrSharedGet extends TaintFunction { + UniqueOrSharedGet() { + this.hasName("get") and + this.getDeclaringType() instanceof UniqueOrSharedPtr + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + input.isQualifierObject() and + output.isReturnValue() + } +} diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll new file mode 100644 index 000000000000..a339dadb860f --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll @@ -0,0 +1,208 @@ +/** + * Provides models for C++ containers `std::array`, `std::vector`, `std::deque`, `std::list` and `std::forward_list`. + */ + +import semmle.code.cpp.models.interfaces.Taint +import semmle.code.cpp.models.implementations.Iterator + +/** + * Additional model for standard container constructors that reference the + * value type of the container (that is, the `T` in `std::vector`). For + * example the fill constructor: + * ``` + * std::vector v(100, potentially_tainted_string); + * ``` + */ +class StdSequenceContainerConstructor extends Constructor, TaintFunction { + StdSequenceContainerConstructor() { + this.getDeclaringType().hasQualifiedName("std", ["vector", "deque", "list", "forward_list"]) + } + + /** + * Gets the index of a parameter to this function that is a reference to the + * value type of the container. + */ + int getAValueTypeParameterIndex() { + getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() = + getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector` + } + + /** + * Gets the index of a parameter to this function that is an iterator. + */ + int getAnIteratorParameterIndex() { getParameter(result).getType() instanceof Iterator } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // taint flow from any parameter of the value type to the returned object + ( + input.isParameterDeref(getAValueTypeParameterIndex()) or + input.isParameter(getAnIteratorParameterIndex()) + ) and + ( + output.isReturnValue() // TODO: this is only needed for AST data flow, which treats constructors as returning the new object + or + output.isQualifierObject() + ) + } +} + +/** + * The standard container function `data`. + */ +class StdSequenceContainerData extends TaintFunction { + StdSequenceContainerData() { this.hasQualifiedName("std", ["array", "vector"], "data") } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from container itself (qualifier) to return value + input.isQualifierObject() and + output.isReturnValueDeref() + or + // reverse flow from returned reference to the qualifier (for writes to + // `data`) + input.isReturnValueDeref() and + output.isQualifierObject() + } +} + +/** + * The standard container functions `push_back` and `push_front`. + */ +class StdSequenceContainerPush extends TaintFunction { + StdSequenceContainerPush() { + this.hasQualifiedName("std", "vector", "push_back") or + this.hasQualifiedName("std", "deque", ["push_back", "push_front"]) or + this.hasQualifiedName("std", "list", ["push_back", "push_front"]) or + this.hasQualifiedName("std", "forward_list", "push_front") + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from parameter to qualifier + input.isParameterDeref(0) and + output.isQualifierObject() + } +} + +/** + * The standard container functions `front` and `back`. + */ +class StdSequenceContainerFrontBack extends TaintFunction { + StdSequenceContainerFrontBack() { + this.hasQualifiedName("std", "array", ["front", "back"]) or + this.hasQualifiedName("std", "vector", ["front", "back"]) or + this.hasQualifiedName("std", "deque", ["front", "back"]) or + this.hasQualifiedName("std", "list", ["front", "back"]) or + this.hasQualifiedName("std", "forward_list", "front") + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from object to returned reference + input.isQualifierObject() and + output.isReturnValueDeref() + } +} + +/** + * The standard container functions `insert` and `insert_after`. + */ +class StdSequenceContainerInsert extends TaintFunction { + StdSequenceContainerInsert() { + this.hasQualifiedName("std", ["vector", "deque", "list"], "insert") or + this.hasQualifiedName("std", ["forward_list"], "insert_after") + } + + /** + * Gets the index of a parameter to this function that is a reference to the + * value type of the container. + */ + int getAValueTypeParameterIndex() { + getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() = + getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector` + } + + /** + * Gets the index of a parameter to this function that is an iterator. + */ + int getAnIteratorParameterIndex() { getParameter(result).getType() instanceof Iterator } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from parameter to container itself (qualifier) and return value + ( + input.isQualifierObject() or + input.isParameterDeref(getAValueTypeParameterIndex()) or + input.isParameter(getAnIteratorParameterIndex()) + ) and + ( + output.isQualifierObject() or + output.isReturnValueDeref() + ) + } +} + +/** + * The standard container function `assign`. + */ +class StdSequenceContainerAssign extends TaintFunction { + StdSequenceContainerAssign() { + this.hasQualifiedName("std", ["vector", "deque", "list", "forward_list"], "assign") + } + + /** + * Gets the index of a parameter to this function that is a reference to the + * value type of the container. + */ + int getAValueTypeParameterIndex() { + getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() = + getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector` + } + + /** + * Gets the index of a parameter to this function that is an iterator. + */ + int getAnIteratorParameterIndex() { getParameter(result).getType() instanceof Iterator } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from parameter to container itself (qualifier) + ( + input.isParameterDeref(getAValueTypeParameterIndex()) or + input.isParameter(getAnIteratorParameterIndex()) + ) and + output.isQualifierObject() + } +} + +/** + * The standard container `swap` functions. + */ +class StdSequenceContainerSwap extends TaintFunction { + StdSequenceContainerSwap() { + this.hasQualifiedName("std", ["array", "vector", "deque", "list", "forward_list"], "swap") + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // container1.swap(container2) + input.isQualifierObject() and + output.isParameterDeref(0) + or + input.isParameterDeref(0) and + output.isQualifierObject() + } +} + +/** + * The standard container functions `at` and `operator[]`. + */ +class StdSequenceContainerAt extends TaintFunction { + StdSequenceContainerAt() { + this.hasQualifiedName("std", ["vector", "array", "deque"], ["at", "operator[]"]) + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from qualifier to referenced return value + input.isQualifierObject() and + output.isReturnValueDeref() + or + // reverse flow from returned reference to the qualifier + input.isReturnValueDeref() and + output.isQualifierObject() + } +} diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdMap.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdMap.qll new file mode 100644 index 000000000000..12e6624903e6 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdMap.qll @@ -0,0 +1,192 @@ +/** + * Provides models for C++ containers `std::map` and `std::unordered_map`. + */ + +import semmle.code.cpp.models.interfaces.Taint +import semmle.code.cpp.models.implementations.Iterator + +/** + * Additional model for map constructors using iterator inputs. + */ +class StdMapConstructor extends Constructor, TaintFunction { + StdMapConstructor() { + this.hasQualifiedName("std", "map", "map") or + this.hasQualifiedName("std", "unordered_map", "unordered_map") + } + + /** + * Gets the index of a parameter to this function that is an iterator. + */ + int getAnIteratorParameterIndex() { + getParameter(result).getUnspecifiedType() instanceof Iterator + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // taint flow from any parameter of an iterator type to the qualifier + input.isParameterDeref(getAnIteratorParameterIndex()) and + ( + output.isReturnValue() // TODO: this is only needed for AST data flow, which treats constructors as returning the new object + or + output.isQualifierObject() + ) + } +} + +/** + * The standard map `insert` and `insert_or_assign` functions. + */ +class StdMapInsert extends TaintFunction { + StdMapInsert() { + this.hasQualifiedName("std", ["map", "unordered_map"], ["insert", "insert_or_assign"]) + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from last parameter to qualifier and return value + // (where the return value is a pair, this should really flow just to the first part of it) + input.isParameterDeref(getNumberOfParameters() - 1) and + ( + output.isQualifierObject() or + output.isReturnValue() + ) + } +} + +/** + * The standard map `emplace` and `emplace_hint` functions. + */ +class StdMapEmplace extends TaintFunction { + StdMapEmplace() { + this.hasQualifiedName("std", ["map", "unordered_map"], ["emplace", "emplace_hint"]) + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from the last parameter (which may be the value part used to + // construct a pair, or a pair to be copied / moved) to the qualifier and + // return value. + // (where the return value is a pair, this should really flow just to the first part of it) + input.isParameterDeref(getNumberOfParameters() - 1) and + ( + output.isQualifierObject() or + output.isReturnValue() + ) + or + input.isQualifierObject() and + output.isReturnValue() + } +} + +/** + * The standard map `try_emplace` function. + */ +class StdMapTryEmplace extends TaintFunction { + StdMapTryEmplace() { this.hasQualifiedName("std", ["map", "unordered_map"], "try_emplace") } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from any parameter apart from the key to qualifier and return value + // (here we assume taint flow from any constructor parameter to the constructed object) + // (where the return value is a pair, this should really flow just to the first part of it) + exists(int arg | arg = [1 .. getNumberOfParameters() - 1] | + ( + not getUnspecifiedType() instanceof Iterator or + arg != 1 + ) and + input.isParameterDeref(arg) + ) and + ( + output.isQualifierObject() or + output.isReturnValue() + ) + or + input.isQualifierObject() and + output.isReturnValue() + } +} + +/** + * The standard map `swap` function. + */ +class StdMapSwap extends TaintFunction { + StdMapSwap() { this.hasQualifiedName("std", ["map", "unordered_map"], "swap") } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // container1.swap(container2) + input.isQualifierObject() and + output.isParameterDeref(0) + or + input.isParameterDeref(0) and + output.isQualifierObject() + } +} + +/** + * The standard map `merge` function. + */ +class StdMapMerge extends TaintFunction { + StdMapMerge() { this.hasQualifiedName("std", ["map", "unordered_map"], "merge") } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // container1.merge(container2) + input.isParameterDeref(0) and + output.isQualifierObject() + } +} + +/** + * The standard map functions `at` and `operator[]`. + */ +class StdMapAt extends TaintFunction { + StdMapAt() { this.hasQualifiedName("std", ["map", "unordered_map"], ["at", "operator[]"]) } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from qualifier to referenced return value + input.isQualifierObject() and + output.isReturnValueDeref() + or + // reverse flow from returned reference to the qualifier + input.isReturnValueDeref() and + output.isQualifierObject() + } +} + +/** + * The standard map `find` function. + */ +class StdMapFind extends TaintFunction { + StdMapFind() { this.hasQualifiedName("std", ["map", "unordered_map"], "find") } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + input.isQualifierObject() and + output.isReturnValue() + } +} + +/** + * The standard map `erase` function. + */ +class StdMapErase extends TaintFunction { + StdMapErase() { this.hasQualifiedName("std", ["map", "unordered_map"], "erase") } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from qualifier to iterator return value + getType().getUnderlyingType() instanceof Iterator and + input.isQualifierObject() and + output.isReturnValue() + } +} + +/** + * The standard map `lower_bound`, `upper_bound` and `equal_range` functions. + */ +class StdMapEqualRange extends TaintFunction { + StdMapEqualRange() { + this + .hasQualifiedName("std", ["map", "unordered_map"], + ["lower_bound", "upper_bound", "equal_range"]) + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from qualifier to return value + input.isQualifierObject() and + output.isReturnValue() + } +} diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll new file mode 100644 index 000000000000..b36f7ab3325d --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll @@ -0,0 +1,48 @@ +/** + * Provides models for the C++ `std::pair` class. + */ + +import semmle.code.cpp.models.interfaces.Taint + +/** + * Additional model for `std::pair` constructors. + */ +class StdPairConstructor extends Constructor, TaintFunction { + StdPairConstructor() { this.hasQualifiedName("std", "pair", "pair") } + + /** + * Gets the index of a parameter to this function that is a reference to + * either value type of the pair. + */ + int getAValueTypeParameterIndex() { + getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() = + getDeclaringType().getTemplateArgument(_).(Type).getUnspecifiedType() // i.e. the `T1` or `T2` of this `std::pair` + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // taint flow from second parameter of a value type to the qualifier + getAValueTypeParameterIndex() = 1 and + input.isParameterDeref(1) and + ( + output.isReturnValue() // TODO: this is only needed for AST data flow, which treats constructors as returning the new object + or + output.isQualifierObject() + ) + } +} + +/** + * The standard pair `swap` function. + */ +class StdPairSwap extends TaintFunction { + StdPairSwap() { this.hasQualifiedName("std", "pair", "swap") } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // container1.swap(container2) + input.isQualifierObject() and + output.isParameterDeref(0) + or + input.isParameterDeref(0) and + output.isQualifierObject() + } +} diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdSet.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdSet.qll new file mode 100644 index 000000000000..06e8be4c4a41 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdSet.qll @@ -0,0 +1,145 @@ +/** + * Provides models for C++ containers `std::set` and `std::unordered_set`. + */ + +import semmle.code.cpp.models.interfaces.Taint +import semmle.code.cpp.models.implementations.Iterator + +/** + * Additional model for set constructors using iterator inputs. + */ +class StdSetConstructor extends Constructor, TaintFunction { + StdSetConstructor() { + this.hasQualifiedName("std", "set", "set") or + this.hasQualifiedName("std", "unordered_set", "unordered_set") + } + + /** + * Gets the index of a parameter to this function that is an iterator. + */ + int getAnIteratorParameterIndex() { + getParameter(result).getUnspecifiedType() instanceof Iterator + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // taint flow from any parameter of an iterator type to the qualifier + input.isParameterDeref(getAnIteratorParameterIndex()) and + ( + output.isReturnValue() // TODO: this is only needed for AST data flow, which treats constructors as returning the new object + or + output.isQualifierObject() + ) + } +} + +/** + * The standard set `insert` and `insert_or_assign` functions. + */ +class StdSetInsert extends TaintFunction { + StdSetInsert() { this.hasQualifiedName("std", ["set", "unordered_set"], "insert") } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from last parameter to qualifier and return value + // (where the return value is a pair, this should really flow just to the first part of it) + input.isParameterDeref(getNumberOfParameters() - 1) and + ( + output.isQualifierObject() or + output.isReturnValue() + ) + } +} + +/** + * The standard set `emplace` and `emplace_hint` functions. + */ +class StdSetEmplace extends TaintFunction { + StdSetEmplace() { + this.hasQualifiedName("std", ["set", "unordered_set"], ["emplace", "emplace_hint"]) + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from any parameter to qualifier and return value + // (here we assume taint flow from any constructor parameter to the constructed object) + // (where the return value is a pair, this should really flow just to the first part of it) + input.isParameter([0 .. getNumberOfParameters() - 1]) and + ( + output.isQualifierObject() or + output.isReturnValue() + ) + or + input.isQualifierObject() and + output.isReturnValue() + } +} + +/** + * The standard set `swap` functions. + */ +class StdSetSwap extends TaintFunction { + StdSetSwap() { this.hasQualifiedName("std", ["set", "unordered_set"], "swap") } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // container1.swap(container2) + input.isQualifierObject() and + output.isParameterDeref(0) + or + input.isParameterDeref(0) and + output.isQualifierObject() + } +} + +/** + * The standard set `merge` function. + */ +class StdSetMerge extends TaintFunction { + StdSetMerge() { this.hasQualifiedName("std", ["set", "unordered_set"], "merge") } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // container1.merge(container2) + input.isParameterDeref(0) and + output.isQualifierObject() + } +} + +/** + * The standard set `find` function. + */ +class StdSetFind extends TaintFunction { + StdSetFind() { this.hasQualifiedName("std", ["set", "unordered_set"], "find") } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + input.isQualifierObject() and + output.isReturnValue() + } +} + +/** + * The standard set `erase` function. + */ +class StdSetErase extends TaintFunction { + StdSetErase() { this.hasQualifiedName("std", ["set", "unordered_set"], "erase") } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from qualifier to iterator return value + getType().getUnderlyingType() instanceof Iterator and + input.isQualifierObject() and + output.isReturnValue() + } +} + +/** + * The standard set `lower_bound`, `upper_bound` and `equal_range` functions. + */ +class StdSetEqualRange extends TaintFunction { + StdSetEqualRange() { + this + .hasQualifiedName("std", ["set", "unordered_set"], + ["lower_bound", "upper_bound", "equal_range"]) + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from qualifier to return value + input.isQualifierObject() and + output.isReturnValue() + } +} diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll index 9c6ebd1a8779..b8a000b963ea 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll @@ -1,21 +1,62 @@ +/** + * Provides implementation classes modeling `std::string` (and other + * instantiations of `std::basic_string`) and `std::ostream`. See + * `semmle.code.cpp.models.Models` for usage information. + */ + import semmle.code.cpp.models.interfaces.Taint +import semmle.code.cpp.models.implementations.Iterator + +/** + * The `std::basic_string` template class. + */ +class StdBasicString extends TemplateClass { + StdBasicString() { this.hasQualifiedName("std", "basic_string") } +} /** - * The `std::basic_string` constructor(s). + * Additional model for `std::string` constructors that reference the character + * type of the container, or an iterator. For example construction from + * iterators: + * ``` + * std::string b(a.begin(), a.end()); + * ``` */ -class StdStringConstructor extends TaintFunction { - pragma[noinline] - StdStringConstructor() { this.hasQualifiedName("std", "basic_string", "basic_string") } +class StdStringConstructor extends Constructor, TaintFunction { + StdStringConstructor() { this.getDeclaringType().hasQualifiedName("std", "basic_string") } + + /** + * Gets the index of a parameter to this function that is a string (or + * character). + */ + int getAStringParameterIndex() { + getParameter(result).getType() instanceof PointerType or // e.g. `std::basic_string::CharT *` + getParameter(result).getType() instanceof ReferenceType or // e.g. `std::basic_string &` + getParameter(result).getUnspecifiedType() = + getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. `std::basic_string::CharT` + } + + /** + * Gets the index of a parameter to this function that is an iterator. + */ + int getAnIteratorParameterIndex() { getParameter(result).getType() instanceof Iterator } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - // flow from any constructor argument to return value - input.isParameter(_) and - output.isReturnValue() + // taint flow from any parameter of the value type to the returned object + ( + input.isParameterDeref(getAStringParameterIndex()) or + input.isParameter(getAnIteratorParameterIndex()) + ) and + ( + output.isReturnValue() // TODO: this is only needed for AST data flow, which treats constructors as returning the new object + or + output.isQualifierObject() + ) } } /** - * The standard function `std::string.c_str`. + * The `std::string` function `c_str`. */ class StdStringCStr extends TaintFunction { StdStringCStr() { this.hasQualifiedName("std", "basic_string", "c_str") } @@ -23,6 +64,547 @@ class StdStringCStr extends TaintFunction { override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from string itself (qualifier) to return value input.isQualifierObject() and + output.isReturnValueDeref() + } +} + +/** + * The `std::string` function `data`. + */ +class StdStringData extends TaintFunction { + StdStringData() { this.hasQualifiedName("std", "basic_string", "data") } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from string itself (qualifier) to return value + input.isQualifierObject() and + output.isReturnValueDeref() + or + // reverse flow from returned reference to the qualifier (for writes to + // `data`) + input.isReturnValueDeref() and + output.isQualifierObject() + } +} + +/** + * The `std::string` function `push_back`. + */ +class StdStringPush extends TaintFunction { + StdStringPush() { this.hasQualifiedName("std", "basic_string", "push_back") } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from parameter to qualifier + input.isParameterDeref(0) and + output.isQualifierObject() + } +} + +/** + * The `std::string` functions `front` and `back`. + */ +class StdStringFrontBack extends TaintFunction { + StdStringFrontBack() { this.hasQualifiedName("std", "basic_string", ["front", "back"]) } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from object to returned reference + input.isQualifierObject() and + output.isReturnValueDeref() + } +} + +/** + * The `std::string` function `operator+`. + */ +class StdStringPlus extends TaintFunction { + StdStringPlus() { + this.hasQualifiedName("std", "operator+") and + this.getUnspecifiedType() = any(StdBasicString s).getAnInstantiation() + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from parameters to return value + ( + input.isParameterDeref(0) or + input.isParameterDeref(1) + ) and + output.isReturnValue() + } +} + +/** + * The `std::string` functions `operator+=`, `append`, `insert` and + * `replace`. All of these functions combine the existing string + * with a new string (or character) from one of the arguments. + */ +class StdStringAppend extends TaintFunction { + StdStringAppend() { + this.hasQualifiedName("std", "basic_string", ["operator+=", "append", "insert", "replace"]) + } + + /** + * Gets the index of a parameter to this function that is a string (or + * character). + */ + int getAStringParameterIndex() { + getParameter(result).getType() instanceof PointerType or // e.g. `std::basic_string::CharT *` + getParameter(result).getType() instanceof ReferenceType or // e.g. `std::basic_string &` + getParameter(result).getUnspecifiedType() = + getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. `std::basic_string::CharT` + } + + /** + * Gets the index of a parameter to this function that is an iterator. + */ + int getAnIteratorParameterIndex() { getParameter(result).getType() instanceof Iterator } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from string and parameter to string (qualifier) and return value + ( + input.isQualifierObject() or + input.isParameterDeref(getAStringParameterIndex()) or + input.isParameter(getAnIteratorParameterIndex()) + ) and + ( + output.isQualifierObject() or + output.isReturnValueDeref() + ) + or + // reverse flow from returned reference to the qualifier (for writes to + // the result) + input.isReturnValueDeref() and + output.isQualifierObject() + } +} + +/** + * The standard function `std::string.assign`. + */ +class StdStringAssign extends TaintFunction { + StdStringAssign() { this.hasQualifiedName("std", "basic_string", "assign") } + + /** + * Gets the index of a parameter to this function that is a string (or + * character). + */ + int getAStringParameterIndex() { + getParameter(result).getType() instanceof PointerType or // e.g. `std::basic_string::CharT *` + getParameter(result).getType() instanceof ReferenceType or // e.g. `std::basic_string &` + getParameter(result).getUnspecifiedType() = + getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. `std::basic_string::CharT` + } + + /** + * Gets the index of a parameter to this function that is an iterator. + */ + int getAnIteratorParameterIndex() { getParameter(result).getType() instanceof Iterator } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from parameter to string itself (qualifier) and return value + ( + input.isParameterDeref(getAStringParameterIndex()) or + input.isParameter(getAnIteratorParameterIndex()) + ) and + ( + output.isQualifierObject() or + output.isReturnValueDeref() + ) + or + // reverse flow from returned reference to the qualifier (for writes to + // the result) + input.isReturnValueDeref() and + output.isQualifierObject() + } +} + +/** + * The standard function `std::string.copy`. + */ +class StdStringCopy extends TaintFunction { + StdStringCopy() { this.hasQualifiedName("std", "basic_string", "copy") } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // copy(dest, num, pos) + input.isQualifierObject() and + output.isParameterDeref(0) + } +} + +/** + * The standard function `std::string.substr`. + */ +class StdStringSubstr extends TaintFunction { + StdStringSubstr() { this.hasQualifiedName("std", "basic_string", "substr") } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // substr(pos, num) + input.isQualifierObject() and + output.isReturnValue() + } +} + +/** + * The standard functions `std::string.swap` and `std::stringstream::swap`. + */ +class StdStringSwap extends TaintFunction { + StdStringSwap() { + this.hasQualifiedName("std", "basic_string", "swap") or + this.hasQualifiedName("std", "basic_stringstream", "swap") + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // str1.swap(str2) + input.isQualifierObject() and + output.isParameterDeref(0) + or + input.isParameterDeref(0) and + output.isQualifierObject() + } +} + +/** + * The `std::string` functions `at` and `operator[]`. + */ +class StdStringAt extends TaintFunction { + StdStringAt() { this.hasQualifiedName("std", "basic_string", ["at", "operator[]"]) } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from qualifier to referenced return value + input.isQualifierObject() and + output.isReturnValueDeref() + or + // reverse flow from returned reference to the qualifier + input.isReturnValueDeref() and + output.isQualifierObject() + } +} + +/** + * The `std::basic_istream` template class. + */ +class StdBasicIStream extends TemplateClass { + StdBasicIStream() { this.hasQualifiedName("std", "basic_istream") } +} + +/** + * The `std::istream` function `operator>>` (defined as a member function). + */ +class StdIStreamIn extends DataFlowFunction, TaintFunction { + StdIStreamIn() { this.hasQualifiedName("std", "basic_istream", "operator>>") } + + override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { + // returns reference to `*this` + input.isQualifierAddress() and + output.isReturnValue() + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from qualifier to first parameter + input.isQualifierObject() and + output.isParameterDeref(0) + or + // reverse flow from returned reference to the qualifier + input.isReturnValueDeref() and + output.isQualifierObject() + } +} + +/** + * The `std::istream` function `operator>>` (defined as a non-member function). + */ +class StdIStreamInNonMember extends DataFlowFunction, TaintFunction { + StdIStreamInNonMember() { + this.hasQualifiedName("std", "operator>>") and + this.getUnspecifiedType().(ReferenceType).getBaseType() = + any(StdBasicIStream s).getAnInstantiation() + } + + override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { + // flow from first parameter to return value + input.isParameter(0) and + output.isReturnValue() + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from first parameter to second parameter + input.isParameterDeref(0) and + output.isParameterDeref(1) + or + // reverse flow from returned reference to the first parameter + input.isReturnValueDeref() and + output.isParameterDeref(0) + } +} + +/** + * The `std::istream` functions `get` (without parameters) and `peek`. + */ +class StdIStreamGet extends TaintFunction { + StdIStreamGet() { + this.hasQualifiedName("std", "basic_istream", ["get", "peek"]) and + this.getNumberOfParameters() = 0 + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from qualifier to return value + input.isQualifierObject() and + output.isReturnValue() + } +} + +/** + * The `std::istream` functions `get` (with parameters) and `read`. + */ +class StdIStreamRead extends DataFlowFunction, TaintFunction { + StdIStreamRead() { + this.hasQualifiedName("std", "basic_istream", ["get", "read"]) and + this.getNumberOfParameters() > 0 + } + + override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { + // returns reference to `*this` + input.isQualifierAddress() and + output.isReturnValue() + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from qualifier to first parameter + input.isQualifierObject() and + output.isParameterDeref(0) + or + // reverse flow from returned reference to the qualifier + input.isReturnValueDeref() and + output.isQualifierObject() + } +} + +/** + * The `std::istream` function `readsome`. + */ +class StdIStreamReadSome extends TaintFunction { + StdIStreamReadSome() { this.hasQualifiedName("std", "basic_istream", "readsome") } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from qualifier to first parameter + input.isQualifierObject() and + output.isParameterDeref(0) + } +} + +/** + * The `std::istream` function `putback`. + */ +class StdIStreamPutBack extends DataFlowFunction, TaintFunction { + StdIStreamPutBack() { this.hasQualifiedName("std", "basic_istream", "putback") } + + override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { + // returns reference to `*this` + input.isQualifierAddress() and + output.isReturnValue() + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from first parameter (value or pointer) to qualifier + input.isParameter(0) and + output.isQualifierObject() + or + input.isParameterDeref(0) and + output.isQualifierObject() + or + // flow from first parameter (value or pointer) to return value + input.isParameter(0) and + output.isReturnValueDeref() + or + input.isParameterDeref(0) and + output.isReturnValueDeref() + or + // reverse flow from returned reference to the qualifier + input.isReturnValueDeref() and + output.isQualifierObject() + } +} + +/** + * The `std::istream` function `getline`. + */ +class StdIStreamGetLine extends DataFlowFunction, TaintFunction { + StdIStreamGetLine() { this.hasQualifiedName("std", "basic_istream", "getline") } + + override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { + // returns reference to `*this` + input.isQualifierAddress() and + output.isReturnValue() + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from qualifier to first parameter + input.isQualifierObject() and + output.isParameterDeref(0) + or + // reverse flow from returned reference to the qualifier + input.isReturnValueDeref() and + output.isQualifierObject() + } +} + +/** + * The (non-member) function `std::getline`. + */ +class StdGetLine extends DataFlowFunction, TaintFunction { + StdGetLine() { this.hasQualifiedName("std", "getline") } + + override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { + // flow from first parameter to return value + input.isParameter(0) and + output.isReturnValue() + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from first parameter to second parameter + input.isParameterDeref(0) and + output.isParameterDeref(1) + or + // reverse flow from returned reference to first parameter + input.isReturnValueDeref() and + output.isParameterDeref(0) + } +} + +/** + * The `std::basic_ostream` template class. + */ +class StdBasicOStream extends TemplateClass { + StdBasicOStream() { this.hasQualifiedName("std", "basic_ostream") } +} + +/** + * The `std::ostream` functions `operator<<` (defined as a member function), + * `put` and `write`. + */ +class StdOStreamOut extends DataFlowFunction, TaintFunction { + StdOStreamOut() { this.hasQualifiedName("std", "basic_ostream", ["operator<<", "put", "write"]) } + + override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { + // returns reference to `*this` + input.isQualifierAddress() and + output.isReturnValue() + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from first parameter (value or pointer) to qualifier + input.isParameter(0) and + output.isQualifierObject() + or + input.isParameterDeref(0) and + output.isQualifierObject() + or + // flow from first parameter (value or pointer) to return value + input.isParameter(0) and + output.isReturnValueDeref() + or + input.isParameterDeref(0) and + output.isReturnValueDeref() + or + // reverse flow from returned reference to the qualifier + input.isReturnValueDeref() and + output.isQualifierObject() + } +} + +/** + * The `std::ostream` function `operator<<` (defined as a non-member function). + */ +class StdOStreamOutNonMember extends DataFlowFunction, TaintFunction { + StdOStreamOutNonMember() { + this.hasQualifiedName("std", "operator<<") and + this.getUnspecifiedType().(ReferenceType).getBaseType() = + any(StdBasicOStream s).getAnInstantiation() + } + + override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { + // flow from first parameter to return value + input.isParameter(0) and + output.isReturnValue() + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from second parameter to first parameter + input.isParameter(1) and + output.isParameterDeref(0) + or + // flow from second parameter to return value + input.isParameter(1) and + output.isReturnValueDeref() + or + // reverse flow from returned reference to the first parameter + input.isReturnValueDeref() and + output.isParameterDeref(0) + } +} + +/** + * Additional model for `std::stringstream` constructors that take a string + * input parameter. + */ +class StdStringStreamConstructor extends Constructor, TaintFunction { + StdStringStreamConstructor() { + this.getDeclaringType().hasQualifiedName("std", "basic_stringstream") + } + + /** + * Gets the index of a parameter to this function that is a string. + */ + int getAStringParameterIndex() { + getParameter(result).getType() instanceof ReferenceType // `const std::basic_string &` + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // taint flow from any parameter of string type to the returned object + input.isParameterDeref(getAStringParameterIndex()) and + ( + output.isReturnValue() // TODO: this is only needed for AST data flow, which treats constructors as returning the new object + or + output.isQualifierObject() + ) + } +} + +/** + * The `std::stringstream` function `str`. + */ +class StdStringStreamStr extends TaintFunction { + StdStringStreamStr() { this.hasQualifiedName("std", "basic_stringstream", "str") } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from qualifier to return value (if any) + input.isQualifierObject() and output.isReturnValue() + or + // flow from first parameter (if any) to qualifier + input.isParameterDeref(0) and + output.isQualifierObject() + } +} + +/** + * A `std::` stream function that does not require a model, except that it + * returns a reference to `*this` and thus could be used in a chain. + */ +class StdStreamFunction extends DataFlowFunction, TaintFunction { + StdStreamFunction() { + this.hasQualifiedName("std", "basic_istream", ["ignore", "unget", "seekg"]) or + this.hasQualifiedName("std", "basic_ostream", ["seekp", "flush"]) or + this.hasQualifiedName("std", "basic_ios", "copyfmt") + } + + override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { + // returns reference to `*this` + input.isQualifierAddress() and + output.isReturnValue() + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // reverse flow from returned reference to the qualifier + input.isReturnValueDeref() and + output.isQualifierObject() } } diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll index d44b28f041da..9acd5b32d4f0 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll @@ -1,3 +1,8 @@ +/** + * Provides implementation classes modeling `strcat` and various similar functions. + * See `semmle.code.cpp.models.Models` for usage information. + */ + import semmle.code.cpp.models.interfaces.ArrayFunction import semmle.code.cpp.models.interfaces.DataFlow import semmle.code.cpp.models.interfaces.Taint @@ -19,6 +24,21 @@ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, Sid ) } + /** + * Gets the index of the parameter that is the size of the copy (in characters). + */ + int getParamSize() { exists(getParameter(2)) and result = 2 } + + /** + * Gets the index of the parameter that is the source of the copy. + */ + int getParamSrc() { result = 1 } + + /** + * Gets the index of the parameter that is the destination to be appended to. + */ + int getParamDest() { result = 0 } + override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { input.isParameter(0) and output.isReturnValue() diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll index c7f0898f3582..d0b3f92fa0fd 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll @@ -1,3 +1,8 @@ +/** + * Provides implementation classes modeling `strcpy` and various similar + * functions. See `semmle.code.cpp.models.Models` for usage information. + */ + import semmle.code.cpp.models.interfaces.ArrayFunction import semmle.code.cpp.models.interfaces.DataFlow import semmle.code.cpp.models.interfaces.Taint @@ -8,70 +13,91 @@ import semmle.code.cpp.models.interfaces.SideEffect */ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, SideEffectFunction { StrcpyFunction() { - this.hasName("strcpy") or - this.hasName("_mbscpy") or - this.hasName("wcscpy") or - this.hasName("strncpy") or - this.hasName("_strncpy_l") or - this.hasName("_mbsncpy") or - this.hasName("_mbsncpy_l") or - this.hasName("wcsncpy") or - this.hasName("_wcsncpy_l") + getName() = + ["strcpy", // strcpy(dst, src) + "wcscpy", // wcscpy(dst, src) + "_mbscpy", // _mbscpy(dst, src) + "strncpy", // strncpy(dst, src, max_amount) + "_strncpy_l", // _strncpy_l(dst, src, max_amount, locale) + "wcsncpy", // wcsncpy(dst, src, max_amount) + "_wcsncpy_l", // _wcsncpy_l(dst, src, max_amount, locale) + "_mbsncpy", // _mbsncpy(dst, src, max_amount) + "_mbsncpy_l"] // _mbsncpy_l(dst, src, max_amount, locale) + or + getName() = + ["strcpy_s", // strcpy_s(dst, max_amount, src) + "wcscpy_s", // wcscpy_s(dst, max_amount, src) + "_mbscpy_s"] and // _mbscpy_s(dst, max_amount, src) + // exclude the 2-parameter template versions + // that find the size of a fixed size destination buffer. + getNumberOfParameters() = 3 } - override predicate hasArrayInput(int bufParam) { bufParam = 1 } + /** + * Holds if this is one of the `strcpy_s` variants. + */ + private predicate isSVariant() { + exists(string name | name = getName() | name.suffix(name.length() - 2) = "_s") + } + + /** + * Gets the index of the parameter that is the maximum size of the copy (in characters). + */ + int getParamSize() { + if isSVariant() + then result = 1 + else + if exists(getName().indexOf("ncpy")) + then result = 2 + else none() + } - override predicate hasArrayOutput(int bufParam) { bufParam = 0 } + /** + * Gets the index of the parameter that is the source of the copy. + */ + int getParamSrc() { if isSVariant() then result = 2 else result = 1 } - override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = 1 } + /** + * Gets the index of the parameter that is the destination of the copy. + */ + int getParamDest() { result = 0 } + + override predicate hasArrayInput(int bufParam) { bufParam = getParamSrc() } + + override predicate hasArrayOutput(int bufParam) { bufParam = getParamDest() } + + override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = getParamSrc() } override predicate hasArrayWithVariableSize(int bufParam, int countParam) { - ( - this.hasName("strncpy") or - this.hasName("_strncpy_l") or - this.hasName("_mbsncpy") or - this.hasName("_mbsncpy_l") or - this.hasName("wcsncpy") or - this.hasName("_wcsncpy_l") - ) and - bufParam = 0 and - countParam = 2 + bufParam = getParamDest() and + countParam = getParamSize() } override predicate hasArrayWithUnknownSize(int bufParam) { - ( - this.hasName("strcpy") or - this.hasName("_mbscpy") or - this.hasName("wcscpy") - ) and - bufParam = 0 + not exists(getParamSize()) and + bufParam = getParamDest() } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { - input.isParameterDeref(1) and - output.isParameterDeref(0) + not exists(getParamSize()) and + input.isParameterDeref(getParamSrc()) and + output.isParameterDeref(getParamDest()) or - input.isParameterDeref(1) and + not exists(getParamSize()) and + input.isParameterDeref(getParamSrc()) and output.isReturnValueDeref() or - input.isParameter(0) and + input.isParameter(getParamDest()) and output.isReturnValue() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // these may do only a partial copy of the input buffer to the output + // buffer + exists(getParamSize()) and + input.isParameter(getParamSrc()) and ( - // these may do only a partial copy of the input buffer to the output - // buffer - this.hasName("strncpy") or - this.hasName("_strncpy_l") or - this.hasName("_mbsncpy") or - this.hasName("_mbsncpy_l") or - this.hasName("wcsncpy") or - this.hasName("_wcsncpy_l") - ) and - input.isParameter(2) and - ( - output.isParameterDeref(0) or + output.isParameterDeref(getParamDest()) or output.isReturnValueDeref() ) } @@ -81,17 +107,18 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid override predicate hasOnlySpecificWriteSideEffects() { any() } override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) { - i = 0 and + i = getParamDest() and buffer = true and mustWrite = false } override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { - i = 1 and + i = getParamSrc() and buffer = true } override ParameterIndex getParameterSizeIndex(ParameterIndex i) { - hasArrayWithVariableSize(i, result) + i = getParamDest() and + result = getParamSize() } } diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strdup.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strdup.qll index f7d122db259b..3497ab9a0650 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strdup.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strdup.qll @@ -1,3 +1,8 @@ +/** + * Provides implementation classes modeling `strdup` and various similar + * functions. See `semmle.code.cpp.models.Models` for usage information. + */ + import semmle.code.cpp.models.interfaces.Allocation import semmle.code.cpp.models.interfaces.ArrayFunction import semmle.code.cpp.models.interfaces.DataFlow diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/Allocation.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/Allocation.qll index 81a40cd349af..1ebf40b1f014 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/Allocation.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/Allocation.qll @@ -1,5 +1,5 @@ /** - * Provides an abstract class for modelling functions and expressions that + * Provides an abstract class for modeling functions and expressions that * allocate memory, such as the standard `malloc` function. To use this QL * library, create one or more QL classes extending a class here with a * characteristic predicate that selects the functions or expressions you are diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/DataFlow.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/DataFlow.qll index 872cfcd29975..c1b65d627069 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/DataFlow.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/DataFlow.qll @@ -19,5 +19,10 @@ import semmle.code.cpp.models.Models * to destinations; that is covered by `TaintModel.qll`. */ abstract class DataFlowFunction extends Function { + /** + * Holds if data can be copied from the argument, qualifier, or buffer + * represented by `input` to the return value or buffer represented by + * `output` + */ abstract predicate hasDataFlow(FunctionInput input, FunctionOutput output); } diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/Deallocation.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/Deallocation.qll index 9223592ef678..23eca5164188 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/Deallocation.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/Deallocation.qll @@ -1,5 +1,5 @@ /** - * Provides an abstract class for modelling functions and expressions that + * Provides an abstract class for modeling functions and expressions that * deallocate memory, such as the standard `free` function. To use this QL * library, create one or more QL classes extending a class here with a * characteristic predicate that selects the functions or expressions you are diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll index 7227e6e95133..f97646ca8330 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll @@ -1,6 +1,6 @@ /** * Provides a class for modeling `printf`-style formatting functions. To use - * this QL library, create a QL class extending `DataFlowFunction` with a + * this QL library, create a QL class extending `FormattingFunction` with a * characteristic predicate that selects the function or set of functions you * are modeling. Within that class, override the predicates provided by * `FormattingFunction` to match the flow within that function. @@ -44,7 +44,7 @@ abstract class FormattingFunction extends ArrayFunction, TaintFunction { /** Gets the position at which the format parameter occurs. */ abstract int getFormatParameterIndex(); - override string getCanonicalQLClass() { result = "FormattingFunction" } + override string getAPrimaryQlClass() { result = "FormattingFunction" } /** * Holds if this `FormattingFunction` is in a context that supports diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll index d0fbb50ebfa8..9804cd6aff75 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll @@ -10,7 +10,8 @@ private newtype TFunctionInput = TInParameter(ParameterIndex i) or TInParameterDeref(ParameterIndex i) or TInQualifierObject() or - TInQualifierAddress() + TInQualifierAddress() or + TInReturnValueDeref() /** * An input to a function. This can be: @@ -106,8 +107,47 @@ class FunctionInput extends TFunctionInput { * (with type `C const *`) on entry to the function. */ predicate isQualifierAddress() { none() } + + /** + * Holds if this is the input value pointed to by the return value of a + * function, if the function returns a pointer, or the input value referred + * to by the return value of a function, if the function returns a reference. + * + * Example: + * ``` + * char* getPointer(); + * float& getReference(); + * int getInt(); + * ``` + * - `isReturnValueDeref()` holds for the `FunctionInput` that represents the + * value of `*getPointer()` (with type `char`). + * - `isReturnValueDeref()` holds for the `FunctionInput` that represents the + * value of `getReference()` (with type `float`). + * - There is no `FunctionInput` of `getInt()` for which + * `isReturnValueDeref()` holds because the return type of `getInt()` is + * neither a pointer nor a reference. + * + * Note that data flows in through function return values are relatively + * rare, but they do occur when a function returns a reference to itself, + * part of itself, or one of its other inputs. + */ + predicate isReturnValueDeref() { none() } } +/** + * The input value of a parameter. + * + * Example: + * ``` + * void func(int n, char* p, float& r); + * ``` + * - There is an `InParameter` representing the value of `n` (with type `int`) on entry to the + * function. + * - There is an `InParameter` representing the value of `p` (with type `char*`) on entry to the + * function. + * - There is an `InParameter` representing the "value" of the reference `r` (with type `float&`) on + * entry to the function, _not_ the value of the referred-to `float`. + */ class InParameter extends FunctionInput, TInParameter { ParameterIndex index; @@ -121,6 +161,21 @@ class InParameter extends FunctionInput, TInParameter { override predicate isParameter(ParameterIndex i) { i = index } } +/** + * The input value pointed to by a pointer parameter to a function, or the input value referred to + * by a reference parameter to a function. + * + * Example: + * ``` + * void func(int n, char* p, float& r); + * ``` + * - There is an `InParameterDeref` with `getIndex() = 1` that represents the value of `*p` (with + * type `char`) on entry to the function. + * - There is an `InParameterDeref` with `getIndex() = 2` that represents the value of `r` (with + * type `float`) on entry to the function. + * - There is no `InParameterDeref` representing the value of `n`, because `n` is neither a pointer + * nor a reference. + */ class InParameterDeref extends FunctionInput, TInParameterDeref { ParameterIndex index; @@ -134,18 +189,70 @@ class InParameterDeref extends FunctionInput, TInParameterDeref { override predicate isParameterDeref(ParameterIndex i) { i = index } } +/** + * The input value pointed to by the `this` pointer of an instance member function. + * + * Example: + * ``` + * struct C { + * void mfunc(int n, char* p, float& r) const; + * }; + * ``` + * - `InQualifierObject` represents the value of `*this` (with type `C const`) on entry to the + * function. + */ class InQualifierObject extends FunctionInput, TInQualifierObject { override string toString() { result = "InQualifierObject" } override predicate isQualifierObject() { any() } } +/** + * The input value of the `this` pointer of an instance member function. + * + * Example: + * ``` + * struct C { + * void mfunc(int n, char* p, float& r) const; + * }; + * ``` + * - `InQualifierAddress` represents the value of `this` (with type `C const *`) on entry to the + * function. + */ class InQualifierAddress extends FunctionInput, TInQualifierAddress { override string toString() { result = "InQualifierAddress" } override predicate isQualifierAddress() { any() } } +/** + * The input value pointed to by the return value of a function, if the + * function returns a pointer, or the input value referred to by the return + * value of a function, if the function returns a reference. + * + * Example: + * ``` + * char* getPointer(); + * float& getReference(); + * int getInt(); + * ``` + * - `InReturnValueDeref` represents the value of `*getPointer()` (with type + * `char`). + * - `InReturnValueDeref` represents the value of `getReference()` (with type + * `float`). + * - `InReturnValueDeref` does not represent the return value of `getInt()` + * because the return type of `getInt()` is neither a pointer nor a reference. + * + * Note that data flows in through function return values are relatively + * rare, but they do occur when a function returns a reference to itself, + * part of itself, or one of its other inputs. + */ +class InReturnValueDeref extends FunctionInput, TInReturnValueDeref { + override string toString() { result = "InReturnValueDeref" } + + override predicate isReturnValueDeref() { any() } +} + private newtype TFunctionOutput = TOutParameterDeref(ParameterIndex i) or TOutQualifierObject() or @@ -265,6 +372,21 @@ class FunctionOutput extends TFunctionOutput { deprecated final predicate isOutReturnPointer() { isReturnValueDeref() } } +/** + * The output value pointed to by a pointer parameter to a function, or the output value referred to + * by a reference parameter to a function. + * + * Example: + * ``` + * void func(int n, char* p, float& r); + * ``` + * - There is an `OutParameterDeref` with `getIndex()=1` that represents the value of `*p` (with + * type `char`) on return from the function. + * - There is an `OutParameterDeref` with `getIndex()=2` that represents the value of `r` (with + * type `float`) on return from the function. + * - There is no `OutParameterDeref` representing the value of `n`, because `n` is neither a + * pointer nor a reference. + */ class OutParameterDeref extends FunctionOutput, TOutParameterDeref { ParameterIndex index; @@ -277,18 +399,62 @@ class OutParameterDeref extends FunctionOutput, TOutParameterDeref { override predicate isParameterDeref(ParameterIndex i) { i = index } } +/** + * The output value pointed to by the `this` pointer of an instance member function. + * + * Example: + * ``` + * struct C { + * void mfunc(int n, char* p, float& r); + * }; + * ``` + * - The `OutQualifierObject` represents the value of `*this` (with type `C`) on return from the + * function. + */ class OutQualifierObject extends FunctionOutput, TOutQualifierObject { override string toString() { result = "OutQualifierObject" } override predicate isQualifierObject() { any() } } +/** + * The value returned by a function. + * + * Example: + * ``` + * int getInt(); + * char* getPointer(); + * float& getReference(); + * ``` + * - `OutReturnValue` represents the value returned by + * `getInt()` (with type `int`). + * - `OutReturnValue` represents the value returned by + * `getPointer()` (with type `char*`). + * - `OutReturnValue` represents the "value" of the reference returned by `getReference()` (with + * type `float&`), _not_ the value of the referred-to `float`. + */ class OutReturnValue extends FunctionOutput, TOutReturnValue { override string toString() { result = "OutReturnValue" } override predicate isReturnValue() { any() } } +/** + * The output value pointed to by the return value of a function, if the function returns a pointer, + * or the output value referred to by the return value of a function, if the function returns a + * reference. + * + * Example: + * ``` + * char* getPointer(); + * float& getReference(); + * int getInt(); + * ``` + * - `OutReturnValueDeref` represents the value of `*getPointer()` (with type `char`). + * - `OutReturnValueDeref` represents the value of `getReference()` (with type `float`). + * - `OutReturnValueDeref` does not represent the return value of `getInt()` because the return type + * of `getInt()` is neither a pointer nor a reference. + */ class OutReturnValueDeref extends FunctionOutput, TOutReturnValueDeref { override string toString() { result = "OutReturnValueDeref" } diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/Iterator.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/Iterator.qll new file mode 100644 index 000000000000..de6977765253 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/Iterator.qll @@ -0,0 +1,17 @@ +/** + * Provides an abstract class for accurate modeling of flow through output + * iterators. To use this QL library, create a QL class extending + * `IteratorReferenceFunction` with a characteristic predicate that selects the + * function or set of functions you are modeling. Within that class, override + * the predicates provided by `AliasFunction` to match the flow within that + * function. + */ + +import cpp +import semmle.code.cpp.models.Models + +/** + * A function which takes an iterator argument and returns a reference that + * can be used to write to the iterator's underlying collection. + */ +abstract class IteratorReferenceFunction extends Function { } diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll index c619f2efaa5c..fe617533f59d 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll @@ -24,5 +24,9 @@ import semmle.code.cpp.models.Models * data flow. */ abstract class TaintFunction extends Function { + /** + * Holds if data passed into the argument, qualifier, or buffer represented by + * `input` influences the return value or buffer represented by `output` + */ abstract predicate hasTaintFlow(FunctionInput input, FunctionOutput output); } diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/NanAnalysis.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/NanAnalysis.qll index ea12434ac5bd..e402b672cbc2 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/NanAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/NanAnalysis.qll @@ -1,3 +1,7 @@ +/** + * Provides classes and predicates for recognizing floating point expressions which cannot be NaN. + */ + import cpp private import semmle.code.cpp.rangeanalysis.RangeSSA diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/PointlessComparison.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/PointlessComparison.qll index 3c9177ad9db5..47289c7552b9 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/PointlessComparison.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/PointlessComparison.qll @@ -11,8 +11,17 @@ private float lowerBoundFC(Expr expr) { result = lowerBound(expr.getFullyConvert /** Gets the upper bound of the fully converted expression. */ private float upperBoundFC(Expr expr) { result = upperBound(expr.getFullyConverted()) } +/** + * Describes which side of a pointless comparison is known to be smaller. + */ newtype SmallSide = + /** + * Represents that the left side of a pointless comparison is known to be smaller. + */ LeftIsSmaller() or + /** + * Represents that the right side of a pointless comparison is known to be smaller. + */ RightIsSmaller() /** diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysisUtils.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysisUtils.qll index 9e99fcb82041..410a39716dc3 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysisUtils.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysisUtils.qll @@ -5,7 +5,13 @@ import cpp * relation) or 'non-strict' (a `<=` or `>=` relation). */ newtype RelationStrictness = + /** + * Represents that a relation is 'strict' (that is, a `<` or `>` relation). + */ Strict() or + /** + * Represents that a relation is 'non-strict' (that is, a `<=` or `>=` relation) + */ Nonstrict() /** @@ -13,7 +19,13 @@ newtype RelationStrictness = * relation) or 'lesser' (a `<` or `<=` relation). */ newtype RelationDirection = + /** + * Represents that a relation is 'greater' (that is, a `>` or `>=` relation). + */ Greater() or + /** + * Represents that a relation is 'lesser' (that is, a `<` or `<=` relation). + */ Lesser() private RelationStrictness negateStrictness(RelationStrictness strict) { @@ -28,12 +40,18 @@ private RelationDirection negateDirection(RelationDirection dir) { dir = Lesser() and result = Greater() } +/** + * Holds if `dir` is `Greater` (that is, a `>` or `>=` relation) + */ boolean directionIsGreater(RelationDirection dir) { dir = Greater() and result = true or dir = Lesser() and result = false } +/** + * Holds if `dir` is `Lesser` (that is, a `<` or `<=` relation) + */ boolean directionIsLesser(RelationDirection dir) { dir = Greater() and result = false or @@ -153,6 +171,65 @@ predicate eqOpWithSwapAndNegate(EqualityOperation cmp, Expr a, Expr b, boolean i eqOpWithSwap(cmp, a, b, branch.booleanNot()) and isEQ = false } +/** + * Holds if `cmp` is an unconverted conversion of `a` to a Boolean that + * evalutes to `isEQ` iff `a` is 0. + * + * Note that `a` can be `cmp` itself or a conversion thereof. + */ +private predicate eqZero(Expr cmp, Expr a, boolean isEQ) { + // The `!a` expression tests `a` equal to zero when `a` is a number converted + // to a Boolean. + isEQ = true and + exists(Expr notOperand | notOperand = cmp.(NotExpr).getOperand().getFullyConverted() | + // In C++ code there will be a BoolConversion in `!myInt` + a = notOperand.(BoolConversion).getExpr() + or + // In C code there is no conversion since there was no bool type before C99 + a = notOperand and + not a instanceof BoolConversion // avoid overlap with the case above + ) + or + // The `(bool)a` expression tests `a` NOT equal to zero when `a` is a number + // converted to a Boolean. To avoid overlap with the case above, this case + // excludes conversions that are right below a `!`. + isEQ = false and + linearAccess(cmp, _, _, _) and + // This test for `isCondition` implies that `cmp` is unconverted and that the + // parent of `cfg` is not a `NotExpr` -- the CFG doesn't do branching from + // inside `NotExpr`. + cmp.isCondition() and + // The GNU two-operand conditional expression is not supported for the + // purpose of guards, but the value of the conditional expression itself is + // modeled in the range analysis. + not exists(ConditionalExpr cond | cmp = cond.getCondition() and cond.isTwoOperand()) and + ( + // In C++ code there will be a BoolConversion in `if (myInt)` + a = cmp.getFullyConverted().(BoolConversion).getExpr() + or + // In C code there is no conversion since there was no bool type before C99 + a = cmp.getFullyConverted() and + not a instanceof BoolConversion // avoid overlap with the case above + ) +} + +/** + * Holds if `branch` of `cmp` is taken when `a` compares `isEQ` to zero. + * + * Note that `a` can be `cmp` itself or a conversion thereof. + */ +predicate eqZeroWithNegate(Expr cmp, Expr a, boolean isEQ, boolean branch) { + // The comparison for _equality_ to zero is on the `true` branch when `cmp` + // compares equal to zero and on the `false` branch when `cmp` compares not + // equal to zero. + eqZero(cmp, a, branch) and isEQ = true + or + // The comparison for _inequality_ to zero is on the `false` branch when + // `cmp` compares equal to zero and on the `true` branch when `cmp` compares + // not equal to zero. + eqZero(cmp, a, branch.booleanNot()) and isEQ = false +} + /** * Holds if `expr` is equivalent to `p*v + q`, where `p` is a non-zero * number. This takes into account the associativity, commutativity and @@ -173,6 +250,8 @@ private predicate linearAccessImpl(Expr expr, VariableAccess v, float p, float q // Base case expr = v and p = 1.0 and q = 0.0 or + expr.(ReferenceDereferenceExpr).getExpr() = v and p = 1.0 and q = 0.0 + or // a+(p*v+b) == p*v + (a+b) exists(AddExpr addExpr, float a, float b | addExpr.getLeftOperand().isConstant() and @@ -331,13 +410,20 @@ private predicate typeBounds(ArithmeticType t, float lb, float ub) { t instanceof FloatingPointType and lb = -(1.0 / 0.0) and ub = 1.0 / 0.0 } +private Type stripReference(Type t) { + if t instanceof ReferenceType then result = t.(ReferenceType).getBaseType() else result = t +} + +/** Gets the type used by range analysis for the given `StackVariable`. */ +Type getVariableRangeType(StackVariable v) { result = stripReference(v.getUnspecifiedType()) } + /** * Gets the lower bound for the unspecified type `t`. * * For example, if `t` is a signed 32-bit type then the result is * `-2^31`. */ -float typeLowerBound(ArithmeticType t) { typeBounds(t, result, _) } +float typeLowerBound(Type t) { typeBounds(stripReference(t), result, _) } /** * Gets the upper bound for the unspecified type `t`. @@ -345,7 +431,7 @@ float typeLowerBound(ArithmeticType t) { typeBounds(t, result, _) } * For example, if `t` is a signed 32-bit type then the result is * `2^31 - 1`. */ -float typeUpperBound(ArithmeticType t) { typeBounds(t, _, result) } +float typeUpperBound(Type t) { typeBounds(stripReference(t), _, result) } /** * Gets the minimum value that this expression could represent, based on diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeSSA.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeSSA.qll index 99e6539658d7..93dcf989590b 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeSSA.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeSSA.qll @@ -25,6 +25,10 @@ import semmle.code.cpp.controlflow.Dominance import semmle.code.cpp.controlflow.SSAUtils private import RangeAnalysisUtils +/** + * The SSA logic comes in two versions: the standard SSA and range-analysis RangeSSA. + * This class provides the range-analysis SSA logic. + */ library class RangeSSA extends SSAHelper { RangeSSA() { this = 1 } @@ -36,21 +40,20 @@ library class RangeSSA extends SSAHelper { } } -private predicate guard_defn( - VariableAccess v, ComparisonOperation guard, BasicBlock b, boolean branch -) { +private predicate guard_defn(VariableAccess v, Expr guard, BasicBlock b, boolean branch) { guardCondition(guard, v, branch) and guardSuccessor(guard, branch, b) } -private predicate guardCondition(ComparisonOperation guard, VariableAccess v, boolean branch) { +private predicate guardCondition(Expr guard, VariableAccess v, boolean branch) { exists(Expr lhs | linearAccess(lhs, v, _, _) | relOpWithSwapAndNegate(guard, lhs, _, _, _, branch) or - eqOpWithSwapAndNegate(guard, lhs, _, _, branch) + eqOpWithSwapAndNegate(guard, lhs, _, _, branch) or + eqZeroWithNegate(guard, lhs, _, branch) ) } -private predicate guardSuccessor(ComparisonOperation guard, boolean branch, BasicBlock succ) { +private predicate guardSuccessor(Expr guard, boolean branch, BasicBlock succ) { branch = true and succ = guard.getATrueSuccessor() or branch = false and succ = guard.getAFalseSuccessor() @@ -84,6 +87,7 @@ class RangeSsaDefinition extends ControlFlowNodeBase { /** Gets the control flow node for this definition. */ ControlFlowNode getDefinition() { result = this } + /** Gets the basic block containing this definition. */ BasicBlock getBasicBlock() { result.contains(getDefinition()) } /** Whether this definition is a phi node for variable `v`. */ @@ -93,15 +97,17 @@ class RangeSsaDefinition extends ControlFlowNodeBase { * If this definition is a phi node corresponding to a guard, * then return the variable and the guard. */ - predicate isGuardPhi(VariableAccess v, ComparisonOperation guard, boolean branch) { + predicate isGuardPhi(VariableAccess v, Expr guard, boolean branch) { guard_defn(v, guard, this, branch) } + /** Gets the primary location of this definition. */ Location getLocation() { result = this.(ControlFlowNode).getLocation() } /** Whether this definition is from a parameter */ predicate definedByParameter(Parameter p) { this = p.getFunction().getEntryPoint() } + /** Gets a definition of `v` that is a phi input for this basic block. */ RangeSsaDefinition getAPhiInput(StackVariable v) { this.isPhiNode(v) and exists(BasicBlock pred | @@ -153,6 +159,9 @@ class RangeSsaDefinition extends ControlFlowNodeBase { ) } + /** + * Holds if this definition of the variable `v` reached the end of the basic block `b`. + */ predicate reachesEndOfBB(StackVariable v, BasicBlock b) { exists(RangeSSA x | x.ssaDefinitionReachesEndOfBB(v, this, b)) } diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll index 867d96b804c6..fcaec3d3e13b 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll @@ -44,6 +44,8 @@ import cpp private import RangeAnalysisUtils +private import experimental.semmle.code.cpp.models.interfaces.SimpleRangeAnalysisExpr +private import experimental.semmle.code.cpp.models.interfaces.SimpleRangeAnalysisDefinition import RangeSSA import SimpleRangeAnalysisCached private import NanAnalysis @@ -126,7 +128,7 @@ private class UnsignedBitwiseAndExpr extends BitwiseAndExpr { UnsignedBitwiseAndExpr() { ( getLeftOperand().getFullyConverted().getType().getUnderlyingType().(IntegralType).isUnsigned() or - getLeftOperand().getFullyConverted().getValue().toInt() >= 0 + getValue(getLeftOperand().getFullyConverted()).toInt() >= 0 ) and ( getRightOperand() @@ -135,7 +137,7 @@ private class UnsignedBitwiseAndExpr extends BitwiseAndExpr { .getUnderlyingType() .(IntegralType) .isUnsigned() or - getRightOperand().getFullyConverted().getValue().toInt() >= 0 + getValue(getRightOperand().getFullyConverted()).toInt() >= 0 ) } } @@ -156,6 +158,92 @@ float safeFloor(float v) { result = v } +/** A `MulExpr` where exactly one operand is constant. */ +private class MulByConstantExpr extends MulExpr { + float constant; + Expr operand; + + MulByConstantExpr() { + exists(Expr constantExpr | + this.hasOperands(constantExpr, operand) and + constant = getValue(constantExpr.getFullyConverted()).toFloat() and + not exists(getValue(operand.getFullyConverted()).toFloat()) + ) + } + + /** Gets the value of the constant operand. */ + float getConstant() { result = constant } + + /** Gets the non-constant operand. */ + Expr getOperand() { result = operand } +} + +private class UnsignedMulExpr extends MulExpr { + UnsignedMulExpr() { + this.getType().(IntegralType).isUnsigned() and + // Avoid overlap. It should be slightly cheaper to analyze + // `MulByConstantExpr`. + not this instanceof MulByConstantExpr + } +} + +/** + * Holds if `expr` is effectively a multiplication of `operand` with the + * positive constant `positive`. + */ +private predicate effectivelyMultipliesByPositive(Expr expr, Expr operand, float positive) { + operand = expr.(MulByConstantExpr).getOperand() and + positive = expr.(MulByConstantExpr).getConstant() and + positive >= 0.0 // includes positive zero + or + operand = expr.(UnaryPlusExpr).getOperand() and + positive = 1.0 + or + operand = expr.(CommaExpr).getRightOperand() and + positive = 1.0 + or + operand = expr.(StmtExpr).getResultExpr() and + positive = 1.0 +} + +/** + * Holds if `expr` is effectively a multiplication of `operand` with the + * negative constant `negative`. + */ +private predicate effectivelyMultipliesByNegative(Expr expr, Expr operand, float negative) { + operand = expr.(MulByConstantExpr).getOperand() and + negative = expr.(MulByConstantExpr).getConstant() and + negative < 0.0 // includes negative zero + or + operand = expr.(UnaryMinusExpr).getOperand() and + negative = -1.0 +} + +private class AssignMulByConstantExpr extends AssignMulExpr { + float constant; + + AssignMulByConstantExpr() { constant = getValue(this.getRValue().getFullyConverted()).toFloat() } + + float getConstant() { result = constant } +} + +private class AssignMulByPositiveConstantExpr extends AssignMulByConstantExpr { + AssignMulByPositiveConstantExpr() { constant >= 0.0 } +} + +private class AssignMulByNegativeConstantExpr extends AssignMulByConstantExpr { + AssignMulByNegativeConstantExpr() { constant < 0.0 } +} + +private class UnsignedAssignMulExpr extends AssignMulExpr { + UnsignedAssignMulExpr() { + this.getType().(IntegralType).isUnsigned() and + // Avoid overlap. It should be slightly cheaper to analyze + // `AssignMulByConstantExpr`. + not this instanceof AssignMulByConstantExpr + } +} + /** Set of expressions which we know how to analyze. */ private predicate analyzableExpr(Expr e) { // The type of the expression must be arithmetic. We reuse the logic in @@ -164,9 +252,9 @@ private predicate analyzableExpr(Expr e) { ( exists(getValue(e).toFloat()) or - e instanceof UnaryPlusExpr + effectivelyMultipliesByPositive(e, _, _) or - e instanceof UnaryMinusExpr + effectivelyMultipliesByNegative(e, _, _) or e instanceof MinExpr or @@ -178,19 +266,21 @@ private predicate analyzableExpr(Expr e) { or e instanceof SubExpr or + e instanceof UnsignedMulExpr + or e instanceof AssignExpr or e instanceof AssignAddExpr or e instanceof AssignSubExpr or - e instanceof CrementOperation + e instanceof UnsignedAssignMulExpr or - e instanceof RemExpr + e instanceof AssignMulByConstantExpr or - e instanceof CommaExpr + e instanceof CrementOperation or - e instanceof StmtExpr + e instanceof RemExpr or // A conversion is analyzable, provided that its child has an arithmetic // type. (Sometimes the child is a reference type, and so does not get @@ -206,7 +296,10 @@ private predicate analyzableExpr(Expr e) { e instanceof UnsignedBitwiseAndExpr or // `>>` by a constant - exists(e.(RShiftExpr).getRightOperand().getValue()) + exists(getValue(e.(RShiftExpr).getRightOperand())) + or + // A modeled expression for range analysis + e instanceof SimpleRangeAnalysisExpr ) } @@ -227,30 +320,27 @@ private predicate defDependsOnDef( // Definitions with a defining value. exists(Expr expr | assignmentDef(def, v, expr) | exprDependsOnDef(expr, srcDef, srcVar)) or - exists(AssignAddExpr assignAdd, RangeSsaDefinition nextDef | - def = assignAdd and - assignAdd.getLValue() = nextDef.getAUse(v) - | - defDependsOnDef(nextDef, v, srcDef, srcVar) or - exprDependsOnDef(assignAdd.getRValue(), srcDef, srcVar) - ) - or - exists(AssignSubExpr assignSub, RangeSsaDefinition nextDef | - def = assignSub and - assignSub.getLValue() = nextDef.getAUse(v) - | - defDependsOnDef(nextDef, v, srcDef, srcVar) or - exprDependsOnDef(assignSub.getRValue(), srcDef, srcVar) + // Assignment operations with a defining value + exists(AssignOperation assignOp | + analyzableExpr(assignOp) and + def = assignOp and + def.getAVariable() = v and + exprDependsOnDef(assignOp, srcDef, srcVar) ) or exists(CrementOperation crem | def = crem and - crem.getOperand() = v.getAnAccess() and + def.getAVariable() = v and exprDependsOnDef(crem.getOperand(), srcDef, srcVar) ) or // Phi nodes. phiDependsOnDef(def, v, srcDef, srcVar) + or + // Extensions + exists(Expr expr | def.(SimpleRangeAnalysisDefinition).dependsOnExpr(v, expr) | + exprDependsOnDef(expr, srcDef, srcVar) + ) } /** @@ -258,12 +348,14 @@ private predicate defDependsOnDef( * the structure of `getLowerBoundsImpl` and `getUpperBoundsImpl`. */ private predicate exprDependsOnDef(Expr e, RangeSsaDefinition srcDef, StackVariable srcVar) { - exists(UnaryMinusExpr negateExpr | e = negateExpr | - exprDependsOnDef(negateExpr.getOperand(), srcDef, srcVar) + exists(Expr operand | + effectivelyMultipliesByNegative(e, operand, _) and + exprDependsOnDef(operand, srcDef, srcVar) ) or - exists(UnaryPlusExpr plusExpr | e = plusExpr | - exprDependsOnDef(plusExpr.getOperand(), srcDef, srcVar) + exists(Expr operand | + effectivelyMultipliesByPositive(e, operand, _) and + exprDependsOnDef(operand, srcDef, srcVar) ) or exists(MinExpr minExpr | e = minExpr | exprDependsOnDef(minExpr.getAnOperand(), srcDef, srcVar)) @@ -278,6 +370,10 @@ private predicate exprDependsOnDef(Expr e, RangeSsaDefinition srcDef, StackVaria or exists(SubExpr subExpr | e = subExpr | exprDependsOnDef(subExpr.getAnOperand(), srcDef, srcVar)) or + exists(UnsignedMulExpr mulExpr | e = mulExpr | + exprDependsOnDef(mulExpr.getAnOperand(), srcDef, srcVar) + ) + or exists(AssignExpr addExpr | e = addExpr | exprDependsOnDef(addExpr.getRValue(), srcDef, srcVar)) or exists(AssignAddExpr addExpr | e = addExpr | @@ -288,20 +384,20 @@ private predicate exprDependsOnDef(Expr e, RangeSsaDefinition srcDef, StackVaria exprDependsOnDef(subExpr.getAnOperand(), srcDef, srcVar) ) or - exists(CrementOperation crementExpr | e = crementExpr | - exprDependsOnDef(crementExpr.getOperand(), srcDef, srcVar) + exists(UnsignedAssignMulExpr mulExpr | e = mulExpr | + exprDependsOnDef(mulExpr.getAnOperand(), srcDef, srcVar) ) or - exists(RemExpr remExpr | e = remExpr | exprDependsOnDef(remExpr.getAnOperand(), srcDef, srcVar)) - or - exists(CommaExpr commaExpr | e = commaExpr | - exprDependsOnDef(commaExpr.getRightOperand(), srcDef, srcVar) + exists(AssignMulByConstantExpr mulExpr | e = mulExpr | + exprDependsOnDef(mulExpr.getLValue(), srcDef, srcVar) ) or - exists(StmtExpr stmtExpr | e = stmtExpr | - exprDependsOnDef(stmtExpr.getResultExpr(), srcDef, srcVar) + exists(CrementOperation crementExpr | e = crementExpr | + exprDependsOnDef(crementExpr.getOperand(), srcDef, srcVar) ) or + exists(RemExpr remExpr | e = remExpr | exprDependsOnDef(remExpr.getAnOperand(), srcDef, srcVar)) + or exists(Conversion convExpr | e = convExpr | exprDependsOnDef(convExpr.getExpr(), srcDef, srcVar)) or // unsigned `&` @@ -313,11 +409,21 @@ private predicate exprDependsOnDef(Expr e, RangeSsaDefinition srcDef, StackVaria // `>>` by a constant exists(RShiftExpr rs | rs = e and - exists(rs.getRightOperand().getValue()) and + exists(getValue(rs.getRightOperand())) and exprDependsOnDef(rs.getLeftOperand(), srcDef, srcVar) ) or e = srcDef.getAUse(srcVar) + or + // A modeled expression for range analysis + exists(SimpleRangeAnalysisExpr rae | rae = e | + rae.dependsOnDef(srcDef, srcVar) + or + exists(Expr child | + rae.dependsOnChild(child) and + exprDependsOnDef(child, srcDef, srcVar) + ) + ) } /** @@ -327,11 +433,11 @@ private predicate exprDependsOnDef(Expr e, RangeSsaDefinition srcDef, StackVaria private predicate phiDependsOnDef( RangeSsaDefinition phi, StackVariable v, RangeSsaDefinition srcDef, StackVariable srcVar ) { - exists(VariableAccess access, ComparisonOperation guard | + exists(VariableAccess access, Expr guard | access = v.getAnAccess() and phi.isGuardPhi(access, guard, _) | - exprDependsOnDef(guard.getAnOperand(), srcDef, srcVar) or + exprDependsOnDef(guard.(ComparisonOperation).getAnOperand(), srcDef, srcVar) or exprDependsOnDef(access, srcDef, srcVar) ) or @@ -354,6 +460,39 @@ private predicate isRecursiveDef(RangeSsaDefinition def, StackVariable v) { defDependsOnDefTransitively(def, v, def, v) } +/** + * Holds if the bounds of `e` depend on a recursive definition, meaning that + * `e` is likely to have many candidate bounds during the main recursion. + */ +private predicate isRecursiveExpr(Expr e) { + exists(RangeSsaDefinition def, StackVariable v | exprDependsOnDef(e, def, v) | + isRecursiveDef(def, v) + ) +} + +/** + * Holds if `binop` is a binary operation that's likely to be assigned a + * quadratic (or more) number of candidate bounds during the analysis. This can + * happen when two conditions are satisfied: + * 1. It is likely there are many more candidate bounds for `binop` than for + * its operands. For example, the number of candidate bounds for `x + y`, + * denoted here nbounds(`x + y`), will be O(nbounds(`x`) * nbounds(`y`)). + * In contrast, nbounds(`b ? x : y`) is only O(nbounds(`x`) + nbounds(`y`)). + * 2. Both operands of `binop` are recursively determined and are therefore + * likely to have a large number of candidate bounds. + */ +private predicate isRecursiveBinary(BinaryOperation binop) { + ( + binop instanceof UnsignedMulExpr + or + binop instanceof AddExpr + or + binop instanceof SubExpr + ) and + isRecursiveExpr(binop.getLeftOperand()) and + isRecursiveExpr(binop.getRightOperand()) +} + /** * We distinguish 3 kinds of RangeSsaDefinition: * @@ -369,7 +508,7 @@ private predicate isRecursiveDef(RangeSsaDefinition def, StackVariable v) { * This predicate finds all the definitions in the first set. */ private predicate assignmentDef(RangeSsaDefinition def, StackVariable v, Expr expr) { - v.getUnspecifiedType() instanceof ArithmeticType and + getVariableRangeType(v) instanceof ArithmeticType and ( def = v.getInitializer().getExpr() and def = expr or @@ -381,9 +520,20 @@ private predicate assignmentDef(RangeSsaDefinition def, StackVariable v, Expr ex ) } -/** See comment above sourceDef. */ +/** See comment above assignmentDef. */ private predicate analyzableDef(RangeSsaDefinition def, StackVariable v) { - assignmentDef(def, v, _) or defDependsOnDef(def, v, _, _) + assignmentDef(def, v, _) + or + analyzableExpr(def.(AssignOperation)) and + v = def.getAVariable() + or + analyzableExpr(def.(CrementOperation)) and + v = def.getAVariable() + or + phiDependsOnDef(def, v, _, _) + or + // A modeled def for range analysis + def.(SimpleRangeAnalysisDefinition).hasRangeInformationFor(v) } /** @@ -435,13 +585,6 @@ private float addRoundingDownSmall(float x, float small) { if (x + small) - x > small then result = (x + small).nextDown() else result = (x + small) } -/** - * Gets the truncated lower bounds of the fully converted expression. - */ -private float getFullyConvertedLowerBounds(Expr expr) { - result = getTruncatedLowerBounds(expr.getFullyConverted()) -} - /** * Gets the lower bounds of the expression. * @@ -469,9 +612,18 @@ private float getTruncatedLowerBounds(Expr expr) { else ( // Some of the bounds computed by getLowerBoundsImpl might // overflow, so we replace invalid bounds with exprMinVal. - exists(float newLB | newLB = getLowerBoundsImpl(expr) | + exists(float newLB | newLB = normalizeFloatUp(getLowerBoundsImpl(expr)) | if exprMinVal(expr) <= newLB and newLB <= exprMaxVal(expr) - then result = newLB + then + // Apply widening where we might get a combinatorial explosion. + if isRecursiveBinary(expr) + then + result = + max(float widenLB | + widenLB = wideningLowerBounds(expr.getUnspecifiedType()) and + not widenLB > newLB + ) + else result = newLB else result = exprMinVal(expr) ) or @@ -488,13 +640,6 @@ private float getTruncatedLowerBounds(Expr expr) { result = exprMinVal(expr) } -/** - * Gets the truncated upper bounds of the fully converted expression. - */ -private float getFullyConvertedUpperBounds(Expr expr) { - result = getTruncatedUpperBounds(expr.getFullyConverted()) -} - /** * Gets the upper bounds of the expression. * @@ -523,9 +668,18 @@ private float getTruncatedUpperBounds(Expr expr) { // Some of the bounds computed by `getUpperBoundsImpl` // might overflow, so we replace invalid bounds with // `exprMaxVal`. - exists(float newUB | newUB = getUpperBoundsImpl(expr) | + exists(float newUB | newUB = normalizeFloatUp(getUpperBoundsImpl(expr)) | if exprMinVal(expr) <= newUB and newUB <= exprMaxVal(expr) - then result = newUB + then + // Apply widening where we might get a combinatorial explosion. + if isRecursiveBinary(expr) + then + result = + min(float widenUB | + widenUB = wideningUpperBounds(expr.getUnspecifiedType()) and + not widenUB < newUB + ) + else result = newUB else result = exprMaxVal(expr) ) or @@ -562,339 +716,393 @@ deprecated predicate positive_overflow(Expr expr) { exprMightOverflowPositively( /** Only to be called by `getTruncatedLowerBounds`. */ private float getLowerBoundsImpl(Expr expr) { - exists(UnaryPlusExpr plusExpr | - expr = plusExpr and - result = getFullyConvertedLowerBounds(plusExpr.getOperand()) - ) - or - exists(UnaryMinusExpr negateExpr, float xHigh | - expr = negateExpr and - xHigh = getFullyConvertedUpperBounds(negateExpr.getOperand()) and - result = -xHigh - ) - or - exists(MinExpr minExpr | - expr = minExpr and - // Return the union of the lower bounds from both children. - result = getFullyConvertedLowerBounds(minExpr.getAnOperand()) - ) - or - exists(MaxExpr maxExpr | - expr = maxExpr and - // Compute the cross product of the bounds from both children. We are - // using this mathematical property: - // - // max (minimum{X}, minimum{Y}) - // = minimum { max(x,y) | x in X, y in Y } - exists(float x, float y | - x = getFullyConvertedLowerBounds(maxExpr.getLeftOperand()) and - y = getFullyConvertedLowerBounds(maxExpr.getRightOperand()) and - if x >= y then result = x else result = y + ( + exists(Expr operand, float operandLow, float positive | + effectivelyMultipliesByPositive(expr, operand, positive) and + operandLow = getFullyConvertedLowerBounds(operand) and + result = positive * operandLow ) - ) - or - // ConditionalExpr (true branch) - exists(ConditionalExpr condExpr | - expr = condExpr and - // Use `boolConversionUpperBound` to determine whether the condition - // might evaluate to `true`. - boolConversionUpperBound(condExpr.getCondition().getFullyConverted()) = 1 and - result = getFullyConvertedLowerBounds(condExpr.getThen()) - ) - or - // ConditionalExpr (false branch) - exists(ConditionalExpr condExpr | - expr = condExpr and - // Use `boolConversionLowerBound` to determine whether the condition - // might evaluate to `false`. - boolConversionLowerBound(condExpr.getCondition().getFullyConverted()) = 0 and - result = getFullyConvertedLowerBounds(condExpr.getElse()) - ) - or - exists(AddExpr addExpr, float xLow, float yLow | - expr = addExpr and - xLow = getFullyConvertedLowerBounds(addExpr.getLeftOperand()) and - yLow = getFullyConvertedLowerBounds(addExpr.getRightOperand()) and - result = addRoundingDown(xLow, yLow) - ) - or - exists(SubExpr subExpr, float xLow, float yHigh | - expr = subExpr and - xLow = getFullyConvertedLowerBounds(subExpr.getLeftOperand()) and - yHigh = getFullyConvertedUpperBounds(subExpr.getRightOperand()) and - result = addRoundingDown(xLow, -yHigh) - ) - or - exists(AssignExpr assign | - expr = assign and - result = getFullyConvertedLowerBounds(assign.getRValue()) - ) - or - exists(AssignAddExpr addExpr, float xLow, float yLow | - expr = addExpr and - xLow = getFullyConvertedLowerBounds(addExpr.getLValue()) and - yLow = getFullyConvertedLowerBounds(addExpr.getRValue()) and - result = addRoundingDown(xLow, yLow) - ) - or - exists(AssignSubExpr subExpr, float xLow, float yHigh | - expr = subExpr and - xLow = getFullyConvertedLowerBounds(subExpr.getLValue()) and - yHigh = getFullyConvertedUpperBounds(subExpr.getRValue()) and - result = addRoundingDown(xLow, -yHigh) - ) - or - exists(PrefixIncrExpr incrExpr, float xLow | - expr = incrExpr and - xLow = getFullyConvertedLowerBounds(incrExpr.getOperand()) and - result = xLow + 1 - ) - or - exists(PrefixDecrExpr decrExpr, float xLow | - expr = decrExpr and - xLow = getFullyConvertedLowerBounds(decrExpr.getOperand()) and - result = addRoundingDownSmall(xLow, -1) - ) - or - // `PostfixIncrExpr` and `PostfixDecrExpr` return the value of their - // operand. The incrementing/decrementing behavior is handled in - // `getDefLowerBoundsImpl`. - exists(PostfixIncrExpr incrExpr | - expr = incrExpr and - result = getFullyConvertedLowerBounds(incrExpr.getOperand()) - ) - or - exists(PostfixDecrExpr decrExpr | - expr = decrExpr and - result = getFullyConvertedLowerBounds(decrExpr.getOperand()) - ) - or - exists(RemExpr remExpr | expr = remExpr | - // If both inputs are positive then the lower bound is zero. - result = 0 or - // If either input could be negative then the output could be - // negative. If so, the lower bound of `x%y` is `-abs(y)`, which is - // equal to `min(-y,y)`. - exists(float childLB | - childLB = getFullyConvertedLowerBounds(remExpr.getAnOperand()) and - not childLB >= 0 - | - result = getFullyConvertedLowerBounds(remExpr.getRightOperand()) + exists(Expr operand, float operandHigh, float negative | + effectivelyMultipliesByNegative(expr, operand, negative) and + operandHigh = getFullyConvertedUpperBounds(operand) and + result = negative * operandHigh + ) + or + exists(MinExpr minExpr | + expr = minExpr and + // Return the union of the lower bounds from both children. + result = getFullyConvertedLowerBounds(minExpr.getAnOperand()) + ) + or + exists(MaxExpr maxExpr | + expr = maxExpr and + // Compute the cross product of the bounds from both children. We are + // using this mathematical property: + // + // max (minimum{X}, minimum{Y}) + // = minimum { max(x,y) | x in X, y in Y } + exists(float x, float y | + x = getFullyConvertedLowerBounds(maxExpr.getLeftOperand()) and + y = getFullyConvertedLowerBounds(maxExpr.getRightOperand()) and + if x >= y then result = x else result = y + ) + ) + or + // ConditionalExpr (true branch) + exists(ConditionalExpr condExpr | + expr = condExpr and + // Use `boolConversionUpperBound` to determine whether the condition + // might evaluate to `true`. + boolConversionUpperBound(condExpr.getCondition().getFullyConverted()) = 1 and + result = getFullyConvertedLowerBounds(condExpr.getThen()) + ) + or + // ConditionalExpr (false branch) + exists(ConditionalExpr condExpr | + expr = condExpr and + // Use `boolConversionLowerBound` to determine whether the condition + // might evaluate to `false`. + boolConversionLowerBound(condExpr.getCondition().getFullyConverted()) = 0 and + result = getFullyConvertedLowerBounds(condExpr.getElse()) + ) + or + exists(AddExpr addExpr, float xLow, float yLow | + expr = addExpr and + xLow = getFullyConvertedLowerBounds(addExpr.getLeftOperand()) and + yLow = getFullyConvertedLowerBounds(addExpr.getRightOperand()) and + result = addRoundingDown(xLow, yLow) + ) + or + exists(SubExpr subExpr, float xLow, float yHigh | + expr = subExpr and + xLow = getFullyConvertedLowerBounds(subExpr.getLeftOperand()) and + yHigh = getFullyConvertedUpperBounds(subExpr.getRightOperand()) and + result = addRoundingDown(xLow, -yHigh) + ) + or + exists(UnsignedMulExpr mulExpr, float xLow, float yLow | + expr = mulExpr and + xLow = getFullyConvertedLowerBounds(mulExpr.getLeftOperand()) and + yLow = getFullyConvertedLowerBounds(mulExpr.getRightOperand()) and + result = xLow * yLow + ) + or + exists(AssignExpr assign | + expr = assign and + result = getFullyConvertedLowerBounds(assign.getRValue()) + ) + or + exists(AssignAddExpr addExpr, float xLow, float yLow | + expr = addExpr and + xLow = getFullyConvertedLowerBounds(addExpr.getLValue()) and + yLow = getFullyConvertedLowerBounds(addExpr.getRValue()) and + result = addRoundingDown(xLow, yLow) + ) + or + exists(AssignSubExpr subExpr, float xLow, float yHigh | + expr = subExpr and + xLow = getFullyConvertedLowerBounds(subExpr.getLValue()) and + yHigh = getFullyConvertedUpperBounds(subExpr.getRValue()) and + result = addRoundingDown(xLow, -yHigh) + ) + or + exists(UnsignedAssignMulExpr mulExpr, float xLow, float yLow | + expr = mulExpr and + xLow = getFullyConvertedLowerBounds(mulExpr.getLValue()) and + yLow = getFullyConvertedLowerBounds(mulExpr.getRValue()) and + result = xLow * yLow + ) + or + exists(AssignMulByPositiveConstantExpr mulExpr, float xLow | + expr = mulExpr and + xLow = getFullyConvertedLowerBounds(mulExpr.getLValue()) and + result = xLow * mulExpr.getConstant() + ) + or + exists(AssignMulByNegativeConstantExpr mulExpr, float xHigh | + expr = mulExpr and + xHigh = getFullyConvertedUpperBounds(mulExpr.getLValue()) and + result = xHigh * mulExpr.getConstant() + ) + or + exists(PrefixIncrExpr incrExpr, float xLow | + expr = incrExpr and + xLow = getFullyConvertedLowerBounds(incrExpr.getOperand()) and + result = xLow + 1 + ) + or + exists(PrefixDecrExpr decrExpr, float xLow | + expr = decrExpr and + xLow = getFullyConvertedLowerBounds(decrExpr.getOperand()) and + result = addRoundingDownSmall(xLow, -1) + ) + or + // `PostfixIncrExpr` and `PostfixDecrExpr` return the value of their + // operand. The incrementing/decrementing behavior is handled in + // `getDefLowerBoundsImpl`. + exists(PostfixIncrExpr incrExpr | + expr = incrExpr and + result = getFullyConvertedLowerBounds(incrExpr.getOperand()) + ) + or + exists(PostfixDecrExpr decrExpr | + expr = decrExpr and + result = getFullyConvertedLowerBounds(decrExpr.getOperand()) + ) + or + exists(RemExpr remExpr | expr = remExpr | + // If both inputs are positive then the lower bound is zero. + result = 0 or - exists(float rhsUB | rhsUB = getFullyConvertedUpperBounds(remExpr.getRightOperand()) | - result = -rhsUB + // If either input could be negative then the output could be + // negative. If so, the lower bound of `x%y` is `-abs(y)`, which is + // equal to `min(-y,y)`. + exists(float childLB | + childLB = getFullyConvertedLowerBounds(remExpr.getAnOperand()) and + not childLB >= 0 + | + result = getFullyConvertedLowerBounds(remExpr.getRightOperand()) + or + exists(float rhsUB | rhsUB = getFullyConvertedUpperBounds(remExpr.getRightOperand()) | + result = -rhsUB + ) ) ) - ) - or - exists(CommaExpr commaExpr | - expr = commaExpr and - result = getFullyConvertedLowerBounds(commaExpr.getRightOperand()) - ) - or - exists(StmtExpr stmtExpr | - expr = stmtExpr and - result = getFullyConvertedLowerBounds(stmtExpr.getResultExpr()) - ) - or - // If the conversion is to an arithmetic type then we just return the - // lower bound of the child. We do not need to handle truncation and - // overflow here, because that is done in `getTruncatedLowerBounds`. - // Conversions to `bool` need to be handled specially because they test - // whether the value of the expression is equal to 0. - exists(Conversion convExpr | expr = convExpr | - if convExpr.getUnspecifiedType() instanceof BoolType - then result = boolConversionLowerBound(convExpr.getExpr()) - else result = getTruncatedLowerBounds(convExpr.getExpr()) - ) - or - // Use SSA to get the lower bounds for a variable use. - exists(RangeSsaDefinition def, StackVariable v | expr = def.getAUse(v) | - result = getDefLowerBounds(def, v) - ) - or - // unsigned `&` (tighter bounds may exist) - exists(UnsignedBitwiseAndExpr andExpr | - andExpr = expr and - result = 0.0 - ) + or + // If the conversion is to an arithmetic type then we just return the + // lower bound of the child. We do not need to handle truncation and + // overflow here, because that is done in `getTruncatedLowerBounds`. + // Conversions to `bool` need to be handled specially because they test + // whether the value of the expression is equal to 0. + exists(Conversion convExpr | expr = convExpr | + if convExpr.getUnspecifiedType() instanceof BoolType + then result = boolConversionLowerBound(convExpr.getExpr()) + else result = getTruncatedLowerBounds(convExpr.getExpr()) + ) + or + // Use SSA to get the lower bounds for a variable use. + exists(RangeSsaDefinition def, StackVariable v | expr = def.getAUse(v) | + result = getDefLowerBounds(def, v) + ) + or + // unsigned `&` (tighter bounds may exist) + exists(UnsignedBitwiseAndExpr andExpr | + andExpr = expr and + result = 0.0 + ) + or + // `>>` by a constant + exists(RShiftExpr rsExpr, float left, int right | + rsExpr = expr and + left = getFullyConvertedLowerBounds(rsExpr.getLeftOperand()) and + right = getValue(rsExpr.getRightOperand().getFullyConverted()).toInt() and + result = safeFloor(left / 2.pow(right)) + ) + // Not explicitly modeled by a SimpleRangeAnalysisExpr + ) and + not expr instanceof SimpleRangeAnalysisExpr or - // `>>` by a constant - exists(RShiftExpr rsExpr, float left, int right | - rsExpr = expr and - left = getFullyConvertedLowerBounds(rsExpr.getLeftOperand()) and - right = rsExpr.getRightOperand().getValue().toInt() and - result = safeFloor(left / 2.pow(right)) + // A modeled expression for range analysis + exists(SimpleRangeAnalysisExpr rangeAnalysisExpr | + rangeAnalysisExpr = expr and + result = rangeAnalysisExpr.getLowerBounds() ) } /** Only to be called by `getTruncatedUpperBounds`. */ private float getUpperBoundsImpl(Expr expr) { - exists(UnaryPlusExpr plusExpr | - expr = plusExpr and - result = getFullyConvertedUpperBounds(plusExpr.getOperand()) - ) - or - exists(UnaryMinusExpr negateExpr, float xLow | - expr = negateExpr and - xLow = getFullyConvertedLowerBounds(negateExpr.getOperand()) and - result = -xLow - ) - or - exists(MaxExpr maxExpr | - expr = maxExpr and - // Return the union of the upper bounds from both children. - result = getFullyConvertedUpperBounds(maxExpr.getAnOperand()) - ) - or - exists(MinExpr minExpr | - expr = minExpr and - // Compute the cross product of the bounds from both children. We are - // using this mathematical property: - // - // min (maximum{X}, maximum{Y}) - // = maximum { min(x,y) | x in X, y in Y } - exists(float x, float y | - x = getFullyConvertedUpperBounds(minExpr.getLeftOperand()) and - y = getFullyConvertedUpperBounds(minExpr.getRightOperand()) and - if x <= y then result = x else result = y + ( + exists(Expr operand, float operandHigh, float positive | + effectivelyMultipliesByPositive(expr, operand, positive) and + operandHigh = getFullyConvertedUpperBounds(operand) and + result = positive * operandHigh ) - ) - or - // ConditionalExpr (true branch) - exists(ConditionalExpr condExpr | - expr = condExpr and - // Use `boolConversionUpperBound` to determine whether the condition - // might evaluate to `true`. - boolConversionUpperBound(condExpr.getCondition().getFullyConverted()) = 1 and - result = getFullyConvertedUpperBounds(condExpr.getThen()) - ) - or - // ConditionalExpr (false branch) - exists(ConditionalExpr condExpr | - expr = condExpr and - // Use `boolConversionLowerBound` to determine whether the condition - // might evaluate to `false`. - boolConversionLowerBound(condExpr.getCondition().getFullyConverted()) = 0 and - result = getFullyConvertedUpperBounds(condExpr.getElse()) - ) - or - exists(AddExpr addExpr, float xHigh, float yHigh | - expr = addExpr and - xHigh = getFullyConvertedUpperBounds(addExpr.getLeftOperand()) and - yHigh = getFullyConvertedUpperBounds(addExpr.getRightOperand()) and - result = addRoundingUp(xHigh, yHigh) - ) - or - exists(SubExpr subExpr, float xHigh, float yLow | - expr = subExpr and - xHigh = getFullyConvertedUpperBounds(subExpr.getLeftOperand()) and - yLow = getFullyConvertedLowerBounds(subExpr.getRightOperand()) and - result = addRoundingUp(xHigh, -yLow) - ) - or - exists(AssignExpr assign | - expr = assign and - result = getFullyConvertedUpperBounds(assign.getRValue()) - ) - or - exists(AssignAddExpr addExpr, float xHigh, float yHigh | - expr = addExpr and - xHigh = getFullyConvertedUpperBounds(addExpr.getLValue()) and - yHigh = getFullyConvertedUpperBounds(addExpr.getRValue()) and - result = addRoundingUp(xHigh, yHigh) - ) - or - exists(AssignSubExpr subExpr, float xHigh, float yLow | - expr = subExpr and - xHigh = getFullyConvertedUpperBounds(subExpr.getLValue()) and - yLow = getFullyConvertedLowerBounds(subExpr.getRValue()) and - result = addRoundingUp(xHigh, -yLow) - ) - or - exists(PrefixIncrExpr incrExpr, float xHigh | - expr = incrExpr and - xHigh = getFullyConvertedUpperBounds(incrExpr.getOperand()) and - result = addRoundingUpSmall(xHigh, 1) - ) - or - exists(PrefixDecrExpr decrExpr, float xHigh | - expr = decrExpr and - xHigh = getFullyConvertedUpperBounds(decrExpr.getOperand()) and - result = xHigh - 1 - ) - or - // `PostfixIncrExpr` and `PostfixDecrExpr` return the value of their operand. - // The incrementing/decrementing behavior is handled in - // `getDefUpperBoundsImpl`. - exists(PostfixIncrExpr incrExpr | - expr = incrExpr and - result = getFullyConvertedUpperBounds(incrExpr.getOperand()) - ) - or - exists(PostfixDecrExpr decrExpr | - expr = decrExpr and - result = getFullyConvertedUpperBounds(decrExpr.getOperand()) - ) - or - exists(RemExpr remExpr, float rhsUB | - expr = remExpr and - rhsUB = getFullyConvertedUpperBounds(remExpr.getRightOperand()) - | - result = rhsUB - or - // If the right hand side could be negative then we need to take its - // absolute value. Since `abs(x) = max(-x,x)` this is equivalent to - // adding `-rhsLB` to the set of upper bounds. - exists(float rhsLB | - rhsLB = getFullyConvertedLowerBounds(remExpr.getAnOperand()) and - not rhsLB >= 0 + or + exists(Expr operand, float operandLow, float negative | + effectivelyMultipliesByNegative(expr, operand, negative) and + operandLow = getFullyConvertedLowerBounds(operand) and + result = negative * operandLow + ) + or + exists(MaxExpr maxExpr | + expr = maxExpr and + // Return the union of the upper bounds from both children. + result = getFullyConvertedUpperBounds(maxExpr.getAnOperand()) + ) + or + exists(MinExpr minExpr | + expr = minExpr and + // Compute the cross product of the bounds from both children. We are + // using this mathematical property: + // + // min (maximum{X}, maximum{Y}) + // = maximum { min(x,y) | x in X, y in Y } + exists(float x, float y | + x = getFullyConvertedUpperBounds(minExpr.getLeftOperand()) and + y = getFullyConvertedUpperBounds(minExpr.getRightOperand()) and + if x <= y then result = x else result = y + ) + ) + or + // ConditionalExpr (true branch) + exists(ConditionalExpr condExpr | + expr = condExpr and + // Use `boolConversionUpperBound` to determine whether the condition + // might evaluate to `true`. + boolConversionUpperBound(condExpr.getCondition().getFullyConverted()) = 1 and + result = getFullyConvertedUpperBounds(condExpr.getThen()) + ) + or + // ConditionalExpr (false branch) + exists(ConditionalExpr condExpr | + expr = condExpr and + // Use `boolConversionLowerBound` to determine whether the condition + // might evaluate to `false`. + boolConversionLowerBound(condExpr.getCondition().getFullyConverted()) = 0 and + result = getFullyConvertedUpperBounds(condExpr.getElse()) + ) + or + exists(AddExpr addExpr, float xHigh, float yHigh | + expr = addExpr and + xHigh = getFullyConvertedUpperBounds(addExpr.getLeftOperand()) and + yHigh = getFullyConvertedUpperBounds(addExpr.getRightOperand()) and + result = addRoundingUp(xHigh, yHigh) + ) + or + exists(SubExpr subExpr, float xHigh, float yLow | + expr = subExpr and + xHigh = getFullyConvertedUpperBounds(subExpr.getLeftOperand()) and + yLow = getFullyConvertedLowerBounds(subExpr.getRightOperand()) and + result = addRoundingUp(xHigh, -yLow) + ) + or + exists(UnsignedMulExpr mulExpr, float xHigh, float yHigh | + expr = mulExpr and + xHigh = getFullyConvertedUpperBounds(mulExpr.getLeftOperand()) and + yHigh = getFullyConvertedUpperBounds(mulExpr.getRightOperand()) and + result = xHigh * yHigh + ) + or + exists(AssignExpr assign | + expr = assign and + result = getFullyConvertedUpperBounds(assign.getRValue()) + ) + or + exists(AssignAddExpr addExpr, float xHigh, float yHigh | + expr = addExpr and + xHigh = getFullyConvertedUpperBounds(addExpr.getLValue()) and + yHigh = getFullyConvertedUpperBounds(addExpr.getRValue()) and + result = addRoundingUp(xHigh, yHigh) + ) + or + exists(AssignSubExpr subExpr, float xHigh, float yLow | + expr = subExpr and + xHigh = getFullyConvertedUpperBounds(subExpr.getLValue()) and + yLow = getFullyConvertedLowerBounds(subExpr.getRValue()) and + result = addRoundingUp(xHigh, -yLow) + ) + or + exists(UnsignedAssignMulExpr mulExpr, float xHigh, float yHigh | + expr = mulExpr and + xHigh = getFullyConvertedUpperBounds(mulExpr.getLValue()) and + yHigh = getFullyConvertedUpperBounds(mulExpr.getRValue()) and + result = xHigh * yHigh + ) + or + exists(AssignMulByPositiveConstantExpr mulExpr, float xHigh | + expr = mulExpr and + xHigh = getFullyConvertedUpperBounds(mulExpr.getLValue()) and + result = xHigh * mulExpr.getConstant() + ) + or + exists(AssignMulByNegativeConstantExpr mulExpr, float xLow | + expr = mulExpr and + xLow = getFullyConvertedLowerBounds(mulExpr.getLValue()) and + result = xLow * mulExpr.getConstant() + ) + or + exists(PrefixIncrExpr incrExpr, float xHigh | + expr = incrExpr and + xHigh = getFullyConvertedUpperBounds(incrExpr.getOperand()) and + result = addRoundingUpSmall(xHigh, 1) + ) + or + exists(PrefixDecrExpr decrExpr, float xHigh | + expr = decrExpr and + xHigh = getFullyConvertedUpperBounds(decrExpr.getOperand()) and + result = xHigh - 1 + ) + or + // `PostfixIncrExpr` and `PostfixDecrExpr` return the value of their operand. + // The incrementing/decrementing behavior is handled in + // `getDefUpperBoundsImpl`. + exists(PostfixIncrExpr incrExpr | + expr = incrExpr and + result = getFullyConvertedUpperBounds(incrExpr.getOperand()) + ) + or + exists(PostfixDecrExpr decrExpr | + expr = decrExpr and + result = getFullyConvertedUpperBounds(decrExpr.getOperand()) + ) + or + exists(RemExpr remExpr, float rhsUB | + expr = remExpr and + rhsUB = getFullyConvertedUpperBounds(remExpr.getRightOperand()) | - result = -rhsLB + result = rhsUB + or + // If the right hand side could be negative then we need to take its + // absolute value. Since `abs(x) = max(-x,x)` this is equivalent to + // adding `-rhsLB` to the set of upper bounds. + exists(float rhsLB | + rhsLB = getFullyConvertedLowerBounds(remExpr.getAnOperand()) and + not rhsLB >= 0 + | + result = -rhsLB + ) ) - ) - or - exists(CommaExpr commaExpr | - expr = commaExpr and - result = getFullyConvertedUpperBounds(commaExpr.getRightOperand()) - ) - or - exists(StmtExpr stmtExpr | - expr = stmtExpr and - result = getFullyConvertedUpperBounds(stmtExpr.getResultExpr()) - ) - or - // If the conversion is to an arithmetic type then we just return the - // upper bound of the child. We do not need to handle truncation and - // overflow here, because that is done in `getTruncatedUpperBounds`. - // Conversions to `bool` need to be handled specially because they test - // whether the value of the expression is equal to 0. - exists(Conversion convExpr | expr = convExpr | - if convExpr.getUnspecifiedType() instanceof BoolType - then result = boolConversionUpperBound(convExpr.getExpr()) - else result = getTruncatedUpperBounds(convExpr.getExpr()) - ) - or - // Use SSA to get the upper bounds for a variable use. - exists(RangeSsaDefinition def, StackVariable v | expr = def.getAUse(v) | - result = getDefUpperBounds(def, v) - ) - or - // unsigned `&` (tighter bounds may exist) - exists(UnsignedBitwiseAndExpr andExpr, float left, float right | - andExpr = expr and - left = getFullyConvertedUpperBounds(andExpr.getLeftOperand()) and - right = getFullyConvertedUpperBounds(andExpr.getRightOperand()) and - result = left.minimum(right) - ) + or + // If the conversion is to an arithmetic type then we just return the + // upper bound of the child. We do not need to handle truncation and + // overflow here, because that is done in `getTruncatedUpperBounds`. + // Conversions to `bool` need to be handled specially because they test + // whether the value of the expression is equal to 0. + exists(Conversion convExpr | expr = convExpr | + if convExpr.getUnspecifiedType() instanceof BoolType + then result = boolConversionUpperBound(convExpr.getExpr()) + else result = getTruncatedUpperBounds(convExpr.getExpr()) + ) + or + // Use SSA to get the upper bounds for a variable use. + exists(RangeSsaDefinition def, StackVariable v | expr = def.getAUse(v) | + result = getDefUpperBounds(def, v) + ) + or + // unsigned `&` (tighter bounds may exist) + exists(UnsignedBitwiseAndExpr andExpr, float left, float right | + andExpr = expr and + left = getFullyConvertedUpperBounds(andExpr.getLeftOperand()) and + right = getFullyConvertedUpperBounds(andExpr.getRightOperand()) and + result = left.minimum(right) + ) + or + // `>>` by a constant + exists(RShiftExpr rsExpr, float left, int right | + rsExpr = expr and + left = getFullyConvertedUpperBounds(rsExpr.getLeftOperand()) and + right = getValue(rsExpr.getRightOperand().getFullyConverted()).toInt() and + result = safeFloor(left / 2.pow(right)) + ) + // Not explicitly modeled by a SimpleRangeAnalysisExpr + ) and + not expr instanceof SimpleRangeAnalysisExpr or - // `>>` by a constant - exists(RShiftExpr rsExpr, float left, int right | - rsExpr = expr and - left = getFullyConvertedUpperBounds(rsExpr.getLeftOperand()) and - right = rsExpr.getRightOperand().getValue().toInt() and - result = safeFloor(left / 2.pow(right)) + // A modeled expression for range analysis + exists(SimpleRangeAnalysisExpr rangeAnalysisExpr | + rangeAnalysisExpr = expr and + result = rangeAnalysisExpr.getUpperBounds() ) } @@ -988,9 +1196,7 @@ private float boolConversionUpperBound(Expr expr) { * use the guard to deduce that the lower bound is 2 inside the block. */ private float getPhiLowerBounds(StackVariable v, RangeSsaDefinition phi) { - exists( - VariableAccess access, ComparisonOperation guard, boolean branch, float defLB, float guardLB - | + exists(VariableAccess access, Expr guard, boolean branch, float defLB, float guardLB | access = v.getAnAccess() and phi.isGuardPhi(access, guard, branch) and lowerBoundFromGuard(guard, access, guardLB, branch) and @@ -1000,14 +1206,23 @@ private float getPhiLowerBounds(StackVariable v, RangeSsaDefinition phi) { if guardLB > defLB then result = guardLB else result = defLB ) or + exists(VariableAccess access, float neConstant, float lower | + isNEPhi(v, phi, access, neConstant) and + lower = getTruncatedLowerBounds(access) and + if lower = neConstant then result = lower + 1 else result = lower + ) + or + exists(VariableAccess access | + isUnsupportedGuardPhi(v, phi, access) and + result = getTruncatedLowerBounds(access) + ) + or result = getDefLowerBounds(phi.getAPhiInput(v), v) } /** See comment for `getPhiLowerBounds`, above. */ private float getPhiUpperBounds(StackVariable v, RangeSsaDefinition phi) { - exists( - VariableAccess access, ComparisonOperation guard, boolean branch, float defUB, float guardUB - | + exists(VariableAccess access, Expr guard, boolean branch, float defUB, float guardUB | access = v.getAnAccess() and phi.isGuardPhi(access, guard, branch) and upperBoundFromGuard(guard, access, guardUB, branch) and @@ -1017,6 +1232,17 @@ private float getPhiUpperBounds(StackVariable v, RangeSsaDefinition phi) { if guardUB < defUB then result = guardUB else result = defUB ) or + exists(VariableAccess access, float neConstant, float upper | + isNEPhi(v, phi, access, neConstant) and + upper = getTruncatedUpperBounds(access) and + if upper = neConstant then result = upper - 1 else result = upper + ) + or + exists(VariableAccess access | + isUnsupportedGuardPhi(v, phi, access) and + result = getTruncatedUpperBounds(access) + ) + or result = getDefUpperBounds(phi.getAPhiInput(v), v) } @@ -1025,20 +1251,11 @@ private float getDefLowerBoundsImpl(RangeSsaDefinition def, StackVariable v) { // Definitions with a defining value. exists(Expr expr | assignmentDef(def, v, expr) | result = getFullyConvertedLowerBounds(expr)) or - exists(AssignAddExpr assignAdd, RangeSsaDefinition nextDef, float lhsLB, float rhsLB | - def = assignAdd and - assignAdd.getLValue() = nextDef.getAUse(v) and - lhsLB = getDefLowerBounds(nextDef, v) and - rhsLB = getFullyConvertedLowerBounds(assignAdd.getRValue()) and - result = addRoundingDown(lhsLB, rhsLB) - ) - or - exists(AssignSubExpr assignSub, RangeSsaDefinition nextDef, float lhsLB, float rhsUB | - def = assignSub and - assignSub.getLValue() = nextDef.getAUse(v) and - lhsLB = getDefLowerBounds(nextDef, v) and - rhsUB = getFullyConvertedUpperBounds(assignSub.getRValue()) and - result = addRoundingDown(lhsLB, -rhsUB) + // Assignment operations with a defining value + exists(AssignOperation assignOp | + def = assignOp and + assignOp.getLValue() = v.getAnAccess() and + result = getTruncatedLowerBounds(assignOp) ) or exists(IncrementOperation incr, float newLB | @@ -1058,6 +1275,9 @@ private float getDefLowerBoundsImpl(RangeSsaDefinition def, StackVariable v) { // Phi nodes. result = getPhiLowerBounds(v, def) or + // A modeled def for range analysis + result = def.(SimpleRangeAnalysisDefinition).getLowerBounds(v) + or // Unanalyzable definitions. unanalyzableDefBounds(def, v, result, _) } @@ -1067,20 +1287,11 @@ private float getDefUpperBoundsImpl(RangeSsaDefinition def, StackVariable v) { // Definitions with a defining value. exists(Expr expr | assignmentDef(def, v, expr) | result = getFullyConvertedUpperBounds(expr)) or - exists(AssignAddExpr assignAdd, RangeSsaDefinition nextDef, float lhsUB, float rhsUB | - def = assignAdd and - assignAdd.getLValue() = nextDef.getAUse(v) and - lhsUB = getDefUpperBounds(nextDef, v) and - rhsUB = getFullyConvertedUpperBounds(assignAdd.getRValue()) and - result = addRoundingUp(lhsUB, rhsUB) - ) - or - exists(AssignSubExpr assignSub, RangeSsaDefinition nextDef, float lhsUB, float rhsLB | - def = assignSub and - assignSub.getLValue() = nextDef.getAUse(v) and - lhsUB = getDefUpperBounds(nextDef, v) and - rhsLB = getFullyConvertedLowerBounds(assignSub.getRValue()) and - result = addRoundingUp(lhsUB, -rhsLB) + // Assignment operations with a defining value + exists(AssignOperation assignOp | + def = assignOp and + assignOp.getLValue() = v.getAnAccess() and + result = getTruncatedUpperBounds(assignOp) ) or exists(IncrementOperation incr, float newUB | @@ -1100,74 +1311,13 @@ private float getDefUpperBoundsImpl(RangeSsaDefinition def, StackVariable v) { // Phi nodes. result = getPhiUpperBounds(v, def) or + // A modeled def for range analysis + result = def.(SimpleRangeAnalysisDefinition).getUpperBounds(v) + or // Unanalyzable definitions. unanalyzableDefBounds(def, v, _, result) } -/** - * Get the lower bounds for a `RangeSsaDefinition`. Most of the work is - * done by `getDefLowerBoundsImpl`, but this is where widening is applied - * to prevent the analysis from exploding due to a recursive definition. - */ -private float getDefLowerBounds(RangeSsaDefinition def, StackVariable v) { - exists(float newLB, float truncatedLB | - newLB = getDefLowerBoundsImpl(def, v) and - if varMinVal(v) <= newLB and newLB <= varMaxVal(v) - then truncatedLB = newLB - else truncatedLB = varMinVal(v) - | - // Widening: check whether the new lower bound is from a source which - // depends recursively on the current definition. - if isRecursiveDef(def, v) - then - // The new lower bound is from a recursive source, so we round - // down to one of a limited set of values to prevent the - // recursion from exploding. - result = - max(float widenLB | - widenLB = wideningLowerBounds(v.getUnspecifiedType()) and - not widenLB > truncatedLB - | - widenLB - ) - else result = truncatedLB - ) - or - // The definition might overflow positively and wrap. If so, the lower - // bound is `typeLowerBound`. - defMightOverflowPositively(def, v) and result = varMinVal(v) -} - -/** See comment for `getDefLowerBounds`, above. */ -private float getDefUpperBounds(RangeSsaDefinition def, StackVariable v) { - exists(float newUB, float truncatedUB | - newUB = getDefUpperBoundsImpl(def, v) and - if varMinVal(v) <= newUB and newUB <= varMaxVal(v) - then truncatedUB = newUB - else truncatedUB = varMaxVal(v) - | - // Widening: check whether the new upper bound is from a source which - // depends recursively on the current definition. - if isRecursiveDef(def, v) - then - // The new upper bound is from a recursive source, so we round - // up to one of a fixed set of values to prevent the recursion - // from exploding. - result = - min(float widenUB | - widenUB = wideningUpperBounds(v.getUnspecifiedType()) and - not widenUB < truncatedUB - | - widenUB - ) - else result = truncatedUB - ) - or - // The definition might overflow negatively and wrap. If so, the upper - // bound is `typeUpperBound`. - defMightOverflowNegatively(def, v) and result = varMaxVal(v) -} - /** * Helper for `getDefLowerBounds` and `getDefUpperBounds`. Find the set of * unanalyzable definitions (such as function parameters) and make their @@ -1186,10 +1336,11 @@ private predicate unanalyzableDefBounds(RangeSsaDefinition def, StackVariable v, * inferences about `v`. */ bindingset[guard, v, branch] -predicate nonNanGuardedVariable(ComparisonOperation guard, VariableAccess v, boolean branch) { - v.getUnspecifiedType() instanceof IntegralType +predicate nonNanGuardedVariable(Expr guard, VariableAccess v, boolean branch) { + getVariableRangeType(v.getTarget()) instanceof IntegralType or - v.getUnspecifiedType() instanceof FloatingPointType and v instanceof NonNanVariableAccess + getVariableRangeType(v.getTarget()) instanceof FloatingPointType and + v instanceof NonNanVariableAccess or // The reason the following case is here is to ensure that when we say // `if (x > 5) { ...then... } else { ...else... }` @@ -1204,9 +1355,7 @@ predicate nonNanGuardedVariable(ComparisonOperation guard, VariableAccess v, boo * predicate uses the bounds information for `r` to compute a lower bound * for `v`. */ -private predicate lowerBoundFromGuard( - ComparisonOperation guard, VariableAccess v, float lb, boolean branch -) { +private predicate lowerBoundFromGuard(Expr guard, VariableAccess v, float lb, boolean branch) { exists(float childLB, RelationStrictness strictness | boundFromGuard(guard, v, childLB, true, strictness, branch) | @@ -1214,7 +1363,7 @@ private predicate lowerBoundFromGuard( then if strictness = Nonstrict() or - not v.getUnspecifiedType() instanceof IntegralType + not getVariableRangeType(v.getTarget()) instanceof IntegralType then lb = childLB else lb = childLB + 1 else lb = varMinVal(v.getTarget()) @@ -1226,9 +1375,7 @@ private predicate lowerBoundFromGuard( * predicate uses the bounds information for `r` to compute a upper bound * for `v`. */ -private predicate upperBoundFromGuard( - ComparisonOperation guard, VariableAccess v, float ub, boolean branch -) { +private predicate upperBoundFromGuard(Expr guard, VariableAccess v, float ub, boolean branch) { exists(float childUB, RelationStrictness strictness | boundFromGuard(guard, v, childUB, false, strictness, branch) | @@ -1236,7 +1383,7 @@ private predicate upperBoundFromGuard( then if strictness = Nonstrict() or - not v.getUnspecifiedType() instanceof IntegralType + not getVariableRangeType(v.getTarget()) instanceof IntegralType then ub = childUB else ub = childUB - 1 else ub = varMaxVal(v.getTarget()) @@ -1248,7 +1395,7 @@ private predicate upperBoundFromGuard( * `linearBoundFromGuard`. */ private predicate boundFromGuard( - ComparisonOperation guard, VariableAccess v, float boundValue, boolean isLowerBound, + Expr guard, VariableAccess v, float boundValue, boolean isLowerBound, RelationStrictness strictness, boolean branch ) { exists(float p, float q, float r, boolean isLB | @@ -1261,6 +1408,15 @@ private predicate boundFromGuard( or p < 0 and isLowerBound = isLB.booleanNot() ) + or + // When `!e` is true, we know that `0 <= e <= 0` + exists(float p, float q, Expr e | + linearAccess(e, v, p, q) and + eqZeroWithNegate(guard, e, true, branch) and + boundValue = (0.0 - q) / p and + isLowerBound = [false, true] and + strictness = Nonstrict() + ) } /** @@ -1296,22 +1452,13 @@ private predicate linearBoundFromGuard( // 1. x <= upperbound(RHS) // 2. x >= lowerbound(RHS) // - // For x != RHS, we create trivial bounds: - // - // 1. x <= typeUpperBound(RHS.getUnspecifiedType()) - // 2. x >= typeLowerBound(RHS.getUnspecifiedType()) - // - exists(Expr lhs, Expr rhs, boolean isEQ | + exists(Expr lhs, Expr rhs | linearAccess(lhs, v, p, q) and - eqOpWithSwapAndNegate(guard, lhs, rhs, isEQ, branch) and + eqOpWithSwapAndNegate(guard, lhs, rhs, true, branch) and + getBounds(rhs, boundValue, isLowerBound) and strictness = Nonstrict() - | - // True branch - isEQ = true and getBounds(rhs, boundValue, isLowerBound) - or - // False branch: set the bounds to the min/max for the type. - isEQ = false and exprTypeBounds(rhs, boundValue, isLowerBound) ) + // x != RHS and !x are handled elsewhere } /** Utility for `linearBoundFromGuard`. */ @@ -1328,6 +1475,54 @@ private predicate exprTypeBounds(Expr expr, float boundValue, boolean isLowerBou isLowerBound = false and boundValue = exprMaxVal(expr.getFullyConverted()) } +/** + * Holds if `(v, phi)` ensures that `access` is not equal to `neConstant`. For + * example, the condition `if (x + 1 != 3)` ensures that `x` is not equal to 2. + * Only integral types are supported. + */ +private predicate isNEPhi( + Variable v, RangeSsaDefinition phi, VariableAccess access, float neConstant +) { + exists( + ComparisonOperation cmp, boolean branch, Expr linearExpr, Expr rExpr, float p, float q, float r + | + access.getTarget() = v and + phi.isGuardPhi(access, cmp, branch) and + eqOpWithSwapAndNegate(cmp, linearExpr, rExpr, false, branch) and + v.getUnspecifiedType() instanceof IntegralOrEnumType and // Float `!=` is too imprecise + r = getValue(rExpr).toFloat() and + linearAccess(linearExpr, access, p, q) and + neConstant = (r - q) / p + ) + or + exists(Expr op, boolean branch, Expr linearExpr, float p, float q | + access.getTarget() = v and + phi.isGuardPhi(access, op, branch) and + eqZeroWithNegate(op, linearExpr, false, branch) and + v.getUnspecifiedType() instanceof IntegralOrEnumType and // Float `!` is too imprecise + linearAccess(linearExpr, access, p, q) and + neConstant = (0.0 - q) / p + ) +} + +/** + * Holds if `(v, phi)` constrains the value of `access` but in a way that + * doesn't allow this library to constrain the upper or lower bounds of + * `access`. An example is `if (x != y)` if neither `x` nor `y` is a + * compile-time constant. + */ +private predicate isUnsupportedGuardPhi(Variable v, RangeSsaDefinition phi, VariableAccess access) { + exists(Expr cmp, boolean branch | + eqOpWithSwapAndNegate(cmp, _, _, false, branch) + or + eqZeroWithNegate(cmp, _, false, branch) + | + access.getTarget() = v and + phi.isGuardPhi(access, cmp, branch) and + not isNEPhi(v, phi, access, _) + ) +} + cached private module SimpleRangeAnalysisCached { /** @@ -1480,3 +1675,89 @@ private module SimpleRangeAnalysisCached { convertedExprMightOverflowPositively(expr) } } + +/** + * INTERNAL: do not use. This module contains utilities for use in the + * experimental `SimpleRangeAnalysisExpr` module. + */ +module SimpleRangeAnalysisInternal { + /** + * Gets the truncated lower bounds of the fully converted expression. + */ + float getFullyConvertedLowerBounds(Expr expr) { + result = getTruncatedLowerBounds(expr.getFullyConverted()) + } + + /** + * Gets the truncated upper bounds of the fully converted expression. + */ + float getFullyConvertedUpperBounds(Expr expr) { + result = getTruncatedUpperBounds(expr.getFullyConverted()) + } + + /** + * Get the lower bounds for a `RangeSsaDefinition`. Most of the work is + * done by `getDefLowerBoundsImpl`, but this is where widening is applied + * to prevent the analysis from exploding due to a recursive definition. + */ + float getDefLowerBounds(RangeSsaDefinition def, StackVariable v) { + exists(float newLB, float truncatedLB | + newLB = getDefLowerBoundsImpl(def, v) and + if varMinVal(v) <= newLB and newLB <= varMaxVal(v) + then truncatedLB = newLB + else truncatedLB = varMinVal(v) + | + // Widening: check whether the new lower bound is from a source which + // depends recursively on the current definition. + if isRecursiveDef(def, v) + then + // The new lower bound is from a recursive source, so we round + // down to one of a limited set of values to prevent the + // recursion from exploding. + result = + max(float widenLB | + widenLB = wideningLowerBounds(getVariableRangeType(v)) and + not widenLB > truncatedLB + | + widenLB + ) + else result = truncatedLB + ) + or + // The definition might overflow positively and wrap. If so, the lower + // bound is `typeLowerBound`. + defMightOverflowPositively(def, v) and result = varMinVal(v) + } + + /** See comment for `getDefLowerBounds`, above. */ + float getDefUpperBounds(RangeSsaDefinition def, StackVariable v) { + exists(float newUB, float truncatedUB | + newUB = getDefUpperBoundsImpl(def, v) and + if varMinVal(v) <= newUB and newUB <= varMaxVal(v) + then truncatedUB = newUB + else truncatedUB = varMaxVal(v) + | + // Widening: check whether the new upper bound is from a source which + // depends recursively on the current definition. + if isRecursiveDef(def, v) + then + // The new upper bound is from a recursive source, so we round + // up to one of a fixed set of values to prevent the recursion + // from exploding. + result = + min(float widenUB | + widenUB = wideningUpperBounds(getVariableRangeType(v)) and + not widenUB < truncatedUB + | + widenUB + ) + else result = truncatedUB + ) + or + // The definition might overflow negatively and wrap. If so, the upper + // bound is `typeUpperBound`. + defMightOverflowNegatively(def, v) and result = varMaxVal(v) + } +} + +private import SimpleRangeAnalysisInternal diff --git a/cpp/ql/src/semmle/code/cpp/security/BufferWrite.qll b/cpp/ql/src/semmle/code/cpp/security/BufferWrite.qll index 4c53f34c9367..f06b0180c231 100644 --- a/cpp/ql/src/semmle/code/cpp/security/BufferWrite.qll +++ b/cpp/ql/src/semmle/code/cpp/security/BufferWrite.qll @@ -10,6 +10,7 @@ import semmle.code.cpp.commons.Alloc import semmle.code.cpp.commons.Buffer import semmle.code.cpp.commons.Scanf import semmle.code.cpp.models.implementations.Strcat +import semmle.code.cpp.models.implementations.Strcpy /* * --- BufferWrite framework --- @@ -106,68 +107,19 @@ abstract class BufferWriteCall extends BufferWrite, FunctionCall { } * A call to a variant of `strcpy`. */ class StrCopyBW extends BufferWriteCall { - StrCopyBW() { - exists(TopLevelFunction fn, string name | fn = getTarget() and name = fn.getName() | - // strcpy(dst, src) - name = "strcpy" - or - // wcscpy(dst, src) - name = "wcscpy" - or - // _mbscpy(dst, src) - name = "_mbscpy" - or - ( - name = "strcpy_s" or // strcpy_s(dst, max_amount, src) - name = "wcscpy_s" or // wcscpy_s(dst, max_amount, src) - name = "_mbscpy_s" // _mbscpy_s(dst, max_amount, src) - ) and - // exclude the 2-parameter template versions - // that find the size of a fixed size destination buffer. - fn.getNumberOfParameters() = 3 - or - // strncpy(dst, src, max_amount) - name = "strncpy" - or - // strncpy_l(dst, src, max_amount, locale) - name = "strncpy_l" - or - // wcsncpy(dst, src, max_amount) - name = "wcsncpy" - or - // _wcsncpy_l(dst, src, max_amount, locale) - name = "_wcsncpy_l" - or - // _mbsncpy(dst, src, max_amount) - name = "_mbsncpy" - or - // _mbsncpy_l(dst, src, max_amount, locale) - name = "_mbsncpy_l" - ) - } + StrcpyFunction f; - int getParamSize() { - exists(TopLevelFunction fn, string name | - fn = getTarget() and - name = fn.getName() and - ( - if name.suffix(name.length() - 2) = "_s" - then result = 1 - else - if exists(name.indexOf("ncpy")) - then result = 2 - else none() - ) - ) - } + StrCopyBW() { getTarget() = f.(TopLevelFunction) } - int getParamSrc() { - exists(TopLevelFunction fn, string name | - fn = getTarget() and - name = fn.getName() and - (if name.suffix(name.length() - 2) = "_s" then result = 2 else result = 1) - ) - } + /** + * Gets the index of the parameter that is the maximum size of the copy (in characters). + */ + int getParamSize() { result = f.getParamSize() } + + /** + * Gets the index of the parameter that is the source of the copy. + */ + int getParamSrc() { result = f.getParamSrc() } override Type getBufferType() { result = this.getTarget().getParameter(getParamSrc()).getUnspecifiedType() @@ -175,7 +127,7 @@ class StrCopyBW extends BufferWriteCall { override Expr getASource() { result = getArgument(getParamSrc()) } - override Expr getDest() { result = getArgument(0) } + override Expr getDest() { result = getArgument(f.getParamDest()) } override predicate hasExplicitLimit() { exists(getParamSize()) } @@ -192,11 +144,19 @@ class StrCopyBW extends BufferWriteCall { * A call to a variant of `strcat`. */ class StrCatBW extends BufferWriteCall { - StrCatBW() { exists(TopLevelFunction fn | fn = getTarget() and fn instanceof StrcatFunction) } + StrcatFunction f; + + StrCatBW() { getTarget() = f.(TopLevelFunction) } - int getParamSize() { if exists(getArgument(2)) then result = 2 else none() } + /** + * Gets the index of the parameter that is the maximum size of the copy (in characters). + */ + int getParamSize() { result = f.getParamSize() } - int getParamSrc() { result = 1 } + /** + * Gets the index of the parameter that is the source of the copy. + */ + int getParamSrc() { result = f.getParamSrc() } override Type getBufferType() { result = this.getTarget().getParameter(getParamSrc()).getUnspecifiedType() @@ -204,7 +164,7 @@ class StrCatBW extends BufferWriteCall { override Expr getASource() { result = getArgument(getParamSrc()) } - override Expr getDest() { result = getArgument(0) } + override Expr getDest() { result = getArgument(f.getParamDest()) } override predicate hasExplicitLimit() { exists(getParamSize()) } @@ -221,8 +181,10 @@ class StrCatBW extends BufferWriteCall { * A call to a variant of `sprintf`. */ class SprintfBW extends BufferWriteCall { + FormattingFunction f; + SprintfBW() { - exists(TopLevelFunction fn, string name | fn = getTarget() and name = fn.getName() | + exists(string name | f = getTarget().(TopLevelFunction) and name = f.getName() | /* * C sprintf variants: */ @@ -258,10 +220,7 @@ class SprintfBW extends BufferWriteCall { } override Type getBufferType() { - exists(FormattingFunction f | - f = this.getTarget() and - result = f.getParameter(f.getFormatParameterIndex()).getUnspecifiedType() - ) + result = f.getParameter(f.getFormatParameterIndex()).getUnspecifiedType() } override Expr getASource() { @@ -270,7 +229,7 @@ class SprintfBW extends BufferWriteCall { result = this.(FormattingFunctionCall).getFormatArgument(_) } - override Expr getDest() { result = getArgument(0) } + override Expr getDest() { result = getArgument(f.getOutputParameterIndex()) } override int getMaxData() { exists(FormatLiteral fl | @@ -349,6 +308,9 @@ class SnprintfBW extends BufferWriteCall { ) } + /** + * Gets the index of the parameter that is the size of the destination (in characters). + */ int getParamSize() { result = 1 } override Type getBufferType() { @@ -392,13 +354,15 @@ class SnprintfBW extends BufferWriteCall { */ class GetsBW extends BufferWriteCall { GetsBW() { - exists(TopLevelFunction fn, string name | fn = getTarget() and name = fn.getName() | - name = "gets" or // gets(dst) - name = "fgets" or // fgets(dst, max_amount, src_stream) - name = "fgetws" // fgetws(dst, max_amount, src_stream) - ) + getTarget().(TopLevelFunction).getName() = + ["gets", // gets(dst) + "fgets", // fgets(dst, max_amount, src_stream) + "fgetws"] // fgetws(dst, max_amount, src_stream) } + /** + * Gets the index of the parameter that is the maximum number of characters to be read. + */ int getParamSize() { if exists(getArgument(1)) then result = 1 else none() } override Type getBufferType() { result = this.getTarget().getParameter(0).getUnspecifiedType() } @@ -434,6 +398,9 @@ class ScanfBW extends BufferWrite { ) } + /** + * Gets the index of the parameter that is the first format argument. + */ int getParamArgs() { exists(FunctionCall fc | this = fc.getArgument(_) and diff --git a/cpp/ql/src/semmle/code/cpp/security/CommandExecution.qll b/cpp/ql/src/semmle/code/cpp/security/CommandExecution.qll index 48fb60442c15..5a24184e1a22 100644 --- a/cpp/ql/src/semmle/code/cpp/security/CommandExecution.qll +++ b/cpp/ql/src/semmle/code/cpp/security/CommandExecution.qll @@ -2,21 +2,44 @@ import cpp import semmle.code.cpp.security.FunctionWithWrappers +import semmle.code.cpp.models.interfaces.SideEffect /** * A function for running a command using a command interpreter. */ -class SystemFunction extends FunctionWithWrappers { +class SystemFunction extends FunctionWithWrappers, ArrayFunction, AliasFunction, SideEffectFunction { SystemFunction() { - hasGlobalOrStdName("system") or - hasGlobalName("popen") or + hasGlobalOrStdName("system") or // system(command) + hasGlobalName("popen") or // popen(command, mode) // Windows variants - hasGlobalName("_popen") or - hasGlobalName("_wpopen") or - hasGlobalName("_wsystem") + hasGlobalName("_popen") or // _popen(command, mode) + hasGlobalName("_wpopen") or // _wpopen(command, mode) + hasGlobalName("_wsystem") // _wsystem(command) } override predicate interestingArg(int arg) { arg = 0 } + + override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = 0 or bufParam = 1 } + + override predicate hasArrayInput(int bufParam) { bufParam = 0 or bufParam = 1 } + + override predicate parameterNeverEscapes(int index) { index = 0 or index = 1 } + + override predicate parameterEscapesOnlyViaReturn(int index) { none() } + + override predicate parameterIsAlwaysReturned(int index) { none() } + + override predicate hasOnlySpecificReadSideEffects() { any() } + + override predicate hasOnlySpecificWriteSideEffects() { + hasGlobalOrStdName("system") or + hasGlobalName("_wsystem") + } + + override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { + (i = 0 or i = 1) and + buffer = true + } } /** diff --git a/cpp/ql/src/semmle/code/cpp/security/Encryption.qll b/cpp/ql/src/semmle/code/cpp/security/Encryption.qll index 61d646733148..d8b2d44c923b 100644 --- a/cpp/ql/src/semmle/code/cpp/security/Encryption.qll +++ b/cpp/ql/src/semmle/code/cpp/security/Encryption.qll @@ -1,8 +1,13 @@ -// Common predicates relating to encryption in C and C++ +/** + * Provides predicates relating to encryption in C and C++. + */ + import cpp -/** A blacklist of algorithms that are known to be insecure */ -string algorithmBlacklist() { +/** + * Gets the name of an algorithm that is known to be insecure. + */ +string getAnInsecureAlgorithmName() { result = "DES" or result = "RC2" or result = "RC4" or @@ -10,29 +15,36 @@ string algorithmBlacklist() { result = "ARCFOUR" // a variant of RC4 } -// these are only bad if they're being used for encryption, and it's -// hard to know when that's happening -string hashAlgorithmBlacklist() { +/** + * Gets the name of a hash algorithm that is insecure if it is being used for + * encryption (but it is hard to know when that is happening). + */ +string getAnInsecureHashAlgorithmName() { result = "SHA1" or result = "MD5" } -/** A regex for matching strings that look like they contain a blacklisted algorithm */ -string algorithmBlacklistRegex() { +/** + * Gets the regular expression used for matching strings that look like they + * contain an algorithm that is known to be insecure. + */ +string getInsecureAlgorithmRegex() { result = // algorithms usually appear in names surrounded by characters that are not // alphabetical characters in the same case. This handles the upper and lower // case cases - "(^|.*[^A-Z])(" + strictconcat(algorithmBlacklist(), "|") + ")([^A-Z].*|$)" + "|" + + "(^|.*[^A-Z])(" + strictconcat(getAnInsecureAlgorithmName(), "|") + ")([^A-Z].*|$)" + "|" + // for lowercase, we want to be careful to avoid being confused by camelCase // hence we require two preceding uppercase letters to be sure of a case switch, // or a preceding non-alphabetic character - "(^|.*[A-Z]{2}|.*[^a-zA-Z])(" + strictconcat(algorithmBlacklist().toLowerCase(), "|") + + "(^|.*[A-Z]{2}|.*[^a-zA-Z])(" + strictconcat(getAnInsecureAlgorithmName().toLowerCase(), "|") + ")([^a-z].*|$)" } -/** A whitelist of algorithms that are known to be secure */ -string algorithmWhitelist() { +/** + * Gets the name of an algorithm that is known to be secure. + */ +string getASecureAlgorithmName() { result = "RSA" or result = "SHA256" or result = "CCM" or @@ -42,17 +54,47 @@ string algorithmWhitelist() { result = "ECIES" } -/** A regex for matching strings that look like they contain a whitelisted algorithm */ -string algorithmWhitelistRegex() { - // The implementation of this is a duplicate of algorithmBlacklistRegex, as it isn't - // possible to have string -> string functions at the moment - // algorithms usually appear in names surrounded by characters that are not - // alphabetical characters in the same case. This handles the upper and lower - // case cases - result = "(^|.*[^A-Z])" + algorithmWhitelist() + "([^A-Z].*|$)" - or - // for lowercase, we want to be careful to avoid being confused by camelCase - // hence we require two preceding uppercase letters to be sure of a case switch, - // or a preceding non-alphabetic character - result = "(^|.*[A-Z]{2}|.*[^a-zA-Z])" + algorithmWhitelist().toLowerCase() + "([^a-z].*|$)" +/** + * Gets a regular expression for matching strings that look like they + * contain an algorithm that is known to be secure. + */ +string getSecureAlgorithmRegex() { + result = + // algorithms usually appear in names surrounded by characters that are not + // alphabetical characters in the same case. This handles the upper and lower + // case cases + "(^|.*[^A-Z])(" + strictconcat(getASecureAlgorithmName(), "|") + ")([^A-Z].*|$)" + "|" + + // for lowercase, we want to be careful to avoid being confused by camelCase + // hence we require two preceding uppercase letters to be sure of a case + // switch, or a preceding non-alphabetic character + "(^|.*[A-Z]{2}|.*[^a-zA-Z])(" + strictconcat(getASecureAlgorithmName().toLowerCase(), "|") + + ")([^a-z].*|$)" } + +/** + * DEPRECATED: Terminology has been updated. Use `getAnInsecureAlgorithmName()` + * instead. + */ +deprecated string algorithmBlacklist() { result = getAnInsecureAlgorithmName() } + +/** + * DEPRECATED: Terminology has been updated. Use + * `getAnInsecureHashAlgorithmName()` instead. + */ +deprecated string hashAlgorithmBlacklist() { result = getAnInsecureHashAlgorithmName() } + +/** + * DEPRECATED: Terminology has been updated. Use `getInsecureAlgorithmRegex()` instead. + */ +deprecated string algorithmBlacklistRegex() { result = getInsecureAlgorithmRegex() } + +/** + * DEPRECATED: Terminology has been updated. Use `getASecureAlgorithmName()` + * instead. + */ +deprecated string algorithmWhitelist() { result = getASecureAlgorithmName() } + +/** + * DEPRECATED: Terminology has been updated. Use `getSecureAlgorithmRegex()` instead. + */ +deprecated string algorithmWhitelistRegex() { result = getSecureAlgorithmRegex() } diff --git a/cpp/ql/src/semmle/code/cpp/security/FileWrite.qll b/cpp/ql/src/semmle/code/cpp/security/FileWrite.qll index 219f3d0a75b7..9f63ce99c0b8 100644 --- a/cpp/ql/src/semmle/code/cpp/security/FileWrite.qll +++ b/cpp/ql/src/semmle/code/cpp/security/FileWrite.qll @@ -1,13 +1,23 @@ +/** + * Provides classes for modeling writing of data to files through various standard mechanisms such as `fprintf`, `fwrite` and `operator<<`. + */ + import cpp /** - * A function call that writes to a file + * A function call that writes to a file. */ class FileWrite extends Expr { FileWrite() { fileWrite(this, _, _) } + /** + * Gets a source expression of this write. + */ Expr getASource() { fileWrite(this, result, _) } + /** + * Gets the expression for the object being written to. + */ Expr getDest() { fileWrite(this, _, result) } } @@ -44,17 +54,17 @@ class BasicOStreamCall extends FunctionCall { */ abstract class ChainedOutputCall extends BasicOStreamCall { /** - * The source expression of this output. + * Gets the source expression of this output. */ abstract Expr getSource(); /** - * The immediate destination expression of this output. + * Gets the immediate destination expression of this output. */ abstract Expr getDest(); /** - * The destination at the far left-hand end of the output chain. + * Gets the destination at the far left-hand end of the output chain. */ Expr getEndDest() { // recurse into the destination @@ -108,14 +118,12 @@ class WriteFunctionCall extends ChainedOutputCall { } /** - * Whether the function call is a call to << that eventually starts at the given file stream. + * Whether the function call is a call to `operator<<` or a similar function, that eventually starts at the given file stream. */ private predicate fileStreamChain(ChainedOutputCall out, Expr source, Expr dest) { source = out.getSource() and dest = out.getEndDest() and - exists(string nme | nme = "basic_ofstream" or nme = "basic_fstream" | - dest.getUnderlyingType().(Class).getSimpleName() = nme - ) + dest.getUnderlyingType().(Class).getSimpleName() = ["basic_ofstream", "basic_fstream"] } /** @@ -129,15 +137,7 @@ private predicate fileWrite(Call write, Expr source, Expr dest) { // named functions name = "fwrite" and s = 0 and d = 3 or - ( - name = "fputs" or - name = "fputws" or - name = "fputc" or - name = "fputwc" or - name = "putc" or - name = "putwc" or - name = "putw" - ) and + name = ["fputs", "fputws", "fputc", "fputwc", "putc", "putwc", "putw"] and s = 0 and d = 1 ) diff --git a/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll b/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll index 23dda0ddb1e9..5451011b3511 100644 --- a/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll +++ b/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll @@ -1,3 +1,20 @@ +/** + * Provides predicates for identifying functions that wrap other functions, + * passing the same arguments from the outer call into the inner call. In the + * following example `MyMalloc` wraps a call to `malloc`, passing in the `size` + * parameter: + * ``` + * void *MyMalloc(size_t size) + * { + * void *ptr = malloc(size); + * + * // ... additional logic? + * + * return ptr; + * } + * ``` + */ + import cpp import PrintfLike private import TaintTracking @@ -152,6 +169,9 @@ abstract class FunctionWithWrappers extends Function { } } +/** + * A `printf`-like formatting function. + */ class PrintfLikeFunction extends FunctionWithWrappers { PrintfLikeFunction() { printfLikeFunction(this, _) } diff --git a/cpp/ql/src/semmle/code/cpp/security/OutputWrite.qll b/cpp/ql/src/semmle/code/cpp/security/OutputWrite.qll index 06abfdb454da..97635d92dbd3 100644 --- a/cpp/ql/src/semmle/code/cpp/security/OutputWrite.qll +++ b/cpp/ql/src/semmle/code/cpp/security/OutputWrite.qll @@ -1,12 +1,19 @@ +/** + * Provides classes for modeling output to standard output / standard error through various mechanisms such as `printf`, `puts` and `operator<<`. + */ + import cpp import FileWrite /** - * A function call that writes to standard output or standard error + * A function call that writes to standard output or standard error. */ class OutputWrite extends Expr { OutputWrite() { outputWrite(this, _) } + /** + * Gets a source expression for this output. + */ Expr getASource() { outputWrite(this, result) } } @@ -41,15 +48,12 @@ private predicate outputFile(Expr e) { name = e.(VariableAccess).getTarget().(GlobalVariable).toString() or name = e.findRootCause().(Macro).getName() ) and - ( - name = "stdout" or - name = "stderr" - ) + name = ["stdout", "stderr"] ) } /** - * is the function call a write to standard output or standard error from 'source' + * Holds if the function call is a write to standard output or standard error from 'source'. */ private predicate outputWrite(Expr write, Expr source) { exists(Function f, int arg | diff --git a/cpp/ql/src/semmle/code/cpp/security/Overflow.qll b/cpp/ql/src/semmle/code/cpp/security/Overflow.qll index 59993954cc8d..e7ad1c559e63 100644 --- a/cpp/ql/src/semmle/code/cpp/security/Overflow.qll +++ b/cpp/ql/src/semmle/code/cpp/security/Overflow.qll @@ -1,11 +1,14 @@ +/** + * Provides predicates for reasoning about when the value of an expression is + * guarded by an operation such as `<`, which confines its range. + */ + import cpp import semmle.code.cpp.controlflow.Dominance -/* - * Guarding +/** + * Holds if the value of `use` is guarded using `abs`. */ - -/** is the size of this use guarded using 'abs'? */ predicate guardedAbs(Operation e, Expr use) { exists(FunctionCall fc | fc.getTarget().getName() = "abs" | fc.getArgument(0).getAChild*() = use and @@ -13,7 +16,10 @@ predicate guardedAbs(Operation e, Expr use) { ) } -/** This is `BasicBlock.getNode`, restricted to `Stmt` for performance. */ +/** + * Gets the position of `stmt` in basic block `block` (this is a thin layer + * over `BasicBlock.getNode`, intended to improve performance). + */ pragma[noinline] private int getStmtIndexInBlock(BasicBlock block, Stmt stmt) { block.getNode(result) = stmt } @@ -30,7 +36,9 @@ private predicate stmtDominates(Stmt dominator, Stmt dominated) { bbStrictlyDominates(dominator.getBasicBlock(), dominated.getBasicBlock()) } -/** is the size of this use guarded to be less than something? */ +/** + * Holds if the value of `use` is guarded to be less than something. + */ pragma[nomagic] predicate guardedLesser(Operation e, Expr use) { exists(IfStmt c, RelationalOperation guard | @@ -54,7 +62,9 @@ predicate guardedLesser(Operation e, Expr use) { guardedAbs(e, use) } -/** is the size of this use guarded to be greater than something? */ +/** + * Holds if the value of `use` is guarded to be greater than something. + */ pragma[nomagic] predicate guardedGreater(Operation e, Expr use) { exists(IfStmt c, RelationalOperation guard | @@ -78,10 +88,14 @@ predicate guardedGreater(Operation e, Expr use) { guardedAbs(e, use) } -/** a use of a given variable */ +/** + * Gets a use of a given variable `v`. + */ VariableAccess varUse(LocalScopeVariable v) { result = v.getAnAccess() } -/** is e not guarded against overflow by use? */ +/** + * Holds if `e` is not guarded against overflow by `use`. + */ predicate missingGuardAgainstOverflow(Operation e, VariableAccess use) { use = e.getAnOperand() and exists(LocalScopeVariable v | use.getTarget() = v | @@ -100,7 +114,9 @@ predicate missingGuardAgainstOverflow(Operation e, VariableAccess use) { ) } -/** is e not guarded against underflow by use? */ +/** + * Holds if `e` is not guarded against underflow by `use`. + */ predicate missingGuardAgainstUnderflow(Operation e, VariableAccess use) { use = e.getAnOperand() and exists(LocalScopeVariable v | use.getTarget() = v | diff --git a/cpp/ql/src/semmle/code/cpp/security/PrintfLike.qll b/cpp/ql/src/semmle/code/cpp/security/PrintfLike.qll index 47d0ca3aa930..197a332aa1a7 100644 --- a/cpp/ql/src/semmle/code/cpp/security/PrintfLike.qll +++ b/cpp/ql/src/semmle/code/cpp/security/PrintfLike.qll @@ -1,6 +1,18 @@ +/** + * Provides a predicate for identifying formatting functions like `printf`. + * + * Consider using the newer model in + * `semmle.code.cpp.models.interfaces.FormattingFunction` directly instead of + * this library. + */ + import semmle.code.cpp.commons.Printf import external.ExternalArtifact +/** + * Holds if `func` is a `printf`-like formatting function and `formatArg` is + * the index of the format string argument. + */ predicate printfLikeFunction(Function func, int formatArg) { formatArg = func.(FormattingFunction).getFormatParameterIndex() and not func instanceof UserDefinedFormattingFunction diff --git a/cpp/ql/src/semmle/code/cpp/security/SecurityOptions.qll b/cpp/ql/src/semmle/code/cpp/security/SecurityOptions.qll index 8d35d80e613a..64babe419c36 100644 --- a/cpp/ql/src/semmle/code/cpp/security/SecurityOptions.qll +++ b/cpp/ql/src/semmle/code/cpp/security/SecurityOptions.qll @@ -1,4 +1,4 @@ -/* +/** * Security pack options. * * see https://semmle.com/wiki/display/SD/_Configuring+SecurityOptions+for+your+code+base @@ -9,6 +9,10 @@ import semmle.code.cpp.security.Security +/** + * This class overrides `SecurityOptions` and can be used to add project + * specific customization. + */ class CustomSecurityOptions extends SecurityOptions { override predicate sqlArgument(string function, int arg) { SecurityOptions.super.sqlArgument(function, arg) diff --git a/cpp/ql/src/semmle/code/cpp/security/SensitiveExprs.qll b/cpp/ql/src/semmle/code/cpp/security/SensitiveExprs.qll index 25d68fde7162..553cc98351cb 100644 --- a/cpp/ql/src/semmle/code/cpp/security/SensitiveExprs.qll +++ b/cpp/ql/src/semmle/code/cpp/security/SensitiveExprs.qll @@ -1,5 +1,14 @@ +/** + * Provides classes for heuristically identifying variables and functions that + * might contain or return a password or other sensitive information. + */ + import cpp +/** + * Holds if the name `s` suggests something might contain or return a password + * or other sensitive information. + */ bindingset[s] private predicate suspicious(string s) { ( @@ -16,14 +25,23 @@ private predicate suspicious(string s) { ) } +/** + * A variable that might contain a password or other sensitive information. + */ class SensitiveVariable extends Variable { SensitiveVariable() { suspicious(getName().toLowerCase()) } } +/** + * A function that might return a password or other sensitive information. + */ class SensitiveFunction extends Function { SensitiveFunction() { suspicious(getName().toLowerCase()) } } +/** + * An expression whose value might be a password or other sensitive information. + */ class SensitiveExpr extends Expr { SensitiveExpr() { this.(VariableAccess).getTarget() instanceof SensitiveVariable or diff --git a/cpp/ql/src/semmle/code/cpp/security/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/security/TaintTrackingImpl.qll index 06cf4c456ce1..4b206d984dc4 100644 --- a/cpp/ql/src/semmle/code/cpp/security/TaintTrackingImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/security/TaintTrackingImpl.qll @@ -252,11 +252,10 @@ private predicate insideFunctionValueMoveTo(Element src, Element dest) { copyValueBetweenArguments(c.getTarget(), sourceArg, destArg) and // Only consider copies from `printf`-like functions if the format is a string ( - exists(FormattingFunctionCall ffc, FormatLiteral format, string argFormat | + exists(FormattingFunctionCall ffc, FormatLiteral format | ffc = c and format = ffc.getFormat() and - format.getConversionChar(sourceArg - ffc.getTarget().getNumberOfParameters()) = argFormat and - (argFormat = "s" or argFormat = "S") + format.getConversionChar(sourceArg - ffc.getTarget().getNumberOfParameters()) = ["s", "S"] ) or not exists(FormatLiteral fl | fl = c.(FormattingFunctionCall).getFormat()) @@ -273,12 +272,12 @@ private predicate insideFunctionValueMoveTo(Element src, Element dest) { dest = c ) or - exists(FormattingFunctionCall formattingSend, int arg, FormatLiteral format, string argFormat | + exists(FormattingFunctionCall formattingSend, int arg, FormatLiteral format | dest = formattingSend and formattingSend.getArgument(arg) = src and format = formattingSend.getFormat() and - format.getConversionChar(arg - formattingSend.getTarget().getNumberOfParameters()) = argFormat and - (argFormat = "s" or argFormat = "S" or argFormat = "@") + format.getConversionChar(arg - formattingSend.getTarget().getNumberOfParameters()) = + ["s", "S", "@"] ) or // Expressions computed from tainted data are also tainted diff --git a/cpp/ql/src/semmle/code/cpp/stmts/Block.qll b/cpp/ql/src/semmle/code/cpp/stmts/Block.qll index 4f69f52caf40..3bebc660456f 100644 --- a/cpp/ql/src/semmle/code/cpp/stmts/Block.qll +++ b/cpp/ql/src/semmle/code/cpp/stmts/Block.qll @@ -1,3 +1,7 @@ +/** + * Provides a class to model C/C++ block statements, enclosed by `{` and `}`. + */ + import semmle.code.cpp.Element import semmle.code.cpp.stmts.Stmt @@ -13,8 +17,8 @@ import semmle.code.cpp.stmts.Stmt * } * ``` */ -class Block extends Stmt, @stmt_block { - override string getCanonicalQLClass() { result = "Block" } +class BlockStmt extends Stmt, @stmt_block { + override string getAPrimaryQlClass() { result = "BlockStmt" } /** * Gets a child declaration of this block. @@ -72,8 +76,8 @@ class Block extends Stmt, @stmt_block { * the result is the expression statement `a = b`. */ Stmt getLastStmtIn() { - if getLastStmt() instanceof Block - then result = getLastStmt().(Block).getLastStmtIn() + if getLastStmt() instanceof BlockStmt + then result = getLastStmt().(BlockStmt).getLastStmtIn() else result = getLastStmt() } @@ -122,3 +126,9 @@ class Block extends Stmt, @stmt_block { override predicate mayBeGloballyImpure() { this.getAStmt().mayBeGloballyImpure() } } + +/** + * DEPRECATED: This is now called `BlockStmt` to avoid confusion with + * `BasicBlock`. + */ +deprecated class Block = BlockStmt; diff --git a/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll b/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll index 1640bee0f35d..08840f2c5054 100644 --- a/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll +++ b/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll @@ -1,3 +1,7 @@ +/** + * Provides a hierarchy of classes for modeling C/C++ statements. + */ + import semmle.code.cpp.Element private import semmle.code.cpp.Enclosing private import semmle.code.cpp.internal.ResolveClass @@ -21,10 +25,10 @@ class Stmt extends StmtParent, @stmt { /** * Gets the nearest enclosing block of this statement in the source, if any. */ - Block getEnclosingBlock() { + BlockStmt getEnclosingBlock() { if - getParentStmt() instanceof Block and - not getParentStmt().(Block).getLocation() instanceof UnknownLocation + getParentStmt() instanceof BlockStmt and + not getParentStmt().(BlockStmt).getLocation() instanceof UnknownLocation then result = getParentStmt() else result = getParentStmt().getEnclosingBlock() } @@ -49,7 +53,7 @@ class Stmt extends StmtParent, @stmt { * to trace the flow of control instead. */ Stmt getFollowingStmt() { - exists(Block b, int i | + exists(BlockStmt b, int i | this = b.getStmt(i) and result = b.getStmt(i + 1) ) @@ -133,12 +137,14 @@ class Stmt extends StmtParent, @stmt { predicate isCompilerGenerated() { compgenerated(underlyingElement(this)) } } +private class TStmtParent = @stmt or @expr; + /** * An element that is the parent of a statement in the C/C++ AST. * * This is normally a statement, but may be a `StmtExpr`. */ -abstract class StmtParent extends ControlFlowNode { } +class StmtParent extends ControlFlowNode, TStmtParent { } /** * A C/C++ 'expression' statement. @@ -150,7 +156,7 @@ abstract class StmtParent extends ControlFlowNode { } * is an assignment expression inside an 'expression' statement. */ class ExprStmt extends Stmt, @stmt_expr { - override string getCanonicalQLClass() { result = "ExprStmt" } + override string getAPrimaryQlClass() { result = "ExprStmt" } /** * Gets the expression of this 'expression' statement. @@ -175,28 +181,32 @@ class ExprStmt extends Stmt, @stmt_expr { } } +private class TControlStructure = TConditionalStmt or TLoop; + /** * A C/C++ control structure, that is, either a conditional statement or * a loop. */ -abstract class ControlStructure extends Stmt { +class ControlStructure extends Stmt, TControlStructure { /** * Gets the controlling expression of this control structure. * * This is the condition of 'if' statements and loops, and the * switched expression for 'switch' statements. */ - abstract Expr getControllingExpr(); + Expr getControllingExpr() { none() } // overridden by subclasses /** Gets a child declaration of this scope. */ Declaration getADeclaration() { none() } } +private class TConditionalStmt = @stmt_if or @stmt_constexpr_if or @stmt_switch; + /** * A C/C++ conditional statement, that is, either an 'if' statement or a * 'switch' statement. */ -abstract class ConditionalStmt extends ControlStructure { } +class ConditionalStmt extends ControlStructure, TConditionalStmt { } /** * A C/C++ 'if' statement. For example, the `if` statement in the following @@ -208,7 +218,7 @@ abstract class ConditionalStmt extends ControlStructure { } * ``` */ class IfStmt extends ConditionalStmt, @stmt_if { - override string getCanonicalQLClass() { result = "IfStmt" } + override string getAPrimaryQlClass() { result = "IfStmt" } /** * Gets the condition expression of this 'if' statement. @@ -230,7 +240,7 @@ class IfStmt extends ConditionalStmt, @stmt_if { * ``` * if (b) { x = 1; } * ``` - * the result is the `Block` `{ x = 1; }`. + * the result is the `BlockStmt` `{ x = 1; }`. */ Stmt getThen() { if_then(underlyingElement(this), unresolveElement(result)) } @@ -241,7 +251,7 @@ class IfStmt extends ConditionalStmt, @stmt_if { * ``` * if (b) { x = 1; } else { x = 2; } * ``` - * the result is the `Block` `{ x = 2; }`, and for + * the result is the `BlockStmt` `{ x = 2; }`, and for * ``` * if (b) { x = 1; } * ``` @@ -294,7 +304,7 @@ class IfStmt extends ConditionalStmt, @stmt_if { * ``` */ class ConstexprIfStmt extends ConditionalStmt, @stmt_constexpr_if { - override string getCanonicalQLClass() { result = "ConstexprIfStmt" } + override string getAPrimaryQlClass() { result = "ConstexprIfStmt" } /** * Gets the condition expression of this 'constexpr if' statement. @@ -316,7 +326,7 @@ class ConstexprIfStmt extends ConditionalStmt, @stmt_constexpr_if { * ``` * if constexpr (b) { x = 1; } * ``` - * the result is the `Block` `{ x = 1; }`. + * the result is the `BlockStmt` `{ x = 1; }`. */ Stmt getThen() { constexpr_if_then(underlyingElement(this), unresolveElement(result)) } @@ -327,7 +337,7 @@ class ConstexprIfStmt extends ConditionalStmt, @stmt_constexpr_if { * ``` * if constexpr (b) { x = 1; } else { x = 2; } * ``` - * the result is the `Block` `{ x = 2; }`, and for + * the result is the `BlockStmt` `{ x = 2; }`, and for * ``` * if constexpr (b) { x = 1; } * ``` @@ -370,16 +380,18 @@ class ConstexprIfStmt extends ConditionalStmt, @stmt_constexpr_if { } } +private class TLoop = @stmt_while or @stmt_end_test_while or @stmt_range_based_for or @stmt_for; + /** * A C/C++ loop, that is, either a 'while' loop, a 'for' loop, or a * 'do' loop. */ -abstract class Loop extends ControlStructure { +class Loop extends ControlStructure, TLoop { /** Gets the condition expression of this loop. */ - abstract Expr getCondition(); + Expr getCondition() { none() } // overridden in subclasses /** Gets the body statement of this loop. */ - abstract Stmt getStmt(); + Stmt getStmt() { none() } // overridden in subclasses } /** @@ -393,7 +405,7 @@ abstract class Loop extends ControlStructure { * ``` */ class WhileStmt extends Loop, @stmt_while { - override string getCanonicalQLClass() { result = "WhileStmt" } + override string getAPrimaryQlClass() { result = "WhileStmt" } override Expr getCondition() { result = this.getChild(0) } @@ -457,8 +469,8 @@ class WhileStmt extends Loop, @stmt_while { /** * A C/C++ jump statement. */ -abstract class JumpStmt extends Stmt, @jump { - override string getCanonicalQLClass() { result = "JumpStmt" } +class JumpStmt extends Stmt, @jump { + override string getAPrimaryQlClass() { result = "JumpStmt" } /** Gets the target of this jump statement. */ Stmt getTarget() { jumpinfo(underlyingElement(this), _, unresolveElement(result)) } @@ -475,7 +487,7 @@ abstract class JumpStmt extends Stmt, @jump { * ``` */ class GotoStmt extends JumpStmt, @stmt_goto { - override string getCanonicalQLClass() { result = "GotoStmt" } + override string getAPrimaryQlClass() { result = "GotoStmt" } /** * Gets the name of the label this 'goto' statement refers to. @@ -570,7 +582,7 @@ class ComputedGotoStmt extends Stmt, @stmt_assigned_goto { * ``` */ class ContinueStmt extends JumpStmt, @stmt_continue { - override string getCanonicalQLClass() { result = "ContinueStmt" } + override string getAPrimaryQlClass() { result = "ContinueStmt" } override string toString() { result = "continue;" } @@ -602,7 +614,7 @@ private Stmt getEnclosingContinuable(Stmt s) { * ``` */ class BreakStmt extends JumpStmt, @stmt_break { - override string getCanonicalQLClass() { result = "BreakStmt" } + override string getAPrimaryQlClass() { result = "BreakStmt" } override string toString() { result = "break;" } @@ -635,7 +647,7 @@ private Stmt getEnclosingBreakable(Stmt s) { * ``` */ class LabelStmt extends Stmt, @stmt_label { - override string getCanonicalQLClass() { result = "LabelStmt" } + override string getAPrimaryQlClass() { result = "LabelStmt" } /** Gets the name of this 'label' statement. */ string getName() { jumpinfo(underlyingElement(this), result, _) and result != "" } @@ -650,6 +662,67 @@ class LabelStmt extends Stmt, @stmt_label { override predicate mayBeGloballyImpure() { none() } } +/** + * A C/C++ `co_return` statement. + * + * For example: + * ``` + * co_return 1+2; + * ``` + * or + * ``` + * co_return; + * ``` + */ +class CoReturnStmt extends Stmt, @stmt_co_return { + override string getAPrimaryQlClass() { result = "CoReturnStmt" } + + /** + * Gets the operand of this 'co_return' statement. + * + * For example, for + * ``` + * co_return 1+2; + * ``` + * the operand is a function call `return_value(1+2)`, and for + * ``` + * co_return; + * ``` + * the operand is a function call `return_void()`. + */ + FunctionCall getOperand() { result = this.getChild(0) } + + /** + * Gets the expression of this 'co_return' statement, if any. + * + * For example, for + * ``` + * co_return 1+2; + * ``` + * the result is `1+2`, and there is no result for + * ``` + * co_return; + * ``` + */ + Expr getExpr() { result = this.getOperand().getArgument(0) } + + /** + * Holds if this 'co_return' statement has an expression. + * + * For example, this holds for + * ``` + * co_return 1+2; + * ``` + * but not for + * ``` + * co_return; + * ``` + */ + predicate hasExpr() { exists(this.getExpr()) } + + override string toString() { result = "co_return ..." } +} + /** * A C/C++ 'return' statement. * @@ -663,7 +736,7 @@ class LabelStmt extends Stmt, @stmt_label { * ``` */ class ReturnStmt extends Stmt, @stmt_return { - override string getCanonicalQLClass() { result = "ReturnStmt" } + override string getAPrimaryQlClass() { result = "ReturnStmt" } /** * Gets the expression of this 'return' statement. @@ -711,7 +784,7 @@ class ReturnStmt extends Stmt, @stmt_return { * ``` */ class DoStmt extends Loop, @stmt_end_test_while { - override string getCanonicalQLClass() { result = "DoStmt" } + override string getAPrimaryQlClass() { result = "DoStmt" } override Expr getCondition() { result = this.getChild(0) } @@ -760,7 +833,7 @@ class DoStmt extends Loop, @stmt_end_test_while { * where `begin_expr` and `end_expr` depend on the type of `xs`. */ class RangeBasedForStmt extends Loop, @stmt_range_based_for { - override string getCanonicalQLClass() { result = "RangeBasedForStmt" } + override string getAPrimaryQlClass() { result = "RangeBasedForStmt" } /** * Gets the 'body' statement of this range-based 'for' statement. @@ -769,7 +842,7 @@ class RangeBasedForStmt extends Loop, @stmt_range_based_for { * ``` * for (int x : xs) { y += x; } * ``` - * the result is the `Block` `{ y += x; }`. + * the result is the `BlockStmt` `{ y += x; }`. */ override Stmt getStmt() { result = this.getChild(5) } @@ -847,7 +920,7 @@ class RangeBasedForStmt extends Loop, @stmt_range_based_for { * ``` */ class ForStmt extends Loop, @stmt_for { - override string getCanonicalQLClass() { result = "ForStmt" } + override string getAPrimaryQlClass() { result = "ForStmt" } /** * Gets the initialization statement of this 'for' statement. @@ -1078,7 +1151,7 @@ private predicate inForUpdate(Expr forUpdate, Expr child) { * ``` */ class SwitchCase extends Stmt, @stmt_switch_case { - override string getCanonicalQLClass() { result = "SwitchCase" } + override string getAPrimaryQlClass() { result = "SwitchCase" } /** * Gets the expression of this 'switch case' statement (or the start of @@ -1156,7 +1229,7 @@ class SwitchCase extends Stmt, @stmt_switch_case { * DEPRECATED: use `SwitchCase.getAStmt` or `ControlFlowNode.getASuccessor` * rather than this predicate. * - * Gets the `Block` statement immediately following this 'switch case' + * Gets the `BlockStmt` statement immediately following this 'switch case' * statement, if any. * * For example, for @@ -1177,7 +1250,7 @@ class SwitchCase extends Stmt, @stmt_switch_case { * the `case 7:` has result `{ x = 2; break; }`, `default:` has result * `{ x = 3; }`, and the others have no result. */ - deprecated Block getLabelledStmt() { + deprecated BlockStmt getLabelledStmt() { exists(int i, Stmt parent | this = parent.getChild(i) and result = parent.getChild(i + 1) @@ -1258,7 +1331,7 @@ class SwitchCase extends Stmt, @stmt_switch_case { * `default:` has results `{ x = 3; }, `x = 4;` and `break;`. */ Stmt getAStmt() { - exists(Block b, int i, int j | + exists(BlockStmt b, int i, int j | b.getStmt(i) = this and b.getStmt(j) = result and i < j and @@ -1297,8 +1370,8 @@ class SwitchCase extends Stmt, @stmt_switch_case { exists(Stmt lastStmt | lastStmt = this.getAStmt() and not lastStmt.getFollowingStmt() = this.getAStmt() and - if lastStmt instanceof Block - then result = lastStmt.(Block).getLastStmtIn() + if lastStmt instanceof BlockStmt + then result = lastStmt.(BlockStmt).getLastStmtIn() else result = lastStmt ) } @@ -1431,7 +1504,7 @@ class DefaultCase extends SwitchCase { * ``` */ class SwitchStmt extends ConditionalStmt, @stmt_switch { - override string getCanonicalQLClass() { result = "SwitchStmt" } + override string getAPrimaryQlClass() { result = "SwitchStmt" } /** * Gets the expression that this 'switch' statement switches on. @@ -1642,7 +1715,7 @@ class EnumSwitch extends SwitchStmt { class Handler extends Stmt, @stmt_handler { override string toString() { result = "" } - override string getCanonicalQLClass() { result = "Handler" } + override string getAPrimaryQlClass() { result = "Handler" } /** * Gets the block containing the implementation of this handler. @@ -1695,7 +1768,7 @@ deprecated class FinallyEnd extends Stmt { * ``` */ class TryStmt extends Stmt, @stmt_try_block { - override string getCanonicalQLClass() { result = "TryStmt" } + override string getAPrimaryQlClass() { result = "TryStmt" } override string toString() { result = "try { ... }" } @@ -1770,7 +1843,7 @@ class TryStmt extends Stmt, @stmt_try_block { class FunctionTryStmt extends TryStmt { FunctionTryStmt() { not exists(this.getEnclosingBlock()) } - override string getCanonicalQLClass() { result = "FunctionTryStmt" } + override string getAPrimaryQlClass() { result = "FunctionTryStmt" } } /** @@ -1786,8 +1859,8 @@ class FunctionTryStmt extends TryStmt { * } * ``` */ -class CatchBlock extends Block { - override string getCanonicalQLClass() { result = "CatchBlock" } +class CatchBlock extends BlockStmt { + override string getAPrimaryQlClass() { result = "CatchBlock" } CatchBlock() { ishandler(underlyingElement(this)) } @@ -1818,7 +1891,7 @@ class CatchBlock extends Block { class CatchAnyBlock extends CatchBlock { CatchAnyBlock() { not exists(this.getParameter()) } - override string getCanonicalQLClass() { result = "CatchAnyBlock" } + override string getAPrimaryQlClass() { result = "CatchAnyBlock" } } /** @@ -1852,10 +1925,10 @@ class MicrosoftTryExceptStmt extends MicrosoftTryStmt { /** Gets the expression guarding the `__except` statement. */ Expr getCondition() { result = getChild(1) } - /** Gets the `__except` statement (usually a `Block`). */ + /** Gets the `__except` statement (usually a `BlockStmt`). */ Stmt getExcept() { result = getChild(2) } - override string getCanonicalQLClass() { result = "MicrosoftTryExceptStmt" } + override string getAPrimaryQlClass() { result = "MicrosoftTryExceptStmt" } } /** @@ -1876,10 +1949,10 @@ class MicrosoftTryFinallyStmt extends MicrosoftTryStmt { override string toString() { result = "__try { ... } __finally { ... }" } - /** Gets the `__finally` statement (usually a `Block`). */ + /** Gets the `__finally` statement (usually a `BlockStmt`). */ Stmt getFinally() { result = getChild(1) } - override string getCanonicalQLClass() { result = "MicrosoftTryFinallyStmt" } + override string getAPrimaryQlClass() { result = "MicrosoftTryFinallyStmt" } } /** @@ -1891,7 +1964,7 @@ class MicrosoftTryFinallyStmt extends MicrosoftTryStmt { * ``` */ class DeclStmt extends Stmt, @stmt_decl { - override string getCanonicalQLClass() { result = "DeclStmt" } + override string getAPrimaryQlClass() { result = "DeclStmt" } /** * Gets the `i`th declaration entry declared by this 'declaration' statement. @@ -1972,7 +2045,7 @@ class DeclStmt extends Stmt, @stmt_decl { * ``` */ class EmptyStmt extends Stmt, @stmt_empty { - override string getCanonicalQLClass() { result = "EmptyStmt" } + override string getAPrimaryQlClass() { result = "EmptyStmt" } override string toString() { result = ";" } @@ -1992,7 +2065,7 @@ class EmptyStmt extends Stmt, @stmt_empty { class AsmStmt extends Stmt, @stmt_asm { override string toString() { result = "asm statement" } - override string getCanonicalQLClass() { result = "AsmStmt" } + override string getAPrimaryQlClass() { result = "AsmStmt" } } /** @@ -2009,7 +2082,7 @@ class AsmStmt extends Stmt, @stmt_asm { class VlaDimensionStmt extends Stmt, @stmt_set_vla_size { override string toString() { result = "VLA dimension size" } - override string getCanonicalQLClass() { result = "VlaDimensionStmt" } + override string getAPrimaryQlClass() { result = "VlaDimensionStmt" } /** Gets the expression which gives the size. */ Expr getDimensionExpr() { result = this.getChild(0) } @@ -2028,14 +2101,14 @@ class VlaDimensionStmt extends Stmt, @stmt_set_vla_size { class VlaDeclStmt extends Stmt, @stmt_vla_decl { override string toString() { result = "VLA declaration" } - override string getCanonicalQLClass() { result = "VlaDeclStmt" } + override string getAPrimaryQlClass() { result = "VlaDeclStmt" } /** * Gets the number of VLA dimension statements in this VLA * declaration statement. */ int getNumberOfVlaDimensionStmts() { - exists(Block b, int j | + exists(BlockStmt b, int j | this = b.getStmt(j) and result = j - 1 - @@ -2052,7 +2125,7 @@ class VlaDeclStmt extends Stmt, @stmt_vla_decl { */ VlaDimensionStmt getVlaDimensionStmt(int i) { i in [0 .. this.getNumberOfVlaDimensionStmts() - 1] and - exists(Block b, int j | + exists(BlockStmt b, int j | this = b.getStmt(j) and result = b.getStmt(j - this.getNumberOfVlaDimensionStmts() + i) ) diff --git a/cpp/ql/src/semmle/uml/MagicDraw.qll b/cpp/ql/src/semmle/uml/MagicDraw.qll index 3cd4701a05dd..cb8fb761c1f4 100644 --- a/cpp/ql/src/semmle/uml/MagicDraw.qll +++ b/cpp/ql/src/semmle/uml/MagicDraw.qll @@ -65,15 +65,8 @@ class UMLElement extends XMLElement { */ class UMLType extends UMLElement { UMLType() { - exists(string type | - this.getName() = "packagedElement" and - this.getAttribute("type").getValue() = type and - ( - type = "uml:Class" or - type = "uml:Interface" or - type = "uml:PrimitiveType" - ) - ) + this.getName() = "packagedElement" and + this.getAttribute("type").getValue() = ["uml:Class", "uml:Interface", "uml:PrimitiveType"] } /** diff --git a/cpp/ql/src/semmlecode.cpp.dbscheme b/cpp/ql/src/semmlecode.cpp.dbscheme index 282c13bfdbcb..ef73d8cf906d 100644 --- a/cpp/ql/src/semmlecode.cpp.dbscheme +++ b/cpp/ql/src/semmlecode.cpp.dbscheme @@ -414,13 +414,35 @@ 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( @@ -508,7 +530,8 @@ static_asserts( unique int id: @static_assert, int condition : @expr ref, string message : string ref, - int location: @location_default ref + int location: @location_default ref, + int enclosing : @element ref ); // each function has an ordered list of parameters @@ -1227,6 +1250,8 @@ funbind( | @builtinaddressof | @vec_fill | @un_log_op_expr + | @co_await + | @co_yield ; @bin_log_op_expr = @andlogicalexpr | @orlogicalexpr; @@ -1646,6 +1671,8 @@ case @expr.kind of | 324 = @builtinconvertvector | 325 = @builtincomplex | 326 = @spaceshipexpr +| 327 = @co_await +| 328 = @co_yield ; @var_args_expr = @vastartexpr @@ -1850,6 +1877,7 @@ case @stmt.kind of | 33 = @stmt_handler // ... 34 @stmt_finally_end deprecated | 35 = @stmt_constexpr_if +| 37 = @stmt_co_return ; type_vla( @@ -1934,20 +1962,6 @@ stmtparents( ishandler(unique int block: @stmt_block ref); @cfgnode = @stmt | @expr | @function | @initialiser ; -successors( - int from: @cfgnode ref, - int to: @cfgnode ref -); - -truecond( - unique int from: @cfgnode ref, - int to: @cfgnode ref -); - -falsecond( - unique int from: @cfgnode ref, - int to: @cfgnode ref -); stmt_decl_bind( int stmt: @stmt_decl ref, diff --git a/cpp/ql/src/semmlecode.cpp.dbscheme.stats b/cpp/ql/src/semmlecode.cpp.dbscheme.stats index 49f84494fd76..eb699cba62e0 100644 --- a/cpp/ql/src/semmlecode.cpp.dbscheme.stats +++ b/cpp/ql/src/semmlecode.cpp.dbscheme.stats @@ -1,7 +1,7 @@ @compilation -9550 +9552 @externalDataElement @@ -9,7 +9,7 @@ @duplication -185065 +185064 @similarity @@ -25,11 +25,11 @@ @location_default -8811984 +8813832 @location_stmt -2176425 +2176409 @location_expr @@ -37,67 +37,67 @@ @diagnostic -68684 +68699 @file -60011 +60023 @folder -10943 +10945 @macroinvocation -35573465 +35580051 @function -3467587 +3468314 @fun_decl -3539879 +3540621 @var_decl -5359112 +5360115 @type_decl -1331883 +1332162 @namespace_decl -136842 +136871 @using -291383 +291444 @static_assert -130659 +130658 @parameter -4627013 +4627983 @membervariable -305626 +305691 @globalvariable -301146 +301143 @localvariable -521220 +521215 @enumconstant -93840 +93839 @builtintype @@ -105,31 +105,31 @@ @derivedtype -4416924 +4463123 @decltype -46995 +47005 @usertype -4193074 +4193942 @mangledname -483588 +483689 @type_mention -1677549 +1677532 @routinetype -430397 +430487 @ptrtomember -12631 +12634 @specifier @@ -137,7 +137,7 @@ @gnuattribute -413730 +413727 @stdattribute @@ -145,7 +145,7 @@ @declspec -57828 +57827 @msattribute @@ -165,7 +165,7 @@ @attribute_arg_constant -146276 +146275 @attribute_arg_type @@ -173,19 +173,19 @@ @derivation -390188 +390270 @frienddecl -240297 +240347 @comment -1580009 +1580341 @namespace -7686 +7688 @specialnamequalifyingelement @@ -193,7 +193,7 @@ @namequalifier -1114421 +1114410 @value @@ -201,11 +201,11 @@ @initialiser -1664822 +1664806 @errorexpr -48706 +48716 @address_of @@ -213,15 +213,15 @@ @reference_to -1058087 +1057914 @indirect -294273 +294271 @ref_indirect -1253933 +1253867 @array_to_pointer @@ -229,7 +229,7 @@ @vacuous_destructor_call -5120 +5121 @assume @@ -237,7 +237,7 @@ @parexpr -2996467 +2996445 @arithnegexpr @@ -253,7 +253,7 @@ @notexpr -337996 +337994 @conjugation @@ -277,31 +277,31 @@ @preincrexpr -62511 +62524 @predecrexpr -24791 +24797 @conditionalexpr -154262 +154261 @addexpr -246479 +246477 @subexpr -134812 +134811 @mulexpr -140470 +140469 @divexpr -63655 +63654 @remexpr @@ -333,7 +333,7 @@ @paddexpr -87144 +87143 @psubexpr @@ -341,11 +341,11 @@ @pdiffexpr -25076 +25082 @lshiftexpr -350150 +350147 @rshiftexpr @@ -353,11 +353,11 @@ @andexpr -257685 +257683 @orexpr -143373 +143371 @xorexpr @@ -365,15 +365,15 @@ @eqexpr -212358 +212356 @neexpr -88347 +88346 @gtexpr -43882 +43881 @ltexpr @@ -385,7 +385,7 @@ @leexpr -213634 +213633 @minexpr @@ -397,7 +397,7 @@ @assignexpr -550955 +550951 @assignaddexpr @@ -409,7 +409,7 @@ @assignmulexpr -6907 +6909 @assigndivexpr @@ -449,19 +449,19 @@ @andlogicalexpr -130796 +130795 @orlogicalexpr -74562 +74561 @commaexpr -10734 +10726 @subscriptexpr -165978 +165977 @virtfunptrexpr @@ -469,7 +469,7 @@ @callexpr -226788 +226781 @vastartexpr @@ -477,7 +477,7 @@ @vaargexpr -986 +987 @vaendexpr @@ -489,27 +489,27 @@ @varaccess -5318255 +5318202 @thisaccess -1167122 +1167110 @new_expr -32127 +32134 @delete_expr -5964 +5966 @throw_expr -22313 +22318 @condition_decl -7028 +7008 @braced_init_list @@ -517,11 +517,11 @@ @type_id -4418 +4419 @runtime_sizeof -278886 +278884 @runtime_alignof @@ -533,11 +533,11 @@ @expr_stmt -156384 +156383 @routineexpr -2265935 +2265785 @type_operand @@ -661,15 +661,15 @@ @ctordirectinit -90175 +90194 @ctorvirtualinit -6228 +6229 @ctorfieldinit -196009 +196051 @ctordelegatinginit @@ -677,7 +677,7 @@ @dtordirectdestruct -29133 +29140 @dtorvirtualdestruct @@ -685,11 +685,11 @@ @dtorfielddestruct -29901 +29907 @static_cast -214716 +214761 @reinterpret_cast @@ -697,11 +697,11 @@ @const_cast -5307 +5308 @dynamic_cast -986 +987 @c_style_cast @@ -713,7 +713,7 @@ @param_ref -85877 +85895 @noopexpr @@ -817,7 +817,7 @@ @noexceptexpr -17522 +17525 @builtinshufflevector @@ -829,7 +829,7 @@ @builtinaddressof -3969 +3970 @vec_fill @@ -848,20 +848,28 @@ 1 +@co_await +6 + + +@co_yield +1 + + @lambdacapture -21653 +21652 @stmt_expr -1269739 +1269727 @stmt_if -523914 +523910 @stmt_while -30997 +30993 @stmt_goto @@ -873,23 +881,23 @@ @stmt_return -1130006 +1130211 @stmt_block -1324997 +1325121 @stmt_end_test_while -149714 +149713 @stmt_for -32154 +32153 @stmt_switch_case -271391 +271389 @stmt_switch @@ -897,11 +905,11 @@ @stmt_asm -241255 +241253 @stmt_try_block -17960 +17964 @stmt_microsoft_try @@ -909,7 +917,7 @@ @stmt_decl -613063 +613092 @stmt_set_vla_size @@ -925,7 +933,7 @@ @stmt_empty -102357 +102356 @stmt_continue @@ -933,7 +941,7 @@ @stmt_break -223843 +223842 @stmt_range_based_for @@ -948,40 +956,44 @@ 3 +@stmt_co_return +2 + + @ppd_if -156064 +156097 @ppd_ifdef -61074 +61087 @ppd_ifndef -83311 +83329 @ppd_elif -20625 +20629 @ppd_else -57653 +57665 @ppd_endif -300451 +300514 @ppd_plain_include -290703 +290764 @ppd_define -318006 +318073 @ppd_undef -19243 +19247 @ppd_line @@ -1038,11 +1050,11 @@ compilations -9550 +9552 id -9550 +9552 cwd @@ -1060,7 +1072,7 @@ 1 2 -9550 +9552 @@ -1086,7 +1098,7 @@ compilation_args -375671 +375669 id @@ -1098,7 +1110,7 @@ arg -18603 +18602 @@ -1382,11 +1394,11 @@ compilation_compiling_files -9550 +9552 id -9550 +9552 num @@ -1394,7 +1406,7 @@ file -4846 +4847 @@ -1408,7 +1420,7 @@ 1 2 -9550 +9552 @@ -1424,7 +1436,7 @@ 1 2 -9550 +9552 @@ -1477,7 +1489,7 @@ 2 3 -4550 +4551 3 @@ -1498,7 +1510,7 @@ 1 2 -4846 +4847 @@ -1508,11 +1520,11 @@ compilation_time -38114 +38122 id -9528 +9530 num @@ -1524,7 +1536,7 @@ seconds -12094 +12700 @@ -1538,7 +1550,7 @@ 1 2 -9528 +9530 @@ -1554,7 +1566,7 @@ 4 5 -9528 +9530 @@ -1570,17 +1582,17 @@ 2 3 -10 +21 3 4 -2675 +2599 4 5 -6842 +6909 @@ -1626,8 +1638,8 @@ 12 -1103 -1104 +1158 +1159 10 @@ -1684,13 +1696,13 @@ 10 -579 -580 +590 +591 10 -670 -671 +694 +695 10 @@ -1707,22 +1719,22 @@ 1 2 -7949 +8653 2 3 -2401 +2588 3 -4 -932 +5 +1074 -4 -627 -811 +5 +629 +383 @@ -1738,7 +1750,7 @@ 1 2 -12094 +12700 @@ -1754,17 +1766,17 @@ 1 2 -10285 +11131 2 3 -1798 +1535 3 4 -10 +32 @@ -1774,15 +1786,15 @@ diagnostic_for -846935 +847112 diagnostic -68684 +68699 compilation -9221 +9223 file_number @@ -1790,7 +1802,7 @@ file_number_diagnostic_number -6502 +6503 @@ -1804,12 +1816,12 @@ 1 2 -9254 +9256 2 3 -56732 +56744 254 @@ -1830,7 +1842,7 @@ 1 2 -68684 +68699 @@ -1846,7 +1858,7 @@ 1 2 -68684 +68699 @@ -1867,7 +1879,7 @@ 7 8 -5811 +5812 8 @@ -1903,7 +1915,7 @@ 1 2 -9221 +9223 @@ -1924,7 +1936,7 @@ 7 8 -5811 +5812 8 @@ -2008,7 +2020,7 @@ 1 2 -2675 +2676 2 @@ -2018,7 +2030,7 @@ 5 6 -953 +954 7 @@ -2069,7 +2081,7 @@ 10 11 -953 +954 14 @@ -2104,7 +2116,7 @@ 254 255 -2620 +2621 309 @@ -2125,7 +2137,7 @@ 1 2 -6502 +6503 @@ -2135,19 +2147,19 @@ compilation_finished -9550 +9552 id -9550 +9552 cpu_seconds -8157 +8093 elapsed_seconds -186 +219 @@ -2161,7 +2173,7 @@ 1 2 -9550 +9552 @@ -2177,7 +2189,7 @@ 1 2 -9550 +9552 @@ -2193,17 +2205,17 @@ 1 2 -7160 +6931 2 3 -756 +954 3 -6 -241 +7 +208 @@ -2219,12 +2231,12 @@ 1 2 -7675 +7764 2 3 -482 +329 @@ -2240,17 +2252,22 @@ 1 2 -32 +54 2 3 -10 +21 3 4 -32 +10 + + +5 +6 +10 7 @@ -2258,48 +2275,53 @@ 10 -8 -9 +9 +10 10 -21 -22 +11 +12 10 -26 -27 +17 +18 10 -31 -32 +41 +42 10 -104 -105 +46 +47 10 -137 -138 +47 +48 10 -144 -145 +86 +87 10 -173 -174 +157 +158 10 -206 -207 +183 +184 +10 + + +250 +251 10 @@ -2316,17 +2338,22 @@ 1 2 -32 +54 2 3 -10 +21 3 4 -32 +10 + + +5 +6 +10 7 @@ -2334,38 +2361,38 @@ 10 -8 -9 +9 +10 10 -21 -22 +11 +12 10 -25 -26 +17 +18 10 -29 -30 +40 +41 10 -84 -85 +44 +45 10 -122 -123 +46 +47 10 -132 -133 +73 +74 10 @@ -2374,8 +2401,13 @@ 10 -196 -197 +164 +165 +10 + + +190 +191 10 @@ -2624,11 +2656,11 @@ duplicateCode -185065 +185064 id -185065 +185064 relativePath @@ -2650,7 +2682,7 @@ 1 2 -185065 +185064 @@ -2666,7 +2698,7 @@ 1 2 -185065 +185064 @@ -3146,11 +3178,11 @@ tokens -39551856 +39551564 id -278635 +278633 offset @@ -3158,7 +3190,7 @@ beginLine -784463 +784457 beginColumn @@ -3166,7 +3198,7 @@ endLine -784463 +784457 endColumn @@ -3270,7 +3302,7 @@ 5 6 -109619 +109618 6 @@ -3285,7 +3317,7 @@ 8 12 -23598 +23597 12 @@ -3310,7 +3342,7 @@ 28 151 -14527 +14526 @@ -3341,7 +3373,7 @@ 32 33 -163370 +163368 33 @@ -3361,7 +3393,7 @@ 80 132 -2860 +2859 @@ -3382,7 +3414,7 @@ 5 6 -109619 +109618 6 @@ -3397,7 +3429,7 @@ 8 12 -23598 +23597 12 @@ -3422,7 +3454,7 @@ 28 151 -14527 +14526 @@ -3453,7 +3485,7 @@ 32 33 -163658 +163657 33 @@ -3819,12 +3851,12 @@ 1 2 -403450 +403447 2 3 -103003 +103002 3 @@ -3834,7 +3866,7 @@ 4 6 -70444 +70443 6 @@ -3844,7 +3876,7 @@ 8 13 -65884 +65883 13 @@ -3870,7 +3902,7 @@ 7 12 -64233 +64232 12 @@ -3885,17 +3917,17 @@ 32 33 -266937 +266935 33 41 -62613 +62612 41 55 -61281 +61280 55 @@ -3931,7 +3963,7 @@ 5 9 -62576 +62575 9 @@ -3951,7 +3983,7 @@ 32 33 -348865 +348862 33 @@ -3961,12 +3993,12 @@ 37 42 -61459 +61458 42 122 -53542 +53541 @@ -3982,7 +4014,7 @@ 1 2 -784463 +784457 @@ -4023,7 +4055,7 @@ 32 33 -349865 +349862 33 @@ -4038,7 +4070,7 @@ 43 123 -47190 +47189 @@ -4454,12 +4486,12 @@ 1 2 -403450 +403447 2 3 -103003 +103002 3 @@ -4469,7 +4501,7 @@ 4 6 -70444 +70443 6 @@ -4479,7 +4511,7 @@ 8 13 -65884 +65883 13 @@ -4505,7 +4537,7 @@ 7 12 -64233 +64232 12 @@ -4520,17 +4552,17 @@ 32 33 -266937 +266935 33 41 -62613 +62612 41 55 -61281 +61280 55 @@ -4561,7 +4593,7 @@ 1 2 -784463 +784457 @@ -4582,7 +4614,7 @@ 5 9 -62576 +62575 9 @@ -4602,7 +4634,7 @@ 32 33 -348865 +348862 33 @@ -4612,12 +4644,12 @@ 37 42 -61459 +61458 42 122 -53542 +53541 @@ -4658,7 +4690,7 @@ 32 33 -349865 +349862 33 @@ -4673,7 +4705,7 @@ 43 123 -47190 +47189 @@ -5279,11 +5311,11 @@ header_to_external_package -8530 +8532 fileid -8530 +8532 package @@ -5301,7 +5333,7 @@ 1 2 -8530 +8532 @@ -6570,31 +6602,31 @@ locations_default -8811984 +8813832 id -8811984 +8813832 container -70954 +70969 startLine -150604 +150635 startColumn -5460 +5461 endLine -150428 +150460 endColumn -10625 +10627 @@ -6608,7 +6640,7 @@ 1 2 -8811984 +8813832 @@ -6624,7 +6656,7 @@ 1 2 -8811984 +8813832 @@ -6640,7 +6672,7 @@ 1 2 -8811984 +8813832 @@ -6656,7 +6688,7 @@ 1 2 -8811984 +8813832 @@ -6672,7 +6704,7 @@ 1 2 -8811984 +8813832 @@ -6688,62 +6720,62 @@ 1 2 -11524 +11526 2 19 -6096 +6097 19 25 -5482 +5483 25 31 -5515 +5516 31 41 -5822 +5823 41 54 -5526 +5527 54 72 -5603 +5604 72 99 -5416 +5417 99 137 -5383 +5384 137 220 -5328 +5330 220 430 -5328 +5330 430 20913 -3925 +3926 @@ -6759,57 +6791,57 @@ 1 2 -11524 +11526 2 15 -6008 +6010 15 20 -6140 +6141 20 25 -5548 +5549 25 32 -6096 +6097 32 41 -5679 +5681 41 53 -5723 +5724 53 71 -5592 +5593 71 99 -5449 +5450 99 158 -5328 +5330 158 351 -5361 +5363 351 @@ -6830,57 +6862,57 @@ 1 2 -11524 +11526 2 4 -6008 +6010 4 8 -6546 +6547 8 11 -5394 +5395 11 14 -5778 +5779 14 18 -6250 +6251 18 23 -5756 +5757 23 29 -5833 +5834 29 37 -5690 +5692 37 50 -5668 +5670 50 78 -5383 +5384 78 @@ -6901,62 +6933,62 @@ 1 2 -11524 +11526 2 15 -5986 +5988 15 20 -6162 +6163 20 25 -5493 +5494 25 32 -6107 +6108 32 41 -5668 +5670 41 53 -5723 +5724 53 70 -5383 +5384 70 96 -5339 +5341 96 153 -5394 +5395 153 333 -5350 +5352 333 9356 -2817 +2818 @@ -6972,57 +7004,57 @@ 1 2 -11524 +11526 2 14 -5734 +5735 14 19 -6118 +6119 19 23 -5712 +5713 23 28 -6414 +6415 28 33 -5515 +5516 33 40 -5953 +5955 40 47 -5350 +5352 47 57 -5603 +5604 57 69 -5635 +5637 69 91 -5328 +5330 91 @@ -7043,52 +7075,52 @@ 1 2 -30844 +30850 2 3 -18026 +18030 3 4 -17949 +17953 4 5 -9714 +9717 5 7 -13706 +13709 7 9 -13410 +13412 9 13 -13201 +13204 13 32 -11568 +11570 32 127 -11304 +11307 127 6472 -10877 +10879 @@ -7104,42 +7136,42 @@ 1 2 -55647 +55658 2 3 -33432 +33439 3 4 -9901 +9903 4 5 -8432 +8433 5 8 -12905 +12908 8 27 -11491 +11493 27 123 -11337 +11340 123 6472 -7456 +7457 @@ -7155,52 +7187,52 @@ 1 2 -31951 +31958 2 3 -17861 +17865 3 4 -19791 +19795 4 5 -9583 +9585 5 7 -13914 +13917 7 9 -13826 +13829 9 13 -12708 +12711 13 27 -11480 +11482 27 62 -11348 +11351 62 153 -8136 +8137 @@ -7216,22 +7248,22 @@ 1 2 -112950 +112973 2 3 -17412 +17416 3 7 -12532 +12535 7 184 -7708 +7709 @@ -7247,52 +7279,52 @@ 1 2 -31798 +31805 2 3 -17774 +17777 3 4 -18640 +18644 4 5 -9868 +9870 5 7 -13728 +13731 7 9 -13772 +13774 9 13 -12730 +12733 13 29 -11655 +11658 29 74 -11348 +11351 74 258 -9287 +9289 @@ -7435,7 +7467,7 @@ 2 3 -997 +998 3 @@ -7501,7 +7533,7 @@ 2 3 -997 +998 3 @@ -7613,52 +7645,52 @@ 1 2 -30559 +30565 2 3 -18059 +18063 3 4 -17807 +17810 4 5 -9868 +9870 5 7 -13772 +13774 7 9 -13454 +13456 9 13 -13048 +13051 13 31 -11458 +11460 31 124 -11293 +11296 124 6472 -11107 +11109 @@ -7674,42 +7706,42 @@ 1 2 -55362 +55373 2 3 -33333 +33340 3 4 -9868 +9870 4 5 -8541 +8543 5 8 -13103 +13105 8 27 -11326 +11329 27 121 -11293 +11296 121 6472 -7598 +7600 @@ -7725,22 +7757,22 @@ 1 2 -112160 +112184 2 3 -17247 +17251 3 7 -12072 +12074 7 46 -8947 +8949 @@ -7756,57 +7788,57 @@ 1 2 -31644 +31651 2 3 -17938 +17942 3 4 -19736 +19741 4 5 -9605 +9607 5 6 -7861 +7863 6 7 -6129 +6130 7 9 -13837 +13840 9 13 -12708 +12711 13 27 -11491 +11493 27 62 -11348 +11351 62 153 -8125 +8126 @@ -7822,52 +7854,52 @@ 1 2 -31546 +31552 2 3 -17741 +17745 3 4 -18629 +18633 4 5 -9934 +9936 5 7 -13815 +13818 7 9 -13772 +13774 9 13 -12785 +12787 13 29 -11513 +11515 29 74 -11359 +11362 74 258 -9331 +9333 @@ -7883,7 +7915,7 @@ 1 2 -4210 +4211 2 @@ -7898,7 +7930,7 @@ 4 5 -646 +647 5 @@ -7939,17 +7971,17 @@ 1 2 -4835 +4836 2 3 -1282 +1283 3 4 -953 +954 4 @@ -7990,7 +8022,7 @@ 1 2 -4243 +4244 2 @@ -8005,7 +8037,7 @@ 4 5 -635 +636 5 @@ -8046,17 +8078,17 @@ 1 2 -4868 +4869 2 3 -1326 +1327 3 4 -942 +943 4 @@ -8097,7 +8129,7 @@ 1 2 -4243 +4244 2 @@ -8112,7 +8144,7 @@ 4 5 -635 +636 5 @@ -8147,19 +8179,19 @@ locations_stmt -2176425 +2176409 id -2176425 +2176409 container -3173 +3172 startLine -296354 +296351 startColumn @@ -8167,7 +8199,7 @@ endLine -294555 +294553 endColumn @@ -8185,7 +8217,7 @@ 1 2 -2176425 +2176409 @@ -8201,7 +8233,7 @@ 1 2 -2176425 +2176409 @@ -8217,7 +8249,7 @@ 1 2 -2176425 +2176409 @@ -8233,7 +8265,7 @@ 1 2 -2176425 +2176409 @@ -8249,7 +8281,7 @@ 1 2 -2176425 +2176409 @@ -8650,7 +8682,7 @@ 1 2 -113657 +113656 2 @@ -8660,7 +8692,7 @@ 3 4 -31282 +31281 4 @@ -8696,12 +8728,12 @@ 1 2 -175337 +175336 2 3 -51977 +51976 3 @@ -8737,7 +8769,7 @@ 1 2 -130651 +130650 2 @@ -8778,7 +8810,7 @@ 1 2 -191442 +191440 2 @@ -8814,7 +8846,7 @@ 1 2 -155827 +155826 2 @@ -8829,7 +8861,7 @@ 4 9 -24672 +24671 9 @@ -9255,7 +9287,7 @@ 6 16 -23107 +23106 16 @@ -9281,7 +9313,7 @@ 1 2 -175049 +175048 2 @@ -9317,7 +9349,7 @@ 1 2 -193725 +193723 2 @@ -9337,7 +9369,7 @@ 8 32 -14613 +14612 @@ -9353,22 +9385,22 @@ 1 2 -132812 +132811 2 3 -67971 +67970 3 4 -32442 +32441 4 7 -26685 +26684 7 @@ -9378,7 +9410,7 @@ 16 46 -12514 +12513 @@ -9394,7 +9426,7 @@ 1 2 -155722 +155721 2 @@ -11616,23 +11648,23 @@ numlines -499158 +499263 element_id -492196 +492299 num_lines -9342 +9344 num_code -7291 +7293 num_comment -3936 +3937 @@ -11646,12 +11678,12 @@ 1 2 -485310 +485411 2 7 -6886 +6887 @@ -11667,12 +11699,12 @@ 1 2 -485364 +485466 2 7 -6831 +6832 @@ -11688,7 +11720,7 @@ 1 2 -492119 +492222 2 @@ -11709,7 +11741,7 @@ 1 2 -4254 +4255 2 @@ -11760,12 +11792,12 @@ 1 2 -4320 +4321 2 3 -1260 +1261 3 @@ -11811,12 +11843,12 @@ 1 2 -4309 +4310 2 3 -1260 +1261 3 @@ -11857,7 +11889,7 @@ 1 2 -3179 +3180 2 @@ -11892,7 +11924,7 @@ 101 7978 -328 +329 @@ -11908,7 +11940,7 @@ 1 2 -3201 +3202 2 @@ -11918,7 +11950,7 @@ 3 4 -635 +636 4 @@ -11928,7 +11960,7 @@ 6 10 -635 +636 10 @@ -11959,7 +11991,7 @@ 1 2 -3190 +3191 2 @@ -11969,7 +12001,7 @@ 3 4 -635 +636 4 @@ -11994,7 +12026,7 @@ 27 34 -317 +318 @@ -12010,7 +12042,7 @@ 1 2 -1885 +1886 2 @@ -12025,12 +12057,12 @@ 4 7 -328 +329 7 13 -328 +329 14 @@ -12061,7 +12093,7 @@ 1 2 -1896 +1897 2 @@ -12081,7 +12113,7 @@ 7 13 -328 +329 13 @@ -12112,7 +12144,7 @@ 1 2 -1896 +1897 2 @@ -12127,7 +12159,7 @@ 4 7 -328 +329 7 @@ -12157,11 +12189,11 @@ diagnostics -68684 +68699 id -68684 +68699 severity @@ -12177,7 +12209,7 @@ full_error_message -59474 +59486 location @@ -12195,7 +12227,7 @@ 1 2 -68684 +68699 @@ -12211,7 +12243,7 @@ 1 2 -68684 +68699 @@ -12227,7 +12259,7 @@ 1 2 -68684 +68699 @@ -12243,7 +12275,7 @@ 1 2 -68684 +68699 @@ -12259,7 +12291,7 @@ 1 2 -68684 +68699 @@ -12675,7 +12707,7 @@ 1 2 -59463 +59475 841 @@ -12696,7 +12728,7 @@ 1 2 -59474 +59486 @@ -12712,7 +12744,7 @@ 1 2 -59474 +59486 @@ -12728,7 +12760,7 @@ 1 2 -59474 +59486 @@ -12744,7 +12776,7 @@ 1 2 -59474 +59486 @@ -12854,19 +12886,19 @@ files -60011 +60023 id -60011 +60023 name -60011 +60023 simple -41052 +41061 ext @@ -12888,7 +12920,7 @@ 1 2 -60011 +60023 @@ -12904,7 +12936,7 @@ 1 2 -60011 +60023 @@ -12920,7 +12952,7 @@ 1 2 -60011 +60023 @@ -12936,7 +12968,7 @@ 1 2 -60011 +60023 @@ -12952,7 +12984,7 @@ 1 2 -60011 +60023 @@ -12968,7 +13000,7 @@ 1 2 -60011 +60023 @@ -12984,7 +13016,7 @@ 1 2 -60011 +60023 @@ -13000,7 +13032,7 @@ 1 2 -60011 +60023 @@ -13016,17 +13048,17 @@ 1 2 -31173 +31179 2 3 -6195 +6196 3 7 -3234 +3235 7 @@ -13047,17 +13079,17 @@ 1 2 -31173 +31179 2 3 -6195 +6196 3 7 -3234 +3235 7 @@ -13078,12 +13110,12 @@ 1 2 -36699 +36707 2 3 -3782 +3783 3 @@ -13104,7 +13136,7 @@ 1 2 -41052 +41061 @@ -13362,19 +13394,19 @@ folders -10943 +10945 id -10943 +10945 name -10943 +10945 simple -3135 +3136 @@ -13388,7 +13420,7 @@ 1 2 -10943 +10945 @@ -13404,7 +13436,7 @@ 1 2 -10943 +10945 @@ -13420,7 +13452,7 @@ 1 2 -10943 +10945 @@ -13436,7 +13468,7 @@ 1 2 -10943 +10945 @@ -13457,7 +13489,7 @@ 2 3 -668 +669 3 @@ -13493,7 +13525,7 @@ 2 3 -668 +669 3 @@ -13518,15 +13550,15 @@ containerparent -70932 +70947 parent -10943 +10945 child -70932 +70947 @@ -13540,7 +13572,7 @@ 1 2 -4989 +4990 2 @@ -13591,7 +13623,7 @@ 1 2 -70932 +70947 @@ -13601,11 +13633,11 @@ fileannotations -5149615 +5150695 id -4824 +4825 kind @@ -13613,11 +13645,11 @@ name -54616 +54628 value -44638 +44647 @@ -13852,42 +13884,42 @@ 1 2 -8925 +8927 2 3 -6030 +6032 3 6 -4517 +4518 6 8 -4451 +4452 8 14 -4407 +4408 14 18 -3914 +3915 18 21 -4243 +4244 21 34 -4396 +4397 34 @@ -13897,12 +13929,12 @@ 129 236 -4155 +4156 236 395 -4111 +4112 395 @@ -13923,7 +13955,7 @@ 1 2 -54616 +54628 @@ -13939,12 +13971,12 @@ 1 2 -9978 +9980 2 3 -8048 +8049 3 @@ -13954,42 +13986,42 @@ 4 6 -3958 +3959 6 10 -4879 +4880 10 14 -3486 +3487 14 18 -4495 +4496 18 23 -4199 +4200 23 44 -4396 +4397 44 97 -4155 +4156 97 405 -4100 +4101 421 @@ -14010,7 +14042,7 @@ 1 2 -6896 +6898 2 @@ -14020,7 +14052,7 @@ 5 8 -3234 +3235 8 @@ -14040,22 +14072,22 @@ 25 40 -3234 +3235 40 195 -3519 +3520 195 207 -3508 +3509 207 273 -3662 +3663 273 @@ -14065,12 +14097,12 @@ 328 407 -3837 +3838 407 441 -1282 +1283 @@ -14086,7 +14118,7 @@ 1 2 -44627 +44636 2 @@ -14107,12 +14139,12 @@ 1 2 -6918 +6920 2 5 -2510 +2511 5 @@ -14122,12 +14154,12 @@ 8 16 -3497 +3498 16 18 -3015 +3016 18 @@ -14137,17 +14169,17 @@ 21 31 -3881 +3882 31 41 -3530 +3531 41 54 -3530 +3531 54 @@ -14177,15 +14209,15 @@ inmacroexpansion -60859049 +60858600 id -15688248 +15688133 inv -2531860 +2531842 @@ -14199,47 +14231,47 @@ 1 2 -3618172 +3618145 2 3 -2444422 +2444404 3 4 -1897977 +1897963 4 5 -1930674 +1930660 5 6 -1866536 +1866522 6 7 -968687 +968680 7 8 -1531676 +1531664 8 11 -1254555 +1254546 11 6193 -175545 +175544 @@ -14255,52 +14287,52 @@ 1 2 -616471 +616466 2 3 -369752 +369750 3 4 -160128 +160127 4 5 -256555 +256553 5 7 -183476 +183475 7 9 -150758 +150757 9 12 -221730 +221729 12 22 -202906 +202905 22 45 -191200 +191199 45 153127 -178879 +178878 @@ -14310,15 +14342,15 @@ affectedbymacroexpansion -35484840 +35484578 id -4079168 +4079138 inv -3279104 +3279080 @@ -14332,37 +14364,37 @@ 1 2 -1340494 +1340484 2 3 -718492 +718487 3 4 -682067 +682062 4 6 -320608 +320606 6 10 -313182 +313180 10 24 -307677 +307675 24 64 -309561 +309559 64 @@ -14383,72 +14415,72 @@ 1 2 -252913 +252912 2 3 -209805 +209803 3 4 -202323 +202322 4 5 -257768 +257766 5 6 -301208 +301206 6 7 -247568 +247566 7 8 -230831 +230830 8 9 -227720 +227718 9 10 -182291 +182290 10 12 -285325 +285323 12 16 -297059 +297057 16 23 -275039 +275036 23 60 -248654 +248652 60 526 -60594 +60593 @@ -14458,19 +14490,19 @@ macroinvocations -35573465 +35580051 id -35573465 +35580051 macro_id -81217 +81234 location -761079 +761238 kind @@ -14488,7 +14520,7 @@ 1 2 -35573465 +35580051 @@ -14504,7 +14536,7 @@ 1 2 -35573465 +35580051 @@ -14520,7 +14552,7 @@ 1 2 -35573465 +35580051 @@ -14536,52 +14568,52 @@ 1 2 -17017 +17021 2 3 -16557 +16560 3 4 -3574 +3575 4 6 -7193 +7194 6 11 -6896 +6898 11 19 -6173 +6174 19 40 -6173 +6174 40 105 -6195 +6196 105 487 -6107 +6108 488 196960 -5328 +5330 @@ -14597,32 +14629,32 @@ 1 2 -43212 +43222 2 3 -10745 +10747 3 4 -5339 +5341 4 6 -6973 +6975 6 13 -6721 +6722 13 66 -6107 +6108 66 @@ -14643,12 +14675,12 @@ 1 2 -75077 +75092 2 3 -6140 +6141 @@ -14664,42 +14696,42 @@ 1 2 -284332 +284425 2 3 -177479 +177483 3 4 -43443 +43452 4 5 -58585 +58598 5 8 -63563 +63577 8 17 -61151 +61164 17 80 -57149 +57161 80 258137 -15372 +15376 @@ -14715,12 +14747,12 @@ 1 2 -712383 +712533 2 354 -48695 +48705 @@ -14736,7 +14768,7 @@ 1 2 -761079 +761238 @@ -14755,8 +14787,8 @@ 10 -3216594 -3216595 +3216514 +3216515 10 @@ -14809,15 +14841,15 @@ macroparent -31697444 +31703249 id -31697444 +31703249 parent_id -24675437 +24680109 @@ -14831,7 +14863,7 @@ 1 2 -31697444 +31703249 @@ -14847,17 +14879,17 @@ 1 2 -18985994 +18989648 2 3 -4852266 +4853131 3 88 -837176 +837329 @@ -14867,15 +14899,15 @@ macrolocationbind -4013345 +4013316 id -2798451 +2798431 location -2003426 +2003411 @@ -14889,17 +14921,17 @@ 1 2 -2198274 +2198258 2 3 -338898 +338895 3 7 -231525 +231523 7 @@ -14920,17 +14952,17 @@ 1 2 -1601810 +1601798 2 3 -170839 +170837 3 8 -155317 +155316 8 @@ -14945,11 +14977,11 @@ macro_argument_unexpanded -92630091 +92648459 invocation -27414544 +27419703 argument_index @@ -14957,7 +14989,7 @@ text -312611 +312677 @@ -14971,22 +15003,22 @@ 1 2 -7655047 +7656521 2 3 -11464654 +11466609 3 4 -6260126 +6261428 4 67 -2034716 +2035143 @@ -15002,22 +15034,22 @@ 1 2 -7722986 +7724474 2 3 -11618525 +11620513 3 4 -6088743 +6090010 4 67 -1984288 +1984704 @@ -15033,7 +15065,7 @@ 50787 50788 -635 +636 50989 @@ -15041,8 +15073,8 @@ 54 -756485 -2500192 +756484 +2500138 32 @@ -15059,7 +15091,7 @@ 2 3 -635 +636 13 @@ -15085,57 +15117,57 @@ 1 2 -37894 +37902 2 3 -61118 +61164 3 4 -14089 +14092 4 5 -42138 +42136 5 8 -25296 +25290 8 12 -15120 +15112 12 16 -21765 +21781 16 21 -23936 +23941 21 41 -24967 +24972 41 121 -23794 +23788 121 567376 -22489 +22493 @@ -15151,17 +15183,17 @@ 1 2 -226021 +226068 2 3 -76294 +76310 3 9 -10296 +10298 @@ -15171,11 +15203,11 @@ macro_argument_expanded -92630091 +92648459 invocation -27414544 +27419703 argument_index @@ -15183,7 +15215,7 @@ text -189409 +189448 @@ -15197,22 +15229,22 @@ 1 2 -7655047 +7656521 2 3 -11464654 +11466609 3 4 -6260126 +6261428 4 67 -2034716 +2035143 @@ -15228,22 +15260,22 @@ 1 2 -11162952 +11165031 2 3 -9892725 +9894482 3 4 -5268749 +5269844 4 9 -1090116 +1090345 @@ -15259,7 +15291,7 @@ 50787 50788 -635 +636 50989 @@ -15267,8 +15299,8 @@ 54 -756485 -2500192 +756484 +2500138 32 @@ -15311,22 +15343,22 @@ 1 2 -22861 +22866 2 3 -38180 +38220 3 4 -6239 +6240 4 5 -15186 +15178 5 @@ -15336,37 +15368,37 @@ 6 7 -22039 +22033 7 9 -15471 +15463 9 15 -16480 +16494 15 28 -14254 +14257 28 77 -14331 +14323 77 337 -14320 +14323 338 -1133308 -7291 +1133296 +7293 @@ -15382,17 +15414,17 @@ 1 2 -95614 +95634 2 3 -79474 +79490 3 6 -14243 +14246 6 @@ -15407,15 +15439,15 @@ functions -3467587 +3468314 id -3467587 +3468314 name -288335 +288395 kind @@ -15433,7 +15465,7 @@ 1 2 -3467587 +3468314 @@ -15449,7 +15481,7 @@ 1 2 -3467587 +3468314 @@ -15465,27 +15497,27 @@ 1 2 -195363 +195404 2 3 -28311 +28317 3 5 -26074 +26080 5 13 -22160 +22164 13 123517 -16425 +16428 @@ -15501,7 +15533,7 @@ 1 2 -286876 +286936 2 @@ -15608,15 +15640,15 @@ function_entry_point -1008372 +1008551 id -1005444 +1005633 entry_point -1008372 +1008551 @@ -15630,12 +15662,12 @@ 1 2 -1002791 +1002990 2 9 -2653 +2643 @@ -15651,7 +15683,7 @@ 1 2 -1008372 +1008551 @@ -15661,15 +15693,15 @@ function_return_type -3477751 +3478481 id -3467115 +3467843 return_type -1023372 +1023587 @@ -15683,12 +15715,12 @@ 1 2 -3456973 +3457698 2 6 -10142 +10144 @@ -15704,17 +15736,329 @@ 1 2 -299102 +299165 2 3 -662569 +662708 3 84263 -61699 +61712 + + + + + + + + +coroutine +2 + + +function +2 + + +traits +2 + + +handle +2 + + +promise +2 + + + + +function +traits + + +12 + + +1 +2 +2 + + + + + + +function +handle + + +12 + + +1 +2 +2 + + + + + + +function +promise + + +12 + + +1 +2 +2 + + + + + + +traits +function + + +12 + + +1 +2 +2 + + + + + + +traits +handle + + +12 + + +1 +2 +2 + + + + + + +traits +promise + + +12 + + +1 +2 +2 + + + + + + +handle +function + + +12 + + +1 +2 +2 + + + + + + +handle +traits + + +12 + + +1 +2 +2 + + + + + + +handle +promise + + +12 + + +1 +2 +2 + + + + + + +promise +function + + +12 + + +1 +2 +2 + + + + + + +promise +traits + + +12 + + +1 +2 +2 + + + + + + +promise +handle + + +12 + + +1 +2 +2 + + + + + + + + +coroutine_new +2 + + +function +2 + + +new +1 + + + + +function +new + + +12 + + +1 +2 +2 + + + + + + +new +function + + +12 + + +2 +3 +1 + + + + + + + + +coroutine_delete +2 + + +function +2 + + +delete +1 + + + + +function +delete + + +12 + + +1 +2 +2 + + + + + + +delete +function + + +12 + + +2 +3 +1 @@ -15735,49 +16079,127 @@ function_deleted -56173 +56185 id -56173 +56185 function_defaulted -12927 +12930 id -12927 +12930 +member_function_this_type +523358 + + +id +523358 + + +this_type +171374 + + + + +id +this_type + + +12 + + +1 +2 +523358 + + + + + + +this_type +id + + +12 + + +1 +2 +62546 + + +2 +3 +44560 + + +3 +4 +22296 + + +4 +5 +15014 + + +5 +7 +13687 + + +7 +36 +12875 + + +40 +87 +394 + + + + + + + + fun_decls -3543146 +3543890 id -3539879 +3540621 function -3374154 +3374862 type_id -1010302 +1010514 name -256788 +256842 location -795290 +795456 @@ -15791,7 +16213,7 @@ 1 2 -3539879 +3540621 @@ -15807,12 +16229,12 @@ 1 2 -3536896 +3537638 2 4 -2982 +2983 @@ -15828,7 +16250,7 @@ 1 2 -3539879 +3540621 @@ -15844,7 +16266,7 @@ 1 2 -3539879 +3540621 @@ -15860,12 +16282,12 @@ 1 2 -3238156 +3238835 2 9 -135998 +136027 @@ -15881,12 +16303,12 @@ 1 2 -3357498 +3358203 2 6 -16655 +16659 @@ -15902,7 +16324,7 @@ 1 2 -3374154 +3374862 @@ -15918,12 +16340,12 @@ 1 2 -3286533 +3287222 2 9 -87621 +87639 @@ -15939,17 +16361,17 @@ 1 2 -280275 +280334 2 3 -660947 +661085 3 89606 -69079 +69093 @@ -15965,17 +16387,17 @@ 1 2 -292107 +292168 2 3 -657295 +657433 3 83378 -60899 +60912 @@ -15991,12 +16413,12 @@ 1 2 -943777 +943975 2 7512 -66524 +66538 @@ -16012,17 +16434,17 @@ 1 2 -912922 +913113 2 6 -80132 +80148 6 22467 -17247 +17251 @@ -16038,32 +16460,32 @@ 1 2 -153520 +153552 2 3 -29298 +29304 3 4 -15932 +15935 4 6 -19517 +19521 6 13 -20197 +20201 13 123766 -18322 +18326 @@ -16079,32 +16501,32 @@ 1 2 -164145 +164180 2 3 -28476 +28482 3 4 -14451 +14454 4 7 -21633 +21638 7 25 -19638 +19642 25 123501 -8443 +8444 @@ -16120,17 +16542,17 @@ 1 2 -224288 +224335 2 5 -20866 +20870 5 63265 -11633 +11636 @@ -16146,27 +16568,27 @@ 1 2 -164639 +164673 2 3 -43454 +43463 3 4 -16436 +16439 4 8 -20570 +20574 8 8921 -11688 +11691 @@ -16182,27 +16604,27 @@ 1 2 -522656 +522766 2 3 -143860 +143890 3 5 -64846 +64860 5 125 -59682 +59694 125 3043 -4243 +4244 @@ -16218,22 +16640,22 @@ 1 2 -537580 +537692 2 3 -156821 +156854 3 9 -64331 +64345 9 3043 -36557 +36564 @@ -16249,17 +16671,17 @@ 1 2 -701660 +701807 2 4 -61776 +61789 4 1522 -31853 +31859 @@ -16275,12 +16697,12 @@ 1 2 -770289 +770451 2 134 -25000 +25005 @@ -16290,11 +16712,11 @@ fun_def -1230544 +1230803 id -1230544 +1230803 @@ -16323,11 +16745,11 @@ fun_decl_specifiers -485338 +485334 id -260688 +260686 name @@ -16345,12 +16767,12 @@ 1 2 -69263 +69262 2 3 -158200 +158199 3 @@ -16517,26 +16939,26 @@ fun_decl_empty_throws -1420688 +1420986 fun_decl -1420688 +1420986 fun_decl_noexcept -32905 +32912 fun_decl -32116 +32123 constant -32785 +32792 @@ -16550,7 +16972,7 @@ 1 2 -31326 +31333 2 @@ -16571,7 +16993,7 @@ 1 2 -32664 +32671 2 @@ -16586,11 +17008,11 @@ fun_decl_empty_noexcept -391877 +391959 fun_decl -391877 +391959 @@ -16645,11 +17067,11 @@ param_decl_bind -4650555 +4651530 id -4650555 +4651530 index @@ -16657,7 +17079,7 @@ fun_decl -3071115 +3071759 @@ -16671,7 +17093,7 @@ 1 2 -4650555 +4651530 @@ -16687,7 +17109,7 @@ 1 2 -4650555 +4651530 @@ -16785,22 +17207,22 @@ 1 2 -2194827 +2195287 2 3 -478478 +478579 3 4 -242665 +242716 4 65 -155143 +155176 @@ -16816,22 +17238,22 @@ 1 2 -2194827 +2195287 2 3 -478478 +478579 3 4 -242665 +242716 4 65 -155143 +155176 @@ -16841,27 +17263,27 @@ var_decls -5367960 +5368966 id -5359112 +5360115 variable -5131248 +5132204 type_id -2007358 +2007769 name -126283 +126310 location -1232189 +1232448 @@ -16875,7 +17297,7 @@ 1 2 -5359112 +5360115 @@ -16891,12 +17313,12 @@ 1 2 -5350449 +5351451 2 4 -8662 +8664 @@ -16912,7 +17334,7 @@ 1 2 -5359112 +5360115 @@ -16928,7 +17350,7 @@ 1 2 -5359068 +5360071 2 @@ -16949,12 +17371,12 @@ 1 2 -4943758 +4944675 2 9 -187490 +187529 @@ -16970,12 +17392,12 @@ 1 2 -5095886 +5096835 2 7 -35362 +35369 @@ -16991,12 +17413,12 @@ 1 2 -5113682 +5114635 2 3 -17565 +17569 @@ -17012,12 +17434,12 @@ 1 2 -5023057 +5023990 2 9 -108191 +108214 @@ -17033,22 +17455,22 @@ 1 2 -1580525 +1580878 2 3 -228861 +228876 3 11 -156941 +156974 11 5924 -41030 +41039 @@ -17064,22 +17486,22 @@ 1 2 -1604713 +1605072 2 3 -219628 +219641 3 13 -151108 +151129 13 5424 -31908 +31925 @@ -17095,17 +17517,17 @@ 1 2 -1832533 +1832906 2 5 -151218 +151238 5 772 -23607 +23623 @@ -17121,17 +17543,17 @@ 1 2 -1758157 +1758515 2 4 -154441 +154496 4 3608 -94759 +94757 @@ -17147,42 +17569,42 @@ 1 2 -52083 +52160 2 3 -19276 +19236 3 4 -10910 +10890 4 5 -7686 +7688 5 8 -10515 +10517 8 15 -9506 +9508 15 47 -9528 +9530 47 165630 -6776 +6777 @@ -17198,37 +17620,37 @@ 1 2 -54901 +54978 2 3 -18826 +18786 3 4 -11809 +11789 4 6 -11195 +11197 6 11 -10734 +10736 11 27 -9484 +9486 27 164602 -9331 +9333 @@ -17244,32 +17666,32 @@ 1 2 -76294 +76321 2 3 -16886 +16878 3 4 -8848 +8861 4 7 -10482 +10473 7 27 -9517 +9519 27 125807 -4254 +4255 @@ -17285,32 +17707,32 @@ 1 2 -72807 +72822 2 3 -19024 +19028 3 4 -6973 +6975 4 7 -11184 +11186 7 21 -9747 +9749 21 10073 -6546 +6547 @@ -17326,22 +17748,22 @@ 1 2 -892231 +892506 2 3 -149123 +149067 3 6 -113388 +113423 6 128450 -77445 +77450 @@ -17357,22 +17779,22 @@ 1 2 -940981 +941266 2 3 -114551 +114487 3 6 -102632 +102664 6 128224 -74024 +74029 @@ -17388,17 +17810,17 @@ 1 2 -1055160 +1055403 2 3 -85099 +85095 3 118388 -91930 +91949 @@ -17414,12 +17836,12 @@ 1 2 -1223220 +1223476 2 52 -8969 +8971 @@ -17429,11 +17851,11 @@ var_def -2437164 +2437554 id -2437164 +2437554 @@ -17503,19 +17925,19 @@ type_decls -1331883 +1332162 id -1331883 +1332162 type_id -1300139 +1300412 location -1086618 +1086846 @@ -17529,7 +17951,7 @@ 1 2 -1331883 +1332162 @@ -17545,7 +17967,7 @@ 1 2 -1331883 +1332162 @@ -17561,12 +17983,12 @@ 1 2 -1277047 +1277315 2 24 -23092 +23097 @@ -17582,12 +18004,12 @@ 1 2 -1278341 +1278609 2 24 -21798 +21802 @@ -17603,12 +18025,12 @@ 1 2 -1031168 +1031384 2 506 -55449 +55461 @@ -17624,12 +18046,12 @@ 1 2 -1032648 +1032865 2 506 -53969 +53980 @@ -17639,45 +18061,45 @@ type_def -937549 +937746 id -937549 +937746 type_decl_top -268642 +268698 type_decl -268642 +268698 namespace_decls -136842 +136871 id -136842 +136871 namespace_id -7675 +7677 location -122226 +122252 bodylocation -122555 +122581 @@ -17691,7 +18113,7 @@ 1 2 -136842 +136871 @@ -17707,7 +18129,7 @@ 1 2 -136842 +136871 @@ -17723,7 +18145,7 @@ 1 2 -136842 +136871 @@ -17739,7 +18161,7 @@ 1 2 -3618 +3619 2 @@ -17754,7 +18176,7 @@ 4 7 -646 +647 7 @@ -17790,7 +18212,7 @@ 1 2 -3618 +3619 2 @@ -17805,7 +18227,7 @@ 4 7 -646 +647 7 @@ -17841,7 +18263,7 @@ 1 2 -3618 +3619 2 @@ -17856,7 +18278,7 @@ 4 7 -646 +647 7 @@ -17892,12 +18314,12 @@ 1 2 -113849 +113873 2 8 -8377 +8379 @@ -17913,12 +18335,12 @@ 1 2 -113849 +113873 2 8 -8377 +8379 @@ -17934,7 +18356,7 @@ 1 2 -121481 +121506 2 @@ -17955,12 +18377,12 @@ 1 2 -114540 +114564 2 11 -8015 +8017 @@ -17976,12 +18398,12 @@ 1 2 -114540 +114564 2 9 -8015 +8017 @@ -17997,7 +18419,7 @@ 1 2 -122160 +122186 2 @@ -18012,19 +18434,19 @@ usings -291383 +291444 id -291383 +291444 element_id -46392 +46402 location -23859 +23864 @@ -18038,7 +18460,7 @@ 1 2 -291383 +291444 @@ -18054,7 +18476,7 @@ 1 2 -291383 +291444 @@ -18070,7 +18492,7 @@ 1 2 -39386 +39394 2 @@ -18080,7 +18502,7 @@ 4 127 -3256 +3257 @@ -18096,7 +18518,7 @@ 1 2 -39386 +39394 2 @@ -18106,7 +18528,7 @@ 4 127 -3256 +3257 @@ -18122,12 +18544,12 @@ 1 2 -18059 +18063 2 3 -2236 +2237 3 @@ -18153,12 +18575,12 @@ 1 2 -18059 +18063 2 3 -2236 +2237 3 @@ -18178,15 +18600,15 @@ using_container -458007 +458103 parent -11228 +11230 child -291383 +291444 @@ -18200,12 +18622,12 @@ 1 2 -3212 +3213 2 4 -942 +943 4 @@ -18230,7 +18652,7 @@ 178 179 -1260 +1261 179 @@ -18256,17 +18678,17 @@ 1 2 -215812 +215858 2 3 -50362 +50372 3 11 -23136 +23140 13 @@ -18281,15 +18703,15 @@ static_asserts -130659 +130658 id -130659 +130658 condition -130659 +130658 message @@ -18299,6 +18721,10 @@ location 16721 + +enclosing +1724 + @@ -18311,7 +18737,7 @@ 1 2 -130659 +130658 @@ -18327,7 +18753,7 @@ 1 2 -130659 +130658 @@ -18343,7 +18769,23 @@ 1 2 -130659 +130658 + + + + + + +id +enclosing + + +12 + + +1 +2 +130658 @@ -18359,7 +18801,7 @@ 1 2 -130659 +130658 @@ -18375,7 +18817,7 @@ 1 2 -130659 +130658 @@ -18391,7 +18833,23 @@ 1 2 -130659 +130658 + + + + + + +condition +enclosing + + +12 + + +1 +2 +130658 @@ -18489,7 +18947,7 @@ 1 2 -27554 +27553 2 @@ -18501,6 +18959,42 @@ +message +enclosing + + +12 + + +1 +2 +23513 + + +2 +3 +182 + + +3 +4 +2654 + + +4 +11 +1301 + + +12 +21 +2055 + + + + + + location id @@ -18643,19 +19137,209 @@ + +location +enclosing + + +12 + + +1 +2 +3441 + + +2 +3 +6193 + + +3 +4 +1125 + + +4 +5 +3715 + + +5 +6 +188 + + +13 +14 +2036 + + +16 +21 +19 + + + + + + +enclosing +id + + +12 + + +1 +2 +1171 + + +2 +3 +130 + + +3 +7 +136 + + +9 +108 +136 + + +170 +347 +130 + + +348 +10697 +19 + + + + + + +enclosing +condition + + +12 + + +1 +2 +1171 + + +2 +3 +130 + + +3 +7 +136 + + +9 +108 +136 + + +170 +347 +130 + + +348 +10697 +19 + + + + + + +enclosing +message + + +12 + + +1 +2 +1327 + + +2 +5 +136 + + +5 +180 +130 + + +211 +2870 +130 + + + + + + +enclosing +location + + +12 + + +1 +2 +1314 + + +2 +5 +149 + + +5 +180 +130 + + +211 +1886 +130 + + + + + params -4644074 +4645049 id -4627013 +4627983 function -3043297 +3043935 index @@ -18663,7 +19347,7 @@ type_id -1856458 +1856848 @@ -18677,12 +19361,12 @@ 1 2 -4626344 +4627314 2 69 -668 +669 @@ -18698,7 +19382,7 @@ 1 2 -4627013 +4627983 @@ -18714,12 +19398,12 @@ 1 2 -4611969 +4612936 2 4 -15043 +15047 @@ -18735,22 +19419,22 @@ 1 2 -2166219 +2166673 2 3 -475024 +475124 3 4 -244409 +244460 4 65 -157643 +157676 @@ -18766,22 +19450,22 @@ 1 2 -2166219 +2166673 2 3 -475024 +475124 3 4 -244409 +244460 4 65 -157643 +157676 @@ -18797,22 +19481,22 @@ 1 2 -2282777 +2283256 2 3 -470880 +470978 3 5 -254277 +254331 5 20 -35362 +35369 @@ -18951,22 +19635,22 @@ 1 2 -1504450 +1504765 2 3 -186678 +186717 3 14 -139463 +139492 14 5175 -25866 +25871 @@ -18982,22 +19666,22 @@ 1 2 -1524307 +1524627 2 3 -179814 +179852 3 23 -139693 +139723 23 4690 -12642 +12645 @@ -19013,12 +19697,12 @@ 1 2 -1744791 +1745157 2 65 -111667 +111690 @@ -19028,11 +19712,11 @@ overrides -159059 +159058 new -124550 +124549 old @@ -19050,7 +19734,7 @@ 1 2 -90047 +90046 2 @@ -19116,19 +19800,19 @@ membervariables -310243 +310308 id -305626 +305691 type_id -132895 +132923 name -53213 +53224 @@ -19142,12 +19826,12 @@ 1 2 -301164 +301227 2 7 -4462 +4463 @@ -19163,7 +19847,7 @@ 1 2 -305626 +305691 @@ -19179,22 +19863,22 @@ 1 2 -108048 +108071 2 3 -12269 +12272 3 9 -10054 +10056 9 1712 -2521 +2522 @@ -19210,17 +19894,17 @@ 1 2 -115099 +115123 2 3 -9089 +9091 3 266 -8706 +8708 @@ -19236,32 +19920,32 @@ 1 2 -28092 +28098 2 3 -8168 +8170 3 4 -5372 +5373 4 6 -4013 +4014 6 15 -4089 +4090 15 1967 -3475 +3476 @@ -19277,12 +19961,12 @@ 1 2 -34287 +34294 2 3 -6853 +6854 3 @@ -19292,12 +19976,12 @@ 4 7 -4298 +4299 7 242 -3991 +3992 262 @@ -19312,11 +19996,11 @@ globalvariables -301154 +301151 id -301146 +301143 type_id @@ -19338,7 +20022,7 @@ 1 2 -301138 +301135 2 @@ -19359,7 +20043,7 @@ 1 2 -301146 +301143 @@ -19447,12 +20131,12 @@ 1 2 -291380 +291383 2 33 -3766 +3763 @@ -19468,12 +20152,12 @@ 1 2 -294542 +294545 2 12 -604 +601 @@ -19483,11 +20167,11 @@ localvariables -521298 +521293 id -521220 +521215 type_id @@ -19495,7 +20179,7 @@ name -75239 +75238 @@ -19509,7 +20193,7 @@ 1 2 -521142 +521137 2 @@ -19530,7 +20214,7 @@ 1 2 -521220 +521215 @@ -19546,12 +20230,12 @@ 1 2 -26474 +26473 2 3 -6760 +6759 3 @@ -19592,7 +20276,7 @@ 1 2 -35700 +35699 2 @@ -19623,12 +20307,12 @@ 1 2 -42961 +42960 2 3 -12915 +12914 3 @@ -19638,12 +20322,12 @@ 4 7 -6721 +6720 7 31 -5706 +5705 31 @@ -19752,11 +20436,11 @@ enumconstants -93840 +93839 id -93840 +93839 parent @@ -19772,11 +20456,11 @@ name -72903 +72902 location -75870 +75869 @@ -19790,7 +20474,7 @@ 1 2 -93840 +93839 @@ -19806,7 +20490,7 @@ 1 2 -93840 +93839 @@ -19822,7 +20506,7 @@ 1 2 -93840 +93839 @@ -19838,7 +20522,7 @@ 1 2 -93840 +93839 @@ -19854,7 +20538,7 @@ 1 2 -93840 +93839 @@ -20620,7 +21304,7 @@ 1 2 -65544 +65543 2 @@ -20651,7 +21335,7 @@ 2 3 -6194 +6193 3 @@ -20672,7 +21356,7 @@ 1 2 -67880 +67879 2 @@ -20693,7 +21377,7 @@ 1 2 -61146 +61145 2 @@ -20740,7 +21424,7 @@ 1 2 -70580 +70579 2 @@ -20761,12 +21445,12 @@ 1 2 -70691 +70690 2 229 -5179 +5178 @@ -20782,7 +21466,7 @@ 1 2 -72272 +72271 2 @@ -21556,15 +22240,15 @@ derivedtypes -4416924 +4463123 id -4416924 +4463123 name -2172217 +2202887 kind @@ -21572,7 +22256,7 @@ type_id -2605685 +2610563 @@ -21586,7 +22270,7 @@ 1 2 -4416924 +4463123 @@ -21602,7 +22286,7 @@ 1 2 -4416924 +4463123 @@ -21618,7 +22302,7 @@ 1 2 -4416924 +4463123 @@ -21634,17 +22318,17 @@ 1 2 -1570229 +1593501 2 3 -487437 +493889 3 45177 -114551 +115496 @@ -21660,7 +22344,7 @@ 1 2 -2172184 +2202855 2 @@ -21681,17 +22365,17 @@ 1 2 -1570470 +1593743 2 3 -487206 +493659 3 45159 -114540 +115485 @@ -21720,8 +22404,8 @@ 10 -27116 -27117 +31133 +31134 10 @@ -21735,8 +22419,8 @@ 10 -96890 -96891 +97001 +97002 10 @@ -21776,8 +22460,8 @@ 10 -14760 -14761 +17432 +17433 10 @@ -21786,8 +22470,8 @@ 10 -48258 -48259 +48341 +48342 10 @@ -21822,8 +22506,8 @@ 10 -27116 -27117 +31133 +31134 10 @@ -21837,8 +22521,8 @@ 10 -96559 -96560 +96670 +96671 10 @@ -21860,22 +22544,22 @@ 1 2 -1545963 +1541056 2 3 -372633 +369487 3 4 -633753 +628085 4 202 -53333 +71934 @@ -21891,22 +22575,22 @@ 1 2 -1547180 +1542273 2 3 -372480 +369334 3 4 -632690 +627021 4 198 -53333 +71934 @@ -21922,22 +22606,22 @@ 1 2 -1547498 +1542591 2 3 -373763 +370617 3 4 -632646 +626977 4 7 -51776 +70377 @@ -21947,11 +22631,11 @@ pointerishsize -3331139 +3375893 id -3331139 +3375893 size @@ -21973,7 +22657,7 @@ 1 2 -3331139 +3375893 @@ -21989,7 +22673,7 @@ 1 2 -3331139 +3375893 @@ -22008,8 +22692,8 @@ 10 -303777 -303778 +307794 +307795 10 @@ -22040,8 +22724,8 @@ 12 -303798 -303799 +307815 +307816 10 @@ -22068,11 +22752,11 @@ arraysizes -17193 +17196 id -17193 +17196 num_elements @@ -22080,7 +22764,7 @@ bytesize -2510 +2511 alignment @@ -22098,7 +22782,7 @@ 1 2 -17193 +17196 @@ -22114,7 +22798,7 @@ 1 2 -17193 +17196 @@ -22130,7 +22814,7 @@ 1 2 -17193 +17196 @@ -22151,7 +22835,7 @@ 2 3 -1271 +1272 3 @@ -22192,7 +22876,7 @@ 1 2 -1589 +1590 2 @@ -22228,7 +22912,7 @@ 1 2 -1589 +1590 2 @@ -22315,7 +22999,7 @@ 1 2 -1907 +1908 2 @@ -22346,7 +23030,7 @@ 1 2 -1951 +1952 2 @@ -22504,15 +23188,15 @@ typedefbase -1819320 +1819702 id -1819320 +1819702 type_id -847209 +847375 @@ -22526,7 +23210,7 @@ 1 2 -1819320 +1819702 @@ -22542,22 +23226,22 @@ 1 2 -656517 +656643 2 3 -87895 +87913 3 6 -69583 +69598 6 5503 -33212 +33219 @@ -22567,19 +23251,19 @@ decltypes -46995 +47005 id -46995 +47005 expr -43432 +43441 base_type -8629 +8631 parentheses_would_change_meaning @@ -22597,7 +23281,7 @@ 1 2 -46995 +47005 @@ -22613,7 +23297,7 @@ 1 2 -46995 +47005 @@ -22629,7 +23313,7 @@ 1 2 -46995 +47005 @@ -22645,12 +23329,12 @@ 1 2 -40153 +40162 2 4 -3278 +3279 @@ -22666,12 +23350,12 @@ 1 2 -40153 +40162 2 4 -3278 +3279 @@ -22687,7 +23371,7 @@ 1 2 -43432 +43441 @@ -22703,12 +23387,12 @@ 1 2 -5822 +5823 2 3 -2521 +2522 3 @@ -22729,12 +23413,12 @@ 1 2 -2313 +2314 2 3 -5701 +5702 3 @@ -22755,7 +23439,7 @@ 1 2 -8629 +8631 @@ -22828,15 +23512,15 @@ usertypes -4193074 +4193942 id -4193074 +4193942 name -879226 +879411 kind @@ -22854,7 +23538,7 @@ 1 2 -4193074 +4193942 @@ -22870,7 +23554,7 @@ 1 2 -4193074 +4193942 @@ -22886,22 +23570,22 @@ 1 2 -577350 +577471 2 3 -194759 +194800 3 7 -69298 +69313 7 32744 -37818 +37826 @@ -22917,12 +23601,12 @@ 1 2 -826595 +826768 2 10 -52631 +52642 @@ -22981,8 +23665,8 @@ 10 -95210 -95211 +95209 +95210 10 @@ -23059,11 +23743,11 @@ usertypesize -1386324 +1386604 id -1386324 +1386604 size @@ -23085,7 +23769,7 @@ 1 2 -1386324 +1386604 @@ -23101,7 +23785,7 @@ 1 2 -1386324 +1386604 @@ -23161,7 +23845,7 @@ 284 -99381 +99380 109 @@ -23237,8 +23921,8 @@ 10 -113882 -113883 +113881 +113882 10 @@ -23354,15 +24038,15 @@ mangled_name -4189795 +4190663 id -4189795 +4190663 mangled_name -483588 +483689 @@ -23376,7 +24060,7 @@ 1 2 -4189795 +4190663 @@ -23392,32 +24076,32 @@ 1 2 -292030 +292091 2 3 -62281 +62294 3 4 -33333 +33340 4 7 -36962 +36970 7 24 -37061 +37069 24 8580 -21918 +21923 @@ -23427,59 +24111,59 @@ is_pod_class -589104 +589228 id -589104 +589228 is_standard_layout_class -1158976 +1159208 id -1158976 +1159208 is_complete -1364822 +1365097 id -1364822 +1365097 is_class_template -225308 +225355 id -225308 +225355 class_instantiation -1157583 +1157815 to -1156015 +1156247 from -68015 +68030 @@ -23493,7 +24177,7 @@ 1 2 -1154535 +1154766 2 @@ -23514,47 +24198,47 @@ 1 2 -19956 +19960 2 3 -11995 +11998 3 4 -6853 +6854 4 5 -4616 +4617 5 7 -5635 +5637 7 11 -6052 +6053 11 20 -5197 +5198 20 84 -5109 +5110 84 4845 -2598 +2599 @@ -23564,11 +24248,11 @@ class_template_argument -3035457 +3036083 type_id -1392563 +1392844 index @@ -23576,7 +24260,7 @@ arg_type -860750 +860931 @@ -23590,27 +24274,27 @@ 1 2 -567010 +567118 2 3 -433654 +433744 3 4 -244935 +244987 4 7 -122785 +122811 7 113 -24177 +24182 @@ -23626,22 +24310,22 @@ 1 2 -593238 +593351 2 3 -445879 +445973 3 4 -258389 +258443 4 113 -95055 +95075 @@ -23686,7 +24370,7 @@ 13712 -123926 +123925 43 @@ -23749,27 +24433,27 @@ 1 2 -522185 +522294 2 3 -187402 +187441 3 4 -56699 +56711 4 11 -67379 +67393 11 -11852 -27083 +11851 +27089 @@ -23785,17 +24469,17 @@ 1 2 -746320 +746476 2 3 -95526 +95546 3 22 -18903 +18907 @@ -23805,11 +24489,11 @@ class_template_argument_value -345736 +345798 type_id -223806 +223842 index @@ -23817,7 +24501,7 @@ arg_value -328181 +328239 @@ -23831,17 +24515,17 @@ 1 2 -201448 +201479 2 3 -13706 +13709 3 14 -8651 +8653 @@ -23857,17 +24541,17 @@ 1 2 -189825 +189854 2 3 -16918 +16922 3 37 -16787 +16790 44 @@ -23931,8 +24615,8 @@ 10 -9813 -9814 +9812 +9813 10 @@ -23992,8 +24676,8 @@ 10 -12053 -12054 +12052 +12053 10 @@ -24010,12 +24694,12 @@ 1 2 -310944 +310999 2 4 -17236 +17240 @@ -24031,7 +24715,7 @@ 1 2 -328181 +328239 @@ -24041,15 +24725,15 @@ is_proxy_class_for -46370 +46380 id -46370 +46380 templ_param_id -46370 +46380 @@ -24063,7 +24747,7 @@ 1 2 -46370 +46380 @@ -24079,7 +24763,7 @@ 1 2 -46370 +46380 @@ -24089,19 +24773,19 @@ type_mentions -1677549 +1677532 id -1677549 +1677532 type_id -67210 +67209 location -1647041 +1647024 kind @@ -24119,7 +24803,7 @@ 1 2 -1677549 +1677532 @@ -24135,7 +24819,7 @@ 1 2 -1677549 +1677532 @@ -24151,7 +24835,7 @@ 1 2 -1677549 +1677532 @@ -24167,7 +24851,7 @@ 1 2 -30072 +30071 2 @@ -24177,7 +24861,7 @@ 3 4 -3637 +3636 4 @@ -24192,7 +24876,7 @@ 13 35 -5192 +5191 35 @@ -24213,7 +24897,7 @@ 1 2 -30072 +30071 2 @@ -24223,7 +24907,7 @@ 3 4 -3637 +3636 4 @@ -24238,7 +24922,7 @@ 13 35 -5192 +5191 35 @@ -24259,7 +24943,7 @@ 1 2 -65967 +65966 2 @@ -24280,7 +24964,7 @@ 1 2 -1616871 +1616855 2 @@ -24301,7 +24985,7 @@ 1 2 -1616871 +1616855 2 @@ -24322,7 +25006,7 @@ 1 2 -1647041 +1647024 @@ -24395,26 +25079,26 @@ is_function_template -983580 +983786 id -983580 +983786 function_instantiation -708184 +708332 to -708184 +708332 from -129310 +129337 @@ -24428,7 +25112,7 @@ 1 2 -708184 +708332 @@ -24444,37 +25128,37 @@ 1 2 -60998 +61010 2 3 -30833 +30839 3 4 -7346 +7348 4 5 -8815 +8817 5 10 -10000 +10002 10 71 -9704 +9706 71 653 -1611 +1612 @@ -24484,11 +25168,11 @@ function_template_argument -1910187 +1910587 function_id -1054173 +1054394 index @@ -24496,7 +25180,7 @@ arg_type -338390 +338461 @@ -24510,22 +25194,22 @@ 1 2 -583479 +583601 2 3 -290955 +291016 3 4 -127742 +127768 4 21 -51995 +52006 @@ -24541,22 +25225,22 @@ 1 2 -597898 +598023 2 3 -288642 +288702 3 4 -110921 +110945 4 21 -56710 +56722 @@ -24794,27 +25478,27 @@ 1 2 -226086 +226134 2 3 -45109 +45119 3 6 -27664 +27670 6 19 -25603 +25608 19 2030 -13925 +13928 @@ -24830,12 +25514,12 @@ 1 2 -314771 +314837 2 12 -23618 +23623 @@ -24845,11 +25529,11 @@ function_template_argument_value -198027 +198069 function_id -107062 +107084 index @@ -24857,7 +25541,7 @@ arg_value -170571 +170607 @@ -24871,12 +25555,12 @@ 1 2 -101546 +101567 2 14 -5515 +5516 @@ -24892,17 +25576,17 @@ 1 2 -84945 +84963 2 3 -16173 +16176 3 113 -5943 +5944 @@ -25030,12 +25714,12 @@ 1 2 -143619 +143649 2 3 -26447 +26453 3 @@ -25056,7 +25740,7 @@ 1 2 -170571 +170607 @@ -25066,26 +25750,26 @@ is_variable_template -17807 +17810 id -17807 +17810 variable_instantiation -35800 +35808 to -35800 +35808 from -6469 +6470 @@ -25099,7 +25783,7 @@ 1 2 -35800 +35808 @@ -25115,12 +25799,12 @@ 1 2 -2236 +2237 2 3 -1907 +1908 3 @@ -25507,15 +26191,15 @@ routinetypes -430397 +430487 id -430397 +430487 return_type -177533 +177571 @@ -25529,7 +26213,7 @@ 1 2 -430397 +430487 @@ -25545,22 +26229,22 @@ 1 2 -143082 +143112 2 3 -18125 +18128 3 9 -13322 +13325 9 8267 -3004 +3005 @@ -25570,11 +26254,11 @@ routinetypeargs -719708 +719859 routine -351778 +351852 index @@ -25582,7 +26266,7 @@ type_id -205527 +205570 @@ -25596,27 +26280,27 @@ 1 2 -161897 +161931 2 3 -95932 +95952 3 4 -53925 +53937 4 6 -32324 +32331 6 33 -7697 +7699 @@ -25632,22 +26316,22 @@ 1 2 -186711 +186750 2 3 -96689 +96709 3 4 -47653 +47663 4 22 -20723 +20728 @@ -25805,27 +26489,27 @@ 1 2 -122391 +122416 2 3 -40833 +40842 3 4 -13212 +13215 4 7 -16633 +16637 7 1349 -12456 +12458 @@ -25841,17 +26525,17 @@ 1 2 -154079 +154112 2 3 -39430 +39438 3 33 -12017 +12020 @@ -25861,19 +26545,19 @@ ptrtomembers -12631 +12634 id -12631 +12634 type_id -9396 +9398 class_id -6359 +6361 @@ -25887,7 +26571,7 @@ 1 2 -12631 +12634 @@ -25903,7 +26587,7 @@ 1 2 -12631 +12634 @@ -25919,7 +26603,7 @@ 1 2 -9035 +9037 2 @@ -25940,7 +26624,7 @@ 1 2 -9035 +9037 2 @@ -25961,7 +26645,7 @@ 1 2 -5339 +5341 2 @@ -25987,7 +26671,7 @@ 1 2 -5339 +5341 2 @@ -26055,11 +26739,11 @@ typespecifiers -1331696 +1333215 type_id -1324832 +1326328 spec_id @@ -26077,12 +26761,12 @@ 1 2 -1317968 +1319440 2 3 -6864 +6887 @@ -26111,8 +26795,8 @@ 10 -955 -956 +957 +958 10 @@ -26126,8 +26810,8 @@ 10 -96425 -96426 +96536 +96537 10 @@ -26138,11 +26822,11 @@ funspecifiers -11101011 +11122577 func_id -3417148 +3417865 spec_id @@ -26160,27 +26844,27 @@ 1 2 -342249 +342321 2 3 -436910 +421977 3 4 -842560 +853879 4 5 -1677016 +1680922 5 8 -118410 +118764 @@ -26254,8 +26938,8 @@ 10 -137685 -137686 +139439 +139440 10 @@ -26281,11 +26965,11 @@ varspecifiers -1112020 +1112009 var_id -924807 +924798 spec_id @@ -26303,7 +26987,7 @@ 1 2 -786197 +786189 2 @@ -26384,11 +27068,11 @@ attributes -413730 +413727 id -413730 +413727 kind @@ -26404,7 +27088,7 @@ location -90510 +90509 @@ -26418,7 +27102,7 @@ 1 2 -413730 +413727 @@ -26434,7 +27118,7 @@ 1 2 -413730 +413727 @@ -26450,7 +27134,7 @@ 1 2 -413730 +413727 @@ -26466,7 +27150,7 @@ 1 2 -413730 +413727 @@ -26825,7 +27509,7 @@ 1 2 -90510 +90509 @@ -26877,7 +27561,7 @@ 1 2 -90510 +90509 @@ -26887,11 +27571,11 @@ attribute_args -152615 +152614 id -152615 +152614 kind @@ -26899,7 +27583,7 @@ attribute -151316 +151315 index @@ -26907,7 +27591,7 @@ location -57362 +57361 @@ -26921,7 +27605,7 @@ 1 2 -152615 +152614 @@ -26937,7 +27621,7 @@ 1 2 -152615 +152614 @@ -26953,7 +27637,7 @@ 1 2 -152615 +152614 @@ -26969,7 +27653,7 @@ 1 2 -152615 +152614 @@ -27069,7 +27753,7 @@ 1 2 -150538 +150537 2 @@ -27090,7 +27774,7 @@ 1 2 -150826 +150825 2 @@ -27111,7 +27795,7 @@ 1 2 -150538 +150537 2 @@ -27132,7 +27816,7 @@ 1 2 -150543 +150542 2 @@ -27272,7 +27956,7 @@ 2 3 -8429 +8428 3 @@ -27303,7 +27987,7 @@ 1 2 -51567 +51566 2 @@ -27324,7 +28008,7 @@ 1 2 -27281 +27280 2 @@ -27360,7 +28044,7 @@ 1 2 -57357 +57356 3 @@ -27375,11 +28059,11 @@ attribute_arg_value -152591 +152590 arg -152591 +152590 value @@ -27397,7 +28081,7 @@ 1 2 -152591 +152590 @@ -27544,15 +28228,15 @@ typeattributes -19320 +19324 type_id -17938 +17942 spec_id -19320 +19324 @@ -27566,7 +28250,7 @@ 1 2 -17236 +17240 2 @@ -27587,7 +28271,7 @@ 1 2 -19320 +19324 @@ -27597,15 +28281,15 @@ funcattributes -304333 +304396 func_id -164211 +164245 spec_id -304333 +304396 @@ -27619,22 +28303,22 @@ 1 2 -89671 +89690 2 3 -12576 +12579 3 4 -59956 +59969 4 14 -2006 +2007 @@ -27650,7 +28334,7 @@ 1 2 -304333 +304396 @@ -27660,7 +28344,7 @@ varattributes -371224 +371223 var_id @@ -27668,7 +28352,7 @@ spec_id -371224 +371223 @@ -27682,12 +28366,12 @@ 1 2 -273654 +273655 2 3 -48764 +48763 14 @@ -27708,7 +28392,7 @@ 1 2 -371224 +371223 @@ -27766,15 +28450,15 @@ unspecifiedtype -9068477 +9115641 type_id -9068477 +9115641 unspecified_type_id -4975940 +5012847 @@ -27788,7 +28472,7 @@ 1 2 -9068477 +9115641 @@ -27804,17 +28488,17 @@ 1 2 -2708920 +2736095 2 3 -1952501 +1962057 3 7950 -314519 +314695 @@ -27824,19 +28508,19 @@ member -4920765 +4921797 parent -814336 +814507 index -2675 +2676 child -4905205 +4906234 @@ -27850,47 +28534,47 @@ 1 2 -42313 +42322 2 3 -223740 +223787 3 4 -204584 +204627 4 5 -86908 +86926 5 7 -65888 +65902 7 9 -61601 +61614 9 15 -62039 +62052 15 47 -61173 +61186 47 245 -6085 +6086 @@ -27906,47 +28590,47 @@ 1 2 -41655 +41664 2 3 -223564 +223611 3 4 -199343 +199385 4 5 -89715 +89734 5 7 -66360 +66373 7 9 -61678 +61690 9 15 -62960 +62974 15 42 -61261 +61274 42 281 -7796 +7797 @@ -28104,7 +28788,7 @@ 1 2 -4905205 +4906234 @@ -28120,12 +28804,12 @@ 1 2 -4889854 +4890880 2 7 -15350 +15354 @@ -28135,15 +28819,15 @@ enclosingfunction -125055 +125081 child -125055 +125081 parent -71392 +71407 @@ -28157,7 +28841,7 @@ 1 2 -125055 +125081 @@ -28173,22 +28857,22 @@ 1 2 -38333 +38341 2 3 -21074 +21079 3 4 -6535 +6536 4 7 -5372 +5373 7 @@ -28203,15 +28887,15 @@ derivations -390188 +390270 derivation -390188 +390270 sub -364377 +364453 index @@ -28219,11 +28903,11 @@ super -235659 +235708 location -86963 +86981 @@ -28237,7 +28921,7 @@ 1 2 -390188 +390270 @@ -28253,7 +28937,7 @@ 1 2 -390188 +390270 @@ -28269,7 +28953,7 @@ 1 2 -390188 +390270 @@ -28285,7 +28969,7 @@ 1 2 -390188 +390270 @@ -28301,12 +28985,12 @@ 1 2 -341811 +341883 2 7 -22565 +22570 @@ -28322,12 +29006,12 @@ 1 2 -351427 +351501 2 7 -12949 +12952 @@ -28343,12 +29027,12 @@ 1 2 -341822 +341893 2 7 -22554 +22559 @@ -28364,12 +29048,12 @@ 1 2 -351416 +351490 2 7 -12960 +12963 @@ -28549,12 +29233,12 @@ 1 2 -220878 +220924 2 1142 -14780 +14783 @@ -28570,12 +29254,12 @@ 1 2 -220889 +220935 2 1142 -14769 +14772 @@ -28591,7 +29275,7 @@ 1 2 -235209 +235259 2 @@ -28612,12 +29296,12 @@ 1 2 -228301 +228349 2 439 -7357 +7359 @@ -28633,22 +29317,22 @@ 1 2 -66338 +66352 2 3 -8388 +8389 3 7 -6611 +6613 7 795 -5625 +5626 @@ -28664,22 +29348,22 @@ 1 2 -68574 +68589 2 3 -6370 +6371 3 8 -7039 +7040 8 795 -4978 +4979 @@ -28695,7 +29379,7 @@ 1 2 -86941 +86959 2 @@ -28716,22 +29400,22 @@ 1 2 -69276 +69291 2 3 -8201 +8203 3 9 -6524 +6525 9 795 -2960 +2961 @@ -28741,11 +29425,11 @@ derspecifiers -392568 +392650 der_id -390155 +390237 spec_id @@ -28763,7 +29447,7 @@ 1 2 -387743 +387824 2 @@ -28809,11 +29493,11 @@ direct_base_offsets -310495 +310560 der_id -310495 +310560 offset @@ -28831,7 +29515,7 @@ 1 2 -310495 +310560 @@ -28917,11 +29601,11 @@ virtual_base_offsets -6337 +6339 sub -3508 +3509 super @@ -28974,7 +29658,7 @@ 1 2 -2960 +2961 2 @@ -29208,23 +29892,23 @@ frienddecls -240297 +240347 id -240297 +240347 type_id -27280 +27286 decl_id -49035 +49045 location -7302 +7304 @@ -29238,7 +29922,7 @@ 1 2 -240297 +240347 @@ -29254,7 +29938,7 @@ 1 2 -240297 +240347 @@ -29270,7 +29954,7 @@ 1 2 -240297 +240347 @@ -29286,17 +29970,17 @@ 1 2 -6217 +6218 2 3 -10230 +10232 3 5 -1984 +1985 5 @@ -29306,7 +29990,7 @@ 6 8 -2313 +2314 8 @@ -29337,17 +30021,17 @@ 1 2 -6217 +6218 2 3 -10230 +10232 3 5 -1984 +1985 5 @@ -29357,7 +30041,7 @@ 6 8 -2313 +2314 8 @@ -29388,12 +30072,12 @@ 1 2 -25701 +25707 2 31 -1578 +1579 @@ -29409,12 +30093,12 @@ 1 2 -33684 +33691 2 3 -4989 +4990 3 @@ -29424,12 +30108,12 @@ 7 23 -3804 +3805 23 394 -2532 +2533 @@ -29445,12 +30129,12 @@ 1 2 -33684 +33691 2 3 -4989 +4990 3 @@ -29460,12 +30144,12 @@ 7 23 -3804 +3805 23 394 -2532 +2533 @@ -29481,7 +30165,7 @@ 1 2 -48498 +48508 2 @@ -29502,12 +30186,12 @@ 1 2 -6239 +6240 2 3 -942 +943 3 @@ -29528,7 +30212,7 @@ 1 2 -6864 +6865 2 @@ -29549,7 +30233,7 @@ 1 2 -6250 +6251 2 @@ -29569,19 +30253,19 @@ comments -1580009 +1580341 id -1580009 +1580341 contents -784018 +784182 location -1580009 +1580341 @@ -29595,7 +30279,7 @@ 1 2 -1580009 +1580341 @@ -29611,7 +30295,7 @@ 1 2 -1580009 +1580341 @@ -29627,17 +30311,17 @@ 1 2 -663819 +663959 2 3 -75088 +75103 3 10738 -45109 +45119 @@ -29653,17 +30337,17 @@ 1 2 -663819 +663959 2 3 -75088 +75103 3 10738 -45109 +45119 @@ -29679,7 +30363,7 @@ 1 2 -1580009 +1580341 @@ -29695,7 +30379,7 @@ 1 2 -1580009 +1580341 @@ -29705,15 +30389,15 @@ commentbinding -713206 +713311 id -618260 +618433 element -684434 +684533 @@ -29727,17 +30411,17 @@ 1 2 -556867 +557093 2 3 -49079 +49045 3 97 -12313 +12294 @@ -29753,12 +30437,12 @@ 1 2 -655661 +655755 2 3 -28772 +28778 @@ -29768,15 +30452,15 @@ exprconv -6443933 +6443797 converted -6443639 +6443503 conversion -6443933 +6443797 @@ -29790,7 +30474,7 @@ 1 2 -6443346 +6443210 2 @@ -29811,7 +30495,7 @@ 1 2 -6443933 +6443797 @@ -29821,22 +30505,22 @@ compgenerated -6708045 +6707808 id -6708045 +6707808 synthetic_destructor_call -59605 +59596 element -46392 +46380 i @@ -29844,7 +30528,7 @@ destructor_call -49463 +49451 @@ -29858,17 +30542,17 @@ 1 2 -36951 +36937 2 3 -6765 +6766 3 29 -2675 +2676 @@ -29884,17 +30568,17 @@ 1 2 -36951 +36937 2 3 -6765 +6766 3 29 -2675 +2676 @@ -29928,8 +30612,8 @@ 21 -4231 -4232 +4229 +4230 10 @@ -29964,8 +30648,8 @@ 21 -3565 -3566 +3563 +3564 10 @@ -29982,17 +30666,17 @@ 1 2 -43618 +43605 2 3 -3618 +3619 3 26 -2225 +2226 @@ -30008,7 +30692,7 @@ 1 2 -49463 +49451 @@ -30018,15 +30702,15 @@ namespaces -7686 +7688 id -7686 +7688 name -4133 +4134 @@ -30040,7 +30724,7 @@ 1 2 -7686 +7688 @@ -30056,7 +30740,7 @@ 1 2 -3475 +3476 2 @@ -30087,15 +30771,15 @@ namespacembrs -1603036 +1603361 parentid -7160 +7161 memberid -1603036 +1603361 @@ -30169,7 +30853,7 @@ 778 39485 -317 +318 @@ -30185,7 +30869,7 @@ 1 2 -1603036 +1603361 @@ -30195,11 +30879,11 @@ exprparents -13453568 +13453475 expr_id -13453379 +13453286 child_index @@ -30207,7 +30891,7 @@ parent_id -9530495 +9530420 @@ -30221,7 +30905,7 @@ 1 2 -13453373 +13453279 2 @@ -30242,7 +30926,7 @@ 1 2 -13453197 +13453104 2 @@ -30292,7 +30976,7 @@ 6420 -1188854 +1188857 45 @@ -30338,7 +31022,7 @@ 6405 -1188867 +1188870 45 @@ -30355,17 +31039,17 @@ 1 2 -6759182 +6759115 2 3 -2187728 +2187726 3 1681 -583583 +583578 @@ -30381,17 +31065,17 @@ 1 2 -6759202 +6759135 2 3 -2187709 +2187707 3 480 -583583 +583578 @@ -30401,11 +31085,11 @@ expr_isload -5007422 +5007373 expr_id -5007422 +5007373 @@ -30458,8 +31142,8 @@ 1 -13857 -13858 +13714 +13715 1 @@ -30473,8 +31157,8 @@ 1 -4155321 -4155322 +4155464 +4155465 1 @@ -30485,11 +31169,11 @@ iscall -2320354 +2320215 caller -2320354 +2320215 kind @@ -30507,7 +31191,7 @@ 1 2 -2320354 +2320215 @@ -30526,13 +31210,13 @@ 10 -6429 -6430 +6428 +6429 10 -203800 -203801 +203744 +203745 10 @@ -30543,11 +31227,11 @@ numtemplatearguments -164694 +164695 expr_id -164694 +164695 num @@ -30565,7 +31249,7 @@ 1 2 -164694 +164695 @@ -30594,8 +31278,8 @@ 10 -14307 -14308 +14304 +14305 10 @@ -30654,23 +31338,23 @@ namequalifiers -1114421 +1114410 id -1114421 +1114410 qualifiableelement -1114421 +1114410 qualifyingelement -38862 +38861 location -504707 +504702 @@ -30684,7 +31368,7 @@ 1 2 -1114421 +1114410 @@ -30700,7 +31384,7 @@ 1 2 -1114421 +1114410 @@ -30716,7 +31400,7 @@ 1 2 -1114421 +1114410 @@ -30732,7 +31416,7 @@ 1 2 -1114421 +1114410 @@ -30748,7 +31432,7 @@ 1 2 -1114421 +1114410 @@ -30764,7 +31448,7 @@ 1 2 -1114421 +1114410 @@ -30862,7 +31546,7 @@ 1 2 -24789 +24788 2 @@ -30882,7 +31566,7 @@ 11 16728 -2596 +2595 @@ -30898,17 +31582,17 @@ 1 2 -383625 +383621 2 3 -56715 +56714 3 7 -38758 +38757 7 @@ -30929,17 +31613,17 @@ 1 2 -383625 +383621 2 3 -56715 +56714 3 7 -38758 +38757 7 @@ -30960,7 +31644,7 @@ 1 2 -447849 +447844 2 @@ -30980,15 +31664,15 @@ varbind -5434639 +5434586 expr -5434516 +5434462 var -1532809 +1532794 @@ -31002,7 +31686,7 @@ 1 2 -5434392 +5434339 2 @@ -31023,32 +31707,32 @@ 1 2 -679968 +679961 2 3 -308900 +308897 3 4 -232743 +232741 4 5 -92819 +92818 5 9 -133060 +133059 9 6150 -85317 +85316 @@ -31058,15 +31742,15 @@ funbind -2416575 +2416551 expr -2119711 +2119690 fun -434036 +434031 @@ -31080,12 +31764,12 @@ 1 2 -1823088 +1823070 2 3 -296447 +296444 3 @@ -31106,7 +31790,7 @@ 1 2 -252054 +252052 2 @@ -31141,11 +31825,11 @@ expr_allocator -30329 +30335 expr -30329 +30335 func @@ -31167,7 +31851,7 @@ 1 2 -30329 +30335 @@ -31183,7 +31867,7 @@ 1 2 -30329 +30335 @@ -31292,11 +31976,11 @@ expr_deallocator -33300 +33307 expr -33300 +33307 func @@ -31318,7 +32002,7 @@ 1 2 -33300 +33307 @@ -31334,7 +32018,7 @@ 1 2 -33300 +33307 @@ -31464,15 +32148,15 @@ expr_cond_guard -154262 +154261 cond -154262 +154261 guard -154262 +154261 @@ -31486,7 +32170,7 @@ 1 2 -154262 +154261 @@ -31502,7 +32186,7 @@ 1 2 -154262 +154261 @@ -31512,15 +32196,15 @@ expr_cond_true -154262 +154261 cond -154262 +154261 true -154262 +154261 @@ -31534,7 +32218,7 @@ 1 2 -154262 +154261 @@ -31550,7 +32234,7 @@ 1 2 -154262 +154261 @@ -31560,15 +32244,15 @@ expr_cond_false -154262 +154261 cond -154262 +154261 false -154262 +154261 @@ -31582,7 +32266,7 @@ 1 2 -154262 +154261 @@ -31598,7 +32282,7 @@ 1 2 -154262 +154261 @@ -31787,11 +32471,11 @@ fieldoffsets -251150 +251147 id -251150 +251147 byteoffset @@ -31813,7 +32497,7 @@ 1 2 -251150 +251147 @@ -31829,7 +32513,7 @@ 1 2 -251150 +251147 @@ -32214,23 +32898,23 @@ initialisers -1664822 +1664806 init -1664822 +1664806 var -642778 +642772 expr -1664822 +1664806 location -318685 +318682 @@ -32244,7 +32928,7 @@ 1 2 -1664822 +1664806 @@ -32260,7 +32944,7 @@ 1 2 -1664822 +1664806 @@ -32276,7 +32960,7 @@ 1 2 -1664822 +1664806 @@ -32292,7 +32976,7 @@ 1 2 -556218 +556212 2 @@ -32302,12 +32986,12 @@ 16 17 -49051 +49050 17 53 -8803 +8802 @@ -32323,7 +33007,7 @@ 1 2 -556218 +556212 2 @@ -32333,12 +33017,12 @@ 16 17 -49051 +49050 17 53 -8803 +8802 @@ -32354,7 +33038,7 @@ 1 2 -642765 +642758 2 @@ -32375,7 +33059,7 @@ 1 2 -1664822 +1664806 @@ -32391,7 +33075,7 @@ 1 2 -1664822 +1664806 @@ -32407,7 +33091,7 @@ 1 2 -1664822 +1664806 @@ -32423,7 +33107,7 @@ 1 2 -246094 +246092 2 @@ -32433,7 +33117,7 @@ 3 7 -24249 +24248 7 @@ -32459,12 +33143,12 @@ 1 2 -268678 +268675 2 3 -24971 +24970 3 @@ -32490,7 +33174,7 @@ 1 2 -246094 +246092 2 @@ -32500,7 +33184,7 @@ 3 7 -24249 +24248 7 @@ -32520,15 +33204,15 @@ expr_ancestor -66085 +66077 exp -65384 +65375 ancestor -47105 +47093 @@ -32542,12 +33226,12 @@ 1 2 -64748 +64739 2 4 -635 +636 @@ -32563,12 +33247,12 @@ 1 2 -34945 +34930 2 3 -9704 +9706 3 @@ -32583,11 +33267,11 @@ exprs -18434237 +18434101 id -18434237 +18434101 kind @@ -32595,7 +33279,7 @@ location -3622478 +3623249 @@ -32609,7 +33293,7 @@ 1 2 -18434237 +18434101 @@ -32625,7 +33309,7 @@ 1 2 -18434237 +18434101 @@ -32660,7 +33344,7 @@ 306 -472 +471 87 @@ -32684,23 +33368,23 @@ 87 -4718 +4717 6425 87 -6723 -13441 +6722 +13439 87 17876 -114359 +114329 87 -192896 -428379 +192871 +428312 43 @@ -32775,7 +33459,7 @@ 87 -72726 +72772 118610 21 @@ -32793,37 +33477,37 @@ 1 2 -1679637 +1680483 2 3 -738677 +738624 3 4 -319727 +319926 4 5 -277074 +276890 5 9 -301811 +301720 9 53 -272074 +272120 53 -144742 -33476 +144478 +33483 @@ -32839,17 +33523,17 @@ 1 2 -2586627 +2586676 2 3 -806737 +807411 3 30 -229113 +229161 @@ -32859,15 +33543,15 @@ expr_types -18573393 +18573385 id -18430421 +18430284 typeid -1322332 +1322456 value_category @@ -32885,12 +33569,12 @@ 1 2 -18288907 +18288641 2 4 -141514 +141642 @@ -32906,7 +33590,7 @@ 1 2 -18430421 +18430284 @@ -32922,42 +33606,42 @@ 1 2 -513731 +513839 2 3 -252041 +251951 3 4 -108355 +108499 4 5 -86009 +86038 5 8 -114200 +114147 8 14 -106042 +106075 14 45 -99759 +99747 45 -126323 -42193 +126297 +42158 @@ -32973,17 +33657,17 @@ 1 2 -1170807 +1170932 2 3 -143125 +143123 3 4 -8399 +8400 @@ -33002,13 +33686,13 @@ 10 -370541 -370542 +370443 +370444 10 -1304856 -1304857 +1304589 +1304590 10 @@ -33028,13 +33712,13 @@ 10 -30957 -30958 +30955 +30956 10 -102771 -102772 +102756 +102757 10 @@ -33045,15 +33729,15 @@ new_allocated_type -32127 +32134 expr -32127 +32134 type_id -16513 +16516 @@ -33067,7 +33751,7 @@ 1 2 -32127 +32134 @@ -33083,7 +33767,7 @@ 1 2 -10339 +10342 2 @@ -33708,15 +34392,15 @@ condition_decl_bind -7028 +7008 expr -7028 +7008 decl -7028 +7008 @@ -33730,7 +34414,7 @@ 1 2 -7028 +7008 @@ -33746,7 +34430,7 @@ 1 2 -7028 +7008 @@ -33756,11 +34440,11 @@ typeid_bind -4418 +4419 expr -4418 +4419 type_id @@ -33778,7 +34462,7 @@ 1 2 -4418 +4419 @@ -33877,11 +34561,11 @@ sizeof_bind -156888 +156887 expr -156888 +156887 type_id @@ -33899,7 +34583,7 @@ 1 2 -156888 +156887 @@ -34144,11 +34828,11 @@ lambda_capture -21653 +21652 id -21653 +21652 lambda @@ -34160,7 +34844,7 @@ field -21653 +21652 captured_by_reference @@ -34186,7 +34870,7 @@ 1 2 -21653 +21652 @@ -34202,7 +34886,7 @@ 1 2 -21653 +21652 @@ -34218,7 +34902,7 @@ 1 2 -21653 +21652 @@ -34234,7 +34918,7 @@ 1 2 -21653 +21652 @@ -34250,7 +34934,7 @@ 1 2 -21653 +21652 @@ -34266,7 +34950,7 @@ 1 2 -21653 +21652 @@ -34894,7 +35578,7 @@ 1 2 -21653 +21652 @@ -34910,7 +35594,7 @@ 1 2 -21653 +21652 @@ -34926,7 +35610,7 @@ 1 2 -21653 +21652 @@ -34942,7 +35626,7 @@ 1 2 -21653 +21652 @@ -34958,7 +35642,7 @@ 1 2 -21653 +21652 @@ -34974,7 +35658,7 @@ 1 2 -21653 +21652 @@ -35473,11 +36157,11 @@ stmts -4688614 +4688994 id -4688614 +4688994 kind @@ -35485,7 +36169,7 @@ location -1193856 +1194106 @@ -35499,7 +36183,7 @@ 1 2 -4688614 +4688994 @@ -35515,7 +36199,7 @@ 1 2 -4688614 +4688994 @@ -35549,8 +36233,8 @@ 10 -736 -737 +735 +736 10 @@ -35564,13 +36248,13 @@ 10 -2237 -2238 +2235 +2236 10 -2267 -2268 +2266 +2267 10 @@ -35579,13 +36263,13 @@ 10 -2827 -2828 +2826 +2827 10 -3121 -3122 +3119 +3120 10 @@ -35594,33 +36278,33 @@ 10 -4775 -4776 +4772 +4773 10 -30484 -30485 +30477 +30478 10 -55911 -55912 +55902 +55903 10 -90778 -90779 +90766 +90767 10 -103056 -103057 +103053 +103054 10 -120839 -120840 +120825 +120826 10 @@ -35743,22 +36427,22 @@ 1 2 -677438 +678008 2 3 -181952 +181585 3 4 -107851 +107907 4 6 -102116 +102105 6 @@ -35768,7 +36452,7 @@ 22 5041 -22960 +22965 @@ -35784,12 +36468,12 @@ 1 2 -1170270 +1170515 2 9 -23585 +23590 @@ -35895,15 +36579,15 @@ if_then -523914 +523910 if_stmt -523914 +523910 then_id -523914 +523910 @@ -35917,7 +36601,7 @@ 1 2 -523914 +523910 @@ -35933,7 +36617,7 @@ 1 2 -523914 +523910 @@ -35943,15 +36627,15 @@ if_else -148100 +148099 if_stmt -148100 +148099 else_id -148100 +148099 @@ -35965,7 +36649,7 @@ 1 2 -148100 +148099 @@ -35981,7 +36665,7 @@ 1 2 -148100 +148099 @@ -36087,15 +36771,15 @@ while_body -30997 +30993 while_stmt -30997 +30993 body_id -30997 +30993 @@ -36109,7 +36793,7 @@ 1 2 -30997 +30993 @@ -36125,7 +36809,7 @@ 1 2 -30997 +30993 @@ -36135,15 +36819,15 @@ do_body -149714 +149713 do_stmt -149714 +149713 body_id -149714 +149713 @@ -36157,7 +36841,7 @@ 1 2 -149714 +149713 @@ -36173,7 +36857,7 @@ 1 2 -149714 +149713 @@ -36183,7 +36867,7 @@ switch_case -271391 +271389 switch_stmt @@ -36195,7 +36879,7 @@ case_id -271391 +271389 @@ -36214,7 +36898,7 @@ 5 6 -47131 +47130 6 @@ -36240,7 +36924,7 @@ 5 6 -47131 +47130 6 @@ -36353,7 +37037,7 @@ 1 2 -271391 +271389 @@ -36369,7 +37053,7 @@ 1 2 -271391 +271389 @@ -36523,15 +37207,15 @@ for_update -29454 +29453 for_stmt -29454 +29453 update_id -29454 +29453 @@ -36545,7 +37229,7 @@ 1 2 -29454 +29453 @@ -36561,7 +37245,7 @@ 1 2 -29454 +29453 @@ -36571,15 +37255,15 @@ for_body -32154 +32153 for_stmt -32154 +32153 body_id -32154 +32153 @@ -36593,7 +37277,7 @@ 1 2 -32154 +32153 @@ -36609,7 +37293,7 @@ 1 2 -32154 +32153 @@ -36619,11 +37303,11 @@ stmtparents -4119908 +4119868 id -4119908 +4119868 index @@ -36631,7 +37315,7 @@ parent -1741441 +1741423 @@ -36645,7 +37329,7 @@ 1 2 -4119908 +4119868 @@ -36661,7 +37345,7 @@ 1 2 -4119908 +4119868 @@ -36799,27 +37483,27 @@ 1 2 -991907 +991897 2 3 -382688 +382684 3 4 -108382 +108381 4 6 -114023 +114022 6 17 -131785 +131784 17 @@ -36840,27 +37524,27 @@ 1 2 -991907 +991897 2 3 -382688 +382684 3 4 -108382 +108381 4 6 -114023 +114022 6 17 -131785 +131784 17 @@ -36885,181 +37569,12 @@ -successors -16889416 - - -from -16062711 - - -to -16041364 - - - - -from -to - - -12 - - -1 -2 -15355208 - - -2 -647 -707503 - - - - - - -to -from - - -12 - - -1 -2 -15497963 - - -2 -647 -543400 - - - - - - - - -truecond -965686 - - -from -965686 - - -to -936031 - - - - -from -to - - -12 - - -1 -2 -965686 - - - - - - -to -from - - -12 - - -1 -2 -912488 - - -2 -21 -23542 - - - - - - - - -falsecond -965686 - - -from -965686 - - -to -811117 - - - - -from -to - - -12 - - -1 -2 -965686 - - - - - - -to -from - - -12 - - -1 -2 -697840 - - -2 -3 -86960 - - -3 -25 -26316 - - - - - - - - stmt_decl_bind -532229 +532224 stmt -525358 +525353 num @@ -37067,7 +37582,7 @@ decl -532229 +532224 @@ -37081,7 +37596,7 @@ 1 2 -519919 +519914 2 @@ -37102,7 +37617,7 @@ 1 2 -519900 +519894 2 @@ -37225,7 +37740,7 @@ 1 2 -532229 +532224 @@ -37241,7 +37756,7 @@ 1 2 -532229 +532224 @@ -37251,11 +37766,11 @@ stmt_decl_entry_bind -497400 +497397 stmt -453689 +453686 num @@ -37263,7 +37778,7 @@ decl_entry -473433 +473430 @@ -37277,7 +37792,7 @@ 1 2 -422159 +422156 2 @@ -37298,7 +37813,7 @@ 1 2 -422159 +422156 2 @@ -37386,7 +37901,7 @@ 1 2 -461768 +461765 2 @@ -37407,7 +37922,7 @@ 1 2 -473354 +473350 2 @@ -37422,15 +37937,15 @@ blockscope -1324975 +1325099 block -1324975 +1325099 enclosing -1186772 +1186944 @@ -37444,7 +37959,7 @@ 1 2 -1324975 +1325099 @@ -37460,12 +37975,12 @@ 1 2 -1106388 +1106598 2 509 -80384 +80346 @@ -37475,11 +37990,11 @@ jumpinfo -350611 +350608 id -350611 +350608 str @@ -37501,7 +38016,7 @@ 1 2 -350611 +350608 @@ -37517,7 +38032,7 @@ 1 2 -350611 +350608 @@ -37661,11 +38176,11 @@ preprocdirects -1323352 +1323630 id -1323352 +1323630 kind @@ -37673,7 +38188,7 @@ location -1317036 +1317312 @@ -37687,7 +38202,7 @@ 1 2 -1323352 +1323630 @@ -37703,7 +38218,7 @@ 1 2 -1323352 +1323630 @@ -37871,12 +38386,12 @@ 1 2 -1316707 +1316983 2 235 -328 +329 @@ -37892,7 +38407,7 @@ 1 2 -1317036 +1317312 @@ -37902,15 +38417,15 @@ preprocpair -378730 +378809 begin -300451 +300514 elseelifend -378730 +378809 @@ -37924,17 +38439,17 @@ 1 2 -238576 +238626 2 3 -54539 +54551 3 53 -7335 +7337 @@ -37950,7 +38465,7 @@ 1 2 -378730 +378809 @@ -37960,41 +38475,41 @@ preproctrue -166536 +166571 branch -166536 +166571 preprocfalse -119101 +119126 branch -119101 +119126 preproctext -965236 +965438 id -965236 +965438 head -463478 +463575 body -175549 +175586 @@ -38008,7 +38523,7 @@ 1 2 -965236 +965438 @@ -38024,7 +38539,7 @@ 1 2 -965236 +965438 @@ -38040,22 +38555,22 @@ 1 2 -345901 +345973 2 3 -78158 +78174 3 19 -34769 +34777 19 752 -4649 +4650 @@ -38071,12 +38586,12 @@ 1 2 -441800 +441893 2 38 -21677 +21682 @@ -38092,12 +38607,12 @@ 1 2 -164979 +165013 2 64816 -10570 +10572 @@ -38113,12 +38628,12 @@ 1 2 -166459 +166494 2 21810 -9089 +9091 @@ -38128,15 +38643,15 @@ includes -290791 +290852 id -290791 +290852 included -54594 +54606 @@ -38150,7 +38665,7 @@ 1 2 -290791 +290852 @@ -38166,37 +38681,37 @@ 1 2 -26886 +26891 2 3 -8958 +8960 3 4 -4616 +4617 4 6 -4846 +4847 6 11 -4188 +4189 11 41 -4111 +4112 41 763 -986 +987 @@ -38254,11 +38769,11 @@ link_parent -18149936 +18153711 element -4991686 +4992722 link_target @@ -38276,32 +38791,32 @@ 1 2 -1493156 +1493469 2 3 -1882851 +1883246 3 4 -718710 +718850 4 6 -400791 +400876 6 29 -398072 +398156 29 45 -98103 +98124 @@ -38351,7 +38866,7 @@ 27154 -32621 +32620 43 @@ -38366,7 +38881,7 @@ 46593 -56499 +56498 43 @@ -38375,8 +38890,8 @@ 43 -370737 -370738 +370736 +370737 10 diff --git a/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll b/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll index bbd9090c8e61..9e30de327f83 100644 --- a/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll +++ b/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll @@ -2,6 +2,11 @@ * Provides a library for writing QL tests whose success or failure is based on expected results * embedded in the test source code as comments, rather than a `.expected` file. * + * To add this framework to a new language: + * - Add a file `InlineExpectationsTestPrivate.qll` that defines a `LineComment` class. This class + * must support a `getContents` method that returns the contents of the given comment, _excluding_ + * the comment indicator itself. It should also define `toString` and `getLocation` as usual. + * * To create a new inline expectations test: * - Declare a class that extends `InlineExpectationsTest`. In the characteristic predicate of the * new class, bind `this` to a unique string (usually the name of the test). @@ -13,7 +18,7 @@ * `hasActualResult()`. Often this is just a single tag. * * Example: - * ``` + * ```ql * class ConstantValueTest extends InlineExpectationsTest { * ConstantValueTest() { this = "ConstantValueTest" } * @@ -23,11 +28,11 @@ * } * * override predicate hasActualResult( - * Location location, string element, string tag, string valuesasas + * Location location, string element, string tag, string value * ) { * exists(Expr e | * tag = "const" and // The tag for this test. - * valuesasas = e.getValue() and // The expected value. Will only hold for constant expressions. + * value = e.getValue() and // The expected value. Will only hold for constant expressions. * location = e.getLocation() and // The location of the result to be reported. * element = e.toString() // The display text for the result. * ) @@ -38,10 +43,10 @@ * There is no need to write a `select` clause or query predicate. All of the differences between * expected results and actual results will be reported in the `failures()` query predicate. * - * To annotate the test source code with an expected result, place a C++-style (`//`) comment on the + * To annotate the test source code with an expected result, place a comment on the * same line as the expected result, with text of the following format as the body of the comment: * - * `// $tag=expected-value` + * `$tag=expected-value` * * Where `tag` is the value of the `tag` parameter from `hasActualResult()`, and `expected-value` is * the value of the `value` parameter from `hasActualResult()`. The `=expected-value` portion may be @@ -53,7 +58,7 @@ * "Missing result: tag=expected-value". * * Example: - * ``` + * ```cpp * int i = x + 5; // $const=5 * int j = y + (7 - 3) // $const=7 $const=3 $const=4 // The result of the subtraction is a constant. * ``` @@ -62,8 +67,8 @@ * annotate that a particular expected result is known to be a false positive, or that a particular * missing result is known to be a false negative: * - * `// $f+:tag=expected-value` // False positive - * `// $f-:tag=expected-value` // False negative + * `$f+:tag=expected-value` // False positive + * `$f-:tag=expected-value` // False negative * * A false positive expectation is treated as any other expected result, except that if there is no * matching actual result, the message will be of the form "Fixed false positive: tag=value". A @@ -74,14 +79,14 @@ * If the same result value is expected for two or more tags on the same line, there is a shorthand * notation available: * - * `// $tag1,tag2=expected-value` + * `$tag1,tag2=expected-value` * * is equivalent to: * - * `// $tag1=expected-value $tag2=expected-value` + * `$tag1=expected-value $tag2=expected-value` */ -import cpp +private import InlineExpectationsTestPrivate /** * Base class for tests with inline expectations. The test extends this class to provide the actual @@ -150,12 +155,12 @@ abstract class InlineExpectationsTest extends string { } /** - * RegEx pattern to match a comment containing one or more expected results. The comment must be a - * C++-style (`//`) comment with `$` as its first non-whitespace character. Any subsequent character + * RegEx pattern to match a comment containing one or more expected results. The comment must have + * `$` as its first non-whitespace character. Any subsequent character * is treated as part of the expected results, except that the comment may contain a `//` sequence * to treat the remainder of the line as a regular (non-interpreted) comment. */ -private string expectationCommentPattern() { result = "//\\s*(\\$(?:[^/]|/[^/])*)(?://.*)?" } +private string expectationCommentPattern() { result = "\\s*(\\$(?:[^/]|/[^/])*)(?://.*)?" } /** * RegEx pattern to match a single expected result, not including the leading `$`. It starts with an @@ -166,7 +171,7 @@ private string expectationPattern() { result = "(?:(f(?:\\+|-)):)?((?:[A-Za-z-_]+)(?:\\s*,\\s*[A-Za-z-_]+)*)(?:=(.*))?" } -private string getAnExpectation(CppStyleComment comment) { +private string getAnExpectation(LineComment comment) { result = comment.getContents().regexpCapture(expectationCommentPattern(), 1).splitAt("$").trim() and result != "" } @@ -177,7 +182,7 @@ private newtype TFailureLocatable = ) { test.hasActualResult(location, element, tag, value) } or - TValidExpectation(CppStyleComment comment, string tag, string value, string knownFailure) { + TValidExpectation(LineComment comment, string tag, string value, string knownFailure) { exists(string expectation | expectation = getAnExpectation(comment) and expectation.regexpMatch(expectationPattern()) and @@ -194,7 +199,7 @@ private newtype TFailureLocatable = ) ) } or - TInvalidExpectation(CppStyleComment comment, string expectation) { + TInvalidExpectation(LineComment comment, string expectation) { expectation = getAnExpectation(comment) and not expectation.regexpMatch(expectationPattern()) } @@ -232,7 +237,7 @@ class ActualResult extends FailureLocatable, TActualResult { } abstract private class Expectation extends FailureLocatable { - CppStyleComment comment; + LineComment comment; override string toString() { result = comment.toString() } diff --git a/cpp/ql/test/TestUtilities/InlineExpectationsTestPrivate.qll b/cpp/ql/test/TestUtilities/InlineExpectationsTestPrivate.qll new file mode 100644 index 000000000000..f3aae029eb4a --- /dev/null +++ b/cpp/ql/test/TestUtilities/InlineExpectationsTestPrivate.qll @@ -0,0 +1,23 @@ +import cpp + +private newtype TLineComment = MkLineComment(CppStyleComment c) + +/** + * Represents a line comment in the CPP style. + * Unlike the `CppStyleComment` class, however, the string returned by `getContents` does _not_ + * include the preceding comment marker (`//`). + */ +class LineComment extends TLineComment { + CppStyleComment comment; + + LineComment() { this = MkLineComment(comment) } + + /** Returns the contents of the given comment, _without_ the preceding comment marker (`//`). */ + string getContents() { result = comment.getContents().suffix(2) } + + /** Gets a textual representation of this element. */ + string toString() { result = comment.toString() } + + /** Gets the location of this comment. */ + Location getLocation() { result = comment.getLocation() } +} diff --git a/cpp/ql/test/examples/expressions/PrintAST.expected b/cpp/ql/test/examples/expressions/PrintAST.expected index 585ebae6ff4f..61c20b14921c 100644 --- a/cpp/ql/test/examples/expressions/PrintAST.expected +++ b/cpp/ql/test/examples/expressions/PrintAST.expected @@ -19,7 +19,7 @@ AddressOf.c: # 1| params: # 1| 0: [Parameter] i # 1| Type = [IntType] int -# 1| body: [Block] { ... } +# 1| body: [BlockStmt] { ... } # 2| 0: [DeclStmt] declaration # 2| 0: [VariableDeclarationEntry] definition of j # 2| Type = [IntPointerType] int * @@ -34,7 +34,7 @@ AddressOf.c: ArrayToPointer.c: # 5| [TopLevelFunction] void ArrayToPointer() # 5| params: -# 6| body: [Block] { ... } +# 6| body: [BlockStmt] { ... } # 7| 0: [DeclStmt] declaration # 7| 0: [VariableDeclarationEntry] definition of c # 7| Type = [ArrayType] char[] @@ -70,7 +70,7 @@ Cast.c: # 1| Type = [CharPointerType] char * # 1| 1: [Parameter] v # 1| Type = [VoidPointerType] void * -# 1| body: [Block] { ... } +# 1| body: [BlockStmt] { ... } # 2| 0: [ExprStmt] ExprStmt # 2| 0: [AssignExpr] ... = ... # 2| Type = [CharPointerType] char * @@ -89,7 +89,7 @@ Cast.c: ConditionDecl.cpp: # 1| [TopLevelFunction] void ConditionDecl() # 1| params: -# 1| body: [Block] { ... } +# 1| body: [BlockStmt] { ... } # 2| 0: [DeclStmt] declaration # 2| 0: [VariableDeclarationEntry] definition of j # 2| Type = [IntType] int @@ -109,7 +109,7 @@ ConditionDecl.cpp: # 3| expr: [VariableAccess] k # 3| Type = [IntType] int # 3| ValueCategory = prvalue(load) -# 3| 1: [Block] { ... } +# 3| 1: [BlockStmt] { ... } # 5| 2: [ReturnStmt] return ... ConstructorCall.cpp: # 1| [CopyAssignmentOperator] C& C::operator=(C const&) @@ -133,7 +133,7 @@ ConstructorCall.cpp: # 3| 0: [Parameter] i # 3| Type = [IntType] int # 3| initializations: -# 3| body: [Block] { ... } +# 3| body: [BlockStmt] { ... } # 4| 0: [ReturnStmt] return ... # 7| [CopyAssignmentOperator] D& D::operator=(D const&) # 7| params: @@ -154,7 +154,7 @@ ConstructorCall.cpp: # 9| [Constructor] void D::D() # 9| params: # 9| initializations: -# 9| body: [Block] { ... } +# 9| body: [BlockStmt] { ... } # 10| 0: [ReturnStmt] return ... # 13| [CopyAssignmentOperator] E& E::operator=(E const&) # 13| params: @@ -172,7 +172,7 @@ ConstructorCall.cpp: # 17| Type = [PointerType] D * # 17| 2: [Parameter] e # 17| Type = [PointerType] E * -# 17| body: [Block] { ... } +# 17| body: [BlockStmt] { ... } # 18| 0: [ExprStmt] ExprStmt # 18| 0: [AssignExpr] ... = ... # 18| Type = [PointerType] C * @@ -221,7 +221,7 @@ ConstructorCall.cpp: Conversion1.c: # 1| [TopLevelFunction] void Conversion1() # 1| params: -# 1| body: [Block] { ... } +# 1| body: [BlockStmt] { ... } # 2| 0: [DeclStmt] declaration # 2| 0: [VariableDeclarationEntry] definition of i # 2| Type = [IntType] int @@ -241,7 +241,7 @@ Conversion2.c: # 1| params: # 1| 0: [Parameter] x # 1| Type = [IntType] int -# 1| body: [Block] { ... } +# 1| body: [BlockStmt] { ... } # 2| 0: [ExprStmt] ExprStmt # 2| 0: [AssignExpr] ... = ... # 2| Type = [IntType] int @@ -277,7 +277,7 @@ Conversion3.cpp: # 1| params: # 1| 0: [Parameter] x # 1| Type = [IntType] int -# 1| body: [Block] { ... } +# 1| body: [BlockStmt] { ... } # 2| 0: [ExprStmt] ExprStmt # 2| 0: [AssignExpr] ... = ... # 2| Type = [IntType] int @@ -327,7 +327,7 @@ Conversion4.c: # 1| params: # 1| 0: [Parameter] x # 1| Type = [IntType] int -# 1| body: [Block] { ... } +# 1| body: [BlockStmt] { ... } # 2| 0: [ExprStmt] ExprStmt # 2| 0: [AssignExpr] ... = ... # 2| Type = [IntType] int @@ -350,9 +350,11 @@ Conversion4.c: # 2| ValueCategory = prvalue # 3| 1: [ReturnStmt] return ... DestructorCall.cpp: +# 1| [Constructor] void C::C() +# 1| params: # 3| [Destructor] void C::~C() # 3| params: -# 3| body: [Block] { ... } +# 3| body: [BlockStmt] { ... } # 4| 0: [ReturnStmt] return ... # 3| destructions: # 11| [TopLevelFunction] void DestructorCall(C*, D*) @@ -361,7 +363,7 @@ DestructorCall.cpp: # 11| Type = [PointerType] C * # 11| 1: [Parameter] d # 11| Type = [PointerType] D * -# 11| body: [Block] { ... } +# 11| body: [BlockStmt] { ... } # 12| 0: [ExprStmt] ExprStmt # 12| 0: [DeleteExpr] delete # 12| Type = [VoidType] void @@ -385,7 +387,7 @@ DynamicCast.cpp: # 1| params: #-----| 0: [Parameter] p#0 #-----| Type = [LValueReferenceType] const Base & -#-----| body: [Block] { ... } +#-----| body: [BlockStmt] { ... } #-----| 0: [ReturnStmt] return ... #-----| 0: [ReferenceToExpr] (reference to) #-----| Type = [LValueReferenceType] Base & @@ -412,13 +414,13 @@ DynamicCast.cpp: #-----| Type = [RValueReferenceType] Base && # 2| [VirtualFunction] void Base::f() # 2| params: -# 2| body: [Block] { ... } +# 2| body: [BlockStmt] { ... } # 2| 0: [ReturnStmt] return ... # 4| [CopyAssignmentOperator] Derived& Derived::operator=(Derived const&) # 4| params: #-----| 0: [Parameter] p#0 #-----| Type = [LValueReferenceType] const Derived & -#-----| body: [Block] { ... } +#-----| body: [BlockStmt] { ... } #-----| 0: [ExprStmt] ExprStmt #-----| 0: [ReferenceDereferenceExpr] (reference dereference) #-----| Type = [Class] Base @@ -478,7 +480,7 @@ DynamicCast.cpp: #-----| Type = [RValueReferenceType] Derived && # 5| [VirtualFunction] void Derived::f() # 5| params: -# 5| body: [Block] { ... } +# 5| body: [BlockStmt] { ... } # 5| 0: [ReturnStmt] return ... # 8| [TopLevelFunction] void DynamicCast(Base*, Derived*) # 8| params: @@ -486,7 +488,7 @@ DynamicCast.cpp: # 8| Type = [PointerType] Base * # 8| 1: [Parameter] d # 8| Type = [PointerType] Derived * -# 8| body: [Block] { ... } +# 8| body: [BlockStmt] { ... } # 9| 0: [ExprStmt] ExprStmt # 9| 0: [AssignExpr] ... = ... # 9| Type = [PointerType] Derived * @@ -508,7 +510,7 @@ DynamicCast.cpp: # 12| Type = [LValueReferenceType] Base & # 12| 1: [Parameter] d # 12| Type = [LValueReferenceType] Derived & -# 12| body: [Block] { ... } +# 12| body: [BlockStmt] { ... } # 13| 0: [ExprStmt] ExprStmt # 13| 0: [ReferenceDereferenceExpr] (reference dereference) # 13| Type = [Class] Derived @@ -545,7 +547,7 @@ Parenthesis.c: # 1| params: # 1| 0: [Parameter] i # 1| Type = [IntType] int -# 1| body: [Block] { ... } +# 1| body: [BlockStmt] { ... } # 2| 0: [ExprStmt] ExprStmt # 2| 0: [AssignExpr] ... = ... # 2| Type = [IntType] int @@ -581,7 +583,7 @@ PointerDereference.c: # 1| Type = [IntPointerType] int * # 1| 1: [Parameter] j # 1| Type = [IntType] int -# 1| body: [Block] { ... } +# 1| body: [BlockStmt] { ... } # 2| 0: [ExprStmt] ExprStmt # 2| 0: [AssignExpr] ... = ... # 2| Type = [IntType] int @@ -603,7 +605,7 @@ ReferenceDereference.cpp: # 4| Type = [LValueReferenceType] int & # 4| 1: [Parameter] j # 4| Type = [IntType] int -# 4| body: [Block] { ... } +# 4| body: [BlockStmt] { ... } # 5| 0: [ExprStmt] ExprStmt # 5| 0: [AssignExpr] ... = ... # 5| Type = [IntType] int @@ -623,7 +625,7 @@ ReferenceTo.cpp: # 1| params: # 1| 0: [Parameter] i # 1| Type = [IntPointerType] int * -# 1| body: [Block] { ... } +# 1| body: [BlockStmt] { ... } # 2| 0: [ReturnStmt] return ... # 2| 0: [ReferenceToExpr] (reference to) # 2| Type = [LValueReferenceType] int & @@ -639,7 +641,7 @@ Sizeof.c: # 1| params: # 1| 0: [Parameter] array # 1| Type = [ArrayType] int[] -# 1| body: [Block] { ... } +# 1| body: [BlockStmt] { ... } # 2| 0: [DeclStmt] declaration # 2| 0: [VariableDeclarationEntry] definition of i # 2| Type = [IntType] int @@ -676,7 +678,7 @@ Sizeof.c: StatementExpr.c: # 1| [TopLevelFunction] void StatementExpr() # 1| params: -# 1| body: [Block] { ... } +# 1| body: [BlockStmt] { ... } # 2| 0: [DeclStmt] declaration # 2| 0: [VariableDeclarationEntry] definition of j # 2| Type = [IntType] int @@ -700,7 +702,7 @@ StaticMemberAccess.cpp: # 5| Type = [IntType] int # 5| 1: [Parameter] xref # 5| Type = [LValueReferenceType] X & -# 5| body: [Block] { ... } +# 5| body: [BlockStmt] { ... } # 7| 0: [ExprStmt] ExprStmt # 7| 0: [AssignExpr] ... = ... # 7| Type = [IntType] int @@ -725,7 +727,7 @@ Subscript.c: # 1| Type = [ArrayType] int[] # 1| 1: [Parameter] j # 1| Type = [IntType] int -# 1| body: [Block] { ... } +# 1| body: [BlockStmt] { ... } # 2| 0: [ExprStmt] ExprStmt # 2| 0: [AssignExpr] ... = ... # 2| Type = [IntType] int @@ -762,20 +764,20 @@ Throw.cpp: #-----| 0: [Parameter] p#0 #-----| Type = [RValueReferenceType] F && # 2| initializations: -# 2| body: [Block] { ... } +# 2| body: [BlockStmt] { ... } # 2| 0: [ReturnStmt] return ... # 4| [Constructor] void F::F() # 4| params: # 4| initializations: -# 4| body: [Block] { ... } +# 4| body: [BlockStmt] { ... } # 4| 0: [ReturnStmt] return ... # 6| [TopLevelFunction] void Throw(int) # 6| params: # 6| 0: [Parameter] i # 6| Type = [IntType] int -# 6| body: [Block] { ... } +# 6| body: [BlockStmt] { ... } # 7| 0: [TryStmt] try { ... } -# 7| 0: [Block] { ... } +# 7| 0: [BlockStmt] { ... } # 8| 0: [IfStmt] if (...) ... # 8| 0: [CStyleCast] (bool)... # 8| Conversion = [BoolConversion] conversion to bool @@ -818,13 +820,13 @@ Typeid.cpp: # 7| params: # 13| [VirtualFunction] void Base::v() # 13| params: -# 13| body: [Block] { ... } +# 13| body: [BlockStmt] { ... } # 13| 0: [ReturnStmt] return ... # 18| [TopLevelFunction] void TypeId(Base*) # 18| params: # 18| 0: [Parameter] bp # 18| Type = [PointerType] Base * -# 18| body: [Block] { ... } +# 18| body: [BlockStmt] { ... } # 19| 0: [DeclStmt] declaration # 19| 0: [VariableDeclarationEntry] definition of name # 19| Type = [PointerType] const char * @@ -846,7 +848,7 @@ VacuousDestructorCall.cpp: # 2| Type = [TemplateParameter] T # 2| 1: [Parameter] y # 2| Type = [PointerType] T * -# 2| body: [Block] { ... } +# 2| body: [BlockStmt] { ... } # 3| 0: [ExprStmt] ExprStmt # 3| 0: [ExprCall] call to expression # 3| Type = [UnknownType] unknown @@ -874,7 +876,7 @@ VacuousDestructorCall.cpp: # 2| Type = [IntType] int # 2| 1: [Parameter] y # 2| Type = [IntPointerType] int * -# 2| body: [Block] { ... } +# 2| body: [BlockStmt] { ... } # 3| 0: [ExprStmt] ExprStmt # 3| 0: [VacuousDestructorCall] (vacuous destructor call) # 3| Type = [VoidType] void @@ -894,7 +896,7 @@ VacuousDestructorCall.cpp: # 7| params: # 7| 0: [Parameter] i # 7| Type = [IntType] int -# 7| body: [Block] { ... } +# 7| body: [BlockStmt] { ... } # 10| 0: [ExprStmt] ExprStmt # 10| 0: [FunctionCall] call to CallDestructor # 10| Type = [VoidType] void @@ -914,7 +916,7 @@ Varargs.c: # 8| params: # 8| 0: [Parameter] text # 8| Type = [PointerType] const char * -# 8| body: [Block] { ... } +# 8| body: [BlockStmt] { ... } # 9| 0: [DeclStmt] declaration # 9| 0: [VariableDeclarationEntry] definition of args # 9| Type = [CTypedefType] va_list @@ -947,7 +949,7 @@ macro_etc.c: # 3| params: # 3| 0: [Parameter] i # 3| Type = [IntType] int -# 3| body: [Block] { ... } +# 3| body: [BlockStmt] { ... } # 4| 0: [DeclStmt] declaration # 4| 0: [TypeDeclarationEntry] definition of u # 4| Type = [LocalUnion] u @@ -997,7 +999,7 @@ macro_etc.c: # 10| ValueCategory = prvalue # 22| [TopLevelFunction] int foo() # 22| params: -# 22| body: [Block] { ... } +# 22| body: [BlockStmt] { ... } # 23| 0: [DeclStmt] declaration # 23| 0: [VariableDeclarationEntry] definition of t # 23| Type = [IntType] int @@ -1059,7 +1061,7 @@ macro_etc.c: # 27| 0: [VariableAccess] i # 27| Type = [PlainCharType] char # 27| ValueCategory = lvalue -# 27| 3: [Block] { ... } +# 27| 3: [BlockStmt] { ... } # 27| 0: [ExprStmt] ExprStmt # 27| 0: [AssignAddExpr] ... += ... # 27| Type = [IntType] int @@ -1111,7 +1113,7 @@ macro_etc.c: # 28| 0: [VariableAccess] i # 28| Type = [PlainCharType] char # 28| ValueCategory = lvalue -# 28| 3: [Block] { ... } +# 28| 3: [BlockStmt] { ... } # 28| 0: [ExprStmt] ExprStmt # 28| 0: [AssignAddExpr] ... += ... # 28| Type = [IntType] int @@ -1210,7 +1212,7 @@ union_etc.cpp: # 2| [Constructor] void S::S() # 2| params: # 2| initializations: -# 2| body: [Block] { ... } +# 2| body: [BlockStmt] { ... } # 2| 0: [ReturnStmt] return ... # 2| [CopyConstructor] void S::S(S const&) # 2| params: @@ -1240,7 +1242,7 @@ union_etc.cpp: # 6| params: # 6| 0: [Parameter] val # 6| Type = [IntType] int -# 6| body: [Block] { ... } +# 6| body: [BlockStmt] { ... } # 6| 0: [ExprStmt] ExprStmt # 6| 0: [AssignExpr] ... = ... # 6| Type = [IntType] int @@ -1305,7 +1307,7 @@ union_etc.cpp: #-----| Type = [RValueReferenceType] C && # 22| [TopLevelFunction] int foo() # 22| params: -# 22| body: [Block] { ... } +# 22| body: [BlockStmt] { ... } # 23| 0: [DeclStmt] declaration # 23| 0: [VariableDeclarationEntry] definition of s # 23| Type = [Struct] S @@ -1423,7 +1425,7 @@ union_etc.cpp: # 33| params: # 33| 0: [Parameter] val # 33| Type = [IntType] int -# 33| body: [Block] { ... } +# 33| body: [BlockStmt] { ... } # 33| 0: [ExprStmt] ExprStmt # 33| 0: [AssignExpr] ... = ... # 33| Type = [IntType] int @@ -1440,7 +1442,7 @@ union_etc.cpp: # 33| 1: [ReturnStmt] return ... # 36| [TopLevelFunction] int bar() # 36| params: -# 36| body: [Block] { ... } +# 36| body: [BlockStmt] { ... } # 37| 0: [DeclStmt] declaration # 37| 0: [VariableDeclarationEntry] definition of s # 37| Type = [PointerType] const T * diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/bitwiseand/bitwiseand.cpp b/cpp/ql/test/experimental/library-tests/rangeanalysis/bitwiseand/bitwiseand.cpp new file mode 100644 index 000000000000..d45b0062d5d4 --- /dev/null +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/bitwiseand/bitwiseand.cpp @@ -0,0 +1,59 @@ +typedef unsigned char uint8_t; +typedef signed char int8_t; +typedef unsigned uint32_t; +typedef signed long long int64_t; + +void test_assign_operator(uint8_t x) { + x &= 7; // [0 .. 7] +} + +void test_non_negative_const(uint8_t x) { + uint8_t unsigned_const = 7; + + // Non-negative range operand and non-negative constant. The operands are promoted + // to signed ints. + x & 0; // [0 .. 0] + x & 7; // [0 .. 7] + x & unsigned_const; // [0 .. 7] + + // This tests what happens when both arguments are promoted to `unsigned int` instead + // of `int`, and when the constant is larger than the max bound + x & 0xFFFFFFFF; // [0 .. 255] +} + +void test_non_const(uint8_t a, uint8_t b, uint32_t c, uint32_t d) { + if (b <= 100) { + // `a` and `b` are promoted to signed ints, meaning neither the range analysis library + // nor this extension handle it + a & b; // [-2147483648 .. 2147483647] + } + if (d <= 100) { + // Handled by the range analysis library + c & d; // [0 .. 100] + } +} + +void test_negative_operand(uint8_t x, int8_t y) { + uint8_t unsigned_const = 7; + int8_t signed_const = -7; + + // The right operand can be negative + x & -7; // [-2147483648 .. 2147483647] + x & signed_const; // [-2147483648 .. 2147483647] + x & y; // [-2147483648 .. 2147483647] + + // The left operand can be negative + y & 7; // [-2147483648 .. 2147483647] + y & unsigned_const; // [-2147483648 .. 2147483647] + y & 0xFFFFFFFF; // [0 .. 4294967295] + (int64_t)y & 0xFFFFFFFF; // [-9223372036854776000 .. 9223372036854776000] + y & x; // [-2147483648 .. 2147483647] + + // Both can be negative + y & -7; // [-2147483648 .. 2147483647] + y & signed_const; // [-2147483648 .. 2147483647] + signed_const & -7; // [-2147483648 .. 2147483647] + signed_const & y; // [-2147483648 .. 2147483647] + -7 & y; // [-2147483648 .. 2147483647] + -7 & signed_const; // [-2147483648 .. 2147483647] +} diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/bitwiseand/bitwiseand.expected b/cpp/ql/test/experimental/library-tests/rangeanalysis/bitwiseand/bitwiseand.expected new file mode 100644 index 000000000000..22ad956469e4 --- /dev/null +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/bitwiseand/bitwiseand.expected @@ -0,0 +1,21 @@ +| bitwiseand.cpp:7:3:7:8 | ... &= ... | 0.0 | 7.0 | +| bitwiseand.cpp:15:3:15:7 | ... & ... | 0.0 | 0.0 | +| bitwiseand.cpp:16:3:16:7 | ... & ... | 0.0 | 7.0 | +| bitwiseand.cpp:17:3:17:20 | ... & ... | 0.0 | 7.0 | +| bitwiseand.cpp:21:3:21:16 | ... & ... | 0.0 | 255.0 | +| bitwiseand.cpp:28:5:28:9 | ... & ... | -2.147483648E9 | 2.147483647E9 | +| bitwiseand.cpp:32:5:32:9 | ... & ... | 0.0 | 100.0 | +| bitwiseand.cpp:41:3:41:8 | ... & ... | -2.147483648E9 | 2.147483647E9 | +| bitwiseand.cpp:42:3:42:18 | ... & ... | -2.147483648E9 | 2.147483647E9 | +| bitwiseand.cpp:43:3:43:7 | ... & ... | -2.147483648E9 | 2.147483647E9 | +| bitwiseand.cpp:46:3:46:7 | ... & ... | -2.147483648E9 | 2.147483647E9 | +| bitwiseand.cpp:47:3:47:20 | ... & ... | -2.147483648E9 | 2.147483647E9 | +| bitwiseand.cpp:48:3:48:16 | ... & ... | 0.0 | 4.294967295E9 | +| bitwiseand.cpp:49:3:49:25 | ... & ... | -9.223372036854776E18 | 9.223372036854776E18 | +| bitwiseand.cpp:50:3:50:7 | ... & ... | -2.147483648E9 | 2.147483647E9 | +| bitwiseand.cpp:53:3:53:8 | ... & ... | -2.147483648E9 | 2.147483647E9 | +| bitwiseand.cpp:54:3:54:18 | ... & ... | -2.147483648E9 | 2.147483647E9 | +| bitwiseand.cpp:55:3:55:19 | ... & ... | -2.147483648E9 | 2.147483647E9 | +| bitwiseand.cpp:56:3:56:18 | ... & ... | -2.147483648E9 | 2.147483647E9 | +| bitwiseand.cpp:57:3:57:8 | ... & ... | -2.147483648E9 | 2.147483647E9 | +| bitwiseand.cpp:58:3:58:19 | ... & ... | -2.147483648E9 | 2.147483647E9 | diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/bitwiseand/bitwiseand.ql b/cpp/ql/test/experimental/library-tests/rangeanalysis/bitwiseand/bitwiseand.ql new file mode 100644 index 000000000000..6521e8f0f610 --- /dev/null +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/bitwiseand/bitwiseand.ql @@ -0,0 +1,8 @@ +import experimental.semmle.code.cpp.rangeanalysis.ExtendedRangeAnalysis + +from Operation expr, float lower, float upper +where + (expr instanceof BitwiseAndExpr or expr instanceof AssignAndExpr) and + lower = lowerBound(expr) and + upper = upperBound(expr) +select expr, lower, upper diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/extended/extended.cpp b/cpp/ql/test/experimental/library-tests/rangeanalysis/extended/extended.cpp new file mode 100644 index 000000000000..0fed35bc9aff --- /dev/null +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/extended/extended.cpp @@ -0,0 +1,9 @@ + + +void test_overridability_sub(int x) { + int zero = x - x; + zero; // 0 + + int nonzero = x - (unsigned char)x; + nonzero; // full range +} diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/extended/extended.expected b/cpp/ql/test/experimental/library-tests/rangeanalysis/extended/extended.expected new file mode 100644 index 000000000000..b43601c80886 --- /dev/null +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/extended/extended.expected @@ -0,0 +1,6 @@ +| extended.cpp:4:14:4:14 | x | -2.147483648E9 | 2.147483647E9 | +| extended.cpp:4:18:4:18 | x | -2.147483648E9 | 2.147483647E9 | +| extended.cpp:5:3:5:6 | zero | 0.0 | 0.0 | +| extended.cpp:7:17:7:17 | x | -2.147483648E9 | 2.147483647E9 | +| extended.cpp:7:36:7:36 | x | -2.147483648E9 | 2.147483647E9 | +| extended.cpp:8:3:8:9 | nonzero | -2.147483648E9 | 2.147483647E9 | diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/extended/extended.ql b/cpp/ql/test/experimental/library-tests/rangeanalysis/extended/extended.ql new file mode 100644 index 000000000000..d6344e5d0629 --- /dev/null +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/extended/extended.ql @@ -0,0 +1,7 @@ +import experimental.semmle.code.cpp.rangeanalysis.ExtendedRangeAnalysis + +from VariableAccess expr, float lower, float upper +where + lower = lowerBound(expr) and + upper = upperBound(expr) +select expr, lower, upper diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/extensibility/extensibility.c b/cpp/ql/test/experimental/library-tests/rangeanalysis/extensibility/extensibility.c new file mode 100644 index 000000000000..33cf54ee9ebf --- /dev/null +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/extensibility/extensibility.c @@ -0,0 +1,19 @@ +/// Adds its arguments (has custom modeling in QL) +int custom_add_function(int a, int b); + +int test_extensibility_add(int x) { + if (x >= -10 && x <= 10) { + int result = custom_add_function(x, 100); + return result; // 90 .. 110 + } +} + +int test_overridability_sub(int x) { + int result = x - (unsigned char)x; // Returns 0 due to custom modeling for this test being deliberately wrong + return result; // 0 +} + +void test_parameter_override(int magic_name_at_most_10, int magic_name_at_most_20) { + magic_name_at_most_10; + magic_name_at_most_20; +} diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/extensibility/extensibility.expected b/cpp/ql/test/experimental/library-tests/rangeanalysis/extensibility/extensibility.expected new file mode 100644 index 000000000000..e9133e191044 --- /dev/null +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/extensibility/extensibility.expected @@ -0,0 +1,9 @@ +| extensibility.c:5:7:5:7 | x | -2.147483648E9 | 2.147483647E9 | +| extensibility.c:5:19:5:19 | x | -10.0 | 2.147483647E9 | +| extensibility.c:6:38:6:38 | x | -10.0 | 10.0 | +| extensibility.c:7:12:7:17 | result | 90.0 | 110.0 | +| extensibility.c:12:16:12:16 | x | -2.147483648E9 | 2.147483647E9 | +| extensibility.c:12:35:12:35 | x | -2.147483648E9 | 2.147483647E9 | +| extensibility.c:13:10:13:15 | result | 0.0 | 0.0 | +| extensibility.c:17:3:17:23 | magic_name_at_most_10 | -2.147483648E9 | 10.0 | +| extensibility.c:18:3:18:23 | magic_name_at_most_20 | -2.147483648E9 | 20.0 | diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/extensibility/extensibility.ql b/cpp/ql/test/experimental/library-tests/rangeanalysis/extensibility/extensibility.ql new file mode 100644 index 000000000000..4fbfed1706db --- /dev/null +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/extensibility/extensibility.ql @@ -0,0 +1,80 @@ +import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis +import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils +import experimental.semmle.code.cpp.models.interfaces.SimpleRangeAnalysisExpr +import experimental.semmle.code.cpp.models.interfaces.SimpleRangeAnalysisDefinition + +class CustomAddFunctionCall extends SimpleRangeAnalysisExpr, FunctionCall { + CustomAddFunctionCall() { this.getTarget().hasGlobalName("custom_add_function") } + + override float getLowerBounds() { + exists(float lower0, float lower1 | + lower0 = getFullyConvertedLowerBounds(this.getArgument(0)) and + lower1 = getFullyConvertedLowerBounds(this.getArgument(1)) and + // Note: this rounds toward 0, not -Inf as it should + result = lower0 + lower1 + ) + } + + override float getUpperBounds() { + exists(float upper0, float upper1 | + upper0 = getFullyConvertedUpperBounds(this.getArgument(0)) and + upper1 = getFullyConvertedUpperBounds(this.getArgument(1)) and + // Note: this rounds toward 0, not Inf as it should + result = upper0 + upper1 + ) + } + + override predicate dependsOnChild(Expr child) { child = this.getAnArgument() } +} + +class SelfSub extends SimpleRangeAnalysisExpr, SubExpr { + SelfSub() { + getLeftOperand().(VariableAccess).getTarget() = getRightOperand().(VariableAccess).getTarget() + } + + override float getLowerBounds() { result = 0 } + + override float getUpperBounds() { result = 0 } + + override predicate dependsOnChild(Expr child) { child = this.getAnOperand() } +} + +/** + * A definition for test purposes of a parameter `p` that starts with a + * special prefix. This class is written to exploit how QL behaves when class + * fields are not functionally determined by `this`. When multiple parameters + * of the same function have the special prefix, there is still only one + * instance of this class. + */ +class MagicParameterName extends SimpleRangeAnalysisDefinition { + Parameter p; + float value; + + MagicParameterName() { + this.definedByParameter(p) and + value = p.getName().regexpCapture("magic_name_at_most_(\\d+)", 1).toFloat() + } + + override predicate hasRangeInformationFor(StackVariable v) { v = p } + + override predicate dependsOnExpr(StackVariable v, Expr e) { + // No dependencies. This sample class yields constant values. + none() + } + + override float getLowerBounds(StackVariable var) { + var = p and + result = typeLowerBound(p.getUnspecifiedType()) + } + + override float getUpperBounds(StackVariable var) { + var = p and + result = value + } +} + +from VariableAccess expr, float lower, float upper +where + lower = lowerBound(expr) and + upper = upperBound(expr) +select expr, lower, upper diff --git a/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected b/cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected similarity index 100% rename from cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected rename to cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected diff --git a/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.ql b/cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.ql similarity index 91% rename from cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.ql rename to cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.ql index ef158f0de28f..1b77763682ad 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.ql +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.ql @@ -1,4 +1,4 @@ -import semmle.code.cpp.rangeanalysis.RangeAnalysis +import experimental.semmle.code.cpp.rangeanalysis.RangeAnalysis import semmle.code.cpp.ir.IR import semmle.code.cpp.controlflow.IRGuards import semmle.code.cpp.ir.ValueNumbering diff --git a/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/test.cpp b/cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/test.cpp similarity index 100% rename from cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/test.cpp rename to cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/test.cpp diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected b/cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected similarity index 100% rename from cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected rename to cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.ql b/cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/SignAnalysis.ql similarity index 86% rename from cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.ql rename to cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/SignAnalysis.ql index fbfeb583283e..fadd86f8a855 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.ql +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/SignAnalysis.ql @@ -1,4 +1,4 @@ -import semmle.code.cpp.rangeanalysis.SignAnalysis +import experimental.semmle.code.cpp.rangeanalysis.SignAnalysis import semmle.code.cpp.ir.IR string getASignString(Instruction i) { diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/binary_logical_operator.c b/cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/binary_logical_operator.c similarity index 100% rename from cpp/ql/test/library-tests/rangeanalysis/signanalysis/binary_logical_operator.c rename to cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/binary_logical_operator.c diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/bounded_bounds.c b/cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/bounded_bounds.c similarity index 100% rename from cpp/ql/test/library-tests/rangeanalysis/signanalysis/bounded_bounds.c rename to cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/bounded_bounds.c diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/inline_assembly.c b/cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/inline_assembly.c similarity index 100% rename from cpp/ql/test/library-tests/rangeanalysis/signanalysis/inline_assembly.c rename to cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/inline_assembly.c diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/minmax.c b/cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/minmax.c similarity index 100% rename from cpp/ql/test/library-tests/rangeanalysis/signanalysis/minmax.c rename to cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/minmax.c diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/test.c b/cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/test.c similarity index 100% rename from cpp/ql/test/library-tests/rangeanalysis/signanalysis/test.c rename to cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/test.c diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/test.cpp b/cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/test.cpp similarity index 100% rename from cpp/ql/test/library-tests/rangeanalysis/signanalysis/test.cpp rename to cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/test.cpp diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-359/semmle/tests/PrivateCleartextWrite.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-359/semmle/tests/PrivateCleartextWrite.expected new file mode 100644 index 000000000000..c263d7e6dfd7 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-359/semmle/tests/PrivateCleartextWrite.expected @@ -0,0 +1,21 @@ +edges +| test.cpp:77:16:77:22 | medical | test.cpp:78:24:78:27 | temp | +| test.cpp:81:17:81:20 | call to func | test.cpp:82:24:82:28 | buff5 | +| test.cpp:81:22:81:28 | medical | test.cpp:81:17:81:20 | call to func | +nodes +| test.cpp:57:9:57:18 | theZipcode | semmle.label | theZipcode | +| test.cpp:74:24:74:30 | medical | semmle.label | medical | +| test.cpp:77:16:77:22 | medical | semmle.label | medical | +| test.cpp:78:24:78:27 | temp | semmle.label | temp | +| test.cpp:81:17:81:20 | call to func | semmle.label | call to func | +| test.cpp:81:22:81:28 | medical | semmle.label | medical | +| test.cpp:82:24:82:28 | buff5 | semmle.label | buff5 | +| test.cpp:96:37:96:46 | theZipcode | semmle.label | theZipcode | +| test.cpp:99:42:99:51 | theZipcode | semmle.label | theZipcode | +#select +| test.cpp:57:9:57:18 | theZipcode | This write into the external location 'theZipcode' may contain unencrypted data from $@ | test.cpp:57:9:57:18 | theZipcode | this source. | +| test.cpp:74:24:74:30 | medical | This write into the external location 'medical' may contain unencrypted data from $@ | test.cpp:74:24:74:30 | medical | this source. | +| test.cpp:78:24:78:27 | temp | This write into the external location 'temp' may contain unencrypted data from $@ | test.cpp:77:16:77:22 | medical | this source. | +| test.cpp:82:24:82:28 | buff5 | This write into the external location 'buff5' may contain unencrypted data from $@ | test.cpp:81:22:81:28 | medical | this source. | +| test.cpp:96:37:96:46 | theZipcode | This write into the external location 'theZipcode' may contain unencrypted data from $@ | test.cpp:96:37:96:46 | theZipcode | this source. | +| test.cpp:99:42:99:51 | theZipcode | This write into the external location 'theZipcode' may contain unencrypted data from $@ | test.cpp:99:42:99:51 | theZipcode | this source. | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-359/semmle/tests/PrivateCleartextWrite.qlref b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-359/semmle/tests/PrivateCleartextWrite.qlref new file mode 100644 index 000000000000..65c8c9c2dd4c --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-359/semmle/tests/PrivateCleartextWrite.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-359/PrivateCleartextWrite.ql \ No newline at end of file diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-359/semmle/tests/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-359/semmle/tests/test.cpp new file mode 100644 index 000000000000..4d69ee5b2b72 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-359/semmle/tests/test.cpp @@ -0,0 +1,105 @@ +#define FILE int +#define wchar char +#define size_t int +typedef int streamsize; + +size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); +int fputs(const char *s, FILE *stream); +int fputc(int c, FILE *stream); +int fprintf(FILE *stream, const char *format, ...); +int sprintf(char *s, const char *format, ...); +size_t strlen(const char *s); + +namespace std +{ + template + struct char_traits; + + template > + class basic_ostream /*: virtual public basic_ios - not needed for this test */ + { + public: + typedef charT char_type; + basic_ostream &write(const char_type *s, streamsize n); + }; + + template > + class basic_ofstream : public basic_ostream + { + public: + }; + + template + basic_ostream &operator<<(basic_ostream &, const charT *); + + typedef basic_ostream ostream; + typedef basic_ofstream ofstream; +}; // namespace std + +using namespace std; + +char *encrypt(char *buffer) +{ + return buffer; +} +char *func(char *buffer) +{ + return buffer; +} + +// test for CleartextFileWrite +void file() +{ + char *theZipcode = "cleartext zipcode!"; + FILE *file; + + // BAD: write zipcode to file in cleartext + fputs(theZipcode, file); + + // GOOD: encrypt first + char *encrypted = encrypt(theZipcode); + fwrite(encrypted, sizeof(encrypted), 1, file); +} + +// test for CleartextBufferWrite +int main(int argc, char **argv) +{ + char *medical = "medical"; + char *buff1; + char *buff2; + char *buff3; + char *buff4; + + // BAD: write medical to buffer in cleartext + sprintf(buff1, "%s", medical); + + // BAD: write medical to buffer in cleartext + char *temp = medical; + sprintf(buff2, "%s", temp); + + // BAD: write medical to buffer in cleartext + char *buff5 = func(medical); + sprintf(buff3, "%s", buff5); + + char *buff6 = encrypt(medical); + // GOOD: encrypt first + sprintf(buff4, "%s", buff6); +} + +// test for CleartextFileWrite +void stream() +{ + char *theZipcode = "cleartext zipcode!"; + ofstream mystream; + + // BAD: write zipcode to file in cleartext + mystream << "the zipcode is: " << theZipcode; + + // BAD: write zipcode to file in cleartext + (mystream << "the zipcode is: ").write(theZipcode, strlen(theZipcode)); + + // GOOD: encrypt first + char *encrypted = encrypt(theZipcode); + mystream << "the zipcode is: " << encrypted; + (mystream << "the zipcode is: ").write(encrypted, strlen(encrypted)); +} diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/semmle/tests/MemoryUnsafeFunctionScan.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/semmle/tests/MemoryUnsafeFunctionScan.cpp new file mode 100644 index 000000000000..f9ffc5e8687e --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/semmle/tests/MemoryUnsafeFunctionScan.cpp @@ -0,0 +1,25 @@ +///// Library routines ///// + +int scanf(const char *format, ...); +int sscanf(const char *str, const char *format, ...); +int fscanf(const char *str, const char *format, ...); + +///// Test code ///// + +int main(int argc, char **argv) +{ + + // BAD, do not use scanf without specifying a length first + char buf1[10]; + scanf("%s", buf1); + + // GOOD, length is specified + char buf2[10]; + sscanf(buf2, "%9s"); + + // BAD, do not use scanf without specifying a length first + char file[10]; + fscanf(file, "%s", buf2); + + return 0; +} diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/semmle/tests/MemoryUnsafeFunctionScan.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/semmle/tests/MemoryUnsafeFunctionScan.expected new file mode 100644 index 000000000000..701fd4320b0f --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/semmle/tests/MemoryUnsafeFunctionScan.expected @@ -0,0 +1,2 @@ +| MemoryUnsafeFunctionScan.cpp:14:5:14:9 | call to scanf | Dangerous use of one of the scanf functions | +| MemoryUnsafeFunctionScan.cpp:22:5:22:10 | call to fscanf | Dangerous use of one of the scanf functions | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/semmle/tests/MemoryUnsafeFunctionScan.qlref b/cpp/ql/test/experimental/query-tests/Security/CWE/semmle/tests/MemoryUnsafeFunctionScan.qlref new file mode 100644 index 000000000000..428d988a161d --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/semmle/tests/MemoryUnsafeFunctionScan.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-120/MemoryUnsafeFunctionScan.ql \ No newline at end of file diff --git a/cpp/ql/test/header-variant-tests/deduplication/functions.expected b/cpp/ql/test/header-variant-tests/deduplication/functions.expected index a5ffe6852907..b55bfa8856fb 100644 --- a/cpp/ql/test/header-variant-tests/deduplication/functions.expected +++ b/cpp/ql/test/header-variant-tests/deduplication/functions.expected @@ -7,6 +7,8 @@ | foo.h:1:13:1:15 | foo | Function | 1 | | | foo.h:1:13:1:15 | foo | MemberFunction | 1 | C | | foo.h:1:13:1:15 | foo | MemberFunction | 1 | C | +| main2.cpp:7:7:7:7 | C | MemberFunction | 0 | C | +| main2.cpp:7:7:7:7 | C | MemberFunction | 0 | C | | main2.cpp:7:7:7:7 | operator= | MemberFunction | 0 | C | | main2.cpp:7:7:7:7 | operator= | MemberFunction | 0 | C | | main2.cpp:7:7:7:7 | operator= | MemberFunction | 0 | C | diff --git a/cpp/ql/test/library-tests/access/canAccessMember/canAccessMember.expected b/cpp/ql/test/library-tests/access/canAccessMember/canAccessMember.expected index 9238c6182984..72beb5a1913e 100644 --- a/cpp/ql/test/library-tests/access/canAccessMember/canAccessMember.expected +++ b/cpp/ql/test/library-tests/access/canAccessMember/canAccessMember.expected @@ -8,89 +8,143 @@ | direct_friend::D::f | Can access D::f | | direct_friend::D::f | Can access D::operator= | | direct_friend::D::f | Can access D::x | +| field_and_base::P::f | Can access B::B | | field_and_base::P::f | Can access B::operator= | +| field_and_base::P::f | Can access P::B | +| field_and_base::P::f | Can access P::P | | field_and_base::P::f | Can access P::f | | field_and_base::P::f | Can access P::fieldB | | field_and_base::P::f | Can access P::m | | field_and_base::P::f | Can access P::m_static | | field_and_base::P::f | Can access P::operator= | +| friend_class::B::fun | Can access B::B | | friend_class::B::fun | Can access B::a | | friend_class::B::fun | Can access B::b | | friend_class::B::fun | Can access B::fun | | friend_class::B::fun | Can access B::operator= | +| friend_class::B::fun | Can access C::C | | friend_class::B::fun | Can access C::operator= | +| friend_class::B::fun | Can access D1::D1 | | friend_class::B::fun | Can access D1::operator= | +| friend_class::B::fun | Can access D2::D2 | | friend_class::B::fun | Can access D2::operator= | +| friend_class::C::fun | Can access B::B | | friend_class::C::fun | Can access B::operator= | +| friend_class::C::fun | Can access C::B | +| friend_class::C::fun | Can access C::C | | friend_class::C::fun | Can access C::fun | | friend_class::C::fun | Can access C::operator= | | friend_class::C::fun | Can access C::x | | friend_class::C::fun | Can access C::y | +| friend_class::C::fun | Can access D1::D1 | | friend_class::C::fun | Can access D1::operator= | +| friend_class::C::fun | Can access D2::D2 | | friend_class::C::fun | Can access D2::operator= | +| friend_class::D1::fun | Can access B::B | | friend_class::D1::fun | Can access B::a | | friend_class::D1::fun | Can access B::b | | friend_class::D1::fun | Can access B::fun | | friend_class::D1::fun | Can access B::operator= | +| friend_class::D1::fun | Can access C::C | | friend_class::D1::fun | Can access C::operator= | +| friend_class::D1::fun | Can access D1::C | +| friend_class::D1::fun | Can access D1::D1 | | friend_class::D1::fun | Can access D1::fun | | friend_class::D1::fun | Can access D1::operator= | +| friend_class::D1::fun | Can access D2::D2 | | friend_class::D1::fun | Can access D2::operator= | +| friend_class::D2::fun | Can access B::B | | friend_class::D2::fun | Can access B::a | | friend_class::D2::fun | Can access B::b | | friend_class::D2::fun | Can access B::fun | | friend_class::D2::fun | Can access B::operator= | +| friend_class::D2::fun | Can access C::C | | friend_class::D2::fun | Can access C::operator= | +| friend_class::D2::fun | Can access D1::D1 | | friend_class::D2::fun | Can access D1::operator= | +| friend_class::D2::fun | Can access D2::B | +| friend_class::D2::fun | Can access D2::D2 | | friend_class::D2::fun | Can access D2::a | | friend_class::D2::fun | Can access D2::b | | friend_class::D2::fun | Can access D2::fun | | friend_class::D2::fun | Can access D2::operator= | | friend_fun::fun1 | Can access A::operator= | +| friend_fun::fun1 | Can access B::B | | friend_fun::fun1 | Can access B::operator= | | friend_fun::fun2 | Can access A::operator= | +| friend_fun::fun2 | Can access B::B | | friend_fun::fun2 | Can access B::operator= | | friend_fun::fun2 | Can access B::x | | friend_fun::fun2 | Can access B::y | +| mixed::B::fun | Can access A::A | | mixed::B::fun | Can access A::operator= | +| mixed::B::fun | Can access B::A | +| mixed::B::fun | Can access B::B | | mixed::B::fun | Can access B::fun | | mixed::B::fun | Can access B::operator= | +| mixed::B::fun | Can access C::C | | mixed::B::fun | Can access C::operator= | +| mixed::B::fun | Can access D::C | +| mixed::B::fun | Can access D::D | | mixed::B::fun | Can access D::operator= | +| mixed::C::fun | Can access A::A | | mixed::C::fun | Can access A::operator= | +| mixed::C::fun | Can access B::B | | mixed::C::fun | Can access B::operator= | +| mixed::C::fun | Can access C::B | +| mixed::C::fun | Can access C::C | | mixed::C::fun | Can access C::fun | | mixed::C::fun | Can access C::operator= | +| mixed::C::fun | Can access D::B | +| mixed::C::fun | Can access D::C | +| mixed::C::fun | Can access D::D | | mixed::C::fun | Can access D::fun | | mixed::C::fun | Can access D::operator= | +| mixed::D::fun | Can access A::A | | mixed::D::fun | Can access A::operator= | +| mixed::D::fun | Can access B::B | | mixed::D::fun | Can access B::operator= | +| mixed::D::fun | Can access C::B | +| mixed::D::fun | Can access C::C | | mixed::D::fun | Can access C::operator= | +| mixed::D::fun | Can access D::B | +| mixed::D::fun | Can access D::C | +| mixed::D::fun | Can access D::D | | mixed::D::fun | Can access D::fun | | mixed::D::fun | Can access D::operator= | | protected_derived::BP::f | Can access B::m | | protected_derived::BP::f | Can access B::operator= | +| protected_derived::BP::f | Can access BN::BN | | protected_derived::BP::f | Can access BN::operator= | +| protected_derived::BP::f | Can access BP::BP | | protected_derived::BP::f | Can access BP::f | | protected_derived::BP::f | Can access BP::m | | protected_derived::BP::f | Can access BP::operator= | +| protected_derived::BP::f | Can access BPNprot::BPNprot | | protected_derived::BP::f | Can access BPNprot::operator= | +| protected_derived::BP::f | Can access BPNpub::BP | +| protected_derived::BP::f | Can access BPNpub::BPNpub | | protected_derived::BP::f | Can access BPNpub::f | | protected_derived::BP::f | Can access BPNpub::m | | protected_derived::BP::f | Can access BPNpub::operator= | +| protected_virtual::P::f | Can access B::B | | protected_virtual::P::f | Can access B::operator= | | protected_virtual::P::f | Can access Nprot::Nprot | | protected_virtual::P::f | Can access Nprot::operator= | +| protected_virtual::P::f | Can access Npub::B | | protected_virtual::P::f | Can access Npub::Npub | | protected_virtual::P::f | Can access Npub::m | | protected_virtual::P::f | Can access Npub::operator= | +| protected_virtual::P::f | Can access P::B | | protected_virtual::P::f | Can access P::P | | protected_virtual::P::f | Can access P::f | | protected_virtual::P::f | Can access P::m | | protected_virtual::P::f | Can access P::operator= | | simple::Derived::castme | Can access Base::operator= | +| simple::Derived::castme | Can access Derived::Derived | | simple::Derived::castme | Can access Derived::castme | | simple::Derived::castme | Can access Derived::operator= | | simple::top | Can access Base::operator= | +| simple::top | Can access Derived::Derived | | simple::top | Can access Derived::castme | | simple::top | Can access Derived::operator= | diff --git a/cpp/ql/test/library-tests/complex_numbers/expr.ql b/cpp/ql/test/library-tests/complex_numbers/expr.ql index 0f2e6f14d4e7..83c6dca9c64d 100644 --- a/cpp/ql/test/library-tests/complex_numbers/expr.ql +++ b/cpp/ql/test/library-tests/complex_numbers/expr.ql @@ -1,4 +1,4 @@ import cpp from Expr e -select e, e.getCanonicalQLClass() +select e, e.getAPrimaryQlClass() diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp index 9836f7fb20df..cd8b0daf6f30 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp @@ -149,3 +149,63 @@ void test_conflated_fields2() { taint_x(&p); y_to_sink(&p); } + +void sink(Point*); +void sink(Point); + +void test_field_to_obj_taint_object(Point p) { + p.x = getenv("VAR")[0]; + sink(p); // not tainted + sink(p.x); // tainted +} + +void test_field_to_obj_taint_object_addrof(Point p) { + taint_x(&p); + sink(p); // tainted [field -> object] + sink(&p); // tainted [field -> object] + sink(p.x); // tainted +} + +void test_field_to_obj_taint_pointer(Point* pp) { + pp->x = getenv("VAR")[0]; + sink(pp); // tainted [field -> object] + sink(*pp); // not tainted +} + +void call_sink_on_object(Point* pp) { + sink(pp); // tainted [field -> object] + sink(*pp); // tainted [field -> object] +} + +void test_field_to_obj_taint_call_sink(Point* pp) { + pp->x = getenv("VAR")[0]; + call_sink_on_object(pp); +} + +void test_field_to_obj_taint_through_setter(Point* pp) { + taint_x(pp); + sink(pp); // tainted [field -> object] + sink(*pp); // not tainted +} + +Point* getPoint(); + +void test_field_to_obj_local_variable() { + Point* pp = getPoint(); + pp->x = getenv("VAR")[0]; + sink(pp); // not tainted + sink(*pp); // not tainted +} + +void test_field_to_obj_taint_array(Point* pp, int i) { + pp[0].x = getenv("VAR")[0]; + sink(pp[i]); // not tainted + sink(pp); // tainted [field -> object] + sink(*pp); // not tainted +} + +void test_field_to_obj_test_pointer_arith(Point* pp) { + (pp + sizeof(*pp))->x = getenv("VAR")[0]; + sink(pp); // tainted [field -> object] + sink(pp + sizeof(*pp)); // tainted [field -> object] +} \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/stl.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/stl.cpp similarity index 79% rename from cpp/ql/test/library-tests/dataflow/taint-tests/stl.cpp rename to cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/stl.cpp index d92bb39d1584..3454e6ac9472 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/stl.cpp +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/stl.cpp @@ -1,4 +1,6 @@ +#include "shared.h" + typedef unsigned long size_t; namespace std @@ -57,8 +59,7 @@ namespace std using stringstream = basic_stringstream; } -char *source(); -void sink(const char *s) {}; +char *source() { return getenv("USERDATA"); } void sink(const std::string &s) {}; void sink(const std::stringstream &s) {}; @@ -70,9 +71,9 @@ void test_string() sink(a); // tainted sink(b); - sink(c); // tainted + sink(c); // tainted [NOT DETECTED] sink(b.c_str()); - sink(c.c_str()); // tainted + sink(c.c_str()); // tainted [NOT DETECTED] } void test_stringstream() @@ -87,14 +88,14 @@ void test_stringstream() ss5 << t; sink(ss1); - sink(ss2); // tainted [NOT DETECTED] + sink(ss2); // tainted sink(ss3); // tainted [NOT DETECTED] - sink(ss4); // tainted [NOT DETECTED] + sink(ss4); // tainted sink(ss5); // tainted [NOT DETECTED] sink(ss1.str()); - sink(ss2.str()); // tainted [NOT DETECTED] + sink(ss2.str()); // tainted sink(ss3.str()); // tainted [NOT DETECTED] - sink(ss4.str()); // tainted [NOT DETECTED] + sink(ss4.str()); // tainted sink(ss5.str()); // tainted [NOT DETECTED] } @@ -122,12 +123,37 @@ void sink(const char *filename, const char *mode); void test_strings2() { string path1 = user_input(); - sink(path1.c_str(), "r"); // tainted + sink(path1.c_str(), "r"); // tainted [NOT DETECTED] string path2; path2 = user_input(); sink(path2.c_str(), "r"); // tainted string path3(user_input()); - sink(path3.c_str(), "r"); // tainted + sink(path3.c_str(), "r"); // tainted [NOT DETECTED] +} + +void test_string3() +{ + const char *cs = source(); + + // convert char * -> std::string + std::string ss(cs); + + sink(cs); // tainted + sink(ss); // tainted [NOT DETECTED] +} + +void test_string4() +{ + const char *cs = source(); + + // convert char * -> std::string + std::string ss(cs); + + // convert back std::string -> char * + cs = ss.c_str(); + + sink(cs); // tainted [NOT DETECTED] + sink(ss); // tainted [NOT DETECTED] } diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected index 4a87761da6fa..83f50d7fe157 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected @@ -112,9 +112,28 @@ | defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:140:11:140:16 | call to getenv | | defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:140:11:140:26 | (int)... | | defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:140:11:140:26 | access to array | -| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:143:23:143:24 | pp | -| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:144:8:144:9 | pp | -| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:150:13:150:14 | & ... | +| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:166:10:166:10 | x | +| defaulttainttracking.cpp:140:11:140:16 | call to getenv | shared.h:6:15:6:23 | sinkparam | +| defaulttainttracking.cpp:157:9:157:14 | call to getenv | defaulttainttracking.cpp:157:9:157:14 | call to getenv | +| defaulttainttracking.cpp:157:9:157:14 | call to getenv | defaulttainttracking.cpp:157:9:157:24 | (int)... | +| defaulttainttracking.cpp:157:9:157:14 | call to getenv | defaulttainttracking.cpp:157:9:157:24 | access to array | +| defaulttainttracking.cpp:157:9:157:14 | call to getenv | defaulttainttracking.cpp:159:10:159:10 | x | +| defaulttainttracking.cpp:157:9:157:14 | call to getenv | shared.h:6:15:6:23 | sinkparam | +| defaulttainttracking.cpp:170:11:170:16 | call to getenv | defaulttainttracking.cpp:170:11:170:16 | call to getenv | +| defaulttainttracking.cpp:170:11:170:16 | call to getenv | defaulttainttracking.cpp:170:11:170:26 | (int)... | +| defaulttainttracking.cpp:170:11:170:16 | call to getenv | defaulttainttracking.cpp:170:11:170:26 | access to array | +| defaulttainttracking.cpp:181:11:181:16 | call to getenv | defaulttainttracking.cpp:181:11:181:16 | call to getenv | +| defaulttainttracking.cpp:181:11:181:16 | call to getenv | defaulttainttracking.cpp:181:11:181:26 | (int)... | +| defaulttainttracking.cpp:181:11:181:16 | call to getenv | defaulttainttracking.cpp:181:11:181:26 | access to array | +| defaulttainttracking.cpp:195:11:195:16 | call to getenv | defaulttainttracking.cpp:195:11:195:16 | call to getenv | +| defaulttainttracking.cpp:195:11:195:16 | call to getenv | defaulttainttracking.cpp:195:11:195:26 | (int)... | +| defaulttainttracking.cpp:195:11:195:16 | call to getenv | defaulttainttracking.cpp:195:11:195:26 | access to array | +| defaulttainttracking.cpp:201:13:201:18 | call to getenv | defaulttainttracking.cpp:201:13:201:18 | call to getenv | +| defaulttainttracking.cpp:201:13:201:18 | call to getenv | defaulttainttracking.cpp:201:13:201:28 | (int)... | +| defaulttainttracking.cpp:201:13:201:18 | call to getenv | defaulttainttracking.cpp:201:13:201:28 | access to array | +| defaulttainttracking.cpp:208:27:208:32 | call to getenv | defaulttainttracking.cpp:208:27:208:32 | call to getenv | +| defaulttainttracking.cpp:208:27:208:32 | call to getenv | defaulttainttracking.cpp:208:27:208:42 | (int)... | +| defaulttainttracking.cpp:208:27:208:32 | call to getenv | defaulttainttracking.cpp:208:27:208:42 | access to array | | dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:28:24:28:27 | call to atoi | | dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:28:29:28:34 | call to getenv | | dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:28:29:28:45 | (const char *)... | @@ -153,6 +172,71 @@ | globals.cpp:13:15:13:20 | call to getenv | globals.cpp:13:15:13:20 | call to getenv | | globals.cpp:23:15:23:20 | call to getenv | globals.cpp:16:15:16:21 | global2 | | globals.cpp:23:15:23:20 | call to getenv | globals.cpp:23:15:23:20 | call to getenv | +| stl.cpp:62:25:62:30 | call to getenv | shared.h:5:23:5:31 | sinkparam | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:21:29:21:29 | s | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:43:78:43:104 | p#0 | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:43:114:43:118 | p#1 | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:62:25:62:30 | call to getenv | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:64:36:64:36 | s | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:68:8:68:8 | a | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:68:12:68:17 | call to source | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:21 | call to source | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:23 | (const char *)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:24 | call to basic_string | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:72:7:72:7 | (const char *)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:72:7:72:7 | a | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:21 | call to source | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:23 | (const char *)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:24 | call to basic_string | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:6:85:6 | call to operator<< | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:6:85:17 | (reference dereference) | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:9:85:14 | call to source | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:9:85:16 | (const char *)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:15:86:15 | call to operator<< | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:15:86:26 | (reference dereference) | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:18:86:23 | call to source | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:18:86:25 | (const char *)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:6:87:6 | call to operator<< | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:6:87:19 | (reference dereference) | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:6:87:19 | (reference to) | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:9:87:14 | call to source | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:9:87:16 | (const char *)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:18:87:18 | call to operator<< | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:18:87:26 | (reference dereference) | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | (const stringstream)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | (reference to) | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | ss2 | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | (const stringstream)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | (reference to) | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | ss4 | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:9 | (const basic_stringstream, allocator>)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:9 | ss2 | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:9 | (const basic_stringstream, allocator>)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:9 | ss4 | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:118:10:118:15 | call to source | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:16:125:28 | call to basic_string | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:17:125:26 | call to user_input | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:17:125:28 | (const char *)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:128:9:128:13 | path2 | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:19 | call to user_input | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | (const char *)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | call to basic_string | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:7:130:11 | (const basic_string, allocator>)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:7:130:11 | path2 | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:24 | call to user_input | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:26 | (const char *)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:27 | call to basic_string | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:138:14:138:15 | cs | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:138:19:138:24 | call to source | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:138:19:138:26 | (const char *)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:141:17:141:18 | cs | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:141:17:141:19 | call to basic_string | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:143:7:143:8 | cs | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:149:14:149:15 | cs | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:149:19:149:24 | call to source | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:149:19:149:26 | (const char *)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:152:17:152:18 | cs | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:152:17:152:19 | call to basic_string | | test_diff.cpp:92:10:92:13 | argv | shared.h:5:23:5:31 | sinkparam | | test_diff.cpp:92:10:92:13 | argv | test_diff.cpp:92:10:92:13 | argv | | test_diff.cpp:92:10:92:13 | argv | test_diff.cpp:92:10:92:16 | (const char *)... | diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected index 79b02cd9d608..414ee9623e59 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected @@ -26,11 +26,53 @@ | defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:134:10:134:10 | x | IR only | | defaulttainttracking.cpp:133:9:133:14 | call to getenv | shared.h:6:15:6:23 | sinkparam | IR only | | defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:140:7:140:7 | x | AST only | -| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:143:23:143:24 | pp | IR only | -| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:144:8:144:9 | pp | IR only | -| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:150:13:150:14 | & ... | IR only | +| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:166:10:166:10 | x | IR only | +| defaulttainttracking.cpp:140:11:140:16 | call to getenv | shared.h:6:15:6:23 | sinkparam | IR only | +| defaulttainttracking.cpp:157:9:157:14 | call to getenv | defaulttainttracking.cpp:157:5:157:5 | x | AST only | +| defaulttainttracking.cpp:157:9:157:14 | call to getenv | defaulttainttracking.cpp:159:10:159:10 | x | IR only | +| defaulttainttracking.cpp:157:9:157:14 | call to getenv | shared.h:6:15:6:23 | sinkparam | IR only | +| defaulttainttracking.cpp:170:11:170:16 | call to getenv | defaulttainttracking.cpp:170:7:170:7 | x | AST only | +| defaulttainttracking.cpp:181:11:181:16 | call to getenv | defaulttainttracking.cpp:181:7:181:7 | x | AST only | +| defaulttainttracking.cpp:195:11:195:16 | call to getenv | defaulttainttracking.cpp:195:7:195:7 | x | AST only | +| defaulttainttracking.cpp:201:13:201:18 | call to getenv | defaulttainttracking.cpp:201:9:201:9 | x | AST only | +| defaulttainttracking.cpp:208:27:208:32 | call to getenv | defaulttainttracking.cpp:208:23:208:23 | x | AST only | | globals.cpp:13:15:13:20 | call to getenv | globals.cpp:13:5:13:11 | global1 | AST only | | globals.cpp:23:15:23:20 | call to getenv | globals.cpp:23:5:23:11 | global2 | AST only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:43:78:43:104 | p#0 | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:62:7:62:12 | source | AST only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:64:36:64:36 | s | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:24 | call to basic_string | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:24 | call to basic_string | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:6:85:6 | call to operator<< | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:6:85:17 | (reference dereference) | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:15:86:15 | call to operator<< | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:15:86:26 | (reference dereference) | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:6:87:6 | call to operator<< | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:6:87:19 | (reference dereference) | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:6:87:19 | (reference to) | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:9:87:16 | (const char *)... | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:18:87:18 | call to operator<< | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:18:87:26 | (reference dereference) | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | (const stringstream)... | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | (reference to) | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | ss2 | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | (const stringstream)... | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | (reference to) | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | ss4 | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:9 | (const basic_stringstream, allocator>)... | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:9 | ss2 | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:9 | (const basic_stringstream, allocator>)... | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:9 | ss4 | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:117:7:117:16 | user_input | AST only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:16:125:28 | call to basic_string | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:128:9:128:13 | path2 | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | call to basic_string | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:7:130:11 | (const basic_string, allocator>)... | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:7:130:11 | path2 | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:27 | call to basic_string | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:141:17:141:19 | call to basic_string | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:152:17:152:19 | call to basic_string | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:157:7:157:8 | cs | AST only | | test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:11:104:20 | (...) | IR only | | test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:36:24:36:24 | p | AST only | | test_diff.cpp:111:10:111:13 | argv | shared.h:5:23:5:31 | sinkparam | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/IRDataflowTestCommon.qll b/cpp/ql/test/library-tests/dataflow/dataflow-tests/IRDataflowTestCommon.qll index 58a1dd2672b1..7ea87aeb583b 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/IRDataflowTestCommon.qll +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/IRDataflowTestCommon.qll @@ -10,7 +10,7 @@ import semmle.code.cpp.ir.IR class TestBarrierGuard extends DataFlow::BarrierGuard { TestBarrierGuard() { this.(CallInstruction).getStaticCallTarget().getName() = "guarded" } - override predicate checks(Instruction checked, boolean isTrue) { + override predicate checksInstr(Instruction checked, boolean isTrue) { checked = this.(CallInstruction).getPositionalArgument(0) and isTrue = true } diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/clang.cpp b/cpp/ql/test/library-tests/dataflow/dataflow-tests/clang.cpp index 0ad17fb47afb..033bdfd1899e 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/clang.cpp +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/clang.cpp @@ -48,6 +48,6 @@ void following_pointers( int stackArray[2] = { source(), source() }; stackArray[0] = source(); - sink(stackArray); // no flow + sink(stackArray); // flow } diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected index d01f0daa6a24..901339c4f386 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected @@ -1,6 +1,5 @@ uniqueEnclosingCallable -uniqueTypeBound -uniqueTypeRepr +uniqueType uniqueNodeLocation missingLocation uniqueNodeToString @@ -15,7 +14,6 @@ postHasUniquePre uniquePostUpdate postIsInSameCallable reverseRead -storeIsPostUpdate argHasPostUpdate | lambdas.cpp:18:7:18:7 | a | ArgumentNode is missing PostUpdateNode. | | lambdas.cpp:25:2:25:2 | b | ArgumentNode is missing PostUpdateNode. | @@ -23,3 +21,69 @@ argHasPostUpdate | lambdas.cpp:38:2:38:2 | d | ArgumentNode is missing PostUpdateNode. | | lambdas.cpp:45:2:45:2 | e | ArgumentNode is missing PostUpdateNode. | | test.cpp:67:29:67:35 | source1 | ArgumentNode is missing PostUpdateNode. | +postWithInFlow +| BarrierGuard.cpp:49:6:49:6 | x [post update] | PostUpdateNode should not be the target of local flow. | +| BarrierGuard.cpp:60:7:60:7 | x [post update] | PostUpdateNode should not be the target of local flow. | +| clang.cpp:22:9:22:20 | sourceArray1 [inner post update] | PostUpdateNode should not be the target of local flow. | +| clang.cpp:28:22:28:23 | m1 [post update] | PostUpdateNode should not be the target of local flow. | +| clang.cpp:50:3:50:12 | stackArray [inner post update] | PostUpdateNode should not be the target of local flow. | +| clang.cpp:50:3:50:15 | access to array [post update] | PostUpdateNode should not be the target of local flow. | +| dispatch.cpp:60:3:60:14 | globalBottom [post update] | PostUpdateNode should not be the target of local flow. | +| dispatch.cpp:61:3:61:14 | globalMiddle [post update] | PostUpdateNode should not be the target of local flow. | +| dispatch.cpp:78:24:78:37 | call to allocateBottom [inner post update] | PostUpdateNode should not be the target of local flow. | +| dispatch.cpp:148:5:148:5 | f [post update] | PostUpdateNode should not be the target of local flow. | +| dispatch.cpp:168:8:168:8 | f [post update] | PostUpdateNode should not be the target of local flow. | +| example.c:24:9:24:9 | x [post update] | PostUpdateNode should not be the target of local flow. | +| example.c:24:20:24:20 | y [post update] | PostUpdateNode should not be the target of local flow. | +| example.c:26:9:26:9 | x [post update] | PostUpdateNode should not be the target of local flow. | +| example.c:26:19:26:24 | coords [inner post update] | PostUpdateNode should not be the target of local flow. | +| example.c:28:23:28:25 | pos [inner post update] | PostUpdateNode should not be the target of local flow. | +| globals.cpp:13:5:13:19 | flowTestGlobal1 [post update] | PostUpdateNode should not be the target of local flow. | +| globals.cpp:23:5:23:19 | flowTestGlobal2 [post update] | PostUpdateNode should not be the target of local flow. | +| lambdas.cpp:23:3:23:14 | v [post update] | PostUpdateNode should not be the target of local flow. | +| lambdas.cpp:43:3:43:3 | c [post update] | PostUpdateNode should not be the target of local flow. | +| ref.cpp:11:5:11:7 | lhs [post update] | PostUpdateNode should not be the target of local flow. | +| ref.cpp:11:5:11:7 | lhs [post update] | PostUpdateNode should not be the target of local flow. | +| ref.cpp:20:5:20:7 | lhs [post update] | PostUpdateNode should not be the target of local flow. | +| ref.cpp:22:7:22:9 | lhs [post update] | PostUpdateNode should not be the target of local flow. | +| ref.cpp:24:7:24:9 | lhs [post update] | PostUpdateNode should not be the target of local flow. | +| ref.cpp:29:5:29:7 | out [post update] | PostUpdateNode should not be the target of local flow. | +| ref.cpp:31:7:31:9 | out [post update] | PostUpdateNode should not be the target of local flow. | +| ref.cpp:39:7:39:9 | out [post update] | PostUpdateNode should not be the target of local flow. | +| ref.cpp:44:5:44:7 | out [post update] | PostUpdateNode should not be the target of local flow. | +| ref.cpp:46:7:46:9 | out [post update] | PostUpdateNode should not be the target of local flow. | +| ref.cpp:48:7:48:9 | out [post update] | PostUpdateNode should not be the target of local flow. | +| ref.cpp:75:9:75:11 | val [post update] | PostUpdateNode should not be the target of local flow. | +| ref.cpp:83:9:83:11 | val [post update] | PostUpdateNode should not be the target of local flow. | +| ref.cpp:87:11:87:13 | val [post update] | PostUpdateNode should not be the target of local flow. | +| ref.cpp:89:11:89:13 | val [post update] | PostUpdateNode should not be the target of local flow. | +| ref.cpp:94:9:94:11 | val [post update] | PostUpdateNode should not be the target of local flow. | +| ref.cpp:96:11:96:13 | val [post update] | PostUpdateNode should not be the target of local flow. | +| ref.cpp:104:11:104:13 | val [post update] | PostUpdateNode should not be the target of local flow. | +| ref.cpp:109:9:109:11 | val [post update] | PostUpdateNode should not be the target of local flow. | +| ref.cpp:113:11:113:13 | val [post update] | PostUpdateNode should not be the target of local flow. | +| ref.cpp:115:11:115:13 | val [post update] | PostUpdateNode should not be the target of local flow. | +| test.cpp:91:3:91:9 | source1 [post update] | PostUpdateNode should not be the target of local flow. | +| test.cpp:115:3:115:6 | * ... [post update] | PostUpdateNode should not be the target of local flow. | +| test.cpp:115:4:115:6 | out [inner post update] | PostUpdateNode should not be the target of local flow. | +| test.cpp:120:3:120:6 | * ... [post update] | PostUpdateNode should not be the target of local flow. | +| test.cpp:120:4:120:6 | out [inner post update] | PostUpdateNode should not be the target of local flow. | +| test.cpp:125:3:125:6 | * ... [post update] | PostUpdateNode should not be the target of local flow. | +| test.cpp:125:4:125:6 | out [inner post update] | PostUpdateNode should not be the target of local flow. | +| test.cpp:333:5:333:13 | globalVar [post update] | PostUpdateNode should not be the target of local flow. | +| test.cpp:347:5:347:13 | globalVar [post update] | PostUpdateNode should not be the target of local flow. | +| test.cpp:359:5:359:9 | field [post update] | PostUpdateNode should not be the target of local flow. | +| test.cpp:373:5:373:9 | field [post update] | PostUpdateNode should not be the target of local flow. | +| test.cpp:384:10:384:13 | ref arg & ... | PostUpdateNode should not be the target of local flow. | +| test.cpp:384:11:384:13 | tmp [inner post update] | PostUpdateNode should not be the target of local flow. | +| test.cpp:391:10:391:13 | ref arg & ... | PostUpdateNode should not be the target of local flow. | +| test.cpp:391:11:391:13 | tmp [inner post update] | PostUpdateNode should not be the target of local flow. | +| test.cpp:400:10:400:13 | ref arg & ... | PostUpdateNode should not be the target of local flow. | +| test.cpp:400:11:400:13 | tmp [inner post update] | PostUpdateNode should not be the target of local flow. | +| test.cpp:407:10:407:13 | ref arg & ... | PostUpdateNode should not be the target of local flow. | +| test.cpp:407:11:407:13 | tmp [inner post update] | PostUpdateNode should not be the target of local flow. | +| test.cpp:423:21:423:25 | local [inner post update] | PostUpdateNode should not be the target of local flow. | +| test.cpp:436:19:436:23 | local [inner post update] | PostUpdateNode should not be the target of local flow. | +| test.cpp:465:3:465:4 | * ... [post update] | PostUpdateNode should not be the target of local flow. | +| test.cpp:465:4:465:4 | p [inner post update] | PostUpdateNode should not be the target of local flow. | +| test.cpp:470:22:470:22 | x [inner post update] | PostUpdateNode should not be the target of local flow. | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected index 0bb9343dcaf8..038a138b2c0b 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected @@ -1,6 +1,5 @@ uniqueEnclosingCallable -uniqueTypeBound -uniqueTypeRepr +uniqueType uniqueNodeLocation | BarrierGuard.cpp:2:11:2:13 | p#0 | Node should have one location but has 6. | | acrossLinkTargets.cpp:2:11:2:13 | p#0 | Node should have one location but has 6. | @@ -28,9 +27,59 @@ localCallNodes postIsNotPre postHasUniquePre uniquePostUpdate -| ref.cpp:83:5:83:17 | Chi | Node has multiple PostUpdateNodes. | -| ref.cpp:109:5:109:22 | Chi | Node has multiple PostUpdateNodes. | postIsInSameCallable reverseRead -storeIsPostUpdate argHasPostUpdate +postWithInFlow +| BarrierGuard.cpp:49:3:49:17 | Chi | PostUpdateNode should not be the target of local flow. | +| BarrierGuard.cpp:60:3:60:18 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:28:3:28:34 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:34:22:34:27 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:34:32:34:37 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:39:32:39:37 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:39:42:39:47 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:43:35:43:40 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:43:51:43:51 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:49:25:49:30 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:49:35:49:40 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:50:3:50:26 | Chi | PostUpdateNode should not be the target of local flow. | +| example.c:17:19:17:22 | Chi | PostUpdateNode should not be the target of local flow. | +| example.c:17:21:17:21 | Chi | PostUpdateNode should not be the target of local flow. | +| example.c:24:2:24:30 | Chi | PostUpdateNode should not be the target of local flow. | +| example.c:24:13:24:30 | Chi | PostUpdateNode should not be the target of local flow. | +| example.c:26:2:26:25 | Chi | PostUpdateNode should not be the target of local flow. | +| file://:0:0:0:0 | Chi | PostUpdateNode should not be the target of local flow. | +| file://:0:0:0:0 | Chi | PostUpdateNode should not be the target of local flow. | +| file://:0:0:0:0 | Chi | PostUpdateNode should not be the target of local flow. | +| lambdas.cpp:13:12:13:12 | Chi | PostUpdateNode should not be the target of local flow. | +| lambdas.cpp:13:15:13:15 | Chi | PostUpdateNode should not be the target of local flow. | +| lambdas.cpp:28:10:31:2 | Chi | PostUpdateNode should not be the target of local flow. | +| lambdas.cpp:28:10:31:2 | Chi | PostUpdateNode should not be the target of local flow. | +| lambdas.cpp:43:3:43:14 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:11:5:11:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:20:5:20:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:22:7:22:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:24:7:24:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:29:5:29:18 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:31:7:31:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:39:7:39:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:44:5:44:18 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:46:7:46:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:48:7:48:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:75:5:75:17 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:83:5:83:17 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:87:7:87:17 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:89:7:89:17 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:94:5:94:22 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:96:7:96:17 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:104:7:104:17 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:109:5:109:22 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:113:7:113:17 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:115:7:115:17 | Chi | PostUpdateNode should not be the target of local flow. | +| test.cpp:91:3:91:18 | Chi | PostUpdateNode should not be the target of local flow. | +| test.cpp:115:3:115:17 | Chi | PostUpdateNode should not be the target of local flow. | +| test.cpp:120:3:120:10 | Chi | PostUpdateNode should not be the target of local flow. | +| test.cpp:125:3:125:11 | Chi | PostUpdateNode should not be the target of local flow. | +| test.cpp:359:5:359:20 | Chi | PostUpdateNode should not be the target of local flow. | +| test.cpp:373:5:373:20 | Chi | PostUpdateNode should not be the target of local flow. | +| test.cpp:465:3:465:15 | Chi | PostUpdateNode should not be the target of local flow. | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/localFlow.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/localFlow.expected index 78d20cbf7ae0..75cdaee69ac4 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/localFlow.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/localFlow.expected @@ -7,11 +7,15 @@ | example.c:17:19:17:22 | {...} | example.c:26:19:26:24 | coords | | example.c:24:2:24:7 | coords [post update] | example.c:26:2:26:7 | coords | | example.c:24:2:24:7 | coords [post update] | example.c:26:19:26:24 | coords | +| example.c:24:2:24:30 | ... = ... | example.c:24:9:24:9 | x [post update] | | example.c:24:13:24:18 | coords [post update] | example.c:24:2:24:7 | coords | | example.c:24:13:24:18 | coords [post update] | example.c:26:2:26:7 | coords | | example.c:24:13:24:18 | coords [post update] | example.c:26:19:26:24 | coords | | example.c:24:13:24:30 | ... = ... | example.c:24:2:24:30 | ... = ... | +| example.c:24:13:24:30 | ... = ... | example.c:24:20:24:20 | y [post update] | +| example.c:24:20:24:20 | y | example.c:24:13:24:30 | ... = ... | | example.c:24:24:24:30 | ... + ... | example.c:24:13:24:30 | ... = ... | +| example.c:26:2:26:25 | ... = ... | example.c:26:9:26:9 | x [post update] | | example.c:26:13:26:16 | call to getX | example.c:26:2:26:25 | ... = ... | | example.c:26:18:26:24 | ref arg & ... | example.c:26:2:26:7 | coords | | example.c:26:18:26:24 | ref arg & ... | example.c:26:19:26:24 | coords [inner post update] | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/ref.cpp b/cpp/ql/test/library-tests/dataflow/dataflow-tests/ref.cpp index 8e1ac7657ea4..52849a557843 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/ref.cpp +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/ref.cpp @@ -56,13 +56,13 @@ namespace withoutFields { sink(x1); // flow [FALSE POSITIVE from uninitialized] notAssign(x2, source()); - sink(x2); // no flow [FALSE POSITIVE from uninitialized] + sink(x2); // no flow [FALSE POSITIVE from uninitialized, FALSE POSITIVE by IR] sourceToParamWrapper(x3); sink(x3); // flow [FALSE POSITIVE from uninitialized] notSource(x4); - sink(x4); // no flow [FALSE POSITIVE from uninitialized] + sink(x4); // no flow [FALSE POSITIVE from uninitialized, FALSE POSITIVE by IR] } } diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp index bce01956dc73..25ab760cbcd9 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp @@ -428,7 +428,7 @@ void intPointerSourceCaller2() { int local[1]; intPointerSource(local); sink(local); // tainted - sink(*local); // clean + sink(*local); // tainted } void intArraySourceCaller() { @@ -441,7 +441,7 @@ void intArraySourceCaller2() { int local[2]; intArraySource(local, 2); sink(local); // tainted - sink(*local); // clean + sink(*local); // tainted } /////////////////////////////////////////////////////////////////////////////// @@ -468,5 +468,5 @@ void intOutparamSource(int *p) { void viaOutparam() { int x = 0; intOutparamSource(&x); - sink(x); // tainted [FALSE NEGATIVE] + sink(x); // tainted } \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.expected index 6ff83eb74b5f..fbe5a51298ed 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.expected @@ -16,6 +16,7 @@ | clang.cpp:30:27:30:34 | call to getFirst | clang.cpp:28:27:28:32 | call to source | | clang.cpp:37:10:37:11 | m2 | clang.cpp:34:32:34:37 | call to source | | clang.cpp:45:17:45:18 | m2 | clang.cpp:43:35:43:40 | call to source | +| clang.cpp:51:8:51:17 | stackArray | clang.cpp:50:19:50:24 | call to source | | dispatch.cpp:11:38:11:38 | x | dispatch.cpp:37:19:37:24 | call to source | | dispatch.cpp:11:38:11:38 | x | dispatch.cpp:45:18:45:23 | call to source | | dispatch.cpp:35:16:35:25 | call to notSource1 | dispatch.cpp:9:37:9:42 | call to source | @@ -79,12 +80,17 @@ | test.cpp:424:8:424:12 | local | test.cpp:423:20:423:25 | ref arg & ... | | test.cpp:430:8:430:12 | local | test.cpp:428:7:428:11 | local | | test.cpp:430:8:430:12 | local | test.cpp:429:20:429:24 | ref arg local | +| test.cpp:431:8:431:13 | * ... | test.cpp:428:7:428:11 | local | +| test.cpp:431:8:431:13 | * ... | test.cpp:429:20:429:24 | ref arg local | | test.cpp:437:8:437:12 | local | test.cpp:435:7:435:11 | local | | test.cpp:437:8:437:12 | local | test.cpp:436:18:436:23 | ref arg & ... | | test.cpp:443:8:443:12 | local | test.cpp:441:7:441:11 | local | | test.cpp:443:8:443:12 | local | test.cpp:442:18:442:22 | ref arg local | +| test.cpp:444:8:444:13 | * ... | test.cpp:441:7:441:11 | local | +| test.cpp:444:8:444:13 | * ... | test.cpp:442:18:442:22 | ref arg local | | test.cpp:450:9:450:22 | (statement expression) | test.cpp:449:26:449:32 | source1 | | test.cpp:461:8:461:12 | local | test.cpp:449:26:449:32 | source1 | +| test.cpp:471:8:471:8 | x | test.cpp:465:8:465:13 | call to source | | true_upon_entry.cpp:21:8:21:8 | x | true_upon_entry.cpp:17:11:17:16 | call to source | | true_upon_entry.cpp:29:8:29:8 | x | true_upon_entry.cpp:27:9:27:14 | call to source | | true_upon_entry.cpp:39:8:39:8 | x | true_upon_entry.cpp:33:11:33:16 | call to source | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected index d663862361cf..7d4bcf36adb2 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected @@ -2,6 +2,7 @@ | BarrierGuard.cpp:60:11:60:16 | BarrierGuard.cpp:62:14:62:14 | AST only | | clang.cpp:12:9:12:20 | clang.cpp:22:8:22:20 | AST only | | clang.cpp:39:42:39:47 | clang.cpp:41:18:41:19 | IR only | +| clang.cpp:50:19:50:24 | clang.cpp:51:8:51:17 | AST only | | dispatch.cpp:16:37:16:42 | dispatch.cpp:32:16:32:24 | IR only | | dispatch.cpp:16:37:16:42 | dispatch.cpp:40:15:40:23 | IR only | | dispatch.cpp:22:37:22:42 | dispatch.cpp:31:16:31:24 | IR only | @@ -19,13 +20,12 @@ | globals.cpp:13:23:13:28 | globals.cpp:12:10:12:24 | IR only | | globals.cpp:23:23:23:28 | globals.cpp:19:10:19:24 | IR only | | lambdas.cpp:8:10:8:15 | lambdas.cpp:21:3:21:6 | AST only | -| lambdas.cpp:43:7:43:12 | lambdas.cpp:46:7:46:7 | AST only | -| ref.cpp:29:11:29:16 | ref.cpp:62:10:62:11 | AST only | +| ref.cpp:44:11:44:16 | ref.cpp:65:10:65:11 | IR only | | ref.cpp:53:9:53:10 | ref.cpp:56:10:56:11 | AST only | | ref.cpp:53:13:53:14 | ref.cpp:59:10:59:11 | AST only | | ref.cpp:53:17:53:18 | ref.cpp:62:10:62:11 | AST only | | ref.cpp:53:21:53:22 | ref.cpp:65:10:65:11 | AST only | -| ref.cpp:55:23:55:28 | ref.cpp:56:10:56:11 | AST only | +| ref.cpp:58:19:58:24 | ref.cpp:59:10:59:11 | IR only | | test.cpp:75:7:75:8 | test.cpp:76:8:76:9 | AST only | | test.cpp:83:7:83:8 | test.cpp:84:8:84:18 | AST only | | test.cpp:83:7:83:8 | test.cpp:86:8:86:9 | AST only | @@ -41,11 +41,15 @@ | test.cpp:422:7:422:11 | test.cpp:424:8:424:12 | AST only | | test.cpp:423:20:423:25 | test.cpp:424:8:424:12 | AST only | | test.cpp:428:7:428:11 | test.cpp:430:8:430:12 | AST only | +| test.cpp:428:7:428:11 | test.cpp:431:8:431:13 | AST only | | test.cpp:429:20:429:24 | test.cpp:430:8:430:12 | AST only | +| test.cpp:429:20:429:24 | test.cpp:431:8:431:13 | AST only | | test.cpp:435:7:435:11 | test.cpp:437:8:437:12 | AST only | | test.cpp:436:18:436:23 | test.cpp:437:8:437:12 | AST only | | test.cpp:441:7:441:11 | test.cpp:443:8:443:12 | AST only | +| test.cpp:441:7:441:11 | test.cpp:444:8:444:13 | AST only | | test.cpp:442:18:442:22 | test.cpp:443:8:443:12 | AST only | +| test.cpp:442:18:442:22 | test.cpp:444:8:444:13 | AST only | | true_upon_entry.cpp:9:11:9:16 | true_upon_entry.cpp:13:8:13:8 | IR only | | true_upon_entry.cpp:62:11:62:16 | true_upon_entry.cpp:66:8:66:8 | IR only | | true_upon_entry.cpp:98:11:98:16 | true_upon_entry.cpp:105:8:105:8 | IR only | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected index f7cedc063eee..945bb7136ce6 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected @@ -44,6 +44,11 @@ | lambdas.cpp:29:3:29:6 | t | lambdas.cpp:8:10:8:15 | call to source | | lambdas.cpp:35:8:35:8 | a | lambdas.cpp:8:10:8:15 | call to source | | lambdas.cpp:41:8:41:8 | (reference dereference) | lambdas.cpp:8:10:8:15 | call to source | +| lambdas.cpp:46:7:46:7 | w | lambdas.cpp:43:7:43:12 | call to source | +| ref.cpp:56:10:56:11 | x1 | ref.cpp:55:23:55:28 | call to source | +| ref.cpp:59:10:59:11 | x2 | ref.cpp:58:19:58:24 | call to source | +| ref.cpp:62:10:62:11 | x3 | ref.cpp:29:11:29:16 | call to source | +| ref.cpp:65:10:65:11 | x4 | ref.cpp:44:11:44:16 | call to source | | ref.cpp:123:13:123:15 | val | ref.cpp:122:23:122:28 | call to source | | ref.cpp:126:13:126:15 | val | ref.cpp:125:19:125:24 | call to source | | ref.cpp:129:13:129:15 | val | ref.cpp:94:15:94:20 | call to source | @@ -77,6 +82,7 @@ | test.cpp:394:10:394:12 | tmp | test.cpp:388:53:388:59 | source1 | | test.cpp:450:9:450:22 | (statement expression) | test.cpp:449:26:449:32 | source1 | | test.cpp:461:8:461:12 | local | test.cpp:449:26:449:32 | source1 | +| test.cpp:471:8:471:8 | x | test.cpp:465:8:465:13 | call to source | | true_upon_entry.cpp:13:8:13:8 | x | true_upon_entry.cpp:9:11:9:16 | call to source | | true_upon_entry.cpp:21:8:21:8 | x | true_upon_entry.cpp:17:11:17:16 | call to source | | true_upon_entry.cpp:29:8:29:8 | x | true_upon_entry.cpp:27:9:27:14 | call to source | diff --git a/cpp/ql/test/library-tests/dataflow/fields/A.cpp b/cpp/ql/test/library-tests/dataflow/fields/A.cpp index ba6736520a9b..d65e900af960 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/A.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/A.cpp @@ -53,8 +53,8 @@ class A { B *b = new B(); b->set(new C1()); - sink(b->get()); // $ast $f-:ir - sink((new B(new C()))->get()); // $ast $f-:ir + sink(b->get()); // $ast $ir=55:12 + sink((new B(new C()))->get()); // $ast $ir } void f3() @@ -104,7 +104,7 @@ class A { if (C1 *c1 = dynamic_cast(c)) { - sink(c1->a); // $ast $ir + sink(c1->a); // $ast,ir } C *cc; if (C2 *c2 = dynamic_cast(c)) @@ -129,7 +129,7 @@ class A { B *b = new B(); f7(b); - sink(b->c); // $ast $f-:ir + sink(b->c); // $ast,ir } class D @@ -149,7 +149,7 @@ class A { B *b = new B(); D *d = new D(b, r()); - sink(d->b); // $ast=143:25 $ast=150:12 $f-:ir + sink(d->b); // $ast,ir=143:25 $ast,ir=150:12 sink(d->b->c); // $ast $f-:ir sink(b->c); // $ast,ir } diff --git a/cpp/ql/test/library-tests/dataflow/fields/C.cpp b/cpp/ql/test/library-tests/dataflow/fields/C.cpp index 896b754ff310..892d298a81d0 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/C.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/C.cpp @@ -26,9 +26,9 @@ class C void func() { - sink(s1); // $ast $f-:ir + sink(s1); // $ast $ir sink(s2); // $f-:ast $f-:ir - sink(s3); // $ast $f-:ir + sink(s3); // $ast $ir sink(s4); // $f-:ast $f-:ir } diff --git a/cpp/ql/test/library-tests/dataflow/fields/IRConfiguration.qll b/cpp/ql/test/library-tests/dataflow/fields/IRConfiguration.qll index 3451061436cf..41ddf5a17a8b 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/IRConfiguration.qll +++ b/cpp/ql/test/library-tests/dataflow/fields/IRConfiguration.qll @@ -18,7 +18,7 @@ class Conf extends Configuration { override predicate isSink(Node sink) { exists(Call c | c.getTarget().hasName("sink") and - c.getAnArgument() = sink.asExpr() + c.getAnArgument() = sink.asConvertedExpr() ) } diff --git a/cpp/ql/test/library-tests/dataflow/fields/Nodes.qll b/cpp/ql/test/library-tests/dataflow/fields/Nodes.qll new file mode 100644 index 000000000000..eb6f3247b82e --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/Nodes.qll @@ -0,0 +1,41 @@ +private import semmle.code.cpp.ir.dataflow.DataFlow as IR +private import semmle.code.cpp.dataflow.DataFlow as AST +private import cpp + +private newtype TNode = + TASTNode(AST::DataFlow::Node n) or + TIRNode(IR::DataFlow::Node n) + +class Node extends TNode { + string toString() { none() } + + IR::DataFlow::Node asIR() { none() } + + AST::DataFlow::Node asAST() { none() } + + Location getLocation() { none() } +} + +class ASTNode extends Node, TASTNode { + AST::DataFlow::Node n; + + ASTNode() { this = TASTNode(n) } + + override string toString() { result = n.toString() } + + override AST::DataFlow::Node asAST() { result = n } + + override Location getLocation() { result = n.getLocation() } +} + +class IRNode extends Node, TIRNode { + IR::DataFlow::Node n; + + IRNode() { this = TIRNode(n) } + + override string toString() { result = n.toString() } + + override IR::DataFlow::Node asIR() { result = n } + + override Location getLocation() { result = n.getLocation() } +} diff --git a/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp b/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp index f096692419be..df33dbb288e2 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp @@ -92,3 +92,116 @@ void nestedAssign() { w.s.m1 = user_input(); sink(w.s.m1); // $ast,ir } + +void addressOfField() { + S s; + s.m1 = user_input(); + + S s_copy = s; + int* px = &s_copy.m1; + sink(*px); // $f-:ast $ir +} + +void taint_a_ptr(int* pa) { + *pa = user_input(); +} + +void test_field_conflation_array_content() { + S s; + taint_a_ptr(&s.m1); + sink(s.m2); +} + +struct S_with_pointer { + int m1, m2; + int* data; +}; + +void pointer_deref(int* xs) { + taint_a_ptr(xs); + sink(xs[0]); // $f-:ast $ir +} + +void pointer_deref_sub(int* xs) { + taint_a_ptr(xs - 2); + sink(*(xs - 2)); // $f-:ast $ir +} + +void pointer_many_addrof_and_deref(int* xs) { + taint_a_ptr(xs); + sink(*&*&*xs); // $f-:ast $ir +} + +void pointer_unary_plus(int* xs) { + taint_a_ptr(+xs); + sink(*+xs); // $f-:ast $ir +} + +void pointer_member_index(S_with_pointer s) { + taint_a_ptr(s.data); + // `s.data` is points to all-aliased-memory + sink(s.data[0]); // $f-:ast,ir +} + +void member_array_different_field(S_with_pointer* s) { + taint_a_ptr(&s[0].m1); + sink(s[0].m2); +} + +struct S_with_array { + int m1, m2; + int data[10]; +}; + +void pointer_member_deref() { + S_with_array s; + taint_a_ptr(s.data); + sink(*s.data); // $ir,ast +} + +void array_member_deref() { + S_with_array s; + taint_a_ptr(s.data); + sink(s.data[0]); // $ir,ast +} + +struct S2 { + S s; + int m3; +}; + +void deep_member_field_dot() { + S2 s2; + taint_a_ptr(&s2.s.m1); + sink(s2.s.m1); // $ir,ast +} + +void deep_member_field_dot_different_fields() { + S2 s2; + taint_a_ptr(&s2.s.m1); + sink(s2.s.m2); +} + +void deep_member_field_dot_2() { + S2 s2; + taint_a_ptr(&s2.s.m1); + S2 s2_2 = s2; + sink(s2_2.s.m1); // $ir,ast +} + +void deep_member_field_dot_different_fields_2() { + S2 s2; + taint_a_ptr(&s2.s.m1); + S2 s2_2 = s2; + sink(s2_2.s.m2); +} + +void deep_member_field_arrow(S2 *ps2) { + taint_a_ptr(&ps2->s.m1); + sink(ps2->s.m1); // $ir,ast +} + +void deep_member_field_arrow_different_fields(S2 *ps2) { + taint_a_ptr(&ps2->s.m1); + sink(ps2->s.m2); +} \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/fields/arrays.cpp b/cpp/ql/test/library-tests/dataflow/fields/arrays.cpp new file mode 100644 index 000000000000..68290dc70770 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/arrays.cpp @@ -0,0 +1,51 @@ +void sink(void *o); +void *user_input(void); + +void local_array() { + void *arr[10] = { 0 }; + arr[0] = user_input(); + sink(arr[0]); // $ast,ir + sink(arr[1]); // $f+:ast + sink(*arr); // $ast,ir + sink(*&arr[0]); // $ast,ir +} + +void local_array_convoluted_assign() { + void *arr[10] = { 0 }; + *&arr[0] = user_input(); + sink(arr[0]); // $ast,ir + sink(arr[1]); // $f+:ast +} + +struct inner { + void *data; + int unrelated; +}; + +struct middle { + inner arr[10]; + inner *ptr; +}; + +struct outer { + middle nested; + middle *indirect; +}; + +void nested_array_1(outer o) { + o.nested.arr[1].data = user_input(); + sink(o.nested.arr[1].data); // $ast,ir + sink(o.nested.arr[0].data); // $f+:ast +} + +void nested_array_2(outer o) { + o.indirect->arr[1].data = user_input(); + sink(o.indirect->arr[1].data); // $ast $f-:ir + sink(o.indirect->arr[0].data); // $f+:ast +} + +void nested_array_3(outer o) { + o.indirect->ptr[1].data = user_input(); + sink(o.indirect->ptr[1].data); // $f-:ast,ir + sink(o.indirect->ptr[0].data); +} diff --git a/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp b/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp index 6a0d61f799a3..84c3b039cb90 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp @@ -48,19 +48,19 @@ struct S { void test_setDirectly() { S s; s.setDirectly(user_input()); - sink(s.getDirectly()); // $ast $f-:ir + sink(s.getDirectly()); // $ast $ir } void test_setIndirectly() { S s; s.setIndirectly(user_input()); - sink(s.getIndirectly()); // $ast $f-:ir + sink(s.getIndirectly()); // $ast $ir } void test_setThroughNonMember() { S s; s.setThroughNonMember(user_input()); - sink(s.getThroughNonMember()); // $ast $f-:ir + sink(s.getThroughNonMember()); // $ast $ir } void test_nonMemberSetA() { @@ -109,11 +109,11 @@ void test_outer_with_ptr(Outer *pouter) { sink(outer.inner_nested.a); // $ast,ir sink(outer.inner_ptr->a); // $ast $f-:ir - sink(outer.a); // $f-:ast $f-:ir + sink(outer.a); // $ast,ir sink(pouter->inner_nested.a); // $ast,ir sink(pouter->inner_ptr->a); // $ast $f-:ir - sink(pouter->a); // $f-:ast $f-:ir + sink(pouter->a); // $ast,ir } void test_outer_with_ref(Outer *pouter) { @@ -129,9 +129,9 @@ void test_outer_with_ref(Outer *pouter) { sink(outer.inner_nested.a); // $ast,ir sink(outer.inner_ptr->a); // $ast $f-:ir - sink(outer.a); // $ast $f-:ir + sink(outer.a); // $ast,ir sink(pouter->inner_nested.a); // $ast,ir sink(pouter->inner_ptr->a); // $ast $f-:ir - sink(pouter->a); // $ast $f-:ir + sink(pouter->a); // $ast,ir } diff --git a/cpp/ql/test/library-tests/dataflow/fields/complex.cpp b/cpp/ql/test/library-tests/dataflow/fields/complex.cpp index bc7ac3f341f8..cb55bdd28637 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/complex.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/complex.cpp @@ -39,17 +39,8 @@ void sink(int x) void bar(Outer &b) { - // The library correctly finds that the four `user_input` sources can make it - // to the `sink` calls, but it also finds some source/sink combinations that - // are impossible. Those false positives here are a consequence of how the - // shared data flow library overapproximates field flow. The library only - // tracks the final two fields (`f` and `inner`) and the length (3) of the field - // access path, and then it tracks that both `a_` and `b_` have followed `f.inner` - // in _some_ access path somewhere in the search. That makes the library conclude - // that there could be flow to `b.inner.f.a_` even when the flow was actually to - // `b.inner.f.b_`. - sink(b.inner.f.a()); // $ast=62:19 $f+:ast=63:19 $ast=64:19 $f+:ast=65:19 $f-:ir - sink(b.inner.f.b()); // $f+:ast=62:19 $ast=63:19 $f+:ast=64:19 $ast=65:19 $f-:ir + sink(b.inner.f.a()); // $ast=53:19 $ast=55:19 $ir=53:19 $ir=55:19 + sink(b.inner.f.b()); // $ast=54:19 $ast=56:19 $ir=54:19 $ir=56:19 } void foo() diff --git a/cpp/ql/test/library-tests/dataflow/fields/constructors.cpp b/cpp/ql/test/library-tests/dataflow/fields/constructors.cpp index 5179ea363957..4816180954ea 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/constructors.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/constructors.cpp @@ -25,8 +25,8 @@ class Foo void bar(Foo &f) { - sink(f.a()); //$ast=34:11 $ast=36:11 $f-:ir - sink(f.b()); //$ast=35:14 $ast=36:25 $f-:ir + sink(f.a()); //$ast=34:11 $ast=36:11 $ir=34:11 $ir=36:11 + sink(f.b()); //$ast=35:14 $ast=36:25 $ir=35:14 $ir=36:25 } void foo() diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected index 04a03e5fb254..49b12c14350b 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected @@ -1,16 +1,7 @@ uniqueEnclosingCallable | C.cpp:37:24:37:33 | 0 | Node should have one enclosing callable but has 0. | | C.cpp:37:24:37:33 | new | Node should have one enclosing callable but has 0. | -uniqueTypeBound -| complex.cpp:22:11:22:17 | constructor init of field f [post-this] | Node should have one type bound but has 0. | -| complex.cpp:22:11:22:17 | constructor init of field f [pre-this] | Node should have one type bound but has 0. | -| complex.cpp:25:7:25:7 | constructor init of field inner [post-this] | Node should have one type bound but has 0. | -| complex.cpp:25:7:25:7 | constructor init of field inner [pre-this] | Node should have one type bound but has 0. | -uniqueTypeRepr -| complex.cpp:22:11:22:17 | constructor init of field f [post-this] | Node should have one type representation but has 0. | -| complex.cpp:22:11:22:17 | constructor init of field f [pre-this] | Node should have one type representation but has 0. | -| complex.cpp:25:7:25:7 | constructor init of field inner [post-this] | Node should have one type representation but has 0. | -| complex.cpp:25:7:25:7 | constructor init of field inner [pre-this] | Node should have one type representation but has 0. | +uniqueType uniqueNodeLocation missingLocation uniqueNodeToString @@ -25,7 +16,6 @@ postHasUniquePre uniquePostUpdate postIsInSameCallable reverseRead -storeIsPostUpdate argHasPostUpdate | A.cpp:41:15:41:21 | new | ArgumentNode is missing PostUpdateNode. | | A.cpp:55:12:55:19 | new | ArgumentNode is missing PostUpdateNode. | @@ -40,6 +30,120 @@ argHasPostUpdate | D.cpp:43:24:43:40 | new | ArgumentNode is missing PostUpdateNode. | | D.cpp:50:24:50:40 | new | ArgumentNode is missing PostUpdateNode. | | D.cpp:57:25:57:41 | new | ArgumentNode is missing PostUpdateNode. | +| arrays.cpp:7:8:7:13 | access to array | ArgumentNode is missing PostUpdateNode. | +| arrays.cpp:8:8:8:13 | access to array | ArgumentNode is missing PostUpdateNode. | +| arrays.cpp:9:8:9:11 | * ... | ArgumentNode is missing PostUpdateNode. | +| arrays.cpp:10:8:10:15 | * ... | ArgumentNode is missing PostUpdateNode. | +| arrays.cpp:16:8:16:13 | access to array | ArgumentNode is missing PostUpdateNode. | +| arrays.cpp:17:8:17:13 | access to array | ArgumentNode is missing PostUpdateNode. | | by_reference.cpp:51:8:51:8 | s | ArgumentNode is missing PostUpdateNode. | | by_reference.cpp:57:8:57:8 | s | ArgumentNode is missing PostUpdateNode. | | by_reference.cpp:63:8:63:8 | s | ArgumentNode is missing PostUpdateNode. | +postWithInFlow +| A.cpp:25:13:25:13 | c [post update] | PostUpdateNode should not be the target of local flow. | +| A.cpp:27:28:27:28 | c [post update] | PostUpdateNode should not be the target of local flow. | +| A.cpp:42:11:42:12 | cc [inner post update] | PostUpdateNode should not be the target of local flow. | +| A.cpp:43:11:43:12 | ct [inner post update] | PostUpdateNode should not be the target of local flow. | +| A.cpp:100:9:100:9 | a [post update] | PostUpdateNode should not be the target of local flow. | +| A.cpp:142:10:142:10 | c [post update] | PostUpdateNode should not be the target of local flow. | +| A.cpp:143:13:143:13 | b [post update] | PostUpdateNode should not be the target of local flow. | +| A.cpp:183:7:183:10 | head [post update] | PostUpdateNode should not be the target of local flow. | +| A.cpp:184:13:184:16 | next [post update] | PostUpdateNode should not be the target of local flow. | +| B.cpp:35:13:35:17 | elem1 [post update] | PostUpdateNode should not be the target of local flow. | +| B.cpp:36:13:36:17 | elem2 [post update] | PostUpdateNode should not be the target of local flow. | +| B.cpp:46:13:46:16 | box1 [post update] | PostUpdateNode should not be the target of local flow. | +| C.cpp:24:11:24:12 | s3 [post update] | PostUpdateNode should not be the target of local flow. | +| D.cpp:9:21:9:24 | elem [post update] | PostUpdateNode should not be the target of local flow. | +| D.cpp:11:29:11:32 | elem [post update] | PostUpdateNode should not be the target of local flow. | +| D.cpp:16:21:16:23 | box [post update] | PostUpdateNode should not be the target of local flow. | +| D.cpp:18:29:18:31 | box [post update] | PostUpdateNode should not be the target of local flow. | +| D.cpp:30:13:30:16 | elem [post update] | PostUpdateNode should not be the target of local flow. | +| D.cpp:44:19:44:22 | elem [post update] | PostUpdateNode should not be the target of local flow. | +| D.cpp:57:5:57:12 | boxfield [post update] | PostUpdateNode should not be the target of local flow. | +| D.cpp:58:20:58:23 | elem [post update] | PostUpdateNode should not be the target of local flow. | +| E.cpp:33:19:33:19 | p [inner post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:9:6:9:7 | m1 [post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:13:5:13:6 | m1 [post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:17:5:17:6 | m1 [post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:25:18:25:19 | s1 [inner post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:37:8:37:9 | m1 [post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:42:6:42:7 | m1 [post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:49:9:49:10 | m1 [post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:54:6:54:7 | m1 [post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:60:6:60:7 | m1 [post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:72:5:72:6 | m1 [post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:79:6:79:7 | m1 [post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:86:5:86:6 | m1 [post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:92:7:92:8 | m1 [post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:98:5:98:6 | m1 [post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:106:3:106:5 | * ... [post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:106:4:106:5 | pa [inner post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:111:18:111:19 | m1 [inner post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:126:15:126:16 | xs [inner post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:136:16:136:17 | xs [inner post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:147:16:147:16 | s [inner post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:147:21:147:22 | m1 [inner post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:175:21:175:22 | m1 [inner post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:181:21:181:22 | m1 [inner post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:187:21:187:22 | m1 [inner post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:194:21:194:22 | m1 [inner post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:200:23:200:24 | m1 [inner post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:205:23:205:24 | m1 [inner post update] | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:6:3:6:5 | arr [inner post update] | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:6:3:6:8 | access to array [post update] | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:15:3:15:10 | * ... [post update] | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:15:5:15:7 | arr [inner post update] | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:36:12:36:14 | arr [inner post update] | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:36:19:36:22 | data [post update] | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:37:17:37:19 | arr [inner post update] | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:38:17:38:19 | arr [inner post update] | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:42:15:42:17 | arr [inner post update] | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:42:22:42:25 | data [post update] | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:43:20:43:22 | arr [inner post update] | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:44:20:44:22 | arr [inner post update] | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:48:15:48:17 | ptr [inner post update] | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:48:22:48:25 | data [post update] | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:49:20:49:22 | ptr [inner post update] | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:50:20:50:22 | ptr [inner post update] | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:12:8:12:8 | a [post update] | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:16:11:16:11 | a [post update] | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:68:18:68:18 | s [inner post update] | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:84:10:84:10 | a [post update] | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:88:9:88:9 | a [post update] | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:92:3:92:5 | * ... [post update] | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:92:4:92:5 | pa [inner post update] | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:96:3:96:4 | pa [post update] | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:102:28:102:39 | inner_nested [inner post update] | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:104:22:104:22 | a [inner post update] | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:106:30:106:41 | inner_nested [inner post update] | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:108:24:108:24 | a [inner post update] | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:123:28:123:36 | inner_ptr [inner post update] | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:127:30:127:38 | inner_ptr [inner post update] | PostUpdateNode should not be the target of local flow. | +| complex.cpp:11:22:11:23 | a_ [post update] | PostUpdateNode should not be the target of local flow. | +| complex.cpp:12:22:12:23 | b_ [post update] | PostUpdateNode should not be the target of local flow. | +| constructors.cpp:20:24:20:25 | a_ [post update] | PostUpdateNode should not be the target of local flow. | +| constructors.cpp:21:24:21:25 | b_ [post update] | PostUpdateNode should not be the target of local flow. | +| qualifiers.cpp:9:36:9:36 | a [post update] | PostUpdateNode should not be the target of local flow. | +| qualifiers.cpp:12:56:12:56 | a [post update] | PostUpdateNode should not be the target of local flow. | +| qualifiers.cpp:13:57:13:57 | a [post update] | PostUpdateNode should not be the target of local flow. | +| qualifiers.cpp:22:23:22:23 | a [post update] | PostUpdateNode should not be the target of local flow. | +| qualifiers.cpp:37:26:37:33 | call to getInner [inner post update] | PostUpdateNode should not be the target of local flow. | +| qualifiers.cpp:42:13:42:20 | call to getInner [inner post update] | PostUpdateNode should not be the target of local flow. | +| qualifiers.cpp:42:25:42:25 | a [post update] | PostUpdateNode should not be the target of local flow. | +| qualifiers.cpp:47:7:47:11 | outer [inner post update] | PostUpdateNode should not be the target of local flow. | +| qualifiers.cpp:47:27:47:27 | a [post update] | PostUpdateNode should not be the target of local flow. | +| realistic.cpp:49:13:49:15 | bar [inner post update] | PostUpdateNode should not be the target of local flow. | +| realistic.cpp:49:20:49:22 | baz [post update] | PostUpdateNode should not be the target of local flow. | +| realistic.cpp:53:13:53:15 | bar [inner post update] | PostUpdateNode should not be the target of local flow. | +| realistic.cpp:53:35:53:43 | bufferLen [post update] | PostUpdateNode should not be the target of local flow. | +| realistic.cpp:54:20:54:22 | bar [inner post update] | PostUpdateNode should not be the target of local flow. | +| realistic.cpp:60:16:60:18 | ref arg dst | PostUpdateNode should not be the target of local flow. | +| realistic.cpp:61:25:61:27 | bar [inner post update] | PostUpdateNode should not be the target of local flow. | +| realistic.cpp:65:25:65:27 | bar [inner post update] | PostUpdateNode should not be the target of local flow. | +| simple.cpp:20:24:20:25 | a_ [post update] | PostUpdateNode should not be the target of local flow. | +| simple.cpp:21:24:21:25 | b_ [post update] | PostUpdateNode should not be the target of local flow. | +| simple.cpp:65:7:65:7 | i [post update] | PostUpdateNode should not be the target of local flow. | +| simple.cpp:83:12:83:13 | f1 [post update] | PostUpdateNode should not be the target of local flow. | +| simple.cpp:92:7:92:7 | i [post update] | PostUpdateNode should not be the target of local flow. | +| struct_init.c:24:11:24:12 | ab [inner post update] | PostUpdateNode should not be the target of local flow. | +| struct_init.c:36:17:36:24 | nestedAB [inner post update] | PostUpdateNode should not be the target of local flow. | diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected index ba7e3bc01257..ce9ed1850808 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected @@ -1,14 +1,10 @@ uniqueEnclosingCallable -uniqueTypeBound -uniqueTypeRepr +uniqueType uniqueNodeLocation -| D.cpp:1:17:1:17 | o | Node should have one location but has 3. | -| by_reference.cpp:1:17:1:17 | o | Node should have one location but has 3. | | file://:0:0:0:0 | p#0 | Node should have one location but has 0. | | file://:0:0:0:0 | p#0 | Node should have one location but has 0. | | file://:0:0:0:0 | p#0 | Node should have one location but has 0. | | file://:0:0:0:0 | p#0 | Node should have one location but has 0. | -| qualifiers.cpp:1:17:1:17 | o | Node should have one location but has 3. | missingLocation | Nodes without location: 4 | uniqueNodeToString @@ -21,8 +17,134 @@ localCallNodes postIsNotPre postHasUniquePre | simple.cpp:65:5:65:22 | Store | PostUpdateNode should have one pre-update node but has 0. | +| simple.cpp:92:5:92:22 | Store | PostUpdateNode should have one pre-update node but has 0. | uniquePostUpdate postIsInSameCallable reverseRead -storeIsPostUpdate argHasPostUpdate +postWithInFlow +| A.cpp:25:7:25:17 | Chi | PostUpdateNode should not be the target of local flow. | +| A.cpp:27:22:27:32 | Chi | PostUpdateNode should not be the target of local flow. | +| A.cpp:98:12:98:18 | Chi | PostUpdateNode should not be the target of local flow. | +| A.cpp:100:5:100:13 | Chi | PostUpdateNode should not be the target of local flow. | +| A.cpp:142:7:142:20 | Chi | PostUpdateNode should not be the target of local flow. | +| A.cpp:143:7:143:31 | Chi | PostUpdateNode should not be the target of local flow. | +| A.cpp:183:7:183:20 | Chi | PostUpdateNode should not be the target of local flow. | +| A.cpp:184:7:184:23 | Chi | PostUpdateNode should not be the target of local flow. | +| B.cpp:6:15:6:24 | Chi | PostUpdateNode should not be the target of local flow. | +| B.cpp:15:15:15:27 | Chi | PostUpdateNode should not be the target of local flow. | +| B.cpp:35:7:35:22 | Chi | PostUpdateNode should not be the target of local flow. | +| B.cpp:36:7:36:22 | Chi | PostUpdateNode should not be the target of local flow. | +| B.cpp:46:7:46:21 | Chi | PostUpdateNode should not be the target of local flow. | +| C.cpp:22:12:22:21 | Chi | PostUpdateNode should not be the target of local flow. | +| C.cpp:22:12:22:21 | Chi | PostUpdateNode should not be the target of local flow. | +| C.cpp:24:5:24:25 | Chi | PostUpdateNode should not be the target of local flow. | +| C.cpp:24:16:24:25 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:9:21:9:28 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:11:29:11:36 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:16:21:16:27 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:18:29:18:35 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:28:15:28:24 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:35:15:35:24 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:42:15:42:24 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:49:15:49:24 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:56:15:56:24 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:57:5:57:42 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:9:3:9:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:13:3:13:21 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:17:3:17:21 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:21:12:21:12 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:21:15:21:15 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:22:12:22:12 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:22:15:22:15 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:23:12:23:12 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:23:15:23:15 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:35:12:35:12 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:35:15:35:15 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:37:3:37:24 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:40:12:40:12 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:40:15:40:15 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:42:3:42:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:47:12:47:12 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:47:15:47:15 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:49:3:49:25 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:52:12:52:12 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:52:15:52:15 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:54:3:54:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:59:12:59:12 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:59:15:59:15 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:60:3:60:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:70:19:70:19 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:70:22:70:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:72:3:72:21 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:77:19:77:19 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:77:22:77:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:79:3:79:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:84:19:84:19 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:84:22:84:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:86:3:86:21 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:91:19:91:19 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:91:22:91:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:92:3:92:23 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:98:3:98:21 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:106:3:106:20 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:111:15:111:19 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:147:15:147:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:175:15:175:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:181:15:181:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:187:15:187:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:194:15:194:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:200:15:200:24 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:205:15:205:24 | Chi | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:5:18:5:23 | Chi | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:5:21:5:21 | Chi | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:6:3:6:23 | Chi | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:14:18:14:23 | Chi | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:14:21:14:21 | Chi | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:15:3:15:25 | Chi | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:36:3:36:37 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:12:5:12:16 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:16:5:16:19 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:84:3:84:25 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:88:3:88:24 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:92:3:92:20 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:96:3:96:19 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:102:21:102:39 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:104:15:104:22 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:106:21:106:41 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:108:15:108:24 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:122:21:122:38 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:124:15:124:21 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:126:21:126:40 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:128:15:128:23 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:11:22:11:27 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:12:22:12:27 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:14:26:14:26 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:14:33:14:33 | Chi | PostUpdateNode should not be the target of local flow. | +| constructors.cpp:20:24:20:29 | Chi | PostUpdateNode should not be the target of local flow. | +| constructors.cpp:21:24:21:29 | Chi | PostUpdateNode should not be the target of local flow. | +| constructors.cpp:23:28:23:28 | Chi | PostUpdateNode should not be the target of local flow. | +| constructors.cpp:23:35:23:35 | Chi | PostUpdateNode should not be the target of local flow. | +| qualifiers.cpp:9:30:9:44 | Chi | PostUpdateNode should not be the target of local flow. | +| qualifiers.cpp:12:49:12:64 | Chi | PostUpdateNode should not be the target of local flow. | +| qualifiers.cpp:13:51:13:65 | Chi | PostUpdateNode should not be the target of local flow. | +| realistic.cpp:39:12:39:95 | Chi | PostUpdateNode should not be the target of local flow. | +| realistic.cpp:49:9:49:64 | Chi | PostUpdateNode should not be the target of local flow. | +| simple.cpp:20:24:20:29 | Chi | PostUpdateNode should not be the target of local flow. | +| simple.cpp:21:24:21:29 | Chi | PostUpdateNode should not be the target of local flow. | +| simple.cpp:23:28:23:28 | Chi | PostUpdateNode should not be the target of local flow. | +| simple.cpp:23:35:23:35 | Chi | PostUpdateNode should not be the target of local flow. | +| simple.cpp:65:5:65:22 | Store | PostUpdateNode should not be the target of local flow. | +| simple.cpp:83:9:83:28 | Chi | PostUpdateNode should not be the target of local flow. | +| simple.cpp:92:5:92:22 | Store | PostUpdateNode should not be the target of local flow. | +| struct_init.c:20:20:20:29 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:20:34:20:34 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:27:7:27:16 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:27:21:27:21 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:28:5:28:7 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:36:10:36:24 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:40:20:40:29 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:40:34:40:34 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:42:7:42:16 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:42:21:42:21 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:43:5:43:7 | Chi | PostUpdateNode should not be the target of local flow. | diff --git a/cpp/ql/test/library-tests/dataflow/fields/flow-diff.expected b/cpp/ql/test/library-tests/dataflow/fields/flow-diff.expected new file mode 100644 index 000000000000..242c09f3a3bd --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/flow-diff.expected @@ -0,0 +1,45 @@ +| A.cpp:41:15:41:21 | new | A.cpp:43:10:43:12 | & ... | AST only | +| A.cpp:47:12:47:18 | new | A.cpp:49:13:49:13 | c | AST only | +| A.cpp:64:21:64:28 | new | A.cpp:66:14:66:14 | c | AST only | +| A.cpp:73:25:73:32 | new | A.cpp:75:14:75:14 | c | AST only | +| A.cpp:98:12:98:18 | new | A.cpp:120:16:120:16 | a | AST only | +| A.cpp:142:14:142:20 | new | A.cpp:153:16:153:16 | c | AST only | +| A.cpp:159:12:159:18 | new | A.cpp:165:26:165:29 | head | AST only | +| A.cpp:159:12:159:18 | new | A.cpp:169:15:169:18 | head | AST only | +| B.cpp:6:15:6:24 | new | B.cpp:9:20:9:24 | elem1 | AST only | +| B.cpp:15:15:15:27 | new | B.cpp:19:20:19:24 | elem2 | AST only | +| D.cpp:28:15:28:24 | new | D.cpp:22:25:22:31 | call to getElem | AST only | +| D.cpp:35:15:35:24 | new | D.cpp:22:25:22:31 | call to getElem | AST only | +| D.cpp:42:15:42:24 | new | D.cpp:22:25:22:31 | call to getElem | AST only | +| D.cpp:49:15:49:24 | new | D.cpp:22:25:22:31 | call to getElem | AST only | +| D.cpp:56:15:56:24 | new | D.cpp:64:25:64:28 | elem | AST only | +| E.cpp:28:21:28:23 | ref arg raw | E.cpp:31:10:31:12 | raw | AST only | +| E.cpp:29:24:29:29 | ref arg buffer | E.cpp:32:13:32:18 | buffer | AST only | +| E.cpp:30:28:30:33 | ref arg buffer | E.cpp:21:18:21:23 | buffer | AST only | +| aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | IR only | +| aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | IR only | +| aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | IR only | +| aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | IR only | +| aliasing.cpp:98:10:98:19 | call to user_input | aliasing.cpp:102:8:102:10 | * ... | IR only | +| aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:122:8:122:12 | access to array | IR only | +| aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:127:8:127:16 | * ... | IR only | +| aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:132:8:132:14 | * ... | IR only | +| aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:137:8:137:11 | * ... | IR only | +| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:8:8:8:13 | access to array | AST only | +| arrays.cpp:15:14:15:23 | call to user_input | arrays.cpp:17:8:17:13 | access to array | AST only | +| arrays.cpp:36:26:36:35 | call to user_input | arrays.cpp:38:24:38:27 | data | AST only | +| arrays.cpp:42:29:42:38 | call to user_input | arrays.cpp:43:27:43:30 | data | AST only | +| arrays.cpp:42:29:42:38 | call to user_input | arrays.cpp:44:27:44:30 | data | AST only | +| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:111:25:111:25 | a | AST only | +| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:115:27:115:27 | a | AST only | +| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:131:25:131:25 | a | AST only | +| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:135:27:135:27 | a | AST only | +| qualifiers.cpp:22:27:22:36 | call to user_input | qualifiers.cpp:23:23:23:23 | a | AST only | +| qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:28:23:28:23 | a | AST only | +| qualifiers.cpp:32:35:32:44 | call to user_input | qualifiers.cpp:33:23:33:23 | a | AST only | +| qualifiers.cpp:37:38:37:47 | call to user_input | qualifiers.cpp:38:23:38:23 | a | AST only | +| qualifiers.cpp:42:29:42:38 | call to user_input | qualifiers.cpp:43:23:43:23 | a | AST only | +| qualifiers.cpp:47:31:47:40 | call to user_input | qualifiers.cpp:48:23:48:23 | a | AST only | +| realistic.cpp:53:55:53:64 | call to user_input | realistic.cpp:61:47:61:55 | bufferLen | AST only | +| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:33:25:33:25 | a | AST only | +| struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/fields/flow-diff.ql b/cpp/ql/test/library-tests/dataflow/fields/flow-diff.ql new file mode 100644 index 000000000000..47bee0db4923 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/flow-diff.ql @@ -0,0 +1,31 @@ +/** + * @kind problem + */ + +import cpp +import Nodes +import IRConfiguration as IRConf +import ASTConfiguration as ASTConf +private import semmle.code.cpp.ir.dataflow.DataFlow as IR +private import semmle.code.cpp.dataflow.DataFlow as AST + +from Node source, Node sink, IRConf::Conf irConf, ASTConf::Conf astConf, string msg +where + irConf.hasFlow(source.asIR(), sink.asIR()) and + not exists(AST::DataFlow::Node astSource, AST::DataFlow::Node astSink | + astSource.asExpr() = source.asIR().asExpr() and + astSink.asExpr() = sink.asIR().asExpr() + | + astConf.hasFlow(astSource, astSink) + ) and + msg = "IR only" + or + astConf.hasFlow(source.asAST(), sink.asAST()) and + not exists(IR::DataFlow::Node irSource, IR::DataFlow::Node irSink | + irSource.asExpr() = source.asAST().asExpr() and + irSink.asExpr() = sink.asAST().asExpr() + | + irConf.hasFlow(irSource, irSink) + ) and + msg = "AST only" +select source, sink, msg diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected index 69c088fb260d..61770c0aca35 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected @@ -1,18 +1,40 @@ edges +| A.cpp:55:5:55:5 | set output argument [c] | A.cpp:56:13:56:15 | call to get | +| A.cpp:55:12:55:19 | (C *)... | A.cpp:55:5:55:5 | set output argument [c] | +| A.cpp:55:12:55:19 | new | A.cpp:55:5:55:5 | set output argument [c] | +| A.cpp:57:11:57:24 | B output argument [c] | A.cpp:57:28:57:30 | call to get | +| A.cpp:57:17:57:23 | new | A.cpp:57:11:57:24 | B output argument [c] | | A.cpp:98:12:98:18 | new | A.cpp:100:5:100:13 | Store | -| A.cpp:100:5:100:13 | Chi [a] | A.cpp:101:8:101:9 | Argument 0 indirection [a] | +| A.cpp:100:5:100:13 | Chi [a] | A.cpp:103:14:103:14 | *c [a] | | A.cpp:100:5:100:13 | Store | A.cpp:100:5:100:13 | Chi [a] | -| A.cpp:101:8:101:9 | Argument 0 indirection [a] | A.cpp:103:14:103:14 | *c [a] | | A.cpp:103:14:103:14 | *c [a] | A.cpp:107:16:107:16 | a | -| A.cpp:103:14:103:14 | *c [a] | A.cpp:107:16:107:16 | a | -| A.cpp:107:16:107:16 | a | A.cpp:107:12:107:16 | (void *)... | +| A.cpp:126:5:126:5 | Chi [c] | A.cpp:131:8:131:8 | f7 output argument [c] | +| A.cpp:126:5:126:5 | set output argument [c] | A.cpp:126:5:126:5 | Chi [c] | +| A.cpp:126:12:126:18 | new | A.cpp:126:5:126:5 | set output argument [c] | +| A.cpp:131:8:131:8 | Chi [c] | A.cpp:132:13:132:13 | c | +| A.cpp:131:8:131:8 | f7 output argument [c] | A.cpp:131:8:131:8 | Chi [c] | | A.cpp:142:7:142:20 | Chi [c] | A.cpp:151:18:151:18 | D output argument [c] | | A.cpp:142:7:142:20 | Store | A.cpp:142:7:142:20 | Chi [c] | | A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | Store | -| A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c | +| A.cpp:143:7:143:31 | Chi [b] | A.cpp:151:12:151:24 | D output argument [b] | +| A.cpp:143:7:143:31 | Store | A.cpp:143:7:143:31 | Chi [b] | +| A.cpp:143:25:143:31 | new | A.cpp:143:7:143:31 | Store | +| A.cpp:150:12:150:18 | new | A.cpp:151:12:151:24 | D output argument [b] | +| A.cpp:151:12:151:24 | Chi [b] | A.cpp:152:13:152:13 | b | +| A.cpp:151:12:151:24 | D output argument [b] | A.cpp:151:12:151:24 | Chi [b] | | A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c | | A.cpp:151:18:151:18 | D output argument [c] | A.cpp:151:18:151:18 | Chi [c] | -| A.cpp:154:13:154:13 | c | A.cpp:154:10:154:13 | (void *)... | +| C.cpp:18:12:18:18 | C output argument [s1] | C.cpp:27:8:27:11 | *#this [s1] | +| C.cpp:18:12:18:18 | C output argument [s3] | C.cpp:27:8:27:11 | *#this [s3] | +| C.cpp:22:12:22:21 | Chi [s1] | C.cpp:24:5:24:25 | Chi [s1] | +| C.cpp:22:12:22:21 | Store | C.cpp:22:12:22:21 | Chi [s1] | +| C.cpp:22:12:22:21 | new | C.cpp:22:12:22:21 | Store | +| C.cpp:24:5:24:25 | Chi [s1] | C.cpp:18:12:18:18 | C output argument [s1] | +| C.cpp:24:5:24:25 | Chi [s3] | C.cpp:18:12:18:18 | C output argument [s3] | +| C.cpp:24:5:24:25 | Store | C.cpp:24:5:24:25 | Chi [s3] | +| C.cpp:24:16:24:25 | new | C.cpp:24:5:24:25 | Store | +| C.cpp:27:8:27:11 | *#this [s1] | C.cpp:29:10:29:11 | s1 | +| C.cpp:27:8:27:11 | *#this [s3] | C.cpp:31:10:31:11 | s3 | | aliasing.cpp:9:3:9:22 | Chi [m1] | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | | aliasing.cpp:9:3:9:22 | Store | aliasing.cpp:9:3:9:22 | Chi [m1] | | aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | Store | @@ -32,9 +54,56 @@ edges | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | -| by_reference.cpp:68:17:68:18 | nonMemberSetA output argument [a] | by_reference.cpp:69:22:69:23 | Argument 0 indirection [a] | +| aliasing.cpp:98:3:98:21 | Chi [m1] | aliasing.cpp:100:14:100:14 | Store [m1] | +| aliasing.cpp:98:3:98:21 | Store | aliasing.cpp:98:3:98:21 | Chi [m1] | +| aliasing.cpp:98:10:98:19 | call to user_input | aliasing.cpp:98:3:98:21 | Store | +| aliasing.cpp:100:14:100:14 | Store [m1] | aliasing.cpp:102:8:102:10 | * ... | +| aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:121:15:121:16 | taint_a_ptr output argument [array content] | +| aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:126:15:126:20 | taint_a_ptr output argument [array content] | +| aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:131:15:131:16 | taint_a_ptr output argument [array content] | +| aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:136:15:136:17 | taint_a_ptr output argument [array content] | +| aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:158:15:158:20 | taint_a_ptr output argument [array content] | +| aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:164:15:164:20 | taint_a_ptr output argument [array content] | +| aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:175:15:175:22 | taint_a_ptr output argument [array content] | +| aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:187:15:187:22 | taint_a_ptr output argument [array content] | +| aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:200:15:200:24 | taint_a_ptr output argument [array content] | +| aliasing.cpp:106:3:106:20 | Store | aliasing.cpp:106:3:106:20 | Chi [array content] | +| aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:106:3:106:20 | Store | +| aliasing.cpp:121:15:121:16 | Chi [array content] | aliasing.cpp:122:8:122:12 | access to array | +| aliasing.cpp:121:15:121:16 | taint_a_ptr output argument [array content] | aliasing.cpp:121:15:121:16 | Chi [array content] | +| aliasing.cpp:126:15:126:20 | Chi [array content] | aliasing.cpp:127:8:127:16 | * ... | +| aliasing.cpp:126:15:126:20 | taint_a_ptr output argument [array content] | aliasing.cpp:126:15:126:20 | Chi [array content] | +| aliasing.cpp:131:15:131:16 | Chi [array content] | aliasing.cpp:132:8:132:14 | * ... | +| aliasing.cpp:131:15:131:16 | taint_a_ptr output argument [array content] | aliasing.cpp:131:15:131:16 | Chi [array content] | +| aliasing.cpp:136:15:136:17 | Chi [array content] | aliasing.cpp:137:8:137:11 | * ... | +| aliasing.cpp:136:15:136:17 | taint_a_ptr output argument [array content] | aliasing.cpp:136:15:136:17 | Chi [array content] | +| aliasing.cpp:158:15:158:20 | Chi [array content] | aliasing.cpp:159:8:159:14 | * ... | +| aliasing.cpp:158:15:158:20 | taint_a_ptr output argument [array content] | aliasing.cpp:158:15:158:20 | Chi [array content] | +| aliasing.cpp:164:15:164:20 | Chi [array content] | aliasing.cpp:165:8:165:16 | access to array | +| aliasing.cpp:164:15:164:20 | taint_a_ptr output argument [array content] | aliasing.cpp:164:15:164:20 | Chi [array content] | +| aliasing.cpp:175:15:175:22 | Chi | aliasing.cpp:175:15:175:22 | Chi [m1] | +| aliasing.cpp:175:15:175:22 | Chi [m1] | aliasing.cpp:176:13:176:14 | m1 | +| aliasing.cpp:175:15:175:22 | taint_a_ptr output argument [array content] | aliasing.cpp:175:15:175:22 | Chi | +| aliasing.cpp:187:15:187:22 | Chi | aliasing.cpp:187:15:187:22 | Chi [m1] | +| aliasing.cpp:187:15:187:22 | Chi [m1] | aliasing.cpp:188:13:188:14 | Store [m1] | +| aliasing.cpp:187:15:187:22 | taint_a_ptr output argument [array content] | aliasing.cpp:187:15:187:22 | Chi | +| aliasing.cpp:188:13:188:14 | Store [m1] | aliasing.cpp:189:15:189:16 | m1 | +| aliasing.cpp:200:15:200:24 | Chi | aliasing.cpp:200:15:200:24 | Chi [m1] | +| aliasing.cpp:200:15:200:24 | Chi [m1] | aliasing.cpp:201:15:201:16 | m1 | +| aliasing.cpp:200:15:200:24 | taint_a_ptr output argument [array content] | aliasing.cpp:200:15:200:24 | Chi | +| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:7:8:7:13 | access to array | +| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:9:8:9:11 | * ... | +| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:10:8:10:15 | * ... | +| arrays.cpp:15:14:15:23 | call to user_input | arrays.cpp:16:8:16:13 | access to array | +| arrays.cpp:36:26:36:35 | call to user_input | arrays.cpp:37:24:37:27 | data | +| by_reference.cpp:50:3:50:3 | setDirectly output argument [a] | by_reference.cpp:51:10:51:20 | call to getDirectly | +| by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:50:3:50:3 | setDirectly output argument [a] | +| by_reference.cpp:56:3:56:3 | setIndirectly output argument [a] | by_reference.cpp:57:10:57:22 | call to getIndirectly | +| by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:56:3:56:3 | setIndirectly output argument [a] | +| by_reference.cpp:62:3:62:3 | setThroughNonMember output argument [a] | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | +| by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:62:3:62:3 | setThroughNonMember output argument [a] | +| by_reference.cpp:68:17:68:18 | nonMemberSetA output argument [a] | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | | by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:68:17:68:18 | nonMemberSetA output argument [a] | -| by_reference.cpp:69:22:69:23 | Argument 0 indirection [a] | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | | by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | | by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | | by_reference.cpp:84:3:84:25 | Store | by_reference.cpp:84:3:84:25 | Chi [a] | @@ -43,49 +112,137 @@ edges | by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | | by_reference.cpp:88:3:88:24 | Store | by_reference.cpp:88:3:88:24 | Chi [a] | | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | Store | +| by_reference.cpp:92:3:92:20 | Chi [array content] | by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [array content] | +| by_reference.cpp:92:3:92:20 | Chi [array content] | by_reference.cpp:108:15:108:24 | taint_a_ptr output argument [array content] | +| by_reference.cpp:92:3:92:20 | Store | by_reference.cpp:92:3:92:20 | Chi [array content] | +| by_reference.cpp:92:9:92:18 | call to user_input | by_reference.cpp:92:3:92:20 | Store | +| by_reference.cpp:96:3:96:19 | Chi [array content] | by_reference.cpp:124:15:124:21 | taint_a_ref output argument [array content] | +| by_reference.cpp:96:3:96:19 | Chi [array content] | by_reference.cpp:128:15:128:23 | taint_a_ref output argument [array content] | +| by_reference.cpp:96:3:96:19 | Store | by_reference.cpp:96:3:96:19 | Chi [array content] | +| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:96:3:96:19 | Store | | by_reference.cpp:102:21:102:39 | Chi [a] | by_reference.cpp:110:27:110:27 | a | | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | by_reference.cpp:102:21:102:39 | Chi [a] | +| by_reference.cpp:104:15:104:22 | Chi | by_reference.cpp:104:15:104:22 | Chi [a] | +| by_reference.cpp:104:15:104:22 | Chi [a] | by_reference.cpp:112:14:112:14 | a | +| by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [array content] | by_reference.cpp:104:15:104:22 | Chi | | by_reference.cpp:106:21:106:41 | Chi [a] | by_reference.cpp:114:29:114:29 | a | | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | by_reference.cpp:106:21:106:41 | Chi [a] | +| by_reference.cpp:108:15:108:24 | Chi | by_reference.cpp:108:15:108:24 | Chi [a] | +| by_reference.cpp:108:15:108:24 | Chi [a] | by_reference.cpp:116:16:116:16 | a | +| by_reference.cpp:108:15:108:24 | taint_a_ptr output argument [array content] | by_reference.cpp:108:15:108:24 | Chi | | by_reference.cpp:122:21:122:38 | Chi [a] | by_reference.cpp:130:27:130:27 | a | | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:122:21:122:38 | Chi [a] | +| by_reference.cpp:124:15:124:21 | Chi | by_reference.cpp:124:15:124:21 | Chi [a] | +| by_reference.cpp:124:15:124:21 | Chi [a] | by_reference.cpp:132:14:132:14 | a | +| by_reference.cpp:124:15:124:21 | taint_a_ref output argument [array content] | by_reference.cpp:124:15:124:21 | Chi | | by_reference.cpp:126:21:126:40 | Chi [a] | by_reference.cpp:134:29:134:29 | a | | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | by_reference.cpp:126:21:126:40 | Chi [a] | +| by_reference.cpp:128:15:128:23 | Chi | by_reference.cpp:128:15:128:23 | Chi [a] | +| by_reference.cpp:128:15:128:23 | Chi [a] | by_reference.cpp:136:16:136:16 | a | +| by_reference.cpp:128:15:128:23 | taint_a_ref output argument [array content] | by_reference.cpp:128:15:128:23 | Chi | +| complex.cpp:40:17:40:17 | *b [a_] | complex.cpp:42:18:42:18 | call to a | +| complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:42:16:42:16 | a output argument [b_] | +| complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:43:18:43:18 | call to b | +| complex.cpp:42:16:42:16 | a output argument [b_] | complex.cpp:43:18:43:18 | call to b | +| complex.cpp:53:12:53:12 | setA output argument [a_] | complex.cpp:40:17:40:17 | *b [a_] | +| complex.cpp:53:19:53:28 | call to user_input | complex.cpp:53:12:53:12 | setA output argument [a_] | +| complex.cpp:54:12:54:12 | setB output argument [b_] | complex.cpp:40:17:40:17 | *b [b_] | +| complex.cpp:54:19:54:28 | call to user_input | complex.cpp:54:12:54:12 | setB output argument [b_] | +| complex.cpp:55:12:55:12 | setA output argument [a_] | complex.cpp:40:17:40:17 | *b [a_] | +| complex.cpp:55:12:55:12 | setA output argument [a_] | complex.cpp:56:12:56:12 | setB output argument [a_] | +| complex.cpp:55:19:55:28 | call to user_input | complex.cpp:55:12:55:12 | setA output argument [a_] | +| complex.cpp:56:12:56:12 | setB output argument [a_] | complex.cpp:40:17:40:17 | *b [a_] | +| complex.cpp:56:12:56:12 | setB output argument [b_] | complex.cpp:40:17:40:17 | *b [b_] | +| complex.cpp:56:19:56:28 | call to user_input | complex.cpp:56:12:56:12 | setB output argument [b_] | +| constructors.cpp:26:15:26:15 | *f [a_] | constructors.cpp:28:12:28:12 | call to a | +| constructors.cpp:26:15:26:15 | *f [b_] | constructors.cpp:28:10:28:10 | a output argument [b_] | +| constructors.cpp:26:15:26:15 | *f [b_] | constructors.cpp:29:12:29:12 | call to b | +| constructors.cpp:28:10:28:10 | a output argument [b_] | constructors.cpp:29:12:29:12 | call to b | +| constructors.cpp:34:11:34:20 | call to user_input | constructors.cpp:34:11:34:26 | Foo output argument [a_] | +| constructors.cpp:34:11:34:26 | Foo output argument [a_] | constructors.cpp:26:15:26:15 | *f [a_] | +| constructors.cpp:35:11:35:26 | Foo output argument [b_] | constructors.cpp:26:15:26:15 | *f [b_] | +| constructors.cpp:35:14:35:23 | call to user_input | constructors.cpp:35:11:35:26 | Foo output argument [b_] | +| constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:36:11:36:37 | Foo output argument [a_] | +| constructors.cpp:36:11:36:37 | Foo output argument [a_] | constructors.cpp:26:15:26:15 | *f [a_] | +| constructors.cpp:36:11:36:37 | Foo output argument [b_] | constructors.cpp:26:15:26:15 | *f [b_] | +| constructors.cpp:36:25:36:34 | call to user_input | constructors.cpp:36:11:36:37 | Foo output argument [b_] | +| simple.cpp:26:15:26:15 | *f [a_] | simple.cpp:28:12:28:12 | call to a | +| simple.cpp:26:15:26:15 | *f [b_] | simple.cpp:28:10:28:10 | a output argument [b_] | +| simple.cpp:26:15:26:15 | *f [b_] | simple.cpp:29:12:29:12 | call to b | +| simple.cpp:28:10:28:10 | a output argument [b_] | simple.cpp:29:12:29:12 | call to b | +| simple.cpp:39:5:39:5 | setA output argument [a_] | simple.cpp:26:15:26:15 | *f [a_] | +| simple.cpp:39:12:39:21 | call to user_input | simple.cpp:39:5:39:5 | setA output argument [a_] | +| simple.cpp:40:5:40:5 | setB output argument [b_] | simple.cpp:26:15:26:15 | *f [b_] | +| simple.cpp:40:12:40:21 | call to user_input | simple.cpp:40:5:40:5 | setB output argument [b_] | +| simple.cpp:41:5:41:5 | setA output argument [a_] | simple.cpp:26:15:26:15 | *f [a_] | +| simple.cpp:41:5:41:5 | setA output argument [a_] | simple.cpp:42:5:42:5 | setB output argument [a_] | +| simple.cpp:41:12:41:21 | call to user_input | simple.cpp:41:5:41:5 | setA output argument [a_] | +| simple.cpp:42:5:42:5 | setB output argument [a_] | simple.cpp:26:15:26:15 | *f [a_] | +| simple.cpp:42:5:42:5 | setB output argument [b_] | simple.cpp:26:15:26:15 | *f [b_] | +| simple.cpp:42:12:42:21 | call to user_input | simple.cpp:42:5:42:5 | setB output argument [b_] | | simple.cpp:65:5:65:22 | Store [i] | simple.cpp:66:12:66:12 | Store [i] | | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | Store [i] | | simple.cpp:66:12:66:12 | Store [i] | simple.cpp:67:13:67:13 | i | -| simple.cpp:83:9:83:28 | Chi [f1] | simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | +| simple.cpp:83:9:83:28 | Chi [f1] | simple.cpp:84:14:84:20 | call to getf2f1 | | simple.cpp:83:9:83:28 | Store | simple.cpp:83:9:83:28 | Chi [f1] | | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | Store | -| simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | simple.cpp:84:14:84:20 | call to getf2f1 | +| simple.cpp:92:5:92:22 | Store [i] | simple.cpp:93:20:93:20 | Store [i] | +| simple.cpp:92:11:92:20 | call to user_input | simple.cpp:92:5:92:22 | Store [i] | +| simple.cpp:93:20:93:20 | Store [i] | simple.cpp:94:13:94:13 | i | | struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:15:12:15:12 | a | -| struct_init.c:20:20:20:29 | Chi [a] | struct_init.c:24:10:24:12 | Argument 0 indirection [a] | +| struct_init.c:20:20:20:29 | Chi [a] | struct_init.c:14:24:14:25 | *ab [a] | | struct_init.c:20:20:20:29 | Store | struct_init.c:20:20:20:29 | Chi [a] | | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:20:20:29 | Store | | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | -| struct_init.c:24:10:24:12 | Argument 0 indirection [a] | struct_init.c:14:24:14:25 | *ab [a] | -| struct_init.c:27:7:27:16 | Chi [a] | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | +| struct_init.c:27:7:27:16 | Chi [a] | struct_init.c:14:24:14:25 | *ab [a] | | struct_init.c:27:7:27:16 | Store | struct_init.c:27:7:27:16 | Chi [a] | | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:27:7:27:16 | Store | | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | -| struct_init.c:36:10:36:24 | Argument 0 indirection [a] | struct_init.c:14:24:14:25 | *ab [a] | nodes +| A.cpp:55:5:55:5 | set output argument [c] | semmle.label | set output argument [c] | +| A.cpp:55:12:55:19 | (C *)... | semmle.label | (C *)... | +| A.cpp:55:12:55:19 | new | semmle.label | new | +| A.cpp:56:13:56:15 | call to get | semmle.label | call to get | +| A.cpp:57:11:57:24 | B output argument [c] | semmle.label | B output argument [c] | +| A.cpp:57:17:57:23 | new | semmle.label | new | +| A.cpp:57:28:57:30 | call to get | semmle.label | call to get | | A.cpp:98:12:98:18 | new | semmle.label | new | | A.cpp:100:5:100:13 | Chi [a] | semmle.label | Chi [a] | | A.cpp:100:5:100:13 | Store | semmle.label | Store | -| A.cpp:101:8:101:9 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | | A.cpp:103:14:103:14 | *c [a] | semmle.label | *c [a] | -| A.cpp:107:12:107:16 | (void *)... | semmle.label | (void *)... | -| A.cpp:107:16:107:16 | a | semmle.label | a | | A.cpp:107:16:107:16 | a | semmle.label | a | +| A.cpp:126:5:126:5 | Chi [c] | semmle.label | Chi [c] | +| A.cpp:126:5:126:5 | set output argument [c] | semmle.label | set output argument [c] | +| A.cpp:126:12:126:18 | new | semmle.label | new | +| A.cpp:131:8:131:8 | Chi [c] | semmle.label | Chi [c] | +| A.cpp:131:8:131:8 | f7 output argument [c] | semmle.label | f7 output argument [c] | +| A.cpp:132:13:132:13 | c | semmle.label | c | | A.cpp:142:7:142:20 | Chi [c] | semmle.label | Chi [c] | | A.cpp:142:7:142:20 | Store | semmle.label | Store | | A.cpp:142:14:142:20 | new | semmle.label | new | +| A.cpp:143:7:143:31 | Chi [b] | semmle.label | Chi [b] | +| A.cpp:143:7:143:31 | Store | semmle.label | Store | +| A.cpp:143:25:143:31 | new | semmle.label | new | +| A.cpp:150:12:150:18 | new | semmle.label | new | +| A.cpp:151:12:151:24 | Chi [b] | semmle.label | Chi [b] | +| A.cpp:151:12:151:24 | D output argument [b] | semmle.label | D output argument [b] | | A.cpp:151:18:151:18 | Chi [c] | semmle.label | Chi [c] | | A.cpp:151:18:151:18 | D output argument [c] | semmle.label | D output argument [c] | -| A.cpp:154:10:154:13 | (void *)... | semmle.label | (void *)... | -| A.cpp:154:13:154:13 | c | semmle.label | c | +| A.cpp:152:13:152:13 | b | semmle.label | b | | A.cpp:154:13:154:13 | c | semmle.label | c | +| C.cpp:18:12:18:18 | C output argument [s1] | semmle.label | C output argument [s1] | +| C.cpp:18:12:18:18 | C output argument [s3] | semmle.label | C output argument [s3] | +| C.cpp:22:12:22:21 | Chi [s1] | semmle.label | Chi [s1] | +| C.cpp:22:12:22:21 | Store | semmle.label | Store | +| C.cpp:22:12:22:21 | new | semmle.label | new | +| C.cpp:24:5:24:25 | Chi [s1] | semmle.label | Chi [s1] | +| C.cpp:24:5:24:25 | Chi [s3] | semmle.label | Chi [s3] | +| C.cpp:24:5:24:25 | Store | semmle.label | Store | +| C.cpp:24:16:24:25 | new | semmle.label | new | +| C.cpp:27:8:27:11 | *#this [s1] | semmle.label | *#this [s1] | +| C.cpp:27:8:27:11 | *#this [s3] | semmle.label | *#this [s3] | +| C.cpp:29:10:29:11 | s1 | semmle.label | s1 | +| C.cpp:31:10:31:11 | s3 | semmle.label | s3 | | aliasing.cpp:9:3:9:22 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:9:3:9:22 | Store | semmle.label | Store | | aliasing.cpp:9:11:9:20 | call to user_input | semmle.label | call to user_input | @@ -113,28 +270,146 @@ nodes | aliasing.cpp:87:12:87:13 | m1 | semmle.label | m1 | | aliasing.cpp:92:12:92:21 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 | +| aliasing.cpp:98:3:98:21 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:98:3:98:21 | Store | semmle.label | Store | +| aliasing.cpp:98:10:98:19 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:100:14:100:14 | Store [m1] | semmle.label | Store [m1] | +| aliasing.cpp:102:8:102:10 | * ... | semmle.label | * ... | +| aliasing.cpp:106:3:106:20 | Chi [array content] | semmle.label | Chi [array content] | +| aliasing.cpp:106:3:106:20 | Store | semmle.label | Store | +| aliasing.cpp:106:9:106:18 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:121:15:121:16 | Chi [array content] | semmle.label | Chi [array content] | +| aliasing.cpp:121:15:121:16 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | +| aliasing.cpp:122:8:122:12 | access to array | semmle.label | access to array | +| aliasing.cpp:126:15:126:20 | Chi [array content] | semmle.label | Chi [array content] | +| aliasing.cpp:126:15:126:20 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | +| aliasing.cpp:127:8:127:16 | * ... | semmle.label | * ... | +| aliasing.cpp:131:15:131:16 | Chi [array content] | semmle.label | Chi [array content] | +| aliasing.cpp:131:15:131:16 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | +| aliasing.cpp:132:8:132:14 | * ... | semmle.label | * ... | +| aliasing.cpp:136:15:136:17 | Chi [array content] | semmle.label | Chi [array content] | +| aliasing.cpp:136:15:136:17 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | +| aliasing.cpp:137:8:137:11 | * ... | semmle.label | * ... | +| aliasing.cpp:158:15:158:20 | Chi [array content] | semmle.label | Chi [array content] | +| aliasing.cpp:158:15:158:20 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | +| aliasing.cpp:159:8:159:14 | * ... | semmle.label | * ... | +| aliasing.cpp:164:15:164:20 | Chi [array content] | semmle.label | Chi [array content] | +| aliasing.cpp:164:15:164:20 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | +| aliasing.cpp:165:8:165:16 | access to array | semmle.label | access to array | +| aliasing.cpp:175:15:175:22 | Chi | semmle.label | Chi | +| aliasing.cpp:175:15:175:22 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:175:15:175:22 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | +| aliasing.cpp:176:13:176:14 | m1 | semmle.label | m1 | +| aliasing.cpp:187:15:187:22 | Chi | semmle.label | Chi | +| aliasing.cpp:187:15:187:22 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:187:15:187:22 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | +| aliasing.cpp:188:13:188:14 | Store [m1] | semmle.label | Store [m1] | +| aliasing.cpp:189:15:189:16 | m1 | semmle.label | m1 | +| aliasing.cpp:200:15:200:24 | Chi | semmle.label | Chi | +| aliasing.cpp:200:15:200:24 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:200:15:200:24 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | +| aliasing.cpp:201:15:201:16 | m1 | semmle.label | m1 | +| arrays.cpp:6:12:6:21 | call to user_input | semmle.label | call to user_input | +| arrays.cpp:7:8:7:13 | access to array | semmle.label | access to array | +| arrays.cpp:9:8:9:11 | * ... | semmle.label | * ... | +| arrays.cpp:10:8:10:15 | * ... | semmle.label | * ... | +| arrays.cpp:15:14:15:23 | call to user_input | semmle.label | call to user_input | +| arrays.cpp:16:8:16:13 | access to array | semmle.label | access to array | +| arrays.cpp:36:26:36:35 | call to user_input | semmle.label | call to user_input | +| arrays.cpp:37:24:37:27 | data | semmle.label | data | +| by_reference.cpp:50:3:50:3 | setDirectly output argument [a] | semmle.label | setDirectly output argument [a] | +| by_reference.cpp:50:17:50:26 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:51:10:51:20 | call to getDirectly | semmle.label | call to getDirectly | +| by_reference.cpp:56:3:56:3 | setIndirectly output argument [a] | semmle.label | setIndirectly output argument [a] | +| by_reference.cpp:56:19:56:28 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:57:10:57:22 | call to getIndirectly | semmle.label | call to getIndirectly | +| by_reference.cpp:62:3:62:3 | setThroughNonMember output argument [a] | semmle.label | setThroughNonMember output argument [a] | +| by_reference.cpp:62:25:62:34 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | semmle.label | call to getThroughNonMember | | by_reference.cpp:68:17:68:18 | nonMemberSetA output argument [a] | semmle.label | nonMemberSetA output argument [a] | | by_reference.cpp:68:21:68:30 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | semmle.label | call to nonMemberGetA | -| by_reference.cpp:69:22:69:23 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | | by_reference.cpp:84:3:84:25 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:84:3:84:25 | Store | semmle.label | Store | | by_reference.cpp:84:14:84:23 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:88:3:88:24 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:88:3:88:24 | Store | semmle.label | Store | | by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:92:3:92:20 | Chi [array content] | semmle.label | Chi [array content] | +| by_reference.cpp:92:3:92:20 | Store | semmle.label | Store | +| by_reference.cpp:92:9:92:18 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:96:3:96:19 | Chi [array content] | semmle.label | Chi [array content] | +| by_reference.cpp:96:3:96:19 | Store | semmle.label | Store | +| by_reference.cpp:96:8:96:17 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:102:21:102:39 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | +| by_reference.cpp:104:15:104:22 | Chi | semmle.label | Chi | +| by_reference.cpp:104:15:104:22 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | | by_reference.cpp:106:21:106:41 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | +| by_reference.cpp:108:15:108:24 | Chi | semmle.label | Chi | +| by_reference.cpp:108:15:108:24 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:108:15:108:24 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | | by_reference.cpp:110:27:110:27 | a | semmle.label | a | +| by_reference.cpp:112:14:112:14 | a | semmle.label | a | | by_reference.cpp:114:29:114:29 | a | semmle.label | a | +| by_reference.cpp:116:16:116:16 | a | semmle.label | a | | by_reference.cpp:122:21:122:38 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | +| by_reference.cpp:124:15:124:21 | Chi | semmle.label | Chi | +| by_reference.cpp:124:15:124:21 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:124:15:124:21 | taint_a_ref output argument [array content] | semmle.label | taint_a_ref output argument [array content] | | by_reference.cpp:126:21:126:40 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | +| by_reference.cpp:128:15:128:23 | Chi | semmle.label | Chi | +| by_reference.cpp:128:15:128:23 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:128:15:128:23 | taint_a_ref output argument [array content] | semmle.label | taint_a_ref output argument [array content] | | by_reference.cpp:130:27:130:27 | a | semmle.label | a | +| by_reference.cpp:132:14:132:14 | a | semmle.label | a | | by_reference.cpp:134:29:134:29 | a | semmle.label | a | +| by_reference.cpp:136:16:136:16 | a | semmle.label | a | +| complex.cpp:40:17:40:17 | *b [a_] | semmle.label | *b [a_] | +| complex.cpp:40:17:40:17 | *b [b_] | semmle.label | *b [b_] | +| complex.cpp:42:16:42:16 | a output argument [b_] | semmle.label | a output argument [b_] | +| complex.cpp:42:18:42:18 | call to a | semmle.label | call to a | +| complex.cpp:43:18:43:18 | call to b | semmle.label | call to b | +| complex.cpp:53:12:53:12 | setA output argument [a_] | semmle.label | setA output argument [a_] | +| complex.cpp:53:19:53:28 | call to user_input | semmle.label | call to user_input | +| complex.cpp:54:12:54:12 | setB output argument [b_] | semmle.label | setB output argument [b_] | +| complex.cpp:54:19:54:28 | call to user_input | semmle.label | call to user_input | +| complex.cpp:55:12:55:12 | setA output argument [a_] | semmle.label | setA output argument [a_] | +| complex.cpp:55:19:55:28 | call to user_input | semmle.label | call to user_input | +| complex.cpp:56:12:56:12 | setB output argument [a_] | semmle.label | setB output argument [a_] | +| complex.cpp:56:12:56:12 | setB output argument [b_] | semmle.label | setB output argument [b_] | +| complex.cpp:56:19:56:28 | call to user_input | semmle.label | call to user_input | +| constructors.cpp:26:15:26:15 | *f [a_] | semmle.label | *f [a_] | +| constructors.cpp:26:15:26:15 | *f [b_] | semmle.label | *f [b_] | +| constructors.cpp:28:10:28:10 | a output argument [b_] | semmle.label | a output argument [b_] | +| constructors.cpp:28:12:28:12 | call to a | semmle.label | call to a | +| constructors.cpp:29:12:29:12 | call to b | semmle.label | call to b | +| constructors.cpp:34:11:34:20 | call to user_input | semmle.label | call to user_input | +| constructors.cpp:34:11:34:26 | Foo output argument [a_] | semmle.label | Foo output argument [a_] | +| constructors.cpp:35:11:35:26 | Foo output argument [b_] | semmle.label | Foo output argument [b_] | +| constructors.cpp:35:14:35:23 | call to user_input | semmle.label | call to user_input | +| constructors.cpp:36:11:36:20 | call to user_input | semmle.label | call to user_input | +| constructors.cpp:36:11:36:37 | Foo output argument [a_] | semmle.label | Foo output argument [a_] | +| constructors.cpp:36:11:36:37 | Foo output argument [b_] | semmle.label | Foo output argument [b_] | +| constructors.cpp:36:25:36:34 | call to user_input | semmle.label | call to user_input | +| simple.cpp:26:15:26:15 | *f [a_] | semmle.label | *f [a_] | +| simple.cpp:26:15:26:15 | *f [b_] | semmle.label | *f [b_] | +| simple.cpp:28:10:28:10 | a output argument [b_] | semmle.label | a output argument [b_] | +| simple.cpp:28:12:28:12 | call to a | semmle.label | call to a | +| simple.cpp:29:12:29:12 | call to b | semmle.label | call to b | +| simple.cpp:39:5:39:5 | setA output argument [a_] | semmle.label | setA output argument [a_] | +| simple.cpp:39:12:39:21 | call to user_input | semmle.label | call to user_input | +| simple.cpp:40:5:40:5 | setB output argument [b_] | semmle.label | setB output argument [b_] | +| simple.cpp:40:12:40:21 | call to user_input | semmle.label | call to user_input | +| simple.cpp:41:5:41:5 | setA output argument [a_] | semmle.label | setA output argument [a_] | +| simple.cpp:41:12:41:21 | call to user_input | semmle.label | call to user_input | +| simple.cpp:42:5:42:5 | setB output argument [a_] | semmle.label | setB output argument [a_] | +| simple.cpp:42:5:42:5 | setB output argument [b_] | semmle.label | setB output argument [b_] | +| simple.cpp:42:12:42:21 | call to user_input | semmle.label | call to user_input | | simple.cpp:65:5:65:22 | Store [i] | semmle.label | Store [i] | | simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input | | simple.cpp:66:12:66:12 | Store [i] | semmle.label | Store [i] | @@ -142,25 +417,32 @@ nodes | simple.cpp:83:9:83:28 | Chi [f1] | semmle.label | Chi [f1] | | simple.cpp:83:9:83:28 | Store | semmle.label | Store | | simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input | -| simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | semmle.label | Argument -1 indirection [f1] | | simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 | +| simple.cpp:92:5:92:22 | Store [i] | semmle.label | Store [i] | +| simple.cpp:92:11:92:20 | call to user_input | semmle.label | call to user_input | +| simple.cpp:93:20:93:20 | Store [i] | semmle.label | Store [i] | +| simple.cpp:94:13:94:13 | i | semmle.label | i | | struct_init.c:14:24:14:25 | *ab [a] | semmle.label | *ab [a] | | struct_init.c:15:12:15:12 | a | semmle.label | a | | struct_init.c:20:20:20:29 | Chi [a] | semmle.label | Chi [a] | | struct_init.c:20:20:20:29 | Store | semmle.label | Store | | struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input | | struct_init.c:22:11:22:11 | a | semmle.label | a | -| struct_init.c:24:10:24:12 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | | struct_init.c:27:7:27:16 | Chi [a] | semmle.label | Chi [a] | | struct_init.c:27:7:27:16 | Store | semmle.label | Store | | struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input | | struct_init.c:31:23:31:23 | a | semmle.label | a | -| struct_init.c:36:10:36:24 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | #select -| A.cpp:107:12:107:16 | (void *)... | A.cpp:98:12:98:18 | new | A.cpp:107:12:107:16 | (void *)... | (void *)... flows from $@ | A.cpp:98:12:98:18 | new | new | +| A.cpp:56:13:56:15 | call to get | A.cpp:55:12:55:19 | (C *)... | A.cpp:56:13:56:15 | call to get | call to get flows from $@ | A.cpp:55:12:55:19 | (C *)... | (C *)... | +| A.cpp:56:13:56:15 | call to get | A.cpp:55:12:55:19 | new | A.cpp:56:13:56:15 | call to get | call to get flows from $@ | A.cpp:55:12:55:19 | new | new | +| A.cpp:57:28:57:30 | call to get | A.cpp:57:17:57:23 | new | A.cpp:57:28:57:30 | call to get | call to get flows from $@ | A.cpp:57:17:57:23 | new | new | | A.cpp:107:16:107:16 | a | A.cpp:98:12:98:18 | new | A.cpp:107:16:107:16 | a | a flows from $@ | A.cpp:98:12:98:18 | new | new | -| A.cpp:154:10:154:13 | (void *)... | A.cpp:142:14:142:20 | new | A.cpp:154:10:154:13 | (void *)... | (void *)... flows from $@ | A.cpp:142:14:142:20 | new | new | +| A.cpp:132:13:132:13 | c | A.cpp:126:12:126:18 | new | A.cpp:132:13:132:13 | c | c flows from $@ | A.cpp:126:12:126:18 | new | new | +| A.cpp:152:13:152:13 | b | A.cpp:143:25:143:31 | new | A.cpp:152:13:152:13 | b | b flows from $@ | A.cpp:143:25:143:31 | new | new | +| A.cpp:152:13:152:13 | b | A.cpp:150:12:150:18 | new | A.cpp:152:13:152:13 | b | b flows from $@ | A.cpp:150:12:150:18 | new | new | | A.cpp:154:13:154:13 | c | A.cpp:142:14:142:20 | new | A.cpp:154:13:154:13 | c | c flows from $@ | A.cpp:142:14:142:20 | new | new | +| C.cpp:29:10:29:11 | s1 | C.cpp:22:12:22:21 | new | C.cpp:29:10:29:11 | s1 | s1 flows from $@ | C.cpp:22:12:22:21 | new | new | +| C.cpp:31:10:31:11 | s3 | C.cpp:24:16:24:25 | new | C.cpp:31:10:31:11 | s3 | s3 flows from $@ | C.cpp:24:16:24:25 | new | new | | aliasing.cpp:29:11:29:12 | m1 | aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:29:11:29:12 | m1 | m1 flows from $@ | aliasing.cpp:9:11:9:20 | call to user_input | call to user_input | | aliasing.cpp:30:11:30:12 | m1 | aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:30:11:30:12 | m1 | m1 flows from $@ | aliasing.cpp:13:10:13:19 | call to user_input | call to user_input | | aliasing.cpp:38:11:38:12 | m1 | aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | m1 flows from $@ | aliasing.cpp:37:13:37:22 | call to user_input | call to user_input | @@ -169,13 +451,48 @@ nodes | aliasing.cpp:80:12:80:13 | m1 | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | m1 flows from $@ | aliasing.cpp:79:11:79:20 | call to user_input | call to user_input | | aliasing.cpp:87:12:87:13 | m1 | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | m1 flows from $@ | aliasing.cpp:86:10:86:19 | call to user_input | call to user_input | | aliasing.cpp:93:12:93:13 | m1 | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | m1 flows from $@ | aliasing.cpp:92:12:92:21 | call to user_input | call to user_input | +| aliasing.cpp:102:8:102:10 | * ... | aliasing.cpp:98:10:98:19 | call to user_input | aliasing.cpp:102:8:102:10 | * ... | * ... flows from $@ | aliasing.cpp:98:10:98:19 | call to user_input | call to user_input | +| aliasing.cpp:122:8:122:12 | access to array | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:122:8:122:12 | access to array | access to array flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | +| aliasing.cpp:127:8:127:16 | * ... | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:127:8:127:16 | * ... | * ... flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | +| aliasing.cpp:132:8:132:14 | * ... | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:132:8:132:14 | * ... | * ... flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | +| aliasing.cpp:137:8:137:11 | * ... | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:137:8:137:11 | * ... | * ... flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | +| aliasing.cpp:159:8:159:14 | * ... | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:159:8:159:14 | * ... | * ... flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | +| aliasing.cpp:165:8:165:16 | access to array | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:165:8:165:16 | access to array | access to array flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | +| aliasing.cpp:176:13:176:14 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:176:13:176:14 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | +| aliasing.cpp:189:15:189:16 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:189:15:189:16 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | +| aliasing.cpp:201:15:201:16 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:201:15:201:16 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | +| arrays.cpp:7:8:7:13 | access to array | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:7:8:7:13 | access to array | access to array flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input | +| arrays.cpp:9:8:9:11 | * ... | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:9:8:9:11 | * ... | * ... flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input | +| arrays.cpp:10:8:10:15 | * ... | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:10:8:10:15 | * ... | * ... flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input | +| arrays.cpp:16:8:16:13 | access to array | arrays.cpp:15:14:15:23 | call to user_input | arrays.cpp:16:8:16:13 | access to array | access to array flows from $@ | arrays.cpp:15:14:15:23 | call to user_input | call to user_input | +| arrays.cpp:37:24:37:27 | data | arrays.cpp:36:26:36:35 | call to user_input | arrays.cpp:37:24:37:27 | data | data flows from $@ | arrays.cpp:36:26:36:35 | call to user_input | call to user_input | +| by_reference.cpp:51:10:51:20 | call to getDirectly | by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:51:10:51:20 | call to getDirectly | call to getDirectly flows from $@ | by_reference.cpp:50:17:50:26 | call to user_input | call to user_input | +| by_reference.cpp:57:10:57:22 | call to getIndirectly | by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:57:10:57:22 | call to getIndirectly | call to getIndirectly flows from $@ | by_reference.cpp:56:19:56:28 | call to user_input | call to user_input | +| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | call to getThroughNonMember flows from $@ | by_reference.cpp:62:25:62:34 | call to user_input | call to user_input | | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | call to nonMemberGetA flows from $@ | by_reference.cpp:68:21:68:30 | call to user_input | call to user_input | | by_reference.cpp:110:27:110:27 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:110:27:110:27 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | +| by_reference.cpp:112:14:112:14 | a | by_reference.cpp:92:9:92:18 | call to user_input | by_reference.cpp:112:14:112:14 | a | a flows from $@ | by_reference.cpp:92:9:92:18 | call to user_input | call to user_input | | by_reference.cpp:114:29:114:29 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:114:29:114:29 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | +| by_reference.cpp:116:16:116:16 | a | by_reference.cpp:92:9:92:18 | call to user_input | by_reference.cpp:116:16:116:16 | a | a flows from $@ | by_reference.cpp:92:9:92:18 | call to user_input | call to user_input | | by_reference.cpp:130:27:130:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:130:27:130:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | +| by_reference.cpp:132:14:132:14 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:132:14:132:14 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input | | by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | +| by_reference.cpp:136:16:136:16 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:136:16:136:16 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input | +| complex.cpp:42:18:42:18 | call to a | complex.cpp:53:19:53:28 | call to user_input | complex.cpp:42:18:42:18 | call to a | call to a flows from $@ | complex.cpp:53:19:53:28 | call to user_input | call to user_input | +| complex.cpp:42:18:42:18 | call to a | complex.cpp:55:19:55:28 | call to user_input | complex.cpp:42:18:42:18 | call to a | call to a flows from $@ | complex.cpp:55:19:55:28 | call to user_input | call to user_input | +| complex.cpp:43:18:43:18 | call to b | complex.cpp:54:19:54:28 | call to user_input | complex.cpp:43:18:43:18 | call to b | call to b flows from $@ | complex.cpp:54:19:54:28 | call to user_input | call to user_input | +| complex.cpp:43:18:43:18 | call to b | complex.cpp:56:19:56:28 | call to user_input | complex.cpp:43:18:43:18 | call to b | call to b flows from $@ | complex.cpp:56:19:56:28 | call to user_input | call to user_input | +| constructors.cpp:28:12:28:12 | call to a | constructors.cpp:34:11:34:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | call to a flows from $@ | constructors.cpp:34:11:34:20 | call to user_input | call to user_input | +| constructors.cpp:28:12:28:12 | call to a | constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | call to a flows from $@ | constructors.cpp:36:11:36:20 | call to user_input | call to user_input | +| constructors.cpp:29:12:29:12 | call to b | constructors.cpp:35:14:35:23 | call to user_input | constructors.cpp:29:12:29:12 | call to b | call to b flows from $@ | constructors.cpp:35:14:35:23 | call to user_input | call to user_input | +| constructors.cpp:29:12:29:12 | call to b | constructors.cpp:36:25:36:34 | call to user_input | constructors.cpp:29:12:29:12 | call to b | call to b flows from $@ | constructors.cpp:36:25:36:34 | call to user_input | call to user_input | +| simple.cpp:28:12:28:12 | call to a | simple.cpp:39:12:39:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:39:12:39:21 | call to user_input | call to user_input | +| simple.cpp:28:12:28:12 | call to a | simple.cpp:41:12:41:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:41:12:41:21 | call to user_input | call to user_input | +| simple.cpp:29:12:29:12 | call to b | simple.cpp:40:12:40:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:40:12:40:21 | call to user_input | call to user_input | +| simple.cpp:29:12:29:12 | call to b | simple.cpp:42:12:42:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:42:12:42:21 | call to user_input | call to user_input | | simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | | simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input | +| simple.cpp:94:13:94:13 | i | simple.cpp:92:11:92:20 | call to user_input | simple.cpp:94:13:94:13 | i | i flows from $@ | simple.cpp:92:11:92:20 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | | struct_init.c:22:11:22:11 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected index 889f789da8d7..51b43e6be1c6 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected @@ -157,6 +157,70 @@ | aliasing.cpp:86:5:86:6 | m1 | AST only | | aliasing.cpp:92:3:92:3 | w | AST only | | aliasing.cpp:92:7:92:8 | m1 | AST only | +| aliasing.cpp:98:5:98:6 | m1 | AST only | +| aliasing.cpp:106:3:106:5 | * ... | AST only | +| aliasing.cpp:111:15:111:19 | & ... | AST only | +| aliasing.cpp:121:15:121:16 | xs | AST only | +| aliasing.cpp:126:15:126:20 | ... - ... | AST only | +| aliasing.cpp:131:15:131:16 | xs | AST only | +| aliasing.cpp:136:15:136:17 | + ... | AST only | +| aliasing.cpp:141:15:141:15 | s | AST only | +| aliasing.cpp:141:17:141:20 | data | AST only | +| aliasing.cpp:147:15:147:22 | & ... | AST only | +| aliasing.cpp:158:15:158:15 | s | AST only | +| aliasing.cpp:158:17:158:20 | data | AST only | +| aliasing.cpp:164:15:164:15 | s | AST only | +| aliasing.cpp:164:17:164:20 | data | AST only | +| aliasing.cpp:175:15:175:22 | & ... | AST only | +| aliasing.cpp:175:16:175:17 | s2 | AST only | +| aliasing.cpp:181:15:181:22 | & ... | AST only | +| aliasing.cpp:181:16:181:17 | s2 | AST only | +| aliasing.cpp:187:15:187:22 | & ... | AST only | +| aliasing.cpp:187:16:187:17 | s2 | AST only | +| aliasing.cpp:194:15:194:22 | & ... | AST only | +| aliasing.cpp:194:16:194:17 | s2 | AST only | +| aliasing.cpp:200:15:200:24 | & ... | AST only | +| aliasing.cpp:200:16:200:18 | ps2 | AST only | +| aliasing.cpp:205:15:205:24 | & ... | AST only | +| aliasing.cpp:205:16:205:18 | ps2 | AST only | +| arrays.cpp:6:3:6:8 | access to array | AST only | +| arrays.cpp:6:3:6:23 | arr | IR only | +| arrays.cpp:15:3:15:10 | * ... | AST only | +| arrays.cpp:36:3:36:3 | o | AST only | +| arrays.cpp:36:5:36:10 | nested | AST only | +| arrays.cpp:36:19:36:22 | data | AST only | +| arrays.cpp:37:8:37:8 | o | AST only | +| arrays.cpp:37:8:37:22 | access to array | AST only | +| arrays.cpp:37:10:37:15 | nested | AST only | +| arrays.cpp:37:24:37:27 | data | AST only | +| arrays.cpp:38:8:38:8 | o | AST only | +| arrays.cpp:38:8:38:22 | access to array | AST only | +| arrays.cpp:38:10:38:15 | nested | AST only | +| arrays.cpp:38:24:38:27 | data | AST only | +| arrays.cpp:42:3:42:3 | o | AST only | +| arrays.cpp:42:3:42:20 | access to array | AST only | +| arrays.cpp:42:5:42:12 | indirect | AST only | +| arrays.cpp:42:22:42:25 | data | AST only | +| arrays.cpp:43:8:43:8 | o | AST only | +| arrays.cpp:43:8:43:25 | access to array | AST only | +| arrays.cpp:43:10:43:17 | indirect | AST only | +| arrays.cpp:43:27:43:30 | data | AST only | +| arrays.cpp:44:8:44:8 | o | AST only | +| arrays.cpp:44:8:44:25 | access to array | AST only | +| arrays.cpp:44:10:44:17 | indirect | AST only | +| arrays.cpp:44:27:44:30 | data | AST only | +| arrays.cpp:48:3:48:3 | o | AST only | +| arrays.cpp:48:3:48:20 | access to array | AST only | +| arrays.cpp:48:5:48:12 | indirect | AST only | +| arrays.cpp:48:22:48:25 | data | AST only | +| arrays.cpp:49:8:49:8 | o | AST only | +| arrays.cpp:49:8:49:25 | access to array | AST only | +| arrays.cpp:49:10:49:17 | indirect | AST only | +| arrays.cpp:49:27:49:30 | data | AST only | +| arrays.cpp:50:8:50:8 | o | AST only | +| arrays.cpp:50:8:50:25 | access to array | AST only | +| arrays.cpp:50:10:50:17 | indirect | AST only | +| arrays.cpp:50:27:50:30 | data | AST only | | by_reference.cpp:12:8:12:8 | a | AST only | | by_reference.cpp:16:11:16:11 | a | AST only | | by_reference.cpp:20:5:20:8 | this | AST only | @@ -177,18 +241,16 @@ | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | AST only | | by_reference.cpp:84:10:84:10 | a | AST only | | by_reference.cpp:88:9:88:9 | a | AST only | +| by_reference.cpp:92:3:92:5 | * ... | AST only | +| by_reference.cpp:96:3:96:4 | pa | AST only | | by_reference.cpp:102:21:102:39 | & ... | AST only | -| by_reference.cpp:102:22:102:26 | outer | AST only | | by_reference.cpp:103:21:103:25 | outer | AST only | | by_reference.cpp:103:27:103:35 | inner_ptr | AST only | | by_reference.cpp:104:15:104:22 | & ... | AST only | -| by_reference.cpp:104:16:104:20 | outer | AST only | | by_reference.cpp:106:21:106:41 | & ... | AST only | -| by_reference.cpp:106:22:106:27 | pouter | AST only | | by_reference.cpp:107:21:107:26 | pouter | AST only | | by_reference.cpp:107:29:107:37 | inner_ptr | AST only | | by_reference.cpp:108:15:108:24 | & ... | AST only | -| by_reference.cpp:108:16:108:21 | pouter | AST only | | by_reference.cpp:110:8:110:12 | outer | AST only | | by_reference.cpp:110:14:110:25 | inner_nested | AST only | | by_reference.cpp:110:27:110:27 | a | AST only | @@ -205,17 +267,13 @@ | by_reference.cpp:115:27:115:27 | a | AST only | | by_reference.cpp:116:8:116:13 | pouter | AST only | | by_reference.cpp:116:16:116:16 | a | AST only | -| by_reference.cpp:122:21:122:25 | outer | AST only | | by_reference.cpp:122:27:122:38 | inner_nested | AST only | | by_reference.cpp:123:21:123:36 | * ... | AST only | | by_reference.cpp:123:22:123:26 | outer | AST only | -| by_reference.cpp:124:15:124:19 | outer | AST only | | by_reference.cpp:124:21:124:21 | a | AST only | -| by_reference.cpp:126:21:126:26 | pouter | AST only | | by_reference.cpp:126:29:126:40 | inner_nested | AST only | | by_reference.cpp:127:21:127:38 | * ... | AST only | | by_reference.cpp:127:22:127:27 | pouter | AST only | -| by_reference.cpp:128:15:128:20 | pouter | AST only | | by_reference.cpp:128:23:128:23 | a | AST only | | by_reference.cpp:130:8:130:12 | outer | AST only | | by_reference.cpp:130:14:130:25 | inner_nested | AST only | @@ -235,28 +293,28 @@ | by_reference.cpp:136:16:136:16 | a | AST only | | complex.cpp:11:22:11:23 | a_ | AST only | | complex.cpp:12:22:12:23 | b_ | AST only | -| complex.cpp:51:8:51:8 | b | AST only | -| complex.cpp:51:10:51:14 | inner | AST only | -| complex.cpp:51:16:51:16 | f | AST only | -| complex.cpp:52:8:52:8 | b | AST only | -| complex.cpp:52:10:52:14 | inner | AST only | -| complex.cpp:52:16:52:16 | f | AST only | -| complex.cpp:62:3:62:4 | b1 | AST only | -| complex.cpp:62:6:62:10 | inner | AST only | -| complex.cpp:62:12:62:12 | f | AST only | -| complex.cpp:63:3:63:4 | b2 | AST only | -| complex.cpp:63:6:63:10 | inner | AST only | -| complex.cpp:63:12:63:12 | f | AST only | -| complex.cpp:64:3:64:4 | b3 | AST only | -| complex.cpp:64:6:64:10 | inner | AST only | -| complex.cpp:64:12:64:12 | f | AST only | -| complex.cpp:65:3:65:4 | b3 | AST only | -| complex.cpp:65:6:65:10 | inner | AST only | -| complex.cpp:65:12:65:12 | f | AST only | -| complex.cpp:68:7:68:8 | b1 | AST only | -| complex.cpp:71:7:71:8 | b2 | AST only | -| complex.cpp:74:7:74:8 | b3 | AST only | -| complex.cpp:77:7:77:8 | b4 | AST only | +| complex.cpp:42:8:42:8 | b | AST only | +| complex.cpp:42:10:42:14 | inner | AST only | +| complex.cpp:42:16:42:16 | f | AST only | +| complex.cpp:43:8:43:8 | b | AST only | +| complex.cpp:43:10:43:14 | inner | AST only | +| complex.cpp:43:16:43:16 | f | AST only | +| complex.cpp:53:3:53:4 | b1 | AST only | +| complex.cpp:53:6:53:10 | inner | AST only | +| complex.cpp:53:12:53:12 | f | AST only | +| complex.cpp:54:3:54:4 | b2 | AST only | +| complex.cpp:54:6:54:10 | inner | AST only | +| complex.cpp:54:12:54:12 | f | AST only | +| complex.cpp:55:3:55:4 | b3 | AST only | +| complex.cpp:55:6:55:10 | inner | AST only | +| complex.cpp:55:12:55:12 | f | AST only | +| complex.cpp:56:3:56:4 | b3 | AST only | +| complex.cpp:56:6:56:10 | inner | AST only | +| complex.cpp:56:12:56:12 | f | AST only | +| complex.cpp:59:7:59:8 | b1 | AST only | +| complex.cpp:62:7:62:8 | b2 | AST only | +| complex.cpp:65:7:65:8 | b3 | AST only | +| complex.cpp:68:7:68:8 | b4 | AST only | | constructors.cpp:20:24:20:25 | a_ | AST only | | constructors.cpp:21:24:21:25 | b_ | AST only | | constructors.cpp:28:10:28:10 | f | AST only | @@ -304,6 +362,32 @@ | qualifiers.cpp:48:10:48:14 | outer | AST only | | qualifiers.cpp:48:16:48:20 | inner | AST only | | qualifiers.cpp:48:23:48:23 | a | AST only | +| realistic.cpp:26:5:26:10 | offset | AST only | +| realistic.cpp:42:20:42:20 | o | AST only | +| realistic.cpp:49:9:49:11 | foo | AST only | +| realistic.cpp:49:20:49:22 | baz | AST only | +| realistic.cpp:53:9:53:11 | foo | AST only | +| realistic.cpp:53:9:53:18 | access to array | AST only | +| realistic.cpp:53:20:53:22 | baz | AST only | +| realistic.cpp:53:25:53:33 | userInput | AST only | +| realistic.cpp:53:35:53:43 | bufferLen | AST only | +| realistic.cpp:54:16:54:18 | foo | AST only | +| realistic.cpp:54:16:54:25 | access to array | AST only | +| realistic.cpp:54:27:54:29 | baz | AST only | +| realistic.cpp:54:32:54:40 | userInput | AST only | +| realistic.cpp:54:42:54:47 | buffer | AST only | +| realistic.cpp:60:16:60:18 | dst | AST only | +| realistic.cpp:61:21:61:23 | foo | AST only | +| realistic.cpp:61:21:61:30 | access to array | AST only | +| realistic.cpp:61:32:61:34 | baz | AST only | +| realistic.cpp:61:37:61:45 | userInput | AST only | +| realistic.cpp:61:47:61:55 | bufferLen | AST only | +| realistic.cpp:65:21:65:23 | foo | AST only | +| realistic.cpp:65:21:65:30 | access to array | AST only | +| realistic.cpp:65:32:65:34 | baz | AST only | +| realistic.cpp:65:37:65:45 | userInput | AST only | +| realistic.cpp:65:47:65:52 | buffer | AST only | +| realistic.cpp:66:21:66:23 | dst | AST only | | simple.cpp:20:24:20:25 | a_ | AST only | | simple.cpp:21:24:21:25 | b_ | AST only | | simple.cpp:28:10:28:10 | f | AST only | @@ -320,6 +404,7 @@ | simple.cpp:83:9:83:10 | this | AST only | | simple.cpp:83:12:83:13 | f1 | AST only | | simple.cpp:84:14:84:20 | this | AST only | +| simple.cpp:92:7:92:7 | i | AST only | | struct_init.c:15:8:15:9 | ab | AST only | | struct_init.c:15:12:15:12 | a | AST only | | struct_init.c:16:8:16:9 | ab | AST only | @@ -342,6 +427,5 @@ | struct_init.c:34:14:34:22 | pointerAB | AST only | | struct_init.c:34:25:34:25 | b | AST only | | struct_init.c:36:10:36:24 | & ... | AST only | -| struct_init.c:36:11:36:15 | outer | AST only | | struct_init.c:46:10:46:14 | outer | AST only | | struct_init.c:46:16:46:24 | pointerAB | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql index 8f6296290e9c..d8b6b4e0e69a 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql @@ -5,43 +5,18 @@ import cpp import semmle.code.cpp.ir.dataflow.DataFlow::DataFlow as IR import semmle.code.cpp.dataflow.DataFlow::DataFlow as AST +import Nodes -newtype TNode = - TASTNode(AST::Node n) or - TIRNode(IR::Node n) - -class Node extends TNode { - string toString() { none() } - - IR::Node asIR() { none() } - - AST::Node asAST() { none() } - - Location getLocation() { none() } -} - -class ASTNode extends Node, TASTNode { - AST::Node n; - - ASTNode() { this = TASTNode(n) } +class ASTPartialDefNode extends ASTNode { + ASTPartialDefNode() { exists(n.asPartialDefinition()) } override string toString() { result = n.asPartialDefinition().toString() } - - override AST::Node asAST() { result = n } - - override Location getLocation() { result = n.getLocation() } } -class IRNode extends Node, TIRNode { - IR::Node n; - - IRNode() { this = TIRNode(n) } +class IRPartialDefNode extends IRNode { + IRPartialDefNode() { exists(n.asPartialDefinition()) } override string toString() { result = n.asPartialDefinition().toString() } - - override IR::Node asIR() { result = n } - - override Location getLocation() { result = n.getLocation() } } from Node node, AST::Node astNode, IR::Node irNode, string msg diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected index 050f4bc47d55..a66dd2869551 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected @@ -26,10 +26,29 @@ | aliasing.cpp:79:3:79:3 | s | | aliasing.cpp:86:3:86:3 | s | | aliasing.cpp:92:5:92:5 | s | +| aliasing.cpp:98:3:98:3 | s | +| aliasing.cpp:111:16:111:16 | s | +| aliasing.cpp:147:16:147:19 | access to array | +| aliasing.cpp:175:19:175:19 | s | +| aliasing.cpp:181:19:181:19 | s | +| aliasing.cpp:187:19:187:19 | s | +| aliasing.cpp:194:19:194:19 | s | +| aliasing.cpp:200:21:200:21 | s | +| aliasing.cpp:205:21:205:21 | s | +| arrays.cpp:6:3:6:5 | arr | +| arrays.cpp:36:3:36:17 | access to array | | by_reference.cpp:12:5:12:5 | s | | by_reference.cpp:16:5:16:8 | this | | by_reference.cpp:84:3:84:7 | inner | | by_reference.cpp:88:3:88:7 | inner | +| by_reference.cpp:102:22:102:26 | outer | +| by_reference.cpp:104:16:104:20 | outer | +| by_reference.cpp:106:22:106:27 | pouter | +| by_reference.cpp:108:16:108:21 | pouter | +| by_reference.cpp:122:21:122:25 | outer | +| by_reference.cpp:124:15:124:19 | outer | +| by_reference.cpp:126:21:126:26 | pouter | +| by_reference.cpp:128:15:128:20 | pouter | | complex.cpp:11:22:11:23 | this | | complex.cpp:12:22:12:23 | this | | constructors.cpp:20:24:20:25 | this | @@ -37,7 +56,10 @@ | qualifiers.cpp:9:30:9:33 | this | | qualifiers.cpp:12:49:12:53 | inner | | qualifiers.cpp:13:51:13:55 | inner | +| realistic.cpp:49:9:49:18 | access to array | | simple.cpp:20:24:20:25 | this | | simple.cpp:21:24:21:25 | this | | simple.cpp:65:5:65:5 | a | | simple.cpp:83:9:83:10 | f2 | +| simple.cpp:92:5:92:5 | a | +| struct_init.c:36:11:36:15 | outer | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected index 3f5a2e497d85..6c58d51ff742 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected @@ -185,6 +185,79 @@ | aliasing.cpp:92:3:92:3 | w | | aliasing.cpp:92:5:92:5 | s | | aliasing.cpp:92:7:92:8 | m1 | +| aliasing.cpp:98:3:98:3 | s | +| aliasing.cpp:98:5:98:6 | m1 | +| aliasing.cpp:106:3:106:5 | * ... | +| aliasing.cpp:111:15:111:19 | & ... | +| aliasing.cpp:111:16:111:16 | s | +| aliasing.cpp:121:15:121:16 | xs | +| aliasing.cpp:126:15:126:20 | ... - ... | +| aliasing.cpp:131:15:131:16 | xs | +| aliasing.cpp:136:15:136:17 | + ... | +| aliasing.cpp:141:15:141:15 | s | +| aliasing.cpp:141:17:141:20 | data | +| aliasing.cpp:147:15:147:22 | & ... | +| aliasing.cpp:147:16:147:19 | access to array | +| aliasing.cpp:158:15:158:15 | s | +| aliasing.cpp:158:17:158:20 | data | +| aliasing.cpp:164:15:164:15 | s | +| aliasing.cpp:164:17:164:20 | data | +| aliasing.cpp:175:15:175:22 | & ... | +| aliasing.cpp:175:16:175:17 | s2 | +| aliasing.cpp:175:19:175:19 | s | +| aliasing.cpp:181:15:181:22 | & ... | +| aliasing.cpp:181:16:181:17 | s2 | +| aliasing.cpp:181:19:181:19 | s | +| aliasing.cpp:187:15:187:22 | & ... | +| aliasing.cpp:187:16:187:17 | s2 | +| aliasing.cpp:187:19:187:19 | s | +| aliasing.cpp:194:15:194:22 | & ... | +| aliasing.cpp:194:16:194:17 | s2 | +| aliasing.cpp:194:19:194:19 | s | +| aliasing.cpp:200:15:200:24 | & ... | +| aliasing.cpp:200:16:200:18 | ps2 | +| aliasing.cpp:200:21:200:21 | s | +| aliasing.cpp:205:15:205:24 | & ... | +| aliasing.cpp:205:16:205:18 | ps2 | +| aliasing.cpp:205:21:205:21 | s | +| arrays.cpp:6:3:6:8 | access to array | +| arrays.cpp:15:3:15:10 | * ... | +| arrays.cpp:36:3:36:3 | o | +| arrays.cpp:36:3:36:17 | access to array | +| arrays.cpp:36:5:36:10 | nested | +| arrays.cpp:36:19:36:22 | data | +| arrays.cpp:37:8:37:8 | o | +| arrays.cpp:37:8:37:22 | access to array | +| arrays.cpp:37:10:37:15 | nested | +| arrays.cpp:37:24:37:27 | data | +| arrays.cpp:38:8:38:8 | o | +| arrays.cpp:38:8:38:22 | access to array | +| arrays.cpp:38:10:38:15 | nested | +| arrays.cpp:38:24:38:27 | data | +| arrays.cpp:42:3:42:3 | o | +| arrays.cpp:42:3:42:20 | access to array | +| arrays.cpp:42:5:42:12 | indirect | +| arrays.cpp:42:22:42:25 | data | +| arrays.cpp:43:8:43:8 | o | +| arrays.cpp:43:8:43:25 | access to array | +| arrays.cpp:43:10:43:17 | indirect | +| arrays.cpp:43:27:43:30 | data | +| arrays.cpp:44:8:44:8 | o | +| arrays.cpp:44:8:44:25 | access to array | +| arrays.cpp:44:10:44:17 | indirect | +| arrays.cpp:44:27:44:30 | data | +| arrays.cpp:48:3:48:3 | o | +| arrays.cpp:48:3:48:20 | access to array | +| arrays.cpp:48:5:48:12 | indirect | +| arrays.cpp:48:22:48:25 | data | +| arrays.cpp:49:8:49:8 | o | +| arrays.cpp:49:8:49:25 | access to array | +| arrays.cpp:49:10:49:17 | indirect | +| arrays.cpp:49:27:49:30 | data | +| arrays.cpp:50:8:50:8 | o | +| arrays.cpp:50:8:50:25 | access to array | +| arrays.cpp:50:10:50:17 | indirect | +| arrays.cpp:50:27:50:30 | data | | by_reference.cpp:12:5:12:5 | s | | by_reference.cpp:12:8:12:8 | a | | by_reference.cpp:16:5:16:8 | this | @@ -209,6 +282,8 @@ | by_reference.cpp:84:10:84:10 | a | | by_reference.cpp:88:3:88:7 | inner | | by_reference.cpp:88:9:88:9 | a | +| by_reference.cpp:92:3:92:5 | * ... | +| by_reference.cpp:96:3:96:4 | pa | | by_reference.cpp:102:21:102:39 | & ... | | by_reference.cpp:102:22:102:26 | outer | | by_reference.cpp:103:21:103:25 | outer | @@ -269,28 +344,28 @@ | complex.cpp:11:22:11:23 | this | | complex.cpp:12:22:12:23 | b_ | | complex.cpp:12:22:12:23 | this | -| complex.cpp:51:8:51:8 | b | -| complex.cpp:51:10:51:14 | inner | -| complex.cpp:51:16:51:16 | f | -| complex.cpp:52:8:52:8 | b | -| complex.cpp:52:10:52:14 | inner | -| complex.cpp:52:16:52:16 | f | -| complex.cpp:62:3:62:4 | b1 | -| complex.cpp:62:6:62:10 | inner | -| complex.cpp:62:12:62:12 | f | -| complex.cpp:63:3:63:4 | b2 | -| complex.cpp:63:6:63:10 | inner | -| complex.cpp:63:12:63:12 | f | -| complex.cpp:64:3:64:4 | b3 | -| complex.cpp:64:6:64:10 | inner | -| complex.cpp:64:12:64:12 | f | -| complex.cpp:65:3:65:4 | b3 | -| complex.cpp:65:6:65:10 | inner | -| complex.cpp:65:12:65:12 | f | -| complex.cpp:68:7:68:8 | b1 | -| complex.cpp:71:7:71:8 | b2 | -| complex.cpp:74:7:74:8 | b3 | -| complex.cpp:77:7:77:8 | b4 | +| complex.cpp:42:8:42:8 | b | +| complex.cpp:42:10:42:14 | inner | +| complex.cpp:42:16:42:16 | f | +| complex.cpp:43:8:43:8 | b | +| complex.cpp:43:10:43:14 | inner | +| complex.cpp:43:16:43:16 | f | +| complex.cpp:53:3:53:4 | b1 | +| complex.cpp:53:6:53:10 | inner | +| complex.cpp:53:12:53:12 | f | +| complex.cpp:54:3:54:4 | b2 | +| complex.cpp:54:6:54:10 | inner | +| complex.cpp:54:12:54:12 | f | +| complex.cpp:55:3:55:4 | b3 | +| complex.cpp:55:6:55:10 | inner | +| complex.cpp:55:12:55:12 | f | +| complex.cpp:56:3:56:4 | b3 | +| complex.cpp:56:6:56:10 | inner | +| complex.cpp:56:12:56:12 | f | +| complex.cpp:59:7:59:8 | b1 | +| complex.cpp:62:7:62:8 | b2 | +| complex.cpp:65:7:65:8 | b3 | +| complex.cpp:68:7:68:8 | b4 | | constructors.cpp:20:24:20:25 | a_ | | constructors.cpp:20:24:20:25 | this | | constructors.cpp:21:24:21:25 | b_ | @@ -343,6 +418,33 @@ | qualifiers.cpp:48:10:48:14 | outer | | qualifiers.cpp:48:16:48:20 | inner | | qualifiers.cpp:48:23:48:23 | a | +| realistic.cpp:26:5:26:10 | offset | +| realistic.cpp:42:20:42:20 | o | +| realistic.cpp:49:9:49:11 | foo | +| realistic.cpp:49:9:49:18 | access to array | +| realistic.cpp:49:20:49:22 | baz | +| realistic.cpp:53:9:53:11 | foo | +| realistic.cpp:53:9:53:18 | access to array | +| realistic.cpp:53:20:53:22 | baz | +| realistic.cpp:53:25:53:33 | userInput | +| realistic.cpp:53:35:53:43 | bufferLen | +| realistic.cpp:54:16:54:18 | foo | +| realistic.cpp:54:16:54:25 | access to array | +| realistic.cpp:54:27:54:29 | baz | +| realistic.cpp:54:32:54:40 | userInput | +| realistic.cpp:54:42:54:47 | buffer | +| realistic.cpp:60:16:60:18 | dst | +| realistic.cpp:61:21:61:23 | foo | +| realistic.cpp:61:21:61:30 | access to array | +| realistic.cpp:61:32:61:34 | baz | +| realistic.cpp:61:37:61:45 | userInput | +| realistic.cpp:61:47:61:55 | bufferLen | +| realistic.cpp:65:21:65:23 | foo | +| realistic.cpp:65:21:65:30 | access to array | +| realistic.cpp:65:32:65:34 | baz | +| realistic.cpp:65:37:65:45 | userInput | +| realistic.cpp:65:47:65:52 | buffer | +| realistic.cpp:66:21:66:23 | dst | | simple.cpp:20:24:20:25 | a_ | | simple.cpp:20:24:20:25 | this | | simple.cpp:21:24:21:25 | b_ | @@ -363,6 +465,8 @@ | simple.cpp:83:9:83:10 | this | | simple.cpp:83:12:83:13 | f1 | | simple.cpp:84:14:84:20 | this | +| simple.cpp:92:5:92:5 | a | +| simple.cpp:92:7:92:7 | i | | struct_init.c:15:8:15:9 | ab | | struct_init.c:15:12:15:12 | a | | struct_init.c:16:8:16:9 | ab | diff --git a/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected index d505ff5d87e9..b932e0395f49 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected @@ -51,14 +51,14 @@ edges | A.cpp:160:29:160:29 | b | A.cpp:160:18:160:60 | call to MyList [head] | | A.cpp:161:18:161:40 | call to MyList [next, head] | A.cpp:162:38:162:39 | l2 [next, head] | | A.cpp:161:38:161:39 | l1 [head] | A.cpp:161:18:161:40 | call to MyList [next, head] | -| A.cpp:162:18:162:40 | call to MyList [next, next, ... (3)] | A.cpp:165:10:165:11 | l3 [next, next, ... (3)] | -| A.cpp:162:18:162:40 | call to MyList [next, next, ... (3)] | A.cpp:167:44:167:44 | l [next, next, ... (3)] | -| A.cpp:162:38:162:39 | l2 [next, head] | A.cpp:162:18:162:40 | call to MyList [next, next, ... (3)] | -| A.cpp:165:10:165:11 | l3 [next, next, ... (3)] | A.cpp:165:14:165:17 | next [next, head] | +| A.cpp:162:18:162:40 | call to MyList [next, next, head] | A.cpp:165:10:165:11 | l3 [next, next, head] | +| A.cpp:162:18:162:40 | call to MyList [next, next, head] | A.cpp:167:44:167:44 | l [next, next, head] | +| A.cpp:162:38:162:39 | l2 [next, head] | A.cpp:162:18:162:40 | call to MyList [next, next, head] | +| A.cpp:165:10:165:11 | l3 [next, next, head] | A.cpp:165:14:165:17 | next [next, head] | | A.cpp:165:14:165:17 | next [next, head] | A.cpp:165:20:165:23 | next [head] | | A.cpp:165:20:165:23 | next [head] | A.cpp:165:26:165:29 | head | | A.cpp:167:44:167:44 | l [next, head] | A.cpp:167:47:167:50 | next [head] | -| A.cpp:167:44:167:44 | l [next, next, ... (3)] | A.cpp:167:47:167:50 | next [next, head] | +| A.cpp:167:44:167:44 | l [next, next, head] | A.cpp:167:47:167:50 | next [next, head] | | A.cpp:167:47:167:50 | next [head] | A.cpp:169:12:169:12 | l [head] | | A.cpp:167:47:167:50 | next [next, head] | A.cpp:167:44:167:44 | l [next, head] | | A.cpp:169:12:169:12 | l [head] | A.cpp:169:15:169:18 | head | @@ -113,14 +113,14 @@ edges | D.cpp:51:27:51:27 | e | D.cpp:51:8:51:14 | ref arg call to getBox1 [elem] | | D.cpp:52:14:52:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] | | D.cpp:56:15:56:24 | new | D.cpp:58:5:58:27 | ... = ... | -| D.cpp:58:5:58:12 | boxfield [post update] [box, elem] | D.cpp:58:5:58:12 | this [post update] [boxfield, box, ... (3)] | -| D.cpp:58:5:58:12 | this [post update] [boxfield, box, ... (3)] | D.cpp:59:5:59:7 | this [boxfield, box, ... (3)] | +| D.cpp:58:5:58:12 | boxfield [post update] [box, elem] | D.cpp:58:5:58:12 | this [post update] [boxfield, box, elem] | +| D.cpp:58:5:58:12 | this [post update] [boxfield, box, elem] | D.cpp:59:5:59:7 | this [boxfield, box, elem] | | D.cpp:58:5:58:27 | ... = ... | D.cpp:58:15:58:17 | box [post update] [elem] | | D.cpp:58:15:58:17 | box [post update] [elem] | D.cpp:58:5:58:12 | boxfield [post update] [box, elem] | -| D.cpp:59:5:59:7 | this [boxfield, box, ... (3)] | D.cpp:63:8:63:10 | this [boxfield, box, ... (3)] | -| D.cpp:63:8:63:10 | this [boxfield, box, ... (3)] | D.cpp:64:10:64:17 | this [boxfield, box, ... (3)] | +| D.cpp:59:5:59:7 | this [boxfield, box, elem] | D.cpp:63:8:63:10 | this [boxfield, box, elem] | +| D.cpp:63:8:63:10 | this [boxfield, box, elem] | D.cpp:64:10:64:17 | this [boxfield, box, elem] | | D.cpp:64:10:64:17 | boxfield [box, elem] | D.cpp:64:20:64:22 | box [elem] | -| D.cpp:64:10:64:17 | this [boxfield, box, ... (3)] | D.cpp:64:10:64:17 | boxfield [box, elem] | +| D.cpp:64:10:64:17 | this [boxfield, box, elem] | D.cpp:64:10:64:17 | boxfield [box, elem] | | D.cpp:64:20:64:22 | box [elem] | D.cpp:64:25:64:28 | elem | | E.cpp:19:27:19:27 | p [data, buffer] | E.cpp:21:10:21:10 | p [data, buffer] | | E.cpp:21:10:21:10 | p [data, buffer] | E.cpp:21:13:21:16 | data [buffer] | @@ -155,6 +155,74 @@ edges | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:92:3:92:23 | ... = ... | | aliasing.cpp:93:8:93:8 | w [s, m1] | aliasing.cpp:93:10:93:10 | s [m1] | | aliasing.cpp:93:10:93:10 | s [m1] | aliasing.cpp:93:12:93:13 | m1 | +| aliasing.cpp:106:4:106:5 | pa [inner post update] | aliasing.cpp:158:17:158:20 | ref arg data | +| aliasing.cpp:106:4:106:5 | pa [inner post update] | aliasing.cpp:164:17:164:20 | ref arg data | +| aliasing.cpp:106:4:106:5 | pa [inner post update] | aliasing.cpp:175:15:175:22 | ref arg & ... | +| aliasing.cpp:106:4:106:5 | pa [inner post update] | aliasing.cpp:187:15:187:22 | ref arg & ... | +| aliasing.cpp:106:4:106:5 | pa [inner post update] | aliasing.cpp:200:15:200:24 | ref arg & ... | +| aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:106:4:106:5 | pa [inner post update] | +| aliasing.cpp:158:15:158:15 | s [post update] [data] | aliasing.cpp:159:9:159:9 | s [data] | +| aliasing.cpp:158:17:158:20 | ref arg data | aliasing.cpp:158:15:158:15 | s [post update] [data] | +| aliasing.cpp:159:9:159:9 | s [data] | aliasing.cpp:159:11:159:14 | data | +| aliasing.cpp:159:11:159:14 | data | aliasing.cpp:159:8:159:14 | * ... | +| aliasing.cpp:164:15:164:15 | s [post update] [data] | aliasing.cpp:165:8:165:8 | s [data] | +| aliasing.cpp:164:17:164:20 | ref arg data | aliasing.cpp:164:15:164:15 | s [post update] [data] | +| aliasing.cpp:165:8:165:8 | s [data] | aliasing.cpp:165:10:165:13 | data | +| aliasing.cpp:165:10:165:13 | data | aliasing.cpp:165:8:165:16 | access to array | +| aliasing.cpp:175:15:175:22 | ref arg & ... | aliasing.cpp:175:21:175:22 | m1 [inner post update] | +| aliasing.cpp:175:16:175:17 | s2 [post update] [s, m1] | aliasing.cpp:176:8:176:9 | s2 [s, m1] | +| aliasing.cpp:175:19:175:19 | s [post update] [m1] | aliasing.cpp:175:16:175:17 | s2 [post update] [s, m1] | +| aliasing.cpp:175:21:175:22 | m1 [inner post update] | aliasing.cpp:175:19:175:19 | s [post update] [m1] | +| aliasing.cpp:176:8:176:9 | s2 [s, m1] | aliasing.cpp:176:11:176:11 | s [m1] | +| aliasing.cpp:176:11:176:11 | s [m1] | aliasing.cpp:176:13:176:14 | m1 | +| aliasing.cpp:187:15:187:22 | ref arg & ... | aliasing.cpp:187:21:187:22 | m1 [inner post update] | +| aliasing.cpp:187:16:187:17 | s2 [post update] [s, m1] | aliasing.cpp:189:8:189:11 | s2_2 [s, m1] | +| aliasing.cpp:187:19:187:19 | s [post update] [m1] | aliasing.cpp:187:16:187:17 | s2 [post update] [s, m1] | +| aliasing.cpp:187:21:187:22 | m1 [inner post update] | aliasing.cpp:187:19:187:19 | s [post update] [m1] | +| aliasing.cpp:189:8:189:11 | s2_2 [s, m1] | aliasing.cpp:189:13:189:13 | s [m1] | +| aliasing.cpp:189:13:189:13 | s [m1] | aliasing.cpp:189:15:189:16 | m1 | +| aliasing.cpp:200:15:200:24 | ref arg & ... | aliasing.cpp:200:23:200:24 | m1 [inner post update] | +| aliasing.cpp:200:16:200:18 | ps2 [post update] [s, m1] | aliasing.cpp:201:8:201:10 | ps2 [s, m1] | +| aliasing.cpp:200:21:200:21 | s [post update] [m1] | aliasing.cpp:200:16:200:18 | ps2 [post update] [s, m1] | +| aliasing.cpp:200:23:200:24 | m1 [inner post update] | aliasing.cpp:200:21:200:21 | s [post update] [m1] | +| aliasing.cpp:201:8:201:10 | ps2 [s, m1] | aliasing.cpp:201:13:201:13 | s [m1] | +| aliasing.cpp:201:13:201:13 | s [m1] | aliasing.cpp:201:15:201:16 | m1 | +| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:7:8:7:13 | access to array | +| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:8:8:8:13 | access to array | +| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:9:8:9:11 | * ... | +| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:10:8:10:15 | * ... | +| arrays.cpp:15:14:15:23 | call to user_input | arrays.cpp:16:8:16:13 | access to array | +| arrays.cpp:15:14:15:23 | call to user_input | arrays.cpp:17:8:17:13 | access to array | +| arrays.cpp:36:3:36:3 | o [post update] [nested, arr, data] | arrays.cpp:37:8:37:8 | o [nested, arr, data] | +| arrays.cpp:36:3:36:3 | o [post update] [nested, arr, data] | arrays.cpp:38:8:38:8 | o [nested, arr, data] | +| arrays.cpp:36:3:36:17 | access to array [post update] [data] | arrays.cpp:36:12:36:14 | arr [inner post update] [data] | +| arrays.cpp:36:3:36:37 | ... = ... | arrays.cpp:36:3:36:17 | access to array [post update] [data] | +| arrays.cpp:36:5:36:10 | nested [post update] [arr, data] | arrays.cpp:36:3:36:3 | o [post update] [nested, arr, data] | +| arrays.cpp:36:12:36:14 | arr [inner post update] [data] | arrays.cpp:36:5:36:10 | nested [post update] [arr, data] | +| arrays.cpp:36:26:36:35 | call to user_input | arrays.cpp:36:3:36:37 | ... = ... | +| arrays.cpp:37:8:37:8 | o [nested, arr, data] | arrays.cpp:37:10:37:15 | nested [arr, data] | +| arrays.cpp:37:8:37:22 | access to array [data] | arrays.cpp:37:24:37:27 | data | +| arrays.cpp:37:10:37:15 | nested [arr, data] | arrays.cpp:37:17:37:19 | arr [data] | +| arrays.cpp:37:17:37:19 | arr [data] | arrays.cpp:37:8:37:22 | access to array [data] | +| arrays.cpp:38:8:38:8 | o [nested, arr, data] | arrays.cpp:38:10:38:15 | nested [arr, data] | +| arrays.cpp:38:8:38:22 | access to array [data] | arrays.cpp:38:24:38:27 | data | +| arrays.cpp:38:10:38:15 | nested [arr, data] | arrays.cpp:38:17:38:19 | arr [data] | +| arrays.cpp:38:17:38:19 | arr [data] | arrays.cpp:38:8:38:22 | access to array [data] | +| arrays.cpp:42:3:42:3 | o [post update] [indirect, arr, data] | arrays.cpp:43:8:43:8 | o [indirect, arr, data] | +| arrays.cpp:42:3:42:3 | o [post update] [indirect, arr, data] | arrays.cpp:44:8:44:8 | o [indirect, arr, data] | +| arrays.cpp:42:3:42:20 | access to array [post update] [data] | arrays.cpp:42:15:42:17 | arr [inner post update] [data] | +| arrays.cpp:42:3:42:40 | ... = ... | arrays.cpp:42:3:42:20 | access to array [post update] [data] | +| arrays.cpp:42:5:42:12 | indirect [post update] [arr, data] | arrays.cpp:42:3:42:3 | o [post update] [indirect, arr, data] | +| arrays.cpp:42:15:42:17 | arr [inner post update] [data] | arrays.cpp:42:5:42:12 | indirect [post update] [arr, data] | +| arrays.cpp:42:29:42:38 | call to user_input | arrays.cpp:42:3:42:40 | ... = ... | +| arrays.cpp:43:8:43:8 | o [indirect, arr, data] | arrays.cpp:43:10:43:17 | indirect [arr, data] | +| arrays.cpp:43:8:43:25 | access to array [data] | arrays.cpp:43:27:43:30 | data | +| arrays.cpp:43:10:43:17 | indirect [arr, data] | arrays.cpp:43:20:43:22 | arr [data] | +| arrays.cpp:43:20:43:22 | arr [data] | arrays.cpp:43:8:43:25 | access to array [data] | +| arrays.cpp:44:8:44:8 | o [indirect, arr, data] | arrays.cpp:44:10:44:17 | indirect [arr, data] | +| arrays.cpp:44:8:44:25 | access to array [data] | arrays.cpp:44:27:44:30 | data | +| arrays.cpp:44:10:44:17 | indirect [arr, data] | arrays.cpp:44:20:44:22 | arr [data] | +| arrays.cpp:44:20:44:22 | arr [data] | arrays.cpp:44:8:44:25 | access to array [data] | | by_reference.cpp:50:3:50:3 | ref arg s [a] | by_reference.cpp:51:8:51:8 | s [a] | | by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:50:3:50:3 | ref arg s [a] | | by_reference.cpp:51:8:51:8 | s [a] | by_reference.cpp:51:10:51:20 | call to getDirectly | @@ -184,6 +252,9 @@ edges | by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:127:21:127:38 | ref arg * ... [a] | | by_reference.cpp:88:3:88:24 | ... = ... | by_reference.cpp:88:3:88:7 | inner [post update] [a] | | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | ... = ... | +| by_reference.cpp:92:4:92:5 | pa [inner post update] | by_reference.cpp:104:15:104:22 | ref arg & ... | +| by_reference.cpp:92:4:92:5 | pa [inner post update] | by_reference.cpp:108:15:108:24 | ref arg & ... | +| by_reference.cpp:92:9:92:18 | call to user_input | by_reference.cpp:92:4:92:5 | pa [inner post update] | | by_reference.cpp:95:25:95:26 | pa | by_reference.cpp:124:21:124:21 | ref arg a | | by_reference.cpp:95:25:95:26 | pa | by_reference.cpp:128:23:128:23 | ref arg a | | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:95:25:95:26 | pa | @@ -192,19 +263,27 @@ edges | by_reference.cpp:102:28:102:39 | inner_nested [inner post update] [a] | by_reference.cpp:102:22:102:26 | outer [post update] [inner_nested, a] | | by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | | by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] | by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | +| by_reference.cpp:104:15:104:22 | ref arg & ... | by_reference.cpp:104:22:104:22 | a [inner post update] | +| by_reference.cpp:104:16:104:20 | outer [post update] [a] | by_reference.cpp:112:8:112:12 | outer [a] | +| by_reference.cpp:104:22:104:22 | a [inner post update] | by_reference.cpp:104:16:104:20 | outer [post update] [a] | | by_reference.cpp:106:21:106:41 | ref arg & ... [a] | by_reference.cpp:106:30:106:41 | inner_nested [inner post update] [a] | | by_reference.cpp:106:22:106:27 | pouter [post update] [inner_nested, a] | by_reference.cpp:114:8:114:13 | pouter [inner_nested, a] | | by_reference.cpp:106:30:106:41 | inner_nested [inner post update] [a] | by_reference.cpp:106:22:106:27 | pouter [post update] [inner_nested, a] | | by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | | by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] | by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | +| by_reference.cpp:108:15:108:24 | ref arg & ... | by_reference.cpp:108:24:108:24 | a [inner post update] | +| by_reference.cpp:108:16:108:21 | pouter [post update] [a] | by_reference.cpp:116:8:116:13 | pouter [a] | +| by_reference.cpp:108:24:108:24 | a [inner post update] | by_reference.cpp:108:16:108:21 | pouter [post update] [a] | | by_reference.cpp:110:8:110:12 | outer [inner_nested, a] | by_reference.cpp:110:14:110:25 | inner_nested [a] | | by_reference.cpp:110:14:110:25 | inner_nested [a] | by_reference.cpp:110:27:110:27 | a | | by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | by_reference.cpp:111:14:111:22 | inner_ptr [a] | | by_reference.cpp:111:14:111:22 | inner_ptr [a] | by_reference.cpp:111:25:111:25 | a | +| by_reference.cpp:112:8:112:12 | outer [a] | by_reference.cpp:112:14:112:14 | a | | by_reference.cpp:114:8:114:13 | pouter [inner_nested, a] | by_reference.cpp:114:16:114:27 | inner_nested [a] | | by_reference.cpp:114:16:114:27 | inner_nested [a] | by_reference.cpp:114:29:114:29 | a | | by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | by_reference.cpp:115:16:115:24 | inner_ptr [a] | | by_reference.cpp:115:16:115:24 | inner_ptr [a] | by_reference.cpp:115:27:115:27 | a | +| by_reference.cpp:116:8:116:13 | pouter [a] | by_reference.cpp:116:16:116:16 | a | | by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | by_reference.cpp:130:8:130:12 | outer [inner_nested, a] | | by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | | by_reference.cpp:123:21:123:36 | ref arg * ... [a] | by_reference.cpp:123:28:123:36 | inner_ptr [inner post update] [a] | @@ -229,33 +308,34 @@ edges | by_reference.cpp:135:8:135:13 | pouter [inner_ptr, a] | by_reference.cpp:135:16:135:24 | inner_ptr [a] | | by_reference.cpp:135:16:135:24 | inner_ptr [a] | by_reference.cpp:135:27:135:27 | a | | by_reference.cpp:136:8:136:13 | pouter [a] | by_reference.cpp:136:16:136:16 | a | -| complex.cpp:40:17:40:17 | b [inner, f, ... (3)] | complex.cpp:51:8:51:8 | b [inner, f, ... (3)] | -| complex.cpp:40:17:40:17 | b [inner, f, ... (3)] | complex.cpp:52:8:52:8 | b [inner, f, ... (3)] | -| complex.cpp:51:8:51:8 | b [inner, f, ... (3)] | complex.cpp:51:10:51:14 | inner [f, a_] | -| complex.cpp:51:10:51:14 | inner [f, a_] | complex.cpp:51:16:51:16 | f [a_] | -| complex.cpp:51:16:51:16 | f [a_] | complex.cpp:51:18:51:18 | call to a | -| complex.cpp:52:8:52:8 | b [inner, f, ... (3)] | complex.cpp:52:10:52:14 | inner [f, b_] | -| complex.cpp:52:10:52:14 | inner [f, b_] | complex.cpp:52:16:52:16 | f [b_] | -| complex.cpp:52:16:52:16 | f [b_] | complex.cpp:52:18:52:18 | call to b | -| complex.cpp:62:3:62:4 | b1 [post update] [inner, f, ... (3)] | complex.cpp:68:7:68:8 | b1 [inner, f, ... (3)] | -| complex.cpp:62:6:62:10 | inner [post update] [f, a_] | complex.cpp:62:3:62:4 | b1 [post update] [inner, f, ... (3)] | -| complex.cpp:62:12:62:12 | ref arg f [a_] | complex.cpp:62:6:62:10 | inner [post update] [f, a_] | -| complex.cpp:62:19:62:28 | call to user_input | complex.cpp:62:12:62:12 | ref arg f [a_] | -| complex.cpp:63:3:63:4 | b2 [post update] [inner, f, ... (3)] | complex.cpp:71:7:71:8 | b2 [inner, f, ... (3)] | -| complex.cpp:63:6:63:10 | inner [post update] [f, b_] | complex.cpp:63:3:63:4 | b2 [post update] [inner, f, ... (3)] | -| complex.cpp:63:12:63:12 | ref arg f [b_] | complex.cpp:63:6:63:10 | inner [post update] [f, b_] | -| complex.cpp:63:19:63:28 | call to user_input | complex.cpp:63:12:63:12 | ref arg f [b_] | -| complex.cpp:64:3:64:4 | b3 [post update] [inner, f, ... (3)] | complex.cpp:74:7:74:8 | b3 [inner, f, ... (3)] | -| complex.cpp:64:6:64:10 | inner [post update] [f, a_] | complex.cpp:64:3:64:4 | b3 [post update] [inner, f, ... (3)] | -| complex.cpp:64:12:64:12 | ref arg f [a_] | complex.cpp:64:6:64:10 | inner [post update] [f, a_] | -| complex.cpp:64:19:64:28 | call to user_input | complex.cpp:64:12:64:12 | ref arg f [a_] | -| complex.cpp:65:3:65:4 | b3 [post update] [inner, f, ... (3)] | complex.cpp:74:7:74:8 | b3 [inner, f, ... (3)] | -| complex.cpp:65:6:65:10 | inner [post update] [f, b_] | complex.cpp:65:3:65:4 | b3 [post update] [inner, f, ... (3)] | -| complex.cpp:65:12:65:12 | ref arg f [b_] | complex.cpp:65:6:65:10 | inner [post update] [f, b_] | -| complex.cpp:65:19:65:28 | call to user_input | complex.cpp:65:12:65:12 | ref arg f [b_] | -| complex.cpp:68:7:68:8 | b1 [inner, f, ... (3)] | complex.cpp:40:17:40:17 | b [inner, f, ... (3)] | -| complex.cpp:71:7:71:8 | b2 [inner, f, ... (3)] | complex.cpp:40:17:40:17 | b [inner, f, ... (3)] | -| complex.cpp:74:7:74:8 | b3 [inner, f, ... (3)] | complex.cpp:40:17:40:17 | b [inner, f, ... (3)] | +| complex.cpp:40:17:40:17 | b [inner, f, a_] | complex.cpp:42:8:42:8 | b [inner, f, a_] | +| complex.cpp:40:17:40:17 | b [inner, f, b_] | complex.cpp:43:8:43:8 | b [inner, f, b_] | +| complex.cpp:42:8:42:8 | b [inner, f, a_] | complex.cpp:42:10:42:14 | inner [f, a_] | +| complex.cpp:42:10:42:14 | inner [f, a_] | complex.cpp:42:16:42:16 | f [a_] | +| complex.cpp:42:16:42:16 | f [a_] | complex.cpp:42:18:42:18 | call to a | +| complex.cpp:43:8:43:8 | b [inner, f, b_] | complex.cpp:43:10:43:14 | inner [f, b_] | +| complex.cpp:43:10:43:14 | inner [f, b_] | complex.cpp:43:16:43:16 | f [b_] | +| complex.cpp:43:16:43:16 | f [b_] | complex.cpp:43:18:43:18 | call to b | +| complex.cpp:53:3:53:4 | b1 [post update] [inner, f, a_] | complex.cpp:59:7:59:8 | b1 [inner, f, a_] | +| complex.cpp:53:6:53:10 | inner [post update] [f, a_] | complex.cpp:53:3:53:4 | b1 [post update] [inner, f, a_] | +| complex.cpp:53:12:53:12 | ref arg f [a_] | complex.cpp:53:6:53:10 | inner [post update] [f, a_] | +| complex.cpp:53:19:53:28 | call to user_input | complex.cpp:53:12:53:12 | ref arg f [a_] | +| complex.cpp:54:3:54:4 | b2 [post update] [inner, f, b_] | complex.cpp:62:7:62:8 | b2 [inner, f, b_] | +| complex.cpp:54:6:54:10 | inner [post update] [f, b_] | complex.cpp:54:3:54:4 | b2 [post update] [inner, f, b_] | +| complex.cpp:54:12:54:12 | ref arg f [b_] | complex.cpp:54:6:54:10 | inner [post update] [f, b_] | +| complex.cpp:54:19:54:28 | call to user_input | complex.cpp:54:12:54:12 | ref arg f [b_] | +| complex.cpp:55:3:55:4 | b3 [post update] [inner, f, a_] | complex.cpp:65:7:65:8 | b3 [inner, f, a_] | +| complex.cpp:55:6:55:10 | inner [post update] [f, a_] | complex.cpp:55:3:55:4 | b3 [post update] [inner, f, a_] | +| complex.cpp:55:12:55:12 | ref arg f [a_] | complex.cpp:55:6:55:10 | inner [post update] [f, a_] | +| complex.cpp:55:19:55:28 | call to user_input | complex.cpp:55:12:55:12 | ref arg f [a_] | +| complex.cpp:56:3:56:4 | b3 [post update] [inner, f, b_] | complex.cpp:65:7:65:8 | b3 [inner, f, b_] | +| complex.cpp:56:6:56:10 | inner [post update] [f, b_] | complex.cpp:56:3:56:4 | b3 [post update] [inner, f, b_] | +| complex.cpp:56:12:56:12 | ref arg f [b_] | complex.cpp:56:6:56:10 | inner [post update] [f, b_] | +| complex.cpp:56:19:56:28 | call to user_input | complex.cpp:56:12:56:12 | ref arg f [b_] | +| complex.cpp:59:7:59:8 | b1 [inner, f, a_] | complex.cpp:40:17:40:17 | b [inner, f, a_] | +| complex.cpp:62:7:62:8 | b2 [inner, f, b_] | complex.cpp:40:17:40:17 | b [inner, f, b_] | +| complex.cpp:65:7:65:8 | b3 [inner, f, a_] | complex.cpp:40:17:40:17 | b [inner, f, a_] | +| complex.cpp:65:7:65:8 | b3 [inner, f, b_] | complex.cpp:40:17:40:17 | b [inner, f, b_] | | constructors.cpp:26:15:26:15 | f [a_] | constructors.cpp:28:10:28:10 | f [a_] | | constructors.cpp:26:15:26:15 | f [b_] | constructors.cpp:29:10:29:10 | f [b_] | | constructors.cpp:28:10:28:10 | f [a_] | constructors.cpp:28:12:28:12 | call to a | @@ -307,6 +387,18 @@ edges | qualifiers.cpp:47:31:47:40 | call to user_input | qualifiers.cpp:47:5:47:42 | ... = ... | | qualifiers.cpp:48:10:48:14 | outer [inner, a] | qualifiers.cpp:48:16:48:20 | inner [a] | | qualifiers.cpp:48:16:48:20 | inner [a] | qualifiers.cpp:48:23:48:23 | a | +| realistic.cpp:53:9:53:11 | foo [post update] [bar, baz, userInput, bufferLen] | realistic.cpp:61:21:61:23 | foo [bar, baz, userInput, bufferLen] | +| realistic.cpp:53:9:53:18 | access to array [post update] [baz, userInput, bufferLen] | realistic.cpp:53:13:53:15 | bar [inner post update] [baz, userInput, bufferLen] | +| realistic.cpp:53:9:53:66 | ... = ... | realistic.cpp:53:25:53:33 | userInput [post update] [bufferLen] | +| realistic.cpp:53:13:53:15 | bar [inner post update] [baz, userInput, bufferLen] | realistic.cpp:53:9:53:11 | foo [post update] [bar, baz, userInput, bufferLen] | +| realistic.cpp:53:20:53:22 | baz [post update] [userInput, bufferLen] | realistic.cpp:53:9:53:18 | access to array [post update] [baz, userInput, bufferLen] | +| realistic.cpp:53:25:53:33 | userInput [post update] [bufferLen] | realistic.cpp:53:20:53:22 | baz [post update] [userInput, bufferLen] | +| realistic.cpp:53:55:53:64 | call to user_input | realistic.cpp:53:9:53:66 | ... = ... | +| realistic.cpp:61:21:61:23 | foo [bar, baz, userInput, bufferLen] | realistic.cpp:61:25:61:27 | bar [baz, userInput, bufferLen] | +| realistic.cpp:61:21:61:30 | access to array [baz, userInput, bufferLen] | realistic.cpp:61:32:61:34 | baz [userInput, bufferLen] | +| realistic.cpp:61:25:61:27 | bar [baz, userInput, bufferLen] | realistic.cpp:61:21:61:30 | access to array [baz, userInput, bufferLen] | +| realistic.cpp:61:32:61:34 | baz [userInput, bufferLen] | realistic.cpp:61:37:61:45 | userInput [bufferLen] | +| realistic.cpp:61:37:61:45 | userInput [bufferLen] | realistic.cpp:61:47:61:55 | bufferLen | | simple.cpp:26:15:26:15 | f [a_] | simple.cpp:28:10:28:10 | f [a_] | | simple.cpp:26:15:26:15 | f [b_] | simple.cpp:29:10:29:10 | f [b_] | | simple.cpp:28:10:28:10 | f [a_] | simple.cpp:28:12:28:12 | call to a | @@ -332,6 +424,10 @@ edges | simple.cpp:83:9:83:28 | ... = ... | simple.cpp:83:9:83:10 | f2 [post update] [f1] | | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | ... = ... | | simple.cpp:84:14:84:20 | this [f2, f1] | simple.cpp:84:14:84:20 | call to getf2f1 | +| simple.cpp:92:5:92:5 | a [post update] [i] | simple.cpp:94:10:94:11 | a2 [i] | +| simple.cpp:92:5:92:22 | ... = ... | simple.cpp:92:5:92:5 | a [post update] [i] | +| simple.cpp:92:11:92:20 | call to user_input | simple.cpp:92:5:92:22 | ... = ... | +| simple.cpp:94:10:94:11 | a2 [i] | simple.cpp:94:13:94:13 | i | | struct_init.c:14:24:14:25 | ab [a] | struct_init.c:15:8:15:9 | ab [a] | | struct_init.c:15:8:15:9 | ab [a] | struct_init.c:15:12:15:12 | a | | struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:22:8:22:9 | ab [a] | @@ -422,14 +518,14 @@ nodes | A.cpp:160:29:160:29 | b | semmle.label | b | | A.cpp:161:18:161:40 | call to MyList [next, head] | semmle.label | call to MyList [next, head] | | A.cpp:161:38:161:39 | l1 [head] | semmle.label | l1 [head] | -| A.cpp:162:18:162:40 | call to MyList [next, next, ... (3)] | semmle.label | call to MyList [next, next, ... (3)] | +| A.cpp:162:18:162:40 | call to MyList [next, next, head] | semmle.label | call to MyList [next, next, head] | | A.cpp:162:38:162:39 | l2 [next, head] | semmle.label | l2 [next, head] | -| A.cpp:165:10:165:11 | l3 [next, next, ... (3)] | semmle.label | l3 [next, next, ... (3)] | +| A.cpp:165:10:165:11 | l3 [next, next, head] | semmle.label | l3 [next, next, head] | | A.cpp:165:14:165:17 | next [next, head] | semmle.label | next [next, head] | | A.cpp:165:20:165:23 | next [head] | semmle.label | next [head] | | A.cpp:165:26:165:29 | head | semmle.label | head | | A.cpp:167:44:167:44 | l [next, head] | semmle.label | l [next, head] | -| A.cpp:167:44:167:44 | l [next, next, ... (3)] | semmle.label | l [next, next, ... (3)] | +| A.cpp:167:44:167:44 | l [next, next, head] | semmle.label | l [next, next, head] | | A.cpp:167:47:167:50 | next [head] | semmle.label | next [head] | | A.cpp:167:47:167:50 | next [next, head] | semmle.label | next [next, head] | | A.cpp:169:12:169:12 | l [head] | semmle.label | l [head] | @@ -491,13 +587,13 @@ nodes | D.cpp:52:14:52:14 | b [box, elem] | semmle.label | b [box, elem] | | D.cpp:56:15:56:24 | new | semmle.label | new | | D.cpp:58:5:58:12 | boxfield [post update] [box, elem] | semmle.label | boxfield [post update] [box, elem] | -| D.cpp:58:5:58:12 | this [post update] [boxfield, box, ... (3)] | semmle.label | this [post update] [boxfield, box, ... (3)] | +| D.cpp:58:5:58:12 | this [post update] [boxfield, box, elem] | semmle.label | this [post update] [boxfield, box, elem] | | D.cpp:58:5:58:27 | ... = ... | semmle.label | ... = ... | | D.cpp:58:15:58:17 | box [post update] [elem] | semmle.label | box [post update] [elem] | -| D.cpp:59:5:59:7 | this [boxfield, box, ... (3)] | semmle.label | this [boxfield, box, ... (3)] | -| D.cpp:63:8:63:10 | this [boxfield, box, ... (3)] | semmle.label | this [boxfield, box, ... (3)] | +| D.cpp:59:5:59:7 | this [boxfield, box, elem] | semmle.label | this [boxfield, box, elem] | +| D.cpp:63:8:63:10 | this [boxfield, box, elem] | semmle.label | this [boxfield, box, elem] | | D.cpp:64:10:64:17 | boxfield [box, elem] | semmle.label | boxfield [box, elem] | -| D.cpp:64:10:64:17 | this [boxfield, box, ... (3)] | semmle.label | this [boxfield, box, ... (3)] | +| D.cpp:64:10:64:17 | this [boxfield, box, elem] | semmle.label | this [boxfield, box, elem] | | D.cpp:64:20:64:22 | box [elem] | semmle.label | box [elem] | | D.cpp:64:25:64:28 | elem | semmle.label | elem | | E.cpp:19:27:19:27 | p [data, buffer] | semmle.label | p [data, buffer] | @@ -539,6 +635,79 @@ nodes | aliasing.cpp:93:8:93:8 | w [s, m1] | semmle.label | w [s, m1] | | aliasing.cpp:93:10:93:10 | s [m1] | semmle.label | s [m1] | | aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 | +| aliasing.cpp:106:4:106:5 | pa [inner post update] | semmle.label | pa [inner post update] | +| aliasing.cpp:106:9:106:18 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:158:15:158:15 | s [post update] [data] | semmle.label | s [post update] [data] | +| aliasing.cpp:158:17:158:20 | ref arg data | semmle.label | ref arg data | +| aliasing.cpp:159:8:159:14 | * ... | semmle.label | * ... | +| aliasing.cpp:159:9:159:9 | s [data] | semmle.label | s [data] | +| aliasing.cpp:159:11:159:14 | data | semmle.label | data | +| aliasing.cpp:164:15:164:15 | s [post update] [data] | semmle.label | s [post update] [data] | +| aliasing.cpp:164:17:164:20 | ref arg data | semmle.label | ref arg data | +| aliasing.cpp:165:8:165:8 | s [data] | semmle.label | s [data] | +| aliasing.cpp:165:8:165:16 | access to array | semmle.label | access to array | +| aliasing.cpp:165:10:165:13 | data | semmle.label | data | +| aliasing.cpp:175:15:175:22 | ref arg & ... | semmle.label | ref arg & ... | +| aliasing.cpp:175:16:175:17 | s2 [post update] [s, m1] | semmle.label | s2 [post update] [s, m1] | +| aliasing.cpp:175:19:175:19 | s [post update] [m1] | semmle.label | s [post update] [m1] | +| aliasing.cpp:175:21:175:22 | m1 [inner post update] | semmle.label | m1 [inner post update] | +| aliasing.cpp:176:8:176:9 | s2 [s, m1] | semmle.label | s2 [s, m1] | +| aliasing.cpp:176:11:176:11 | s [m1] | semmle.label | s [m1] | +| aliasing.cpp:176:13:176:14 | m1 | semmle.label | m1 | +| aliasing.cpp:187:15:187:22 | ref arg & ... | semmle.label | ref arg & ... | +| aliasing.cpp:187:16:187:17 | s2 [post update] [s, m1] | semmle.label | s2 [post update] [s, m1] | +| aliasing.cpp:187:19:187:19 | s [post update] [m1] | semmle.label | s [post update] [m1] | +| aliasing.cpp:187:21:187:22 | m1 [inner post update] | semmle.label | m1 [inner post update] | +| aliasing.cpp:189:8:189:11 | s2_2 [s, m1] | semmle.label | s2_2 [s, m1] | +| aliasing.cpp:189:13:189:13 | s [m1] | semmle.label | s [m1] | +| aliasing.cpp:189:15:189:16 | m1 | semmle.label | m1 | +| aliasing.cpp:200:15:200:24 | ref arg & ... | semmle.label | ref arg & ... | +| aliasing.cpp:200:16:200:18 | ps2 [post update] [s, m1] | semmle.label | ps2 [post update] [s, m1] | +| aliasing.cpp:200:21:200:21 | s [post update] [m1] | semmle.label | s [post update] [m1] | +| aliasing.cpp:200:23:200:24 | m1 [inner post update] | semmle.label | m1 [inner post update] | +| aliasing.cpp:201:8:201:10 | ps2 [s, m1] | semmle.label | ps2 [s, m1] | +| aliasing.cpp:201:13:201:13 | s [m1] | semmle.label | s [m1] | +| aliasing.cpp:201:15:201:16 | m1 | semmle.label | m1 | +| arrays.cpp:6:12:6:21 | call to user_input | semmle.label | call to user_input | +| arrays.cpp:7:8:7:13 | access to array | semmle.label | access to array | +| arrays.cpp:8:8:8:13 | access to array | semmle.label | access to array | +| arrays.cpp:9:8:9:11 | * ... | semmle.label | * ... | +| arrays.cpp:10:8:10:15 | * ... | semmle.label | * ... | +| arrays.cpp:15:14:15:23 | call to user_input | semmle.label | call to user_input | +| arrays.cpp:16:8:16:13 | access to array | semmle.label | access to array | +| arrays.cpp:17:8:17:13 | access to array | semmle.label | access to array | +| arrays.cpp:36:3:36:3 | o [post update] [nested, arr, data] | semmle.label | o [post update] [nested, arr, data] | +| arrays.cpp:36:3:36:17 | access to array [post update] [data] | semmle.label | access to array [post update] [data] | +| arrays.cpp:36:3:36:37 | ... = ... | semmle.label | ... = ... | +| arrays.cpp:36:5:36:10 | nested [post update] [arr, data] | semmle.label | nested [post update] [arr, data] | +| arrays.cpp:36:12:36:14 | arr [inner post update] [data] | semmle.label | arr [inner post update] [data] | +| arrays.cpp:36:26:36:35 | call to user_input | semmle.label | call to user_input | +| arrays.cpp:37:8:37:8 | o [nested, arr, data] | semmle.label | o [nested, arr, data] | +| arrays.cpp:37:8:37:22 | access to array [data] | semmle.label | access to array [data] | +| arrays.cpp:37:10:37:15 | nested [arr, data] | semmle.label | nested [arr, data] | +| arrays.cpp:37:17:37:19 | arr [data] | semmle.label | arr [data] | +| arrays.cpp:37:24:37:27 | data | semmle.label | data | +| arrays.cpp:38:8:38:8 | o [nested, arr, data] | semmle.label | o [nested, arr, data] | +| arrays.cpp:38:8:38:22 | access to array [data] | semmle.label | access to array [data] | +| arrays.cpp:38:10:38:15 | nested [arr, data] | semmle.label | nested [arr, data] | +| arrays.cpp:38:17:38:19 | arr [data] | semmle.label | arr [data] | +| arrays.cpp:38:24:38:27 | data | semmle.label | data | +| arrays.cpp:42:3:42:3 | o [post update] [indirect, arr, data] | semmle.label | o [post update] [indirect, arr, data] | +| arrays.cpp:42:3:42:20 | access to array [post update] [data] | semmle.label | access to array [post update] [data] | +| arrays.cpp:42:3:42:40 | ... = ... | semmle.label | ... = ... | +| arrays.cpp:42:5:42:12 | indirect [post update] [arr, data] | semmle.label | indirect [post update] [arr, data] | +| arrays.cpp:42:15:42:17 | arr [inner post update] [data] | semmle.label | arr [inner post update] [data] | +| arrays.cpp:42:29:42:38 | call to user_input | semmle.label | call to user_input | +| arrays.cpp:43:8:43:8 | o [indirect, arr, data] | semmle.label | o [indirect, arr, data] | +| arrays.cpp:43:8:43:25 | access to array [data] | semmle.label | access to array [data] | +| arrays.cpp:43:10:43:17 | indirect [arr, data] | semmle.label | indirect [arr, data] | +| arrays.cpp:43:20:43:22 | arr [data] | semmle.label | arr [data] | +| arrays.cpp:43:27:43:30 | data | semmle.label | data | +| arrays.cpp:44:8:44:8 | o [indirect, arr, data] | semmle.label | o [indirect, arr, data] | +| arrays.cpp:44:8:44:25 | access to array [data] | semmle.label | access to array [data] | +| arrays.cpp:44:10:44:17 | indirect [arr, data] | semmle.label | indirect [arr, data] | +| arrays.cpp:44:20:44:22 | arr [data] | semmle.label | arr [data] | +| arrays.cpp:44:27:44:30 | data | semmle.label | data | | by_reference.cpp:50:3:50:3 | ref arg s [a] | semmle.label | ref arg s [a] | | by_reference.cpp:50:17:50:26 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:51:8:51:8 | s [a] | semmle.label | s [a] | @@ -562,6 +731,8 @@ nodes | by_reference.cpp:88:3:88:7 | inner [post update] [a] | semmle.label | inner [post update] [a] | | by_reference.cpp:88:3:88:24 | ... = ... | semmle.label | ... = ... | | by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:92:4:92:5 | pa [inner post update] | semmle.label | pa [inner post update] | +| by_reference.cpp:92:9:92:18 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:95:25:95:26 | pa | semmle.label | pa | | by_reference.cpp:96:8:96:17 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:102:21:102:39 | ref arg & ... [a] | semmle.label | ref arg & ... [a] | @@ -569,23 +740,33 @@ nodes | by_reference.cpp:102:28:102:39 | inner_nested [inner post update] [a] | semmle.label | inner_nested [inner post update] [a] | | by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | semmle.label | outer [post update] [inner_ptr, a] | | by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] | semmle.label | ref arg inner_ptr [a] | +| by_reference.cpp:104:15:104:22 | ref arg & ... | semmle.label | ref arg & ... | +| by_reference.cpp:104:16:104:20 | outer [post update] [a] | semmle.label | outer [post update] [a] | +| by_reference.cpp:104:22:104:22 | a [inner post update] | semmle.label | a [inner post update] | | by_reference.cpp:106:21:106:41 | ref arg & ... [a] | semmle.label | ref arg & ... [a] | | by_reference.cpp:106:22:106:27 | pouter [post update] [inner_nested, a] | semmle.label | pouter [post update] [inner_nested, a] | | by_reference.cpp:106:30:106:41 | inner_nested [inner post update] [a] | semmle.label | inner_nested [inner post update] [a] | | by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | semmle.label | pouter [post update] [inner_ptr, a] | | by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] | semmle.label | ref arg inner_ptr [a] | +| by_reference.cpp:108:15:108:24 | ref arg & ... | semmle.label | ref arg & ... | +| by_reference.cpp:108:16:108:21 | pouter [post update] [a] | semmle.label | pouter [post update] [a] | +| by_reference.cpp:108:24:108:24 | a [inner post update] | semmle.label | a [inner post update] | | by_reference.cpp:110:8:110:12 | outer [inner_nested, a] | semmle.label | outer [inner_nested, a] | | by_reference.cpp:110:14:110:25 | inner_nested [a] | semmle.label | inner_nested [a] | | by_reference.cpp:110:27:110:27 | a | semmle.label | a | | by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | semmle.label | outer [inner_ptr, a] | | by_reference.cpp:111:14:111:22 | inner_ptr [a] | semmle.label | inner_ptr [a] | | by_reference.cpp:111:25:111:25 | a | semmle.label | a | +| by_reference.cpp:112:8:112:12 | outer [a] | semmle.label | outer [a] | +| by_reference.cpp:112:14:112:14 | a | semmle.label | a | | by_reference.cpp:114:8:114:13 | pouter [inner_nested, a] | semmle.label | pouter [inner_nested, a] | | by_reference.cpp:114:16:114:27 | inner_nested [a] | semmle.label | inner_nested [a] | | by_reference.cpp:114:29:114:29 | a | semmle.label | a | | by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | semmle.label | pouter [inner_ptr, a] | | by_reference.cpp:115:16:115:24 | inner_ptr [a] | semmle.label | inner_ptr [a] | | by_reference.cpp:115:27:115:27 | a | semmle.label | a | +| by_reference.cpp:116:8:116:13 | pouter [a] | semmle.label | pouter [a] | +| by_reference.cpp:116:16:116:16 | a | semmle.label | a | | by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | semmle.label | outer [post update] [inner_nested, a] | | by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | semmle.label | ref arg inner_nested [a] | | by_reference.cpp:123:21:123:36 | ref arg * ... [a] | semmle.label | ref arg * ... [a] | @@ -616,34 +797,36 @@ nodes | by_reference.cpp:135:27:135:27 | a | semmle.label | a | | by_reference.cpp:136:8:136:13 | pouter [a] | semmle.label | pouter [a] | | by_reference.cpp:136:16:136:16 | a | semmle.label | a | -| complex.cpp:40:17:40:17 | b [inner, f, ... (3)] | semmle.label | b [inner, f, ... (3)] | -| complex.cpp:51:8:51:8 | b [inner, f, ... (3)] | semmle.label | b [inner, f, ... (3)] | -| complex.cpp:51:10:51:14 | inner [f, a_] | semmle.label | inner [f, a_] | -| complex.cpp:51:16:51:16 | f [a_] | semmle.label | f [a_] | -| complex.cpp:51:18:51:18 | call to a | semmle.label | call to a | -| complex.cpp:52:8:52:8 | b [inner, f, ... (3)] | semmle.label | b [inner, f, ... (3)] | -| complex.cpp:52:10:52:14 | inner [f, b_] | semmle.label | inner [f, b_] | -| complex.cpp:52:16:52:16 | f [b_] | semmle.label | f [b_] | -| complex.cpp:52:18:52:18 | call to b | semmle.label | call to b | -| complex.cpp:62:3:62:4 | b1 [post update] [inner, f, ... (3)] | semmle.label | b1 [post update] [inner, f, ... (3)] | -| complex.cpp:62:6:62:10 | inner [post update] [f, a_] | semmle.label | inner [post update] [f, a_] | -| complex.cpp:62:12:62:12 | ref arg f [a_] | semmle.label | ref arg f [a_] | -| complex.cpp:62:19:62:28 | call to user_input | semmle.label | call to user_input | -| complex.cpp:63:3:63:4 | b2 [post update] [inner, f, ... (3)] | semmle.label | b2 [post update] [inner, f, ... (3)] | -| complex.cpp:63:6:63:10 | inner [post update] [f, b_] | semmle.label | inner [post update] [f, b_] | -| complex.cpp:63:12:63:12 | ref arg f [b_] | semmle.label | ref arg f [b_] | -| complex.cpp:63:19:63:28 | call to user_input | semmle.label | call to user_input | -| complex.cpp:64:3:64:4 | b3 [post update] [inner, f, ... (3)] | semmle.label | b3 [post update] [inner, f, ... (3)] | -| complex.cpp:64:6:64:10 | inner [post update] [f, a_] | semmle.label | inner [post update] [f, a_] | -| complex.cpp:64:12:64:12 | ref arg f [a_] | semmle.label | ref arg f [a_] | -| complex.cpp:64:19:64:28 | call to user_input | semmle.label | call to user_input | -| complex.cpp:65:3:65:4 | b3 [post update] [inner, f, ... (3)] | semmle.label | b3 [post update] [inner, f, ... (3)] | -| complex.cpp:65:6:65:10 | inner [post update] [f, b_] | semmle.label | inner [post update] [f, b_] | -| complex.cpp:65:12:65:12 | ref arg f [b_] | semmle.label | ref arg f [b_] | -| complex.cpp:65:19:65:28 | call to user_input | semmle.label | call to user_input | -| complex.cpp:68:7:68:8 | b1 [inner, f, ... (3)] | semmle.label | b1 [inner, f, ... (3)] | -| complex.cpp:71:7:71:8 | b2 [inner, f, ... (3)] | semmle.label | b2 [inner, f, ... (3)] | -| complex.cpp:74:7:74:8 | b3 [inner, f, ... (3)] | semmle.label | b3 [inner, f, ... (3)] | +| complex.cpp:40:17:40:17 | b [inner, f, a_] | semmle.label | b [inner, f, a_] | +| complex.cpp:40:17:40:17 | b [inner, f, b_] | semmle.label | b [inner, f, b_] | +| complex.cpp:42:8:42:8 | b [inner, f, a_] | semmle.label | b [inner, f, a_] | +| complex.cpp:42:10:42:14 | inner [f, a_] | semmle.label | inner [f, a_] | +| complex.cpp:42:16:42:16 | f [a_] | semmle.label | f [a_] | +| complex.cpp:42:18:42:18 | call to a | semmle.label | call to a | +| complex.cpp:43:8:43:8 | b [inner, f, b_] | semmle.label | b [inner, f, b_] | +| complex.cpp:43:10:43:14 | inner [f, b_] | semmle.label | inner [f, b_] | +| complex.cpp:43:16:43:16 | f [b_] | semmle.label | f [b_] | +| complex.cpp:43:18:43:18 | call to b | semmle.label | call to b | +| complex.cpp:53:3:53:4 | b1 [post update] [inner, f, a_] | semmle.label | b1 [post update] [inner, f, a_] | +| complex.cpp:53:6:53:10 | inner [post update] [f, a_] | semmle.label | inner [post update] [f, a_] | +| complex.cpp:53:12:53:12 | ref arg f [a_] | semmle.label | ref arg f [a_] | +| complex.cpp:53:19:53:28 | call to user_input | semmle.label | call to user_input | +| complex.cpp:54:3:54:4 | b2 [post update] [inner, f, b_] | semmle.label | b2 [post update] [inner, f, b_] | +| complex.cpp:54:6:54:10 | inner [post update] [f, b_] | semmle.label | inner [post update] [f, b_] | +| complex.cpp:54:12:54:12 | ref arg f [b_] | semmle.label | ref arg f [b_] | +| complex.cpp:54:19:54:28 | call to user_input | semmle.label | call to user_input | +| complex.cpp:55:3:55:4 | b3 [post update] [inner, f, a_] | semmle.label | b3 [post update] [inner, f, a_] | +| complex.cpp:55:6:55:10 | inner [post update] [f, a_] | semmle.label | inner [post update] [f, a_] | +| complex.cpp:55:12:55:12 | ref arg f [a_] | semmle.label | ref arg f [a_] | +| complex.cpp:55:19:55:28 | call to user_input | semmle.label | call to user_input | +| complex.cpp:56:3:56:4 | b3 [post update] [inner, f, b_] | semmle.label | b3 [post update] [inner, f, b_] | +| complex.cpp:56:6:56:10 | inner [post update] [f, b_] | semmle.label | inner [post update] [f, b_] | +| complex.cpp:56:12:56:12 | ref arg f [b_] | semmle.label | ref arg f [b_] | +| complex.cpp:56:19:56:28 | call to user_input | semmle.label | call to user_input | +| complex.cpp:59:7:59:8 | b1 [inner, f, a_] | semmle.label | b1 [inner, f, a_] | +| complex.cpp:62:7:62:8 | b2 [inner, f, b_] | semmle.label | b2 [inner, f, b_] | +| complex.cpp:65:7:65:8 | b3 [inner, f, a_] | semmle.label | b3 [inner, f, a_] | +| complex.cpp:65:7:65:8 | b3 [inner, f, b_] | semmle.label | b3 [inner, f, b_] | | constructors.cpp:26:15:26:15 | f [a_] | semmle.label | f [a_] | | constructors.cpp:26:15:26:15 | f [b_] | semmle.label | f [b_] | | constructors.cpp:28:10:28:10 | f [a_] | semmle.label | f [a_] | @@ -703,6 +886,19 @@ nodes | qualifiers.cpp:48:10:48:14 | outer [inner, a] | semmle.label | outer [inner, a] | | qualifiers.cpp:48:16:48:20 | inner [a] | semmle.label | inner [a] | | qualifiers.cpp:48:23:48:23 | a | semmle.label | a | +| realistic.cpp:53:9:53:11 | foo [post update] [bar, baz, userInput, bufferLen] | semmle.label | foo [post update] [bar, baz, userInput, bufferLen] | +| realistic.cpp:53:9:53:18 | access to array [post update] [baz, userInput, bufferLen] | semmle.label | access to array [post update] [baz, userInput, bufferLen] | +| realistic.cpp:53:9:53:66 | ... = ... | semmle.label | ... = ... | +| realistic.cpp:53:13:53:15 | bar [inner post update] [baz, userInput, bufferLen] | semmle.label | bar [inner post update] [baz, userInput, bufferLen] | +| realistic.cpp:53:20:53:22 | baz [post update] [userInput, bufferLen] | semmle.label | baz [post update] [userInput, bufferLen] | +| realistic.cpp:53:25:53:33 | userInput [post update] [bufferLen] | semmle.label | userInput [post update] [bufferLen] | +| realistic.cpp:53:55:53:64 | call to user_input | semmle.label | call to user_input | +| realistic.cpp:61:21:61:23 | foo [bar, baz, userInput, bufferLen] | semmle.label | foo [bar, baz, userInput, bufferLen] | +| realistic.cpp:61:21:61:30 | access to array [baz, userInput, bufferLen] | semmle.label | access to array [baz, userInput, bufferLen] | +| realistic.cpp:61:25:61:27 | bar [baz, userInput, bufferLen] | semmle.label | bar [baz, userInput, bufferLen] | +| realistic.cpp:61:32:61:34 | baz [userInput, bufferLen] | semmle.label | baz [userInput, bufferLen] | +| realistic.cpp:61:37:61:45 | userInput [bufferLen] | semmle.label | userInput [bufferLen] | +| realistic.cpp:61:47:61:55 | bufferLen | semmle.label | bufferLen | | simple.cpp:26:15:26:15 | f [a_] | semmle.label | f [a_] | | simple.cpp:26:15:26:15 | f [b_] | semmle.label | f [b_] | | simple.cpp:28:10:28:10 | f [a_] | semmle.label | f [a_] | @@ -732,6 +928,11 @@ nodes | simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input | | simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 | | simple.cpp:84:14:84:20 | this [f2, f1] | semmle.label | this [f2, f1] | +| simple.cpp:92:5:92:5 | a [post update] [i] | semmle.label | a [post update] [i] | +| simple.cpp:92:5:92:22 | ... = ... | semmle.label | ... = ... | +| simple.cpp:92:11:92:20 | call to user_input | semmle.label | call to user_input | +| simple.cpp:94:10:94:11 | a2 [i] | semmle.label | a2 [i] | +| simple.cpp:94:13:94:13 | i | semmle.label | i | | struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] | | struct_init.c:15:8:15:9 | ab [a] | semmle.label | ab [a] | | struct_init.c:15:12:15:12 | a | semmle.label | a | @@ -792,28 +993,41 @@ nodes | aliasing.cpp:30:11:30:12 | m1 | aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:30:11:30:12 | m1 | m1 flows from $@ | aliasing.cpp:13:10:13:19 | call to user_input | call to user_input | | aliasing.cpp:62:14:62:15 | m1 | aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:62:14:62:15 | m1 | m1 flows from $@ | aliasing.cpp:60:11:60:20 | call to user_input | call to user_input | | aliasing.cpp:93:12:93:13 | m1 | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | m1 flows from $@ | aliasing.cpp:92:12:92:21 | call to user_input | call to user_input | +| aliasing.cpp:159:8:159:14 | * ... | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:159:8:159:14 | * ... | * ... flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | +| aliasing.cpp:165:8:165:16 | access to array | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:165:8:165:16 | access to array | access to array flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | +| aliasing.cpp:176:13:176:14 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:176:13:176:14 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | +| aliasing.cpp:189:15:189:16 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:189:15:189:16 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | +| aliasing.cpp:201:15:201:16 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:201:15:201:16 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | +| arrays.cpp:7:8:7:13 | access to array | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:7:8:7:13 | access to array | access to array flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input | +| arrays.cpp:8:8:8:13 | access to array | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:8:8:8:13 | access to array | access to array flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input | +| arrays.cpp:9:8:9:11 | * ... | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:9:8:9:11 | * ... | * ... flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input | +| arrays.cpp:10:8:10:15 | * ... | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:10:8:10:15 | * ... | * ... flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input | +| arrays.cpp:16:8:16:13 | access to array | arrays.cpp:15:14:15:23 | call to user_input | arrays.cpp:16:8:16:13 | access to array | access to array flows from $@ | arrays.cpp:15:14:15:23 | call to user_input | call to user_input | +| arrays.cpp:17:8:17:13 | access to array | arrays.cpp:15:14:15:23 | call to user_input | arrays.cpp:17:8:17:13 | access to array | access to array flows from $@ | arrays.cpp:15:14:15:23 | call to user_input | call to user_input | +| arrays.cpp:37:24:37:27 | data | arrays.cpp:36:26:36:35 | call to user_input | arrays.cpp:37:24:37:27 | data | data flows from $@ | arrays.cpp:36:26:36:35 | call to user_input | call to user_input | +| arrays.cpp:38:24:38:27 | data | arrays.cpp:36:26:36:35 | call to user_input | arrays.cpp:38:24:38:27 | data | data flows from $@ | arrays.cpp:36:26:36:35 | call to user_input | call to user_input | +| arrays.cpp:43:27:43:30 | data | arrays.cpp:42:29:42:38 | call to user_input | arrays.cpp:43:27:43:30 | data | data flows from $@ | arrays.cpp:42:29:42:38 | call to user_input | call to user_input | +| arrays.cpp:44:27:44:30 | data | arrays.cpp:42:29:42:38 | call to user_input | arrays.cpp:44:27:44:30 | data | data flows from $@ | arrays.cpp:42:29:42:38 | call to user_input | call to user_input | | by_reference.cpp:51:10:51:20 | call to getDirectly | by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:51:10:51:20 | call to getDirectly | call to getDirectly flows from $@ | by_reference.cpp:50:17:50:26 | call to user_input | call to user_input | | by_reference.cpp:57:10:57:22 | call to getIndirectly | by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:57:10:57:22 | call to getIndirectly | call to getIndirectly flows from $@ | by_reference.cpp:56:19:56:28 | call to user_input | call to user_input | | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | call to getThroughNonMember flows from $@ | by_reference.cpp:62:25:62:34 | call to user_input | call to user_input | | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | call to nonMemberGetA flows from $@ | by_reference.cpp:68:21:68:30 | call to user_input | call to user_input | | by_reference.cpp:110:27:110:27 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:110:27:110:27 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | | by_reference.cpp:111:25:111:25 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:111:25:111:25 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | +| by_reference.cpp:112:14:112:14 | a | by_reference.cpp:92:9:92:18 | call to user_input | by_reference.cpp:112:14:112:14 | a | a flows from $@ | by_reference.cpp:92:9:92:18 | call to user_input | call to user_input | | by_reference.cpp:114:29:114:29 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:114:29:114:29 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | | by_reference.cpp:115:27:115:27 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:115:27:115:27 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | +| by_reference.cpp:116:16:116:16 | a | by_reference.cpp:92:9:92:18 | call to user_input | by_reference.cpp:116:16:116:16 | a | a flows from $@ | by_reference.cpp:92:9:92:18 | call to user_input | call to user_input | | by_reference.cpp:130:27:130:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:130:27:130:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | | by_reference.cpp:131:25:131:25 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:131:25:131:25 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | | by_reference.cpp:132:14:132:14 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:132:14:132:14 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input | | by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | | by_reference.cpp:135:27:135:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:135:27:135:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | | by_reference.cpp:136:16:136:16 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:136:16:136:16 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input | -| complex.cpp:51:18:51:18 | call to a | complex.cpp:62:19:62:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:62:19:62:28 | call to user_input | call to user_input | -| complex.cpp:51:18:51:18 | call to a | complex.cpp:63:19:63:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:63:19:63:28 | call to user_input | call to user_input | -| complex.cpp:51:18:51:18 | call to a | complex.cpp:64:19:64:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:64:19:64:28 | call to user_input | call to user_input | -| complex.cpp:51:18:51:18 | call to a | complex.cpp:65:19:65:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:65:19:65:28 | call to user_input | call to user_input | -| complex.cpp:52:18:52:18 | call to b | complex.cpp:62:19:62:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:62:19:62:28 | call to user_input | call to user_input | -| complex.cpp:52:18:52:18 | call to b | complex.cpp:63:19:63:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:63:19:63:28 | call to user_input | call to user_input | -| complex.cpp:52:18:52:18 | call to b | complex.cpp:64:19:64:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:64:19:64:28 | call to user_input | call to user_input | -| complex.cpp:52:18:52:18 | call to b | complex.cpp:65:19:65:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:65:19:65:28 | call to user_input | call to user_input | +| complex.cpp:42:18:42:18 | call to a | complex.cpp:53:19:53:28 | call to user_input | complex.cpp:42:18:42:18 | call to a | call to a flows from $@ | complex.cpp:53:19:53:28 | call to user_input | call to user_input | +| complex.cpp:42:18:42:18 | call to a | complex.cpp:55:19:55:28 | call to user_input | complex.cpp:42:18:42:18 | call to a | call to a flows from $@ | complex.cpp:55:19:55:28 | call to user_input | call to user_input | +| complex.cpp:43:18:43:18 | call to b | complex.cpp:54:19:54:28 | call to user_input | complex.cpp:43:18:43:18 | call to b | call to b flows from $@ | complex.cpp:54:19:54:28 | call to user_input | call to user_input | +| complex.cpp:43:18:43:18 | call to b | complex.cpp:56:19:56:28 | call to user_input | complex.cpp:43:18:43:18 | call to b | call to b flows from $@ | complex.cpp:56:19:56:28 | call to user_input | call to user_input | | constructors.cpp:28:12:28:12 | call to a | constructors.cpp:34:11:34:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | call to a flows from $@ | constructors.cpp:34:11:34:20 | call to user_input | call to user_input | | constructors.cpp:28:12:28:12 | call to a | constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | call to a flows from $@ | constructors.cpp:36:11:36:20 | call to user_input | call to user_input | | constructors.cpp:29:12:29:12 | call to b | constructors.cpp:35:14:35:23 | call to user_input | constructors.cpp:29:12:29:12 | call to b | call to b flows from $@ | constructors.cpp:35:14:35:23 | call to user_input | call to user_input | @@ -824,12 +1038,14 @@ nodes | qualifiers.cpp:38:23:38:23 | a | qualifiers.cpp:37:38:37:47 | call to user_input | qualifiers.cpp:38:23:38:23 | a | a flows from $@ | qualifiers.cpp:37:38:37:47 | call to user_input | call to user_input | | qualifiers.cpp:43:23:43:23 | a | qualifiers.cpp:42:29:42:38 | call to user_input | qualifiers.cpp:43:23:43:23 | a | a flows from $@ | qualifiers.cpp:42:29:42:38 | call to user_input | call to user_input | | qualifiers.cpp:48:23:48:23 | a | qualifiers.cpp:47:31:47:40 | call to user_input | qualifiers.cpp:48:23:48:23 | a | a flows from $@ | qualifiers.cpp:47:31:47:40 | call to user_input | call to user_input | +| realistic.cpp:61:47:61:55 | bufferLen | realistic.cpp:53:55:53:64 | call to user_input | realistic.cpp:61:47:61:55 | bufferLen | bufferLen flows from $@ | realistic.cpp:53:55:53:64 | call to user_input | call to user_input | | simple.cpp:28:12:28:12 | call to a | simple.cpp:39:12:39:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:39:12:39:21 | call to user_input | call to user_input | | simple.cpp:28:12:28:12 | call to a | simple.cpp:41:12:41:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:41:12:41:21 | call to user_input | call to user_input | | simple.cpp:29:12:29:12 | call to b | simple.cpp:40:12:40:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:40:12:40:21 | call to user_input | call to user_input | | simple.cpp:29:12:29:12 | call to b | simple.cpp:42:12:42:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:42:12:42:21 | call to user_input | call to user_input | | simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | | simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input | +| simple.cpp:94:13:94:13 | i | simple.cpp:92:11:92:20 | call to user_input | simple.cpp:94:13:94:13 | i | i flows from $@ | simple.cpp:92:11:92:20 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:40:20:40:29 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/realistic.cpp b/cpp/ql/test/library-tests/dataflow/fields/realistic.cpp new file mode 100644 index 000000000000..f121dc58b4d7 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/realistic.cpp @@ -0,0 +1,70 @@ +typedef unsigned char u8; +typedef unsigned long size_t; +struct UserInput { + size_t bufferLen; + u8 buffer[256]; +}; +struct Baz { + int foo; + struct UserInput userInput; +}; +struct Bar { + u8* foo; + struct Baz * baz; +}; +struct Foo { + struct Bar bar[128]; +}; +void printf(const char *fmt, ...) { + return; +} +void * malloc(size_t size) { + static unsigned char buffer[0x1000]; + static unsigned int offset; + if (size + offset >= sizeof(buffer)) return nullptr; + void* m = (void*)&buffer[offset]; + offset += size; + return m; +} +void * memcpy ( void * destination, const void * source, size_t num ) { + u8* d = (u8*)destination; + u8* s = (u8*)source; + u8* e = d + num; + while(d != e) { + *d++ = *s++; + } + return destination; +} +void *user_input(void) { + return (void*)"\x0a\x00\x00\x00\x00\x00\x00\x00The quick brown fox jumps over the lazy dog"; +} +void sink(void *o) { + printf("%p\n", o); +} +#define MAX_BAZ 3 +int main(int argc, char** argv) { + char dst[256]; + struct Foo foo; + for (int i = 0; i < MAX_BAZ; i++) { + foo.bar[i].baz = (struct Baz*)malloc(sizeof(struct Baz)); + } + int i = 0; + while(i < MAX_BAZ) { + foo.bar[i].baz->userInput.bufferLen = (size_t)user_input(); + memcpy(foo.bar[i].baz->userInput.buffer, user_input(), sizeof(foo.bar[i].baz->userInput.buffer)); + if(foo.bar[i].baz->userInput.bufferLen > sizeof(foo.bar[i].baz->userInput.buffer)) + { + printf("The user-supplied input 0x%lx is larger than the buffer 0x%lx!\n", foo.bar[i].baz->userInput.bufferLen, sizeof(foo.bar[i].baz->userInput.buffer)); + return -1; + } + memcpy(dst, foo.bar[i].baz->userInput.buffer, foo.bar[i].baz->userInput.bufferLen); + sink((void*)foo.bar[i].baz->userInput.bufferLen); // $ast $f-:ir + // There is no flow to the following two `sink` calls because the + // source is the _pointer_ returned by `user_input` rather than the + // _data_ to which it points. + sink((void*)foo.bar[i].baz->userInput.buffer); // $f-:ast,ir + sink((void*)dst); // $f-:ast,ir + i++; + } + return 0; +} diff --git a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp index 4a3a15a0b176..3f7c91f77471 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp @@ -25,8 +25,8 @@ class Foo void bar(Foo &f) { - sink(f.a()); //$ast=39:12 $ast=41:12 $f-:ir - sink(f.b()); //$ast=40:12 $ast=42:12 $f-:ir + sink(f.a()); //$ast=39:12 $ast=41:12 $ir=39:12 $ir=41:12 + sink(f.b()); //$ast=40:12 $ast=42:12 $ir=40:12 $ir=42:12 } void foo() @@ -85,4 +85,13 @@ struct C2 } }; +typedef A A_typedef; + +void single_field_test_typedef(A_typedef a) +{ + a.i = user_input(); + A_typedef a2 = a; + sink(a2.i); //$ast,ir +} + } // namespace Simple diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/IRTaintTestCommon.qll b/cpp/ql/test/library-tests/dataflow/taint-tests/IRTaintTestCommon.qll index aa24c2629c7c..715d1883525a 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/IRTaintTestCommon.qll +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/IRTaintTestCommon.qll @@ -1,4 +1,5 @@ import cpp +import semmle.code.cpp.ir.IR import semmle.code.cpp.ir.dataflow.TaintTracking /** Common data flow configuration to be used by tests. */ @@ -6,7 +7,7 @@ class TestAllocationConfig extends TaintTracking::Configuration { TestAllocationConfig() { this = "TestAllocationConfig" } override predicate isSource(DataFlow::Node source) { - source.asExpr().(FunctionCall).getTarget().getName() = "source" + source.(DataFlow::ExprNode).getConvertedExpr().(FunctionCall).getTarget().getName() = "source" or source.asParameter().getName().matches("source%") or @@ -17,7 +18,16 @@ class TestAllocationConfig extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { exists(FunctionCall call | call.getTarget().getName() = "sink" and - sink.asExpr() = call.getAnArgument() + sink.(DataFlow::ExprNode).getConvertedExpr() = call.getAnArgument() + or + call.getTarget().getName() = "sink" and + sink.asExpr() = call.getAnArgument() and + sink.(DataFlow::ExprNode).getConvertedExpr() instanceof ReferenceDereferenceExpr + ) + or + exists(ReadSideEffectInstruction read | + read.getSideEffectOperand() = sink.asOperand() and + read.getPrimaryInstruction().(CallInstruction).getStaticCallTarget().hasName("sink") ) } diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/arrayassignment.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/arrayassignment.cpp new file mode 100644 index 000000000000..b86d2bf02346 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/arrayassignment.cpp @@ -0,0 +1,147 @@ + +int source(); +void sink(int); +void sink(class MyInt); +void sink(class MyArray); + +void test_pointer_deref_assignment() +{ + int x = 0; + int *p_x = &x; + int *p2_x = &x; + int &r_x = x; + + *p_x = source(); + + sink(x); // tainted [DETECTED BY IR ONLY] + sink(*p_x); // tainted + sink(*p2_x); // tainted [DETECTED BY IR ONLY] + sink(r_x); // tainted [DETECTED BY IR ONLY] +} + +void test_reference_deref_assignment() +{ + int x = 0; + int *p_x = &x; + int &r_x = x; + int &r2_x = x; + + r_x = source(); + + sink(x); // tainted [DETECTED BY IR ONLY] + sink(*p_x); // tainted [DETECTED BY IR ONLY] + sink(r_x); // tainted + sink(r2_x); // tainted [DETECTED BY IR ONLY] +} + +class MyInt +{ +public: + MyInt() : i(0) {} + + int &get() { return i; } + + MyInt &operator=(const int &other); + MyInt &operator=(const MyInt &other); + + int i; +}; + +void test_myint_member_assignment() +{ + MyInt mi; + + mi.i = source(); + + sink(mi); // tainted [DETECTED BY IR ONLY] + sink(mi.get()); // tainted +} + +void test_myint_method_assignment() +{ + MyInt mi; + + mi.get() = source(); + + sink(mi); // tainted [DETECTED BY IR ONLY] + sink(mi.get()); // tainted +} + +void test_myint_overloaded_assignment() +{ + MyInt mi, mi2; + + mi = source(); + mi2 = mi; + + sink(mi); // tainted [NOT DETECTED] + sink(mi.get()); // tainted [NOT DETECTED] + sink(mi2); // tainted [NOT DETECTED] + sink(mi2.get()); // tainted [NOT DETECTED] +} + +class MyArray +{ +public: + MyArray() : values({0}) {} + + int &get(int i) { return values[i]; } + + int &operator[](int i); + + int values[10]; +}; + +void test_myarray_member_assignment() +{ + MyArray ma; + + ma.values[0] = source(); + + sink(ma.values[0]); // tainted +} + +void test_myarray_method_assignment() +{ + MyArray ma; + + ma.get(0) = source(); + + sink(ma.get(0)); // tainted [NOT DETECTED] +} + +void test_myarray_overloaded_assignment() +{ + MyArray ma, ma2; + + ma[0] = source(); + ma2 = ma; + + sink(ma[0]); // tainted [NOT DETECTED] + sink(ma2[0]); // tainted [NOT DETECTED] +} + +void sink(int *); + +void test_array_reference_assignment() +{ + int arr1[10] = {0}; + int arr2[10] = {0}; + int arr3[10] = {0}; + int &ref1 = arr1[5]; + int *ptr2, *ptr3; + + ref1 = source(); + sink(ref1); // tainted + sink(arr1[5]); // tainted [DETECTED BY IR ONLY] + + ptr2 = &(arr2[5]); + *ptr2 = source(); + sink(*ptr2); // tainted + sink(arr2[5]); // tainted [DETECTED BY IR ONLY] + + ptr3 = arr3; + ptr3[5] = source(); + sink(ptr3[5]); // tainted + sink(arr3[5]); // tainted [DETECTED BY IR ONLY] +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass.cpp new file mode 100644 index 000000000000..d5745bcb7133 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass.cpp @@ -0,0 +1,69 @@ + +int source(); +void sink(...) {}; + +class MyCopyableClass { +public: + MyCopyableClass() {} // Constructor + MyCopyableClass(int _v) : v(_v) {} // ConversionConstructor + MyCopyableClass(const MyCopyableClass &other) : v(other.v) {} // CopyConstructor + MyCopyableClass &operator=(const MyCopyableClass &other) { // CopyAssignmentOperator + v = other.v; + return *this; + } + + int v; +}; + +void test_copyableclass() +{ + { + MyCopyableClass s1(1); + MyCopyableClass s2 = 1; + MyCopyableClass s3(s1); + MyCopyableClass s4; + s4 = 1; + + sink(s1); + sink(s2); + sink(s3); + sink(s4); + } + + { + MyCopyableClass s1(source()); + MyCopyableClass s2 = source(); + MyCopyableClass s3(s1); + MyCopyableClass s4; + s4 = source(); + + sink(s1); // tainted + sink(s2); // tainted + sink(s3); // tainted + sink(s4); // tainted + } + + { + MyCopyableClass s1; + MyCopyableClass s2 = s1; + MyCopyableClass s3(s1); + MyCopyableClass s4; + s4 = s1; + + sink(s1); + sink(s2); + sink(s3); + sink(s4); + } + + { + MyCopyableClass s1 = MyCopyableClass(source()); + MyCopyableClass s2; + MyCopyableClass s3; + s2 = MyCopyableClass(source()); + + sink(s1); // tainted + sink(s2); // tainted + sink(s3 = source()); // tainted + } +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass_declonly.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass_declonly.cpp new file mode 100644 index 000000000000..67f6a45fbe7c --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass_declonly.cpp @@ -0,0 +1,69 @@ + +int source(); +void sink(...) {}; + +class MyCopyableClassDeclOnly { +public: + MyCopyableClassDeclOnly(); // Constructor + MyCopyableClassDeclOnly(int _v); // ConversionConstructor + MyCopyableClassDeclOnly(const MyCopyableClassDeclOnly &other); // CopyConstructor + MyCopyableClassDeclOnly &operator=(const MyCopyableClassDeclOnly &other); // CopyAssignmentOperator + + + + + int v; +}; + +void test_copyableclass() +{ + { + MyCopyableClassDeclOnly s1(1); + MyCopyableClassDeclOnly s2 = 1; + MyCopyableClassDeclOnly s3(s1); + MyCopyableClassDeclOnly s4; + s4 = 1; + + sink(s1); + sink(s2); + sink(s3); + sink(s4); + } + + { + MyCopyableClassDeclOnly s1(source()); + MyCopyableClassDeclOnly s2 = source(); + MyCopyableClassDeclOnly s3(s1); + MyCopyableClassDeclOnly s4; + s4 = source(); + + sink(s1); // tainted + sink(s2); // tainted + sink(s3); // tainted + sink(s4); // tainted + } + + { + MyCopyableClassDeclOnly s1; + MyCopyableClassDeclOnly s2 = s1; + MyCopyableClassDeclOnly s3(s1); + MyCopyableClassDeclOnly s4; + s4 = s1; + + sink(s1); + sink(s2); + sink(s3); + sink(s4); + } + + { + MyCopyableClassDeclOnly s1 = MyCopyableClassDeclOnly(source()); + MyCopyableClassDeclOnly s2; + MyCopyableClassDeclOnly s3; + s2 = MyCopyableClassDeclOnly(source()); + + sink(s1); // tainted + sink(s2); // tainted + sink(s3 = source()); // tainted + } +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp index 90bbb1ca0cd3..fbe78cf02e10 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp @@ -112,7 +112,7 @@ void test1() { char buffer[256] = {0}; sink(mysprintf(buffer, 256, "%s", string::source())); - sink(buffer); // tainted [NOT DETECTED - implement UserDefinedFormattingFunction.getOutputParameterIndex()] + sink(buffer); // tainted } { diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected index 48d96a5c2c22..cc5f33b50c3c 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -1,3 +1,260 @@ +| arrayassignment.cpp:9:9:9:10 | 0 | arrayassignment.cpp:10:14:10:14 | x | | +| arrayassignment.cpp:9:9:9:10 | 0 | arrayassignment.cpp:11:15:11:15 | x | | +| arrayassignment.cpp:9:9:9:10 | 0 | arrayassignment.cpp:12:13:12:13 | x | | +| arrayassignment.cpp:9:9:9:10 | 0 | arrayassignment.cpp:16:7:16:7 | x | | +| arrayassignment.cpp:10:13:10:14 | & ... | arrayassignment.cpp:14:3:14:5 | p_x | | +| arrayassignment.cpp:10:13:10:14 | & ... | arrayassignment.cpp:17:8:17:10 | p_x | | +| arrayassignment.cpp:10:14:10:14 | x | arrayassignment.cpp:10:13:10:14 | & ... | | +| arrayassignment.cpp:11:14:11:15 | & ... | arrayassignment.cpp:18:8:18:11 | p2_x | | +| arrayassignment.cpp:11:15:11:15 | x | arrayassignment.cpp:11:14:11:15 | & ... | | +| arrayassignment.cpp:12:13:12:13 | x | arrayassignment.cpp:19:7:19:9 | r_x | | +| arrayassignment.cpp:14:2:14:5 | * ... [post update] | arrayassignment.cpp:14:3:14:5 | p_x [inner post update] | | +| arrayassignment.cpp:14:2:14:5 | * ... [post update] | arrayassignment.cpp:17:8:17:10 | p_x | | +| arrayassignment.cpp:14:2:14:16 | ... = ... | arrayassignment.cpp:14:2:14:5 | * ... [post update] | | +| arrayassignment.cpp:14:3:14:5 | p_x | arrayassignment.cpp:14:2:14:5 | * ... | TAINT | +| arrayassignment.cpp:14:9:14:14 | call to source | arrayassignment.cpp:14:2:14:16 | ... = ... | | +| arrayassignment.cpp:17:8:17:10 | p_x | arrayassignment.cpp:17:7:17:10 | * ... | TAINT | +| arrayassignment.cpp:18:8:18:11 | p2_x | arrayassignment.cpp:18:7:18:11 | * ... | TAINT | +| arrayassignment.cpp:24:9:24:10 | 0 | arrayassignment.cpp:25:14:25:14 | x | | +| arrayassignment.cpp:24:9:24:10 | 0 | arrayassignment.cpp:26:13:26:13 | x | | +| arrayassignment.cpp:24:9:24:10 | 0 | arrayassignment.cpp:27:14:27:14 | x | | +| arrayassignment.cpp:24:9:24:10 | 0 | arrayassignment.cpp:31:7:31:7 | x | | +| arrayassignment.cpp:25:13:25:14 | & ... | arrayassignment.cpp:32:8:32:10 | p_x | | +| arrayassignment.cpp:25:14:25:14 | x | arrayassignment.cpp:25:13:25:14 | & ... | | +| arrayassignment.cpp:27:14:27:14 | x | arrayassignment.cpp:34:7:34:10 | r2_x | | +| arrayassignment.cpp:29:2:29:4 | r_x [post update] | arrayassignment.cpp:33:7:33:9 | r_x | | +| arrayassignment.cpp:29:2:29:15 | ... = ... | arrayassignment.cpp:29:2:29:4 | r_x [post update] | | +| arrayassignment.cpp:29:8:29:13 | call to source | arrayassignment.cpp:29:2:29:15 | ... = ... | | +| arrayassignment.cpp:29:8:29:13 | call to source | arrayassignment.cpp:33:7:33:9 | r_x | | +| arrayassignment.cpp:32:8:32:10 | p_x | arrayassignment.cpp:32:7:32:10 | * ... | TAINT | +| arrayassignment.cpp:37:7:37:7 | Unknown literal | arrayassignment.cpp:37:7:37:7 | constructor init of field i | TAINT | +| arrayassignment.cpp:37:7:37:7 | this | arrayassignment.cpp:37:7:37:7 | constructor init of field i [pre-this] | | +| arrayassignment.cpp:40:2:40:6 | this | arrayassignment.cpp:40:12:40:15 | constructor init of field i [pre-this] | | +| arrayassignment.cpp:40:12:40:15 | 0 | arrayassignment.cpp:40:12:40:15 | constructor init of field i | TAINT | +| arrayassignment.cpp:42:7:42:9 | this | arrayassignment.cpp:42:22:42:22 | this | | +| arrayassignment.cpp:52:8:52:9 | call to MyInt | arrayassignment.cpp:54:2:54:3 | mi | | +| arrayassignment.cpp:52:8:52:9 | call to MyInt | arrayassignment.cpp:56:7:56:8 | mi | | +| arrayassignment.cpp:52:8:52:9 | call to MyInt | arrayassignment.cpp:57:7:57:8 | mi | | +| arrayassignment.cpp:54:2:54:3 | mi [post update] | arrayassignment.cpp:56:7:56:8 | mi | | +| arrayassignment.cpp:54:2:54:3 | mi [post update] | arrayassignment.cpp:57:7:57:8 | mi | | +| arrayassignment.cpp:54:2:54:16 | ... = ... | arrayassignment.cpp:54:5:54:5 | i [post update] | | +| arrayassignment.cpp:54:9:54:14 | call to source | arrayassignment.cpp:54:2:54:16 | ... = ... | | +| arrayassignment.cpp:62:8:62:9 | call to MyInt | arrayassignment.cpp:64:2:64:3 | mi | | +| arrayassignment.cpp:62:8:62:9 | call to MyInt | arrayassignment.cpp:66:7:66:8 | mi | | +| arrayassignment.cpp:62:8:62:9 | call to MyInt | arrayassignment.cpp:67:7:67:8 | mi | | +| arrayassignment.cpp:64:2:64:3 | ref arg mi | arrayassignment.cpp:66:7:66:8 | mi | | +| arrayassignment.cpp:64:2:64:3 | ref arg mi | arrayassignment.cpp:67:7:67:8 | mi | | +| arrayassignment.cpp:64:2:64:20 | ... = ... | arrayassignment.cpp:64:5:64:7 | call to get [post update] | | +| arrayassignment.cpp:64:13:64:18 | call to source | arrayassignment.cpp:64:2:64:20 | ... = ... | | +| arrayassignment.cpp:72:8:72:9 | call to MyInt | arrayassignment.cpp:74:2:74:3 | mi | | +| arrayassignment.cpp:72:8:72:9 | call to MyInt | arrayassignment.cpp:75:8:75:9 | mi | | +| arrayassignment.cpp:72:8:72:9 | call to MyInt | arrayassignment.cpp:77:7:77:8 | mi | | +| arrayassignment.cpp:72:8:72:9 | call to MyInt | arrayassignment.cpp:78:7:78:8 | mi | | +| arrayassignment.cpp:72:12:72:14 | call to MyInt | arrayassignment.cpp:75:2:75:4 | mi2 | | +| arrayassignment.cpp:72:12:72:14 | call to MyInt | arrayassignment.cpp:79:7:79:9 | mi2 | | +| arrayassignment.cpp:72:12:72:14 | call to MyInt | arrayassignment.cpp:80:7:80:9 | mi2 | | +| arrayassignment.cpp:74:2:74:3 | ref arg mi | arrayassignment.cpp:75:8:75:9 | mi | | +| arrayassignment.cpp:74:2:74:3 | ref arg mi | arrayassignment.cpp:77:7:77:8 | mi | | +| arrayassignment.cpp:74:2:74:3 | ref arg mi | arrayassignment.cpp:78:7:78:8 | mi | | +| arrayassignment.cpp:75:2:75:4 | ref arg mi2 | arrayassignment.cpp:79:7:79:9 | mi2 | | +| arrayassignment.cpp:75:2:75:4 | ref arg mi2 | arrayassignment.cpp:80:7:80:9 | mi2 | | +| arrayassignment.cpp:75:8:75:9 | mi | arrayassignment.cpp:75:2:75:4 | ref arg mi2 | TAINT | +| arrayassignment.cpp:75:8:75:9 | mi | arrayassignment.cpp:75:6:75:6 | call to operator= | TAINT | +| arrayassignment.cpp:86:2:86:8 | this | arrayassignment.cpp:86:14:86:24 | constructor init of field values [pre-this] | | +| arrayassignment.cpp:86:14:86:24 | {...} | arrayassignment.cpp:86:14:86:24 | constructor init of field values | TAINT | +| arrayassignment.cpp:86:22:86:22 | 0 | arrayassignment.cpp:86:14:86:24 | {...} | TAINT | +| arrayassignment.cpp:88:7:88:9 | this | arrayassignment.cpp:88:27:88:32 | this | | +| arrayassignment.cpp:88:15:88:15 | i | arrayassignment.cpp:88:34:88:34 | i | | +| arrayassignment.cpp:88:27:88:32 | values | arrayassignment.cpp:88:27:88:35 | access to array | TAINT | +| arrayassignment.cpp:88:34:88:34 | i | arrayassignment.cpp:88:27:88:35 | access to array | TAINT | +| arrayassignment.cpp:97:10:97:11 | call to MyArray | arrayassignment.cpp:99:2:99:3 | ma | | +| arrayassignment.cpp:97:10:97:11 | call to MyArray | arrayassignment.cpp:101:7:101:8 | ma | | +| arrayassignment.cpp:99:2:99:3 | ma [post update] | arrayassignment.cpp:101:7:101:8 | ma | | +| arrayassignment.cpp:99:2:99:13 | access to array [post update] | arrayassignment.cpp:99:5:99:10 | values [inner post update] | | +| arrayassignment.cpp:99:2:99:24 | ... = ... | arrayassignment.cpp:99:2:99:13 | access to array [post update] | | +| arrayassignment.cpp:99:5:99:10 | values | arrayassignment.cpp:99:2:99:13 | access to array | | +| arrayassignment.cpp:99:12:99:12 | 0 | arrayassignment.cpp:99:2:99:13 | access to array | TAINT | +| arrayassignment.cpp:99:17:99:22 | call to source | arrayassignment.cpp:99:2:99:24 | ... = ... | | +| arrayassignment.cpp:101:10:101:15 | values | arrayassignment.cpp:101:7:101:18 | access to array | | +| arrayassignment.cpp:101:17:101:17 | 0 | arrayassignment.cpp:101:7:101:18 | access to array | TAINT | +| arrayassignment.cpp:106:10:106:11 | call to MyArray | arrayassignment.cpp:108:2:108:3 | ma | | +| arrayassignment.cpp:106:10:106:11 | call to MyArray | arrayassignment.cpp:110:7:110:8 | ma | | +| arrayassignment.cpp:108:2:108:3 | ref arg ma | arrayassignment.cpp:110:7:110:8 | ma | | +| arrayassignment.cpp:108:2:108:21 | ... = ... | arrayassignment.cpp:108:5:108:7 | call to get [post update] | | +| arrayassignment.cpp:108:14:108:19 | call to source | arrayassignment.cpp:108:2:108:21 | ... = ... | | +| arrayassignment.cpp:115:10:115:11 | call to MyArray | arrayassignment.cpp:117:2:117:3 | ma | | +| arrayassignment.cpp:115:10:115:11 | call to MyArray | arrayassignment.cpp:118:8:118:9 | ma | | +| arrayassignment.cpp:115:10:115:11 | call to MyArray | arrayassignment.cpp:120:7:120:8 | ma | | +| arrayassignment.cpp:117:2:117:3 | ref arg ma | arrayassignment.cpp:118:8:118:9 | ma | | +| arrayassignment.cpp:117:2:117:3 | ref arg ma | arrayassignment.cpp:120:7:120:8 | ma | | +| arrayassignment.cpp:117:2:117:17 | ... = ... | arrayassignment.cpp:117:4:117:4 | call to operator[] [post update] | | +| arrayassignment.cpp:117:10:117:15 | call to source | arrayassignment.cpp:117:2:117:17 | ... = ... | | +| arrayassignment.cpp:118:8:118:9 | ma | arrayassignment.cpp:118:2:118:9 | ... = ... | | +| arrayassignment.cpp:118:8:118:9 | ma | arrayassignment.cpp:121:7:121:9 | ma2 | | +| arrayassignment.cpp:128:16:128:19 | {...} | arrayassignment.cpp:131:14:131:17 | arr1 | | +| arrayassignment.cpp:128:16:128:19 | {...} | arrayassignment.cpp:136:7:136:10 | arr1 | | +| arrayassignment.cpp:128:18:128:18 | 0 | arrayassignment.cpp:128:16:128:19 | {...} | TAINT | +| arrayassignment.cpp:129:16:129:19 | {...} | arrayassignment.cpp:138:11:138:14 | arr2 | | +| arrayassignment.cpp:129:16:129:19 | {...} | arrayassignment.cpp:141:7:141:10 | arr2 | | +| arrayassignment.cpp:129:18:129:18 | 0 | arrayassignment.cpp:129:16:129:19 | {...} | TAINT | +| arrayassignment.cpp:130:16:130:19 | {...} | arrayassignment.cpp:143:9:143:12 | arr3 | | +| arrayassignment.cpp:130:16:130:19 | {...} | arrayassignment.cpp:146:7:146:10 | arr3 | | +| arrayassignment.cpp:130:18:130:18 | 0 | arrayassignment.cpp:130:16:130:19 | {...} | TAINT | +| arrayassignment.cpp:131:14:131:17 | arr1 | arrayassignment.cpp:131:14:131:20 | access to array | TAINT | +| arrayassignment.cpp:131:19:131:19 | 5 | arrayassignment.cpp:131:14:131:20 | access to array | TAINT | +| arrayassignment.cpp:134:2:134:5 | ref1 [post update] | arrayassignment.cpp:135:7:135:10 | ref1 | | +| arrayassignment.cpp:134:2:134:16 | ... = ... | arrayassignment.cpp:134:2:134:5 | ref1 [post update] | | +| arrayassignment.cpp:134:9:134:14 | call to source | arrayassignment.cpp:134:2:134:16 | ... = ... | | +| arrayassignment.cpp:134:9:134:14 | call to source | arrayassignment.cpp:135:7:135:10 | ref1 | | +| arrayassignment.cpp:136:7:136:10 | arr1 | arrayassignment.cpp:136:7:136:13 | access to array | | +| arrayassignment.cpp:136:12:136:12 | 5 | arrayassignment.cpp:136:7:136:13 | access to array | TAINT | +| arrayassignment.cpp:138:9:138:18 | & ... | arrayassignment.cpp:138:2:138:18 | ... = ... | | +| arrayassignment.cpp:138:9:138:18 | & ... | arrayassignment.cpp:139:3:139:6 | ptr2 | | +| arrayassignment.cpp:138:9:138:18 | & ... | arrayassignment.cpp:140:8:140:11 | ptr2 | | +| arrayassignment.cpp:138:11:138:14 | arr2 | arrayassignment.cpp:138:11:138:17 | access to array | TAINT | +| arrayassignment.cpp:138:11:138:17 | access to array | arrayassignment.cpp:138:9:138:18 | & ... | | +| arrayassignment.cpp:138:16:138:16 | 5 | arrayassignment.cpp:138:11:138:17 | access to array | TAINT | +| arrayassignment.cpp:139:2:139:6 | * ... [post update] | arrayassignment.cpp:139:3:139:6 | ptr2 [inner post update] | | +| arrayassignment.cpp:139:2:139:6 | * ... [post update] | arrayassignment.cpp:140:8:140:11 | ptr2 | | +| arrayassignment.cpp:139:2:139:17 | ... = ... | arrayassignment.cpp:139:2:139:6 | * ... [post update] | | +| arrayassignment.cpp:139:3:139:6 | ptr2 | arrayassignment.cpp:139:2:139:6 | * ... | TAINT | +| arrayassignment.cpp:139:10:139:15 | call to source | arrayassignment.cpp:139:2:139:17 | ... = ... | | +| arrayassignment.cpp:140:8:140:11 | ptr2 | arrayassignment.cpp:140:7:140:11 | * ... | TAINT | +| arrayassignment.cpp:141:7:141:10 | arr2 | arrayassignment.cpp:141:7:141:13 | access to array | | +| arrayassignment.cpp:141:12:141:12 | 5 | arrayassignment.cpp:141:7:141:13 | access to array | TAINT | +| arrayassignment.cpp:143:9:143:12 | arr3 | arrayassignment.cpp:143:2:143:12 | ... = ... | | +| arrayassignment.cpp:143:9:143:12 | arr3 | arrayassignment.cpp:144:2:144:5 | ptr3 | | +| arrayassignment.cpp:143:9:143:12 | arr3 | arrayassignment.cpp:145:7:145:10 | ptr3 | | +| arrayassignment.cpp:144:2:144:5 | ptr3 | arrayassignment.cpp:144:2:144:8 | access to array | TAINT | +| arrayassignment.cpp:144:2:144:8 | access to array [post update] | arrayassignment.cpp:144:2:144:5 | ptr3 [inner post update] | | +| arrayassignment.cpp:144:2:144:8 | access to array [post update] | arrayassignment.cpp:145:7:145:10 | ptr3 | | +| arrayassignment.cpp:144:2:144:19 | ... = ... | arrayassignment.cpp:144:2:144:8 | access to array [post update] | | +| arrayassignment.cpp:144:7:144:7 | 5 | arrayassignment.cpp:144:2:144:8 | access to array | TAINT | +| arrayassignment.cpp:144:12:144:17 | call to source | arrayassignment.cpp:144:2:144:19 | ... = ... | | +| arrayassignment.cpp:145:7:145:10 | ptr3 | arrayassignment.cpp:145:7:145:13 | access to array | TAINT | +| arrayassignment.cpp:145:12:145:12 | 5 | arrayassignment.cpp:145:7:145:13 | access to array | TAINT | +| arrayassignment.cpp:146:7:146:10 | arr3 | arrayassignment.cpp:146:7:146:13 | access to array | | +| arrayassignment.cpp:146:12:146:12 | 5 | arrayassignment.cpp:146:7:146:13 | access to array | TAINT | +| copyableclass.cpp:8:2:8:16 | this | copyableclass.cpp:8:28:8:32 | constructor init of field v [pre-this] | | +| copyableclass.cpp:8:22:8:23 | _v | copyableclass.cpp:8:30:8:31 | _v | | +| copyableclass.cpp:8:30:8:31 | _v | copyableclass.cpp:8:28:8:32 | constructor init of field v | TAINT | +| copyableclass.cpp:9:2:9:16 | this | copyableclass.cpp:9:50:9:59 | constructor init of field v [pre-this] | | +| copyableclass.cpp:9:41:9:45 | other | copyableclass.cpp:9:52:9:56 | other | | +| copyableclass.cpp:9:58:9:58 | v | copyableclass.cpp:9:50:9:59 | constructor init of field v | TAINT | +| copyableclass.cpp:9:58:9:58 | v | copyableclass.cpp:9:58:9:58 | v | | +| copyableclass.cpp:10:19:10:27 | this | copyableclass.cpp:11:3:11:3 | this | | +| copyableclass.cpp:10:52:10:56 | other | copyableclass.cpp:11:7:11:11 | other | | +| copyableclass.cpp:11:3:11:3 | this | copyableclass.cpp:12:11:12:14 | this | | +| copyableclass.cpp:11:3:11:3 | this [post update] | copyableclass.cpp:12:11:12:14 | this | | +| copyableclass.cpp:11:3:11:13 | ... = ... | copyableclass.cpp:11:3:11:3 | v [post update] | | +| copyableclass.cpp:11:13:11:13 | v | copyableclass.cpp:11:3:11:13 | ... = ... | | +| copyableclass.cpp:12:11:12:14 | this | copyableclass.cpp:12:10:12:14 | * ... | TAINT | +| copyableclass.cpp:21:22:21:22 | 1 | copyableclass.cpp:21:22:21:23 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:21:22:21:23 | call to MyCopyableClass | copyableclass.cpp:23:22:23:23 | s1 | | +| copyableclass.cpp:21:22:21:23 | call to MyCopyableClass | copyableclass.cpp:27:8:27:9 | s1 | | +| copyableclass.cpp:22:23:22:24 | call to MyCopyableClass | copyableclass.cpp:28:8:28:9 | s2 | | +| copyableclass.cpp:22:24:22:24 | 1 | copyableclass.cpp:22:23:22:24 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:23:22:23:23 | s1 | copyableclass.cpp:23:22:23:24 | call to MyCopyableClass | | +| copyableclass.cpp:23:22:23:24 | call to MyCopyableClass | copyableclass.cpp:29:8:29:9 | s3 | | +| copyableclass.cpp:24:19:24:20 | call to MyCopyableClass | copyableclass.cpp:25:3:25:4 | s4 | | +| copyableclass.cpp:24:19:24:20 | call to MyCopyableClass | copyableclass.cpp:30:8:30:9 | s4 | | +| copyableclass.cpp:25:3:25:4 | ref arg s4 | copyableclass.cpp:30:8:30:9 | s4 | | +| copyableclass.cpp:25:8:25:8 | 1 | copyableclass.cpp:25:8:25:8 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:25:8:25:8 | call to MyCopyableClass | copyableclass.cpp:25:3:25:4 | ref arg s4 | TAINT | +| copyableclass.cpp:25:8:25:8 | call to MyCopyableClass | copyableclass.cpp:25:6:25:6 | call to operator= | TAINT | +| copyableclass.cpp:34:22:34:27 | call to source | copyableclass.cpp:34:22:34:30 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:34:22:34:30 | call to MyCopyableClass | copyableclass.cpp:36:22:36:23 | s1 | | +| copyableclass.cpp:34:22:34:30 | call to MyCopyableClass | copyableclass.cpp:40:8:40:9 | s1 | | +| copyableclass.cpp:35:23:35:31 | call to MyCopyableClass | copyableclass.cpp:41:8:41:9 | s2 | | +| copyableclass.cpp:35:24:35:29 | call to source | copyableclass.cpp:35:23:35:31 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:36:22:36:23 | s1 | copyableclass.cpp:36:22:36:24 | call to MyCopyableClass | | +| copyableclass.cpp:36:22:36:24 | call to MyCopyableClass | copyableclass.cpp:42:8:42:9 | s3 | | +| copyableclass.cpp:37:19:37:20 | call to MyCopyableClass | copyableclass.cpp:38:3:38:4 | s4 | | +| copyableclass.cpp:37:19:37:20 | call to MyCopyableClass | copyableclass.cpp:43:8:43:9 | s4 | | +| copyableclass.cpp:38:3:38:4 | ref arg s4 | copyableclass.cpp:43:8:43:9 | s4 | | +| copyableclass.cpp:38:8:38:13 | call to source | copyableclass.cpp:38:8:38:15 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:38:8:38:15 | call to MyCopyableClass | copyableclass.cpp:38:3:38:4 | ref arg s4 | TAINT | +| copyableclass.cpp:38:8:38:15 | call to MyCopyableClass | copyableclass.cpp:38:6:38:6 | call to operator= | TAINT | +| copyableclass.cpp:47:19:47:20 | call to MyCopyableClass | copyableclass.cpp:48:24:48:25 | s1 | | +| copyableclass.cpp:47:19:47:20 | call to MyCopyableClass | copyableclass.cpp:49:22:49:23 | s1 | | +| copyableclass.cpp:47:19:47:20 | call to MyCopyableClass | copyableclass.cpp:51:8:51:9 | s1 | | +| copyableclass.cpp:47:19:47:20 | call to MyCopyableClass | copyableclass.cpp:53:8:53:9 | s1 | | +| copyableclass.cpp:48:23:48:25 | call to MyCopyableClass | copyableclass.cpp:54:8:54:9 | s2 | | +| copyableclass.cpp:48:24:48:25 | s1 | copyableclass.cpp:48:23:48:25 | call to MyCopyableClass | | +| copyableclass.cpp:49:22:49:23 | s1 | copyableclass.cpp:49:22:49:24 | call to MyCopyableClass | | +| copyableclass.cpp:49:22:49:24 | call to MyCopyableClass | copyableclass.cpp:55:8:55:9 | s3 | | +| copyableclass.cpp:50:19:50:20 | call to MyCopyableClass | copyableclass.cpp:51:3:51:4 | s4 | | +| copyableclass.cpp:50:19:50:20 | call to MyCopyableClass | copyableclass.cpp:56:8:56:9 | s4 | | +| copyableclass.cpp:51:3:51:4 | ref arg s4 | copyableclass.cpp:56:8:56:9 | s4 | | +| copyableclass.cpp:51:8:51:9 | s1 | copyableclass.cpp:51:3:51:4 | ref arg s4 | TAINT | +| copyableclass.cpp:51:8:51:9 | s1 | copyableclass.cpp:51:6:51:6 | call to operator= | TAINT | +| copyableclass.cpp:60:23:60:48 | call to MyCopyableClass | copyableclass.cpp:65:8:65:9 | s1 | | +| copyableclass.cpp:60:40:60:45 | call to source | copyableclass.cpp:60:23:60:48 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:61:19:61:20 | call to MyCopyableClass | copyableclass.cpp:63:3:63:4 | s2 | | +| copyableclass.cpp:61:19:61:20 | call to MyCopyableClass | copyableclass.cpp:66:8:66:9 | s2 | | +| copyableclass.cpp:62:19:62:20 | call to MyCopyableClass | copyableclass.cpp:67:8:67:9 | s3 | | +| copyableclass.cpp:63:3:63:4 | ref arg s2 | copyableclass.cpp:66:8:66:9 | s2 | | +| copyableclass.cpp:63:8:63:32 | call to MyCopyableClass | copyableclass.cpp:63:3:63:4 | ref arg s2 | TAINT | +| copyableclass.cpp:63:8:63:32 | call to MyCopyableClass | copyableclass.cpp:63:6:63:6 | call to operator= | TAINT | +| copyableclass.cpp:63:24:63:29 | call to source | copyableclass.cpp:63:8:63:32 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:67:13:67:18 | call to source | copyableclass.cpp:67:13:67:20 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:67:13:67:20 | call to MyCopyableClass | copyableclass.cpp:67:8:67:9 | ref arg s3 | TAINT | +| copyableclass.cpp:67:13:67:20 | call to MyCopyableClass | copyableclass.cpp:67:11:67:11 | call to operator= | TAINT | +| copyableclass_declonly.cpp:21:30:21:30 | 1 | copyableclass_declonly.cpp:21:30:21:31 | call to MyCopyableClassDeclOnly | TAINT | +| copyableclass_declonly.cpp:21:30:21:31 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:23:30:23:31 | s1 | | +| copyableclass_declonly.cpp:21:30:21:31 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:27:8:27:9 | s1 | | +| copyableclass_declonly.cpp:22:31:22:32 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:28:8:28:9 | s2 | | +| copyableclass_declonly.cpp:22:32:22:32 | 1 | copyableclass_declonly.cpp:22:31:22:32 | call to MyCopyableClassDeclOnly | TAINT | +| copyableclass_declonly.cpp:23:30:23:31 | s1 | copyableclass_declonly.cpp:23:30:23:32 | call to MyCopyableClassDeclOnly | | +| copyableclass_declonly.cpp:23:30:23:32 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:29:8:29:9 | s3 | | +| copyableclass_declonly.cpp:24:27:24:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:25:3:25:4 | s4 | | +| copyableclass_declonly.cpp:24:27:24:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:30:8:30:9 | s4 | | +| copyableclass_declonly.cpp:25:3:25:4 | ref arg s4 | copyableclass_declonly.cpp:30:8:30:9 | s4 | | +| copyableclass_declonly.cpp:25:8:25:8 | 1 | copyableclass_declonly.cpp:25:8:25:8 | call to MyCopyableClassDeclOnly | TAINT | +| copyableclass_declonly.cpp:25:8:25:8 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:25:3:25:4 | ref arg s4 | TAINT | +| copyableclass_declonly.cpp:25:8:25:8 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:25:6:25:6 | call to operator= | TAINT | +| copyableclass_declonly.cpp:34:30:34:35 | call to source | copyableclass_declonly.cpp:34:30:34:38 | call to MyCopyableClassDeclOnly | TAINT | +| copyableclass_declonly.cpp:34:30:34:38 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:36:30:36:31 | s1 | | +| copyableclass_declonly.cpp:34:30:34:38 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:40:8:40:9 | s1 | | +| copyableclass_declonly.cpp:35:31:35:39 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:41:8:41:9 | s2 | | +| copyableclass_declonly.cpp:35:32:35:37 | call to source | copyableclass_declonly.cpp:35:31:35:39 | call to MyCopyableClassDeclOnly | TAINT | +| copyableclass_declonly.cpp:36:30:36:31 | s1 | copyableclass_declonly.cpp:36:30:36:32 | call to MyCopyableClassDeclOnly | | +| copyableclass_declonly.cpp:36:30:36:32 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:42:8:42:9 | s3 | | +| copyableclass_declonly.cpp:37:27:37:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:38:3:38:4 | s4 | | +| copyableclass_declonly.cpp:37:27:37:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:43:8:43:9 | s4 | | +| copyableclass_declonly.cpp:38:3:38:4 | ref arg s4 | copyableclass_declonly.cpp:43:8:43:9 | s4 | | +| copyableclass_declonly.cpp:38:8:38:13 | call to source | copyableclass_declonly.cpp:38:8:38:15 | call to MyCopyableClassDeclOnly | TAINT | +| copyableclass_declonly.cpp:38:8:38:15 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:38:3:38:4 | ref arg s4 | TAINT | +| copyableclass_declonly.cpp:38:8:38:15 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:38:6:38:6 | call to operator= | TAINT | +| copyableclass_declonly.cpp:47:27:47:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:48:32:48:33 | s1 | | +| copyableclass_declonly.cpp:47:27:47:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:49:30:49:31 | s1 | | +| copyableclass_declonly.cpp:47:27:47:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:51:8:51:9 | s1 | | +| copyableclass_declonly.cpp:47:27:47:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:53:8:53:9 | s1 | | +| copyableclass_declonly.cpp:48:31:48:33 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:54:8:54:9 | s2 | | +| copyableclass_declonly.cpp:48:32:48:33 | s1 | copyableclass_declonly.cpp:48:31:48:33 | call to MyCopyableClassDeclOnly | | +| copyableclass_declonly.cpp:49:30:49:31 | s1 | copyableclass_declonly.cpp:49:30:49:32 | call to MyCopyableClassDeclOnly | | +| copyableclass_declonly.cpp:49:30:49:32 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:55:8:55:9 | s3 | | +| copyableclass_declonly.cpp:50:27:50:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:51:3:51:4 | s4 | | +| copyableclass_declonly.cpp:50:27:50:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:56:8:56:9 | s4 | | +| copyableclass_declonly.cpp:51:3:51:4 | ref arg s4 | copyableclass_declonly.cpp:56:8:56:9 | s4 | | +| copyableclass_declonly.cpp:51:8:51:9 | s1 | copyableclass_declonly.cpp:51:3:51:4 | ref arg s4 | TAINT | +| copyableclass_declonly.cpp:51:8:51:9 | s1 | copyableclass_declonly.cpp:51:6:51:6 | call to operator= | TAINT | +| copyableclass_declonly.cpp:60:31:60:64 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:65:8:65:9 | s1 | | +| copyableclass_declonly.cpp:60:56:60:61 | call to source | copyableclass_declonly.cpp:60:31:60:64 | call to MyCopyableClassDeclOnly | TAINT | +| copyableclass_declonly.cpp:61:27:61:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:63:3:63:4 | s2 | | +| copyableclass_declonly.cpp:61:27:61:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:66:8:66:9 | s2 | | +| copyableclass_declonly.cpp:62:27:62:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:67:8:67:9 | s3 | | +| copyableclass_declonly.cpp:63:3:63:4 | ref arg s2 | copyableclass_declonly.cpp:66:8:66:9 | s2 | | +| copyableclass_declonly.cpp:63:8:63:40 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:63:3:63:4 | ref arg s2 | TAINT | +| copyableclass_declonly.cpp:63:8:63:40 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:63:6:63:6 | call to operator= | TAINT | +| copyableclass_declonly.cpp:63:32:63:37 | call to source | copyableclass_declonly.cpp:63:8:63:40 | call to MyCopyableClassDeclOnly | TAINT | +| copyableclass_declonly.cpp:67:13:67:18 | call to source | copyableclass_declonly.cpp:67:13:67:20 | call to MyCopyableClassDeclOnly | TAINT | +| copyableclass_declonly.cpp:67:13:67:20 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:67:8:67:9 | ref arg s3 | TAINT | +| copyableclass_declonly.cpp:67:13:67:20 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:67:11:67:11 | call to operator= | TAINT | +| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | +| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | +| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | +| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | @@ -89,6 +346,8 @@ | format.cpp:113:21:113:24 | {...} | format.cpp:115:8:115:13 | buffer | | | format.cpp:113:23:113:23 | 0 | format.cpp:113:21:113:24 | {...} | TAINT | | format.cpp:114:18:114:23 | ref arg buffer | format.cpp:115:8:115:13 | buffer | | +| format.cpp:114:31:114:34 | %s | format.cpp:114:18:114:23 | ref arg buffer | TAINT | +| format.cpp:114:37:114:50 | call to source | format.cpp:114:18:114:23 | ref arg buffer | TAINT | | format.cpp:119:10:119:11 | 0 | format.cpp:120:29:120:29 | i | | | format.cpp:119:10:119:11 | 0 | format.cpp:121:8:121:8 | i | | | format.cpp:120:28:120:29 | ref arg & ... | format.cpp:120:29:120:29 | i [inner post update] | | @@ -131,63 +390,4921 @@ | format.cpp:158:13:158:18 | call to wcslen | format.cpp:158:13:158:26 | ... / ... | TAINT | | format.cpp:158:13:158:26 | ... / ... | format.cpp:158:7:158:27 | ... + ... | TAINT | | format.cpp:158:26:158:26 | 2 | format.cpp:158:13:158:26 | ... / ... | TAINT | -| stl.cpp:67:12:67:17 | call to source | stl.cpp:71:7:71:7 | a | | -| stl.cpp:68:16:68:20 | 123 | stl.cpp:68:16:68:21 | call to basic_string | TAINT | -| stl.cpp:68:16:68:21 | call to basic_string | stl.cpp:72:7:72:7 | b | | -| stl.cpp:68:16:68:21 | call to basic_string | stl.cpp:74:7:74:7 | b | | -| stl.cpp:69:16:69:21 | call to source | stl.cpp:69:16:69:24 | call to basic_string | TAINT | -| stl.cpp:69:16:69:24 | call to basic_string | stl.cpp:73:7:73:7 | c | | -| stl.cpp:69:16:69:24 | call to basic_string | stl.cpp:75:7:75:7 | c | | -| stl.cpp:74:7:74:7 | b | stl.cpp:74:9:74:13 | call to c_str | TAINT | -| stl.cpp:75:7:75:7 | c | stl.cpp:75:9:75:13 | call to c_str | TAINT | -| stl.cpp:80:20:80:22 | call to basic_stringstream | stl.cpp:83:2:83:4 | ss1 | | -| stl.cpp:80:20:80:22 | call to basic_stringstream | stl.cpp:89:7:89:9 | ss1 | | -| stl.cpp:80:20:80:22 | call to basic_stringstream | stl.cpp:94:7:94:9 | ss1 | | -| stl.cpp:80:25:80:27 | call to basic_stringstream | stl.cpp:84:2:84:4 | ss2 | | -| stl.cpp:80:25:80:27 | call to basic_stringstream | stl.cpp:90:7:90:9 | ss2 | | -| stl.cpp:80:25:80:27 | call to basic_stringstream | stl.cpp:95:7:95:9 | ss2 | | -| stl.cpp:80:30:80:32 | call to basic_stringstream | stl.cpp:85:2:85:4 | ss3 | | -| stl.cpp:80:30:80:32 | call to basic_stringstream | stl.cpp:91:7:91:9 | ss3 | | -| stl.cpp:80:30:80:32 | call to basic_stringstream | stl.cpp:96:7:96:9 | ss3 | | -| stl.cpp:80:35:80:37 | call to basic_stringstream | stl.cpp:86:2:86:4 | ss4 | | -| stl.cpp:80:35:80:37 | call to basic_stringstream | stl.cpp:92:7:92:9 | ss4 | | -| stl.cpp:80:35:80:37 | call to basic_stringstream | stl.cpp:97:7:97:9 | ss4 | | -| stl.cpp:80:40:80:42 | call to basic_stringstream | stl.cpp:87:2:87:4 | ss5 | | -| stl.cpp:80:40:80:42 | call to basic_stringstream | stl.cpp:93:7:93:9 | ss5 | | -| stl.cpp:80:40:80:42 | call to basic_stringstream | stl.cpp:98:7:98:9 | ss5 | | -| stl.cpp:81:16:81:21 | call to source | stl.cpp:81:16:81:24 | call to basic_string | TAINT | -| stl.cpp:81:16:81:24 | call to basic_string | stl.cpp:87:9:87:9 | t | | -| stl.cpp:83:2:83:4 | ref arg ss1 | stl.cpp:89:7:89:9 | ss1 | | -| stl.cpp:83:2:83:4 | ref arg ss1 | stl.cpp:94:7:94:9 | ss1 | | -| stl.cpp:84:2:84:4 | ref arg ss2 | stl.cpp:90:7:90:9 | ss2 | | -| stl.cpp:84:2:84:4 | ref arg ss2 | stl.cpp:95:7:95:9 | ss2 | | -| stl.cpp:85:2:85:4 | ref arg ss3 | stl.cpp:91:7:91:9 | ss3 | | -| stl.cpp:85:2:85:4 | ref arg ss3 | stl.cpp:96:7:96:9 | ss3 | | -| stl.cpp:86:2:86:4 | ref arg ss4 | stl.cpp:92:7:92:9 | ss4 | | -| stl.cpp:86:2:86:4 | ref arg ss4 | stl.cpp:97:7:97:9 | ss4 | | -| stl.cpp:87:2:87:4 | ref arg ss5 | stl.cpp:93:7:93:9 | ss5 | | -| stl.cpp:87:2:87:4 | ref arg ss5 | stl.cpp:98:7:98:9 | ss5 | | -| stl.cpp:101:32:101:37 | source | stl.cpp:106:9:106:14 | source | | -| stl.cpp:103:20:103:22 | call to basic_stringstream | stl.cpp:105:2:105:4 | ss1 | | -| stl.cpp:103:20:103:22 | call to basic_stringstream | stl.cpp:108:7:108:9 | ss1 | | -| stl.cpp:103:20:103:22 | call to basic_stringstream | stl.cpp:110:7:110:9 | ss1 | | -| stl.cpp:103:25:103:27 | call to basic_stringstream | stl.cpp:106:2:106:4 | ss2 | | -| stl.cpp:103:25:103:27 | call to basic_stringstream | stl.cpp:109:7:109:9 | ss2 | | -| stl.cpp:103:25:103:27 | call to basic_stringstream | stl.cpp:111:7:111:9 | ss2 | | -| stl.cpp:105:2:105:4 | ref arg ss1 | stl.cpp:108:7:108:9 | ss1 | | -| stl.cpp:105:2:105:4 | ref arg ss1 | stl.cpp:110:7:110:9 | ss1 | | -| stl.cpp:106:2:106:4 | ref arg ss2 | stl.cpp:109:7:109:9 | ss2 | | -| stl.cpp:106:2:106:4 | ref arg ss2 | stl.cpp:111:7:111:9 | ss2 | | -| stl.cpp:124:16:124:28 | call to basic_string | stl.cpp:125:7:125:11 | path1 | | -| stl.cpp:124:17:124:26 | call to user_input | stl.cpp:124:16:124:28 | call to basic_string | TAINT | -| stl.cpp:125:7:125:11 | path1 | stl.cpp:125:13:125:17 | call to c_str | TAINT | -| stl.cpp:128:10:128:19 | call to user_input | stl.cpp:128:10:128:21 | call to basic_string | TAINT | -| stl.cpp:128:10:128:21 | call to basic_string | stl.cpp:128:2:128:21 | ... = ... | | -| stl.cpp:128:10:128:21 | call to basic_string | stl.cpp:129:7:129:11 | path2 | | -| stl.cpp:129:7:129:11 | path2 | stl.cpp:129:13:129:17 | call to c_str | TAINT | -| stl.cpp:131:15:131:24 | call to user_input | stl.cpp:131:15:131:27 | call to basic_string | TAINT | -| stl.cpp:131:15:131:27 | call to basic_string | stl.cpp:132:7:132:11 | path3 | | -| stl.cpp:132:7:132:11 | path3 | stl.cpp:132:13:132:17 | call to c_str | TAINT | +| map.cpp:21:28:21:28 | call to pair | map.cpp:23:2:23:2 | a | | +| map.cpp:21:28:21:28 | call to pair | map.cpp:24:7:24:7 | a | | +| map.cpp:21:28:21:28 | call to pair | map.cpp:25:7:25:7 | a | | +| map.cpp:21:28:21:28 | call to pair | map.cpp:26:7:26:7 | a | | +| map.cpp:21:31:21:31 | call to pair | map.cpp:28:2:28:2 | b | | +| map.cpp:21:31:21:31 | call to pair | map.cpp:29:7:29:7 | b | | +| map.cpp:21:31:21:31 | call to pair | map.cpp:30:7:30:7 | b | | +| map.cpp:21:31:21:31 | call to pair | map.cpp:31:7:31:7 | b | | +| map.cpp:21:34:21:34 | call to pair | map.cpp:33:2:33:2 | c | | +| map.cpp:21:34:21:34 | call to pair | map.cpp:34:7:34:7 | c | | +| map.cpp:21:34:21:34 | call to pair | map.cpp:35:7:35:7 | c | | +| map.cpp:21:34:21:34 | call to pair | map.cpp:36:7:36:7 | c | | +| map.cpp:23:2:23:2 | a [post update] | map.cpp:24:7:24:7 | a | | +| map.cpp:23:2:23:2 | a [post update] | map.cpp:25:7:25:7 | a | | +| map.cpp:23:2:23:2 | a [post update] | map.cpp:26:7:26:7 | a | | +| map.cpp:23:2:23:16 | ... = ... | map.cpp:23:4:23:8 | first [post update] | | +| map.cpp:23:2:23:16 | ... = ... | map.cpp:24:9:24:13 | first | | +| map.cpp:23:12:23:16 | 123 | map.cpp:23:2:23:16 | ... = ... | | +| map.cpp:24:7:24:7 | a [post update] | map.cpp:25:7:25:7 | a | | +| map.cpp:24:7:24:7 | a [post update] | map.cpp:26:7:26:7 | a | | +| map.cpp:25:7:25:7 | a [post update] | map.cpp:26:7:26:7 | a | | +| map.cpp:28:2:28:2 | b [post update] | map.cpp:29:7:29:7 | b | | +| map.cpp:28:2:28:2 | b [post update] | map.cpp:30:7:30:7 | b | | +| map.cpp:28:2:28:2 | b [post update] | map.cpp:31:7:31:7 | b | | +| map.cpp:28:2:28:19 | ... = ... | map.cpp:28:4:28:8 | first [post update] | | +| map.cpp:28:2:28:19 | ... = ... | map.cpp:29:9:29:13 | first | | +| map.cpp:28:12:28:17 | call to source | map.cpp:28:2:28:19 | ... = ... | | +| map.cpp:29:7:29:7 | b [post update] | map.cpp:30:7:30:7 | b | | +| map.cpp:29:7:29:7 | b [post update] | map.cpp:31:7:31:7 | b | | +| map.cpp:30:7:30:7 | b [post update] | map.cpp:31:7:31:7 | b | | +| map.cpp:33:2:33:2 | c [post update] | map.cpp:34:7:34:7 | c | | +| map.cpp:33:2:33:2 | c [post update] | map.cpp:35:7:35:7 | c | | +| map.cpp:33:2:33:2 | c [post update] | map.cpp:36:7:36:7 | c | | +| map.cpp:33:2:33:20 | ... = ... | map.cpp:33:4:33:9 | second [post update] | | +| map.cpp:33:2:33:20 | ... = ... | map.cpp:35:9:35:14 | second | | +| map.cpp:33:13:33:18 | call to source | map.cpp:33:2:33:20 | ... = ... | | +| map.cpp:34:7:34:7 | c [post update] | map.cpp:35:7:35:7 | c | | +| map.cpp:34:7:34:7 | c [post update] | map.cpp:36:7:36:7 | c | | +| map.cpp:35:7:35:7 | c [post update] | map.cpp:36:7:36:7 | c | | +| map.cpp:38:30:38:42 | call to pair | map.cpp:39:7:39:7 | d | | +| map.cpp:38:30:38:42 | call to pair | map.cpp:40:7:40:7 | d | | +| map.cpp:38:30:38:42 | call to pair | map.cpp:41:7:41:7 | d | | +| map.cpp:38:37:38:41 | 456 | map.cpp:38:30:38:42 | call to pair | TAINT | +| map.cpp:39:7:39:7 | d [post update] | map.cpp:40:7:40:7 | d | | +| map.cpp:39:7:39:7 | d [post update] | map.cpp:41:7:41:7 | d | | +| map.cpp:40:7:40:7 | d [post update] | map.cpp:41:7:41:7 | d | | +| map.cpp:43:30:43:45 | call to pair | map.cpp:44:7:44:7 | e | | +| map.cpp:43:30:43:45 | call to pair | map.cpp:45:7:45:7 | e | | +| map.cpp:43:30:43:45 | call to pair | map.cpp:46:7:46:7 | e | | +| map.cpp:43:40:43:44 | 456 | map.cpp:43:30:43:45 | call to pair | TAINT | +| map.cpp:44:7:44:7 | e [post update] | map.cpp:45:7:45:7 | e | | +| map.cpp:44:7:44:7 | e [post update] | map.cpp:46:7:46:7 | e | | +| map.cpp:45:7:45:7 | e [post update] | map.cpp:46:7:46:7 | e | | +| map.cpp:48:30:48:45 | call to pair | map.cpp:49:7:49:7 | f | | +| map.cpp:48:30:48:45 | call to pair | map.cpp:50:7:50:7 | f | | +| map.cpp:48:30:48:45 | call to pair | map.cpp:51:7:51:7 | f | | +| map.cpp:48:30:48:45 | call to pair | map.cpp:53:30:53:30 | f | | +| map.cpp:48:30:48:45 | call to pair | map.cpp:59:6:59:6 | f | | +| map.cpp:48:37:48:42 | call to source | map.cpp:48:30:48:45 | call to pair | TAINT | +| map.cpp:49:7:49:7 | f [post update] | map.cpp:50:7:50:7 | f | | +| map.cpp:49:7:49:7 | f [post update] | map.cpp:51:7:51:7 | f | | +| map.cpp:49:7:49:7 | f [post update] | map.cpp:53:30:53:30 | f | | +| map.cpp:49:7:49:7 | f [post update] | map.cpp:59:6:59:6 | f | | +| map.cpp:50:7:50:7 | f [post update] | map.cpp:51:7:51:7 | f | | +| map.cpp:50:7:50:7 | f [post update] | map.cpp:53:30:53:30 | f | | +| map.cpp:50:7:50:7 | f [post update] | map.cpp:59:6:59:6 | f | | +| map.cpp:53:30:53:30 | f | map.cpp:54:7:54:7 | g | | +| map.cpp:53:30:53:30 | f | map.cpp:55:7:55:7 | g | | +| map.cpp:53:30:53:30 | f | map.cpp:56:7:56:7 | g | | +| map.cpp:54:7:54:7 | g [post update] | map.cpp:55:7:55:7 | g | | +| map.cpp:54:7:54:7 | g [post update] | map.cpp:56:7:56:7 | g | | +| map.cpp:55:7:55:7 | g [post update] | map.cpp:56:7:56:7 | g | | +| map.cpp:59:6:59:6 | f | map.cpp:59:2:59:6 | ... = ... | | +| map.cpp:59:6:59:6 | f | map.cpp:60:7:60:7 | h | | +| map.cpp:59:6:59:6 | f | map.cpp:61:7:61:7 | h | | +| map.cpp:59:6:59:6 | f | map.cpp:62:7:62:7 | h | | +| map.cpp:60:7:60:7 | h [post update] | map.cpp:61:7:61:7 | h | | +| map.cpp:60:7:60:7 | h [post update] | map.cpp:62:7:62:7 | h | | +| map.cpp:61:7:61:7 | h [post update] | map.cpp:62:7:62:7 | h | | +| map.cpp:64:30:64:42 | call to pair | map.cpp:68:3:68:3 | i | | +| map.cpp:64:30:64:42 | call to pair | map.cpp:70:7:70:7 | i | | +| map.cpp:64:30:64:42 | call to pair | map.cpp:71:7:71:7 | i | | +| map.cpp:64:30:64:42 | call to pair | map.cpp:72:7:72:7 | i | | +| map.cpp:64:37:64:41 | 456 | map.cpp:64:30:64:42 | call to pair | TAINT | +| map.cpp:65:30:65:45 | call to pair | map.cpp:68:10:68:10 | j | | +| map.cpp:65:30:65:45 | call to pair | map.cpp:73:7:73:7 | j | | +| map.cpp:65:30:65:45 | call to pair | map.cpp:74:7:74:7 | j | | +| map.cpp:65:30:65:45 | call to pair | map.cpp:75:7:75:7 | j | | +| map.cpp:65:37:65:42 | call to source | map.cpp:65:30:65:45 | call to pair | TAINT | +| map.cpp:66:30:66:45 | call to pair | map.cpp:69:2:69:2 | k | | +| map.cpp:66:30:66:45 | call to pair | map.cpp:76:7:76:7 | k | | +| map.cpp:66:30:66:45 | call to pair | map.cpp:77:7:77:7 | k | | +| map.cpp:66:30:66:45 | call to pair | map.cpp:78:7:78:7 | k | | +| map.cpp:66:37:66:42 | call to source | map.cpp:66:30:66:45 | call to pair | TAINT | +| map.cpp:67:30:67:42 | call to pair | map.cpp:69:9:69:9 | l | | +| map.cpp:67:30:67:42 | call to pair | map.cpp:79:7:79:7 | l | | +| map.cpp:67:30:67:42 | call to pair | map.cpp:80:7:80:7 | l | | +| map.cpp:67:30:67:42 | call to pair | map.cpp:81:7:81:7 | l | | +| map.cpp:67:37:67:41 | 456 | map.cpp:67:30:67:42 | call to pair | TAINT | +| map.cpp:68:3:68:3 | i | map.cpp:68:10:68:10 | ref arg j | TAINT | +| map.cpp:68:3:68:3 | ref arg i | map.cpp:70:7:70:7 | i | | +| map.cpp:68:3:68:3 | ref arg i | map.cpp:71:7:71:7 | i | | +| map.cpp:68:3:68:3 | ref arg i | map.cpp:72:7:72:7 | i | | +| map.cpp:68:10:68:10 | j | map.cpp:68:3:68:3 | ref arg i | TAINT | +| map.cpp:68:10:68:10 | ref arg j | map.cpp:73:7:73:7 | j | | +| map.cpp:68:10:68:10 | ref arg j | map.cpp:74:7:74:7 | j | | +| map.cpp:68:10:68:10 | ref arg j | map.cpp:75:7:75:7 | j | | +| map.cpp:69:2:69:2 | k | map.cpp:69:9:69:9 | ref arg l | TAINT | +| map.cpp:69:2:69:2 | ref arg k | map.cpp:76:7:76:7 | k | | +| map.cpp:69:2:69:2 | ref arg k | map.cpp:77:7:77:7 | k | | +| map.cpp:69:2:69:2 | ref arg k | map.cpp:78:7:78:7 | k | | +| map.cpp:69:9:69:9 | l | map.cpp:69:2:69:2 | ref arg k | TAINT | +| map.cpp:69:9:69:9 | ref arg l | map.cpp:79:7:79:7 | l | | +| map.cpp:69:9:69:9 | ref arg l | map.cpp:80:7:80:7 | l | | +| map.cpp:69:9:69:9 | ref arg l | map.cpp:81:7:81:7 | l | | +| map.cpp:70:7:70:7 | i [post update] | map.cpp:71:7:71:7 | i | | +| map.cpp:70:7:70:7 | i [post update] | map.cpp:72:7:72:7 | i | | +| map.cpp:71:7:71:7 | i [post update] | map.cpp:72:7:72:7 | i | | +| map.cpp:73:7:73:7 | j [post update] | map.cpp:74:7:74:7 | j | | +| map.cpp:73:7:73:7 | j [post update] | map.cpp:75:7:75:7 | j | | +| map.cpp:74:7:74:7 | j [post update] | map.cpp:75:7:75:7 | j | | +| map.cpp:76:7:76:7 | k [post update] | map.cpp:77:7:77:7 | k | | +| map.cpp:76:7:76:7 | k [post update] | map.cpp:78:7:78:7 | k | | +| map.cpp:77:7:77:7 | k [post update] | map.cpp:78:7:78:7 | k | | +| map.cpp:79:7:79:7 | l [post update] | map.cpp:80:7:80:7 | l | | +| map.cpp:79:7:79:7 | l [post update] | map.cpp:81:7:81:7 | l | | +| map.cpp:80:7:80:7 | l [post update] | map.cpp:81:7:81:7 | l | | +| map.cpp:83:7:83:15 | call to make_pair | map.cpp:83:7:83:29 | call to pair | TAINT | +| map.cpp:86:7:86:15 | call to make_pair | map.cpp:86:7:86:32 | call to pair | TAINT | +| map.cpp:89:7:89:15 | call to make_pair | map.cpp:89:7:89:32 | call to pair | TAINT | +| map.cpp:94:6:94:14 | call to make_pair | map.cpp:94:6:94:49 | call to pair | TAINT | +| map.cpp:94:6:94:49 | call to pair | map.cpp:94:2:94:49 | ... = ... | | +| map.cpp:94:6:94:49 | call to pair | map.cpp:95:7:95:7 | m | | +| map.cpp:94:6:94:49 | call to pair | map.cpp:96:7:96:7 | m | | +| map.cpp:94:6:94:49 | call to pair | map.cpp:97:7:97:7 | m | | +| map.cpp:94:6:94:49 | call to pair | map.cpp:98:7:98:7 | m | | +| map.cpp:94:6:94:49 | call to pair | map.cpp:99:7:99:7 | m | | +| map.cpp:95:7:95:7 | m | map.cpp:95:7:95:7 | call to pair | TAINT | +| map.cpp:97:7:97:7 | m [post update] | map.cpp:98:7:98:7 | m | | +| map.cpp:97:7:97:7 | m [post update] | map.cpp:99:7:99:7 | m | | +| map.cpp:98:7:98:7 | m [post update] | map.cpp:99:7:99:7 | m | | +| map.cpp:105:27:105:28 | call to map | map.cpp:107:7:107:8 | m1 | | +| map.cpp:105:27:105:28 | call to map | map.cpp:113:7:113:8 | m1 | | +| map.cpp:105:27:105:28 | call to map | map.cpp:119:7:119:8 | m1 | | +| map.cpp:105:27:105:28 | call to map | map.cpp:125:7:125:8 | m1 | | +| map.cpp:105:27:105:28 | call to map | map.cpp:146:12:146:13 | m1 | | +| map.cpp:105:27:105:28 | call to map | map.cpp:146:30:146:31 | m1 | | +| map.cpp:105:27:105:28 | call to map | map.cpp:252:1:252:1 | m1 | | +| map.cpp:105:31:105:32 | call to map | map.cpp:108:7:108:8 | m2 | | +| map.cpp:105:31:105:32 | call to map | map.cpp:114:7:114:8 | m2 | | +| map.cpp:105:31:105:32 | call to map | map.cpp:120:7:120:8 | m2 | | +| map.cpp:105:31:105:32 | call to map | map.cpp:126:7:126:8 | m2 | | +| map.cpp:105:31:105:32 | call to map | map.cpp:133:30:133:31 | m2 | | +| map.cpp:105:31:105:32 | call to map | map.cpp:134:32:134:33 | m2 | | +| map.cpp:105:31:105:32 | call to map | map.cpp:136:7:136:8 | m2 | | +| map.cpp:105:31:105:32 | call to map | map.cpp:152:12:152:13 | m2 | | +| map.cpp:105:31:105:32 | call to map | map.cpp:152:30:152:31 | m2 | | +| map.cpp:105:31:105:32 | call to map | map.cpp:182:7:182:8 | m2 | | +| map.cpp:105:31:105:32 | call to map | map.cpp:183:7:183:8 | m2 | | +| map.cpp:105:31:105:32 | call to map | map.cpp:184:7:184:8 | m2 | | +| map.cpp:105:31:105:32 | call to map | map.cpp:185:7:185:8 | m2 | | +| map.cpp:105:31:105:32 | call to map | map.cpp:186:7:186:8 | m2 | | +| map.cpp:105:31:105:32 | call to map | map.cpp:187:7:187:8 | m2 | | +| map.cpp:105:31:105:32 | call to map | map.cpp:252:1:252:1 | m2 | | +| map.cpp:105:35:105:36 | call to map | map.cpp:109:7:109:8 | m3 | | +| map.cpp:105:35:105:36 | call to map | map.cpp:115:7:115:8 | m3 | | +| map.cpp:105:35:105:36 | call to map | map.cpp:121:7:121:8 | m3 | | +| map.cpp:105:35:105:36 | call to map | map.cpp:127:7:127:8 | m3 | | +| map.cpp:105:35:105:36 | call to map | map.cpp:158:12:158:13 | m3 | | +| map.cpp:105:35:105:36 | call to map | map.cpp:158:30:158:31 | m3 | | +| map.cpp:105:35:105:36 | call to map | map.cpp:252:1:252:1 | m3 | | +| map.cpp:105:39:105:40 | call to map | map.cpp:110:7:110:8 | m4 | | +| map.cpp:105:39:105:40 | call to map | map.cpp:110:17:110:18 | m4 | | +| map.cpp:105:39:105:40 | call to map | map.cpp:116:7:116:8 | m4 | | +| map.cpp:105:39:105:40 | call to map | map.cpp:122:7:122:8 | m4 | | +| map.cpp:105:39:105:40 | call to map | map.cpp:128:7:128:8 | m4 | | +| map.cpp:105:39:105:40 | call to map | map.cpp:252:1:252:1 | m4 | | +| map.cpp:105:43:105:44 | call to map | map.cpp:111:7:111:8 | m5 | | +| map.cpp:105:43:105:44 | call to map | map.cpp:117:7:117:8 | m5 | | +| map.cpp:105:43:105:44 | call to map | map.cpp:123:7:123:8 | m5 | | +| map.cpp:105:43:105:44 | call to map | map.cpp:129:7:129:8 | m5 | | +| map.cpp:105:43:105:44 | call to map | map.cpp:252:1:252:1 | m5 | | +| map.cpp:105:47:105:48 | call to map | map.cpp:112:7:112:8 | m6 | | +| map.cpp:105:47:105:48 | call to map | map.cpp:112:27:112:28 | m6 | | +| map.cpp:105:47:105:48 | call to map | map.cpp:118:7:118:8 | m6 | | +| map.cpp:105:47:105:48 | call to map | map.cpp:124:7:124:8 | m6 | | +| map.cpp:105:47:105:48 | call to map | map.cpp:130:7:130:8 | m6 | | +| map.cpp:105:47:105:48 | call to map | map.cpp:252:1:252:1 | m6 | | +| map.cpp:107:7:107:8 | ref arg m1 | map.cpp:113:7:113:8 | m1 | | +| map.cpp:107:7:107:8 | ref arg m1 | map.cpp:119:7:119:8 | m1 | | +| map.cpp:107:7:107:8 | ref arg m1 | map.cpp:125:7:125:8 | m1 | | +| map.cpp:107:7:107:8 | ref arg m1 | map.cpp:146:12:146:13 | m1 | | +| map.cpp:107:7:107:8 | ref arg m1 | map.cpp:146:30:146:31 | m1 | | +| map.cpp:107:7:107:8 | ref arg m1 | map.cpp:252:1:252:1 | m1 | | +| map.cpp:107:17:107:30 | call to make_pair | map.cpp:107:17:107:44 | call to pair | TAINT | +| map.cpp:107:17:107:44 | call to pair | map.cpp:107:7:107:8 | ref arg m1 | TAINT | +| map.cpp:107:17:107:44 | call to pair | map.cpp:107:10:107:15 | call to insert | TAINT | +| map.cpp:107:47:107:51 | first | map.cpp:107:7:107:51 | call to iterator | | +| map.cpp:108:7:108:8 | ref arg m2 | map.cpp:114:7:114:8 | m2 | | +| map.cpp:108:7:108:8 | ref arg m2 | map.cpp:120:7:120:8 | m2 | | +| map.cpp:108:7:108:8 | ref arg m2 | map.cpp:126:7:126:8 | m2 | | +| map.cpp:108:7:108:8 | ref arg m2 | map.cpp:133:30:133:31 | m2 | | +| map.cpp:108:7:108:8 | ref arg m2 | map.cpp:134:32:134:33 | m2 | | +| map.cpp:108:7:108:8 | ref arg m2 | map.cpp:136:7:136:8 | m2 | | +| map.cpp:108:7:108:8 | ref arg m2 | map.cpp:152:12:152:13 | m2 | | +| map.cpp:108:7:108:8 | ref arg m2 | map.cpp:152:30:152:31 | m2 | | +| map.cpp:108:7:108:8 | ref arg m2 | map.cpp:182:7:182:8 | m2 | | +| map.cpp:108:7:108:8 | ref arg m2 | map.cpp:183:7:183:8 | m2 | | +| map.cpp:108:7:108:8 | ref arg m2 | map.cpp:184:7:184:8 | m2 | | +| map.cpp:108:7:108:8 | ref arg m2 | map.cpp:185:7:185:8 | m2 | | +| map.cpp:108:7:108:8 | ref arg m2 | map.cpp:186:7:186:8 | m2 | | +| map.cpp:108:7:108:8 | ref arg m2 | map.cpp:187:7:187:8 | m2 | | +| map.cpp:108:7:108:8 | ref arg m2 | map.cpp:252:1:252:1 | m2 | | +| map.cpp:108:17:108:30 | call to make_pair | map.cpp:108:17:108:47 | call to pair | TAINT | +| map.cpp:108:17:108:47 | call to pair | map.cpp:108:7:108:8 | ref arg m2 | TAINT | +| map.cpp:108:17:108:47 | call to pair | map.cpp:108:10:108:15 | call to insert | TAINT | +| map.cpp:108:50:108:54 | first | map.cpp:108:7:108:54 | call to iterator | | +| map.cpp:109:7:109:8 | ref arg m3 | map.cpp:115:7:115:8 | m3 | | +| map.cpp:109:7:109:8 | ref arg m3 | map.cpp:121:7:121:8 | m3 | | +| map.cpp:109:7:109:8 | ref arg m3 | map.cpp:127:7:127:8 | m3 | | +| map.cpp:109:7:109:8 | ref arg m3 | map.cpp:158:12:158:13 | m3 | | +| map.cpp:109:7:109:8 | ref arg m3 | map.cpp:158:30:158:31 | m3 | | +| map.cpp:109:7:109:8 | ref arg m3 | map.cpp:252:1:252:1 | m3 | | +| map.cpp:109:17:109:30 | call to make_pair | map.cpp:109:17:109:47 | call to pair | TAINT | +| map.cpp:109:17:109:47 | call to pair | map.cpp:109:7:109:8 | ref arg m3 | TAINT | +| map.cpp:109:17:109:47 | call to pair | map.cpp:109:10:109:15 | call to insert | TAINT | +| map.cpp:109:50:109:54 | first | map.cpp:109:7:109:54 | call to iterator | | +| map.cpp:110:7:110:8 | ref arg m4 | map.cpp:116:7:116:8 | m4 | | +| map.cpp:110:7:110:8 | ref arg m4 | map.cpp:122:7:122:8 | m4 | | +| map.cpp:110:7:110:8 | ref arg m4 | map.cpp:128:7:128:8 | m4 | | +| map.cpp:110:7:110:8 | ref arg m4 | map.cpp:252:1:252:1 | m4 | | +| map.cpp:110:17:110:18 | m4 | map.cpp:110:20:110:24 | call to begin | TAINT | +| map.cpp:110:17:110:18 | ref arg m4 | map.cpp:110:7:110:8 | m4 | | +| map.cpp:110:17:110:18 | ref arg m4 | map.cpp:116:7:116:8 | m4 | | +| map.cpp:110:17:110:18 | ref arg m4 | map.cpp:122:7:122:8 | m4 | | +| map.cpp:110:17:110:18 | ref arg m4 | map.cpp:128:7:128:8 | m4 | | +| map.cpp:110:17:110:18 | ref arg m4 | map.cpp:252:1:252:1 | m4 | | +| map.cpp:110:20:110:24 | call to begin | map.cpp:110:17:110:26 | call to iterator | TAINT | +| map.cpp:110:29:110:70 | call to pair | map.cpp:110:7:110:8 | ref arg m4 | TAINT | +| map.cpp:110:29:110:70 | call to pair | map.cpp:110:10:110:15 | call to insert | TAINT | +| map.cpp:110:29:110:70 | call to pair | map.cpp:110:29:110:70 | call to pair | TAINT | +| map.cpp:110:62:110:67 | call to source | map.cpp:110:29:110:70 | call to pair | TAINT | +| map.cpp:111:7:111:8 | ref arg m5 | map.cpp:117:7:117:8 | m5 | | +| map.cpp:111:7:111:8 | ref arg m5 | map.cpp:123:7:123:8 | m5 | | +| map.cpp:111:7:111:8 | ref arg m5 | map.cpp:129:7:129:8 | m5 | | +| map.cpp:111:7:111:8 | ref arg m5 | map.cpp:252:1:252:1 | m5 | | +| map.cpp:111:34:111:39 | call to source | map.cpp:111:7:111:8 | ref arg m5 | TAINT | +| map.cpp:111:34:111:39 | call to source | map.cpp:111:10:111:25 | call to insert_or_assign | TAINT | +| map.cpp:111:44:111:48 | first | map.cpp:111:7:111:48 | call to iterator | | +| map.cpp:112:7:112:8 | ref arg m6 | map.cpp:118:7:118:8 | m6 | | +| map.cpp:112:7:112:8 | ref arg m6 | map.cpp:124:7:124:8 | m6 | | +| map.cpp:112:7:112:8 | ref arg m6 | map.cpp:130:7:130:8 | m6 | | +| map.cpp:112:7:112:8 | ref arg m6 | map.cpp:252:1:252:1 | m6 | | +| map.cpp:112:27:112:28 | m6 | map.cpp:112:30:112:34 | call to begin | TAINT | +| map.cpp:112:27:112:28 | ref arg m6 | map.cpp:112:7:112:8 | m6 | | +| map.cpp:112:27:112:28 | ref arg m6 | map.cpp:118:7:118:8 | m6 | | +| map.cpp:112:27:112:28 | ref arg m6 | map.cpp:124:7:124:8 | m6 | | +| map.cpp:112:27:112:28 | ref arg m6 | map.cpp:130:7:130:8 | m6 | | +| map.cpp:112:27:112:28 | ref arg m6 | map.cpp:252:1:252:1 | m6 | | +| map.cpp:112:30:112:34 | call to begin | map.cpp:112:27:112:36 | call to iterator | TAINT | +| map.cpp:112:46:112:51 | call to source | map.cpp:112:7:112:8 | ref arg m6 | TAINT | +| map.cpp:112:46:112:51 | call to source | map.cpp:112:10:112:25 | call to insert_or_assign | TAINT | +| map.cpp:113:7:113:8 | m1 | map.cpp:113:7:113:8 | call to map | | +| map.cpp:114:7:114:8 | m2 | map.cpp:114:7:114:8 | call to map | | +| map.cpp:115:7:115:8 | m3 | map.cpp:115:7:115:8 | call to map | | +| map.cpp:116:7:116:8 | m4 | map.cpp:116:7:116:8 | call to map | | +| map.cpp:117:7:117:8 | m5 | map.cpp:117:7:117:8 | call to map | | +| map.cpp:118:7:118:8 | m6 | map.cpp:118:7:118:8 | call to map | | +| map.cpp:119:7:119:8 | m1 | map.cpp:119:10:119:13 | call to find | TAINT | +| map.cpp:119:7:119:8 | ref arg m1 | map.cpp:125:7:125:8 | m1 | | +| map.cpp:119:7:119:8 | ref arg m1 | map.cpp:146:12:146:13 | m1 | | +| map.cpp:119:7:119:8 | ref arg m1 | map.cpp:146:30:146:31 | m1 | | +| map.cpp:119:7:119:8 | ref arg m1 | map.cpp:252:1:252:1 | m1 | | +| map.cpp:120:7:120:8 | m2 | map.cpp:120:10:120:13 | call to find | TAINT | +| map.cpp:120:7:120:8 | ref arg m2 | map.cpp:126:7:126:8 | m2 | | +| map.cpp:120:7:120:8 | ref arg m2 | map.cpp:133:30:133:31 | m2 | | +| map.cpp:120:7:120:8 | ref arg m2 | map.cpp:134:32:134:33 | m2 | | +| map.cpp:120:7:120:8 | ref arg m2 | map.cpp:136:7:136:8 | m2 | | +| map.cpp:120:7:120:8 | ref arg m2 | map.cpp:152:12:152:13 | m2 | | +| map.cpp:120:7:120:8 | ref arg m2 | map.cpp:152:30:152:31 | m2 | | +| map.cpp:120:7:120:8 | ref arg m2 | map.cpp:182:7:182:8 | m2 | | +| map.cpp:120:7:120:8 | ref arg m2 | map.cpp:183:7:183:8 | m2 | | +| map.cpp:120:7:120:8 | ref arg m2 | map.cpp:184:7:184:8 | m2 | | +| map.cpp:120:7:120:8 | ref arg m2 | map.cpp:185:7:185:8 | m2 | | +| map.cpp:120:7:120:8 | ref arg m2 | map.cpp:186:7:186:8 | m2 | | +| map.cpp:120:7:120:8 | ref arg m2 | map.cpp:187:7:187:8 | m2 | | +| map.cpp:120:7:120:8 | ref arg m2 | map.cpp:252:1:252:1 | m2 | | +| map.cpp:121:7:121:8 | m3 | map.cpp:121:10:121:13 | call to find | TAINT | +| map.cpp:121:7:121:8 | ref arg m3 | map.cpp:127:7:127:8 | m3 | | +| map.cpp:121:7:121:8 | ref arg m3 | map.cpp:158:12:158:13 | m3 | | +| map.cpp:121:7:121:8 | ref arg m3 | map.cpp:158:30:158:31 | m3 | | +| map.cpp:121:7:121:8 | ref arg m3 | map.cpp:252:1:252:1 | m3 | | +| map.cpp:122:7:122:8 | m4 | map.cpp:122:10:122:13 | call to find | TAINT | +| map.cpp:122:7:122:8 | ref arg m4 | map.cpp:128:7:128:8 | m4 | | +| map.cpp:122:7:122:8 | ref arg m4 | map.cpp:252:1:252:1 | m4 | | +| map.cpp:123:7:123:8 | m5 | map.cpp:123:10:123:13 | call to find | TAINT | +| map.cpp:123:7:123:8 | ref arg m5 | map.cpp:129:7:129:8 | m5 | | +| map.cpp:123:7:123:8 | ref arg m5 | map.cpp:252:1:252:1 | m5 | | +| map.cpp:124:7:124:8 | m6 | map.cpp:124:10:124:13 | call to find | TAINT | +| map.cpp:124:7:124:8 | ref arg m6 | map.cpp:130:7:130:8 | m6 | | +| map.cpp:124:7:124:8 | ref arg m6 | map.cpp:252:1:252:1 | m6 | | +| map.cpp:125:7:125:8 | m1 | map.cpp:125:10:125:13 | call to find | TAINT | +| map.cpp:125:7:125:8 | ref arg m1 | map.cpp:146:12:146:13 | m1 | | +| map.cpp:125:7:125:8 | ref arg m1 | map.cpp:146:30:146:31 | m1 | | +| map.cpp:125:7:125:8 | ref arg m1 | map.cpp:252:1:252:1 | m1 | | +| map.cpp:126:7:126:8 | m2 | map.cpp:126:10:126:13 | call to find | TAINT | +| map.cpp:126:7:126:8 | ref arg m2 | map.cpp:133:30:133:31 | m2 | | +| map.cpp:126:7:126:8 | ref arg m2 | map.cpp:134:32:134:33 | m2 | | +| map.cpp:126:7:126:8 | ref arg m2 | map.cpp:136:7:136:8 | m2 | | +| map.cpp:126:7:126:8 | ref arg m2 | map.cpp:152:12:152:13 | m2 | | +| map.cpp:126:7:126:8 | ref arg m2 | map.cpp:152:30:152:31 | m2 | | +| map.cpp:126:7:126:8 | ref arg m2 | map.cpp:182:7:182:8 | m2 | | +| map.cpp:126:7:126:8 | ref arg m2 | map.cpp:183:7:183:8 | m2 | | +| map.cpp:126:7:126:8 | ref arg m2 | map.cpp:184:7:184:8 | m2 | | +| map.cpp:126:7:126:8 | ref arg m2 | map.cpp:185:7:185:8 | m2 | | +| map.cpp:126:7:126:8 | ref arg m2 | map.cpp:186:7:186:8 | m2 | | +| map.cpp:126:7:126:8 | ref arg m2 | map.cpp:187:7:187:8 | m2 | | +| map.cpp:126:7:126:8 | ref arg m2 | map.cpp:252:1:252:1 | m2 | | +| map.cpp:127:7:127:8 | m3 | map.cpp:127:10:127:13 | call to find | TAINT | +| map.cpp:127:7:127:8 | ref arg m3 | map.cpp:158:12:158:13 | m3 | | +| map.cpp:127:7:127:8 | ref arg m3 | map.cpp:158:30:158:31 | m3 | | +| map.cpp:127:7:127:8 | ref arg m3 | map.cpp:252:1:252:1 | m3 | | +| map.cpp:128:7:128:8 | m4 | map.cpp:128:10:128:13 | call to find | TAINT | +| map.cpp:128:7:128:8 | ref arg m4 | map.cpp:252:1:252:1 | m4 | | +| map.cpp:129:7:129:8 | m5 | map.cpp:129:10:129:13 | call to find | TAINT | +| map.cpp:129:7:129:8 | ref arg m5 | map.cpp:252:1:252:1 | m5 | | +| map.cpp:130:7:130:8 | m6 | map.cpp:130:10:130:13 | call to find | TAINT | +| map.cpp:130:7:130:8 | ref arg m6 | map.cpp:252:1:252:1 | m6 | | +| map.cpp:133:30:133:31 | m2 | map.cpp:133:30:133:32 | call to map | | +| map.cpp:133:30:133:32 | call to map | map.cpp:137:7:137:8 | m7 | | +| map.cpp:133:30:133:32 | call to map | map.cpp:140:7:140:8 | m7 | | +| map.cpp:133:30:133:32 | call to map | map.cpp:252:1:252:1 | m7 | | +| map.cpp:134:31:134:33 | call to map | map.cpp:138:7:138:8 | m8 | | +| map.cpp:134:31:134:33 | call to map | map.cpp:141:7:141:8 | m8 | | +| map.cpp:134:31:134:33 | call to map | map.cpp:252:1:252:1 | m8 | | +| map.cpp:134:32:134:33 | m2 | map.cpp:134:31:134:33 | call to map | | +| map.cpp:135:27:135:28 | call to map | map.cpp:136:2:136:3 | m9 | | +| map.cpp:135:27:135:28 | call to map | map.cpp:139:7:139:8 | m9 | | +| map.cpp:135:27:135:28 | call to map | map.cpp:142:7:142:8 | m9 | | +| map.cpp:135:27:135:28 | call to map | map.cpp:252:1:252:1 | m9 | | +| map.cpp:136:2:136:3 | ref arg m9 | map.cpp:139:7:139:8 | m9 | | +| map.cpp:136:2:136:3 | ref arg m9 | map.cpp:142:7:142:8 | m9 | | +| map.cpp:136:2:136:3 | ref arg m9 | map.cpp:252:1:252:1 | m9 | | +| map.cpp:136:7:136:8 | m2 | map.cpp:136:2:136:3 | ref arg m9 | TAINT | +| map.cpp:136:7:136:8 | m2 | map.cpp:136:5:136:5 | call to operator= | TAINT | +| map.cpp:137:7:137:8 | m7 | map.cpp:137:7:137:8 | call to map | | +| map.cpp:138:7:138:8 | m8 | map.cpp:138:7:138:8 | call to map | | +| map.cpp:139:7:139:8 | m9 | map.cpp:139:7:139:8 | call to map | | +| map.cpp:140:7:140:8 | m7 | map.cpp:140:10:140:13 | call to find | TAINT | +| map.cpp:140:7:140:8 | ref arg m7 | map.cpp:252:1:252:1 | m7 | | +| map.cpp:141:7:141:8 | m8 | map.cpp:141:10:141:13 | call to find | TAINT | +| map.cpp:141:7:141:8 | ref arg m8 | map.cpp:252:1:252:1 | m8 | | +| map.cpp:142:7:142:8 | m9 | map.cpp:142:10:142:13 | call to find | TAINT | +| map.cpp:142:7:142:8 | ref arg m9 | map.cpp:252:1:252:1 | m9 | | +| map.cpp:146:12:146:13 | m1 | map.cpp:146:15:146:19 | call to begin | TAINT | +| map.cpp:146:12:146:13 | ref arg m1 | map.cpp:146:30:146:31 | m1 | | +| map.cpp:146:12:146:13 | ref arg m1 | map.cpp:252:1:252:1 | m1 | | +| map.cpp:146:15:146:19 | call to begin | map.cpp:146:7:146:21 | ... = ... | | +| map.cpp:146:15:146:19 | call to begin | map.cpp:146:24:146:25 | i1 | | +| map.cpp:146:15:146:19 | call to begin | map.cpp:146:40:146:41 | i1 | | +| map.cpp:146:15:146:19 | call to begin | map.cpp:148:9:148:10 | i1 | | +| map.cpp:146:15:146:19 | call to begin | map.cpp:149:8:149:9 | i1 | | +| map.cpp:146:15:146:19 | call to begin | map.cpp:150:8:150:9 | i1 | | +| map.cpp:146:30:146:31 | m1 | map.cpp:146:33:146:35 | call to end | TAINT | +| map.cpp:146:30:146:31 | ref arg m1 | map.cpp:146:30:146:31 | m1 | | +| map.cpp:146:30:146:31 | ref arg m1 | map.cpp:252:1:252:1 | m1 | | +| map.cpp:146:40:146:41 | i1 | map.cpp:146:42:146:42 | call to operator++ | | +| map.cpp:146:40:146:41 | ref arg i1 | map.cpp:146:24:146:25 | i1 | | +| map.cpp:146:40:146:41 | ref arg i1 | map.cpp:146:40:146:41 | i1 | | +| map.cpp:146:40:146:41 | ref arg i1 | map.cpp:148:9:148:10 | i1 | | +| map.cpp:146:40:146:41 | ref arg i1 | map.cpp:149:8:149:9 | i1 | | +| map.cpp:146:40:146:41 | ref arg i1 | map.cpp:150:8:150:9 | i1 | | +| map.cpp:148:8:148:8 | call to operator* | map.cpp:148:8:148:10 | call to pair | TAINT | +| map.cpp:148:9:148:10 | i1 | map.cpp:148:8:148:8 | call to operator* | TAINT | +| map.cpp:149:8:149:9 | i1 | map.cpp:149:10:149:10 | call to operator-> | TAINT | +| map.cpp:150:8:150:9 | i1 | map.cpp:150:10:150:10 | call to operator-> | TAINT | +| map.cpp:152:12:152:13 | m2 | map.cpp:152:15:152:19 | call to begin | TAINT | +| map.cpp:152:12:152:13 | ref arg m2 | map.cpp:152:30:152:31 | m2 | | +| map.cpp:152:12:152:13 | ref arg m2 | map.cpp:182:7:182:8 | m2 | | +| map.cpp:152:12:152:13 | ref arg m2 | map.cpp:183:7:183:8 | m2 | | +| map.cpp:152:12:152:13 | ref arg m2 | map.cpp:184:7:184:8 | m2 | | +| map.cpp:152:12:152:13 | ref arg m2 | map.cpp:185:7:185:8 | m2 | | +| map.cpp:152:12:152:13 | ref arg m2 | map.cpp:186:7:186:8 | m2 | | +| map.cpp:152:12:152:13 | ref arg m2 | map.cpp:187:7:187:8 | m2 | | +| map.cpp:152:12:152:13 | ref arg m2 | map.cpp:252:1:252:1 | m2 | | +| map.cpp:152:15:152:19 | call to begin | map.cpp:152:7:152:21 | ... = ... | | +| map.cpp:152:15:152:19 | call to begin | map.cpp:152:24:152:25 | i2 | | +| map.cpp:152:15:152:19 | call to begin | map.cpp:152:40:152:41 | i2 | | +| map.cpp:152:15:152:19 | call to begin | map.cpp:154:9:154:10 | i2 | | +| map.cpp:152:15:152:19 | call to begin | map.cpp:155:8:155:9 | i2 | | +| map.cpp:152:15:152:19 | call to begin | map.cpp:156:8:156:9 | i2 | | +| map.cpp:152:15:152:19 | call to begin | map.cpp:161:8:161:9 | i2 | | +| map.cpp:152:15:152:19 | call to begin | map.cpp:162:8:162:9 | i2 | | +| map.cpp:152:30:152:31 | m2 | map.cpp:152:33:152:35 | call to end | TAINT | +| map.cpp:152:30:152:31 | ref arg m2 | map.cpp:152:30:152:31 | m2 | | +| map.cpp:152:30:152:31 | ref arg m2 | map.cpp:182:7:182:8 | m2 | | +| map.cpp:152:30:152:31 | ref arg m2 | map.cpp:183:7:183:8 | m2 | | +| map.cpp:152:30:152:31 | ref arg m2 | map.cpp:184:7:184:8 | m2 | | +| map.cpp:152:30:152:31 | ref arg m2 | map.cpp:185:7:185:8 | m2 | | +| map.cpp:152:30:152:31 | ref arg m2 | map.cpp:186:7:186:8 | m2 | | +| map.cpp:152:30:152:31 | ref arg m2 | map.cpp:187:7:187:8 | m2 | | +| map.cpp:152:30:152:31 | ref arg m2 | map.cpp:252:1:252:1 | m2 | | +| map.cpp:152:40:152:41 | i2 | map.cpp:152:42:152:42 | call to operator++ | | +| map.cpp:152:40:152:41 | ref arg i2 | map.cpp:152:24:152:25 | i2 | | +| map.cpp:152:40:152:41 | ref arg i2 | map.cpp:152:40:152:41 | i2 | | +| map.cpp:152:40:152:41 | ref arg i2 | map.cpp:154:9:154:10 | i2 | | +| map.cpp:152:40:152:41 | ref arg i2 | map.cpp:155:8:155:9 | i2 | | +| map.cpp:152:40:152:41 | ref arg i2 | map.cpp:156:8:156:9 | i2 | | +| map.cpp:152:40:152:41 | ref arg i2 | map.cpp:161:8:161:9 | i2 | | +| map.cpp:152:40:152:41 | ref arg i2 | map.cpp:162:8:162:9 | i2 | | +| map.cpp:154:8:154:8 | call to operator* | map.cpp:154:8:154:10 | call to pair | TAINT | +| map.cpp:154:9:154:10 | i2 | map.cpp:154:8:154:8 | call to operator* | TAINT | +| map.cpp:155:8:155:9 | i2 | map.cpp:155:10:155:10 | call to operator-> | TAINT | +| map.cpp:156:8:156:9 | i2 | map.cpp:156:10:156:10 | call to operator-> | TAINT | +| map.cpp:158:12:158:13 | m3 | map.cpp:158:15:158:19 | call to begin | TAINT | +| map.cpp:158:12:158:13 | ref arg m3 | map.cpp:158:30:158:31 | m3 | | +| map.cpp:158:12:158:13 | ref arg m3 | map.cpp:252:1:252:1 | m3 | | +| map.cpp:158:15:158:19 | call to begin | map.cpp:158:7:158:21 | ... = ... | | +| map.cpp:158:15:158:19 | call to begin | map.cpp:158:24:158:25 | i3 | | +| map.cpp:158:15:158:19 | call to begin | map.cpp:158:40:158:41 | i3 | | +| map.cpp:158:15:158:19 | call to begin | map.cpp:160:9:160:10 | i3 | | +| map.cpp:158:30:158:31 | m3 | map.cpp:158:33:158:35 | call to end | TAINT | +| map.cpp:158:30:158:31 | ref arg m3 | map.cpp:158:30:158:31 | m3 | | +| map.cpp:158:30:158:31 | ref arg m3 | map.cpp:252:1:252:1 | m3 | | +| map.cpp:158:40:158:41 | i3 | map.cpp:158:42:158:42 | call to operator++ | | +| map.cpp:158:40:158:41 | ref arg i3 | map.cpp:158:24:158:25 | i3 | | +| map.cpp:158:40:158:41 | ref arg i3 | map.cpp:158:40:158:41 | i3 | | +| map.cpp:158:40:158:41 | ref arg i3 | map.cpp:160:9:160:10 | i3 | | +| map.cpp:160:8:160:8 | call to operator* | map.cpp:160:8:160:10 | call to pair | TAINT | +| map.cpp:160:9:160:10 | i3 | map.cpp:160:8:160:8 | call to operator* | TAINT | +| map.cpp:161:8:161:9 | i2 | map.cpp:161:10:161:10 | call to operator-> | TAINT | +| map.cpp:162:8:162:9 | i2 | map.cpp:162:10:162:10 | call to operator-> | TAINT | +| map.cpp:166:27:166:29 | call to map | map.cpp:167:7:167:9 | m10 | | +| map.cpp:166:27:166:29 | call to map | map.cpp:171:7:171:9 | m10 | | +| map.cpp:166:27:166:29 | call to map | map.cpp:252:1:252:1 | m10 | | +| map.cpp:166:32:166:34 | call to map | map.cpp:168:7:168:9 | m11 | | +| map.cpp:166:32:166:34 | call to map | map.cpp:172:7:172:9 | m11 | | +| map.cpp:166:32:166:34 | call to map | map.cpp:252:1:252:1 | m11 | | +| map.cpp:166:37:166:39 | call to map | map.cpp:169:7:169:9 | m12 | | +| map.cpp:166:37:166:39 | call to map | map.cpp:173:7:173:9 | m12 | | +| map.cpp:166:37:166:39 | call to map | map.cpp:252:1:252:1 | m12 | | +| map.cpp:166:42:166:44 | call to map | map.cpp:170:7:170:9 | m13 | | +| map.cpp:166:42:166:44 | call to map | map.cpp:174:7:174:9 | m13 | | +| map.cpp:166:42:166:44 | call to map | map.cpp:252:1:252:1 | m13 | | +| map.cpp:167:7:167:9 | m10 | map.cpp:167:10:167:10 | call to operator[] | TAINT | +| map.cpp:167:7:167:9 | ref arg m10 | map.cpp:171:7:171:9 | m10 | | +| map.cpp:167:7:167:9 | ref arg m10 | map.cpp:252:1:252:1 | m10 | | +| map.cpp:167:7:167:24 | ... = ... | map.cpp:167:10:167:10 | call to operator[] [post update] | | +| map.cpp:167:10:167:10 | call to operator[] [post update] | map.cpp:167:7:167:9 | ref arg m10 | TAINT | +| map.cpp:167:20:167:24 | def | map.cpp:167:7:167:24 | ... = ... | | +| map.cpp:168:7:168:9 | m11 | map.cpp:168:10:168:10 | call to operator[] | TAINT | +| map.cpp:168:7:168:9 | ref arg m11 | map.cpp:172:7:172:9 | m11 | | +| map.cpp:168:7:168:9 | ref arg m11 | map.cpp:252:1:252:1 | m11 | | +| map.cpp:168:7:168:27 | ... = ... | map.cpp:168:10:168:10 | call to operator[] [post update] | | +| map.cpp:168:10:168:10 | call to operator[] [post update] | map.cpp:168:7:168:9 | ref arg m11 | TAINT | +| map.cpp:168:20:168:25 | call to source | map.cpp:168:7:168:27 | ... = ... | | +| map.cpp:169:7:169:9 | m12 | map.cpp:169:11:169:12 | call to at | TAINT | +| map.cpp:169:7:169:9 | ref arg m12 | map.cpp:173:7:173:9 | m12 | | +| map.cpp:169:7:169:9 | ref arg m12 | map.cpp:252:1:252:1 | m12 | | +| map.cpp:169:7:169:27 | ... = ... | map.cpp:169:11:169:12 | call to at [post update] | | +| map.cpp:169:11:169:12 | call to at [post update] | map.cpp:169:7:169:9 | ref arg m12 | TAINT | +| map.cpp:169:23:169:27 | def | map.cpp:169:7:169:27 | ... = ... | | +| map.cpp:170:7:170:9 | m13 | map.cpp:170:11:170:12 | call to at | TAINT | +| map.cpp:170:7:170:9 | ref arg m13 | map.cpp:174:7:174:9 | m13 | | +| map.cpp:170:7:170:9 | ref arg m13 | map.cpp:252:1:252:1 | m13 | | +| map.cpp:170:7:170:30 | ... = ... | map.cpp:170:11:170:12 | call to at [post update] | | +| map.cpp:170:11:170:12 | call to at [post update] | map.cpp:170:7:170:9 | ref arg m13 | TAINT | +| map.cpp:170:23:170:28 | call to source | map.cpp:170:7:170:30 | ... = ... | | +| map.cpp:171:7:171:9 | m10 | map.cpp:171:10:171:10 | call to operator[] | TAINT | +| map.cpp:171:7:171:9 | ref arg m10 | map.cpp:252:1:252:1 | m10 | | +| map.cpp:172:7:172:9 | m11 | map.cpp:172:10:172:10 | call to operator[] | TAINT | +| map.cpp:172:7:172:9 | ref arg m11 | map.cpp:252:1:252:1 | m11 | | +| map.cpp:173:7:173:9 | m12 | map.cpp:173:10:173:10 | call to operator[] | TAINT | +| map.cpp:173:7:173:9 | ref arg m12 | map.cpp:252:1:252:1 | m12 | | +| map.cpp:174:7:174:9 | m13 | map.cpp:174:10:174:10 | call to operator[] | TAINT | +| map.cpp:174:7:174:9 | ref arg m13 | map.cpp:252:1:252:1 | m13 | | +| map.cpp:177:27:177:29 | call to map | map.cpp:178:2:178:4 | m14 | | +| map.cpp:177:27:177:29 | call to map | map.cpp:179:2:179:4 | m14 | | +| map.cpp:177:27:177:29 | call to map | map.cpp:180:2:180:4 | m14 | | +| map.cpp:177:27:177:29 | call to map | map.cpp:181:2:181:4 | m14 | | +| map.cpp:177:27:177:29 | call to map | map.cpp:252:1:252:1 | m14 | | +| map.cpp:178:2:178:4 | ref arg m14 | map.cpp:179:2:179:4 | m14 | | +| map.cpp:178:2:178:4 | ref arg m14 | map.cpp:180:2:180:4 | m14 | | +| map.cpp:178:2:178:4 | ref arg m14 | map.cpp:181:2:181:4 | m14 | | +| map.cpp:178:2:178:4 | ref arg m14 | map.cpp:252:1:252:1 | m14 | | +| map.cpp:178:13:178:26 | call to make_pair | map.cpp:178:13:178:36 | call to pair | TAINT | +| map.cpp:178:13:178:36 | call to pair | map.cpp:178:2:178:4 | ref arg m14 | TAINT | +| map.cpp:178:13:178:36 | call to pair | map.cpp:178:6:178:11 | call to insert | TAINT | +| map.cpp:179:2:179:4 | ref arg m14 | map.cpp:180:2:180:4 | m14 | | +| map.cpp:179:2:179:4 | ref arg m14 | map.cpp:181:2:181:4 | m14 | | +| map.cpp:179:2:179:4 | ref arg m14 | map.cpp:252:1:252:1 | m14 | | +| map.cpp:179:13:179:26 | call to make_pair | map.cpp:179:13:179:41 | call to pair | TAINT | +| map.cpp:179:13:179:41 | call to pair | map.cpp:179:2:179:4 | ref arg m14 | TAINT | +| map.cpp:179:13:179:41 | call to pair | map.cpp:179:6:179:11 | call to insert | TAINT | +| map.cpp:180:2:180:4 | ref arg m14 | map.cpp:181:2:181:4 | m14 | | +| map.cpp:180:2:180:4 | ref arg m14 | map.cpp:252:1:252:1 | m14 | | +| map.cpp:180:13:180:26 | call to make_pair | map.cpp:180:13:180:41 | call to pair | TAINT | +| map.cpp:180:13:180:41 | call to pair | map.cpp:180:2:180:4 | ref arg m14 | TAINT | +| map.cpp:180:13:180:41 | call to pair | map.cpp:180:6:180:11 | call to insert | TAINT | +| map.cpp:181:2:181:4 | ref arg m14 | map.cpp:252:1:252:1 | m14 | | +| map.cpp:181:13:181:26 | call to make_pair | map.cpp:181:13:181:36 | call to pair | TAINT | +| map.cpp:181:13:181:36 | call to pair | map.cpp:181:2:181:4 | ref arg m14 | TAINT | +| map.cpp:181:13:181:36 | call to pair | map.cpp:181:6:181:11 | call to insert | TAINT | +| map.cpp:182:7:182:8 | m2 | map.cpp:182:10:182:20 | call to lower_bound | TAINT | +| map.cpp:182:7:182:8 | ref arg m2 | map.cpp:183:7:183:8 | m2 | | +| map.cpp:182:7:182:8 | ref arg m2 | map.cpp:184:7:184:8 | m2 | | +| map.cpp:182:7:182:8 | ref arg m2 | map.cpp:185:7:185:8 | m2 | | +| map.cpp:182:7:182:8 | ref arg m2 | map.cpp:186:7:186:8 | m2 | | +| map.cpp:182:7:182:8 | ref arg m2 | map.cpp:187:7:187:8 | m2 | | +| map.cpp:182:7:182:8 | ref arg m2 | map.cpp:252:1:252:1 | m2 | | +| map.cpp:183:7:183:8 | m2 | map.cpp:183:10:183:20 | call to upper_bound | TAINT | +| map.cpp:183:7:183:8 | ref arg m2 | map.cpp:184:7:184:8 | m2 | | +| map.cpp:183:7:183:8 | ref arg m2 | map.cpp:185:7:185:8 | m2 | | +| map.cpp:183:7:183:8 | ref arg m2 | map.cpp:186:7:186:8 | m2 | | +| map.cpp:183:7:183:8 | ref arg m2 | map.cpp:187:7:187:8 | m2 | | +| map.cpp:183:7:183:8 | ref arg m2 | map.cpp:252:1:252:1 | m2 | | +| map.cpp:184:7:184:8 | m2 | map.cpp:184:10:184:20 | call to equal_range | TAINT | +| map.cpp:184:7:184:8 | ref arg m2 | map.cpp:185:7:185:8 | m2 | | +| map.cpp:184:7:184:8 | ref arg m2 | map.cpp:186:7:186:8 | m2 | | +| map.cpp:184:7:184:8 | ref arg m2 | map.cpp:187:7:187:8 | m2 | | +| map.cpp:184:7:184:8 | ref arg m2 | map.cpp:252:1:252:1 | m2 | | +| map.cpp:184:27:184:31 | first | map.cpp:184:7:184:31 | call to iterator | | +| map.cpp:185:7:185:8 | m2 | map.cpp:185:10:185:20 | call to equal_range | TAINT | +| map.cpp:185:7:185:8 | ref arg m2 | map.cpp:186:7:186:8 | m2 | | +| map.cpp:185:7:185:8 | ref arg m2 | map.cpp:187:7:187:8 | m2 | | +| map.cpp:185:7:185:8 | ref arg m2 | map.cpp:252:1:252:1 | m2 | | +| map.cpp:185:27:185:32 | second | map.cpp:185:7:185:32 | call to iterator | | +| map.cpp:186:7:186:8 | m2 | map.cpp:186:10:186:20 | call to upper_bound | TAINT | +| map.cpp:186:7:186:8 | ref arg m2 | map.cpp:187:7:187:8 | m2 | | +| map.cpp:186:7:186:8 | ref arg m2 | map.cpp:252:1:252:1 | m2 | | +| map.cpp:187:7:187:8 | m2 | map.cpp:187:10:187:20 | call to equal_range | TAINT | +| map.cpp:187:7:187:8 | ref arg m2 | map.cpp:252:1:252:1 | m2 | | +| map.cpp:187:27:187:32 | second | map.cpp:187:7:187:32 | call to iterator | | +| map.cpp:190:27:190:29 | call to map | map.cpp:191:2:191:4 | m15 | | +| map.cpp:190:27:190:29 | call to map | map.cpp:193:7:193:9 | m15 | | +| map.cpp:190:27:190:29 | call to map | map.cpp:197:2:197:4 | m15 | | +| map.cpp:190:27:190:29 | call to map | map.cpp:199:7:199:9 | m15 | | +| map.cpp:190:27:190:29 | call to map | map.cpp:252:1:252:1 | m15 | | +| map.cpp:190:32:190:34 | call to map | map.cpp:194:7:194:9 | m16 | | +| map.cpp:190:32:190:34 | call to map | map.cpp:197:11:197:13 | m16 | | +| map.cpp:190:32:190:34 | call to map | map.cpp:200:7:200:9 | m16 | | +| map.cpp:190:32:190:34 | call to map | map.cpp:252:1:252:1 | m16 | | +| map.cpp:190:37:190:39 | call to map | map.cpp:195:7:195:9 | m17 | | +| map.cpp:190:37:190:39 | call to map | map.cpp:198:2:198:4 | m17 | | +| map.cpp:190:37:190:39 | call to map | map.cpp:201:7:201:9 | m17 | | +| map.cpp:190:37:190:39 | call to map | map.cpp:252:1:252:1 | m17 | | +| map.cpp:190:42:190:44 | call to map | map.cpp:192:2:192:4 | m18 | | +| map.cpp:190:42:190:44 | call to map | map.cpp:196:7:196:9 | m18 | | +| map.cpp:190:42:190:44 | call to map | map.cpp:198:11:198:13 | m18 | | +| map.cpp:190:42:190:44 | call to map | map.cpp:202:7:202:9 | m18 | | +| map.cpp:190:42:190:44 | call to map | map.cpp:252:1:252:1 | m18 | | +| map.cpp:191:2:191:4 | ref arg m15 | map.cpp:193:7:193:9 | m15 | | +| map.cpp:191:2:191:4 | ref arg m15 | map.cpp:197:2:197:4 | m15 | | +| map.cpp:191:2:191:4 | ref arg m15 | map.cpp:199:7:199:9 | m15 | | +| map.cpp:191:2:191:4 | ref arg m15 | map.cpp:252:1:252:1 | m15 | | +| map.cpp:191:13:191:57 | call to pair | map.cpp:191:2:191:4 | ref arg m15 | TAINT | +| map.cpp:191:13:191:57 | call to pair | map.cpp:191:6:191:11 | call to insert | TAINT | +| map.cpp:191:13:191:57 | call to pair | map.cpp:191:13:191:57 | call to pair | TAINT | +| map.cpp:191:49:191:54 | call to source | map.cpp:191:13:191:57 | call to pair | TAINT | +| map.cpp:192:2:192:4 | ref arg m18 | map.cpp:196:7:196:9 | m18 | | +| map.cpp:192:2:192:4 | ref arg m18 | map.cpp:198:11:198:13 | m18 | | +| map.cpp:192:2:192:4 | ref arg m18 | map.cpp:202:7:202:9 | m18 | | +| map.cpp:192:2:192:4 | ref arg m18 | map.cpp:252:1:252:1 | m18 | | +| map.cpp:192:13:192:57 | call to pair | map.cpp:192:2:192:4 | ref arg m18 | TAINT | +| map.cpp:192:13:192:57 | call to pair | map.cpp:192:6:192:11 | call to insert | TAINT | +| map.cpp:192:13:192:57 | call to pair | map.cpp:192:13:192:57 | call to pair | TAINT | +| map.cpp:192:49:192:54 | call to source | map.cpp:192:13:192:57 | call to pair | TAINT | +| map.cpp:193:7:193:9 | m15 | map.cpp:193:7:193:9 | call to map | | +| map.cpp:194:7:194:9 | m16 | map.cpp:194:7:194:9 | call to map | | +| map.cpp:195:7:195:9 | m17 | map.cpp:195:7:195:9 | call to map | | +| map.cpp:196:7:196:9 | m18 | map.cpp:196:7:196:9 | call to map | | +| map.cpp:197:2:197:4 | m15 | map.cpp:197:11:197:13 | ref arg m16 | TAINT | +| map.cpp:197:2:197:4 | ref arg m15 | map.cpp:199:7:199:9 | m15 | | +| map.cpp:197:2:197:4 | ref arg m15 | map.cpp:252:1:252:1 | m15 | | +| map.cpp:197:11:197:13 | m16 | map.cpp:197:2:197:4 | ref arg m15 | TAINT | +| map.cpp:197:11:197:13 | ref arg m16 | map.cpp:200:7:200:9 | m16 | | +| map.cpp:197:11:197:13 | ref arg m16 | map.cpp:252:1:252:1 | m16 | | +| map.cpp:198:2:198:4 | m17 | map.cpp:198:11:198:13 | ref arg m18 | TAINT | +| map.cpp:198:2:198:4 | ref arg m17 | map.cpp:201:7:201:9 | m17 | | +| map.cpp:198:2:198:4 | ref arg m17 | map.cpp:252:1:252:1 | m17 | | +| map.cpp:198:11:198:13 | m18 | map.cpp:198:2:198:4 | ref arg m17 | TAINT | +| map.cpp:198:11:198:13 | ref arg m18 | map.cpp:202:7:202:9 | m18 | | +| map.cpp:198:11:198:13 | ref arg m18 | map.cpp:252:1:252:1 | m18 | | +| map.cpp:199:7:199:9 | m15 | map.cpp:199:7:199:9 | call to map | | +| map.cpp:200:7:200:9 | m16 | map.cpp:200:7:200:9 | call to map | | +| map.cpp:201:7:201:9 | m17 | map.cpp:201:7:201:9 | call to map | | +| map.cpp:202:7:202:9 | m18 | map.cpp:202:7:202:9 | call to map | | +| map.cpp:205:27:205:29 | call to map | map.cpp:206:2:206:4 | m19 | | +| map.cpp:205:27:205:29 | call to map | map.cpp:210:7:210:9 | m19 | | +| map.cpp:205:27:205:29 | call to map | map.cpp:214:2:214:4 | m19 | | +| map.cpp:205:27:205:29 | call to map | map.cpp:216:7:216:9 | m19 | | +| map.cpp:205:27:205:29 | call to map | map.cpp:252:1:252:1 | m19 | | +| map.cpp:205:32:205:34 | call to map | map.cpp:207:2:207:4 | m20 | | +| map.cpp:205:32:205:34 | call to map | map.cpp:211:7:211:9 | m20 | | +| map.cpp:205:32:205:34 | call to map | map.cpp:214:12:214:14 | m20 | | +| map.cpp:205:32:205:34 | call to map | map.cpp:217:7:217:9 | m20 | | +| map.cpp:205:32:205:34 | call to map | map.cpp:252:1:252:1 | m20 | | +| map.cpp:205:37:205:39 | call to map | map.cpp:208:2:208:4 | m21 | | +| map.cpp:205:37:205:39 | call to map | map.cpp:212:7:212:9 | m21 | | +| map.cpp:205:37:205:39 | call to map | map.cpp:215:2:215:4 | m21 | | +| map.cpp:205:37:205:39 | call to map | map.cpp:218:7:218:9 | m21 | | +| map.cpp:205:37:205:39 | call to map | map.cpp:252:1:252:1 | m21 | | +| map.cpp:205:42:205:44 | call to map | map.cpp:209:2:209:4 | m22 | | +| map.cpp:205:42:205:44 | call to map | map.cpp:213:7:213:9 | m22 | | +| map.cpp:205:42:205:44 | call to map | map.cpp:215:12:215:14 | m22 | | +| map.cpp:205:42:205:44 | call to map | map.cpp:219:7:219:9 | m22 | | +| map.cpp:205:42:205:44 | call to map | map.cpp:252:1:252:1 | m22 | | +| map.cpp:206:2:206:4 | ref arg m19 | map.cpp:210:7:210:9 | m19 | | +| map.cpp:206:2:206:4 | ref arg m19 | map.cpp:214:2:214:4 | m19 | | +| map.cpp:206:2:206:4 | ref arg m19 | map.cpp:216:7:216:9 | m19 | | +| map.cpp:206:2:206:4 | ref arg m19 | map.cpp:252:1:252:1 | m19 | | +| map.cpp:206:13:206:57 | call to pair | map.cpp:206:2:206:4 | ref arg m19 | TAINT | +| map.cpp:206:13:206:57 | call to pair | map.cpp:206:6:206:11 | call to insert | TAINT | +| map.cpp:206:13:206:57 | call to pair | map.cpp:206:13:206:57 | call to pair | TAINT | +| map.cpp:206:49:206:54 | call to source | map.cpp:206:13:206:57 | call to pair | TAINT | +| map.cpp:207:2:207:4 | ref arg m20 | map.cpp:211:7:211:9 | m20 | | +| map.cpp:207:2:207:4 | ref arg m20 | map.cpp:214:12:214:14 | m20 | | +| map.cpp:207:2:207:4 | ref arg m20 | map.cpp:217:7:217:9 | m20 | | +| map.cpp:207:2:207:4 | ref arg m20 | map.cpp:252:1:252:1 | m20 | | +| map.cpp:207:13:207:51 | call to pair | map.cpp:207:2:207:4 | ref arg m20 | TAINT | +| map.cpp:207:13:207:51 | call to pair | map.cpp:207:6:207:11 | call to insert | TAINT | +| map.cpp:207:13:207:51 | call to pair | map.cpp:207:13:207:51 | call to pair | TAINT | +| map.cpp:207:46:207:50 | def | map.cpp:207:13:207:51 | call to pair | TAINT | +| map.cpp:208:2:208:4 | ref arg m21 | map.cpp:212:7:212:9 | m21 | | +| map.cpp:208:2:208:4 | ref arg m21 | map.cpp:215:2:215:4 | m21 | | +| map.cpp:208:2:208:4 | ref arg m21 | map.cpp:218:7:218:9 | m21 | | +| map.cpp:208:2:208:4 | ref arg m21 | map.cpp:252:1:252:1 | m21 | | +| map.cpp:208:13:208:51 | call to pair | map.cpp:208:2:208:4 | ref arg m21 | TAINT | +| map.cpp:208:13:208:51 | call to pair | map.cpp:208:6:208:11 | call to insert | TAINT | +| map.cpp:208:13:208:51 | call to pair | map.cpp:208:13:208:51 | call to pair | TAINT | +| map.cpp:208:46:208:50 | def | map.cpp:208:13:208:51 | call to pair | TAINT | +| map.cpp:209:2:209:4 | ref arg m22 | map.cpp:213:7:213:9 | m22 | | +| map.cpp:209:2:209:4 | ref arg m22 | map.cpp:215:12:215:14 | m22 | | +| map.cpp:209:2:209:4 | ref arg m22 | map.cpp:219:7:219:9 | m22 | | +| map.cpp:209:2:209:4 | ref arg m22 | map.cpp:252:1:252:1 | m22 | | +| map.cpp:209:13:209:57 | call to pair | map.cpp:209:2:209:4 | ref arg m22 | TAINT | +| map.cpp:209:13:209:57 | call to pair | map.cpp:209:6:209:11 | call to insert | TAINT | +| map.cpp:209:13:209:57 | call to pair | map.cpp:209:13:209:57 | call to pair | TAINT | +| map.cpp:209:49:209:54 | call to source | map.cpp:209:13:209:57 | call to pair | TAINT | +| map.cpp:210:7:210:9 | m19 | map.cpp:210:7:210:9 | call to map | | +| map.cpp:211:7:211:9 | m20 | map.cpp:211:7:211:9 | call to map | | +| map.cpp:212:7:212:9 | m21 | map.cpp:212:7:212:9 | call to map | | +| map.cpp:213:7:213:9 | m22 | map.cpp:213:7:213:9 | call to map | | +| map.cpp:214:2:214:4 | ref arg m19 | map.cpp:216:7:216:9 | m19 | | +| map.cpp:214:2:214:4 | ref arg m19 | map.cpp:252:1:252:1 | m19 | | +| map.cpp:214:12:214:14 | m20 | map.cpp:214:2:214:4 | ref arg m19 | TAINT | +| map.cpp:214:12:214:14 | ref arg m20 | map.cpp:217:7:217:9 | m20 | | +| map.cpp:214:12:214:14 | ref arg m20 | map.cpp:252:1:252:1 | m20 | | +| map.cpp:215:2:215:4 | ref arg m21 | map.cpp:218:7:218:9 | m21 | | +| map.cpp:215:2:215:4 | ref arg m21 | map.cpp:252:1:252:1 | m21 | | +| map.cpp:215:12:215:14 | m22 | map.cpp:215:2:215:4 | ref arg m21 | TAINT | +| map.cpp:215:12:215:14 | ref arg m22 | map.cpp:219:7:219:9 | m22 | | +| map.cpp:215:12:215:14 | ref arg m22 | map.cpp:252:1:252:1 | m22 | | +| map.cpp:216:7:216:9 | m19 | map.cpp:216:7:216:9 | call to map | | +| map.cpp:217:7:217:9 | m20 | map.cpp:217:7:217:9 | call to map | | +| map.cpp:218:7:218:9 | m21 | map.cpp:218:7:218:9 | call to map | | +| map.cpp:219:7:219:9 | m22 | map.cpp:219:7:219:9 | call to map | | +| map.cpp:222:27:222:29 | call to map | map.cpp:223:2:223:4 | m23 | | +| map.cpp:222:27:222:29 | call to map | map.cpp:224:2:224:4 | m23 | | +| map.cpp:222:27:222:29 | call to map | map.cpp:225:7:225:9 | m23 | | +| map.cpp:222:27:222:29 | call to map | map.cpp:226:7:226:9 | m23 | | +| map.cpp:222:27:222:29 | call to map | map.cpp:226:17:226:19 | m23 | | +| map.cpp:222:27:222:29 | call to map | map.cpp:227:7:227:9 | m23 | | +| map.cpp:222:27:222:29 | call to map | map.cpp:228:2:228:4 | m23 | | +| map.cpp:222:27:222:29 | call to map | map.cpp:229:7:229:9 | m23 | | +| map.cpp:222:27:222:29 | call to map | map.cpp:252:1:252:1 | m23 | | +| map.cpp:223:2:223:4 | ref arg m23 | map.cpp:224:2:224:4 | m23 | | +| map.cpp:223:2:223:4 | ref arg m23 | map.cpp:225:7:225:9 | m23 | | +| map.cpp:223:2:223:4 | ref arg m23 | map.cpp:226:7:226:9 | m23 | | +| map.cpp:223:2:223:4 | ref arg m23 | map.cpp:226:17:226:19 | m23 | | +| map.cpp:223:2:223:4 | ref arg m23 | map.cpp:227:7:227:9 | m23 | | +| map.cpp:223:2:223:4 | ref arg m23 | map.cpp:228:2:228:4 | m23 | | +| map.cpp:223:2:223:4 | ref arg m23 | map.cpp:229:7:229:9 | m23 | | +| map.cpp:223:2:223:4 | ref arg m23 | map.cpp:252:1:252:1 | m23 | | +| map.cpp:223:13:223:57 | call to pair | map.cpp:223:2:223:4 | ref arg m23 | TAINT | +| map.cpp:223:13:223:57 | call to pair | map.cpp:223:6:223:11 | call to insert | TAINT | +| map.cpp:223:13:223:57 | call to pair | map.cpp:223:13:223:57 | call to pair | TAINT | +| map.cpp:223:49:223:54 | call to source | map.cpp:223:13:223:57 | call to pair | TAINT | +| map.cpp:224:2:224:4 | ref arg m23 | map.cpp:225:7:225:9 | m23 | | +| map.cpp:224:2:224:4 | ref arg m23 | map.cpp:226:7:226:9 | m23 | | +| map.cpp:224:2:224:4 | ref arg m23 | map.cpp:226:17:226:19 | m23 | | +| map.cpp:224:2:224:4 | ref arg m23 | map.cpp:227:7:227:9 | m23 | | +| map.cpp:224:2:224:4 | ref arg m23 | map.cpp:228:2:228:4 | m23 | | +| map.cpp:224:2:224:4 | ref arg m23 | map.cpp:229:7:229:9 | m23 | | +| map.cpp:224:2:224:4 | ref arg m23 | map.cpp:252:1:252:1 | m23 | | +| map.cpp:224:13:224:57 | call to pair | map.cpp:224:2:224:4 | ref arg m23 | TAINT | +| map.cpp:224:13:224:57 | call to pair | map.cpp:224:6:224:11 | call to insert | TAINT | +| map.cpp:224:13:224:57 | call to pair | map.cpp:224:13:224:57 | call to pair | TAINT | +| map.cpp:224:49:224:54 | call to source | map.cpp:224:13:224:57 | call to pair | TAINT | +| map.cpp:225:7:225:9 | m23 | map.cpp:225:7:225:9 | call to map | | +| map.cpp:226:7:226:9 | m23 | map.cpp:226:11:226:15 | call to erase | TAINT | +| map.cpp:226:7:226:9 | ref arg m23 | map.cpp:227:7:227:9 | m23 | | +| map.cpp:226:7:226:9 | ref arg m23 | map.cpp:228:2:228:4 | m23 | | +| map.cpp:226:7:226:9 | ref arg m23 | map.cpp:229:7:229:9 | m23 | | +| map.cpp:226:7:226:9 | ref arg m23 | map.cpp:252:1:252:1 | m23 | | +| map.cpp:226:17:226:19 | m23 | map.cpp:226:21:226:25 | call to begin | TAINT | +| map.cpp:226:17:226:19 | ref arg m23 | map.cpp:226:7:226:9 | m23 | | +| map.cpp:226:17:226:19 | ref arg m23 | map.cpp:227:7:227:9 | m23 | | +| map.cpp:226:17:226:19 | ref arg m23 | map.cpp:228:2:228:4 | m23 | | +| map.cpp:226:17:226:19 | ref arg m23 | map.cpp:229:7:229:9 | m23 | | +| map.cpp:226:17:226:19 | ref arg m23 | map.cpp:252:1:252:1 | m23 | | +| map.cpp:227:7:227:9 | m23 | map.cpp:227:7:227:9 | call to map | | +| map.cpp:228:2:228:4 | ref arg m23 | map.cpp:229:7:229:9 | m23 | | +| map.cpp:228:2:228:4 | ref arg m23 | map.cpp:252:1:252:1 | m23 | | +| map.cpp:229:7:229:9 | m23 | map.cpp:229:7:229:9 | call to map | | +| map.cpp:232:27:232:29 | call to map | map.cpp:233:7:233:9 | m24 | | +| map.cpp:232:27:232:29 | call to map | map.cpp:234:7:234:9 | m24 | | +| map.cpp:232:27:232:29 | call to map | map.cpp:235:7:235:9 | m24 | | +| map.cpp:232:27:232:29 | call to map | map.cpp:236:7:236:9 | m24 | | +| map.cpp:232:27:232:29 | call to map | map.cpp:252:1:252:1 | m24 | | +| map.cpp:232:32:232:34 | call to map | map.cpp:237:7:237:9 | m25 | | +| map.cpp:232:32:232:34 | call to map | map.cpp:237:24:237:26 | m25 | | +| map.cpp:232:32:232:34 | call to map | map.cpp:238:7:238:9 | m25 | | +| map.cpp:232:32:232:34 | call to map | map.cpp:239:7:239:9 | m25 | | +| map.cpp:232:32:232:34 | call to map | map.cpp:239:24:239:26 | m25 | | +| map.cpp:232:32:232:34 | call to map | map.cpp:240:7:240:9 | m25 | | +| map.cpp:232:32:232:34 | call to map | map.cpp:252:1:252:1 | m25 | | +| map.cpp:233:7:233:9 | m24 | map.cpp:233:11:233:17 | call to emplace | TAINT | +| map.cpp:233:7:233:9 | ref arg m24 | map.cpp:234:7:234:9 | m24 | | +| map.cpp:233:7:233:9 | ref arg m24 | map.cpp:235:7:235:9 | m24 | | +| map.cpp:233:7:233:9 | ref arg m24 | map.cpp:236:7:236:9 | m24 | | +| map.cpp:233:7:233:9 | ref arg m24 | map.cpp:252:1:252:1 | m24 | | +| map.cpp:233:26:233:30 | def | map.cpp:233:7:233:9 | ref arg m24 | TAINT | +| map.cpp:233:26:233:30 | def | map.cpp:233:11:233:17 | call to emplace | TAINT | +| map.cpp:233:33:233:37 | first | map.cpp:233:7:233:37 | call to iterator | | +| map.cpp:234:7:234:9 | m24 | map.cpp:234:7:234:9 | call to map | | +| map.cpp:235:7:235:9 | m24 | map.cpp:235:11:235:17 | call to emplace | TAINT | +| map.cpp:235:7:235:9 | ref arg m24 | map.cpp:236:7:236:9 | m24 | | +| map.cpp:235:7:235:9 | ref arg m24 | map.cpp:252:1:252:1 | m24 | | +| map.cpp:235:26:235:31 | call to source | map.cpp:235:7:235:9 | ref arg m24 | TAINT | +| map.cpp:235:26:235:31 | call to source | map.cpp:235:11:235:17 | call to emplace | TAINT | +| map.cpp:235:36:235:40 | first | map.cpp:235:7:235:40 | call to iterator | | +| map.cpp:236:7:236:9 | m24 | map.cpp:236:7:236:9 | call to map | | +| map.cpp:237:7:237:9 | m25 | map.cpp:237:11:237:22 | call to emplace_hint | TAINT | +| map.cpp:237:7:237:9 | ref arg m25 | map.cpp:238:7:238:9 | m25 | | +| map.cpp:237:7:237:9 | ref arg m25 | map.cpp:239:7:239:9 | m25 | | +| map.cpp:237:7:237:9 | ref arg m25 | map.cpp:239:24:239:26 | m25 | | +| map.cpp:237:7:237:9 | ref arg m25 | map.cpp:240:7:240:9 | m25 | | +| map.cpp:237:7:237:9 | ref arg m25 | map.cpp:252:1:252:1 | m25 | | +| map.cpp:237:24:237:26 | m25 | map.cpp:237:28:237:32 | call to begin | TAINT | +| map.cpp:237:24:237:26 | ref arg m25 | map.cpp:237:7:237:9 | m25 | | +| map.cpp:237:24:237:26 | ref arg m25 | map.cpp:238:7:238:9 | m25 | | +| map.cpp:237:24:237:26 | ref arg m25 | map.cpp:239:7:239:9 | m25 | | +| map.cpp:237:24:237:26 | ref arg m25 | map.cpp:239:24:239:26 | m25 | | +| map.cpp:237:24:237:26 | ref arg m25 | map.cpp:240:7:240:9 | m25 | | +| map.cpp:237:24:237:26 | ref arg m25 | map.cpp:252:1:252:1 | m25 | | +| map.cpp:237:28:237:32 | call to begin | map.cpp:237:24:237:34 | call to iterator | TAINT | +| map.cpp:237:44:237:48 | def | map.cpp:237:7:237:9 | ref arg m25 | TAINT | +| map.cpp:237:44:237:48 | def | map.cpp:237:11:237:22 | call to emplace_hint | TAINT | +| map.cpp:238:7:238:9 | m25 | map.cpp:238:7:238:9 | call to map | | +| map.cpp:239:7:239:9 | m25 | map.cpp:239:11:239:22 | call to emplace_hint | TAINT | +| map.cpp:239:7:239:9 | ref arg m25 | map.cpp:240:7:240:9 | m25 | | +| map.cpp:239:7:239:9 | ref arg m25 | map.cpp:252:1:252:1 | m25 | | +| map.cpp:239:24:239:26 | m25 | map.cpp:239:28:239:32 | call to begin | TAINT | +| map.cpp:239:24:239:26 | ref arg m25 | map.cpp:239:7:239:9 | m25 | | +| map.cpp:239:24:239:26 | ref arg m25 | map.cpp:240:7:240:9 | m25 | | +| map.cpp:239:24:239:26 | ref arg m25 | map.cpp:252:1:252:1 | m25 | | +| map.cpp:239:28:239:32 | call to begin | map.cpp:239:24:239:34 | call to iterator | TAINT | +| map.cpp:239:44:239:49 | call to source | map.cpp:239:7:239:9 | ref arg m25 | TAINT | +| map.cpp:239:44:239:49 | call to source | map.cpp:239:11:239:22 | call to emplace_hint | TAINT | +| map.cpp:240:7:240:9 | m25 | map.cpp:240:7:240:9 | call to map | | +| map.cpp:243:27:243:29 | call to map | map.cpp:244:7:244:9 | m26 | | +| map.cpp:243:27:243:29 | call to map | map.cpp:245:7:245:9 | m26 | | +| map.cpp:243:27:243:29 | call to map | map.cpp:246:7:246:9 | m26 | | +| map.cpp:243:27:243:29 | call to map | map.cpp:247:7:247:9 | m26 | | +| map.cpp:243:27:243:29 | call to map | map.cpp:252:1:252:1 | m26 | | +| map.cpp:243:32:243:34 | call to map | map.cpp:248:7:248:9 | m27 | | +| map.cpp:243:32:243:34 | call to map | map.cpp:248:23:248:25 | m27 | | +| map.cpp:243:32:243:34 | call to map | map.cpp:249:7:249:9 | m27 | | +| map.cpp:243:32:243:34 | call to map | map.cpp:250:7:250:9 | m27 | | +| map.cpp:243:32:243:34 | call to map | map.cpp:250:23:250:25 | m27 | | +| map.cpp:243:32:243:34 | call to map | map.cpp:251:7:251:9 | m27 | | +| map.cpp:243:32:243:34 | call to map | map.cpp:252:1:252:1 | m27 | | +| map.cpp:244:7:244:9 | m26 | map.cpp:244:11:244:21 | call to try_emplace | TAINT | +| map.cpp:244:7:244:9 | ref arg m26 | map.cpp:245:7:245:9 | m26 | | +| map.cpp:244:7:244:9 | ref arg m26 | map.cpp:246:7:246:9 | m26 | | +| map.cpp:244:7:244:9 | ref arg m26 | map.cpp:247:7:247:9 | m26 | | +| map.cpp:244:7:244:9 | ref arg m26 | map.cpp:252:1:252:1 | m26 | | +| map.cpp:244:30:244:34 | def | map.cpp:244:7:244:9 | ref arg m26 | TAINT | +| map.cpp:244:30:244:34 | def | map.cpp:244:11:244:21 | call to try_emplace | TAINT | +| map.cpp:244:37:244:41 | first | map.cpp:244:7:244:41 | call to iterator | | +| map.cpp:245:7:245:9 | m26 | map.cpp:245:7:245:9 | call to map | | +| map.cpp:246:7:246:9 | m26 | map.cpp:246:11:246:21 | call to try_emplace | TAINT | +| map.cpp:246:7:246:9 | ref arg m26 | map.cpp:247:7:247:9 | m26 | | +| map.cpp:246:7:246:9 | ref arg m26 | map.cpp:252:1:252:1 | m26 | | +| map.cpp:246:30:246:35 | call to source | map.cpp:246:7:246:9 | ref arg m26 | TAINT | +| map.cpp:246:30:246:35 | call to source | map.cpp:246:11:246:21 | call to try_emplace | TAINT | +| map.cpp:246:40:246:44 | first | map.cpp:246:7:246:44 | call to iterator | | +| map.cpp:247:7:247:9 | m26 | map.cpp:247:7:247:9 | call to map | | +| map.cpp:248:7:248:9 | m27 | map.cpp:248:11:248:21 | call to try_emplace | TAINT | +| map.cpp:248:7:248:9 | ref arg m27 | map.cpp:249:7:249:9 | m27 | | +| map.cpp:248:7:248:9 | ref arg m27 | map.cpp:250:7:250:9 | m27 | | +| map.cpp:248:7:248:9 | ref arg m27 | map.cpp:250:23:250:25 | m27 | | +| map.cpp:248:7:248:9 | ref arg m27 | map.cpp:251:7:251:9 | m27 | | +| map.cpp:248:7:248:9 | ref arg m27 | map.cpp:252:1:252:1 | m27 | | +| map.cpp:248:23:248:25 | m27 | map.cpp:248:27:248:31 | call to begin | TAINT | +| map.cpp:248:23:248:25 | ref arg m27 | map.cpp:248:7:248:9 | m27 | | +| map.cpp:248:23:248:25 | ref arg m27 | map.cpp:249:7:249:9 | m27 | | +| map.cpp:248:23:248:25 | ref arg m27 | map.cpp:250:7:250:9 | m27 | | +| map.cpp:248:23:248:25 | ref arg m27 | map.cpp:250:23:250:25 | m27 | | +| map.cpp:248:23:248:25 | ref arg m27 | map.cpp:251:7:251:9 | m27 | | +| map.cpp:248:23:248:25 | ref arg m27 | map.cpp:252:1:252:1 | m27 | | +| map.cpp:248:27:248:31 | call to begin | map.cpp:248:23:248:33 | call to iterator | TAINT | +| map.cpp:248:43:248:47 | def | map.cpp:248:7:248:9 | ref arg m27 | TAINT | +| map.cpp:248:43:248:47 | def | map.cpp:248:11:248:21 | call to try_emplace | TAINT | +| map.cpp:249:7:249:9 | m27 | map.cpp:249:7:249:9 | call to map | | +| map.cpp:250:7:250:9 | m27 | map.cpp:250:11:250:21 | call to try_emplace | TAINT | +| map.cpp:250:7:250:9 | ref arg m27 | map.cpp:251:7:251:9 | m27 | | +| map.cpp:250:7:250:9 | ref arg m27 | map.cpp:252:1:252:1 | m27 | | +| map.cpp:250:23:250:25 | m27 | map.cpp:250:27:250:31 | call to begin | TAINT | +| map.cpp:250:23:250:25 | ref arg m27 | map.cpp:250:7:250:9 | m27 | | +| map.cpp:250:23:250:25 | ref arg m27 | map.cpp:251:7:251:9 | m27 | | +| map.cpp:250:23:250:25 | ref arg m27 | map.cpp:252:1:252:1 | m27 | | +| map.cpp:250:27:250:31 | call to begin | map.cpp:250:23:250:33 | call to iterator | TAINT | +| map.cpp:250:43:250:48 | call to source | map.cpp:250:7:250:9 | ref arg m27 | TAINT | +| map.cpp:250:43:250:48 | call to source | map.cpp:250:11:250:21 | call to try_emplace | TAINT | +| map.cpp:251:7:251:9 | m27 | map.cpp:251:7:251:9 | call to map | | +| map.cpp:257:37:257:38 | call to unordered_map | map.cpp:259:7:259:8 | m1 | | +| map.cpp:257:37:257:38 | call to unordered_map | map.cpp:265:7:265:8 | m1 | | +| map.cpp:257:37:257:38 | call to unordered_map | map.cpp:271:7:271:8 | m1 | | +| map.cpp:257:37:257:38 | call to unordered_map | map.cpp:277:7:277:8 | m1 | | +| map.cpp:257:37:257:38 | call to unordered_map | map.cpp:298:12:298:13 | m1 | | +| map.cpp:257:37:257:38 | call to unordered_map | map.cpp:298:30:298:31 | m1 | | +| map.cpp:257:37:257:38 | call to unordered_map | map.cpp:438:1:438:1 | m1 | | +| map.cpp:257:41:257:42 | call to unordered_map | map.cpp:260:7:260:8 | m2 | | +| map.cpp:257:41:257:42 | call to unordered_map | map.cpp:266:7:266:8 | m2 | | +| map.cpp:257:41:257:42 | call to unordered_map | map.cpp:272:7:272:8 | m2 | | +| map.cpp:257:41:257:42 | call to unordered_map | map.cpp:278:7:278:8 | m2 | | +| map.cpp:257:41:257:42 | call to unordered_map | map.cpp:285:40:285:41 | m2 | | +| map.cpp:257:41:257:42 | call to unordered_map | map.cpp:286:42:286:43 | m2 | | +| map.cpp:257:41:257:42 | call to unordered_map | map.cpp:288:7:288:8 | m2 | | +| map.cpp:257:41:257:42 | call to unordered_map | map.cpp:304:12:304:13 | m2 | | +| map.cpp:257:41:257:42 | call to unordered_map | map.cpp:304:30:304:31 | m2 | | +| map.cpp:257:41:257:42 | call to unordered_map | map.cpp:334:7:334:8 | m2 | | +| map.cpp:257:41:257:42 | call to unordered_map | map.cpp:335:7:335:8 | m2 | | +| map.cpp:257:41:257:42 | call to unordered_map | map.cpp:336:7:336:8 | m2 | | +| map.cpp:257:41:257:42 | call to unordered_map | map.cpp:438:1:438:1 | m2 | | +| map.cpp:257:45:257:46 | call to unordered_map | map.cpp:261:7:261:8 | m3 | | +| map.cpp:257:45:257:46 | call to unordered_map | map.cpp:267:7:267:8 | m3 | | +| map.cpp:257:45:257:46 | call to unordered_map | map.cpp:273:7:273:8 | m3 | | +| map.cpp:257:45:257:46 | call to unordered_map | map.cpp:279:7:279:8 | m3 | | +| map.cpp:257:45:257:46 | call to unordered_map | map.cpp:310:12:310:13 | m3 | | +| map.cpp:257:45:257:46 | call to unordered_map | map.cpp:310:30:310:31 | m3 | | +| map.cpp:257:45:257:46 | call to unordered_map | map.cpp:438:1:438:1 | m3 | | +| map.cpp:257:49:257:50 | call to unordered_map | map.cpp:262:7:262:8 | m4 | | +| map.cpp:257:49:257:50 | call to unordered_map | map.cpp:262:17:262:18 | m4 | | +| map.cpp:257:49:257:50 | call to unordered_map | map.cpp:268:7:268:8 | m4 | | +| map.cpp:257:49:257:50 | call to unordered_map | map.cpp:274:7:274:8 | m4 | | +| map.cpp:257:49:257:50 | call to unordered_map | map.cpp:280:7:280:8 | m4 | | +| map.cpp:257:49:257:50 | call to unordered_map | map.cpp:438:1:438:1 | m4 | | +| map.cpp:257:53:257:54 | call to unordered_map | map.cpp:263:7:263:8 | m5 | | +| map.cpp:257:53:257:54 | call to unordered_map | map.cpp:269:7:269:8 | m5 | | +| map.cpp:257:53:257:54 | call to unordered_map | map.cpp:275:7:275:8 | m5 | | +| map.cpp:257:53:257:54 | call to unordered_map | map.cpp:281:7:281:8 | m5 | | +| map.cpp:257:53:257:54 | call to unordered_map | map.cpp:438:1:438:1 | m5 | | +| map.cpp:257:57:257:58 | call to unordered_map | map.cpp:264:7:264:8 | m6 | | +| map.cpp:257:57:257:58 | call to unordered_map | map.cpp:264:27:264:28 | m6 | | +| map.cpp:257:57:257:58 | call to unordered_map | map.cpp:270:7:270:8 | m6 | | +| map.cpp:257:57:257:58 | call to unordered_map | map.cpp:276:7:276:8 | m6 | | +| map.cpp:257:57:257:58 | call to unordered_map | map.cpp:282:7:282:8 | m6 | | +| map.cpp:257:57:257:58 | call to unordered_map | map.cpp:438:1:438:1 | m6 | | +| map.cpp:259:7:259:8 | ref arg m1 | map.cpp:265:7:265:8 | m1 | | +| map.cpp:259:7:259:8 | ref arg m1 | map.cpp:271:7:271:8 | m1 | | +| map.cpp:259:7:259:8 | ref arg m1 | map.cpp:277:7:277:8 | m1 | | +| map.cpp:259:7:259:8 | ref arg m1 | map.cpp:298:12:298:13 | m1 | | +| map.cpp:259:7:259:8 | ref arg m1 | map.cpp:298:30:298:31 | m1 | | +| map.cpp:259:7:259:8 | ref arg m1 | map.cpp:438:1:438:1 | m1 | | +| map.cpp:259:17:259:30 | call to make_pair | map.cpp:259:17:259:44 | call to pair | TAINT | +| map.cpp:259:17:259:44 | call to pair | map.cpp:259:7:259:8 | ref arg m1 | TAINT | +| map.cpp:259:17:259:44 | call to pair | map.cpp:259:10:259:15 | call to insert | TAINT | +| map.cpp:259:47:259:51 | first | map.cpp:259:7:259:51 | call to iterator | | +| map.cpp:260:7:260:8 | ref arg m2 | map.cpp:266:7:266:8 | m2 | | +| map.cpp:260:7:260:8 | ref arg m2 | map.cpp:272:7:272:8 | m2 | | +| map.cpp:260:7:260:8 | ref arg m2 | map.cpp:278:7:278:8 | m2 | | +| map.cpp:260:7:260:8 | ref arg m2 | map.cpp:285:40:285:41 | m2 | | +| map.cpp:260:7:260:8 | ref arg m2 | map.cpp:286:42:286:43 | m2 | | +| map.cpp:260:7:260:8 | ref arg m2 | map.cpp:288:7:288:8 | m2 | | +| map.cpp:260:7:260:8 | ref arg m2 | map.cpp:304:12:304:13 | m2 | | +| map.cpp:260:7:260:8 | ref arg m2 | map.cpp:304:30:304:31 | m2 | | +| map.cpp:260:7:260:8 | ref arg m2 | map.cpp:334:7:334:8 | m2 | | +| map.cpp:260:7:260:8 | ref arg m2 | map.cpp:335:7:335:8 | m2 | | +| map.cpp:260:7:260:8 | ref arg m2 | map.cpp:336:7:336:8 | m2 | | +| map.cpp:260:7:260:8 | ref arg m2 | map.cpp:438:1:438:1 | m2 | | +| map.cpp:260:17:260:30 | call to make_pair | map.cpp:260:17:260:47 | call to pair | TAINT | +| map.cpp:260:17:260:47 | call to pair | map.cpp:260:7:260:8 | ref arg m2 | TAINT | +| map.cpp:260:17:260:47 | call to pair | map.cpp:260:10:260:15 | call to insert | TAINT | +| map.cpp:260:50:260:54 | first | map.cpp:260:7:260:54 | call to iterator | | +| map.cpp:261:7:261:8 | ref arg m3 | map.cpp:267:7:267:8 | m3 | | +| map.cpp:261:7:261:8 | ref arg m3 | map.cpp:273:7:273:8 | m3 | | +| map.cpp:261:7:261:8 | ref arg m3 | map.cpp:279:7:279:8 | m3 | | +| map.cpp:261:7:261:8 | ref arg m3 | map.cpp:310:12:310:13 | m3 | | +| map.cpp:261:7:261:8 | ref arg m3 | map.cpp:310:30:310:31 | m3 | | +| map.cpp:261:7:261:8 | ref arg m3 | map.cpp:438:1:438:1 | m3 | | +| map.cpp:261:17:261:30 | call to make_pair | map.cpp:261:17:261:47 | call to pair | TAINT | +| map.cpp:261:17:261:47 | call to pair | map.cpp:261:7:261:8 | ref arg m3 | TAINT | +| map.cpp:261:17:261:47 | call to pair | map.cpp:261:10:261:15 | call to insert | TAINT | +| map.cpp:261:50:261:54 | first | map.cpp:261:7:261:54 | call to iterator | | +| map.cpp:262:7:262:8 | ref arg m4 | map.cpp:268:7:268:8 | m4 | | +| map.cpp:262:7:262:8 | ref arg m4 | map.cpp:274:7:274:8 | m4 | | +| map.cpp:262:7:262:8 | ref arg m4 | map.cpp:280:7:280:8 | m4 | | +| map.cpp:262:7:262:8 | ref arg m4 | map.cpp:438:1:438:1 | m4 | | +| map.cpp:262:17:262:18 | m4 | map.cpp:262:20:262:24 | call to begin | TAINT | +| map.cpp:262:17:262:18 | ref arg m4 | map.cpp:262:7:262:8 | m4 | | +| map.cpp:262:17:262:18 | ref arg m4 | map.cpp:268:7:268:8 | m4 | | +| map.cpp:262:17:262:18 | ref arg m4 | map.cpp:274:7:274:8 | m4 | | +| map.cpp:262:17:262:18 | ref arg m4 | map.cpp:280:7:280:8 | m4 | | +| map.cpp:262:17:262:18 | ref arg m4 | map.cpp:438:1:438:1 | m4 | | +| map.cpp:262:20:262:24 | call to begin | map.cpp:262:17:262:26 | call to iterator | TAINT | +| map.cpp:262:29:262:70 | call to pair | map.cpp:262:7:262:8 | ref arg m4 | TAINT | +| map.cpp:262:29:262:70 | call to pair | map.cpp:262:10:262:15 | call to insert | TAINT | +| map.cpp:262:29:262:70 | call to pair | map.cpp:262:29:262:70 | call to pair | TAINT | +| map.cpp:262:62:262:67 | call to source | map.cpp:262:29:262:70 | call to pair | TAINT | +| map.cpp:263:7:263:8 | ref arg m5 | map.cpp:269:7:269:8 | m5 | | +| map.cpp:263:7:263:8 | ref arg m5 | map.cpp:275:7:275:8 | m5 | | +| map.cpp:263:7:263:8 | ref arg m5 | map.cpp:281:7:281:8 | m5 | | +| map.cpp:263:7:263:8 | ref arg m5 | map.cpp:438:1:438:1 | m5 | | +| map.cpp:263:34:263:39 | call to source | map.cpp:263:7:263:8 | ref arg m5 | TAINT | +| map.cpp:263:34:263:39 | call to source | map.cpp:263:10:263:25 | call to insert_or_assign | TAINT | +| map.cpp:263:44:263:48 | first | map.cpp:263:7:263:48 | call to iterator | | +| map.cpp:264:7:264:8 | ref arg m6 | map.cpp:270:7:270:8 | m6 | | +| map.cpp:264:7:264:8 | ref arg m6 | map.cpp:276:7:276:8 | m6 | | +| map.cpp:264:7:264:8 | ref arg m6 | map.cpp:282:7:282:8 | m6 | | +| map.cpp:264:7:264:8 | ref arg m6 | map.cpp:438:1:438:1 | m6 | | +| map.cpp:264:27:264:28 | m6 | map.cpp:264:30:264:34 | call to begin | TAINT | +| map.cpp:264:27:264:28 | ref arg m6 | map.cpp:264:7:264:8 | m6 | | +| map.cpp:264:27:264:28 | ref arg m6 | map.cpp:270:7:270:8 | m6 | | +| map.cpp:264:27:264:28 | ref arg m6 | map.cpp:276:7:276:8 | m6 | | +| map.cpp:264:27:264:28 | ref arg m6 | map.cpp:282:7:282:8 | m6 | | +| map.cpp:264:27:264:28 | ref arg m6 | map.cpp:438:1:438:1 | m6 | | +| map.cpp:264:30:264:34 | call to begin | map.cpp:264:27:264:36 | call to iterator | TAINT | +| map.cpp:264:46:264:51 | call to source | map.cpp:264:7:264:8 | ref arg m6 | TAINT | +| map.cpp:264:46:264:51 | call to source | map.cpp:264:10:264:25 | call to insert_or_assign | TAINT | +| map.cpp:265:7:265:8 | m1 | map.cpp:265:7:265:8 | call to unordered_map | | +| map.cpp:266:7:266:8 | m2 | map.cpp:266:7:266:8 | call to unordered_map | | +| map.cpp:267:7:267:8 | m3 | map.cpp:267:7:267:8 | call to unordered_map | | +| map.cpp:268:7:268:8 | m4 | map.cpp:268:7:268:8 | call to unordered_map | | +| map.cpp:269:7:269:8 | m5 | map.cpp:269:7:269:8 | call to unordered_map | | +| map.cpp:270:7:270:8 | m6 | map.cpp:270:7:270:8 | call to unordered_map | | +| map.cpp:271:7:271:8 | m1 | map.cpp:271:10:271:13 | call to find | TAINT | +| map.cpp:271:7:271:8 | ref arg m1 | map.cpp:277:7:277:8 | m1 | | +| map.cpp:271:7:271:8 | ref arg m1 | map.cpp:298:12:298:13 | m1 | | +| map.cpp:271:7:271:8 | ref arg m1 | map.cpp:298:30:298:31 | m1 | | +| map.cpp:271:7:271:8 | ref arg m1 | map.cpp:438:1:438:1 | m1 | | +| map.cpp:272:7:272:8 | m2 | map.cpp:272:10:272:13 | call to find | TAINT | +| map.cpp:272:7:272:8 | ref arg m2 | map.cpp:278:7:278:8 | m2 | | +| map.cpp:272:7:272:8 | ref arg m2 | map.cpp:285:40:285:41 | m2 | | +| map.cpp:272:7:272:8 | ref arg m2 | map.cpp:286:42:286:43 | m2 | | +| map.cpp:272:7:272:8 | ref arg m2 | map.cpp:288:7:288:8 | m2 | | +| map.cpp:272:7:272:8 | ref arg m2 | map.cpp:304:12:304:13 | m2 | | +| map.cpp:272:7:272:8 | ref arg m2 | map.cpp:304:30:304:31 | m2 | | +| map.cpp:272:7:272:8 | ref arg m2 | map.cpp:334:7:334:8 | m2 | | +| map.cpp:272:7:272:8 | ref arg m2 | map.cpp:335:7:335:8 | m2 | | +| map.cpp:272:7:272:8 | ref arg m2 | map.cpp:336:7:336:8 | m2 | | +| map.cpp:272:7:272:8 | ref arg m2 | map.cpp:438:1:438:1 | m2 | | +| map.cpp:273:7:273:8 | m3 | map.cpp:273:10:273:13 | call to find | TAINT | +| map.cpp:273:7:273:8 | ref arg m3 | map.cpp:279:7:279:8 | m3 | | +| map.cpp:273:7:273:8 | ref arg m3 | map.cpp:310:12:310:13 | m3 | | +| map.cpp:273:7:273:8 | ref arg m3 | map.cpp:310:30:310:31 | m3 | | +| map.cpp:273:7:273:8 | ref arg m3 | map.cpp:438:1:438:1 | m3 | | +| map.cpp:274:7:274:8 | m4 | map.cpp:274:10:274:13 | call to find | TAINT | +| map.cpp:274:7:274:8 | ref arg m4 | map.cpp:280:7:280:8 | m4 | | +| map.cpp:274:7:274:8 | ref arg m4 | map.cpp:438:1:438:1 | m4 | | +| map.cpp:275:7:275:8 | m5 | map.cpp:275:10:275:13 | call to find | TAINT | +| map.cpp:275:7:275:8 | ref arg m5 | map.cpp:281:7:281:8 | m5 | | +| map.cpp:275:7:275:8 | ref arg m5 | map.cpp:438:1:438:1 | m5 | | +| map.cpp:276:7:276:8 | m6 | map.cpp:276:10:276:13 | call to find | TAINT | +| map.cpp:276:7:276:8 | ref arg m6 | map.cpp:282:7:282:8 | m6 | | +| map.cpp:276:7:276:8 | ref arg m6 | map.cpp:438:1:438:1 | m6 | | +| map.cpp:277:7:277:8 | m1 | map.cpp:277:10:277:13 | call to find | TAINT | +| map.cpp:277:7:277:8 | ref arg m1 | map.cpp:298:12:298:13 | m1 | | +| map.cpp:277:7:277:8 | ref arg m1 | map.cpp:298:30:298:31 | m1 | | +| map.cpp:277:7:277:8 | ref arg m1 | map.cpp:438:1:438:1 | m1 | | +| map.cpp:278:7:278:8 | m2 | map.cpp:278:10:278:13 | call to find | TAINT | +| map.cpp:278:7:278:8 | ref arg m2 | map.cpp:285:40:285:41 | m2 | | +| map.cpp:278:7:278:8 | ref arg m2 | map.cpp:286:42:286:43 | m2 | | +| map.cpp:278:7:278:8 | ref arg m2 | map.cpp:288:7:288:8 | m2 | | +| map.cpp:278:7:278:8 | ref arg m2 | map.cpp:304:12:304:13 | m2 | | +| map.cpp:278:7:278:8 | ref arg m2 | map.cpp:304:30:304:31 | m2 | | +| map.cpp:278:7:278:8 | ref arg m2 | map.cpp:334:7:334:8 | m2 | | +| map.cpp:278:7:278:8 | ref arg m2 | map.cpp:335:7:335:8 | m2 | | +| map.cpp:278:7:278:8 | ref arg m2 | map.cpp:336:7:336:8 | m2 | | +| map.cpp:278:7:278:8 | ref arg m2 | map.cpp:438:1:438:1 | m2 | | +| map.cpp:279:7:279:8 | m3 | map.cpp:279:10:279:13 | call to find | TAINT | +| map.cpp:279:7:279:8 | ref arg m3 | map.cpp:310:12:310:13 | m3 | | +| map.cpp:279:7:279:8 | ref arg m3 | map.cpp:310:30:310:31 | m3 | | +| map.cpp:279:7:279:8 | ref arg m3 | map.cpp:438:1:438:1 | m3 | | +| map.cpp:280:7:280:8 | m4 | map.cpp:280:10:280:13 | call to find | TAINT | +| map.cpp:280:7:280:8 | ref arg m4 | map.cpp:438:1:438:1 | m4 | | +| map.cpp:281:7:281:8 | m5 | map.cpp:281:10:281:13 | call to find | TAINT | +| map.cpp:281:7:281:8 | ref arg m5 | map.cpp:438:1:438:1 | m5 | | +| map.cpp:282:7:282:8 | m6 | map.cpp:282:10:282:13 | call to find | TAINT | +| map.cpp:282:7:282:8 | ref arg m6 | map.cpp:438:1:438:1 | m6 | | +| map.cpp:285:40:285:41 | m2 | map.cpp:285:40:285:42 | call to unordered_map | | +| map.cpp:285:40:285:42 | call to unordered_map | map.cpp:289:7:289:8 | m7 | | +| map.cpp:285:40:285:42 | call to unordered_map | map.cpp:292:7:292:8 | m7 | | +| map.cpp:285:40:285:42 | call to unordered_map | map.cpp:438:1:438:1 | m7 | | +| map.cpp:286:41:286:43 | call to unordered_map | map.cpp:290:7:290:8 | m8 | | +| map.cpp:286:41:286:43 | call to unordered_map | map.cpp:293:7:293:8 | m8 | | +| map.cpp:286:41:286:43 | call to unordered_map | map.cpp:438:1:438:1 | m8 | | +| map.cpp:286:42:286:43 | m2 | map.cpp:286:41:286:43 | call to unordered_map | | +| map.cpp:287:37:287:38 | call to unordered_map | map.cpp:288:2:288:3 | m9 | | +| map.cpp:287:37:287:38 | call to unordered_map | map.cpp:291:7:291:8 | m9 | | +| map.cpp:287:37:287:38 | call to unordered_map | map.cpp:294:7:294:8 | m9 | | +| map.cpp:287:37:287:38 | call to unordered_map | map.cpp:438:1:438:1 | m9 | | +| map.cpp:288:2:288:3 | ref arg m9 | map.cpp:291:7:291:8 | m9 | | +| map.cpp:288:2:288:3 | ref arg m9 | map.cpp:294:7:294:8 | m9 | | +| map.cpp:288:2:288:3 | ref arg m9 | map.cpp:438:1:438:1 | m9 | | +| map.cpp:288:7:288:8 | m2 | map.cpp:288:2:288:3 | ref arg m9 | TAINT | +| map.cpp:288:7:288:8 | m2 | map.cpp:288:5:288:5 | call to operator= | TAINT | +| map.cpp:289:7:289:8 | m7 | map.cpp:289:7:289:8 | call to unordered_map | | +| map.cpp:290:7:290:8 | m8 | map.cpp:290:7:290:8 | call to unordered_map | | +| map.cpp:291:7:291:8 | m9 | map.cpp:291:7:291:8 | call to unordered_map | | +| map.cpp:292:7:292:8 | m7 | map.cpp:292:10:292:13 | call to find | TAINT | +| map.cpp:292:7:292:8 | ref arg m7 | map.cpp:438:1:438:1 | m7 | | +| map.cpp:293:7:293:8 | m8 | map.cpp:293:10:293:13 | call to find | TAINT | +| map.cpp:293:7:293:8 | ref arg m8 | map.cpp:438:1:438:1 | m8 | | +| map.cpp:294:7:294:8 | m9 | map.cpp:294:10:294:13 | call to find | TAINT | +| map.cpp:294:7:294:8 | ref arg m9 | map.cpp:438:1:438:1 | m9 | | +| map.cpp:298:12:298:13 | m1 | map.cpp:298:15:298:19 | call to begin | TAINT | +| map.cpp:298:12:298:13 | ref arg m1 | map.cpp:298:30:298:31 | m1 | | +| map.cpp:298:12:298:13 | ref arg m1 | map.cpp:438:1:438:1 | m1 | | +| map.cpp:298:15:298:19 | call to begin | map.cpp:298:7:298:21 | ... = ... | | +| map.cpp:298:15:298:19 | call to begin | map.cpp:298:24:298:25 | i1 | | +| map.cpp:298:15:298:19 | call to begin | map.cpp:298:40:298:41 | i1 | | +| map.cpp:298:15:298:19 | call to begin | map.cpp:300:9:300:10 | i1 | | +| map.cpp:298:15:298:19 | call to begin | map.cpp:301:8:301:9 | i1 | | +| map.cpp:298:15:298:19 | call to begin | map.cpp:302:8:302:9 | i1 | | +| map.cpp:298:30:298:31 | m1 | map.cpp:298:33:298:35 | call to end | TAINT | +| map.cpp:298:30:298:31 | ref arg m1 | map.cpp:298:30:298:31 | m1 | | +| map.cpp:298:30:298:31 | ref arg m1 | map.cpp:438:1:438:1 | m1 | | +| map.cpp:298:40:298:41 | i1 | map.cpp:298:42:298:42 | call to operator++ | | +| map.cpp:298:40:298:41 | ref arg i1 | map.cpp:298:24:298:25 | i1 | | +| map.cpp:298:40:298:41 | ref arg i1 | map.cpp:298:40:298:41 | i1 | | +| map.cpp:298:40:298:41 | ref arg i1 | map.cpp:300:9:300:10 | i1 | | +| map.cpp:298:40:298:41 | ref arg i1 | map.cpp:301:8:301:9 | i1 | | +| map.cpp:298:40:298:41 | ref arg i1 | map.cpp:302:8:302:9 | i1 | | +| map.cpp:300:8:300:8 | call to operator* | map.cpp:300:8:300:10 | call to pair | TAINT | +| map.cpp:300:9:300:10 | i1 | map.cpp:300:8:300:8 | call to operator* | TAINT | +| map.cpp:301:8:301:9 | i1 | map.cpp:301:10:301:10 | call to operator-> | TAINT | +| map.cpp:302:8:302:9 | i1 | map.cpp:302:10:302:10 | call to operator-> | TAINT | +| map.cpp:304:12:304:13 | m2 | map.cpp:304:15:304:19 | call to begin | TAINT | +| map.cpp:304:12:304:13 | ref arg m2 | map.cpp:304:30:304:31 | m2 | | +| map.cpp:304:12:304:13 | ref arg m2 | map.cpp:334:7:334:8 | m2 | | +| map.cpp:304:12:304:13 | ref arg m2 | map.cpp:335:7:335:8 | m2 | | +| map.cpp:304:12:304:13 | ref arg m2 | map.cpp:336:7:336:8 | m2 | | +| map.cpp:304:12:304:13 | ref arg m2 | map.cpp:438:1:438:1 | m2 | | +| map.cpp:304:15:304:19 | call to begin | map.cpp:304:7:304:21 | ... = ... | | +| map.cpp:304:15:304:19 | call to begin | map.cpp:304:24:304:25 | i2 | | +| map.cpp:304:15:304:19 | call to begin | map.cpp:304:40:304:41 | i2 | | +| map.cpp:304:15:304:19 | call to begin | map.cpp:306:9:306:10 | i2 | | +| map.cpp:304:15:304:19 | call to begin | map.cpp:307:8:307:9 | i2 | | +| map.cpp:304:15:304:19 | call to begin | map.cpp:308:8:308:9 | i2 | | +| map.cpp:304:15:304:19 | call to begin | map.cpp:313:8:313:9 | i2 | | +| map.cpp:304:15:304:19 | call to begin | map.cpp:314:8:314:9 | i2 | | +| map.cpp:304:30:304:31 | m2 | map.cpp:304:33:304:35 | call to end | TAINT | +| map.cpp:304:30:304:31 | ref arg m2 | map.cpp:304:30:304:31 | m2 | | +| map.cpp:304:30:304:31 | ref arg m2 | map.cpp:334:7:334:8 | m2 | | +| map.cpp:304:30:304:31 | ref arg m2 | map.cpp:335:7:335:8 | m2 | | +| map.cpp:304:30:304:31 | ref arg m2 | map.cpp:336:7:336:8 | m2 | | +| map.cpp:304:30:304:31 | ref arg m2 | map.cpp:438:1:438:1 | m2 | | +| map.cpp:304:40:304:41 | i2 | map.cpp:304:42:304:42 | call to operator++ | | +| map.cpp:304:40:304:41 | ref arg i2 | map.cpp:304:24:304:25 | i2 | | +| map.cpp:304:40:304:41 | ref arg i2 | map.cpp:304:40:304:41 | i2 | | +| map.cpp:304:40:304:41 | ref arg i2 | map.cpp:306:9:306:10 | i2 | | +| map.cpp:304:40:304:41 | ref arg i2 | map.cpp:307:8:307:9 | i2 | | +| map.cpp:304:40:304:41 | ref arg i2 | map.cpp:308:8:308:9 | i2 | | +| map.cpp:304:40:304:41 | ref arg i2 | map.cpp:313:8:313:9 | i2 | | +| map.cpp:304:40:304:41 | ref arg i2 | map.cpp:314:8:314:9 | i2 | | +| map.cpp:306:8:306:8 | call to operator* | map.cpp:306:8:306:10 | call to pair | TAINT | +| map.cpp:306:9:306:10 | i2 | map.cpp:306:8:306:8 | call to operator* | TAINT | +| map.cpp:307:8:307:9 | i2 | map.cpp:307:10:307:10 | call to operator-> | TAINT | +| map.cpp:308:8:308:9 | i2 | map.cpp:308:10:308:10 | call to operator-> | TAINT | +| map.cpp:310:12:310:13 | m3 | map.cpp:310:15:310:19 | call to begin | TAINT | +| map.cpp:310:12:310:13 | ref arg m3 | map.cpp:310:30:310:31 | m3 | | +| map.cpp:310:12:310:13 | ref arg m3 | map.cpp:438:1:438:1 | m3 | | +| map.cpp:310:15:310:19 | call to begin | map.cpp:310:7:310:21 | ... = ... | | +| map.cpp:310:15:310:19 | call to begin | map.cpp:310:24:310:25 | i3 | | +| map.cpp:310:15:310:19 | call to begin | map.cpp:310:40:310:41 | i3 | | +| map.cpp:310:15:310:19 | call to begin | map.cpp:312:9:312:10 | i3 | | +| map.cpp:310:30:310:31 | m3 | map.cpp:310:33:310:35 | call to end | TAINT | +| map.cpp:310:30:310:31 | ref arg m3 | map.cpp:310:30:310:31 | m3 | | +| map.cpp:310:30:310:31 | ref arg m3 | map.cpp:438:1:438:1 | m3 | | +| map.cpp:310:40:310:41 | i3 | map.cpp:310:42:310:42 | call to operator++ | | +| map.cpp:310:40:310:41 | ref arg i3 | map.cpp:310:24:310:25 | i3 | | +| map.cpp:310:40:310:41 | ref arg i3 | map.cpp:310:40:310:41 | i3 | | +| map.cpp:310:40:310:41 | ref arg i3 | map.cpp:312:9:312:10 | i3 | | +| map.cpp:312:8:312:8 | call to operator* | map.cpp:312:8:312:10 | call to pair | TAINT | +| map.cpp:312:9:312:10 | i3 | map.cpp:312:8:312:8 | call to operator* | TAINT | +| map.cpp:313:8:313:9 | i2 | map.cpp:313:10:313:10 | call to operator-> | TAINT | +| map.cpp:314:8:314:9 | i2 | map.cpp:314:10:314:10 | call to operator-> | TAINT | +| map.cpp:318:37:318:39 | call to unordered_map | map.cpp:319:7:319:9 | m10 | | +| map.cpp:318:37:318:39 | call to unordered_map | map.cpp:323:7:323:9 | m10 | | +| map.cpp:318:37:318:39 | call to unordered_map | map.cpp:438:1:438:1 | m10 | | +| map.cpp:318:42:318:44 | call to unordered_map | map.cpp:320:7:320:9 | m11 | | +| map.cpp:318:42:318:44 | call to unordered_map | map.cpp:324:7:324:9 | m11 | | +| map.cpp:318:42:318:44 | call to unordered_map | map.cpp:438:1:438:1 | m11 | | +| map.cpp:318:47:318:49 | call to unordered_map | map.cpp:321:7:321:9 | m12 | | +| map.cpp:318:47:318:49 | call to unordered_map | map.cpp:325:7:325:9 | m12 | | +| map.cpp:318:47:318:49 | call to unordered_map | map.cpp:438:1:438:1 | m12 | | +| map.cpp:318:52:318:54 | call to unordered_map | map.cpp:322:7:322:9 | m13 | | +| map.cpp:318:52:318:54 | call to unordered_map | map.cpp:326:7:326:9 | m13 | | +| map.cpp:318:52:318:54 | call to unordered_map | map.cpp:438:1:438:1 | m13 | | +| map.cpp:319:7:319:9 | m10 | map.cpp:319:10:319:10 | call to operator[] | TAINT | +| map.cpp:319:7:319:9 | ref arg m10 | map.cpp:323:7:323:9 | m10 | | +| map.cpp:319:7:319:9 | ref arg m10 | map.cpp:438:1:438:1 | m10 | | +| map.cpp:319:7:319:24 | ... = ... | map.cpp:319:10:319:10 | call to operator[] [post update] | | +| map.cpp:319:10:319:10 | call to operator[] [post update] | map.cpp:319:7:319:9 | ref arg m10 | TAINT | +| map.cpp:319:20:319:24 | def | map.cpp:319:7:319:24 | ... = ... | | +| map.cpp:320:7:320:9 | m11 | map.cpp:320:10:320:10 | call to operator[] | TAINT | +| map.cpp:320:7:320:9 | ref arg m11 | map.cpp:324:7:324:9 | m11 | | +| map.cpp:320:7:320:9 | ref arg m11 | map.cpp:438:1:438:1 | m11 | | +| map.cpp:320:7:320:27 | ... = ... | map.cpp:320:10:320:10 | call to operator[] [post update] | | +| map.cpp:320:10:320:10 | call to operator[] [post update] | map.cpp:320:7:320:9 | ref arg m11 | TAINT | +| map.cpp:320:20:320:25 | call to source | map.cpp:320:7:320:27 | ... = ... | | +| map.cpp:321:7:321:9 | m12 | map.cpp:321:11:321:12 | call to at | TAINT | +| map.cpp:321:7:321:9 | ref arg m12 | map.cpp:325:7:325:9 | m12 | | +| map.cpp:321:7:321:9 | ref arg m12 | map.cpp:438:1:438:1 | m12 | | +| map.cpp:321:7:321:27 | ... = ... | map.cpp:321:11:321:12 | call to at [post update] | | +| map.cpp:321:11:321:12 | call to at [post update] | map.cpp:321:7:321:9 | ref arg m12 | TAINT | +| map.cpp:321:23:321:27 | def | map.cpp:321:7:321:27 | ... = ... | | +| map.cpp:322:7:322:9 | m13 | map.cpp:322:11:322:12 | call to at | TAINT | +| map.cpp:322:7:322:9 | ref arg m13 | map.cpp:326:7:326:9 | m13 | | +| map.cpp:322:7:322:9 | ref arg m13 | map.cpp:438:1:438:1 | m13 | | +| map.cpp:322:7:322:30 | ... = ... | map.cpp:322:11:322:12 | call to at [post update] | | +| map.cpp:322:11:322:12 | call to at [post update] | map.cpp:322:7:322:9 | ref arg m13 | TAINT | +| map.cpp:322:23:322:28 | call to source | map.cpp:322:7:322:30 | ... = ... | | +| map.cpp:323:7:323:9 | m10 | map.cpp:323:10:323:10 | call to operator[] | TAINT | +| map.cpp:323:7:323:9 | ref arg m10 | map.cpp:438:1:438:1 | m10 | | +| map.cpp:324:7:324:9 | m11 | map.cpp:324:10:324:10 | call to operator[] | TAINT | +| map.cpp:324:7:324:9 | ref arg m11 | map.cpp:438:1:438:1 | m11 | | +| map.cpp:325:7:325:9 | m12 | map.cpp:325:10:325:10 | call to operator[] | TAINT | +| map.cpp:325:7:325:9 | ref arg m12 | map.cpp:438:1:438:1 | m12 | | +| map.cpp:326:7:326:9 | m13 | map.cpp:326:10:326:10 | call to operator[] | TAINT | +| map.cpp:326:7:326:9 | ref arg m13 | map.cpp:438:1:438:1 | m13 | | +| map.cpp:329:37:329:39 | call to unordered_map | map.cpp:330:2:330:4 | m14 | | +| map.cpp:329:37:329:39 | call to unordered_map | map.cpp:331:2:331:4 | m14 | | +| map.cpp:329:37:329:39 | call to unordered_map | map.cpp:332:2:332:4 | m14 | | +| map.cpp:329:37:329:39 | call to unordered_map | map.cpp:333:2:333:4 | m14 | | +| map.cpp:329:37:329:39 | call to unordered_map | map.cpp:438:1:438:1 | m14 | | +| map.cpp:330:2:330:4 | ref arg m14 | map.cpp:331:2:331:4 | m14 | | +| map.cpp:330:2:330:4 | ref arg m14 | map.cpp:332:2:332:4 | m14 | | +| map.cpp:330:2:330:4 | ref arg m14 | map.cpp:333:2:333:4 | m14 | | +| map.cpp:330:2:330:4 | ref arg m14 | map.cpp:438:1:438:1 | m14 | | +| map.cpp:330:13:330:26 | call to make_pair | map.cpp:330:13:330:36 | call to pair | TAINT | +| map.cpp:330:13:330:36 | call to pair | map.cpp:330:2:330:4 | ref arg m14 | TAINT | +| map.cpp:330:13:330:36 | call to pair | map.cpp:330:6:330:11 | call to insert | TAINT | +| map.cpp:331:2:331:4 | ref arg m14 | map.cpp:332:2:332:4 | m14 | | +| map.cpp:331:2:331:4 | ref arg m14 | map.cpp:333:2:333:4 | m14 | | +| map.cpp:331:2:331:4 | ref arg m14 | map.cpp:438:1:438:1 | m14 | | +| map.cpp:331:13:331:26 | call to make_pair | map.cpp:331:13:331:41 | call to pair | TAINT | +| map.cpp:331:13:331:41 | call to pair | map.cpp:331:2:331:4 | ref arg m14 | TAINT | +| map.cpp:331:13:331:41 | call to pair | map.cpp:331:6:331:11 | call to insert | TAINT | +| map.cpp:332:2:332:4 | ref arg m14 | map.cpp:333:2:333:4 | m14 | | +| map.cpp:332:2:332:4 | ref arg m14 | map.cpp:438:1:438:1 | m14 | | +| map.cpp:332:13:332:26 | call to make_pair | map.cpp:332:13:332:41 | call to pair | TAINT | +| map.cpp:332:13:332:41 | call to pair | map.cpp:332:2:332:4 | ref arg m14 | TAINT | +| map.cpp:332:13:332:41 | call to pair | map.cpp:332:6:332:11 | call to insert | TAINT | +| map.cpp:333:2:333:4 | ref arg m14 | map.cpp:438:1:438:1 | m14 | | +| map.cpp:333:13:333:26 | call to make_pair | map.cpp:333:13:333:36 | call to pair | TAINT | +| map.cpp:333:13:333:36 | call to pair | map.cpp:333:2:333:4 | ref arg m14 | TAINT | +| map.cpp:333:13:333:36 | call to pair | map.cpp:333:6:333:11 | call to insert | TAINT | +| map.cpp:334:7:334:8 | m2 | map.cpp:334:10:334:20 | call to equal_range | TAINT | +| map.cpp:334:7:334:8 | ref arg m2 | map.cpp:335:7:335:8 | m2 | | +| map.cpp:334:7:334:8 | ref arg m2 | map.cpp:336:7:336:8 | m2 | | +| map.cpp:334:7:334:8 | ref arg m2 | map.cpp:438:1:438:1 | m2 | | +| map.cpp:334:27:334:31 | first | map.cpp:334:7:334:31 | call to iterator | | +| map.cpp:335:7:335:8 | m2 | map.cpp:335:10:335:20 | call to equal_range | TAINT | +| map.cpp:335:7:335:8 | ref arg m2 | map.cpp:336:7:336:8 | m2 | | +| map.cpp:335:7:335:8 | ref arg m2 | map.cpp:438:1:438:1 | m2 | | +| map.cpp:335:27:335:32 | second | map.cpp:335:7:335:32 | call to iterator | | +| map.cpp:336:7:336:8 | m2 | map.cpp:336:10:336:20 | call to equal_range | TAINT | +| map.cpp:336:7:336:8 | ref arg m2 | map.cpp:438:1:438:1 | m2 | | +| map.cpp:336:27:336:32 | second | map.cpp:336:7:336:32 | call to iterator | | +| map.cpp:339:37:339:39 | call to unordered_map | map.cpp:340:2:340:4 | m15 | | +| map.cpp:339:37:339:39 | call to unordered_map | map.cpp:342:7:342:9 | m15 | | +| map.cpp:339:37:339:39 | call to unordered_map | map.cpp:346:2:346:4 | m15 | | +| map.cpp:339:37:339:39 | call to unordered_map | map.cpp:348:7:348:9 | m15 | | +| map.cpp:339:37:339:39 | call to unordered_map | map.cpp:438:1:438:1 | m15 | | +| map.cpp:339:42:339:44 | call to unordered_map | map.cpp:343:7:343:9 | m16 | | +| map.cpp:339:42:339:44 | call to unordered_map | map.cpp:346:11:346:13 | m16 | | +| map.cpp:339:42:339:44 | call to unordered_map | map.cpp:349:7:349:9 | m16 | | +| map.cpp:339:42:339:44 | call to unordered_map | map.cpp:438:1:438:1 | m16 | | +| map.cpp:339:47:339:49 | call to unordered_map | map.cpp:344:7:344:9 | m17 | | +| map.cpp:339:47:339:49 | call to unordered_map | map.cpp:347:2:347:4 | m17 | | +| map.cpp:339:47:339:49 | call to unordered_map | map.cpp:350:7:350:9 | m17 | | +| map.cpp:339:47:339:49 | call to unordered_map | map.cpp:438:1:438:1 | m17 | | +| map.cpp:339:52:339:54 | call to unordered_map | map.cpp:341:2:341:4 | m18 | | +| map.cpp:339:52:339:54 | call to unordered_map | map.cpp:345:7:345:9 | m18 | | +| map.cpp:339:52:339:54 | call to unordered_map | map.cpp:347:11:347:13 | m18 | | +| map.cpp:339:52:339:54 | call to unordered_map | map.cpp:351:7:351:9 | m18 | | +| map.cpp:339:52:339:54 | call to unordered_map | map.cpp:438:1:438:1 | m18 | | +| map.cpp:340:2:340:4 | ref arg m15 | map.cpp:342:7:342:9 | m15 | | +| map.cpp:340:2:340:4 | ref arg m15 | map.cpp:346:2:346:4 | m15 | | +| map.cpp:340:2:340:4 | ref arg m15 | map.cpp:348:7:348:9 | m15 | | +| map.cpp:340:2:340:4 | ref arg m15 | map.cpp:438:1:438:1 | m15 | | +| map.cpp:340:13:340:57 | call to pair | map.cpp:340:2:340:4 | ref arg m15 | TAINT | +| map.cpp:340:13:340:57 | call to pair | map.cpp:340:6:340:11 | call to insert | TAINT | +| map.cpp:340:13:340:57 | call to pair | map.cpp:340:13:340:57 | call to pair | TAINT | +| map.cpp:340:49:340:54 | call to source | map.cpp:340:13:340:57 | call to pair | TAINT | +| map.cpp:341:2:341:4 | ref arg m18 | map.cpp:345:7:345:9 | m18 | | +| map.cpp:341:2:341:4 | ref arg m18 | map.cpp:347:11:347:13 | m18 | | +| map.cpp:341:2:341:4 | ref arg m18 | map.cpp:351:7:351:9 | m18 | | +| map.cpp:341:2:341:4 | ref arg m18 | map.cpp:438:1:438:1 | m18 | | +| map.cpp:341:13:341:57 | call to pair | map.cpp:341:2:341:4 | ref arg m18 | TAINT | +| map.cpp:341:13:341:57 | call to pair | map.cpp:341:6:341:11 | call to insert | TAINT | +| map.cpp:341:13:341:57 | call to pair | map.cpp:341:13:341:57 | call to pair | TAINT | +| map.cpp:341:49:341:54 | call to source | map.cpp:341:13:341:57 | call to pair | TAINT | +| map.cpp:342:7:342:9 | m15 | map.cpp:342:7:342:9 | call to unordered_map | | +| map.cpp:343:7:343:9 | m16 | map.cpp:343:7:343:9 | call to unordered_map | | +| map.cpp:344:7:344:9 | m17 | map.cpp:344:7:344:9 | call to unordered_map | | +| map.cpp:345:7:345:9 | m18 | map.cpp:345:7:345:9 | call to unordered_map | | +| map.cpp:346:2:346:4 | m15 | map.cpp:346:11:346:13 | ref arg m16 | TAINT | +| map.cpp:346:2:346:4 | ref arg m15 | map.cpp:348:7:348:9 | m15 | | +| map.cpp:346:2:346:4 | ref arg m15 | map.cpp:438:1:438:1 | m15 | | +| map.cpp:346:11:346:13 | m16 | map.cpp:346:2:346:4 | ref arg m15 | TAINT | +| map.cpp:346:11:346:13 | ref arg m16 | map.cpp:349:7:349:9 | m16 | | +| map.cpp:346:11:346:13 | ref arg m16 | map.cpp:438:1:438:1 | m16 | | +| map.cpp:347:2:347:4 | m17 | map.cpp:347:11:347:13 | ref arg m18 | TAINT | +| map.cpp:347:2:347:4 | ref arg m17 | map.cpp:350:7:350:9 | m17 | | +| map.cpp:347:2:347:4 | ref arg m17 | map.cpp:438:1:438:1 | m17 | | +| map.cpp:347:11:347:13 | m18 | map.cpp:347:2:347:4 | ref arg m17 | TAINT | +| map.cpp:347:11:347:13 | ref arg m18 | map.cpp:351:7:351:9 | m18 | | +| map.cpp:347:11:347:13 | ref arg m18 | map.cpp:438:1:438:1 | m18 | | +| map.cpp:348:7:348:9 | m15 | map.cpp:348:7:348:9 | call to unordered_map | | +| map.cpp:349:7:349:9 | m16 | map.cpp:349:7:349:9 | call to unordered_map | | +| map.cpp:350:7:350:9 | m17 | map.cpp:350:7:350:9 | call to unordered_map | | +| map.cpp:351:7:351:9 | m18 | map.cpp:351:7:351:9 | call to unordered_map | | +| map.cpp:354:37:354:39 | call to unordered_map | map.cpp:355:2:355:4 | m19 | | +| map.cpp:354:37:354:39 | call to unordered_map | map.cpp:359:7:359:9 | m19 | | +| map.cpp:354:37:354:39 | call to unordered_map | map.cpp:363:2:363:4 | m19 | | +| map.cpp:354:37:354:39 | call to unordered_map | map.cpp:365:7:365:9 | m19 | | +| map.cpp:354:37:354:39 | call to unordered_map | map.cpp:438:1:438:1 | m19 | | +| map.cpp:354:42:354:44 | call to unordered_map | map.cpp:356:2:356:4 | m20 | | +| map.cpp:354:42:354:44 | call to unordered_map | map.cpp:360:7:360:9 | m20 | | +| map.cpp:354:42:354:44 | call to unordered_map | map.cpp:363:12:363:14 | m20 | | +| map.cpp:354:42:354:44 | call to unordered_map | map.cpp:366:7:366:9 | m20 | | +| map.cpp:354:42:354:44 | call to unordered_map | map.cpp:438:1:438:1 | m20 | | +| map.cpp:354:47:354:49 | call to unordered_map | map.cpp:357:2:357:4 | m21 | | +| map.cpp:354:47:354:49 | call to unordered_map | map.cpp:361:7:361:9 | m21 | | +| map.cpp:354:47:354:49 | call to unordered_map | map.cpp:364:2:364:4 | m21 | | +| map.cpp:354:47:354:49 | call to unordered_map | map.cpp:367:7:367:9 | m21 | | +| map.cpp:354:47:354:49 | call to unordered_map | map.cpp:438:1:438:1 | m21 | | +| map.cpp:354:52:354:54 | call to unordered_map | map.cpp:358:2:358:4 | m22 | | +| map.cpp:354:52:354:54 | call to unordered_map | map.cpp:362:7:362:9 | m22 | | +| map.cpp:354:52:354:54 | call to unordered_map | map.cpp:364:12:364:14 | m22 | | +| map.cpp:354:52:354:54 | call to unordered_map | map.cpp:368:7:368:9 | m22 | | +| map.cpp:354:52:354:54 | call to unordered_map | map.cpp:438:1:438:1 | m22 | | +| map.cpp:355:2:355:4 | ref arg m19 | map.cpp:359:7:359:9 | m19 | | +| map.cpp:355:2:355:4 | ref arg m19 | map.cpp:363:2:363:4 | m19 | | +| map.cpp:355:2:355:4 | ref arg m19 | map.cpp:365:7:365:9 | m19 | | +| map.cpp:355:2:355:4 | ref arg m19 | map.cpp:438:1:438:1 | m19 | | +| map.cpp:355:13:355:57 | call to pair | map.cpp:355:2:355:4 | ref arg m19 | TAINT | +| map.cpp:355:13:355:57 | call to pair | map.cpp:355:6:355:11 | call to insert | TAINT | +| map.cpp:355:13:355:57 | call to pair | map.cpp:355:13:355:57 | call to pair | TAINT | +| map.cpp:355:49:355:54 | call to source | map.cpp:355:13:355:57 | call to pair | TAINT | +| map.cpp:356:2:356:4 | ref arg m20 | map.cpp:360:7:360:9 | m20 | | +| map.cpp:356:2:356:4 | ref arg m20 | map.cpp:363:12:363:14 | m20 | | +| map.cpp:356:2:356:4 | ref arg m20 | map.cpp:366:7:366:9 | m20 | | +| map.cpp:356:2:356:4 | ref arg m20 | map.cpp:438:1:438:1 | m20 | | +| map.cpp:356:13:356:51 | call to pair | map.cpp:356:2:356:4 | ref arg m20 | TAINT | +| map.cpp:356:13:356:51 | call to pair | map.cpp:356:6:356:11 | call to insert | TAINT | +| map.cpp:356:13:356:51 | call to pair | map.cpp:356:13:356:51 | call to pair | TAINT | +| map.cpp:356:46:356:50 | def | map.cpp:356:13:356:51 | call to pair | TAINT | +| map.cpp:357:2:357:4 | ref arg m21 | map.cpp:361:7:361:9 | m21 | | +| map.cpp:357:2:357:4 | ref arg m21 | map.cpp:364:2:364:4 | m21 | | +| map.cpp:357:2:357:4 | ref arg m21 | map.cpp:367:7:367:9 | m21 | | +| map.cpp:357:2:357:4 | ref arg m21 | map.cpp:438:1:438:1 | m21 | | +| map.cpp:357:13:357:51 | call to pair | map.cpp:357:2:357:4 | ref arg m21 | TAINT | +| map.cpp:357:13:357:51 | call to pair | map.cpp:357:6:357:11 | call to insert | TAINT | +| map.cpp:357:13:357:51 | call to pair | map.cpp:357:13:357:51 | call to pair | TAINT | +| map.cpp:357:46:357:50 | def | map.cpp:357:13:357:51 | call to pair | TAINT | +| map.cpp:358:2:358:4 | ref arg m22 | map.cpp:362:7:362:9 | m22 | | +| map.cpp:358:2:358:4 | ref arg m22 | map.cpp:364:12:364:14 | m22 | | +| map.cpp:358:2:358:4 | ref arg m22 | map.cpp:368:7:368:9 | m22 | | +| map.cpp:358:2:358:4 | ref arg m22 | map.cpp:438:1:438:1 | m22 | | +| map.cpp:358:13:358:57 | call to pair | map.cpp:358:2:358:4 | ref arg m22 | TAINT | +| map.cpp:358:13:358:57 | call to pair | map.cpp:358:6:358:11 | call to insert | TAINT | +| map.cpp:358:13:358:57 | call to pair | map.cpp:358:13:358:57 | call to pair | TAINT | +| map.cpp:358:49:358:54 | call to source | map.cpp:358:13:358:57 | call to pair | TAINT | +| map.cpp:359:7:359:9 | m19 | map.cpp:359:7:359:9 | call to unordered_map | | +| map.cpp:360:7:360:9 | m20 | map.cpp:360:7:360:9 | call to unordered_map | | +| map.cpp:361:7:361:9 | m21 | map.cpp:361:7:361:9 | call to unordered_map | | +| map.cpp:362:7:362:9 | m22 | map.cpp:362:7:362:9 | call to unordered_map | | +| map.cpp:363:2:363:4 | ref arg m19 | map.cpp:365:7:365:9 | m19 | | +| map.cpp:363:2:363:4 | ref arg m19 | map.cpp:438:1:438:1 | m19 | | +| map.cpp:363:12:363:14 | m20 | map.cpp:363:2:363:4 | ref arg m19 | TAINT | +| map.cpp:363:12:363:14 | ref arg m20 | map.cpp:366:7:366:9 | m20 | | +| map.cpp:363:12:363:14 | ref arg m20 | map.cpp:438:1:438:1 | m20 | | +| map.cpp:364:2:364:4 | ref arg m21 | map.cpp:367:7:367:9 | m21 | | +| map.cpp:364:2:364:4 | ref arg m21 | map.cpp:438:1:438:1 | m21 | | +| map.cpp:364:12:364:14 | m22 | map.cpp:364:2:364:4 | ref arg m21 | TAINT | +| map.cpp:364:12:364:14 | ref arg m22 | map.cpp:368:7:368:9 | m22 | | +| map.cpp:364:12:364:14 | ref arg m22 | map.cpp:438:1:438:1 | m22 | | +| map.cpp:365:7:365:9 | m19 | map.cpp:365:7:365:9 | call to unordered_map | | +| map.cpp:366:7:366:9 | m20 | map.cpp:366:7:366:9 | call to unordered_map | | +| map.cpp:367:7:367:9 | m21 | map.cpp:367:7:367:9 | call to unordered_map | | +| map.cpp:368:7:368:9 | m22 | map.cpp:368:7:368:9 | call to unordered_map | | +| map.cpp:371:37:371:39 | call to unordered_map | map.cpp:372:2:372:4 | m23 | | +| map.cpp:371:37:371:39 | call to unordered_map | map.cpp:373:2:373:4 | m23 | | +| map.cpp:371:37:371:39 | call to unordered_map | map.cpp:374:7:374:9 | m23 | | +| map.cpp:371:37:371:39 | call to unordered_map | map.cpp:375:7:375:9 | m23 | | +| map.cpp:371:37:371:39 | call to unordered_map | map.cpp:375:17:375:19 | m23 | | +| map.cpp:371:37:371:39 | call to unordered_map | map.cpp:376:7:376:9 | m23 | | +| map.cpp:371:37:371:39 | call to unordered_map | map.cpp:377:2:377:4 | m23 | | +| map.cpp:371:37:371:39 | call to unordered_map | map.cpp:378:7:378:9 | m23 | | +| map.cpp:371:37:371:39 | call to unordered_map | map.cpp:438:1:438:1 | m23 | | +| map.cpp:372:2:372:4 | ref arg m23 | map.cpp:373:2:373:4 | m23 | | +| map.cpp:372:2:372:4 | ref arg m23 | map.cpp:374:7:374:9 | m23 | | +| map.cpp:372:2:372:4 | ref arg m23 | map.cpp:375:7:375:9 | m23 | | +| map.cpp:372:2:372:4 | ref arg m23 | map.cpp:375:17:375:19 | m23 | | +| map.cpp:372:2:372:4 | ref arg m23 | map.cpp:376:7:376:9 | m23 | | +| map.cpp:372:2:372:4 | ref arg m23 | map.cpp:377:2:377:4 | m23 | | +| map.cpp:372:2:372:4 | ref arg m23 | map.cpp:378:7:378:9 | m23 | | +| map.cpp:372:2:372:4 | ref arg m23 | map.cpp:438:1:438:1 | m23 | | +| map.cpp:372:13:372:57 | call to pair | map.cpp:372:2:372:4 | ref arg m23 | TAINT | +| map.cpp:372:13:372:57 | call to pair | map.cpp:372:6:372:11 | call to insert | TAINT | +| map.cpp:372:13:372:57 | call to pair | map.cpp:372:13:372:57 | call to pair | TAINT | +| map.cpp:372:49:372:54 | call to source | map.cpp:372:13:372:57 | call to pair | TAINT | +| map.cpp:373:2:373:4 | ref arg m23 | map.cpp:374:7:374:9 | m23 | | +| map.cpp:373:2:373:4 | ref arg m23 | map.cpp:375:7:375:9 | m23 | | +| map.cpp:373:2:373:4 | ref arg m23 | map.cpp:375:17:375:19 | m23 | | +| map.cpp:373:2:373:4 | ref arg m23 | map.cpp:376:7:376:9 | m23 | | +| map.cpp:373:2:373:4 | ref arg m23 | map.cpp:377:2:377:4 | m23 | | +| map.cpp:373:2:373:4 | ref arg m23 | map.cpp:378:7:378:9 | m23 | | +| map.cpp:373:2:373:4 | ref arg m23 | map.cpp:438:1:438:1 | m23 | | +| map.cpp:373:13:373:57 | call to pair | map.cpp:373:2:373:4 | ref arg m23 | TAINT | +| map.cpp:373:13:373:57 | call to pair | map.cpp:373:6:373:11 | call to insert | TAINT | +| map.cpp:373:13:373:57 | call to pair | map.cpp:373:13:373:57 | call to pair | TAINT | +| map.cpp:373:49:373:54 | call to source | map.cpp:373:13:373:57 | call to pair | TAINT | +| map.cpp:374:7:374:9 | m23 | map.cpp:374:7:374:9 | call to unordered_map | | +| map.cpp:375:7:375:9 | m23 | map.cpp:375:11:375:15 | call to erase | TAINT | +| map.cpp:375:7:375:9 | ref arg m23 | map.cpp:376:7:376:9 | m23 | | +| map.cpp:375:7:375:9 | ref arg m23 | map.cpp:377:2:377:4 | m23 | | +| map.cpp:375:7:375:9 | ref arg m23 | map.cpp:378:7:378:9 | m23 | | +| map.cpp:375:7:375:9 | ref arg m23 | map.cpp:438:1:438:1 | m23 | | +| map.cpp:375:17:375:19 | m23 | map.cpp:375:21:375:25 | call to begin | TAINT | +| map.cpp:375:17:375:19 | ref arg m23 | map.cpp:375:7:375:9 | m23 | | +| map.cpp:375:17:375:19 | ref arg m23 | map.cpp:376:7:376:9 | m23 | | +| map.cpp:375:17:375:19 | ref arg m23 | map.cpp:377:2:377:4 | m23 | | +| map.cpp:375:17:375:19 | ref arg m23 | map.cpp:378:7:378:9 | m23 | | +| map.cpp:375:17:375:19 | ref arg m23 | map.cpp:438:1:438:1 | m23 | | +| map.cpp:376:7:376:9 | m23 | map.cpp:376:7:376:9 | call to unordered_map | | +| map.cpp:377:2:377:4 | ref arg m23 | map.cpp:378:7:378:9 | m23 | | +| map.cpp:377:2:377:4 | ref arg m23 | map.cpp:438:1:438:1 | m23 | | +| map.cpp:378:7:378:9 | m23 | map.cpp:378:7:378:9 | call to unordered_map | | +| map.cpp:381:37:381:39 | call to unordered_map | map.cpp:382:7:382:9 | m24 | | +| map.cpp:381:37:381:39 | call to unordered_map | map.cpp:383:7:383:9 | m24 | | +| map.cpp:381:37:381:39 | call to unordered_map | map.cpp:384:7:384:9 | m24 | | +| map.cpp:381:37:381:39 | call to unordered_map | map.cpp:385:7:385:9 | m24 | | +| map.cpp:381:37:381:39 | call to unordered_map | map.cpp:438:1:438:1 | m24 | | +| map.cpp:381:42:381:44 | call to unordered_map | map.cpp:386:7:386:9 | m25 | | +| map.cpp:381:42:381:44 | call to unordered_map | map.cpp:386:24:386:26 | m25 | | +| map.cpp:381:42:381:44 | call to unordered_map | map.cpp:387:7:387:9 | m25 | | +| map.cpp:381:42:381:44 | call to unordered_map | map.cpp:388:7:388:9 | m25 | | +| map.cpp:381:42:381:44 | call to unordered_map | map.cpp:388:24:388:26 | m25 | | +| map.cpp:381:42:381:44 | call to unordered_map | map.cpp:389:7:389:9 | m25 | | +| map.cpp:381:42:381:44 | call to unordered_map | map.cpp:438:1:438:1 | m25 | | +| map.cpp:382:7:382:9 | m24 | map.cpp:382:11:382:17 | call to emplace | TAINT | +| map.cpp:382:7:382:9 | ref arg m24 | map.cpp:383:7:383:9 | m24 | | +| map.cpp:382:7:382:9 | ref arg m24 | map.cpp:384:7:384:9 | m24 | | +| map.cpp:382:7:382:9 | ref arg m24 | map.cpp:385:7:385:9 | m24 | | +| map.cpp:382:7:382:9 | ref arg m24 | map.cpp:438:1:438:1 | m24 | | +| map.cpp:382:26:382:30 | def | map.cpp:382:7:382:9 | ref arg m24 | TAINT | +| map.cpp:382:26:382:30 | def | map.cpp:382:11:382:17 | call to emplace | TAINT | +| map.cpp:382:33:382:37 | first | map.cpp:382:7:382:37 | call to iterator | | +| map.cpp:383:7:383:9 | m24 | map.cpp:383:7:383:9 | call to unordered_map | | +| map.cpp:384:7:384:9 | m24 | map.cpp:384:11:384:17 | call to emplace | TAINT | +| map.cpp:384:7:384:9 | ref arg m24 | map.cpp:385:7:385:9 | m24 | | +| map.cpp:384:7:384:9 | ref arg m24 | map.cpp:438:1:438:1 | m24 | | +| map.cpp:384:26:384:31 | call to source | map.cpp:384:7:384:9 | ref arg m24 | TAINT | +| map.cpp:384:26:384:31 | call to source | map.cpp:384:11:384:17 | call to emplace | TAINT | +| map.cpp:384:36:384:40 | first | map.cpp:384:7:384:40 | call to iterator | | +| map.cpp:385:7:385:9 | m24 | map.cpp:385:7:385:9 | call to unordered_map | | +| map.cpp:386:7:386:9 | m25 | map.cpp:386:11:386:22 | call to emplace_hint | TAINT | +| map.cpp:386:7:386:9 | ref arg m25 | map.cpp:387:7:387:9 | m25 | | +| map.cpp:386:7:386:9 | ref arg m25 | map.cpp:388:7:388:9 | m25 | | +| map.cpp:386:7:386:9 | ref arg m25 | map.cpp:388:24:388:26 | m25 | | +| map.cpp:386:7:386:9 | ref arg m25 | map.cpp:389:7:389:9 | m25 | | +| map.cpp:386:7:386:9 | ref arg m25 | map.cpp:438:1:438:1 | m25 | | +| map.cpp:386:24:386:26 | m25 | map.cpp:386:28:386:32 | call to begin | TAINT | +| map.cpp:386:24:386:26 | ref arg m25 | map.cpp:386:7:386:9 | m25 | | +| map.cpp:386:24:386:26 | ref arg m25 | map.cpp:387:7:387:9 | m25 | | +| map.cpp:386:24:386:26 | ref arg m25 | map.cpp:388:7:388:9 | m25 | | +| map.cpp:386:24:386:26 | ref arg m25 | map.cpp:388:24:388:26 | m25 | | +| map.cpp:386:24:386:26 | ref arg m25 | map.cpp:389:7:389:9 | m25 | | +| map.cpp:386:24:386:26 | ref arg m25 | map.cpp:438:1:438:1 | m25 | | +| map.cpp:386:28:386:32 | call to begin | map.cpp:386:24:386:34 | call to iterator | TAINT | +| map.cpp:386:44:386:48 | def | map.cpp:386:7:386:9 | ref arg m25 | TAINT | +| map.cpp:386:44:386:48 | def | map.cpp:386:11:386:22 | call to emplace_hint | TAINT | +| map.cpp:387:7:387:9 | m25 | map.cpp:387:7:387:9 | call to unordered_map | | +| map.cpp:388:7:388:9 | m25 | map.cpp:388:11:388:22 | call to emplace_hint | TAINT | +| map.cpp:388:7:388:9 | ref arg m25 | map.cpp:389:7:389:9 | m25 | | +| map.cpp:388:7:388:9 | ref arg m25 | map.cpp:438:1:438:1 | m25 | | +| map.cpp:388:24:388:26 | m25 | map.cpp:388:28:388:32 | call to begin | TAINT | +| map.cpp:388:24:388:26 | ref arg m25 | map.cpp:388:7:388:9 | m25 | | +| map.cpp:388:24:388:26 | ref arg m25 | map.cpp:389:7:389:9 | m25 | | +| map.cpp:388:24:388:26 | ref arg m25 | map.cpp:438:1:438:1 | m25 | | +| map.cpp:388:28:388:32 | call to begin | map.cpp:388:24:388:34 | call to iterator | TAINT | +| map.cpp:388:44:388:49 | call to source | map.cpp:388:7:388:9 | ref arg m25 | TAINT | +| map.cpp:388:44:388:49 | call to source | map.cpp:388:11:388:22 | call to emplace_hint | TAINT | +| map.cpp:389:7:389:9 | m25 | map.cpp:389:7:389:9 | call to unordered_map | | +| map.cpp:392:37:392:39 | call to unordered_map | map.cpp:393:7:393:9 | m26 | | +| map.cpp:392:37:392:39 | call to unordered_map | map.cpp:394:7:394:9 | m26 | | +| map.cpp:392:37:392:39 | call to unordered_map | map.cpp:395:7:395:9 | m26 | | +| map.cpp:392:37:392:39 | call to unordered_map | map.cpp:396:7:396:9 | m26 | | +| map.cpp:392:37:392:39 | call to unordered_map | map.cpp:397:7:397:9 | m26 | | +| map.cpp:392:37:392:39 | call to unordered_map | map.cpp:398:7:398:9 | m26 | | +| map.cpp:392:37:392:39 | call to unordered_map | map.cpp:438:1:438:1 | m26 | | +| map.cpp:392:42:392:44 | call to unordered_map | map.cpp:399:7:399:9 | m27 | | +| map.cpp:392:42:392:44 | call to unordered_map | map.cpp:399:23:399:25 | m27 | | +| map.cpp:392:42:392:44 | call to unordered_map | map.cpp:400:7:400:9 | m27 | | +| map.cpp:392:42:392:44 | call to unordered_map | map.cpp:401:7:401:9 | m27 | | +| map.cpp:392:42:392:44 | call to unordered_map | map.cpp:401:23:401:25 | m27 | | +| map.cpp:392:42:392:44 | call to unordered_map | map.cpp:402:7:402:9 | m27 | | +| map.cpp:392:42:392:44 | call to unordered_map | map.cpp:438:1:438:1 | m27 | | +| map.cpp:392:47:392:49 | call to unordered_map | map.cpp:403:7:403:9 | m28 | | +| map.cpp:392:47:392:49 | call to unordered_map | map.cpp:403:23:403:25 | m28 | | +| map.cpp:392:47:392:49 | call to unordered_map | map.cpp:404:7:404:9 | m28 | | +| map.cpp:392:47:392:49 | call to unordered_map | map.cpp:405:7:405:9 | m28 | | +| map.cpp:392:47:392:49 | call to unordered_map | map.cpp:405:23:405:25 | m28 | | +| map.cpp:392:47:392:49 | call to unordered_map | map.cpp:406:7:406:9 | m28 | | +| map.cpp:392:47:392:49 | call to unordered_map | map.cpp:438:1:438:1 | m28 | | +| map.cpp:393:7:393:9 | m26 | map.cpp:393:11:393:21 | call to try_emplace | TAINT | +| map.cpp:393:7:393:9 | ref arg m26 | map.cpp:394:7:394:9 | m26 | | +| map.cpp:393:7:393:9 | ref arg m26 | map.cpp:395:7:395:9 | m26 | | +| map.cpp:393:7:393:9 | ref arg m26 | map.cpp:396:7:396:9 | m26 | | +| map.cpp:393:7:393:9 | ref arg m26 | map.cpp:397:7:397:9 | m26 | | +| map.cpp:393:7:393:9 | ref arg m26 | map.cpp:398:7:398:9 | m26 | | +| map.cpp:393:7:393:9 | ref arg m26 | map.cpp:438:1:438:1 | m26 | | +| map.cpp:393:30:393:34 | def | map.cpp:393:7:393:9 | ref arg m26 | TAINT | +| map.cpp:393:30:393:34 | def | map.cpp:393:11:393:21 | call to try_emplace | TAINT | +| map.cpp:393:37:393:41 | first | map.cpp:393:7:393:41 | call to iterator | | +| map.cpp:394:7:394:9 | m26 | map.cpp:394:11:394:21 | call to try_emplace | TAINT | +| map.cpp:394:7:394:9 | ref arg m26 | map.cpp:395:7:395:9 | m26 | | +| map.cpp:394:7:394:9 | ref arg m26 | map.cpp:396:7:396:9 | m26 | | +| map.cpp:394:7:394:9 | ref arg m26 | map.cpp:397:7:397:9 | m26 | | +| map.cpp:394:7:394:9 | ref arg m26 | map.cpp:398:7:398:9 | m26 | | +| map.cpp:394:7:394:9 | ref arg m26 | map.cpp:438:1:438:1 | m26 | | +| map.cpp:394:30:394:34 | def | map.cpp:394:7:394:9 | ref arg m26 | TAINT | +| map.cpp:394:30:394:34 | def | map.cpp:394:11:394:21 | call to try_emplace | TAINT | +| map.cpp:395:7:395:9 | m26 | map.cpp:395:7:395:9 | call to unordered_map | | +| map.cpp:396:7:396:9 | m26 | map.cpp:396:11:396:21 | call to try_emplace | TAINT | +| map.cpp:396:7:396:9 | ref arg m26 | map.cpp:397:7:397:9 | m26 | | +| map.cpp:396:7:396:9 | ref arg m26 | map.cpp:398:7:398:9 | m26 | | +| map.cpp:396:7:396:9 | ref arg m26 | map.cpp:438:1:438:1 | m26 | | +| map.cpp:396:30:396:35 | call to source | map.cpp:396:7:396:9 | ref arg m26 | TAINT | +| map.cpp:396:30:396:35 | call to source | map.cpp:396:11:396:21 | call to try_emplace | TAINT | +| map.cpp:396:40:396:44 | first | map.cpp:396:7:396:44 | call to iterator | | +| map.cpp:397:7:397:9 | m26 | map.cpp:397:11:397:21 | call to try_emplace | TAINT | +| map.cpp:397:7:397:9 | ref arg m26 | map.cpp:398:7:398:9 | m26 | | +| map.cpp:397:7:397:9 | ref arg m26 | map.cpp:438:1:438:1 | m26 | | +| map.cpp:397:30:397:35 | call to source | map.cpp:397:7:397:9 | ref arg m26 | TAINT | +| map.cpp:397:30:397:35 | call to source | map.cpp:397:11:397:21 | call to try_emplace | TAINT | +| map.cpp:398:7:398:9 | m26 | map.cpp:398:7:398:9 | call to unordered_map | | +| map.cpp:399:7:399:9 | m27 | map.cpp:399:11:399:21 | call to try_emplace | TAINT | +| map.cpp:399:7:399:9 | ref arg m27 | map.cpp:400:7:400:9 | m27 | | +| map.cpp:399:7:399:9 | ref arg m27 | map.cpp:401:7:401:9 | m27 | | +| map.cpp:399:7:399:9 | ref arg m27 | map.cpp:401:23:401:25 | m27 | | +| map.cpp:399:7:399:9 | ref arg m27 | map.cpp:402:7:402:9 | m27 | | +| map.cpp:399:7:399:9 | ref arg m27 | map.cpp:438:1:438:1 | m27 | | +| map.cpp:399:23:399:25 | m27 | map.cpp:399:27:399:31 | call to begin | TAINT | +| map.cpp:399:23:399:25 | ref arg m27 | map.cpp:399:7:399:9 | m27 | | +| map.cpp:399:23:399:25 | ref arg m27 | map.cpp:400:7:400:9 | m27 | | +| map.cpp:399:23:399:25 | ref arg m27 | map.cpp:401:7:401:9 | m27 | | +| map.cpp:399:23:399:25 | ref arg m27 | map.cpp:401:23:401:25 | m27 | | +| map.cpp:399:23:399:25 | ref arg m27 | map.cpp:402:7:402:9 | m27 | | +| map.cpp:399:23:399:25 | ref arg m27 | map.cpp:438:1:438:1 | m27 | | +| map.cpp:399:27:399:31 | call to begin | map.cpp:399:23:399:33 | call to iterator | TAINT | +| map.cpp:399:43:399:47 | def | map.cpp:399:7:399:9 | ref arg m27 | TAINT | +| map.cpp:399:43:399:47 | def | map.cpp:399:11:399:21 | call to try_emplace | TAINT | +| map.cpp:400:7:400:9 | m27 | map.cpp:400:7:400:9 | call to unordered_map | | +| map.cpp:401:7:401:9 | m27 | map.cpp:401:11:401:21 | call to try_emplace | TAINT | +| map.cpp:401:7:401:9 | ref arg m27 | map.cpp:402:7:402:9 | m27 | | +| map.cpp:401:7:401:9 | ref arg m27 | map.cpp:438:1:438:1 | m27 | | +| map.cpp:401:23:401:25 | m27 | map.cpp:401:27:401:31 | call to begin | TAINT | +| map.cpp:401:23:401:25 | ref arg m27 | map.cpp:401:7:401:9 | m27 | | +| map.cpp:401:23:401:25 | ref arg m27 | map.cpp:402:7:402:9 | m27 | | +| map.cpp:401:23:401:25 | ref arg m27 | map.cpp:438:1:438:1 | m27 | | +| map.cpp:401:27:401:31 | call to begin | map.cpp:401:23:401:33 | call to iterator | TAINT | +| map.cpp:401:43:401:48 | call to source | map.cpp:401:7:401:9 | ref arg m27 | TAINT | +| map.cpp:401:43:401:48 | call to source | map.cpp:401:11:401:21 | call to try_emplace | TAINT | +| map.cpp:402:7:402:9 | m27 | map.cpp:402:7:402:9 | call to unordered_map | | +| map.cpp:403:7:403:9 | m28 | map.cpp:403:11:403:21 | call to try_emplace | TAINT | +| map.cpp:403:7:403:9 | ref arg m28 | map.cpp:404:7:404:9 | m28 | | +| map.cpp:403:7:403:9 | ref arg m28 | map.cpp:405:7:405:9 | m28 | | +| map.cpp:403:7:403:9 | ref arg m28 | map.cpp:405:23:405:25 | m28 | | +| map.cpp:403:7:403:9 | ref arg m28 | map.cpp:406:7:406:9 | m28 | | +| map.cpp:403:7:403:9 | ref arg m28 | map.cpp:438:1:438:1 | m28 | | +| map.cpp:403:23:403:25 | m28 | map.cpp:403:27:403:31 | call to begin | TAINT | +| map.cpp:403:23:403:25 | ref arg m28 | map.cpp:403:7:403:9 | m28 | | +| map.cpp:403:23:403:25 | ref arg m28 | map.cpp:404:7:404:9 | m28 | | +| map.cpp:403:23:403:25 | ref arg m28 | map.cpp:405:7:405:9 | m28 | | +| map.cpp:403:23:403:25 | ref arg m28 | map.cpp:405:23:405:25 | m28 | | +| map.cpp:403:23:403:25 | ref arg m28 | map.cpp:406:7:406:9 | m28 | | +| map.cpp:403:23:403:25 | ref arg m28 | map.cpp:438:1:438:1 | m28 | | +| map.cpp:403:27:403:31 | call to begin | map.cpp:403:23:403:33 | call to iterator | TAINT | +| map.cpp:403:43:403:47 | def | map.cpp:403:7:403:9 | ref arg m28 | TAINT | +| map.cpp:403:43:403:47 | def | map.cpp:403:11:403:21 | call to try_emplace | TAINT | +| map.cpp:404:7:404:9 | m28 | map.cpp:404:7:404:9 | call to unordered_map | | +| map.cpp:405:7:405:9 | m28 | map.cpp:405:11:405:21 | call to try_emplace | TAINT | +| map.cpp:405:7:405:9 | ref arg m28 | map.cpp:406:7:406:9 | m28 | | +| map.cpp:405:7:405:9 | ref arg m28 | map.cpp:438:1:438:1 | m28 | | +| map.cpp:405:23:405:25 | m28 | map.cpp:405:27:405:31 | call to begin | TAINT | +| map.cpp:405:23:405:25 | ref arg m28 | map.cpp:405:7:405:9 | m28 | | +| map.cpp:405:23:405:25 | ref arg m28 | map.cpp:406:7:406:9 | m28 | | +| map.cpp:405:23:405:25 | ref arg m28 | map.cpp:438:1:438:1 | m28 | | +| map.cpp:405:27:405:31 | call to begin | map.cpp:405:23:405:33 | call to iterator | TAINT | +| map.cpp:405:46:405:50 | def | map.cpp:405:7:405:9 | ref arg m28 | TAINT | +| map.cpp:405:46:405:50 | def | map.cpp:405:11:405:21 | call to try_emplace | TAINT | +| map.cpp:406:7:406:9 | m28 | map.cpp:406:7:406:9 | call to unordered_map | | +| map.cpp:409:50:409:52 | call to unordered_map | map.cpp:410:7:410:9 | m29 | | +| map.cpp:409:50:409:52 | call to unordered_map | map.cpp:411:7:411:9 | m29 | | +| map.cpp:409:50:409:52 | call to unordered_map | map.cpp:412:7:412:9 | m29 | | +| map.cpp:409:50:409:52 | call to unordered_map | map.cpp:438:1:438:1 | m29 | | +| map.cpp:409:55:409:57 | call to unordered_map | map.cpp:413:7:413:9 | m30 | | +| map.cpp:409:55:409:57 | call to unordered_map | map.cpp:414:7:414:9 | m30 | | +| map.cpp:409:55:409:57 | call to unordered_map | map.cpp:415:7:415:9 | m30 | | +| map.cpp:409:55:409:57 | call to unordered_map | map.cpp:438:1:438:1 | m30 | | +| map.cpp:409:60:409:62 | call to unordered_map | map.cpp:416:7:416:9 | m31 | | +| map.cpp:409:60:409:62 | call to unordered_map | map.cpp:417:7:417:9 | m31 | | +| map.cpp:409:60:409:62 | call to unordered_map | map.cpp:418:7:418:9 | m31 | | +| map.cpp:409:60:409:62 | call to unordered_map | map.cpp:438:1:438:1 | m31 | | +| map.cpp:409:65:409:67 | call to unordered_map | map.cpp:419:7:419:9 | m32 | | +| map.cpp:409:65:409:67 | call to unordered_map | map.cpp:420:7:420:9 | m32 | | +| map.cpp:409:65:409:67 | call to unordered_map | map.cpp:421:7:421:9 | m32 | | +| map.cpp:409:65:409:67 | call to unordered_map | map.cpp:438:1:438:1 | m32 | | +| map.cpp:410:7:410:9 | m29 | map.cpp:410:11:410:21 | call to try_emplace | TAINT | +| map.cpp:410:7:410:9 | ref arg m29 | map.cpp:411:7:411:9 | m29 | | +| map.cpp:410:7:410:9 | ref arg m29 | map.cpp:412:7:412:9 | m29 | | +| map.cpp:410:7:410:9 | ref arg m29 | map.cpp:438:1:438:1 | m29 | | +| map.cpp:410:11:410:21 | call to try_emplace | map.cpp:410:7:410:34 | call to pair | TAINT | +| map.cpp:410:30:410:30 | 1 | map.cpp:410:7:410:9 | ref arg m29 | TAINT | +| map.cpp:410:30:410:30 | 1 | map.cpp:410:11:410:21 | call to try_emplace | TAINT | +| map.cpp:410:33:410:33 | 2 | map.cpp:410:7:410:9 | ref arg m29 | TAINT | +| map.cpp:410:33:410:33 | 2 | map.cpp:410:11:410:21 | call to try_emplace | TAINT | +| map.cpp:411:7:411:9 | m29 | map.cpp:411:7:411:9 | call to unordered_map | | +| map.cpp:412:7:412:9 | m29 | map.cpp:412:10:412:10 | call to operator[] | TAINT | +| map.cpp:412:7:412:9 | ref arg m29 | map.cpp:438:1:438:1 | m29 | | +| map.cpp:412:10:412:10 | call to operator[] | map.cpp:412:7:412:16 | call to pair | TAINT | +| map.cpp:413:7:413:9 | m30 | map.cpp:413:11:413:21 | call to try_emplace | TAINT | +| map.cpp:413:7:413:9 | ref arg m30 | map.cpp:414:7:414:9 | m30 | | +| map.cpp:413:7:413:9 | ref arg m30 | map.cpp:415:7:415:9 | m30 | | +| map.cpp:413:7:413:9 | ref arg m30 | map.cpp:438:1:438:1 | m30 | | +| map.cpp:413:11:413:21 | call to try_emplace | map.cpp:413:7:413:37 | call to pair | TAINT | +| map.cpp:413:33:413:33 | 1 | map.cpp:413:7:413:9 | ref arg m30 | TAINT | +| map.cpp:413:33:413:33 | 1 | map.cpp:413:11:413:21 | call to try_emplace | TAINT | +| map.cpp:413:36:413:36 | 2 | map.cpp:413:7:413:9 | ref arg m30 | TAINT | +| map.cpp:413:36:413:36 | 2 | map.cpp:413:11:413:21 | call to try_emplace | TAINT | +| map.cpp:414:7:414:9 | m30 | map.cpp:414:7:414:9 | call to unordered_map | | +| map.cpp:415:7:415:9 | m30 | map.cpp:415:10:415:10 | call to operator[] | TAINT | +| map.cpp:415:7:415:9 | ref arg m30 | map.cpp:438:1:438:1 | m30 | | +| map.cpp:415:10:415:10 | call to operator[] | map.cpp:415:7:415:16 | call to pair | TAINT | +| map.cpp:416:7:416:9 | m31 | map.cpp:416:11:416:21 | call to try_emplace | TAINT | +| map.cpp:416:7:416:9 | ref arg m31 | map.cpp:417:7:417:9 | m31 | | +| map.cpp:416:7:416:9 | ref arg m31 | map.cpp:418:7:418:9 | m31 | | +| map.cpp:416:7:416:9 | ref arg m31 | map.cpp:438:1:438:1 | m31 | | +| map.cpp:416:11:416:21 | call to try_emplace | map.cpp:416:7:416:41 | call to pair | TAINT | +| map.cpp:416:30:416:35 | call to source | map.cpp:416:7:416:9 | ref arg m31 | TAINT | +| map.cpp:416:30:416:35 | call to source | map.cpp:416:11:416:21 | call to try_emplace | TAINT | +| map.cpp:416:40:416:40 | 2 | map.cpp:416:7:416:9 | ref arg m31 | TAINT | +| map.cpp:416:40:416:40 | 2 | map.cpp:416:11:416:21 | call to try_emplace | TAINT | +| map.cpp:417:7:417:9 | m31 | map.cpp:417:7:417:9 | call to unordered_map | | +| map.cpp:418:7:418:9 | m31 | map.cpp:418:10:418:10 | call to operator[] | TAINT | +| map.cpp:418:7:418:9 | ref arg m31 | map.cpp:438:1:438:1 | m31 | | +| map.cpp:418:10:418:10 | call to operator[] | map.cpp:418:7:418:16 | call to pair | TAINT | +| map.cpp:419:7:419:9 | m32 | map.cpp:419:11:419:21 | call to try_emplace | TAINT | +| map.cpp:419:7:419:9 | ref arg m32 | map.cpp:420:7:420:9 | m32 | | +| map.cpp:419:7:419:9 | ref arg m32 | map.cpp:421:7:421:9 | m32 | | +| map.cpp:419:7:419:9 | ref arg m32 | map.cpp:438:1:438:1 | m32 | | +| map.cpp:419:11:419:21 | call to try_emplace | map.cpp:419:7:419:41 | call to pair | TAINT | +| map.cpp:419:30:419:30 | 1 | map.cpp:419:7:419:9 | ref arg m32 | TAINT | +| map.cpp:419:30:419:30 | 1 | map.cpp:419:11:419:21 | call to try_emplace | TAINT | +| map.cpp:419:33:419:38 | call to source | map.cpp:419:7:419:9 | ref arg m32 | TAINT | +| map.cpp:419:33:419:38 | call to source | map.cpp:419:11:419:21 | call to try_emplace | TAINT | +| map.cpp:420:7:420:9 | m32 | map.cpp:420:7:420:9 | call to unordered_map | | +| map.cpp:421:7:421:9 | m32 | map.cpp:421:10:421:10 | call to operator[] | TAINT | +| map.cpp:421:7:421:9 | ref arg m32 | map.cpp:438:1:438:1 | m32 | | +| map.cpp:421:10:421:10 | call to operator[] | map.cpp:421:7:421:16 | call to pair | TAINT | +| map.cpp:424:37:424:39 | call to unordered_map | map.cpp:425:7:425:9 | m33 | | +| map.cpp:424:37:424:39 | call to unordered_map | map.cpp:426:7:426:9 | m33 | | +| map.cpp:424:37:424:39 | call to unordered_map | map.cpp:438:1:438:1 | m33 | | +| map.cpp:425:7:425:9 | m33 | map.cpp:425:11:425:17 | call to emplace | TAINT | +| map.cpp:425:7:425:9 | ref arg m33 | map.cpp:426:7:426:9 | m33 | | +| map.cpp:425:7:425:9 | ref arg m33 | map.cpp:438:1:438:1 | m33 | | +| map.cpp:425:29:425:33 | def | map.cpp:425:7:425:9 | ref arg m33 | TAINT | +| map.cpp:425:29:425:33 | def | map.cpp:425:11:425:17 | call to emplace | TAINT | +| map.cpp:425:36:425:40 | first | map.cpp:425:7:425:40 | call to iterator | | +| map.cpp:426:7:426:9 | m33 | map.cpp:426:7:426:9 | call to unordered_map | | +| map.cpp:428:37:428:39 | call to unordered_map | map.cpp:429:7:429:9 | m34 | | +| map.cpp:428:37:428:39 | call to unordered_map | map.cpp:430:7:430:9 | m34 | | +| map.cpp:428:37:428:39 | call to unordered_map | map.cpp:431:7:431:9 | m34 | | +| map.cpp:428:37:428:39 | call to unordered_map | map.cpp:432:7:432:9 | m34 | | +| map.cpp:428:37:428:39 | call to unordered_map | map.cpp:433:7:433:9 | m34 | | +| map.cpp:428:37:428:39 | call to unordered_map | map.cpp:433:24:433:26 | m34 | | +| map.cpp:428:37:428:39 | call to unordered_map | map.cpp:438:1:438:1 | m34 | | +| map.cpp:428:42:428:44 | call to unordered_map | map.cpp:434:7:434:9 | m35 | | +| map.cpp:428:42:428:44 | call to unordered_map | map.cpp:435:7:435:9 | m35 | | +| map.cpp:428:42:428:44 | call to unordered_map | map.cpp:436:7:436:9 | m35 | | +| map.cpp:428:42:428:44 | call to unordered_map | map.cpp:437:7:437:9 | m35 | | +| map.cpp:428:42:428:44 | call to unordered_map | map.cpp:438:1:438:1 | m35 | | +| map.cpp:429:7:429:9 | m34 | map.cpp:429:11:429:17 | call to emplace | TAINT | +| map.cpp:429:7:429:9 | ref arg m34 | map.cpp:430:7:430:9 | m34 | | +| map.cpp:429:7:429:9 | ref arg m34 | map.cpp:431:7:431:9 | m34 | | +| map.cpp:429:7:429:9 | ref arg m34 | map.cpp:432:7:432:9 | m34 | | +| map.cpp:429:7:429:9 | ref arg m34 | map.cpp:433:7:433:9 | m34 | | +| map.cpp:429:7:429:9 | ref arg m34 | map.cpp:433:24:433:26 | m34 | | +| map.cpp:429:7:429:9 | ref arg m34 | map.cpp:438:1:438:1 | m34 | | +| map.cpp:429:19:429:57 | call to pair | map.cpp:429:7:429:9 | ref arg m34 | TAINT | +| map.cpp:429:19:429:57 | call to pair | map.cpp:429:11:429:17 | call to emplace | TAINT | +| map.cpp:429:52:429:56 | def | map.cpp:429:19:429:57 | call to pair | TAINT | +| map.cpp:429:60:429:64 | first | map.cpp:429:7:429:64 | call to iterator | | +| map.cpp:430:7:430:9 | m34 | map.cpp:430:7:430:9 | call to unordered_map | | +| map.cpp:431:7:431:9 | m34 | map.cpp:431:11:431:17 | call to emplace | TAINT | +| map.cpp:431:7:431:9 | ref arg m34 | map.cpp:432:7:432:9 | m34 | | +| map.cpp:431:7:431:9 | ref arg m34 | map.cpp:433:7:433:9 | m34 | | +| map.cpp:431:7:431:9 | ref arg m34 | map.cpp:433:24:433:26 | m34 | | +| map.cpp:431:7:431:9 | ref arg m34 | map.cpp:438:1:438:1 | m34 | | +| map.cpp:431:19:431:60 | call to pair | map.cpp:431:7:431:9 | ref arg m34 | TAINT | +| map.cpp:431:19:431:60 | call to pair | map.cpp:431:11:431:17 | call to emplace | TAINT | +| map.cpp:431:52:431:57 | call to source | map.cpp:431:19:431:60 | call to pair | TAINT | +| map.cpp:431:63:431:67 | first | map.cpp:431:7:431:67 | call to iterator | | +| map.cpp:432:7:432:9 | m34 | map.cpp:432:7:432:9 | call to unordered_map | | +| map.cpp:433:7:433:9 | m34 | map.cpp:433:11:433:22 | call to emplace_hint | TAINT | +| map.cpp:433:7:433:9 | ref arg m34 | map.cpp:438:1:438:1 | m34 | | +| map.cpp:433:24:433:26 | m34 | map.cpp:433:28:433:32 | call to begin | TAINT | +| map.cpp:433:24:433:26 | ref arg m34 | map.cpp:433:7:433:9 | m34 | | +| map.cpp:433:24:433:26 | ref arg m34 | map.cpp:438:1:438:1 | m34 | | +| map.cpp:433:28:433:32 | call to begin | map.cpp:433:24:433:34 | call to iterator | TAINT | +| map.cpp:433:44:433:48 | def | map.cpp:433:7:433:9 | ref arg m34 | TAINT | +| map.cpp:433:44:433:48 | def | map.cpp:433:11:433:22 | call to emplace_hint | TAINT | +| map.cpp:434:7:434:9 | m35 | map.cpp:434:7:434:9 | ref arg m35 | TAINT | +| map.cpp:434:7:434:9 | m35 | map.cpp:434:11:434:17 | call to emplace | TAINT | +| map.cpp:434:7:434:9 | ref arg m35 | map.cpp:435:7:435:9 | m35 | | +| map.cpp:434:7:434:9 | ref arg m35 | map.cpp:436:7:436:9 | m35 | | +| map.cpp:434:7:434:9 | ref arg m35 | map.cpp:437:7:437:9 | m35 | | +| map.cpp:434:7:434:9 | ref arg m35 | map.cpp:438:1:438:1 | m35 | | +| map.cpp:434:21:434:25 | first | map.cpp:434:7:434:25 | call to iterator | | +| map.cpp:435:7:435:9 | m35 | map.cpp:435:7:435:9 | call to unordered_map | | +| map.cpp:436:7:436:9 | m35 | map.cpp:436:11:436:17 | call to emplace | TAINT | +| map.cpp:436:7:436:9 | ref arg m35 | map.cpp:437:7:437:9 | m35 | | +| map.cpp:436:7:436:9 | ref arg m35 | map.cpp:438:1:438:1 | m35 | | +| map.cpp:436:19:436:60 | call to pair | map.cpp:436:7:436:9 | ref arg m35 | TAINT | +| map.cpp:436:19:436:60 | call to pair | map.cpp:436:11:436:17 | call to emplace | TAINT | +| map.cpp:436:55:436:59 | def | map.cpp:436:19:436:60 | call to pair | TAINT | +| map.cpp:436:63:436:67 | first | map.cpp:436:7:436:67 | call to iterator | | +| map.cpp:437:7:437:9 | m35 | map.cpp:437:7:437:9 | call to unordered_map | | +| movableclass.cpp:8:2:8:15 | this | movableclass.cpp:8:27:8:31 | constructor init of field v [pre-this] | | +| movableclass.cpp:8:21:8:22 | _v | movableclass.cpp:8:29:8:30 | _v | | +| movableclass.cpp:8:29:8:30 | _v | movableclass.cpp:8:27:8:31 | constructor init of field v | TAINT | +| movableclass.cpp:9:2:9:15 | this | movableclass.cpp:10:3:10:3 | this | | +| movableclass.cpp:9:34:9:38 | other | movableclass.cpp:9:34:9:38 | other | | +| movableclass.cpp:9:34:9:38 | other | movableclass.cpp:10:7:10:11 | other | | +| movableclass.cpp:9:34:9:38 | other | movableclass.cpp:11:3:11:7 | other | | +| movableclass.cpp:10:3:10:13 | ... = ... | movableclass.cpp:10:3:10:3 | v [post update] | | +| movableclass.cpp:10:13:10:13 | v | movableclass.cpp:10:3:10:13 | ... = ... | | +| movableclass.cpp:11:3:11:7 | other [post update] | movableclass.cpp:9:34:9:38 | other | | +| movableclass.cpp:11:3:11:13 | ... = ... | movableclass.cpp:11:9:11:9 | v [post update] | | +| movableclass.cpp:11:13:11:13 | 0 | movableclass.cpp:11:3:11:13 | ... = ... | | +| movableclass.cpp:13:18:13:26 | this | movableclass.cpp:14:3:14:3 | this | | +| movableclass.cpp:13:45:13:49 | other | movableclass.cpp:13:45:13:49 | other | | +| movableclass.cpp:13:45:13:49 | other | movableclass.cpp:14:7:14:11 | other | | +| movableclass.cpp:13:45:13:49 | other | movableclass.cpp:15:3:15:7 | other | | +| movableclass.cpp:14:3:14:3 | this | movableclass.cpp:16:11:16:14 | this | | +| movableclass.cpp:14:3:14:3 | this [post update] | movableclass.cpp:16:11:16:14 | this | | +| movableclass.cpp:14:3:14:13 | ... = ... | movableclass.cpp:14:3:14:3 | v [post update] | | +| movableclass.cpp:14:13:14:13 | v | movableclass.cpp:14:3:14:13 | ... = ... | | +| movableclass.cpp:15:3:15:7 | other [post update] | movableclass.cpp:13:45:13:49 | other | | +| movableclass.cpp:15:3:15:13 | ... = ... | movableclass.cpp:15:9:15:9 | v [post update] | | +| movableclass.cpp:15:13:15:13 | 0 | movableclass.cpp:15:3:15:13 | ... = ... | | +| movableclass.cpp:16:11:16:14 | this | movableclass.cpp:16:10:16:14 | * ... | TAINT | +| movableclass.cpp:22:57:22:57 | 1 | movableclass.cpp:22:42:22:58 | call to MyMovableClass | TAINT | +| movableclass.cpp:23:55:23:60 | call to source | movableclass.cpp:23:40:23:63 | call to MyMovableClass | TAINT | +| movableclass.cpp:28:21:28:21 | 1 | movableclass.cpp:28:21:28:22 | call to MyMovableClass | TAINT | +| movableclass.cpp:28:21:28:22 | call to MyMovableClass | movableclass.cpp:33:8:33:9 | s1 | | +| movableclass.cpp:29:22:29:23 | call to MyMovableClass | movableclass.cpp:34:8:34:9 | s2 | | +| movableclass.cpp:29:23:29:23 | 1 | movableclass.cpp:29:22:29:23 | call to MyMovableClass | TAINT | +| movableclass.cpp:30:18:30:19 | call to MyMovableClass | movableclass.cpp:31:3:31:4 | s3 | | +| movableclass.cpp:30:18:30:19 | call to MyMovableClass | movableclass.cpp:35:8:35:9 | s3 | | +| movableclass.cpp:31:3:31:4 | ref arg s3 | movableclass.cpp:35:8:35:9 | s3 | | +| movableclass.cpp:31:8:31:8 | 1 | movableclass.cpp:31:8:31:8 | call to MyMovableClass | TAINT | +| movableclass.cpp:31:8:31:8 | call to MyMovableClass | movableclass.cpp:31:3:31:4 | ref arg s3 | TAINT | +| movableclass.cpp:31:8:31:8 | call to MyMovableClass | movableclass.cpp:31:6:31:6 | call to operator= | TAINT | +| movableclass.cpp:39:21:39:26 | call to source | movableclass.cpp:39:21:39:29 | call to MyMovableClass | TAINT | +| movableclass.cpp:39:21:39:29 | call to MyMovableClass | movableclass.cpp:44:8:44:9 | s1 | | +| movableclass.cpp:40:22:40:30 | call to MyMovableClass | movableclass.cpp:45:8:45:9 | s2 | | +| movableclass.cpp:40:23:40:28 | call to source | movableclass.cpp:40:22:40:30 | call to MyMovableClass | TAINT | +| movableclass.cpp:41:18:41:19 | call to MyMovableClass | movableclass.cpp:42:3:42:4 | s3 | | +| movableclass.cpp:41:18:41:19 | call to MyMovableClass | movableclass.cpp:46:8:46:9 | s3 | | +| movableclass.cpp:42:3:42:4 | ref arg s3 | movableclass.cpp:46:8:46:9 | s3 | | +| movableclass.cpp:42:8:42:13 | call to source | movableclass.cpp:42:8:42:15 | call to MyMovableClass | TAINT | +| movableclass.cpp:42:8:42:15 | call to MyMovableClass | movableclass.cpp:42:3:42:4 | ref arg s3 | TAINT | +| movableclass.cpp:42:8:42:15 | call to MyMovableClass | movableclass.cpp:42:6:42:6 | call to operator= | TAINT | +| movableclass.cpp:50:22:50:46 | call to MyMovableClass | movableclass.cpp:54:8:54:9 | s1 | | +| movableclass.cpp:50:38:50:43 | call to source | movableclass.cpp:50:22:50:46 | call to MyMovableClass | TAINT | +| movableclass.cpp:51:18:51:19 | call to MyMovableClass | movableclass.cpp:52:3:52:4 | s2 | | +| movableclass.cpp:51:18:51:19 | call to MyMovableClass | movableclass.cpp:55:8:55:9 | s2 | | +| movableclass.cpp:52:3:52:4 | ref arg s2 | movableclass.cpp:55:8:55:9 | s2 | | +| movableclass.cpp:52:8:52:31 | call to MyMovableClass | movableclass.cpp:52:3:52:4 | ref arg s2 | TAINT | +| movableclass.cpp:52:8:52:31 | call to MyMovableClass | movableclass.cpp:52:6:52:6 | call to operator= | TAINT | +| movableclass.cpp:52:23:52:28 | call to source | movableclass.cpp:52:8:52:31 | call to MyMovableClass | TAINT | +| movableclass.cpp:59:21:59:32 | call to getUnTainted | movableclass.cpp:59:21:59:35 | call to MyMovableClass | | +| movableclass.cpp:59:21:59:35 | call to MyMovableClass | movableclass.cpp:63:8:63:9 | s1 | | +| movableclass.cpp:60:21:60:30 | call to getTainted | movableclass.cpp:60:21:60:33 | call to MyMovableClass | | +| movableclass.cpp:60:21:60:33 | call to MyMovableClass | movableclass.cpp:64:8:64:9 | s2 | | +| movableclass.cpp:61:18:61:19 | call to MyMovableClass | movableclass.cpp:65:8:65:9 | s3 | | +| movableclass.cpp:65:13:65:18 | call to source | movableclass.cpp:65:13:65:20 | call to MyMovableClass | TAINT | +| movableclass.cpp:65:13:65:20 | call to MyMovableClass | movableclass.cpp:65:8:65:9 | ref arg s3 | TAINT | +| movableclass.cpp:65:13:65:20 | call to MyMovableClass | movableclass.cpp:65:11:65:11 | call to operator= | TAINT | +| set.cpp:17:19:17:20 | call to set | set.cpp:19:7:19:8 | s1 | | +| set.cpp:17:19:17:20 | call to set | set.cpp:23:12:23:13 | s1 | | +| set.cpp:17:19:17:20 | call to set | set.cpp:23:24:23:25 | s1 | | +| set.cpp:17:19:17:20 | call to set | set.cpp:25:7:25:8 | s1 | | +| set.cpp:17:19:17:20 | call to set | set.cpp:31:7:31:8 | s1 | | +| set.cpp:17:19:17:20 | call to set | set.cpp:55:12:55:13 | s1 | | +| set.cpp:17:19:17:20 | call to set | set.cpp:55:30:55:31 | s1 | | +| set.cpp:17:19:17:20 | call to set | set.cpp:126:1:126:1 | s1 | | +| set.cpp:17:23:17:24 | call to set | set.cpp:20:7:20:8 | s2 | | +| set.cpp:17:23:17:24 | call to set | set.cpp:24:12:24:13 | s2 | | +| set.cpp:17:23:17:24 | call to set | set.cpp:24:24:24:25 | s2 | | +| set.cpp:17:23:17:24 | call to set | set.cpp:26:7:26:8 | s2 | | +| set.cpp:17:23:17:24 | call to set | set.cpp:32:7:32:8 | s2 | | +| set.cpp:17:23:17:24 | call to set | set.cpp:39:22:39:23 | s2 | | +| set.cpp:17:23:17:24 | call to set | set.cpp:40:24:40:25 | s2 | | +| set.cpp:17:23:17:24 | call to set | set.cpp:41:22:41:23 | s2 | | +| set.cpp:17:23:17:24 | call to set | set.cpp:41:34:41:35 | s2 | | +| set.cpp:17:23:17:24 | call to set | set.cpp:43:8:43:9 | s2 | | +| set.cpp:17:23:17:24 | call to set | set.cpp:59:12:59:13 | s2 | | +| set.cpp:17:23:17:24 | call to set | set.cpp:59:30:59:31 | s2 | | +| set.cpp:17:23:17:24 | call to set | set.cpp:126:1:126:1 | s2 | | +| set.cpp:17:27:17:28 | call to set | set.cpp:21:7:21:8 | s3 | | +| set.cpp:17:27:17:28 | call to set | set.cpp:21:17:21:18 | s3 | | +| set.cpp:17:27:17:28 | call to set | set.cpp:27:7:27:8 | s3 | | +| set.cpp:17:27:17:28 | call to set | set.cpp:33:7:33:8 | s3 | | +| set.cpp:17:27:17:28 | call to set | set.cpp:126:1:126:1 | s3 | | +| set.cpp:17:31:17:32 | call to set | set.cpp:22:7:22:8 | s4 | | +| set.cpp:17:31:17:32 | call to set | set.cpp:22:17:22:18 | s4 | | +| set.cpp:17:31:17:32 | call to set | set.cpp:28:7:28:8 | s4 | | +| set.cpp:17:31:17:32 | call to set | set.cpp:34:7:34:8 | s4 | | +| set.cpp:17:31:17:32 | call to set | set.cpp:126:1:126:1 | s4 | | +| set.cpp:17:35:17:36 | call to set | set.cpp:23:2:23:3 | s5 | | +| set.cpp:17:35:17:36 | call to set | set.cpp:29:7:29:8 | s5 | | +| set.cpp:17:35:17:36 | call to set | set.cpp:35:7:35:8 | s5 | | +| set.cpp:17:35:17:36 | call to set | set.cpp:126:1:126:1 | s5 | | +| set.cpp:17:39:17:40 | call to set | set.cpp:24:2:24:3 | s6 | | +| set.cpp:17:39:17:40 | call to set | set.cpp:30:7:30:8 | s6 | | +| set.cpp:17:39:17:40 | call to set | set.cpp:36:7:36:8 | s6 | | +| set.cpp:17:39:17:40 | call to set | set.cpp:126:1:126:1 | s6 | | +| set.cpp:19:7:19:8 | ref arg s1 | set.cpp:23:12:23:13 | s1 | | +| set.cpp:19:7:19:8 | ref arg s1 | set.cpp:23:24:23:25 | s1 | | +| set.cpp:19:7:19:8 | ref arg s1 | set.cpp:25:7:25:8 | s1 | | +| set.cpp:19:7:19:8 | ref arg s1 | set.cpp:31:7:31:8 | s1 | | +| set.cpp:19:7:19:8 | ref arg s1 | set.cpp:55:12:55:13 | s1 | | +| set.cpp:19:7:19:8 | ref arg s1 | set.cpp:55:30:55:31 | s1 | | +| set.cpp:19:7:19:8 | ref arg s1 | set.cpp:126:1:126:1 | s1 | | +| set.cpp:19:17:19:21 | abc | set.cpp:19:7:19:8 | ref arg s1 | TAINT | +| set.cpp:19:17:19:21 | abc | set.cpp:19:10:19:15 | call to insert | TAINT | +| set.cpp:19:24:19:28 | first | set.cpp:19:7:19:28 | call to iterator | | +| set.cpp:20:7:20:8 | ref arg s2 | set.cpp:24:12:24:13 | s2 | | +| set.cpp:20:7:20:8 | ref arg s2 | set.cpp:24:24:24:25 | s2 | | +| set.cpp:20:7:20:8 | ref arg s2 | set.cpp:26:7:26:8 | s2 | | +| set.cpp:20:7:20:8 | ref arg s2 | set.cpp:32:7:32:8 | s2 | | +| set.cpp:20:7:20:8 | ref arg s2 | set.cpp:39:22:39:23 | s2 | | +| set.cpp:20:7:20:8 | ref arg s2 | set.cpp:40:24:40:25 | s2 | | +| set.cpp:20:7:20:8 | ref arg s2 | set.cpp:41:22:41:23 | s2 | | +| set.cpp:20:7:20:8 | ref arg s2 | set.cpp:41:34:41:35 | s2 | | +| set.cpp:20:7:20:8 | ref arg s2 | set.cpp:43:8:43:9 | s2 | | +| set.cpp:20:7:20:8 | ref arg s2 | set.cpp:59:12:59:13 | s2 | | +| set.cpp:20:7:20:8 | ref arg s2 | set.cpp:59:30:59:31 | s2 | | +| set.cpp:20:7:20:8 | ref arg s2 | set.cpp:126:1:126:1 | s2 | | +| set.cpp:20:17:20:22 | call to source | set.cpp:20:7:20:8 | ref arg s2 | TAINT | +| set.cpp:20:17:20:22 | call to source | set.cpp:20:10:20:15 | call to insert | TAINT | +| set.cpp:20:27:20:31 | first | set.cpp:20:7:20:31 | call to iterator | | +| set.cpp:21:7:21:8 | ref arg s3 | set.cpp:27:7:27:8 | s3 | | +| set.cpp:21:7:21:8 | ref arg s3 | set.cpp:33:7:33:8 | s3 | | +| set.cpp:21:7:21:8 | ref arg s3 | set.cpp:126:1:126:1 | s3 | | +| set.cpp:21:17:21:18 | ref arg s3 | set.cpp:21:7:21:8 | s3 | | +| set.cpp:21:17:21:18 | ref arg s3 | set.cpp:27:7:27:8 | s3 | | +| set.cpp:21:17:21:18 | ref arg s3 | set.cpp:33:7:33:8 | s3 | | +| set.cpp:21:17:21:18 | ref arg s3 | set.cpp:126:1:126:1 | s3 | | +| set.cpp:21:17:21:18 | s3 | set.cpp:21:20:21:24 | call to begin | TAINT | +| set.cpp:21:20:21:24 | call to begin | set.cpp:21:17:21:26 | call to iterator | TAINT | +| set.cpp:21:29:21:33 | abc | set.cpp:21:7:21:8 | ref arg s3 | TAINT | +| set.cpp:21:29:21:33 | abc | set.cpp:21:10:21:15 | call to insert | TAINT | +| set.cpp:22:7:22:8 | ref arg s4 | set.cpp:28:7:28:8 | s4 | | +| set.cpp:22:7:22:8 | ref arg s4 | set.cpp:34:7:34:8 | s4 | | +| set.cpp:22:7:22:8 | ref arg s4 | set.cpp:126:1:126:1 | s4 | | +| set.cpp:22:17:22:18 | ref arg s4 | set.cpp:22:7:22:8 | s4 | | +| set.cpp:22:17:22:18 | ref arg s4 | set.cpp:28:7:28:8 | s4 | | +| set.cpp:22:17:22:18 | ref arg s4 | set.cpp:34:7:34:8 | s4 | | +| set.cpp:22:17:22:18 | ref arg s4 | set.cpp:126:1:126:1 | s4 | | +| set.cpp:22:17:22:18 | s4 | set.cpp:22:20:22:24 | call to begin | TAINT | +| set.cpp:22:20:22:24 | call to begin | set.cpp:22:17:22:26 | call to iterator | TAINT | +| set.cpp:22:29:22:34 | call to source | set.cpp:22:7:22:8 | ref arg s4 | TAINT | +| set.cpp:22:29:22:34 | call to source | set.cpp:22:10:22:15 | call to insert | TAINT | +| set.cpp:23:2:23:3 | ref arg s5 | set.cpp:29:7:29:8 | s5 | | +| set.cpp:23:2:23:3 | ref arg s5 | set.cpp:35:7:35:8 | s5 | | +| set.cpp:23:2:23:3 | ref arg s5 | set.cpp:126:1:126:1 | s5 | | +| set.cpp:23:12:23:13 | ref arg s1 | set.cpp:23:24:23:25 | s1 | | +| set.cpp:23:12:23:13 | ref arg s1 | set.cpp:25:7:25:8 | s1 | | +| set.cpp:23:12:23:13 | ref arg s1 | set.cpp:31:7:31:8 | s1 | | +| set.cpp:23:12:23:13 | ref arg s1 | set.cpp:55:12:55:13 | s1 | | +| set.cpp:23:12:23:13 | ref arg s1 | set.cpp:55:30:55:31 | s1 | | +| set.cpp:23:12:23:13 | ref arg s1 | set.cpp:126:1:126:1 | s1 | | +| set.cpp:23:12:23:13 | s1 | set.cpp:23:15:23:19 | call to begin | TAINT | +| set.cpp:23:24:23:25 | ref arg s1 | set.cpp:25:7:25:8 | s1 | | +| set.cpp:23:24:23:25 | ref arg s1 | set.cpp:31:7:31:8 | s1 | | +| set.cpp:23:24:23:25 | ref arg s1 | set.cpp:55:12:55:13 | s1 | | +| set.cpp:23:24:23:25 | ref arg s1 | set.cpp:55:30:55:31 | s1 | | +| set.cpp:23:24:23:25 | ref arg s1 | set.cpp:126:1:126:1 | s1 | | +| set.cpp:23:24:23:25 | s1 | set.cpp:23:27:23:29 | call to end | TAINT | +| set.cpp:23:27:23:29 | call to end | set.cpp:23:2:23:3 | ref arg s5 | TAINT | +| set.cpp:23:27:23:29 | call to end | set.cpp:23:5:23:10 | call to insert | TAINT | +| set.cpp:24:2:24:3 | ref arg s6 | set.cpp:30:7:30:8 | s6 | | +| set.cpp:24:2:24:3 | ref arg s6 | set.cpp:36:7:36:8 | s6 | | +| set.cpp:24:2:24:3 | ref arg s6 | set.cpp:126:1:126:1 | s6 | | +| set.cpp:24:12:24:13 | ref arg s2 | set.cpp:24:24:24:25 | s2 | | +| set.cpp:24:12:24:13 | ref arg s2 | set.cpp:26:7:26:8 | s2 | | +| set.cpp:24:12:24:13 | ref arg s2 | set.cpp:32:7:32:8 | s2 | | +| set.cpp:24:12:24:13 | ref arg s2 | set.cpp:39:22:39:23 | s2 | | +| set.cpp:24:12:24:13 | ref arg s2 | set.cpp:40:24:40:25 | s2 | | +| set.cpp:24:12:24:13 | ref arg s2 | set.cpp:41:22:41:23 | s2 | | +| set.cpp:24:12:24:13 | ref arg s2 | set.cpp:41:34:41:35 | s2 | | +| set.cpp:24:12:24:13 | ref arg s2 | set.cpp:43:8:43:9 | s2 | | +| set.cpp:24:12:24:13 | ref arg s2 | set.cpp:59:12:59:13 | s2 | | +| set.cpp:24:12:24:13 | ref arg s2 | set.cpp:59:30:59:31 | s2 | | +| set.cpp:24:12:24:13 | ref arg s2 | set.cpp:126:1:126:1 | s2 | | +| set.cpp:24:12:24:13 | s2 | set.cpp:24:15:24:19 | call to begin | TAINT | +| set.cpp:24:24:24:25 | ref arg s2 | set.cpp:26:7:26:8 | s2 | | +| set.cpp:24:24:24:25 | ref arg s2 | set.cpp:32:7:32:8 | s2 | | +| set.cpp:24:24:24:25 | ref arg s2 | set.cpp:39:22:39:23 | s2 | | +| set.cpp:24:24:24:25 | ref arg s2 | set.cpp:40:24:40:25 | s2 | | +| set.cpp:24:24:24:25 | ref arg s2 | set.cpp:41:22:41:23 | s2 | | +| set.cpp:24:24:24:25 | ref arg s2 | set.cpp:41:34:41:35 | s2 | | +| set.cpp:24:24:24:25 | ref arg s2 | set.cpp:43:8:43:9 | s2 | | +| set.cpp:24:24:24:25 | ref arg s2 | set.cpp:59:12:59:13 | s2 | | +| set.cpp:24:24:24:25 | ref arg s2 | set.cpp:59:30:59:31 | s2 | | +| set.cpp:24:24:24:25 | ref arg s2 | set.cpp:126:1:126:1 | s2 | | +| set.cpp:24:24:24:25 | s2 | set.cpp:24:27:24:29 | call to end | TAINT | +| set.cpp:24:27:24:29 | call to end | set.cpp:24:2:24:3 | ref arg s6 | TAINT | +| set.cpp:24:27:24:29 | call to end | set.cpp:24:5:24:10 | call to insert | TAINT | +| set.cpp:25:7:25:8 | s1 | set.cpp:25:7:25:8 | call to set | | +| set.cpp:26:7:26:8 | s2 | set.cpp:26:7:26:8 | call to set | | +| set.cpp:27:7:27:8 | s3 | set.cpp:27:7:27:8 | call to set | | +| set.cpp:28:7:28:8 | s4 | set.cpp:28:7:28:8 | call to set | | +| set.cpp:29:7:29:8 | s5 | set.cpp:29:7:29:8 | call to set | | +| set.cpp:30:7:30:8 | s6 | set.cpp:30:7:30:8 | call to set | | +| set.cpp:31:7:31:8 | ref arg s1 | set.cpp:55:12:55:13 | s1 | | +| set.cpp:31:7:31:8 | ref arg s1 | set.cpp:55:30:55:31 | s1 | | +| set.cpp:31:7:31:8 | ref arg s1 | set.cpp:126:1:126:1 | s1 | | +| set.cpp:31:7:31:8 | s1 | set.cpp:31:10:31:13 | call to find | TAINT | +| set.cpp:32:7:32:8 | ref arg s2 | set.cpp:39:22:39:23 | s2 | | +| set.cpp:32:7:32:8 | ref arg s2 | set.cpp:40:24:40:25 | s2 | | +| set.cpp:32:7:32:8 | ref arg s2 | set.cpp:41:22:41:23 | s2 | | +| set.cpp:32:7:32:8 | ref arg s2 | set.cpp:41:34:41:35 | s2 | | +| set.cpp:32:7:32:8 | ref arg s2 | set.cpp:43:8:43:9 | s2 | | +| set.cpp:32:7:32:8 | ref arg s2 | set.cpp:59:12:59:13 | s2 | | +| set.cpp:32:7:32:8 | ref arg s2 | set.cpp:59:30:59:31 | s2 | | +| set.cpp:32:7:32:8 | ref arg s2 | set.cpp:126:1:126:1 | s2 | | +| set.cpp:32:7:32:8 | s2 | set.cpp:32:10:32:13 | call to find | TAINT | +| set.cpp:33:7:33:8 | ref arg s3 | set.cpp:126:1:126:1 | s3 | | +| set.cpp:33:7:33:8 | s3 | set.cpp:33:10:33:13 | call to find | TAINT | +| set.cpp:34:7:34:8 | ref arg s4 | set.cpp:126:1:126:1 | s4 | | +| set.cpp:34:7:34:8 | s4 | set.cpp:34:10:34:13 | call to find | TAINT | +| set.cpp:35:7:35:8 | ref arg s5 | set.cpp:126:1:126:1 | s5 | | +| set.cpp:35:7:35:8 | s5 | set.cpp:35:10:35:13 | call to find | TAINT | +| set.cpp:36:7:36:8 | ref arg s6 | set.cpp:126:1:126:1 | s6 | | +| set.cpp:36:7:36:8 | s6 | set.cpp:36:10:36:13 | call to find | TAINT | +| set.cpp:39:22:39:23 | s2 | set.cpp:39:22:39:24 | call to set | | +| set.cpp:39:22:39:24 | call to set | set.cpp:44:7:44:8 | s7 | | +| set.cpp:39:22:39:24 | call to set | set.cpp:48:7:48:8 | s7 | | +| set.cpp:39:22:39:24 | call to set | set.cpp:126:1:126:1 | s7 | | +| set.cpp:40:23:40:25 | call to set | set.cpp:45:7:45:8 | s8 | | +| set.cpp:40:23:40:25 | call to set | set.cpp:49:7:49:8 | s8 | | +| set.cpp:40:23:40:25 | call to set | set.cpp:126:1:126:1 | s8 | | +| set.cpp:40:24:40:25 | s2 | set.cpp:40:23:40:25 | call to set | | +| set.cpp:41:22:41:23 | ref arg s2 | set.cpp:41:34:41:35 | s2 | | +| set.cpp:41:22:41:23 | ref arg s2 | set.cpp:43:8:43:9 | s2 | | +| set.cpp:41:22:41:23 | ref arg s2 | set.cpp:59:12:59:13 | s2 | | +| set.cpp:41:22:41:23 | ref arg s2 | set.cpp:59:30:59:31 | s2 | | +| set.cpp:41:22:41:23 | ref arg s2 | set.cpp:126:1:126:1 | s2 | | +| set.cpp:41:22:41:23 | s2 | set.cpp:41:25:41:29 | call to begin | TAINT | +| set.cpp:41:22:41:42 | call to set | set.cpp:46:7:46:8 | s9 | | +| set.cpp:41:22:41:42 | call to set | set.cpp:50:7:50:8 | s9 | | +| set.cpp:41:22:41:42 | call to set | set.cpp:126:1:126:1 | s9 | | +| set.cpp:41:25:41:29 | call to begin | set.cpp:41:22:41:42 | call to set | TAINT | +| set.cpp:41:34:41:35 | ref arg s2 | set.cpp:43:8:43:9 | s2 | | +| set.cpp:41:34:41:35 | ref arg s2 | set.cpp:59:12:59:13 | s2 | | +| set.cpp:41:34:41:35 | ref arg s2 | set.cpp:59:30:59:31 | s2 | | +| set.cpp:41:34:41:35 | ref arg s2 | set.cpp:126:1:126:1 | s2 | | +| set.cpp:41:34:41:35 | s2 | set.cpp:41:37:41:39 | call to end | TAINT | +| set.cpp:41:37:41:39 | call to end | set.cpp:41:22:41:42 | call to set | TAINT | +| set.cpp:42:19:42:21 | call to set | set.cpp:43:2:43:4 | s10 | | +| set.cpp:42:19:42:21 | call to set | set.cpp:47:7:47:9 | s10 | | +| set.cpp:42:19:42:21 | call to set | set.cpp:51:7:51:9 | s10 | | +| set.cpp:42:19:42:21 | call to set | set.cpp:126:1:126:1 | s10 | | +| set.cpp:43:2:43:4 | ref arg s10 | set.cpp:47:7:47:9 | s10 | | +| set.cpp:43:2:43:4 | ref arg s10 | set.cpp:51:7:51:9 | s10 | | +| set.cpp:43:2:43:4 | ref arg s10 | set.cpp:126:1:126:1 | s10 | | +| set.cpp:43:8:43:9 | s2 | set.cpp:43:2:43:4 | ref arg s10 | TAINT | +| set.cpp:43:8:43:9 | s2 | set.cpp:43:6:43:6 | call to operator= | TAINT | +| set.cpp:44:7:44:8 | s7 | set.cpp:44:7:44:8 | call to set | | +| set.cpp:45:7:45:8 | s8 | set.cpp:45:7:45:8 | call to set | | +| set.cpp:46:7:46:8 | s9 | set.cpp:46:7:46:8 | call to set | | +| set.cpp:47:7:47:9 | s10 | set.cpp:47:7:47:9 | call to set | | +| set.cpp:48:7:48:8 | ref arg s7 | set.cpp:126:1:126:1 | s7 | | +| set.cpp:48:7:48:8 | s7 | set.cpp:48:10:48:13 | call to find | TAINT | +| set.cpp:49:7:49:8 | ref arg s8 | set.cpp:126:1:126:1 | s8 | | +| set.cpp:49:7:49:8 | s8 | set.cpp:49:10:49:13 | call to find | TAINT | +| set.cpp:50:7:50:8 | ref arg s9 | set.cpp:126:1:126:1 | s9 | | +| set.cpp:50:7:50:8 | s9 | set.cpp:50:10:50:13 | call to find | TAINT | +| set.cpp:51:7:51:9 | ref arg s10 | set.cpp:126:1:126:1 | s10 | | +| set.cpp:51:7:51:9 | s10 | set.cpp:51:11:51:14 | call to find | TAINT | +| set.cpp:55:12:55:13 | ref arg s1 | set.cpp:55:30:55:31 | s1 | | +| set.cpp:55:12:55:13 | ref arg s1 | set.cpp:126:1:126:1 | s1 | | +| set.cpp:55:12:55:13 | s1 | set.cpp:55:15:55:19 | call to begin | TAINT | +| set.cpp:55:15:55:19 | call to begin | set.cpp:55:7:55:21 | ... = ... | | +| set.cpp:55:15:55:19 | call to begin | set.cpp:55:24:55:25 | i1 | | +| set.cpp:55:15:55:19 | call to begin | set.cpp:55:40:55:41 | i1 | | +| set.cpp:55:15:55:19 | call to begin | set.cpp:57:9:57:10 | i1 | | +| set.cpp:55:30:55:31 | ref arg s1 | set.cpp:55:30:55:31 | s1 | | +| set.cpp:55:30:55:31 | ref arg s1 | set.cpp:126:1:126:1 | s1 | | +| set.cpp:55:30:55:31 | s1 | set.cpp:55:33:55:35 | call to end | TAINT | +| set.cpp:55:40:55:41 | i1 | set.cpp:55:42:55:42 | call to operator++ | | +| set.cpp:55:40:55:41 | ref arg i1 | set.cpp:55:24:55:25 | i1 | | +| set.cpp:55:40:55:41 | ref arg i1 | set.cpp:55:40:55:41 | i1 | | +| set.cpp:55:40:55:41 | ref arg i1 | set.cpp:57:9:57:10 | i1 | | +| set.cpp:57:9:57:10 | i1 | set.cpp:57:8:57:8 | call to operator* | TAINT | +| set.cpp:59:12:59:13 | ref arg s2 | set.cpp:59:30:59:31 | s2 | | +| set.cpp:59:12:59:13 | ref arg s2 | set.cpp:126:1:126:1 | s2 | | +| set.cpp:59:12:59:13 | s2 | set.cpp:59:15:59:19 | call to begin | TAINT | +| set.cpp:59:15:59:19 | call to begin | set.cpp:59:7:59:21 | ... = ... | | +| set.cpp:59:15:59:19 | call to begin | set.cpp:59:24:59:25 | i2 | | +| set.cpp:59:15:59:19 | call to begin | set.cpp:59:40:59:41 | i2 | | +| set.cpp:59:15:59:19 | call to begin | set.cpp:61:9:61:10 | i2 | | +| set.cpp:59:30:59:31 | ref arg s2 | set.cpp:59:30:59:31 | s2 | | +| set.cpp:59:30:59:31 | ref arg s2 | set.cpp:126:1:126:1 | s2 | | +| set.cpp:59:30:59:31 | s2 | set.cpp:59:33:59:35 | call to end | TAINT | +| set.cpp:59:40:59:41 | i2 | set.cpp:59:42:59:42 | call to operator++ | | +| set.cpp:59:40:59:41 | ref arg i2 | set.cpp:59:24:59:25 | i2 | | +| set.cpp:59:40:59:41 | ref arg i2 | set.cpp:59:40:59:41 | i2 | | +| set.cpp:59:40:59:41 | ref arg i2 | set.cpp:61:9:61:10 | i2 | | +| set.cpp:61:9:61:10 | i2 | set.cpp:61:8:61:8 | call to operator* | TAINT | +| set.cpp:65:19:65:21 | call to set | set.cpp:66:2:66:4 | s11 | | +| set.cpp:65:19:65:21 | call to set | set.cpp:67:2:67:4 | s11 | | +| set.cpp:65:19:65:21 | call to set | set.cpp:68:2:68:4 | s11 | | +| set.cpp:65:19:65:21 | call to set | set.cpp:69:7:69:9 | s11 | | +| set.cpp:65:19:65:21 | call to set | set.cpp:70:7:70:9 | s11 | | +| set.cpp:65:19:65:21 | call to set | set.cpp:71:7:71:9 | s11 | | +| set.cpp:65:19:65:21 | call to set | set.cpp:72:7:72:9 | s11 | | +| set.cpp:65:19:65:21 | call to set | set.cpp:126:1:126:1 | s11 | | +| set.cpp:66:2:66:4 | ref arg s11 | set.cpp:67:2:67:4 | s11 | | +| set.cpp:66:2:66:4 | ref arg s11 | set.cpp:68:2:68:4 | s11 | | +| set.cpp:66:2:66:4 | ref arg s11 | set.cpp:69:7:69:9 | s11 | | +| set.cpp:66:2:66:4 | ref arg s11 | set.cpp:70:7:70:9 | s11 | | +| set.cpp:66:2:66:4 | ref arg s11 | set.cpp:71:7:71:9 | s11 | | +| set.cpp:66:2:66:4 | ref arg s11 | set.cpp:72:7:72:9 | s11 | | +| set.cpp:66:2:66:4 | ref arg s11 | set.cpp:126:1:126:1 | s11 | | +| set.cpp:66:13:66:15 | a | set.cpp:66:2:66:4 | ref arg s11 | TAINT | +| set.cpp:66:13:66:15 | a | set.cpp:66:6:66:11 | call to insert | TAINT | +| set.cpp:67:2:67:4 | ref arg s11 | set.cpp:68:2:68:4 | s11 | | +| set.cpp:67:2:67:4 | ref arg s11 | set.cpp:69:7:69:9 | s11 | | +| set.cpp:67:2:67:4 | ref arg s11 | set.cpp:70:7:70:9 | s11 | | +| set.cpp:67:2:67:4 | ref arg s11 | set.cpp:71:7:71:9 | s11 | | +| set.cpp:67:2:67:4 | ref arg s11 | set.cpp:72:7:72:9 | s11 | | +| set.cpp:67:2:67:4 | ref arg s11 | set.cpp:126:1:126:1 | s11 | | +| set.cpp:67:13:67:18 | call to source | set.cpp:67:2:67:4 | ref arg s11 | TAINT | +| set.cpp:67:13:67:18 | call to source | set.cpp:67:6:67:11 | call to insert | TAINT | +| set.cpp:68:2:68:4 | ref arg s11 | set.cpp:69:7:69:9 | s11 | | +| set.cpp:68:2:68:4 | ref arg s11 | set.cpp:70:7:70:9 | s11 | | +| set.cpp:68:2:68:4 | ref arg s11 | set.cpp:71:7:71:9 | s11 | | +| set.cpp:68:2:68:4 | ref arg s11 | set.cpp:72:7:72:9 | s11 | | +| set.cpp:68:2:68:4 | ref arg s11 | set.cpp:126:1:126:1 | s11 | | +| set.cpp:68:13:68:15 | c | set.cpp:68:2:68:4 | ref arg s11 | TAINT | +| set.cpp:68:13:68:15 | c | set.cpp:68:6:68:11 | call to insert | TAINT | +| set.cpp:69:7:69:9 | ref arg s11 | set.cpp:70:7:70:9 | s11 | | +| set.cpp:69:7:69:9 | ref arg s11 | set.cpp:71:7:71:9 | s11 | | +| set.cpp:69:7:69:9 | ref arg s11 | set.cpp:72:7:72:9 | s11 | | +| set.cpp:69:7:69:9 | ref arg s11 | set.cpp:126:1:126:1 | s11 | | +| set.cpp:69:7:69:9 | s11 | set.cpp:69:11:69:21 | call to lower_bound | TAINT | +| set.cpp:70:7:70:9 | ref arg s11 | set.cpp:71:7:71:9 | s11 | | +| set.cpp:70:7:70:9 | ref arg s11 | set.cpp:72:7:72:9 | s11 | | +| set.cpp:70:7:70:9 | ref arg s11 | set.cpp:126:1:126:1 | s11 | | +| set.cpp:70:7:70:9 | s11 | set.cpp:70:11:70:21 | call to upper_bound | TAINT | +| set.cpp:71:7:71:9 | ref arg s11 | set.cpp:72:7:72:9 | s11 | | +| set.cpp:71:7:71:9 | ref arg s11 | set.cpp:126:1:126:1 | s11 | | +| set.cpp:71:7:71:9 | s11 | set.cpp:71:11:71:21 | call to equal_range | TAINT | +| set.cpp:71:28:71:32 | first | set.cpp:71:7:71:32 | call to iterator | | +| set.cpp:72:7:72:9 | ref arg s11 | set.cpp:126:1:126:1 | s11 | | +| set.cpp:72:7:72:9 | s11 | set.cpp:72:11:72:21 | call to equal_range | TAINT | +| set.cpp:72:28:72:33 | second | set.cpp:72:7:72:33 | call to iterator | | +| set.cpp:75:19:75:21 | call to set | set.cpp:76:2:76:4 | s12 | | +| set.cpp:75:19:75:21 | call to set | set.cpp:78:7:78:9 | s12 | | +| set.cpp:75:19:75:21 | call to set | set.cpp:82:2:82:4 | s12 | | +| set.cpp:75:19:75:21 | call to set | set.cpp:84:7:84:9 | s12 | | +| set.cpp:75:19:75:21 | call to set | set.cpp:126:1:126:1 | s12 | | +| set.cpp:75:24:75:26 | call to set | set.cpp:79:7:79:9 | s13 | | +| set.cpp:75:24:75:26 | call to set | set.cpp:82:11:82:13 | s13 | | +| set.cpp:75:24:75:26 | call to set | set.cpp:85:7:85:9 | s13 | | +| set.cpp:75:24:75:26 | call to set | set.cpp:126:1:126:1 | s13 | | +| set.cpp:75:29:75:31 | call to set | set.cpp:80:7:80:9 | s14 | | +| set.cpp:75:29:75:31 | call to set | set.cpp:83:2:83:4 | s14 | | +| set.cpp:75:29:75:31 | call to set | set.cpp:86:7:86:9 | s14 | | +| set.cpp:75:29:75:31 | call to set | set.cpp:126:1:126:1 | s14 | | +| set.cpp:75:34:75:36 | call to set | set.cpp:77:2:77:4 | s15 | | +| set.cpp:75:34:75:36 | call to set | set.cpp:81:7:81:9 | s15 | | +| set.cpp:75:34:75:36 | call to set | set.cpp:83:11:83:13 | s15 | | +| set.cpp:75:34:75:36 | call to set | set.cpp:87:7:87:9 | s15 | | +| set.cpp:75:34:75:36 | call to set | set.cpp:126:1:126:1 | s15 | | +| set.cpp:76:2:76:4 | ref arg s12 | set.cpp:78:7:78:9 | s12 | | +| set.cpp:76:2:76:4 | ref arg s12 | set.cpp:82:2:82:4 | s12 | | +| set.cpp:76:2:76:4 | ref arg s12 | set.cpp:84:7:84:9 | s12 | | +| set.cpp:76:2:76:4 | ref arg s12 | set.cpp:126:1:126:1 | s12 | | +| set.cpp:76:13:76:18 | call to source | set.cpp:76:2:76:4 | ref arg s12 | TAINT | +| set.cpp:76:13:76:18 | call to source | set.cpp:76:6:76:11 | call to insert | TAINT | +| set.cpp:77:2:77:4 | ref arg s15 | set.cpp:81:7:81:9 | s15 | | +| set.cpp:77:2:77:4 | ref arg s15 | set.cpp:83:11:83:13 | s15 | | +| set.cpp:77:2:77:4 | ref arg s15 | set.cpp:87:7:87:9 | s15 | | +| set.cpp:77:2:77:4 | ref arg s15 | set.cpp:126:1:126:1 | s15 | | +| set.cpp:77:13:77:18 | call to source | set.cpp:77:2:77:4 | ref arg s15 | TAINT | +| set.cpp:77:13:77:18 | call to source | set.cpp:77:6:77:11 | call to insert | TAINT | +| set.cpp:78:7:78:9 | s12 | set.cpp:78:7:78:9 | call to set | | +| set.cpp:79:7:79:9 | s13 | set.cpp:79:7:79:9 | call to set | | +| set.cpp:80:7:80:9 | s14 | set.cpp:80:7:80:9 | call to set | | +| set.cpp:81:7:81:9 | s15 | set.cpp:81:7:81:9 | call to set | | +| set.cpp:82:2:82:4 | ref arg s12 | set.cpp:84:7:84:9 | s12 | | +| set.cpp:82:2:82:4 | ref arg s12 | set.cpp:126:1:126:1 | s12 | | +| set.cpp:82:2:82:4 | s12 | set.cpp:82:11:82:13 | ref arg s13 | TAINT | +| set.cpp:82:11:82:13 | ref arg s13 | set.cpp:85:7:85:9 | s13 | | +| set.cpp:82:11:82:13 | ref arg s13 | set.cpp:126:1:126:1 | s13 | | +| set.cpp:82:11:82:13 | s13 | set.cpp:82:2:82:4 | ref arg s12 | TAINT | +| set.cpp:83:2:83:4 | ref arg s14 | set.cpp:86:7:86:9 | s14 | | +| set.cpp:83:2:83:4 | ref arg s14 | set.cpp:126:1:126:1 | s14 | | +| set.cpp:83:2:83:4 | s14 | set.cpp:83:11:83:13 | ref arg s15 | TAINT | +| set.cpp:83:11:83:13 | ref arg s15 | set.cpp:87:7:87:9 | s15 | | +| set.cpp:83:11:83:13 | ref arg s15 | set.cpp:126:1:126:1 | s15 | | +| set.cpp:83:11:83:13 | s15 | set.cpp:83:2:83:4 | ref arg s14 | TAINT | +| set.cpp:84:7:84:9 | s12 | set.cpp:84:7:84:9 | call to set | | +| set.cpp:85:7:85:9 | s13 | set.cpp:85:7:85:9 | call to set | | +| set.cpp:86:7:86:9 | s14 | set.cpp:86:7:86:9 | call to set | | +| set.cpp:87:7:87:9 | s15 | set.cpp:87:7:87:9 | call to set | | +| set.cpp:90:19:90:21 | call to set | set.cpp:91:2:91:4 | s16 | | +| set.cpp:90:19:90:21 | call to set | set.cpp:95:7:95:9 | s16 | | +| set.cpp:90:19:90:21 | call to set | set.cpp:99:2:99:4 | s16 | | +| set.cpp:90:19:90:21 | call to set | set.cpp:101:7:101:9 | s16 | | +| set.cpp:90:19:90:21 | call to set | set.cpp:126:1:126:1 | s16 | | +| set.cpp:90:24:90:26 | call to set | set.cpp:92:2:92:4 | s17 | | +| set.cpp:90:24:90:26 | call to set | set.cpp:96:7:96:9 | s17 | | +| set.cpp:90:24:90:26 | call to set | set.cpp:99:12:99:14 | s17 | | +| set.cpp:90:24:90:26 | call to set | set.cpp:102:7:102:9 | s17 | | +| set.cpp:90:24:90:26 | call to set | set.cpp:126:1:126:1 | s17 | | +| set.cpp:90:29:90:31 | call to set | set.cpp:93:2:93:4 | s18 | | +| set.cpp:90:29:90:31 | call to set | set.cpp:97:7:97:9 | s18 | | +| set.cpp:90:29:90:31 | call to set | set.cpp:100:2:100:4 | s18 | | +| set.cpp:90:29:90:31 | call to set | set.cpp:103:7:103:9 | s18 | | +| set.cpp:90:29:90:31 | call to set | set.cpp:126:1:126:1 | s18 | | +| set.cpp:90:34:90:36 | call to set | set.cpp:94:2:94:4 | s19 | | +| set.cpp:90:34:90:36 | call to set | set.cpp:98:7:98:9 | s19 | | +| set.cpp:90:34:90:36 | call to set | set.cpp:100:12:100:14 | s19 | | +| set.cpp:90:34:90:36 | call to set | set.cpp:104:7:104:9 | s19 | | +| set.cpp:90:34:90:36 | call to set | set.cpp:126:1:126:1 | s19 | | +| set.cpp:91:2:91:4 | ref arg s16 | set.cpp:95:7:95:9 | s16 | | +| set.cpp:91:2:91:4 | ref arg s16 | set.cpp:99:2:99:4 | s16 | | +| set.cpp:91:2:91:4 | ref arg s16 | set.cpp:101:7:101:9 | s16 | | +| set.cpp:91:2:91:4 | ref arg s16 | set.cpp:126:1:126:1 | s16 | | +| set.cpp:91:13:91:18 | call to source | set.cpp:91:2:91:4 | ref arg s16 | TAINT | +| set.cpp:91:13:91:18 | call to source | set.cpp:91:6:91:11 | call to insert | TAINT | +| set.cpp:92:2:92:4 | ref arg s17 | set.cpp:96:7:96:9 | s17 | | +| set.cpp:92:2:92:4 | ref arg s17 | set.cpp:99:12:99:14 | s17 | | +| set.cpp:92:2:92:4 | ref arg s17 | set.cpp:102:7:102:9 | s17 | | +| set.cpp:92:2:92:4 | ref arg s17 | set.cpp:126:1:126:1 | s17 | | +| set.cpp:92:13:92:17 | abc | set.cpp:92:2:92:4 | ref arg s17 | TAINT | +| set.cpp:92:13:92:17 | abc | set.cpp:92:6:92:11 | call to insert | TAINT | +| set.cpp:93:2:93:4 | ref arg s18 | set.cpp:97:7:97:9 | s18 | | +| set.cpp:93:2:93:4 | ref arg s18 | set.cpp:100:2:100:4 | s18 | | +| set.cpp:93:2:93:4 | ref arg s18 | set.cpp:103:7:103:9 | s18 | | +| set.cpp:93:2:93:4 | ref arg s18 | set.cpp:126:1:126:1 | s18 | | +| set.cpp:93:13:93:17 | def | set.cpp:93:2:93:4 | ref arg s18 | TAINT | +| set.cpp:93:13:93:17 | def | set.cpp:93:6:93:11 | call to insert | TAINT | +| set.cpp:94:2:94:4 | ref arg s19 | set.cpp:98:7:98:9 | s19 | | +| set.cpp:94:2:94:4 | ref arg s19 | set.cpp:100:12:100:14 | s19 | | +| set.cpp:94:2:94:4 | ref arg s19 | set.cpp:104:7:104:9 | s19 | | +| set.cpp:94:2:94:4 | ref arg s19 | set.cpp:126:1:126:1 | s19 | | +| set.cpp:94:13:94:18 | call to source | set.cpp:94:2:94:4 | ref arg s19 | TAINT | +| set.cpp:94:13:94:18 | call to source | set.cpp:94:6:94:11 | call to insert | TAINT | +| set.cpp:95:7:95:9 | s16 | set.cpp:95:7:95:9 | call to set | | +| set.cpp:96:7:96:9 | s17 | set.cpp:96:7:96:9 | call to set | | +| set.cpp:97:7:97:9 | s18 | set.cpp:97:7:97:9 | call to set | | +| set.cpp:98:7:98:9 | s19 | set.cpp:98:7:98:9 | call to set | | +| set.cpp:99:2:99:4 | ref arg s16 | set.cpp:101:7:101:9 | s16 | | +| set.cpp:99:2:99:4 | ref arg s16 | set.cpp:126:1:126:1 | s16 | | +| set.cpp:99:12:99:14 | ref arg s17 | set.cpp:102:7:102:9 | s17 | | +| set.cpp:99:12:99:14 | ref arg s17 | set.cpp:126:1:126:1 | s17 | | +| set.cpp:99:12:99:14 | s17 | set.cpp:99:2:99:4 | ref arg s16 | TAINT | +| set.cpp:100:2:100:4 | ref arg s18 | set.cpp:103:7:103:9 | s18 | | +| set.cpp:100:2:100:4 | ref arg s18 | set.cpp:126:1:126:1 | s18 | | +| set.cpp:100:12:100:14 | ref arg s19 | set.cpp:104:7:104:9 | s19 | | +| set.cpp:100:12:100:14 | ref arg s19 | set.cpp:126:1:126:1 | s19 | | +| set.cpp:100:12:100:14 | s19 | set.cpp:100:2:100:4 | ref arg s18 | TAINT | +| set.cpp:101:7:101:9 | s16 | set.cpp:101:7:101:9 | call to set | | +| set.cpp:102:7:102:9 | s17 | set.cpp:102:7:102:9 | call to set | | +| set.cpp:103:7:103:9 | s18 | set.cpp:103:7:103:9 | call to set | | +| set.cpp:104:7:104:9 | s19 | set.cpp:104:7:104:9 | call to set | | +| set.cpp:107:19:107:21 | call to set | set.cpp:108:2:108:4 | s20 | | +| set.cpp:107:19:107:21 | call to set | set.cpp:109:2:109:4 | s20 | | +| set.cpp:107:19:107:21 | call to set | set.cpp:110:7:110:9 | s20 | | +| set.cpp:107:19:107:21 | call to set | set.cpp:111:7:111:9 | s20 | | +| set.cpp:107:19:107:21 | call to set | set.cpp:111:17:111:19 | s20 | | +| set.cpp:107:19:107:21 | call to set | set.cpp:112:7:112:9 | s20 | | +| set.cpp:107:19:107:21 | call to set | set.cpp:113:2:113:4 | s20 | | +| set.cpp:107:19:107:21 | call to set | set.cpp:114:7:114:9 | s20 | | +| set.cpp:107:19:107:21 | call to set | set.cpp:126:1:126:1 | s20 | | +| set.cpp:108:2:108:4 | ref arg s20 | set.cpp:109:2:109:4 | s20 | | +| set.cpp:108:2:108:4 | ref arg s20 | set.cpp:110:7:110:9 | s20 | | +| set.cpp:108:2:108:4 | ref arg s20 | set.cpp:111:7:111:9 | s20 | | +| set.cpp:108:2:108:4 | ref arg s20 | set.cpp:111:17:111:19 | s20 | | +| set.cpp:108:2:108:4 | ref arg s20 | set.cpp:112:7:112:9 | s20 | | +| set.cpp:108:2:108:4 | ref arg s20 | set.cpp:113:2:113:4 | s20 | | +| set.cpp:108:2:108:4 | ref arg s20 | set.cpp:114:7:114:9 | s20 | | +| set.cpp:108:2:108:4 | ref arg s20 | set.cpp:126:1:126:1 | s20 | | +| set.cpp:108:13:108:18 | call to source | set.cpp:108:2:108:4 | ref arg s20 | TAINT | +| set.cpp:108:13:108:18 | call to source | set.cpp:108:6:108:11 | call to insert | TAINT | +| set.cpp:109:2:109:4 | ref arg s20 | set.cpp:110:7:110:9 | s20 | | +| set.cpp:109:2:109:4 | ref arg s20 | set.cpp:111:7:111:9 | s20 | | +| set.cpp:109:2:109:4 | ref arg s20 | set.cpp:111:17:111:19 | s20 | | +| set.cpp:109:2:109:4 | ref arg s20 | set.cpp:112:7:112:9 | s20 | | +| set.cpp:109:2:109:4 | ref arg s20 | set.cpp:113:2:113:4 | s20 | | +| set.cpp:109:2:109:4 | ref arg s20 | set.cpp:114:7:114:9 | s20 | | +| set.cpp:109:2:109:4 | ref arg s20 | set.cpp:126:1:126:1 | s20 | | +| set.cpp:109:13:109:18 | call to source | set.cpp:109:2:109:4 | ref arg s20 | TAINT | +| set.cpp:109:13:109:18 | call to source | set.cpp:109:6:109:11 | call to insert | TAINT | +| set.cpp:110:7:110:9 | s20 | set.cpp:110:7:110:9 | call to set | | +| set.cpp:111:7:111:9 | ref arg s20 | set.cpp:112:7:112:9 | s20 | | +| set.cpp:111:7:111:9 | ref arg s20 | set.cpp:113:2:113:4 | s20 | | +| set.cpp:111:7:111:9 | ref arg s20 | set.cpp:114:7:114:9 | s20 | | +| set.cpp:111:7:111:9 | ref arg s20 | set.cpp:126:1:126:1 | s20 | | +| set.cpp:111:7:111:9 | s20 | set.cpp:111:11:111:15 | call to erase | TAINT | +| set.cpp:111:17:111:19 | ref arg s20 | set.cpp:111:7:111:9 | s20 | | +| set.cpp:111:17:111:19 | ref arg s20 | set.cpp:112:7:112:9 | s20 | | +| set.cpp:111:17:111:19 | ref arg s20 | set.cpp:113:2:113:4 | s20 | | +| set.cpp:111:17:111:19 | ref arg s20 | set.cpp:114:7:114:9 | s20 | | +| set.cpp:111:17:111:19 | ref arg s20 | set.cpp:126:1:126:1 | s20 | | +| set.cpp:111:17:111:19 | s20 | set.cpp:111:21:111:25 | call to begin | TAINT | +| set.cpp:112:7:112:9 | s20 | set.cpp:112:7:112:9 | call to set | | +| set.cpp:113:2:113:4 | ref arg s20 | set.cpp:114:7:114:9 | s20 | | +| set.cpp:113:2:113:4 | ref arg s20 | set.cpp:126:1:126:1 | s20 | | +| set.cpp:114:7:114:9 | s20 | set.cpp:114:7:114:9 | call to set | | +| set.cpp:117:19:117:21 | call to set | set.cpp:118:7:118:9 | s21 | | +| set.cpp:117:19:117:21 | call to set | set.cpp:119:7:119:9 | s21 | | +| set.cpp:117:19:117:21 | call to set | set.cpp:120:7:120:9 | s21 | | +| set.cpp:117:19:117:21 | call to set | set.cpp:121:7:121:9 | s21 | | +| set.cpp:117:19:117:21 | call to set | set.cpp:126:1:126:1 | s21 | | +| set.cpp:117:24:117:26 | call to set | set.cpp:122:7:122:9 | s22 | | +| set.cpp:117:24:117:26 | call to set | set.cpp:122:24:122:26 | s22 | | +| set.cpp:117:24:117:26 | call to set | set.cpp:123:7:123:9 | s22 | | +| set.cpp:117:24:117:26 | call to set | set.cpp:124:7:124:9 | s22 | | +| set.cpp:117:24:117:26 | call to set | set.cpp:124:24:124:26 | s22 | | +| set.cpp:117:24:117:26 | call to set | set.cpp:125:7:125:9 | s22 | | +| set.cpp:117:24:117:26 | call to set | set.cpp:126:1:126:1 | s22 | | +| set.cpp:118:7:118:9 | ref arg s21 | set.cpp:119:7:119:9 | s21 | | +| set.cpp:118:7:118:9 | ref arg s21 | set.cpp:120:7:120:9 | s21 | | +| set.cpp:118:7:118:9 | ref arg s21 | set.cpp:121:7:121:9 | s21 | | +| set.cpp:118:7:118:9 | ref arg s21 | set.cpp:126:1:126:1 | s21 | | +| set.cpp:118:7:118:9 | s21 | set.cpp:118:11:118:17 | call to emplace | TAINT | +| set.cpp:118:19:118:23 | abc | set.cpp:118:7:118:9 | ref arg s21 | TAINT | +| set.cpp:118:19:118:23 | abc | set.cpp:118:11:118:17 | call to emplace | TAINT | +| set.cpp:118:26:118:30 | first | set.cpp:118:7:118:30 | call to iterator | | +| set.cpp:119:7:119:9 | s21 | set.cpp:119:7:119:9 | call to set | | +| set.cpp:120:7:120:9 | ref arg s21 | set.cpp:121:7:121:9 | s21 | | +| set.cpp:120:7:120:9 | ref arg s21 | set.cpp:126:1:126:1 | s21 | | +| set.cpp:120:7:120:9 | s21 | set.cpp:120:11:120:17 | call to emplace | TAINT | +| set.cpp:120:19:120:24 | call to source | set.cpp:120:7:120:9 | ref arg s21 | TAINT | +| set.cpp:120:19:120:24 | call to source | set.cpp:120:11:120:17 | call to emplace | TAINT | +| set.cpp:120:29:120:33 | first | set.cpp:120:7:120:33 | call to iterator | | +| set.cpp:121:7:121:9 | s21 | set.cpp:121:7:121:9 | call to set | | +| set.cpp:122:7:122:9 | ref arg s22 | set.cpp:123:7:123:9 | s22 | | +| set.cpp:122:7:122:9 | ref arg s22 | set.cpp:124:7:124:9 | s22 | | +| set.cpp:122:7:122:9 | ref arg s22 | set.cpp:124:24:124:26 | s22 | | +| set.cpp:122:7:122:9 | ref arg s22 | set.cpp:125:7:125:9 | s22 | | +| set.cpp:122:7:122:9 | ref arg s22 | set.cpp:126:1:126:1 | s22 | | +| set.cpp:122:7:122:9 | s22 | set.cpp:122:11:122:22 | call to emplace_hint | TAINT | +| set.cpp:122:24:122:26 | ref arg s22 | set.cpp:122:7:122:9 | s22 | | +| set.cpp:122:24:122:26 | ref arg s22 | set.cpp:123:7:123:9 | s22 | | +| set.cpp:122:24:122:26 | ref arg s22 | set.cpp:124:7:124:9 | s22 | | +| set.cpp:122:24:122:26 | ref arg s22 | set.cpp:124:24:124:26 | s22 | | +| set.cpp:122:24:122:26 | ref arg s22 | set.cpp:125:7:125:9 | s22 | | +| set.cpp:122:24:122:26 | ref arg s22 | set.cpp:126:1:126:1 | s22 | | +| set.cpp:122:24:122:26 | s22 | set.cpp:122:28:122:32 | call to begin | TAINT | +| set.cpp:122:24:122:34 | call to iterator | set.cpp:122:7:122:9 | ref arg s22 | TAINT | +| set.cpp:122:24:122:34 | call to iterator | set.cpp:122:11:122:22 | call to emplace_hint | TAINT | +| set.cpp:122:28:122:32 | call to begin | set.cpp:122:24:122:34 | call to iterator | TAINT | +| set.cpp:122:37:122:41 | abc | set.cpp:122:7:122:9 | ref arg s22 | TAINT | +| set.cpp:122:37:122:41 | abc | set.cpp:122:11:122:22 | call to emplace_hint | TAINT | +| set.cpp:123:7:123:9 | s22 | set.cpp:123:7:123:9 | call to set | | +| set.cpp:124:7:124:9 | ref arg s22 | set.cpp:125:7:125:9 | s22 | | +| set.cpp:124:7:124:9 | ref arg s22 | set.cpp:126:1:126:1 | s22 | | +| set.cpp:124:7:124:9 | s22 | set.cpp:124:11:124:22 | call to emplace_hint | TAINT | +| set.cpp:124:24:124:26 | ref arg s22 | set.cpp:124:7:124:9 | s22 | | +| set.cpp:124:24:124:26 | ref arg s22 | set.cpp:125:7:125:9 | s22 | | +| set.cpp:124:24:124:26 | ref arg s22 | set.cpp:126:1:126:1 | s22 | | +| set.cpp:124:24:124:26 | s22 | set.cpp:124:28:124:32 | call to begin | TAINT | +| set.cpp:124:24:124:34 | call to iterator | set.cpp:124:7:124:9 | ref arg s22 | TAINT | +| set.cpp:124:24:124:34 | call to iterator | set.cpp:124:11:124:22 | call to emplace_hint | TAINT | +| set.cpp:124:28:124:32 | call to begin | set.cpp:124:24:124:34 | call to iterator | TAINT | +| set.cpp:124:37:124:42 | call to source | set.cpp:124:7:124:9 | ref arg s22 | TAINT | +| set.cpp:124:37:124:42 | call to source | set.cpp:124:11:124:22 | call to emplace_hint | TAINT | +| set.cpp:125:7:125:9 | s22 | set.cpp:125:7:125:9 | call to set | | +| set.cpp:131:29:131:30 | call to unordered_set | set.cpp:133:7:133:8 | s1 | | +| set.cpp:131:29:131:30 | call to unordered_set | set.cpp:137:12:137:13 | s1 | | +| set.cpp:131:29:131:30 | call to unordered_set | set.cpp:137:24:137:25 | s1 | | +| set.cpp:131:29:131:30 | call to unordered_set | set.cpp:139:7:139:8 | s1 | | +| set.cpp:131:29:131:30 | call to unordered_set | set.cpp:145:7:145:8 | s1 | | +| set.cpp:131:29:131:30 | call to unordered_set | set.cpp:169:12:169:13 | s1 | | +| set.cpp:131:29:131:30 | call to unordered_set | set.cpp:169:30:169:31 | s1 | | +| set.cpp:131:29:131:30 | call to unordered_set | set.cpp:238:1:238:1 | s1 | | +| set.cpp:131:33:131:34 | call to unordered_set | set.cpp:134:7:134:8 | s2 | | +| set.cpp:131:33:131:34 | call to unordered_set | set.cpp:138:12:138:13 | s2 | | +| set.cpp:131:33:131:34 | call to unordered_set | set.cpp:138:24:138:25 | s2 | | +| set.cpp:131:33:131:34 | call to unordered_set | set.cpp:140:7:140:8 | s2 | | +| set.cpp:131:33:131:34 | call to unordered_set | set.cpp:146:7:146:8 | s2 | | +| set.cpp:131:33:131:34 | call to unordered_set | set.cpp:153:32:153:33 | s2 | | +| set.cpp:131:33:131:34 | call to unordered_set | set.cpp:154:34:154:35 | s2 | | +| set.cpp:131:33:131:34 | call to unordered_set | set.cpp:155:32:155:33 | s2 | | +| set.cpp:131:33:131:34 | call to unordered_set | set.cpp:155:44:155:45 | s2 | | +| set.cpp:131:33:131:34 | call to unordered_set | set.cpp:157:8:157:9 | s2 | | +| set.cpp:131:33:131:34 | call to unordered_set | set.cpp:173:12:173:13 | s2 | | +| set.cpp:131:33:131:34 | call to unordered_set | set.cpp:173:30:173:31 | s2 | | +| set.cpp:131:33:131:34 | call to unordered_set | set.cpp:238:1:238:1 | s2 | | +| set.cpp:131:37:131:38 | call to unordered_set | set.cpp:135:7:135:8 | s3 | | +| set.cpp:131:37:131:38 | call to unordered_set | set.cpp:135:17:135:18 | s3 | | +| set.cpp:131:37:131:38 | call to unordered_set | set.cpp:141:7:141:8 | s3 | | +| set.cpp:131:37:131:38 | call to unordered_set | set.cpp:147:7:147:8 | s3 | | +| set.cpp:131:37:131:38 | call to unordered_set | set.cpp:238:1:238:1 | s3 | | +| set.cpp:131:41:131:42 | call to unordered_set | set.cpp:136:7:136:8 | s4 | | +| set.cpp:131:41:131:42 | call to unordered_set | set.cpp:136:17:136:18 | s4 | | +| set.cpp:131:41:131:42 | call to unordered_set | set.cpp:142:7:142:8 | s4 | | +| set.cpp:131:41:131:42 | call to unordered_set | set.cpp:148:7:148:8 | s4 | | +| set.cpp:131:41:131:42 | call to unordered_set | set.cpp:238:1:238:1 | s4 | | +| set.cpp:131:45:131:46 | call to unordered_set | set.cpp:137:2:137:3 | s5 | | +| set.cpp:131:45:131:46 | call to unordered_set | set.cpp:143:7:143:8 | s5 | | +| set.cpp:131:45:131:46 | call to unordered_set | set.cpp:149:7:149:8 | s5 | | +| set.cpp:131:45:131:46 | call to unordered_set | set.cpp:238:1:238:1 | s5 | | +| set.cpp:131:49:131:50 | call to unordered_set | set.cpp:138:2:138:3 | s6 | | +| set.cpp:131:49:131:50 | call to unordered_set | set.cpp:144:7:144:8 | s6 | | +| set.cpp:131:49:131:50 | call to unordered_set | set.cpp:150:7:150:8 | s6 | | +| set.cpp:131:49:131:50 | call to unordered_set | set.cpp:238:1:238:1 | s6 | | +| set.cpp:133:7:133:8 | ref arg s1 | set.cpp:137:12:137:13 | s1 | | +| set.cpp:133:7:133:8 | ref arg s1 | set.cpp:137:24:137:25 | s1 | | +| set.cpp:133:7:133:8 | ref arg s1 | set.cpp:139:7:139:8 | s1 | | +| set.cpp:133:7:133:8 | ref arg s1 | set.cpp:145:7:145:8 | s1 | | +| set.cpp:133:7:133:8 | ref arg s1 | set.cpp:169:12:169:13 | s1 | | +| set.cpp:133:7:133:8 | ref arg s1 | set.cpp:169:30:169:31 | s1 | | +| set.cpp:133:7:133:8 | ref arg s1 | set.cpp:238:1:238:1 | s1 | | +| set.cpp:133:17:133:21 | abc | set.cpp:133:7:133:8 | ref arg s1 | TAINT | +| set.cpp:133:17:133:21 | abc | set.cpp:133:10:133:15 | call to insert | TAINT | +| set.cpp:133:24:133:28 | first | set.cpp:133:7:133:28 | call to iterator | | +| set.cpp:134:7:134:8 | ref arg s2 | set.cpp:138:12:138:13 | s2 | | +| set.cpp:134:7:134:8 | ref arg s2 | set.cpp:138:24:138:25 | s2 | | +| set.cpp:134:7:134:8 | ref arg s2 | set.cpp:140:7:140:8 | s2 | | +| set.cpp:134:7:134:8 | ref arg s2 | set.cpp:146:7:146:8 | s2 | | +| set.cpp:134:7:134:8 | ref arg s2 | set.cpp:153:32:153:33 | s2 | | +| set.cpp:134:7:134:8 | ref arg s2 | set.cpp:154:34:154:35 | s2 | | +| set.cpp:134:7:134:8 | ref arg s2 | set.cpp:155:32:155:33 | s2 | | +| set.cpp:134:7:134:8 | ref arg s2 | set.cpp:155:44:155:45 | s2 | | +| set.cpp:134:7:134:8 | ref arg s2 | set.cpp:157:8:157:9 | s2 | | +| set.cpp:134:7:134:8 | ref arg s2 | set.cpp:173:12:173:13 | s2 | | +| set.cpp:134:7:134:8 | ref arg s2 | set.cpp:173:30:173:31 | s2 | | +| set.cpp:134:7:134:8 | ref arg s2 | set.cpp:238:1:238:1 | s2 | | +| set.cpp:134:17:134:22 | call to source | set.cpp:134:7:134:8 | ref arg s2 | TAINT | +| set.cpp:134:17:134:22 | call to source | set.cpp:134:10:134:15 | call to insert | TAINT | +| set.cpp:134:27:134:31 | first | set.cpp:134:7:134:31 | call to iterator | | +| set.cpp:135:7:135:8 | ref arg s3 | set.cpp:141:7:141:8 | s3 | | +| set.cpp:135:7:135:8 | ref arg s3 | set.cpp:147:7:147:8 | s3 | | +| set.cpp:135:7:135:8 | ref arg s3 | set.cpp:238:1:238:1 | s3 | | +| set.cpp:135:17:135:18 | ref arg s3 | set.cpp:135:7:135:8 | s3 | | +| set.cpp:135:17:135:18 | ref arg s3 | set.cpp:141:7:141:8 | s3 | | +| set.cpp:135:17:135:18 | ref arg s3 | set.cpp:147:7:147:8 | s3 | | +| set.cpp:135:17:135:18 | ref arg s3 | set.cpp:238:1:238:1 | s3 | | +| set.cpp:135:17:135:18 | s3 | set.cpp:135:20:135:24 | call to begin | TAINT | +| set.cpp:135:20:135:24 | call to begin | set.cpp:135:17:135:26 | call to iterator | TAINT | +| set.cpp:135:29:135:33 | abc | set.cpp:135:7:135:8 | ref arg s3 | TAINT | +| set.cpp:135:29:135:33 | abc | set.cpp:135:10:135:15 | call to insert | TAINT | +| set.cpp:136:7:136:8 | ref arg s4 | set.cpp:142:7:142:8 | s4 | | +| set.cpp:136:7:136:8 | ref arg s4 | set.cpp:148:7:148:8 | s4 | | +| set.cpp:136:7:136:8 | ref arg s4 | set.cpp:238:1:238:1 | s4 | | +| set.cpp:136:17:136:18 | ref arg s4 | set.cpp:136:7:136:8 | s4 | | +| set.cpp:136:17:136:18 | ref arg s4 | set.cpp:142:7:142:8 | s4 | | +| set.cpp:136:17:136:18 | ref arg s4 | set.cpp:148:7:148:8 | s4 | | +| set.cpp:136:17:136:18 | ref arg s4 | set.cpp:238:1:238:1 | s4 | | +| set.cpp:136:17:136:18 | s4 | set.cpp:136:20:136:24 | call to begin | TAINT | +| set.cpp:136:20:136:24 | call to begin | set.cpp:136:17:136:26 | call to iterator | TAINT | +| set.cpp:136:29:136:34 | call to source | set.cpp:136:7:136:8 | ref arg s4 | TAINT | +| set.cpp:136:29:136:34 | call to source | set.cpp:136:10:136:15 | call to insert | TAINT | +| set.cpp:137:2:137:3 | ref arg s5 | set.cpp:143:7:143:8 | s5 | | +| set.cpp:137:2:137:3 | ref arg s5 | set.cpp:149:7:149:8 | s5 | | +| set.cpp:137:2:137:3 | ref arg s5 | set.cpp:238:1:238:1 | s5 | | +| set.cpp:137:12:137:13 | ref arg s1 | set.cpp:137:24:137:25 | s1 | | +| set.cpp:137:12:137:13 | ref arg s1 | set.cpp:139:7:139:8 | s1 | | +| set.cpp:137:12:137:13 | ref arg s1 | set.cpp:145:7:145:8 | s1 | | +| set.cpp:137:12:137:13 | ref arg s1 | set.cpp:169:12:169:13 | s1 | | +| set.cpp:137:12:137:13 | ref arg s1 | set.cpp:169:30:169:31 | s1 | | +| set.cpp:137:12:137:13 | ref arg s1 | set.cpp:238:1:238:1 | s1 | | +| set.cpp:137:12:137:13 | s1 | set.cpp:137:15:137:19 | call to begin | TAINT | +| set.cpp:137:24:137:25 | ref arg s1 | set.cpp:139:7:139:8 | s1 | | +| set.cpp:137:24:137:25 | ref arg s1 | set.cpp:145:7:145:8 | s1 | | +| set.cpp:137:24:137:25 | ref arg s1 | set.cpp:169:12:169:13 | s1 | | +| set.cpp:137:24:137:25 | ref arg s1 | set.cpp:169:30:169:31 | s1 | | +| set.cpp:137:24:137:25 | ref arg s1 | set.cpp:238:1:238:1 | s1 | | +| set.cpp:137:24:137:25 | s1 | set.cpp:137:27:137:29 | call to end | TAINT | +| set.cpp:137:27:137:29 | call to end | set.cpp:137:2:137:3 | ref arg s5 | TAINT | +| set.cpp:137:27:137:29 | call to end | set.cpp:137:5:137:10 | call to insert | TAINT | +| set.cpp:138:2:138:3 | ref arg s6 | set.cpp:144:7:144:8 | s6 | | +| set.cpp:138:2:138:3 | ref arg s6 | set.cpp:150:7:150:8 | s6 | | +| set.cpp:138:2:138:3 | ref arg s6 | set.cpp:238:1:238:1 | s6 | | +| set.cpp:138:12:138:13 | ref arg s2 | set.cpp:138:24:138:25 | s2 | | +| set.cpp:138:12:138:13 | ref arg s2 | set.cpp:140:7:140:8 | s2 | | +| set.cpp:138:12:138:13 | ref arg s2 | set.cpp:146:7:146:8 | s2 | | +| set.cpp:138:12:138:13 | ref arg s2 | set.cpp:153:32:153:33 | s2 | | +| set.cpp:138:12:138:13 | ref arg s2 | set.cpp:154:34:154:35 | s2 | | +| set.cpp:138:12:138:13 | ref arg s2 | set.cpp:155:32:155:33 | s2 | | +| set.cpp:138:12:138:13 | ref arg s2 | set.cpp:155:44:155:45 | s2 | | +| set.cpp:138:12:138:13 | ref arg s2 | set.cpp:157:8:157:9 | s2 | | +| set.cpp:138:12:138:13 | ref arg s2 | set.cpp:173:12:173:13 | s2 | | +| set.cpp:138:12:138:13 | ref arg s2 | set.cpp:173:30:173:31 | s2 | | +| set.cpp:138:12:138:13 | ref arg s2 | set.cpp:238:1:238:1 | s2 | | +| set.cpp:138:12:138:13 | s2 | set.cpp:138:15:138:19 | call to begin | TAINT | +| set.cpp:138:24:138:25 | ref arg s2 | set.cpp:140:7:140:8 | s2 | | +| set.cpp:138:24:138:25 | ref arg s2 | set.cpp:146:7:146:8 | s2 | | +| set.cpp:138:24:138:25 | ref arg s2 | set.cpp:153:32:153:33 | s2 | | +| set.cpp:138:24:138:25 | ref arg s2 | set.cpp:154:34:154:35 | s2 | | +| set.cpp:138:24:138:25 | ref arg s2 | set.cpp:155:32:155:33 | s2 | | +| set.cpp:138:24:138:25 | ref arg s2 | set.cpp:155:44:155:45 | s2 | | +| set.cpp:138:24:138:25 | ref arg s2 | set.cpp:157:8:157:9 | s2 | | +| set.cpp:138:24:138:25 | ref arg s2 | set.cpp:173:12:173:13 | s2 | | +| set.cpp:138:24:138:25 | ref arg s2 | set.cpp:173:30:173:31 | s2 | | +| set.cpp:138:24:138:25 | ref arg s2 | set.cpp:238:1:238:1 | s2 | | +| set.cpp:138:24:138:25 | s2 | set.cpp:138:27:138:29 | call to end | TAINT | +| set.cpp:138:27:138:29 | call to end | set.cpp:138:2:138:3 | ref arg s6 | TAINT | +| set.cpp:138:27:138:29 | call to end | set.cpp:138:5:138:10 | call to insert | TAINT | +| set.cpp:139:7:139:8 | s1 | set.cpp:139:7:139:8 | call to unordered_set | | +| set.cpp:140:7:140:8 | s2 | set.cpp:140:7:140:8 | call to unordered_set | | +| set.cpp:141:7:141:8 | s3 | set.cpp:141:7:141:8 | call to unordered_set | | +| set.cpp:142:7:142:8 | s4 | set.cpp:142:7:142:8 | call to unordered_set | | +| set.cpp:143:7:143:8 | s5 | set.cpp:143:7:143:8 | call to unordered_set | | +| set.cpp:144:7:144:8 | s6 | set.cpp:144:7:144:8 | call to unordered_set | | +| set.cpp:145:7:145:8 | ref arg s1 | set.cpp:169:12:169:13 | s1 | | +| set.cpp:145:7:145:8 | ref arg s1 | set.cpp:169:30:169:31 | s1 | | +| set.cpp:145:7:145:8 | ref arg s1 | set.cpp:238:1:238:1 | s1 | | +| set.cpp:145:7:145:8 | s1 | set.cpp:145:10:145:13 | call to find | TAINT | +| set.cpp:146:7:146:8 | ref arg s2 | set.cpp:153:32:153:33 | s2 | | +| set.cpp:146:7:146:8 | ref arg s2 | set.cpp:154:34:154:35 | s2 | | +| set.cpp:146:7:146:8 | ref arg s2 | set.cpp:155:32:155:33 | s2 | | +| set.cpp:146:7:146:8 | ref arg s2 | set.cpp:155:44:155:45 | s2 | | +| set.cpp:146:7:146:8 | ref arg s2 | set.cpp:157:8:157:9 | s2 | | +| set.cpp:146:7:146:8 | ref arg s2 | set.cpp:173:12:173:13 | s2 | | +| set.cpp:146:7:146:8 | ref arg s2 | set.cpp:173:30:173:31 | s2 | | +| set.cpp:146:7:146:8 | ref arg s2 | set.cpp:238:1:238:1 | s2 | | +| set.cpp:146:7:146:8 | s2 | set.cpp:146:10:146:13 | call to find | TAINT | +| set.cpp:147:7:147:8 | ref arg s3 | set.cpp:238:1:238:1 | s3 | | +| set.cpp:147:7:147:8 | s3 | set.cpp:147:10:147:13 | call to find | TAINT | +| set.cpp:148:7:148:8 | ref arg s4 | set.cpp:238:1:238:1 | s4 | | +| set.cpp:148:7:148:8 | s4 | set.cpp:148:10:148:13 | call to find | TAINT | +| set.cpp:149:7:149:8 | ref arg s5 | set.cpp:238:1:238:1 | s5 | | +| set.cpp:149:7:149:8 | s5 | set.cpp:149:10:149:13 | call to find | TAINT | +| set.cpp:150:7:150:8 | ref arg s6 | set.cpp:238:1:238:1 | s6 | | +| set.cpp:150:7:150:8 | s6 | set.cpp:150:10:150:13 | call to find | TAINT | +| set.cpp:153:32:153:33 | s2 | set.cpp:153:32:153:34 | call to unordered_set | | +| set.cpp:153:32:153:34 | call to unordered_set | set.cpp:158:7:158:8 | s7 | | +| set.cpp:153:32:153:34 | call to unordered_set | set.cpp:162:7:162:8 | s7 | | +| set.cpp:153:32:153:34 | call to unordered_set | set.cpp:238:1:238:1 | s7 | | +| set.cpp:154:33:154:35 | call to unordered_set | set.cpp:159:7:159:8 | s8 | | +| set.cpp:154:33:154:35 | call to unordered_set | set.cpp:163:7:163:8 | s8 | | +| set.cpp:154:33:154:35 | call to unordered_set | set.cpp:238:1:238:1 | s8 | | +| set.cpp:154:34:154:35 | s2 | set.cpp:154:33:154:35 | call to unordered_set | | +| set.cpp:155:32:155:33 | ref arg s2 | set.cpp:155:44:155:45 | s2 | | +| set.cpp:155:32:155:33 | ref arg s2 | set.cpp:157:8:157:9 | s2 | | +| set.cpp:155:32:155:33 | ref arg s2 | set.cpp:173:12:173:13 | s2 | | +| set.cpp:155:32:155:33 | ref arg s2 | set.cpp:173:30:173:31 | s2 | | +| set.cpp:155:32:155:33 | ref arg s2 | set.cpp:238:1:238:1 | s2 | | +| set.cpp:155:32:155:33 | s2 | set.cpp:155:35:155:39 | call to begin | TAINT | +| set.cpp:155:32:155:52 | call to unordered_set | set.cpp:160:7:160:8 | s9 | | +| set.cpp:155:32:155:52 | call to unordered_set | set.cpp:164:7:164:8 | s9 | | +| set.cpp:155:32:155:52 | call to unordered_set | set.cpp:238:1:238:1 | s9 | | +| set.cpp:155:35:155:39 | call to begin | set.cpp:155:32:155:52 | call to unordered_set | TAINT | +| set.cpp:155:44:155:45 | ref arg s2 | set.cpp:157:8:157:9 | s2 | | +| set.cpp:155:44:155:45 | ref arg s2 | set.cpp:173:12:173:13 | s2 | | +| set.cpp:155:44:155:45 | ref arg s2 | set.cpp:173:30:173:31 | s2 | | +| set.cpp:155:44:155:45 | ref arg s2 | set.cpp:238:1:238:1 | s2 | | +| set.cpp:155:44:155:45 | s2 | set.cpp:155:47:155:49 | call to end | TAINT | +| set.cpp:155:47:155:49 | call to end | set.cpp:155:32:155:52 | call to unordered_set | TAINT | +| set.cpp:156:29:156:31 | call to unordered_set | set.cpp:157:2:157:4 | s10 | | +| set.cpp:156:29:156:31 | call to unordered_set | set.cpp:161:7:161:9 | s10 | | +| set.cpp:156:29:156:31 | call to unordered_set | set.cpp:165:7:165:9 | s10 | | +| set.cpp:156:29:156:31 | call to unordered_set | set.cpp:238:1:238:1 | s10 | | +| set.cpp:157:2:157:4 | ref arg s10 | set.cpp:161:7:161:9 | s10 | | +| set.cpp:157:2:157:4 | ref arg s10 | set.cpp:165:7:165:9 | s10 | | +| set.cpp:157:2:157:4 | ref arg s10 | set.cpp:238:1:238:1 | s10 | | +| set.cpp:157:8:157:9 | s2 | set.cpp:157:2:157:4 | ref arg s10 | TAINT | +| set.cpp:157:8:157:9 | s2 | set.cpp:157:6:157:6 | call to operator= | TAINT | +| set.cpp:158:7:158:8 | s7 | set.cpp:158:7:158:8 | call to unordered_set | | +| set.cpp:159:7:159:8 | s8 | set.cpp:159:7:159:8 | call to unordered_set | | +| set.cpp:160:7:160:8 | s9 | set.cpp:160:7:160:8 | call to unordered_set | | +| set.cpp:161:7:161:9 | s10 | set.cpp:161:7:161:9 | call to unordered_set | | +| set.cpp:162:7:162:8 | ref arg s7 | set.cpp:238:1:238:1 | s7 | | +| set.cpp:162:7:162:8 | s7 | set.cpp:162:10:162:13 | call to find | TAINT | +| set.cpp:163:7:163:8 | ref arg s8 | set.cpp:238:1:238:1 | s8 | | +| set.cpp:163:7:163:8 | s8 | set.cpp:163:10:163:13 | call to find | TAINT | +| set.cpp:164:7:164:8 | ref arg s9 | set.cpp:238:1:238:1 | s9 | | +| set.cpp:164:7:164:8 | s9 | set.cpp:164:10:164:13 | call to find | TAINT | +| set.cpp:165:7:165:9 | ref arg s10 | set.cpp:238:1:238:1 | s10 | | +| set.cpp:165:7:165:9 | s10 | set.cpp:165:11:165:14 | call to find | TAINT | +| set.cpp:169:12:169:13 | ref arg s1 | set.cpp:169:30:169:31 | s1 | | +| set.cpp:169:12:169:13 | ref arg s1 | set.cpp:238:1:238:1 | s1 | | +| set.cpp:169:12:169:13 | s1 | set.cpp:169:15:169:19 | call to begin | TAINT | +| set.cpp:169:15:169:19 | call to begin | set.cpp:169:7:169:21 | ... = ... | | +| set.cpp:169:15:169:19 | call to begin | set.cpp:169:24:169:25 | i1 | | +| set.cpp:169:15:169:19 | call to begin | set.cpp:169:40:169:41 | i1 | | +| set.cpp:169:15:169:19 | call to begin | set.cpp:171:9:171:10 | i1 | | +| set.cpp:169:30:169:31 | ref arg s1 | set.cpp:169:30:169:31 | s1 | | +| set.cpp:169:30:169:31 | ref arg s1 | set.cpp:238:1:238:1 | s1 | | +| set.cpp:169:30:169:31 | s1 | set.cpp:169:33:169:35 | call to end | TAINT | +| set.cpp:169:40:169:41 | i1 | set.cpp:169:42:169:42 | call to operator++ | | +| set.cpp:169:40:169:41 | ref arg i1 | set.cpp:169:24:169:25 | i1 | | +| set.cpp:169:40:169:41 | ref arg i1 | set.cpp:169:40:169:41 | i1 | | +| set.cpp:169:40:169:41 | ref arg i1 | set.cpp:171:9:171:10 | i1 | | +| set.cpp:171:9:171:10 | i1 | set.cpp:171:8:171:8 | call to operator* | TAINT | +| set.cpp:173:12:173:13 | ref arg s2 | set.cpp:173:30:173:31 | s2 | | +| set.cpp:173:12:173:13 | ref arg s2 | set.cpp:238:1:238:1 | s2 | | +| set.cpp:173:12:173:13 | s2 | set.cpp:173:15:173:19 | call to begin | TAINT | +| set.cpp:173:15:173:19 | call to begin | set.cpp:173:7:173:21 | ... = ... | | +| set.cpp:173:15:173:19 | call to begin | set.cpp:173:24:173:25 | i2 | | +| set.cpp:173:15:173:19 | call to begin | set.cpp:173:40:173:41 | i2 | | +| set.cpp:173:15:173:19 | call to begin | set.cpp:175:9:175:10 | i2 | | +| set.cpp:173:30:173:31 | ref arg s2 | set.cpp:173:30:173:31 | s2 | | +| set.cpp:173:30:173:31 | ref arg s2 | set.cpp:238:1:238:1 | s2 | | +| set.cpp:173:30:173:31 | s2 | set.cpp:173:33:173:35 | call to end | TAINT | +| set.cpp:173:40:173:41 | i2 | set.cpp:173:42:173:42 | call to operator++ | | +| set.cpp:173:40:173:41 | ref arg i2 | set.cpp:173:24:173:25 | i2 | | +| set.cpp:173:40:173:41 | ref arg i2 | set.cpp:173:40:173:41 | i2 | | +| set.cpp:173:40:173:41 | ref arg i2 | set.cpp:175:9:175:10 | i2 | | +| set.cpp:175:9:175:10 | i2 | set.cpp:175:8:175:8 | call to operator* | TAINT | +| set.cpp:179:29:179:31 | call to unordered_set | set.cpp:180:2:180:4 | s11 | | +| set.cpp:179:29:179:31 | call to unordered_set | set.cpp:181:2:181:4 | s11 | | +| set.cpp:179:29:179:31 | call to unordered_set | set.cpp:182:2:182:4 | s11 | | +| set.cpp:179:29:179:31 | call to unordered_set | set.cpp:183:7:183:9 | s11 | | +| set.cpp:179:29:179:31 | call to unordered_set | set.cpp:184:7:184:9 | s11 | | +| set.cpp:179:29:179:31 | call to unordered_set | set.cpp:238:1:238:1 | s11 | | +| set.cpp:180:2:180:4 | ref arg s11 | set.cpp:181:2:181:4 | s11 | | +| set.cpp:180:2:180:4 | ref arg s11 | set.cpp:182:2:182:4 | s11 | | +| set.cpp:180:2:180:4 | ref arg s11 | set.cpp:183:7:183:9 | s11 | | +| set.cpp:180:2:180:4 | ref arg s11 | set.cpp:184:7:184:9 | s11 | | +| set.cpp:180:2:180:4 | ref arg s11 | set.cpp:238:1:238:1 | s11 | | +| set.cpp:180:13:180:15 | a | set.cpp:180:2:180:4 | ref arg s11 | TAINT | +| set.cpp:180:13:180:15 | a | set.cpp:180:6:180:11 | call to insert | TAINT | +| set.cpp:181:2:181:4 | ref arg s11 | set.cpp:182:2:182:4 | s11 | | +| set.cpp:181:2:181:4 | ref arg s11 | set.cpp:183:7:183:9 | s11 | | +| set.cpp:181:2:181:4 | ref arg s11 | set.cpp:184:7:184:9 | s11 | | +| set.cpp:181:2:181:4 | ref arg s11 | set.cpp:238:1:238:1 | s11 | | +| set.cpp:181:13:181:18 | call to source | set.cpp:181:2:181:4 | ref arg s11 | TAINT | +| set.cpp:181:13:181:18 | call to source | set.cpp:181:6:181:11 | call to insert | TAINT | +| set.cpp:182:2:182:4 | ref arg s11 | set.cpp:183:7:183:9 | s11 | | +| set.cpp:182:2:182:4 | ref arg s11 | set.cpp:184:7:184:9 | s11 | | +| set.cpp:182:2:182:4 | ref arg s11 | set.cpp:238:1:238:1 | s11 | | +| set.cpp:182:13:182:15 | c | set.cpp:182:2:182:4 | ref arg s11 | TAINT | +| set.cpp:182:13:182:15 | c | set.cpp:182:6:182:11 | call to insert | TAINT | +| set.cpp:183:7:183:9 | ref arg s11 | set.cpp:184:7:184:9 | s11 | | +| set.cpp:183:7:183:9 | ref arg s11 | set.cpp:238:1:238:1 | s11 | | +| set.cpp:183:7:183:9 | s11 | set.cpp:183:11:183:21 | call to equal_range | TAINT | +| set.cpp:183:28:183:32 | first | set.cpp:183:7:183:32 | call to iterator | | +| set.cpp:184:7:184:9 | ref arg s11 | set.cpp:238:1:238:1 | s11 | | +| set.cpp:184:7:184:9 | s11 | set.cpp:184:11:184:21 | call to equal_range | TAINT | +| set.cpp:184:28:184:33 | second | set.cpp:184:7:184:33 | call to iterator | | +| set.cpp:187:29:187:31 | call to unordered_set | set.cpp:188:2:188:4 | s12 | | +| set.cpp:187:29:187:31 | call to unordered_set | set.cpp:190:7:190:9 | s12 | | +| set.cpp:187:29:187:31 | call to unordered_set | set.cpp:194:2:194:4 | s12 | | +| set.cpp:187:29:187:31 | call to unordered_set | set.cpp:196:7:196:9 | s12 | | +| set.cpp:187:29:187:31 | call to unordered_set | set.cpp:238:1:238:1 | s12 | | +| set.cpp:187:34:187:36 | call to unordered_set | set.cpp:191:7:191:9 | s13 | | +| set.cpp:187:34:187:36 | call to unordered_set | set.cpp:194:11:194:13 | s13 | | +| set.cpp:187:34:187:36 | call to unordered_set | set.cpp:197:7:197:9 | s13 | | +| set.cpp:187:34:187:36 | call to unordered_set | set.cpp:238:1:238:1 | s13 | | +| set.cpp:187:39:187:41 | call to unordered_set | set.cpp:192:7:192:9 | s14 | | +| set.cpp:187:39:187:41 | call to unordered_set | set.cpp:195:2:195:4 | s14 | | +| set.cpp:187:39:187:41 | call to unordered_set | set.cpp:198:7:198:9 | s14 | | +| set.cpp:187:39:187:41 | call to unordered_set | set.cpp:238:1:238:1 | s14 | | +| set.cpp:187:44:187:46 | call to unordered_set | set.cpp:189:2:189:4 | s15 | | +| set.cpp:187:44:187:46 | call to unordered_set | set.cpp:193:7:193:9 | s15 | | +| set.cpp:187:44:187:46 | call to unordered_set | set.cpp:195:11:195:13 | s15 | | +| set.cpp:187:44:187:46 | call to unordered_set | set.cpp:199:7:199:9 | s15 | | +| set.cpp:187:44:187:46 | call to unordered_set | set.cpp:238:1:238:1 | s15 | | +| set.cpp:188:2:188:4 | ref arg s12 | set.cpp:190:7:190:9 | s12 | | +| set.cpp:188:2:188:4 | ref arg s12 | set.cpp:194:2:194:4 | s12 | | +| set.cpp:188:2:188:4 | ref arg s12 | set.cpp:196:7:196:9 | s12 | | +| set.cpp:188:2:188:4 | ref arg s12 | set.cpp:238:1:238:1 | s12 | | +| set.cpp:188:13:188:18 | call to source | set.cpp:188:2:188:4 | ref arg s12 | TAINT | +| set.cpp:188:13:188:18 | call to source | set.cpp:188:6:188:11 | call to insert | TAINT | +| set.cpp:189:2:189:4 | ref arg s15 | set.cpp:193:7:193:9 | s15 | | +| set.cpp:189:2:189:4 | ref arg s15 | set.cpp:195:11:195:13 | s15 | | +| set.cpp:189:2:189:4 | ref arg s15 | set.cpp:199:7:199:9 | s15 | | +| set.cpp:189:2:189:4 | ref arg s15 | set.cpp:238:1:238:1 | s15 | | +| set.cpp:189:13:189:18 | call to source | set.cpp:189:2:189:4 | ref arg s15 | TAINT | +| set.cpp:189:13:189:18 | call to source | set.cpp:189:6:189:11 | call to insert | TAINT | +| set.cpp:190:7:190:9 | s12 | set.cpp:190:7:190:9 | call to unordered_set | | +| set.cpp:191:7:191:9 | s13 | set.cpp:191:7:191:9 | call to unordered_set | | +| set.cpp:192:7:192:9 | s14 | set.cpp:192:7:192:9 | call to unordered_set | | +| set.cpp:193:7:193:9 | s15 | set.cpp:193:7:193:9 | call to unordered_set | | +| set.cpp:194:2:194:4 | ref arg s12 | set.cpp:196:7:196:9 | s12 | | +| set.cpp:194:2:194:4 | ref arg s12 | set.cpp:238:1:238:1 | s12 | | +| set.cpp:194:2:194:4 | s12 | set.cpp:194:11:194:13 | ref arg s13 | TAINT | +| set.cpp:194:11:194:13 | ref arg s13 | set.cpp:197:7:197:9 | s13 | | +| set.cpp:194:11:194:13 | ref arg s13 | set.cpp:238:1:238:1 | s13 | | +| set.cpp:194:11:194:13 | s13 | set.cpp:194:2:194:4 | ref arg s12 | TAINT | +| set.cpp:195:2:195:4 | ref arg s14 | set.cpp:198:7:198:9 | s14 | | +| set.cpp:195:2:195:4 | ref arg s14 | set.cpp:238:1:238:1 | s14 | | +| set.cpp:195:2:195:4 | s14 | set.cpp:195:11:195:13 | ref arg s15 | TAINT | +| set.cpp:195:11:195:13 | ref arg s15 | set.cpp:199:7:199:9 | s15 | | +| set.cpp:195:11:195:13 | ref arg s15 | set.cpp:238:1:238:1 | s15 | | +| set.cpp:195:11:195:13 | s15 | set.cpp:195:2:195:4 | ref arg s14 | TAINT | +| set.cpp:196:7:196:9 | s12 | set.cpp:196:7:196:9 | call to unordered_set | | +| set.cpp:197:7:197:9 | s13 | set.cpp:197:7:197:9 | call to unordered_set | | +| set.cpp:198:7:198:9 | s14 | set.cpp:198:7:198:9 | call to unordered_set | | +| set.cpp:199:7:199:9 | s15 | set.cpp:199:7:199:9 | call to unordered_set | | +| set.cpp:202:29:202:31 | call to unordered_set | set.cpp:203:2:203:4 | s16 | | +| set.cpp:202:29:202:31 | call to unordered_set | set.cpp:207:7:207:9 | s16 | | +| set.cpp:202:29:202:31 | call to unordered_set | set.cpp:211:2:211:4 | s16 | | +| set.cpp:202:29:202:31 | call to unordered_set | set.cpp:213:7:213:9 | s16 | | +| set.cpp:202:29:202:31 | call to unordered_set | set.cpp:238:1:238:1 | s16 | | +| set.cpp:202:34:202:36 | call to unordered_set | set.cpp:204:2:204:4 | s17 | | +| set.cpp:202:34:202:36 | call to unordered_set | set.cpp:208:7:208:9 | s17 | | +| set.cpp:202:34:202:36 | call to unordered_set | set.cpp:211:12:211:14 | s17 | | +| set.cpp:202:34:202:36 | call to unordered_set | set.cpp:214:7:214:9 | s17 | | +| set.cpp:202:34:202:36 | call to unordered_set | set.cpp:238:1:238:1 | s17 | | +| set.cpp:202:39:202:41 | call to unordered_set | set.cpp:205:2:205:4 | s18 | | +| set.cpp:202:39:202:41 | call to unordered_set | set.cpp:209:7:209:9 | s18 | | +| set.cpp:202:39:202:41 | call to unordered_set | set.cpp:212:2:212:4 | s18 | | +| set.cpp:202:39:202:41 | call to unordered_set | set.cpp:215:7:215:9 | s18 | | +| set.cpp:202:39:202:41 | call to unordered_set | set.cpp:238:1:238:1 | s18 | | +| set.cpp:202:44:202:46 | call to unordered_set | set.cpp:206:2:206:4 | s19 | | +| set.cpp:202:44:202:46 | call to unordered_set | set.cpp:210:7:210:9 | s19 | | +| set.cpp:202:44:202:46 | call to unordered_set | set.cpp:212:12:212:14 | s19 | | +| set.cpp:202:44:202:46 | call to unordered_set | set.cpp:216:7:216:9 | s19 | | +| set.cpp:202:44:202:46 | call to unordered_set | set.cpp:238:1:238:1 | s19 | | +| set.cpp:203:2:203:4 | ref arg s16 | set.cpp:207:7:207:9 | s16 | | +| set.cpp:203:2:203:4 | ref arg s16 | set.cpp:211:2:211:4 | s16 | | +| set.cpp:203:2:203:4 | ref arg s16 | set.cpp:213:7:213:9 | s16 | | +| set.cpp:203:2:203:4 | ref arg s16 | set.cpp:238:1:238:1 | s16 | | +| set.cpp:203:13:203:18 | call to source | set.cpp:203:2:203:4 | ref arg s16 | TAINT | +| set.cpp:203:13:203:18 | call to source | set.cpp:203:6:203:11 | call to insert | TAINT | +| set.cpp:204:2:204:4 | ref arg s17 | set.cpp:208:7:208:9 | s17 | | +| set.cpp:204:2:204:4 | ref arg s17 | set.cpp:211:12:211:14 | s17 | | +| set.cpp:204:2:204:4 | ref arg s17 | set.cpp:214:7:214:9 | s17 | | +| set.cpp:204:2:204:4 | ref arg s17 | set.cpp:238:1:238:1 | s17 | | +| set.cpp:204:13:204:17 | abc | set.cpp:204:2:204:4 | ref arg s17 | TAINT | +| set.cpp:204:13:204:17 | abc | set.cpp:204:6:204:11 | call to insert | TAINT | +| set.cpp:205:2:205:4 | ref arg s18 | set.cpp:209:7:209:9 | s18 | | +| set.cpp:205:2:205:4 | ref arg s18 | set.cpp:212:2:212:4 | s18 | | +| set.cpp:205:2:205:4 | ref arg s18 | set.cpp:215:7:215:9 | s18 | | +| set.cpp:205:2:205:4 | ref arg s18 | set.cpp:238:1:238:1 | s18 | | +| set.cpp:205:13:205:17 | def | set.cpp:205:2:205:4 | ref arg s18 | TAINT | +| set.cpp:205:13:205:17 | def | set.cpp:205:6:205:11 | call to insert | TAINT | +| set.cpp:206:2:206:4 | ref arg s19 | set.cpp:210:7:210:9 | s19 | | +| set.cpp:206:2:206:4 | ref arg s19 | set.cpp:212:12:212:14 | s19 | | +| set.cpp:206:2:206:4 | ref arg s19 | set.cpp:216:7:216:9 | s19 | | +| set.cpp:206:2:206:4 | ref arg s19 | set.cpp:238:1:238:1 | s19 | | +| set.cpp:206:13:206:18 | call to source | set.cpp:206:2:206:4 | ref arg s19 | TAINT | +| set.cpp:206:13:206:18 | call to source | set.cpp:206:6:206:11 | call to insert | TAINT | +| set.cpp:207:7:207:9 | s16 | set.cpp:207:7:207:9 | call to unordered_set | | +| set.cpp:208:7:208:9 | s17 | set.cpp:208:7:208:9 | call to unordered_set | | +| set.cpp:209:7:209:9 | s18 | set.cpp:209:7:209:9 | call to unordered_set | | +| set.cpp:210:7:210:9 | s19 | set.cpp:210:7:210:9 | call to unordered_set | | +| set.cpp:211:2:211:4 | ref arg s16 | set.cpp:213:7:213:9 | s16 | | +| set.cpp:211:2:211:4 | ref arg s16 | set.cpp:238:1:238:1 | s16 | | +| set.cpp:211:12:211:14 | ref arg s17 | set.cpp:214:7:214:9 | s17 | | +| set.cpp:211:12:211:14 | ref arg s17 | set.cpp:238:1:238:1 | s17 | | +| set.cpp:211:12:211:14 | s17 | set.cpp:211:2:211:4 | ref arg s16 | TAINT | +| set.cpp:212:2:212:4 | ref arg s18 | set.cpp:215:7:215:9 | s18 | | +| set.cpp:212:2:212:4 | ref arg s18 | set.cpp:238:1:238:1 | s18 | | +| set.cpp:212:12:212:14 | ref arg s19 | set.cpp:216:7:216:9 | s19 | | +| set.cpp:212:12:212:14 | ref arg s19 | set.cpp:238:1:238:1 | s19 | | +| set.cpp:212:12:212:14 | s19 | set.cpp:212:2:212:4 | ref arg s18 | TAINT | +| set.cpp:213:7:213:9 | s16 | set.cpp:213:7:213:9 | call to unordered_set | | +| set.cpp:214:7:214:9 | s17 | set.cpp:214:7:214:9 | call to unordered_set | | +| set.cpp:215:7:215:9 | s18 | set.cpp:215:7:215:9 | call to unordered_set | | +| set.cpp:216:7:216:9 | s19 | set.cpp:216:7:216:9 | call to unordered_set | | +| set.cpp:219:29:219:31 | call to unordered_set | set.cpp:220:2:220:4 | s20 | | +| set.cpp:219:29:219:31 | call to unordered_set | set.cpp:221:2:221:4 | s20 | | +| set.cpp:219:29:219:31 | call to unordered_set | set.cpp:222:7:222:9 | s20 | | +| set.cpp:219:29:219:31 | call to unordered_set | set.cpp:223:7:223:9 | s20 | | +| set.cpp:219:29:219:31 | call to unordered_set | set.cpp:223:17:223:19 | s20 | | +| set.cpp:219:29:219:31 | call to unordered_set | set.cpp:224:7:224:9 | s20 | | +| set.cpp:219:29:219:31 | call to unordered_set | set.cpp:225:2:225:4 | s20 | | +| set.cpp:219:29:219:31 | call to unordered_set | set.cpp:226:7:226:9 | s20 | | +| set.cpp:219:29:219:31 | call to unordered_set | set.cpp:238:1:238:1 | s20 | | +| set.cpp:220:2:220:4 | ref arg s20 | set.cpp:221:2:221:4 | s20 | | +| set.cpp:220:2:220:4 | ref arg s20 | set.cpp:222:7:222:9 | s20 | | +| set.cpp:220:2:220:4 | ref arg s20 | set.cpp:223:7:223:9 | s20 | | +| set.cpp:220:2:220:4 | ref arg s20 | set.cpp:223:17:223:19 | s20 | | +| set.cpp:220:2:220:4 | ref arg s20 | set.cpp:224:7:224:9 | s20 | | +| set.cpp:220:2:220:4 | ref arg s20 | set.cpp:225:2:225:4 | s20 | | +| set.cpp:220:2:220:4 | ref arg s20 | set.cpp:226:7:226:9 | s20 | | +| set.cpp:220:2:220:4 | ref arg s20 | set.cpp:238:1:238:1 | s20 | | +| set.cpp:220:13:220:18 | call to source | set.cpp:220:2:220:4 | ref arg s20 | TAINT | +| set.cpp:220:13:220:18 | call to source | set.cpp:220:6:220:11 | call to insert | TAINT | +| set.cpp:221:2:221:4 | ref arg s20 | set.cpp:222:7:222:9 | s20 | | +| set.cpp:221:2:221:4 | ref arg s20 | set.cpp:223:7:223:9 | s20 | | +| set.cpp:221:2:221:4 | ref arg s20 | set.cpp:223:17:223:19 | s20 | | +| set.cpp:221:2:221:4 | ref arg s20 | set.cpp:224:7:224:9 | s20 | | +| set.cpp:221:2:221:4 | ref arg s20 | set.cpp:225:2:225:4 | s20 | | +| set.cpp:221:2:221:4 | ref arg s20 | set.cpp:226:7:226:9 | s20 | | +| set.cpp:221:2:221:4 | ref arg s20 | set.cpp:238:1:238:1 | s20 | | +| set.cpp:221:13:221:18 | call to source | set.cpp:221:2:221:4 | ref arg s20 | TAINT | +| set.cpp:221:13:221:18 | call to source | set.cpp:221:6:221:11 | call to insert | TAINT | +| set.cpp:222:7:222:9 | s20 | set.cpp:222:7:222:9 | call to unordered_set | | +| set.cpp:223:7:223:9 | ref arg s20 | set.cpp:224:7:224:9 | s20 | | +| set.cpp:223:7:223:9 | ref arg s20 | set.cpp:225:2:225:4 | s20 | | +| set.cpp:223:7:223:9 | ref arg s20 | set.cpp:226:7:226:9 | s20 | | +| set.cpp:223:7:223:9 | ref arg s20 | set.cpp:238:1:238:1 | s20 | | +| set.cpp:223:7:223:9 | s20 | set.cpp:223:11:223:15 | call to erase | TAINT | +| set.cpp:223:17:223:19 | ref arg s20 | set.cpp:223:7:223:9 | s20 | | +| set.cpp:223:17:223:19 | ref arg s20 | set.cpp:224:7:224:9 | s20 | | +| set.cpp:223:17:223:19 | ref arg s20 | set.cpp:225:2:225:4 | s20 | | +| set.cpp:223:17:223:19 | ref arg s20 | set.cpp:226:7:226:9 | s20 | | +| set.cpp:223:17:223:19 | ref arg s20 | set.cpp:238:1:238:1 | s20 | | +| set.cpp:223:17:223:19 | s20 | set.cpp:223:21:223:25 | call to begin | TAINT | +| set.cpp:224:7:224:9 | s20 | set.cpp:224:7:224:9 | call to unordered_set | | +| set.cpp:225:2:225:4 | ref arg s20 | set.cpp:226:7:226:9 | s20 | | +| set.cpp:225:2:225:4 | ref arg s20 | set.cpp:238:1:238:1 | s20 | | +| set.cpp:226:7:226:9 | s20 | set.cpp:226:7:226:9 | call to unordered_set | | +| set.cpp:229:29:229:31 | call to unordered_set | set.cpp:230:7:230:9 | s21 | | +| set.cpp:229:29:229:31 | call to unordered_set | set.cpp:231:7:231:9 | s21 | | +| set.cpp:229:29:229:31 | call to unordered_set | set.cpp:232:7:232:9 | s21 | | +| set.cpp:229:29:229:31 | call to unordered_set | set.cpp:233:7:233:9 | s21 | | +| set.cpp:229:29:229:31 | call to unordered_set | set.cpp:238:1:238:1 | s21 | | +| set.cpp:229:34:229:36 | call to unordered_set | set.cpp:234:7:234:9 | s22 | | +| set.cpp:229:34:229:36 | call to unordered_set | set.cpp:234:24:234:26 | s22 | | +| set.cpp:229:34:229:36 | call to unordered_set | set.cpp:235:7:235:9 | s22 | | +| set.cpp:229:34:229:36 | call to unordered_set | set.cpp:236:7:236:9 | s22 | | +| set.cpp:229:34:229:36 | call to unordered_set | set.cpp:236:24:236:26 | s22 | | +| set.cpp:229:34:229:36 | call to unordered_set | set.cpp:237:7:237:9 | s22 | | +| set.cpp:229:34:229:36 | call to unordered_set | set.cpp:238:1:238:1 | s22 | | +| set.cpp:230:7:230:9 | ref arg s21 | set.cpp:231:7:231:9 | s21 | | +| set.cpp:230:7:230:9 | ref arg s21 | set.cpp:232:7:232:9 | s21 | | +| set.cpp:230:7:230:9 | ref arg s21 | set.cpp:233:7:233:9 | s21 | | +| set.cpp:230:7:230:9 | ref arg s21 | set.cpp:238:1:238:1 | s21 | | +| set.cpp:230:7:230:9 | s21 | set.cpp:230:11:230:17 | call to emplace | TAINT | +| set.cpp:230:19:230:23 | abc | set.cpp:230:7:230:9 | ref arg s21 | TAINT | +| set.cpp:230:19:230:23 | abc | set.cpp:230:11:230:17 | call to emplace | TAINT | +| set.cpp:230:26:230:30 | first | set.cpp:230:7:230:30 | call to iterator | | +| set.cpp:231:7:231:9 | s21 | set.cpp:231:7:231:9 | call to unordered_set | | +| set.cpp:232:7:232:9 | ref arg s21 | set.cpp:233:7:233:9 | s21 | | +| set.cpp:232:7:232:9 | ref arg s21 | set.cpp:238:1:238:1 | s21 | | +| set.cpp:232:7:232:9 | s21 | set.cpp:232:11:232:17 | call to emplace | TAINT | +| set.cpp:232:19:232:24 | call to source | set.cpp:232:7:232:9 | ref arg s21 | TAINT | +| set.cpp:232:19:232:24 | call to source | set.cpp:232:11:232:17 | call to emplace | TAINT | +| set.cpp:232:29:232:33 | first | set.cpp:232:7:232:33 | call to iterator | | +| set.cpp:233:7:233:9 | s21 | set.cpp:233:7:233:9 | call to unordered_set | | +| set.cpp:234:7:234:9 | ref arg s22 | set.cpp:235:7:235:9 | s22 | | +| set.cpp:234:7:234:9 | ref arg s22 | set.cpp:236:7:236:9 | s22 | | +| set.cpp:234:7:234:9 | ref arg s22 | set.cpp:236:24:236:26 | s22 | | +| set.cpp:234:7:234:9 | ref arg s22 | set.cpp:237:7:237:9 | s22 | | +| set.cpp:234:7:234:9 | ref arg s22 | set.cpp:238:1:238:1 | s22 | | +| set.cpp:234:7:234:9 | s22 | set.cpp:234:11:234:22 | call to emplace_hint | TAINT | +| set.cpp:234:24:234:26 | ref arg s22 | set.cpp:234:7:234:9 | s22 | | +| set.cpp:234:24:234:26 | ref arg s22 | set.cpp:235:7:235:9 | s22 | | +| set.cpp:234:24:234:26 | ref arg s22 | set.cpp:236:7:236:9 | s22 | | +| set.cpp:234:24:234:26 | ref arg s22 | set.cpp:236:24:236:26 | s22 | | +| set.cpp:234:24:234:26 | ref arg s22 | set.cpp:237:7:237:9 | s22 | | +| set.cpp:234:24:234:26 | ref arg s22 | set.cpp:238:1:238:1 | s22 | | +| set.cpp:234:24:234:26 | s22 | set.cpp:234:28:234:32 | call to begin | TAINT | +| set.cpp:234:24:234:34 | call to iterator | set.cpp:234:7:234:9 | ref arg s22 | TAINT | +| set.cpp:234:24:234:34 | call to iterator | set.cpp:234:11:234:22 | call to emplace_hint | TAINT | +| set.cpp:234:28:234:32 | call to begin | set.cpp:234:24:234:34 | call to iterator | TAINT | +| set.cpp:234:37:234:41 | abc | set.cpp:234:7:234:9 | ref arg s22 | TAINT | +| set.cpp:234:37:234:41 | abc | set.cpp:234:11:234:22 | call to emplace_hint | TAINT | +| set.cpp:235:7:235:9 | s22 | set.cpp:235:7:235:9 | call to unordered_set | | +| set.cpp:236:7:236:9 | ref arg s22 | set.cpp:237:7:237:9 | s22 | | +| set.cpp:236:7:236:9 | ref arg s22 | set.cpp:238:1:238:1 | s22 | | +| set.cpp:236:7:236:9 | s22 | set.cpp:236:11:236:22 | call to emplace_hint | TAINT | +| set.cpp:236:24:236:26 | ref arg s22 | set.cpp:236:7:236:9 | s22 | | +| set.cpp:236:24:236:26 | ref arg s22 | set.cpp:237:7:237:9 | s22 | | +| set.cpp:236:24:236:26 | ref arg s22 | set.cpp:238:1:238:1 | s22 | | +| set.cpp:236:24:236:26 | s22 | set.cpp:236:28:236:32 | call to begin | TAINT | +| set.cpp:236:24:236:34 | call to iterator | set.cpp:236:7:236:9 | ref arg s22 | TAINT | +| set.cpp:236:24:236:34 | call to iterator | set.cpp:236:11:236:22 | call to emplace_hint | TAINT | +| set.cpp:236:28:236:32 | call to begin | set.cpp:236:24:236:34 | call to iterator | TAINT | +| set.cpp:236:37:236:42 | call to source | set.cpp:236:7:236:9 | ref arg s22 | TAINT | +| set.cpp:236:37:236:42 | call to source | set.cpp:236:11:236:22 | call to emplace_hint | TAINT | +| set.cpp:237:7:237:9 | s22 | set.cpp:237:7:237:9 | call to unordered_set | | +| smart_pointer.cpp:11:30:11:50 | call to make_shared | smart_pointer.cpp:12:11:12:11 | p | | +| smart_pointer.cpp:11:30:11:50 | call to make_shared | smart_pointer.cpp:13:10:13:10 | p | | +| smart_pointer.cpp:11:52:11:57 | call to source | smart_pointer.cpp:11:30:11:50 | call to make_shared | TAINT | +| smart_pointer.cpp:12:11:12:11 | p | smart_pointer.cpp:12:10:12:10 | call to operator* | TAINT | +| smart_pointer.cpp:17:32:17:54 | call to make_shared | smart_pointer.cpp:18:11:18:11 | p | | +| smart_pointer.cpp:17:32:17:54 | call to make_shared | smart_pointer.cpp:19:10:19:10 | p | | +| smart_pointer.cpp:18:11:18:11 | p | smart_pointer.cpp:18:10:18:10 | call to operator* | TAINT | +| smart_pointer.cpp:23:30:23:50 | call to make_unique | smart_pointer.cpp:24:11:24:11 | p | | +| smart_pointer.cpp:23:30:23:50 | call to make_unique | smart_pointer.cpp:25:10:25:10 | p | | +| smart_pointer.cpp:23:52:23:57 | call to source | smart_pointer.cpp:23:30:23:50 | call to make_unique | TAINT | +| smart_pointer.cpp:24:11:24:11 | p | smart_pointer.cpp:24:10:24:10 | call to operator* | TAINT | +| smart_pointer.cpp:29:32:29:54 | call to make_unique | smart_pointer.cpp:30:11:30:11 | p | | +| smart_pointer.cpp:29:32:29:54 | call to make_unique | smart_pointer.cpp:31:10:31:10 | p | | +| smart_pointer.cpp:30:11:30:11 | p | smart_pointer.cpp:30:10:30:10 | call to operator* | TAINT | +| smart_pointer.cpp:35:30:35:50 | call to make_shared | smart_pointer.cpp:37:6:37:6 | p | | +| smart_pointer.cpp:35:30:35:50 | call to make_shared | smart_pointer.cpp:38:10:38:10 | p | | +| smart_pointer.cpp:35:30:35:50 | call to make_shared | smart_pointer.cpp:39:11:39:11 | p | | +| smart_pointer.cpp:37:5:37:17 | ... = ... | smart_pointer.cpp:37:5:37:5 | call to operator* [post update] | | +| smart_pointer.cpp:37:6:37:6 | p | smart_pointer.cpp:37:5:37:5 | call to operator* | TAINT | +| smart_pointer.cpp:37:10:37:15 | call to source | smart_pointer.cpp:37:5:37:17 | ... = ... | | +| smart_pointer.cpp:38:10:38:10 | ref arg p | smart_pointer.cpp:39:11:39:11 | p | | +| smart_pointer.cpp:39:11:39:11 | p | smart_pointer.cpp:39:10:39:10 | call to operator* | TAINT | +| smart_pointer.cpp:43:29:43:51 | call to unique_ptr | smart_pointer.cpp:45:6:45:6 | p | | +| smart_pointer.cpp:43:29:43:51 | call to unique_ptr | smart_pointer.cpp:46:10:46:10 | p | | +| smart_pointer.cpp:43:29:43:51 | call to unique_ptr | smart_pointer.cpp:47:11:47:11 | p | | +| smart_pointer.cpp:45:5:45:17 | ... = ... | smart_pointer.cpp:45:5:45:5 | call to operator* [post update] | | +| smart_pointer.cpp:45:6:45:6 | p | smart_pointer.cpp:45:5:45:5 | call to operator* | TAINT | +| smart_pointer.cpp:45:10:45:15 | call to source | smart_pointer.cpp:45:5:45:17 | ... = ... | | +| smart_pointer.cpp:46:10:46:10 | ref arg p | smart_pointer.cpp:47:11:47:11 | p | | +| smart_pointer.cpp:47:11:47:11 | p | smart_pointer.cpp:47:10:47:10 | call to operator* | TAINT | +| smart_pointer.cpp:51:30:51:50 | call to make_shared | smart_pointer.cpp:52:10:52:10 | p | | +| smart_pointer.cpp:51:52:51:57 | call to source | smart_pointer.cpp:51:30:51:50 | call to make_shared | TAINT | +| smart_pointer.cpp:52:10:52:10 | p | smart_pointer.cpp:52:12:52:14 | call to get | TAINT | +| smart_pointer.cpp:56:30:56:50 | call to make_unique | smart_pointer.cpp:57:10:57:10 | p | | +| smart_pointer.cpp:56:52:56:57 | call to source | smart_pointer.cpp:56:30:56:50 | call to make_unique | TAINT | +| smart_pointer.cpp:57:10:57:10 | p | smart_pointer.cpp:57:12:57:14 | call to get | TAINT | +| smart_pointer.cpp:65:28:65:46 | call to make_unique | smart_pointer.cpp:66:10:66:10 | p | | +| smart_pointer.cpp:65:28:65:46 | call to make_unique | smart_pointer.cpp:67:10:67:10 | p | | +| smart_pointer.cpp:65:48:65:53 | call to source | smart_pointer.cpp:65:28:65:46 | call to make_unique | TAINT | +| smart_pointer.cpp:65:58:65:58 | 0 | smart_pointer.cpp:65:28:65:46 | call to make_unique | TAINT | +| standalone_iterators.cpp:39:45:39:51 | source1 | standalone_iterators.cpp:39:45:39:51 | source1 | | +| standalone_iterators.cpp:39:45:39:51 | source1 | standalone_iterators.cpp:40:11:40:17 | source1 | | +| standalone_iterators.cpp:39:45:39:51 | source1 | standalone_iterators.cpp:41:12:41:18 | source1 | | +| standalone_iterators.cpp:39:45:39:51 | source1 | standalone_iterators.cpp:42:14:42:20 | source1 | | +| standalone_iterators.cpp:40:11:40:17 | source1 | standalone_iterators.cpp:40:10:40:10 | call to operator* | TAINT | +| standalone_iterators.cpp:41:12:41:18 | ref arg source1 | standalone_iterators.cpp:39:45:39:51 | source1 | | +| standalone_iterators.cpp:41:12:41:18 | ref arg source1 | standalone_iterators.cpp:42:14:42:20 | source1 | | +| standalone_iterators.cpp:41:12:41:18 | source1 | standalone_iterators.cpp:41:19:41:19 | call to operator++ | | +| standalone_iterators.cpp:41:19:41:19 | call to operator++ | standalone_iterators.cpp:41:10:41:10 | call to operator* | TAINT | +| standalone_iterators.cpp:42:12:42:12 | call to operator++ | standalone_iterators.cpp:42:10:42:10 | call to operator* | TAINT | +| standalone_iterators.cpp:42:14:42:20 | ref arg source1 | standalone_iterators.cpp:39:45:39:51 | source1 | | +| standalone_iterators.cpp:42:14:42:20 | source1 | standalone_iterators.cpp:42:12:42:12 | call to operator++ | | +| standalone_iterators.cpp:45:39:45:45 | source1 | standalone_iterators.cpp:45:39:45:45 | source1 | | +| standalone_iterators.cpp:45:39:45:45 | source1 | standalone_iterators.cpp:46:11:46:17 | source1 | | +| standalone_iterators.cpp:45:39:45:45 | source1 | standalone_iterators.cpp:47:12:47:18 | source1 | | +| standalone_iterators.cpp:45:39:45:45 | source1 | standalone_iterators.cpp:48:14:48:20 | source1 | | +| standalone_iterators.cpp:46:11:46:17 | source1 | standalone_iterators.cpp:46:10:46:10 | call to operator* | TAINT | +| standalone_iterators.cpp:47:12:47:18 | ref arg source1 | standalone_iterators.cpp:45:39:45:45 | source1 | | +| standalone_iterators.cpp:47:12:47:18 | ref arg source1 | standalone_iterators.cpp:48:14:48:20 | source1 | | +| standalone_iterators.cpp:47:12:47:18 | source1 | standalone_iterators.cpp:47:19:47:19 | call to operator++ | | +| standalone_iterators.cpp:47:19:47:19 | call to operator++ | standalone_iterators.cpp:47:10:47:10 | call to operator* | TAINT | +| standalone_iterators.cpp:48:12:48:12 | call to operator++ | standalone_iterators.cpp:48:10:48:10 | call to operator* | TAINT | +| standalone_iterators.cpp:48:14:48:20 | ref arg source1 | standalone_iterators.cpp:45:39:45:45 | source1 | | +| standalone_iterators.cpp:48:14:48:20 | source1 | standalone_iterators.cpp:48:12:48:12 | call to operator++ | | +| standalone_iterators.cpp:51:37:51:43 | source1 | standalone_iterators.cpp:52:11:52:17 | source1 | | +| standalone_iterators.cpp:51:37:51:43 | source1 | standalone_iterators.cpp:53:12:53:18 | source1 | | +| standalone_iterators.cpp:51:37:51:43 | source1 | standalone_iterators.cpp:54:14:54:20 | source1 | | +| standalone_iterators.cpp:53:12:53:18 | ref arg source1 | standalone_iterators.cpp:54:14:54:20 | source1 | | +| stl.h:241:30:241:40 | call to allocator | stl.h:241:21:241:41 | noexcept(...) | TAINT | +| stl.h:241:30:241:40 | call to allocator | stl.h:241:21:241:41 | noexcept(...) | TAINT | +| stl.h:241:30:241:40 | call to allocator | stl.h:241:21:241:41 | noexcept(...) | TAINT | +| stl.h:241:30:241:40 | call to allocator | stl.h:241:21:241:41 | noexcept(...) | TAINT | +| stl.h:241:30:241:40 | call to allocator | stl.h:241:21:241:41 | noexcept(...) | TAINT | +| stl.h:241:53:241:63 | 0 | stl.h:241:46:241:64 | (no string representation) | TAINT | +| stl.h:334:9:334:9 | Unknown literal | stl.h:334:9:334:9 | constructor init of field first | TAINT | +| stl.h:334:9:334:9 | Unknown literal | stl.h:334:9:334:9 | constructor init of field second | TAINT | +| stl.h:334:9:334:9 | constructor init of field first [post-this] | stl.h:334:9:334:9 | constructor init of field second [pre-this] | | +| stl.h:334:9:334:9 | constructor init of field first [pre-this] | stl.h:334:9:334:9 | constructor init of field second [pre-this] | | +| stl.h:334:9:334:9 | this | stl.h:334:9:334:9 | constructor init of field first [pre-this] | | +| stl.h:341:3:341:3 | this | stl.h:341:36:341:43 | constructor init of field first [pre-this] | | +| stl.h:341:3:341:3 | this | stl.h:341:36:341:43 | constructor init of field first [pre-this] | | +| stl.h:341:3:341:3 | this | stl.h:341:36:341:43 | constructor init of field first [pre-this] | | +| stl.h:341:3:341:3 | this | stl.h:341:36:341:43 | constructor init of field first [pre-this] | | +| stl.h:341:3:341:3 | this | stl.h:341:36:341:43 | constructor init of field first [pre-this] | | +| stl.h:341:3:341:3 | this | stl.h:341:36:341:43 | constructor init of field first [pre-this] | | +| stl.h:341:3:341:3 | this | stl.h:341:36:341:43 | constructor init of field first [pre-this] | | +| stl.h:341:3:341:6 | this | stl.h:341:36:341:43 | constructor init of field first [pre-this] | | +| stl.h:341:18:341:18 | x | stl.h:341:18:341:18 | x | | +| stl.h:341:18:341:18 | x | stl.h:341:18:341:18 | x | | +| stl.h:341:18:341:18 | x | stl.h:341:18:341:18 | x | | +| stl.h:341:18:341:18 | x | stl.h:341:18:341:18 | x | | +| stl.h:341:18:341:18 | x | stl.h:341:42:341:42 | x | | +| stl.h:341:18:341:18 | x | stl.h:341:42:341:42 | x | | +| stl.h:341:18:341:18 | x | stl.h:341:42:341:42 | x | | +| stl.h:341:18:341:18 | x | stl.h:341:42:341:42 | x | | +| stl.h:341:18:341:18 | x | stl.h:341:42:341:42 | x | | +| stl.h:341:18:341:18 | x | stl.h:341:42:341:42 | x | | +| stl.h:341:18:341:18 | x | stl.h:341:42:341:42 | x | | +| stl.h:341:18:341:18 | x | stl.h:341:42:341:42 | x | | +| stl.h:341:31:341:31 | y | stl.h:341:31:341:31 | y | | +| stl.h:341:31:341:31 | y | stl.h:341:31:341:31 | y | | +| stl.h:341:31:341:31 | y | stl.h:341:31:341:31 | y | | +| stl.h:341:31:341:31 | y | stl.h:341:31:341:31 | y | | +| stl.h:341:31:341:31 | y | stl.h:341:53:341:53 | y | | +| stl.h:341:31:341:31 | y | stl.h:341:53:341:53 | y | | +| stl.h:341:31:341:31 | y | stl.h:341:53:341:53 | y | | +| stl.h:341:31:341:31 | y | stl.h:341:53:341:53 | y | | +| stl.h:341:31:341:31 | y | stl.h:341:53:341:53 | y | | +| stl.h:341:31:341:31 | y | stl.h:341:53:341:53 | y | | +| stl.h:341:31:341:31 | y | stl.h:341:53:341:53 | y | | +| stl.h:341:31:341:31 | y | stl.h:341:53:341:53 | y | | +| stl.h:341:36:341:43 | call to unknown function | stl.h:341:36:341:43 | constructor init of field first | TAINT | +| stl.h:341:36:341:43 | constructor init of field first [post-this] | stl.h:341:46:341:54 | constructor init of field second [pre-this] | | +| stl.h:341:36:341:43 | constructor init of field first [post-this] | stl.h:341:46:341:54 | constructor init of field second [pre-this] | | +| stl.h:341:36:341:43 | constructor init of field first [post-this] | stl.h:341:46:341:54 | constructor init of field second [pre-this] | | +| stl.h:341:36:341:43 | constructor init of field first [post-this] | stl.h:341:46:341:54 | constructor init of field second [pre-this] | | +| stl.h:341:36:341:43 | constructor init of field first [post-this] | stl.h:341:46:341:54 | constructor init of field second [pre-this] | | +| stl.h:341:36:341:43 | constructor init of field first [post-this] | stl.h:341:46:341:54 | constructor init of field second [pre-this] | | +| stl.h:341:36:341:43 | constructor init of field first [post-this] | stl.h:341:46:341:54 | constructor init of field second [pre-this] | | +| stl.h:341:36:341:43 | constructor init of field first [post-this] | stl.h:341:46:341:54 | constructor init of field second [pre-this] | | +| stl.h:341:36:341:43 | constructor init of field first [pre-this] | stl.h:341:46:341:54 | constructor init of field second [pre-this] | | +| stl.h:341:36:341:43 | constructor init of field first [pre-this] | stl.h:341:46:341:54 | constructor init of field second [pre-this] | | +| stl.h:341:36:341:43 | constructor init of field first [pre-this] | stl.h:341:46:341:54 | constructor init of field second [pre-this] | | +| stl.h:341:36:341:43 | constructor init of field first [pre-this] | stl.h:341:46:341:54 | constructor init of field second [pre-this] | | +| stl.h:341:36:341:43 | constructor init of field first [pre-this] | stl.h:341:46:341:54 | constructor init of field second [pre-this] | | +| stl.h:341:36:341:43 | constructor init of field first [pre-this] | stl.h:341:46:341:54 | constructor init of field second [pre-this] | | +| stl.h:341:36:341:43 | constructor init of field first [pre-this] | stl.h:341:46:341:54 | constructor init of field second [pre-this] | | +| stl.h:341:36:341:43 | constructor init of field first [pre-this] | stl.h:341:46:341:54 | constructor init of field second [pre-this] | | +| stl.h:341:42:341:42 | x | stl.h:341:36:341:43 | constructor init of field first | TAINT | +| stl.h:341:42:341:42 | x | stl.h:341:36:341:43 | constructor init of field first | TAINT | +| stl.h:341:42:341:42 | x | stl.h:341:36:341:43 | constructor init of field first | TAINT | +| stl.h:341:42:341:42 | x | stl.h:341:36:341:43 | constructor init of field first | TAINT | +| stl.h:341:42:341:42 | x | stl.h:341:36:341:43 | constructor init of field first | TAINT | +| stl.h:341:42:341:42 | x | stl.h:341:36:341:43 | constructor init of field first | TAINT | +| stl.h:341:42:341:42 | x | stl.h:341:36:341:43 | constructor init of field first | TAINT | +| stl.h:341:46:341:54 | call to unknown function | stl.h:341:46:341:54 | constructor init of field second | TAINT | +| stl.h:341:53:341:53 | y | stl.h:341:46:341:54 | constructor init of field second | TAINT | +| stl.h:341:53:341:53 | y | stl.h:341:46:341:54 | constructor init of field second | TAINT | +| stl.h:341:53:341:53 | y | stl.h:341:46:341:54 | constructor init of field second | TAINT | +| stl.h:341:53:341:53 | y | stl.h:341:46:341:54 | constructor init of field second | TAINT | +| stl.h:341:53:341:53 | y | stl.h:341:46:341:54 | constructor init of field second | TAINT | +| stl.h:341:53:341:53 | y | stl.h:341:46:341:54 | constructor init of field second | TAINT | +| stl.h:341:53:341:53 | y | stl.h:341:46:341:54 | constructor init of field second | TAINT | +| stl.h:347:109:347:109 | x | stl.h:347:109:347:109 | x | | +| stl.h:347:109:347:109 | x | stl.h:347:109:347:109 | x | | +| stl.h:347:109:347:109 | x | stl.h:347:109:347:109 | x | | +| stl.h:347:109:347:109 | x | stl.h:347:109:347:109 | x | | +| stl.h:347:109:347:109 | x | stl.h:347:109:347:109 | x | | +| stl.h:347:109:347:109 | x | stl.h:347:109:347:109 | x | | +| stl.h:347:109:347:109 | x | stl.h:347:109:347:109 | x | | +| stl.h:347:109:347:109 | x | stl.h:348:40:348:40 | x | | +| stl.h:347:109:347:109 | x | stl.h:348:40:348:40 | x | | +| stl.h:347:109:347:109 | x | stl.h:348:40:348:40 | x | | +| stl.h:347:109:347:109 | x | stl.h:348:40:348:40 | x | | +| stl.h:347:109:347:109 | x | stl.h:348:40:348:40 | x | | +| stl.h:347:109:347:109 | x | stl.h:348:40:348:40 | x | | +| stl.h:347:109:347:109 | x | stl.h:348:40:348:40 | x | | +| stl.h:347:117:347:117 | y | stl.h:347:117:347:117 | y | | +| stl.h:347:117:347:117 | y | stl.h:347:117:347:117 | y | | +| stl.h:347:117:347:117 | y | stl.h:347:117:347:117 | y | | +| stl.h:347:117:347:117 | y | stl.h:347:117:347:117 | y | | +| stl.h:347:117:347:117 | y | stl.h:347:117:347:117 | y | | +| stl.h:347:117:347:117 | y | stl.h:347:117:347:117 | y | | +| stl.h:347:117:347:117 | y | stl.h:347:117:347:117 | y | | +| stl.h:347:117:347:117 | y | stl.h:348:61:348:61 | y | | +| stl.h:347:117:347:117 | y | stl.h:348:61:348:61 | y | | +| stl.h:347:117:347:117 | y | stl.h:348:61:348:61 | y | | +| stl.h:347:117:347:117 | y | stl.h:348:61:348:61 | y | | +| stl.h:347:117:347:117 | y | stl.h:348:61:348:61 | y | | +| stl.h:347:117:347:117 | y | stl.h:348:61:348:61 | y | | +| stl.h:347:117:347:117 | y | stl.h:348:61:348:61 | y | | +| stl.h:348:10:348:63 | call to pair | stl.h:348:10:348:63 | call to pair | TAINT | +| stl.h:348:10:348:63 | call to pair | stl.h:348:10:348:63 | call to pair | TAINT | +| stl.h:348:10:348:63 | call to pair | stl.h:348:10:348:63 | call to pair | TAINT | +| stl.h:348:10:348:63 | call to pair | stl.h:348:10:348:63 | call to pair | TAINT | +| stl.h:348:10:348:63 | call to pair | stl.h:348:10:348:63 | call to pair | TAINT | +| stl.h:348:10:348:63 | call to pair | stl.h:348:10:348:63 | call to pair | TAINT | +| stl.h:348:23:348:38 | ref arg call to forward | stl.h:347:109:347:109 | x | | +| stl.h:348:23:348:38 | ref arg call to forward | stl.h:347:109:347:109 | x | | +| stl.h:348:23:348:38 | ref arg call to forward | stl.h:347:109:347:109 | x | | +| stl.h:348:23:348:38 | ref arg call to forward | stl.h:347:109:347:109 | x | | +| stl.h:348:23:348:38 | ref arg call to forward | stl.h:348:40:348:40 | x [inner post update] | | +| stl.h:348:23:348:38 | ref arg call to forward | stl.h:348:40:348:40 | x [inner post update] | | +| stl.h:348:23:348:38 | ref arg call to forward | stl.h:348:40:348:40 | x [inner post update] | | +| stl.h:348:23:348:38 | ref arg call to forward | stl.h:348:40:348:40 | x [inner post update] | | +| stl.h:348:40:348:40 | x | stl.h:348:23:348:38 | call to forward | | +| stl.h:348:40:348:40 | x | stl.h:348:23:348:38 | call to forward | | +| stl.h:348:40:348:40 | x | stl.h:348:23:348:38 | call to forward | | +| stl.h:348:40:348:40 | x | stl.h:348:23:348:38 | call to forward | | +| stl.h:348:40:348:40 | x | stl.h:348:23:348:38 | call to forward | | +| stl.h:348:40:348:40 | x | stl.h:348:23:348:38 | call to forward | | +| stl.h:348:44:348:59 | call to forward | stl.h:348:10:348:63 | call to pair | TAINT | +| stl.h:348:44:348:59 | call to forward | stl.h:348:10:348:63 | call to pair | TAINT | +| stl.h:348:44:348:59 | ref arg call to forward | stl.h:347:117:347:117 | y | | +| stl.h:348:44:348:59 | ref arg call to forward | stl.h:347:117:347:117 | y | | +| stl.h:348:44:348:59 | ref arg call to forward | stl.h:347:117:347:117 | y | | +| stl.h:348:44:348:59 | ref arg call to forward | stl.h:347:117:347:117 | y | | +| stl.h:348:44:348:59 | ref arg call to forward | stl.h:348:61:348:61 | y [inner post update] | | +| stl.h:348:44:348:59 | ref arg call to forward | stl.h:348:61:348:61 | y [inner post update] | | +| stl.h:348:44:348:59 | ref arg call to forward | stl.h:348:61:348:61 | y [inner post update] | | +| stl.h:348:44:348:59 | ref arg call to forward | stl.h:348:61:348:61 | y [inner post update] | | +| stl.h:348:61:348:61 | y | stl.h:348:10:348:63 | call to pair | TAINT | +| stl.h:348:61:348:61 | y | stl.h:348:10:348:63 | call to pair | TAINT | +| stl.h:348:61:348:61 | y | stl.h:348:44:348:59 | call to forward | | +| stl.h:348:61:348:61 | y | stl.h:348:44:348:59 | call to forward | | +| stl.h:348:61:348:61 | y | stl.h:348:44:348:59 | call to forward | | +| stl.h:348:61:348:61 | y | stl.h:348:44:348:59 | call to forward | | +| stl.h:348:61:348:61 | y | stl.h:348:44:348:59 | call to forward | | +| stl.h:348:61:348:61 | y | stl.h:348:44:348:59 | call to forward | | +| string.cpp:25:12:25:17 | call to source | string.cpp:29:7:29:7 | a | | +| string.cpp:26:16:26:20 | 123 | string.cpp:26:16:26:21 | call to basic_string | TAINT | +| string.cpp:26:16:26:21 | call to basic_string | string.cpp:30:7:30:7 | b | | +| string.cpp:26:16:26:21 | call to basic_string | string.cpp:32:7:32:7 | b | | +| string.cpp:27:16:27:21 | call to source | string.cpp:27:16:27:24 | call to basic_string | TAINT | +| string.cpp:27:16:27:24 | call to basic_string | string.cpp:31:7:31:7 | c | | +| string.cpp:27:16:27:24 | call to basic_string | string.cpp:33:7:33:7 | c | | +| string.cpp:32:7:32:7 | b | string.cpp:32:9:32:13 | call to c_str | TAINT | +| string.cpp:33:7:33:7 | c | string.cpp:33:9:33:13 | call to c_str | TAINT | +| string.cpp:38:16:38:28 | call to basic_string | string.cpp:39:7:39:11 | path1 | | +| string.cpp:38:17:38:26 | call to user_input | string.cpp:38:16:38:28 | call to basic_string | TAINT | +| string.cpp:39:7:39:11 | path1 | string.cpp:39:13:39:17 | call to c_str | TAINT | +| string.cpp:42:10:42:19 | call to user_input | string.cpp:42:10:42:21 | call to basic_string | TAINT | +| string.cpp:42:10:42:21 | call to basic_string | string.cpp:42:2:42:21 | ... = ... | | +| string.cpp:42:10:42:21 | call to basic_string | string.cpp:43:7:43:11 | path2 | | +| string.cpp:43:7:43:11 | path2 | string.cpp:43:13:43:17 | call to c_str | TAINT | +| string.cpp:45:15:45:24 | call to user_input | string.cpp:45:15:45:27 | call to basic_string | TAINT | +| string.cpp:45:15:45:27 | call to basic_string | string.cpp:46:7:46:11 | path3 | | +| string.cpp:46:7:46:11 | path3 | string.cpp:46:13:46:17 | call to c_str | TAINT | +| string.cpp:51:19:51:24 | call to source | string.cpp:54:17:54:18 | cs | | +| string.cpp:51:19:51:24 | call to source | string.cpp:56:7:56:8 | cs | | +| string.cpp:54:17:54:18 | cs | string.cpp:54:17:54:19 | call to basic_string | TAINT | +| string.cpp:54:17:54:19 | call to basic_string | string.cpp:57:7:57:8 | ss | | +| string.cpp:62:19:62:24 | call to source | string.cpp:65:17:65:18 | cs | | +| string.cpp:65:17:65:18 | cs | string.cpp:65:17:65:19 | call to basic_string | TAINT | +| string.cpp:65:17:65:19 | call to basic_string | string.cpp:68:7:68:8 | ss | | +| string.cpp:65:17:65:19 | call to basic_string | string.cpp:71:7:71:8 | ss | | +| string.cpp:68:7:68:8 | ss | string.cpp:68:10:68:14 | call to c_str | TAINT | +| string.cpp:68:10:68:14 | call to c_str | string.cpp:68:2:68:16 | ... = ... | | +| string.cpp:68:10:68:14 | call to c_str | string.cpp:70:7:70:8 | cs | | +| string.cpp:77:18:77:24 | hello | string.cpp:77:18:77:25 | call to basic_string | TAINT | +| string.cpp:77:18:77:25 | call to basic_string | string.cpp:82:8:82:9 | s1 | | +| string.cpp:78:19:78:26 | call to basic_string | string.cpp:83:8:83:9 | s2 | | +| string.cpp:78:20:78:26 | hello | string.cpp:78:19:78:26 | call to basic_string | TAINT | +| string.cpp:80:8:80:14 | call to basic_string | string.cpp:80:3:80:14 | ... = ... | | +| string.cpp:80:8:80:14 | call to basic_string | string.cpp:84:8:84:9 | s3 | | +| string.cpp:80:8:80:14 | hello | string.cpp:80:8:80:14 | call to basic_string | TAINT | +| string.cpp:88:18:88:23 | call to source | string.cpp:88:18:88:26 | call to basic_string | TAINT | +| string.cpp:88:18:88:26 | call to basic_string | string.cpp:93:8:93:9 | s1 | | +| string.cpp:89:19:89:27 | call to basic_string | string.cpp:94:8:94:9 | s2 | | +| string.cpp:89:20:89:25 | call to source | string.cpp:89:19:89:27 | call to basic_string | TAINT | +| string.cpp:91:8:91:13 | call to source | string.cpp:91:8:91:15 | call to basic_string | TAINT | +| string.cpp:91:8:91:15 | call to basic_string | string.cpp:91:3:91:15 | ... = ... | | +| string.cpp:91:8:91:15 | call to basic_string | string.cpp:95:8:95:9 | s3 | | +| string.cpp:99:15:99:16 | call to basic_string | string.cpp:100:20:100:21 | s1 | | +| string.cpp:99:15:99:16 | call to basic_string | string.cpp:102:8:102:9 | s1 | | +| string.cpp:99:15:99:16 | call to basic_string | string.cpp:104:8:104:9 | s1 | | +| string.cpp:100:20:100:21 | s1 | string.cpp:105:8:105:9 | s2 | | +| string.cpp:102:8:102:9 | s1 | string.cpp:102:3:102:9 | ... = ... | | +| string.cpp:102:8:102:9 | s1 | string.cpp:106:8:106:9 | s3 | | +| string.cpp:110:19:110:40 | call to basic_string | string.cpp:114:8:114:9 | s1 | | +| string.cpp:110:32:110:37 | call to source | string.cpp:110:19:110:40 | call to basic_string | TAINT | +| string.cpp:112:8:112:28 | call to basic_string | string.cpp:112:3:112:28 | ... = ... | | +| string.cpp:112:8:112:28 | call to basic_string | string.cpp:115:8:115:9 | s2 | | +| string.cpp:112:20:112:25 | call to source | string.cpp:112:8:112:28 | call to basic_string | TAINT | +| string.cpp:120:16:120:21 | call to source | string.cpp:120:16:120:24 | call to basic_string | TAINT | +| string.cpp:120:16:120:24 | call to basic_string | string.cpp:121:15:121:15 | s | | +| string.cpp:120:16:120:24 | call to basic_string | string.cpp:125:33:125:33 | s | | +| string.cpp:120:16:120:24 | call to basic_string | string.cpp:125:50:125:50 | s | | +| string.cpp:120:16:120:24 | call to basic_string | string.cpp:129:16:129:16 | s | | +| string.cpp:121:15:121:15 | (__begin) | string.cpp:121:15:121:15 | call to operator* | TAINT | +| string.cpp:121:15:121:15 | (__begin) | string.cpp:121:15:121:15 | call to operator++ | | +| string.cpp:121:15:121:15 | (__end) | string.cpp:121:15:121:15 | call to iterator | | +| string.cpp:121:15:121:15 | (__range) | string.cpp:121:15:121:15 | call to begin | TAINT | +| string.cpp:121:15:121:15 | (__range) | string.cpp:121:15:121:15 | call to end | TAINT | +| string.cpp:121:15:121:15 | call to begin | string.cpp:121:15:121:15 | (__begin) | | +| string.cpp:121:15:121:15 | call to begin | string.cpp:121:15:121:15 | (__begin) | | +| string.cpp:121:15:121:15 | call to begin | string.cpp:121:15:121:15 | (__begin) | | +| string.cpp:121:15:121:15 | call to end | string.cpp:121:15:121:15 | (__end) | | +| string.cpp:121:15:121:15 | call to operator* | string.cpp:122:8:122:8 | c | | +| string.cpp:121:15:121:15 | ref arg (__begin) | string.cpp:121:15:121:15 | (__begin) | | +| string.cpp:121:15:121:15 | ref arg (__begin) | string.cpp:121:15:121:15 | (__begin) | | +| string.cpp:121:15:121:15 | ref arg (__begin) | string.cpp:121:15:121:15 | (__begin) | | +| string.cpp:121:15:121:15 | ref arg (__range) | string.cpp:121:15:121:15 | (__range) | | +| string.cpp:121:15:121:15 | s | string.cpp:121:15:121:15 | (__range) | | +| string.cpp:121:15:121:15 | s | string.cpp:121:15:121:15 | (__range) | | +| string.cpp:121:15:121:15 | s | string.cpp:121:15:121:15 | call to operator* | TAINT | +| string.cpp:125:33:125:33 | ref arg s | string.cpp:125:50:125:50 | s | | +| string.cpp:125:33:125:33 | ref arg s | string.cpp:129:16:129:16 | s | | +| string.cpp:125:33:125:33 | s | string.cpp:125:35:125:39 | call to begin | TAINT | +| string.cpp:125:35:125:39 | call to begin | string.cpp:125:44:125:45 | it | | +| string.cpp:125:35:125:39 | call to begin | string.cpp:125:61:125:62 | it | | +| string.cpp:125:35:125:39 | call to begin | string.cpp:126:9:126:10 | it | | +| string.cpp:125:50:125:50 | ref arg s | string.cpp:125:50:125:50 | s | | +| string.cpp:125:50:125:50 | ref arg s | string.cpp:129:16:129:16 | s | | +| string.cpp:125:50:125:50 | s | string.cpp:125:52:125:54 | call to end | TAINT | +| string.cpp:125:61:125:62 | it | string.cpp:125:59:125:59 | call to operator++ | | +| string.cpp:125:61:125:62 | ref arg it | string.cpp:125:44:125:45 | it | | +| string.cpp:125:61:125:62 | ref arg it | string.cpp:125:61:125:62 | it | | +| string.cpp:125:61:125:62 | ref arg it | string.cpp:126:9:126:10 | it | | +| string.cpp:126:9:126:10 | it | string.cpp:126:8:126:8 | call to operator* | TAINT | +| string.cpp:129:16:129:16 | (__begin) | string.cpp:129:16:129:16 | call to operator* | TAINT | +| string.cpp:129:16:129:16 | (__begin) | string.cpp:129:16:129:16 | call to operator++ | | +| string.cpp:129:16:129:16 | (__end) | string.cpp:129:16:129:16 | call to iterator | | +| string.cpp:129:16:129:16 | (__range) | string.cpp:129:16:129:16 | call to begin | TAINT | +| string.cpp:129:16:129:16 | (__range) | string.cpp:129:16:129:16 | call to end | TAINT | +| string.cpp:129:16:129:16 | call to begin | string.cpp:129:16:129:16 | (__begin) | | +| string.cpp:129:16:129:16 | call to begin | string.cpp:129:16:129:16 | (__begin) | | +| string.cpp:129:16:129:16 | call to begin | string.cpp:129:16:129:16 | (__begin) | | +| string.cpp:129:16:129:16 | call to end | string.cpp:129:16:129:16 | (__end) | | +| string.cpp:129:16:129:16 | call to operator* | string.cpp:130:8:130:8 | c | | +| string.cpp:129:16:129:16 | ref arg (__begin) | string.cpp:129:16:129:16 | (__begin) | | +| string.cpp:129:16:129:16 | ref arg (__begin) | string.cpp:129:16:129:16 | (__begin) | | +| string.cpp:129:16:129:16 | ref arg (__begin) | string.cpp:129:16:129:16 | (__begin) | | +| string.cpp:129:16:129:16 | ref arg (__range) | string.cpp:129:16:129:16 | (__range) | | +| string.cpp:129:16:129:16 | s | string.cpp:129:16:129:16 | (__range) | | +| string.cpp:129:16:129:16 | s | string.cpp:129:16:129:16 | (__range) | | +| string.cpp:129:16:129:16 | s | string.cpp:129:16:129:16 | call to operator* | TAINT | +| string.cpp:133:28:133:33 | call to source | string.cpp:133:28:133:36 | call to basic_string | TAINT | +| string.cpp:133:28:133:36 | call to basic_string | string.cpp:134:22:134:28 | const_s | | +| string.cpp:134:22:134:22 | (__begin) | string.cpp:134:22:134:22 | call to operator* | TAINT | +| string.cpp:134:22:134:22 | (__begin) | string.cpp:134:22:134:22 | call to operator++ | | +| string.cpp:134:22:134:22 | (__range) | string.cpp:134:22:134:22 | call to begin | TAINT | +| string.cpp:134:22:134:22 | (__range) | string.cpp:134:22:134:22 | call to end | TAINT | +| string.cpp:134:22:134:22 | call to begin | string.cpp:134:22:134:22 | (__begin) | | +| string.cpp:134:22:134:22 | call to begin | string.cpp:134:22:134:22 | (__begin) | | +| string.cpp:134:22:134:22 | call to begin | string.cpp:134:22:134:22 | (__begin) | | +| string.cpp:134:22:134:22 | call to end | string.cpp:134:22:134:22 | (__end) | | +| string.cpp:134:22:134:22 | call to operator* | string.cpp:135:8:135:8 | c | | +| string.cpp:134:22:134:22 | ref arg (__begin) | string.cpp:134:22:134:22 | (__begin) | | +| string.cpp:134:22:134:22 | ref arg (__begin) | string.cpp:134:22:134:22 | (__begin) | | +| string.cpp:134:22:134:22 | ref arg (__begin) | string.cpp:134:22:134:22 | (__begin) | | +| string.cpp:134:22:134:28 | const_s | string.cpp:134:22:134:22 | (__range) | | +| string.cpp:134:22:134:28 | const_s | string.cpp:134:22:134:22 | (__range) | | +| string.cpp:134:22:134:28 | const_s | string.cpp:134:22:134:22 | call to operator* | TAINT | +| string.cpp:141:18:141:24 | hello | string.cpp:141:18:141:25 | call to basic_string | TAINT | +| string.cpp:141:18:141:25 | call to basic_string | string.cpp:144:8:144:9 | s1 | | +| string.cpp:141:18:141:25 | call to basic_string | string.cpp:144:13:144:14 | s1 | | +| string.cpp:141:18:141:25 | call to basic_string | string.cpp:145:8:145:9 | s1 | | +| string.cpp:141:18:141:25 | call to basic_string | string.cpp:146:13:146:14 | s1 | | +| string.cpp:141:18:141:25 | call to basic_string | string.cpp:149:8:149:9 | s1 | | +| string.cpp:141:18:141:25 | call to basic_string | string.cpp:150:8:150:9 | s1 | | +| string.cpp:142:18:142:23 | call to source | string.cpp:142:18:142:26 | call to basic_string | TAINT | +| string.cpp:142:18:142:26 | call to basic_string | string.cpp:145:13:145:14 | s2 | | +| string.cpp:142:18:142:26 | call to basic_string | string.cpp:146:8:146:9 | s2 | | +| string.cpp:142:18:142:26 | call to basic_string | string.cpp:147:8:147:9 | s2 | | +| string.cpp:142:18:142:26 | call to basic_string | string.cpp:147:13:147:14 | s2 | | +| string.cpp:144:8:144:9 | s1 | string.cpp:144:11:144:11 | call to operator+ | TAINT | +| string.cpp:144:13:144:14 | s1 | string.cpp:144:11:144:11 | call to operator+ | TAINT | +| string.cpp:145:8:145:9 | s1 | string.cpp:145:11:145:11 | call to operator+ | TAINT | +| string.cpp:145:13:145:14 | s2 | string.cpp:145:11:145:11 | call to operator+ | TAINT | +| string.cpp:146:8:146:9 | s2 | string.cpp:146:11:146:11 | call to operator+ | TAINT | +| string.cpp:146:13:146:14 | s1 | string.cpp:146:11:146:11 | call to operator+ | TAINT | +| string.cpp:147:8:147:9 | s2 | string.cpp:147:11:147:11 | call to operator+ | TAINT | +| string.cpp:147:13:147:14 | s2 | string.cpp:147:11:147:11 | call to operator+ | TAINT | +| string.cpp:149:8:149:9 | s1 | string.cpp:149:11:149:11 | call to operator+ | TAINT | +| string.cpp:149:13:149:20 | world | string.cpp:149:11:149:11 | call to operator+ | TAINT | +| string.cpp:150:8:150:9 | s1 | string.cpp:150:11:150:11 | call to operator+ | TAINT | +| string.cpp:150:13:150:18 | call to source | string.cpp:150:11:150:11 | call to operator+ | TAINT | +| string.cpp:154:18:154:22 | abc | string.cpp:154:18:154:23 | call to basic_string | TAINT | +| string.cpp:154:18:154:23 | call to basic_string | string.cpp:158:8:158:9 | s3 | | +| string.cpp:154:18:154:23 | call to basic_string | string.cpp:161:8:161:9 | s3 | | +| string.cpp:154:18:154:23 | call to basic_string | string.cpp:165:8:165:9 | s3 | | +| string.cpp:154:18:154:23 | call to basic_string | string.cpp:170:8:170:9 | s3 | | +| string.cpp:154:18:154:23 | call to basic_string | string.cpp:174:8:174:9 | s3 | | +| string.cpp:155:18:155:23 | call to source | string.cpp:155:18:155:26 | call to basic_string | TAINT | +| string.cpp:155:18:155:26 | call to basic_string | string.cpp:158:13:158:14 | s4 | | +| string.cpp:155:18:155:26 | call to basic_string | string.cpp:162:14:162:15 | s4 | | +| string.cpp:155:18:155:26 | call to basic_string | string.cpp:171:13:171:14 | s4 | | +| string.cpp:158:8:158:9 | s3 | string.cpp:158:11:158:11 | call to operator+ | TAINT | +| string.cpp:158:11:158:11 | call to operator+ | string.cpp:158:3:158:14 | ... = ... | | +| string.cpp:158:11:158:11 | call to operator+ | string.cpp:159:8:159:9 | s5 | | +| string.cpp:158:13:158:14 | s4 | string.cpp:158:11:158:11 | call to operator+ | TAINT | +| string.cpp:161:8:161:9 | s3 | string.cpp:161:3:161:9 | ... = ... | | +| string.cpp:161:8:161:9 | s3 | string.cpp:162:8:162:9 | s6 | | +| string.cpp:161:8:161:9 | s3 | string.cpp:163:8:163:9 | s6 | | +| string.cpp:162:8:162:9 | ref arg s6 | string.cpp:163:8:163:9 | s6 | | +| string.cpp:162:8:162:9 | s6 | string.cpp:162:11:162:11 | call to operator+= | TAINT | +| string.cpp:162:14:162:15 | s4 | string.cpp:162:8:162:9 | ref arg s6 | TAINT | +| string.cpp:162:14:162:15 | s4 | string.cpp:162:11:162:11 | call to operator+= | TAINT | +| string.cpp:165:8:165:9 | s3 | string.cpp:165:3:165:9 | ... = ... | | +| string.cpp:165:8:165:9 | s3 | string.cpp:166:8:166:9 | s7 | | +| string.cpp:165:8:165:9 | s3 | string.cpp:167:8:167:9 | s7 | | +| string.cpp:165:8:165:9 | s3 | string.cpp:168:8:168:9 | s7 | | +| string.cpp:166:8:166:9 | ref arg s7 | string.cpp:167:8:167:9 | s7 | | +| string.cpp:166:8:166:9 | ref arg s7 | string.cpp:168:8:168:9 | s7 | | +| string.cpp:166:8:166:9 | s7 | string.cpp:166:11:166:11 | call to operator+= | TAINT | +| string.cpp:166:14:166:19 | call to source | string.cpp:166:8:166:9 | ref arg s7 | TAINT | +| string.cpp:166:14:166:19 | call to source | string.cpp:166:11:166:11 | call to operator+= | TAINT | +| string.cpp:167:8:167:9 | ref arg s7 | string.cpp:168:8:168:9 | s7 | | +| string.cpp:167:8:167:9 | s7 | string.cpp:167:11:167:11 | call to operator+= | TAINT | +| string.cpp:167:14:167:16 | | string.cpp:167:8:167:9 | ref arg s7 | TAINT | +| string.cpp:167:14:167:16 | | string.cpp:167:11:167:11 | call to operator+= | TAINT | +| string.cpp:170:8:170:9 | s3 | string.cpp:170:3:170:9 | ... = ... | | +| string.cpp:170:8:170:9 | s3 | string.cpp:171:3:171:4 | s8 | | +| string.cpp:170:8:170:9 | s3 | string.cpp:172:8:172:9 | s8 | | +| string.cpp:171:3:171:4 | ref arg s8 | string.cpp:172:8:172:9 | s8 | | +| string.cpp:171:3:171:4 | s8 | string.cpp:171:6:171:11 | call to append | TAINT | +| string.cpp:171:13:171:14 | s4 | string.cpp:171:3:171:4 | ref arg s8 | TAINT | +| string.cpp:171:13:171:14 | s4 | string.cpp:171:6:171:11 | call to append | TAINT | +| string.cpp:174:8:174:9 | s3 | string.cpp:174:3:174:9 | ... = ... | | +| string.cpp:174:8:174:9 | s3 | string.cpp:175:3:175:4 | s9 | | +| string.cpp:174:8:174:9 | s3 | string.cpp:176:3:176:4 | s9 | | +| string.cpp:174:8:174:9 | s3 | string.cpp:177:8:177:9 | s9 | | +| string.cpp:175:3:175:4 | ref arg s9 | string.cpp:176:3:176:4 | s9 | | +| string.cpp:175:3:175:4 | ref arg s9 | string.cpp:177:8:177:9 | s9 | | +| string.cpp:175:3:175:4 | s9 | string.cpp:175:6:175:11 | call to append | TAINT | +| string.cpp:175:13:175:18 | call to source | string.cpp:175:3:175:4 | ref arg s9 | TAINT | +| string.cpp:175:13:175:18 | call to source | string.cpp:175:6:175:11 | call to append | TAINT | +| string.cpp:176:3:176:4 | ref arg s9 | string.cpp:177:8:177:9 | s9 | | +| string.cpp:176:3:176:4 | s9 | string.cpp:176:6:176:11 | call to append | TAINT | +| string.cpp:176:13:176:15 | | string.cpp:176:3:176:4 | ref arg s9 | TAINT | +| string.cpp:176:13:176:15 | | string.cpp:176:6:176:11 | call to append | TAINT | +| string.cpp:181:19:181:23 | abc | string.cpp:181:19:181:24 | call to basic_string | TAINT | +| string.cpp:181:19:181:24 | call to basic_string | string.cpp:184:3:184:5 | s10 | | +| string.cpp:181:19:181:24 | call to basic_string | string.cpp:185:8:185:10 | s10 | | +| string.cpp:182:12:182:26 | call to source | string.cpp:184:17:184:17 | c | | +| string.cpp:184:3:184:5 | ref arg s10 | string.cpp:185:8:185:10 | s10 | | +| string.cpp:184:3:184:5 | s10 | string.cpp:184:7:184:12 | call to append | TAINT | +| string.cpp:184:17:184:17 | c | string.cpp:184:3:184:5 | ref arg s10 | TAINT | +| string.cpp:184:17:184:17 | c | string.cpp:184:7:184:12 | call to append | TAINT | +| string.cpp:190:17:190:23 | hello | string.cpp:190:17:190:24 | call to basic_string | TAINT | +| string.cpp:190:17:190:24 | call to basic_string | string.cpp:196:17:196:18 | s1 | | +| string.cpp:190:17:190:24 | call to basic_string | string.cpp:205:17:205:18 | s1 | | +| string.cpp:191:17:191:22 | call to source | string.cpp:191:17:191:25 | call to basic_string | TAINT | +| string.cpp:191:17:191:25 | call to basic_string | string.cpp:199:17:199:18 | s2 | | +| string.cpp:192:11:192:25 | call to source | string.cpp:202:21:202:21 | c | | +| string.cpp:193:14:193:15 | call to basic_string | string.cpp:196:7:196:8 | s3 | | +| string.cpp:193:14:193:15 | call to basic_string | string.cpp:197:7:197:8 | s3 | | +| string.cpp:193:18:193:19 | call to basic_string | string.cpp:199:7:199:8 | s4 | | +| string.cpp:193:18:193:19 | call to basic_string | string.cpp:200:7:200:8 | s4 | | +| string.cpp:193:22:193:23 | call to basic_string | string.cpp:202:7:202:8 | s5 | | +| string.cpp:193:22:193:23 | call to basic_string | string.cpp:203:7:203:8 | s5 | | +| string.cpp:194:17:194:22 | call to source | string.cpp:194:17:194:25 | call to basic_string | TAINT | +| string.cpp:194:17:194:25 | call to basic_string | string.cpp:205:7:205:8 | s6 | | +| string.cpp:194:17:194:25 | call to basic_string | string.cpp:206:7:206:8 | s6 | | +| string.cpp:196:7:196:8 | ref arg s3 | string.cpp:197:7:197:8 | s3 | | +| string.cpp:196:17:196:18 | s1 | string.cpp:196:7:196:8 | ref arg s3 | TAINT | +| string.cpp:196:17:196:18 | s1 | string.cpp:196:10:196:15 | call to assign | TAINT | +| string.cpp:199:7:199:8 | ref arg s4 | string.cpp:200:7:200:8 | s4 | | +| string.cpp:199:17:199:18 | s2 | string.cpp:199:7:199:8 | ref arg s4 | TAINT | +| string.cpp:199:17:199:18 | s2 | string.cpp:199:10:199:15 | call to assign | TAINT | +| string.cpp:202:7:202:8 | ref arg s5 | string.cpp:203:7:203:8 | s5 | | +| string.cpp:202:21:202:21 | c | string.cpp:202:7:202:8 | ref arg s5 | TAINT | +| string.cpp:202:21:202:21 | c | string.cpp:202:10:202:15 | call to assign | TAINT | +| string.cpp:205:7:205:8 | ref arg s6 | string.cpp:206:7:206:8 | s6 | | +| string.cpp:205:17:205:18 | s1 | string.cpp:205:7:205:8 | ref arg s6 | TAINT | +| string.cpp:205:17:205:18 | s1 | string.cpp:205:10:205:15 | call to assign | TAINT | +| string.cpp:210:17:210:23 | hello | string.cpp:210:17:210:24 | call to basic_string | TAINT | +| string.cpp:210:17:210:24 | call to basic_string | string.cpp:215:7:215:8 | s1 | | +| string.cpp:210:17:210:24 | call to basic_string | string.cpp:216:20:216:21 | s1 | | +| string.cpp:210:17:210:24 | call to basic_string | string.cpp:220:20:220:21 | s1 | | +| string.cpp:210:17:210:24 | call to basic_string | string.cpp:223:7:223:8 | s1 | | +| string.cpp:210:17:210:24 | call to basic_string | string.cpp:227:7:227:8 | s1 | | +| string.cpp:211:17:211:22 | call to source | string.cpp:211:17:211:25 | call to basic_string | TAINT | +| string.cpp:211:17:211:25 | call to basic_string | string.cpp:219:7:219:8 | s2 | | +| string.cpp:211:17:211:25 | call to basic_string | string.cpp:224:20:224:21 | s2 | | +| string.cpp:212:11:212:25 | call to source | string.cpp:228:24:228:24 | c | | +| string.cpp:215:7:215:8 | s1 | string.cpp:215:2:215:8 | ... = ... | | +| string.cpp:215:7:215:8 | s1 | string.cpp:216:7:216:8 | s3 | | +| string.cpp:215:7:215:8 | s1 | string.cpp:217:7:217:8 | s3 | | +| string.cpp:216:7:216:8 | ref arg s3 | string.cpp:217:7:217:8 | s3 | | +| string.cpp:216:7:216:8 | s3 | string.cpp:216:10:216:15 | call to insert | TAINT | +| string.cpp:216:20:216:21 | s1 | string.cpp:216:7:216:8 | ref arg s3 | TAINT | +| string.cpp:216:20:216:21 | s1 | string.cpp:216:10:216:15 | call to insert | TAINT | +| string.cpp:219:7:219:8 | s2 | string.cpp:219:2:219:8 | ... = ... | | +| string.cpp:219:7:219:8 | s2 | string.cpp:220:7:220:8 | s4 | | +| string.cpp:219:7:219:8 | s2 | string.cpp:221:7:221:8 | s4 | | +| string.cpp:220:7:220:8 | ref arg s4 | string.cpp:221:7:221:8 | s4 | | +| string.cpp:220:7:220:8 | s4 | string.cpp:220:10:220:15 | call to insert | TAINT | +| string.cpp:220:20:220:21 | s1 | string.cpp:220:7:220:8 | ref arg s4 | TAINT | +| string.cpp:220:20:220:21 | s1 | string.cpp:220:10:220:15 | call to insert | TAINT | +| string.cpp:223:7:223:8 | s1 | string.cpp:223:2:223:8 | ... = ... | | +| string.cpp:223:7:223:8 | s1 | string.cpp:224:7:224:8 | s5 | | +| string.cpp:223:7:223:8 | s1 | string.cpp:225:7:225:8 | s5 | | +| string.cpp:224:7:224:8 | ref arg s5 | string.cpp:225:7:225:8 | s5 | | +| string.cpp:224:7:224:8 | s5 | string.cpp:224:10:224:15 | call to insert | TAINT | +| string.cpp:224:20:224:21 | s2 | string.cpp:224:7:224:8 | ref arg s5 | TAINT | +| string.cpp:224:20:224:21 | s2 | string.cpp:224:10:224:15 | call to insert | TAINT | +| string.cpp:227:7:227:8 | s1 | string.cpp:227:2:227:8 | ... = ... | | +| string.cpp:227:7:227:8 | s1 | string.cpp:228:7:228:8 | s6 | | +| string.cpp:227:7:227:8 | s1 | string.cpp:229:7:229:8 | s6 | | +| string.cpp:228:7:228:8 | ref arg s6 | string.cpp:229:7:229:8 | s6 | | +| string.cpp:228:7:228:8 | s6 | string.cpp:228:10:228:15 | call to insert | TAINT | +| string.cpp:228:24:228:24 | c | string.cpp:228:7:228:8 | ref arg s6 | TAINT | +| string.cpp:228:24:228:24 | c | string.cpp:228:10:228:15 | call to insert | TAINT | +| string.cpp:233:17:233:23 | hello | string.cpp:233:17:233:24 | call to basic_string | TAINT | +| string.cpp:233:17:233:24 | call to basic_string | string.cpp:238:7:238:8 | s1 | | +| string.cpp:233:17:233:24 | call to basic_string | string.cpp:239:24:239:25 | s1 | | +| string.cpp:233:17:233:24 | call to basic_string | string.cpp:243:24:243:25 | s1 | | +| string.cpp:233:17:233:24 | call to basic_string | string.cpp:246:7:246:8 | s1 | | +| string.cpp:233:17:233:24 | call to basic_string | string.cpp:250:7:250:8 | s1 | | +| string.cpp:234:17:234:22 | call to source | string.cpp:234:17:234:25 | call to basic_string | TAINT | +| string.cpp:234:17:234:25 | call to basic_string | string.cpp:242:7:242:8 | s2 | | +| string.cpp:234:17:234:25 | call to basic_string | string.cpp:247:24:247:25 | s2 | | +| string.cpp:235:11:235:25 | call to source | string.cpp:251:28:251:28 | c | | +| string.cpp:238:7:238:8 | s1 | string.cpp:238:2:238:8 | ... = ... | | +| string.cpp:238:7:238:8 | s1 | string.cpp:239:7:239:8 | s3 | | +| string.cpp:238:7:238:8 | s1 | string.cpp:240:7:240:8 | s3 | | +| string.cpp:239:7:239:8 | ref arg s3 | string.cpp:240:7:240:8 | s3 | | +| string.cpp:239:7:239:8 | s3 | string.cpp:239:10:239:16 | call to replace | TAINT | +| string.cpp:239:24:239:25 | s1 | string.cpp:239:7:239:8 | ref arg s3 | TAINT | +| string.cpp:239:24:239:25 | s1 | string.cpp:239:10:239:16 | call to replace | TAINT | +| string.cpp:242:7:242:8 | s2 | string.cpp:242:2:242:8 | ... = ... | | +| string.cpp:242:7:242:8 | s2 | string.cpp:243:7:243:8 | s4 | | +| string.cpp:242:7:242:8 | s2 | string.cpp:244:7:244:8 | s4 | | +| string.cpp:243:7:243:8 | ref arg s4 | string.cpp:244:7:244:8 | s4 | | +| string.cpp:243:7:243:8 | s4 | string.cpp:243:10:243:16 | call to replace | TAINT | +| string.cpp:243:24:243:25 | s1 | string.cpp:243:7:243:8 | ref arg s4 | TAINT | +| string.cpp:243:24:243:25 | s1 | string.cpp:243:10:243:16 | call to replace | TAINT | +| string.cpp:246:7:246:8 | s1 | string.cpp:246:2:246:8 | ... = ... | | +| string.cpp:246:7:246:8 | s1 | string.cpp:247:7:247:8 | s5 | | +| string.cpp:246:7:246:8 | s1 | string.cpp:248:7:248:8 | s5 | | +| string.cpp:247:7:247:8 | ref arg s5 | string.cpp:248:7:248:8 | s5 | | +| string.cpp:247:7:247:8 | s5 | string.cpp:247:10:247:16 | call to replace | TAINT | +| string.cpp:247:24:247:25 | s2 | string.cpp:247:7:247:8 | ref arg s5 | TAINT | +| string.cpp:247:24:247:25 | s2 | string.cpp:247:10:247:16 | call to replace | TAINT | +| string.cpp:250:7:250:8 | s1 | string.cpp:250:2:250:8 | ... = ... | | +| string.cpp:250:7:250:8 | s1 | string.cpp:251:7:251:8 | s6 | | +| string.cpp:250:7:250:8 | s1 | string.cpp:252:7:252:8 | s6 | | +| string.cpp:251:7:251:8 | ref arg s6 | string.cpp:252:7:252:8 | s6 | | +| string.cpp:251:7:251:8 | s6 | string.cpp:251:10:251:16 | call to replace | TAINT | +| string.cpp:251:28:251:28 | c | string.cpp:251:7:251:8 | ref arg s6 | TAINT | +| string.cpp:251:28:251:28 | c | string.cpp:251:10:251:16 | call to replace | TAINT | +| string.cpp:256:17:256:20 | {...} | string.cpp:261:10:261:11 | b1 | | +| string.cpp:256:17:256:20 | {...} | string.cpp:262:7:262:8 | b1 | | +| string.cpp:256:19:256:19 | 0 | string.cpp:256:17:256:20 | {...} | TAINT | +| string.cpp:257:17:257:20 | {...} | string.cpp:264:10:264:11 | b2 | | +| string.cpp:257:17:257:20 | {...} | string.cpp:265:7:265:8 | b2 | | +| string.cpp:257:19:257:19 | 0 | string.cpp:257:17:257:20 | {...} | TAINT | +| string.cpp:258:17:258:23 | hello | string.cpp:258:17:258:24 | call to basic_string | TAINT | +| string.cpp:258:17:258:24 | call to basic_string | string.cpp:261:2:261:3 | s1 | | +| string.cpp:258:17:258:24 | call to basic_string | string.cpp:261:14:261:15 | s1 | | +| string.cpp:258:17:258:24 | call to basic_string | string.cpp:264:14:264:15 | s1 | | +| string.cpp:259:17:259:22 | call to source | string.cpp:259:17:259:25 | call to basic_string | TAINT | +| string.cpp:259:17:259:25 | call to basic_string | string.cpp:264:2:264:3 | s2 | | +| string.cpp:261:2:261:3 | s1 | string.cpp:261:10:261:11 | ref arg b1 | TAINT | +| string.cpp:261:10:261:11 | ref arg b1 | string.cpp:262:7:262:8 | b1 | | +| string.cpp:264:2:264:3 | s2 | string.cpp:264:10:264:11 | ref arg b2 | TAINT | +| string.cpp:264:10:264:11 | ref arg b2 | string.cpp:265:7:265:8 | b2 | | +| string.cpp:269:17:269:23 | hello | string.cpp:269:17:269:24 | call to basic_string | TAINT | +| string.cpp:269:17:269:24 | call to basic_string | string.cpp:274:7:274:8 | s1 | | +| string.cpp:269:17:269:24 | call to basic_string | string.cpp:279:2:279:3 | s1 | | +| string.cpp:269:17:269:24 | call to basic_string | string.cpp:282:7:282:8 | s1 | | +| string.cpp:270:17:270:22 | call to source | string.cpp:270:17:270:25 | call to basic_string | TAINT | +| string.cpp:270:17:270:25 | call to basic_string | string.cpp:275:7:275:8 | s2 | | +| string.cpp:270:17:270:25 | call to basic_string | string.cpp:279:10:279:11 | s2 | | +| string.cpp:270:17:270:25 | call to basic_string | string.cpp:283:7:283:8 | s2 | | +| string.cpp:271:17:271:23 | world | string.cpp:271:17:271:24 | call to basic_string | TAINT | +| string.cpp:271:17:271:24 | call to basic_string | string.cpp:276:7:276:8 | s3 | | +| string.cpp:271:17:271:24 | call to basic_string | string.cpp:280:10:280:11 | s3 | | +| string.cpp:271:17:271:24 | call to basic_string | string.cpp:284:7:284:8 | s3 | | +| string.cpp:272:17:272:22 | call to source | string.cpp:272:17:272:25 | call to basic_string | TAINT | +| string.cpp:272:17:272:25 | call to basic_string | string.cpp:277:7:277:8 | s4 | | +| string.cpp:272:17:272:25 | call to basic_string | string.cpp:280:2:280:3 | s4 | | +| string.cpp:272:17:272:25 | call to basic_string | string.cpp:285:7:285:8 | s4 | | +| string.cpp:279:2:279:3 | ref arg s1 | string.cpp:282:7:282:8 | s1 | | +| string.cpp:279:2:279:3 | s1 | string.cpp:279:10:279:11 | ref arg s2 | TAINT | +| string.cpp:279:10:279:11 | ref arg s2 | string.cpp:283:7:283:8 | s2 | | +| string.cpp:279:10:279:11 | s2 | string.cpp:279:2:279:3 | ref arg s1 | TAINT | +| string.cpp:280:2:280:3 | ref arg s4 | string.cpp:285:7:285:8 | s4 | | +| string.cpp:280:2:280:3 | s4 | string.cpp:280:10:280:11 | ref arg s3 | TAINT | +| string.cpp:280:10:280:11 | ref arg s3 | string.cpp:284:7:284:8 | s3 | | +| string.cpp:280:10:280:11 | s3 | string.cpp:280:2:280:3 | ref arg s4 | TAINT | +| string.cpp:289:17:289:22 | call to source | string.cpp:289:17:289:25 | call to basic_string | TAINT | +| string.cpp:289:17:289:25 | call to basic_string | string.cpp:293:7:293:8 | s1 | | +| string.cpp:289:17:289:25 | call to basic_string | string.cpp:297:2:297:3 | s1 | | +| string.cpp:289:17:289:25 | call to basic_string | string.cpp:301:7:301:8 | s1 | | +| string.cpp:290:17:290:22 | call to source | string.cpp:290:17:290:25 | call to basic_string | TAINT | +| string.cpp:290:17:290:25 | call to basic_string | string.cpp:294:7:294:8 | s2 | | +| string.cpp:291:17:291:22 | call to source | string.cpp:291:17:291:25 | call to basic_string | TAINT | +| string.cpp:291:17:291:25 | call to basic_string | string.cpp:295:7:295:8 | s3 | | +| string.cpp:291:17:291:25 | call to basic_string | string.cpp:299:7:299:8 | s3 | | +| string.cpp:297:2:297:3 | ref arg s1 | string.cpp:301:7:301:8 | s1 | | +| string.cpp:298:7:298:8 | | string.cpp:298:7:298:8 | call to basic_string | TAINT | +| string.cpp:298:7:298:8 | call to basic_string | string.cpp:298:2:298:8 | ... = ... | | +| string.cpp:298:7:298:8 | call to basic_string | string.cpp:302:7:302:8 | s2 | | +| string.cpp:299:7:299:8 | s3 | string.cpp:299:2:299:8 | ... = ... | | +| string.cpp:299:7:299:8 | s3 | string.cpp:303:7:303:8 | s3 | | +| string.cpp:308:16:308:20 | 123 | string.cpp:308:16:308:21 | call to basic_string | TAINT | +| string.cpp:308:16:308:21 | call to basic_string | string.cpp:311:7:311:7 | a | | +| string.cpp:308:16:308:21 | call to basic_string | string.cpp:313:7:313:7 | a | | +| string.cpp:309:16:309:21 | call to source | string.cpp:309:16:309:24 | call to basic_string | TAINT | +| string.cpp:309:16:309:24 | call to basic_string | string.cpp:312:7:312:7 | b | | +| string.cpp:309:16:309:24 | call to basic_string | string.cpp:314:7:314:7 | b | | +| string.cpp:311:7:311:7 | a | string.cpp:311:9:311:12 | call to data | TAINT | +| string.cpp:311:7:311:7 | ref arg a | string.cpp:313:7:313:7 | a | | +| string.cpp:312:7:312:7 | b | string.cpp:312:9:312:12 | call to data | TAINT | +| string.cpp:312:7:312:7 | ref arg b | string.cpp:314:7:314:7 | b | | +| string.cpp:319:16:319:20 | 123 | string.cpp:319:16:319:21 | call to basic_string | TAINT | +| string.cpp:319:16:319:21 | call to basic_string | string.cpp:322:7:322:7 | a | | +| string.cpp:319:16:319:21 | call to basic_string | string.cpp:322:19:322:19 | a | | +| string.cpp:320:16:320:21 | call to source | string.cpp:320:16:320:24 | call to basic_string | TAINT | +| string.cpp:320:16:320:24 | call to basic_string | string.cpp:323:7:323:7 | b | | +| string.cpp:320:16:320:24 | call to basic_string | string.cpp:323:19:323:19 | b | | +| string.cpp:322:7:322:7 | a | string.cpp:322:9:322:14 | call to substr | TAINT | +| string.cpp:323:7:323:7 | b | string.cpp:323:9:323:14 | call to substr | TAINT | +| string.cpp:328:16:328:20 | 123 | string.cpp:328:16:328:21 | call to basic_string | TAINT | +| string.cpp:328:16:328:21 | call to basic_string | string.cpp:332:7:332:7 | a | | +| string.cpp:328:16:328:21 | call to basic_string | string.cpp:336:2:336:2 | a | | +| string.cpp:328:16:328:21 | call to basic_string | string.cpp:338:9:338:9 | a | | +| string.cpp:328:16:328:21 | call to basic_string | string.cpp:340:7:340:7 | a | | +| string.cpp:329:16:329:20 | 123 | string.cpp:329:16:329:21 | call to basic_string | TAINT | +| string.cpp:329:16:329:21 | call to basic_string | string.cpp:333:7:333:7 | b | | +| string.cpp:329:16:329:21 | call to basic_string | string.cpp:337:2:337:2 | b | | +| string.cpp:329:16:329:21 | call to basic_string | string.cpp:341:7:341:7 | b | | +| string.cpp:330:16:330:20 | 123 | string.cpp:330:16:330:21 | call to basic_string | TAINT | +| string.cpp:330:16:330:21 | call to basic_string | string.cpp:334:7:334:7 | c | | +| string.cpp:330:16:330:21 | call to basic_string | string.cpp:338:2:338:2 | c | | +| string.cpp:330:16:330:21 | call to basic_string | string.cpp:342:7:342:7 | c | | +| string.cpp:336:2:336:2 | a | string.cpp:336:3:336:3 | call to operator[] | TAINT | +| string.cpp:336:2:336:2 | ref arg a | string.cpp:338:9:338:9 | a | | +| string.cpp:336:2:336:2 | ref arg a | string.cpp:340:7:340:7 | a | | +| string.cpp:336:2:336:25 | ... = ... | string.cpp:336:3:336:3 | call to operator[] [post update] | | +| string.cpp:336:3:336:3 | call to operator[] [post update] | string.cpp:336:2:336:2 | ref arg a | TAINT | +| string.cpp:336:9:336:23 | call to source | string.cpp:336:2:336:25 | ... = ... | | +| string.cpp:337:2:337:2 | b | string.cpp:337:4:337:5 | call to at | TAINT | +| string.cpp:337:2:337:2 | ref arg b | string.cpp:341:7:341:7 | b | | +| string.cpp:337:2:337:28 | ... = ... | string.cpp:337:4:337:5 | call to at [post update] | | +| string.cpp:337:4:337:5 | call to at [post update] | string.cpp:337:2:337:2 | ref arg b | TAINT | +| string.cpp:337:12:337:26 | call to source | string.cpp:337:2:337:28 | ... = ... | | +| string.cpp:338:2:338:2 | c | string.cpp:338:3:338:3 | call to operator[] | TAINT | +| string.cpp:338:2:338:2 | ref arg c | string.cpp:342:7:342:7 | c | | +| string.cpp:338:2:338:12 | ... = ... | string.cpp:338:3:338:3 | call to operator[] [post update] | | +| string.cpp:338:3:338:3 | call to operator[] [post update] | string.cpp:338:2:338:2 | ref arg c | TAINT | +| string.cpp:338:9:338:9 | a | string.cpp:338:10:338:10 | call to operator[] | TAINT | +| string.cpp:338:9:338:9 | ref arg a | string.cpp:340:7:340:7 | a | | +| string.cpp:338:10:338:10 | call to operator[] | string.cpp:338:2:338:12 | ... = ... | | +| string.cpp:347:18:347:22 | 123 | string.cpp:347:18:347:23 | call to basic_string | TAINT | +| string.cpp:347:18:347:23 | call to basic_string | string.cpp:349:2:349:4 | str | | +| string.cpp:347:18:347:23 | call to basic_string | string.cpp:350:7:350:9 | str | | +| string.cpp:347:18:347:23 | call to basic_string | string.cpp:351:7:351:9 | str | | +| string.cpp:349:2:349:4 | ref arg str | string.cpp:350:7:350:9 | str | | +| string.cpp:349:2:349:4 | ref arg str | string.cpp:351:7:351:9 | str | | +| string.cpp:349:2:349:4 | str | string.cpp:349:6:349:9 | call to data | TAINT | +| string.cpp:349:2:349:14 | access to array [post update] | string.cpp:349:6:349:9 | call to data [inner post update] | | +| string.cpp:349:2:349:34 | ... = ... | string.cpp:349:2:349:14 | access to array [post update] | | +| string.cpp:349:6:349:9 | call to data | string.cpp:349:2:349:14 | access to array | TAINT | +| string.cpp:349:6:349:9 | call to data [inner post update] | string.cpp:349:2:349:4 | ref arg str | TAINT | +| string.cpp:349:13:349:13 | 1 | string.cpp:349:2:349:14 | access to array | TAINT | +| string.cpp:349:18:349:32 | call to source | string.cpp:349:2:349:34 | ... = ... | | +| string.cpp:351:7:351:9 | str | string.cpp:351:11:351:14 | call to data | TAINT | +| string.cpp:357:18:357:24 | hello | string.cpp:357:18:357:25 | call to basic_string | TAINT | +| string.cpp:357:18:357:25 | call to basic_string | string.cpp:362:8:362:9 | s1 | | +| string.cpp:357:18:357:25 | call to basic_string | string.cpp:363:8:363:9 | s1 | | +| string.cpp:357:18:357:25 | call to basic_string | string.cpp:364:8:364:9 | s1 | | +| string.cpp:358:18:358:23 | call to source | string.cpp:358:18:358:26 | call to basic_string | TAINT | +| string.cpp:358:18:358:26 | call to basic_string | string.cpp:363:18:363:19 | s2 | | +| string.cpp:358:18:358:26 | call to basic_string | string.cpp:363:30:363:31 | s2 | | +| string.cpp:359:18:359:24 | hello | string.cpp:359:18:359:25 | call to basic_string | TAINT | +| string.cpp:359:18:359:25 | call to basic_string | string.cpp:366:8:366:9 | s3 | | +| string.cpp:359:18:359:25 | call to basic_string | string.cpp:367:8:367:9 | s3 | | +| string.cpp:359:18:359:25 | call to basic_string | string.cpp:368:8:368:9 | s3 | | +| string.cpp:360:18:360:24 | world | string.cpp:360:18:360:25 | call to basic_string | TAINT | +| string.cpp:360:18:360:25 | call to basic_string | string.cpp:367:18:367:19 | s4 | | +| string.cpp:360:18:360:25 | call to basic_string | string.cpp:367:30:367:31 | s4 | | +| string.cpp:363:8:363:9 | ref arg s1 | string.cpp:364:8:364:9 | s1 | | +| string.cpp:363:8:363:9 | s1 | string.cpp:363:11:363:16 | call to append | TAINT | +| string.cpp:363:18:363:19 | ref arg s2 | string.cpp:363:30:363:31 | s2 | | +| string.cpp:363:18:363:19 | s2 | string.cpp:363:21:363:25 | call to begin | TAINT | +| string.cpp:363:21:363:25 | call to begin | string.cpp:363:8:363:9 | ref arg s1 | TAINT | +| string.cpp:363:21:363:25 | call to begin | string.cpp:363:11:363:16 | call to append | TAINT | +| string.cpp:363:30:363:31 | s2 | string.cpp:363:33:363:35 | call to end | TAINT | +| string.cpp:363:33:363:35 | call to end | string.cpp:363:8:363:9 | ref arg s1 | TAINT | +| string.cpp:363:33:363:35 | call to end | string.cpp:363:11:363:16 | call to append | TAINT | +| string.cpp:367:8:367:9 | ref arg s3 | string.cpp:368:8:368:9 | s3 | | +| string.cpp:367:8:367:9 | s3 | string.cpp:367:11:367:16 | call to append | TAINT | +| string.cpp:367:18:367:19 | ref arg s4 | string.cpp:367:30:367:31 | s4 | | +| string.cpp:367:18:367:19 | s4 | string.cpp:367:21:367:25 | call to begin | TAINT | +| string.cpp:367:21:367:25 | call to begin | string.cpp:367:8:367:9 | ref arg s3 | TAINT | +| string.cpp:367:21:367:25 | call to begin | string.cpp:367:11:367:16 | call to append | TAINT | +| string.cpp:367:30:367:31 | s4 | string.cpp:367:33:367:35 | call to end | TAINT | +| string.cpp:367:33:367:35 | call to end | string.cpp:367:8:367:9 | ref arg s3 | TAINT | +| string.cpp:367:33:367:35 | call to end | string.cpp:367:11:367:16 | call to append | TAINT | +| string.cpp:373:18:373:24 | hello | string.cpp:373:18:373:25 | call to basic_string | TAINT | +| string.cpp:373:18:373:25 | call to basic_string | string.cpp:376:28:376:29 | s1 | | +| string.cpp:374:18:374:23 | call to source | string.cpp:374:18:374:26 | call to basic_string | TAINT | +| string.cpp:374:18:374:26 | call to basic_string | string.cpp:380:28:380:29 | s2 | | +| string.cpp:376:28:376:29 | s1 | string.cpp:376:31:376:35 | call to begin | TAINT | +| string.cpp:376:31:376:35 | call to begin | string.cpp:378:9:378:13 | iter1 | | +| string.cpp:376:31:376:35 | call to begin | string.cpp:379:8:379:12 | iter1 | | +| string.cpp:378:9:378:13 | iter1 | string.cpp:378:8:378:8 | call to operator* | TAINT | +| string.cpp:379:8:379:12 | iter1 | string.cpp:379:13:379:13 | call to operator[] | TAINT | +| string.cpp:380:28:380:29 | s2 | string.cpp:380:31:380:35 | call to begin | TAINT | +| string.cpp:380:31:380:35 | call to begin | string.cpp:382:9:382:13 | iter2 | | +| string.cpp:380:31:380:35 | call to begin | string.cpp:383:8:383:12 | iter2 | | +| string.cpp:382:9:382:13 | iter2 | string.cpp:382:8:382:8 | call to operator* | TAINT | +| string.cpp:383:8:383:12 | iter2 | string.cpp:383:13:383:13 | call to operator[] | TAINT | +| string.cpp:388:18:388:24 | hello | string.cpp:388:18:388:25 | call to basic_string | TAINT | +| string.cpp:388:18:388:25 | call to basic_string | string.cpp:391:25:391:26 | s1 | | +| string.cpp:389:18:389:23 | call to source | string.cpp:389:18:389:26 | call to basic_string | TAINT | +| string.cpp:389:18:389:26 | call to basic_string | string.cpp:393:25:393:26 | s2 | | +| string.cpp:389:18:389:26 | call to basic_string | string.cpp:413:8:413:9 | s2 | | +| string.cpp:391:25:391:26 | s1 | string.cpp:391:28:391:32 | call to begin | TAINT | +| string.cpp:393:25:393:26 | ref arg s2 | string.cpp:413:8:413:9 | s2 | | +| string.cpp:393:25:393:26 | s2 | string.cpp:393:28:393:32 | call to begin | TAINT | +| string.cpp:393:28:393:32 | call to begin | string.cpp:396:10:396:11 | i2 | | +| string.cpp:393:28:393:32 | call to begin | string.cpp:397:10:397:11 | i2 | | +| string.cpp:393:28:393:32 | call to begin | string.cpp:398:8:398:9 | i2 | | +| string.cpp:393:28:393:32 | call to begin | string.cpp:400:8:400:9 | i2 | | +| string.cpp:393:28:393:32 | call to begin | string.cpp:402:8:402:9 | i2 | | +| string.cpp:393:28:393:32 | call to begin | string.cpp:405:8:405:9 | i2 | | +| string.cpp:393:28:393:32 | call to begin | string.cpp:408:8:408:9 | i2 | | +| string.cpp:393:28:393:32 | call to begin | string.cpp:410:8:410:9 | i2 | | +| string.cpp:393:28:393:32 | call to begin | string.cpp:417:9:417:10 | i2 | | +| string.cpp:393:28:393:32 | call to begin | string.cpp:420:9:420:10 | i2 | | +| string.cpp:396:10:396:11 | i2 | string.cpp:396:12:396:12 | call to operator+ | TAINT | +| string.cpp:396:10:396:11 | ref arg i2 | string.cpp:397:10:397:11 | i2 | | +| string.cpp:396:10:396:11 | ref arg i2 | string.cpp:398:8:398:9 | i2 | | +| string.cpp:396:10:396:11 | ref arg i2 | string.cpp:400:8:400:9 | i2 | | +| string.cpp:396:10:396:11 | ref arg i2 | string.cpp:402:8:402:9 | i2 | | +| string.cpp:396:10:396:11 | ref arg i2 | string.cpp:405:8:405:9 | i2 | | +| string.cpp:396:10:396:11 | ref arg i2 | string.cpp:408:8:408:9 | i2 | | +| string.cpp:396:10:396:11 | ref arg i2 | string.cpp:410:8:410:9 | i2 | | +| string.cpp:396:10:396:11 | ref arg i2 | string.cpp:417:9:417:10 | i2 | | +| string.cpp:396:10:396:11 | ref arg i2 | string.cpp:420:9:420:10 | i2 | | +| string.cpp:396:12:396:12 | call to operator+ | string.cpp:396:8:396:8 | call to operator* | TAINT | +| string.cpp:397:10:397:11 | i2 | string.cpp:397:12:397:12 | call to operator- | TAINT | +| string.cpp:397:10:397:11 | ref arg i2 | string.cpp:398:8:398:9 | i2 | | +| string.cpp:397:10:397:11 | ref arg i2 | string.cpp:400:8:400:9 | i2 | | +| string.cpp:397:10:397:11 | ref arg i2 | string.cpp:402:8:402:9 | i2 | | +| string.cpp:397:10:397:11 | ref arg i2 | string.cpp:405:8:405:9 | i2 | | +| string.cpp:397:10:397:11 | ref arg i2 | string.cpp:408:8:408:9 | i2 | | +| string.cpp:397:10:397:11 | ref arg i2 | string.cpp:410:8:410:9 | i2 | | +| string.cpp:397:10:397:11 | ref arg i2 | string.cpp:417:9:417:10 | i2 | | +| string.cpp:397:10:397:11 | ref arg i2 | string.cpp:420:9:420:10 | i2 | | +| string.cpp:397:12:397:12 | call to operator- | string.cpp:397:8:397:8 | call to operator* | TAINT | +| string.cpp:398:8:398:9 | i2 | string.cpp:398:3:398:9 | ... = ... | | +| string.cpp:398:8:398:9 | i2 | string.cpp:399:12:399:13 | i3 | | +| string.cpp:399:10:399:10 | call to operator++ | string.cpp:399:8:399:8 | call to operator* | TAINT | +| string.cpp:399:12:399:13 | i3 | string.cpp:399:10:399:10 | call to operator++ | | +| string.cpp:400:8:400:9 | i2 | string.cpp:400:3:400:9 | ... = ... | | +| string.cpp:400:8:400:9 | i2 | string.cpp:401:12:401:13 | i4 | | +| string.cpp:401:10:401:10 | call to operator-- | string.cpp:401:8:401:8 | call to operator* | TAINT | +| string.cpp:401:12:401:13 | i4 | string.cpp:401:10:401:10 | call to operator-- | | +| string.cpp:402:8:402:9 | i2 | string.cpp:402:3:402:9 | ... = ... | | +| string.cpp:402:8:402:9 | i2 | string.cpp:403:3:403:4 | i5 | | +| string.cpp:402:8:402:9 | i2 | string.cpp:404:9:404:10 | i5 | | +| string.cpp:403:3:403:4 | i5 | string.cpp:403:5:403:5 | call to operator++ | | +| string.cpp:403:3:403:4 | ref arg i5 | string.cpp:404:9:404:10 | i5 | | +| string.cpp:404:9:404:10 | i5 | string.cpp:404:8:404:8 | call to operator* | TAINT | +| string.cpp:405:8:405:9 | i2 | string.cpp:405:3:405:9 | ... = ... | | +| string.cpp:405:8:405:9 | i2 | string.cpp:406:3:406:4 | i6 | | +| string.cpp:405:8:405:9 | i2 | string.cpp:407:9:407:10 | i6 | | +| string.cpp:406:3:406:4 | i6 | string.cpp:406:5:406:5 | call to operator-- | | +| string.cpp:406:3:406:4 | ref arg i6 | string.cpp:407:9:407:10 | i6 | | +| string.cpp:407:9:407:10 | i6 | string.cpp:407:8:407:8 | call to operator* | TAINT | +| string.cpp:408:8:408:9 | i2 | string.cpp:408:3:408:9 | ... = ... | | +| string.cpp:408:8:408:9 | i2 | string.cpp:409:10:409:11 | i7 | | +| string.cpp:409:10:409:11 | i7 | string.cpp:409:12:409:12 | call to operator+= | | +| string.cpp:409:12:409:12 | call to operator+= | string.cpp:409:8:409:8 | call to operator* | TAINT | +| string.cpp:409:14:409:14 | 1 | string.cpp:409:12:409:12 | call to operator+= | | +| string.cpp:410:8:410:9 | i2 | string.cpp:410:3:410:9 | ... = ... | | +| string.cpp:410:8:410:9 | i2 | string.cpp:411:10:411:11 | i8 | | +| string.cpp:411:10:411:11 | i8 | string.cpp:411:12:411:12 | call to operator-= | | +| string.cpp:411:12:411:12 | call to operator-= | string.cpp:411:8:411:8 | call to operator* | TAINT | +| string.cpp:411:14:411:14 | 1 | string.cpp:411:12:411:12 | call to operator-= | | +| string.cpp:413:8:413:9 | s2 | string.cpp:413:11:413:13 | call to end | TAINT | +| string.cpp:413:11:413:13 | call to end | string.cpp:413:3:413:15 | ... = ... | | +| string.cpp:413:11:413:13 | call to end | string.cpp:414:5:414:6 | i9 | | +| string.cpp:413:11:413:13 | call to end | string.cpp:415:9:415:10 | i9 | | +| string.cpp:414:5:414:6 | i9 | string.cpp:414:3:414:3 | call to operator-- | | +| string.cpp:414:5:414:6 | ref arg i9 | string.cpp:415:9:415:10 | i9 | | +| string.cpp:415:9:415:10 | i9 | string.cpp:415:8:415:8 | call to operator* | TAINT | +| string.cpp:417:9:417:10 | i2 | string.cpp:417:3:417:10 | ... = ... | | +| string.cpp:417:9:417:10 | i2 | string.cpp:418:10:418:12 | i10 | | +| string.cpp:417:9:417:10 | i2 | string.cpp:419:8:419:10 | i10 | | +| string.cpp:418:10:418:12 | i10 | string.cpp:418:13:418:13 | call to operator++ | | +| string.cpp:418:10:418:12 | ref arg i10 | string.cpp:419:8:419:10 | i10 | | +| string.cpp:418:13:418:13 | call to operator++ | string.cpp:418:8:418:8 | call to operator* | TAINT | +| string.cpp:419:8:419:10 | i10 | string.cpp:419:8:419:10 | call to iterator | | +| string.cpp:420:9:420:10 | i2 | string.cpp:420:3:420:10 | ... = ... | | +| string.cpp:420:9:420:10 | i2 | string.cpp:421:10:421:12 | i11 | | +| string.cpp:420:9:420:10 | i2 | string.cpp:422:8:422:10 | i11 | | +| string.cpp:421:10:421:12 | i11 | string.cpp:421:13:421:13 | call to operator-- | | +| string.cpp:421:10:421:12 | ref arg i11 | string.cpp:422:8:422:10 | i11 | | +| string.cpp:421:13:421:13 | call to operator-- | string.cpp:421:8:421:8 | call to operator* | TAINT | +| string.cpp:422:8:422:10 | i11 | string.cpp:422:8:422:10 | call to iterator | | +| string.cpp:428:17:428:20 | aa | string.cpp:428:17:428:21 | call to basic_string | TAINT | +| string.cpp:428:17:428:21 | call to basic_string | string.cpp:433:7:433:8 | s1 | | +| string.cpp:428:17:428:21 | call to basic_string | string.cpp:434:7:434:8 | s1 | | +| string.cpp:429:17:429:20 | bb | string.cpp:429:17:429:21 | call to basic_string | TAINT | +| string.cpp:429:17:429:21 | call to basic_string | string.cpp:436:7:436:8 | s2 | | +| string.cpp:429:17:429:21 | call to basic_string | string.cpp:437:7:437:8 | s2 | | +| string.cpp:430:14:430:17 | cc | string.cpp:433:20:433:22 | cs1 | | +| string.cpp:431:14:431:19 | call to source | string.cpp:436:20:436:22 | cs2 | | +| string.cpp:433:7:433:8 | ref arg s1 | string.cpp:434:7:434:8 | s1 | | +| string.cpp:433:7:433:8 | s1 | string.cpp:433:10:433:15 | call to insert | TAINT | +| string.cpp:433:20:433:22 | cs1 | string.cpp:433:7:433:8 | ref arg s1 | TAINT | +| string.cpp:433:20:433:22 | cs1 | string.cpp:433:10:433:15 | call to insert | TAINT | +| string.cpp:436:7:436:8 | ref arg s2 | string.cpp:437:7:437:8 | s2 | | +| string.cpp:436:7:436:8 | s2 | string.cpp:436:10:436:15 | call to insert | TAINT | +| string.cpp:436:20:436:22 | cs2 | string.cpp:436:7:436:8 | ref arg s2 | TAINT | +| string.cpp:436:20:436:22 | cs2 | string.cpp:436:10:436:15 | call to insert | TAINT | +| string.cpp:443:17:443:20 | aa | string.cpp:443:17:443:21 | call to basic_string | TAINT | +| string.cpp:443:17:443:21 | call to basic_string | string.cpp:446:8:446:8 | a | | +| string.cpp:443:17:443:21 | call to basic_string | string.cpp:446:17:446:17 | a | | +| string.cpp:443:17:443:21 | call to basic_string | string.cpp:447:8:447:8 | a | | +| string.cpp:444:17:444:20 | bb | string.cpp:444:17:444:21 | call to basic_string | TAINT | +| string.cpp:444:17:444:21 | call to basic_string | string.cpp:449:8:449:8 | b | | +| string.cpp:444:17:444:21 | call to basic_string | string.cpp:449:17:449:17 | b | | +| string.cpp:444:17:444:21 | call to basic_string | string.cpp:450:8:450:8 | b | | +| string.cpp:446:8:446:8 | a | string.cpp:446:10:446:15 | call to insert | TAINT | +| string.cpp:446:8:446:8 | ref arg a | string.cpp:447:8:447:8 | a | | +| string.cpp:446:17:446:17 | a | string.cpp:446:19:446:23 | call to begin | TAINT | +| string.cpp:446:17:446:17 | ref arg a | string.cpp:446:8:446:8 | a | | +| string.cpp:446:17:446:17 | ref arg a | string.cpp:447:8:447:8 | a | | +| string.cpp:446:19:446:23 | call to begin | string.cpp:446:17:446:25 | call to iterator | TAINT | +| string.cpp:446:32:446:34 | 120 | string.cpp:446:8:446:8 | ref arg a | TAINT | +| string.cpp:446:32:446:34 | 120 | string.cpp:446:10:446:15 | call to insert | TAINT | +| string.cpp:449:8:449:8 | b | string.cpp:449:10:449:15 | call to insert | TAINT | +| string.cpp:449:8:449:8 | ref arg b | string.cpp:450:8:450:8 | b | | +| string.cpp:449:17:449:17 | b | string.cpp:449:19:449:23 | call to begin | TAINT | +| string.cpp:449:17:449:17 | ref arg b | string.cpp:449:8:449:8 | b | | +| string.cpp:449:17:449:17 | ref arg b | string.cpp:450:8:450:8 | b | | +| string.cpp:449:19:449:23 | call to begin | string.cpp:449:17:449:25 | call to iterator | TAINT | +| string.cpp:449:32:449:46 | call to source | string.cpp:449:8:449:8 | ref arg b | TAINT | +| string.cpp:449:32:449:46 | call to source | string.cpp:449:10:449:15 | call to insert | TAINT | +| string.cpp:454:17:454:20 | cc | string.cpp:454:17:454:21 | call to basic_string | TAINT | +| string.cpp:454:17:454:21 | call to basic_string | string.cpp:459:8:459:8 | c | | +| string.cpp:454:17:454:21 | call to basic_string | string.cpp:459:17:459:17 | c | | +| string.cpp:454:17:454:21 | call to basic_string | string.cpp:460:8:460:8 | c | | +| string.cpp:455:17:455:20 | dd | string.cpp:455:17:455:21 | call to basic_string | TAINT | +| string.cpp:455:17:455:21 | call to basic_string | string.cpp:462:8:462:8 | d | | +| string.cpp:455:17:455:21 | call to basic_string | string.cpp:462:17:462:17 | d | | +| string.cpp:455:17:455:21 | call to basic_string | string.cpp:463:8:463:8 | d | | +| string.cpp:456:18:456:21 | 11 | string.cpp:456:18:456:22 | call to basic_string | TAINT | +| string.cpp:456:18:456:22 | call to basic_string | string.cpp:459:26:459:27 | s1 | | +| string.cpp:456:18:456:22 | call to basic_string | string.cpp:459:38:459:39 | s1 | | +| string.cpp:456:18:456:22 | call to basic_string | string.cpp:465:28:465:29 | s1 | | +| string.cpp:456:18:456:22 | call to basic_string | string.cpp:465:40:465:41 | s1 | | +| string.cpp:457:18:457:23 | call to source | string.cpp:457:18:457:26 | call to basic_string | TAINT | +| string.cpp:457:18:457:26 | call to basic_string | string.cpp:462:26:462:27 | s2 | | +| string.cpp:457:18:457:26 | call to basic_string | string.cpp:462:38:462:39 | s2 | | +| string.cpp:457:18:457:26 | call to basic_string | string.cpp:465:8:465:9 | s2 | | +| string.cpp:457:18:457:26 | call to basic_string | string.cpp:465:18:465:19 | s2 | | +| string.cpp:457:18:457:26 | call to basic_string | string.cpp:466:8:466:9 | s2 | | +| string.cpp:459:8:459:8 | c | string.cpp:459:10:459:15 | call to insert | TAINT | +| string.cpp:459:8:459:8 | ref arg c | string.cpp:460:8:460:8 | c | | +| string.cpp:459:17:459:17 | c | string.cpp:459:19:459:21 | call to end | TAINT | +| string.cpp:459:17:459:17 | ref arg c | string.cpp:459:8:459:8 | c | | +| string.cpp:459:17:459:17 | ref arg c | string.cpp:460:8:460:8 | c | | +| string.cpp:459:19:459:21 | call to end | string.cpp:459:17:459:23 | call to iterator | TAINT | +| string.cpp:459:26:459:27 | ref arg s1 | string.cpp:459:38:459:39 | s1 | | +| string.cpp:459:26:459:27 | ref arg s1 | string.cpp:465:28:465:29 | s1 | | +| string.cpp:459:26:459:27 | ref arg s1 | string.cpp:465:40:465:41 | s1 | | +| string.cpp:459:26:459:27 | s1 | string.cpp:459:29:459:33 | call to begin | TAINT | +| string.cpp:459:29:459:33 | call to begin | string.cpp:459:8:459:8 | ref arg c | TAINT | +| string.cpp:459:29:459:33 | call to begin | string.cpp:459:10:459:15 | call to insert | TAINT | +| string.cpp:459:38:459:39 | ref arg s1 | string.cpp:465:28:465:29 | s1 | | +| string.cpp:459:38:459:39 | ref arg s1 | string.cpp:465:40:465:41 | s1 | | +| string.cpp:459:38:459:39 | s1 | string.cpp:459:41:459:43 | call to end | TAINT | +| string.cpp:459:41:459:43 | call to end | string.cpp:459:8:459:8 | ref arg c | TAINT | +| string.cpp:459:41:459:43 | call to end | string.cpp:459:10:459:15 | call to insert | TAINT | +| string.cpp:462:8:462:8 | d | string.cpp:462:10:462:15 | call to insert | TAINT | +| string.cpp:462:8:462:8 | ref arg d | string.cpp:463:8:463:8 | d | | +| string.cpp:462:17:462:17 | d | string.cpp:462:19:462:21 | call to end | TAINT | +| string.cpp:462:17:462:17 | ref arg d | string.cpp:462:8:462:8 | d | | +| string.cpp:462:17:462:17 | ref arg d | string.cpp:463:8:463:8 | d | | +| string.cpp:462:19:462:21 | call to end | string.cpp:462:17:462:23 | call to iterator | TAINT | +| string.cpp:462:26:462:27 | ref arg s2 | string.cpp:462:38:462:39 | s2 | | +| string.cpp:462:26:462:27 | ref arg s2 | string.cpp:465:8:465:9 | s2 | | +| string.cpp:462:26:462:27 | ref arg s2 | string.cpp:465:18:465:19 | s2 | | +| string.cpp:462:26:462:27 | ref arg s2 | string.cpp:466:8:466:9 | s2 | | +| string.cpp:462:26:462:27 | s2 | string.cpp:462:29:462:33 | call to begin | TAINT | +| string.cpp:462:29:462:33 | call to begin | string.cpp:462:8:462:8 | ref arg d | TAINT | +| string.cpp:462:29:462:33 | call to begin | string.cpp:462:10:462:15 | call to insert | TAINT | +| string.cpp:462:38:462:39 | ref arg s2 | string.cpp:465:8:465:9 | s2 | | +| string.cpp:462:38:462:39 | ref arg s2 | string.cpp:465:18:465:19 | s2 | | +| string.cpp:462:38:462:39 | ref arg s2 | string.cpp:466:8:466:9 | s2 | | +| string.cpp:462:38:462:39 | s2 | string.cpp:462:41:462:43 | call to end | TAINT | +| string.cpp:462:41:462:43 | call to end | string.cpp:462:8:462:8 | ref arg d | TAINT | +| string.cpp:462:41:462:43 | call to end | string.cpp:462:10:462:15 | call to insert | TAINT | +| string.cpp:465:8:465:9 | ref arg s2 | string.cpp:466:8:466:9 | s2 | | +| string.cpp:465:8:465:9 | s2 | string.cpp:465:11:465:16 | call to insert | TAINT | +| string.cpp:465:18:465:19 | ref arg s2 | string.cpp:465:8:465:9 | s2 | | +| string.cpp:465:18:465:19 | ref arg s2 | string.cpp:466:8:466:9 | s2 | | +| string.cpp:465:18:465:19 | s2 | string.cpp:465:21:465:23 | call to end | TAINT | +| string.cpp:465:21:465:23 | call to end | string.cpp:465:18:465:25 | call to iterator | TAINT | +| string.cpp:465:28:465:29 | ref arg s1 | string.cpp:465:40:465:41 | s1 | | +| string.cpp:465:28:465:29 | s1 | string.cpp:465:31:465:35 | call to begin | TAINT | +| string.cpp:465:31:465:35 | call to begin | string.cpp:465:8:465:9 | ref arg s2 | TAINT | +| string.cpp:465:31:465:35 | call to begin | string.cpp:465:11:465:16 | call to insert | TAINT | +| string.cpp:465:40:465:41 | s1 | string.cpp:465:43:465:45 | call to end | TAINT | +| string.cpp:465:43:465:45 | call to end | string.cpp:465:8:465:9 | ref arg s2 | TAINT | +| string.cpp:465:43:465:45 | call to end | string.cpp:465:11:465:16 | call to insert | TAINT | +| string.cpp:470:17:470:20 | ee | string.cpp:470:17:470:21 | call to basic_string | TAINT | +| string.cpp:470:17:470:21 | call to basic_string | string.cpp:475:8:475:8 | e | | +| string.cpp:470:17:470:21 | call to basic_string | string.cpp:476:8:476:8 | e | | +| string.cpp:471:17:471:20 | ff | string.cpp:471:17:471:21 | call to basic_string | TAINT | +| string.cpp:471:17:471:21 | call to basic_string | string.cpp:478:8:478:8 | f | | +| string.cpp:471:17:471:21 | call to basic_string | string.cpp:479:8:479:8 | f | | +| string.cpp:472:18:472:21 | 33 | string.cpp:472:18:472:22 | call to basic_string | TAINT | +| string.cpp:472:18:472:22 | call to basic_string | string.cpp:475:17:475:18 | s3 | | +| string.cpp:472:18:472:22 | call to basic_string | string.cpp:475:29:475:30 | s3 | | +| string.cpp:472:18:472:22 | call to basic_string | string.cpp:481:18:481:19 | s3 | | +| string.cpp:472:18:472:22 | call to basic_string | string.cpp:481:30:481:31 | s3 | | +| string.cpp:473:18:473:23 | call to source | string.cpp:473:18:473:26 | call to basic_string | TAINT | +| string.cpp:473:18:473:26 | call to basic_string | string.cpp:478:17:478:18 | s4 | | +| string.cpp:473:18:473:26 | call to basic_string | string.cpp:478:29:478:30 | s4 | | +| string.cpp:473:18:473:26 | call to basic_string | string.cpp:481:8:481:9 | s4 | | +| string.cpp:473:18:473:26 | call to basic_string | string.cpp:482:8:482:9 | s4 | | +| string.cpp:475:8:475:8 | e | string.cpp:475:10:475:15 | call to append | TAINT | +| string.cpp:475:8:475:8 | ref arg e | string.cpp:476:8:476:8 | e | | +| string.cpp:475:17:475:18 | ref arg s3 | string.cpp:475:29:475:30 | s3 | | +| string.cpp:475:17:475:18 | ref arg s3 | string.cpp:481:18:481:19 | s3 | | +| string.cpp:475:17:475:18 | ref arg s3 | string.cpp:481:30:481:31 | s3 | | +| string.cpp:475:17:475:18 | s3 | string.cpp:475:20:475:24 | call to begin | TAINT | +| string.cpp:475:20:475:24 | call to begin | string.cpp:475:8:475:8 | ref arg e | TAINT | +| string.cpp:475:20:475:24 | call to begin | string.cpp:475:10:475:15 | call to append | TAINT | +| string.cpp:475:29:475:30 | ref arg s3 | string.cpp:481:18:481:19 | s3 | | +| string.cpp:475:29:475:30 | ref arg s3 | string.cpp:481:30:481:31 | s3 | | +| string.cpp:475:29:475:30 | s3 | string.cpp:475:32:475:34 | call to end | TAINT | +| string.cpp:475:32:475:34 | call to end | string.cpp:475:8:475:8 | ref arg e | TAINT | +| string.cpp:475:32:475:34 | call to end | string.cpp:475:10:475:15 | call to append | TAINT | +| string.cpp:478:8:478:8 | f | string.cpp:478:10:478:15 | call to append | TAINT | +| string.cpp:478:8:478:8 | ref arg f | string.cpp:479:8:479:8 | f | | +| string.cpp:478:17:478:18 | ref arg s4 | string.cpp:478:29:478:30 | s4 | | +| string.cpp:478:17:478:18 | ref arg s4 | string.cpp:481:8:481:9 | s4 | | +| string.cpp:478:17:478:18 | ref arg s4 | string.cpp:482:8:482:9 | s4 | | +| string.cpp:478:17:478:18 | s4 | string.cpp:478:20:478:24 | call to begin | TAINT | +| string.cpp:478:20:478:24 | call to begin | string.cpp:478:8:478:8 | ref arg f | TAINT | +| string.cpp:478:20:478:24 | call to begin | string.cpp:478:10:478:15 | call to append | TAINT | +| string.cpp:478:29:478:30 | ref arg s4 | string.cpp:481:8:481:9 | s4 | | +| string.cpp:478:29:478:30 | ref arg s4 | string.cpp:482:8:482:9 | s4 | | +| string.cpp:478:29:478:30 | s4 | string.cpp:478:32:478:34 | call to end | TAINT | +| string.cpp:478:32:478:34 | call to end | string.cpp:478:8:478:8 | ref arg f | TAINT | +| string.cpp:478:32:478:34 | call to end | string.cpp:478:10:478:15 | call to append | TAINT | +| string.cpp:481:8:481:9 | ref arg s4 | string.cpp:482:8:482:9 | s4 | | +| string.cpp:481:8:481:9 | s4 | string.cpp:481:11:481:16 | call to append | TAINT | +| string.cpp:481:18:481:19 | ref arg s3 | string.cpp:481:30:481:31 | s3 | | +| string.cpp:481:18:481:19 | s3 | string.cpp:481:21:481:25 | call to begin | TAINT | +| string.cpp:481:21:481:25 | call to begin | string.cpp:481:8:481:9 | ref arg s4 | TAINT | +| string.cpp:481:21:481:25 | call to begin | string.cpp:481:11:481:16 | call to append | TAINT | +| string.cpp:481:30:481:31 | s3 | string.cpp:481:33:481:35 | call to end | TAINT | +| string.cpp:481:33:481:35 | call to end | string.cpp:481:8:481:9 | ref arg s4 | TAINT | +| string.cpp:481:33:481:35 | call to end | string.cpp:481:11:481:16 | call to append | TAINT | +| string.cpp:486:17:486:20 | gg | string.cpp:486:17:486:21 | call to basic_string | TAINT | +| string.cpp:486:17:486:21 | call to basic_string | string.cpp:491:8:491:8 | g | | +| string.cpp:486:17:486:21 | call to basic_string | string.cpp:492:8:492:8 | g | | +| string.cpp:487:17:487:20 | hh | string.cpp:487:17:487:21 | call to basic_string | TAINT | +| string.cpp:487:17:487:21 | call to basic_string | string.cpp:494:8:494:8 | h | | +| string.cpp:487:17:487:21 | call to basic_string | string.cpp:495:8:495:8 | h | | +| string.cpp:488:18:488:21 | 55 | string.cpp:488:18:488:22 | call to basic_string | TAINT | +| string.cpp:488:18:488:22 | call to basic_string | string.cpp:491:17:491:18 | s5 | | +| string.cpp:488:18:488:22 | call to basic_string | string.cpp:491:30:491:31 | s5 | | +| string.cpp:488:18:488:22 | call to basic_string | string.cpp:497:18:497:19 | s5 | | +| string.cpp:488:18:488:22 | call to basic_string | string.cpp:497:31:497:32 | s5 | | +| string.cpp:489:18:489:23 | call to source | string.cpp:489:18:489:26 | call to basic_string | TAINT | +| string.cpp:489:18:489:26 | call to basic_string | string.cpp:494:17:494:18 | s6 | | +| string.cpp:489:18:489:26 | call to basic_string | string.cpp:494:30:494:31 | s6 | | +| string.cpp:489:18:489:26 | call to basic_string | string.cpp:497:8:497:9 | s6 | | +| string.cpp:489:18:489:26 | call to basic_string | string.cpp:498:8:498:9 | s6 | | +| string.cpp:491:8:491:8 | ref arg g | string.cpp:492:8:492:8 | g | | +| string.cpp:491:17:491:18 | s5 | string.cpp:491:20:491:25 | call to cbegin | TAINT | +| string.cpp:491:20:491:25 | call to cbegin | string.cpp:491:8:491:8 | ref arg g | TAINT | +| string.cpp:491:20:491:25 | call to cbegin | string.cpp:491:10:491:15 | call to assign | TAINT | +| string.cpp:491:30:491:31 | s5 | string.cpp:491:33:491:36 | call to cend | TAINT | +| string.cpp:491:33:491:36 | call to cend | string.cpp:491:8:491:8 | ref arg g | TAINT | +| string.cpp:491:33:491:36 | call to cend | string.cpp:491:10:491:15 | call to assign | TAINT | +| string.cpp:494:8:494:8 | ref arg h | string.cpp:495:8:495:8 | h | | +| string.cpp:494:17:494:18 | s6 | string.cpp:494:20:494:25 | call to cbegin | TAINT | +| string.cpp:494:20:494:25 | call to cbegin | string.cpp:494:8:494:8 | ref arg h | TAINT | +| string.cpp:494:20:494:25 | call to cbegin | string.cpp:494:10:494:15 | call to assign | TAINT | +| string.cpp:494:30:494:31 | s6 | string.cpp:494:33:494:36 | call to cend | TAINT | +| string.cpp:494:33:494:36 | call to cend | string.cpp:494:8:494:8 | ref arg h | TAINT | +| string.cpp:494:33:494:36 | call to cend | string.cpp:494:10:494:15 | call to assign | TAINT | +| string.cpp:497:8:497:9 | ref arg s6 | string.cpp:498:8:498:9 | s6 | | +| string.cpp:497:18:497:19 | s5 | string.cpp:497:21:497:26 | call to cbegin | TAINT | +| string.cpp:497:21:497:26 | call to cbegin | string.cpp:497:8:497:9 | ref arg s6 | TAINT | +| string.cpp:497:21:497:26 | call to cbegin | string.cpp:497:11:497:16 | call to assign | TAINT | +| string.cpp:497:31:497:32 | s5 | string.cpp:497:34:497:37 | call to cend | TAINT | +| string.cpp:497:34:497:37 | call to cend | string.cpp:497:8:497:9 | ref arg s6 | TAINT | +| string.cpp:497:34:497:37 | call to cend | string.cpp:497:11:497:16 | call to assign | TAINT | +| string.cpp:503:14:503:18 | abc | string.cpp:505:17:505:19 | cs1 | | +| string.cpp:504:14:504:19 | call to source | string.cpp:506:17:506:19 | cs2 | | +| string.cpp:505:17:505:19 | cs1 | string.cpp:505:17:505:20 | call to basic_string | TAINT | +| string.cpp:505:17:505:20 | call to basic_string | string.cpp:507:17:507:18 | s1 | | +| string.cpp:505:17:505:20 | call to basic_string | string.cpp:507:29:507:30 | s1 | | +| string.cpp:505:17:505:20 | call to basic_string | string.cpp:510:7:510:8 | s1 | | +| string.cpp:506:17:506:19 | cs2 | string.cpp:506:17:506:20 | call to basic_string | TAINT | +| string.cpp:506:17:506:20 | call to basic_string | string.cpp:508:17:508:18 | s2 | | +| string.cpp:506:17:506:20 | call to basic_string | string.cpp:508:29:508:30 | s2 | | +| string.cpp:506:17:506:20 | call to basic_string | string.cpp:511:7:511:8 | s2 | | +| string.cpp:507:17:507:18 | ref arg s1 | string.cpp:507:29:507:30 | s1 | | +| string.cpp:507:17:507:18 | ref arg s1 | string.cpp:510:7:510:8 | s1 | | +| string.cpp:507:17:507:18 | s1 | string.cpp:507:20:507:24 | call to begin | TAINT | +| string.cpp:507:17:507:37 | call to basic_string | string.cpp:512:7:512:8 | s3 | | +| string.cpp:507:20:507:24 | call to begin | string.cpp:507:17:507:37 | call to basic_string | TAINT | +| string.cpp:507:29:507:30 | ref arg s1 | string.cpp:510:7:510:8 | s1 | | +| string.cpp:507:29:507:30 | s1 | string.cpp:507:32:507:34 | call to end | TAINT | +| string.cpp:507:32:507:34 | call to end | string.cpp:507:17:507:37 | call to basic_string | TAINT | +| string.cpp:508:17:508:18 | ref arg s2 | string.cpp:508:29:508:30 | s2 | | +| string.cpp:508:17:508:18 | ref arg s2 | string.cpp:511:7:511:8 | s2 | | +| string.cpp:508:17:508:18 | s2 | string.cpp:508:20:508:24 | call to begin | TAINT | +| string.cpp:508:17:508:37 | call to basic_string | string.cpp:513:7:513:8 | s4 | | +| string.cpp:508:20:508:24 | call to begin | string.cpp:508:17:508:37 | call to basic_string | TAINT | +| string.cpp:508:29:508:30 | ref arg s2 | string.cpp:511:7:511:8 | s2 | | +| string.cpp:508:29:508:30 | s2 | string.cpp:508:32:508:34 | call to end | TAINT | +| string.cpp:508:32:508:34 | call to end | string.cpp:508:17:508:37 | call to basic_string | TAINT | +| string.cpp:517:16:517:19 | aa | string.cpp:517:16:517:20 | call to basic_string | TAINT | +| string.cpp:517:16:517:20 | call to basic_string | string.cpp:519:7:519:7 | a | | +| string.cpp:517:16:517:20 | call to basic_string | string.cpp:520:7:520:7 | a | | +| string.cpp:517:16:517:20 | call to basic_string | string.cpp:521:2:521:2 | a | | +| string.cpp:517:16:517:20 | call to basic_string | string.cpp:522:7:522:7 | a | | +| string.cpp:517:16:517:20 | call to basic_string | string.cpp:523:7:523:7 | a | | +| string.cpp:519:7:519:7 | a | string.cpp:519:9:519:13 | call to front | TAINT | +| string.cpp:519:7:519:7 | ref arg a | string.cpp:520:7:520:7 | a | | +| string.cpp:519:7:519:7 | ref arg a | string.cpp:521:2:521:2 | a | | +| string.cpp:519:7:519:7 | ref arg a | string.cpp:522:7:522:7 | a | | +| string.cpp:519:7:519:7 | ref arg a | string.cpp:523:7:523:7 | a | | +| string.cpp:520:7:520:7 | a | string.cpp:520:9:520:12 | call to back | TAINT | +| string.cpp:520:7:520:7 | ref arg a | string.cpp:521:2:521:2 | a | | +| string.cpp:520:7:520:7 | ref arg a | string.cpp:522:7:522:7 | a | | +| string.cpp:520:7:520:7 | ref arg a | string.cpp:523:7:523:7 | a | | +| string.cpp:521:2:521:2 | ref arg a | string.cpp:522:7:522:7 | a | | +| string.cpp:521:2:521:2 | ref arg a | string.cpp:523:7:523:7 | a | | +| string.cpp:521:14:521:28 | call to source | string.cpp:521:2:521:2 | ref arg a | TAINT | +| string.cpp:522:7:522:7 | a | string.cpp:522:9:522:13 | call to front | TAINT | +| string.cpp:522:7:522:7 | ref arg a | string.cpp:523:7:523:7 | a | | +| string.cpp:523:7:523:7 | a | string.cpp:523:9:523:12 | call to back | TAINT | +| string.cpp:528:17:528:20 | aa | string.cpp:528:17:528:21 | call to basic_string | TAINT | +| string.cpp:528:17:528:21 | call to basic_string | string.cpp:535:9:535:9 | a | | +| string.cpp:528:17:528:21 | call to basic_string | string.cpp:539:8:539:8 | a | | +| string.cpp:529:17:529:20 | bb | string.cpp:529:17:529:21 | call to basic_string | TAINT | +| string.cpp:529:17:529:21 | call to basic_string | string.cpp:535:15:535:15 | b | | +| string.cpp:529:17:529:21 | call to basic_string | string.cpp:540:8:540:8 | b | | +| string.cpp:530:17:530:20 | cc | string.cpp:530:17:530:21 | call to basic_string | TAINT | +| string.cpp:530:17:530:21 | call to basic_string | string.cpp:536:9:536:9 | c | | +| string.cpp:530:17:530:21 | call to basic_string | string.cpp:541:8:541:8 | c | | +| string.cpp:531:17:531:20 | dd | string.cpp:531:17:531:21 | call to basic_string | TAINT | +| string.cpp:531:17:531:21 | call to basic_string | string.cpp:536:15:536:15 | d | | +| string.cpp:531:17:531:21 | call to basic_string | string.cpp:542:8:542:8 | d | | +| string.cpp:532:17:532:20 | ee | string.cpp:532:17:532:21 | call to basic_string | TAINT | +| string.cpp:532:17:532:21 | call to basic_string | string.cpp:537:10:537:10 | e | | +| string.cpp:532:17:532:21 | call to basic_string | string.cpp:543:8:543:8 | e | | +| string.cpp:533:17:533:20 | ff | string.cpp:533:17:533:21 | call to basic_string | TAINT | +| string.cpp:533:17:533:21 | call to basic_string | string.cpp:538:10:538:10 | f | | +| string.cpp:533:17:533:21 | call to basic_string | string.cpp:544:8:544:8 | f | | +| string.cpp:535:9:535:9 | a | string.cpp:535:11:535:11 | call to operator+= | TAINT | +| string.cpp:535:9:535:9 | ref arg a | string.cpp:539:8:539:8 | a | | +| string.cpp:535:15:535:15 | b | string.cpp:535:17:535:17 | call to operator+= | TAINT | +| string.cpp:535:15:535:15 | ref arg b | string.cpp:540:8:540:8 | b | | +| string.cpp:535:17:535:17 | call to operator+= | string.cpp:535:9:535:9 | ref arg a | TAINT | +| string.cpp:535:17:535:17 | call to operator+= | string.cpp:535:11:535:11 | call to operator+= | TAINT | +| string.cpp:535:20:535:23 | bb | string.cpp:535:15:535:15 | ref arg b | TAINT | +| string.cpp:535:20:535:23 | bb | string.cpp:535:17:535:17 | call to operator+= | TAINT | +| string.cpp:536:9:536:9 | c | string.cpp:536:11:536:11 | call to operator+= | TAINT | +| string.cpp:536:9:536:9 | ref arg c | string.cpp:541:8:541:8 | c | | +| string.cpp:536:15:536:15 | d | string.cpp:536:17:536:17 | call to operator+= | TAINT | +| string.cpp:536:15:536:15 | ref arg d | string.cpp:542:8:542:8 | d | | +| string.cpp:536:17:536:17 | call to operator+= | string.cpp:536:9:536:9 | ref arg c | TAINT | +| string.cpp:536:17:536:17 | call to operator+= | string.cpp:536:11:536:11 | call to operator+= | TAINT | +| string.cpp:536:20:536:25 | call to source | string.cpp:536:15:536:15 | ref arg d | TAINT | +| string.cpp:536:20:536:25 | call to source | string.cpp:536:17:536:17 | call to operator+= | TAINT | +| string.cpp:537:10:537:10 | e | string.cpp:537:12:537:12 | call to operator+= | TAINT | +| string.cpp:537:10:537:10 | ref arg e | string.cpp:543:8:543:8 | e | | +| string.cpp:537:12:537:12 | call to operator+= | string.cpp:537:21:537:21 | call to operator+= | TAINT | +| string.cpp:537:12:537:12 | ref arg call to operator+= | string.cpp:537:10:537:10 | ref arg e | TAINT | +| string.cpp:537:15:537:18 | ee | string.cpp:537:10:537:10 | ref arg e | TAINT | +| string.cpp:537:15:537:18 | ee | string.cpp:537:12:537:12 | call to operator+= | TAINT | +| string.cpp:537:24:537:29 | call to source | string.cpp:537:12:537:12 | ref arg call to operator+= | TAINT | +| string.cpp:537:24:537:29 | call to source | string.cpp:537:21:537:21 | call to operator+= | TAINT | +| string.cpp:538:10:538:10 | f | string.cpp:538:12:538:12 | call to operator+= | TAINT | +| string.cpp:538:10:538:10 | ref arg f | string.cpp:544:8:544:8 | f | | +| string.cpp:538:12:538:12 | call to operator+= | string.cpp:538:25:538:25 | call to operator+= | TAINT | +| string.cpp:538:12:538:12 | ref arg call to operator+= | string.cpp:538:10:538:10 | ref arg f | TAINT | +| string.cpp:538:15:538:20 | call to source | string.cpp:538:10:538:10 | ref arg f | TAINT | +| string.cpp:538:15:538:20 | call to source | string.cpp:538:12:538:12 | call to operator+= | TAINT | +| string.cpp:538:28:538:31 | ff | string.cpp:538:12:538:12 | ref arg call to operator+= | TAINT | +| string.cpp:538:28:538:31 | ff | string.cpp:538:25:538:25 | call to operator+= | TAINT | +| string.cpp:548:17:548:20 | aa | string.cpp:548:17:548:21 | call to basic_string | TAINT | +| string.cpp:548:17:548:21 | call to basic_string | string.cpp:555:9:555:9 | a | | +| string.cpp:548:17:548:21 | call to basic_string | string.cpp:559:8:559:8 | a | | +| string.cpp:549:17:549:20 | bb | string.cpp:549:17:549:21 | call to basic_string | TAINT | +| string.cpp:549:17:549:21 | call to basic_string | string.cpp:555:18:555:18 | b | | +| string.cpp:549:17:549:21 | call to basic_string | string.cpp:560:8:560:8 | b | | +| string.cpp:550:17:550:20 | cc | string.cpp:550:17:550:21 | call to basic_string | TAINT | +| string.cpp:550:17:550:21 | call to basic_string | string.cpp:556:9:556:9 | c | | +| string.cpp:550:17:550:21 | call to basic_string | string.cpp:561:8:561:8 | c | | +| string.cpp:551:17:551:20 | dd | string.cpp:551:17:551:21 | call to basic_string | TAINT | +| string.cpp:551:17:551:21 | call to basic_string | string.cpp:556:18:556:18 | d | | +| string.cpp:551:17:551:21 | call to basic_string | string.cpp:562:8:562:8 | d | | +| string.cpp:552:17:552:20 | ee | string.cpp:552:17:552:21 | call to basic_string | TAINT | +| string.cpp:552:17:552:21 | call to basic_string | string.cpp:557:9:557:9 | e | | +| string.cpp:552:17:552:21 | call to basic_string | string.cpp:563:8:563:8 | e | | +| string.cpp:553:17:553:20 | ff | string.cpp:553:17:553:21 | call to basic_string | TAINT | +| string.cpp:553:17:553:21 | call to basic_string | string.cpp:558:9:558:9 | f | | +| string.cpp:553:17:553:21 | call to basic_string | string.cpp:564:8:564:8 | f | | +| string.cpp:555:9:555:9 | ref arg a | string.cpp:559:8:559:8 | a | | +| string.cpp:555:18:555:18 | ref arg b | string.cpp:560:8:560:8 | b | | +| string.cpp:555:20:555:25 | call to assign | string.cpp:555:9:555:9 | ref arg a | TAINT | +| string.cpp:555:20:555:25 | call to assign | string.cpp:555:11:555:16 | call to assign | TAINT | +| string.cpp:555:27:555:30 | bb | string.cpp:555:27:555:30 | call to basic_string | TAINT | +| string.cpp:555:27:555:30 | call to basic_string | string.cpp:555:18:555:18 | ref arg b | TAINT | +| string.cpp:555:27:555:30 | call to basic_string | string.cpp:555:20:555:25 | call to assign | TAINT | +| string.cpp:556:9:556:9 | ref arg c | string.cpp:561:8:561:8 | c | | +| string.cpp:556:18:556:18 | ref arg d | string.cpp:562:8:562:8 | d | | +| string.cpp:556:20:556:25 | call to assign | string.cpp:556:9:556:9 | ref arg c | TAINT | +| string.cpp:556:20:556:25 | call to assign | string.cpp:556:11:556:16 | call to assign | TAINT | +| string.cpp:556:27:556:32 | call to source | string.cpp:556:27:556:34 | call to basic_string | TAINT | +| string.cpp:556:27:556:34 | call to basic_string | string.cpp:556:18:556:18 | ref arg d | TAINT | +| string.cpp:556:27:556:34 | call to basic_string | string.cpp:556:20:556:25 | call to assign | TAINT | +| string.cpp:557:9:557:9 | ref arg e | string.cpp:563:8:563:8 | e | | +| string.cpp:557:11:557:16 | ref arg call to assign | string.cpp:557:9:557:9 | ref arg e | TAINT | +| string.cpp:557:18:557:21 | call to basic_string | string.cpp:557:9:557:9 | ref arg e | TAINT | +| string.cpp:557:18:557:21 | call to basic_string | string.cpp:557:11:557:16 | call to assign | TAINT | +| string.cpp:557:18:557:21 | ee | string.cpp:557:18:557:21 | call to basic_string | TAINT | +| string.cpp:557:31:557:36 | call to source | string.cpp:557:31:557:38 | call to basic_string | TAINT | +| string.cpp:557:31:557:38 | call to basic_string | string.cpp:557:11:557:16 | ref arg call to assign | TAINT | +| string.cpp:557:31:557:38 | call to basic_string | string.cpp:557:24:557:29 | call to assign | TAINT | +| string.cpp:558:9:558:9 | ref arg f | string.cpp:564:8:564:8 | f | | +| string.cpp:558:11:558:16 | ref arg call to assign | string.cpp:558:9:558:9 | ref arg f | TAINT | +| string.cpp:558:18:558:23 | call to source | string.cpp:558:18:558:25 | call to basic_string | TAINT | +| string.cpp:558:18:558:25 | call to basic_string | string.cpp:558:9:558:9 | ref arg f | TAINT | +| string.cpp:558:18:558:25 | call to basic_string | string.cpp:558:11:558:16 | call to assign | TAINT | +| string.cpp:558:35:558:38 | call to basic_string | string.cpp:558:11:558:16 | ref arg call to assign | TAINT | +| string.cpp:558:35:558:38 | call to basic_string | string.cpp:558:28:558:33 | call to assign | TAINT | +| string.cpp:558:35:558:38 | ff | string.cpp:558:35:558:38 | call to basic_string | TAINT | +| stringstream.cpp:26:35:26:40 | amount | stringstream.cpp:64:46:64:51 | amount | | +| stringstream.cpp:28:20:28:22 | call to basic_stringstream | stringstream.cpp:31:7:31:9 | ss1 | | +| stringstream.cpp:28:20:28:22 | call to basic_stringstream | stringstream.cpp:37:7:37:9 | ss1 | | +| stringstream.cpp:28:20:28:22 | call to basic_stringstream | stringstream.cpp:42:7:42:9 | ss1 | | +| stringstream.cpp:28:25:28:27 | call to basic_stringstream | stringstream.cpp:32:7:32:9 | ss2 | | +| stringstream.cpp:28:25:28:27 | call to basic_stringstream | stringstream.cpp:38:7:38:9 | ss2 | | +| stringstream.cpp:28:25:28:27 | call to basic_stringstream | stringstream.cpp:43:7:43:9 | ss2 | | +| stringstream.cpp:28:30:28:32 | call to basic_stringstream | stringstream.cpp:33:7:33:9 | ss3 | | +| stringstream.cpp:28:30:28:32 | call to basic_stringstream | stringstream.cpp:39:7:39:9 | ss3 | | +| stringstream.cpp:28:30:28:32 | call to basic_stringstream | stringstream.cpp:44:7:44:9 | ss3 | | +| stringstream.cpp:28:35:28:37 | call to basic_stringstream | stringstream.cpp:34:7:34:9 | ss4 | | +| stringstream.cpp:28:35:28:37 | call to basic_stringstream | stringstream.cpp:40:7:40:9 | ss4 | | +| stringstream.cpp:28:35:28:37 | call to basic_stringstream | stringstream.cpp:45:7:45:9 | ss4 | | +| stringstream.cpp:28:40:28:42 | call to basic_stringstream | stringstream.cpp:35:7:35:9 | ss5 | | +| stringstream.cpp:28:40:28:42 | call to basic_stringstream | stringstream.cpp:41:7:41:9 | ss5 | | +| stringstream.cpp:28:40:28:42 | call to basic_stringstream | stringstream.cpp:46:7:46:9 | ss5 | | +| stringstream.cpp:28:45:28:47 | call to basic_stringstream | stringstream.cpp:48:2:48:4 | ss6 | | +| stringstream.cpp:28:45:28:47 | call to basic_stringstream | stringstream.cpp:49:2:49:4 | ss6 | | +| stringstream.cpp:28:45:28:47 | call to basic_stringstream | stringstream.cpp:52:7:52:9 | ss6 | | +| stringstream.cpp:28:50:28:52 | call to basic_stringstream | stringstream.cpp:50:2:50:4 | ss7 | | +| stringstream.cpp:28:50:28:52 | call to basic_stringstream | stringstream.cpp:51:2:51:4 | ss7 | | +| stringstream.cpp:28:50:28:52 | call to basic_stringstream | stringstream.cpp:53:7:53:9 | ss7 | | +| stringstream.cpp:28:55:28:57 | call to basic_stringstream | stringstream.cpp:55:7:55:9 | ss8 | | +| stringstream.cpp:28:55:28:57 | call to basic_stringstream | stringstream.cpp:58:7:58:9 | ss8 | | +| stringstream.cpp:28:60:28:62 | call to basic_stringstream | stringstream.cpp:56:7:56:9 | ss9 | | +| stringstream.cpp:28:60:28:62 | call to basic_stringstream | stringstream.cpp:59:7:59:9 | ss9 | | +| stringstream.cpp:28:65:28:68 | call to basic_stringstream | stringstream.cpp:57:7:57:10 | ss10 | | +| stringstream.cpp:28:65:28:68 | call to basic_stringstream | stringstream.cpp:60:7:60:10 | ss10 | | +| stringstream.cpp:28:71:28:74 | call to basic_stringstream | stringstream.cpp:62:7:62:10 | ss11 | | +| stringstream.cpp:28:71:28:74 | call to basic_stringstream | stringstream.cpp:65:7:65:10 | ss11 | | +| stringstream.cpp:28:77:28:80 | call to basic_stringstream | stringstream.cpp:63:7:63:10 | ss12 | | +| stringstream.cpp:28:77:28:80 | call to basic_stringstream | stringstream.cpp:66:7:66:10 | ss12 | | +| stringstream.cpp:28:83:28:86 | call to basic_stringstream | stringstream.cpp:64:7:64:10 | ss13 | | +| stringstream.cpp:28:83:28:86 | call to basic_stringstream | stringstream.cpp:67:7:67:10 | ss13 | | +| stringstream.cpp:29:16:29:21 | call to source | stringstream.cpp:29:16:29:24 | call to basic_string | TAINT | +| stringstream.cpp:29:16:29:24 | call to basic_string | stringstream.cpp:35:14:35:14 | t | | +| stringstream.cpp:31:7:31:9 | ref arg ss1 | stringstream.cpp:37:7:37:9 | ss1 | | +| stringstream.cpp:31:7:31:9 | ref arg ss1 | stringstream.cpp:42:7:42:9 | ss1 | | +| stringstream.cpp:31:7:31:9 | ss1 | stringstream.cpp:31:11:31:11 | call to operator<< | | +| stringstream.cpp:31:14:31:19 | 1234 | stringstream.cpp:31:7:31:9 | ref arg ss1 | TAINT | +| stringstream.cpp:31:14:31:19 | 1234 | stringstream.cpp:31:11:31:11 | call to operator<< | TAINT | +| stringstream.cpp:32:7:32:9 | ref arg ss2 | stringstream.cpp:38:7:38:9 | ss2 | | +| stringstream.cpp:32:7:32:9 | ref arg ss2 | stringstream.cpp:43:7:43:9 | ss2 | | +| stringstream.cpp:32:7:32:9 | ss2 | stringstream.cpp:32:11:32:11 | call to operator<< | | +| stringstream.cpp:32:14:32:19 | call to source | stringstream.cpp:32:7:32:9 | ref arg ss2 | TAINT | +| stringstream.cpp:32:14:32:19 | call to source | stringstream.cpp:32:11:32:11 | call to operator<< | TAINT | +| stringstream.cpp:33:7:33:9 | ref arg ss3 | stringstream.cpp:39:7:39:9 | ss3 | | +| stringstream.cpp:33:7:33:9 | ref arg ss3 | stringstream.cpp:44:7:44:9 | ss3 | | +| stringstream.cpp:33:7:33:9 | ss3 | stringstream.cpp:33:11:33:11 | call to operator<< | | +| stringstream.cpp:33:11:33:11 | call to operator<< | stringstream.cpp:33:20:33:20 | call to operator<< | | +| stringstream.cpp:33:11:33:11 | ref arg call to operator<< | stringstream.cpp:33:7:33:9 | ref arg ss3 | TAINT | +| stringstream.cpp:33:14:33:18 | 123 | stringstream.cpp:33:7:33:9 | ref arg ss3 | TAINT | +| stringstream.cpp:33:14:33:18 | 123 | stringstream.cpp:33:11:33:11 | call to operator<< | TAINT | +| stringstream.cpp:33:23:33:28 | call to source | stringstream.cpp:33:11:33:11 | ref arg call to operator<< | TAINT | +| stringstream.cpp:33:23:33:28 | call to source | stringstream.cpp:33:20:33:20 | call to operator<< | TAINT | +| stringstream.cpp:34:7:34:9 | ref arg ss4 | stringstream.cpp:40:7:40:9 | ss4 | | +| stringstream.cpp:34:7:34:9 | ref arg ss4 | stringstream.cpp:45:7:45:9 | ss4 | | +| stringstream.cpp:34:7:34:9 | ss4 | stringstream.cpp:34:11:34:11 | call to operator<< | | +| stringstream.cpp:34:11:34:11 | call to operator<< | stringstream.cpp:34:23:34:23 | call to operator<< | | +| stringstream.cpp:34:11:34:11 | ref arg call to operator<< | stringstream.cpp:34:7:34:9 | ref arg ss4 | TAINT | +| stringstream.cpp:34:14:34:19 | call to source | stringstream.cpp:34:7:34:9 | ref arg ss4 | TAINT | +| stringstream.cpp:34:14:34:19 | call to source | stringstream.cpp:34:11:34:11 | call to operator<< | TAINT | +| stringstream.cpp:34:26:34:30 | 456 | stringstream.cpp:34:11:34:11 | ref arg call to operator<< | TAINT | +| stringstream.cpp:34:26:34:30 | 456 | stringstream.cpp:34:23:34:23 | call to operator<< | TAINT | +| stringstream.cpp:35:7:35:9 | ref arg ss5 | stringstream.cpp:41:7:41:9 | ss5 | | +| stringstream.cpp:35:7:35:9 | ref arg ss5 | stringstream.cpp:46:7:46:9 | ss5 | | +| stringstream.cpp:35:7:35:9 | ss5 | stringstream.cpp:35:11:35:11 | call to operator<< | | +| stringstream.cpp:35:14:35:14 | t | stringstream.cpp:35:7:35:9 | ref arg ss5 | TAINT | +| stringstream.cpp:35:14:35:14 | t | stringstream.cpp:35:11:35:11 | call to operator<< | TAINT | +| stringstream.cpp:42:7:42:9 | ss1 | stringstream.cpp:42:11:42:13 | call to str | TAINT | +| stringstream.cpp:43:7:43:9 | ss2 | stringstream.cpp:43:11:43:13 | call to str | TAINT | +| stringstream.cpp:44:7:44:9 | ss3 | stringstream.cpp:44:11:44:13 | call to str | TAINT | +| stringstream.cpp:45:7:45:9 | ss4 | stringstream.cpp:45:11:45:13 | call to str | TAINT | +| stringstream.cpp:46:7:46:9 | ss5 | stringstream.cpp:46:11:46:13 | call to str | TAINT | +| stringstream.cpp:48:2:48:4 | ref arg ss6 | stringstream.cpp:49:2:49:4 | ss6 | | +| stringstream.cpp:48:2:48:4 | ref arg ss6 | stringstream.cpp:52:7:52:9 | ss6 | | +| stringstream.cpp:48:2:48:4 | ss6 | stringstream.cpp:48:6:48:8 | call to str | TAINT | +| stringstream.cpp:48:10:48:14 | abc | stringstream.cpp:48:10:48:14 | call to basic_string | TAINT | +| stringstream.cpp:48:10:48:14 | call to basic_string | stringstream.cpp:48:2:48:4 | ref arg ss6 | TAINT | +| stringstream.cpp:49:2:49:4 | ref arg ss6 | stringstream.cpp:52:7:52:9 | ss6 | | +| stringstream.cpp:49:2:49:4 | ss6 | stringstream.cpp:49:6:49:8 | call to str | TAINT | +| stringstream.cpp:49:10:49:15 | call to source | stringstream.cpp:49:10:49:17 | call to basic_string | TAINT | +| stringstream.cpp:49:10:49:17 | call to basic_string | stringstream.cpp:49:2:49:4 | ref arg ss6 | TAINT | +| stringstream.cpp:50:2:50:4 | ref arg ss7 | stringstream.cpp:51:2:51:4 | ss7 | | +| stringstream.cpp:50:2:50:4 | ref arg ss7 | stringstream.cpp:53:7:53:9 | ss7 | | +| stringstream.cpp:50:2:50:4 | ss7 | stringstream.cpp:50:6:50:8 | call to str | TAINT | +| stringstream.cpp:50:10:50:15 | call to source | stringstream.cpp:50:10:50:17 | call to basic_string | TAINT | +| stringstream.cpp:50:10:50:17 | call to basic_string | stringstream.cpp:50:2:50:4 | ref arg ss7 | TAINT | +| stringstream.cpp:51:2:51:4 | ref arg ss7 | stringstream.cpp:53:7:53:9 | ss7 | | +| stringstream.cpp:51:2:51:4 | ss7 | stringstream.cpp:51:6:51:8 | call to str | TAINT | +| stringstream.cpp:51:10:51:14 | abc | stringstream.cpp:51:10:51:14 | call to basic_string | TAINT | +| stringstream.cpp:51:10:51:14 | call to basic_string | stringstream.cpp:51:2:51:4 | ref arg ss7 | TAINT | +| stringstream.cpp:55:7:55:9 | ref arg ss8 | stringstream.cpp:58:7:58:9 | ss8 | | +| stringstream.cpp:55:7:55:9 | ss8 | stringstream.cpp:55:11:55:13 | call to put | | +| stringstream.cpp:55:15:55:17 | 97 | stringstream.cpp:55:7:55:9 | ref arg ss8 | TAINT | +| stringstream.cpp:55:15:55:17 | 97 | stringstream.cpp:55:11:55:13 | call to put | TAINT | +| stringstream.cpp:56:7:56:9 | ref arg ss9 | stringstream.cpp:59:7:59:9 | ss9 | | +| stringstream.cpp:56:7:56:9 | ss9 | stringstream.cpp:56:11:56:13 | call to put | | +| stringstream.cpp:56:15:56:29 | call to source | stringstream.cpp:56:7:56:9 | ref arg ss9 | TAINT | +| stringstream.cpp:56:15:56:29 | call to source | stringstream.cpp:56:11:56:13 | call to put | TAINT | +| stringstream.cpp:57:7:57:10 | ref arg ss10 | stringstream.cpp:60:7:60:10 | ss10 | | +| stringstream.cpp:57:7:57:10 | ss10 | stringstream.cpp:57:12:57:14 | call to put | | +| stringstream.cpp:57:12:57:14 | call to put | stringstream.cpp:57:21:57:23 | call to put | | +| stringstream.cpp:57:12:57:14 | ref arg call to put | stringstream.cpp:57:7:57:10 | ref arg ss10 | TAINT | +| stringstream.cpp:57:16:57:18 | 97 | stringstream.cpp:57:7:57:10 | ref arg ss10 | TAINT | +| stringstream.cpp:57:16:57:18 | 97 | stringstream.cpp:57:12:57:14 | call to put | TAINT | +| stringstream.cpp:57:21:57:23 | call to put | stringstream.cpp:57:44:57:46 | call to put | | +| stringstream.cpp:57:21:57:23 | ref arg call to put | stringstream.cpp:57:12:57:14 | ref arg call to put | TAINT | +| stringstream.cpp:57:25:57:39 | call to source | stringstream.cpp:57:12:57:14 | ref arg call to put | TAINT | +| stringstream.cpp:57:25:57:39 | call to source | stringstream.cpp:57:21:57:23 | call to put | TAINT | +| stringstream.cpp:57:48:57:50 | 122 | stringstream.cpp:57:21:57:23 | ref arg call to put | TAINT | +| stringstream.cpp:57:48:57:50 | 122 | stringstream.cpp:57:44:57:46 | call to put | TAINT | +| stringstream.cpp:62:7:62:10 | ref arg ss11 | stringstream.cpp:65:7:65:10 | ss11 | | +| stringstream.cpp:62:7:62:10 | ss11 | stringstream.cpp:62:12:62:16 | call to write | | +| stringstream.cpp:62:18:62:24 | begin | stringstream.cpp:62:7:62:10 | ref arg ss11 | TAINT | +| stringstream.cpp:62:18:62:24 | begin | stringstream.cpp:62:12:62:16 | call to write | TAINT | +| stringstream.cpp:63:7:63:10 | ref arg ss12 | stringstream.cpp:66:7:66:10 | ss12 | | +| stringstream.cpp:63:7:63:10 | ss12 | stringstream.cpp:63:12:63:16 | call to write | | +| stringstream.cpp:63:18:63:23 | call to source | stringstream.cpp:63:7:63:10 | ref arg ss12 | TAINT | +| stringstream.cpp:63:18:63:23 | call to source | stringstream.cpp:63:12:63:16 | call to write | TAINT | +| stringstream.cpp:64:7:64:10 | ref arg ss13 | stringstream.cpp:67:7:67:10 | ss13 | | +| stringstream.cpp:64:7:64:10 | ss13 | stringstream.cpp:64:12:64:16 | call to write | | +| stringstream.cpp:64:12:64:16 | call to write | stringstream.cpp:64:30:64:34 | call to write | | +| stringstream.cpp:64:12:64:16 | ref arg call to write | stringstream.cpp:64:7:64:10 | ref arg ss13 | TAINT | +| stringstream.cpp:64:18:64:24 | begin | stringstream.cpp:64:7:64:10 | ref arg ss13 | TAINT | +| stringstream.cpp:64:18:64:24 | begin | stringstream.cpp:64:12:64:16 | call to write | TAINT | +| stringstream.cpp:64:30:64:34 | call to write | stringstream.cpp:64:54:64:58 | call to write | | +| stringstream.cpp:64:30:64:34 | ref arg call to write | stringstream.cpp:64:12:64:16 | ref arg call to write | TAINT | +| stringstream.cpp:64:36:64:41 | call to source | stringstream.cpp:64:12:64:16 | ref arg call to write | TAINT | +| stringstream.cpp:64:36:64:41 | call to source | stringstream.cpp:64:30:64:34 | call to write | TAINT | +| stringstream.cpp:64:60:64:64 | end | stringstream.cpp:64:30:64:34 | ref arg call to write | TAINT | +| stringstream.cpp:64:60:64:64 | end | stringstream.cpp:64:54:64:58 | call to write | TAINT | +| stringstream.cpp:70:32:70:37 | source | stringstream.cpp:76:14:76:19 | source | | +| stringstream.cpp:72:20:72:22 | call to basic_stringstream | stringstream.cpp:75:7:75:9 | ss1 | | +| stringstream.cpp:72:20:72:22 | call to basic_stringstream | stringstream.cpp:77:7:77:9 | ss1 | | +| stringstream.cpp:72:20:72:22 | call to basic_stringstream | stringstream.cpp:80:7:80:9 | ss1 | | +| stringstream.cpp:72:20:72:22 | call to basic_stringstream | stringstream.cpp:82:7:82:9 | ss1 | | +| stringstream.cpp:72:25:72:27 | call to basic_stringstream | stringstream.cpp:76:7:76:9 | ss2 | | +| stringstream.cpp:72:25:72:27 | call to basic_stringstream | stringstream.cpp:78:7:78:9 | ss2 | | +| stringstream.cpp:72:25:72:27 | call to basic_stringstream | stringstream.cpp:81:7:81:9 | ss2 | | +| stringstream.cpp:72:25:72:27 | call to basic_stringstream | stringstream.cpp:83:7:83:9 | ss2 | | +| stringstream.cpp:73:10:73:11 | 0 | stringstream.cpp:77:14:77:15 | v1 | | +| stringstream.cpp:73:10:73:11 | 0 | stringstream.cpp:84:7:84:8 | v1 | | +| stringstream.cpp:73:18:73:19 | 0 | stringstream.cpp:78:14:78:15 | v2 | | +| stringstream.cpp:73:18:73:19 | 0 | stringstream.cpp:85:7:85:8 | v2 | | +| stringstream.cpp:75:7:75:9 | ref arg ss1 | stringstream.cpp:77:7:77:9 | ss1 | | +| stringstream.cpp:75:7:75:9 | ref arg ss1 | stringstream.cpp:80:7:80:9 | ss1 | | +| stringstream.cpp:75:7:75:9 | ref arg ss1 | stringstream.cpp:82:7:82:9 | ss1 | | +| stringstream.cpp:75:7:75:9 | ss1 | stringstream.cpp:75:11:75:11 | call to operator<< | | +| stringstream.cpp:75:14:75:17 | 1234 | stringstream.cpp:75:7:75:9 | ref arg ss1 | TAINT | +| stringstream.cpp:75:14:75:17 | 1234 | stringstream.cpp:75:11:75:11 | call to operator<< | TAINT | +| stringstream.cpp:76:7:76:9 | ref arg ss2 | stringstream.cpp:78:7:78:9 | ss2 | | +| stringstream.cpp:76:7:76:9 | ref arg ss2 | stringstream.cpp:81:7:81:9 | ss2 | | +| stringstream.cpp:76:7:76:9 | ref arg ss2 | stringstream.cpp:83:7:83:9 | ss2 | | +| stringstream.cpp:76:7:76:9 | ss2 | stringstream.cpp:76:11:76:11 | call to operator<< | | +| stringstream.cpp:76:14:76:19 | source | stringstream.cpp:76:7:76:9 | ref arg ss2 | TAINT | +| stringstream.cpp:76:14:76:19 | source | stringstream.cpp:76:11:76:11 | call to operator<< | TAINT | +| stringstream.cpp:77:7:77:9 | ref arg ss1 | stringstream.cpp:80:7:80:9 | ss1 | | +| stringstream.cpp:77:7:77:9 | ref arg ss1 | stringstream.cpp:82:7:82:9 | ss1 | | +| stringstream.cpp:77:7:77:9 | ss1 | stringstream.cpp:77:11:77:11 | call to operator>> | | +| stringstream.cpp:77:7:77:9 | ss1 | stringstream.cpp:77:14:77:15 | ref arg v1 | TAINT | +| stringstream.cpp:77:14:77:15 | ref arg v1 | stringstream.cpp:84:7:84:8 | v1 | | +| stringstream.cpp:78:7:78:9 | ref arg ss2 | stringstream.cpp:81:7:81:9 | ss2 | | +| stringstream.cpp:78:7:78:9 | ref arg ss2 | stringstream.cpp:83:7:83:9 | ss2 | | +| stringstream.cpp:78:7:78:9 | ss2 | stringstream.cpp:78:11:78:11 | call to operator>> | | +| stringstream.cpp:78:7:78:9 | ss2 | stringstream.cpp:78:14:78:15 | ref arg v2 | TAINT | +| stringstream.cpp:78:14:78:15 | ref arg v2 | stringstream.cpp:85:7:85:8 | v2 | | +| stringstream.cpp:82:7:82:9 | ss1 | stringstream.cpp:82:11:82:13 | call to str | TAINT | +| stringstream.cpp:83:7:83:9 | ss2 | stringstream.cpp:83:11:83:13 | call to str | TAINT | +| stringstream.cpp:90:18:90:23 | call to basic_string | stringstream.cpp:92:24:92:25 | s1 | | +| stringstream.cpp:90:19:90:23 | abc | stringstream.cpp:90:18:90:23 | call to basic_string | TAINT | +| stringstream.cpp:91:18:91:26 | call to basic_string | stringstream.cpp:93:24:93:25 | s2 | | +| stringstream.cpp:91:19:91:24 | call to source | stringstream.cpp:91:18:91:26 | call to basic_string | TAINT | +| stringstream.cpp:92:24:92:25 | s1 | stringstream.cpp:92:24:92:26 | call to basic_stringstream | TAINT | +| stringstream.cpp:92:24:92:26 | call to basic_stringstream | stringstream.cpp:102:7:102:9 | ss1 | | +| stringstream.cpp:93:24:93:25 | s2 | stringstream.cpp:93:24:93:26 | call to basic_stringstream | TAINT | +| stringstream.cpp:93:24:93:26 | call to basic_stringstream | stringstream.cpp:103:7:103:9 | ss2 | | +| stringstream.cpp:94:25:94:49 | call to basic_stringstream | stringstream.cpp:104:7:104:9 | ss3 | | +| stringstream.cpp:94:44:94:48 | abc | stringstream.cpp:94:44:94:48 | call to basic_string | TAINT | +| stringstream.cpp:94:44:94:48 | call to basic_string | stringstream.cpp:94:25:94:49 | call to basic_stringstream | TAINT | +| stringstream.cpp:95:25:95:52 | call to basic_stringstream | stringstream.cpp:105:7:105:9 | ss4 | | +| stringstream.cpp:95:44:95:49 | call to source | stringstream.cpp:95:44:95:51 | call to basic_string | TAINT | +| stringstream.cpp:95:44:95:51 | call to basic_string | stringstream.cpp:95:25:95:52 | call to basic_stringstream | TAINT | +| stringstream.cpp:96:20:96:22 | call to basic_stringstream | stringstream.cpp:99:7:99:9 | ss5 | | +| stringstream.cpp:96:20:96:22 | call to basic_stringstream | stringstream.cpp:106:7:106:9 | ss5 | | +| stringstream.cpp:97:20:97:22 | call to basic_stringstream | stringstream.cpp:100:7:100:9 | ss6 | | +| stringstream.cpp:97:20:97:22 | call to basic_stringstream | stringstream.cpp:107:7:107:9 | ss6 | | +| stringstream.cpp:99:7:99:9 | ref arg ss5 | stringstream.cpp:106:7:106:9 | ss5 | | +| stringstream.cpp:99:13:99:36 | call to basic_stringstream | stringstream.cpp:99:7:99:9 | ref arg ss5 | TAINT | +| stringstream.cpp:99:13:99:36 | call to basic_stringstream | stringstream.cpp:99:11:99:11 | call to operator= | TAINT | +| stringstream.cpp:99:31:99:35 | abc | stringstream.cpp:99:31:99:35 | call to basic_string | TAINT | +| stringstream.cpp:99:31:99:35 | call to basic_string | stringstream.cpp:99:13:99:36 | call to basic_stringstream | TAINT | +| stringstream.cpp:100:7:100:9 | ref arg ss6 | stringstream.cpp:107:7:107:9 | ss6 | | +| stringstream.cpp:100:13:100:39 | call to basic_stringstream | stringstream.cpp:100:7:100:9 | ref arg ss6 | TAINT | +| stringstream.cpp:100:13:100:39 | call to basic_stringstream | stringstream.cpp:100:11:100:11 | call to operator= | TAINT | +| stringstream.cpp:100:31:100:36 | call to source | stringstream.cpp:100:31:100:38 | call to basic_string | TAINT | +| stringstream.cpp:100:31:100:38 | call to basic_string | stringstream.cpp:100:13:100:39 | call to basic_stringstream | TAINT | +| stringstream.cpp:112:24:112:28 | abc | stringstream.cpp:112:24:112:28 | call to basic_string | TAINT | +| stringstream.cpp:112:24:112:28 | call to basic_string | stringstream.cpp:112:24:112:29 | call to basic_stringstream | TAINT | +| stringstream.cpp:112:24:112:29 | call to basic_stringstream | stringstream.cpp:117:2:117:4 | ss1 | | +| stringstream.cpp:112:24:112:29 | call to basic_stringstream | stringstream.cpp:120:7:120:9 | ss1 | | +| stringstream.cpp:113:24:113:29 | call to source | stringstream.cpp:113:24:113:31 | call to basic_string | TAINT | +| stringstream.cpp:113:24:113:31 | call to basic_string | stringstream.cpp:113:24:113:32 | call to basic_stringstream | TAINT | +| stringstream.cpp:113:24:113:32 | call to basic_stringstream | stringstream.cpp:117:11:117:13 | ss2 | | +| stringstream.cpp:113:24:113:32 | call to basic_stringstream | stringstream.cpp:121:7:121:9 | ss2 | | +| stringstream.cpp:114:24:114:28 | abc | stringstream.cpp:114:24:114:28 | call to basic_string | TAINT | +| stringstream.cpp:114:24:114:28 | call to basic_string | stringstream.cpp:114:24:114:29 | call to basic_stringstream | TAINT | +| stringstream.cpp:114:24:114:29 | call to basic_stringstream | stringstream.cpp:118:11:118:13 | ss3 | | +| stringstream.cpp:114:24:114:29 | call to basic_stringstream | stringstream.cpp:122:7:122:9 | ss3 | | +| stringstream.cpp:115:24:115:29 | call to source | stringstream.cpp:115:24:115:31 | call to basic_string | TAINT | +| stringstream.cpp:115:24:115:31 | call to basic_string | stringstream.cpp:115:24:115:32 | call to basic_stringstream | TAINT | +| stringstream.cpp:115:24:115:32 | call to basic_stringstream | stringstream.cpp:118:2:118:4 | ss4 | | +| stringstream.cpp:115:24:115:32 | call to basic_stringstream | stringstream.cpp:123:7:123:9 | ss4 | | +| stringstream.cpp:117:2:117:4 | ref arg ss1 | stringstream.cpp:120:7:120:9 | ss1 | | +| stringstream.cpp:117:2:117:4 | ss1 | stringstream.cpp:117:11:117:13 | ref arg ss2 | TAINT | +| stringstream.cpp:117:11:117:13 | ref arg ss2 | stringstream.cpp:121:7:121:9 | ss2 | | +| stringstream.cpp:117:11:117:13 | ss2 | stringstream.cpp:117:2:117:4 | ref arg ss1 | TAINT | +| stringstream.cpp:118:2:118:4 | ref arg ss4 | stringstream.cpp:123:7:123:9 | ss4 | | +| stringstream.cpp:118:2:118:4 | ss4 | stringstream.cpp:118:11:118:13 | ref arg ss3 | TAINT | +| stringstream.cpp:118:11:118:13 | ref arg ss3 | stringstream.cpp:122:7:122:9 | ss3 | | +| stringstream.cpp:118:11:118:13 | ss3 | stringstream.cpp:118:2:118:4 | ref arg ss4 | TAINT | +| stringstream.cpp:128:20:128:22 | call to basic_stringstream | stringstream.cpp:142:7:142:9 | ss1 | | +| stringstream.cpp:128:20:128:22 | call to basic_stringstream | stringstream.cpp:145:7:145:9 | ss1 | | +| stringstream.cpp:128:20:128:22 | call to basic_stringstream | stringstream.cpp:153:7:153:9 | ss1 | | +| stringstream.cpp:128:20:128:22 | call to basic_stringstream | stringstream.cpp:161:7:161:9 | ss1 | | +| stringstream.cpp:128:20:128:22 | call to basic_stringstream | stringstream.cpp:163:7:163:9 | ss1 | | +| stringstream.cpp:128:20:128:22 | call to basic_stringstream | stringstream.cpp:165:7:165:9 | ss1 | | +| stringstream.cpp:128:20:128:22 | call to basic_stringstream | stringstream.cpp:174:12:174:14 | ss1 | | +| stringstream.cpp:128:20:128:22 | call to basic_stringstream | stringstream.cpp:176:12:176:14 | ss1 | | +| stringstream.cpp:128:20:128:22 | call to basic_stringstream | stringstream.cpp:178:7:178:9 | ss1 | | +| stringstream.cpp:128:25:128:27 | call to basic_stringstream | stringstream.cpp:143:7:143:9 | ss2 | | +| stringstream.cpp:128:25:128:27 | call to basic_stringstream | stringstream.cpp:146:7:146:9 | ss2 | | +| stringstream.cpp:128:25:128:27 | call to basic_stringstream | stringstream.cpp:147:7:147:9 | ss2 | | +| stringstream.cpp:128:25:128:27 | call to basic_stringstream | stringstream.cpp:154:7:154:9 | ss2 | | +| stringstream.cpp:128:25:128:27 | call to basic_stringstream | stringstream.cpp:155:7:155:9 | ss2 | | +| stringstream.cpp:128:25:128:27 | call to basic_stringstream | stringstream.cpp:162:7:162:9 | ss2 | | +| stringstream.cpp:128:25:128:27 | call to basic_stringstream | stringstream.cpp:164:7:164:9 | ss2 | | +| stringstream.cpp:128:25:128:27 | call to basic_stringstream | stringstream.cpp:166:7:166:9 | ss2 | | +| stringstream.cpp:128:25:128:27 | call to basic_stringstream | stringstream.cpp:175:12:175:14 | ss2 | | +| stringstream.cpp:128:25:128:27 | call to basic_stringstream | stringstream.cpp:177:12:177:14 | ss2 | | +| stringstream.cpp:128:25:128:27 | call to basic_stringstream | stringstream.cpp:179:7:179:9 | ss2 | | +| stringstream.cpp:129:14:129:15 | call to basic_string | stringstream.cpp:145:14:145:15 | s1 | | +| stringstream.cpp:129:14:129:15 | call to basic_string | stringstream.cpp:148:7:148:8 | s1 | | +| stringstream.cpp:129:18:129:19 | call to basic_string | stringstream.cpp:146:14:146:15 | s2 | | +| stringstream.cpp:129:18:129:19 | call to basic_string | stringstream.cpp:149:7:149:8 | s2 | | +| stringstream.cpp:129:22:129:23 | call to basic_string | stringstream.cpp:147:14:147:15 | s3 | | +| stringstream.cpp:129:22:129:23 | call to basic_string | stringstream.cpp:150:7:150:8 | s3 | | +| stringstream.cpp:129:26:129:27 | call to basic_string | stringstream.cpp:147:20:147:21 | s4 | | +| stringstream.cpp:129:26:129:27 | call to basic_string | stringstream.cpp:151:7:151:8 | s4 | | +| stringstream.cpp:130:16:130:19 | {...} | stringstream.cpp:153:14:153:15 | b1 | | +| stringstream.cpp:130:16:130:19 | {...} | stringstream.cpp:156:7:156:8 | b1 | | +| stringstream.cpp:130:18:130:18 | 0 | stringstream.cpp:130:16:130:19 | {...} | TAINT | +| stringstream.cpp:131:16:131:19 | {...} | stringstream.cpp:154:14:154:15 | b2 | | +| stringstream.cpp:131:16:131:19 | {...} | stringstream.cpp:157:7:157:8 | b2 | | +| stringstream.cpp:131:18:131:18 | 0 | stringstream.cpp:131:16:131:19 | {...} | TAINT | +| stringstream.cpp:132:16:132:19 | {...} | stringstream.cpp:155:14:155:15 | b3 | | +| stringstream.cpp:132:16:132:19 | {...} | stringstream.cpp:158:7:158:8 | b3 | | +| stringstream.cpp:132:18:132:18 | 0 | stringstream.cpp:132:16:132:19 | {...} | TAINT | +| stringstream.cpp:133:16:133:19 | {...} | stringstream.cpp:155:20:155:21 | b4 | | +| stringstream.cpp:133:16:133:19 | {...} | stringstream.cpp:159:7:159:8 | b4 | | +| stringstream.cpp:133:18:133:18 | 0 | stringstream.cpp:133:16:133:19 | {...} | TAINT | +| stringstream.cpp:134:16:134:19 | {...} | stringstream.cpp:161:16:161:17 | b5 | | +| stringstream.cpp:134:16:134:19 | {...} | stringstream.cpp:167:7:167:8 | b5 | | +| stringstream.cpp:134:18:134:18 | 0 | stringstream.cpp:134:16:134:19 | {...} | TAINT | +| stringstream.cpp:135:16:135:19 | {...} | stringstream.cpp:162:16:162:17 | b6 | | +| stringstream.cpp:135:16:135:19 | {...} | stringstream.cpp:168:7:168:8 | b6 | | +| stringstream.cpp:135:18:135:18 | 0 | stringstream.cpp:135:16:135:19 | {...} | TAINT | +| stringstream.cpp:136:16:136:19 | {...} | stringstream.cpp:163:20:163:21 | b7 | | +| stringstream.cpp:136:16:136:19 | {...} | stringstream.cpp:169:7:169:8 | b7 | | +| stringstream.cpp:136:18:136:18 | 0 | stringstream.cpp:136:16:136:19 | {...} | TAINT | +| stringstream.cpp:137:16:137:19 | {...} | stringstream.cpp:164:20:164:21 | b8 | | +| stringstream.cpp:137:16:137:19 | {...} | stringstream.cpp:170:7:170:8 | b8 | | +| stringstream.cpp:137:18:137:18 | 0 | stringstream.cpp:137:16:137:19 | {...} | TAINT | +| stringstream.cpp:138:16:138:19 | {...} | stringstream.cpp:165:15:165:16 | b9 | | +| stringstream.cpp:138:16:138:19 | {...} | stringstream.cpp:171:7:171:8 | b9 | | +| stringstream.cpp:138:18:138:18 | 0 | stringstream.cpp:138:16:138:19 | {...} | TAINT | +| stringstream.cpp:139:17:139:20 | {...} | stringstream.cpp:166:15:166:17 | b10 | | +| stringstream.cpp:139:17:139:20 | {...} | stringstream.cpp:172:7:172:9 | b10 | | +| stringstream.cpp:139:19:139:19 | 0 | stringstream.cpp:139:17:139:20 | {...} | TAINT | +| stringstream.cpp:140:44:140:44 | 0 | stringstream.cpp:178:15:178:16 | c5 | | +| stringstream.cpp:140:44:140:44 | 0 | stringstream.cpp:184:7:184:8 | c5 | | +| stringstream.cpp:140:52:140:52 | 0 | stringstream.cpp:179:15:179:16 | c6 | | +| stringstream.cpp:140:52:140:52 | 0 | stringstream.cpp:185:7:185:8 | c6 | | +| stringstream.cpp:142:7:142:9 | ref arg ss1 | stringstream.cpp:145:7:145:9 | ss1 | | +| stringstream.cpp:142:7:142:9 | ref arg ss1 | stringstream.cpp:153:7:153:9 | ss1 | | +| stringstream.cpp:142:7:142:9 | ref arg ss1 | stringstream.cpp:161:7:161:9 | ss1 | | +| stringstream.cpp:142:7:142:9 | ref arg ss1 | stringstream.cpp:163:7:163:9 | ss1 | | +| stringstream.cpp:142:7:142:9 | ref arg ss1 | stringstream.cpp:165:7:165:9 | ss1 | | +| stringstream.cpp:142:7:142:9 | ref arg ss1 | stringstream.cpp:174:12:174:14 | ss1 | | +| stringstream.cpp:142:7:142:9 | ref arg ss1 | stringstream.cpp:176:12:176:14 | ss1 | | +| stringstream.cpp:142:7:142:9 | ref arg ss1 | stringstream.cpp:178:7:178:9 | ss1 | | +| stringstream.cpp:142:7:142:9 | ss1 | stringstream.cpp:142:11:142:11 | call to operator<< | | +| stringstream.cpp:142:14:142:18 | abc | stringstream.cpp:142:7:142:9 | ref arg ss1 | TAINT | +| stringstream.cpp:142:14:142:18 | abc | stringstream.cpp:142:11:142:11 | call to operator<< | TAINT | +| stringstream.cpp:143:7:143:9 | ref arg ss2 | stringstream.cpp:146:7:146:9 | ss2 | | +| stringstream.cpp:143:7:143:9 | ref arg ss2 | stringstream.cpp:147:7:147:9 | ss2 | | +| stringstream.cpp:143:7:143:9 | ref arg ss2 | stringstream.cpp:154:7:154:9 | ss2 | | +| stringstream.cpp:143:7:143:9 | ref arg ss2 | stringstream.cpp:155:7:155:9 | ss2 | | +| stringstream.cpp:143:7:143:9 | ref arg ss2 | stringstream.cpp:162:7:162:9 | ss2 | | +| stringstream.cpp:143:7:143:9 | ref arg ss2 | stringstream.cpp:164:7:164:9 | ss2 | | +| stringstream.cpp:143:7:143:9 | ref arg ss2 | stringstream.cpp:166:7:166:9 | ss2 | | +| stringstream.cpp:143:7:143:9 | ref arg ss2 | stringstream.cpp:175:12:175:14 | ss2 | | +| stringstream.cpp:143:7:143:9 | ref arg ss2 | stringstream.cpp:177:12:177:14 | ss2 | | +| stringstream.cpp:143:7:143:9 | ref arg ss2 | stringstream.cpp:179:7:179:9 | ss2 | | +| stringstream.cpp:143:7:143:9 | ss2 | stringstream.cpp:143:11:143:11 | call to operator<< | | +| stringstream.cpp:143:14:143:19 | call to source | stringstream.cpp:143:7:143:9 | ref arg ss2 | TAINT | +| stringstream.cpp:143:14:143:19 | call to source | stringstream.cpp:143:11:143:11 | call to operator<< | TAINT | +| stringstream.cpp:145:7:145:9 | ref arg ss1 | stringstream.cpp:153:7:153:9 | ss1 | | +| stringstream.cpp:145:7:145:9 | ref arg ss1 | stringstream.cpp:161:7:161:9 | ss1 | | +| stringstream.cpp:145:7:145:9 | ref arg ss1 | stringstream.cpp:163:7:163:9 | ss1 | | +| stringstream.cpp:145:7:145:9 | ref arg ss1 | stringstream.cpp:165:7:165:9 | ss1 | | +| stringstream.cpp:145:7:145:9 | ref arg ss1 | stringstream.cpp:174:12:174:14 | ss1 | | +| stringstream.cpp:145:7:145:9 | ref arg ss1 | stringstream.cpp:176:12:176:14 | ss1 | | +| stringstream.cpp:145:7:145:9 | ref arg ss1 | stringstream.cpp:178:7:178:9 | ss1 | | +| stringstream.cpp:145:7:145:9 | ss1 | stringstream.cpp:145:11:145:11 | call to operator>> | | +| stringstream.cpp:145:7:145:9 | ss1 | stringstream.cpp:145:14:145:15 | ref arg s1 | TAINT | +| stringstream.cpp:145:14:145:15 | ref arg s1 | stringstream.cpp:148:7:148:8 | s1 | | +| stringstream.cpp:146:7:146:9 | ref arg ss2 | stringstream.cpp:147:7:147:9 | ss2 | | +| stringstream.cpp:146:7:146:9 | ref arg ss2 | stringstream.cpp:154:7:154:9 | ss2 | | +| stringstream.cpp:146:7:146:9 | ref arg ss2 | stringstream.cpp:155:7:155:9 | ss2 | | +| stringstream.cpp:146:7:146:9 | ref arg ss2 | stringstream.cpp:162:7:162:9 | ss2 | | +| stringstream.cpp:146:7:146:9 | ref arg ss2 | stringstream.cpp:164:7:164:9 | ss2 | | +| stringstream.cpp:146:7:146:9 | ref arg ss2 | stringstream.cpp:166:7:166:9 | ss2 | | +| stringstream.cpp:146:7:146:9 | ref arg ss2 | stringstream.cpp:175:12:175:14 | ss2 | | +| stringstream.cpp:146:7:146:9 | ref arg ss2 | stringstream.cpp:177:12:177:14 | ss2 | | +| stringstream.cpp:146:7:146:9 | ref arg ss2 | stringstream.cpp:179:7:179:9 | ss2 | | +| stringstream.cpp:146:7:146:9 | ss2 | stringstream.cpp:146:11:146:11 | call to operator>> | | +| stringstream.cpp:146:7:146:9 | ss2 | stringstream.cpp:146:14:146:15 | ref arg s2 | TAINT | +| stringstream.cpp:146:14:146:15 | ref arg s2 | stringstream.cpp:149:7:149:8 | s2 | | +| stringstream.cpp:147:7:147:9 | ref arg ss2 | stringstream.cpp:154:7:154:9 | ss2 | | +| stringstream.cpp:147:7:147:9 | ref arg ss2 | stringstream.cpp:155:7:155:9 | ss2 | | +| stringstream.cpp:147:7:147:9 | ref arg ss2 | stringstream.cpp:162:7:162:9 | ss2 | | +| stringstream.cpp:147:7:147:9 | ref arg ss2 | stringstream.cpp:164:7:164:9 | ss2 | | +| stringstream.cpp:147:7:147:9 | ref arg ss2 | stringstream.cpp:166:7:166:9 | ss2 | | +| stringstream.cpp:147:7:147:9 | ref arg ss2 | stringstream.cpp:175:12:175:14 | ss2 | | +| stringstream.cpp:147:7:147:9 | ref arg ss2 | stringstream.cpp:177:12:177:14 | ss2 | | +| stringstream.cpp:147:7:147:9 | ref arg ss2 | stringstream.cpp:179:7:179:9 | ss2 | | +| stringstream.cpp:147:7:147:9 | ss2 | stringstream.cpp:147:11:147:11 | call to operator>> | | +| stringstream.cpp:147:7:147:9 | ss2 | stringstream.cpp:147:14:147:15 | ref arg s3 | TAINT | +| stringstream.cpp:147:11:147:11 | call to operator>> | stringstream.cpp:147:17:147:17 | call to operator>> | | +| stringstream.cpp:147:11:147:11 | call to operator>> | stringstream.cpp:147:20:147:21 | ref arg s4 | TAINT | +| stringstream.cpp:147:11:147:11 | ref arg call to operator>> | stringstream.cpp:147:7:147:9 | ref arg ss2 | TAINT | +| stringstream.cpp:147:14:147:15 | ref arg s3 | stringstream.cpp:150:7:150:8 | s3 | | +| stringstream.cpp:147:20:147:21 | ref arg s4 | stringstream.cpp:151:7:151:8 | s4 | | +| stringstream.cpp:153:7:153:9 | ref arg ss1 | stringstream.cpp:161:7:161:9 | ss1 | | +| stringstream.cpp:153:7:153:9 | ref arg ss1 | stringstream.cpp:163:7:163:9 | ss1 | | +| stringstream.cpp:153:7:153:9 | ref arg ss1 | stringstream.cpp:165:7:165:9 | ss1 | | +| stringstream.cpp:153:7:153:9 | ref arg ss1 | stringstream.cpp:174:12:174:14 | ss1 | | +| stringstream.cpp:153:7:153:9 | ref arg ss1 | stringstream.cpp:176:12:176:14 | ss1 | | +| stringstream.cpp:153:7:153:9 | ref arg ss1 | stringstream.cpp:178:7:178:9 | ss1 | | +| stringstream.cpp:153:7:153:9 | ss1 | stringstream.cpp:153:11:153:11 | call to operator>> | | +| stringstream.cpp:153:7:153:9 | ss1 | stringstream.cpp:153:14:153:15 | ref arg b1 | TAINT | +| stringstream.cpp:153:14:153:15 | ref arg b1 | stringstream.cpp:156:7:156:8 | b1 | | +| stringstream.cpp:154:7:154:9 | ref arg ss2 | stringstream.cpp:155:7:155:9 | ss2 | | +| stringstream.cpp:154:7:154:9 | ref arg ss2 | stringstream.cpp:162:7:162:9 | ss2 | | +| stringstream.cpp:154:7:154:9 | ref arg ss2 | stringstream.cpp:164:7:164:9 | ss2 | | +| stringstream.cpp:154:7:154:9 | ref arg ss2 | stringstream.cpp:166:7:166:9 | ss2 | | +| stringstream.cpp:154:7:154:9 | ref arg ss2 | stringstream.cpp:175:12:175:14 | ss2 | | +| stringstream.cpp:154:7:154:9 | ref arg ss2 | stringstream.cpp:177:12:177:14 | ss2 | | +| stringstream.cpp:154:7:154:9 | ref arg ss2 | stringstream.cpp:179:7:179:9 | ss2 | | +| stringstream.cpp:154:7:154:9 | ss2 | stringstream.cpp:154:11:154:11 | call to operator>> | | +| stringstream.cpp:154:7:154:9 | ss2 | stringstream.cpp:154:14:154:15 | ref arg b2 | TAINT | +| stringstream.cpp:154:14:154:15 | ref arg b2 | stringstream.cpp:157:7:157:8 | b2 | | +| stringstream.cpp:155:7:155:9 | ref arg ss2 | stringstream.cpp:162:7:162:9 | ss2 | | +| stringstream.cpp:155:7:155:9 | ref arg ss2 | stringstream.cpp:164:7:164:9 | ss2 | | +| stringstream.cpp:155:7:155:9 | ref arg ss2 | stringstream.cpp:166:7:166:9 | ss2 | | +| stringstream.cpp:155:7:155:9 | ref arg ss2 | stringstream.cpp:175:12:175:14 | ss2 | | +| stringstream.cpp:155:7:155:9 | ref arg ss2 | stringstream.cpp:177:12:177:14 | ss2 | | +| stringstream.cpp:155:7:155:9 | ref arg ss2 | stringstream.cpp:179:7:179:9 | ss2 | | +| stringstream.cpp:155:7:155:9 | ss2 | stringstream.cpp:155:11:155:11 | call to operator>> | | +| stringstream.cpp:155:7:155:9 | ss2 | stringstream.cpp:155:14:155:15 | ref arg b3 | TAINT | +| stringstream.cpp:155:11:155:11 | call to operator>> | stringstream.cpp:155:17:155:17 | call to operator>> | | +| stringstream.cpp:155:11:155:11 | call to operator>> | stringstream.cpp:155:20:155:21 | ref arg b4 | TAINT | +| stringstream.cpp:155:11:155:11 | ref arg call to operator>> | stringstream.cpp:155:7:155:9 | ref arg ss2 | TAINT | +| stringstream.cpp:155:14:155:15 | ref arg b3 | stringstream.cpp:158:7:158:8 | b3 | | +| stringstream.cpp:155:20:155:21 | ref arg b4 | stringstream.cpp:159:7:159:8 | b4 | | +| stringstream.cpp:156:7:156:8 | b1 | stringstream.cpp:156:7:156:8 | call to basic_string | TAINT | +| stringstream.cpp:157:7:157:8 | b2 | stringstream.cpp:157:7:157:8 | call to basic_string | TAINT | +| stringstream.cpp:158:7:158:8 | b3 | stringstream.cpp:158:7:158:8 | call to basic_string | TAINT | +| stringstream.cpp:159:7:159:8 | b4 | stringstream.cpp:159:7:159:8 | call to basic_string | TAINT | +| stringstream.cpp:161:7:161:9 | ref arg ss1 | stringstream.cpp:163:7:163:9 | ss1 | | +| stringstream.cpp:161:7:161:9 | ref arg ss1 | stringstream.cpp:165:7:165:9 | ss1 | | +| stringstream.cpp:161:7:161:9 | ref arg ss1 | stringstream.cpp:174:12:174:14 | ss1 | | +| stringstream.cpp:161:7:161:9 | ref arg ss1 | stringstream.cpp:176:12:176:14 | ss1 | | +| stringstream.cpp:161:7:161:9 | ref arg ss1 | stringstream.cpp:178:7:178:9 | ss1 | | +| stringstream.cpp:161:7:161:9 | ss1 | stringstream.cpp:161:11:161:14 | call to read | | +| stringstream.cpp:161:7:161:9 | ss1 | stringstream.cpp:161:16:161:17 | ref arg b5 | TAINT | +| stringstream.cpp:161:16:161:17 | ref arg b5 | stringstream.cpp:167:7:167:8 | b5 | | +| stringstream.cpp:162:7:162:9 | ref arg ss2 | stringstream.cpp:164:7:164:9 | ss2 | | +| stringstream.cpp:162:7:162:9 | ref arg ss2 | stringstream.cpp:166:7:166:9 | ss2 | | +| stringstream.cpp:162:7:162:9 | ref arg ss2 | stringstream.cpp:175:12:175:14 | ss2 | | +| stringstream.cpp:162:7:162:9 | ref arg ss2 | stringstream.cpp:177:12:177:14 | ss2 | | +| stringstream.cpp:162:7:162:9 | ref arg ss2 | stringstream.cpp:179:7:179:9 | ss2 | | +| stringstream.cpp:162:7:162:9 | ss2 | stringstream.cpp:162:11:162:14 | call to read | | +| stringstream.cpp:162:7:162:9 | ss2 | stringstream.cpp:162:16:162:17 | ref arg b6 | TAINT | +| stringstream.cpp:162:16:162:17 | ref arg b6 | stringstream.cpp:168:7:168:8 | b6 | | +| stringstream.cpp:163:7:163:9 | ref arg ss1 | stringstream.cpp:165:7:165:9 | ss1 | | +| stringstream.cpp:163:7:163:9 | ref arg ss1 | stringstream.cpp:174:12:174:14 | ss1 | | +| stringstream.cpp:163:7:163:9 | ref arg ss1 | stringstream.cpp:176:12:176:14 | ss1 | | +| stringstream.cpp:163:7:163:9 | ref arg ss1 | stringstream.cpp:178:7:178:9 | ss1 | | +| stringstream.cpp:163:7:163:9 | ss1 | stringstream.cpp:163:20:163:21 | ref arg b7 | TAINT | +| stringstream.cpp:163:20:163:21 | ref arg b7 | stringstream.cpp:169:7:169:8 | b7 | | +| stringstream.cpp:164:7:164:9 | ref arg ss2 | stringstream.cpp:166:7:166:9 | ss2 | | +| stringstream.cpp:164:7:164:9 | ref arg ss2 | stringstream.cpp:175:12:175:14 | ss2 | | +| stringstream.cpp:164:7:164:9 | ref arg ss2 | stringstream.cpp:177:12:177:14 | ss2 | | +| stringstream.cpp:164:7:164:9 | ref arg ss2 | stringstream.cpp:179:7:179:9 | ss2 | | +| stringstream.cpp:164:7:164:9 | ss2 | stringstream.cpp:164:20:164:21 | ref arg b8 | TAINT | +| stringstream.cpp:164:20:164:21 | ref arg b8 | stringstream.cpp:170:7:170:8 | b8 | | +| stringstream.cpp:165:7:165:9 | ref arg ss1 | stringstream.cpp:174:12:174:14 | ss1 | | +| stringstream.cpp:165:7:165:9 | ref arg ss1 | stringstream.cpp:176:12:176:14 | ss1 | | +| stringstream.cpp:165:7:165:9 | ref arg ss1 | stringstream.cpp:178:7:178:9 | ss1 | | +| stringstream.cpp:165:7:165:9 | ss1 | stringstream.cpp:165:11:165:13 | call to get | | +| stringstream.cpp:165:7:165:9 | ss1 | stringstream.cpp:165:15:165:16 | ref arg b9 | TAINT | +| stringstream.cpp:165:15:165:16 | ref arg b9 | stringstream.cpp:171:7:171:8 | b9 | | +| stringstream.cpp:166:7:166:9 | ref arg ss2 | stringstream.cpp:175:12:175:14 | ss2 | | +| stringstream.cpp:166:7:166:9 | ref arg ss2 | stringstream.cpp:177:12:177:14 | ss2 | | +| stringstream.cpp:166:7:166:9 | ref arg ss2 | stringstream.cpp:179:7:179:9 | ss2 | | +| stringstream.cpp:166:7:166:9 | ss2 | stringstream.cpp:166:11:166:13 | call to get | | +| stringstream.cpp:166:7:166:9 | ss2 | stringstream.cpp:166:15:166:17 | ref arg b10 | TAINT | +| stringstream.cpp:166:15:166:17 | ref arg b10 | stringstream.cpp:172:7:172:9 | b10 | | +| stringstream.cpp:167:7:167:8 | b5 | stringstream.cpp:167:7:167:8 | call to basic_string | TAINT | +| stringstream.cpp:168:7:168:8 | b6 | stringstream.cpp:168:7:168:8 | call to basic_string | TAINT | +| stringstream.cpp:169:7:169:8 | b7 | stringstream.cpp:169:7:169:8 | call to basic_string | TAINT | +| stringstream.cpp:170:7:170:8 | b8 | stringstream.cpp:170:7:170:8 | call to basic_string | TAINT | +| stringstream.cpp:171:7:171:8 | b9 | stringstream.cpp:171:7:171:8 | call to basic_string | TAINT | +| stringstream.cpp:172:7:172:9 | b10 | stringstream.cpp:172:7:172:9 | call to basic_string | TAINT | +| stringstream.cpp:174:7:174:8 | c1 | stringstream.cpp:174:7:174:20 | ... = ... | | +| stringstream.cpp:174:12:174:14 | ref arg ss1 | stringstream.cpp:176:12:176:14 | ss1 | | +| stringstream.cpp:174:12:174:14 | ref arg ss1 | stringstream.cpp:178:7:178:9 | ss1 | | +| stringstream.cpp:174:12:174:14 | ss1 | stringstream.cpp:174:16:174:18 | call to get | TAINT | +| stringstream.cpp:174:16:174:18 | call to get | stringstream.cpp:174:7:174:20 | ... = ... | | +| stringstream.cpp:174:16:174:18 | call to get | stringstream.cpp:180:7:180:8 | c1 | | +| stringstream.cpp:175:7:175:8 | c2 | stringstream.cpp:175:7:175:20 | ... = ... | | +| stringstream.cpp:175:12:175:14 | ref arg ss2 | stringstream.cpp:177:12:177:14 | ss2 | | +| stringstream.cpp:175:12:175:14 | ref arg ss2 | stringstream.cpp:179:7:179:9 | ss2 | | +| stringstream.cpp:175:12:175:14 | ss2 | stringstream.cpp:175:16:175:18 | call to get | TAINT | +| stringstream.cpp:175:16:175:18 | call to get | stringstream.cpp:175:7:175:20 | ... = ... | | +| stringstream.cpp:175:16:175:18 | call to get | stringstream.cpp:181:7:181:8 | c2 | | +| stringstream.cpp:176:7:176:8 | c3 | stringstream.cpp:176:7:176:21 | ... = ... | | +| stringstream.cpp:176:12:176:14 | ref arg ss1 | stringstream.cpp:178:7:178:9 | ss1 | | +| stringstream.cpp:176:12:176:14 | ss1 | stringstream.cpp:176:16:176:19 | call to peek | TAINT | +| stringstream.cpp:176:16:176:19 | call to peek | stringstream.cpp:176:7:176:21 | ... = ... | | +| stringstream.cpp:176:16:176:19 | call to peek | stringstream.cpp:182:7:182:8 | c3 | | +| stringstream.cpp:177:7:177:8 | c4 | stringstream.cpp:177:7:177:21 | ... = ... | | +| stringstream.cpp:177:12:177:14 | ref arg ss2 | stringstream.cpp:179:7:179:9 | ss2 | | +| stringstream.cpp:177:12:177:14 | ss2 | stringstream.cpp:177:16:177:19 | call to peek | TAINT | +| stringstream.cpp:177:16:177:19 | call to peek | stringstream.cpp:177:7:177:21 | ... = ... | | +| stringstream.cpp:177:16:177:19 | call to peek | stringstream.cpp:183:7:183:8 | c4 | | +| stringstream.cpp:178:7:178:9 | ss1 | stringstream.cpp:178:11:178:13 | call to get | | +| stringstream.cpp:178:7:178:9 | ss1 | stringstream.cpp:178:15:178:16 | ref arg c5 | TAINT | +| stringstream.cpp:178:15:178:16 | ref arg c5 | stringstream.cpp:184:7:184:8 | c5 | | +| stringstream.cpp:179:7:179:9 | ss2 | stringstream.cpp:179:11:179:13 | call to get | | +| stringstream.cpp:179:7:179:9 | ss2 | stringstream.cpp:179:15:179:16 | ref arg c6 | TAINT | +| stringstream.cpp:179:15:179:16 | ref arg c6 | stringstream.cpp:185:7:185:8 | c6 | | +| stringstream.cpp:190:20:190:21 | call to basic_stringstream | stringstream.cpp:192:7:192:8 | ss | | +| stringstream.cpp:190:20:190:21 | call to basic_stringstream | stringstream.cpp:193:7:193:8 | ss | | +| stringstream.cpp:190:20:190:21 | call to basic_stringstream | stringstream.cpp:194:7:194:8 | ss | | +| stringstream.cpp:190:20:190:21 | call to basic_stringstream | stringstream.cpp:195:7:195:8 | ss | | +| stringstream.cpp:190:20:190:21 | call to basic_stringstream | stringstream.cpp:196:7:196:8 | ss | | +| stringstream.cpp:190:20:190:21 | call to basic_stringstream | stringstream.cpp:197:7:197:8 | ss | | +| stringstream.cpp:192:7:192:8 | ref arg ss | stringstream.cpp:193:7:193:8 | ss | | +| stringstream.cpp:192:7:192:8 | ref arg ss | stringstream.cpp:194:7:194:8 | ss | | +| stringstream.cpp:192:7:192:8 | ref arg ss | stringstream.cpp:195:7:195:8 | ss | | +| stringstream.cpp:192:7:192:8 | ref arg ss | stringstream.cpp:196:7:196:8 | ss | | +| stringstream.cpp:192:7:192:8 | ref arg ss | stringstream.cpp:197:7:197:8 | ss | | +| stringstream.cpp:192:7:192:8 | ss | stringstream.cpp:192:10:192:12 | call to put | | +| stringstream.cpp:192:14:192:16 | 97 | stringstream.cpp:192:7:192:8 | ref arg ss | TAINT | +| stringstream.cpp:192:14:192:16 | 97 | stringstream.cpp:192:10:192:12 | call to put | TAINT | +| stringstream.cpp:193:7:193:8 | ref arg ss | stringstream.cpp:194:7:194:8 | ss | | +| stringstream.cpp:193:7:193:8 | ref arg ss | stringstream.cpp:195:7:195:8 | ss | | +| stringstream.cpp:193:7:193:8 | ref arg ss | stringstream.cpp:196:7:196:8 | ss | | +| stringstream.cpp:193:7:193:8 | ref arg ss | stringstream.cpp:197:7:197:8 | ss | | +| stringstream.cpp:193:7:193:8 | ss | stringstream.cpp:193:10:193:12 | call to get | TAINT | +| stringstream.cpp:194:7:194:8 | ref arg ss | stringstream.cpp:195:7:195:8 | ss | | +| stringstream.cpp:194:7:194:8 | ref arg ss | stringstream.cpp:196:7:196:8 | ss | | +| stringstream.cpp:194:7:194:8 | ref arg ss | stringstream.cpp:197:7:197:8 | ss | | +| stringstream.cpp:194:7:194:8 | ss | stringstream.cpp:194:10:194:16 | call to putback | | +| stringstream.cpp:194:18:194:20 | 98 | stringstream.cpp:194:7:194:8 | ref arg ss | TAINT | +| stringstream.cpp:194:18:194:20 | 98 | stringstream.cpp:194:10:194:16 | call to putback | TAINT | +| stringstream.cpp:195:7:195:8 | ref arg ss | stringstream.cpp:196:7:196:8 | ss | | +| stringstream.cpp:195:7:195:8 | ref arg ss | stringstream.cpp:197:7:197:8 | ss | | +| stringstream.cpp:195:7:195:8 | ss | stringstream.cpp:195:10:195:12 | call to get | TAINT | +| stringstream.cpp:196:7:196:8 | ref arg ss | stringstream.cpp:197:7:197:8 | ss | | +| stringstream.cpp:196:7:196:8 | ss | stringstream.cpp:196:10:196:16 | call to putback | | +| stringstream.cpp:196:18:196:32 | call to source | stringstream.cpp:196:7:196:8 | ref arg ss | TAINT | +| stringstream.cpp:196:18:196:32 | call to source | stringstream.cpp:196:10:196:16 | call to putback | TAINT | +| stringstream.cpp:197:7:197:8 | ss | stringstream.cpp:197:10:197:12 | call to get | TAINT | +| stringstream.cpp:202:24:202:28 | abc | stringstream.cpp:202:24:202:28 | call to basic_string | TAINT | +| stringstream.cpp:202:24:202:28 | call to basic_string | stringstream.cpp:202:24:202:29 | call to basic_stringstream | TAINT | +| stringstream.cpp:202:24:202:29 | call to basic_stringstream | stringstream.cpp:214:7:214:9 | ss1 | | +| stringstream.cpp:202:24:202:29 | call to basic_stringstream | stringstream.cpp:217:7:217:9 | ss1 | | +| stringstream.cpp:202:24:202:29 | call to basic_stringstream | stringstream.cpp:222:7:222:9 | ss1 | | +| stringstream.cpp:202:24:202:29 | call to basic_stringstream | stringstream.cpp:225:7:225:9 | ss1 | | +| stringstream.cpp:202:24:202:29 | call to basic_stringstream | stringstream.cpp:234:15:234:17 | ss1 | | +| stringstream.cpp:202:24:202:29 | call to basic_stringstream | stringstream.cpp:237:15:237:17 | ss1 | | +| stringstream.cpp:202:24:202:29 | call to basic_stringstream | stringstream.cpp:242:15:242:17 | ss1 | | +| stringstream.cpp:202:24:202:29 | call to basic_stringstream | stringstream.cpp:245:15:245:17 | ss1 | | +| stringstream.cpp:203:24:203:29 | call to source | stringstream.cpp:203:24:203:31 | call to basic_string | TAINT | +| stringstream.cpp:203:24:203:31 | call to basic_string | stringstream.cpp:203:24:203:32 | call to basic_stringstream | TAINT | +| stringstream.cpp:203:24:203:32 | call to basic_stringstream | stringstream.cpp:215:7:215:9 | ss2 | | +| stringstream.cpp:203:24:203:32 | call to basic_stringstream | stringstream.cpp:216:7:216:9 | ss2 | | +| stringstream.cpp:203:24:203:32 | call to basic_stringstream | stringstream.cpp:223:7:223:9 | ss2 | | +| stringstream.cpp:203:24:203:32 | call to basic_stringstream | stringstream.cpp:224:7:224:9 | ss2 | | +| stringstream.cpp:203:24:203:32 | call to basic_stringstream | stringstream.cpp:230:7:230:9 | ss2 | | +| stringstream.cpp:203:24:203:32 | call to basic_stringstream | stringstream.cpp:235:15:235:17 | ss2 | | +| stringstream.cpp:203:24:203:32 | call to basic_stringstream | stringstream.cpp:236:15:236:17 | ss2 | | +| stringstream.cpp:203:24:203:32 | call to basic_stringstream | stringstream.cpp:243:15:243:17 | ss2 | | +| stringstream.cpp:203:24:203:32 | call to basic_stringstream | stringstream.cpp:244:15:244:17 | ss2 | | +| stringstream.cpp:203:24:203:32 | call to basic_stringstream | stringstream.cpp:250:23:250:25 | ss2 | | +| stringstream.cpp:204:17:204:20 | {...} | stringstream.cpp:214:19:214:20 | b1 | | +| stringstream.cpp:204:17:204:20 | {...} | stringstream.cpp:218:7:218:8 | b1 | | +| stringstream.cpp:204:19:204:19 | 0 | stringstream.cpp:204:17:204:20 | {...} | TAINT | +| stringstream.cpp:205:17:205:20 | {...} | stringstream.cpp:215:19:215:20 | b2 | | +| stringstream.cpp:205:17:205:20 | {...} | stringstream.cpp:219:7:219:8 | b2 | | +| stringstream.cpp:205:19:205:19 | 0 | stringstream.cpp:205:17:205:20 | {...} | TAINT | +| stringstream.cpp:206:17:206:20 | {...} | stringstream.cpp:216:19:216:20 | b3 | | +| stringstream.cpp:206:17:206:20 | {...} | stringstream.cpp:217:19:217:20 | b3 | | +| stringstream.cpp:206:17:206:20 | {...} | stringstream.cpp:220:7:220:8 | b3 | | +| stringstream.cpp:206:19:206:19 | 0 | stringstream.cpp:206:17:206:20 | {...} | TAINT | +| stringstream.cpp:207:17:207:20 | {...} | stringstream.cpp:222:19:222:20 | b4 | | +| stringstream.cpp:207:17:207:20 | {...} | stringstream.cpp:226:7:226:8 | b4 | | +| stringstream.cpp:207:19:207:19 | 0 | stringstream.cpp:207:17:207:20 | {...} | TAINT | +| stringstream.cpp:208:17:208:20 | {...} | stringstream.cpp:223:19:223:20 | b5 | | +| stringstream.cpp:208:17:208:20 | {...} | stringstream.cpp:227:7:227:8 | b5 | | +| stringstream.cpp:208:19:208:19 | 0 | stringstream.cpp:208:17:208:20 | {...} | TAINT | +| stringstream.cpp:209:17:209:20 | {...} | stringstream.cpp:224:19:224:20 | b6 | | +| stringstream.cpp:209:17:209:20 | {...} | stringstream.cpp:225:19:225:20 | b6 | | +| stringstream.cpp:209:17:209:20 | {...} | stringstream.cpp:228:7:228:8 | b6 | | +| stringstream.cpp:209:19:209:19 | 0 | stringstream.cpp:209:17:209:20 | {...} | TAINT | +| stringstream.cpp:210:17:210:20 | {...} | stringstream.cpp:230:19:230:20 | b7 | | +| stringstream.cpp:210:17:210:20 | {...} | stringstream.cpp:231:7:231:8 | b7 | | +| stringstream.cpp:210:19:210:19 | 0 | stringstream.cpp:210:17:210:20 | {...} | TAINT | +| stringstream.cpp:211:17:211:20 | {...} | stringstream.cpp:230:37:230:38 | b8 | | +| stringstream.cpp:211:17:211:20 | {...} | stringstream.cpp:232:7:232:8 | b8 | | +| stringstream.cpp:211:19:211:19 | 0 | stringstream.cpp:211:17:211:20 | {...} | TAINT | +| stringstream.cpp:212:14:212:15 | call to basic_string | stringstream.cpp:234:20:234:21 | s1 | | +| stringstream.cpp:212:14:212:15 | call to basic_string | stringstream.cpp:238:7:238:8 | s1 | | +| stringstream.cpp:212:18:212:19 | call to basic_string | stringstream.cpp:235:20:235:21 | s2 | | +| stringstream.cpp:212:18:212:19 | call to basic_string | stringstream.cpp:239:7:239:8 | s2 | | +| stringstream.cpp:212:22:212:23 | call to basic_string | stringstream.cpp:236:20:236:21 | s3 | | +| stringstream.cpp:212:22:212:23 | call to basic_string | stringstream.cpp:237:20:237:21 | s3 | | +| stringstream.cpp:212:22:212:23 | call to basic_string | stringstream.cpp:240:7:240:8 | s3 | | +| stringstream.cpp:212:26:212:27 | call to basic_string | stringstream.cpp:242:20:242:21 | s4 | | +| stringstream.cpp:212:26:212:27 | call to basic_string | stringstream.cpp:246:7:246:8 | s4 | | +| stringstream.cpp:212:30:212:31 | call to basic_string | stringstream.cpp:243:20:243:21 | s5 | | +| stringstream.cpp:212:30:212:31 | call to basic_string | stringstream.cpp:247:7:247:8 | s5 | | +| stringstream.cpp:212:34:212:35 | call to basic_string | stringstream.cpp:244:20:244:21 | s6 | | +| stringstream.cpp:212:34:212:35 | call to basic_string | stringstream.cpp:245:20:245:21 | s6 | | +| stringstream.cpp:212:34:212:35 | call to basic_string | stringstream.cpp:248:7:248:8 | s6 | | +| stringstream.cpp:212:38:212:39 | call to basic_string | stringstream.cpp:250:28:250:29 | s7 | | +| stringstream.cpp:212:38:212:39 | call to basic_string | stringstream.cpp:251:7:251:8 | s7 | | +| stringstream.cpp:212:42:212:43 | call to basic_string | stringstream.cpp:250:33:250:34 | s8 | | +| stringstream.cpp:212:42:212:43 | call to basic_string | stringstream.cpp:252:7:252:8 | s8 | | +| stringstream.cpp:214:7:214:9 | ref arg ss1 | stringstream.cpp:217:7:217:9 | ss1 | | +| stringstream.cpp:214:7:214:9 | ref arg ss1 | stringstream.cpp:222:7:222:9 | ss1 | | +| stringstream.cpp:214:7:214:9 | ref arg ss1 | stringstream.cpp:225:7:225:9 | ss1 | | +| stringstream.cpp:214:7:214:9 | ref arg ss1 | stringstream.cpp:234:15:234:17 | ss1 | | +| stringstream.cpp:214:7:214:9 | ref arg ss1 | stringstream.cpp:237:15:237:17 | ss1 | | +| stringstream.cpp:214:7:214:9 | ref arg ss1 | stringstream.cpp:242:15:242:17 | ss1 | | +| stringstream.cpp:214:7:214:9 | ref arg ss1 | stringstream.cpp:245:15:245:17 | ss1 | | +| stringstream.cpp:214:7:214:9 | ss1 | stringstream.cpp:214:11:214:17 | call to getline | | +| stringstream.cpp:214:7:214:9 | ss1 | stringstream.cpp:214:19:214:20 | ref arg b1 | TAINT | +| stringstream.cpp:214:19:214:20 | ref arg b1 | stringstream.cpp:218:7:218:8 | b1 | | +| stringstream.cpp:215:7:215:9 | ref arg ss2 | stringstream.cpp:216:7:216:9 | ss2 | | +| stringstream.cpp:215:7:215:9 | ref arg ss2 | stringstream.cpp:223:7:223:9 | ss2 | | +| stringstream.cpp:215:7:215:9 | ref arg ss2 | stringstream.cpp:224:7:224:9 | ss2 | | +| stringstream.cpp:215:7:215:9 | ref arg ss2 | stringstream.cpp:230:7:230:9 | ss2 | | +| stringstream.cpp:215:7:215:9 | ref arg ss2 | stringstream.cpp:235:15:235:17 | ss2 | | +| stringstream.cpp:215:7:215:9 | ref arg ss2 | stringstream.cpp:236:15:236:17 | ss2 | | +| stringstream.cpp:215:7:215:9 | ref arg ss2 | stringstream.cpp:243:15:243:17 | ss2 | | +| stringstream.cpp:215:7:215:9 | ref arg ss2 | stringstream.cpp:244:15:244:17 | ss2 | | +| stringstream.cpp:215:7:215:9 | ref arg ss2 | stringstream.cpp:250:23:250:25 | ss2 | | +| stringstream.cpp:215:7:215:9 | ss2 | stringstream.cpp:215:11:215:17 | call to getline | | +| stringstream.cpp:215:7:215:9 | ss2 | stringstream.cpp:215:19:215:20 | ref arg b2 | TAINT | +| stringstream.cpp:215:19:215:20 | ref arg b2 | stringstream.cpp:219:7:219:8 | b2 | | +| stringstream.cpp:216:7:216:9 | ref arg ss2 | stringstream.cpp:223:7:223:9 | ss2 | | +| stringstream.cpp:216:7:216:9 | ref arg ss2 | stringstream.cpp:224:7:224:9 | ss2 | | +| stringstream.cpp:216:7:216:9 | ref arg ss2 | stringstream.cpp:230:7:230:9 | ss2 | | +| stringstream.cpp:216:7:216:9 | ref arg ss2 | stringstream.cpp:235:15:235:17 | ss2 | | +| stringstream.cpp:216:7:216:9 | ref arg ss2 | stringstream.cpp:236:15:236:17 | ss2 | | +| stringstream.cpp:216:7:216:9 | ref arg ss2 | stringstream.cpp:243:15:243:17 | ss2 | | +| stringstream.cpp:216:7:216:9 | ref arg ss2 | stringstream.cpp:244:15:244:17 | ss2 | | +| stringstream.cpp:216:7:216:9 | ref arg ss2 | stringstream.cpp:250:23:250:25 | ss2 | | +| stringstream.cpp:216:7:216:9 | ss2 | stringstream.cpp:216:11:216:17 | call to getline | | +| stringstream.cpp:216:7:216:9 | ss2 | stringstream.cpp:216:19:216:20 | ref arg b3 | TAINT | +| stringstream.cpp:216:19:216:20 | ref arg b3 | stringstream.cpp:217:19:217:20 | b3 | | +| stringstream.cpp:216:19:216:20 | ref arg b3 | stringstream.cpp:220:7:220:8 | b3 | | +| stringstream.cpp:217:7:217:9 | ref arg ss1 | stringstream.cpp:222:7:222:9 | ss1 | | +| stringstream.cpp:217:7:217:9 | ref arg ss1 | stringstream.cpp:225:7:225:9 | ss1 | | +| stringstream.cpp:217:7:217:9 | ref arg ss1 | stringstream.cpp:234:15:234:17 | ss1 | | +| stringstream.cpp:217:7:217:9 | ref arg ss1 | stringstream.cpp:237:15:237:17 | ss1 | | +| stringstream.cpp:217:7:217:9 | ref arg ss1 | stringstream.cpp:242:15:242:17 | ss1 | | +| stringstream.cpp:217:7:217:9 | ref arg ss1 | stringstream.cpp:245:15:245:17 | ss1 | | +| stringstream.cpp:217:7:217:9 | ss1 | stringstream.cpp:217:11:217:17 | call to getline | | +| stringstream.cpp:217:7:217:9 | ss1 | stringstream.cpp:217:19:217:20 | ref arg b3 | TAINT | +| stringstream.cpp:217:19:217:20 | ref arg b3 | stringstream.cpp:220:7:220:8 | b3 | | +| stringstream.cpp:218:7:218:8 | b1 | stringstream.cpp:218:7:218:8 | call to basic_string | TAINT | +| stringstream.cpp:219:7:219:8 | b2 | stringstream.cpp:219:7:219:8 | call to basic_string | TAINT | +| stringstream.cpp:220:7:220:8 | b3 | stringstream.cpp:220:7:220:8 | call to basic_string | TAINT | +| stringstream.cpp:222:7:222:9 | ref arg ss1 | stringstream.cpp:225:7:225:9 | ss1 | | +| stringstream.cpp:222:7:222:9 | ref arg ss1 | stringstream.cpp:234:15:234:17 | ss1 | | +| stringstream.cpp:222:7:222:9 | ref arg ss1 | stringstream.cpp:237:15:237:17 | ss1 | | +| stringstream.cpp:222:7:222:9 | ref arg ss1 | stringstream.cpp:242:15:242:17 | ss1 | | +| stringstream.cpp:222:7:222:9 | ref arg ss1 | stringstream.cpp:245:15:245:17 | ss1 | | +| stringstream.cpp:222:7:222:9 | ss1 | stringstream.cpp:222:11:222:17 | call to getline | | +| stringstream.cpp:222:7:222:9 | ss1 | stringstream.cpp:222:19:222:20 | ref arg b4 | TAINT | +| stringstream.cpp:222:19:222:20 | ref arg b4 | stringstream.cpp:226:7:226:8 | b4 | | +| stringstream.cpp:223:7:223:9 | ref arg ss2 | stringstream.cpp:224:7:224:9 | ss2 | | +| stringstream.cpp:223:7:223:9 | ref arg ss2 | stringstream.cpp:230:7:230:9 | ss2 | | +| stringstream.cpp:223:7:223:9 | ref arg ss2 | stringstream.cpp:235:15:235:17 | ss2 | | +| stringstream.cpp:223:7:223:9 | ref arg ss2 | stringstream.cpp:236:15:236:17 | ss2 | | +| stringstream.cpp:223:7:223:9 | ref arg ss2 | stringstream.cpp:243:15:243:17 | ss2 | | +| stringstream.cpp:223:7:223:9 | ref arg ss2 | stringstream.cpp:244:15:244:17 | ss2 | | +| stringstream.cpp:223:7:223:9 | ref arg ss2 | stringstream.cpp:250:23:250:25 | ss2 | | +| stringstream.cpp:223:7:223:9 | ss2 | stringstream.cpp:223:11:223:17 | call to getline | | +| stringstream.cpp:223:7:223:9 | ss2 | stringstream.cpp:223:19:223:20 | ref arg b5 | TAINT | +| stringstream.cpp:223:19:223:20 | ref arg b5 | stringstream.cpp:227:7:227:8 | b5 | | +| stringstream.cpp:224:7:224:9 | ref arg ss2 | stringstream.cpp:230:7:230:9 | ss2 | | +| stringstream.cpp:224:7:224:9 | ref arg ss2 | stringstream.cpp:235:15:235:17 | ss2 | | +| stringstream.cpp:224:7:224:9 | ref arg ss2 | stringstream.cpp:236:15:236:17 | ss2 | | +| stringstream.cpp:224:7:224:9 | ref arg ss2 | stringstream.cpp:243:15:243:17 | ss2 | | +| stringstream.cpp:224:7:224:9 | ref arg ss2 | stringstream.cpp:244:15:244:17 | ss2 | | +| stringstream.cpp:224:7:224:9 | ref arg ss2 | stringstream.cpp:250:23:250:25 | ss2 | | +| stringstream.cpp:224:7:224:9 | ss2 | stringstream.cpp:224:11:224:17 | call to getline | | +| stringstream.cpp:224:7:224:9 | ss2 | stringstream.cpp:224:19:224:20 | ref arg b6 | TAINT | +| stringstream.cpp:224:19:224:20 | ref arg b6 | stringstream.cpp:225:19:225:20 | b6 | | +| stringstream.cpp:224:19:224:20 | ref arg b6 | stringstream.cpp:228:7:228:8 | b6 | | +| stringstream.cpp:225:7:225:9 | ref arg ss1 | stringstream.cpp:234:15:234:17 | ss1 | | +| stringstream.cpp:225:7:225:9 | ref arg ss1 | stringstream.cpp:237:15:237:17 | ss1 | | +| stringstream.cpp:225:7:225:9 | ref arg ss1 | stringstream.cpp:242:15:242:17 | ss1 | | +| stringstream.cpp:225:7:225:9 | ref arg ss1 | stringstream.cpp:245:15:245:17 | ss1 | | +| stringstream.cpp:225:7:225:9 | ss1 | stringstream.cpp:225:11:225:17 | call to getline | | +| stringstream.cpp:225:7:225:9 | ss1 | stringstream.cpp:225:19:225:20 | ref arg b6 | TAINT | +| stringstream.cpp:225:19:225:20 | ref arg b6 | stringstream.cpp:228:7:228:8 | b6 | | +| stringstream.cpp:226:7:226:8 | b4 | stringstream.cpp:226:7:226:8 | call to basic_string | TAINT | +| stringstream.cpp:227:7:227:8 | b5 | stringstream.cpp:227:7:227:8 | call to basic_string | TAINT | +| stringstream.cpp:228:7:228:8 | b6 | stringstream.cpp:228:7:228:8 | call to basic_string | TAINT | +| stringstream.cpp:230:7:230:9 | ref arg ss2 | stringstream.cpp:235:15:235:17 | ss2 | | +| stringstream.cpp:230:7:230:9 | ref arg ss2 | stringstream.cpp:236:15:236:17 | ss2 | | +| stringstream.cpp:230:7:230:9 | ref arg ss2 | stringstream.cpp:243:15:243:17 | ss2 | | +| stringstream.cpp:230:7:230:9 | ref arg ss2 | stringstream.cpp:244:15:244:17 | ss2 | | +| stringstream.cpp:230:7:230:9 | ref arg ss2 | stringstream.cpp:250:23:250:25 | ss2 | | +| stringstream.cpp:230:7:230:9 | ss2 | stringstream.cpp:230:11:230:17 | call to getline | | +| stringstream.cpp:230:7:230:9 | ss2 | stringstream.cpp:230:19:230:20 | ref arg b7 | TAINT | +| stringstream.cpp:230:11:230:17 | call to getline | stringstream.cpp:230:29:230:35 | call to getline | | +| stringstream.cpp:230:11:230:17 | call to getline | stringstream.cpp:230:37:230:38 | ref arg b8 | TAINT | +| stringstream.cpp:230:11:230:17 | ref arg call to getline | stringstream.cpp:230:7:230:9 | ref arg ss2 | TAINT | +| stringstream.cpp:230:19:230:20 | ref arg b7 | stringstream.cpp:231:7:231:8 | b7 | | +| stringstream.cpp:230:37:230:38 | ref arg b8 | stringstream.cpp:232:7:232:8 | b8 | | +| stringstream.cpp:231:7:231:8 | b7 | stringstream.cpp:231:7:231:8 | call to basic_string | TAINT | +| stringstream.cpp:232:7:232:8 | b8 | stringstream.cpp:232:7:232:8 | call to basic_string | TAINT | +| stringstream.cpp:234:15:234:17 | ref arg ss1 | stringstream.cpp:237:15:237:17 | ss1 | | +| stringstream.cpp:234:15:234:17 | ref arg ss1 | stringstream.cpp:242:15:242:17 | ss1 | | +| stringstream.cpp:234:15:234:17 | ref arg ss1 | stringstream.cpp:245:15:245:17 | ss1 | | +| stringstream.cpp:234:15:234:17 | ss1 | stringstream.cpp:234:7:234:13 | call to getline | | +| stringstream.cpp:234:15:234:17 | ss1 | stringstream.cpp:234:20:234:21 | ref arg s1 | TAINT | +| stringstream.cpp:234:20:234:21 | ref arg s1 | stringstream.cpp:238:7:238:8 | s1 | | +| stringstream.cpp:235:15:235:17 | ref arg ss2 | stringstream.cpp:236:15:236:17 | ss2 | | +| stringstream.cpp:235:15:235:17 | ref arg ss2 | stringstream.cpp:243:15:243:17 | ss2 | | +| stringstream.cpp:235:15:235:17 | ref arg ss2 | stringstream.cpp:244:15:244:17 | ss2 | | +| stringstream.cpp:235:15:235:17 | ref arg ss2 | stringstream.cpp:250:23:250:25 | ss2 | | +| stringstream.cpp:235:15:235:17 | ss2 | stringstream.cpp:235:7:235:13 | call to getline | | +| stringstream.cpp:235:15:235:17 | ss2 | stringstream.cpp:235:20:235:21 | ref arg s2 | TAINT | +| stringstream.cpp:235:20:235:21 | ref arg s2 | stringstream.cpp:239:7:239:8 | s2 | | +| stringstream.cpp:236:15:236:17 | ref arg ss2 | stringstream.cpp:243:15:243:17 | ss2 | | +| stringstream.cpp:236:15:236:17 | ref arg ss2 | stringstream.cpp:244:15:244:17 | ss2 | | +| stringstream.cpp:236:15:236:17 | ref arg ss2 | stringstream.cpp:250:23:250:25 | ss2 | | +| stringstream.cpp:236:15:236:17 | ss2 | stringstream.cpp:236:7:236:13 | call to getline | | +| stringstream.cpp:236:15:236:17 | ss2 | stringstream.cpp:236:20:236:21 | ref arg s3 | TAINT | +| stringstream.cpp:236:20:236:21 | ref arg s3 | stringstream.cpp:237:20:237:21 | s3 | | +| stringstream.cpp:236:20:236:21 | ref arg s3 | stringstream.cpp:240:7:240:8 | s3 | | +| stringstream.cpp:237:15:237:17 | ref arg ss1 | stringstream.cpp:242:15:242:17 | ss1 | | +| stringstream.cpp:237:15:237:17 | ref arg ss1 | stringstream.cpp:245:15:245:17 | ss1 | | +| stringstream.cpp:237:15:237:17 | ss1 | stringstream.cpp:237:7:237:13 | call to getline | | +| stringstream.cpp:237:15:237:17 | ss1 | stringstream.cpp:237:20:237:21 | ref arg s3 | TAINT | +| stringstream.cpp:237:20:237:21 | ref arg s3 | stringstream.cpp:240:7:240:8 | s3 | | +| stringstream.cpp:242:15:242:17 | ref arg ss1 | stringstream.cpp:245:15:245:17 | ss1 | | +| stringstream.cpp:242:15:242:17 | ss1 | stringstream.cpp:242:7:242:13 | call to getline | | +| stringstream.cpp:242:15:242:17 | ss1 | stringstream.cpp:242:20:242:21 | ref arg s4 | TAINT | +| stringstream.cpp:242:20:242:21 | ref arg s4 | stringstream.cpp:246:7:246:8 | s4 | | +| stringstream.cpp:243:15:243:17 | ref arg ss2 | stringstream.cpp:244:15:244:17 | ss2 | | +| stringstream.cpp:243:15:243:17 | ref arg ss2 | stringstream.cpp:250:23:250:25 | ss2 | | +| stringstream.cpp:243:15:243:17 | ss2 | stringstream.cpp:243:7:243:13 | call to getline | | +| stringstream.cpp:243:15:243:17 | ss2 | stringstream.cpp:243:20:243:21 | ref arg s5 | TAINT | +| stringstream.cpp:243:20:243:21 | ref arg s5 | stringstream.cpp:247:7:247:8 | s5 | | +| stringstream.cpp:244:15:244:17 | ref arg ss2 | stringstream.cpp:250:23:250:25 | ss2 | | +| stringstream.cpp:244:15:244:17 | ss2 | stringstream.cpp:244:7:244:13 | call to getline | | +| stringstream.cpp:244:15:244:17 | ss2 | stringstream.cpp:244:20:244:21 | ref arg s6 | TAINT | +| stringstream.cpp:244:20:244:21 | ref arg s6 | stringstream.cpp:245:20:245:21 | s6 | | +| stringstream.cpp:244:20:244:21 | ref arg s6 | stringstream.cpp:248:7:248:8 | s6 | | +| stringstream.cpp:245:15:245:17 | ss1 | stringstream.cpp:245:7:245:13 | call to getline | | +| stringstream.cpp:245:15:245:17 | ss1 | stringstream.cpp:245:20:245:21 | ref arg s6 | TAINT | +| stringstream.cpp:245:20:245:21 | ref arg s6 | stringstream.cpp:248:7:248:8 | s6 | | +| stringstream.cpp:250:15:250:21 | call to getline | stringstream.cpp:250:7:250:13 | call to getline | | +| stringstream.cpp:250:15:250:21 | call to getline | stringstream.cpp:250:33:250:34 | ref arg s8 | TAINT | +| stringstream.cpp:250:15:250:21 | ref arg call to getline | stringstream.cpp:250:23:250:25 | ref arg ss2 | TAINT | +| stringstream.cpp:250:23:250:25 | ss2 | stringstream.cpp:250:15:250:21 | call to getline | | +| stringstream.cpp:250:23:250:25 | ss2 | stringstream.cpp:250:28:250:29 | ref arg s7 | TAINT | +| stringstream.cpp:250:28:250:29 | ref arg s7 | stringstream.cpp:251:7:251:8 | s7 | | +| stringstream.cpp:250:33:250:34 | ref arg s8 | stringstream.cpp:252:7:252:8 | s8 | | +| stringstream.cpp:257:24:257:29 | call to source | stringstream.cpp:257:24:257:31 | call to basic_string | TAINT | +| stringstream.cpp:257:24:257:31 | call to basic_string | stringstream.cpp:257:24:257:32 | call to basic_stringstream | TAINT | +| stringstream.cpp:257:24:257:32 | call to basic_stringstream | stringstream.cpp:262:7:262:9 | ss1 | | +| stringstream.cpp:258:20:258:22 | call to basic_stringstream | stringstream.cpp:266:7:266:9 | ss2 | | +| stringstream.cpp:258:20:258:22 | call to basic_stringstream | stringstream.cpp:267:7:267:9 | ss2 | | +| stringstream.cpp:259:17:259:20 | {...} | stringstream.cpp:262:15:262:16 | b1 | | +| stringstream.cpp:259:17:259:20 | {...} | stringstream.cpp:263:7:263:8 | b1 | | +| stringstream.cpp:259:19:259:19 | 0 | stringstream.cpp:259:17:259:20 | {...} | TAINT | +| stringstream.cpp:260:17:260:20 | {...} | stringstream.cpp:262:36:262:37 | b2 | | +| stringstream.cpp:260:17:260:20 | {...} | stringstream.cpp:264:7:264:8 | b2 | | +| stringstream.cpp:260:19:260:19 | 0 | stringstream.cpp:260:17:260:20 | {...} | TAINT | +| stringstream.cpp:262:7:262:9 | ss1 | stringstream.cpp:262:11:262:13 | call to get | | +| stringstream.cpp:262:7:262:9 | ss1 | stringstream.cpp:262:15:262:16 | ref arg b1 | TAINT | +| stringstream.cpp:262:11:262:13 | call to get | stringstream.cpp:262:24:262:28 | call to unget | | +| stringstream.cpp:262:11:262:13 | ref arg call to get | stringstream.cpp:262:7:262:9 | ref arg ss1 | TAINT | +| stringstream.cpp:262:15:262:16 | ref arg b1 | stringstream.cpp:263:7:263:8 | b1 | | +| stringstream.cpp:262:24:262:28 | call to unget | stringstream.cpp:262:32:262:34 | call to get | | +| stringstream.cpp:262:24:262:28 | call to unget | stringstream.cpp:262:36:262:37 | ref arg b2 | TAINT | +| stringstream.cpp:262:24:262:28 | ref arg call to unget | stringstream.cpp:262:11:262:13 | ref arg call to get | TAINT | +| stringstream.cpp:262:36:262:37 | ref arg b2 | stringstream.cpp:264:7:264:8 | b2 | | +| stringstream.cpp:263:7:263:8 | b1 | stringstream.cpp:263:7:263:8 | call to basic_string | TAINT | +| stringstream.cpp:264:7:264:8 | b2 | stringstream.cpp:264:7:264:8 | call to basic_string | TAINT | +| stringstream.cpp:266:7:266:9 | ref arg ss2 | stringstream.cpp:267:7:267:9 | ss2 | | +| stringstream.cpp:266:7:266:9 | ss2 | stringstream.cpp:266:11:266:15 | call to write | | +| stringstream.cpp:266:11:266:15 | call to write | stringstream.cpp:266:27:266:31 | call to flush | | +| stringstream.cpp:266:11:266:15 | ref arg call to write | stringstream.cpp:266:7:266:9 | ref arg ss2 | TAINT | +| stringstream.cpp:266:17:266:21 | abc | stringstream.cpp:266:7:266:9 | ref arg ss2 | TAINT | +| stringstream.cpp:266:17:266:21 | abc | stringstream.cpp:266:11:266:15 | call to write | TAINT | +| stringstream.cpp:266:27:266:31 | call to flush | stringstream.cpp:266:35:266:39 | call to write | | +| stringstream.cpp:266:27:266:31 | ref arg call to flush | stringstream.cpp:266:11:266:15 | ref arg call to write | TAINT | +| stringstream.cpp:266:35:266:39 | call to write | stringstream.cpp:266:54:266:58 | call to flush | | +| stringstream.cpp:266:35:266:39 | ref arg call to write | stringstream.cpp:266:27:266:31 | ref arg call to flush | TAINT | +| stringstream.cpp:266:41:266:46 | call to source | stringstream.cpp:266:27:266:31 | ref arg call to flush | TAINT | +| stringstream.cpp:266:41:266:46 | call to source | stringstream.cpp:266:35:266:39 | call to write | TAINT | +| stringstream.cpp:266:54:266:58 | call to flush | stringstream.cpp:266:62:266:66 | call to write | | +| stringstream.cpp:266:54:266:58 | ref arg call to flush | stringstream.cpp:266:35:266:39 | ref arg call to write | TAINT | +| stringstream.cpp:266:68:266:72 | xyz | stringstream.cpp:266:54:266:58 | ref arg call to flush | TAINT | +| stringstream.cpp:266:68:266:72 | xyz | stringstream.cpp:266:62:266:66 | call to write | TAINT | +| structlikeclass.cpp:5:7:5:7 | Unknown literal | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT | +| structlikeclass.cpp:5:7:5:7 | Unknown literal | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT | +| structlikeclass.cpp:5:7:5:7 | this | structlikeclass.cpp:5:7:5:7 | constructor init of field v [pre-this] | | +| structlikeclass.cpp:5:7:5:7 | this | structlikeclass.cpp:5:7:5:7 | constructor init of field v [pre-this] | | +| structlikeclass.cpp:8:2:8:16 | this | structlikeclass.cpp:8:28:8:32 | constructor init of field v [pre-this] | | +| structlikeclass.cpp:8:22:8:23 | _v | structlikeclass.cpp:8:30:8:31 | _v | | +| structlikeclass.cpp:8:30:8:31 | _v | structlikeclass.cpp:8:28:8:32 | constructor init of field v | TAINT | +| structlikeclass.cpp:16:22:16:22 | 1 | structlikeclass.cpp:16:22:16:23 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:16:22:16:23 | call to StructLikeClass | structlikeclass.cpp:18:22:18:23 | s1 | | +| structlikeclass.cpp:16:22:16:23 | call to StructLikeClass | structlikeclass.cpp:22:8:22:9 | s1 | | +| structlikeclass.cpp:17:23:17:24 | call to StructLikeClass | structlikeclass.cpp:23:8:23:9 | s2 | | +| structlikeclass.cpp:17:24:17:24 | 1 | structlikeclass.cpp:17:23:17:24 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:18:22:18:23 | s1 | structlikeclass.cpp:24:8:24:9 | s3 | | +| structlikeclass.cpp:20:8:20:8 | 1 | structlikeclass.cpp:20:8:20:8 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:20:8:20:8 | call to StructLikeClass | structlikeclass.cpp:20:3:20:8 | ... = ... | | +| structlikeclass.cpp:20:8:20:8 | call to StructLikeClass | structlikeclass.cpp:25:8:25:9 | s4 | | +| structlikeclass.cpp:29:22:29:27 | call to source | structlikeclass.cpp:29:22:29:30 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:29:22:29:30 | call to StructLikeClass | structlikeclass.cpp:31:22:31:23 | s1 | | +| structlikeclass.cpp:29:22:29:30 | call to StructLikeClass | structlikeclass.cpp:35:8:35:9 | s1 | | +| structlikeclass.cpp:30:23:30:31 | call to StructLikeClass | structlikeclass.cpp:36:8:36:9 | s2 | | +| structlikeclass.cpp:30:24:30:29 | call to source | structlikeclass.cpp:30:23:30:31 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:31:22:31:23 | s1 | structlikeclass.cpp:37:8:37:9 | s3 | | +| structlikeclass.cpp:33:8:33:13 | call to source | structlikeclass.cpp:33:8:33:15 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:33:8:33:15 | call to StructLikeClass | structlikeclass.cpp:33:3:33:15 | ... = ... | | +| structlikeclass.cpp:33:8:33:15 | call to StructLikeClass | structlikeclass.cpp:38:8:38:9 | s4 | | +| structlikeclass.cpp:42:19:42:20 | call to StructLikeClass | structlikeclass.cpp:43:24:43:25 | s1 | | +| structlikeclass.cpp:42:19:42:20 | call to StructLikeClass | structlikeclass.cpp:44:22:44:23 | s1 | | +| structlikeclass.cpp:42:19:42:20 | call to StructLikeClass | structlikeclass.cpp:46:8:46:9 | s1 | | +| structlikeclass.cpp:42:19:42:20 | call to StructLikeClass | structlikeclass.cpp:48:8:48:9 | s1 | | +| structlikeclass.cpp:43:24:43:25 | s1 | structlikeclass.cpp:49:8:49:9 | s2 | | +| structlikeclass.cpp:44:22:44:23 | s1 | structlikeclass.cpp:50:8:50:9 | s3 | | +| structlikeclass.cpp:46:8:46:9 | s1 | structlikeclass.cpp:46:3:46:9 | ... = ... | | +| structlikeclass.cpp:46:8:46:9 | s1 | structlikeclass.cpp:51:8:51:9 | s4 | | +| structlikeclass.cpp:55:23:55:48 | call to StructLikeClass | structlikeclass.cpp:60:8:60:9 | s1 | | +| structlikeclass.cpp:55:40:55:45 | call to source | structlikeclass.cpp:55:23:55:48 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:58:8:58:32 | call to StructLikeClass | structlikeclass.cpp:58:3:58:32 | ... = ... | | +| structlikeclass.cpp:58:8:58:32 | call to StructLikeClass | structlikeclass.cpp:61:8:61:9 | s2 | | +| structlikeclass.cpp:58:24:58:29 | call to source | structlikeclass.cpp:58:8:58:32 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:62:8:62:9 | s3 | structlikeclass.cpp:62:8:62:20 | ... = ... | | +| structlikeclass.cpp:62:13:62:18 | call to source | structlikeclass.cpp:62:13:62:20 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:62:13:62:20 | call to StructLikeClass | structlikeclass.cpp:62:8:62:20 | ... = ... | | +| swap1.cpp:14:17:14:17 | t | swap1.cpp:14:17:14:17 | t | | +| swap1.cpp:14:17:14:17 | t | swap1.cpp:14:17:14:17 | t | | +| swap1.cpp:14:17:14:17 | t | swap1.cpp:14:56:14:56 | t | | +| swap1.cpp:14:17:14:17 | t | swap1.cpp:14:56:14:56 | t | | +| swap1.cpp:24:9:24:13 | this | swap1.cpp:24:31:24:34 | this | | +| swap1.cpp:24:23:24:26 | that | swap1.cpp:24:23:24:26 | that | | +| swap1.cpp:24:23:24:26 | that | swap1.cpp:24:36:24:39 | that | | +| swap1.cpp:24:36:24:39 | ref arg that | swap1.cpp:24:23:24:26 | that | | +| swap1.cpp:25:9:25:13 | this | swap1.cpp:25:36:25:52 | constructor init of field data1 [pre-this] | | +| swap1.cpp:25:28:25:31 | that | swap1.cpp:25:42:25:45 | that | | +| swap1.cpp:25:47:25:51 | data1 | swap1.cpp:25:36:25:52 | constructor init of field data1 | TAINT | +| swap1.cpp:25:47:25:51 | data1 | swap1.cpp:25:47:25:51 | data1 | | +| swap1.cpp:27:16:27:24 | this | swap1.cpp:30:13:30:16 | this | | +| swap1.cpp:27:39:27:42 | that | swap1.cpp:29:24:29:27 | that | | +| swap1.cpp:29:23:29:27 | call to Class | swap1.cpp:30:18:30:20 | tmp | | +| swap1.cpp:29:24:29:27 | that | swap1.cpp:29:23:29:27 | call to Class | | +| swap1.cpp:30:13:30:16 | ref arg this | swap1.cpp:31:21:31:24 | this | | +| swap1.cpp:30:13:30:16 | this | swap1.cpp:31:21:31:24 | this | | +| swap1.cpp:31:21:31:24 | this | swap1.cpp:31:20:31:24 | * ... | TAINT | +| swap1.cpp:34:16:34:24 | this | swap1.cpp:36:13:36:16 | this | | +| swap1.cpp:34:34:34:37 | that | swap1.cpp:34:34:34:37 | that | | +| swap1.cpp:34:34:34:37 | that | swap1.cpp:36:18:36:21 | that | | +| swap1.cpp:36:13:36:16 | ref arg this | swap1.cpp:37:21:37:24 | this | | +| swap1.cpp:36:13:36:16 | this | swap1.cpp:37:21:37:24 | this | | +| swap1.cpp:36:18:36:21 | ref arg that | swap1.cpp:34:34:34:37 | that | | +| swap1.cpp:37:21:37:24 | this | swap1.cpp:37:20:37:24 | * ... | TAINT | +| swap1.cpp:40:16:40:26 | this | swap1.cpp:43:13:43:16 | this | | +| swap1.cpp:40:41:40:44 | that | swap1.cpp:42:24:42:27 | that | | +| swap1.cpp:42:23:42:27 | call to Class | swap1.cpp:43:18:43:20 | tmp | | +| swap1.cpp:42:24:42:27 | that | swap1.cpp:42:23:42:27 | call to Class | | +| swap1.cpp:43:13:43:16 | ref arg this | swap1.cpp:44:21:44:24 | this | | +| swap1.cpp:43:13:43:16 | this | swap1.cpp:44:21:44:24 | this | | +| swap1.cpp:44:21:44:24 | this | swap1.cpp:44:20:44:24 | * ... | TAINT | +| swap1.cpp:47:16:47:26 | this | swap1.cpp:49:13:49:16 | this | | +| swap1.cpp:47:36:47:39 | that | swap1.cpp:47:36:47:39 | that | | +| swap1.cpp:47:36:47:39 | that | swap1.cpp:49:18:49:21 | that | | +| swap1.cpp:49:13:49:16 | ref arg this | swap1.cpp:50:21:50:24 | this | | +| swap1.cpp:49:13:49:16 | this | swap1.cpp:50:21:50:24 | this | | +| swap1.cpp:49:18:49:21 | ref arg that | swap1.cpp:47:36:47:39 | that | | +| swap1.cpp:50:21:50:24 | this | swap1.cpp:50:20:50:24 | * ... | TAINT | +| swap1.cpp:53:14:53:17 | this | swap1.cpp:56:18:56:22 | this | | +| swap1.cpp:53:26:53:29 | that | swap1.cpp:53:26:53:29 | that | | +| swap1.cpp:53:26:53:29 | that | swap1.cpp:56:25:56:28 | that | | +| swap1.cpp:56:18:56:22 | data1 | swap1.cpp:56:30:56:34 | ref arg data1 | | +| swap1.cpp:56:25:56:28 | that | swap1.cpp:56:18:56:22 | ref arg data1 | | +| swap1.cpp:56:25:56:28 | that [post update] | swap1.cpp:53:26:53:29 | that | | +| swap1.cpp:56:30:56:34 | data1 | swap1.cpp:56:18:56:22 | ref arg data1 | | +| swap1.cpp:61:22:61:22 | x | swap1.cpp:61:22:61:22 | x | | +| swap1.cpp:61:22:61:22 | x | swap1.cpp:63:9:63:9 | x | | +| swap1.cpp:61:22:61:22 | x | swap2.cpp:61:22:61:22 | x | | +| swap1.cpp:61:22:61:22 | x | swap2.cpp:63:9:63:9 | x | | +| swap1.cpp:61:32:61:32 | y | swap1.cpp:61:32:61:32 | y | | +| swap1.cpp:61:32:61:32 | y | swap1.cpp:63:16:63:16 | y | | +| swap1.cpp:61:32:61:32 | y | swap2.cpp:61:32:61:32 | y | | +| swap1.cpp:61:32:61:32 | y | swap2.cpp:63:16:63:16 | y | | +| swap1.cpp:63:9:63:9 | ref arg x | swap1.cpp:61:22:61:22 | x | | +| swap1.cpp:63:9:63:9 | ref arg x | swap2.cpp:61:22:61:22 | x | | +| swap1.cpp:63:16:63:16 | ref arg y | swap1.cpp:61:32:61:32 | y | | +| swap1.cpp:63:16:63:16 | ref arg y | swap2.cpp:61:32:61:32 | y | | +| swap1.cpp:69:23:69:23 | x | swap1.cpp:71:5:71:5 | x | | +| swap1.cpp:69:23:69:23 | x | swap1.cpp:73:10:73:10 | x | | +| swap1.cpp:69:23:69:23 | x | swap1.cpp:76:9:76:9 | x | | +| swap1.cpp:69:23:69:23 | x | swap1.cpp:79:10:79:10 | x | | +| swap1.cpp:70:23:70:23 | y | swap1.cpp:74:10:74:10 | y | | +| swap1.cpp:70:23:70:23 | y | swap1.cpp:76:5:76:5 | y | | +| swap1.cpp:70:23:70:23 | y | swap1.cpp:78:10:78:10 | y | | +| swap1.cpp:71:5:71:5 | x [post update] | swap1.cpp:73:10:73:10 | x | | +| swap1.cpp:71:5:71:5 | x [post update] | swap1.cpp:76:9:76:9 | x | | +| swap1.cpp:71:5:71:5 | x [post update] | swap1.cpp:79:10:79:10 | x | | +| swap1.cpp:71:5:71:22 | ... = ... | swap1.cpp:71:7:71:11 | data1 [post update] | | +| swap1.cpp:71:5:71:22 | ... = ... | swap1.cpp:73:12:73:16 | data1 | | +| swap1.cpp:71:5:71:22 | ... = ... | swap1.cpp:79:12:79:16 | data1 | | +| swap1.cpp:71:15:71:20 | call to source | swap1.cpp:71:5:71:22 | ... = ... | | +| swap1.cpp:76:5:76:5 | ref arg y | swap1.cpp:78:10:78:10 | y | | +| swap1.cpp:76:9:76:9 | x | swap1.cpp:76:5:76:5 | ref arg y | TAINT | +| swap1.cpp:76:9:76:9 | x | swap1.cpp:76:7:76:7 | call to operator= | TAINT | +| swap1.cpp:81:23:81:24 | z1 | swap1.cpp:82:5:82:6 | z1 | | +| swap1.cpp:81:23:81:24 | z1 | swap1.cpp:83:10:83:11 | z1 | | +| swap1.cpp:81:23:81:24 | z1 | swap1.cpp:85:10:85:11 | z1 | | +| swap1.cpp:81:23:81:24 | z1 | swap1.cpp:88:10:88:11 | z1 | | +| swap1.cpp:81:27:81:28 | z2 | swap1.cpp:85:14:85:15 | z2 | | +| swap1.cpp:81:27:81:28 | z2 | swap1.cpp:87:10:87:11 | z2 | | +| swap1.cpp:82:5:82:6 | z1 [post update] | swap1.cpp:83:10:83:11 | z1 | | +| swap1.cpp:82:5:82:6 | z1 [post update] | swap1.cpp:85:10:85:11 | z1 | | +| swap1.cpp:82:5:82:6 | z1 [post update] | swap1.cpp:88:10:88:11 | z1 | | +| swap1.cpp:82:5:82:23 | ... = ... | swap1.cpp:82:8:82:12 | data1 [post update] | | +| swap1.cpp:82:5:82:23 | ... = ... | swap1.cpp:83:13:83:17 | data1 | | +| swap1.cpp:82:5:82:23 | ... = ... | swap1.cpp:88:13:88:17 | data1 | | +| swap1.cpp:82:16:82:21 | call to source | swap1.cpp:82:5:82:23 | ... = ... | | +| swap1.cpp:85:10:85:11 | ref arg z1 | swap1.cpp:88:10:88:11 | z1 | | +| swap1.cpp:85:14:85:15 | ref arg z2 | swap1.cpp:87:10:87:11 | z2 | | +| swap1.cpp:93:23:93:23 | x | swap1.cpp:95:5:95:5 | x | | +| swap1.cpp:93:23:93:23 | x | swap1.cpp:97:10:97:10 | x | | +| swap1.cpp:93:23:93:23 | x | swap1.cpp:100:19:100:19 | x | | +| swap1.cpp:93:23:93:23 | x | swap1.cpp:103:10:103:10 | x | | +| swap1.cpp:94:23:94:23 | y | swap1.cpp:98:10:98:10 | y | | +| swap1.cpp:94:23:94:23 | y | swap1.cpp:100:5:100:5 | y | | +| swap1.cpp:94:23:94:23 | y | swap1.cpp:102:10:102:10 | y | | +| swap1.cpp:95:5:95:5 | x [post update] | swap1.cpp:97:10:97:10 | x | | +| swap1.cpp:95:5:95:5 | x [post update] | swap1.cpp:100:19:100:19 | x | | +| swap1.cpp:95:5:95:5 | x [post update] | swap1.cpp:103:10:103:10 | x | | +| swap1.cpp:95:5:95:22 | ... = ... | swap1.cpp:95:7:95:11 | data1 [post update] | | +| swap1.cpp:95:5:95:22 | ... = ... | swap1.cpp:97:12:97:16 | data1 | | +| swap1.cpp:95:5:95:22 | ... = ... | swap1.cpp:103:12:103:16 | data1 | | +| swap1.cpp:95:15:95:20 | call to source | swap1.cpp:95:5:95:22 | ... = ... | | +| swap1.cpp:100:5:100:5 | ref arg y | swap1.cpp:102:10:102:10 | y | | +| swap1.cpp:100:9:100:17 | call to move | swap1.cpp:100:5:100:5 | ref arg y | TAINT | +| swap1.cpp:100:9:100:17 | call to move | swap1.cpp:100:7:100:7 | call to operator= | TAINT | +| swap1.cpp:100:9:100:17 | ref arg call to move | swap1.cpp:100:19:100:19 | x [inner post update] | | +| swap1.cpp:100:9:100:17 | ref arg call to move | swap1.cpp:103:10:103:10 | x | | +| swap1.cpp:100:19:100:19 | x | swap1.cpp:100:5:100:5 | ref arg y | TAINT | +| swap1.cpp:100:19:100:19 | x | swap1.cpp:100:7:100:7 | call to operator= | TAINT | +| swap1.cpp:100:19:100:19 | x | swap1.cpp:100:9:100:17 | call to move | | +| swap1.cpp:108:23:108:31 | move_from | swap1.cpp:109:5:109:13 | move_from | | +| swap1.cpp:108:23:108:31 | move_from | swap1.cpp:111:10:111:18 | move_from | | +| swap1.cpp:108:23:108:31 | move_from | swap1.cpp:113:41:113:49 | move_from | | +| swap1.cpp:109:5:109:13 | move_from [post update] | swap1.cpp:111:10:111:18 | move_from | | +| swap1.cpp:109:5:109:13 | move_from [post update] | swap1.cpp:113:41:113:49 | move_from | | +| swap1.cpp:109:5:109:30 | ... = ... | swap1.cpp:109:15:109:19 | data1 [post update] | | +| swap1.cpp:109:5:109:30 | ... = ... | swap1.cpp:111:20:111:24 | data1 | | +| swap1.cpp:109:5:109:30 | ... = ... | swap1.cpp:115:18:115:22 | data1 | | +| swap1.cpp:109:23:109:28 | call to source | swap1.cpp:109:5:109:30 | ... = ... | | +| swap1.cpp:113:31:113:39 | call to move | swap1.cpp:113:31:113:51 | call to Class | | +| swap1.cpp:113:31:113:39 | ref arg call to move | swap1.cpp:113:41:113:49 | move_from [inner post update] | | +| swap1.cpp:113:31:113:51 | call to Class | swap1.cpp:115:10:115:16 | move_to | | +| swap1.cpp:113:41:113:49 | move_from | swap1.cpp:113:31:113:39 | call to move | | +| swap1.cpp:120:23:120:23 | x | swap1.cpp:122:5:122:5 | x | | +| swap1.cpp:120:23:120:23 | x | swap1.cpp:124:10:124:10 | x | | +| swap1.cpp:120:23:120:23 | x | swap1.cpp:127:19:127:19 | x | | +| swap1.cpp:120:23:120:23 | x | swap1.cpp:130:10:130:10 | x | | +| swap1.cpp:121:23:121:23 | y | swap1.cpp:125:10:125:10 | y | | +| swap1.cpp:121:23:121:23 | y | swap1.cpp:127:5:127:5 | y | | +| swap1.cpp:121:23:121:23 | y | swap1.cpp:129:10:129:10 | y | | +| swap1.cpp:122:5:122:5 | x [post update] | swap1.cpp:124:10:124:10 | x | | +| swap1.cpp:122:5:122:5 | x [post update] | swap1.cpp:127:19:127:19 | x | | +| swap1.cpp:122:5:122:5 | x [post update] | swap1.cpp:130:10:130:10 | x | | +| swap1.cpp:122:5:122:22 | ... = ... | swap1.cpp:122:7:122:11 | data1 [post update] | | +| swap1.cpp:122:5:122:22 | ... = ... | swap1.cpp:124:12:124:16 | data1 | | +| swap1.cpp:122:5:122:22 | ... = ... | swap1.cpp:130:12:130:16 | data1 | | +| swap1.cpp:122:15:122:20 | call to source | swap1.cpp:122:5:122:22 | ... = ... | | +| swap1.cpp:127:5:127:5 | ref arg y | swap1.cpp:129:10:129:10 | y | | +| swap1.cpp:135:23:135:23 | x | swap1.cpp:137:5:137:5 | x | | +| swap1.cpp:135:23:135:23 | x | swap1.cpp:139:10:139:10 | x | | +| swap1.cpp:135:23:135:23 | x | swap1.cpp:142:29:142:29 | x | | +| swap1.cpp:135:23:135:23 | x | swap1.cpp:145:10:145:10 | x | | +| swap1.cpp:136:23:136:23 | y | swap1.cpp:140:10:140:10 | y | | +| swap1.cpp:136:23:136:23 | y | swap1.cpp:142:5:142:5 | y | | +| swap1.cpp:136:23:136:23 | y | swap1.cpp:144:10:144:10 | y | | +| swap1.cpp:137:5:137:5 | x [post update] | swap1.cpp:139:10:139:10 | x | | +| swap1.cpp:137:5:137:5 | x [post update] | swap1.cpp:142:29:142:29 | x | | +| swap1.cpp:137:5:137:5 | x [post update] | swap1.cpp:145:10:145:10 | x | | +| swap1.cpp:137:5:137:22 | ... = ... | swap1.cpp:137:7:137:11 | data1 [post update] | | +| swap1.cpp:137:5:137:22 | ... = ... | swap1.cpp:139:12:139:16 | data1 | | +| swap1.cpp:137:5:137:22 | ... = ... | swap1.cpp:145:12:145:16 | data1 | | +| swap1.cpp:137:15:137:20 | call to source | swap1.cpp:137:5:137:22 | ... = ... | | +| swap1.cpp:142:5:142:5 | ref arg y | swap1.cpp:144:10:144:10 | y | | +| swap1.cpp:142:19:142:27 | ref arg call to move | swap1.cpp:142:29:142:29 | x [inner post update] | | +| swap1.cpp:142:19:142:27 | ref arg call to move | swap1.cpp:145:10:145:10 | x | | +| swap1.cpp:142:29:142:29 | x | swap1.cpp:142:19:142:27 | call to move | | +| swap2.cpp:14:17:14:17 | t | swap2.cpp:14:17:14:17 | t | | +| swap2.cpp:14:17:14:17 | t | swap2.cpp:14:17:14:17 | t | | +| swap2.cpp:14:17:14:17 | t | swap2.cpp:14:56:14:56 | t | | +| swap2.cpp:14:17:14:17 | t | swap2.cpp:14:56:14:56 | t | | +| swap2.cpp:24:9:24:13 | this | swap2.cpp:24:31:24:34 | this | | +| swap2.cpp:24:23:24:26 | that | swap2.cpp:24:23:24:26 | that | | +| swap2.cpp:24:23:24:26 | that | swap2.cpp:24:36:24:39 | that | | +| swap2.cpp:24:36:24:39 | ref arg that | swap2.cpp:24:23:24:26 | that | | +| swap2.cpp:25:9:25:13 | this | swap2.cpp:25:36:25:52 | constructor init of field data1 [pre-this] | | +| swap2.cpp:25:28:25:31 | that | swap2.cpp:25:42:25:45 | that | | +| swap2.cpp:25:28:25:31 | that | swap2.cpp:25:61:25:64 | that | | +| swap2.cpp:25:36:25:52 | constructor init of field data1 [post-this] | swap2.cpp:25:55:25:71 | constructor init of field data2 [pre-this] | | +| swap2.cpp:25:36:25:52 | constructor init of field data1 [pre-this] | swap2.cpp:25:55:25:71 | constructor init of field data2 [pre-this] | | +| swap2.cpp:25:47:25:51 | data1 | swap2.cpp:25:36:25:52 | constructor init of field data1 | TAINT | +| swap2.cpp:25:47:25:51 | data1 | swap2.cpp:25:47:25:51 | data1 | | +| swap2.cpp:25:66:25:70 | data2 | swap2.cpp:25:55:25:71 | constructor init of field data2 | TAINT | +| swap2.cpp:25:66:25:70 | data2 | swap2.cpp:25:66:25:70 | data2 | | +| swap2.cpp:27:16:27:24 | this | swap2.cpp:30:13:30:16 | this | | +| swap2.cpp:27:39:27:42 | that | swap2.cpp:29:24:29:27 | that | | +| swap2.cpp:29:23:29:27 | call to Class | swap2.cpp:30:18:30:20 | tmp | | +| swap2.cpp:29:24:29:27 | that | swap2.cpp:29:23:29:27 | call to Class | | +| swap2.cpp:30:13:30:16 | ref arg this | swap2.cpp:31:21:31:24 | this | | +| swap2.cpp:30:13:30:16 | this | swap2.cpp:31:21:31:24 | this | | +| swap2.cpp:31:21:31:24 | this | swap2.cpp:31:20:31:24 | * ... | TAINT | +| swap2.cpp:34:16:34:24 | this | swap2.cpp:36:13:36:16 | this | | +| swap2.cpp:34:34:34:37 | that | swap2.cpp:34:34:34:37 | that | | +| swap2.cpp:34:34:34:37 | that | swap2.cpp:36:18:36:21 | that | | +| swap2.cpp:36:13:36:16 | ref arg this | swap2.cpp:37:21:37:24 | this | | +| swap2.cpp:36:13:36:16 | this | swap2.cpp:37:21:37:24 | this | | +| swap2.cpp:36:18:36:21 | ref arg that | swap2.cpp:34:34:34:37 | that | | +| swap2.cpp:37:21:37:24 | this | swap2.cpp:37:20:37:24 | * ... | TAINT | +| swap2.cpp:40:16:40:26 | this | swap2.cpp:43:13:43:16 | this | | +| swap2.cpp:40:41:40:44 | that | swap2.cpp:42:24:42:27 | that | | +| swap2.cpp:42:23:42:27 | call to Class | swap2.cpp:43:18:43:20 | tmp | | +| swap2.cpp:42:24:42:27 | that | swap2.cpp:42:23:42:27 | call to Class | | +| swap2.cpp:43:13:43:16 | ref arg this | swap2.cpp:44:21:44:24 | this | | +| swap2.cpp:43:13:43:16 | this | swap2.cpp:44:21:44:24 | this | | +| swap2.cpp:44:21:44:24 | this | swap2.cpp:44:20:44:24 | * ... | TAINT | +| swap2.cpp:47:16:47:26 | this | swap2.cpp:49:13:49:16 | this | | +| swap2.cpp:47:36:47:39 | that | swap2.cpp:47:36:47:39 | that | | +| swap2.cpp:47:36:47:39 | that | swap2.cpp:49:18:49:21 | that | | +| swap2.cpp:49:13:49:16 | ref arg this | swap2.cpp:50:21:50:24 | this | | +| swap2.cpp:49:13:49:16 | this | swap2.cpp:50:21:50:24 | this | | +| swap2.cpp:49:18:49:21 | ref arg that | swap2.cpp:47:36:47:39 | that | | +| swap2.cpp:50:21:50:24 | this | swap2.cpp:50:20:50:24 | * ... | TAINT | +| swap2.cpp:53:14:53:17 | this | swap2.cpp:56:18:56:22 | this | | +| swap2.cpp:53:26:53:29 | that | swap2.cpp:53:26:53:29 | that | | +| swap2.cpp:53:26:53:29 | that | swap2.cpp:56:25:56:28 | that | | +| swap2.cpp:53:26:53:29 | that | swap2.cpp:56:50:56:53 | that | | +| swap2.cpp:56:18:56:22 | data1 | swap2.cpp:56:30:56:34 | ref arg data1 | | +| swap2.cpp:56:18:56:22 | this | swap2.cpp:56:43:56:47 | this | | +| swap2.cpp:56:18:56:22 | this [post update] | swap2.cpp:56:43:56:47 | this | | +| swap2.cpp:56:25:56:28 | that | swap2.cpp:56:18:56:22 | ref arg data1 | | +| swap2.cpp:56:25:56:28 | that [post update] | swap2.cpp:53:26:53:29 | that | | +| swap2.cpp:56:25:56:28 | that [post update] | swap2.cpp:56:50:56:53 | that | | +| swap2.cpp:56:30:56:34 | data1 | swap2.cpp:56:18:56:22 | ref arg data1 | | +| swap2.cpp:56:43:56:47 | data2 | swap2.cpp:56:55:56:59 | ref arg data2 | | +| swap2.cpp:56:50:56:53 | that | swap2.cpp:56:43:56:47 | ref arg data2 | | +| swap2.cpp:56:50:56:53 | that [post update] | swap2.cpp:53:26:53:29 | that | | +| swap2.cpp:56:55:56:59 | data2 | swap2.cpp:56:43:56:47 | ref arg data2 | | +| swap2.cpp:61:22:61:22 | x | swap1.cpp:61:22:61:22 | x | | +| swap2.cpp:61:22:61:22 | x | swap1.cpp:63:9:63:9 | x | | +| swap2.cpp:61:22:61:22 | x | swap2.cpp:61:22:61:22 | x | | +| swap2.cpp:61:22:61:22 | x | swap2.cpp:63:9:63:9 | x | | +| swap2.cpp:61:32:61:32 | y | swap1.cpp:61:32:61:32 | y | | +| swap2.cpp:61:32:61:32 | y | swap1.cpp:63:16:63:16 | y | | +| swap2.cpp:61:32:61:32 | y | swap2.cpp:61:32:61:32 | y | | +| swap2.cpp:61:32:61:32 | y | swap2.cpp:63:16:63:16 | y | | +| swap2.cpp:63:9:63:9 | ref arg x | swap1.cpp:61:22:61:22 | x | | +| swap2.cpp:63:9:63:9 | ref arg x | swap2.cpp:61:22:61:22 | x | | +| swap2.cpp:63:16:63:16 | ref arg y | swap1.cpp:61:32:61:32 | y | | +| swap2.cpp:63:16:63:16 | ref arg y | swap2.cpp:61:32:61:32 | y | | +| swap2.cpp:69:23:69:23 | x | swap2.cpp:71:5:71:5 | x | | +| swap2.cpp:69:23:69:23 | x | swap2.cpp:73:10:73:10 | x | | +| swap2.cpp:69:23:69:23 | x | swap2.cpp:76:9:76:9 | x | | +| swap2.cpp:69:23:69:23 | x | swap2.cpp:79:10:79:10 | x | | +| swap2.cpp:70:23:70:23 | y | swap2.cpp:74:10:74:10 | y | | +| swap2.cpp:70:23:70:23 | y | swap2.cpp:76:5:76:5 | y | | +| swap2.cpp:70:23:70:23 | y | swap2.cpp:78:10:78:10 | y | | +| swap2.cpp:71:5:71:5 | x [post update] | swap2.cpp:73:10:73:10 | x | | +| swap2.cpp:71:5:71:5 | x [post update] | swap2.cpp:76:9:76:9 | x | | +| swap2.cpp:71:5:71:5 | x [post update] | swap2.cpp:79:10:79:10 | x | | +| swap2.cpp:71:5:71:22 | ... = ... | swap2.cpp:71:7:71:11 | data1 [post update] | | +| swap2.cpp:71:5:71:22 | ... = ... | swap2.cpp:73:12:73:16 | data1 | | +| swap2.cpp:71:5:71:22 | ... = ... | swap2.cpp:79:12:79:16 | data1 | | +| swap2.cpp:71:15:71:20 | call to source | swap2.cpp:71:5:71:22 | ... = ... | | +| swap2.cpp:76:5:76:5 | ref arg y | swap2.cpp:78:10:78:10 | y | | +| swap2.cpp:76:9:76:9 | x | swap2.cpp:76:5:76:5 | ref arg y | TAINT | +| swap2.cpp:76:9:76:9 | x | swap2.cpp:76:7:76:7 | call to operator= | TAINT | +| swap2.cpp:81:23:81:24 | z1 | swap2.cpp:82:5:82:6 | z1 | | +| swap2.cpp:81:23:81:24 | z1 | swap2.cpp:83:10:83:11 | z1 | | +| swap2.cpp:81:23:81:24 | z1 | swap2.cpp:85:10:85:11 | z1 | | +| swap2.cpp:81:23:81:24 | z1 | swap2.cpp:88:10:88:11 | z1 | | +| swap2.cpp:81:27:81:28 | z2 | swap2.cpp:85:14:85:15 | z2 | | +| swap2.cpp:81:27:81:28 | z2 | swap2.cpp:87:10:87:11 | z2 | | +| swap2.cpp:82:5:82:6 | z1 [post update] | swap2.cpp:83:10:83:11 | z1 | | +| swap2.cpp:82:5:82:6 | z1 [post update] | swap2.cpp:85:10:85:11 | z1 | | +| swap2.cpp:82:5:82:6 | z1 [post update] | swap2.cpp:88:10:88:11 | z1 | | +| swap2.cpp:82:5:82:23 | ... = ... | swap2.cpp:82:8:82:12 | data1 [post update] | | +| swap2.cpp:82:5:82:23 | ... = ... | swap2.cpp:83:13:83:17 | data1 | | +| swap2.cpp:82:5:82:23 | ... = ... | swap2.cpp:88:13:88:17 | data1 | | +| swap2.cpp:82:16:82:21 | call to source | swap2.cpp:82:5:82:23 | ... = ... | | +| swap2.cpp:85:10:85:11 | ref arg z1 | swap2.cpp:88:10:88:11 | z1 | | +| swap2.cpp:85:14:85:15 | ref arg z2 | swap2.cpp:87:10:87:11 | z2 | | +| swap2.cpp:93:23:93:23 | x | swap2.cpp:95:5:95:5 | x | | +| swap2.cpp:93:23:93:23 | x | swap2.cpp:97:10:97:10 | x | | +| swap2.cpp:93:23:93:23 | x | swap2.cpp:100:19:100:19 | x | | +| swap2.cpp:93:23:93:23 | x | swap2.cpp:103:10:103:10 | x | | +| swap2.cpp:94:23:94:23 | y | swap2.cpp:98:10:98:10 | y | | +| swap2.cpp:94:23:94:23 | y | swap2.cpp:100:5:100:5 | y | | +| swap2.cpp:94:23:94:23 | y | swap2.cpp:102:10:102:10 | y | | +| swap2.cpp:95:5:95:5 | x [post update] | swap2.cpp:97:10:97:10 | x | | +| swap2.cpp:95:5:95:5 | x [post update] | swap2.cpp:100:19:100:19 | x | | +| swap2.cpp:95:5:95:5 | x [post update] | swap2.cpp:103:10:103:10 | x | | +| swap2.cpp:95:5:95:22 | ... = ... | swap2.cpp:95:7:95:11 | data1 [post update] | | +| swap2.cpp:95:5:95:22 | ... = ... | swap2.cpp:97:12:97:16 | data1 | | +| swap2.cpp:95:5:95:22 | ... = ... | swap2.cpp:103:12:103:16 | data1 | | +| swap2.cpp:95:15:95:20 | call to source | swap2.cpp:95:5:95:22 | ... = ... | | +| swap2.cpp:100:5:100:5 | ref arg y | swap2.cpp:102:10:102:10 | y | | +| swap2.cpp:100:9:100:17 | call to move | swap2.cpp:100:5:100:5 | ref arg y | TAINT | +| swap2.cpp:100:9:100:17 | call to move | swap2.cpp:100:7:100:7 | call to operator= | TAINT | +| swap2.cpp:100:9:100:17 | ref arg call to move | swap2.cpp:100:19:100:19 | x [inner post update] | | +| swap2.cpp:100:9:100:17 | ref arg call to move | swap2.cpp:103:10:103:10 | x | | +| swap2.cpp:100:19:100:19 | x | swap2.cpp:100:5:100:5 | ref arg y | TAINT | +| swap2.cpp:100:19:100:19 | x | swap2.cpp:100:7:100:7 | call to operator= | TAINT | +| swap2.cpp:100:19:100:19 | x | swap2.cpp:100:9:100:17 | call to move | | +| swap2.cpp:108:23:108:31 | move_from | swap2.cpp:109:5:109:13 | move_from | | +| swap2.cpp:108:23:108:31 | move_from | swap2.cpp:111:10:111:18 | move_from | | +| swap2.cpp:108:23:108:31 | move_from | swap2.cpp:113:41:113:49 | move_from | | +| swap2.cpp:109:5:109:13 | move_from [post update] | swap2.cpp:111:10:111:18 | move_from | | +| swap2.cpp:109:5:109:13 | move_from [post update] | swap2.cpp:113:41:113:49 | move_from | | +| swap2.cpp:109:5:109:30 | ... = ... | swap2.cpp:109:15:109:19 | data1 [post update] | | +| swap2.cpp:109:5:109:30 | ... = ... | swap2.cpp:111:20:111:24 | data1 | | +| swap2.cpp:109:5:109:30 | ... = ... | swap2.cpp:115:18:115:22 | data1 | | +| swap2.cpp:109:23:109:28 | call to source | swap2.cpp:109:5:109:30 | ... = ... | | +| swap2.cpp:113:31:113:39 | call to move | swap2.cpp:113:31:113:51 | call to Class | | +| swap2.cpp:113:31:113:39 | ref arg call to move | swap2.cpp:113:41:113:49 | move_from [inner post update] | | +| swap2.cpp:113:31:113:51 | call to Class | swap2.cpp:115:10:115:16 | move_to | | +| swap2.cpp:113:41:113:49 | move_from | swap2.cpp:113:31:113:39 | call to move | | +| swap2.cpp:120:23:120:23 | x | swap2.cpp:122:5:122:5 | x | | +| swap2.cpp:120:23:120:23 | x | swap2.cpp:124:10:124:10 | x | | +| swap2.cpp:120:23:120:23 | x | swap2.cpp:127:19:127:19 | x | | +| swap2.cpp:120:23:120:23 | x | swap2.cpp:130:10:130:10 | x | | +| swap2.cpp:121:23:121:23 | y | swap2.cpp:125:10:125:10 | y | | +| swap2.cpp:121:23:121:23 | y | swap2.cpp:127:5:127:5 | y | | +| swap2.cpp:121:23:121:23 | y | swap2.cpp:129:10:129:10 | y | | +| swap2.cpp:122:5:122:5 | x [post update] | swap2.cpp:124:10:124:10 | x | | +| swap2.cpp:122:5:122:5 | x [post update] | swap2.cpp:127:19:127:19 | x | | +| swap2.cpp:122:5:122:5 | x [post update] | swap2.cpp:130:10:130:10 | x | | +| swap2.cpp:122:5:122:22 | ... = ... | swap2.cpp:122:7:122:11 | data1 [post update] | | +| swap2.cpp:122:5:122:22 | ... = ... | swap2.cpp:124:12:124:16 | data1 | | +| swap2.cpp:122:5:122:22 | ... = ... | swap2.cpp:130:12:130:16 | data1 | | +| swap2.cpp:122:15:122:20 | call to source | swap2.cpp:122:5:122:22 | ... = ... | | +| swap2.cpp:127:5:127:5 | ref arg y | swap2.cpp:129:10:129:10 | y | | +| swap2.cpp:135:23:135:23 | x | swap2.cpp:137:5:137:5 | x | | +| swap2.cpp:135:23:135:23 | x | swap2.cpp:139:10:139:10 | x | | +| swap2.cpp:135:23:135:23 | x | swap2.cpp:142:29:142:29 | x | | +| swap2.cpp:135:23:135:23 | x | swap2.cpp:145:10:145:10 | x | | +| swap2.cpp:136:23:136:23 | y | swap2.cpp:140:10:140:10 | y | | +| swap2.cpp:136:23:136:23 | y | swap2.cpp:142:5:142:5 | y | | +| swap2.cpp:136:23:136:23 | y | swap2.cpp:144:10:144:10 | y | | +| swap2.cpp:137:5:137:5 | x [post update] | swap2.cpp:139:10:139:10 | x | | +| swap2.cpp:137:5:137:5 | x [post update] | swap2.cpp:142:29:142:29 | x | | +| swap2.cpp:137:5:137:5 | x [post update] | swap2.cpp:145:10:145:10 | x | | +| swap2.cpp:137:5:137:22 | ... = ... | swap2.cpp:137:7:137:11 | data1 [post update] | | +| swap2.cpp:137:5:137:22 | ... = ... | swap2.cpp:139:12:139:16 | data1 | | +| swap2.cpp:137:5:137:22 | ... = ... | swap2.cpp:145:12:145:16 | data1 | | +| swap2.cpp:137:15:137:20 | call to source | swap2.cpp:137:5:137:22 | ... = ... | | +| swap2.cpp:142:5:142:5 | ref arg y | swap2.cpp:144:10:144:10 | y | | +| swap2.cpp:142:19:142:27 | ref arg call to move | swap2.cpp:142:29:142:29 | x [inner post update] | | +| swap2.cpp:142:19:142:27 | ref arg call to move | swap2.cpp:145:10:145:10 | x | | +| swap2.cpp:142:29:142:29 | x | swap2.cpp:142:19:142:27 | call to move | | | taint.cpp:4:27:4:33 | source1 | taint.cpp:6:13:6:19 | source1 | | | taint.cpp:4:40:4:45 | clean1 | taint.cpp:5:8:5:13 | clean1 | | | taint.cpp:4:40:4:45 | clean1 | taint.cpp:6:3:6:8 | clean1 | | @@ -197,9 +5314,11 @@ | taint.cpp:7:3:7:8 | clean1 | taint.cpp:7:3:7:13 | ... += ... | TAINT | | taint.cpp:7:3:7:13 | ... += ... | taint.cpp:8:8:8:13 | clean1 | | | taint.cpp:7:13:7:13 | 1 | taint.cpp:7:3:7:13 | ... += ... | TAINT | +| taint.cpp:10:12:10:18 | source1 | taint.cpp:10:12:10:22 | ... = ... | | | taint.cpp:10:12:10:22 | ... = ... | taint.cpp:10:3:10:22 | ... = ... | | | taint.cpp:10:12:10:22 | ... = ... | taint.cpp:11:8:11:13 | clean1 | | | taint.cpp:10:22:10:22 | 1 | taint.cpp:10:12:10:22 | ... = ... | | +| taint.cpp:12:13:12:18 | clean1 | taint.cpp:12:13:12:29 | ... = ... | | | taint.cpp:12:13:12:29 | ... = ... | taint.cpp:12:3:12:29 | ... = ... | | | taint.cpp:12:13:12:29 | ... = ... | taint.cpp:13:3:13:9 | source1 | | | taint.cpp:12:22:12:27 | call to source | taint.cpp:12:13:12:29 | ... = ... | | @@ -211,23 +5330,34 @@ | taint.cpp:15:3:15:14 | ... += ... | taint.cpp:16:8:16:14 | source1 | | | taint.cpp:15:3:15:14 | ... += ... | taint.cpp:17:10:17:16 | source1 | | | taint.cpp:15:14:15:14 | 1 | taint.cpp:15:3:15:14 | ... += ... | TAINT | -| taint.cpp:17:10:17:16 | source1 | taint.cpp:17:8:17:16 | ++ ... | TAINT | +| taint.cpp:17:10:17:16 | source1 | taint.cpp:17:8:17:16 | ++ ... | | | taint.cpp:22:19:22:19 | x | taint.cpp:22:30:22:30 | x | | | taint.cpp:22:30:22:30 | x | taint.cpp:22:30:22:34 | ... + ... | TAINT | | taint.cpp:22:34:22:34 | 1 | taint.cpp:22:30:22:34 | ... + ... | TAINT | | taint.cpp:27:15:27:21 | global2 | taint.cpp:27:15:27:25 | ... + ... | TAINT | | taint.cpp:27:25:27:25 | 1 | taint.cpp:27:15:27:25 | ... + ... | TAINT | +| taint.cpp:34:2:34:8 | global6 [post update] | taint.cpp:40:7:40:13 | global6 | | +| taint.cpp:34:2:34:12 | ... = ... | taint.cpp:34:2:34:8 | global6 [post update] | | | taint.cpp:34:12:34:12 | 0 | taint.cpp:34:2:34:12 | ... = ... | | | taint.cpp:34:12:34:12 | 0 | taint.cpp:40:7:40:13 | global6 | | +| taint.cpp:35:2:35:8 | global7 [post update] | taint.cpp:36:12:36:18 | global7 | | +| taint.cpp:35:2:35:8 | global7 [post update] | taint.cpp:41:7:41:13 | global7 | | +| taint.cpp:35:2:35:19 | ... = ... | taint.cpp:35:2:35:8 | global7 [post update] | | | taint.cpp:35:12:35:17 | call to source | taint.cpp:35:2:35:19 | ... = ... | | | taint.cpp:35:12:35:17 | call to source | taint.cpp:36:12:36:18 | global7 | | | taint.cpp:35:12:35:17 | call to source | taint.cpp:41:7:41:13 | global7 | | +| taint.cpp:36:2:36:8 | global8 [post update] | taint.cpp:42:7:42:13 | global8 | | +| taint.cpp:36:2:36:22 | ... = ... | taint.cpp:36:2:36:8 | global8 [post update] | | | taint.cpp:36:12:36:18 | global7 | taint.cpp:36:12:36:22 | ... + ... | TAINT | | taint.cpp:36:12:36:22 | ... + ... | taint.cpp:36:2:36:22 | ... = ... | | | taint.cpp:36:12:36:22 | ... + ... | taint.cpp:42:7:42:13 | global8 | | | taint.cpp:36:22:36:22 | 1 | taint.cpp:36:12:36:22 | ... + ... | TAINT | +| taint.cpp:37:2:37:8 | global9 [post update] | taint.cpp:43:7:43:13 | global9 | | +| taint.cpp:37:2:37:30 | ... = ... | taint.cpp:37:2:37:8 | global9 [post update] | | | taint.cpp:37:12:37:20 | call to increment | taint.cpp:37:2:37:30 | ... = ... | | | taint.cpp:37:12:37:20 | call to increment | taint.cpp:43:7:43:13 | global9 | | +| taint.cpp:38:2:38:9 | global10 [post update] | taint.cpp:44:7:44:14 | global10 | | +| taint.cpp:38:2:38:26 | ... = ... | taint.cpp:38:2:38:9 | global10 [post update] | | | taint.cpp:38:13:38:16 | call to zero | taint.cpp:38:2:38:26 | ... = ... | | | taint.cpp:38:13:38:16 | call to zero | taint.cpp:44:7:44:14 | global10 | | | taint.cpp:71:2:71:8 | this | taint.cpp:71:14:71:17 | constructor init of field a [pre-this] | | @@ -239,9 +5369,12 @@ | taint.cpp:71:22:71:27 | call to source | taint.cpp:71:20:71:30 | constructor init of field b | TAINT | | taint.cpp:72:3:72:3 | this | taint.cpp:73:3:73:3 | this | | | taint.cpp:72:3:72:3 | this [post update] | taint.cpp:73:3:73:3 | this | | +| taint.cpp:72:3:72:14 | ... = ... | taint.cpp:72:3:72:3 | c [post update] | | | taint.cpp:72:7:72:12 | call to source | taint.cpp:72:3:72:14 | ... = ... | | +| taint.cpp:73:3:73:7 | ... = ... | taint.cpp:73:3:73:3 | d [post update] | | | taint.cpp:73:7:73:7 | 0 | taint.cpp:73:3:73:7 | ... = ... | | | taint.cpp:76:7:76:14 | this | taint.cpp:77:3:77:3 | this | | +| taint.cpp:77:3:77:14 | ... = ... | taint.cpp:77:3:77:3 | d [post update] | | | taint.cpp:77:7:77:12 | call to source | taint.cpp:77:3:77:14 | ... = ... | | | taint.cpp:84:10:84:12 | call to MyClass | taint.cpp:86:2:86:4 | mc1 | | | taint.cpp:84:10:84:12 | call to MyClass | taint.cpp:88:7:88:9 | mc1 | | @@ -261,31 +5394,49 @@ | taint.cpp:100:21:100:21 | i | taint.cpp:112:12:112:12 | i | | | taint.cpp:100:21:100:21 | i | taint.cpp:114:12:114:12 | i | | | taint.cpp:101:16:101:19 | {...} | taint.cpp:105:2:105:5 | arr1 | | +| taint.cpp:101:16:101:19 | {...} | taint.cpp:109:7:109:10 | arr1 | | +| taint.cpp:101:16:101:19 | {...} | taint.cpp:110:7:110:10 | arr1 | | | taint.cpp:101:18:101:18 | 0 | taint.cpp:101:16:101:19 | {...} | TAINT | | taint.cpp:102:16:102:19 | {...} | taint.cpp:106:2:106:5 | arr2 | | +| taint.cpp:102:16:102:19 | {...} | taint.cpp:111:7:111:10 | arr2 | | +| taint.cpp:102:16:102:19 | {...} | taint.cpp:112:7:112:10 | arr2 | | | taint.cpp:102:18:102:18 | 0 | taint.cpp:102:16:102:19 | {...} | TAINT | | taint.cpp:103:16:103:19 | {...} | taint.cpp:107:2:107:5 | arr3 | | +| taint.cpp:103:16:103:19 | {...} | taint.cpp:113:7:113:10 | arr3 | | +| taint.cpp:103:16:103:19 | {...} | taint.cpp:114:7:114:10 | arr3 | | | taint.cpp:103:18:103:18 | 0 | taint.cpp:103:16:103:19 | {...} | TAINT | -| taint.cpp:105:2:105:5 | arr1 | taint.cpp:105:2:105:8 | access to array | TAINT | +| taint.cpp:105:2:105:5 | arr1 | taint.cpp:105:2:105:8 | access to array | | +| taint.cpp:105:2:105:8 | access to array [post update] | taint.cpp:105:2:105:5 | arr1 [inner post update] | | +| taint.cpp:105:2:105:8 | access to array [post update] | taint.cpp:109:7:109:10 | arr1 | | +| taint.cpp:105:2:105:8 | access to array [post update] | taint.cpp:110:7:110:10 | arr1 | | +| taint.cpp:105:2:105:19 | ... = ... | taint.cpp:105:2:105:8 | access to array [post update] | | | taint.cpp:105:7:105:7 | 5 | taint.cpp:105:2:105:8 | access to array | TAINT | | taint.cpp:105:12:105:17 | call to source | taint.cpp:105:2:105:19 | ... = ... | | -| taint.cpp:106:2:106:5 | arr2 | taint.cpp:106:2:106:8 | access to array | TAINT | +| taint.cpp:106:2:106:5 | arr2 | taint.cpp:106:2:106:8 | access to array | | +| taint.cpp:106:2:106:8 | access to array [post update] | taint.cpp:106:2:106:5 | arr2 [inner post update] | | +| taint.cpp:106:2:106:8 | access to array [post update] | taint.cpp:111:7:111:10 | arr2 | | +| taint.cpp:106:2:106:8 | access to array [post update] | taint.cpp:112:7:112:10 | arr2 | | +| taint.cpp:106:2:106:19 | ... = ... | taint.cpp:106:2:106:8 | access to array [post update] | | | taint.cpp:106:7:106:7 | i | taint.cpp:106:2:106:8 | access to array | TAINT | | taint.cpp:106:12:106:17 | call to source | taint.cpp:106:2:106:19 | ... = ... | | -| taint.cpp:107:2:107:5 | arr3 | taint.cpp:107:2:107:8 | access to array | TAINT | +| taint.cpp:107:2:107:5 | arr3 | taint.cpp:107:2:107:8 | access to array | | +| taint.cpp:107:2:107:8 | access to array [post update] | taint.cpp:107:2:107:5 | arr3 [inner post update] | | +| taint.cpp:107:2:107:8 | access to array [post update] | taint.cpp:113:7:113:10 | arr3 | | +| taint.cpp:107:2:107:8 | access to array [post update] | taint.cpp:114:7:114:10 | arr3 | | +| taint.cpp:107:2:107:12 | ... = ... | taint.cpp:107:2:107:8 | access to array [post update] | | | taint.cpp:107:7:107:7 | 5 | taint.cpp:107:2:107:8 | access to array | TAINT | | taint.cpp:107:12:107:12 | 0 | taint.cpp:107:2:107:12 | ... = ... | | -| taint.cpp:109:7:109:10 | arr1 | taint.cpp:109:7:109:13 | access to array | TAINT | +| taint.cpp:109:7:109:10 | arr1 | taint.cpp:109:7:109:13 | access to array | | | taint.cpp:109:12:109:12 | 5 | taint.cpp:109:7:109:13 | access to array | TAINT | -| taint.cpp:110:7:110:10 | arr1 | taint.cpp:110:7:110:13 | access to array | TAINT | +| taint.cpp:110:7:110:10 | arr1 | taint.cpp:110:7:110:13 | access to array | | | taint.cpp:110:12:110:12 | i | taint.cpp:110:7:110:13 | access to array | TAINT | -| taint.cpp:111:7:111:10 | arr2 | taint.cpp:111:7:111:13 | access to array | TAINT | +| taint.cpp:111:7:111:10 | arr2 | taint.cpp:111:7:111:13 | access to array | | | taint.cpp:111:12:111:12 | 5 | taint.cpp:111:7:111:13 | access to array | TAINT | -| taint.cpp:112:7:112:10 | arr2 | taint.cpp:112:7:112:13 | access to array | TAINT | +| taint.cpp:112:7:112:10 | arr2 | taint.cpp:112:7:112:13 | access to array | | | taint.cpp:112:12:112:12 | i | taint.cpp:112:7:112:13 | access to array | TAINT | -| taint.cpp:113:7:113:10 | arr3 | taint.cpp:113:7:113:13 | access to array | TAINT | +| taint.cpp:113:7:113:10 | arr3 | taint.cpp:113:7:113:13 | access to array | | | taint.cpp:113:12:113:12 | 5 | taint.cpp:113:7:113:13 | access to array | TAINT | -| taint.cpp:114:7:114:10 | arr3 | taint.cpp:114:7:114:13 | access to array | TAINT | +| taint.cpp:114:7:114:10 | arr3 | taint.cpp:114:7:114:13 | access to array | | | taint.cpp:114:12:114:12 | i | taint.cpp:114:7:114:13 | access to array | TAINT | | taint.cpp:120:11:120:16 | call to source | taint.cpp:123:13:123:14 | t1 | | | taint.cpp:120:11:120:16 | call to source | taint.cpp:133:8:133:9 | t1 | | @@ -298,6 +5449,9 @@ | taint.cpp:124:13:124:14 | t2 | taint.cpp:124:12:124:14 | & ... | | | taint.cpp:125:12:125:14 | & ... | taint.cpp:131:8:131:9 | p3 | | | taint.cpp:125:13:125:14 | t3 | taint.cpp:125:12:125:14 | & ... | | +| taint.cpp:127:2:127:4 | * ... [post update] | taint.cpp:127:3:127:4 | p2 [inner post update] | | +| taint.cpp:127:2:127:4 | * ... [post update] | taint.cpp:130:8:130:9 | p2 | | +| taint.cpp:127:2:127:15 | ... = ... | taint.cpp:127:2:127:4 | * ... [post update] | | | taint.cpp:127:3:127:4 | p2 | taint.cpp:127:2:127:4 | * ... | TAINT | | taint.cpp:127:8:127:13 | call to source | taint.cpp:127:2:127:15 | ... = ... | | | taint.cpp:129:8:129:9 | p1 | taint.cpp:129:7:129:9 | * ... | TAINT | @@ -309,6 +5463,9 @@ | taint.cpp:133:7:133:9 | & ... | taint.cpp:137:8:137:9 | p3 | | | taint.cpp:133:8:133:9 | t1 | taint.cpp:133:7:133:9 | & ... | | | taint.cpp:134:8:134:9 | p3 | taint.cpp:134:7:134:9 | * ... | TAINT | +| taint.cpp:136:2:136:4 | * ... [post update] | taint.cpp:136:3:136:4 | p3 [inner post update] | | +| taint.cpp:136:2:136:4 | * ... [post update] | taint.cpp:137:8:137:9 | p3 | | +| taint.cpp:136:2:136:8 | ... = ... | taint.cpp:136:2:136:4 | * ... [post update] | | | taint.cpp:136:3:136:4 | p3 | taint.cpp:136:2:136:4 | * ... | TAINT | | taint.cpp:136:8:136:8 | 0 | taint.cpp:136:2:136:8 | ... = ... | | | taint.cpp:137:8:137:9 | p3 | taint.cpp:137:7:137:9 | * ... | TAINT | @@ -401,6 +5558,7 @@ | taint.cpp:235:15:235:15 | this | taint.cpp:236:3:236:6 | this | | | taint.cpp:236:3:236:6 | this | taint.cpp:237:3:237:6 | this | | | taint.cpp:237:3:237:6 | this | taint.cpp:238:3:238:14 | this | | +| taint.cpp:238:3:238:14 | ... = ... | taint.cpp:238:3:238:14 | v [post update] | | | taint.cpp:238:7:238:12 | call to source | taint.cpp:238:3:238:14 | ... = ... | | | taint.cpp:243:10:246:2 | [...](...){...} | taint.cpp:247:2:247:2 | c | | | taint.cpp:243:10:246:2 | {...} | taint.cpp:243:10:246:2 | [...](...){...} | | @@ -419,6 +5577,8 @@ | taint.cpp:255:19:255:19 | a | taint.cpp:256:8:256:8 | a | | | taint.cpp:255:27:255:27 | b | taint.cpp:255:27:255:27 | b | | | taint.cpp:255:27:255:27 | b | taint.cpp:257:8:257:8 | b | | +| taint.cpp:258:3:258:3 | c [post update] | taint.cpp:255:35:255:35 | c | | +| taint.cpp:258:3:258:14 | ... = ... | taint.cpp:258:3:258:3 | c [post update] | | | taint.cpp:258:7:258:12 | call to source | taint.cpp:255:35:255:35 | c | | | taint.cpp:258:7:258:12 | call to source | taint.cpp:258:3:258:14 | ... = ... | | | taint.cpp:260:10:260:10 | ref arg w | taint.cpp:261:7:261:7 | w | | @@ -443,13 +5603,19 @@ | taint.cpp:287:6:287:7 | call to id | taint.cpp:292:7:292:7 | z | | | taint.cpp:297:29:297:29 | b | taint.cpp:297:29:297:29 | b | | | taint.cpp:297:29:297:29 | b | taint.cpp:299:6:299:6 | b | | +| taint.cpp:299:2:299:2 | a [post update] | taint.cpp:297:21:297:21 | a | | +| taint.cpp:299:2:299:6 | ... = ... | taint.cpp:299:2:299:2 | a [post update] | | | taint.cpp:299:6:299:6 | b | taint.cpp:297:21:297:21 | a | | | taint.cpp:299:6:299:6 | b | taint.cpp:299:2:299:6 | ... = ... | | | taint.cpp:302:28:302:28 | b | taint.cpp:304:6:304:6 | b | | +| taint.cpp:304:2:304:2 | a [post update] | taint.cpp:302:21:302:21 | a | | +| taint.cpp:304:2:304:6 | ... = ... | taint.cpp:304:2:304:2 | a [post update] | | | taint.cpp:304:6:304:6 | b | taint.cpp:302:21:302:21 | a | | | taint.cpp:304:6:304:6 | b | taint.cpp:304:2:304:6 | ... = ... | | | taint.cpp:307:21:307:21 | a | taint.cpp:309:3:309:3 | a | | | taint.cpp:307:28:307:28 | b | taint.cpp:309:7:309:7 | b | | +| taint.cpp:309:2:309:3 | * ... [post update] | taint.cpp:309:3:309:3 | a [inner post update] | | +| taint.cpp:309:2:309:7 | ... = ... | taint.cpp:309:2:309:3 | * ... [post update] | | | taint.cpp:309:3:309:3 | a | taint.cpp:309:2:309:3 | * ... | TAINT | | taint.cpp:309:7:309:7 | b | taint.cpp:309:2:309:7 | ... = ... | | | taint.cpp:312:21:312:21 | a | taint.cpp:317:3:317:3 | a | | @@ -458,14 +5624,20 @@ | taint.cpp:316:6:316:10 | ... + ... | taint.cpp:316:2:316:10 | ... = ... | | | taint.cpp:316:6:316:10 | ... + ... | taint.cpp:317:7:317:7 | c | | | taint.cpp:316:10:316:10 | 1 | taint.cpp:316:6:316:10 | ... + ... | TAINT | +| taint.cpp:317:2:317:3 | * ... [post update] | taint.cpp:317:3:317:3 | a [inner post update] | | +| taint.cpp:317:2:317:7 | ... = ... | taint.cpp:317:2:317:3 | * ... [post update] | | | taint.cpp:317:3:317:3 | a | taint.cpp:317:2:317:3 | * ... | TAINT | | taint.cpp:317:7:317:7 | c | taint.cpp:317:2:317:7 | ... = ... | | | taint.cpp:320:23:320:23 | a | taint.cpp:322:6:322:6 | a | | | taint.cpp:320:31:320:31 | b | taint.cpp:323:6:323:6 | b | | +| taint.cpp:322:2:322:2 | a [post update] | taint.cpp:320:23:320:23 | a | | +| taint.cpp:322:2:322:10 | ... = ... | taint.cpp:322:2:322:2 | a [post update] | | | taint.cpp:322:6:322:6 | a | taint.cpp:322:6:322:10 | ... + ... | TAINT | | taint.cpp:322:6:322:10 | ... + ... | taint.cpp:320:23:320:23 | a | | | taint.cpp:322:6:322:10 | ... + ... | taint.cpp:322:2:322:10 | ... = ... | | | taint.cpp:322:10:322:10 | 1 | taint.cpp:322:6:322:10 | ... + ... | TAINT | +| taint.cpp:323:2:323:2 | b [post update] | taint.cpp:320:31:320:31 | b | | +| taint.cpp:323:2:323:10 | ... = ... | taint.cpp:323:2:323:2 | b [post update] | | | taint.cpp:323:6:323:6 | b | taint.cpp:323:6:323:10 | ... + ... | TAINT | | taint.cpp:323:6:323:10 | ... + ... | taint.cpp:320:31:320:31 | b | | | taint.cpp:323:6:323:10 | ... + ... | taint.cpp:323:2:323:10 | ... = ... | | @@ -537,17 +5709,20 @@ | taint.cpp:390:6:390:11 | call to wcsdup | taint.cpp:390:2:390:28 | ... = ... | | | taint.cpp:390:6:390:11 | call to wcsdup | taint.cpp:392:7:392:7 | b | | | taint.cpp:390:13:390:27 | hello, world | taint.cpp:390:6:390:11 | call to wcsdup | TAINT | +| taint.cpp:417:13:417:13 | 0 | taint.cpp:417:13:417:14 | call to MyClass2 | TAINT | | taint.cpp:417:13:417:14 | call to MyClass2 | taint.cpp:420:7:420:7 | a | | | taint.cpp:417:13:417:14 | call to MyClass2 | taint.cpp:421:7:421:7 | a | | | taint.cpp:417:13:417:14 | call to MyClass2 | taint.cpp:422:2:422:2 | a | | | taint.cpp:417:13:417:14 | call to MyClass2 | taint.cpp:423:7:423:7 | a | | | taint.cpp:417:13:417:14 | call to MyClass2 | taint.cpp:424:7:424:7 | a | | +| taint.cpp:417:19:417:19 | 0 | taint.cpp:417:19:417:20 | call to MyClass2 | TAINT | | taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:426:7:426:7 | b | | | taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:427:7:427:7 | b | | | taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:428:2:428:2 | b | | | taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:429:7:429:7 | b | | | taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:430:7:430:7 | b | | | taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:431:7:431:7 | b | | +| taint.cpp:418:13:418:14 | | taint.cpp:418:13:418:15 | call to MyClass3 | TAINT | | taint.cpp:418:13:418:15 | call to MyClass3 | taint.cpp:443:7:443:7 | d | | | taint.cpp:418:13:418:15 | call to MyClass3 | taint.cpp:444:7:444:7 | d | | | taint.cpp:418:13:418:15 | call to MyClass3 | taint.cpp:445:2:445:2 | d | | @@ -565,6 +5740,7 @@ | taint.cpp:428:2:428:2 | b [post update] | taint.cpp:429:7:429:7 | b | | | taint.cpp:428:2:428:2 | b [post update] | taint.cpp:430:7:430:7 | b | | | taint.cpp:428:2:428:2 | b [post update] | taint.cpp:431:7:431:7 | b | | +| taint.cpp:428:2:428:20 | ... = ... | taint.cpp:428:4:428:9 | member [post update] | | | taint.cpp:428:2:428:20 | ... = ... | taint.cpp:430:9:430:14 | member | | | taint.cpp:428:13:428:18 | call to source | taint.cpp:428:2:428:20 | ... = ... | | | taint.cpp:433:6:433:20 | call to MyClass2 | taint.cpp:433:6:433:20 | new | | @@ -575,6 +5751,7 @@ | taint.cpp:433:6:433:20 | new | taint.cpp:438:7:438:7 | c | | | taint.cpp:433:6:433:20 | new | taint.cpp:439:7:439:7 | c | | | taint.cpp:433:6:433:20 | new | taint.cpp:441:9:441:9 | c | | +| taint.cpp:433:19:433:19 | 0 | taint.cpp:433:6:433:20 | call to MyClass2 | TAINT | | taint.cpp:435:7:435:7 | ref arg c | taint.cpp:436:7:436:7 | c | | | taint.cpp:435:7:435:7 | ref arg c | taint.cpp:437:2:437:2 | c | | | taint.cpp:435:7:435:7 | ref arg c | taint.cpp:438:7:438:7 | c | | @@ -599,8 +5776,12 @@ | taint.cpp:452:16:452:16 | a | taint.cpp:454:10:454:10 | a | | | taint.cpp:452:24:452:24 | b | taint.cpp:455:6:455:6 | b | | | taint.cpp:454:10:454:10 | a | taint.cpp:456:6:456:6 | c | | +| taint.cpp:455:2:455:2 | a [post update] | taint.cpp:452:16:452:16 | a | | +| taint.cpp:455:2:455:6 | ... = ... | taint.cpp:455:2:455:2 | a [post update] | | | taint.cpp:455:6:455:6 | b | taint.cpp:452:16:452:16 | a | | | taint.cpp:455:6:455:6 | b | taint.cpp:455:2:455:6 | ... = ... | | +| taint.cpp:456:2:456:2 | b [post update] | taint.cpp:452:24:452:24 | b | | +| taint.cpp:456:2:456:6 | ... = ... | taint.cpp:456:2:456:2 | b [post update] | | | taint.cpp:456:6:456:6 | c | taint.cpp:452:24:452:24 | b | | | taint.cpp:456:6:456:6 | c | taint.cpp:456:2:456:6 | ... = ... | | | taint.cpp:462:6:462:11 | call to source | taint.cpp:462:2:462:13 | ... = ... | | @@ -623,3 +5804,1239 @@ | taint.cpp:483:18:483:19 | ref arg & ... | taint.cpp:483:19:483:19 | n [inner post update] | | | taint.cpp:483:19:483:19 | n | taint.cpp:483:18:483:19 | & ... | | | taint.cpp:483:28:483:34 | source1 | taint.cpp:483:11:483:15 | ref arg & ... | TAINT | +| vector.cpp:16:43:16:49 | source1 | vector.cpp:17:26:17:32 | source1 | | +| vector.cpp:16:43:16:49 | source1 | vector.cpp:31:38:31:44 | source1 | | +| vector.cpp:17:21:17:33 | call to vector | vector.cpp:19:14:19:14 | v | | +| vector.cpp:17:21:17:33 | call to vector | vector.cpp:23:38:23:38 | v | | +| vector.cpp:17:21:17:33 | call to vector | vector.cpp:23:55:23:55 | v | | +| vector.cpp:17:21:17:33 | call to vector | vector.cpp:27:15:27:15 | v | | +| vector.cpp:17:21:17:33 | call to vector | vector.cpp:35:1:35:1 | v | | +| vector.cpp:17:26:17:32 | source1 | vector.cpp:17:21:17:33 | call to vector | TAINT | +| vector.cpp:19:14:19:14 | (__begin) | vector.cpp:19:14:19:14 | call to operator* | TAINT | +| vector.cpp:19:14:19:14 | (__begin) | vector.cpp:19:14:19:14 | call to operator++ | | +| vector.cpp:19:14:19:14 | (__end) | vector.cpp:19:14:19:14 | call to iterator | | +| vector.cpp:19:14:19:14 | (__range) | vector.cpp:19:14:19:14 | call to begin | TAINT | +| vector.cpp:19:14:19:14 | (__range) | vector.cpp:19:14:19:14 | call to end | TAINT | +| vector.cpp:19:14:19:14 | call to begin | vector.cpp:19:14:19:14 | (__begin) | | +| vector.cpp:19:14:19:14 | call to begin | vector.cpp:19:14:19:14 | (__begin) | | +| vector.cpp:19:14:19:14 | call to begin | vector.cpp:19:14:19:14 | (__begin) | | +| vector.cpp:19:14:19:14 | call to end | vector.cpp:19:14:19:14 | (__end) | | +| vector.cpp:19:14:19:14 | call to operator* | vector.cpp:20:8:20:8 | x | | +| vector.cpp:19:14:19:14 | ref arg (__begin) | vector.cpp:19:14:19:14 | (__begin) | | +| vector.cpp:19:14:19:14 | ref arg (__begin) | vector.cpp:19:14:19:14 | (__begin) | | +| vector.cpp:19:14:19:14 | ref arg (__begin) | vector.cpp:19:14:19:14 | (__begin) | | +| vector.cpp:19:14:19:14 | ref arg (__range) | vector.cpp:19:14:19:14 | (__range) | | +| vector.cpp:19:14:19:14 | v | vector.cpp:19:14:19:14 | (__range) | | +| vector.cpp:19:14:19:14 | v | vector.cpp:19:14:19:14 | (__range) | | +| vector.cpp:19:14:19:14 | v | vector.cpp:19:14:19:14 | call to operator* | TAINT | +| vector.cpp:23:38:23:38 | ref arg v | vector.cpp:23:55:23:55 | v | | +| vector.cpp:23:38:23:38 | ref arg v | vector.cpp:27:15:27:15 | v | | +| vector.cpp:23:38:23:38 | ref arg v | vector.cpp:35:1:35:1 | v | | +| vector.cpp:23:38:23:38 | v | vector.cpp:23:40:23:44 | call to begin | TAINT | +| vector.cpp:23:40:23:44 | call to begin | vector.cpp:23:49:23:50 | it | | +| vector.cpp:23:40:23:44 | call to begin | vector.cpp:23:66:23:67 | it | | +| vector.cpp:23:40:23:44 | call to begin | vector.cpp:24:9:24:10 | it | | +| vector.cpp:23:55:23:55 | ref arg v | vector.cpp:23:55:23:55 | v | | +| vector.cpp:23:55:23:55 | ref arg v | vector.cpp:27:15:27:15 | v | | +| vector.cpp:23:55:23:55 | ref arg v | vector.cpp:35:1:35:1 | v | | +| vector.cpp:23:55:23:55 | v | vector.cpp:23:57:23:59 | call to end | TAINT | +| vector.cpp:23:66:23:67 | it | vector.cpp:23:64:23:64 | call to operator++ | | +| vector.cpp:23:66:23:67 | ref arg it | vector.cpp:23:49:23:50 | it | | +| vector.cpp:23:66:23:67 | ref arg it | vector.cpp:23:66:23:67 | it | | +| vector.cpp:23:66:23:67 | ref arg it | vector.cpp:24:9:24:10 | it | | +| vector.cpp:24:9:24:10 | it | vector.cpp:24:8:24:8 | call to operator* | TAINT | +| vector.cpp:27:15:27:15 | (__begin) | vector.cpp:27:15:27:15 | call to operator* | TAINT | +| vector.cpp:27:15:27:15 | (__begin) | vector.cpp:27:15:27:15 | call to operator++ | | +| vector.cpp:27:15:27:15 | (__end) | vector.cpp:27:15:27:15 | call to iterator | | +| vector.cpp:27:15:27:15 | (__range) | vector.cpp:27:15:27:15 | call to begin | TAINT | +| vector.cpp:27:15:27:15 | (__range) | vector.cpp:27:15:27:15 | call to end | TAINT | +| vector.cpp:27:15:27:15 | call to begin | vector.cpp:27:15:27:15 | (__begin) | | +| vector.cpp:27:15:27:15 | call to begin | vector.cpp:27:15:27:15 | (__begin) | | +| vector.cpp:27:15:27:15 | call to begin | vector.cpp:27:15:27:15 | (__begin) | | +| vector.cpp:27:15:27:15 | call to end | vector.cpp:27:15:27:15 | (__end) | | +| vector.cpp:27:15:27:15 | call to operator* | vector.cpp:28:8:28:8 | x | | +| vector.cpp:27:15:27:15 | ref arg (__begin) | vector.cpp:27:15:27:15 | (__begin) | | +| vector.cpp:27:15:27:15 | ref arg (__begin) | vector.cpp:27:15:27:15 | (__begin) | | +| vector.cpp:27:15:27:15 | ref arg (__begin) | vector.cpp:27:15:27:15 | (__begin) | | +| vector.cpp:27:15:27:15 | ref arg (__range) | vector.cpp:27:15:27:15 | (__range) | | +| vector.cpp:27:15:27:15 | v | vector.cpp:27:15:27:15 | (__range) | | +| vector.cpp:27:15:27:15 | v | vector.cpp:27:15:27:15 | (__range) | | +| vector.cpp:27:15:27:15 | v | vector.cpp:27:15:27:15 | call to operator* | TAINT | +| vector.cpp:31:33:31:45 | call to vector | vector.cpp:32:21:32:27 | const_v | | +| vector.cpp:31:33:31:45 | call to vector | vector.cpp:35:1:35:1 | const_v | | +| vector.cpp:31:38:31:44 | source1 | vector.cpp:31:33:31:45 | call to vector | TAINT | +| vector.cpp:32:21:32:21 | (__begin) | vector.cpp:32:21:32:21 | call to operator* | TAINT | +| vector.cpp:32:21:32:21 | (__begin) | vector.cpp:32:21:32:21 | call to operator++ | | +| vector.cpp:32:21:32:21 | (__range) | vector.cpp:32:21:32:21 | call to begin | TAINT | +| vector.cpp:32:21:32:21 | (__range) | vector.cpp:32:21:32:21 | call to end | TAINT | +| vector.cpp:32:21:32:21 | call to begin | vector.cpp:32:21:32:21 | (__begin) | | +| vector.cpp:32:21:32:21 | call to begin | vector.cpp:32:21:32:21 | (__begin) | | +| vector.cpp:32:21:32:21 | call to begin | vector.cpp:32:21:32:21 | (__begin) | | +| vector.cpp:32:21:32:21 | call to end | vector.cpp:32:21:32:21 | (__end) | | +| vector.cpp:32:21:32:21 | call to operator* | vector.cpp:33:8:33:8 | x | | +| vector.cpp:32:21:32:21 | ref arg (__begin) | vector.cpp:32:21:32:21 | (__begin) | | +| vector.cpp:32:21:32:21 | ref arg (__begin) | vector.cpp:32:21:32:21 | (__begin) | | +| vector.cpp:32:21:32:21 | ref arg (__begin) | vector.cpp:32:21:32:21 | (__begin) | | +| vector.cpp:32:21:32:27 | const_v | vector.cpp:32:21:32:21 | (__range) | | +| vector.cpp:32:21:32:27 | const_v | vector.cpp:32:21:32:21 | (__range) | | +| vector.cpp:32:21:32:27 | const_v | vector.cpp:32:21:32:21 | call to operator* | TAINT | +| vector.cpp:37:29:37:29 | x | vector.cpp:42:5:42:5 | x | | +| vector.cpp:37:29:37:29 | x | vector.cpp:47:10:47:10 | x | | +| vector.cpp:37:29:37:29 | x | vector.cpp:55:10:55:10 | x | | +| vector.cpp:37:29:37:29 | x | vector.cpp:61:10:61:10 | x | | +| vector.cpp:37:29:37:29 | x | vector.cpp:63:5:63:5 | x | | +| vector.cpp:37:29:37:29 | x | vector.cpp:67:10:67:10 | x | | +| vector.cpp:37:29:37:29 | x | vector.cpp:96:8:96:8 | x | | +| vector.cpp:37:29:37:29 | x | vector.cpp:100:13:100:13 | x | | +| vector.cpp:38:22:38:24 | call to vector | vector.cpp:40:2:40:3 | v1 | | +| vector.cpp:38:22:38:24 | call to vector | vector.cpp:41:2:41:3 | v1 | | +| vector.cpp:38:22:38:24 | call to vector | vector.cpp:42:2:42:3 | v1 | | +| vector.cpp:38:22:38:24 | call to vector | vector.cpp:43:2:43:3 | v1 | | +| vector.cpp:38:22:38:24 | call to vector | vector.cpp:44:7:44:8 | v1 | | +| vector.cpp:38:22:38:24 | call to vector | vector.cpp:45:7:45:8 | v1 | | +| vector.cpp:38:22:38:24 | call to vector | vector.cpp:46:7:46:8 | v1 | | +| vector.cpp:38:22:38:24 | call to vector | vector.cpp:47:7:47:8 | v1 | | +| vector.cpp:38:22:38:24 | call to vector | vector.cpp:48:7:48:8 | v1 | | +| vector.cpp:38:22:38:24 | call to vector | vector.cpp:49:7:49:8 | v1 | | +| vector.cpp:38:22:38:24 | call to vector | vector.cpp:101:1:101:1 | v1 | | +| vector.cpp:38:30:38:32 | call to vector | vector.cpp:51:2:51:3 | v2 | | +| vector.cpp:38:30:38:32 | call to vector | vector.cpp:52:7:52:8 | v2 | | +| vector.cpp:38:30:38:32 | call to vector | vector.cpp:53:7:53:8 | v2 | | +| vector.cpp:38:30:38:32 | call to vector | vector.cpp:54:7:54:8 | v2 | | +| vector.cpp:38:30:38:32 | call to vector | vector.cpp:55:7:55:8 | v2 | | +| vector.cpp:38:30:38:32 | call to vector | vector.cpp:57:7:57:8 | v2 | | +| vector.cpp:38:30:38:32 | call to vector | vector.cpp:101:1:101:1 | v2 | | +| vector.cpp:38:38:38:40 | call to vector | vector.cpp:57:2:57:3 | v3 | | +| vector.cpp:38:38:38:40 | call to vector | vector.cpp:58:7:58:8 | v3 | | +| vector.cpp:38:38:38:40 | call to vector | vector.cpp:59:7:59:8 | v3 | | +| vector.cpp:38:38:38:40 | call to vector | vector.cpp:60:7:60:8 | v3 | | +| vector.cpp:38:38:38:40 | call to vector | vector.cpp:61:7:61:8 | v3 | | +| vector.cpp:38:38:38:40 | call to vector | vector.cpp:101:1:101:1 | v3 | | +| vector.cpp:38:46:38:48 | call to vector | vector.cpp:63:2:63:3 | v4 | | +| vector.cpp:38:46:38:48 | call to vector | vector.cpp:64:7:64:8 | v4 | | +| vector.cpp:38:46:38:48 | call to vector | vector.cpp:65:7:65:8 | v4 | | +| vector.cpp:38:46:38:48 | call to vector | vector.cpp:66:7:66:8 | v4 | | +| vector.cpp:38:46:38:48 | call to vector | vector.cpp:67:7:67:8 | v4 | | +| vector.cpp:38:46:38:48 | call to vector | vector.cpp:101:1:101:1 | v4 | | +| vector.cpp:38:54:38:56 | call to vector | vector.cpp:69:2:69:3 | v5 | | +| vector.cpp:38:54:38:56 | call to vector | vector.cpp:70:7:70:8 | v5 | | +| vector.cpp:38:54:38:56 | call to vector | vector.cpp:71:7:71:8 | v5 | | +| vector.cpp:38:54:38:56 | call to vector | vector.cpp:72:7:72:8 | v5 | | +| vector.cpp:38:54:38:56 | call to vector | vector.cpp:101:1:101:1 | v5 | | +| vector.cpp:38:62:38:64 | call to vector | vector.cpp:74:2:74:3 | v6 | | +| vector.cpp:38:62:38:64 | call to vector | vector.cpp:75:7:75:8 | v6 | | +| vector.cpp:38:62:38:64 | call to vector | vector.cpp:76:7:76:8 | v6 | | +| vector.cpp:38:62:38:64 | call to vector | vector.cpp:101:1:101:1 | v6 | | +| vector.cpp:38:70:38:72 | call to vector | vector.cpp:80:41:80:42 | v7 | | +| vector.cpp:38:70:38:72 | call to vector | vector.cpp:81:3:81:4 | v7 | | +| vector.cpp:38:70:38:72 | call to vector | vector.cpp:83:7:83:8 | v7 | | +| vector.cpp:38:70:38:72 | call to vector | vector.cpp:84:7:84:8 | v7 | | +| vector.cpp:38:70:38:72 | call to vector | vector.cpp:85:7:85:8 | v7 | | +| vector.cpp:38:70:38:72 | call to vector | vector.cpp:101:1:101:1 | v7 | | +| vector.cpp:38:78:38:80 | call to vector | vector.cpp:88:33:88:34 | v8 | | +| vector.cpp:38:78:38:80 | call to vector | vector.cpp:90:3:90:4 | v8 | | +| vector.cpp:38:78:38:80 | call to vector | vector.cpp:92:7:92:8 | v8 | | +| vector.cpp:38:78:38:80 | call to vector | vector.cpp:93:7:93:8 | v8 | | +| vector.cpp:38:78:38:80 | call to vector | vector.cpp:94:7:94:8 | v8 | | +| vector.cpp:38:78:38:80 | call to vector | vector.cpp:101:1:101:1 | v8 | | +| vector.cpp:38:86:38:88 | call to vector | vector.cpp:96:2:96:3 | v9 | | +| vector.cpp:38:86:38:88 | call to vector | vector.cpp:97:7:97:8 | v9 | | +| vector.cpp:38:86:38:88 | call to vector | vector.cpp:98:7:98:8 | v9 | | +| vector.cpp:38:86:38:88 | call to vector | vector.cpp:99:7:99:8 | v9 | | +| vector.cpp:38:86:38:88 | call to vector | vector.cpp:100:7:100:8 | v9 | | +| vector.cpp:38:86:38:88 | call to vector | vector.cpp:101:1:101:1 | v9 | | +| vector.cpp:40:2:40:3 | ref arg v1 | vector.cpp:41:2:41:3 | v1 | | +| vector.cpp:40:2:40:3 | ref arg v1 | vector.cpp:42:2:42:3 | v1 | | +| vector.cpp:40:2:40:3 | ref arg v1 | vector.cpp:43:2:43:3 | v1 | | +| vector.cpp:40:2:40:3 | ref arg v1 | vector.cpp:44:7:44:8 | v1 | | +| vector.cpp:40:2:40:3 | ref arg v1 | vector.cpp:45:7:45:8 | v1 | | +| vector.cpp:40:2:40:3 | ref arg v1 | vector.cpp:46:7:46:8 | v1 | | +| vector.cpp:40:2:40:3 | ref arg v1 | vector.cpp:47:7:47:8 | v1 | | +| vector.cpp:40:2:40:3 | ref arg v1 | vector.cpp:48:7:48:8 | v1 | | +| vector.cpp:40:2:40:3 | ref arg v1 | vector.cpp:49:7:49:8 | v1 | | +| vector.cpp:40:2:40:3 | ref arg v1 | vector.cpp:101:1:101:1 | v1 | | +| vector.cpp:40:2:40:3 | v1 | vector.cpp:40:4:40:4 | call to operator[] | TAINT | +| vector.cpp:40:2:40:10 | ... = ... | vector.cpp:40:4:40:4 | call to operator[] [post update] | | +| vector.cpp:40:4:40:4 | call to operator[] [post update] | vector.cpp:40:2:40:3 | ref arg v1 | TAINT | +| vector.cpp:40:10:40:10 | 0 | vector.cpp:40:2:40:10 | ... = ... | | +| vector.cpp:41:2:41:3 | ref arg v1 | vector.cpp:42:2:42:3 | v1 | | +| vector.cpp:41:2:41:3 | ref arg v1 | vector.cpp:43:2:43:3 | v1 | | +| vector.cpp:41:2:41:3 | ref arg v1 | vector.cpp:44:7:44:8 | v1 | | +| vector.cpp:41:2:41:3 | ref arg v1 | vector.cpp:45:7:45:8 | v1 | | +| vector.cpp:41:2:41:3 | ref arg v1 | vector.cpp:46:7:46:8 | v1 | | +| vector.cpp:41:2:41:3 | ref arg v1 | vector.cpp:47:7:47:8 | v1 | | +| vector.cpp:41:2:41:3 | ref arg v1 | vector.cpp:48:7:48:8 | v1 | | +| vector.cpp:41:2:41:3 | ref arg v1 | vector.cpp:49:7:49:8 | v1 | | +| vector.cpp:41:2:41:3 | ref arg v1 | vector.cpp:101:1:101:1 | v1 | | +| vector.cpp:41:2:41:3 | v1 | vector.cpp:41:4:41:4 | call to operator[] | TAINT | +| vector.cpp:41:2:41:10 | ... = ... | vector.cpp:41:4:41:4 | call to operator[] [post update] | | +| vector.cpp:41:4:41:4 | call to operator[] [post update] | vector.cpp:41:2:41:3 | ref arg v1 | TAINT | +| vector.cpp:41:10:41:10 | 0 | vector.cpp:41:2:41:10 | ... = ... | | +| vector.cpp:42:2:42:3 | ref arg v1 | vector.cpp:43:2:43:3 | v1 | | +| vector.cpp:42:2:42:3 | ref arg v1 | vector.cpp:44:7:44:8 | v1 | | +| vector.cpp:42:2:42:3 | ref arg v1 | vector.cpp:45:7:45:8 | v1 | | +| vector.cpp:42:2:42:3 | ref arg v1 | vector.cpp:46:7:46:8 | v1 | | +| vector.cpp:42:2:42:3 | ref arg v1 | vector.cpp:47:7:47:8 | v1 | | +| vector.cpp:42:2:42:3 | ref arg v1 | vector.cpp:48:7:48:8 | v1 | | +| vector.cpp:42:2:42:3 | ref arg v1 | vector.cpp:49:7:49:8 | v1 | | +| vector.cpp:42:2:42:3 | ref arg v1 | vector.cpp:101:1:101:1 | v1 | | +| vector.cpp:42:2:42:3 | v1 | vector.cpp:42:4:42:4 | call to operator[] | TAINT | +| vector.cpp:42:2:42:10 | ... = ... | vector.cpp:42:4:42:4 | call to operator[] [post update] | | +| vector.cpp:42:4:42:4 | call to operator[] [post update] | vector.cpp:42:2:42:3 | ref arg v1 | TAINT | +| vector.cpp:42:10:42:10 | 0 | vector.cpp:42:2:42:10 | ... = ... | | +| vector.cpp:43:2:43:3 | ref arg v1 | vector.cpp:44:7:44:8 | v1 | | +| vector.cpp:43:2:43:3 | ref arg v1 | vector.cpp:45:7:45:8 | v1 | | +| vector.cpp:43:2:43:3 | ref arg v1 | vector.cpp:46:7:46:8 | v1 | | +| vector.cpp:43:2:43:3 | ref arg v1 | vector.cpp:47:7:47:8 | v1 | | +| vector.cpp:43:2:43:3 | ref arg v1 | vector.cpp:48:7:48:8 | v1 | | +| vector.cpp:43:2:43:3 | ref arg v1 | vector.cpp:49:7:49:8 | v1 | | +| vector.cpp:43:2:43:3 | ref arg v1 | vector.cpp:101:1:101:1 | v1 | | +| vector.cpp:43:15:43:15 | 1 | vector.cpp:43:2:43:3 | ref arg v1 | TAINT | +| vector.cpp:44:7:44:8 | ref arg v1 | vector.cpp:45:7:45:8 | v1 | | +| vector.cpp:44:7:44:8 | ref arg v1 | vector.cpp:46:7:46:8 | v1 | | +| vector.cpp:44:7:44:8 | ref arg v1 | vector.cpp:47:7:47:8 | v1 | | +| vector.cpp:44:7:44:8 | ref arg v1 | vector.cpp:48:7:48:8 | v1 | | +| vector.cpp:44:7:44:8 | ref arg v1 | vector.cpp:49:7:49:8 | v1 | | +| vector.cpp:44:7:44:8 | ref arg v1 | vector.cpp:101:1:101:1 | v1 | | +| vector.cpp:45:7:45:8 | ref arg v1 | vector.cpp:46:7:46:8 | v1 | | +| vector.cpp:45:7:45:8 | ref arg v1 | vector.cpp:47:7:47:8 | v1 | | +| vector.cpp:45:7:45:8 | ref arg v1 | vector.cpp:48:7:48:8 | v1 | | +| vector.cpp:45:7:45:8 | ref arg v1 | vector.cpp:49:7:49:8 | v1 | | +| vector.cpp:45:7:45:8 | ref arg v1 | vector.cpp:101:1:101:1 | v1 | | +| vector.cpp:45:7:45:8 | v1 | vector.cpp:45:9:45:9 | call to operator[] | TAINT | +| vector.cpp:46:7:46:8 | ref arg v1 | vector.cpp:47:7:47:8 | v1 | | +| vector.cpp:46:7:46:8 | ref arg v1 | vector.cpp:48:7:48:8 | v1 | | +| vector.cpp:46:7:46:8 | ref arg v1 | vector.cpp:49:7:49:8 | v1 | | +| vector.cpp:46:7:46:8 | ref arg v1 | vector.cpp:101:1:101:1 | v1 | | +| vector.cpp:46:7:46:8 | v1 | vector.cpp:46:9:46:9 | call to operator[] | TAINT | +| vector.cpp:47:7:47:8 | ref arg v1 | vector.cpp:48:7:48:8 | v1 | | +| vector.cpp:47:7:47:8 | ref arg v1 | vector.cpp:49:7:49:8 | v1 | | +| vector.cpp:47:7:47:8 | ref arg v1 | vector.cpp:101:1:101:1 | v1 | | +| vector.cpp:47:7:47:8 | v1 | vector.cpp:47:9:47:9 | call to operator[] | TAINT | +| vector.cpp:48:7:48:8 | ref arg v1 | vector.cpp:49:7:49:8 | v1 | | +| vector.cpp:48:7:48:8 | ref arg v1 | vector.cpp:101:1:101:1 | v1 | | +| vector.cpp:48:7:48:8 | v1 | vector.cpp:48:10:48:14 | call to front | TAINT | +| vector.cpp:49:7:49:8 | ref arg v1 | vector.cpp:101:1:101:1 | v1 | | +| vector.cpp:49:7:49:8 | v1 | vector.cpp:49:10:49:13 | call to back | TAINT | +| vector.cpp:51:2:51:3 | ref arg v2 | vector.cpp:52:7:52:8 | v2 | | +| vector.cpp:51:2:51:3 | ref arg v2 | vector.cpp:53:7:53:8 | v2 | | +| vector.cpp:51:2:51:3 | ref arg v2 | vector.cpp:54:7:54:8 | v2 | | +| vector.cpp:51:2:51:3 | ref arg v2 | vector.cpp:55:7:55:8 | v2 | | +| vector.cpp:51:2:51:3 | ref arg v2 | vector.cpp:57:7:57:8 | v2 | | +| vector.cpp:51:2:51:3 | ref arg v2 | vector.cpp:101:1:101:1 | v2 | | +| vector.cpp:51:2:51:3 | v2 | vector.cpp:51:4:51:4 | call to operator[] | TAINT | +| vector.cpp:51:2:51:17 | ... = ... | vector.cpp:51:4:51:4 | call to operator[] [post update] | | +| vector.cpp:51:4:51:4 | call to operator[] [post update] | vector.cpp:51:2:51:3 | ref arg v2 | TAINT | +| vector.cpp:51:10:51:15 | call to source | vector.cpp:51:2:51:17 | ... = ... | | +| vector.cpp:52:7:52:8 | ref arg v2 | vector.cpp:53:7:53:8 | v2 | | +| vector.cpp:52:7:52:8 | ref arg v2 | vector.cpp:54:7:54:8 | v2 | | +| vector.cpp:52:7:52:8 | ref arg v2 | vector.cpp:55:7:55:8 | v2 | | +| vector.cpp:52:7:52:8 | ref arg v2 | vector.cpp:57:7:57:8 | v2 | | +| vector.cpp:52:7:52:8 | ref arg v2 | vector.cpp:101:1:101:1 | v2 | | +| vector.cpp:53:7:53:8 | ref arg v2 | vector.cpp:54:7:54:8 | v2 | | +| vector.cpp:53:7:53:8 | ref arg v2 | vector.cpp:55:7:55:8 | v2 | | +| vector.cpp:53:7:53:8 | ref arg v2 | vector.cpp:57:7:57:8 | v2 | | +| vector.cpp:53:7:53:8 | ref arg v2 | vector.cpp:101:1:101:1 | v2 | | +| vector.cpp:53:7:53:8 | v2 | vector.cpp:53:9:53:9 | call to operator[] | TAINT | +| vector.cpp:54:7:54:8 | ref arg v2 | vector.cpp:55:7:55:8 | v2 | | +| vector.cpp:54:7:54:8 | ref arg v2 | vector.cpp:57:7:57:8 | v2 | | +| vector.cpp:54:7:54:8 | ref arg v2 | vector.cpp:101:1:101:1 | v2 | | +| vector.cpp:54:7:54:8 | v2 | vector.cpp:54:9:54:9 | call to operator[] | TAINT | +| vector.cpp:55:7:55:8 | ref arg v2 | vector.cpp:57:7:57:8 | v2 | | +| vector.cpp:55:7:55:8 | ref arg v2 | vector.cpp:101:1:101:1 | v2 | | +| vector.cpp:55:7:55:8 | v2 | vector.cpp:55:9:55:9 | call to operator[] | TAINT | +| vector.cpp:57:2:57:3 | ref arg v3 | vector.cpp:58:7:58:8 | v3 | | +| vector.cpp:57:2:57:3 | ref arg v3 | vector.cpp:59:7:59:8 | v3 | | +| vector.cpp:57:2:57:3 | ref arg v3 | vector.cpp:60:7:60:8 | v3 | | +| vector.cpp:57:2:57:3 | ref arg v3 | vector.cpp:61:7:61:8 | v3 | | +| vector.cpp:57:2:57:3 | ref arg v3 | vector.cpp:101:1:101:1 | v3 | | +| vector.cpp:57:7:57:8 | v2 | vector.cpp:57:2:57:3 | ref arg v3 | TAINT | +| vector.cpp:57:7:57:8 | v2 | vector.cpp:57:5:57:5 | call to operator= | TAINT | +| vector.cpp:58:7:58:8 | ref arg v3 | vector.cpp:59:7:59:8 | v3 | | +| vector.cpp:58:7:58:8 | ref arg v3 | vector.cpp:60:7:60:8 | v3 | | +| vector.cpp:58:7:58:8 | ref arg v3 | vector.cpp:61:7:61:8 | v3 | | +| vector.cpp:58:7:58:8 | ref arg v3 | vector.cpp:101:1:101:1 | v3 | | +| vector.cpp:59:7:59:8 | ref arg v3 | vector.cpp:60:7:60:8 | v3 | | +| vector.cpp:59:7:59:8 | ref arg v3 | vector.cpp:61:7:61:8 | v3 | | +| vector.cpp:59:7:59:8 | ref arg v3 | vector.cpp:101:1:101:1 | v3 | | +| vector.cpp:59:7:59:8 | v3 | vector.cpp:59:9:59:9 | call to operator[] | TAINT | +| vector.cpp:60:7:60:8 | ref arg v3 | vector.cpp:61:7:61:8 | v3 | | +| vector.cpp:60:7:60:8 | ref arg v3 | vector.cpp:101:1:101:1 | v3 | | +| vector.cpp:60:7:60:8 | v3 | vector.cpp:60:9:60:9 | call to operator[] | TAINT | +| vector.cpp:61:7:61:8 | ref arg v3 | vector.cpp:101:1:101:1 | v3 | | +| vector.cpp:61:7:61:8 | v3 | vector.cpp:61:9:61:9 | call to operator[] | TAINT | +| vector.cpp:63:2:63:3 | ref arg v4 | vector.cpp:64:7:64:8 | v4 | | +| vector.cpp:63:2:63:3 | ref arg v4 | vector.cpp:65:7:65:8 | v4 | | +| vector.cpp:63:2:63:3 | ref arg v4 | vector.cpp:66:7:66:8 | v4 | | +| vector.cpp:63:2:63:3 | ref arg v4 | vector.cpp:67:7:67:8 | v4 | | +| vector.cpp:63:2:63:3 | ref arg v4 | vector.cpp:101:1:101:1 | v4 | | +| vector.cpp:63:2:63:3 | v4 | vector.cpp:63:4:63:4 | call to operator[] | TAINT | +| vector.cpp:63:2:63:17 | ... = ... | vector.cpp:63:4:63:4 | call to operator[] [post update] | | +| vector.cpp:63:4:63:4 | call to operator[] [post update] | vector.cpp:63:2:63:3 | ref arg v4 | TAINT | +| vector.cpp:63:10:63:15 | call to source | vector.cpp:63:2:63:17 | ... = ... | | +| vector.cpp:64:7:64:8 | ref arg v4 | vector.cpp:65:7:65:8 | v4 | | +| vector.cpp:64:7:64:8 | ref arg v4 | vector.cpp:66:7:66:8 | v4 | | +| vector.cpp:64:7:64:8 | ref arg v4 | vector.cpp:67:7:67:8 | v4 | | +| vector.cpp:64:7:64:8 | ref arg v4 | vector.cpp:101:1:101:1 | v4 | | +| vector.cpp:65:7:65:8 | ref arg v4 | vector.cpp:66:7:66:8 | v4 | | +| vector.cpp:65:7:65:8 | ref arg v4 | vector.cpp:67:7:67:8 | v4 | | +| vector.cpp:65:7:65:8 | ref arg v4 | vector.cpp:101:1:101:1 | v4 | | +| vector.cpp:65:7:65:8 | v4 | vector.cpp:65:9:65:9 | call to operator[] | TAINT | +| vector.cpp:66:7:66:8 | ref arg v4 | vector.cpp:67:7:67:8 | v4 | | +| vector.cpp:66:7:66:8 | ref arg v4 | vector.cpp:101:1:101:1 | v4 | | +| vector.cpp:66:7:66:8 | v4 | vector.cpp:66:9:66:9 | call to operator[] | TAINT | +| vector.cpp:67:7:67:8 | ref arg v4 | vector.cpp:101:1:101:1 | v4 | | +| vector.cpp:67:7:67:8 | v4 | vector.cpp:67:9:67:9 | call to operator[] | TAINT | +| vector.cpp:69:2:69:3 | ref arg v5 | vector.cpp:70:7:70:8 | v5 | | +| vector.cpp:69:2:69:3 | ref arg v5 | vector.cpp:71:7:71:8 | v5 | | +| vector.cpp:69:2:69:3 | ref arg v5 | vector.cpp:72:7:72:8 | v5 | | +| vector.cpp:69:2:69:3 | ref arg v5 | vector.cpp:101:1:101:1 | v5 | | +| vector.cpp:69:15:69:20 | call to source | vector.cpp:69:2:69:3 | ref arg v5 | TAINT | +| vector.cpp:70:7:70:8 | ref arg v5 | vector.cpp:71:7:71:8 | v5 | | +| vector.cpp:70:7:70:8 | ref arg v5 | vector.cpp:72:7:72:8 | v5 | | +| vector.cpp:70:7:70:8 | ref arg v5 | vector.cpp:101:1:101:1 | v5 | | +| vector.cpp:71:7:71:8 | ref arg v5 | vector.cpp:72:7:72:8 | v5 | | +| vector.cpp:71:7:71:8 | ref arg v5 | vector.cpp:101:1:101:1 | v5 | | +| vector.cpp:71:7:71:8 | v5 | vector.cpp:71:10:71:14 | call to front | TAINT | +| vector.cpp:72:7:72:8 | ref arg v5 | vector.cpp:101:1:101:1 | v5 | | +| vector.cpp:72:7:72:8 | v5 | vector.cpp:72:10:72:13 | call to back | TAINT | +| vector.cpp:74:2:74:3 | ref arg v6 | vector.cpp:75:7:75:8 | v6 | | +| vector.cpp:74:2:74:3 | ref arg v6 | vector.cpp:76:7:76:8 | v6 | | +| vector.cpp:74:2:74:3 | ref arg v6 | vector.cpp:101:1:101:1 | v6 | | +| vector.cpp:74:2:74:3 | v6 | vector.cpp:74:5:74:8 | call to data | TAINT | +| vector.cpp:74:2:74:13 | access to array [post update] | vector.cpp:74:5:74:8 | call to data [inner post update] | | +| vector.cpp:74:2:74:24 | ... = ... | vector.cpp:74:2:74:13 | access to array [post update] | | +| vector.cpp:74:5:74:8 | call to data | vector.cpp:74:2:74:13 | access to array | TAINT | +| vector.cpp:74:5:74:8 | call to data [inner post update] | vector.cpp:74:2:74:3 | ref arg v6 | TAINT | +| vector.cpp:74:12:74:12 | 2 | vector.cpp:74:2:74:13 | access to array | TAINT | +| vector.cpp:74:17:74:22 | call to source | vector.cpp:74:2:74:24 | ... = ... | | +| vector.cpp:75:7:75:8 | ref arg v6 | vector.cpp:76:7:76:8 | v6 | | +| vector.cpp:75:7:75:8 | ref arg v6 | vector.cpp:101:1:101:1 | v6 | | +| vector.cpp:76:7:76:8 | ref arg v6 | vector.cpp:101:1:101:1 | v6 | | +| vector.cpp:76:7:76:8 | v6 | vector.cpp:76:10:76:13 | call to data | TAINT | +| vector.cpp:76:10:76:13 | call to data | vector.cpp:76:7:76:18 | access to array | TAINT | +| vector.cpp:76:17:76:17 | 2 | vector.cpp:76:7:76:18 | access to array | TAINT | +| vector.cpp:80:40:80:50 | call to iterator | vector.cpp:81:13:81:14 | it | | +| vector.cpp:80:41:80:42 | ref arg v7 | vector.cpp:81:3:81:4 | v7 | | +| vector.cpp:80:41:80:42 | ref arg v7 | vector.cpp:83:7:83:8 | v7 | | +| vector.cpp:80:41:80:42 | ref arg v7 | vector.cpp:84:7:84:8 | v7 | | +| vector.cpp:80:41:80:42 | ref arg v7 | vector.cpp:85:7:85:8 | v7 | | +| vector.cpp:80:41:80:42 | ref arg v7 | vector.cpp:101:1:101:1 | v7 | | +| vector.cpp:80:41:80:42 | v7 | vector.cpp:80:44:80:48 | call to begin | TAINT | +| vector.cpp:80:44:80:48 | call to begin | vector.cpp:80:40:80:50 | call to iterator | TAINT | +| vector.cpp:81:3:81:4 | ref arg v7 | vector.cpp:83:7:83:8 | v7 | | +| vector.cpp:81:3:81:4 | ref arg v7 | vector.cpp:84:7:84:8 | v7 | | +| vector.cpp:81:3:81:4 | ref arg v7 | vector.cpp:85:7:85:8 | v7 | | +| vector.cpp:81:3:81:4 | ref arg v7 | vector.cpp:101:1:101:1 | v7 | | +| vector.cpp:81:3:81:4 | v7 | vector.cpp:81:6:81:11 | call to insert | TAINT | +| vector.cpp:81:17:81:22 | call to source | vector.cpp:81:3:81:4 | ref arg v7 | TAINT | +| vector.cpp:81:17:81:22 | call to source | vector.cpp:81:6:81:11 | call to insert | TAINT | +| vector.cpp:83:7:83:8 | ref arg v7 | vector.cpp:84:7:84:8 | v7 | | +| vector.cpp:83:7:83:8 | ref arg v7 | vector.cpp:85:7:85:8 | v7 | | +| vector.cpp:83:7:83:8 | ref arg v7 | vector.cpp:101:1:101:1 | v7 | | +| vector.cpp:84:7:84:8 | ref arg v7 | vector.cpp:85:7:85:8 | v7 | | +| vector.cpp:84:7:84:8 | ref arg v7 | vector.cpp:101:1:101:1 | v7 | | +| vector.cpp:84:7:84:8 | v7 | vector.cpp:84:10:84:14 | call to front | TAINT | +| vector.cpp:85:7:85:8 | ref arg v7 | vector.cpp:101:1:101:1 | v7 | | +| vector.cpp:85:7:85:8 | v7 | vector.cpp:85:10:85:13 | call to back | TAINT | +| vector.cpp:88:33:88:34 | v8 | vector.cpp:89:41:89:43 | v8c | | +| vector.cpp:89:41:89:43 | v8c | vector.cpp:89:45:89:49 | call to begin | TAINT | +| vector.cpp:89:45:89:49 | call to begin | vector.cpp:90:13:90:14 | it | | +| vector.cpp:90:3:90:4 | ref arg v8 | vector.cpp:92:7:92:8 | v8 | | +| vector.cpp:90:3:90:4 | ref arg v8 | vector.cpp:93:7:93:8 | v8 | | +| vector.cpp:90:3:90:4 | ref arg v8 | vector.cpp:94:7:94:8 | v8 | | +| vector.cpp:90:3:90:4 | ref arg v8 | vector.cpp:101:1:101:1 | v8 | | +| vector.cpp:90:3:90:4 | v8 | vector.cpp:90:6:90:11 | call to insert | TAINT | +| vector.cpp:92:7:92:8 | ref arg v8 | vector.cpp:93:7:93:8 | v8 | | +| vector.cpp:92:7:92:8 | ref arg v8 | vector.cpp:94:7:94:8 | v8 | | +| vector.cpp:92:7:92:8 | ref arg v8 | vector.cpp:101:1:101:1 | v8 | | +| vector.cpp:93:7:93:8 | ref arg v8 | vector.cpp:94:7:94:8 | v8 | | +| vector.cpp:93:7:93:8 | ref arg v8 | vector.cpp:101:1:101:1 | v8 | | +| vector.cpp:93:7:93:8 | v8 | vector.cpp:93:10:93:14 | call to front | TAINT | +| vector.cpp:94:7:94:8 | ref arg v8 | vector.cpp:101:1:101:1 | v8 | | +| vector.cpp:94:7:94:8 | v8 | vector.cpp:94:10:94:13 | call to back | TAINT | +| vector.cpp:96:2:96:3 | ref arg v9 | vector.cpp:97:7:97:8 | v9 | | +| vector.cpp:96:2:96:3 | ref arg v9 | vector.cpp:98:7:98:8 | v9 | | +| vector.cpp:96:2:96:3 | ref arg v9 | vector.cpp:99:7:99:8 | v9 | | +| vector.cpp:96:2:96:3 | ref arg v9 | vector.cpp:100:7:100:8 | v9 | | +| vector.cpp:96:2:96:3 | ref arg v9 | vector.cpp:101:1:101:1 | v9 | | +| vector.cpp:96:2:96:3 | v9 | vector.cpp:96:5:96:6 | call to at | TAINT | +| vector.cpp:96:2:96:20 | ... = ... | vector.cpp:96:5:96:6 | call to at [post update] | | +| vector.cpp:96:5:96:6 | call to at [post update] | vector.cpp:96:2:96:3 | ref arg v9 | TAINT | +| vector.cpp:96:13:96:18 | call to source | vector.cpp:96:2:96:20 | ... = ... | | +| vector.cpp:97:7:97:8 | ref arg v9 | vector.cpp:98:7:98:8 | v9 | | +| vector.cpp:97:7:97:8 | ref arg v9 | vector.cpp:99:7:99:8 | v9 | | +| vector.cpp:97:7:97:8 | ref arg v9 | vector.cpp:100:7:100:8 | v9 | | +| vector.cpp:97:7:97:8 | ref arg v9 | vector.cpp:101:1:101:1 | v9 | | +| vector.cpp:98:7:98:8 | ref arg v9 | vector.cpp:99:7:99:8 | v9 | | +| vector.cpp:98:7:98:8 | ref arg v9 | vector.cpp:100:7:100:8 | v9 | | +| vector.cpp:98:7:98:8 | ref arg v9 | vector.cpp:101:1:101:1 | v9 | | +| vector.cpp:98:7:98:8 | v9 | vector.cpp:98:10:98:11 | call to at | TAINT | +| vector.cpp:99:7:99:8 | ref arg v9 | vector.cpp:100:7:100:8 | v9 | | +| vector.cpp:99:7:99:8 | ref arg v9 | vector.cpp:101:1:101:1 | v9 | | +| vector.cpp:99:7:99:8 | v9 | vector.cpp:99:10:99:11 | call to at | TAINT | +| vector.cpp:100:7:100:8 | ref arg v9 | vector.cpp:101:1:101:1 | v9 | | +| vector.cpp:100:7:100:8 | v9 | vector.cpp:100:10:100:11 | call to at | TAINT | +| vector.cpp:104:22:104:24 | call to vector | vector.cpp:106:2:106:3 | v1 | | +| vector.cpp:104:22:104:24 | call to vector | vector.cpp:109:7:109:8 | v1 | | +| vector.cpp:104:22:104:24 | call to vector | vector.cpp:114:2:114:3 | v1 | | +| vector.cpp:104:22:104:24 | call to vector | vector.cpp:117:7:117:8 | v1 | | +| vector.cpp:104:22:104:24 | call to vector | vector.cpp:121:1:121:1 | v1 | | +| vector.cpp:104:30:104:32 | call to vector | vector.cpp:110:7:110:8 | v2 | | +| vector.cpp:104:30:104:32 | call to vector | vector.cpp:114:10:114:11 | v2 | | +| vector.cpp:104:30:104:32 | call to vector | vector.cpp:118:7:118:8 | v2 | | +| vector.cpp:104:30:104:32 | call to vector | vector.cpp:121:1:121:1 | v2 | | +| vector.cpp:104:38:104:40 | call to vector | vector.cpp:111:7:111:8 | v3 | | +| vector.cpp:104:38:104:40 | call to vector | vector.cpp:115:2:115:3 | v3 | | +| vector.cpp:104:38:104:40 | call to vector | vector.cpp:119:7:119:8 | v3 | | +| vector.cpp:104:38:104:40 | call to vector | vector.cpp:121:1:121:1 | v3 | | +| vector.cpp:104:46:104:48 | call to vector | vector.cpp:107:2:107:3 | v4 | | +| vector.cpp:104:46:104:48 | call to vector | vector.cpp:112:7:112:8 | v4 | | +| vector.cpp:104:46:104:48 | call to vector | vector.cpp:115:10:115:11 | v4 | | +| vector.cpp:104:46:104:48 | call to vector | vector.cpp:120:7:120:8 | v4 | | +| vector.cpp:104:46:104:48 | call to vector | vector.cpp:121:1:121:1 | v4 | | +| vector.cpp:106:2:106:3 | ref arg v1 | vector.cpp:109:7:109:8 | v1 | | +| vector.cpp:106:2:106:3 | ref arg v1 | vector.cpp:114:2:114:3 | v1 | | +| vector.cpp:106:2:106:3 | ref arg v1 | vector.cpp:117:7:117:8 | v1 | | +| vector.cpp:106:2:106:3 | ref arg v1 | vector.cpp:121:1:121:1 | v1 | | +| vector.cpp:106:15:106:20 | call to source | vector.cpp:106:2:106:3 | ref arg v1 | TAINT | +| vector.cpp:107:2:107:3 | ref arg v4 | vector.cpp:112:7:112:8 | v4 | | +| vector.cpp:107:2:107:3 | ref arg v4 | vector.cpp:115:10:115:11 | v4 | | +| vector.cpp:107:2:107:3 | ref arg v4 | vector.cpp:120:7:120:8 | v4 | | +| vector.cpp:107:2:107:3 | ref arg v4 | vector.cpp:121:1:121:1 | v4 | | +| vector.cpp:107:15:107:20 | call to source | vector.cpp:107:2:107:3 | ref arg v4 | TAINT | +| vector.cpp:109:7:109:8 | ref arg v1 | vector.cpp:114:2:114:3 | v1 | | +| vector.cpp:109:7:109:8 | ref arg v1 | vector.cpp:117:7:117:8 | v1 | | +| vector.cpp:109:7:109:8 | ref arg v1 | vector.cpp:121:1:121:1 | v1 | | +| vector.cpp:110:7:110:8 | ref arg v2 | vector.cpp:114:10:114:11 | v2 | | +| vector.cpp:110:7:110:8 | ref arg v2 | vector.cpp:118:7:118:8 | v2 | | +| vector.cpp:110:7:110:8 | ref arg v2 | vector.cpp:121:1:121:1 | v2 | | +| vector.cpp:111:7:111:8 | ref arg v3 | vector.cpp:115:2:115:3 | v3 | | +| vector.cpp:111:7:111:8 | ref arg v3 | vector.cpp:119:7:119:8 | v3 | | +| vector.cpp:111:7:111:8 | ref arg v3 | vector.cpp:121:1:121:1 | v3 | | +| vector.cpp:112:7:112:8 | ref arg v4 | vector.cpp:115:10:115:11 | v4 | | +| vector.cpp:112:7:112:8 | ref arg v4 | vector.cpp:120:7:120:8 | v4 | | +| vector.cpp:112:7:112:8 | ref arg v4 | vector.cpp:121:1:121:1 | v4 | | +| vector.cpp:114:2:114:3 | ref arg v1 | vector.cpp:117:7:117:8 | v1 | | +| vector.cpp:114:2:114:3 | ref arg v1 | vector.cpp:121:1:121:1 | v1 | | +| vector.cpp:114:2:114:3 | v1 | vector.cpp:114:10:114:11 | ref arg v2 | TAINT | +| vector.cpp:114:10:114:11 | ref arg v2 | vector.cpp:118:7:118:8 | v2 | | +| vector.cpp:114:10:114:11 | ref arg v2 | vector.cpp:121:1:121:1 | v2 | | +| vector.cpp:114:10:114:11 | v2 | vector.cpp:114:2:114:3 | ref arg v1 | TAINT | +| vector.cpp:115:2:115:3 | ref arg v3 | vector.cpp:119:7:119:8 | v3 | | +| vector.cpp:115:2:115:3 | ref arg v3 | vector.cpp:121:1:121:1 | v3 | | +| vector.cpp:115:2:115:3 | v3 | vector.cpp:115:10:115:11 | ref arg v4 | TAINT | +| vector.cpp:115:10:115:11 | ref arg v4 | vector.cpp:120:7:120:8 | v4 | | +| vector.cpp:115:10:115:11 | ref arg v4 | vector.cpp:121:1:121:1 | v4 | | +| vector.cpp:115:10:115:11 | v4 | vector.cpp:115:2:115:3 | ref arg v3 | TAINT | +| vector.cpp:117:7:117:8 | ref arg v1 | vector.cpp:121:1:121:1 | v1 | | +| vector.cpp:118:7:118:8 | ref arg v2 | vector.cpp:121:1:121:1 | v2 | | +| vector.cpp:119:7:119:8 | ref arg v3 | vector.cpp:121:1:121:1 | v3 | | +| vector.cpp:120:7:120:8 | ref arg v4 | vector.cpp:121:1:121:1 | v4 | | +| vector.cpp:124:22:124:24 | call to vector | vector.cpp:126:2:126:3 | v1 | | +| vector.cpp:124:22:124:24 | call to vector | vector.cpp:130:7:130:8 | v1 | | +| vector.cpp:124:22:124:24 | call to vector | vector.cpp:135:2:135:3 | v1 | | +| vector.cpp:124:22:124:24 | call to vector | vector.cpp:139:7:139:8 | v1 | | +| vector.cpp:124:22:124:24 | call to vector | vector.cpp:143:1:143:1 | v1 | | +| vector.cpp:124:30:124:32 | call to vector | vector.cpp:127:2:127:3 | v2 | | +| vector.cpp:124:30:124:32 | call to vector | vector.cpp:131:7:131:8 | v2 | | +| vector.cpp:124:30:124:32 | call to vector | vector.cpp:136:2:136:3 | v2 | | +| vector.cpp:124:30:124:32 | call to vector | vector.cpp:136:7:136:8 | v2 | | +| vector.cpp:124:30:124:32 | call to vector | vector.cpp:140:7:140:8 | v2 | | +| vector.cpp:124:30:124:32 | call to vector | vector.cpp:143:1:143:1 | v2 | | +| vector.cpp:124:38:124:40 | call to vector | vector.cpp:128:2:128:3 | v3 | | +| vector.cpp:124:38:124:40 | call to vector | vector.cpp:132:7:132:8 | v3 | | +| vector.cpp:124:38:124:40 | call to vector | vector.cpp:137:2:137:3 | v3 | | +| vector.cpp:124:38:124:40 | call to vector | vector.cpp:141:7:141:8 | v3 | | +| vector.cpp:124:38:124:40 | call to vector | vector.cpp:143:1:143:1 | v3 | | +| vector.cpp:124:46:124:48 | call to vector | vector.cpp:133:7:133:8 | v4 | | +| vector.cpp:124:46:124:48 | call to vector | vector.cpp:137:7:137:8 | v4 | | +| vector.cpp:124:46:124:48 | call to vector | vector.cpp:142:7:142:8 | v4 | | +| vector.cpp:124:46:124:48 | call to vector | vector.cpp:143:1:143:1 | v4 | | +| vector.cpp:126:2:126:3 | ref arg v1 | vector.cpp:130:7:130:8 | v1 | | +| vector.cpp:126:2:126:3 | ref arg v1 | vector.cpp:135:2:135:3 | v1 | | +| vector.cpp:126:2:126:3 | ref arg v1 | vector.cpp:139:7:139:8 | v1 | | +| vector.cpp:126:2:126:3 | ref arg v1 | vector.cpp:143:1:143:1 | v1 | | +| vector.cpp:126:15:126:20 | call to source | vector.cpp:126:2:126:3 | ref arg v1 | TAINT | +| vector.cpp:127:2:127:3 | ref arg v2 | vector.cpp:131:7:131:8 | v2 | | +| vector.cpp:127:2:127:3 | ref arg v2 | vector.cpp:136:2:136:3 | v2 | | +| vector.cpp:127:2:127:3 | ref arg v2 | vector.cpp:136:7:136:8 | v2 | | +| vector.cpp:127:2:127:3 | ref arg v2 | vector.cpp:140:7:140:8 | v2 | | +| vector.cpp:127:2:127:3 | ref arg v2 | vector.cpp:143:1:143:1 | v2 | | +| vector.cpp:127:15:127:20 | call to source | vector.cpp:127:2:127:3 | ref arg v2 | TAINT | +| vector.cpp:128:2:128:3 | ref arg v3 | vector.cpp:132:7:132:8 | v3 | | +| vector.cpp:128:2:128:3 | ref arg v3 | vector.cpp:137:2:137:3 | v3 | | +| vector.cpp:128:2:128:3 | ref arg v3 | vector.cpp:141:7:141:8 | v3 | | +| vector.cpp:128:2:128:3 | ref arg v3 | vector.cpp:143:1:143:1 | v3 | | +| vector.cpp:128:15:128:20 | call to source | vector.cpp:128:2:128:3 | ref arg v3 | TAINT | +| vector.cpp:130:7:130:8 | ref arg v1 | vector.cpp:135:2:135:3 | v1 | | +| vector.cpp:130:7:130:8 | ref arg v1 | vector.cpp:139:7:139:8 | v1 | | +| vector.cpp:130:7:130:8 | ref arg v1 | vector.cpp:143:1:143:1 | v1 | | +| vector.cpp:131:7:131:8 | ref arg v2 | vector.cpp:136:2:136:3 | v2 | | +| vector.cpp:131:7:131:8 | ref arg v2 | vector.cpp:136:7:136:8 | v2 | | +| vector.cpp:131:7:131:8 | ref arg v2 | vector.cpp:140:7:140:8 | v2 | | +| vector.cpp:131:7:131:8 | ref arg v2 | vector.cpp:143:1:143:1 | v2 | | +| vector.cpp:132:7:132:8 | ref arg v3 | vector.cpp:137:2:137:3 | v3 | | +| vector.cpp:132:7:132:8 | ref arg v3 | vector.cpp:141:7:141:8 | v3 | | +| vector.cpp:132:7:132:8 | ref arg v3 | vector.cpp:143:1:143:1 | v3 | | +| vector.cpp:133:7:133:8 | ref arg v4 | vector.cpp:137:7:137:8 | v4 | | +| vector.cpp:133:7:133:8 | ref arg v4 | vector.cpp:142:7:142:8 | v4 | | +| vector.cpp:133:7:133:8 | ref arg v4 | vector.cpp:143:1:143:1 | v4 | | +| vector.cpp:135:2:135:3 | ref arg v1 | vector.cpp:139:7:139:8 | v1 | | +| vector.cpp:135:2:135:3 | ref arg v1 | vector.cpp:143:1:143:1 | v1 | | +| vector.cpp:136:2:136:3 | ref arg v2 | vector.cpp:140:7:140:8 | v2 | | +| vector.cpp:136:2:136:3 | ref arg v2 | vector.cpp:143:1:143:1 | v2 | | +| vector.cpp:136:7:136:8 | v2 | vector.cpp:136:2:136:3 | ref arg v2 | TAINT | +| vector.cpp:136:7:136:8 | v2 | vector.cpp:136:5:136:5 | call to operator= | TAINT | +| vector.cpp:137:2:137:3 | ref arg v3 | vector.cpp:141:7:141:8 | v3 | | +| vector.cpp:137:2:137:3 | ref arg v3 | vector.cpp:143:1:143:1 | v3 | | +| vector.cpp:137:7:137:8 | v4 | vector.cpp:137:2:137:3 | ref arg v3 | TAINT | +| vector.cpp:137:7:137:8 | v4 | vector.cpp:137:5:137:5 | call to operator= | TAINT | +| vector.cpp:139:7:139:8 | ref arg v1 | vector.cpp:143:1:143:1 | v1 | | +| vector.cpp:140:7:140:8 | ref arg v2 | vector.cpp:143:1:143:1 | v2 | | +| vector.cpp:141:7:141:8 | ref arg v3 | vector.cpp:143:1:143:1 | v3 | | +| vector.cpp:142:7:142:8 | ref arg v4 | vector.cpp:143:1:143:1 | v4 | | +| vector.cpp:150:8:150:8 | call to vector | vector.cpp:150:8:150:8 | constructor init of field vs | TAINT | +| vector.cpp:150:8:150:8 | call to ~vector | vector.cpp:150:8:150:8 | destructor field destruction of vs | TAINT | +| vector.cpp:150:8:150:8 | this | vector.cpp:150:8:150:8 | constructor init of field vs [pre-this] | | +| vector.cpp:158:19:158:22 | {...} | vector.cpp:160:8:160:9 | aa | | +| vector.cpp:158:19:158:22 | {...} | vector.cpp:161:3:161:4 | aa | | +| vector.cpp:158:19:158:22 | {...} | vector.cpp:162:8:162:9 | aa | | +| vector.cpp:158:21:158:21 | 0 | vector.cpp:158:21:158:21 | {...} | TAINT | +| vector.cpp:158:21:158:21 | {...} | vector.cpp:158:19:158:22 | {...} | TAINT | +| vector.cpp:160:8:160:9 | aa | vector.cpp:160:8:160:12 | access to array | TAINT | +| vector.cpp:160:8:160:9 | aa | vector.cpp:160:8:160:15 | access to array | | +| vector.cpp:160:8:160:12 | access to array | vector.cpp:160:8:160:15 | access to array | TAINT | +| vector.cpp:160:11:160:11 | 0 | vector.cpp:160:8:160:12 | access to array | TAINT | +| vector.cpp:160:14:160:14 | 0 | vector.cpp:160:8:160:15 | access to array | TAINT | +| vector.cpp:161:3:161:4 | aa | vector.cpp:161:3:161:7 | access to array | TAINT | +| vector.cpp:161:3:161:4 | aa | vector.cpp:161:3:161:10 | access to array | | +| vector.cpp:161:3:161:7 | access to array | vector.cpp:161:3:161:10 | access to array | TAINT | +| vector.cpp:161:3:161:10 | access to array [post update] | vector.cpp:161:3:161:4 | aa [inner post update] | | +| vector.cpp:161:3:161:10 | access to array [post update] | vector.cpp:162:8:162:9 | aa | | +| vector.cpp:161:3:161:21 | ... = ... | vector.cpp:161:3:161:10 | access to array [post update] | | +| vector.cpp:161:6:161:6 | 0 | vector.cpp:161:3:161:7 | access to array | TAINT | +| vector.cpp:161:9:161:9 | 0 | vector.cpp:161:3:161:10 | access to array | TAINT | +| vector.cpp:161:14:161:19 | call to source | vector.cpp:161:3:161:21 | ... = ... | | +| vector.cpp:162:8:162:9 | aa | vector.cpp:162:8:162:12 | access to array | TAINT | +| vector.cpp:162:8:162:9 | aa | vector.cpp:162:8:162:15 | access to array | | +| vector.cpp:162:8:162:12 | access to array | vector.cpp:162:8:162:15 | access to array | TAINT | +| vector.cpp:162:11:162:11 | 0 | vector.cpp:162:8:162:12 | access to array | TAINT | +| vector.cpp:162:14:162:14 | 0 | vector.cpp:162:8:162:15 | access to array | TAINT | +| vector.cpp:166:37:166:39 | call to vector | vector.cpp:168:3:168:4 | bb | | +| vector.cpp:166:37:166:39 | call to vector | vector.cpp:169:8:169:9 | bb | | +| vector.cpp:166:37:166:39 | call to vector | vector.cpp:170:3:170:4 | bb | | +| vector.cpp:166:37:166:39 | call to vector | vector.cpp:171:8:171:9 | bb | | +| vector.cpp:166:37:166:39 | call to vector | vector.cpp:172:2:172:2 | bb | | +| vector.cpp:168:3:168:4 | bb | vector.cpp:168:5:168:5 | call to operator[] | TAINT | +| vector.cpp:168:3:168:4 | ref arg bb | vector.cpp:169:8:169:9 | bb | | +| vector.cpp:168:3:168:4 | ref arg bb | vector.cpp:170:3:170:4 | bb | | +| vector.cpp:168:3:168:4 | ref arg bb | vector.cpp:171:8:171:9 | bb | | +| vector.cpp:168:3:168:4 | ref arg bb | vector.cpp:172:2:172:2 | bb | | +| vector.cpp:168:5:168:5 | ref arg call to operator[] | vector.cpp:168:3:168:4 | ref arg bb | TAINT | +| vector.cpp:168:19:168:19 | 0 | vector.cpp:168:5:168:5 | ref arg call to operator[] | TAINT | +| vector.cpp:169:8:169:9 | bb | vector.cpp:169:10:169:10 | call to operator[] | TAINT | +| vector.cpp:169:8:169:9 | ref arg bb | vector.cpp:170:3:170:4 | bb | | +| vector.cpp:169:8:169:9 | ref arg bb | vector.cpp:171:8:171:9 | bb | | +| vector.cpp:169:8:169:9 | ref arg bb | vector.cpp:172:2:172:2 | bb | | +| vector.cpp:169:10:169:10 | call to operator[] | vector.cpp:169:13:169:13 | call to operator[] | TAINT | +| vector.cpp:169:10:169:10 | ref arg call to operator[] | vector.cpp:169:8:169:9 | ref arg bb | TAINT | +| vector.cpp:170:3:170:4 | bb | vector.cpp:170:5:170:5 | call to operator[] | TAINT | +| vector.cpp:170:3:170:4 | ref arg bb | vector.cpp:171:8:171:9 | bb | | +| vector.cpp:170:3:170:4 | ref arg bb | vector.cpp:172:2:172:2 | bb | | +| vector.cpp:170:3:170:21 | ... = ... | vector.cpp:170:8:170:8 | call to operator[] [post update] | | +| vector.cpp:170:5:170:5 | call to operator[] | vector.cpp:170:8:170:8 | call to operator[] | TAINT | +| vector.cpp:170:5:170:5 | ref arg call to operator[] | vector.cpp:170:3:170:4 | ref arg bb | TAINT | +| vector.cpp:170:8:170:8 | call to operator[] [post update] | vector.cpp:170:5:170:5 | ref arg call to operator[] | TAINT | +| vector.cpp:170:14:170:19 | call to source | vector.cpp:170:3:170:21 | ... = ... | | +| vector.cpp:171:8:171:9 | bb | vector.cpp:171:10:171:10 | call to operator[] | TAINT | +| vector.cpp:171:8:171:9 | ref arg bb | vector.cpp:172:2:172:2 | bb | | +| vector.cpp:171:10:171:10 | call to operator[] | vector.cpp:171:13:171:13 | call to operator[] | TAINT | +| vector.cpp:171:10:171:10 | ref arg call to operator[] | vector.cpp:171:8:171:9 | ref arg bb | TAINT | +| vector.cpp:175:20:175:21 | call to vector | vector.cpp:175:20:175:21 | {...} | TAINT | +| vector.cpp:175:20:175:21 | {...} | vector.cpp:177:3:177:4 | cc | | +| vector.cpp:175:20:175:21 | {...} | vector.cpp:178:8:178:9 | cc | | +| vector.cpp:175:20:175:21 | {...} | vector.cpp:179:3:179:4 | cc | | +| vector.cpp:175:20:175:21 | {...} | vector.cpp:180:8:180:9 | cc | | +| vector.cpp:175:20:175:21 | {...} | vector.cpp:181:2:181:2 | cc | | +| vector.cpp:177:3:177:4 | cc | vector.cpp:177:3:177:7 | access to array | | +| vector.cpp:177:3:177:7 | ref arg access to array | vector.cpp:177:3:177:4 | cc [inner post update] | | +| vector.cpp:177:3:177:7 | ref arg access to array | vector.cpp:178:8:178:9 | cc | | +| vector.cpp:177:3:177:7 | ref arg access to array | vector.cpp:179:3:179:4 | cc | | +| vector.cpp:177:3:177:7 | ref arg access to array | vector.cpp:180:8:180:9 | cc | | +| vector.cpp:177:3:177:7 | ref arg access to array | vector.cpp:181:2:181:2 | cc | | +| vector.cpp:177:6:177:6 | 0 | vector.cpp:177:3:177:7 | access to array | TAINT | +| vector.cpp:177:19:177:19 | 0 | vector.cpp:177:3:177:7 | ref arg access to array | TAINT | +| vector.cpp:178:8:178:9 | cc | vector.cpp:178:8:178:12 | access to array | | +| vector.cpp:178:8:178:12 | access to array | vector.cpp:178:13:178:13 | call to operator[] | TAINT | +| vector.cpp:178:8:178:12 | ref arg access to array | vector.cpp:178:8:178:9 | cc [inner post update] | | +| vector.cpp:178:8:178:12 | ref arg access to array | vector.cpp:179:3:179:4 | cc | | +| vector.cpp:178:8:178:12 | ref arg access to array | vector.cpp:180:8:180:9 | cc | | +| vector.cpp:178:8:178:12 | ref arg access to array | vector.cpp:181:2:181:2 | cc | | +| vector.cpp:178:11:178:11 | 0 | vector.cpp:178:8:178:12 | access to array | TAINT | +| vector.cpp:179:3:179:4 | cc | vector.cpp:179:3:179:7 | access to array | | +| vector.cpp:179:3:179:7 | access to array | vector.cpp:179:8:179:8 | call to operator[] | TAINT | +| vector.cpp:179:3:179:7 | ref arg access to array | vector.cpp:179:3:179:4 | cc [inner post update] | | +| vector.cpp:179:3:179:7 | ref arg access to array | vector.cpp:180:8:180:9 | cc | | +| vector.cpp:179:3:179:7 | ref arg access to array | vector.cpp:181:2:181:2 | cc | | +| vector.cpp:179:3:179:21 | ... = ... | vector.cpp:179:8:179:8 | call to operator[] [post update] | | +| vector.cpp:179:6:179:6 | 0 | vector.cpp:179:3:179:7 | access to array | TAINT | +| vector.cpp:179:8:179:8 | call to operator[] [post update] | vector.cpp:179:3:179:7 | ref arg access to array | TAINT | +| vector.cpp:179:14:179:19 | call to source | vector.cpp:179:3:179:21 | ... = ... | | +| vector.cpp:180:8:180:9 | cc | vector.cpp:180:8:180:12 | access to array | | +| vector.cpp:180:8:180:12 | access to array | vector.cpp:180:13:180:13 | call to operator[] | TAINT | +| vector.cpp:180:8:180:12 | ref arg access to array | vector.cpp:180:8:180:9 | cc [inner post update] | | +| vector.cpp:180:8:180:12 | ref arg access to array | vector.cpp:181:2:181:2 | cc | | +| vector.cpp:180:11:180:11 | 0 | vector.cpp:180:8:180:12 | access to array | TAINT | +| vector.cpp:184:23:184:24 | call to vector | vector.cpp:187:3:187:4 | dd | | +| vector.cpp:184:23:184:24 | call to vector | vector.cpp:188:8:188:9 | dd | | +| vector.cpp:184:23:184:24 | call to vector | vector.cpp:189:8:189:9 | dd | | +| vector.cpp:184:23:184:24 | call to vector | vector.cpp:190:3:190:4 | dd | | +| vector.cpp:184:23:184:24 | call to vector | vector.cpp:191:8:191:9 | dd | | +| vector.cpp:184:23:184:24 | call to vector | vector.cpp:192:8:192:9 | dd | | +| vector.cpp:184:23:184:24 | call to vector | vector.cpp:193:2:193:2 | dd | | +| vector.cpp:185:14:185:20 | {...} | vector.cpp:187:16:187:17 | mp | | +| vector.cpp:187:3:187:4 | ref arg dd | vector.cpp:188:8:188:9 | dd | | +| vector.cpp:187:3:187:4 | ref arg dd | vector.cpp:189:8:189:9 | dd | | +| vector.cpp:187:3:187:4 | ref arg dd | vector.cpp:190:3:190:4 | dd | | +| vector.cpp:187:3:187:4 | ref arg dd | vector.cpp:191:8:191:9 | dd | | +| vector.cpp:187:3:187:4 | ref arg dd | vector.cpp:192:8:192:9 | dd | | +| vector.cpp:187:3:187:4 | ref arg dd | vector.cpp:193:2:193:2 | dd | | +| vector.cpp:187:16:187:17 | mp | vector.cpp:187:3:187:4 | ref arg dd | TAINT | +| vector.cpp:188:8:188:9 | dd | vector.cpp:188:10:188:10 | call to operator[] | TAINT | +| vector.cpp:188:8:188:9 | ref arg dd | vector.cpp:189:8:189:9 | dd | | +| vector.cpp:188:8:188:9 | ref arg dd | vector.cpp:190:3:190:4 | dd | | +| vector.cpp:188:8:188:9 | ref arg dd | vector.cpp:191:8:191:9 | dd | | +| vector.cpp:188:8:188:9 | ref arg dd | vector.cpp:192:8:192:9 | dd | | +| vector.cpp:188:8:188:9 | ref arg dd | vector.cpp:193:2:193:2 | dd | | +| vector.cpp:189:8:189:9 | dd | vector.cpp:189:10:189:10 | call to operator[] | TAINT | +| vector.cpp:189:8:189:9 | ref arg dd | vector.cpp:190:3:190:4 | dd | | +| vector.cpp:189:8:189:9 | ref arg dd | vector.cpp:191:8:191:9 | dd | | +| vector.cpp:189:8:189:9 | ref arg dd | vector.cpp:192:8:192:9 | dd | | +| vector.cpp:189:8:189:9 | ref arg dd | vector.cpp:193:2:193:2 | dd | | +| vector.cpp:190:3:190:4 | dd | vector.cpp:190:5:190:5 | call to operator[] | TAINT | +| vector.cpp:190:3:190:4 | ref arg dd | vector.cpp:191:8:191:9 | dd | | +| vector.cpp:190:3:190:4 | ref arg dd | vector.cpp:192:8:192:9 | dd | | +| vector.cpp:190:3:190:4 | ref arg dd | vector.cpp:193:2:193:2 | dd | | +| vector.cpp:190:3:190:20 | ... = ... | vector.cpp:190:9:190:9 | a [post update] | | +| vector.cpp:190:5:190:5 | call to operator[] [post update] | vector.cpp:190:3:190:4 | ref arg dd | TAINT | +| vector.cpp:190:13:190:18 | call to source | vector.cpp:190:3:190:20 | ... = ... | | +| vector.cpp:191:8:191:9 | dd | vector.cpp:191:10:191:10 | call to operator[] | TAINT | +| vector.cpp:191:8:191:9 | ref arg dd | vector.cpp:192:8:192:9 | dd | | +| vector.cpp:191:8:191:9 | ref arg dd | vector.cpp:193:2:193:2 | dd | | +| vector.cpp:192:8:192:9 | dd | vector.cpp:192:10:192:10 | call to operator[] | TAINT | +| vector.cpp:192:8:192:9 | ref arg dd | vector.cpp:193:2:193:2 | dd | | +| vector.cpp:196:21:196:22 | call to MyVectorContainer | vector.cpp:198:3:198:4 | ee | | +| vector.cpp:196:21:196:22 | call to MyVectorContainer | vector.cpp:199:8:199:9 | ee | | +| vector.cpp:196:21:196:22 | call to MyVectorContainer | vector.cpp:200:3:200:4 | ee | | +| vector.cpp:196:21:196:22 | call to MyVectorContainer | vector.cpp:201:8:201:9 | ee | | +| vector.cpp:196:21:196:22 | call to MyVectorContainer | vector.cpp:202:2:202:2 | ee | | +| vector.cpp:198:3:198:4 | ee [post update] | vector.cpp:199:8:199:9 | ee | | +| vector.cpp:198:3:198:4 | ee [post update] | vector.cpp:200:3:200:4 | ee | | +| vector.cpp:198:3:198:4 | ee [post update] | vector.cpp:201:8:201:9 | ee | | +| vector.cpp:198:3:198:4 | ee [post update] | vector.cpp:202:2:202:2 | ee | | +| vector.cpp:198:19:198:19 | 0 | vector.cpp:198:6:198:7 | ref arg vs | TAINT | +| vector.cpp:199:8:199:9 | ee [post update] | vector.cpp:200:3:200:4 | ee | | +| vector.cpp:199:8:199:9 | ee [post update] | vector.cpp:201:8:201:9 | ee | | +| vector.cpp:199:8:199:9 | ee [post update] | vector.cpp:202:2:202:2 | ee | | +| vector.cpp:199:11:199:12 | vs | vector.cpp:199:13:199:13 | call to operator[] | TAINT | +| vector.cpp:200:3:200:4 | ee [post update] | vector.cpp:201:8:201:9 | ee | | +| vector.cpp:200:3:200:4 | ee [post update] | vector.cpp:202:2:202:2 | ee | | +| vector.cpp:200:3:200:21 | ... = ... | vector.cpp:200:8:200:8 | call to operator[] [post update] | | +| vector.cpp:200:6:200:7 | vs | vector.cpp:200:8:200:8 | call to operator[] | TAINT | +| vector.cpp:200:8:200:8 | call to operator[] [post update] | vector.cpp:200:6:200:7 | ref arg vs | TAINT | +| vector.cpp:200:14:200:19 | call to source | vector.cpp:200:3:200:21 | ... = ... | | +| vector.cpp:201:8:201:9 | ee [post update] | vector.cpp:202:2:202:2 | ee | | +| vector.cpp:201:11:201:12 | vs | vector.cpp:201:13:201:13 | call to operator[] | TAINT | +| vector.cpp:205:34:205:35 | call to vector | vector.cpp:209:3:209:4 | ff | | +| vector.cpp:205:34:205:35 | call to vector | vector.cpp:210:8:210:9 | ff | | +| vector.cpp:205:34:205:35 | call to vector | vector.cpp:211:3:211:4 | ff | | +| vector.cpp:205:34:205:35 | call to vector | vector.cpp:212:8:212:9 | ff | | +| vector.cpp:205:34:205:35 | call to vector | vector.cpp:213:2:213:2 | ff | | +| vector.cpp:206:21:206:23 | call to MyVectorContainer | vector.cpp:208:3:208:5 | mvc | | +| vector.cpp:206:21:206:23 | call to MyVectorContainer | vector.cpp:209:16:209:18 | mvc | | +| vector.cpp:206:21:206:23 | call to MyVectorContainer | vector.cpp:213:2:213:2 | mvc | | +| vector.cpp:208:3:208:5 | mvc [post update] | vector.cpp:209:16:209:18 | mvc | | +| vector.cpp:208:3:208:5 | mvc [post update] | vector.cpp:213:2:213:2 | mvc | | +| vector.cpp:208:20:208:20 | 0 | vector.cpp:208:7:208:8 | ref arg vs | TAINT | +| vector.cpp:209:3:209:4 | ref arg ff | vector.cpp:210:8:210:9 | ff | | +| vector.cpp:209:3:209:4 | ref arg ff | vector.cpp:211:3:211:4 | ff | | +| vector.cpp:209:3:209:4 | ref arg ff | vector.cpp:212:8:212:9 | ff | | +| vector.cpp:209:3:209:4 | ref arg ff | vector.cpp:213:2:213:2 | ff | | +| vector.cpp:209:16:209:18 | mvc | vector.cpp:209:3:209:4 | ref arg ff | TAINT | +| vector.cpp:210:8:210:9 | ff | vector.cpp:210:10:210:10 | call to operator[] | TAINT | +| vector.cpp:210:8:210:9 | ref arg ff | vector.cpp:211:3:211:4 | ff | | +| vector.cpp:210:8:210:9 | ref arg ff | vector.cpp:212:8:212:9 | ff | | +| vector.cpp:210:8:210:9 | ref arg ff | vector.cpp:213:2:213:2 | ff | | +| vector.cpp:210:10:210:10 | call to operator[] [post update] | vector.cpp:210:8:210:9 | ref arg ff | TAINT | +| vector.cpp:210:14:210:15 | vs | vector.cpp:210:16:210:16 | call to operator[] | TAINT | +| vector.cpp:211:3:211:4 | ff | vector.cpp:211:5:211:5 | call to operator[] | TAINT | +| vector.cpp:211:3:211:4 | ref arg ff | vector.cpp:212:8:212:9 | ff | | +| vector.cpp:211:3:211:4 | ref arg ff | vector.cpp:213:2:213:2 | ff | | +| vector.cpp:211:3:211:24 | ... = ... | vector.cpp:211:11:211:11 | call to operator[] [post update] | | +| vector.cpp:211:5:211:5 | call to operator[] [post update] | vector.cpp:211:3:211:4 | ref arg ff | TAINT | +| vector.cpp:211:9:211:10 | vs | vector.cpp:211:11:211:11 | call to operator[] | TAINT | +| vector.cpp:211:11:211:11 | call to operator[] [post update] | vector.cpp:211:9:211:10 | ref arg vs | TAINT | +| vector.cpp:211:17:211:22 | call to source | vector.cpp:211:3:211:24 | ... = ... | | +| vector.cpp:212:8:212:9 | ff | vector.cpp:212:10:212:10 | call to operator[] | TAINT | +| vector.cpp:212:8:212:9 | ref arg ff | vector.cpp:213:2:213:2 | ff | | +| vector.cpp:212:10:212:10 | call to operator[] [post update] | vector.cpp:212:8:212:9 | ref arg ff | TAINT | +| vector.cpp:212:14:212:15 | vs | vector.cpp:212:16:212:16 | call to operator[] | TAINT | +| vector.cpp:235:19:235:20 | call to vector | vector.cpp:237:2:237:3 | v1 | | +| vector.cpp:235:19:235:20 | call to vector | vector.cpp:241:7:241:8 | v1 | | +| vector.cpp:235:19:235:20 | call to vector | vector.cpp:249:13:249:14 | v1 | | +| vector.cpp:235:19:235:20 | call to vector | vector.cpp:249:25:249:26 | v1 | | +| vector.cpp:235:19:235:20 | call to vector | vector.cpp:277:1:277:1 | v1 | | +| vector.cpp:235:23:235:24 | call to vector | vector.cpp:238:2:238:3 | v2 | | +| vector.cpp:235:23:235:24 | call to vector | vector.cpp:242:7:242:8 | v2 | | +| vector.cpp:235:23:235:24 | call to vector | vector.cpp:277:1:277:1 | v2 | | +| vector.cpp:235:27:235:28 | call to vector | vector.cpp:239:2:239:3 | v3 | | +| vector.cpp:235:27:235:28 | call to vector | vector.cpp:243:7:243:8 | v3 | | +| vector.cpp:235:27:235:28 | call to vector | vector.cpp:250:13:250:14 | v3 | | +| vector.cpp:235:27:235:28 | call to vector | vector.cpp:250:25:250:26 | v3 | | +| vector.cpp:235:27:235:28 | call to vector | vector.cpp:251:8:251:9 | v3 | | +| vector.cpp:235:27:235:28 | call to vector | vector.cpp:277:1:277:1 | v3 | | +| vector.cpp:237:2:237:3 | ref arg v1 | vector.cpp:241:7:241:8 | v1 | | +| vector.cpp:237:2:237:3 | ref arg v1 | vector.cpp:249:13:249:14 | v1 | | +| vector.cpp:237:2:237:3 | ref arg v1 | vector.cpp:249:25:249:26 | v1 | | +| vector.cpp:237:2:237:3 | ref arg v1 | vector.cpp:277:1:277:1 | v1 | | +| vector.cpp:237:17:237:17 | 0 | vector.cpp:237:2:237:3 | ref arg v1 | TAINT | +| vector.cpp:238:2:238:3 | ref arg v2 | vector.cpp:242:7:242:8 | v2 | | +| vector.cpp:238:2:238:3 | ref arg v2 | vector.cpp:277:1:277:1 | v2 | | +| vector.cpp:238:17:238:30 | call to source | vector.cpp:238:2:238:3 | ref arg v2 | TAINT | +| vector.cpp:239:2:239:3 | ref arg v3 | vector.cpp:243:7:243:8 | v3 | | +| vector.cpp:239:2:239:3 | ref arg v3 | vector.cpp:250:13:250:14 | v3 | | +| vector.cpp:239:2:239:3 | ref arg v3 | vector.cpp:250:25:250:26 | v3 | | +| vector.cpp:239:2:239:3 | ref arg v3 | vector.cpp:251:8:251:9 | v3 | | +| vector.cpp:239:2:239:3 | ref arg v3 | vector.cpp:277:1:277:1 | v3 | | +| vector.cpp:239:15:239:20 | call to source | vector.cpp:239:2:239:3 | ref arg v3 | TAINT | +| vector.cpp:241:7:241:8 | ref arg v1 | vector.cpp:249:13:249:14 | v1 | | +| vector.cpp:241:7:241:8 | ref arg v1 | vector.cpp:249:25:249:26 | v1 | | +| vector.cpp:241:7:241:8 | ref arg v1 | vector.cpp:277:1:277:1 | v1 | | +| vector.cpp:242:7:242:8 | ref arg v2 | vector.cpp:277:1:277:1 | v2 | | +| vector.cpp:243:7:243:8 | ref arg v3 | vector.cpp:250:13:250:14 | v3 | | +| vector.cpp:243:7:243:8 | ref arg v3 | vector.cpp:250:25:250:26 | v3 | | +| vector.cpp:243:7:243:8 | ref arg v3 | vector.cpp:251:8:251:9 | v3 | | +| vector.cpp:243:7:243:8 | ref arg v3 | vector.cpp:277:1:277:1 | v3 | | +| vector.cpp:246:20:246:21 | call to vector | vector.cpp:249:3:249:4 | v4 | | +| vector.cpp:246:20:246:21 | call to vector | vector.cpp:257:8:257:9 | v4 | | +| vector.cpp:246:20:246:21 | call to vector | vector.cpp:262:2:262:2 | v4 | | +| vector.cpp:246:24:246:25 | call to vector | vector.cpp:250:3:250:4 | v5 | | +| vector.cpp:246:24:246:25 | call to vector | vector.cpp:258:8:258:9 | v5 | | +| vector.cpp:246:24:246:25 | call to vector | vector.cpp:262:2:262:2 | v5 | | +| vector.cpp:246:28:246:29 | call to vector | vector.cpp:255:3:255:4 | v6 | | +| vector.cpp:246:28:246:29 | call to vector | vector.cpp:261:8:261:9 | v6 | | +| vector.cpp:246:28:246:29 | call to vector | vector.cpp:262:2:262:2 | v6 | | +| vector.cpp:249:3:249:4 | ref arg v4 | vector.cpp:257:8:257:9 | v4 | | +| vector.cpp:249:3:249:4 | ref arg v4 | vector.cpp:262:2:262:2 | v4 | | +| vector.cpp:249:13:249:14 | ref arg v1 | vector.cpp:249:25:249:26 | v1 | | +| vector.cpp:249:13:249:14 | ref arg v1 | vector.cpp:277:1:277:1 | v1 | | +| vector.cpp:249:13:249:14 | v1 | vector.cpp:249:16:249:20 | call to begin | TAINT | +| vector.cpp:249:16:249:20 | call to begin | vector.cpp:249:3:249:4 | ref arg v4 | TAINT | +| vector.cpp:249:25:249:26 | ref arg v1 | vector.cpp:277:1:277:1 | v1 | | +| vector.cpp:249:25:249:26 | v1 | vector.cpp:249:28:249:30 | call to end | TAINT | +| vector.cpp:249:28:249:30 | call to end | vector.cpp:249:3:249:4 | ref arg v4 | TAINT | +| vector.cpp:250:3:250:4 | ref arg v5 | vector.cpp:258:8:258:9 | v5 | | +| vector.cpp:250:3:250:4 | ref arg v5 | vector.cpp:262:2:262:2 | v5 | | +| vector.cpp:250:13:250:14 | ref arg v3 | vector.cpp:250:25:250:26 | v3 | | +| vector.cpp:250:13:250:14 | ref arg v3 | vector.cpp:251:8:251:9 | v3 | | +| vector.cpp:250:13:250:14 | ref arg v3 | vector.cpp:277:1:277:1 | v3 | | +| vector.cpp:250:13:250:14 | v3 | vector.cpp:250:16:250:20 | call to begin | TAINT | +| vector.cpp:250:16:250:20 | call to begin | vector.cpp:250:3:250:4 | ref arg v5 | TAINT | +| vector.cpp:250:25:250:26 | ref arg v3 | vector.cpp:251:8:251:9 | v3 | | +| vector.cpp:250:25:250:26 | ref arg v3 | vector.cpp:277:1:277:1 | v3 | | +| vector.cpp:250:25:250:26 | v3 | vector.cpp:250:28:250:30 | call to end | TAINT | +| vector.cpp:250:28:250:30 | call to end | vector.cpp:250:3:250:4 | ref arg v5 | TAINT | +| vector.cpp:251:8:251:9 | ref arg v3 | vector.cpp:277:1:277:1 | v3 | | +| vector.cpp:251:8:251:9 | v3 | vector.cpp:251:11:251:15 | call to begin | TAINT | +| vector.cpp:251:11:251:15 | call to begin | vector.cpp:251:3:251:17 | ... = ... | | +| vector.cpp:251:11:251:15 | call to begin | vector.cpp:252:3:252:4 | i1 | | +| vector.cpp:251:11:251:15 | call to begin | vector.cpp:253:8:253:9 | i1 | | +| vector.cpp:251:11:251:15 | call to begin | vector.cpp:255:13:255:14 | i1 | | +| vector.cpp:251:11:251:15 | call to begin | vector.cpp:259:8:259:9 | i1 | | +| vector.cpp:252:3:252:4 | i1 | vector.cpp:252:5:252:5 | call to operator++ | | +| vector.cpp:252:3:252:4 | ref arg i1 | vector.cpp:253:8:253:9 | i1 | | +| vector.cpp:252:3:252:4 | ref arg i1 | vector.cpp:255:13:255:14 | i1 | | +| vector.cpp:252:3:252:4 | ref arg i1 | vector.cpp:259:8:259:9 | i1 | | +| vector.cpp:253:8:253:9 | i1 | vector.cpp:253:3:253:9 | ... = ... | | +| vector.cpp:253:8:253:9 | i1 | vector.cpp:254:3:254:4 | i2 | | +| vector.cpp:253:8:253:9 | i1 | vector.cpp:255:17:255:18 | i2 | | +| vector.cpp:253:8:253:9 | i1 | vector.cpp:260:8:260:9 | i2 | | +| vector.cpp:254:3:254:4 | i2 | vector.cpp:254:5:254:5 | call to operator++ | | +| vector.cpp:254:3:254:4 | ref arg i2 | vector.cpp:255:17:255:18 | i2 | | +| vector.cpp:254:3:254:4 | ref arg i2 | vector.cpp:260:8:260:9 | i2 | | +| vector.cpp:255:3:255:4 | ref arg v6 | vector.cpp:261:8:261:9 | v6 | | +| vector.cpp:255:3:255:4 | ref arg v6 | vector.cpp:262:2:262:2 | v6 | | +| vector.cpp:255:13:255:14 | call to iterator | vector.cpp:255:3:255:4 | ref arg v6 | TAINT | +| vector.cpp:255:13:255:14 | call to iterator [post update] | vector.cpp:277:1:277:1 | v3 | | +| vector.cpp:255:13:255:14 | i1 | vector.cpp:255:13:255:14 | call to iterator | | +| vector.cpp:255:13:255:14 | i1 [post update] | vector.cpp:277:1:277:1 | v3 | | +| vector.cpp:255:17:255:18 | call to iterator | vector.cpp:255:3:255:4 | ref arg v6 | TAINT | +| vector.cpp:255:17:255:18 | i2 | vector.cpp:255:17:255:18 | call to iterator | | +| vector.cpp:257:8:257:9 | ref arg v4 | vector.cpp:262:2:262:2 | v4 | | +| vector.cpp:258:8:258:9 | ref arg v5 | vector.cpp:262:2:262:2 | v5 | | +| vector.cpp:259:8:259:9 | ref arg i1 | vector.cpp:277:1:277:1 | v3 | | +| vector.cpp:261:8:261:9 | ref arg v6 | vector.cpp:262:2:262:2 | v6 | | +| vector.cpp:265:22:265:23 | call to vector | vector.cpp:269:3:269:4 | v7 | | +| vector.cpp:265:22:265:23 | call to vector | vector.cpp:273:8:273:9 | v7 | | +| vector.cpp:265:22:265:23 | call to vector | vector.cpp:276:2:276:2 | v7 | | +| vector.cpp:266:24:266:25 | call to vector | vector.cpp:270:3:270:4 | v8 | | +| vector.cpp:266:24:266:25 | call to vector | vector.cpp:274:8:274:9 | v8 | | +| vector.cpp:266:24:266:25 | call to vector | vector.cpp:276:2:276:2 | v8 | | +| vector.cpp:267:28:267:29 | call to vector | vector.cpp:271:3:271:4 | v9 | | +| vector.cpp:267:28:267:29 | call to vector | vector.cpp:275:8:275:9 | v9 | | +| vector.cpp:267:28:267:29 | call to vector | vector.cpp:276:2:276:2 | v9 | | +| vector.cpp:269:3:269:4 | ref arg v7 | vector.cpp:273:8:273:9 | v7 | | +| vector.cpp:269:3:269:4 | ref arg v7 | vector.cpp:276:2:276:2 | v7 | | +| vector.cpp:269:18:269:31 | call to source | vector.cpp:269:3:269:4 | ref arg v7 | TAINT | +| vector.cpp:270:3:270:4 | ref arg v8 | vector.cpp:274:8:274:9 | v8 | | +| vector.cpp:270:3:270:4 | ref arg v8 | vector.cpp:276:2:276:2 | v8 | | +| vector.cpp:270:18:270:35 | call to source | vector.cpp:270:3:270:4 | ref arg v8 | TAINT | +| vector.cpp:271:3:271:4 | ref arg v9 | vector.cpp:275:8:275:9 | v9 | | +| vector.cpp:271:3:271:4 | ref arg v9 | vector.cpp:276:2:276:2 | v9 | | +| vector.cpp:271:18:271:34 | call to source | vector.cpp:271:3:271:4 | ref arg v9 | TAINT | +| vector.cpp:273:8:273:9 | ref arg v7 | vector.cpp:276:2:276:2 | v7 | | +| vector.cpp:274:8:274:9 | ref arg v8 | vector.cpp:276:2:276:2 | v8 | | +| vector.cpp:275:8:275:9 | ref arg v9 | vector.cpp:276:2:276:2 | v9 | | +| vector.cpp:282:19:282:20 | call to vector | vector.cpp:284:2:284:3 | v1 | | +| vector.cpp:282:19:282:20 | call to vector | vector.cpp:285:7:285:8 | v1 | | +| vector.cpp:282:19:282:20 | call to vector | vector.cpp:286:7:286:8 | v1 | | +| vector.cpp:282:19:282:20 | call to vector | vector.cpp:287:7:287:8 | v1 | | +| vector.cpp:282:19:282:20 | call to vector | vector.cpp:293:1:293:1 | v1 | | +| vector.cpp:282:23:282:24 | call to vector | vector.cpp:289:4:289:5 | v2 | | +| vector.cpp:282:23:282:24 | call to vector | vector.cpp:290:7:290:8 | v2 | | +| vector.cpp:282:23:282:24 | call to vector | vector.cpp:291:7:291:8 | v2 | | +| vector.cpp:282:23:282:24 | call to vector | vector.cpp:292:7:292:8 | v2 | | +| vector.cpp:282:23:282:24 | call to vector | vector.cpp:293:1:293:1 | v2 | | +| vector.cpp:284:2:284:3 | ref arg v1 | vector.cpp:285:7:285:8 | v1 | | +| vector.cpp:284:2:284:3 | ref arg v1 | vector.cpp:286:7:286:8 | v1 | | +| vector.cpp:284:2:284:3 | ref arg v1 | vector.cpp:287:7:287:8 | v1 | | +| vector.cpp:284:2:284:3 | ref arg v1 | vector.cpp:293:1:293:1 | v1 | | +| vector.cpp:284:15:284:20 | call to source | vector.cpp:284:2:284:3 | ref arg v1 | TAINT | +| vector.cpp:285:7:285:8 | ref arg v1 | vector.cpp:286:7:286:8 | v1 | | +| vector.cpp:285:7:285:8 | ref arg v1 | vector.cpp:287:7:287:8 | v1 | | +| vector.cpp:285:7:285:8 | ref arg v1 | vector.cpp:293:1:293:1 | v1 | | +| vector.cpp:286:7:286:8 | ref arg v1 | vector.cpp:287:7:287:8 | v1 | | +| vector.cpp:286:7:286:8 | ref arg v1 | vector.cpp:293:1:293:1 | v1 | | +| vector.cpp:286:7:286:8 | v1 | vector.cpp:286:10:286:13 | call to data | TAINT | +| vector.cpp:286:10:286:13 | ref arg call to data | vector.cpp:286:7:286:8 | ref arg v1 | TAINT | +| vector.cpp:287:7:287:8 | ref arg v1 | vector.cpp:293:1:293:1 | v1 | | +| vector.cpp:287:7:287:8 | v1 | vector.cpp:287:10:287:13 | call to data | TAINT | +| vector.cpp:287:10:287:13 | call to data | vector.cpp:287:7:287:18 | access to array | TAINT | +| vector.cpp:287:17:287:17 | 2 | vector.cpp:287:7:287:18 | access to array | TAINT | +| vector.cpp:289:2:289:13 | * ... [post update] | vector.cpp:289:7:289:10 | call to data [inner post update] | | +| vector.cpp:289:2:289:32 | ... = ... | vector.cpp:289:2:289:13 | * ... [post update] | | +| vector.cpp:289:4:289:5 | ref arg v2 | vector.cpp:290:7:290:8 | v2 | | +| vector.cpp:289:4:289:5 | ref arg v2 | vector.cpp:291:7:291:8 | v2 | | +| vector.cpp:289:4:289:5 | ref arg v2 | vector.cpp:292:7:292:8 | v2 | | +| vector.cpp:289:4:289:5 | ref arg v2 | vector.cpp:293:1:293:1 | v2 | | +| vector.cpp:289:4:289:5 | v2 | vector.cpp:289:7:289:10 | call to data | TAINT | +| vector.cpp:289:7:289:10 | call to data | vector.cpp:289:2:289:13 | * ... | TAINT | +| vector.cpp:289:7:289:10 | call to data [inner post update] | vector.cpp:289:4:289:5 | ref arg v2 | TAINT | +| vector.cpp:289:17:289:30 | call to source | vector.cpp:289:2:289:32 | ... = ... | | +| vector.cpp:290:7:290:8 | ref arg v2 | vector.cpp:291:7:291:8 | v2 | | +| vector.cpp:290:7:290:8 | ref arg v2 | vector.cpp:292:7:292:8 | v2 | | +| vector.cpp:290:7:290:8 | ref arg v2 | vector.cpp:293:1:293:1 | v2 | | +| vector.cpp:291:7:291:8 | ref arg v2 | vector.cpp:292:7:292:8 | v2 | | +| vector.cpp:291:7:291:8 | ref arg v2 | vector.cpp:293:1:293:1 | v2 | | +| vector.cpp:291:7:291:8 | v2 | vector.cpp:291:10:291:13 | call to data | TAINT | +| vector.cpp:291:10:291:13 | ref arg call to data | vector.cpp:291:7:291:8 | ref arg v2 | TAINT | +| vector.cpp:292:7:292:8 | ref arg v2 | vector.cpp:293:1:293:1 | v2 | | +| vector.cpp:292:7:292:8 | v2 | vector.cpp:292:10:292:13 | call to data | TAINT | +| vector.cpp:292:10:292:13 | call to data | vector.cpp:292:7:292:18 | access to array | TAINT | +| vector.cpp:292:17:292:17 | 2 | vector.cpp:292:7:292:18 | access to array | TAINT | +| vector.cpp:298:19:298:19 | call to vector | vector.cpp:305:7:305:7 | a | | +| vector.cpp:298:19:298:19 | call to vector | vector.cpp:305:16:305:16 | a | | +| vector.cpp:298:19:298:19 | call to vector | vector.cpp:306:7:306:7 | a | | +| vector.cpp:298:19:298:19 | call to vector | vector.cpp:311:25:311:25 | a | | +| vector.cpp:298:19:298:19 | call to vector | vector.cpp:311:36:311:36 | a | | +| vector.cpp:298:19:298:19 | call to vector | vector.cpp:313:1:313:1 | a | | +| vector.cpp:299:19:299:19 | call to vector | vector.cpp:305:25:305:25 | b | | +| vector.cpp:299:19:299:19 | call to vector | vector.cpp:305:36:305:36 | b | | +| vector.cpp:299:19:299:19 | call to vector | vector.cpp:313:1:313:1 | b | | +| vector.cpp:300:19:300:19 | call to vector | vector.cpp:308:7:308:7 | c | | +| vector.cpp:300:19:300:19 | call to vector | vector.cpp:308:16:308:16 | c | | +| vector.cpp:300:19:300:19 | call to vector | vector.cpp:309:7:309:7 | c | | +| vector.cpp:300:19:300:19 | call to vector | vector.cpp:313:1:313:1 | c | | +| vector.cpp:301:19:301:19 | call to vector | vector.cpp:303:2:303:2 | d | | +| vector.cpp:301:19:301:19 | call to vector | vector.cpp:308:25:308:25 | d | | +| vector.cpp:301:19:301:19 | call to vector | vector.cpp:308:36:308:36 | d | | +| vector.cpp:301:19:301:19 | call to vector | vector.cpp:311:7:311:7 | d | | +| vector.cpp:301:19:301:19 | call to vector | vector.cpp:311:16:311:16 | d | | +| vector.cpp:301:19:301:19 | call to vector | vector.cpp:312:7:312:7 | d | | +| vector.cpp:301:19:301:19 | call to vector | vector.cpp:313:1:313:1 | d | | +| vector.cpp:303:2:303:2 | ref arg d | vector.cpp:308:25:308:25 | d | | +| vector.cpp:303:2:303:2 | ref arg d | vector.cpp:308:36:308:36 | d | | +| vector.cpp:303:2:303:2 | ref arg d | vector.cpp:311:7:311:7 | d | | +| vector.cpp:303:2:303:2 | ref arg d | vector.cpp:311:16:311:16 | d | | +| vector.cpp:303:2:303:2 | ref arg d | vector.cpp:312:7:312:7 | d | | +| vector.cpp:303:2:303:2 | ref arg d | vector.cpp:313:1:313:1 | d | | +| vector.cpp:303:14:303:19 | call to source | vector.cpp:303:2:303:2 | ref arg d | TAINT | +| vector.cpp:305:7:305:7 | a | vector.cpp:305:9:305:14 | call to insert | TAINT | +| vector.cpp:305:7:305:7 | ref arg a | vector.cpp:306:7:306:7 | a | | +| vector.cpp:305:7:305:7 | ref arg a | vector.cpp:311:25:311:25 | a | | +| vector.cpp:305:7:305:7 | ref arg a | vector.cpp:311:36:311:36 | a | | +| vector.cpp:305:7:305:7 | ref arg a | vector.cpp:313:1:313:1 | a | | +| vector.cpp:305:16:305:16 | a | vector.cpp:305:18:305:20 | call to end | TAINT | +| vector.cpp:305:16:305:16 | ref arg a | vector.cpp:305:7:305:7 | a | | +| vector.cpp:305:16:305:16 | ref arg a | vector.cpp:306:7:306:7 | a | | +| vector.cpp:305:16:305:16 | ref arg a | vector.cpp:311:25:311:25 | a | | +| vector.cpp:305:16:305:16 | ref arg a | vector.cpp:311:36:311:36 | a | | +| vector.cpp:305:16:305:16 | ref arg a | vector.cpp:313:1:313:1 | a | | +| vector.cpp:305:18:305:20 | call to end | vector.cpp:305:16:305:22 | call to iterator | TAINT | +| vector.cpp:305:25:305:25 | b | vector.cpp:305:27:305:31 | call to begin | TAINT | +| vector.cpp:305:25:305:25 | ref arg b | vector.cpp:305:36:305:36 | b | | +| vector.cpp:305:25:305:25 | ref arg b | vector.cpp:313:1:313:1 | b | | +| vector.cpp:305:27:305:31 | call to begin | vector.cpp:305:7:305:7 | ref arg a | TAINT | +| vector.cpp:305:27:305:31 | call to begin | vector.cpp:305:9:305:14 | call to insert | TAINT | +| vector.cpp:305:36:305:36 | b | vector.cpp:305:38:305:40 | call to end | TAINT | +| vector.cpp:305:36:305:36 | ref arg b | vector.cpp:313:1:313:1 | b | | +| vector.cpp:305:38:305:40 | call to end | vector.cpp:305:7:305:7 | ref arg a | TAINT | +| vector.cpp:305:38:305:40 | call to end | vector.cpp:305:9:305:14 | call to insert | TAINT | +| vector.cpp:306:7:306:7 | ref arg a | vector.cpp:311:25:311:25 | a | | +| vector.cpp:306:7:306:7 | ref arg a | vector.cpp:311:36:311:36 | a | | +| vector.cpp:306:7:306:7 | ref arg a | vector.cpp:313:1:313:1 | a | | +| vector.cpp:308:7:308:7 | c | vector.cpp:308:9:308:14 | call to insert | TAINT | +| vector.cpp:308:7:308:7 | ref arg c | vector.cpp:309:7:309:7 | c | | +| vector.cpp:308:7:308:7 | ref arg c | vector.cpp:313:1:313:1 | c | | +| vector.cpp:308:16:308:16 | c | vector.cpp:308:18:308:20 | call to end | TAINT | +| vector.cpp:308:16:308:16 | ref arg c | vector.cpp:308:7:308:7 | c | | +| vector.cpp:308:16:308:16 | ref arg c | vector.cpp:309:7:309:7 | c | | +| vector.cpp:308:16:308:16 | ref arg c | vector.cpp:313:1:313:1 | c | | +| vector.cpp:308:18:308:20 | call to end | vector.cpp:308:16:308:22 | call to iterator | TAINT | +| vector.cpp:308:25:308:25 | d | vector.cpp:308:27:308:31 | call to begin | TAINT | +| vector.cpp:308:25:308:25 | ref arg d | vector.cpp:308:36:308:36 | d | | +| vector.cpp:308:25:308:25 | ref arg d | vector.cpp:311:7:311:7 | d | | +| vector.cpp:308:25:308:25 | ref arg d | vector.cpp:311:16:311:16 | d | | +| vector.cpp:308:25:308:25 | ref arg d | vector.cpp:312:7:312:7 | d | | +| vector.cpp:308:25:308:25 | ref arg d | vector.cpp:313:1:313:1 | d | | +| vector.cpp:308:27:308:31 | call to begin | vector.cpp:308:7:308:7 | ref arg c | TAINT | +| vector.cpp:308:27:308:31 | call to begin | vector.cpp:308:9:308:14 | call to insert | TAINT | +| vector.cpp:308:36:308:36 | d | vector.cpp:308:38:308:40 | call to end | TAINT | +| vector.cpp:308:36:308:36 | ref arg d | vector.cpp:311:7:311:7 | d | | +| vector.cpp:308:36:308:36 | ref arg d | vector.cpp:311:16:311:16 | d | | +| vector.cpp:308:36:308:36 | ref arg d | vector.cpp:312:7:312:7 | d | | +| vector.cpp:308:36:308:36 | ref arg d | vector.cpp:313:1:313:1 | d | | +| vector.cpp:308:38:308:40 | call to end | vector.cpp:308:7:308:7 | ref arg c | TAINT | +| vector.cpp:308:38:308:40 | call to end | vector.cpp:308:9:308:14 | call to insert | TAINT | +| vector.cpp:309:7:309:7 | ref arg c | vector.cpp:313:1:313:1 | c | | +| vector.cpp:311:7:311:7 | d | vector.cpp:311:9:311:14 | call to insert | TAINT | +| vector.cpp:311:7:311:7 | ref arg d | vector.cpp:312:7:312:7 | d | | +| vector.cpp:311:7:311:7 | ref arg d | vector.cpp:313:1:313:1 | d | | +| vector.cpp:311:16:311:16 | d | vector.cpp:311:18:311:20 | call to end | TAINT | +| vector.cpp:311:16:311:16 | ref arg d | vector.cpp:311:7:311:7 | d | | +| vector.cpp:311:16:311:16 | ref arg d | vector.cpp:312:7:312:7 | d | | +| vector.cpp:311:16:311:16 | ref arg d | vector.cpp:313:1:313:1 | d | | +| vector.cpp:311:18:311:20 | call to end | vector.cpp:311:16:311:22 | call to iterator | TAINT | +| vector.cpp:311:25:311:25 | a | vector.cpp:311:27:311:31 | call to begin | TAINT | +| vector.cpp:311:25:311:25 | ref arg a | vector.cpp:311:36:311:36 | a | | +| vector.cpp:311:25:311:25 | ref arg a | vector.cpp:313:1:313:1 | a | | +| vector.cpp:311:27:311:31 | call to begin | vector.cpp:311:7:311:7 | ref arg d | TAINT | +| vector.cpp:311:27:311:31 | call to begin | vector.cpp:311:9:311:14 | call to insert | TAINT | +| vector.cpp:311:36:311:36 | a | vector.cpp:311:38:311:40 | call to end | TAINT | +| vector.cpp:311:36:311:36 | ref arg a | vector.cpp:313:1:313:1 | a | | +| vector.cpp:311:38:311:40 | call to end | vector.cpp:311:7:311:7 | ref arg d | TAINT | +| vector.cpp:311:38:311:40 | call to end | vector.cpp:311:9:311:14 | call to insert | TAINT | +| vector.cpp:312:7:312:7 | ref arg d | vector.cpp:313:1:313:1 | d | | +| vector.cpp:316:19:316:20 | call to vector | vector.cpp:320:22:320:23 | v1 | | +| vector.cpp:316:19:316:20 | call to vector | vector.cpp:320:34:320:35 | v1 | | +| vector.cpp:316:19:316:20 | call to vector | vector.cpp:323:7:323:8 | v1 | | +| vector.cpp:316:19:316:20 | call to vector | vector.cpp:327:1:327:1 | v1 | | +| vector.cpp:317:19:317:20 | call to vector | vector.cpp:318:2:318:3 | v2 | | +| vector.cpp:317:19:317:20 | call to vector | vector.cpp:321:22:321:23 | v2 | | +| vector.cpp:317:19:317:20 | call to vector | vector.cpp:321:34:321:35 | v2 | | +| vector.cpp:317:19:317:20 | call to vector | vector.cpp:324:7:324:8 | v2 | | +| vector.cpp:317:19:317:20 | call to vector | vector.cpp:327:1:327:1 | v2 | | +| vector.cpp:318:2:318:3 | ref arg v2 | vector.cpp:321:22:321:23 | v2 | | +| vector.cpp:318:2:318:3 | ref arg v2 | vector.cpp:321:34:321:35 | v2 | | +| vector.cpp:318:2:318:3 | ref arg v2 | vector.cpp:324:7:324:8 | v2 | | +| vector.cpp:318:2:318:3 | ref arg v2 | vector.cpp:327:1:327:1 | v2 | | +| vector.cpp:318:15:318:20 | call to source | vector.cpp:318:2:318:3 | ref arg v2 | TAINT | +| vector.cpp:320:22:320:23 | ref arg v1 | vector.cpp:320:34:320:35 | v1 | | +| vector.cpp:320:22:320:23 | ref arg v1 | vector.cpp:323:7:323:8 | v1 | | +| vector.cpp:320:22:320:23 | ref arg v1 | vector.cpp:327:1:327:1 | v1 | | +| vector.cpp:320:22:320:23 | v1 | vector.cpp:320:25:320:29 | call to begin | TAINT | +| vector.cpp:320:22:320:42 | call to vector | vector.cpp:325:7:325:8 | v3 | | +| vector.cpp:320:22:320:42 | call to vector | vector.cpp:327:1:327:1 | v3 | | +| vector.cpp:320:25:320:29 | call to begin | vector.cpp:320:22:320:42 | call to vector | TAINT | +| vector.cpp:320:34:320:35 | ref arg v1 | vector.cpp:323:7:323:8 | v1 | | +| vector.cpp:320:34:320:35 | ref arg v1 | vector.cpp:327:1:327:1 | v1 | | +| vector.cpp:320:34:320:35 | v1 | vector.cpp:320:37:320:39 | call to end | TAINT | +| vector.cpp:320:37:320:39 | call to end | vector.cpp:320:22:320:42 | call to vector | TAINT | +| vector.cpp:321:22:321:23 | ref arg v2 | vector.cpp:321:34:321:35 | v2 | | +| vector.cpp:321:22:321:23 | ref arg v2 | vector.cpp:324:7:324:8 | v2 | | +| vector.cpp:321:22:321:23 | ref arg v2 | vector.cpp:327:1:327:1 | v2 | | +| vector.cpp:321:22:321:23 | v2 | vector.cpp:321:25:321:29 | call to begin | TAINT | +| vector.cpp:321:22:321:42 | call to vector | vector.cpp:326:7:326:8 | v4 | | +| vector.cpp:321:22:321:42 | call to vector | vector.cpp:327:1:327:1 | v4 | | +| vector.cpp:321:25:321:29 | call to begin | vector.cpp:321:22:321:42 | call to vector | TAINT | +| vector.cpp:321:34:321:35 | ref arg v2 | vector.cpp:324:7:324:8 | v2 | | +| vector.cpp:321:34:321:35 | ref arg v2 | vector.cpp:327:1:327:1 | v2 | | +| vector.cpp:321:34:321:35 | v2 | vector.cpp:321:37:321:39 | call to end | TAINT | +| vector.cpp:321:37:321:39 | call to end | vector.cpp:321:22:321:42 | call to vector | TAINT | +| vector.cpp:323:7:323:8 | ref arg v1 | vector.cpp:327:1:327:1 | v1 | | +| vector.cpp:324:7:324:8 | ref arg v2 | vector.cpp:327:1:327:1 | v2 | | +| vector.cpp:325:7:325:8 | ref arg v3 | vector.cpp:327:1:327:1 | v3 | | +| vector.cpp:326:7:326:8 | ref arg v4 | vector.cpp:327:1:327:1 | v4 | | +| vector.cpp:329:62:329:65 | iter | vector.cpp:329:62:329:65 | iter | | +| vector.cpp:329:62:329:65 | iter | vector.cpp:330:3:330:6 | iter | | +| vector.cpp:330:2:330:2 | call to operator* [post update] | vector.cpp:329:62:329:65 | iter | | +| vector.cpp:330:2:330:17 | ... = ... | vector.cpp:330:2:330:2 | call to operator* [post update] | | +| vector.cpp:330:3:330:6 | iter | vector.cpp:330:2:330:2 | call to operator* | TAINT | +| vector.cpp:330:10:330:15 | call to source | vector.cpp:330:2:330:2 | call to operator* [post update] | TAINT | +| vector.cpp:330:10:330:15 | call to source | vector.cpp:330:2:330:17 | ... = ... | | +| vector.cpp:333:64:333:67 | iter | vector.cpp:333:64:333:67 | iter | | +| vector.cpp:333:64:333:67 | iter | vector.cpp:334:3:334:6 | iter | | +| vector.cpp:333:74:333:74 | i | vector.cpp:334:10:334:10 | i | | +| vector.cpp:334:2:334:2 | call to operator* [post update] | vector.cpp:333:64:333:67 | iter | | +| vector.cpp:334:2:334:10 | ... = ... | vector.cpp:334:2:334:2 | call to operator* [post update] | | +| vector.cpp:334:3:334:6 | iter | vector.cpp:334:2:334:2 | call to operator* | TAINT | +| vector.cpp:334:10:334:10 | i | vector.cpp:334:2:334:2 | call to operator* [post update] | TAINT | +| vector.cpp:334:10:334:10 | i | vector.cpp:334:2:334:10 | ... = ... | | +| vector.cpp:337:38:337:38 | b | vector.cpp:372:5:372:5 | b | | +| vector.cpp:338:22:338:24 | call to vector | vector.cpp:340:34:340:35 | v1 | | +| vector.cpp:338:22:338:24 | call to vector | vector.cpp:342:7:342:8 | v1 | | +| vector.cpp:338:22:338:24 | call to vector | vector.cpp:401:1:401:1 | v1 | | +| vector.cpp:338:30:338:32 | call to vector | vector.cpp:344:38:344:39 | v2 | | +| vector.cpp:338:30:338:32 | call to vector | vector.cpp:344:56:344:57 | v2 | | +| vector.cpp:338:30:338:32 | call to vector | vector.cpp:347:7:347:8 | v2 | | +| vector.cpp:338:30:338:32 | call to vector | vector.cpp:401:1:401:1 | v2 | | +| vector.cpp:338:38:338:40 | call to vector | vector.cpp:349:15:349:16 | v3 | | +| vector.cpp:338:38:338:40 | call to vector | vector.cpp:352:7:352:8 | v3 | | +| vector.cpp:338:38:338:40 | call to vector | vector.cpp:401:1:401:1 | v3 | | +| vector.cpp:338:46:338:48 | call to vector | vector.cpp:354:38:354:39 | v4 | | +| vector.cpp:338:46:338:48 | call to vector | vector.cpp:354:56:354:57 | v4 | | +| vector.cpp:338:46:338:48 | call to vector | vector.cpp:357:7:357:8 | v4 | | +| vector.cpp:338:46:338:48 | call to vector | vector.cpp:401:1:401:1 | v4 | | +| vector.cpp:338:54:338:56 | call to vector | vector.cpp:359:34:359:35 | v5 | | +| vector.cpp:338:54:338:56 | call to vector | vector.cpp:361:7:361:8 | v5 | | +| vector.cpp:338:54:338:56 | call to vector | vector.cpp:363:7:363:8 | v5 | | +| vector.cpp:338:54:338:56 | call to vector | vector.cpp:401:1:401:1 | v5 | | +| vector.cpp:338:62:338:64 | call to vector | vector.cpp:365:34:365:35 | v6 | | +| vector.cpp:338:62:338:64 | call to vector | vector.cpp:367:7:367:8 | v6 | | +| vector.cpp:338:62:338:64 | call to vector | vector.cpp:368:2:368:3 | v6 | | +| vector.cpp:338:62:338:64 | call to vector | vector.cpp:369:7:369:8 | v6 | | +| vector.cpp:338:62:338:64 | call to vector | vector.cpp:401:1:401:1 | v6 | | +| vector.cpp:338:70:338:72 | call to vector | vector.cpp:371:34:371:35 | v7 | | +| vector.cpp:338:70:338:72 | call to vector | vector.cpp:374:8:374:9 | v7 | | +| vector.cpp:338:70:338:72 | call to vector | vector.cpp:377:8:377:9 | v7 | | +| vector.cpp:338:70:338:72 | call to vector | vector.cpp:379:7:379:8 | v7 | | +| vector.cpp:338:70:338:72 | call to vector | vector.cpp:401:1:401:1 | v7 | | +| vector.cpp:338:78:338:80 | call to vector | vector.cpp:381:34:381:35 | v8 | | +| vector.cpp:338:78:338:80 | call to vector | vector.cpp:383:7:383:8 | v8 | | +| vector.cpp:338:78:338:80 | call to vector | vector.cpp:385:7:385:8 | v8 | | +| vector.cpp:338:78:338:80 | call to vector | vector.cpp:401:1:401:1 | v8 | | +| vector.cpp:338:86:338:88 | call to vector | vector.cpp:387:34:387:35 | v9 | | +| vector.cpp:338:86:338:88 | call to vector | vector.cpp:392:7:392:8 | v9 | | +| vector.cpp:338:86:338:88 | call to vector | vector.cpp:401:1:401:1 | v9 | | +| vector.cpp:338:95:338:97 | call to vector | vector.cpp:394:35:394:37 | v10 | | +| vector.cpp:338:95:338:97 | call to vector | vector.cpp:396:7:396:9 | v10 | | +| vector.cpp:338:95:338:97 | call to vector | vector.cpp:401:1:401:1 | v10 | | +| vector.cpp:338:104:338:106 | call to vector | vector.cpp:398:35:398:37 | v11 | | +| vector.cpp:338:104:338:106 | call to vector | vector.cpp:400:7:400:9 | v11 | | +| vector.cpp:338:104:338:106 | call to vector | vector.cpp:401:1:401:1 | v11 | | +| vector.cpp:340:34:340:35 | ref arg v1 | vector.cpp:342:7:342:8 | v1 | | +| vector.cpp:340:34:340:35 | ref arg v1 | vector.cpp:401:1:401:1 | v1 | | +| vector.cpp:340:34:340:35 | v1 | vector.cpp:340:37:340:41 | call to begin | TAINT | +| vector.cpp:340:37:340:41 | call to begin | vector.cpp:341:3:341:4 | i1 | | +| vector.cpp:341:2:341:2 | call to operator* [post update] | vector.cpp:342:7:342:8 | v1 | | +| vector.cpp:341:2:341:2 | call to operator* [post update] | vector.cpp:401:1:401:1 | v1 | | +| vector.cpp:341:2:341:15 | ... = ... | vector.cpp:341:2:341:2 | call to operator* [post update] | | +| vector.cpp:341:3:341:4 | i1 | vector.cpp:341:2:341:2 | call to operator* | TAINT | +| vector.cpp:341:8:341:13 | call to source | vector.cpp:341:2:341:2 | call to operator* [post update] | TAINT | +| vector.cpp:341:8:341:13 | call to source | vector.cpp:341:2:341:15 | ... = ... | | +| vector.cpp:342:7:342:8 | ref arg v1 | vector.cpp:401:1:401:1 | v1 | | +| vector.cpp:344:38:344:39 | ref arg v2 | vector.cpp:344:56:344:57 | v2 | | +| vector.cpp:344:38:344:39 | ref arg v2 | vector.cpp:347:7:347:8 | v2 | | +| vector.cpp:344:38:344:39 | ref arg v2 | vector.cpp:401:1:401:1 | v2 | | +| vector.cpp:344:38:344:39 | v2 | vector.cpp:344:41:344:45 | call to begin | TAINT | +| vector.cpp:344:41:344:45 | call to begin | vector.cpp:344:50:344:51 | it | | +| vector.cpp:344:41:344:45 | call to begin | vector.cpp:344:68:344:69 | it | | +| vector.cpp:344:41:344:45 | call to begin | vector.cpp:345:4:345:5 | it | | +| vector.cpp:344:56:344:57 | ref arg v2 | vector.cpp:344:56:344:57 | v2 | | +| vector.cpp:344:56:344:57 | ref arg v2 | vector.cpp:347:7:347:8 | v2 | | +| vector.cpp:344:56:344:57 | ref arg v2 | vector.cpp:401:1:401:1 | v2 | | +| vector.cpp:344:56:344:57 | v2 | vector.cpp:344:59:344:61 | call to end | TAINT | +| vector.cpp:344:68:344:69 | it | vector.cpp:344:66:344:66 | call to operator++ | | +| vector.cpp:344:68:344:69 | ref arg it | vector.cpp:344:50:344:51 | it | | +| vector.cpp:344:68:344:69 | ref arg it | vector.cpp:344:68:344:69 | it | | +| vector.cpp:344:68:344:69 | ref arg it | vector.cpp:345:4:345:5 | it | | +| vector.cpp:345:3:345:3 | call to operator* [post update] | vector.cpp:344:56:344:57 | v2 | | +| vector.cpp:345:3:345:3 | call to operator* [post update] | vector.cpp:347:7:347:8 | v2 | | +| vector.cpp:345:3:345:3 | call to operator* [post update] | vector.cpp:401:1:401:1 | v2 | | +| vector.cpp:345:3:345:16 | ... = ... | vector.cpp:345:3:345:3 | call to operator* [post update] | | +| vector.cpp:345:4:345:5 | it | vector.cpp:345:3:345:3 | call to operator* | TAINT | +| vector.cpp:345:9:345:14 | call to source | vector.cpp:345:3:345:3 | call to operator* [post update] | TAINT | +| vector.cpp:345:9:345:14 | call to source | vector.cpp:345:3:345:16 | ... = ... | | +| vector.cpp:347:7:347:8 | ref arg v2 | vector.cpp:401:1:401:1 | v2 | | +| vector.cpp:349:15:349:15 | (__begin) | vector.cpp:349:15:349:15 | call to operator* | TAINT | +| vector.cpp:349:15:349:15 | (__begin) | vector.cpp:349:15:349:15 | call to operator++ | | +| vector.cpp:349:15:349:15 | (__end) | vector.cpp:349:15:349:15 | call to iterator | | +| vector.cpp:349:15:349:15 | (__range) | vector.cpp:349:15:349:15 | call to begin | TAINT | +| vector.cpp:349:15:349:15 | (__range) | vector.cpp:349:15:349:15 | call to end | TAINT | +| vector.cpp:349:15:349:15 | call to begin | vector.cpp:349:15:349:15 | (__begin) | | +| vector.cpp:349:15:349:15 | call to begin | vector.cpp:349:15:349:15 | (__begin) | | +| vector.cpp:349:15:349:15 | call to begin | vector.cpp:349:15:349:15 | (__begin) | | +| vector.cpp:349:15:349:15 | call to end | vector.cpp:349:15:349:15 | (__end) | | +| vector.cpp:349:15:349:15 | ref arg (__begin) | vector.cpp:349:15:349:15 | (__begin) | | +| vector.cpp:349:15:349:15 | ref arg (__begin) | vector.cpp:349:15:349:15 | (__begin) | | +| vector.cpp:349:15:349:15 | ref arg (__begin) | vector.cpp:349:15:349:15 | (__begin) | | +| vector.cpp:349:15:349:15 | ref arg (__range) | vector.cpp:349:15:349:15 | (__range) | | +| vector.cpp:349:15:349:16 | v3 | vector.cpp:349:15:349:15 | (__range) | | +| vector.cpp:349:15:349:16 | v3 | vector.cpp:349:15:349:15 | (__range) | | +| vector.cpp:349:15:349:16 | v3 | vector.cpp:349:15:349:15 | call to operator* | TAINT | +| vector.cpp:350:3:350:14 | ... = ... | vector.cpp:350:3:350:3 | x [post update] | | +| vector.cpp:350:7:350:12 | call to source | vector.cpp:350:3:350:14 | ... = ... | | +| vector.cpp:352:7:352:8 | ref arg v3 | vector.cpp:401:1:401:1 | v3 | | +| vector.cpp:354:38:354:39 | ref arg v4 | vector.cpp:354:56:354:57 | v4 | | +| vector.cpp:354:38:354:39 | ref arg v4 | vector.cpp:357:7:357:8 | v4 | | +| vector.cpp:354:38:354:39 | ref arg v4 | vector.cpp:401:1:401:1 | v4 | | +| vector.cpp:354:38:354:39 | v4 | vector.cpp:354:41:354:45 | call to begin | TAINT | +| vector.cpp:354:41:354:45 | call to begin | vector.cpp:354:50:354:51 | it | | +| vector.cpp:354:41:354:45 | call to begin | vector.cpp:354:68:354:69 | it | | +| vector.cpp:354:41:354:45 | call to begin | vector.cpp:355:32:355:33 | it | | +| vector.cpp:354:56:354:57 | ref arg v4 | vector.cpp:354:56:354:57 | v4 | | +| vector.cpp:354:56:354:57 | ref arg v4 | vector.cpp:357:7:357:8 | v4 | | +| vector.cpp:354:56:354:57 | ref arg v4 | vector.cpp:401:1:401:1 | v4 | | +| vector.cpp:354:56:354:57 | v4 | vector.cpp:354:59:354:61 | call to end | TAINT | +| vector.cpp:354:68:354:69 | it | vector.cpp:354:66:354:66 | call to operator++ | | +| vector.cpp:354:68:354:69 | ref arg it | vector.cpp:354:50:354:51 | it | | +| vector.cpp:354:68:354:69 | ref arg it | vector.cpp:354:68:354:69 | it | | +| vector.cpp:354:68:354:69 | ref arg it | vector.cpp:355:32:355:33 | it | | +| vector.cpp:355:32:355:33 | call to iterator [post update] | vector.cpp:354:56:354:57 | v4 | | +| vector.cpp:355:32:355:33 | call to iterator [post update] | vector.cpp:357:7:357:8 | v4 | | +| vector.cpp:355:32:355:33 | call to iterator [post update] | vector.cpp:401:1:401:1 | v4 | | +| vector.cpp:355:32:355:33 | it | vector.cpp:355:32:355:33 | call to iterator | | +| vector.cpp:355:32:355:33 | it [post update] | vector.cpp:354:56:354:57 | v4 | | +| vector.cpp:355:32:355:33 | it [post update] | vector.cpp:357:7:357:8 | v4 | | +| vector.cpp:355:32:355:33 | it [post update] | vector.cpp:401:1:401:1 | v4 | | +| vector.cpp:357:7:357:8 | ref arg v4 | vector.cpp:401:1:401:1 | v4 | | +| vector.cpp:359:34:359:35 | ref arg v5 | vector.cpp:361:7:361:8 | v5 | | +| vector.cpp:359:34:359:35 | ref arg v5 | vector.cpp:363:7:363:8 | v5 | | +| vector.cpp:359:34:359:35 | ref arg v5 | vector.cpp:401:1:401:1 | v5 | | +| vector.cpp:359:34:359:35 | v5 | vector.cpp:359:37:359:41 | call to begin | TAINT | +| vector.cpp:359:37:359:41 | call to begin | vector.cpp:360:3:360:4 | i5 | | +| vector.cpp:359:37:359:41 | call to begin | vector.cpp:362:3:362:4 | i5 | | +| vector.cpp:360:2:360:2 | call to operator* [post update] | vector.cpp:361:7:361:8 | v5 | | +| vector.cpp:360:2:360:2 | call to operator* [post update] | vector.cpp:363:7:363:8 | v5 | | +| vector.cpp:360:2:360:2 | call to operator* [post update] | vector.cpp:401:1:401:1 | v5 | | +| vector.cpp:360:2:360:15 | ... = ... | vector.cpp:360:2:360:2 | call to operator* [post update] | | +| vector.cpp:360:3:360:4 | i5 | vector.cpp:360:2:360:2 | call to operator* | TAINT | +| vector.cpp:360:8:360:13 | call to source | vector.cpp:360:2:360:2 | call to operator* [post update] | TAINT | +| vector.cpp:360:8:360:13 | call to source | vector.cpp:360:2:360:15 | ... = ... | | +| vector.cpp:361:7:361:8 | ref arg v5 | vector.cpp:363:7:363:8 | v5 | | +| vector.cpp:361:7:361:8 | ref arg v5 | vector.cpp:401:1:401:1 | v5 | | +| vector.cpp:362:2:362:2 | call to operator* [post update] | vector.cpp:363:7:363:8 | v5 | | +| vector.cpp:362:2:362:2 | call to operator* [post update] | vector.cpp:401:1:401:1 | v5 | | +| vector.cpp:362:2:362:8 | ... = ... | vector.cpp:362:2:362:2 | call to operator* [post update] | | +| vector.cpp:362:3:362:4 | i5 | vector.cpp:362:2:362:2 | call to operator* | TAINT | +| vector.cpp:362:8:362:8 | 1 | vector.cpp:362:2:362:2 | call to operator* [post update] | TAINT | +| vector.cpp:362:8:362:8 | 1 | vector.cpp:362:2:362:8 | ... = ... | | +| vector.cpp:363:7:363:8 | ref arg v5 | vector.cpp:401:1:401:1 | v5 | | +| vector.cpp:365:34:365:35 | ref arg v6 | vector.cpp:367:7:367:8 | v6 | | +| vector.cpp:365:34:365:35 | ref arg v6 | vector.cpp:368:2:368:3 | v6 | | +| vector.cpp:365:34:365:35 | ref arg v6 | vector.cpp:369:7:369:8 | v6 | | +| vector.cpp:365:34:365:35 | ref arg v6 | vector.cpp:401:1:401:1 | v6 | | +| vector.cpp:365:34:365:35 | v6 | vector.cpp:365:37:365:41 | call to begin | TAINT | +| vector.cpp:365:37:365:41 | call to begin | vector.cpp:366:3:366:4 | i6 | | +| vector.cpp:366:2:366:2 | call to operator* [post update] | vector.cpp:367:7:367:8 | v6 | | +| vector.cpp:366:2:366:2 | call to operator* [post update] | vector.cpp:368:2:368:3 | v6 | | +| vector.cpp:366:2:366:2 | call to operator* [post update] | vector.cpp:369:7:369:8 | v6 | | +| vector.cpp:366:2:366:2 | call to operator* [post update] | vector.cpp:401:1:401:1 | v6 | | +| vector.cpp:366:2:366:15 | ... = ... | vector.cpp:366:2:366:2 | call to operator* [post update] | | +| vector.cpp:366:3:366:4 | i6 | vector.cpp:366:2:366:2 | call to operator* | TAINT | +| vector.cpp:366:8:366:13 | call to source | vector.cpp:366:2:366:2 | call to operator* [post update] | TAINT | +| vector.cpp:366:8:366:13 | call to source | vector.cpp:366:2:366:15 | ... = ... | | +| vector.cpp:367:7:367:8 | ref arg v6 | vector.cpp:368:2:368:3 | v6 | | +| vector.cpp:367:7:367:8 | ref arg v6 | vector.cpp:369:7:369:8 | v6 | | +| vector.cpp:367:7:367:8 | ref arg v6 | vector.cpp:401:1:401:1 | v6 | | +| vector.cpp:368:2:368:3 | ref arg v6 | vector.cpp:369:7:369:8 | v6 | | +| vector.cpp:368:2:368:3 | ref arg v6 | vector.cpp:401:1:401:1 | v6 | | +| vector.cpp:368:7:368:26 | call to vector | vector.cpp:368:2:368:3 | ref arg v6 | TAINT | +| vector.cpp:368:7:368:26 | call to vector | vector.cpp:368:5:368:5 | call to operator= | TAINT | +| vector.cpp:369:7:369:8 | ref arg v6 | vector.cpp:401:1:401:1 | v6 | | +| vector.cpp:371:34:371:35 | ref arg v7 | vector.cpp:374:8:374:9 | v7 | | +| vector.cpp:371:34:371:35 | ref arg v7 | vector.cpp:377:8:377:9 | v7 | | +| vector.cpp:371:34:371:35 | ref arg v7 | vector.cpp:379:7:379:8 | v7 | | +| vector.cpp:371:34:371:35 | ref arg v7 | vector.cpp:401:1:401:1 | v7 | | +| vector.cpp:371:34:371:35 | v7 | vector.cpp:371:37:371:41 | call to begin | TAINT | +| vector.cpp:371:37:371:41 | call to begin | vector.cpp:373:4:373:5 | i7 | | +| vector.cpp:371:37:371:41 | call to begin | vector.cpp:376:4:376:5 | i7 | | +| vector.cpp:373:3:373:3 | call to operator* [post update] | vector.cpp:374:8:374:9 | v7 | | +| vector.cpp:373:3:373:3 | call to operator* [post update] | vector.cpp:379:7:379:8 | v7 | | +| vector.cpp:373:3:373:3 | call to operator* [post update] | vector.cpp:401:1:401:1 | v7 | | +| vector.cpp:373:3:373:16 | ... = ... | vector.cpp:373:3:373:3 | call to operator* [post update] | | +| vector.cpp:373:4:373:5 | i7 | vector.cpp:373:3:373:3 | call to operator* | TAINT | +| vector.cpp:373:9:373:14 | call to source | vector.cpp:373:3:373:3 | call to operator* [post update] | TAINT | +| vector.cpp:373:9:373:14 | call to source | vector.cpp:373:3:373:16 | ... = ... | | +| vector.cpp:374:8:374:9 | ref arg v7 | vector.cpp:379:7:379:8 | v7 | | +| vector.cpp:374:8:374:9 | ref arg v7 | vector.cpp:401:1:401:1 | v7 | | +| vector.cpp:376:3:376:3 | call to operator* [post update] | vector.cpp:377:8:377:9 | v7 | | +| vector.cpp:376:3:376:3 | call to operator* [post update] | vector.cpp:379:7:379:8 | v7 | | +| vector.cpp:376:3:376:3 | call to operator* [post update] | vector.cpp:401:1:401:1 | v7 | | +| vector.cpp:376:3:376:9 | ... = ... | vector.cpp:376:3:376:3 | call to operator* [post update] | | +| vector.cpp:376:4:376:5 | i7 | vector.cpp:376:3:376:3 | call to operator* | TAINT | +| vector.cpp:376:9:376:9 | 1 | vector.cpp:376:3:376:3 | call to operator* [post update] | TAINT | +| vector.cpp:376:9:376:9 | 1 | vector.cpp:376:3:376:9 | ... = ... | | +| vector.cpp:377:8:377:9 | ref arg v7 | vector.cpp:379:7:379:8 | v7 | | +| vector.cpp:377:8:377:9 | ref arg v7 | vector.cpp:401:1:401:1 | v7 | | +| vector.cpp:379:7:379:8 | ref arg v7 | vector.cpp:401:1:401:1 | v7 | | +| vector.cpp:381:34:381:35 | ref arg v8 | vector.cpp:383:7:383:8 | v8 | | +| vector.cpp:381:34:381:35 | ref arg v8 | vector.cpp:385:7:385:8 | v8 | | +| vector.cpp:381:34:381:35 | ref arg v8 | vector.cpp:401:1:401:1 | v8 | | +| vector.cpp:381:34:381:35 | v8 | vector.cpp:381:37:381:41 | call to begin | TAINT | +| vector.cpp:381:37:381:41 | call to begin | vector.cpp:382:3:382:4 | i8 | | +| vector.cpp:381:37:381:41 | call to begin | vector.cpp:384:3:384:4 | i8 | | +| vector.cpp:382:2:382:2 | call to operator* [post update] | vector.cpp:383:7:383:8 | v8 | | +| vector.cpp:382:2:382:2 | call to operator* [post update] | vector.cpp:385:7:385:8 | v8 | | +| vector.cpp:382:2:382:2 | call to operator* [post update] | vector.cpp:401:1:401:1 | v8 | | +| vector.cpp:382:2:382:15 | ... = ... | vector.cpp:382:2:382:2 | call to operator* [post update] | | +| vector.cpp:382:3:382:4 | i8 | vector.cpp:382:2:382:2 | call to operator* | TAINT | +| vector.cpp:382:8:382:13 | call to source | vector.cpp:382:2:382:2 | call to operator* [post update] | TAINT | +| vector.cpp:382:8:382:13 | call to source | vector.cpp:382:2:382:15 | ... = ... | | +| vector.cpp:383:7:383:8 | ref arg v8 | vector.cpp:385:7:385:8 | v8 | | +| vector.cpp:383:7:383:8 | ref arg v8 | vector.cpp:401:1:401:1 | v8 | | +| vector.cpp:384:2:384:2 | call to operator* [post update] | vector.cpp:385:7:385:8 | v8 | | +| vector.cpp:384:2:384:2 | call to operator* [post update] | vector.cpp:401:1:401:1 | v8 | | +| vector.cpp:384:2:384:8 | ... = ... | vector.cpp:384:2:384:2 | call to operator* [post update] | | +| vector.cpp:384:3:384:4 | i8 | vector.cpp:384:2:384:2 | call to operator* | TAINT | +| vector.cpp:384:8:384:8 | 1 | vector.cpp:384:2:384:2 | call to operator* [post update] | TAINT | +| vector.cpp:384:8:384:8 | 1 | vector.cpp:384:2:384:8 | ... = ... | | +| vector.cpp:385:7:385:8 | ref arg v8 | vector.cpp:401:1:401:1 | v8 | | +| vector.cpp:387:34:387:35 | ref arg v9 | vector.cpp:392:7:392:8 | v9 | | +| vector.cpp:387:34:387:35 | ref arg v9 | vector.cpp:401:1:401:1 | v9 | | +| vector.cpp:387:34:387:35 | v9 | vector.cpp:387:37:387:41 | call to begin | TAINT | +| vector.cpp:387:37:387:41 | call to begin | vector.cpp:389:3:389:4 | i9 | | +| vector.cpp:387:37:387:41 | call to begin | vector.cpp:390:31:390:32 | i9 | | +| vector.cpp:389:2:389:2 | call to operator* [post update] | vector.cpp:392:7:392:8 | v9 | | +| vector.cpp:389:2:389:2 | call to operator* [post update] | vector.cpp:401:1:401:1 | v9 | | +| vector.cpp:389:2:389:15 | ... = ... | vector.cpp:389:2:389:2 | call to operator* [post update] | | +| vector.cpp:389:3:389:4 | i9 | vector.cpp:389:2:389:2 | call to operator* | TAINT | +| vector.cpp:389:8:389:13 | call to source | vector.cpp:389:2:389:2 | call to operator* [post update] | TAINT | +| vector.cpp:389:8:389:13 | call to source | vector.cpp:389:2:389:15 | ... = ... | | +| vector.cpp:390:31:390:32 | call to iterator [post update] | vector.cpp:392:7:392:8 | v9 | | +| vector.cpp:390:31:390:32 | call to iterator [post update] | vector.cpp:401:1:401:1 | v9 | | +| vector.cpp:390:31:390:32 | i9 | vector.cpp:390:31:390:32 | call to iterator | | +| vector.cpp:390:31:390:32 | i9 [post update] | vector.cpp:392:7:392:8 | v9 | | +| vector.cpp:390:31:390:32 | i9 [post update] | vector.cpp:401:1:401:1 | v9 | | +| vector.cpp:392:7:392:8 | ref arg v9 | vector.cpp:401:1:401:1 | v9 | | +| vector.cpp:394:35:394:37 | ref arg v10 | vector.cpp:396:7:396:9 | v10 | | +| vector.cpp:394:35:394:37 | ref arg v10 | vector.cpp:401:1:401:1 | v10 | | +| vector.cpp:394:35:394:37 | v10 | vector.cpp:394:39:394:43 | call to begin | TAINT | +| vector.cpp:394:39:394:43 | call to begin | vector.cpp:395:33:395:35 | i10 | | +| vector.cpp:395:33:395:35 | call to iterator [post update] | vector.cpp:396:7:396:9 | v10 | | +| vector.cpp:395:33:395:35 | call to iterator [post update] | vector.cpp:401:1:401:1 | v10 | | +| vector.cpp:395:33:395:35 | i10 | vector.cpp:395:33:395:35 | call to iterator | | +| vector.cpp:395:33:395:35 | i10 [post update] | vector.cpp:396:7:396:9 | v10 | | +| vector.cpp:395:33:395:35 | i10 [post update] | vector.cpp:401:1:401:1 | v10 | | +| vector.cpp:396:7:396:9 | ref arg v10 | vector.cpp:401:1:401:1 | v10 | | +| vector.cpp:398:35:398:37 | ref arg v11 | vector.cpp:400:7:400:9 | v11 | | +| vector.cpp:398:35:398:37 | ref arg v11 | vector.cpp:401:1:401:1 | v11 | | +| vector.cpp:398:35:398:37 | v11 | vector.cpp:398:39:398:43 | call to begin | TAINT | +| vector.cpp:398:39:398:43 | call to begin | vector.cpp:399:33:399:35 | i11 | | +| vector.cpp:399:33:399:35 | call to iterator [post update] | vector.cpp:400:7:400:9 | v11 | | +| vector.cpp:399:33:399:35 | call to iterator [post update] | vector.cpp:401:1:401:1 | v11 | | +| vector.cpp:399:33:399:35 | i11 | vector.cpp:399:33:399:35 | call to iterator | | +| vector.cpp:399:33:399:35 | i11 [post update] | vector.cpp:400:7:400:9 | v11 | | +| vector.cpp:399:33:399:35 | i11 [post update] | vector.cpp:401:1:401:1 | v11 | | +| vector.cpp:400:7:400:9 | ref arg v11 | vector.cpp:401:1:401:1 | v11 | | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/map.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/map.cpp new file mode 100644 index 000000000000..6b4d32f074f4 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/map.cpp @@ -0,0 +1,438 @@ + +#include "stl.h" + +using namespace std; + +char *source(); + +void sink(char *); +void sink(const char *); +void sink(bool); +void sink(std::pair); +void sink(std::map); +void sink(std::map::iterator); +void sink(std::unordered_map); +void sink(std::unordered_map::iterator); +void sink(std::unordered_map >); +void sink(std::unordered_map >::iterator); + +void test_pair() +{ + std::pair a, b, c; + + a.first = "123"; + sink(a.first); + sink(a.second); + sink(a); + + b.first = source(); + sink(b.first); // tainted + sink(b.second); + sink(b); // tainted [NOT DETECTED] + + c.second = source(); + sink(c.first); + sink(c.second); // tainted + sink(c); // tainted [NOT DETECTED] + + std::pair d("123", "456"); + sink(d.first); + sink(d.second); + sink(d); + + std::pair e(source(), "456"); + sink(e.first); // tainted + sink(e.second); + sink(e); // tainted [NOT DETECTED] + + std::pair f("123", source()); + sink(f.first); // [FALSE POSITIVE] + sink(f.second); // tainted + sink(f); // tainted + + std::pair g(f); + sink(g.first); // [FALSE POSITIVE] + sink(g.second); // tainted + sink(g); // tainted + + std::pair h; + h = f; + sink(h.first); // [FALSE POSITIVE] + sink(h.second); // tainted + sink(h); // tainted + + std::pair i("123", "456"); + std::pair j("123", source()); + std::pair k("123", source()); + std::pair l("123", "456"); + i.swap(j); + k.swap(l); + sink(i.first); // [FALSE POSITIVE] + sink(i.second); // tainted + sink(i); // tainted + sink(j.first); // [FALSE POSITIVE] + sink(j.second); // [FALSE POSITIVE] + sink(j); // [FALSE POSITIVE] + sink(k.first); // [FALSE POSITIVE] + sink(k.second); // [FALSE POSITIVE] + sink(k); // [FALSE POSITIVE] + sink(l.first); // [FALSE POSITIVE] + sink(l.second); // tainted + sink(l); // tainted + + sink(make_pair("123", "456")); + sink(make_pair("123", "456").first); + sink(make_pair("123", "456").second); + sink(make_pair(source(), "456")); // tainted [NOT DETECTED] + sink(make_pair(source(), "456").first); // tainted [NOT DETECTED] + sink(make_pair(source(), "456").second); + sink(make_pair("123", source())); // tainted + sink(make_pair("123", source()).first); // [FALSE POSITIVE] + sink(make_pair("123", source()).second); // tainted + + std::pair, char *> m; + m = make_pair(make_pair("123", source()), "789"); + sink(m); // tainted [NOT DETECTED] + sink(m.first); // tainted [NOT DETECTED] + sink(m.first.first); + sink(m.first.second); // tainted [NOT DETECTED] + sink(m.second); +} + +void test_map() +{ + // insert + std::map m1, m2, m3, m4, m5, m6; + + sink(m1.insert(std::make_pair("abc", "def")).first); + sink(m2.insert(std::make_pair("abc", source())).first); // tainted + sink(m3.insert(std::make_pair(source(), "def")).first); // tainted [NOT DETECTED] + sink(m4.insert(m4.begin(), std::pair("abc", source()))); // tainted + sink(m5.insert_or_assign("abc", source()).first); // tainted + sink(m6.insert_or_assign(m6.begin(), "abc", source())); // tainted + sink(m1); + sink(m2); // tainted + sink(m3); // tainted [NOT DETECTED] + sink(m4); // tainted + sink(m5); // tainted + sink(m6); // tainted + sink(m1.find("abc")); + sink(m2.find("abc")); // tainted + sink(m3.find("abc")); + sink(m4.find("abc")); // tainted + sink(m5.find("abc")); // tainted + sink(m6.find("abc")); // tainted + sink(m1.find("def")); + sink(m2.find("def")); // [FALSE POSITIVE] + sink(m3.find("def")); + sink(m4.find("def")); // [FALSE POSITIVE] + sink(m5.find("def")); // [FALSE POSITIVE] + sink(m6.find("def")); // [FALSE POSITIVE] + + // copy constructors and assignment + std::map m7(m2); + std::map m8 = m2; + std::map m9; + m9 = m2; + sink(m7); // tainted + sink(m8); // tainted + sink(m9); // tainted + sink(m7.find("abc")); // tainted + sink(m8.find("abc")); // tainted + sink(m9.find("abc")); // tainted + + // iterators + std::map::iterator i1, i2, i3; + for (i1 = m1.begin(); i1 != m1.end(); i1++) + { + sink(*i1); + sink(i1->first); + sink(i1->second); + } + for (i2 = m2.begin(); i2 != m2.end(); i2++) + { + sink(*i2); // tainted + sink(i2->first); // [FALSE POSITIVE] + sink(i2->second); // tainted + } + for (i3 = m3.begin(); i3 != m3.end(); i3++) + { + sink(*i3); // tainted [NOT DETECTED] + sink(i2->first); // tainted + sink(i2->second); // [FALSE POSITIVE] + } + + // array-like access + std::map m10, m11, m12, m13; + sink(m10["abc"] = "def"); + sink(m11["abc"] = source()); // tainted + sink(m12.at("abc") = "def"); + sink(m13.at("abc") = source()); // tainted + sink(m10["abc"]); + sink(m11["abc"]); // tainted + sink(m12["abc"]); + sink(m13["abc"]); // tainted + + // ranges + std::map m14; + m14.insert(std::make_pair("a", "a")); + m14.insert(std::make_pair("b", source())); + m14.insert(std::make_pair("c", source())); + m14.insert(std::make_pair("d", "d")); + sink(m2.lower_bound("b")); // tainted + sink(m2.upper_bound("b")); // tainted + sink(m2.equal_range("b").first); // tainted + sink(m2.equal_range("b").second); // tainted + sink(m2.upper_bound("c")); // [FALSE POSITIVE] + sink(m2.equal_range("c").second); // [FALSE POSITIVE] + + // swap + std::map m15, m16, m17, m18; + m15.insert(std::pair(source(), source())); + m18.insert(std::pair(source(), source())); + sink(m15); // tainted + sink(m16); + sink(m17); + sink(m18); // tainted + m15.swap(m16); + m17.swap(m18); + sink(m15); // [FALSE POSITIVE] + sink(m16); // tainted + sink(m17); // tainted + sink(m18); // [FALSE POSITIVE] + + // merge + std::map m19, m20, m21, m22; + m19.insert(std::pair(source(), source())); + m20.insert(std::pair("abc", "def")); + m21.insert(std::pair("abc", "def")); + m22.insert(std::pair(source(), source())); + sink(m19); // tainted + sink(m20); + sink(m21); + sink(m22); // tainted + m19.merge(m20); + m21.merge(m22); + sink(m19); // tainted + sink(m20); + sink(m21); // tainted + sink(m22); // tainted + + // erase, clear + std::map m23; + m23.insert(std::pair(source(), source())); + m23.insert(std::pair(source(), source())); + sink(m23); // tainted + sink(m23.erase(m23.begin())); // tainted + sink(m23); // tainted + m23.clear(); + sink(m23); // [FALSE POSITIVE] + + // emplace, emplace_hint + std::map m24, m25; + sink(m24.emplace("abc", "def").first); + sink(m24); + sink(m24.emplace("abc", source()).first); // tainted + sink(m24); // tainted + sink(m25.emplace_hint(m25.begin(), "abc", "def")); + sink(m25); + sink(m25.emplace_hint(m25.begin(), "abc", source())); // tainted + sink(m25); // tainted + + // try_emplace + std::map m26, m27; + sink(m26.try_emplace("abc", "def").first); + sink(m26); + sink(m26.try_emplace("abc", source()).first); // tainted + sink(m26); // tainted + sink(m27.try_emplace(m27.begin(), "abc", "def")); + sink(m27); + sink(m27.try_emplace(m27.begin(), "abc", source())); // tainted + sink(m27); // tainted +} + +void test_unordered_map() +{ + // insert + std::unordered_map m1, m2, m3, m4, m5, m6; + + sink(m1.insert(std::make_pair("abc", "def")).first); + sink(m2.insert(std::make_pair("abc", source())).first); // tainted + sink(m3.insert(std::make_pair(source(), "def")).first); // tainted [NOT DETECTED] + sink(m4.insert(m4.begin(), std::pair("abc", source()))); // tainted + sink(m5.insert_or_assign("abc", source()).first); // tainted + sink(m6.insert_or_assign(m6.begin(), "abc", source())); // tainted + sink(m1); + sink(m2); // tainted + sink(m3); // tainted [NOT DETECTED] + sink(m4); // tainted + sink(m5); // tainted + sink(m6); // tainted + sink(m1.find("abc")); + sink(m2.find("abc")); // tainted + sink(m3.find("abc")); + sink(m4.find("abc")); // tainted + sink(m5.find("abc")); // tainted + sink(m6.find("abc")); // tainted + sink(m1.find("def")); + sink(m2.find("def")); // [FALSE POSITIVE] + sink(m3.find("def")); + sink(m4.find("def")); // [FALSE POSITIVE] + sink(m5.find("def")); // [FALSE POSITIVE] + sink(m6.find("def")); // [FALSE POSITIVE] + + // copy constructors and assignment + std::unordered_map m7(m2); + std::unordered_map m8 = m2; + std::unordered_map m9; + m9 = m2; + sink(m7); // tainted + sink(m8); // tainted + sink(m9); // tainted + sink(m7.find("abc")); // tainted + sink(m8.find("abc")); // tainted + sink(m9.find("abc")); // tainted + + // iterators + std::unordered_map::iterator i1, i2, i3; + for (i1 = m1.begin(); i1 != m1.end(); i1++) + { + sink(*i1); + sink(i1->first); + sink(i1->second); + } + for (i2 = m2.begin(); i2 != m2.end(); i2++) + { + sink(*i2); // tainted + sink(i2->first); // [FALSE POSITIVE] + sink(i2->second); // tainted + } + for (i3 = m3.begin(); i3 != m3.end(); i3++) + { + sink(*i3); // tainted [NOT DETECTED] + sink(i2->first); // tainted + sink(i2->second); // [FALSE POSITIVE] + } + + // array-like access + std::unordered_map m10, m11, m12, m13; + sink(m10["abc"] = "def"); + sink(m11["abc"] = source()); // tainted + sink(m12.at("abc") = "def"); + sink(m13.at("abc") = source()); // tainted + sink(m10["abc"]); + sink(m11["abc"]); // tainted + sink(m12["abc"]); + sink(m13["abc"]); // tainted + + // ranges + std::unordered_map m14; + m14.insert(std::make_pair("a", "a")); + m14.insert(std::make_pair("b", source())); + m14.insert(std::make_pair("c", source())); + m14.insert(std::make_pair("d", "d")); + sink(m2.equal_range("b").first); // tainted + sink(m2.equal_range("b").second); // tainted + sink(m2.equal_range("c").second); // [FALSE POSITIVE] + + // swap + std::unordered_map m15, m16, m17, m18; + m15.insert(std::pair(source(), source())); + m18.insert(std::pair(source(), source())); + sink(m15); // tainted + sink(m16); + sink(m17); + sink(m18); // tainted + m15.swap(m16); + m17.swap(m18); + sink(m15); // [FALSE POSITIVE] + sink(m16); // tainted + sink(m17); // tainted + sink(m18); // [FALSE POSITIVE] + + // merge + std::unordered_map m19, m20, m21, m22; + m19.insert(std::pair(source(), source())); + m20.insert(std::pair("abc", "def")); + m21.insert(std::pair("abc", "def")); + m22.insert(std::pair(source(), source())); + sink(m19); // tainted + sink(m20); + sink(m21); + sink(m22); // tainted + m19.merge(m20); + m21.merge(m22); + sink(m19); // tainted + sink(m20); + sink(m21); // tainted + sink(m22); // tainted + + // erase, clear + std::unordered_map m23; + m23.insert(std::pair(source(), source())); + m23.insert(std::pair(source(), source())); + sink(m23); // tainted + sink(m23.erase(m23.begin())); // tainted + sink(m23); // tainted + m23.clear(); + sink(m23); // [FALSE POSITIVE] + + // emplace, emplace_hint + std::unordered_map m24, m25; + sink(m24.emplace("abc", "def").first); + sink(m24); + sink(m24.emplace("abc", source()).first); // tainted + sink(m24); // tainted + sink(m25.emplace_hint(m25.begin(), "abc", "def")); + sink(m25); + sink(m25.emplace_hint(m25.begin(), "abc", source())); // tainted + sink(m25); // tainted + + // try_emplace + std::unordered_map m26, m27, m28; + sink(m26.try_emplace("abc", "def").first); + sink(m26.try_emplace("abc", "def").second); + sink(m26); + sink(m26.try_emplace("abc", source()).first); // tainted + sink(m26.try_emplace("abc", source()).second); // [FALSE POSITIVE] + sink(m26); // tainted + sink(m27.try_emplace(m27.begin(), "abc", "def")); + sink(m27); + sink(m27.try_emplace(m27.begin(), "abc", source())); // tainted + sink(m27); // tainted + sink(m28.try_emplace(m28.begin(), "abc", "def")); + sink(m28); + sink(m28.try_emplace(m28.begin(), source(), "def")); // tainted [NOT DETECTED] + sink(m28); // tainted [NOT DETECTED] + + // additional try_emplace test cases + std::unordered_map> m29, m30, m31, m32; + sink(m29.try_emplace("abc", 1, 2)); + sink(m29); + sink(m29["abc"]); + sink(m30.try_emplace(source(), 1, 2)); // tainted [NOT DETECTED] + sink(m30); // tainted [NOT DETECTED] + sink(m30["abc"]); + sink(m31.try_emplace("abc", source(), 2)); // tainted + sink(m31); // tainted + sink(m31["abc"]); // tainted + sink(m32.try_emplace("abc", 1, source())); // tainted + sink(m32); // tainted + sink(m32["abc"]); // tainted + + // additional emplace test cases + std::unordered_map m33; + sink(m33.emplace(source(), "def").first); // tainted [NOT DETECTED] + sink(m33); // tainted [NOT DETECTED] + + std::unordered_map m34, m35; + sink(m34.emplace(std::pair("abc", "def")).first); + sink(m34); + sink(m34.emplace(std::pair("abc", source())).first); // tainted + sink(m34); // tainted + sink(m34.emplace_hint(m34.begin(), "abc", "def")); // tainted + sink(m35.emplace().first); + sink(m35); + sink(m35.emplace(std::pair(source(), "def")).first); // tainted [NOT DETECTED] + sink(m35); // tainted [NOT DETECTED] +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/movableclass.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/movableclass.cpp new file mode 100644 index 000000000000..c0003388307a --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/movableclass.cpp @@ -0,0 +1,67 @@ + +int source(); +void sink(...) {}; + +class MyMovableClass { +public: + MyMovableClass() {} // Constructor + MyMovableClass(int _v) : v(_v) {} // ConversionConstructor + MyMovableClass(MyMovableClass &&other) noexcept { // ConversionConstructor, MoveConstructor + v = other.v; + other.v = 0; + } + MyMovableClass &operator=(MyMovableClass &&other) noexcept { // MoveAssignmentOperator + v = other.v; + other.v = 0; + return *this; + } + + int v; +}; + +MyMovableClass &&getUnTainted() { return MyMovableClass(1); } +MyMovableClass &&getTainted() { return MyMovableClass(source()); } + +void test_copyableclass() +{ + { + MyMovableClass s1(1); + MyMovableClass s2 = 1; + MyMovableClass s3; + s3 = 1; + + sink(s1); + sink(s2); + sink(s3); + } + + { + MyMovableClass s1(source()); + MyMovableClass s2 = source(); + MyMovableClass s3; + s3 = source(); + + sink(s1); // tainted + sink(s2); // tainted + sink(s3); // tainted + } + + { + MyMovableClass s1 = MyMovableClass(source()); + MyMovableClass s2; + s2 = MyMovableClass(source()); + + sink(s1); // tainted + sink(s2); // tainted + } + + { + MyMovableClass s1(getUnTainted()); + MyMovableClass s2(getTainted()); + MyMovableClass s3; + + sink(s1); + sink(s2); // tainted + sink(s3 = source()); // tainted + } +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/set.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/set.cpp new file mode 100644 index 000000000000..bcc764e35730 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/set.cpp @@ -0,0 +1,238 @@ + +#include "stl.h" + +using namespace std; + +char *source(); + +void sink(char *); +void sink(std::set); +void sink(std::set::iterator); +void sink(std::unordered_set); +void sink(std::unordered_set::iterator); + +void test_set() +{ + // insert, find + std::set s1, s2, s3, s4, s5, s6; + + sink(s1.insert("abc").first); + sink(s2.insert(source()).first); // tainted + sink(s3.insert(s3.begin(), "abc")); + sink(s4.insert(s4.begin(), source())); // tainted + s5.insert(s1.begin(), s1.end()); + s6.insert(s2.begin(), s2.end()); + sink(s1); + sink(s2); // tainted + sink(s3); + sink(s4); // tainted + sink(s5); + sink(s6); // tainted + sink(s1.find("abc")); + sink(s2.find("abc")); // tainted + sink(s3.find("abc")); + sink(s4.find("abc")); // tainted + sink(s5.find("abc")); + sink(s6.find("abc")); // tainted + + // copy constructors and assignment + std::set s7(s2); + std::set s8 = s2; + std::set s9(s2.begin(), s2.end()); + std::set s10; + s10 = s2; + sink(s7); // tainted + sink(s8); // tainted + sink(s9); // tainted + sink(s10); // tainted + sink(s7.find("abc")); // tainted + sink(s8.find("abc")); // tainted + sink(s9.find("abc")); // tainted + sink(s10.find("abc")); // tainted + + // iterators + std::set::iterator i1, i2; + for (i1 = s1.begin(); i1 != s1.end(); i1++) + { + sink(*i1); + } + for (i2 = s2.begin(); i2 != s2.end(); i2++) + { + sink(*i2); // tainted + } + + // ranges + std::set s11; + s11.insert("a"); + s11.insert(source()); + s11.insert("c"); + sink(s11.lower_bound("b")); // tainted + sink(s11.upper_bound("b")); // tainted + sink(s11.equal_range("b").first); // tainted + sink(s11.equal_range("b").second); // tainted + + // swap + std::set s12, s13, s14, s15; + s12.insert(source()); + s15.insert(source()); + sink(s12); // tainted + sink(s13); + sink(s14); + sink(s15); // tainted + s12.swap(s13); + s14.swap(s15); + sink(s12); // [FALSE POSITIVE] + sink(s13); // tainted + sink(s14); // tainted + sink(s15); // [FALSE POSITIVE] + + // merge + std::set s16, s17, s18, s19; + s16.insert(source()); + s17.insert("abc"); + s18.insert("def"); + s19.insert(source()); + sink(s16); // tainted + sink(s17); + sink(s18); + sink(s19); // tainted + s16.merge(s17); + s18.merge(s19); + sink(s16); // tainted + sink(s17); + sink(s18); // tainted + sink(s19); // tainted + + // erase, clear + std::set s20; + s20.insert(source()); + s20.insert(source()); + sink(s20); // tainted + sink(s20.erase(s20.begin())); // tainted + sink(s20); // tainted + s20.clear(); + sink(s20); // [FALSE POSITIVE] + + // emplace, emplace_hint + std::set s21, s22; + sink(s21.emplace("abc").first); + sink(s21); + sink(s21.emplace(source()).first); // tainted + sink(s21); // tainted + sink(s22.emplace_hint(s22.begin(), "abc")); + sink(s22); + sink(s22.emplace_hint(s22.begin(), source())); // tainted + sink(s22); // tainted +} + +void test_unordered_set() +{ + // insert, find + std::unordered_set s1, s2, s3, s4, s5, s6; + + sink(s1.insert("abc").first); + sink(s2.insert(source()).first); // tainted + sink(s3.insert(s3.begin(), "abc")); + sink(s4.insert(s4.begin(), source())); // tainted + s5.insert(s1.begin(), s1.end()); + s6.insert(s2.begin(), s2.end()); + sink(s1); + sink(s2); // tainted + sink(s3); + sink(s4); // tainted + sink(s5); + sink(s6); // tainted + sink(s1.find("abc")); + sink(s2.find("abc")); // tainted + sink(s3.find("abc")); + sink(s4.find("abc")); // tainted + sink(s5.find("abc")); + sink(s6.find("abc")); // tainted + + // copy constructors and assignment + std::unordered_set s7(s2); + std::unordered_set s8 = s2; + std::unordered_set s9(s2.begin(), s2.end()); + std::unordered_set s10; + s10 = s2; + sink(s7); // tainted + sink(s8); // tainted + sink(s9); // tainted + sink(s10); // tainted + sink(s7.find("abc")); // tainted + sink(s8.find("abc")); // tainted + sink(s9.find("abc")); // tainted + sink(s10.find("abc")); // tainted + + // iterators + std::unordered_set::iterator i1, i2; + for (i1 = s1.begin(); i1 != s1.end(); i1++) + { + sink(*i1); + } + for (i2 = s2.begin(); i2 != s2.end(); i2++) + { + sink(*i2); // tainted + } + + // ranges + std::unordered_set s11; + s11.insert("a"); + s11.insert(source()); + s11.insert("c"); + sink(s11.equal_range("b").first); // tainted + sink(s11.equal_range("b").second); // tainted + + // swap + std::unordered_set s12, s13, s14, s15; + s12.insert(source()); + s15.insert(source()); + sink(s12); // tainted + sink(s13); + sink(s14); + sink(s15); // tainted + s12.swap(s13); + s14.swap(s15); + sink(s12); // [FALSE POSITIVE] + sink(s13); // tainted + sink(s14); // tainted + sink(s15); // [FALSE POSITIVE] + + // merge + std::unordered_set s16, s17, s18, s19; + s16.insert(source()); + s17.insert("abc"); + s18.insert("def"); + s19.insert(source()); + sink(s16); // tainted + sink(s17); + sink(s18); + sink(s19); // tainted + s16.merge(s17); + s18.merge(s19); + sink(s16); // tainted + sink(s17); + sink(s18); // tainted + sink(s19); // tainted + + // erase, clear + std::unordered_set s20; + s20.insert(source()); + s20.insert(source()); + sink(s20); // tainted + sink(s20.erase(s20.begin())); // tainted + sink(s20); // tainted + s20.clear(); + sink(s20); // [FALSE POSITIVE] + + // emplace, emplace_hint + std::unordered_set s21, s22; + sink(s21.emplace("abc").first); + sink(s21); + sink(s21.emplace(source()).first); // tainted + sink(s21); // tainted + sink(s22.emplace_hint(s22.begin(), "abc")); + sink(s22); + sink(s22.emplace_hint(s22.begin(), source())); // tainted + sink(s22); // tainted +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/smart_pointer.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/smart_pointer.cpp new file mode 100644 index 000000000000..e6a5a1a0847b --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/smart_pointer.cpp @@ -0,0 +1,68 @@ +#include "stl.h" + +int source(); +void sink(int); +void sink(int*); + +template void sink(std::shared_ptr&); +template void sink(std::unique_ptr&); + +void test_make_shared() { + std::shared_ptr p = std::make_shared(source()); + sink(*p); // tainted + sink(p); // tainted +} + +void test_make_shared_array() { + std::shared_ptr p = std::make_shared(source()); + sink(*p); // not tainted + sink(p); // not tainted +} + +void test_make_unique() { + std::unique_ptr p = std::make_unique(source()); + sink(*p); // tainted + sink(p); // tainted +} + +void test_make_unique_array() { + std::unique_ptr p = std::make_unique(source()); + sink(*p); // not tainted + sink(p); // not tainted +} + +void test_reverse_taint_shared() { + std::shared_ptr p = std::make_shared(); + + *p = source(); + sink(p); // tainted [NOT DETECTED] + sink(*p); // tainted [NOT DETECTED] +} + +void test_reverse_taint_unique() { + std::unique_ptr p = std::unique_ptr(); + + *p = source(); + sink(p); // tainted [NOT DETECTED] + sink(*p); // tainted [NOT DETECTED] +} + +void test_shared_get() { + std::shared_ptr p = std::make_shared(source()); + sink(p.get()); // tainted +} + +void test_unique_get() { + std::unique_ptr p = std::make_unique(source()); + sink(p.get()); // tainted +} + +struct A { + int x, y; +}; + +void test_shared_field_member() { + std::unique_ptr p = std::make_unique(source(), 0); + sink(p->x); // tainted [NOT DETECTED] + sink(p->y); // not tainted +} \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/standalone_iterators.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/standalone_iterators.cpp new file mode 100644 index 000000000000..60c36412a910 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/standalone_iterators.cpp @@ -0,0 +1,55 @@ +#include "stl.h" + +using namespace std; + +void sink(int); + +class int_iterator_by_typedefs { +public: + typedef input_iterator_tag iterator_category; + typedef int value_type; + typedef size_t difference_type; + typedef int * pointer; + typedef int & reference; + + int_iterator_by_typedefs &operator++(); + int_iterator_by_typedefs operator++(int); + int operator*() const; +}; + +class int_iterator_by_trait { +public: + int_iterator_by_trait &operator++(); + int_iterator_by_trait operator++(int); + int operator*() const; +}; + +template<> +struct std::iterator_traits { + typedef input_iterator_tag iterator_category; +}; + +class non_iterator { +public: + non_iterator &operator++(); + non_iterator operator++(int); + int operator*() const; +}; + +void test_typedefs(int_iterator_by_typedefs source1) { + sink(*source1); // tainted + sink(*(source1++)); // tainted + sink(*(++source1)); // tainted +} + +void test_trait(int_iterator_by_trait source1) { + sink(*source1); // tainted + sink(*(source1++)); // tainted + sink(*(++source1)); // tainted +} + +void test_non_iterator(non_iterator source1) { + sink(*source1); + sink(*(source1++)); + sink(*(++source1)); +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/stl.h b/cpp/ql/test/library-tests/dataflow/taint-tests/stl.h new file mode 100644 index 000000000000..d767218c1007 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/stl.h @@ -0,0 +1,589 @@ + +typedef unsigned long size_t; + +template +struct remove_const { typedef T type; }; + +template +struct remove_const { typedef T type; }; + +// `remove_const_t` removes any `const` specifier from `T` +template +using remove_const_t = typename remove_const::type; + +template +struct remove_reference { typedef T type; }; + +template +struct remove_reference { typedef T type; }; + +template +struct remove_reference { typedef T type; }; + +// `remove_reference_t` removes any `&` from `T` +template +using remove_reference_t = typename remove_reference::type; + +namespace std +{ + template constexpr T&& forward(remove_reference_t& t) noexcept; + template constexpr T&& forward(remove_reference_t&& t) noexcept; +} + +// --- iterator --- + +namespace std { + struct ptrdiff_t; + + template struct iterator_traits; + + template + struct iterator { + typedef Category iterator_category; + + iterator(); + iterator(iterator > const &other); // non-const -> const conversion constructor + + iterator &operator++(); + iterator operator++(int); + iterator &operator--(); + iterator operator--(int); + bool operator==(iterator other) const; + bool operator!=(iterator other) const; + reference_type operator*() const; + pointer_type operator->() const; + iterator operator+(int); + iterator operator-(int); + iterator &operator+=(int); + iterator &operator-=(int); + int operator-(iterator); + reference_type operator[](int); + }; + + struct input_iterator_tag {}; + struct forward_iterator_tag : public input_iterator_tag {}; + struct bidirectional_iterator_tag : public forward_iterator_tag {}; + struct random_access_iterator_tag : public bidirectional_iterator_tag {}; +} + +// --- string --- + +namespace std +{ + template struct char_traits; + + typedef size_t streamsize; + + template class allocator { + public: + allocator() throw(); + typedef size_t size_type; + }; + + template, class Allocator = allocator > + class basic_string { + public: + using value_type = charT; + using reference = value_type&; + using const_reference = const value_type&; + typedef typename Allocator::size_type size_type; + static const size_type npos = -1; + + explicit basic_string(const Allocator& a = Allocator()); + basic_string(const charT* s, const Allocator& a = Allocator()); + template basic_string(InputIterator begin, InputIterator end, const Allocator& a = Allocator()); + + const charT* c_str() const; + charT* data() noexcept; + size_t length() const; + + typedef std::iterator iterator; + typedef std::iterator const_iterator; + + iterator begin(); + iterator end(); + const_iterator begin() const; + const_iterator end() const; + const_iterator cbegin() const; + const_iterator cend() const; + + void push_back(charT c); + + const charT& front() const; + charT& front(); + const charT& back() const; + charT& back(); + + const_reference operator[](size_type pos) const; + reference operator[](size_type pos); + const_reference at(size_type n) const; + reference at(size_type n); + template basic_string& operator+=(const T& t); + basic_string& operator+=(const charT* s); + basic_string& append(const basic_string& str); + basic_string& append(const charT* s); + basic_string& append(size_type n, charT c); + template basic_string& append(InputIterator first, InputIterator last); + basic_string& assign(const basic_string& str); + basic_string& assign(size_type n, charT c); + template basic_string& assign(InputIterator first, InputIterator last); + basic_string& insert(size_type pos, const basic_string& str); + basic_string& insert(size_type pos, size_type n, charT c); + basic_string& insert(size_type pos, const charT* s); + iterator insert(const_iterator p, size_type n, charT c); + template iterator insert(const_iterator p, InputIterator first, InputIterator last); + basic_string& replace(size_type pos1, size_type n1, const basic_string& str); + basic_string& replace(size_type pos1, size_type n1, size_type n2, charT c); + size_type copy(charT* s, size_type n, size_type pos = 0) const; + void clear() noexcept; + basic_string substr(size_type pos = 0, size_type n = npos) const; + void swap(basic_string& s) noexcept/*(allocator_traits::propagate_on_container_swap::value || allocator_traits::is_always_equal::value)*/; + }; + + template basic_string operator+(const basic_string& lhs, const basic_string& rhs); + template basic_string operator+(const basic_string& lhs, const charT* rhs); + + typedef basic_string string; +} + +// --- istring / ostream / stringstream --- + +namespace std +{ + template > + class basic_istream /*: virtual public basic_ios - not needed for this test */ { + public: + using char_type = charT; + using int_type = int; //typename traits::int_type; + + basic_istream& operator>>(int& n); + + int_type get(); + basic_istream& get(char_type& c); + basic_istream& get(char_type* s, streamsize n); + int_type peek(); + basic_istream& read (char_type* s, streamsize n); + streamsize readsome(char_type* s, streamsize n); + basic_istream& putback(char_type c); + basic_istream& unget(); + + basic_istream& getline(char_type* s, streamsize n); + basic_istream& getline(char_type* s, streamsize n, char_type delim); + }; + + template basic_istream& operator>>(basic_istream&, charT*); + template basic_istream& operator>>(basic_istream& is, basic_string& str); + + template basic_istream& getline(basic_istream& is, basic_string& str, charT delim); + template basic_istream& getline(basic_istream& is, basic_string& str); + + template > + class basic_ostream /*: virtual public basic_ios - not needed for this test */ { + public: + typedef charT char_type; + + basic_ostream& operator<<(int n); + + basic_ostream& put(char_type c); + basic_ostream& write(const char_type* s, streamsize n); + basic_ostream& flush(); + }; + + template basic_ostream& operator<<(basic_ostream&, const charT*); + template basic_ostream& operator<<(basic_ostream& os, const basic_string& str); + + template> + class basic_iostream : public basic_istream, public basic_ostream { + public: + }; + + template, class Allocator = allocator> + class basic_stringstream : public basic_iostream { + public: + explicit basic_stringstream(/*ios_base::openmode which = ios_base::out|ios_base::in - not needed for this test*/); + explicit basic_stringstream( const basic_string& str/*, ios_base::openmode which = ios_base::out | ios_base::in*/); + basic_stringstream(const basic_stringstream& rhs) = delete; + basic_stringstream(basic_stringstream&& rhs); + basic_stringstream& operator=(const basic_stringstream& rhs) = delete; + basic_stringstream& operator=(basic_stringstream&& rhs); + + void swap(basic_stringstream& rhs); + + basic_string str() const; + void str(const basic_string& str); + }; + + typedef basic_istream istream; + typedef basic_ostream ostream; + extern istream cin; + extern ostream cout; + + using stringstream = basic_stringstream; +} + +// --- vector --- + +namespace std { + template> + class vector { + public: + using value_type = T; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = unsigned int; + using iterator = std::iterator; + using const_iterator = std::iterator; + + vector() noexcept(noexcept(Allocator())) : vector(Allocator()) { } + explicit vector(const Allocator&) noexcept; + explicit vector(size_type n, const Allocator& = Allocator()); + vector(size_type n, const T& value, const Allocator& = Allocator()); + template vector(InputIterator first, InputIterator last, const Allocator& = Allocator()); + // use of `iterator_category` makes sure InputIterator is (probably) an iterator, and not an `int` or + // similar that should match a different overload (SFINAE). + ~vector(); + + vector& operator=(const vector& x); + vector& operator=(vector&& x) noexcept/*(allocator_traits::propagate_on_container_move_assignment::value || allocator_traits::is_always_equal::value)*/; + template void assign(InputIterator first, InputIterator last); + // use of `iterator_category` makes sure InputIterator is (probably) an iterator, and not an `int` or + // similar that should match a different overload (SFINAE). + void assign(size_type n, const T& u); + + iterator begin() noexcept; + const_iterator begin() const noexcept; + iterator end() noexcept; + const_iterator end() const noexcept; + + size_type size() const noexcept; + + reference operator[](size_type n); + const_reference operator[](size_type n) const; + const_reference at(size_type n) const; + reference at(size_type n); + reference front(); + const_reference front() const; + reference back(); + const_reference back() const; + + T* data() noexcept; + const T* data() const noexcept; + + void push_back(const T& x); + void push_back(T&& x); + + iterator insert(const_iterator position, const T& x); + iterator insert(const_iterator position, T&& x); + iterator insert(const_iterator position, size_type n, const T& x); + template iterator insert(const_iterator position, InputIterator first, InputIterator last); + + void swap(vector&) noexcept/*(allocator_traits::propagate_on_container_swap::value || allocator_traits::is_always_equal::value)*/; + + void clear() noexcept; + }; +} + +// --- make_shared / make_unique --- + +namespace std { + template + class shared_ptr { + public: + shared_ptr() noexcept; + explicit shared_ptr(T*); + template shared_ptr(const shared_ptr&) noexcept; + template shared_ptr(shared_ptr&&) noexcept; + + shared_ptr& operator=(const shared_ptr&) noexcept; + shared_ptr& operator=(shared_ptr&&) noexcept; + + T& operator*() const noexcept; + T* operator->() const noexcept; + + T* get() const noexcept; + }; + + template + class unique_ptr { + public: + constexpr unique_ptr() noexcept; + explicit unique_ptr(T*) noexcept; + unique_ptr(unique_ptr&&) noexcept; + + unique_ptr& operator=(unique_ptr&&) noexcept; + + T& operator*() const; + T* operator->() const noexcept; + + T* get() const noexcept; + }; + + template unique_ptr make_unique(Args&&...); + + template shared_ptr make_shared(Args&&...); +} + +// --- pair --- + +namespace std { + template + struct pair { + typedef T1 first_type; + typedef T2 second_type; + + T1 first; + T2 second; + pair(); + pair(const T1& x, const T2& y) : first(x), second(y) {}; + template pair(const pair &p); + + void swap(pair& p) /*noexcept(...)*/; + }; + + template constexpr pair, remove_reference_t> make_pair(T1&& x, T2&& y) { + return pair(std::forward(x), std::forward(y)); + } +} + +// --- map --- + +namespace std { + template struct less; + + template, class Allocator = allocator>> + class map { + public: + using key_type = Key; + using mapped_type = T; + using value_type = pair; + using iterator = std::iterator; + using const_iterator = std::iterator; + + map() /*: map(Compare()) { }*/; + map(const map& x); + map(map&& x); + ~map(); + + map& operator=(const map& x); + map& operator=(map&& x) /*noexcept(allocator_traits::is_always_equal::value && is_nothrow_move_assignable_v)*/; + + iterator begin() noexcept; + const_iterator begin() const noexcept; + iterator end() noexcept; + const_iterator end() const noexcept; + + T& operator[](const key_type& x); + T& operator[](key_type&& x); + T& at(const key_type& x); + const T& at(const key_type& x) const; + + template pair emplace(Args&&... args); + template iterator emplace_hint(const_iterator position, Args&&... args); + + pair insert(const value_type& x); + pair insert(value_type&& x); + iterator insert(const_iterator position, const value_type& x); + iterator insert(const_iterator position, value_type&& x); + + template pair try_emplace(const key_type& k, Args&&... args); + template pair try_emplace(key_type&& k, Args&&... args); + template iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); + template iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); + template pair insert_or_assign(const key_type& k, M&& obj); + template pair insert_or_assign(key_type&& k, M&& obj); + template iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); + template iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); + + iterator erase(iterator position); + iterator erase(const_iterator position); + iterator erase(const_iterator first, const_iterator last); + void swap(map&) /*noexcept(/*==allocator_traits::is_always_equal::value && is_nothrow_swappable_v)*/; + void clear() noexcept; + + template void merge(map& source); + template void merge(map&& source); + + iterator find(const key_type& x); + const_iterator find(const key_type& x) const; + + iterator lower_bound(const key_type& x); + const_iterator lower_bound(const key_type& x) const; + iterator upper_bound(const key_type& x); + const_iterator upper_bound(const key_type& x) const; + + pair equal_range(const key_type& x); + pair equal_range(const key_type& x) const; + }; + + template struct hash; + template struct equal_to; + + template, class Pred = equal_to, class Allocator = allocator>> + class unordered_map { + public: + using key_type = Key; + using mapped_type = T; + using value_type = pair; + using iterator = std::iterator; + using const_iterator = std::iterator; + + unordered_map(); + unordered_map(const unordered_map&); + unordered_map(unordered_map&&); + ~unordered_map(); + + unordered_map& operator=(const unordered_map&); + unordered_map& operator=(unordered_map&&) /*noexcept(allocator_traits::is_always_equal::value && is_nothrow_move_assignable_v && is_nothrow_move_assignable_v)*/; + + iterator begin() noexcept; + const_iterator begin() const noexcept; + iterator end() noexcept; + const_iterator end() const noexcept; + + mapped_type& operator[](const key_type& k); + mapped_type& operator[](key_type&& k); + mapped_type& at(const key_type& k); + const mapped_type& at(const key_type& k) const; + + template pair emplace(Args&&... args); + template iterator emplace_hint(const_iterator position, Args&&... args); + + pair insert(const value_type& obj); + pair insert(value_type&& obj); + iterator insert(const_iterator hint, const value_type& obj); + iterator insert(const_iterator hint, value_type&& obj); + + template pair try_emplace(const key_type& k, Args&&... args); + template pair try_emplace(key_type&& k, Args&&... args); + template iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); + template iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); + template pair insert_or_assign(const key_type& k, M&& obj); + template pair insert_or_assign(key_type&& k, M&& obj); + template iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); + template iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); + + iterator erase(iterator position); + iterator erase(const_iterator position); + iterator erase(const_iterator first, const_iterator last); + void swap(unordered_map&) /*noexcept(allocator_traits::is_always_equal::value && is_nothrow_swappable_v && is_nothrow_swappable_v)*/; + void clear() noexcept; + + template void merge(unordered_map& source); + template void merge(unordered_map&& source); + + iterator find(const key_type& k); + const_iterator find(const key_type& k) const; + + pair equal_range(const key_type& k); + pair equal_range(const key_type& k) const; + }; +}; + +// --- set --- + +namespace std { + template, class Allocator = allocator> + class set { + public: + using key_type = Key; + using value_type = Key; + using size_type = size_t; + using allocator_type = Allocator; + using iterator = std::iterator; + using const_iterator = std::iterator; + + set() /*: set(Compare())*/ { } + set(const set& x); + set(set&& x); + template set(InputIterator first, InputIterator last/*, const Compare& comp = Compare(), const Allocator& = Allocator()*/); + ~set(); + + set& operator=(const set& x); + set& operator=(set&& x) noexcept/*(allocator_traits::is_always_equal::value && is_nothrow_move_assignable_v)*/; + + iterator begin() noexcept; + const_iterator begin() const noexcept; + iterator end() noexcept; + const_iterator end() const noexcept; + + template pair emplace(Args&&... args); + template iterator emplace_hint(const_iterator position, Args&&... args); + pair insert(const value_type& x); + pair insert(value_type&& x); + iterator insert(const_iterator position, const value_type& x); + iterator insert(const_iterator position, value_type&& x); + template void insert(InputIterator first, InputIterator last); + + iterator erase(iterator position); + iterator erase(const_iterator position); + iterator erase(const_iterator first, const_iterator last); + void swap(set&) noexcept/*(allocator_traits::is_always_equal::value && is_nothrow_swappable_v)*/; + void clear() noexcept; + + template void merge(set& source); + template void merge(set&& source); + + iterator find(const key_type& x); + const_iterator find(const key_type& x) const; + + iterator lower_bound(const key_type& x); + const_iterator lower_bound(const key_type& x) const; + iterator upper_bound(const key_type& x); + const_iterator upper_bound(const key_type& x) const; + pair equal_range(const key_type& x); + pair equal_range(const key_type& x) const; + }; + + template, class Pred = equal_to, class Allocator = allocator> + class unordered_set { + public: + using key_type = Key; + using value_type = Key; + using hasher = Hash; + using key_equal = Pred; + using allocator_type = Allocator; + using size_type = size_t; + using iterator = std::iterator; + using const_iterator = std::iterator; + + unordered_set(); + unordered_set(const unordered_set&); + unordered_set(unordered_set&&); + template unordered_set(InputIterator f, InputIterator l, size_type n = 0/*, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type()*/); + ~unordered_set(); + + unordered_set& operator=(const unordered_set&); + unordered_set& operator=(unordered_set&&) noexcept/*(allocator_traits::is_always_equal::value && is_nothrow_move_assignable_v && is_nothrow_move_assignable_v)*/; + + iterator begin() noexcept; + const_iterator begin() const noexcept; + iterator end() noexcept; + const_iterator end() const noexcept; + + template pair emplace(Args&&... args); + template iterator emplace_hint(const_iterator position, Args&&... args); + pair insert(const value_type& obj); + pair insert(value_type&& obj); + iterator insert(const_iterator hint, const value_type& obj); + iterator insert(const_iterator hint, value_type&& obj); + template void insert(InputIterator first, InputIterator last); + + iterator erase(iterator position); + iterator erase(const_iterator position); + iterator erase(const_iterator first, const_iterator last); + void swap(unordered_set&) noexcept/*(allocator_traits::is_always_equal::value && is_nothrow_swappable_v && is_nothrow_swappable_v)*/; + void clear() noexcept; + + template void merge(unordered_set& source); + template void merge(unordered_set&& source); + + iterator find(const key_type& k); + const_iterator find(const key_type& k) const; + pair equal_range(const key_type& k); + pair equal_range(const key_type& k) const; + }; +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/string.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/string.cpp new file mode 100644 index 000000000000..6a0bf47e4d7d --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/string.cpp @@ -0,0 +1,566 @@ + +#include "stl.h" + +using namespace std; + +char *source(); + +namespace ns_char +{ + char source(); +} + +char *user_input() { + return source(); +} + +void sink(const char *s); +void sink(const std::string &s); +void sink(const char *filename, const char *mode); +void sink(char); +void sink(std::string::iterator); + +void test_string() +{ + char *a = source(); + std::string b("123"); + std::string c(source()); + + sink(a); // tainted + sink(b); + sink(c); // tainted + sink(b.c_str()); + sink(c.c_str()); // tainted +} + +void test_strings2() +{ + string path1 = user_input(); + sink(path1.c_str(), "r"); // tainted + + string path2; + path2 = user_input(); + sink(path2.c_str(), "r"); // tainted + + string path3(user_input()); + sink(path3.c_str(), "r"); // tainted +} + +void test_string3() +{ + const char *cs = source(); + + // convert char * -> std::string + std::string ss(cs); + + sink(cs); // tainted + sink(ss); // tainted +} + +void test_string4() +{ + const char *cs = source(); + + // convert char * -> std::string + std::string ss(cs); + + // convert back std::string -> char * + cs = ss.c_str(); + + sink(cs); // tainted + sink(ss); // tainted +} + +void test_string_constructors_assignments() +{ + { + std::string s1("hello"); + std::string s2 = "hello"; + std::string s3; + s3 = "hello"; + + sink(s1); + sink(s2); + sink(s3); + } + + { + std::string s1(source()); + std::string s2 = source(); + std::string s3; + s3 = source(); + + sink(s1); // tainted + sink(s2); // tainted + sink(s3); // tainted + } + + { + std::string s1; + std::string s2 = s1; + std::string s3; + s3 = s1; + + sink(s1); + sink(s2); + sink(s3); + } + + { + std::string s1 = std::string(source()); + std::string s2; + s2 = std::string(source()); + + sink(s1); // tainted + sink(s2); // tainted + } +} + +void test_range_based_for_loop_string() { + std::string s(source()); + for(char c : s) { + sink(c); // tainted [NOT DETECTED by IR] + } + + for(std::string::iterator it = s.begin(); it != s.end(); ++it) { + sink(*it); // tainted [NOT DETECTED by IR] + } + + for(char& c : s) { + sink(c); // tainted [NOT DETECTED by IR] + } + + const std::string const_s(source()); + for(const char& c : const_s) { + sink(c); // tainted [NOT DETECTED by IR] + } +} + +void test_string_append() { + { + std::string s1("hello"); + std::string s2(source()); + + sink(s1 + s1); + sink(s1 + s2); // tainted + sink(s2 + s1); // tainted + sink(s2 + s2); // tainted + + sink(s1 + " world"); + sink(s1 + source()); // tainted + } + + { + std::string s3("abc"); + std::string s4(source()); + std::string s5, s6, s7, s8, s9; + + s5 = s3 + s4; + sink(s5); // tainted + + s6 = s3; + sink(s6 += s4); // tainted + sink(s6); // tainted + + s7 = s3; + sink(s7 += source()); // tainted + sink(s7 += " "); // tainted + sink(s7); // tainted + + s8 = s3; + s8.append(s4); + sink(s8); // tainted + + s9 = s3; + s9.append(source()); + s9.append(" "); + sink(s9); // tainted + } + + { + std::string s10("abc"); + char c = ns_char::source(); + + s10.append(1, c); + sink(s10); // tainted + } +} + +void test_string_assign() { + std::string s1("hello"); + std::string s2(source()); + char c = ns_char::source(); + std::string s3, s4, s5; + std::string s6(source()); + + sink(s3.assign(s1)); + sink(s3); + + sink(s4.assign(s2)); // tainted + sink(s4); // tainted + + sink(s5.assign(10, c)); // tainted + sink(s5); // tainted + + sink(s6.assign(s1)); + sink(s6); // [FALSE POSITIVE] +} + +void test_string_insert() { + std::string s1("hello"); + std::string s2(source()); + char c = ns_char::source(); + std::string s3, s4, s5, s6; + + s3 = s1; + sink(s3.insert(0, s1)); + sink(s3); + + s4 = s2; + sink(s4.insert(0, s1)); // tainted + sink(s4); // tainted + + s5 = s1; + sink(s5.insert(0, s2)); // tainted + sink(s5); // tainted + + s6 = s1; + sink(s6.insert(0, 10, c)); // tainted + sink(s6); // tainted +} + +void test_string_replace() { + std::string s1("hello"); + std::string s2(source()); + char c = ns_char::source(); + std::string s3, s4, s5, s6; + + s3 = s1; + sink(s3.replace(1, 2, s1)); + sink(s3); + + s4 = s2; + sink(s4.replace(1, 2, s1)); // tainted + sink(s4); // tainted + + s5 = s1; + sink(s5.replace(1, 2, s2)); // tainted + sink(s5); // tainted + + s6 = s1; + sink(s6.replace(1, 2, 10, c)); // tainted + sink(s6); // tainted +} + +void test_string_copy() { + char b1[1024] = {0}; + char b2[1024] = {0}; + std::string s1("hello"); + std::string s2(source()); + + s1.copy(b1, s1.length(), 0); + sink(b1); + + s2.copy(b2, s1.length(), 0); + sink(b2); // tainted +} + +void test_string_swap() { + std::string s1("hello"); + std::string s2(source()); + std::string s3("world"); + std::string s4(source()); + + sink(s1); + sink(s2); // tainted + sink(s3); + sink(s4); // tainted + + s1.swap(s2); + s4.swap(s3); + + sink(s1); // tainted + sink(s2); // [FALSE POSITIVE] + sink(s3); // tainted + sink(s4); // [FALSE POSITIVE] +} + +void test_string_clear() { + std::string s1(source()); + std::string s2(source()); + std::string s3(source()); + + sink(s1); // tainted + sink(s2); // tainted + sink(s3); // tainted + + s1.clear(); + s2 = ""; + s3 = s3; + + sink(s1); // [FALSE POSITIVE] + sink(s2); + sink(s3); // tainted +} + +void test_string_data() +{ + std::string a("123"); + std::string b(source()); + + sink(a.data()); + sink(b.data()); // tainted + sink(a.length()); + sink(b.length()); +} + +void test_string_substr() +{ + std::string a("123"); + std::string b(source()); + + sink(a.substr(0, a.length())); + sink(b.substr(0, b.length())); // tainted +} + +void test_string_at() +{ + std::string a("123"); + std::string b("123"); + std::string c("123"); + + sink(a); + sink(b); + sink(c); + + a[0] = ns_char::source(); + b.at(0) = ns_char::source(); + c[0] = a[0]; + + sink(a); // tainted + sink(b); // tainted + sink(c); // tainted +} + +void test_string_data_more() +{ + std::string str("123"); + + str.data()[1] = ns_char::source(); + sink(str); // tainted + sink(str.data()); // tainted +} + +void test_string_iterators() { + // string append + { + std::string s1("hello"); + std::string s2(source()); + std::string s3("hello"); + std::string s4("world"); + + sink(s1); + sink(s1.append(s2.begin(), s2.end())); // tainted + sink(s1); // tainted + + sink(s3); + sink(s3.append(s4.begin(), s4.end())); + sink(s3); + } + + // dereference + { + std::string s1("hello"); + std::string s2(source()); + + string::iterator iter1 = s1.begin(); + + sink(*iter1); + sink(iter1[1]); + string::iterator iter2 = s2.begin(); + + sink(*iter2); // tainted + sink(iter2[1]); // tainted + } + + // arithmetic operators + { + std::string s1("hello"); + std::string s2(source()); + + string::iterator i1 = s1.begin(); + + string::iterator i2 = s2.begin(); + string::iterator i3, i4, i5, i6, i7, i8, i9, i10, i11; + + sink(*(i2+1)); //tainted + sink(*(i2-1)); // tainted + i3 = i2; + sink(*(++i3)); // tainted + i4 = i2; + sink(*(--i4)); // tainted + i5 = i2; + i5++; + sink(*i5); // tainted + i6 = i2; + i6--; + sink(*i6); // tainted + i7 = i2; + sink(*(i7+=1)); // tainted + i8 = i2; + sink(*(i8-=1)); // tainted + + i9 = s2.end(); + --i9; + sink(*i9); // tainted + + i10 = i2; + sink(*(i10++)); // tainted + sink(i10); // tainted + i11 = i2; + sink(*(i11--)); // tainted + sink(i11); // tainted + } +} + +void test_string_insert_more() +{ + std::string s1("aa"); + std::string s2("bb"); + char *cs1 = "cc"; + char *cs2 = source(); + + sink(s1.insert(0, cs1)); + sink(s1); + + sink(s2.insert(0, cs2)); // tainted + sink(s2); // tainted +} + +void test_string_iterator_methods() +{ + { + std::string a("aa"); + std::string b("bb"); + + sink(a.insert(a.begin(), 10, 'x')); + sink(a); + + sink(b.insert(b.begin(), 10, ns_char::source())); // tainted + sink(b); // tainted + } + + { + std::string c("cc"); + std::string d("dd"); + std::string s1("11"); + std::string s2(source()); + + sink(c.insert(c.end(), s1.begin(), s1.end())); + sink(c); + + sink(d.insert(d.end(), s2.begin(), s2.end())); // tainted + sink(d); // tainted + + sink(s2.insert(s2.end(), s1.begin(), s1.end())); // tainted + sink(s2); // tainted + } + + { + std::string e("ee"); + std::string f("ff"); + std::string s3("33"); + std::string s4(source()); + + sink(e.append(s3.begin(), s3.end())); + sink(e); + + sink(f.append(s4.begin(), s4.end())); // tainted + sink(f); // tainted + + sink(s4.append(s3.begin(), s3.end())); // tainted + sink(s4); // tainted + } + + { + std::string g("gg"); + std::string h("hh"); + std::string s5("55"); + std::string s6(source()); + + sink(g.assign(s5.cbegin(), s5.cend())); + sink(g); + + sink(h.assign(s6.cbegin(), s6.cend())); // tainted + sink(h); // tainted + + sink(s6.assign(s5.cbegin(), s5.cend())); + sink(s6); // [FALSE POSITIVE] + } +} + +void test_constructors_more() { + char *cs1 = "abc"; + char *cs2 = source(); + std::string s1(cs1); + std::string s2(cs2); + std::string s3(s1.begin(), s1.end()); + std::string s4(s2.begin(), s2.end()); + + sink(s1); + sink(s2); // tainted + sink(s3); + sink(s4); // tainted +} + +void test_string_front_back() { + std::string a("aa"); + + sink(a.front()); + sink(a.back()); + a.push_back(ns_char::source()); + sink(a.front()); // [FALSE POSITIVE] + sink(a.back()); // tainted +} + +void test_string_return_assign() { + { + std::string a("aa"); + std::string b("bb"); + std::string c("cc"); + std::string d("dd"); + std::string e("ee"); + std::string f("ff"); + + sink( a += (b += "bb") ); + sink( c += (d += source()) ); // tainted + sink( (e += "ee") += source() ); // tainted + sink( (f += source()) += "ff" ); // tainted + sink(a); + sink(b); + sink(c); // tainted + sink(d); // tainted + sink(e); // tainted + sink(f); // tainted + } + + { + std::string a("aa"); + std::string b("bb"); + std::string c("cc"); + std::string d("dd"); + std::string e("ee"); + std::string f("ff"); + + sink( a.assign(b.assign("bb")) ); + sink( c.assign(d.assign(source())) ); // tainted + sink( e.assign("ee").assign(source()) ); // tainted + sink( f.assign(source()).assign("ff") ); + sink(a); + sink(b); + sink(c); // tainted + sink(d); // tainted + sink(e); // tainted + sink(f); // [FALSE POSITIVE] + } +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/stringstream.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/stringstream.cpp new file mode 100644 index 000000000000..e700bccb9300 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/stringstream.cpp @@ -0,0 +1,268 @@ + +#include "stl.h" + +using namespace std; + +char *source(); + +namespace ns_char +{ + char source(); +} + +void sink(int i); + +void sink(const std::string &s); + +template +void sink(const std::basic_ostream &s); + +template +void sink(const std::basic_istream &s); + +template +void sink(const std::basic_iostream &s); + +void test_stringstream_string(int amount) +{ + std::stringstream ss1, ss2, ss3, ss4, ss5, ss6, ss7, ss8, ss9, ss10, ss11, ss12, ss13; + std::string t(source()); + + sink(ss1 << "1234"); + sink(ss2 << source()); // tainted + sink(ss3 << "123" << source()); // tainted + sink(ss4 << source() << "456"); // tainted + sink(ss5 << t); // tainted + + sink(ss1); + sink(ss2); // tainted + sink(ss3); // tainted + sink(ss4); // tainted + sink(ss5); // tainted + sink(ss1.str()); + sink(ss2.str()); // tainted + sink(ss3.str()); // tainted + sink(ss4.str()); // tainted + sink(ss5.str()); // tainted + + ss6.str("abc"); + ss6.str(source()); // (overwrites) + ss7.str(source()); + ss7.str("abc"); // (overwrites) + sink(ss6); // tainted + sink(ss7); // [FALSE POSITIVE] + + sink(ss8.put('a')); + sink(ss9.put(ns_char::source())); // tainted + sink(ss10.put('a').put(ns_char::source()).put('z')); // tainted + sink(ss8); + sink(ss9); // tainted + sink(ss10); // tainted + + sink(ss11.write("begin", 5)); + sink(ss12.write(source(), 5)); // tainted + sink(ss13.write("begin", 5).write(source(), amount).write("end", 3)); // tainted + sink(ss11); + sink(ss12); // tainted + sink(ss13); // tainted +} + +void test_stringstream_int(int source) +{ + std::stringstream ss1, ss2; + int v1 = 0, v2 = 0; + + sink(ss1 << 1234); + sink(ss2 << source); // tainted + sink(ss1 >> v1); + sink(ss2 >> v2); // tainted + + sink(ss1); + sink(ss2); // tainted + sink(ss1.str()); + sink(ss2.str()); // tainted + sink(v1); + sink(v2); // tainted +} + +void test_stringstream_constructors() +{ + std::string s1 = "abc"; + std::string s2 = source(); + std::stringstream ss1(s1); + std::stringstream ss2(s2); + std::stringstream ss3 = std::stringstream("abc"); + std::stringstream ss4 = std::stringstream(source()); + std::stringstream ss5; + std::stringstream ss6; + + sink(ss5 = std::stringstream("abc")); + sink(ss6 = std::stringstream(source())); // tainted + + sink(ss1); + sink(ss2); // tainted + sink(ss3); + sink(ss4); // tainted + sink(ss5); + sink(ss6); // tainted +} + +void test_stringstream_swap() +{ + std::stringstream ss1("abc"); + std::stringstream ss2(source()); + std::stringstream ss3("abc"); + std::stringstream ss4(source()); + + ss1.swap(ss2); + ss4.swap(ss3); + + sink(ss1); // tainted + sink(ss2); // [FALSE POSITIVE] + sink(ss3); // tainted + sink(ss4); // [FALSE POSITIVE] +} + +void test_stringstream_in() +{ + std::stringstream ss1, ss2; + std::string s1, s2, s3, s4; + char b1[100] = {0}; + char b2[100] = {0}; + char b3[100] = {0}; + char b4[100] = {0}; + char b5[100] = {0}; + char b6[100] = {0}; + char b7[100] = {0}; + char b8[100] = {0}; + char b9[100] = {0}; + char b10[100] = {0}; + char c1 = 0, c2 = 0, c3 = 0, c4 = 0, c5 = 0, c6 = 0; + + sink(ss1 << "abc"); + sink(ss2 << source()); // tainted + + sink(ss1 >> s1); + sink(ss2 >> s2); // tainted + sink(ss2 >> s3 >> s4); // tainted + sink(s1); + sink(s2); // tainted + sink(s3); // tainted + sink(s4); // tainted + + sink(ss1 >> b1); + sink(ss2 >> b2); // tainted + sink(ss2 >> b3 >> b4); // tainted + sink(b1); + sink(b2); // tainted + sink(b3); // tainted + sink(b4); // tainted + + sink(ss1.read(b5, 100)); + sink(ss2.read(b6, 100)); // tainted + sink(ss1.readsome(b7, 100)); + sink(ss2.readsome(b8, 100)); // (returns a length, not significantly tainted) + sink(ss1.get(b9, 100)); + sink(ss2.get(b10, 100)); // tainted + sink(b5); + sink(b6); // tainted + sink(b7); + sink(b8); // tainted + sink(b9); + sink(b10); // tainted + + sink(c1 = ss1.get()); + sink(c2 = ss2.get()); // tainted + sink(c3 = ss1.peek()); + sink(c4 = ss2.peek()); // tainted + sink(ss1.get(c5)); + sink(ss2.get(c6)); // tainted + sink(c1); + sink(c2); // tainted + sink(c3); + sink(c4); // tainted + sink(c5); + sink(c6); // tainted +} + +void test_stringstream_putback() +{ + std::stringstream ss; + + sink(ss.put('a')); + sink(ss.get()); + sink(ss.putback('b')); + sink(ss.get()); + sink(ss.putback(ns_char::source())); // tainted + sink(ss.get()); // tainted +} + +void test_getline() +{ + std::stringstream ss1("abc"); + std::stringstream ss2(source()); + char b1[1000] = {0}; + char b2[1000] = {0}; + char b3[1000] = {0}; + char b4[1000] = {0}; + char b5[1000] = {0}; + char b6[1000] = {0}; + char b7[1000] = {0}; + char b8[1000] = {0}; + std::string s1, s2, s3, s4, s5, s6, s7, s8; + + sink(ss1.getline(b1, 1000)); + sink(ss2.getline(b2, 1000)); // tainted + sink(ss2.getline(b3, 1000)); // tainted + sink(ss1.getline(b3, 1000)); + sink(b1); + sink(b2); // tainted + sink(b3); // [FALSE POSITIVE] + + sink(ss1.getline(b4, 1000, ' ')); + sink(ss2.getline(b5, 1000, ' ')); // tainted + sink(ss2.getline(b6, 1000, ' ')); // tainted + sink(ss1.getline(b6, 1000, ' ')); + sink(b4); + sink(b5); // tainted + sink(b6); // [FALSE POSITIVE] + + sink(ss2.getline(b7, 1000).getline(b8, 1000)); // tainted + sink(b7); // tainted + sink(b8); // tainted + + sink(getline(ss1, s1)); + sink(getline(ss2, s2)); // tainted + sink(getline(ss2, s3)); // tainted + sink(getline(ss1, s3)); + sink(s1); + sink(s2); // tainted + sink(s3); // [FALSE POSITIVE] + + sink(getline(ss1, s4, ' ')); + sink(getline(ss2, s5, ' ')); // tainted + sink(getline(ss2, s6, ' ')); // tainted + sink(getline(ss1, s6, ' ')); + sink(s4); + sink(s5); // tainted + sink(s6); // [FALSE POSITIVE] + + sink(getline(getline(ss2, s7), s8)); // tainted + sink(s7); // tainted + sink(s8); // tainted +} + +void test_chaining() +{ + std::stringstream ss1(source()); + std::stringstream ss2; + char b1[1000] = {0}; + char b2[1000] = {0}; + + sink(ss1.get(b1, 100).unget().get(b2, 100)); // tainted + sink(b1); // tainted + sink(b2); // tainted + + sink(ss2.write("abc", 3).flush().write(source(), 3).flush().write("xyz", 3)); // tainted + sink(ss2); // tainted +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/structlikeclass.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/structlikeclass.cpp new file mode 100644 index 000000000000..727a0fff53b9 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/structlikeclass.cpp @@ -0,0 +1,64 @@ + +int source(); +void sink(...) {}; + +class StructLikeClass { +public: + StructLikeClass() {} // Constructor + StructLikeClass(int _v) : v(_v) {} // ConversionConstructor + + int v; +}; + +void test_structlikeclass() +{ + { + StructLikeClass s1(1); + StructLikeClass s2 = 1; + StructLikeClass s3(s1); + StructLikeClass s4; + s4 = 1; + + sink(s1); + sink(s2); + sink(s3); + sink(s4); + } + + { + StructLikeClass s1(source()); + StructLikeClass s2 = source(); + StructLikeClass s3(s1); + StructLikeClass s4; + s4 = source(); + + sink(s1); // tainted + sink(s2); // tainted + sink(s3); // tainted + sink(s4); // tainted + } + + { + StructLikeClass s1; + StructLikeClass s2 = s1; + StructLikeClass s3(s1); + StructLikeClass s4; + s4 = s1; + + sink(s1); + sink(s2); + sink(s3); + sink(s4); + } + + { + StructLikeClass s1 = StructLikeClass(source()); + StructLikeClass s2; + StructLikeClass s3; + s2 = StructLikeClass(source()); + + sink(s1); // tainted + sink(s2); // tainted + sink(s3 = source()); // tainted + } +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/swap.h b/cpp/ql/test/library-tests/dataflow/taint-tests/swap.h new file mode 100644 index 000000000000..6e554ac15dba --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/swap.h @@ -0,0 +1,5 @@ +namespace std +{ + template + constexpr void swap(T &a, T &b); +} \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp new file mode 100644 index 000000000000..7ba05b86f729 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp @@ -0,0 +1,146 @@ +#include "swap.h" +/* + * Note: This file exists in two versions (swap1.cpp and swap2.cpp). + * The only difference is that `IntWrapper` in swap1.cpp contains a single data member, and swap2.cpp + * contains two data members. + */ + +int source(); +void sink(...); + +namespace std +{ + template + T &&move(T &t) noexcept { return static_cast(t); } // simplified signature (and implementation) +} // namespace std + +namespace IntWrapper +{ + struct Class + { + int data1; + + Class() = default; + Class(Class &&that) { swap(that); } + Class(const Class &that) : data1(that.data1) {} + + Class &operator=(const Class &that) + { + auto tmp = that; + swap(tmp); + return *this; + } + + Class &operator=(Class &&that) + { + swap(that); + return *this; + } + + Class ©_assign(const Class &that) // copy assignment without the usual signature + { + auto tmp = that; + swap(tmp); + return *this; + } + + Class &move_assign(Class &&that) // move assignment without the usual signature + { + swap(that); + return *this; + } + + void swap(Class &that) noexcept + { + using std::swap; + swap(data1, that.data1); + } + }; + + // For ADL + void swap(Class &x, Class &y) + { + x.swap(y); + } +} // namespace IntWrapper + +void test_copy_assignment_operator() +{ + IntWrapper::Class x; + IntWrapper::Class y; + x.data1 = source(); + + sink(x.data1); // tainted + sink(y.data1); // clean + + y = x; + + sink(y.data1); // tainted + sink(x.data1); // tainted + + IntWrapper::Class z1, z2; + z1.data1 = source(); + sink(z1.data1); // tainted + + swap(z1, z2); + + sink(z2.data1); // tainted [FALSE NEGATIVE in IR] + sink(z1.data1); // clean [FALSE POSITIVE] +} + +void test_move_assignment_operator() +{ + IntWrapper::Class x; + IntWrapper::Class y; + x.data1 = source(); + + sink(x.data1); // tainted + sink(y.data1); // clean + + y = std::move(x); + + sink(y.data1); // tainted + sink(x.data1); // tainted +} + +void test_move_constructor() +{ + IntWrapper::Class move_from; + move_from.data1 = source(); + + sink(move_from.data1); // tainted + + IntWrapper::Class move_to(std::move(move_from)); + + sink(move_to.data1); // tainted +} + +void test_copy_assignment_method() +{ + IntWrapper::Class x; + IntWrapper::Class y; + x.data1 = source(); + + sink(x.data1); // tainted + sink(y.data1); // clean + + y.copy_assign(x); + + sink(y.data1); // tainted + sink(x.data1); // tainted +} + +void test_move_assignment_method() +{ + IntWrapper::Class x; + IntWrapper::Class y; + x.data1 = source(); + + sink(x.data1); // tainted + sink(y.data1); // clean + + y.move_assign(std::move(x)); + + sink(y.data1); // tainted + sink(x.data1); // tainted +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp new file mode 100644 index 000000000000..e5203f344f2e --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp @@ -0,0 +1,146 @@ +#include "swap.h" +/* + * Note: This file exists in two versions (swap1.cpp and swap2.cpp). + * The only difference is that `IntWrapper` in swap1.cpp contains a single data member, and swap2.cpp + * contains two data members. + */ + +int source(); +void sink(...); + +namespace std +{ + template + T &&move(T &t) noexcept { return static_cast(t); } // simplified signature (and implementation) +} // namespace std + +namespace IntWrapper +{ + struct Class + { + int data1; int data2; + + Class() = default; + Class(Class &&that) { swap(that); } + Class(const Class &that) : data1(that.data1), data2(that.data2) {} + + Class &operator=(const Class &that) + { + auto tmp = that; + swap(tmp); + return *this; + } + + Class &operator=(Class &&that) + { + swap(that); + return *this; + } + + Class ©_assign(const Class &that) // copy assignment without the usual signature + { + auto tmp = that; + swap(tmp); + return *this; + } + + Class &move_assign(Class &&that) // move assignment without the usual signature + { + swap(that); + return *this; + } + + void swap(Class &that) noexcept + { + using std::swap; + swap(data1, that.data1); swap(data2, that.data2); + } + }; + + // For ADL + void swap(Class &x, Class &y) + { + x.swap(y); + } +} // namespace IntWrapper + +void test_copy_assignment_operator() +{ + IntWrapper::Class x; + IntWrapper::Class y; + x.data1 = source(); + + sink(x.data1); // tainted + sink(y.data1); // clean + + y = x; + + sink(y.data1); // tainted + sink(x.data1); // tainted + + IntWrapper::Class z1, z2; + z1.data1 = source(); + sink(z1.data1); // tainted + + swap(z1, z2); + + sink(z2.data1); // tainted [FALSE NEGATIVE in IR] + sink(z1.data1); // clean [FALSE POSITIVE] +} + +void test_move_assignment_operator() +{ + IntWrapper::Class x; + IntWrapper::Class y; + x.data1 = source(); + + sink(x.data1); // tainted + sink(y.data1); // clean + + y = std::move(x); + + sink(y.data1); // tainted + sink(x.data1); // tainted +} + +void test_move_constructor() +{ + IntWrapper::Class move_from; + move_from.data1 = source(); + + sink(move_from.data1); // tainted + + IntWrapper::Class move_to(std::move(move_from)); + + sink(move_to.data1); // tainted +} + +void test_copy_assignment_method() +{ + IntWrapper::Class x; + IntWrapper::Class y; + x.data1 = source(); + + sink(x.data1); // tainted + sink(y.data1); // clean + + y.copy_assign(x); + + sink(y.data1); // tainted + sink(x.data1); // tainted +} + +void test_move_assignment_method() +{ + IntWrapper::Class x; + IntWrapper::Class y; + x.data1 = source(); + + sink(x.data1); // tainted + sink(y.data1); // clean + + y.move_assign(std::move(x)); + + sink(y.data1); // tainted + sink(x.data1); // tainted +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp index 3d09f075a40e..48e78c62147f 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp @@ -86,12 +86,12 @@ void class_field_test() { mc1.myMethod(); sink(mc1.a); - sink(mc1.b); // tainted [NOT DETECTED with IR] - sink(mc1.c); // tainted [NOT DETECTED with IR] - sink(mc1.d); // tainted [NOT DETECTED with IR] + sink(mc1.b); // tainted + sink(mc1.c); // tainted + sink(mc1.d); // tainted sink(mc2.a); - sink(mc2.b); // tainted [NOT DETECTED with IR] - sink(mc2.c); // tainted [NOT DETECTED with IR] + sink(mc2.b); // tainted + sink(mc2.c); // tainted sink(mc2.d); } @@ -107,9 +107,9 @@ void array_test(int i) { arr3[5] = 0; sink(arr1[5]); // tainted - sink(arr1[i]); // tainted [NOT DETECTED] - sink(arr2[5]); // tainted [NOT DETECTED] - sink(arr2[i]); // tainted [NOT DETECTED] + sink(arr1[i]); // tainted + sink(arr2[5]); // tainted + sink(arr2[i]); // tainted sink(arr3[5]); sink(arr3[i]); } @@ -127,7 +127,7 @@ void pointer_test() { *p2 = source(); sink(*p1); // tainted - sink(*p2); // tainted [NOT DETECTED] + sink(*p2); // tainted sink(*p3); p3 = &t1; @@ -197,9 +197,9 @@ void test_memcpy(int *source) { // --- std::swap --- -namespace std { - template constexpr void swap(T& a, T& b); -} +#include "swap.h" + + void test_swap() { int x, y; @@ -350,8 +350,8 @@ void test_outparams() sink(t); // tainted sink(a); // tainted sink(b); // tainted - sink(c); // tainted [NOT DETECTED] - sink(d); // tainted [NOT DETECTED] + sink(c); // tainted + sink(d); // tainted sink(e); } @@ -483,4 +483,4 @@ void test_getdelim(FILE* source1) { getdelim(&line, &n, '\n', source1); sink(line); -} \ No newline at end of file +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected index 312a46e979e9..deecad605dde 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -1,3 +1,25 @@ +| arrayassignment.cpp:17:7:17:10 | * ... | arrayassignment.cpp:14:9:14:14 | call to source | +| arrayassignment.cpp:33:7:33:9 | r_x | arrayassignment.cpp:29:8:29:13 | call to source | +| arrayassignment.cpp:57:10:57:12 | call to get | arrayassignment.cpp:54:9:54:14 | call to source | +| arrayassignment.cpp:67:10:67:12 | call to get | arrayassignment.cpp:64:13:64:18 | call to source | +| arrayassignment.cpp:101:7:101:18 | access to array | arrayassignment.cpp:99:17:99:22 | call to source | +| arrayassignment.cpp:135:7:135:10 | ref1 | arrayassignment.cpp:134:9:134:14 | call to source | +| arrayassignment.cpp:140:7:140:11 | * ... | arrayassignment.cpp:139:10:139:15 | call to source | +| arrayassignment.cpp:145:7:145:13 | access to array | arrayassignment.cpp:144:12:144:17 | call to source | +| copyableclass.cpp:40:8:40:9 | s1 | copyableclass.cpp:34:22:34:27 | call to source | +| copyableclass.cpp:41:8:41:9 | s2 | copyableclass.cpp:35:24:35:29 | call to source | +| copyableclass.cpp:42:8:42:9 | s3 | copyableclass.cpp:34:22:34:27 | call to source | +| copyableclass.cpp:43:8:43:9 | s4 | copyableclass.cpp:38:8:38:13 | call to source | +| copyableclass.cpp:65:8:65:9 | s1 | copyableclass.cpp:60:40:60:45 | call to source | +| copyableclass.cpp:66:8:66:9 | s2 | copyableclass.cpp:63:24:63:29 | call to source | +| copyableclass.cpp:67:11:67:11 | call to operator= | copyableclass.cpp:67:13:67:18 | call to source | +| copyableclass_declonly.cpp:40:8:40:9 | s1 | copyableclass_declonly.cpp:34:30:34:35 | call to source | +| copyableclass_declonly.cpp:41:8:41:9 | s2 | copyableclass_declonly.cpp:35:32:35:37 | call to source | +| copyableclass_declonly.cpp:42:8:42:9 | s3 | copyableclass_declonly.cpp:34:30:34:35 | call to source | +| copyableclass_declonly.cpp:43:8:43:9 | s4 | copyableclass_declonly.cpp:38:8:38:13 | call to source | +| copyableclass_declonly.cpp:65:8:65:9 | s1 | copyableclass_declonly.cpp:60:56:60:61 | call to source | +| copyableclass_declonly.cpp:66:8:66:9 | s2 | copyableclass_declonly.cpp:63:32:63:37 | call to source | +| copyableclass_declonly.cpp:67:11:67:11 | call to operator= | copyableclass_declonly.cpp:67:13:67:18 | call to source | | format.cpp:57:8:57:13 | buffer | format.cpp:56:36:56:49 | call to source | | format.cpp:62:8:62:13 | buffer | format.cpp:61:30:61:43 | call to source | | format.cpp:67:8:67:13 | buffer | format.cpp:66:52:66:65 | call to source | @@ -8,14 +30,489 @@ | format.cpp:100:8:100:13 | buffer | format.cpp:99:30:99:43 | call to source | | format.cpp:105:8:105:13 | buffer | format.cpp:104:31:104:45 | call to source | | format.cpp:110:8:110:14 | wbuffer | format.cpp:109:38:109:52 | call to source | +| format.cpp:115:8:115:13 | buffer | format.cpp:114:37:114:50 | call to source | | format.cpp:157:7:157:22 | access to array | format.cpp:147:12:147:25 | call to source | | format.cpp:158:7:158:27 | ... + ... | format.cpp:148:16:148:30 | call to source | -| stl.cpp:71:7:71:7 | a | stl.cpp:67:12:67:17 | call to source | -| stl.cpp:73:7:73:7 | c | stl.cpp:69:16:69:21 | call to source | -| stl.cpp:75:9:75:13 | call to c_str | stl.cpp:69:16:69:21 | call to source | -| stl.cpp:125:13:125:17 | call to c_str | stl.cpp:117:10:117:15 | call to source | -| stl.cpp:129:13:129:17 | call to c_str | stl.cpp:117:10:117:15 | call to source | -| stl.cpp:132:13:132:17 | call to c_str | stl.cpp:117:10:117:15 | call to source | +| map.cpp:29:9:29:13 | first | map.cpp:28:12:28:17 | call to source | +| map.cpp:35:9:35:14 | second | map.cpp:33:13:33:18 | call to source | +| map.cpp:44:9:44:13 | first | map.cpp:43:30:43:35 | call to source | +| map.cpp:50:9:50:14 | second | map.cpp:48:37:48:42 | call to source | +| map.cpp:51:7:51:7 | f | map.cpp:48:37:48:42 | call to source | +| map.cpp:55:9:55:14 | second | map.cpp:48:37:48:42 | call to source | +| map.cpp:56:7:56:7 | g | map.cpp:48:37:48:42 | call to source | +| map.cpp:61:9:61:14 | second | map.cpp:48:37:48:42 | call to source | +| map.cpp:62:7:62:7 | h | map.cpp:48:37:48:42 | call to source | +| map.cpp:72:7:72:7 | i | map.cpp:65:37:65:42 | call to source | +| map.cpp:74:9:74:14 | second | map.cpp:65:37:65:42 | call to source | +| map.cpp:75:7:75:7 | j | map.cpp:65:37:65:42 | call to source | +| map.cpp:77:9:77:14 | second | map.cpp:66:37:66:42 | call to source | +| map.cpp:78:7:78:7 | k | map.cpp:66:37:66:42 | call to source | +| map.cpp:81:7:81:7 | l | map.cpp:66:37:66:42 | call to source | +| map.cpp:89:7:89:32 | call to pair | map.cpp:89:24:89:29 | call to source | +| map.cpp:110:10:110:15 | call to insert | map.cpp:110:62:110:67 | call to source | +| map.cpp:112:10:112:25 | call to insert_or_assign | map.cpp:112:46:112:51 | call to source | +| map.cpp:114:7:114:8 | call to map | map.cpp:108:39:108:44 | call to source | +| map.cpp:116:7:116:8 | call to map | map.cpp:110:62:110:67 | call to source | +| map.cpp:117:7:117:8 | call to map | map.cpp:111:34:111:39 | call to source | +| map.cpp:118:7:118:8 | call to map | map.cpp:112:46:112:51 | call to source | +| map.cpp:120:10:120:13 | call to find | map.cpp:108:39:108:44 | call to source | +| map.cpp:122:10:122:13 | call to find | map.cpp:110:62:110:67 | call to source | +| map.cpp:123:10:123:13 | call to find | map.cpp:111:34:111:39 | call to source | +| map.cpp:124:10:124:13 | call to find | map.cpp:112:46:112:51 | call to source | +| map.cpp:126:10:126:13 | call to find | map.cpp:108:39:108:44 | call to source | +| map.cpp:128:10:128:13 | call to find | map.cpp:110:62:110:67 | call to source | +| map.cpp:129:10:129:13 | call to find | map.cpp:111:34:111:39 | call to source | +| map.cpp:130:10:130:13 | call to find | map.cpp:112:46:112:51 | call to source | +| map.cpp:137:7:137:8 | call to map | map.cpp:108:39:108:44 | call to source | +| map.cpp:138:7:138:8 | call to map | map.cpp:108:39:108:44 | call to source | +| map.cpp:139:7:139:8 | call to map | map.cpp:108:39:108:44 | call to source | +| map.cpp:140:10:140:13 | call to find | map.cpp:108:39:108:44 | call to source | +| map.cpp:141:10:141:13 | call to find | map.cpp:108:39:108:44 | call to source | +| map.cpp:142:10:142:13 | call to find | map.cpp:108:39:108:44 | call to source | +| map.cpp:154:8:154:10 | call to pair | map.cpp:108:39:108:44 | call to source | +| map.cpp:168:7:168:27 | ... = ... | map.cpp:168:20:168:25 | call to source | +| map.cpp:170:7:170:30 | ... = ... | map.cpp:170:23:170:28 | call to source | +| map.cpp:172:10:172:10 | call to operator[] | map.cpp:168:20:168:25 | call to source | +| map.cpp:174:10:174:10 | call to operator[] | map.cpp:170:23:170:28 | call to source | +| map.cpp:182:10:182:20 | call to lower_bound | map.cpp:108:39:108:44 | call to source | +| map.cpp:183:10:183:20 | call to upper_bound | map.cpp:108:39:108:44 | call to source | +| map.cpp:186:10:186:20 | call to upper_bound | map.cpp:108:39:108:44 | call to source | +| map.cpp:193:7:193:9 | call to map | map.cpp:191:49:191:54 | call to source | +| map.cpp:196:7:196:9 | call to map | map.cpp:192:49:192:54 | call to source | +| map.cpp:199:7:199:9 | call to map | map.cpp:191:49:191:54 | call to source | +| map.cpp:200:7:200:9 | call to map | map.cpp:191:49:191:54 | call to source | +| map.cpp:201:7:201:9 | call to map | map.cpp:192:49:192:54 | call to source | +| map.cpp:202:7:202:9 | call to map | map.cpp:192:49:192:54 | call to source | +| map.cpp:210:7:210:9 | call to map | map.cpp:206:49:206:54 | call to source | +| map.cpp:213:7:213:9 | call to map | map.cpp:209:49:209:54 | call to source | +| map.cpp:216:7:216:9 | call to map | map.cpp:206:49:206:54 | call to source | +| map.cpp:218:7:218:9 | call to map | map.cpp:209:49:209:54 | call to source | +| map.cpp:219:7:219:9 | call to map | map.cpp:209:49:209:54 | call to source | +| map.cpp:225:7:225:9 | call to map | map.cpp:223:49:223:54 | call to source | +| map.cpp:225:7:225:9 | call to map | map.cpp:224:49:224:54 | call to source | +| map.cpp:226:11:226:15 | call to erase | map.cpp:223:49:223:54 | call to source | +| map.cpp:226:11:226:15 | call to erase | map.cpp:224:49:224:54 | call to source | +| map.cpp:227:7:227:9 | call to map | map.cpp:223:49:223:54 | call to source | +| map.cpp:227:7:227:9 | call to map | map.cpp:224:49:224:54 | call to source | +| map.cpp:229:7:229:9 | call to map | map.cpp:223:49:223:54 | call to source | +| map.cpp:229:7:229:9 | call to map | map.cpp:224:49:224:54 | call to source | +| map.cpp:236:7:236:9 | call to map | map.cpp:235:26:235:31 | call to source | +| map.cpp:239:11:239:22 | call to emplace_hint | map.cpp:239:44:239:49 | call to source | +| map.cpp:240:7:240:9 | call to map | map.cpp:239:44:239:49 | call to source | +| map.cpp:247:7:247:9 | call to map | map.cpp:246:30:246:35 | call to source | +| map.cpp:250:11:250:21 | call to try_emplace | map.cpp:250:43:250:48 | call to source | +| map.cpp:251:7:251:9 | call to map | map.cpp:250:43:250:48 | call to source | +| map.cpp:262:10:262:15 | call to insert | map.cpp:262:62:262:67 | call to source | +| map.cpp:264:10:264:25 | call to insert_or_assign | map.cpp:264:46:264:51 | call to source | +| map.cpp:266:7:266:8 | call to unordered_map | map.cpp:260:39:260:44 | call to source | +| map.cpp:268:7:268:8 | call to unordered_map | map.cpp:262:62:262:67 | call to source | +| map.cpp:269:7:269:8 | call to unordered_map | map.cpp:263:34:263:39 | call to source | +| map.cpp:270:7:270:8 | call to unordered_map | map.cpp:264:46:264:51 | call to source | +| map.cpp:272:10:272:13 | call to find | map.cpp:260:39:260:44 | call to source | +| map.cpp:274:10:274:13 | call to find | map.cpp:262:62:262:67 | call to source | +| map.cpp:275:10:275:13 | call to find | map.cpp:263:34:263:39 | call to source | +| map.cpp:276:10:276:13 | call to find | map.cpp:264:46:264:51 | call to source | +| map.cpp:278:10:278:13 | call to find | map.cpp:260:39:260:44 | call to source | +| map.cpp:280:10:280:13 | call to find | map.cpp:262:62:262:67 | call to source | +| map.cpp:281:10:281:13 | call to find | map.cpp:263:34:263:39 | call to source | +| map.cpp:282:10:282:13 | call to find | map.cpp:264:46:264:51 | call to source | +| map.cpp:289:7:289:8 | call to unordered_map | map.cpp:260:39:260:44 | call to source | +| map.cpp:290:7:290:8 | call to unordered_map | map.cpp:260:39:260:44 | call to source | +| map.cpp:291:7:291:8 | call to unordered_map | map.cpp:260:39:260:44 | call to source | +| map.cpp:292:10:292:13 | call to find | map.cpp:260:39:260:44 | call to source | +| map.cpp:293:10:293:13 | call to find | map.cpp:260:39:260:44 | call to source | +| map.cpp:294:10:294:13 | call to find | map.cpp:260:39:260:44 | call to source | +| map.cpp:306:8:306:10 | call to pair | map.cpp:260:39:260:44 | call to source | +| map.cpp:320:7:320:27 | ... = ... | map.cpp:320:20:320:25 | call to source | +| map.cpp:322:7:322:30 | ... = ... | map.cpp:322:23:322:28 | call to source | +| map.cpp:324:10:324:10 | call to operator[] | map.cpp:320:20:320:25 | call to source | +| map.cpp:326:10:326:10 | call to operator[] | map.cpp:322:23:322:28 | call to source | +| map.cpp:342:7:342:9 | call to unordered_map | map.cpp:340:49:340:54 | call to source | +| map.cpp:345:7:345:9 | call to unordered_map | map.cpp:341:49:341:54 | call to source | +| map.cpp:348:7:348:9 | call to unordered_map | map.cpp:340:49:340:54 | call to source | +| map.cpp:349:7:349:9 | call to unordered_map | map.cpp:340:49:340:54 | call to source | +| map.cpp:350:7:350:9 | call to unordered_map | map.cpp:341:49:341:54 | call to source | +| map.cpp:351:7:351:9 | call to unordered_map | map.cpp:341:49:341:54 | call to source | +| map.cpp:359:7:359:9 | call to unordered_map | map.cpp:355:49:355:54 | call to source | +| map.cpp:362:7:362:9 | call to unordered_map | map.cpp:358:49:358:54 | call to source | +| map.cpp:365:7:365:9 | call to unordered_map | map.cpp:355:49:355:54 | call to source | +| map.cpp:367:7:367:9 | call to unordered_map | map.cpp:358:49:358:54 | call to source | +| map.cpp:368:7:368:9 | call to unordered_map | map.cpp:358:49:358:54 | call to source | +| map.cpp:374:7:374:9 | call to unordered_map | map.cpp:372:49:372:54 | call to source | +| map.cpp:374:7:374:9 | call to unordered_map | map.cpp:373:49:373:54 | call to source | +| map.cpp:375:11:375:15 | call to erase | map.cpp:372:49:372:54 | call to source | +| map.cpp:375:11:375:15 | call to erase | map.cpp:373:49:373:54 | call to source | +| map.cpp:376:7:376:9 | call to unordered_map | map.cpp:372:49:372:54 | call to source | +| map.cpp:376:7:376:9 | call to unordered_map | map.cpp:373:49:373:54 | call to source | +| map.cpp:378:7:378:9 | call to unordered_map | map.cpp:372:49:372:54 | call to source | +| map.cpp:378:7:378:9 | call to unordered_map | map.cpp:373:49:373:54 | call to source | +| map.cpp:385:7:385:9 | call to unordered_map | map.cpp:384:26:384:31 | call to source | +| map.cpp:388:11:388:22 | call to emplace_hint | map.cpp:388:44:388:49 | call to source | +| map.cpp:389:7:389:9 | call to unordered_map | map.cpp:388:44:388:49 | call to source | +| map.cpp:398:7:398:9 | call to unordered_map | map.cpp:396:30:396:35 | call to source | +| map.cpp:398:7:398:9 | call to unordered_map | map.cpp:397:30:397:35 | call to source | +| map.cpp:401:11:401:21 | call to try_emplace | map.cpp:401:43:401:48 | call to source | +| map.cpp:402:7:402:9 | call to unordered_map | map.cpp:401:43:401:48 | call to source | +| map.cpp:416:7:416:41 | call to pair | map.cpp:416:30:416:35 | call to source | +| map.cpp:417:7:417:9 | call to unordered_map | map.cpp:416:30:416:35 | call to source | +| map.cpp:418:7:418:16 | call to pair | map.cpp:416:30:416:35 | call to source | +| map.cpp:419:7:419:41 | call to pair | map.cpp:419:33:419:38 | call to source | +| map.cpp:420:7:420:9 | call to unordered_map | map.cpp:419:33:419:38 | call to source | +| map.cpp:421:7:421:16 | call to pair | map.cpp:419:33:419:38 | call to source | +| map.cpp:432:7:432:9 | call to unordered_map | map.cpp:431:52:431:57 | call to source | +| map.cpp:433:11:433:22 | call to emplace_hint | map.cpp:431:52:431:57 | call to source | +| movableclass.cpp:44:8:44:9 | s1 | movableclass.cpp:39:21:39:26 | call to source | +| movableclass.cpp:45:8:45:9 | s2 | movableclass.cpp:40:23:40:28 | call to source | +| movableclass.cpp:46:8:46:9 | s3 | movableclass.cpp:42:8:42:13 | call to source | +| movableclass.cpp:54:8:54:9 | s1 | movableclass.cpp:50:38:50:43 | call to source | +| movableclass.cpp:55:8:55:9 | s2 | movableclass.cpp:52:23:52:28 | call to source | +| movableclass.cpp:64:8:64:9 | s2 | movableclass.cpp:23:55:23:60 | call to source | +| movableclass.cpp:65:11:65:11 | call to operator= | movableclass.cpp:65:13:65:18 | call to source | +| set.cpp:22:10:22:15 | call to insert | set.cpp:22:29:22:34 | call to source | +| set.cpp:26:7:26:8 | call to set | set.cpp:20:17:20:22 | call to source | +| set.cpp:28:7:28:8 | call to set | set.cpp:22:29:22:34 | call to source | +| set.cpp:30:7:30:8 | call to set | set.cpp:20:17:20:22 | call to source | +| set.cpp:32:10:32:13 | call to find | set.cpp:20:17:20:22 | call to source | +| set.cpp:34:10:34:13 | call to find | set.cpp:22:29:22:34 | call to source | +| set.cpp:36:10:36:13 | call to find | set.cpp:20:17:20:22 | call to source | +| set.cpp:44:7:44:8 | call to set | set.cpp:20:17:20:22 | call to source | +| set.cpp:45:7:45:8 | call to set | set.cpp:20:17:20:22 | call to source | +| set.cpp:46:7:46:8 | call to set | set.cpp:20:17:20:22 | call to source | +| set.cpp:47:7:47:9 | call to set | set.cpp:20:17:20:22 | call to source | +| set.cpp:48:10:48:13 | call to find | set.cpp:20:17:20:22 | call to source | +| set.cpp:49:10:49:13 | call to find | set.cpp:20:17:20:22 | call to source | +| set.cpp:50:10:50:13 | call to find | set.cpp:20:17:20:22 | call to source | +| set.cpp:51:11:51:14 | call to find | set.cpp:20:17:20:22 | call to source | +| set.cpp:61:8:61:8 | call to operator* | set.cpp:20:17:20:22 | call to source | +| set.cpp:69:11:69:21 | call to lower_bound | set.cpp:67:13:67:18 | call to source | +| set.cpp:70:11:70:21 | call to upper_bound | set.cpp:67:13:67:18 | call to source | +| set.cpp:78:7:78:9 | call to set | set.cpp:76:13:76:18 | call to source | +| set.cpp:81:7:81:9 | call to set | set.cpp:77:13:77:18 | call to source | +| set.cpp:84:7:84:9 | call to set | set.cpp:76:13:76:18 | call to source | +| set.cpp:85:7:85:9 | call to set | set.cpp:76:13:76:18 | call to source | +| set.cpp:86:7:86:9 | call to set | set.cpp:77:13:77:18 | call to source | +| set.cpp:87:7:87:9 | call to set | set.cpp:77:13:77:18 | call to source | +| set.cpp:95:7:95:9 | call to set | set.cpp:91:13:91:18 | call to source | +| set.cpp:98:7:98:9 | call to set | set.cpp:94:13:94:18 | call to source | +| set.cpp:101:7:101:9 | call to set | set.cpp:91:13:91:18 | call to source | +| set.cpp:103:7:103:9 | call to set | set.cpp:94:13:94:18 | call to source | +| set.cpp:104:7:104:9 | call to set | set.cpp:94:13:94:18 | call to source | +| set.cpp:110:7:110:9 | call to set | set.cpp:108:13:108:18 | call to source | +| set.cpp:110:7:110:9 | call to set | set.cpp:109:13:109:18 | call to source | +| set.cpp:111:11:111:15 | call to erase | set.cpp:108:13:108:18 | call to source | +| set.cpp:111:11:111:15 | call to erase | set.cpp:109:13:109:18 | call to source | +| set.cpp:112:7:112:9 | call to set | set.cpp:108:13:108:18 | call to source | +| set.cpp:112:7:112:9 | call to set | set.cpp:109:13:109:18 | call to source | +| set.cpp:114:7:114:9 | call to set | set.cpp:108:13:108:18 | call to source | +| set.cpp:114:7:114:9 | call to set | set.cpp:109:13:109:18 | call to source | +| set.cpp:121:7:121:9 | call to set | set.cpp:120:19:120:24 | call to source | +| set.cpp:124:11:124:22 | call to emplace_hint | set.cpp:124:37:124:42 | call to source | +| set.cpp:125:7:125:9 | call to set | set.cpp:124:37:124:42 | call to source | +| set.cpp:136:10:136:15 | call to insert | set.cpp:136:29:136:34 | call to source | +| set.cpp:140:7:140:8 | call to unordered_set | set.cpp:134:17:134:22 | call to source | +| set.cpp:142:7:142:8 | call to unordered_set | set.cpp:136:29:136:34 | call to source | +| set.cpp:144:7:144:8 | call to unordered_set | set.cpp:134:17:134:22 | call to source | +| set.cpp:146:10:146:13 | call to find | set.cpp:134:17:134:22 | call to source | +| set.cpp:148:10:148:13 | call to find | set.cpp:136:29:136:34 | call to source | +| set.cpp:150:10:150:13 | call to find | set.cpp:134:17:134:22 | call to source | +| set.cpp:158:7:158:8 | call to unordered_set | set.cpp:134:17:134:22 | call to source | +| set.cpp:159:7:159:8 | call to unordered_set | set.cpp:134:17:134:22 | call to source | +| set.cpp:160:7:160:8 | call to unordered_set | set.cpp:134:17:134:22 | call to source | +| set.cpp:161:7:161:9 | call to unordered_set | set.cpp:134:17:134:22 | call to source | +| set.cpp:162:10:162:13 | call to find | set.cpp:134:17:134:22 | call to source | +| set.cpp:163:10:163:13 | call to find | set.cpp:134:17:134:22 | call to source | +| set.cpp:164:10:164:13 | call to find | set.cpp:134:17:134:22 | call to source | +| set.cpp:165:11:165:14 | call to find | set.cpp:134:17:134:22 | call to source | +| set.cpp:175:8:175:8 | call to operator* | set.cpp:134:17:134:22 | call to source | +| set.cpp:190:7:190:9 | call to unordered_set | set.cpp:188:13:188:18 | call to source | +| set.cpp:193:7:193:9 | call to unordered_set | set.cpp:189:13:189:18 | call to source | +| set.cpp:196:7:196:9 | call to unordered_set | set.cpp:188:13:188:18 | call to source | +| set.cpp:197:7:197:9 | call to unordered_set | set.cpp:188:13:188:18 | call to source | +| set.cpp:198:7:198:9 | call to unordered_set | set.cpp:189:13:189:18 | call to source | +| set.cpp:199:7:199:9 | call to unordered_set | set.cpp:189:13:189:18 | call to source | +| set.cpp:207:7:207:9 | call to unordered_set | set.cpp:203:13:203:18 | call to source | +| set.cpp:210:7:210:9 | call to unordered_set | set.cpp:206:13:206:18 | call to source | +| set.cpp:213:7:213:9 | call to unordered_set | set.cpp:203:13:203:18 | call to source | +| set.cpp:215:7:215:9 | call to unordered_set | set.cpp:206:13:206:18 | call to source | +| set.cpp:216:7:216:9 | call to unordered_set | set.cpp:206:13:206:18 | call to source | +| set.cpp:222:7:222:9 | call to unordered_set | set.cpp:220:13:220:18 | call to source | +| set.cpp:222:7:222:9 | call to unordered_set | set.cpp:221:13:221:18 | call to source | +| set.cpp:223:11:223:15 | call to erase | set.cpp:220:13:220:18 | call to source | +| set.cpp:223:11:223:15 | call to erase | set.cpp:221:13:221:18 | call to source | +| set.cpp:224:7:224:9 | call to unordered_set | set.cpp:220:13:220:18 | call to source | +| set.cpp:224:7:224:9 | call to unordered_set | set.cpp:221:13:221:18 | call to source | +| set.cpp:226:7:226:9 | call to unordered_set | set.cpp:220:13:220:18 | call to source | +| set.cpp:226:7:226:9 | call to unordered_set | set.cpp:221:13:221:18 | call to source | +| set.cpp:233:7:233:9 | call to unordered_set | set.cpp:232:19:232:24 | call to source | +| set.cpp:236:11:236:22 | call to emplace_hint | set.cpp:236:37:236:42 | call to source | +| set.cpp:237:7:237:9 | call to unordered_set | set.cpp:236:37:236:42 | call to source | +| smart_pointer.cpp:12:10:12:10 | call to operator* | smart_pointer.cpp:11:52:11:57 | call to source | +| smart_pointer.cpp:13:10:13:10 | p | smart_pointer.cpp:11:52:11:57 | call to source | +| smart_pointer.cpp:24:10:24:10 | call to operator* | smart_pointer.cpp:23:52:23:57 | call to source | +| smart_pointer.cpp:25:10:25:10 | p | smart_pointer.cpp:23:52:23:57 | call to source | +| smart_pointer.cpp:52:12:52:14 | call to get | smart_pointer.cpp:51:52:51:57 | call to source | +| smart_pointer.cpp:57:12:57:14 | call to get | smart_pointer.cpp:56:52:56:57 | call to source | +| standalone_iterators.cpp:40:10:40:10 | call to operator* | standalone_iterators.cpp:39:45:39:51 | source1 | +| standalone_iterators.cpp:41:10:41:10 | call to operator* | standalone_iterators.cpp:39:45:39:51 | source1 | +| standalone_iterators.cpp:42:10:42:10 | call to operator* | standalone_iterators.cpp:39:45:39:51 | source1 | +| standalone_iterators.cpp:46:10:46:10 | call to operator* | standalone_iterators.cpp:45:39:45:45 | source1 | +| standalone_iterators.cpp:47:10:47:10 | call to operator* | standalone_iterators.cpp:45:39:45:45 | source1 | +| standalone_iterators.cpp:48:10:48:10 | call to operator* | standalone_iterators.cpp:45:39:45:45 | source1 | +| string.cpp:29:7:29:7 | a | string.cpp:25:12:25:17 | call to source | +| string.cpp:31:7:31:7 | c | string.cpp:27:16:27:21 | call to source | +| string.cpp:33:9:33:13 | call to c_str | string.cpp:27:16:27:21 | call to source | +| string.cpp:39:13:39:17 | call to c_str | string.cpp:14:10:14:15 | call to source | +| string.cpp:43:13:43:17 | call to c_str | string.cpp:14:10:14:15 | call to source | +| string.cpp:46:13:46:17 | call to c_str | string.cpp:14:10:14:15 | call to source | +| string.cpp:56:7:56:8 | cs | string.cpp:51:19:51:24 | call to source | +| string.cpp:57:7:57:8 | ss | string.cpp:51:19:51:24 | call to source | +| string.cpp:70:7:70:8 | cs | string.cpp:62:19:62:24 | call to source | +| string.cpp:71:7:71:8 | ss | string.cpp:62:19:62:24 | call to source | +| string.cpp:93:8:93:9 | s1 | string.cpp:88:18:88:23 | call to source | +| string.cpp:94:8:94:9 | s2 | string.cpp:89:20:89:25 | call to source | +| string.cpp:95:8:95:9 | s3 | string.cpp:91:8:91:13 | call to source | +| string.cpp:114:8:114:9 | s1 | string.cpp:110:32:110:37 | call to source | +| string.cpp:115:8:115:9 | s2 | string.cpp:112:20:112:25 | call to source | +| string.cpp:122:8:122:8 | c | string.cpp:120:16:120:21 | call to source | +| string.cpp:126:8:126:8 | call to operator* | string.cpp:120:16:120:21 | call to source | +| string.cpp:130:8:130:8 | c | string.cpp:120:16:120:21 | call to source | +| string.cpp:135:8:135:8 | c | string.cpp:133:28:133:33 | call to source | +| string.cpp:145:11:145:11 | call to operator+ | string.cpp:142:18:142:23 | call to source | +| string.cpp:146:11:146:11 | call to operator+ | string.cpp:142:18:142:23 | call to source | +| string.cpp:147:11:147:11 | call to operator+ | string.cpp:142:18:142:23 | call to source | +| string.cpp:150:11:150:11 | call to operator+ | string.cpp:150:13:150:18 | call to source | +| string.cpp:159:8:159:9 | s5 | string.cpp:155:18:155:23 | call to source | +| string.cpp:162:11:162:11 | call to operator+= | string.cpp:155:18:155:23 | call to source | +| string.cpp:163:8:163:9 | s6 | string.cpp:155:18:155:23 | call to source | +| string.cpp:166:11:166:11 | call to operator+= | string.cpp:166:14:166:19 | call to source | +| string.cpp:167:11:167:11 | call to operator+= | string.cpp:166:14:166:19 | call to source | +| string.cpp:168:8:168:9 | s7 | string.cpp:166:14:166:19 | call to source | +| string.cpp:172:8:172:9 | s8 | string.cpp:155:18:155:23 | call to source | +| string.cpp:177:8:177:9 | s9 | string.cpp:175:13:175:18 | call to source | +| string.cpp:185:8:185:10 | s10 | string.cpp:182:12:182:26 | call to source | +| string.cpp:199:10:199:15 | call to assign | string.cpp:191:17:191:22 | call to source | +| string.cpp:200:7:200:8 | s4 | string.cpp:191:17:191:22 | call to source | +| string.cpp:202:10:202:15 | call to assign | string.cpp:192:11:192:25 | call to source | +| string.cpp:203:7:203:8 | s5 | string.cpp:192:11:192:25 | call to source | +| string.cpp:206:7:206:8 | s6 | string.cpp:194:17:194:22 | call to source | +| string.cpp:220:10:220:15 | call to insert | string.cpp:211:17:211:22 | call to source | +| string.cpp:221:7:221:8 | s4 | string.cpp:211:17:211:22 | call to source | +| string.cpp:224:10:224:15 | call to insert | string.cpp:211:17:211:22 | call to source | +| string.cpp:225:7:225:8 | s5 | string.cpp:211:17:211:22 | call to source | +| string.cpp:228:10:228:15 | call to insert | string.cpp:212:11:212:25 | call to source | +| string.cpp:229:7:229:8 | s6 | string.cpp:212:11:212:25 | call to source | +| string.cpp:243:10:243:16 | call to replace | string.cpp:234:17:234:22 | call to source | +| string.cpp:244:7:244:8 | s4 | string.cpp:234:17:234:22 | call to source | +| string.cpp:247:10:247:16 | call to replace | string.cpp:234:17:234:22 | call to source | +| string.cpp:248:7:248:8 | s5 | string.cpp:234:17:234:22 | call to source | +| string.cpp:251:10:251:16 | call to replace | string.cpp:235:11:235:25 | call to source | +| string.cpp:252:7:252:8 | s6 | string.cpp:235:11:235:25 | call to source | +| string.cpp:265:7:265:8 | b2 | string.cpp:259:17:259:22 | call to source | +| string.cpp:275:7:275:8 | s2 | string.cpp:270:17:270:22 | call to source | +| string.cpp:277:7:277:8 | s4 | string.cpp:272:17:272:22 | call to source | +| string.cpp:282:7:282:8 | s1 | string.cpp:270:17:270:22 | call to source | +| string.cpp:283:7:283:8 | s2 | string.cpp:270:17:270:22 | call to source | +| string.cpp:284:7:284:8 | s3 | string.cpp:272:17:272:22 | call to source | +| string.cpp:285:7:285:8 | s4 | string.cpp:272:17:272:22 | call to source | +| string.cpp:293:7:293:8 | s1 | string.cpp:289:17:289:22 | call to source | +| string.cpp:294:7:294:8 | s2 | string.cpp:290:17:290:22 | call to source | +| string.cpp:295:7:295:8 | s3 | string.cpp:291:17:291:22 | call to source | +| string.cpp:301:7:301:8 | s1 | string.cpp:289:17:289:22 | call to source | +| string.cpp:303:7:303:8 | s3 | string.cpp:291:17:291:22 | call to source | +| string.cpp:312:9:312:12 | call to data | string.cpp:309:16:309:21 | call to source | +| string.cpp:323:9:323:14 | call to substr | string.cpp:320:16:320:21 | call to source | +| string.cpp:340:7:340:7 | a | string.cpp:336:9:336:23 | call to source | +| string.cpp:341:7:341:7 | b | string.cpp:337:12:337:26 | call to source | +| string.cpp:342:7:342:7 | c | string.cpp:336:9:336:23 | call to source | +| string.cpp:350:7:350:9 | str | string.cpp:349:18:349:32 | call to source | +| string.cpp:351:11:351:14 | call to data | string.cpp:349:18:349:32 | call to source | +| string.cpp:363:11:363:16 | call to append | string.cpp:358:18:358:23 | call to source | +| string.cpp:364:8:364:9 | s1 | string.cpp:358:18:358:23 | call to source | +| string.cpp:382:8:382:8 | call to operator* | string.cpp:374:18:374:23 | call to source | +| string.cpp:383:13:383:13 | call to operator[] | string.cpp:374:18:374:23 | call to source | +| string.cpp:396:8:396:8 | call to operator* | string.cpp:389:18:389:23 | call to source | +| string.cpp:397:8:397:8 | call to operator* | string.cpp:389:18:389:23 | call to source | +| string.cpp:399:8:399:8 | call to operator* | string.cpp:389:18:389:23 | call to source | +| string.cpp:401:8:401:8 | call to operator* | string.cpp:389:18:389:23 | call to source | +| string.cpp:404:8:404:8 | call to operator* | string.cpp:389:18:389:23 | call to source | +| string.cpp:407:8:407:8 | call to operator* | string.cpp:389:18:389:23 | call to source | +| string.cpp:409:8:409:8 | call to operator* | string.cpp:389:18:389:23 | call to source | +| string.cpp:411:8:411:8 | call to operator* | string.cpp:389:18:389:23 | call to source | +| string.cpp:415:8:415:8 | call to operator* | string.cpp:389:18:389:23 | call to source | +| string.cpp:418:8:418:8 | call to operator* | string.cpp:389:18:389:23 | call to source | +| string.cpp:419:8:419:10 | call to iterator | string.cpp:389:18:389:23 | call to source | +| string.cpp:421:8:421:8 | call to operator* | string.cpp:389:18:389:23 | call to source | +| string.cpp:422:8:422:10 | call to iterator | string.cpp:389:18:389:23 | call to source | +| string.cpp:436:10:436:15 | call to insert | string.cpp:431:14:431:19 | call to source | +| string.cpp:437:7:437:8 | s2 | string.cpp:431:14:431:19 | call to source | +| string.cpp:449:10:449:15 | call to insert | string.cpp:449:32:449:46 | call to source | +| string.cpp:450:8:450:8 | b | string.cpp:449:32:449:46 | call to source | +| string.cpp:462:10:462:15 | call to insert | string.cpp:457:18:457:23 | call to source | +| string.cpp:463:8:463:8 | d | string.cpp:457:18:457:23 | call to source | +| string.cpp:465:11:465:16 | call to insert | string.cpp:457:18:457:23 | call to source | +| string.cpp:466:8:466:9 | s2 | string.cpp:457:18:457:23 | call to source | +| string.cpp:478:10:478:15 | call to append | string.cpp:473:18:473:23 | call to source | +| string.cpp:479:8:479:8 | f | string.cpp:473:18:473:23 | call to source | +| string.cpp:481:11:481:16 | call to append | string.cpp:473:18:473:23 | call to source | +| string.cpp:482:8:482:9 | s4 | string.cpp:473:18:473:23 | call to source | +| string.cpp:494:10:494:15 | call to assign | string.cpp:489:18:489:23 | call to source | +| string.cpp:495:8:495:8 | h | string.cpp:489:18:489:23 | call to source | +| string.cpp:498:8:498:9 | s6 | string.cpp:489:18:489:23 | call to source | +| string.cpp:511:7:511:8 | s2 | string.cpp:504:14:504:19 | call to source | +| string.cpp:513:7:513:8 | s4 | string.cpp:504:14:504:19 | call to source | +| string.cpp:522:9:522:13 | call to front | string.cpp:521:14:521:28 | call to source | +| string.cpp:523:9:523:12 | call to back | string.cpp:521:14:521:28 | call to source | +| string.cpp:536:11:536:11 | call to operator+= | string.cpp:536:20:536:25 | call to source | +| string.cpp:537:21:537:21 | call to operator+= | string.cpp:537:24:537:29 | call to source | +| string.cpp:538:25:538:25 | call to operator+= | string.cpp:538:15:538:20 | call to source | +| string.cpp:541:8:541:8 | c | string.cpp:536:20:536:25 | call to source | +| string.cpp:542:8:542:8 | d | string.cpp:536:20:536:25 | call to source | +| string.cpp:543:8:543:8 | e | string.cpp:537:24:537:29 | call to source | +| string.cpp:544:8:544:8 | f | string.cpp:538:15:538:20 | call to source | +| string.cpp:556:11:556:16 | call to assign | string.cpp:556:27:556:32 | call to source | +| string.cpp:557:24:557:29 | call to assign | string.cpp:557:31:557:36 | call to source | +| string.cpp:561:8:561:8 | c | string.cpp:556:27:556:32 | call to source | +| string.cpp:562:8:562:8 | d | string.cpp:556:27:556:32 | call to source | +| string.cpp:563:8:563:8 | e | string.cpp:557:31:557:36 | call to source | +| string.cpp:564:8:564:8 | f | string.cpp:558:18:558:23 | call to source | +| stringstream.cpp:32:11:32:11 | call to operator<< | stringstream.cpp:32:14:32:19 | call to source | +| stringstream.cpp:33:20:33:20 | call to operator<< | stringstream.cpp:33:23:33:28 | call to source | +| stringstream.cpp:34:23:34:23 | call to operator<< | stringstream.cpp:34:14:34:19 | call to source | +| stringstream.cpp:35:11:35:11 | call to operator<< | stringstream.cpp:29:16:29:21 | call to source | +| stringstream.cpp:38:7:38:9 | ss2 | stringstream.cpp:32:14:32:19 | call to source | +| stringstream.cpp:39:7:39:9 | ss3 | stringstream.cpp:33:23:33:28 | call to source | +| stringstream.cpp:40:7:40:9 | ss4 | stringstream.cpp:34:14:34:19 | call to source | +| stringstream.cpp:41:7:41:9 | ss5 | stringstream.cpp:29:16:29:21 | call to source | +| stringstream.cpp:43:11:43:13 | call to str | stringstream.cpp:32:14:32:19 | call to source | +| stringstream.cpp:44:11:44:13 | call to str | stringstream.cpp:33:23:33:28 | call to source | +| stringstream.cpp:45:11:45:13 | call to str | stringstream.cpp:34:14:34:19 | call to source | +| stringstream.cpp:46:11:46:13 | call to str | stringstream.cpp:29:16:29:21 | call to source | +| stringstream.cpp:52:7:52:9 | ss6 | stringstream.cpp:49:10:49:15 | call to source | +| stringstream.cpp:53:7:53:9 | ss7 | stringstream.cpp:50:10:50:15 | call to source | +| stringstream.cpp:56:11:56:13 | call to put | stringstream.cpp:56:15:56:29 | call to source | +| stringstream.cpp:57:44:57:46 | call to put | stringstream.cpp:57:25:57:39 | call to source | +| stringstream.cpp:59:7:59:9 | ss9 | stringstream.cpp:56:15:56:29 | call to source | +| stringstream.cpp:60:7:60:10 | ss10 | stringstream.cpp:57:25:57:39 | call to source | +| stringstream.cpp:63:12:63:16 | call to write | stringstream.cpp:63:18:63:23 | call to source | +| stringstream.cpp:64:54:64:58 | call to write | stringstream.cpp:64:36:64:41 | call to source | +| stringstream.cpp:66:7:66:10 | ss12 | stringstream.cpp:63:18:63:23 | call to source | +| stringstream.cpp:67:7:67:10 | ss13 | stringstream.cpp:64:36:64:41 | call to source | +| stringstream.cpp:76:11:76:11 | call to operator<< | stringstream.cpp:70:32:70:37 | source | +| stringstream.cpp:78:11:78:11 | call to operator>> | stringstream.cpp:70:32:70:37 | source | +| stringstream.cpp:81:7:81:9 | ss2 | stringstream.cpp:70:32:70:37 | source | +| stringstream.cpp:83:11:83:13 | call to str | stringstream.cpp:70:32:70:37 | source | +| stringstream.cpp:85:7:85:8 | v2 | stringstream.cpp:70:32:70:37 | source | +| stringstream.cpp:100:11:100:11 | call to operator= | stringstream.cpp:100:31:100:36 | call to source | +| stringstream.cpp:103:7:103:9 | ss2 | stringstream.cpp:91:19:91:24 | call to source | +| stringstream.cpp:105:7:105:9 | ss4 | stringstream.cpp:95:44:95:49 | call to source | +| stringstream.cpp:107:7:107:9 | ss6 | stringstream.cpp:100:31:100:36 | call to source | +| stringstream.cpp:120:7:120:9 | ss1 | stringstream.cpp:113:24:113:29 | call to source | +| stringstream.cpp:121:7:121:9 | ss2 | stringstream.cpp:113:24:113:29 | call to source | +| stringstream.cpp:122:7:122:9 | ss3 | stringstream.cpp:115:24:115:29 | call to source | +| stringstream.cpp:123:7:123:9 | ss4 | stringstream.cpp:115:24:115:29 | call to source | +| stringstream.cpp:143:11:143:11 | call to operator<< | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:146:11:146:11 | call to operator>> | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:147:17:147:17 | call to operator>> | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:149:7:149:8 | s2 | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:150:7:150:8 | s3 | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:151:7:151:8 | s4 | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:154:11:154:11 | call to operator>> | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:155:17:155:17 | call to operator>> | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:157:7:157:8 | call to basic_string | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:158:7:158:8 | call to basic_string | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:159:7:159:8 | call to basic_string | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:162:11:162:14 | call to read | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:166:11:166:13 | call to get | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:168:7:168:8 | call to basic_string | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:170:7:170:8 | call to basic_string | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:172:7:172:9 | call to basic_string | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:175:7:175:20 | ... = ... | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:177:7:177:21 | ... = ... | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:179:11:179:13 | call to get | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:181:7:181:8 | c2 | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:183:7:183:8 | c4 | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:185:7:185:8 | c6 | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:196:10:196:16 | call to putback | stringstream.cpp:196:18:196:32 | call to source | +| stringstream.cpp:197:10:197:12 | call to get | stringstream.cpp:196:18:196:32 | call to source | +| stringstream.cpp:215:11:215:17 | call to getline | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:216:11:216:17 | call to getline | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:219:7:219:8 | call to basic_string | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:220:7:220:8 | call to basic_string | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:223:11:223:17 | call to getline | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:224:11:224:17 | call to getline | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:227:7:227:8 | call to basic_string | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:228:7:228:8 | call to basic_string | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:230:29:230:35 | call to getline | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:231:7:231:8 | call to basic_string | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:232:7:232:8 | call to basic_string | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:235:7:235:13 | call to getline | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:236:7:236:13 | call to getline | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:239:7:239:8 | s2 | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:240:7:240:8 | s3 | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:243:7:243:13 | call to getline | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:244:7:244:13 | call to getline | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:247:7:247:8 | s5 | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:248:7:248:8 | s6 | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:250:7:250:13 | call to getline | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:251:7:251:8 | s7 | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:252:7:252:8 | s8 | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:262:32:262:34 | call to get | stringstream.cpp:257:24:257:29 | call to source | +| stringstream.cpp:263:7:263:8 | call to basic_string | stringstream.cpp:257:24:257:29 | call to source | +| stringstream.cpp:264:7:264:8 | call to basic_string | stringstream.cpp:257:24:257:29 | call to source | +| stringstream.cpp:266:62:266:66 | call to write | stringstream.cpp:266:41:266:46 | call to source | +| stringstream.cpp:267:7:267:9 | ss2 | stringstream.cpp:266:41:266:46 | call to source | +| structlikeclass.cpp:35:8:35:9 | s1 | structlikeclass.cpp:29:22:29:27 | call to source | +| structlikeclass.cpp:36:8:36:9 | s2 | structlikeclass.cpp:30:24:30:29 | call to source | +| structlikeclass.cpp:37:8:37:9 | s3 | structlikeclass.cpp:29:22:29:27 | call to source | +| structlikeclass.cpp:38:8:38:9 | s4 | structlikeclass.cpp:33:8:33:13 | call to source | +| structlikeclass.cpp:60:8:60:9 | s1 | structlikeclass.cpp:55:40:55:45 | call to source | +| structlikeclass.cpp:61:8:61:9 | s2 | structlikeclass.cpp:58:24:58:29 | call to source | +| structlikeclass.cpp:62:8:62:20 | ... = ... | structlikeclass.cpp:62:13:62:18 | call to source | +| swap1.cpp:73:12:73:16 | data1 | swap1.cpp:71:15:71:20 | call to source | +| swap1.cpp:78:12:78:16 | data1 | swap1.cpp:69:23:69:23 | x | +| swap1.cpp:78:12:78:16 | data1 | swap1.cpp:71:15:71:20 | call to source | +| swap1.cpp:79:12:79:16 | data1 | swap1.cpp:71:15:71:20 | call to source | +| swap1.cpp:83:13:83:17 | data1 | swap1.cpp:82:16:82:21 | call to source | +| swap1.cpp:87:13:87:17 | data1 | swap1.cpp:82:16:82:21 | call to source | +| swap1.cpp:88:13:88:17 | data1 | swap1.cpp:81:27:81:28 | z2 | +| swap1.cpp:88:13:88:17 | data1 | swap1.cpp:82:16:82:21 | call to source | +| swap1.cpp:97:12:97:16 | data1 | swap1.cpp:95:15:95:20 | call to source | +| swap1.cpp:102:12:102:16 | data1 | swap1.cpp:93:23:93:23 | x | +| swap1.cpp:102:12:102:16 | data1 | swap1.cpp:95:15:95:20 | call to source | +| swap1.cpp:103:12:103:16 | data1 | swap1.cpp:95:15:95:20 | call to source | +| swap1.cpp:111:20:111:24 | data1 | swap1.cpp:109:23:109:28 | call to source | +| swap1.cpp:115:18:115:22 | data1 | swap1.cpp:108:23:108:31 | move_from | +| swap1.cpp:115:18:115:22 | data1 | swap1.cpp:109:23:109:28 | call to source | +| swap1.cpp:124:12:124:16 | data1 | swap1.cpp:122:15:122:20 | call to source | +| swap1.cpp:129:12:129:16 | data1 | swap1.cpp:120:23:120:23 | x | +| swap1.cpp:129:12:129:16 | data1 | swap1.cpp:122:15:122:20 | call to source | +| swap1.cpp:130:12:130:16 | data1 | swap1.cpp:122:15:122:20 | call to source | +| swap1.cpp:139:12:139:16 | data1 | swap1.cpp:137:15:137:20 | call to source | +| swap1.cpp:144:12:144:16 | data1 | swap1.cpp:135:23:135:23 | x | +| swap1.cpp:144:12:144:16 | data1 | swap1.cpp:137:15:137:20 | call to source | +| swap1.cpp:145:12:145:16 | data1 | swap1.cpp:137:15:137:20 | call to source | +| swap2.cpp:73:12:73:16 | data1 | swap2.cpp:71:15:71:20 | call to source | +| swap2.cpp:78:12:78:16 | data1 | swap2.cpp:69:23:69:23 | x | +| swap2.cpp:78:12:78:16 | data1 | swap2.cpp:71:15:71:20 | call to source | +| swap2.cpp:79:12:79:16 | data1 | swap2.cpp:71:15:71:20 | call to source | +| swap2.cpp:83:13:83:17 | data1 | swap2.cpp:82:16:82:21 | call to source | +| swap2.cpp:88:13:88:17 | data1 | swap2.cpp:81:27:81:28 | z2 | +| swap2.cpp:88:13:88:17 | data1 | swap2.cpp:82:16:82:21 | call to source | +| swap2.cpp:97:12:97:16 | data1 | swap2.cpp:95:15:95:20 | call to source | +| swap2.cpp:102:12:102:16 | data1 | swap2.cpp:93:23:93:23 | x | +| swap2.cpp:102:12:102:16 | data1 | swap2.cpp:95:15:95:20 | call to source | +| swap2.cpp:103:12:103:16 | data1 | swap2.cpp:95:15:95:20 | call to source | +| swap2.cpp:111:20:111:24 | data1 | swap2.cpp:109:23:109:28 | call to source | +| swap2.cpp:115:18:115:22 | data1 | swap2.cpp:108:23:108:31 | move_from | +| swap2.cpp:115:18:115:22 | data1 | swap2.cpp:109:23:109:28 | call to source | +| swap2.cpp:124:12:124:16 | data1 | swap2.cpp:122:15:122:20 | call to source | +| swap2.cpp:129:12:129:16 | data1 | swap2.cpp:120:23:120:23 | x | +| swap2.cpp:129:12:129:16 | data1 | swap2.cpp:122:15:122:20 | call to source | +| swap2.cpp:130:12:130:16 | data1 | swap2.cpp:122:15:122:20 | call to source | +| swap2.cpp:139:12:139:16 | data1 | swap2.cpp:137:15:137:20 | call to source | +| swap2.cpp:144:12:144:16 | data1 | swap2.cpp:135:23:135:23 | x | +| swap2.cpp:144:12:144:16 | data1 | swap2.cpp:137:15:137:20 | call to source | +| swap2.cpp:145:12:145:16 | data1 | swap2.cpp:137:15:137:20 | call to source | | taint.cpp:8:8:8:13 | clean1 | taint.cpp:4:27:4:33 | source1 | | taint.cpp:16:8:16:14 | source1 | taint.cpp:12:22:12:27 | call to source | | taint.cpp:17:8:17:16 | ++ ... | taint.cpp:12:22:12:27 | call to source | @@ -27,7 +524,12 @@ | taint.cpp:91:11:91:11 | d | taint.cpp:77:7:77:12 | call to source | | taint.cpp:93:11:93:11 | b | taint.cpp:71:22:71:27 | call to source | | taint.cpp:94:11:94:11 | c | taint.cpp:72:7:72:12 | call to source | +| taint.cpp:109:7:109:13 | access to array | taint.cpp:105:12:105:17 | call to source | +| taint.cpp:110:7:110:13 | access to array | taint.cpp:105:12:105:17 | call to source | +| taint.cpp:111:7:111:13 | access to array | taint.cpp:106:12:106:17 | call to source | +| taint.cpp:112:7:112:13 | access to array | taint.cpp:106:12:106:17 | call to source | | taint.cpp:129:7:129:9 | * ... | taint.cpp:120:11:120:16 | call to source | +| taint.cpp:130:7:130:9 | * ... | taint.cpp:127:8:127:13 | call to source | | taint.cpp:134:7:134:9 | * ... | taint.cpp:120:11:120:16 | call to source | | taint.cpp:137:7:137:9 | * ... | taint.cpp:120:11:120:16 | call to source | | taint.cpp:151:7:151:12 | call to select | taint.cpp:151:20:151:25 | call to source | @@ -55,6 +557,8 @@ | taint.cpp:350:7:350:7 | t | taint.cpp:330:6:330:11 | call to source | | taint.cpp:351:7:351:7 | a | taint.cpp:330:6:330:11 | call to source | | taint.cpp:352:7:352:7 | b | taint.cpp:330:6:330:11 | call to source | +| taint.cpp:353:7:353:7 | c | taint.cpp:330:6:330:11 | call to source | +| taint.cpp:354:7:354:7 | d | taint.cpp:330:6:330:11 | call to source | | taint.cpp:372:7:372:7 | a | taint.cpp:365:24:365:29 | source | | taint.cpp:374:7:374:7 | c | taint.cpp:365:24:365:29 | source | | taint.cpp:382:7:382:7 | a | taint.cpp:377:23:377:28 | source | @@ -70,3 +574,82 @@ | taint.cpp:470:7:470:7 | x | taint.cpp:462:6:462:11 | call to source | | taint.cpp:471:7:471:7 | y | taint.cpp:462:6:462:11 | call to source | | taint.cpp:485:7:485:10 | line | taint.cpp:480:26:480:32 | source1 | +| vector.cpp:20:8:20:8 | x | vector.cpp:16:43:16:49 | source1 | +| vector.cpp:24:8:24:8 | call to operator* | vector.cpp:16:43:16:49 | source1 | +| vector.cpp:28:8:28:8 | x | vector.cpp:16:43:16:49 | source1 | +| vector.cpp:33:8:33:8 | x | vector.cpp:16:43:16:49 | source1 | +| vector.cpp:52:7:52:8 | v2 | vector.cpp:51:10:51:15 | call to source | +| vector.cpp:53:9:53:9 | call to operator[] | vector.cpp:51:10:51:15 | call to source | +| vector.cpp:54:9:54:9 | call to operator[] | vector.cpp:51:10:51:15 | call to source | +| vector.cpp:55:9:55:9 | call to operator[] | vector.cpp:51:10:51:15 | call to source | +| vector.cpp:58:7:58:8 | v3 | vector.cpp:51:10:51:15 | call to source | +| vector.cpp:59:9:59:9 | call to operator[] | vector.cpp:51:10:51:15 | call to source | +| vector.cpp:60:9:60:9 | call to operator[] | vector.cpp:51:10:51:15 | call to source | +| vector.cpp:61:9:61:9 | call to operator[] | vector.cpp:51:10:51:15 | call to source | +| vector.cpp:64:7:64:8 | v4 | vector.cpp:63:10:63:15 | call to source | +| vector.cpp:65:9:65:9 | call to operator[] | vector.cpp:63:10:63:15 | call to source | +| vector.cpp:66:9:66:9 | call to operator[] | vector.cpp:63:10:63:15 | call to source | +| vector.cpp:67:9:67:9 | call to operator[] | vector.cpp:63:10:63:15 | call to source | +| vector.cpp:70:7:70:8 | v5 | vector.cpp:69:15:69:20 | call to source | +| vector.cpp:71:10:71:14 | call to front | vector.cpp:69:15:69:20 | call to source | +| vector.cpp:72:10:72:13 | call to back | vector.cpp:69:15:69:20 | call to source | +| vector.cpp:75:7:75:8 | v6 | vector.cpp:74:17:74:22 | call to source | +| vector.cpp:76:7:76:18 | access to array | vector.cpp:74:17:74:22 | call to source | +| vector.cpp:83:7:83:8 | v7 | vector.cpp:81:17:81:22 | call to source | +| vector.cpp:84:10:84:14 | call to front | vector.cpp:81:17:81:22 | call to source | +| vector.cpp:85:10:85:13 | call to back | vector.cpp:81:17:81:22 | call to source | +| vector.cpp:97:7:97:8 | v9 | vector.cpp:96:13:96:18 | call to source | +| vector.cpp:98:10:98:11 | call to at | vector.cpp:96:13:96:18 | call to source | +| vector.cpp:99:10:99:11 | call to at | vector.cpp:96:13:96:18 | call to source | +| vector.cpp:100:10:100:11 | call to at | vector.cpp:96:13:96:18 | call to source | +| vector.cpp:109:7:109:8 | v1 | vector.cpp:106:15:106:20 | call to source | +| vector.cpp:112:7:112:8 | v4 | vector.cpp:107:15:107:20 | call to source | +| vector.cpp:117:7:117:8 | v1 | vector.cpp:106:15:106:20 | call to source | +| vector.cpp:118:7:118:8 | v2 | vector.cpp:106:15:106:20 | call to source | +| vector.cpp:119:7:119:8 | v3 | vector.cpp:107:15:107:20 | call to source | +| vector.cpp:120:7:120:8 | v4 | vector.cpp:107:15:107:20 | call to source | +| vector.cpp:130:7:130:8 | v1 | vector.cpp:126:15:126:20 | call to source | +| vector.cpp:131:7:131:8 | v2 | vector.cpp:127:15:127:20 | call to source | +| vector.cpp:132:7:132:8 | v3 | vector.cpp:128:15:128:20 | call to source | +| vector.cpp:139:7:139:8 | v1 | vector.cpp:126:15:126:20 | call to source | +| vector.cpp:140:7:140:8 | v2 | vector.cpp:127:15:127:20 | call to source | +| vector.cpp:141:7:141:8 | v3 | vector.cpp:128:15:128:20 | call to source | +| vector.cpp:162:8:162:15 | access to array | vector.cpp:161:14:161:19 | call to source | +| vector.cpp:171:13:171:13 | call to operator[] | vector.cpp:170:14:170:19 | call to source | +| vector.cpp:180:13:180:13 | call to operator[] | vector.cpp:179:14:179:19 | call to source | +| vector.cpp:201:13:201:13 | call to operator[] | vector.cpp:200:14:200:19 | call to source | +| vector.cpp:242:7:242:8 | v2 | vector.cpp:238:17:238:30 | call to source | +| vector.cpp:243:7:243:8 | v3 | vector.cpp:239:15:239:20 | call to source | +| vector.cpp:258:8:258:9 | v5 | vector.cpp:239:15:239:20 | call to source | +| vector.cpp:259:8:259:9 | i1 | vector.cpp:239:15:239:20 | call to source | +| vector.cpp:260:8:260:9 | i2 | vector.cpp:239:15:239:20 | call to source | +| vector.cpp:261:8:261:9 | v6 | vector.cpp:239:15:239:20 | call to source | +| vector.cpp:273:8:273:9 | v7 | vector.cpp:269:18:269:31 | call to source | +| vector.cpp:274:8:274:9 | v8 | vector.cpp:270:18:270:35 | call to source | +| vector.cpp:275:8:275:9 | v9 | vector.cpp:271:18:271:34 | call to source | +| vector.cpp:285:7:285:8 | v1 | vector.cpp:284:15:284:20 | call to source | +| vector.cpp:286:10:286:13 | call to data | vector.cpp:284:15:284:20 | call to source | +| vector.cpp:287:7:287:18 | access to array | vector.cpp:284:15:284:20 | call to source | +| vector.cpp:290:7:290:8 | v2 | vector.cpp:289:17:289:30 | call to source | +| vector.cpp:291:10:291:13 | call to data | vector.cpp:289:17:289:30 | call to source | +| vector.cpp:292:7:292:18 | access to array | vector.cpp:289:17:289:30 | call to source | +| vector.cpp:308:9:308:14 | call to insert | vector.cpp:303:14:303:19 | call to source | +| vector.cpp:309:7:309:7 | c | vector.cpp:303:14:303:19 | call to source | +| vector.cpp:311:9:311:14 | call to insert | vector.cpp:303:14:303:19 | call to source | +| vector.cpp:312:7:312:7 | d | vector.cpp:303:14:303:19 | call to source | +| vector.cpp:324:7:324:8 | v2 | vector.cpp:318:15:318:20 | call to source | +| vector.cpp:326:7:326:8 | v4 | vector.cpp:318:15:318:20 | call to source | +| vector.cpp:342:7:342:8 | v1 | vector.cpp:341:8:341:13 | call to source | +| vector.cpp:347:7:347:8 | v2 | vector.cpp:345:9:345:14 | call to source | +| vector.cpp:357:7:357:8 | v4 | vector.cpp:330:10:330:15 | call to source | +| vector.cpp:361:7:361:8 | v5 | vector.cpp:360:8:360:13 | call to source | +| vector.cpp:363:7:363:8 | v5 | vector.cpp:360:8:360:13 | call to source | +| vector.cpp:367:7:367:8 | v6 | vector.cpp:366:8:366:13 | call to source | +| vector.cpp:369:7:369:8 | v6 | vector.cpp:366:8:366:13 | call to source | +| vector.cpp:374:8:374:9 | v7 | vector.cpp:373:9:373:14 | call to source | +| vector.cpp:379:7:379:8 | v7 | vector.cpp:373:9:373:14 | call to source | +| vector.cpp:383:7:383:8 | v8 | vector.cpp:382:8:382:13 | call to source | +| vector.cpp:385:7:385:8 | v8 | vector.cpp:382:8:382:13 | call to source | +| vector.cpp:392:7:392:8 | v9 | vector.cpp:330:10:330:15 | call to source | +| vector.cpp:392:7:392:8 | v9 | vector.cpp:389:8:389:13 | call to source | +| vector.cpp:400:7:400:9 | v11 | vector.cpp:399:38:399:43 | call to source | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected index 0426082e01bf..9da6b44c7808 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected @@ -1,47 +1,381 @@ -| format.cpp:57:8:57:13 | format.cpp:56:36:56:49 | AST only | -| format.cpp:62:8:62:13 | format.cpp:61:30:61:43 | AST only | -| format.cpp:67:8:67:13 | format.cpp:66:52:66:65 | AST only | -| format.cpp:72:8:72:13 | format.cpp:71:42:71:55 | AST only | -| format.cpp:83:8:83:13 | format.cpp:82:36:82:41 | AST only | -| format.cpp:88:8:88:13 | format.cpp:87:38:87:43 | AST only | -| format.cpp:94:8:94:13 | format.cpp:93:36:93:49 | AST only | -| format.cpp:100:8:100:13 | format.cpp:99:30:99:43 | AST only | -| format.cpp:105:8:105:13 | format.cpp:104:31:104:45 | AST only | -| format.cpp:110:8:110:14 | format.cpp:109:38:109:52 | AST only | -| stl.cpp:73:7:73:7 | stl.cpp:69:16:69:21 | AST only | -| stl.cpp:75:9:75:13 | stl.cpp:69:16:69:21 | AST only | -| stl.cpp:125:13:125:17 | stl.cpp:117:10:117:15 | AST only | -| stl.cpp:129:13:129:17 | stl.cpp:117:10:117:15 | AST only | -| stl.cpp:132:13:132:17 | stl.cpp:117:10:117:15 | AST only | +| arrayassignment.cpp:16:7:16:7 | arrayassignment.cpp:14:9:14:14 | IR only | +| arrayassignment.cpp:18:7:18:11 | arrayassignment.cpp:14:9:14:14 | IR only | +| arrayassignment.cpp:19:7:19:9 | arrayassignment.cpp:14:9:14:14 | IR only | +| arrayassignment.cpp:31:7:31:7 | arrayassignment.cpp:29:8:29:13 | IR only | +| arrayassignment.cpp:32:7:32:10 | arrayassignment.cpp:29:8:29:13 | IR only | +| arrayassignment.cpp:34:7:34:10 | arrayassignment.cpp:29:8:29:13 | IR only | +| arrayassignment.cpp:56:7:56:8 | arrayassignment.cpp:54:9:54:14 | IR only | +| arrayassignment.cpp:57:10:57:12 | arrayassignment.cpp:54:9:54:14 | AST only | +| arrayassignment.cpp:57:10:57:15 | arrayassignment.cpp:54:9:54:14 | IR only | +| arrayassignment.cpp:66:7:66:8 | arrayassignment.cpp:64:13:64:18 | IR only | +| arrayassignment.cpp:67:10:67:12 | arrayassignment.cpp:64:13:64:18 | AST only | +| arrayassignment.cpp:67:10:67:15 | arrayassignment.cpp:64:13:64:18 | IR only | +| arrayassignment.cpp:136:7:136:13 | arrayassignment.cpp:134:9:134:14 | IR only | +| arrayassignment.cpp:141:7:141:13 | arrayassignment.cpp:139:10:139:15 | IR only | +| arrayassignment.cpp:146:7:146:13 | arrayassignment.cpp:144:12:144:17 | IR only | +| copyableclass.cpp:67:11:67:11 | copyableclass.cpp:67:13:67:18 | AST only | +| copyableclass.cpp:67:11:67:21 | copyableclass.cpp:67:13:67:18 | IR only | +| copyableclass_declonly.cpp:42:8:42:9 | copyableclass_declonly.cpp:34:30:34:35 | AST only | +| copyableclass_declonly.cpp:67:11:67:11 | copyableclass_declonly.cpp:67:13:67:18 | AST only | +| map.cpp:49:9:49:13 | map.cpp:48:37:48:42 | IR only | +| map.cpp:54:9:54:13 | map.cpp:48:37:48:42 | IR only | +| map.cpp:60:9:60:13 | map.cpp:48:37:48:42 | IR only | +| map.cpp:70:9:70:13 | map.cpp:65:37:65:42 | IR only | +| map.cpp:71:9:71:14 | map.cpp:65:37:65:42 | IR only | +| map.cpp:73:9:73:13 | map.cpp:65:37:65:42 | IR only | +| map.cpp:76:9:76:13 | map.cpp:66:37:66:42 | IR only | +| map.cpp:79:9:79:13 | map.cpp:66:37:66:42 | IR only | +| map.cpp:80:9:80:14 | map.cpp:66:37:66:42 | IR only | +| map.cpp:90:34:90:38 | map.cpp:90:24:90:29 | IR only | +| map.cpp:91:34:91:39 | map.cpp:91:24:91:29 | IR only | +| map.cpp:108:7:108:54 | map.cpp:108:39:108:44 | IR only | +| map.cpp:111:7:111:48 | map.cpp:111:34:111:39 | IR only | +| map.cpp:114:7:114:8 | map.cpp:108:39:108:44 | AST only | +| map.cpp:116:7:116:8 | map.cpp:110:62:110:67 | AST only | +| map.cpp:117:7:117:8 | map.cpp:111:34:111:39 | AST only | +| map.cpp:118:7:118:8 | map.cpp:112:46:112:51 | AST only | +| map.cpp:123:10:123:13 | map.cpp:111:34:111:39 | AST only | +| map.cpp:124:10:124:13 | map.cpp:112:46:112:51 | AST only | +| map.cpp:129:10:129:13 | map.cpp:111:34:111:39 | AST only | +| map.cpp:130:10:130:13 | map.cpp:112:46:112:51 | AST only | +| map.cpp:137:7:137:8 | map.cpp:108:39:108:44 | AST only | +| map.cpp:138:7:138:8 | map.cpp:108:39:108:44 | AST only | +| map.cpp:139:7:139:8 | map.cpp:108:39:108:44 | AST only | +| map.cpp:140:10:140:13 | map.cpp:108:39:108:44 | AST only | +| map.cpp:141:10:141:13 | map.cpp:108:39:108:44 | AST only | +| map.cpp:155:12:155:16 | map.cpp:108:39:108:44 | IR only | +| map.cpp:156:12:156:17 | map.cpp:108:39:108:44 | IR only | +| map.cpp:161:12:161:16 | map.cpp:108:39:108:44 | IR only | +| map.cpp:162:12:162:17 | map.cpp:108:39:108:44 | IR only | +| map.cpp:172:10:172:10 | map.cpp:168:20:168:25 | AST only | +| map.cpp:174:10:174:10 | map.cpp:170:23:170:28 | AST only | +| map.cpp:184:7:184:31 | map.cpp:108:39:108:44 | IR only | +| map.cpp:185:7:185:32 | map.cpp:108:39:108:44 | IR only | +| map.cpp:187:7:187:32 | map.cpp:108:39:108:44 | IR only | +| map.cpp:193:7:193:9 | map.cpp:191:49:191:54 | AST only | +| map.cpp:196:7:196:9 | map.cpp:192:49:192:54 | AST only | +| map.cpp:199:7:199:9 | map.cpp:191:49:191:54 | AST only | +| map.cpp:200:7:200:9 | map.cpp:191:49:191:54 | AST only | +| map.cpp:201:7:201:9 | map.cpp:192:49:192:54 | AST only | +| map.cpp:202:7:202:9 | map.cpp:192:49:192:54 | AST only | +| map.cpp:210:7:210:9 | map.cpp:206:49:206:54 | AST only | +| map.cpp:213:7:213:9 | map.cpp:209:49:209:54 | AST only | +| map.cpp:216:7:216:9 | map.cpp:206:49:206:54 | AST only | +| map.cpp:218:7:218:9 | map.cpp:209:49:209:54 | AST only | +| map.cpp:219:7:219:9 | map.cpp:209:49:209:54 | AST only | +| map.cpp:225:7:225:9 | map.cpp:223:49:223:54 | AST only | +| map.cpp:225:7:225:9 | map.cpp:224:49:224:54 | AST only | +| map.cpp:227:7:227:9 | map.cpp:223:49:223:54 | AST only | +| map.cpp:227:7:227:9 | map.cpp:224:49:224:54 | AST only | +| map.cpp:229:7:229:9 | map.cpp:223:49:223:54 | AST only | +| map.cpp:229:7:229:9 | map.cpp:224:49:224:54 | AST only | +| map.cpp:235:7:235:40 | map.cpp:235:26:235:31 | IR only | +| map.cpp:236:7:236:9 | map.cpp:235:26:235:31 | AST only | +| map.cpp:240:7:240:9 | map.cpp:239:44:239:49 | AST only | +| map.cpp:246:7:246:44 | map.cpp:246:30:246:35 | IR only | +| map.cpp:247:7:247:9 | map.cpp:246:30:246:35 | AST only | +| map.cpp:251:7:251:9 | map.cpp:250:43:250:48 | AST only | +| map.cpp:260:7:260:54 | map.cpp:260:39:260:44 | IR only | +| map.cpp:263:7:263:48 | map.cpp:263:34:263:39 | IR only | +| map.cpp:266:7:266:8 | map.cpp:260:39:260:44 | AST only | +| map.cpp:268:7:268:8 | map.cpp:262:62:262:67 | AST only | +| map.cpp:269:7:269:8 | map.cpp:263:34:263:39 | AST only | +| map.cpp:270:7:270:8 | map.cpp:264:46:264:51 | AST only | +| map.cpp:275:10:275:13 | map.cpp:263:34:263:39 | AST only | +| map.cpp:276:10:276:13 | map.cpp:264:46:264:51 | AST only | +| map.cpp:281:10:281:13 | map.cpp:263:34:263:39 | AST only | +| map.cpp:282:10:282:13 | map.cpp:264:46:264:51 | AST only | +| map.cpp:289:7:289:8 | map.cpp:260:39:260:44 | AST only | +| map.cpp:290:7:290:8 | map.cpp:260:39:260:44 | AST only | +| map.cpp:291:7:291:8 | map.cpp:260:39:260:44 | AST only | +| map.cpp:292:10:292:13 | map.cpp:260:39:260:44 | AST only | +| map.cpp:293:10:293:13 | map.cpp:260:39:260:44 | AST only | +| map.cpp:307:12:307:16 | map.cpp:260:39:260:44 | IR only | +| map.cpp:308:12:308:17 | map.cpp:260:39:260:44 | IR only | +| map.cpp:313:12:313:16 | map.cpp:260:39:260:44 | IR only | +| map.cpp:314:12:314:17 | map.cpp:260:39:260:44 | IR only | +| map.cpp:324:10:324:10 | map.cpp:320:20:320:25 | AST only | +| map.cpp:326:10:326:10 | map.cpp:322:23:322:28 | AST only | +| map.cpp:334:7:334:31 | map.cpp:260:39:260:44 | IR only | +| map.cpp:335:7:335:32 | map.cpp:260:39:260:44 | IR only | +| map.cpp:336:7:336:32 | map.cpp:260:39:260:44 | IR only | +| map.cpp:342:7:342:9 | map.cpp:340:49:340:54 | AST only | +| map.cpp:345:7:345:9 | map.cpp:341:49:341:54 | AST only | +| map.cpp:348:7:348:9 | map.cpp:340:49:340:54 | AST only | +| map.cpp:349:7:349:9 | map.cpp:340:49:340:54 | AST only | +| map.cpp:350:7:350:9 | map.cpp:341:49:341:54 | AST only | +| map.cpp:351:7:351:9 | map.cpp:341:49:341:54 | AST only | +| map.cpp:359:7:359:9 | map.cpp:355:49:355:54 | AST only | +| map.cpp:362:7:362:9 | map.cpp:358:49:358:54 | AST only | +| map.cpp:365:7:365:9 | map.cpp:355:49:355:54 | AST only | +| map.cpp:367:7:367:9 | map.cpp:358:49:358:54 | AST only | +| map.cpp:368:7:368:9 | map.cpp:358:49:358:54 | AST only | +| map.cpp:374:7:374:9 | map.cpp:372:49:372:54 | AST only | +| map.cpp:374:7:374:9 | map.cpp:373:49:373:54 | AST only | +| map.cpp:376:7:376:9 | map.cpp:372:49:372:54 | AST only | +| map.cpp:376:7:376:9 | map.cpp:373:49:373:54 | AST only | +| map.cpp:378:7:378:9 | map.cpp:372:49:372:54 | AST only | +| map.cpp:378:7:378:9 | map.cpp:373:49:373:54 | AST only | +| map.cpp:384:7:384:40 | map.cpp:384:26:384:31 | IR only | +| map.cpp:385:7:385:9 | map.cpp:384:26:384:31 | AST only | +| map.cpp:389:7:389:9 | map.cpp:388:44:388:49 | AST only | +| map.cpp:396:7:396:44 | map.cpp:396:30:396:35 | IR only | +| map.cpp:397:40:397:45 | map.cpp:397:30:397:35 | IR only | +| map.cpp:398:7:398:9 | map.cpp:396:30:396:35 | AST only | +| map.cpp:398:7:398:9 | map.cpp:397:30:397:35 | AST only | +| map.cpp:402:7:402:9 | map.cpp:401:43:401:48 | AST only | +| map.cpp:417:7:417:9 | map.cpp:416:30:416:35 | AST only | +| map.cpp:418:7:418:16 | map.cpp:416:30:416:35 | AST only | +| map.cpp:420:7:420:9 | map.cpp:419:33:419:38 | AST only | +| map.cpp:421:7:421:16 | map.cpp:419:33:419:38 | AST only | +| map.cpp:431:7:431:67 | map.cpp:431:52:431:57 | IR only | +| map.cpp:432:7:432:9 | map.cpp:431:52:431:57 | AST only | +| movableclass.cpp:65:11:65:11 | movableclass.cpp:65:13:65:18 | AST only | +| movableclass.cpp:65:11:65:21 | movableclass.cpp:65:13:65:18 | IR only | +| set.cpp:20:7:20:31 | set.cpp:20:17:20:22 | IR only | +| set.cpp:26:7:26:8 | set.cpp:20:17:20:22 | AST only | +| set.cpp:28:7:28:8 | set.cpp:22:29:22:34 | AST only | +| set.cpp:30:7:30:8 | set.cpp:20:17:20:22 | AST only | +| set.cpp:44:7:44:8 | set.cpp:20:17:20:22 | AST only | +| set.cpp:45:7:45:8 | set.cpp:20:17:20:22 | AST only | +| set.cpp:46:7:46:8 | set.cpp:20:17:20:22 | AST only | +| set.cpp:47:7:47:9 | set.cpp:20:17:20:22 | AST only | +| set.cpp:48:10:48:13 | set.cpp:20:17:20:22 | AST only | +| set.cpp:49:10:49:13 | set.cpp:20:17:20:22 | AST only | +| set.cpp:61:8:61:11 | set.cpp:20:17:20:22 | IR only | +| set.cpp:71:7:71:32 | set.cpp:67:13:67:18 | IR only | +| set.cpp:72:7:72:33 | set.cpp:67:13:67:18 | IR only | +| set.cpp:78:7:78:9 | set.cpp:76:13:76:18 | AST only | +| set.cpp:81:7:81:9 | set.cpp:77:13:77:18 | AST only | +| set.cpp:84:7:84:9 | set.cpp:76:13:76:18 | AST only | +| set.cpp:85:7:85:9 | set.cpp:76:13:76:18 | AST only | +| set.cpp:86:7:86:9 | set.cpp:77:13:77:18 | AST only | +| set.cpp:87:7:87:9 | set.cpp:77:13:77:18 | AST only | +| set.cpp:95:7:95:9 | set.cpp:91:13:91:18 | AST only | +| set.cpp:98:7:98:9 | set.cpp:94:13:94:18 | AST only | +| set.cpp:101:7:101:9 | set.cpp:91:13:91:18 | AST only | +| set.cpp:103:7:103:9 | set.cpp:94:13:94:18 | AST only | +| set.cpp:104:7:104:9 | set.cpp:94:13:94:18 | AST only | +| set.cpp:110:7:110:9 | set.cpp:108:13:108:18 | AST only | +| set.cpp:110:7:110:9 | set.cpp:109:13:109:18 | AST only | +| set.cpp:112:7:112:9 | set.cpp:108:13:108:18 | AST only | +| set.cpp:112:7:112:9 | set.cpp:109:13:109:18 | AST only | +| set.cpp:114:7:114:9 | set.cpp:108:13:108:18 | AST only | +| set.cpp:114:7:114:9 | set.cpp:109:13:109:18 | AST only | +| set.cpp:120:7:120:33 | set.cpp:120:19:120:24 | IR only | +| set.cpp:121:7:121:9 | set.cpp:120:19:120:24 | AST only | +| set.cpp:125:7:125:9 | set.cpp:124:37:124:42 | AST only | +| set.cpp:134:7:134:31 | set.cpp:134:17:134:22 | IR only | +| set.cpp:140:7:140:8 | set.cpp:134:17:134:22 | AST only | +| set.cpp:142:7:142:8 | set.cpp:136:29:136:34 | AST only | +| set.cpp:144:7:144:8 | set.cpp:134:17:134:22 | AST only | +| set.cpp:158:7:158:8 | set.cpp:134:17:134:22 | AST only | +| set.cpp:159:7:159:8 | set.cpp:134:17:134:22 | AST only | +| set.cpp:160:7:160:8 | set.cpp:134:17:134:22 | AST only | +| set.cpp:161:7:161:9 | set.cpp:134:17:134:22 | AST only | +| set.cpp:162:10:162:13 | set.cpp:134:17:134:22 | AST only | +| set.cpp:163:10:163:13 | set.cpp:134:17:134:22 | AST only | +| set.cpp:175:8:175:11 | set.cpp:134:17:134:22 | IR only | +| set.cpp:183:7:183:32 | set.cpp:181:13:181:18 | IR only | +| set.cpp:184:7:184:33 | set.cpp:181:13:181:18 | IR only | +| set.cpp:190:7:190:9 | set.cpp:188:13:188:18 | AST only | +| set.cpp:193:7:193:9 | set.cpp:189:13:189:18 | AST only | +| set.cpp:196:7:196:9 | set.cpp:188:13:188:18 | AST only | +| set.cpp:197:7:197:9 | set.cpp:188:13:188:18 | AST only | +| set.cpp:198:7:198:9 | set.cpp:189:13:189:18 | AST only | +| set.cpp:199:7:199:9 | set.cpp:189:13:189:18 | AST only | +| set.cpp:207:7:207:9 | set.cpp:203:13:203:18 | AST only | +| set.cpp:210:7:210:9 | set.cpp:206:13:206:18 | AST only | +| set.cpp:213:7:213:9 | set.cpp:203:13:203:18 | AST only | +| set.cpp:215:7:215:9 | set.cpp:206:13:206:18 | AST only | +| set.cpp:216:7:216:9 | set.cpp:206:13:206:18 | AST only | +| set.cpp:222:7:222:9 | set.cpp:220:13:220:18 | AST only | +| set.cpp:222:7:222:9 | set.cpp:221:13:221:18 | AST only | +| set.cpp:224:7:224:9 | set.cpp:220:13:220:18 | AST only | +| set.cpp:224:7:224:9 | set.cpp:221:13:221:18 | AST only | +| set.cpp:226:7:226:9 | set.cpp:220:13:220:18 | AST only | +| set.cpp:226:7:226:9 | set.cpp:221:13:221:18 | AST only | +| set.cpp:232:7:232:33 | set.cpp:232:19:232:24 | IR only | +| set.cpp:233:7:233:9 | set.cpp:232:19:232:24 | AST only | +| set.cpp:237:7:237:9 | set.cpp:236:37:236:42 | AST only | +| smart_pointer.cpp:12:10:12:10 | smart_pointer.cpp:11:52:11:57 | AST only | +| smart_pointer.cpp:24:10:24:10 | smart_pointer.cpp:23:52:23:57 | AST only | +| standalone_iterators.cpp:41:10:41:10 | standalone_iterators.cpp:39:45:39:51 | AST only | +| standalone_iterators.cpp:42:10:42:10 | standalone_iterators.cpp:39:45:39:51 | AST only | +| standalone_iterators.cpp:47:10:47:10 | standalone_iterators.cpp:45:39:45:45 | AST only | +| standalone_iterators.cpp:48:10:48:10 | standalone_iterators.cpp:45:39:45:45 | AST only | +| string.cpp:33:9:33:13 | string.cpp:27:16:27:21 | AST only | +| string.cpp:39:13:39:17 | string.cpp:14:10:14:15 | AST only | +| string.cpp:43:13:43:17 | string.cpp:14:10:14:15 | AST only | +| string.cpp:46:13:46:17 | string.cpp:14:10:14:15 | AST only | +| string.cpp:70:7:70:8 | string.cpp:62:19:62:24 | AST only | +| string.cpp:126:8:126:11 | string.cpp:120:16:120:21 | IR only | +| string.cpp:162:11:162:11 | string.cpp:155:18:155:23 | AST only | +| string.cpp:166:11:166:11 | string.cpp:166:14:166:19 | AST only | +| string.cpp:167:11:167:11 | string.cpp:166:14:166:19 | AST only | +| string.cpp:199:10:199:15 | string.cpp:191:17:191:22 | AST only | +| string.cpp:202:10:202:15 | string.cpp:192:11:192:25 | AST only | +| string.cpp:220:10:220:15 | string.cpp:211:17:211:22 | AST only | +| string.cpp:224:10:224:15 | string.cpp:211:17:211:22 | AST only | +| string.cpp:228:10:228:15 | string.cpp:212:11:212:25 | AST only | +| string.cpp:243:10:243:16 | string.cpp:234:17:234:22 | AST only | +| string.cpp:247:10:247:16 | string.cpp:234:17:234:22 | AST only | +| string.cpp:251:10:251:16 | string.cpp:235:11:235:25 | AST only | +| string.cpp:312:9:312:12 | string.cpp:309:16:309:21 | AST only | +| string.cpp:340:7:340:7 | string.cpp:336:9:336:23 | AST only | +| string.cpp:341:7:341:7 | string.cpp:337:12:337:26 | AST only | +| string.cpp:342:7:342:7 | string.cpp:336:9:336:23 | AST only | +| string.cpp:350:7:350:9 | string.cpp:349:18:349:32 | AST only | +| string.cpp:351:11:351:14 | string.cpp:349:18:349:32 | AST only | +| string.cpp:363:11:363:16 | string.cpp:358:18:358:23 | AST only | +| string.cpp:382:8:382:14 | string.cpp:374:18:374:23 | IR only | +| string.cpp:383:13:383:15 | string.cpp:374:18:374:23 | IR only | +| string.cpp:396:8:396:8 | string.cpp:389:18:389:23 | AST only | +| string.cpp:397:8:397:8 | string.cpp:389:18:389:23 | AST only | +| string.cpp:399:8:399:8 | string.cpp:389:18:389:23 | AST only | +| string.cpp:401:8:401:8 | string.cpp:389:18:389:23 | AST only | +| string.cpp:404:8:404:11 | string.cpp:389:18:389:23 | IR only | +| string.cpp:407:8:407:11 | string.cpp:389:18:389:23 | IR only | +| string.cpp:409:8:409:8 | string.cpp:389:18:389:23 | AST only | +| string.cpp:411:8:411:8 | string.cpp:389:18:389:23 | AST only | +| string.cpp:415:8:415:11 | string.cpp:389:18:389:23 | IR only | +| string.cpp:418:8:418:8 | string.cpp:389:18:389:23 | AST only | +| string.cpp:419:8:419:10 | string.cpp:389:18:389:23 | AST only | +| string.cpp:421:8:421:8 | string.cpp:389:18:389:23 | AST only | +| string.cpp:422:8:422:10 | string.cpp:389:18:389:23 | AST only | +| string.cpp:436:10:436:15 | string.cpp:431:14:431:19 | AST only | +| string.cpp:449:10:449:15 | string.cpp:449:32:449:46 | AST only | +| string.cpp:462:10:462:15 | string.cpp:457:18:457:23 | AST only | +| string.cpp:465:11:465:16 | string.cpp:457:18:457:23 | AST only | +| string.cpp:478:10:478:15 | string.cpp:473:18:473:23 | AST only | +| string.cpp:481:11:481:16 | string.cpp:473:18:473:23 | AST only | +| string.cpp:494:10:494:15 | string.cpp:489:18:489:23 | AST only | +| string.cpp:522:9:522:13 | string.cpp:521:14:521:28 | AST only | +| string.cpp:523:9:523:12 | string.cpp:521:14:521:28 | AST only | +| string.cpp:536:11:536:11 | string.cpp:536:20:536:25 | AST only | +| string.cpp:537:21:537:21 | string.cpp:537:24:537:29 | AST only | +| string.cpp:538:25:538:25 | string.cpp:538:15:538:20 | AST only | +| string.cpp:541:8:541:8 | string.cpp:536:20:536:25 | AST only | +| string.cpp:543:8:543:8 | string.cpp:537:24:537:29 | AST only | +| string.cpp:556:11:556:16 | string.cpp:556:27:556:32 | AST only | +| string.cpp:557:24:557:29 | string.cpp:557:31:557:36 | AST only | +| string.cpp:561:8:561:8 | string.cpp:556:27:556:32 | AST only | +| string.cpp:563:8:563:8 | string.cpp:557:31:557:36 | AST only | +| stringstream.cpp:32:11:32:22 | stringstream.cpp:32:14:32:19 | IR only | +| stringstream.cpp:33:20:33:31 | stringstream.cpp:33:23:33:28 | IR only | +| stringstream.cpp:34:23:34:31 | stringstream.cpp:34:14:34:19 | IR only | +| stringstream.cpp:35:11:35:11 | stringstream.cpp:29:16:29:21 | AST only | +| stringstream.cpp:39:7:39:9 | stringstream.cpp:33:23:33:28 | AST only | +| stringstream.cpp:41:7:41:9 | stringstream.cpp:29:16:29:21 | AST only | +| stringstream.cpp:44:11:44:13 | stringstream.cpp:33:23:33:28 | AST only | +| stringstream.cpp:46:11:46:13 | stringstream.cpp:29:16:29:21 | AST only | +| stringstream.cpp:56:11:56:13 | stringstream.cpp:56:15:56:29 | AST only | +| stringstream.cpp:57:44:57:46 | stringstream.cpp:57:25:57:39 | AST only | +| stringstream.cpp:60:7:60:10 | stringstream.cpp:57:25:57:39 | AST only | +| stringstream.cpp:63:12:63:16 | stringstream.cpp:63:18:63:23 | AST only | +| stringstream.cpp:64:54:64:58 | stringstream.cpp:64:36:64:41 | AST only | +| stringstream.cpp:67:7:67:10 | stringstream.cpp:64:36:64:41 | AST only | +| stringstream.cpp:76:11:76:11 | stringstream.cpp:70:32:70:37 | AST only | +| stringstream.cpp:78:11:78:11 | stringstream.cpp:70:32:70:37 | AST only | +| stringstream.cpp:100:11:100:11 | stringstream.cpp:100:31:100:36 | AST only | +| stringstream.cpp:143:11:143:22 | stringstream.cpp:143:14:143:19 | IR only | +| stringstream.cpp:146:11:146:11 | stringstream.cpp:143:14:143:19 | AST only | +| stringstream.cpp:147:17:147:17 | stringstream.cpp:143:14:143:19 | AST only | +| stringstream.cpp:151:7:151:8 | stringstream.cpp:143:14:143:19 | AST only | +| stringstream.cpp:154:11:154:11 | stringstream.cpp:143:14:143:19 | AST only | +| stringstream.cpp:155:17:155:17 | stringstream.cpp:143:14:143:19 | AST only | +| stringstream.cpp:159:7:159:8 | stringstream.cpp:143:14:143:19 | AST only | +| stringstream.cpp:162:11:162:14 | stringstream.cpp:143:14:143:19 | AST only | +| stringstream.cpp:166:11:166:13 | stringstream.cpp:143:14:143:19 | AST only | +| stringstream.cpp:179:11:179:13 | stringstream.cpp:143:14:143:19 | AST only | +| stringstream.cpp:196:10:196:16 | stringstream.cpp:196:18:196:32 | AST only | +| stringstream.cpp:215:11:215:17 | stringstream.cpp:203:24:203:29 | AST only | +| stringstream.cpp:216:11:216:17 | stringstream.cpp:203:24:203:29 | AST only | +| stringstream.cpp:223:11:223:17 | stringstream.cpp:203:24:203:29 | AST only | +| stringstream.cpp:224:11:224:17 | stringstream.cpp:203:24:203:29 | AST only | +| stringstream.cpp:230:29:230:35 | stringstream.cpp:203:24:203:29 | AST only | +| stringstream.cpp:232:7:232:8 | stringstream.cpp:203:24:203:29 | AST only | +| stringstream.cpp:235:7:235:13 | stringstream.cpp:203:24:203:29 | AST only | +| stringstream.cpp:236:7:236:13 | stringstream.cpp:203:24:203:29 | AST only | +| stringstream.cpp:243:7:243:13 | stringstream.cpp:203:24:203:29 | AST only | +| stringstream.cpp:244:7:244:13 | stringstream.cpp:203:24:203:29 | AST only | +| stringstream.cpp:250:7:250:13 | stringstream.cpp:203:24:203:29 | AST only | +| stringstream.cpp:252:7:252:8 | stringstream.cpp:203:24:203:29 | AST only | +| stringstream.cpp:262:32:262:34 | stringstream.cpp:257:24:257:29 | AST only | +| stringstream.cpp:264:7:264:8 | stringstream.cpp:257:24:257:29 | AST only | +| stringstream.cpp:266:62:266:66 | stringstream.cpp:266:41:266:46 | AST only | +| stringstream.cpp:267:7:267:9 | stringstream.cpp:266:41:266:46 | AST only | +| swap1.cpp:78:12:78:16 | swap1.cpp:69:23:69:23 | AST only | +| swap1.cpp:87:13:87:17 | swap1.cpp:82:16:82:21 | AST only | +| swap1.cpp:88:13:88:17 | swap1.cpp:81:27:81:28 | AST only | +| swap1.cpp:102:12:102:16 | swap1.cpp:93:23:93:23 | AST only | +| swap1.cpp:115:18:115:22 | swap1.cpp:108:23:108:31 | AST only | +| swap1.cpp:129:12:129:16 | swap1.cpp:120:23:120:23 | AST only | +| swap1.cpp:144:12:144:16 | swap1.cpp:135:23:135:23 | AST only | +| swap2.cpp:78:12:78:16 | swap2.cpp:69:23:69:23 | AST only | +| swap2.cpp:88:13:88:17 | swap2.cpp:81:27:81:28 | AST only | +| swap2.cpp:102:12:102:16 | swap2.cpp:93:23:93:23 | AST only | +| swap2.cpp:115:18:115:22 | swap2.cpp:108:23:108:31 | AST only | +| swap2.cpp:129:12:129:16 | swap2.cpp:120:23:120:23 | AST only | +| swap2.cpp:144:12:144:16 | swap2.cpp:135:23:135:23 | AST only | | taint.cpp:41:7:41:13 | taint.cpp:35:12:35:17 | AST only | | taint.cpp:42:7:42:13 | taint.cpp:35:12:35:17 | AST only | | taint.cpp:43:7:43:13 | taint.cpp:37:22:37:27 | AST only | -| taint.cpp:89:11:89:11 | taint.cpp:71:22:71:27 | AST only | -| taint.cpp:90:11:90:11 | taint.cpp:72:7:72:12 | AST only | -| taint.cpp:91:11:91:11 | taint.cpp:77:7:77:12 | AST only | -| taint.cpp:93:11:93:11 | taint.cpp:71:22:71:27 | AST only | -| taint.cpp:94:11:94:11 | taint.cpp:72:7:72:12 | AST only | -| taint.cpp:109:7:109:13 | taint.cpp:105:12:105:17 | IR only | -| taint.cpp:110:7:110:13 | taint.cpp:105:12:105:17 | IR only | -| taint.cpp:111:7:111:13 | taint.cpp:106:12:106:17 | IR only | -| taint.cpp:112:7:112:13 | taint.cpp:106:12:106:17 | IR only | -| taint.cpp:130:7:130:9 | taint.cpp:127:8:127:13 | IR only | | taint.cpp:137:7:137:9 | taint.cpp:120:11:120:16 | AST only | -| taint.cpp:173:8:173:13 | taint.cpp:164:19:164:24 | AST only | | taint.cpp:195:7:195:7 | taint.cpp:192:23:192:28 | AST only | | taint.cpp:195:7:195:7 | taint.cpp:193:6:193:6 | AST only | | taint.cpp:236:3:236:6 | taint.cpp:223:10:223:15 | AST only | -| taint.cpp:261:7:261:7 | taint.cpp:258:7:258:12 | AST only | -| taint.cpp:351:7:351:7 | taint.cpp:330:6:330:11 | AST only | -| taint.cpp:352:7:352:7 | taint.cpp:330:6:330:11 | AST only | | taint.cpp:372:7:372:7 | taint.cpp:365:24:365:29 | AST only | | taint.cpp:374:7:374:7 | taint.cpp:365:24:365:29 | AST only | | taint.cpp:391:7:391:7 | taint.cpp:385:27:385:32 | AST only | -| taint.cpp:423:7:423:7 | taint.cpp:422:14:422:19 | AST only | -| taint.cpp:424:9:424:17 | taint.cpp:422:14:422:19 | AST only | | taint.cpp:429:7:429:7 | taint.cpp:428:13:428:18 | IR only | -| taint.cpp:438:7:438:7 | taint.cpp:437:15:437:20 | AST only | -| taint.cpp:439:10:439:18 | taint.cpp:437:15:437:20 | AST only | -| taint.cpp:446:7:446:7 | taint.cpp:445:14:445:28 | AST only | +| taint.cpp:431:9:431:17 | taint.cpp:428:13:428:18 | IR only | | taint.cpp:447:9:447:17 | taint.cpp:445:14:445:28 | AST only | -| taint.cpp:471:7:471:7 | taint.cpp:462:6:462:11 | AST only | +| vector.cpp:24:8:24:11 | vector.cpp:16:43:16:49 | IR only | +| vector.cpp:52:7:52:8 | vector.cpp:51:10:51:15 | AST only | +| vector.cpp:53:9:53:9 | vector.cpp:51:10:51:15 | AST only | +| vector.cpp:54:9:54:9 | vector.cpp:51:10:51:15 | AST only | +| vector.cpp:55:9:55:9 | vector.cpp:51:10:51:15 | AST only | +| vector.cpp:58:7:58:8 | vector.cpp:51:10:51:15 | AST only | +| vector.cpp:59:9:59:9 | vector.cpp:51:10:51:15 | AST only | +| vector.cpp:60:9:60:9 | vector.cpp:51:10:51:15 | AST only | +| vector.cpp:61:9:61:9 | vector.cpp:51:10:51:15 | AST only | +| vector.cpp:64:7:64:8 | vector.cpp:63:10:63:15 | AST only | +| vector.cpp:65:9:65:9 | vector.cpp:63:10:63:15 | AST only | +| vector.cpp:66:9:66:9 | vector.cpp:63:10:63:15 | AST only | +| vector.cpp:67:9:67:9 | vector.cpp:63:10:63:15 | AST only | +| vector.cpp:71:10:71:14 | vector.cpp:69:15:69:20 | AST only | +| vector.cpp:72:10:72:13 | vector.cpp:69:15:69:20 | AST only | +| vector.cpp:75:7:75:8 | vector.cpp:74:17:74:22 | AST only | +| vector.cpp:76:7:76:18 | vector.cpp:74:17:74:22 | AST only | +| vector.cpp:84:10:84:14 | vector.cpp:81:17:81:22 | AST only | +| vector.cpp:85:10:85:13 | vector.cpp:81:17:81:22 | AST only | +| vector.cpp:97:7:97:8 | vector.cpp:96:13:96:18 | AST only | +| vector.cpp:98:10:98:11 | vector.cpp:96:13:96:18 | AST only | +| vector.cpp:99:10:99:11 | vector.cpp:96:13:96:18 | AST only | +| vector.cpp:100:10:100:11 | vector.cpp:96:13:96:18 | AST only | +| vector.cpp:171:13:171:13 | vector.cpp:170:14:170:19 | AST only | +| vector.cpp:180:13:180:13 | vector.cpp:179:14:179:19 | AST only | +| vector.cpp:201:13:201:13 | vector.cpp:200:14:200:19 | AST only | +| vector.cpp:261:8:261:9 | vector.cpp:239:15:239:20 | AST only | +| vector.cpp:286:10:286:13 | vector.cpp:284:15:284:20 | AST only | +| vector.cpp:287:7:287:18 | vector.cpp:284:15:284:20 | AST only | +| vector.cpp:290:7:290:8 | vector.cpp:289:17:289:30 | AST only | +| vector.cpp:291:10:291:13 | vector.cpp:289:17:289:30 | AST only | +| vector.cpp:292:7:292:18 | vector.cpp:289:17:289:30 | AST only | +| vector.cpp:308:9:308:14 | vector.cpp:303:14:303:19 | AST only | +| vector.cpp:311:9:311:14 | vector.cpp:303:14:303:19 | AST only | +| vector.cpp:342:7:342:8 | vector.cpp:341:8:341:13 | AST only | +| vector.cpp:347:7:347:8 | vector.cpp:345:9:345:14 | AST only | +| vector.cpp:357:7:357:8 | vector.cpp:330:10:330:15 | AST only | +| vector.cpp:361:7:361:8 | vector.cpp:360:8:360:13 | AST only | +| vector.cpp:363:7:363:8 | vector.cpp:360:8:360:13 | AST only | +| vector.cpp:367:7:367:8 | vector.cpp:366:8:366:13 | AST only | +| vector.cpp:369:7:369:8 | vector.cpp:366:8:366:13 | AST only | +| vector.cpp:374:8:374:9 | vector.cpp:373:9:373:14 | AST only | +| vector.cpp:379:7:379:8 | vector.cpp:373:9:373:14 | AST only | +| vector.cpp:383:7:383:8 | vector.cpp:382:8:382:13 | AST only | +| vector.cpp:385:7:385:8 | vector.cpp:382:8:382:13 | AST only | +| vector.cpp:392:7:392:8 | vector.cpp:330:10:330:15 | AST only | +| vector.cpp:392:7:392:8 | vector.cpp:389:8:389:13 | AST only | +| vector.cpp:400:7:400:9 | vector.cpp:399:38:399:43 | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected index bb52de0d7c51..29e6f4f7635b 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected @@ -1,11 +1,348 @@ -| format.cpp:157:7:157:22 | (int)... | format.cpp:147:12:147:25 | call to source | +| arrayassignment.cpp:16:7:16:7 | x | arrayassignment.cpp:14:9:14:14 | call to source | +| arrayassignment.cpp:17:7:17:10 | * ... | arrayassignment.cpp:14:9:14:14 | call to source | +| arrayassignment.cpp:18:7:18:11 | * ... | arrayassignment.cpp:14:9:14:14 | call to source | +| arrayassignment.cpp:19:7:19:9 | (reference dereference) | arrayassignment.cpp:14:9:14:14 | call to source | +| arrayassignment.cpp:31:7:31:7 | x | arrayassignment.cpp:29:8:29:13 | call to source | +| arrayassignment.cpp:32:7:32:10 | * ... | arrayassignment.cpp:29:8:29:13 | call to source | +| arrayassignment.cpp:33:7:33:9 | (reference dereference) | arrayassignment.cpp:29:8:29:13 | call to source | +| arrayassignment.cpp:34:7:34:10 | (reference dereference) | arrayassignment.cpp:29:8:29:13 | call to source | +| arrayassignment.cpp:56:7:56:8 | mi | arrayassignment.cpp:54:9:54:14 | call to source | +| arrayassignment.cpp:57:10:57:15 | (reference dereference) | arrayassignment.cpp:54:9:54:14 | call to source | +| arrayassignment.cpp:66:7:66:8 | mi | arrayassignment.cpp:64:13:64:18 | call to source | +| arrayassignment.cpp:67:10:67:15 | (reference dereference) | arrayassignment.cpp:64:13:64:18 | call to source | +| arrayassignment.cpp:101:7:101:18 | access to array | arrayassignment.cpp:99:17:99:22 | call to source | +| arrayassignment.cpp:135:7:135:10 | (reference dereference) | arrayassignment.cpp:134:9:134:14 | call to source | +| arrayassignment.cpp:136:7:136:13 | access to array | arrayassignment.cpp:134:9:134:14 | call to source | +| arrayassignment.cpp:140:7:140:11 | * ... | arrayassignment.cpp:139:10:139:15 | call to source | +| arrayassignment.cpp:141:7:141:13 | access to array | arrayassignment.cpp:139:10:139:15 | call to source | +| arrayassignment.cpp:145:7:145:13 | access to array | arrayassignment.cpp:144:12:144:17 | call to source | +| arrayassignment.cpp:146:7:146:13 | access to array | arrayassignment.cpp:144:12:144:17 | call to source | +| copyableclass.cpp:40:8:40:9 | s1 | copyableclass.cpp:34:22:34:27 | call to source | +| copyableclass.cpp:41:8:41:9 | s2 | copyableclass.cpp:35:24:35:29 | call to source | +| copyableclass.cpp:42:8:42:9 | s3 | copyableclass.cpp:34:22:34:27 | call to source | +| copyableclass.cpp:43:8:43:9 | s4 | copyableclass.cpp:38:8:38:13 | call to source | +| copyableclass.cpp:65:8:65:9 | s1 | copyableclass.cpp:60:40:60:45 | call to source | +| copyableclass.cpp:66:8:66:9 | s2 | copyableclass.cpp:63:24:63:29 | call to source | +| copyableclass.cpp:67:11:67:21 | (reference dereference) | copyableclass.cpp:67:13:67:18 | call to source | +| copyableclass_declonly.cpp:40:8:40:9 | s1 | copyableclass_declonly.cpp:34:30:34:35 | call to source | +| copyableclass_declonly.cpp:41:8:41:9 | s2 | copyableclass_declonly.cpp:35:32:35:37 | call to source | +| copyableclass_declonly.cpp:43:8:43:9 | s4 | copyableclass_declonly.cpp:38:8:38:13 | call to source | +| copyableclass_declonly.cpp:65:8:65:9 | s1 | copyableclass_declonly.cpp:60:56:60:61 | call to source | +| copyableclass_declonly.cpp:66:8:66:9 | s2 | copyableclass_declonly.cpp:63:32:63:37 | call to source | +| format.cpp:57:8:57:13 | Argument 0 indirection | format.cpp:56:36:56:49 | call to source | +| format.cpp:62:8:62:13 | Argument 0 indirection | format.cpp:61:30:61:43 | call to source | +| format.cpp:67:8:67:13 | Argument 0 indirection | format.cpp:66:52:66:65 | call to source | +| format.cpp:72:8:72:13 | Argument 0 indirection | format.cpp:71:42:71:55 | call to source | +| format.cpp:83:8:83:13 | Argument 0 indirection | format.cpp:82:36:82:41 | call to source | +| format.cpp:88:8:88:13 | Argument 0 indirection | format.cpp:87:38:87:43 | call to source | +| format.cpp:94:8:94:13 | Argument 0 indirection | format.cpp:93:36:93:49 | call to source | +| format.cpp:100:8:100:13 | Argument 0 indirection | format.cpp:99:30:99:43 | call to source | +| format.cpp:105:8:105:13 | Argument 0 indirection | format.cpp:104:31:104:45 | call to source | +| format.cpp:110:8:110:14 | Argument 0 indirection | format.cpp:109:38:109:52 | call to source | +| format.cpp:115:8:115:13 | Argument 0 indirection | format.cpp:114:37:114:50 | call to source | | format.cpp:157:7:157:22 | access to array | format.cpp:147:12:147:25 | call to source | | format.cpp:158:7:158:27 | ... + ... | format.cpp:148:16:148:30 | call to source | -| stl.cpp:71:7:71:7 | (const char *)... | stl.cpp:67:12:67:17 | call to source | -| stl.cpp:71:7:71:7 | a | stl.cpp:67:12:67:17 | call to source | +| map.cpp:29:9:29:13 | first | map.cpp:28:12:28:17 | call to source | +| map.cpp:35:9:35:14 | second | map.cpp:33:13:33:18 | call to source | +| map.cpp:44:9:44:13 | first | map.cpp:43:30:43:35 | call to source | +| map.cpp:49:9:49:13 | first | map.cpp:48:37:48:42 | call to source | +| map.cpp:50:9:50:14 | second | map.cpp:48:37:48:42 | call to source | +| map.cpp:51:7:51:7 | f | map.cpp:48:37:48:42 | call to source | +| map.cpp:54:9:54:13 | first | map.cpp:48:37:48:42 | call to source | +| map.cpp:55:9:55:14 | second | map.cpp:48:37:48:42 | call to source | +| map.cpp:56:7:56:7 | g | map.cpp:48:37:48:42 | call to source | +| map.cpp:60:9:60:13 | first | map.cpp:48:37:48:42 | call to source | +| map.cpp:61:9:61:14 | second | map.cpp:48:37:48:42 | call to source | +| map.cpp:62:7:62:7 | h | map.cpp:48:37:48:42 | call to source | +| map.cpp:70:9:70:13 | first | map.cpp:65:37:65:42 | call to source | +| map.cpp:71:9:71:14 | second | map.cpp:65:37:65:42 | call to source | +| map.cpp:72:7:72:7 | i | map.cpp:65:37:65:42 | call to source | +| map.cpp:73:9:73:13 | first | map.cpp:65:37:65:42 | call to source | +| map.cpp:74:9:74:14 | second | map.cpp:65:37:65:42 | call to source | +| map.cpp:75:7:75:7 | j | map.cpp:65:37:65:42 | call to source | +| map.cpp:76:9:76:13 | first | map.cpp:66:37:66:42 | call to source | +| map.cpp:77:9:77:14 | second | map.cpp:66:37:66:42 | call to source | +| map.cpp:78:7:78:7 | k | map.cpp:66:37:66:42 | call to source | +| map.cpp:79:9:79:13 | first | map.cpp:66:37:66:42 | call to source | +| map.cpp:80:9:80:14 | second | map.cpp:66:37:66:42 | call to source | +| map.cpp:81:7:81:7 | l | map.cpp:66:37:66:42 | call to source | +| map.cpp:89:7:89:32 | call to pair | map.cpp:89:24:89:29 | call to source | +| map.cpp:90:34:90:38 | first | map.cpp:90:24:90:29 | call to source | +| map.cpp:91:34:91:39 | second | map.cpp:91:24:91:29 | call to source | +| map.cpp:108:7:108:54 | call to iterator | map.cpp:108:39:108:44 | call to source | +| map.cpp:110:10:110:15 | call to insert | map.cpp:110:62:110:67 | call to source | +| map.cpp:111:7:111:48 | call to iterator | map.cpp:111:34:111:39 | call to source | +| map.cpp:112:10:112:25 | call to insert_or_assign | map.cpp:112:46:112:51 | call to source | +| map.cpp:120:10:120:13 | call to find | map.cpp:108:39:108:44 | call to source | +| map.cpp:122:10:122:13 | call to find | map.cpp:110:62:110:67 | call to source | +| map.cpp:126:10:126:13 | call to find | map.cpp:108:39:108:44 | call to source | +| map.cpp:128:10:128:13 | call to find | map.cpp:110:62:110:67 | call to source | +| map.cpp:142:10:142:13 | call to find | map.cpp:108:39:108:44 | call to source | +| map.cpp:154:8:154:10 | call to pair | map.cpp:108:39:108:44 | call to source | +| map.cpp:155:12:155:16 | first | map.cpp:108:39:108:44 | call to source | +| map.cpp:156:12:156:17 | second | map.cpp:108:39:108:44 | call to source | +| map.cpp:161:12:161:16 | first | map.cpp:108:39:108:44 | call to source | +| map.cpp:162:12:162:17 | second | map.cpp:108:39:108:44 | call to source | +| map.cpp:168:7:168:27 | ... = ... | map.cpp:168:20:168:25 | call to source | +| map.cpp:170:7:170:30 | ... = ... | map.cpp:170:23:170:28 | call to source | +| map.cpp:182:10:182:20 | call to lower_bound | map.cpp:108:39:108:44 | call to source | +| map.cpp:183:10:183:20 | call to upper_bound | map.cpp:108:39:108:44 | call to source | +| map.cpp:184:7:184:31 | call to iterator | map.cpp:108:39:108:44 | call to source | +| map.cpp:185:7:185:32 | call to iterator | map.cpp:108:39:108:44 | call to source | +| map.cpp:186:10:186:20 | call to upper_bound | map.cpp:108:39:108:44 | call to source | +| map.cpp:187:7:187:32 | call to iterator | map.cpp:108:39:108:44 | call to source | +| map.cpp:226:11:226:15 | call to erase | map.cpp:223:49:223:54 | call to source | +| map.cpp:226:11:226:15 | call to erase | map.cpp:224:49:224:54 | call to source | +| map.cpp:235:7:235:40 | call to iterator | map.cpp:235:26:235:31 | call to source | +| map.cpp:239:11:239:22 | call to emplace_hint | map.cpp:239:44:239:49 | call to source | +| map.cpp:246:7:246:44 | call to iterator | map.cpp:246:30:246:35 | call to source | +| map.cpp:250:11:250:21 | call to try_emplace | map.cpp:250:43:250:48 | call to source | +| map.cpp:260:7:260:54 | call to iterator | map.cpp:260:39:260:44 | call to source | +| map.cpp:262:10:262:15 | call to insert | map.cpp:262:62:262:67 | call to source | +| map.cpp:263:7:263:48 | call to iterator | map.cpp:263:34:263:39 | call to source | +| map.cpp:264:10:264:25 | call to insert_or_assign | map.cpp:264:46:264:51 | call to source | +| map.cpp:272:10:272:13 | call to find | map.cpp:260:39:260:44 | call to source | +| map.cpp:274:10:274:13 | call to find | map.cpp:262:62:262:67 | call to source | +| map.cpp:278:10:278:13 | call to find | map.cpp:260:39:260:44 | call to source | +| map.cpp:280:10:280:13 | call to find | map.cpp:262:62:262:67 | call to source | +| map.cpp:294:10:294:13 | call to find | map.cpp:260:39:260:44 | call to source | +| map.cpp:306:8:306:10 | call to pair | map.cpp:260:39:260:44 | call to source | +| map.cpp:307:12:307:16 | first | map.cpp:260:39:260:44 | call to source | +| map.cpp:308:12:308:17 | second | map.cpp:260:39:260:44 | call to source | +| map.cpp:313:12:313:16 | first | map.cpp:260:39:260:44 | call to source | +| map.cpp:314:12:314:17 | second | map.cpp:260:39:260:44 | call to source | +| map.cpp:320:7:320:27 | ... = ... | map.cpp:320:20:320:25 | call to source | +| map.cpp:322:7:322:30 | ... = ... | map.cpp:322:23:322:28 | call to source | +| map.cpp:334:7:334:31 | call to iterator | map.cpp:260:39:260:44 | call to source | +| map.cpp:335:7:335:32 | call to iterator | map.cpp:260:39:260:44 | call to source | +| map.cpp:336:7:336:32 | call to iterator | map.cpp:260:39:260:44 | call to source | +| map.cpp:375:11:375:15 | call to erase | map.cpp:372:49:372:54 | call to source | +| map.cpp:375:11:375:15 | call to erase | map.cpp:373:49:373:54 | call to source | +| map.cpp:384:7:384:40 | call to iterator | map.cpp:384:26:384:31 | call to source | +| map.cpp:388:11:388:22 | call to emplace_hint | map.cpp:388:44:388:49 | call to source | +| map.cpp:396:7:396:44 | call to iterator | map.cpp:396:30:396:35 | call to source | +| map.cpp:397:40:397:45 | second | map.cpp:397:30:397:35 | call to source | +| map.cpp:401:11:401:21 | call to try_emplace | map.cpp:401:43:401:48 | call to source | +| map.cpp:416:7:416:41 | call to pair | map.cpp:416:30:416:35 | call to source | +| map.cpp:419:7:419:41 | call to pair | map.cpp:419:33:419:38 | call to source | +| map.cpp:431:7:431:67 | call to iterator | map.cpp:431:52:431:57 | call to source | +| map.cpp:433:11:433:22 | call to emplace_hint | map.cpp:431:52:431:57 | call to source | +| movableclass.cpp:44:8:44:9 | s1 | movableclass.cpp:39:21:39:26 | call to source | +| movableclass.cpp:45:8:45:9 | s2 | movableclass.cpp:40:23:40:28 | call to source | +| movableclass.cpp:46:8:46:9 | s3 | movableclass.cpp:42:8:42:13 | call to source | +| movableclass.cpp:54:8:54:9 | s1 | movableclass.cpp:50:38:50:43 | call to source | +| movableclass.cpp:55:8:55:9 | s2 | movableclass.cpp:52:23:52:28 | call to source | +| movableclass.cpp:64:8:64:9 | s2 | movableclass.cpp:23:55:23:60 | call to source | +| movableclass.cpp:65:11:65:21 | (reference dereference) | movableclass.cpp:65:13:65:18 | call to source | +| set.cpp:20:7:20:31 | call to iterator | set.cpp:20:17:20:22 | call to source | +| set.cpp:22:10:22:15 | call to insert | set.cpp:22:29:22:34 | call to source | +| set.cpp:32:10:32:13 | call to find | set.cpp:20:17:20:22 | call to source | +| set.cpp:34:10:34:13 | call to find | set.cpp:22:29:22:34 | call to source | +| set.cpp:36:10:36:13 | call to find | set.cpp:20:17:20:22 | call to source | +| set.cpp:50:10:50:13 | call to find | set.cpp:20:17:20:22 | call to source | +| set.cpp:51:11:51:14 | call to find | set.cpp:20:17:20:22 | call to source | +| set.cpp:61:8:61:8 | call to operator* | set.cpp:20:17:20:22 | call to source | +| set.cpp:61:8:61:11 | (reference dereference) | set.cpp:20:17:20:22 | call to source | +| set.cpp:69:11:69:21 | call to lower_bound | set.cpp:67:13:67:18 | call to source | +| set.cpp:70:11:70:21 | call to upper_bound | set.cpp:67:13:67:18 | call to source | +| set.cpp:71:7:71:32 | call to iterator | set.cpp:67:13:67:18 | call to source | +| set.cpp:72:7:72:33 | call to iterator | set.cpp:67:13:67:18 | call to source | +| set.cpp:111:11:111:15 | call to erase | set.cpp:108:13:108:18 | call to source | +| set.cpp:111:11:111:15 | call to erase | set.cpp:109:13:109:18 | call to source | +| set.cpp:120:7:120:33 | call to iterator | set.cpp:120:19:120:24 | call to source | +| set.cpp:124:11:124:22 | call to emplace_hint | set.cpp:124:37:124:42 | call to source | +| set.cpp:134:7:134:31 | call to iterator | set.cpp:134:17:134:22 | call to source | +| set.cpp:136:10:136:15 | call to insert | set.cpp:136:29:136:34 | call to source | +| set.cpp:146:10:146:13 | call to find | set.cpp:134:17:134:22 | call to source | +| set.cpp:148:10:148:13 | call to find | set.cpp:136:29:136:34 | call to source | +| set.cpp:150:10:150:13 | call to find | set.cpp:134:17:134:22 | call to source | +| set.cpp:164:10:164:13 | call to find | set.cpp:134:17:134:22 | call to source | +| set.cpp:165:11:165:14 | call to find | set.cpp:134:17:134:22 | call to source | +| set.cpp:175:8:175:8 | call to operator* | set.cpp:134:17:134:22 | call to source | +| set.cpp:175:8:175:11 | (reference dereference) | set.cpp:134:17:134:22 | call to source | +| set.cpp:183:7:183:32 | call to iterator | set.cpp:181:13:181:18 | call to source | +| set.cpp:184:7:184:33 | call to iterator | set.cpp:181:13:181:18 | call to source | +| set.cpp:223:11:223:15 | call to erase | set.cpp:220:13:220:18 | call to source | +| set.cpp:223:11:223:15 | call to erase | set.cpp:221:13:221:18 | call to source | +| set.cpp:232:7:232:33 | call to iterator | set.cpp:232:19:232:24 | call to source | +| set.cpp:236:11:236:22 | call to emplace_hint | set.cpp:236:37:236:42 | call to source | +| smart_pointer.cpp:13:10:13:10 | Argument 0 indirection | smart_pointer.cpp:11:52:11:57 | call to source | +| smart_pointer.cpp:25:10:25:10 | Argument 0 indirection | smart_pointer.cpp:23:52:23:57 | call to source | +| smart_pointer.cpp:52:12:52:14 | call to get | smart_pointer.cpp:51:52:51:57 | call to source | +| smart_pointer.cpp:57:12:57:14 | call to get | smart_pointer.cpp:56:52:56:57 | call to source | +| standalone_iterators.cpp:40:10:40:10 | call to operator* | standalone_iterators.cpp:39:45:39:51 | source1 | +| standalone_iterators.cpp:46:10:46:10 | call to operator* | standalone_iterators.cpp:45:39:45:45 | source1 | +| string.cpp:29:7:29:7 | a | string.cpp:25:12:25:17 | call to source | +| string.cpp:31:7:31:7 | Argument 0 indirection | string.cpp:27:16:27:21 | call to source | +| string.cpp:56:7:56:8 | cs | string.cpp:51:19:51:24 | call to source | +| string.cpp:57:7:57:8 | Argument 0 indirection | string.cpp:51:19:51:24 | call to source | +| string.cpp:71:7:71:8 | Argument 0 indirection | string.cpp:62:19:62:24 | call to source | +| string.cpp:93:8:93:9 | Argument 0 indirection | string.cpp:88:18:88:23 | call to source | +| string.cpp:94:8:94:9 | Argument 0 indirection | string.cpp:89:20:89:25 | call to source | +| string.cpp:95:8:95:9 | Argument 0 indirection | string.cpp:91:8:91:13 | call to source | +| string.cpp:114:8:114:9 | Argument 0 indirection | string.cpp:110:32:110:37 | call to source | +| string.cpp:115:8:115:9 | Argument 0 indirection | string.cpp:112:20:112:25 | call to source | +| string.cpp:122:8:122:8 | c | string.cpp:120:16:120:21 | call to source | +| string.cpp:126:8:126:8 | call to operator* | string.cpp:120:16:120:21 | call to source | +| string.cpp:126:8:126:11 | (reference dereference) | string.cpp:120:16:120:21 | call to source | +| string.cpp:130:8:130:8 | (reference dereference) | string.cpp:120:16:120:21 | call to source | +| string.cpp:130:8:130:8 | c | string.cpp:120:16:120:21 | call to source | +| string.cpp:135:8:135:8 | (reference dereference) | string.cpp:133:28:133:33 | call to source | +| string.cpp:135:8:135:8 | c | string.cpp:133:28:133:33 | call to source | +| string.cpp:145:11:145:11 | call to operator+ | string.cpp:142:18:142:23 | call to source | +| string.cpp:146:11:146:11 | call to operator+ | string.cpp:142:18:142:23 | call to source | +| string.cpp:147:11:147:11 | call to operator+ | string.cpp:142:18:142:23 | call to source | +| string.cpp:150:11:150:11 | call to operator+ | string.cpp:150:13:150:18 | call to source | +| string.cpp:159:8:159:9 | Argument 0 indirection | string.cpp:155:18:155:23 | call to source | +| string.cpp:163:8:163:9 | Argument 0 indirection | string.cpp:155:18:155:23 | call to source | +| string.cpp:168:8:168:9 | Argument 0 indirection | string.cpp:166:14:166:19 | call to source | +| string.cpp:172:8:172:9 | Argument 0 indirection | string.cpp:155:18:155:23 | call to source | +| string.cpp:177:8:177:9 | Argument 0 indirection | string.cpp:175:13:175:18 | call to source | +| string.cpp:185:8:185:10 | Argument 0 indirection | string.cpp:182:12:182:26 | call to source | +| string.cpp:200:7:200:8 | Argument 0 indirection | string.cpp:191:17:191:22 | call to source | +| string.cpp:203:7:203:8 | Argument 0 indirection | string.cpp:192:11:192:25 | call to source | +| string.cpp:206:7:206:8 | Argument 0 indirection | string.cpp:194:17:194:22 | call to source | +| string.cpp:221:7:221:8 | Argument 0 indirection | string.cpp:211:17:211:22 | call to source | +| string.cpp:225:7:225:8 | Argument 0 indirection | string.cpp:211:17:211:22 | call to source | +| string.cpp:229:7:229:8 | Argument 0 indirection | string.cpp:212:11:212:25 | call to source | +| string.cpp:244:7:244:8 | Argument 0 indirection | string.cpp:234:17:234:22 | call to source | +| string.cpp:248:7:248:8 | Argument 0 indirection | string.cpp:234:17:234:22 | call to source | +| string.cpp:252:7:252:8 | Argument 0 indirection | string.cpp:235:11:235:25 | call to source | +| string.cpp:265:7:265:8 | Argument 0 indirection | string.cpp:259:17:259:22 | call to source | +| string.cpp:275:7:275:8 | Argument 0 indirection | string.cpp:270:17:270:22 | call to source | +| string.cpp:277:7:277:8 | Argument 0 indirection | string.cpp:272:17:272:22 | call to source | +| string.cpp:282:7:282:8 | Argument 0 indirection | string.cpp:270:17:270:22 | call to source | +| string.cpp:283:7:283:8 | Argument 0 indirection | string.cpp:270:17:270:22 | call to source | +| string.cpp:284:7:284:8 | Argument 0 indirection | string.cpp:272:17:272:22 | call to source | +| string.cpp:285:7:285:8 | Argument 0 indirection | string.cpp:272:17:272:22 | call to source | +| string.cpp:293:7:293:8 | Argument 0 indirection | string.cpp:289:17:289:22 | call to source | +| string.cpp:294:7:294:8 | Argument 0 indirection | string.cpp:290:17:290:22 | call to source | +| string.cpp:295:7:295:8 | Argument 0 indirection | string.cpp:291:17:291:22 | call to source | +| string.cpp:301:7:301:8 | Argument 0 indirection | string.cpp:289:17:289:22 | call to source | +| string.cpp:303:7:303:8 | Argument 0 indirection | string.cpp:291:17:291:22 | call to source | +| string.cpp:323:9:323:14 | call to substr | string.cpp:320:16:320:21 | call to source | +| string.cpp:364:8:364:9 | Argument 0 indirection | string.cpp:358:18:358:23 | call to source | +| string.cpp:382:8:382:8 | call to operator* | string.cpp:374:18:374:23 | call to source | +| string.cpp:382:8:382:14 | (reference dereference) | string.cpp:374:18:374:23 | call to source | +| string.cpp:383:13:383:13 | call to operator[] | string.cpp:374:18:374:23 | call to source | +| string.cpp:383:13:383:15 | (reference dereference) | string.cpp:374:18:374:23 | call to source | +| string.cpp:404:8:404:8 | call to operator* | string.cpp:389:18:389:23 | call to source | +| string.cpp:404:8:404:11 | (reference dereference) | string.cpp:389:18:389:23 | call to source | +| string.cpp:407:8:407:8 | call to operator* | string.cpp:389:18:389:23 | call to source | +| string.cpp:407:8:407:11 | (reference dereference) | string.cpp:389:18:389:23 | call to source | +| string.cpp:415:8:415:8 | call to operator* | string.cpp:389:18:389:23 | call to source | +| string.cpp:415:8:415:11 | (reference dereference) | string.cpp:389:18:389:23 | call to source | +| string.cpp:437:7:437:8 | Argument 0 indirection | string.cpp:431:14:431:19 | call to source | +| string.cpp:450:8:450:8 | Argument 0 indirection | string.cpp:449:32:449:46 | call to source | +| string.cpp:463:8:463:8 | Argument 0 indirection | string.cpp:457:18:457:23 | call to source | +| string.cpp:466:8:466:9 | Argument 0 indirection | string.cpp:457:18:457:23 | call to source | +| string.cpp:479:8:479:8 | Argument 0 indirection | string.cpp:473:18:473:23 | call to source | +| string.cpp:482:8:482:9 | Argument 0 indirection | string.cpp:473:18:473:23 | call to source | +| string.cpp:495:8:495:8 | Argument 0 indirection | string.cpp:489:18:489:23 | call to source | +| string.cpp:498:8:498:9 | Argument 0 indirection | string.cpp:489:18:489:23 | call to source | +| string.cpp:511:7:511:8 | Argument 0 indirection | string.cpp:504:14:504:19 | call to source | +| string.cpp:513:7:513:8 | Argument 0 indirection | string.cpp:504:14:504:19 | call to source | +| string.cpp:542:8:542:8 | Argument 0 indirection | string.cpp:536:20:536:25 | call to source | +| string.cpp:544:8:544:8 | Argument 0 indirection | string.cpp:538:15:538:20 | call to source | +| string.cpp:562:8:562:8 | Argument 0 indirection | string.cpp:556:27:556:32 | call to source | +| string.cpp:564:8:564:8 | Argument 0 indirection | string.cpp:558:18:558:23 | call to source | +| stringstream.cpp:32:11:32:11 | call to operator<< | stringstream.cpp:32:14:32:19 | call to source | +| stringstream.cpp:32:11:32:22 | (reference dereference) | stringstream.cpp:32:14:32:19 | call to source | +| stringstream.cpp:33:20:33:20 | call to operator<< | stringstream.cpp:33:23:33:28 | call to source | +| stringstream.cpp:33:20:33:31 | (reference dereference) | stringstream.cpp:33:23:33:28 | call to source | +| stringstream.cpp:34:23:34:23 | call to operator<< | stringstream.cpp:34:14:34:19 | call to source | +| stringstream.cpp:34:23:34:31 | (reference dereference) | stringstream.cpp:34:14:34:19 | call to source | +| stringstream.cpp:38:7:38:9 | Argument 0 indirection | stringstream.cpp:32:14:32:19 | call to source | +| stringstream.cpp:40:7:40:9 | Argument 0 indirection | stringstream.cpp:34:14:34:19 | call to source | +| stringstream.cpp:43:11:43:13 | call to str | stringstream.cpp:32:14:32:19 | call to source | +| stringstream.cpp:45:11:45:13 | call to str | stringstream.cpp:34:14:34:19 | call to source | +| stringstream.cpp:52:7:52:9 | Argument 0 indirection | stringstream.cpp:49:10:49:15 | call to source | +| stringstream.cpp:53:7:53:9 | Argument 0 indirection | stringstream.cpp:50:10:50:15 | call to source | +| stringstream.cpp:59:7:59:9 | Argument 0 indirection | stringstream.cpp:56:15:56:29 | call to source | +| stringstream.cpp:66:7:66:10 | Argument 0 indirection | stringstream.cpp:63:18:63:23 | call to source | +| stringstream.cpp:81:7:81:9 | Argument 0 indirection | stringstream.cpp:70:32:70:37 | source | +| stringstream.cpp:83:11:83:13 | call to str | stringstream.cpp:70:32:70:37 | source | +| stringstream.cpp:85:7:85:8 | v2 | stringstream.cpp:70:32:70:37 | source | +| stringstream.cpp:103:7:103:9 | Argument 0 indirection | stringstream.cpp:91:19:91:24 | call to source | +| stringstream.cpp:105:7:105:9 | Argument 0 indirection | stringstream.cpp:95:44:95:49 | call to source | +| stringstream.cpp:107:7:107:9 | Argument 0 indirection | stringstream.cpp:100:31:100:36 | call to source | +| stringstream.cpp:120:7:120:9 | Argument 0 indirection | stringstream.cpp:113:24:113:29 | call to source | +| stringstream.cpp:121:7:121:9 | Argument 0 indirection | stringstream.cpp:113:24:113:29 | call to source | +| stringstream.cpp:122:7:122:9 | Argument 0 indirection | stringstream.cpp:115:24:115:29 | call to source | +| stringstream.cpp:123:7:123:9 | Argument 0 indirection | stringstream.cpp:115:24:115:29 | call to source | +| stringstream.cpp:143:11:143:11 | call to operator<< | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:143:11:143:22 | (reference dereference) | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:149:7:149:8 | Argument 0 indirection | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:150:7:150:8 | Argument 0 indirection | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:157:7:157:8 | call to basic_string | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:158:7:158:8 | call to basic_string | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:168:7:168:8 | call to basic_string | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:170:7:170:8 | call to basic_string | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:172:7:172:9 | call to basic_string | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:175:7:175:20 | ... = ... | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:177:7:177:21 | ... = ... | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:181:7:181:8 | c2 | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:183:7:183:8 | c4 | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:185:7:185:8 | c6 | stringstream.cpp:143:14:143:19 | call to source | +| stringstream.cpp:197:10:197:12 | call to get | stringstream.cpp:196:18:196:32 | call to source | +| stringstream.cpp:219:7:219:8 | call to basic_string | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:220:7:220:8 | call to basic_string | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:227:7:227:8 | call to basic_string | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:228:7:228:8 | call to basic_string | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:231:7:231:8 | call to basic_string | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:239:7:239:8 | Argument 0 indirection | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:240:7:240:8 | Argument 0 indirection | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:247:7:247:8 | Argument 0 indirection | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:248:7:248:8 | Argument 0 indirection | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:251:7:251:8 | Argument 0 indirection | stringstream.cpp:203:24:203:29 | call to source | +| stringstream.cpp:263:7:263:8 | call to basic_string | stringstream.cpp:257:24:257:29 | call to source | +| structlikeclass.cpp:35:8:35:9 | s1 | structlikeclass.cpp:29:22:29:27 | call to source | +| structlikeclass.cpp:36:8:36:9 | s2 | structlikeclass.cpp:30:24:30:29 | call to source | +| structlikeclass.cpp:37:8:37:9 | s3 | structlikeclass.cpp:29:22:29:27 | call to source | +| structlikeclass.cpp:38:8:38:9 | s4 | structlikeclass.cpp:33:8:33:13 | call to source | +| structlikeclass.cpp:60:8:60:9 | s1 | structlikeclass.cpp:55:40:55:45 | call to source | +| structlikeclass.cpp:61:8:61:9 | s2 | structlikeclass.cpp:58:24:58:29 | call to source | +| structlikeclass.cpp:62:8:62:20 | ... = ... | structlikeclass.cpp:62:13:62:18 | call to source | +| swap1.cpp:73:12:73:16 | data1 | swap1.cpp:71:15:71:20 | call to source | +| swap1.cpp:78:12:78:16 | data1 | swap1.cpp:71:15:71:20 | call to source | +| swap1.cpp:79:12:79:16 | data1 | swap1.cpp:71:15:71:20 | call to source | +| swap1.cpp:83:13:83:17 | data1 | swap1.cpp:82:16:82:21 | call to source | +| swap1.cpp:88:13:88:17 | data1 | swap1.cpp:82:16:82:21 | call to source | +| swap1.cpp:97:12:97:16 | data1 | swap1.cpp:95:15:95:20 | call to source | +| swap1.cpp:102:12:102:16 | data1 | swap1.cpp:95:15:95:20 | call to source | +| swap1.cpp:103:12:103:16 | data1 | swap1.cpp:95:15:95:20 | call to source | +| swap1.cpp:111:20:111:24 | data1 | swap1.cpp:109:23:109:28 | call to source | +| swap1.cpp:115:18:115:22 | data1 | swap1.cpp:109:23:109:28 | call to source | +| swap1.cpp:124:12:124:16 | data1 | swap1.cpp:122:15:122:20 | call to source | +| swap1.cpp:129:12:129:16 | data1 | swap1.cpp:122:15:122:20 | call to source | +| swap1.cpp:130:12:130:16 | data1 | swap1.cpp:122:15:122:20 | call to source | +| swap1.cpp:139:12:139:16 | data1 | swap1.cpp:137:15:137:20 | call to source | +| swap1.cpp:144:12:144:16 | data1 | swap1.cpp:137:15:137:20 | call to source | +| swap1.cpp:145:12:145:16 | data1 | swap1.cpp:137:15:137:20 | call to source | +| swap2.cpp:73:12:73:16 | data1 | swap2.cpp:71:15:71:20 | call to source | +| swap2.cpp:78:12:78:16 | data1 | swap2.cpp:71:15:71:20 | call to source | +| swap2.cpp:79:12:79:16 | data1 | swap2.cpp:71:15:71:20 | call to source | +| swap2.cpp:83:13:83:17 | data1 | swap2.cpp:82:16:82:21 | call to source | +| swap2.cpp:88:13:88:17 | data1 | swap2.cpp:82:16:82:21 | call to source | +| swap2.cpp:97:12:97:16 | data1 | swap2.cpp:95:15:95:20 | call to source | +| swap2.cpp:102:12:102:16 | data1 | swap2.cpp:95:15:95:20 | call to source | +| swap2.cpp:103:12:103:16 | data1 | swap2.cpp:95:15:95:20 | call to source | +| swap2.cpp:111:20:111:24 | data1 | swap2.cpp:109:23:109:28 | call to source | +| swap2.cpp:115:18:115:22 | data1 | swap2.cpp:109:23:109:28 | call to source | +| swap2.cpp:124:12:124:16 | data1 | swap2.cpp:122:15:122:20 | call to source | +| swap2.cpp:129:12:129:16 | data1 | swap2.cpp:122:15:122:20 | call to source | +| swap2.cpp:130:12:130:16 | data1 | swap2.cpp:122:15:122:20 | call to source | +| swap2.cpp:139:12:139:16 | data1 | swap2.cpp:137:15:137:20 | call to source | +| swap2.cpp:144:12:144:16 | data1 | swap2.cpp:137:15:137:20 | call to source | +| swap2.cpp:145:12:145:16 | data1 | swap2.cpp:137:15:137:20 | call to source | | taint.cpp:8:8:8:13 | clean1 | taint.cpp:4:27:4:33 | source1 | | taint.cpp:16:8:16:14 | source1 | taint.cpp:12:22:12:27 | call to source | | taint.cpp:17:8:17:16 | ++ ... | taint.cpp:12:22:12:27 | call to source | +| taint.cpp:89:11:89:11 | b | taint.cpp:71:22:71:27 | call to source | +| taint.cpp:90:11:90:11 | c | taint.cpp:72:7:72:12 | call to source | +| taint.cpp:91:11:91:11 | d | taint.cpp:77:7:77:12 | call to source | +| taint.cpp:93:11:93:11 | b | taint.cpp:71:22:71:27 | call to source | +| taint.cpp:94:11:94:11 | c | taint.cpp:72:7:72:12 | call to source | | taint.cpp:109:7:109:13 | access to array | taint.cpp:105:12:105:17 | call to source | | taint.cpp:110:7:110:13 | access to array | taint.cpp:105:12:105:17 | call to source | | taint.cpp:111:7:111:13 | access to array | taint.cpp:106:12:106:17 | call to source | @@ -16,6 +353,7 @@ | taint.cpp:151:7:151:12 | call to select | taint.cpp:151:20:151:25 | call to source | | taint.cpp:167:8:167:13 | call to source | taint.cpp:167:8:167:13 | call to source | | taint.cpp:168:8:168:14 | tainted | taint.cpp:164:19:164:24 | call to source | +| taint.cpp:173:8:173:13 | Argument 0 indirection | taint.cpp:164:19:164:24 | call to source | | taint.cpp:181:8:181:9 | * ... | taint.cpp:185:11:185:16 | call to source | | taint.cpp:210:7:210:7 | x | taint.cpp:207:6:207:11 | call to source | | taint.cpp:215:7:215:7 | x | taint.cpp:207:6:207:11 | call to source | @@ -25,15 +363,56 @@ | taint.cpp:244:3:244:6 | t | taint.cpp:223:10:223:15 | call to source | | taint.cpp:250:8:250:8 | a | taint.cpp:223:10:223:15 | call to source | | taint.cpp:256:8:256:8 | (reference dereference) | taint.cpp:223:10:223:15 | call to source | +| taint.cpp:261:7:261:7 | w | taint.cpp:258:7:258:12 | call to source | | taint.cpp:280:7:280:7 | t | taint.cpp:275:6:275:11 | call to source | | taint.cpp:289:7:289:7 | t | taint.cpp:275:6:275:11 | call to source | | taint.cpp:290:7:290:7 | x | taint.cpp:275:6:275:11 | call to source | | taint.cpp:291:7:291:7 | y | taint.cpp:275:6:275:11 | call to source | | taint.cpp:337:7:337:7 | t | taint.cpp:330:6:330:11 | call to source | | taint.cpp:350:7:350:7 | t | taint.cpp:330:6:330:11 | call to source | +| taint.cpp:351:7:351:7 | a | taint.cpp:330:6:330:11 | call to source | +| taint.cpp:352:7:352:7 | b | taint.cpp:330:6:330:11 | call to source | +| taint.cpp:353:7:353:7 | c | taint.cpp:330:6:330:11 | call to source | +| taint.cpp:354:7:354:7 | d | taint.cpp:330:6:330:11 | call to source | | taint.cpp:382:7:382:7 | a | taint.cpp:377:23:377:28 | source | | taint.cpp:429:7:429:7 | b | taint.cpp:428:13:428:18 | call to source | | taint.cpp:430:9:430:14 | member | taint.cpp:428:13:428:18 | call to source | | taint.cpp:465:7:465:7 | x | taint.cpp:462:6:462:11 | call to source | | taint.cpp:470:7:470:7 | x | taint.cpp:462:6:462:11 | call to source | +| taint.cpp:471:7:471:7 | y | taint.cpp:462:6:462:11 | call to source | | taint.cpp:485:7:485:10 | line | taint.cpp:480:26:480:32 | source1 | +| vector.cpp:20:8:20:8 | x | vector.cpp:16:43:16:49 | source1 | +| vector.cpp:24:8:24:8 | call to operator* | vector.cpp:16:43:16:49 | source1 | +| vector.cpp:24:8:24:11 | (reference dereference) | vector.cpp:16:43:16:49 | source1 | +| vector.cpp:28:8:28:8 | (reference dereference) | vector.cpp:16:43:16:49 | source1 | +| vector.cpp:28:8:28:8 | x | vector.cpp:16:43:16:49 | source1 | +| vector.cpp:33:8:33:8 | (reference dereference) | vector.cpp:16:43:16:49 | source1 | +| vector.cpp:33:8:33:8 | x | vector.cpp:16:43:16:49 | source1 | +| vector.cpp:70:7:70:8 | Argument 0 indirection | vector.cpp:69:15:69:20 | call to source | +| vector.cpp:83:7:83:8 | Argument 0 indirection | vector.cpp:81:17:81:22 | call to source | +| vector.cpp:109:7:109:8 | Argument 0 indirection | vector.cpp:106:15:106:20 | call to source | +| vector.cpp:112:7:112:8 | Argument 0 indirection | vector.cpp:107:15:107:20 | call to source | +| vector.cpp:117:7:117:8 | Argument 0 indirection | vector.cpp:106:15:106:20 | call to source | +| vector.cpp:118:7:118:8 | Argument 0 indirection | vector.cpp:106:15:106:20 | call to source | +| vector.cpp:119:7:119:8 | Argument 0 indirection | vector.cpp:107:15:107:20 | call to source | +| vector.cpp:120:7:120:8 | Argument 0 indirection | vector.cpp:107:15:107:20 | call to source | +| vector.cpp:130:7:130:8 | Argument 0 indirection | vector.cpp:126:15:126:20 | call to source | +| vector.cpp:131:7:131:8 | Argument 0 indirection | vector.cpp:127:15:127:20 | call to source | +| vector.cpp:132:7:132:8 | Argument 0 indirection | vector.cpp:128:15:128:20 | call to source | +| vector.cpp:139:7:139:8 | Argument 0 indirection | vector.cpp:126:15:126:20 | call to source | +| vector.cpp:140:7:140:8 | Argument 0 indirection | vector.cpp:127:15:127:20 | call to source | +| vector.cpp:141:7:141:8 | Argument 0 indirection | vector.cpp:128:15:128:20 | call to source | +| vector.cpp:162:8:162:15 | access to array | vector.cpp:161:14:161:19 | call to source | +| vector.cpp:242:7:242:8 | Argument 0 indirection | vector.cpp:238:17:238:30 | call to source | +| vector.cpp:243:7:243:8 | Argument 0 indirection | vector.cpp:239:15:239:20 | call to source | +| vector.cpp:258:8:258:9 | Argument 0 indirection | vector.cpp:239:15:239:20 | call to source | +| vector.cpp:259:8:259:9 | Argument 0 indirection | vector.cpp:239:15:239:20 | call to source | +| vector.cpp:260:8:260:9 | Argument 0 indirection | vector.cpp:239:15:239:20 | call to source | +| vector.cpp:273:8:273:9 | Argument 0 indirection | vector.cpp:269:18:269:31 | call to source | +| vector.cpp:274:8:274:9 | Argument 0 indirection | vector.cpp:270:18:270:35 | call to source | +| vector.cpp:275:8:275:9 | Argument 0 indirection | vector.cpp:271:18:271:34 | call to source | +| vector.cpp:285:7:285:8 | Argument 0 indirection | vector.cpp:284:15:284:20 | call to source | +| vector.cpp:309:7:309:7 | Argument 0 indirection | vector.cpp:303:14:303:19 | call to source | +| vector.cpp:312:7:312:7 | Argument 0 indirection | vector.cpp:303:14:303:19 | call to source | +| vector.cpp:324:7:324:8 | Argument 0 indirection | vector.cpp:318:15:318:20 | call to source | +| vector.cpp:326:7:326:8 | Argument 0 indirection | vector.cpp:318:15:318:20 | call to source | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp new file mode 100644 index 000000000000..b5dad8119989 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp @@ -0,0 +1,401 @@ + +#include "stl.h" + +using namespace std; + +int source(); + +namespace ns_int +{ + int source(); +} + +void sink(int); +void sink(std::vector &); + +void test_range_based_for_loop_vector(int source1) { + std::vector v(100, source1); + + for(int x : v) { + sink(x); // tainted [NOT DETECTED by IR] + } + + for(std::vector::iterator it = v.begin(); it != v.end(); ++it) { + sink(*it); // tainted [NOT DETECTED by IR] + } + + for(int& x : v) { + sink(x); // tainted [NOT DETECTED by IR] + } + + const std::vector const_v(100, source1); + for(const int& x : const_v) { + sink(x); // tainted [NOT DETECTED by IR] + } +} + +void test_element_taint(int x) { + std::vector v1(10), v2(10), v3(10), v4(10), v5(10), v6(10), v7(10), v8(10), v9(10); + + v1[0] = 0; + v1[1] = 0; + v1[x] = 0; + v1.push_back(1); + sink(v1); + sink(v1[0]); + sink(v1[1]); + sink(v1[x]); + sink(v1.front()); + sink(v1.back()); + + v2[0] = source(); + sink(v2); // tainted + sink(v2[0]); // tainted + sink(v2[1]); // [FALSE POSITIVE] + sink(v2[x]); // potentially tainted + + v3 = v2; + sink(v3); // tainted + sink(v3[0]); // tainted + sink(v3[1]); // [FALSE POSITIVE] + sink(v3[x]); // potentially tainted + + v4[x] = source(); + sink(v4); // tainted + sink(v4[0]); // potentially tainted + sink(v4[1]); // potentially tainted + sink(v4[x]); // tainted + + v5.push_back(source()); + sink(v5); // tainted + sink(v5.front()); // [FALSE POSITIVE] + sink(v5.back()); // tainted + + v6.data()[2] = source(); + sink(v6); // tainted + sink(v6.data()[2]); // tainted + + + { + std::vector::const_iterator it = v7.begin(); + v7.insert(it, source()); + } + sink(v7); // tainted + sink(v7.front()); // tainted + sink(v7.back()); // [FALSE POSITIVE] + + { + const std::vector &v8c = v8; + std::vector::const_iterator it = v8c.begin(); + v8.insert(it, 10, ns_int::source()); + } + sink(v8); // tainted [NOT DETECTED] + sink(v8.front()); // tainted [NOT DETECTED] + sink(v8.back()); + + v9.at(x) = source(); + sink(v9); // tainted + sink(v9.at(0)); // potentially tainted + sink(v9.at(1)); // potentially tainted + sink(v9.at(x)); // tainted +} + +void test_vector_swap() { + std::vector v1(10), v2(10), v3(10), v4(10); + + v1.push_back(source()); + v4.push_back(source()); + + sink(v1); // tainted + sink(v2); + sink(v3); + sink(v4); // tainted + + v1.swap(v2); + v3.swap(v4); + + sink(v1); // [FALSE POSITIVE] + sink(v2); // tainted + sink(v3); // tainted + sink(v4); // [FALSE POSITIVE] +} + +void test_vector_clear() { + std::vector v1(10), v2(10), v3(10), v4(10); + + v1.push_back(source()); + v2.push_back(source()); + v3.push_back(source()); + + sink(v1); // tainted + sink(v2); // tainted + sink(v3); // tainted + sink(v4); + + v1.clear(); + v2 = v2; + v3 = v4; + + sink(v1); // [FALSE POSITIVE] + sink(v2); // tainted + sink(v3); // [FALSE POSITIVE] + sink(v4); +} + +struct MyPair +{ + int a, b; +}; + +struct MyVectorContainer +{ + std::vector vs; +}; + +void test_nested_vectors() +{ + { + int aa[10][20] = {0}; + + sink(aa[0][0]); + aa[0][0] = source(); + sink(aa[0][0]); // tainted + } + + { + std::vector > bb(30); + + bb[0].push_back(0); + sink(bb[0][0]); + bb[0][0] = source(); + sink(bb[0][0]); // tainted + } + + { + std::vector cc[40]; + + cc[0].push_back(0); + sink(cc[0][0]); + cc[0][0] = source(); + sink(cc[0][0]); // tainted + } + + { + std::vector dd; + MyPair mp = {0, 0}; + + dd.push_back(mp); + sink(dd[0].a); + sink(dd[0].b); + dd[0].a = source(); + sink(dd[0].a); // tainted [NOT DETECTED] + sink(dd[0].b); + } + + { + MyVectorContainer ee; + + ee.vs.push_back(0); + sink(ee.vs[0]); + ee.vs[0] = source(); + sink(ee.vs[0]); // tainted + } + + { + std::vector ff; + MyVectorContainer mvc; + + mvc.vs.push_back(0); + ff.push_back(mvc); + sink(ff[0].vs[0]); + ff[0].vs[0] = source(); + sink(ff[0].vs[0]); // tainted [NOT DETECTED] + } +} + +void sink(std::vector::iterator &); + +typedef int myInt; +typedef float myFloat; + +namespace ns_myFloat +{ + myFloat source(); +} + +namespace ns_ci_ptr +{ + const int *source(); +} + +void sink(std::vector &); +void sink(std::vector &); + +void test_vector_assign() { + std::vector v1, v2, v3; + + v1.assign(100, 0); + v2.assign(100, ns_int::source()); + v3.push_back(source()); + + sink(v1); + sink(v2); // tainted + sink(v3); // tainted + + { + std::vector v4, v5, v6; + std::vector::iterator i1, i2; + + v4.assign(v1.begin(), v1.end()); + v5.assign(v3.begin(), v3.end()); + i1 = v3.begin(); + i1++; + i2 = i1; + i2++; + v6.assign(i1, i2); + + sink(v4); + sink(v5); // tainted + sink(i1); // tainted + sink(i2); // tainted + sink(v6); // tainted + } + + { + std::vector v7; + std::vector v8; + std::vector v9; + + v7.assign(100, ns_int::source()); + v8.assign(100, ns_myFloat::source()); + v9.assign(100, ns_ci_ptr::source()); + + sink(v7); // tainted + sink(v8); // tainted + sink(v9); // tainted + } +} + +void sink(int *); + +void test_data_more() { + std::vector v1, v2; + + v1.push_back(source()); + sink(v1); // tainted + sink(v1.data()); // tainted + sink(v1.data()[2]); // tainted + + *(v2.data()) = ns_int::source(); + sink(v2); // tainted + sink(v2.data()); // tainted + sink(v2.data()[2]); // tainted +} + +void sink(std::vector::iterator); + +void test_vector_insert() { + std::vector a; + std::vector b; + std::vector c; + std::vector d; + + d.push_back(source()); + + sink(a.insert(a.end(), b.begin(), b.end())); + sink(a); + + sink(c.insert(c.end(), d.begin(), d.end())); // tainted + sink(c); // tainted + + sink(d.insert(d.end(), a.begin(), a.end())); // tainted + sink(d); // tainted +} + +void test_constructors_more() { + std::vector v1; + std::vector v2; + v2.push_back(source()); + + std::vector v3(v1.begin(), v1.end()); + std::vector v4(v2.begin(), v2.end()); + + sink(v1); + sink(v2); // tainted + sink(v3); + sink(v4); // tainted +} + +void taint_vector_output_iterator(std::vector::iterator iter) { + *iter = source(); +} + +void vector_iterator_assign_wrapper(std::vector::iterator iter, int i) { + *iter = i; +} + +void test_vector_output_iterator(int b) { + std::vector v1(10), v2(10), v3(10), v4(10), v5(10), v6(10), v7(10), v8(10), v9(10), v10(10), v11(10); + + std::vector::iterator i1 = v1.begin(); + *i1 = source(); + sink(v1); // tainted [NOT DETECTED by IR] + + for(std::vector::iterator it = v2.begin(); it != v2.end(); ++it) { + *it = source(); + } + sink(v2); // tainted [NOT DETECTED by IR] + + for(int& x : v3) { + x = source(); + } + sink(v3); // tainted [NOT DETECTED] + + for(std::vector::iterator it = v4.begin(); it != v4.end(); ++it) { + taint_vector_output_iterator(it); + } + sink(v4); // tainted [NOT DETECTED by IR] + + std::vector::iterator i5 = v5.begin(); + *i5 = source(); + sink(v5); // tainted [NOT DETECTED by IR] + *i5 = 1; + sink(v5); // tainted [NOT DETECTED by IR] + + std::vector::iterator i6 = v6.begin(); + *i6 = source(); + sink(v6); // tainted [NOT DETECTED by IR] + v6 = std::vector(10); + sink(v6); // [FALSE POSITIVE in AST] + + std::vector::iterator i7 = v7.begin(); + if(b) { + *i7 = source(); + sink(v7); // tainted [NOT DETECTED by IR] + } else { + *i7 = 1; + sink(v7); + } + sink(v7); // tainted [NOT DETECTED by IR] + + std::vector::iterator i8 = v8.begin(); + *i8 = source(); + sink(v8); // tainted [NOT DETECTED by IR] + *i8 = 1; + sink(v8); + + std::vector::iterator i9 = v9.begin(); + + *i9 = source(); + taint_vector_output_iterator(i9); + + sink(v9); + + std::vector::iterator i10 = v10.begin(); + vector_iterator_assign_wrapper(i10, 10); + sink(v10); + + std::vector::iterator i11 = v11.begin(); + vector_iterator_assign_wrapper(i11, source()); + sink(v11); // tainted [NOT DETECTED by IR] +} diff --git a/cpp/ql/test/library-tests/declaration/IsMember.expected b/cpp/ql/test/library-tests/declaration/IsMember.expected index 174b8745c854..80fcd74689ce 100644 --- a/cpp/ql/test/library-tests/declaration/IsMember.expected +++ b/cpp/ql/test/library-tests/declaration/IsMember.expected @@ -3,6 +3,7 @@ | declaration.cpp:32:7:32:7 | operator= | | declaration.cpp:32:7:32:7 | operator= | | declaration.cpp:34:7:34:14 | myField0 | +| declaration.cpp:36:9:36:9 | MyNestedClass | | declaration.cpp:36:9:36:9 | operator= | | declaration.cpp:36:9:36:9 | operator= | | declaration.cpp:36:9:36:21 | MyNestedClass | @@ -28,6 +29,7 @@ | declaration.cpp:100:7:100:7 | operator= | | declaration.cpp:100:7:100:7 | operator= | | declaration.cpp:102:7:102:14 | myField1 | +| declaration.cpp:104:9:104:9 | MyNestedClass | | declaration.cpp:104:9:104:9 | operator= | | declaration.cpp:104:9:104:9 | operator= | | declaration.cpp:104:9:104:21 | MyNestedClass | diff --git a/cpp/ql/test/library-tests/declarationEntry/more/declarationEntry.expected b/cpp/ql/test/library-tests/declarationEntry/more/declarationEntry.expected index 47c5f075a412..6018624fd043 100644 --- a/cpp/ql/test/library-tests/declarationEntry/more/declarationEntry.expected +++ b/cpp/ql/test/library-tests/declarationEntry/more/declarationEntry.expected @@ -27,6 +27,7 @@ | test.cpp:20:6:20:20 | definition of tmplProtoAndDef | | test.cpp:20:24:20:24 | declaration of t | | test.cpp:20:24:20:24 | definition of t | +| test.cpp:22:7:22:7 | declaration of Cl | | test.cpp:22:7:22:7 | declaration of operator= | | test.cpp:22:7:22:7 | declaration of operator= | | test.cpp:22:7:22:8 | definition of Cl | @@ -75,6 +76,8 @@ | test.cpp:67:7:67:7 | declaration of operator= | | test.cpp:67:7:67:7 | declaration of operator= | | test.cpp:67:7:67:7 | declaration of operator= | +| test.cpp:67:7:67:7 | definition of tmplInstantiatedClass | +| test.cpp:67:7:67:7 | definition of tmplInstantiatedClass | | test.cpp:67:7:67:27 | definition of tmplInstantiatedClass | | test.cpp:68:7:68:7 | definition of t | | test.cpp:68:7:68:7 | definition of t | diff --git a/cpp/ql/test/library-tests/fun_decl/test.expected b/cpp/ql/test/library-tests/fun_decl/test.expected index cd72c33fe674..dfa716838ee4 100644 --- a/cpp/ql/test/library-tests/fun_decl/test.expected +++ b/cpp/ql/test/library-tests/fun_decl/test.expected @@ -1,4 +1,5 @@ | compile1.cpp:3:6:3:10 | func1 | +| compile2.cpp:3:7:3:7 | classA | | compile2.cpp:3:7:3:7 | operator= | | compile2.cpp:5:2:5:8 | ~classA | | compile2.cpp:8:9:8:19 | create_an_a | diff --git a/cpp/ql/test/library-tests/functions/functions/Functions1.expected b/cpp/ql/test/library-tests/functions/functions/Functions1.expected index f491fa10b6ed..cebf0359fdcf 100644 --- a/cpp/ql/test/library-tests/functions/functions/Functions1.expected +++ b/cpp/ql/test/library-tests/functions/functions/Functions1.expected @@ -1,3 +1,4 @@ +| ODASA-5186.cpp:4:8:4:8 | MyClass | MyClass | | declaration:ODASA-5186.cpp:4:8:4:8, definition:ODASA-5186.cpp:4:8:4:8 | | ODASA-5186.cpp:4:8:4:8 | operator= | operator= | MyClass && p#0 | declaration:ODASA-5186.cpp:4:8:4:8 | | ODASA-5186.cpp:4:8:4:8 | operator= | operator= | const MyClass & p#0 | declaration:ODASA-5186.cpp:4:8:4:8 | | ODASA-5186.cpp:5:8:5:8 | operator== | operator== | const MyClass & other | declaration:ODASA-5186.cpp:5:8:5:8, definition:ODASA-5186.cpp:5:8:5:8 | @@ -13,6 +14,7 @@ | functions.cpp:8:7:8:8 | af | af | | declaration:functions.cpp:8:7:8:8, definition:functions.cpp:8:7:8:8 | | functions.cpp:11:7:11:8 | ag | ag | | declaration:functions.cpp:11:7:11:8 | | functions.cpp:14:6:14:6 | g | g | | TopLevelFunction, declaration:functions.cpp:14:6:14:6, declaration:functions.cpp:5:6:5:6, definition:functions.cpp:14:6:14:6, isTopLevel | +| functions.cpp:19:7:19:7 | Name | Name | | declaration:functions.cpp:19:7:19:7 | | functions.cpp:19:7:19:7 | operator= | operator= | Name && p#0 | declaration:functions.cpp:19:7:19:7 | | functions.cpp:19:7:19:7 | operator= | operator= | const Name & p#0 | declaration:functions.cpp:19:7:19:7 | | functions.cpp:23:7:23:7 | Table | Table | const Table & p#0 | declaration:functions.cpp:23:7:23:7 | diff --git a/cpp/ql/test/library-tests/functions/functions/Functions2.expected b/cpp/ql/test/library-tests/functions/functions/Functions2.expected index 8242831d5f6a..4040d024ebb5 100644 --- a/cpp/ql/test/library-tests/functions/functions/Functions2.expected +++ b/cpp/ql/test/library-tests/functions/functions/Functions2.expected @@ -1,4 +1,5 @@ | ODASA-5186.cpp:4:8:4:14 | MyClass | Class | ODASA-5186.cpp:5:8:5:17 | operator== | | +| ODASA-5186.cpp:4:8:4:14 | MyClass | Struct | ODASA-5186.cpp:4:8:4:8 | MyClass | Constructor, NoArgConstructor, getAConstructor() | | ODASA-5186.cpp:4:8:4:14 | MyClass | Struct | ODASA-5186.cpp:4:8:4:8 | operator= | | | ODASA-5186.cpp:4:8:4:14 | MyClass | Struct | ODASA-5186.cpp:4:8:4:8 | operator= | | | ODASA-5186.cpp:4:8:4:14 | MyClass | Struct | ODASA-5186.cpp:5:8:5:8 | operator== | | @@ -10,6 +11,7 @@ | functions.cpp:7:8:7:8 | A | Struct | functions.cpp:7:8:7:8 | operator= | | | functions.cpp:7:8:7:8 | A | Struct | functions.cpp:8:7:8:8 | af | | | functions.cpp:7:8:7:8 | A | Struct | functions.cpp:11:7:11:8 | ag | | +| functions.cpp:19:7:19:10 | Name | Class | functions.cpp:19:7:19:7 | Name | Constructor, NoArgConstructor, getAConstructor() | | functions.cpp:19:7:19:10 | Name | Class | functions.cpp:19:7:19:7 | operator= | | | functions.cpp:19:7:19:10 | Name | Class | functions.cpp:19:7:19:7 | operator= | | | functions.cpp:23:7:23:11 | Table | Class | functions.cpp:23:7:23:7 | Table | Constructor, CopyConstructor, getAConstructor() | @@ -20,7 +22,7 @@ | functions.cpp:23:7:23:11 | Table | Class | functions.cpp:30:8:30:13 | insert | | | functions.cpp:33:7:33:13 | MyClass | Class | functions.cpp:33:7:33:7 | operator= | | | functions.cpp:33:7:33:13 | MyClass | Class | functions.cpp:36:2:36:8 | MyClass | Constructor, NoArgConstructor, getAConstructor() | -| functions.cpp:33:7:33:13 | MyClass | Class | functions.cpp:37:2:37:8 | MyClass | Constructor, ConversionConstructor, getAConstructor() | +| functions.cpp:33:7:33:13 | MyClass | Class | functions.cpp:37:2:37:8 | MyClass | Constructor, getAConstructor() | | functions.cpp:33:7:33:13 | MyClass | Class | functions.cpp:38:2:38:8 | MyClass | Constructor, CopyConstructor, getAConstructor() | -| functions.cpp:33:7:33:13 | MyClass | Class | functions.cpp:39:2:39:8 | MyClass | Constructor, ConversionConstructor, MoveConstructor, getAConstructor() | +| functions.cpp:33:7:33:13 | MyClass | Class | functions.cpp:39:2:39:8 | MyClass | Constructor, MoveConstructor, getAConstructor() | | functions.cpp:33:7:33:13 | MyClass | Class | functions.cpp:40:2:40:13 | operator int | ConversionOperator | diff --git a/cpp/ql/test/library-tests/functions/functions/Functions2.ql b/cpp/ql/test/library-tests/functions/functions/Functions2.ql index 6cf558e54a90..506b47891197 100644 --- a/cpp/ql/test/library-tests/functions/functions/Functions2.ql +++ b/cpp/ql/test/library-tests/functions/functions/Functions2.ql @@ -19,9 +19,6 @@ string describe(Class c, MemberFunction f) { f instanceof Destructor and result = "Destructor" or - f instanceof ConversionConstructor and - result = "ConversionConstructor" - or f instanceof CopyConstructor and result = "CopyConstructor" or diff --git a/cpp/ql/test/library-tests/identifiers/qualified_names/unnamed.expected b/cpp/ql/test/library-tests/identifiers/qualified_names/unnamed.expected index 04c877da4ca4..78df738f9c77 100644 --- a/cpp/ql/test/library-tests/identifiers/qualified_names/unnamed.expected +++ b/cpp/ql/test/library-tests/identifiers/qualified_names/unnamed.expected @@ -1,6 +1,7 @@ | qualifiedNames.cpp:3:25:3:27 | p#0 | | qualifiedNames.cpp:4:25:4:28 | p#0 | | qualifiedNames.cpp:18:18:18:31 | Nested's friend | +| qualifiedNames.cpp:26:9:26:9 | LocalClass | | qualifiedNames.cpp:26:9:26:9 | operator= | | qualifiedNames.cpp:26:9:26:9 | operator= | | qualifiedNames.cpp:26:9:26:18 | LocalClass | diff --git a/cpp/ql/test/library-tests/instantiations/test.expected b/cpp/ql/test/library-tests/instantiations/test.expected index 3e23680b5fbb..7460a9fa9dcc 100644 --- a/cpp/ql/test/library-tests/instantiations/test.expected +++ b/cpp/ql/test/library-tests/instantiations/test.expected @@ -2,6 +2,7 @@ | file://:0:0:0:0 | operator new | | file://:0:0:0:0 | operator= | | file://:0:0:0:0 | operator= | +| test.cpp:2:7:2:7 | A | | test.cpp:2:7:2:7 | operator= | | test.cpp:2:19:2:20 | ~A | | test.cpp:4:7:4:7 | X | diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected index 2e204cde8562..e58a36e747dc 100644 --- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected +++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected @@ -71,7 +71,7 @@ bad_asts.cpp: # 9| params: # 9| 0: [Parameter] y # 9| Type = [IntType] int -# 9| body: [Block] { ... } +# 9| body: [BlockStmt] { ... } # 10| 0: [ReturnStmt] return ... # 10| 0: [AddExpr] ... + ... # 10| Type = [IntType] int @@ -96,7 +96,7 @@ bad_asts.cpp: # 9| params: # 9| 0: [Parameter] y # 9| Type = [IntType] int -# 9| body: [Block] { ... } +# 9| body: [BlockStmt] { ... } # 10| 0: [ReturnStmt] return ... # 10| 0: [AddExpr] ... + ... # 10| Type = [IntType] int @@ -119,7 +119,7 @@ bad_asts.cpp: # 10| ValueCategory = prvalue(load) # 14| [TopLevelFunction] void Bad::CallBadMemberFunction() # 14| params: -# 14| body: [Block] { ... } +# 14| body: [BlockStmt] { ... } # 15| 0: [DeclStmt] declaration # 15| 0: [VariableDeclarationEntry] definition of s # 15| Type = [Struct] S @@ -164,7 +164,7 @@ bad_asts.cpp: # 19| 0: [Literal] Unknown literal # 19| Type = [IntType] int # 19| ValueCategory = prvalue -# 19| body: [Block] { ... } +# 19| body: [BlockStmt] { ... } # 19| 0: [ReturnStmt] return ... # 19| [MoveConstructor] void Bad::Point::Point(Bad::Point&&) # 19| params: @@ -173,13 +173,13 @@ bad_asts.cpp: # 22| [Constructor] void Bad::Point::Point() # 22| params: # 22| initializations: -# 22| body: [Block] { ... } +# 22| body: [BlockStmt] { ... } # 23| 0: [ReturnStmt] return ... # 26| [TopLevelFunction] void Bad::CallCopyConstructor(Bad::Point const&) # 26| params: # 26| 0: [Parameter] a # 26| Type = [LValueReferenceType] const Point & -# 26| body: [Block] { ... } +# 26| body: [BlockStmt] { ... } # 27| 0: [DeclStmt] declaration # 27| 0: [VariableDeclarationEntry] definition of b # 27| Type = [Struct] Point @@ -197,7 +197,7 @@ bad_asts.cpp: # 28| 1: [ReturnStmt] return ... # 30| [TopLevelFunction] void Bad::errorExpr() # 30| params: -# 30| body: [Block] { ... } +# 30| body: [BlockStmt] { ... } # 31| 0: [DeclStmt] declaration # 31| 0: [VariableDeclarationEntry] definition of intref # 31| Type = [LValueReferenceType] int & @@ -226,7 +226,7 @@ bad_asts.cpp: clang.cpp: # 5| [TopLevelFunction] int* globalIntAddress() # 5| params: -# 5| body: [Block] { ... } +# 5| body: [BlockStmt] { ... } # 6| 0: [ReturnStmt] return ... # 6| 0: [BuiltInOperationBuiltInAddressOf] __builtin_addressof ... # 6| Type = [IntPointerType] int * @@ -237,7 +237,7 @@ clang.cpp: complex.c: # 1| [TopLevelFunction] void complex_literals() # 1| params: -# 1| body: [Block] { ... } +# 1| body: [BlockStmt] { ... } # 2| 0: [DeclStmt] declaration # 2| 0: [VariableDeclarationEntry] definition of cf # 2| Type = [ArithmeticType] _Complex float @@ -354,7 +354,7 @@ complex.c: # 12| 9: [ReturnStmt] return ... # 14| [TopLevelFunction] void complex_arithmetic() # 14| params: -# 14| body: [Block] { ... } +# 14| body: [BlockStmt] { ... } # 15| 0: [DeclStmt] declaration # 15| 0: [VariableDeclarationEntry] definition of f1 # 15| Type = [FloatType] float @@ -741,7 +741,7 @@ complex.c: # 56| 29: [ReturnStmt] return ... # 58| [TopLevelFunction] void complex_conversions() # 58| params: -# 58| body: [Block] { ... } +# 58| body: [BlockStmt] { ... } # 59| 0: [DeclStmt] declaration # 59| 0: [VariableDeclarationEntry] definition of f # 59| Type = [FloatType] float @@ -1718,7 +1718,7 @@ complex.c: ir.cpp: # 1| [TopLevelFunction] void Constants() # 1| params: -# 1| body: [Block] { ... } +# 1| body: [BlockStmt] { ... } # 2| 0: [DeclStmt] declaration # 2| 0: [VariableDeclarationEntry] definition of c_i # 2| Type = [PlainCharType] char @@ -2035,7 +2035,7 @@ ir.cpp: # 41| 28: [ReturnStmt] return ... # 43| [TopLevelFunction] void Foo() # 43| params: -# 43| body: [Block] { ... } +# 43| body: [BlockStmt] { ... } # 44| 0: [DeclStmt] declaration # 44| 0: [VariableDeclarationEntry] definition of x # 44| Type = [IntType] int @@ -2116,7 +2116,7 @@ ir.cpp: # 50| Type = [IntType] int # 50| 1: [Parameter] y # 50| Type = [IntType] int -# 50| body: [Block] { ... } +# 50| body: [BlockStmt] { ... } # 51| 0: [DeclStmt] declaration # 51| 0: [VariableDeclarationEntry] definition of z # 51| Type = [IntType] int @@ -2457,7 +2457,7 @@ ir.cpp: # 87| Type = [IntType] int # 87| 1: [Parameter] y # 87| Type = [IntType] int -# 87| body: [Block] { ... } +# 87| body: [BlockStmt] { ... } # 88| 0: [DeclStmt] declaration # 88| 0: [VariableDeclarationEntry] definition of b # 88| Type = [BoolType] bool @@ -2562,7 +2562,7 @@ ir.cpp: # 98| params: # 98| 0: [Parameter] x # 98| Type = [IntType] int -# 98| body: [Block] { ... } +# 98| body: [BlockStmt] { ... } # 99| 0: [DeclStmt] declaration # 99| 0: [VariableDeclarationEntry] definition of y # 99| Type = [IntType] int @@ -2623,7 +2623,7 @@ ir.cpp: # 107| params: # 107| 0: [Parameter] x # 107| Type = [IntType] int -# 107| body: [Block] { ... } +# 107| body: [BlockStmt] { ... } # 108| 0: [DeclStmt] declaration # 108| 0: [VariableDeclarationEntry] definition of p # 108| Type = [IntPointerType] int * @@ -2672,7 +2672,7 @@ ir.cpp: # 114| Type = [DoubleType] double # 114| 1: [Parameter] y # 114| Type = [DoubleType] double -# 114| body: [Block] { ... } +# 114| body: [BlockStmt] { ... } # 115| 0: [DeclStmt] declaration # 115| 0: [VariableDeclarationEntry] definition of z # 115| Type = [DoubleType] double @@ -2823,7 +2823,7 @@ ir.cpp: # 133| Type = [DoubleType] double # 133| 1: [Parameter] y # 133| Type = [DoubleType] double -# 133| body: [Block] { ... } +# 133| body: [BlockStmt] { ... } # 134| 0: [DeclStmt] declaration # 134| 0: [VariableDeclarationEntry] definition of b # 134| Type = [BoolType] bool @@ -2928,7 +2928,7 @@ ir.cpp: # 144| params: # 144| 0: [Parameter] x # 144| Type = [FloatType] float -# 144| body: [Block] { ... } +# 144| body: [BlockStmt] { ... } # 145| 0: [DeclStmt] declaration # 145| 0: [VariableDeclarationEntry] definition of y # 145| Type = [FloatType] float @@ -2991,7 +2991,7 @@ ir.cpp: # 153| Type = [IntPointerType] int * # 153| 1: [Parameter] i # 153| Type = [IntType] int -# 153| body: [Block] { ... } +# 153| body: [BlockStmt] { ... } # 154| 0: [DeclStmt] declaration # 154| 0: [VariableDeclarationEntry] definition of q # 154| Type = [IntPointerType] int * @@ -3134,7 +3134,7 @@ ir.cpp: # 171| Type = [IntPointerType] int * # 171| 1: [Parameter] i # 171| Type = [IntType] int -# 171| body: [Block] { ... } +# 171| body: [BlockStmt] { ... } # 172| 0: [DeclStmt] declaration # 172| 0: [VariableDeclarationEntry] definition of x # 172| Type = [IntType] int @@ -3286,7 +3286,7 @@ ir.cpp: # 187| params: # 187| 0: [Parameter] i # 187| Type = [IntType] int -# 187| body: [Block] { ... } +# 187| body: [BlockStmt] { ... } # 188| 0: [DeclStmt] declaration # 188| 0: [VariableDeclarationEntry] definition of c # 188| Type = [PlainCharType] char @@ -3339,7 +3339,7 @@ ir.cpp: # 193| Type = [IntPointerType] int * # 193| 1: [Parameter] q # 193| Type = [IntPointerType] int * -# 193| body: [Block] { ... } +# 193| body: [BlockStmt] { ... } # 194| 0: [DeclStmt] declaration # 194| 0: [VariableDeclarationEntry] definition of b # 194| Type = [BoolType] bool @@ -3444,7 +3444,7 @@ ir.cpp: # 204| params: # 204| 0: [Parameter] p # 204| Type = [IntPointerType] int * -# 204| body: [Block] { ... } +# 204| body: [BlockStmt] { ... } # 205| 0: [DeclStmt] declaration # 205| 0: [VariableDeclarationEntry] definition of q # 205| Type = [IntPointerType] int * @@ -3503,7 +3503,7 @@ ir.cpp: # 211| 5: [ReturnStmt] return ... # 213| [TopLevelFunction] void CompoundAssignment() # 213| params: -# 213| body: [Block] { ... } +# 213| body: [BlockStmt] { ... } # 215| 0: [DeclStmt] declaration # 215| 0: [VariableDeclarationEntry] definition of x # 215| Type = [IntType] int @@ -3584,7 +3584,7 @@ ir.cpp: # 228| 7: [ReturnStmt] return ... # 230| [TopLevelFunction] void UninitializedVariables() # 230| params: -# 230| body: [Block] { ... } +# 230| body: [BlockStmt] { ... } # 231| 0: [DeclStmt] declaration # 231| 0: [VariableDeclarationEntry] definition of x # 231| Type = [IntType] int @@ -3602,7 +3602,7 @@ ir.cpp: # 235| Type = [IntType] int # 235| 1: [Parameter] y # 235| Type = [IntType] int -# 235| body: [Block] { ... } +# 235| body: [BlockStmt] { ... } # 236| 0: [ReturnStmt] return ... # 236| 0: [RemExpr] ... % ... # 236| Type = [IntType] int @@ -3621,17 +3621,17 @@ ir.cpp: # 239| Type = [IntType] int # 239| 2: [Parameter] y # 239| Type = [IntType] int -# 239| body: [Block] { ... } +# 239| body: [BlockStmt] { ... } # 240| 0: [IfStmt] if (...) ... # 240| 0: [VariableAccess] b # 240| Type = [BoolType] bool # 240| ValueCategory = prvalue(load) -# 240| 1: [Block] { ... } +# 240| 1: [BlockStmt] { ... } # 243| 1: [IfStmt] if (...) ... # 243| 0: [VariableAccess] b # 243| Type = [BoolType] bool # 243| ValueCategory = prvalue(load) -# 243| 1: [Block] { ... } +# 243| 1: [BlockStmt] { ... } # 244| 0: [ExprStmt] ExprStmt # 244| 0: [AssignExpr] ... = ... # 244| Type = [IntType] int @@ -3680,7 +3680,7 @@ ir.cpp: # 253| params: # 253| 0: [Parameter] n # 253| Type = [IntType] int -# 253| body: [Block] { ... } +# 253| body: [BlockStmt] { ... } # 254| 0: [WhileStmt] while (...) ... # 254| 0: [GTExpr] ... > ... # 254| Type = [BoolType] bool @@ -3692,7 +3692,7 @@ ir.cpp: # 254| Type = [IntType] int # 254| Value = [Literal] 0 # 254| ValueCategory = prvalue -# 254| 1: [Block] { ... } +# 254| 1: [BlockStmt] { ... } # 255| 0: [ExprStmt] ExprStmt # 255| 0: [AssignSubExpr] ... -= ... # 255| Type = [IntType] int @@ -3709,7 +3709,7 @@ ir.cpp: # 259| params: # 259| 0: [Parameter] n # 259| Type = [IntType] int -# 259| body: [Block] { ... } +# 259| body: [BlockStmt] { ... } # 260| 0: [DoStmt] do (...) ... # 262| 0: [GTExpr] ... > ... # 262| Type = [BoolType] bool @@ -3721,7 +3721,7 @@ ir.cpp: # 262| Type = [IntType] int # 262| Value = [Literal] 0 # 262| ValueCategory = prvalue -# 260| 1: [Block] { ... } +# 260| 1: [BlockStmt] { ... } # 261| 0: [ExprStmt] ExprStmt # 261| 0: [AssignSubExpr] ... -= ... # 261| Type = [IntType] int @@ -3736,16 +3736,16 @@ ir.cpp: # 263| 1: [ReturnStmt] return ... # 265| [TopLevelFunction] void For_Empty() # 265| params: -# 265| body: [Block] { ... } +# 265| body: [BlockStmt] { ... } # 266| 0: [DeclStmt] declaration # 266| 0: [VariableDeclarationEntry] definition of j # 266| Type = [IntType] int # 267| 1: [ForStmt] for(...;...;...) ... -# 267| 3: [Block] { ... } +# 267| 3: [BlockStmt] { ... } # 268| 0: [EmptyStmt] ; # 272| [TopLevelFunction] void For_Init() # 272| params: -# 272| body: [Block] { ... } +# 272| body: [BlockStmt] { ... } # 273| 0: [ForStmt] for(...;...;...) ... # 273| 0: [DeclStmt] declaration # 273| 0: [VariableDeclarationEntry] definition of i @@ -3755,11 +3755,11 @@ ir.cpp: # 273| Type = [IntType] int # 273| Value = [Literal] 0 # 273| ValueCategory = prvalue -# 273| 3: [Block] { ... } +# 273| 3: [BlockStmt] { ... } # 274| 0: [EmptyStmt] ; # 278| [TopLevelFunction] void For_Condition() # 278| params: -# 278| body: [Block] { ... } +# 278| body: [BlockStmt] { ... } # 279| 0: [DeclStmt] declaration # 279| 0: [VariableDeclarationEntry] definition of i # 279| Type = [IntType] int @@ -3779,12 +3779,12 @@ ir.cpp: # 280| Type = [IntType] int # 280| Value = [Literal] 10 # 280| ValueCategory = prvalue -# 280| 3: [Block] { ... } +# 280| 3: [BlockStmt] { ... } # 281| 0: [EmptyStmt] ; # 283| 2: [ReturnStmt] return ... # 285| [TopLevelFunction] void For_Update() # 285| params: -# 285| body: [Block] { ... } +# 285| body: [BlockStmt] { ... } # 286| 0: [DeclStmt] declaration # 286| 0: [VariableDeclarationEntry] definition of i # 286| Type = [IntType] int @@ -3804,11 +3804,11 @@ ir.cpp: # 287| Type = [IntType] int # 287| Value = [Literal] 1 # 287| ValueCategory = prvalue -# 287| 3: [Block] { ... } +# 287| 3: [BlockStmt] { ... } # 288| 0: [EmptyStmt] ; # 292| [TopLevelFunction] void For_InitCondition() # 292| params: -# 292| body: [Block] { ... } +# 292| body: [BlockStmt] { ... } # 293| 0: [ForStmt] for(...;...;...) ... # 293| 0: [DeclStmt] declaration # 293| 0: [VariableDeclarationEntry] definition of i @@ -3828,12 +3828,12 @@ ir.cpp: # 293| Type = [IntType] int # 293| Value = [Literal] 10 # 293| ValueCategory = prvalue -# 293| 3: [Block] { ... } +# 293| 3: [BlockStmt] { ... } # 294| 0: [EmptyStmt] ; # 296| 1: [ReturnStmt] return ... # 298| [TopLevelFunction] void For_InitUpdate() # 298| params: -# 298| body: [Block] { ... } +# 298| body: [BlockStmt] { ... } # 299| 0: [ForStmt] for(...;...;...) ... # 299| 0: [DeclStmt] declaration # 299| 0: [VariableDeclarationEntry] definition of i @@ -3853,11 +3853,11 @@ ir.cpp: # 299| Type = [IntType] int # 299| Value = [Literal] 1 # 299| ValueCategory = prvalue -# 299| 3: [Block] { ... } +# 299| 3: [BlockStmt] { ... } # 300| 0: [EmptyStmt] ; # 304| [TopLevelFunction] void For_ConditionUpdate() # 304| params: -# 304| body: [Block] { ... } +# 304| body: [BlockStmt] { ... } # 305| 0: [DeclStmt] declaration # 305| 0: [VariableDeclarationEntry] definition of i # 305| Type = [IntType] int @@ -3887,12 +3887,12 @@ ir.cpp: # 306| Type = [IntType] int # 306| Value = [Literal] 1 # 306| ValueCategory = prvalue -# 306| 3: [Block] { ... } +# 306| 3: [BlockStmt] { ... } # 307| 0: [EmptyStmt] ; # 309| 2: [ReturnStmt] return ... # 311| [TopLevelFunction] void For_InitConditionUpdate() # 311| params: -# 311| body: [Block] { ... } +# 311| body: [BlockStmt] { ... } # 312| 0: [ForStmt] for(...;...;...) ... # 312| 0: [DeclStmt] declaration # 312| 0: [VariableDeclarationEntry] definition of i @@ -3922,12 +3922,12 @@ ir.cpp: # 312| Type = [IntType] int # 312| Value = [Literal] 1 # 312| ValueCategory = prvalue -# 312| 3: [Block] { ... } +# 312| 3: [BlockStmt] { ... } # 313| 0: [EmptyStmt] ; # 315| 1: [ReturnStmt] return ... # 317| [TopLevelFunction] void For_Break() # 317| params: -# 317| body: [Block] { ... } +# 317| body: [BlockStmt] { ... } # 318| 0: [ForStmt] for(...;...;...) ... # 318| 0: [DeclStmt] declaration # 318| 0: [VariableDeclarationEntry] definition of i @@ -3957,7 +3957,7 @@ ir.cpp: # 318| Type = [IntType] int # 318| Value = [Literal] 1 # 318| ValueCategory = prvalue -# 318| 3: [Block] { ... } +# 318| 3: [BlockStmt] { ... } # 319| 0: [IfStmt] if (...) ... # 319| 0: [EQExpr] ... == ... # 319| Type = [BoolType] bool @@ -3969,13 +3969,13 @@ ir.cpp: # 319| Type = [IntType] int # 319| Value = [Literal] 5 # 319| ValueCategory = prvalue -# 319| 1: [Block] { ... } +# 319| 1: [BlockStmt] { ... } # 320| 0: [BreakStmt] break; # 322| 1: [LabelStmt] label ...: # 323| 2: [ReturnStmt] return ... # 325| [TopLevelFunction] void For_Continue_Update() # 325| params: -# 325| body: [Block] { ... } +# 325| body: [BlockStmt] { ... } # 326| 0: [ForStmt] for(...;...;...) ... # 326| 0: [DeclStmt] declaration # 326| 0: [VariableDeclarationEntry] definition of i @@ -4005,7 +4005,7 @@ ir.cpp: # 326| Type = [IntType] int # 326| Value = [Literal] 1 # 326| ValueCategory = prvalue -# 326| 3: [Block] { ... } +# 326| 3: [BlockStmt] { ... } # 327| 0: [IfStmt] if (...) ... # 327| 0: [EQExpr] ... == ... # 327| Type = [BoolType] bool @@ -4017,13 +4017,13 @@ ir.cpp: # 327| Type = [IntType] int # 327| Value = [Literal] 5 # 327| ValueCategory = prvalue -# 327| 1: [Block] { ... } +# 327| 1: [BlockStmt] { ... } # 328| 0: [ContinueStmt] continue; # 326| 1: [LabelStmt] label ...: # 331| 1: [ReturnStmt] return ... # 333| [TopLevelFunction] void For_Continue_NoUpdate() # 333| params: -# 333| body: [Block] { ... } +# 333| body: [BlockStmt] { ... } # 334| 0: [ForStmt] for(...;...;...) ... # 334| 0: [DeclStmt] declaration # 334| 0: [VariableDeclarationEntry] definition of i @@ -4043,7 +4043,7 @@ ir.cpp: # 334| Type = [IntType] int # 334| Value = [Literal] 10 # 334| ValueCategory = prvalue -# 334| 3: [Block] { ... } +# 334| 3: [BlockStmt] { ... } # 335| 0: [IfStmt] if (...) ... # 335| 0: [EQExpr] ... == ... # 335| Type = [BoolType] bool @@ -4055,7 +4055,7 @@ ir.cpp: # 335| Type = [IntType] int # 335| Value = [Literal] 5 # 335| ValueCategory = prvalue -# 335| 1: [Block] { ... } +# 335| 1: [BlockStmt] { ... } # 336| 0: [ContinueStmt] continue; # 334| 1: [LabelStmt] label ...: # 339| 1: [ReturnStmt] return ... @@ -4063,7 +4063,7 @@ ir.cpp: # 341| params: # 341| 0: [Parameter] p # 341| Type = [IntPointerType] int * -# 341| body: [Block] { ... } +# 341| body: [BlockStmt] { ... } # 342| 0: [ExprStmt] ExprStmt # 342| 0: [AssignExpr] ... = ... # 342| Type = [IntType] int @@ -4087,7 +4087,7 @@ ir.cpp: # 343| ValueCategory = prvalue(load) # 348| [TopLevelFunction] int* AddressOf() # 348| params: -# 348| body: [Block] { ... } +# 348| body: [BlockStmt] { ... } # 349| 0: [ReturnStmt] return ... # 349| 0: [AddressOfExpr] & ... # 349| Type = [IntPointerType] int * @@ -4099,7 +4099,7 @@ ir.cpp: # 352| params: # 352| 0: [Parameter] n # 352| Type = [IntType] int -# 352| body: [Block] { ... } +# 352| body: [BlockStmt] { ... } # 353| 0: [WhileStmt] while (...) ... # 353| 0: [GTExpr] ... > ... # 353| Type = [BoolType] bool @@ -4111,7 +4111,7 @@ ir.cpp: # 353| Type = [IntType] int # 353| Value = [Literal] 0 # 353| ValueCategory = prvalue -# 353| 1: [Block] { ... } +# 353| 1: [BlockStmt] { ... } # 354| 0: [IfStmt] if (...) ... # 354| 0: [EQExpr] ... == ... # 354| Type = [BoolType] bool @@ -4141,7 +4141,7 @@ ir.cpp: # 360| params: # 360| 0: [Parameter] n # 360| Type = [IntType] int -# 360| body: [Block] { ... } +# 360| body: [BlockStmt] { ... } # 361| 0: [DoStmt] do (...) ... # 366| 0: [GTExpr] ... > ... # 366| Type = [BoolType] bool @@ -4153,7 +4153,7 @@ ir.cpp: # 366| Type = [IntType] int # 366| Value = [Literal] 0 # 366| ValueCategory = prvalue -# 361| 1: [Block] { ... } +# 361| 1: [BlockStmt] { ... } # 362| 0: [IfStmt] if (...) ... # 362| 0: [EQExpr] ... == ... # 362| Type = [BoolType] bool @@ -4165,7 +4165,7 @@ ir.cpp: # 362| Type = [IntType] int # 362| Value = [Literal] 1 # 362| ValueCategory = prvalue -# 362| 1: [Block] { ... } +# 362| 1: [BlockStmt] { ... } # 363| 0: [ContinueStmt] continue; # 365| 1: [ExprStmt] ExprStmt # 365| 0: [AssignSubExpr] ... -= ... @@ -4190,7 +4190,7 @@ ir.cpp: # 370| Type = [IntType] int # 372| [TopLevelFunction] void Call() # 372| params: -# 372| body: [Block] { ... } +# 372| body: [BlockStmt] { ... } # 373| 0: [ExprStmt] ExprStmt # 373| 0: [FunctionCall] call to VoidFunc # 373| Type = [VoidType] void @@ -4202,7 +4202,7 @@ ir.cpp: # 376| Type = [IntType] int # 376| 1: [Parameter] y # 376| Type = [IntType] int -# 376| body: [Block] { ... } +# 376| body: [BlockStmt] { ... } # 377| 0: [ReturnStmt] return ... # 377| 0: [FunctionCall] call to Add # 377| Type = [IntType] int @@ -4219,7 +4219,7 @@ ir.cpp: # 380| Type = [IntType] int # 380| 1: [Parameter] y # 380| Type = [IntType] int -# 380| body: [Block] { ... } +# 380| body: [BlockStmt] { ... } # 381| 0: [ReturnStmt] return ... # 381| 0: [CommaExpr] ... , ... # 381| Type = [IntType] int @@ -4240,7 +4240,7 @@ ir.cpp: # 384| params: # 384| 0: [Parameter] x # 384| Type = [IntType] int -# 384| body: [Block] { ... } +# 384| body: [BlockStmt] { ... } # 385| 0: [DeclStmt] declaration # 385| 0: [VariableDeclarationEntry] definition of y # 385| Type = [IntType] int @@ -4248,7 +4248,7 @@ ir.cpp: # 386| 0: [VariableAccess] x # 386| Type = [IntType] int # 386| ValueCategory = prvalue(load) -# 386| 1: [Block] { ... } +# 386| 1: [BlockStmt] { ... } # 387| 0: [ExprStmt] ExprStmt # 387| 0: [AssignExpr] ... = ... # 387| Type = [IntType] int @@ -4386,14 +4386,14 @@ ir.cpp: # 422| params: # 422| 0: [Parameter] pt # 422| Type = [Struct] Point -# 422| body: [Block] { ... } +# 422| body: [BlockStmt] { ... } # 423| 0: [ReturnStmt] return ... # 423| 0: [VariableAccess] pt # 423| Type = [Struct] Point # 423| ValueCategory = prvalue(load) # 426| [TopLevelFunction] void FieldAccess() # 426| params: -# 426| body: [Block] { ... } +# 426| body: [BlockStmt] { ... } # 427| 0: [DeclStmt] declaration # 427| 0: [VariableDeclarationEntry] definition of pt # 427| Type = [Struct] Point @@ -4447,7 +4447,7 @@ ir.cpp: # 433| Type = [BoolType] bool # 433| 1: [Parameter] b # 433| Type = [BoolType] bool -# 433| body: [Block] { ... } +# 433| body: [BlockStmt] { ... } # 434| 0: [DeclStmt] declaration # 434| 0: [VariableDeclarationEntry] definition of x # 434| Type = [IntType] int @@ -4461,7 +4461,7 @@ ir.cpp: # 435| 1: [VariableAccess] b # 435| Type = [BoolType] bool # 435| ValueCategory = prvalue(load) -# 435| 1: [Block] { ... } +# 435| 1: [BlockStmt] { ... } # 436| 0: [ExprStmt] ExprStmt # 436| 0: [AssignExpr] ... = ... # 436| Type = [IntType] int @@ -4483,7 +4483,7 @@ ir.cpp: # 439| 1: [VariableAccess] b # 439| Type = [BoolType] bool # 439| ValueCategory = prvalue(load) -# 439| 1: [Block] { ... } +# 439| 1: [BlockStmt] { ... } # 440| 0: [ExprStmt] ExprStmt # 440| 0: [AssignExpr] ... = ... # 440| Type = [IntType] int @@ -4495,7 +4495,7 @@ ir.cpp: # 440| Type = [IntType] int # 440| Value = [Literal] 1 # 440| ValueCategory = prvalue -# 442| 2: [Block] { ... } +# 442| 2: [BlockStmt] { ... } # 443| 0: [ExprStmt] ExprStmt # 443| 0: [AssignExpr] ... = ... # 443| Type = [IntType] int @@ -4514,7 +4514,7 @@ ir.cpp: # 447| Type = [BoolType] bool # 447| 1: [Parameter] b # 447| Type = [BoolType] bool -# 447| body: [Block] { ... } +# 447| body: [BlockStmt] { ... } # 448| 0: [DeclStmt] declaration # 448| 0: [VariableDeclarationEntry] definition of x # 448| Type = [IntType] int @@ -4528,7 +4528,7 @@ ir.cpp: # 449| 1: [VariableAccess] b # 449| Type = [BoolType] bool # 449| ValueCategory = prvalue(load) -# 449| 1: [Block] { ... } +# 449| 1: [BlockStmt] { ... } # 450| 0: [ExprStmt] ExprStmt # 450| 0: [AssignExpr] ... = ... # 450| Type = [IntType] int @@ -4550,7 +4550,7 @@ ir.cpp: # 453| 1: [VariableAccess] b # 453| Type = [BoolType] bool # 453| ValueCategory = prvalue(load) -# 453| 1: [Block] { ... } +# 453| 1: [BlockStmt] { ... } # 454| 0: [ExprStmt] ExprStmt # 454| 0: [AssignExpr] ... = ... # 454| Type = [IntType] int @@ -4562,7 +4562,7 @@ ir.cpp: # 454| Type = [IntType] int # 454| Value = [Literal] 1 # 454| ValueCategory = prvalue -# 456| 2: [Block] { ... } +# 456| 2: [BlockStmt] { ... } # 457| 0: [ExprStmt] ExprStmt # 457| 0: [AssignExpr] ... = ... # 457| Type = [IntType] int @@ -4581,7 +4581,7 @@ ir.cpp: # 461| Type = [BoolType] bool # 461| 1: [Parameter] b # 461| Type = [BoolType] bool -# 461| body: [Block] { ... } +# 461| body: [BlockStmt] { ... } # 462| 0: [DeclStmt] declaration # 462| 0: [VariableDeclarationEntry] definition of x # 462| Type = [IntType] int @@ -4592,7 +4592,7 @@ ir.cpp: # 463| 0: [VariableAccess] a # 463| Type = [BoolType] bool # 463| ValueCategory = prvalue(load) -# 463| 1: [Block] { ... } +# 463| 1: [BlockStmt] { ... } # 464| 0: [ExprStmt] ExprStmt # 464| 0: [AssignExpr] ... = ... # 464| Type = [IntType] int @@ -4620,7 +4620,7 @@ ir.cpp: # 467| 1: [VariableAccess] b # 467| Type = [BoolType] bool # 467| ValueCategory = prvalue(load) -# 467| 1: [Block] { ... } +# 467| 1: [BlockStmt] { ... } # 468| 0: [ExprStmt] ExprStmt # 468| 0: [AssignExpr] ... = ... # 468| Type = [IntType] int @@ -4632,7 +4632,7 @@ ir.cpp: # 468| Type = [IntType] int # 468| Value = [Literal] 2 # 468| ValueCategory = prvalue -# 470| 2: [Block] { ... } +# 470| 2: [BlockStmt] { ... } # 471| 0: [ExprStmt] ExprStmt # 471| 0: [AssignExpr] ... = ... # 471| Type = [IntType] int @@ -4651,7 +4651,7 @@ ir.cpp: # 475| Type = [BoolType] bool # 475| 1: [Parameter] b # 475| Type = [BoolType] bool -# 475| body: [Block] { ... } +# 475| body: [BlockStmt] { ... } # 476| 0: [DeclStmt] declaration # 476| 0: [VariableDeclarationEntry] definition of x # 476| Type = [BoolType] bool @@ -4718,7 +4718,7 @@ ir.cpp: # 482| Type = [IntType] int # 482| 2: [Parameter] y # 482| Type = [IntType] int -# 482| body: [Block] { ... } +# 482| body: [BlockStmt] { ... } # 483| 0: [DeclStmt] declaration # 483| 0: [VariableDeclarationEntry] definition of z # 483| Type = [IntType] int @@ -4740,7 +4740,7 @@ ir.cpp: # 486| params: # 486| 0: [Parameter] a # 486| Type = [BoolType] bool -# 486| body: [Block] { ... } +# 486| body: [BlockStmt] { ... } # 487| 0: [DeclStmt] declaration # 487| 0: [VariableDeclarationEntry] definition of x # 487| Type = [IntType] int @@ -4775,7 +4775,7 @@ ir.cpp: # 492| params: # 492| 0: [Parameter] a # 492| Type = [BoolType] bool -# 492| body: [Block] { ... } +# 492| body: [BlockStmt] { ... } # 493| 0: [ExprStmt] ExprStmt # 493| 0: [ConditionalExpr] ... ? ... : ... # 493| Type = [VoidType] void @@ -4792,7 +4792,7 @@ ir.cpp: # 494| 1: [ReturnStmt] return ... # 496| [TopLevelFunction] void Nullptr() # 496| params: -# 496| body: [Block] { ... } +# 496| body: [BlockStmt] { ... } # 497| 0: [DeclStmt] declaration # 497| 0: [VariableDeclarationEntry] definition of p # 497| Type = [IntPointerType] int * @@ -4858,7 +4858,7 @@ ir.cpp: # 503| Type = [IntType] int # 503| 1: [Parameter] f # 503| Type = [FloatType] float -# 503| body: [Block] { ... } +# 503| body: [BlockStmt] { ... } # 504| 0: [DeclStmt] declaration # 504| 0: [VariableDeclarationEntry] definition of pt1 # 504| Type = [Struct] Point @@ -4916,7 +4916,7 @@ ir.cpp: # 512| Type = [IntType] int # 512| 1: [Parameter] f # 512| Type = [FloatType] float -# 512| body: [Block] { ... } +# 512| body: [BlockStmt] { ... } # 513| 0: [DeclStmt] declaration # 513| 0: [VariableDeclarationEntry] definition of r1 # 513| Type = [Struct] Rect @@ -5003,7 +5003,7 @@ ir.cpp: # 519| Type = [IntType] int # 519| 1: [Parameter] f # 519| Type = [FloatType] float -# 519| body: [Block] { ... } +# 519| body: [BlockStmt] { ... } # 520| 0: [DeclStmt] declaration # 520| 0: [VariableDeclarationEntry] definition of a1 # 520| Type = [ArrayType] int[3] @@ -5057,7 +5057,7 @@ ir.cpp: # 530| Type = [IntType] int # 530| 1: [Parameter] f # 530| Type = [FloatType] float -# 530| body: [Block] { ... } +# 530| body: [BlockStmt] { ... } # 531| 0: [DeclStmt] declaration # 531| 0: [VariableDeclarationEntry] definition of u1 # 531| Type = [Union] U @@ -5079,7 +5079,7 @@ ir.cpp: # 535| Type = [IntType] int # 535| 1: [Parameter] y # 535| Type = [IntType] int -# 535| body: [Block] { ... } +# 535| body: [BlockStmt] { ... } # 536| 0: [IfStmt] if (...) ... # 536| 0: [LTExpr] ... < ... # 536| Type = [BoolType] bool @@ -5090,7 +5090,7 @@ ir.cpp: # 536| 1: [VariableAccess] y # 536| Type = [IntType] int # 536| ValueCategory = prvalue(load) -# 536| 1: [Block] { ... } +# 536| 1: [BlockStmt] { ... } # 537| 0: [ReturnStmt] return ... # 540| 1: [ExprStmt] ExprStmt # 540| 0: [AssignExpr] ... = ... @@ -5109,7 +5109,7 @@ ir.cpp: # 543| Type = [IntType] int # 543| 1: [Parameter] y # 543| Type = [IntType] int -# 543| body: [Block] { ... } +# 543| body: [BlockStmt] { ... } # 544| 0: [IfStmt] if (...) ... # 544| 0: [LTExpr] ... < ... # 544| Type = [BoolType] bool @@ -5120,7 +5120,7 @@ ir.cpp: # 544| 1: [VariableAccess] y # 544| Type = [IntType] int # 544| ValueCategory = prvalue(load) -# 544| 1: [Block] { ... } +# 544| 1: [BlockStmt] { ... } # 545| 0: [ReturnStmt] return ... # 545| 0: [VariableAccess] x # 545| Type = [IntType] int @@ -5139,7 +5139,7 @@ ir.cpp: # 551| params: # 551| 0: [Parameter] pfn # 551| Type = [FunctionPointerType] ..(*)(..) -# 551| body: [Block] { ... } +# 551| body: [BlockStmt] { ... } # 552| 0: [ReturnStmt] return ... # 552| 0: [VariableCall] call to expression # 552| Type = [IntType] int @@ -5155,7 +5155,7 @@ ir.cpp: # 560| params: # 560| 0: [Parameter] e # 560| Type = [CTypedefType] E -# 560| body: [Block] { ... } +# 560| body: [BlockStmt] { ... } # 561| 0: [SwitchStmt] switch (...) ... # 561| 0: [CStyleCast] (int)... # 561| Conversion = [IntegralConversion] integral conversion @@ -5164,7 +5164,7 @@ ir.cpp: # 561| expr: [VariableAccess] e # 561| Type = [CTypedefType] E # 561| ValueCategory = prvalue(load) -# 561| 1: [Block] { ... } +# 561| 1: [BlockStmt] { ... } # 562| 0: [SwitchCase] case ...: # 562| 0: [CStyleCast] (int)... # 562| Conversion = [IntegralConversion] integral conversion @@ -5207,7 +5207,7 @@ ir.cpp: # 567| ValueCategory = prvalue # 571| [TopLevelFunction] void InitArray() # 571| params: -# 571| body: [Block] { ... } +# 571| body: [BlockStmt] { ... } # 572| 0: [DeclStmt] declaration # 572| 0: [VariableDeclarationEntry] definition of a_pad # 572| Type = [ArrayType] char[32] @@ -5306,7 +5306,7 @@ ir.cpp: # 582| Type = [PointerType] const char * # 584| [TopLevelFunction] void VarArgs() # 584| params: -# 584| body: [Block] { ... } +# 584| body: [BlockStmt] { ... } # 585| 0: [ExprStmt] ExprStmt # 585| 0: [FunctionCall] call to VarArgFunction # 585| Type = [VoidType] void @@ -5336,7 +5336,7 @@ ir.cpp: # 588| Type = [IntType] int # 590| [TopLevelFunction] void SetFuncPtr() # 590| params: -# 590| body: [Block] { ... } +# 590| body: [BlockStmt] { ... } # 591| 0: [DeclStmt] declaration # 591| 0: [VariableDeclarationEntry] definition of pfn # 591| Type = [FunctionPointerType] ..(*)(..) @@ -5421,7 +5421,7 @@ ir.cpp: # 613| params: # 615| [TopLevelFunction] void DeclareObject() # 615| params: -# 615| body: [Block] { ... } +# 615| body: [BlockStmt] { ... } # 616| 0: [DeclStmt] declaration # 616| 0: [VariableDeclarationEntry] definition of s1 # 616| Type = [Struct] String @@ -5473,7 +5473,7 @@ ir.cpp: # 622| Type = [PointerType] String * # 622| 2: [Parameter] s # 622| Type = [Struct] String -# 622| body: [Block] { ... } +# 622| body: [BlockStmt] { ... } # 623| 0: [ExprStmt] ExprStmt # 623| 0: [FunctionCall] call to c_str # 623| Type = [PointerType] const char * @@ -5529,7 +5529,7 @@ ir.cpp: #-----| Type = [RValueReferenceType] C && # 628| [Destructor] void C::~C() # 628| params: -#-----| body: [Block] { ... } +#-----| body: [BlockStmt] { ... } #-----| 0: [ReturnStmt] return ... # 628| destructions: # 628| 0: [DestructorFieldDestruction] destructor field destruction of m_f @@ -5554,7 +5554,7 @@ ir.cpp: # 630| params: # 630| 0: [Parameter] x # 630| Type = [IntType] int -# 630| body: [Block] { ... } +# 630| body: [BlockStmt] { ... } # 631| 0: [ReturnStmt] return ... # 631| 0: [VariableAccess] x # 631| Type = [IntType] int @@ -5563,7 +5563,7 @@ ir.cpp: # 634| params: # 634| 0: [Parameter] x # 634| Type = [IntType] int -# 634| body: [Block] { ... } +# 634| body: [BlockStmt] { ... } # 635| 0: [ReturnStmt] return ... # 635| 0: [VariableAccess] x # 635| Type = [IntType] int @@ -5572,14 +5572,14 @@ ir.cpp: # 638| params: # 638| 0: [Parameter] x # 638| Type = [IntType] int -# 638| body: [Block] { ... } +# 638| body: [BlockStmt] { ... } # 639| 0: [ReturnStmt] return ... # 639| 0: [VariableAccess] x # 639| Type = [IntType] int # 639| ValueCategory = prvalue(load) # 642| [MemberFunction] void C::FieldAccess() # 642| params: -# 642| body: [Block] { ... } +# 642| body: [BlockStmt] { ... } # 643| 0: [ExprStmt] ExprStmt # 643| 0: [AssignExpr] ... = ... # 643| Type = [IntType] int @@ -5679,7 +5679,7 @@ ir.cpp: # 650| 7: [ReturnStmt] return ... # 652| [MemberFunction] void C::MethodCalls() # 652| params: -# 652| body: [Block] { ... } +# 652| body: [BlockStmt] { ... } # 653| 0: [ExprStmt] ExprStmt # 653| 0: [FunctionCall] call to InstanceMemberFunction # 653| Type = [IntType] int @@ -5768,13 +5768,13 @@ ir.cpp: # 662| Type = [ArrayType] const char[5] # 662| Value = [StringLiteral] "test" # 662| ValueCategory = lvalue -# 663| body: [Block] { ... } +# 663| body: [BlockStmt] { ... } # 664| 0: [ReturnStmt] return ... # 675| [TopLevelFunction] int DerefReference(int&) # 675| params: # 675| 0: [Parameter] r # 675| Type = [LValueReferenceType] int & -# 675| body: [Block] { ... } +# 675| body: [BlockStmt] { ... } # 676| 0: [ReturnStmt] return ... # 676| 0: [ReferenceDereferenceExpr] (reference dereference) # 676| Type = [IntType] int @@ -5784,7 +5784,7 @@ ir.cpp: # 676| ValueCategory = prvalue(load) # 679| [TopLevelFunction] int& TakeReference() # 679| params: -# 679| body: [Block] { ... } +# 679| body: [BlockStmt] { ... } # 680| 0: [ReturnStmt] return ... # 680| 0: [ReferenceToExpr] (reference to) # 680| Type = [LValueReferenceType] int & @@ -5798,7 +5798,7 @@ ir.cpp: # 685| params: # 685| 0: [Parameter] x # 685| Type = [IntType] int -# 685| body: [Block] { ... } +# 685| body: [BlockStmt] { ... } # 686| 0: [DeclStmt] declaration # 686| 0: [VariableDeclarationEntry] definition of r # 686| Type = [LValueReferenceType] int & @@ -5842,7 +5842,7 @@ ir.cpp: # 689| 3: [ReturnStmt] return ... # 691| [TopLevelFunction] void ArrayReferences() # 691| params: -# 691| body: [Block] { ... } +# 691| body: [BlockStmt] { ... } # 692| 0: [DeclStmt] declaration # 692| 0: [VariableDeclarationEntry] definition of a # 692| Type = [ArrayType] int[10] @@ -5879,7 +5879,7 @@ ir.cpp: # 695| 3: [ReturnStmt] return ... # 697| [TopLevelFunction] void FunctionReferences() # 697| params: -# 697| body: [Block] { ... } +# 697| body: [BlockStmt] { ... } # 698| 0: [DeclStmt] declaration # 698| 0: [VariableDeclarationEntry] definition of rfn # 698| Type = [FunctionReferenceType] ..(&)(..) @@ -5921,7 +5921,7 @@ ir.cpp: # 704| Type = [TemplateParameter] T # 704| 1: [Parameter] y # 704| Type = [TemplateParameter] T -# 704| body: [Block] { ... } +# 704| body: [BlockStmt] { ... } # 705| 0: [ReturnStmt] return ... # 705| 0: [ConditionalExpr] ... ? ... : ... # 705| Type = [UnknownType] unknown @@ -5954,7 +5954,7 @@ ir.cpp: # 704| Type = [IntType] int # 704| 1: [Parameter] y # 704| Type = [IntType] int -# 704| body: [Block] { ... } +# 704| body: [BlockStmt] { ... } # 705| 0: [ReturnStmt] return ... # 705| 0: [ConditionalExpr] ... ? ... : ... # 705| Type = [IntType] int @@ -5983,7 +5983,7 @@ ir.cpp: # 708| Type = [IntType] int # 708| 1: [Parameter] y # 708| Type = [IntType] int -# 708| body: [Block] { ... } +# 708| body: [BlockStmt] { ... } # 709| 0: [ReturnStmt] return ... # 709| 0: [FunctionCall] call to min # 709| Type = [IntType] int @@ -6008,7 +6008,7 @@ ir.cpp: # 715| Type = [TemplateParameter] U # 715| 1: [Parameter] y # 715| Type = [TemplateParameter] V -# 715| body: [Block] { ... } +# 715| body: [BlockStmt] { ... } # 716| 0: [ReturnStmt] return ... # 716| 0: [Literal] 0 # 716| Type = [TemplateParameter] T @@ -6026,7 +6026,7 @@ ir.cpp: # 715| Type = [VoidPointerType] void * # 715| 1: [Parameter] y # 715| Type = [PlainCharType] char -# 715| body: [Block] { ... } +# 715| body: [BlockStmt] { ... } # 716| 0: [ReturnStmt] return ... # 716| 0: [Literal] 0 # 716| Type = [LongType] long @@ -6034,7 +6034,7 @@ ir.cpp: # 716| ValueCategory = prvalue # 720| [TopLevelFunction] double CallNestedTemplateFunc() # 720| params: -# 720| body: [Block] { ... } +# 720| body: [BlockStmt] { ... } # 721| 0: [ReturnStmt] return ... # 721| 0: [CStyleCast] (double)... # 721| Conversion = [IntegralToFloatingPointConversion] integral to floating point conversion @@ -6060,9 +6060,9 @@ ir.cpp: # 724| params: # 724| 0: [Parameter] b # 724| Type = [BoolType] bool -# 724| body: [Block] { ... } +# 724| body: [BlockStmt] { ... } # 725| 0: [TryStmt] try { ... } -# 725| 0: [Block] { ... } +# 725| 0: [BlockStmt] { ... } # 726| 0: [DeclStmt] declaration # 726| 0: [VariableDeclarationEntry] definition of x # 726| Type = [IntType] int @@ -6075,7 +6075,7 @@ ir.cpp: # 727| 0: [VariableAccess] b # 727| Type = [BoolType] bool # 727| ValueCategory = prvalue(load) -# 727| 1: [Block] { ... } +# 727| 1: [BlockStmt] { ... } # 728| 0: [ExprStmt] ExprStmt # 728| 0: [ThrowExpr] throw ... # 728| Type = [PointerType] const char * @@ -6098,7 +6098,7 @@ ir.cpp: # 730| Type = [IntType] int # 730| Value = [Literal] 2 # 730| ValueCategory = prvalue -# 730| 1: [Block] { ... } +# 730| 1: [BlockStmt] { ... } # 731| 0: [ExprStmt] ExprStmt # 731| 0: [AssignExpr] ... = ... # 731| Type = [IntType] int @@ -6165,7 +6165,7 @@ ir.cpp: # 745| params: #-----| 0: [Parameter] p#0 #-----| Type = [LValueReferenceType] const Base & -#-----| body: [Block] { ... } +#-----| body: [BlockStmt] { ... } #-----| 0: [ExprStmt] ExprStmt #-----| 0: [ReferenceDereferenceExpr] (reference dereference) #-----| Type = [Struct] String @@ -6215,7 +6215,7 @@ ir.cpp: # 745| 0: [ConstructorCall] call to String # 745| Type = [VoidType] void # 745| ValueCategory = prvalue -# 745| body: [Block] { ... } +# 745| body: [BlockStmt] { ... } # 745| 0: [ReturnStmt] return ... # 748| [Constructor] void Base::Base() # 748| params: @@ -6226,11 +6226,11 @@ ir.cpp: # 748| 0: [ConstructorCall] call to String # 748| Type = [VoidType] void # 748| ValueCategory = prvalue -# 748| body: [Block] { ... } +# 748| body: [BlockStmt] { ... } # 749| 0: [ReturnStmt] return ... # 750| [Destructor] void Base::~Base() # 750| params: -# 750| body: [Block] { ... } +# 750| body: [BlockStmt] { ... } # 751| 0: [ReturnStmt] return ... # 750| destructions: # 751| 0: [DestructorFieldDestruction] destructor field destruction of base_s @@ -6246,7 +6246,7 @@ ir.cpp: # 754| params: #-----| 0: [Parameter] p#0 #-----| Type = [LValueReferenceType] const Middle & -#-----| body: [Block] { ... } +#-----| body: [BlockStmt] { ... } #-----| 0: [ExprStmt] ExprStmt #-----| 0: [ReferenceDereferenceExpr] (reference dereference) #-----| Type = [Struct,VirtualBaseClass] Base @@ -6334,11 +6334,11 @@ ir.cpp: # 757| 0: [ConstructorCall] call to String # 757| Type = [VoidType] void # 757| ValueCategory = prvalue -# 757| body: [Block] { ... } +# 757| body: [BlockStmt] { ... } # 758| 0: [ReturnStmt] return ... # 759| [Destructor] void Middle::~Middle() # 759| params: -# 759| body: [Block] { ... } +# 759| body: [BlockStmt] { ... } # 760| 0: [ReturnStmt] return ... # 759| destructions: # 760| 0: [DestructorFieldDestruction] destructor field destruction of middle_s @@ -6357,7 +6357,7 @@ ir.cpp: # 763| params: #-----| 0: [Parameter] p#0 #-----| Type = [LValueReferenceType] const Derived & -#-----| body: [Block] { ... } +#-----| body: [BlockStmt] { ... } #-----| 0: [ExprStmt] ExprStmt #-----| 0: [ReferenceDereferenceExpr] (reference dereference) #-----| Type = [Struct] Middle @@ -6445,11 +6445,11 @@ ir.cpp: # 766| 0: [ConstructorCall] call to String # 766| Type = [VoidType] void # 766| ValueCategory = prvalue -# 766| body: [Block] { ... } +# 766| body: [BlockStmt] { ... } # 767| 0: [ReturnStmt] return ... # 768| [Destructor] void Derived::~Derived() # 768| params: -# 768| body: [Block] { ... } +# 768| body: [BlockStmt] { ... } # 769| 0: [ReturnStmt] return ... # 768| destructions: # 769| 0: [DestructorFieldDestruction] destructor field destruction of derived_s @@ -6484,11 +6484,11 @@ ir.cpp: # 775| 0: [ConstructorCall] call to String # 775| Type = [VoidType] void # 775| ValueCategory = prvalue -# 775| body: [Block] { ... } +# 775| body: [BlockStmt] { ... } # 776| 0: [ReturnStmt] return ... # 777| [Destructor] void MiddleVB1::~MiddleVB1() # 777| params: -# 777| body: [Block] { ... } +# 777| body: [BlockStmt] { ... } # 778| 0: [ReturnStmt] return ... # 777| destructions: # 778| 0: [DestructorFieldDestruction] destructor field destruction of middlevb1_s @@ -6523,11 +6523,11 @@ ir.cpp: # 784| 0: [ConstructorCall] call to String # 784| Type = [VoidType] void # 784| ValueCategory = prvalue -# 784| body: [Block] { ... } +# 784| body: [BlockStmt] { ... } # 785| 0: [ReturnStmt] return ... # 786| [Destructor] void MiddleVB2::~MiddleVB2() # 786| params: -# 786| body: [Block] { ... } +# 786| body: [BlockStmt] { ... } # 787| 0: [ReturnStmt] return ... # 786| destructions: # 787| 0: [DestructorFieldDestruction] destructor field destruction of middlevb2_s @@ -6568,11 +6568,11 @@ ir.cpp: # 793| 0: [ConstructorCall] call to String # 793| Type = [VoidType] void # 793| ValueCategory = prvalue -# 793| body: [Block] { ... } +# 793| body: [BlockStmt] { ... } # 794| 0: [ReturnStmt] return ... # 795| [Destructor] void DerivedVB::~DerivedVB() # 795| params: -# 795| body: [Block] { ... } +# 795| body: [BlockStmt] { ... } # 796| 0: [ReturnStmt] return ... # 795| destructions: # 796| 0: [DestructorFieldDestruction] destructor field destruction of derivedvb_s @@ -6595,7 +6595,7 @@ ir.cpp: # 796| ValueCategory = prvalue # 799| [TopLevelFunction] void HierarchyConversions() # 799| params: -# 799| body: [Block] { ... } +# 799| body: [BlockStmt] { ... } # 800| 0: [DeclStmt] declaration # 800| 0: [VariableDeclarationEntry] definition of b # 800| Type = [Struct,VirtualBaseClass] Base @@ -7201,7 +7201,7 @@ ir.cpp: # 842| [Constructor] void PolymorphicBase::PolymorphicBase() # 842| params: # 842| initializations: -# 842| body: [Block] { ... } +# 842| body: [BlockStmt] { ... } # 842| 0: [ReturnStmt] return ... # 842| [CopyConstructor] void PolymorphicBase::PolymorphicBase(PolymorphicBase const&) # 842| params: @@ -7223,7 +7223,7 @@ ir.cpp: # 846| 0: [ConstructorDirectInit] call to PolymorphicBase # 846| Type = [VoidType] void # 846| ValueCategory = prvalue -# 846| body: [Block] { ... } +# 846| body: [BlockStmt] { ... } # 846| 0: [ReturnStmt] return ... # 846| [CopyConstructor] void PolymorphicDerived::PolymorphicDerived(PolymorphicDerived const&) # 846| params: @@ -7235,7 +7235,7 @@ ir.cpp: #-----| Type = [RValueReferenceType] PolymorphicDerived && # 846| [Destructor,VirtualFunction] void PolymorphicDerived::~PolymorphicDerived() # 846| params: -#-----| body: [Block] { ... } +#-----| body: [BlockStmt] { ... } #-----| 0: [ReturnStmt] return ... # 846| destructions: # 846| 0: [DestructorDirectDestruction] call to ~PolymorphicBase @@ -7243,7 +7243,7 @@ ir.cpp: # 846| ValueCategory = prvalue # 849| [TopLevelFunction] void DynamicCast() # 849| params: -# 849| body: [Block] { ... } +# 849| body: [BlockStmt] { ... } # 850| 0: [DeclStmt] declaration # 850| 0: [VariableDeclarationEntry] definition of b # 850| Type = [Struct] PolymorphicBase @@ -7370,11 +7370,11 @@ ir.cpp: # 868| Type = [ArrayType] const char[1] # 868| Value = [StringLiteral] "" # 868| ValueCategory = lvalue -# 868| body: [Block] { ... } +# 868| body: [BlockStmt] { ... } # 869| 0: [ReturnStmt] return ... # 871| [TopLevelFunction] void ArrayConversions() # 871| params: -# 871| body: [Block] { ... } +# 871| body: [BlockStmt] { ... } # 872| 0: [DeclStmt] declaration # 872| 0: [VariableDeclarationEntry] definition of a # 872| Type = [ArrayType] char[5] @@ -7513,7 +7513,7 @@ ir.cpp: # 883| Type = [FunctionPointerType] ..(*)(..) # 883| 1: [Parameter] p # 883| Type = [VoidPointerType] void * -# 883| body: [Block] { ... } +# 883| body: [BlockStmt] { ... } # 884| 0: [ExprStmt] ExprStmt # 884| 0: [AssignExpr] ... = ... # 884| Type = [VoidPointerType] void * @@ -7549,7 +7549,7 @@ ir.cpp: # 888| Type = [IntType] int # 888| 1: [Parameter] args # 888| Type = [ArrayType] __va_list_tag[1] -# 888| body: [Block] { ... } +# 888| body: [BlockStmt] { ... } # 889| 0: [DeclStmt] declaration # 889| 0: [VariableDeclarationEntry] definition of args2 # 889| Type = [ArrayType] __va_list_tag[1] @@ -7605,7 +7605,7 @@ ir.cpp: # 896| params: # 896| 0: [Parameter] x # 896| Type = [IntType] int -# 896| body: [Block] { ... } +# 896| body: [BlockStmt] { ... } # 897| 0: [DeclStmt] declaration # 897| 0: [VariableDeclarationEntry] definition of args # 897| Type = [ArrayType] __va_list_tag[1] @@ -7709,7 +7709,7 @@ ir.cpp: # 909| params: # 909| 0: [Parameter] x # 909| Type = [IntType] int -# 909| body: [Block] { ... } +# 909| body: [BlockStmt] { ... } # 910| 0: [ExprStmt] ExprStmt # 910| 0: [CStyleCast] (void)... # 910| Conversion = [VoidConversion] conversion to void @@ -7723,7 +7723,7 @@ ir.cpp: # 913| params: # 913| 0: [Parameter] x # 913| Type = [IntType] int -# 913| body: [Block] { ... } +# 913| body: [BlockStmt] { ... } # 914| 0: [DeclStmt] declaration # 914| 0: [VariableDeclarationEntry] definition of a # 914| Type = [BoolType] bool @@ -7876,7 +7876,7 @@ ir.cpp: # 946| Type = [DoubleType] double # 949| [TopLevelFunction] void OperatorNew() # 949| params: -# 949| body: [Block] { ... } +# 949| body: [BlockStmt] { ... } # 950| 0: [ExprStmt] ExprStmt # 950| 0: [NewExpr] new # 950| Type = [IntPointerType] int * @@ -7969,7 +7969,7 @@ ir.cpp: # 959| params: # 959| 0: [Parameter] n # 959| Type = [IntType] int -# 959| body: [Block] { ... } +# 959| body: [BlockStmt] { ... } # 960| 0: [ExprStmt] ExprStmt # 960| 0: [NewArrayExpr] new[] # 960| Type = [IntPointerType] int * @@ -8078,7 +8078,7 @@ ir.cpp: # 968| 8: [ReturnStmt] return ... # 970| [TopLevelFunction] int designatedInit() # 970| params: -# 970| body: [Block] { ... } +# 970| body: [BlockStmt] { ... } # 971| 0: [DeclStmt] declaration # 971| 0: [VariableDeclarationEntry] definition of a1 # 971| Type = [ArrayType] int[1000] @@ -8114,7 +8114,7 @@ ir.cpp: # 975| Type = [IntType] int # 975| 1: [Parameter] y # 975| Type = [IntType] int -# 975| body: [Block] { ... } +# 975| body: [BlockStmt] { ... } # 976| 0: [IfStmt] if (...) ... # 976| 0: [ConditionDeclExpr] (condition decl) # 976| Type = [BoolType] bool @@ -8122,7 +8122,7 @@ ir.cpp: # 976| 0: [VariableAccess] b # 976| Type = [BoolType] bool # 976| ValueCategory = prvalue(load) -# 976| 1: [Block] { ... } +# 976| 1: [BlockStmt] { ... } # 977| 0: [ExprStmt] ExprStmt # 977| 0: [AssignExpr] ... = ... # 977| Type = [IntType] int @@ -8145,7 +8145,7 @@ ir.cpp: # 979| expr: [VariableAccess] z # 979| Type = [IntType] int # 979| ValueCategory = prvalue(load) -# 979| 1: [Block] { ... } +# 979| 1: [BlockStmt] { ... } # 980| 0: [ExprStmt] ExprStmt # 980| 0: [AssignExpr] ... = ... # 980| Type = [IntType] int @@ -8168,7 +8168,7 @@ ir.cpp: # 982| expr: [VariableAccess] p # 982| Type = [IntPointerType] int * # 982| ValueCategory = prvalue(load) -# 982| 1: [Block] { ... } +# 982| 1: [BlockStmt] { ... } # 983| 0: [ExprStmt] ExprStmt # 983| 0: [AssignExpr] ... = ... # 983| Type = [IntType] int @@ -8190,7 +8190,7 @@ ir.cpp: # 987| Type = [IntType] int # 987| 1: [Parameter] y # 987| Type = [IntType] int -# 987| body: [Block] { ... } +# 987| body: [BlockStmt] { ... } # 988| 0: [WhileStmt] while (...) ... # 988| 0: [ConditionDeclExpr] (condition decl) # 988| Type = [BoolType] bool @@ -8198,7 +8198,7 @@ ir.cpp: # 988| 0: [VariableAccess] b # 988| Type = [BoolType] bool # 988| ValueCategory = prvalue(load) -# 988| 1: [Block] { ... } +# 988| 1: [BlockStmt] { ... } # 990| 1: [WhileStmt] while (...) ... # 990| 0: [ConditionDeclExpr] (condition decl) # 990| Type = [BoolType] bool @@ -8210,7 +8210,7 @@ ir.cpp: # 990| expr: [VariableAccess] z # 990| Type = [IntType] int # 990| ValueCategory = prvalue(load) -# 990| 1: [Block] { ... } +# 990| 1: [BlockStmt] { ... } # 992| 2: [WhileStmt] while (...) ... # 992| 0: [ConditionDeclExpr] (condition decl) # 992| Type = [BoolType] bool @@ -8222,7 +8222,7 @@ ir.cpp: # 992| expr: [VariableAccess] p # 992| Type = [IntPointerType] int * # 992| ValueCategory = prvalue(load) -# 992| 1: [Block] { ... } +# 992| 1: [BlockStmt] { ... } # 994| 3: [ReturnStmt] return ... # 996| [TopLevelFunction] int PointerDecay(int[], int(float)) # 996| params: @@ -8230,7 +8230,7 @@ ir.cpp: # 996| Type = [ArrayType] int[] # 996| 1: [Parameter] fn # 996| Type = [RoutineType] ..()(..) -# 996| body: [Block] { ... } +# 996| body: [BlockStmt] { ... } # 997| 0: [ReturnStmt] return ... # 997| 0: [AddExpr] ... + ... # 997| Type = [IntType] int @@ -8268,7 +8268,7 @@ ir.cpp: # 1000| Type = [IntType] int # 1000| 2: [Parameter] z # 1000| Type = [IntType] int -# 1000| body: [Block] { ... } +# 1000| body: [BlockStmt] { ... } # 1001| 0: [DeclStmt] declaration # 1001| 0: [VariableDeclarationEntry] definition of x # 1001| Type = [IntType] int @@ -8282,7 +8282,7 @@ ir.cpp: # 1011| ValueCategory = prvalue # 1015| [TopLevelFunction] void OperatorDelete() # 1015| params: -# 1015| body: [Block] { ... } +# 1015| body: [BlockStmt] { ... } # 1016| 0: [ExprStmt] ExprStmt # 1016| 0: [DeleteExpr] delete # 1016| Type = [VoidType] void @@ -8360,7 +8360,7 @@ ir.cpp: # 1021| 5: [ReturnStmt] return ... # 1024| [TopLevelFunction] void OperatorDeleteArray() # 1024| params: -# 1024| body: [Block] { ... } +# 1024| body: [BlockStmt] { ... } # 1025| 0: [ExprStmt] ExprStmt # 1025| 0: [DeleteArrayExpr] delete[] # 1025| Type = [VoidType] void @@ -8446,7 +8446,7 @@ ir.cpp: #-----| Type = [RValueReferenceType] EmptyStruct && # 1034| [TopLevelFunction] void EmptyStructInit() # 1034| params: -# 1034| body: [Block] { ... } +# 1034| body: [BlockStmt] { ... } # 1035| 0: [DeclStmt] declaration # 1035| 0: [VariableDeclarationEntry] definition of s # 1035| Type = [Struct] EmptyStruct @@ -8473,11 +8473,11 @@ ir.cpp: # 1038| params: # 1038| [ConstMemberFunction] void (lambda [] type at line 1038, col. 12)::operator()() const # 1038| params: -# 1038| body: [Block] { ... } +# 1038| body: [BlockStmt] { ... } # 1038| 0: [ReturnStmt] return ... # 1038| [ConstMemberFunction,ConversionOperator] void(* (lambda [] type at line 1038, col. 12)::operator void (*)()() const)() # 1038| params: -#-----| body: [Block] { ... } +#-----| body: [BlockStmt] { ... } # 1038| 0: [ReturnStmt] return ... # 1038| 0: [FunctionAccess] _FUN # 1038| Type = [FunctionPointerType] ..(*)(..) @@ -8488,7 +8488,7 @@ ir.cpp: # 1040| Type = [IntType] int # 1040| 1: [Parameter] s # 1040| Type = [LValueReferenceType] const String & -# 1040| body: [Block] { ... } +# 1040| body: [BlockStmt] { ... } # 1041| 0: [DeclStmt] declaration # 1041| 0: [VariableDeclarationEntry] definition of lambda_empty # 1041| Type = [Closure,LocalClass] decltype([...](...){...}) @@ -8807,7 +8807,7 @@ ir.cpp: # 1041| params: # 1041| 0: [Parameter] f # 1041| Type = [FloatType] float -# 1041| body: [Block] { ... } +# 1041| body: [BlockStmt] { ... } # 1041| 0: [ReturnStmt] return ... # 1041| 0: [CharLiteral] 65 # 1041| Type = [PlainCharType] char @@ -8815,7 +8815,7 @@ ir.cpp: # 1041| ValueCategory = prvalue # 1041| [ConstMemberFunction,ConversionOperator] char(* (void Lambda(int, String const&))::(lambda [] type at line 1041, col. 23)::operator char (*)(float)() const)(float) # 1041| params: -#-----| body: [Block] { ... } +#-----| body: [BlockStmt] { ... } # 1041| 0: [ReturnStmt] return ... # 1041| 0: [FunctionAccess] _FUN # 1041| Type = [FunctionPointerType] ..(*)(..) @@ -8838,7 +8838,7 @@ ir.cpp: # 1043| params: # 1043| 0: [Parameter] f # 1043| Type = [FloatType] float -# 1043| body: [Block] { ... } +# 1043| body: [BlockStmt] { ... } # 1043| 0: [ReturnStmt] return ... # 1043| 0: [ArrayExpr] access to array # 1043| Type = [PlainCharType] char @@ -8880,7 +8880,7 @@ ir.cpp: # 1045| params: # 1045| [Destructor] void (void Lambda(int, String const&))::(lambda [] type at line 1045, col. 21)::~() # 1045| params: -#-----| body: [Block] { ... } +#-----| body: [BlockStmt] { ... } #-----| 0: [ReturnStmt] return ... # 1045| destructions: # 1045| 0: [DestructorFieldDestruction] destructor field destruction of s @@ -8896,7 +8896,7 @@ ir.cpp: # 1045| params: # 1045| 0: [Parameter] f # 1045| Type = [FloatType] float -# 1045| body: [Block] { ... } +# 1045| body: [BlockStmt] { ... } # 1045| 0: [ReturnStmt] return ... # 1045| 0: [ArrayExpr] access to array # 1045| Type = [PlainCharType] char @@ -8934,7 +8934,7 @@ ir.cpp: # 1047| params: # 1047| 0: [Parameter] f # 1047| Type = [FloatType] float -# 1047| body: [Block] { ... } +# 1047| body: [BlockStmt] { ... } # 1047| 0: [ReturnStmt] return ... # 1047| 0: [ArrayExpr] access to array # 1047| Type = [PlainCharType] char @@ -8971,7 +8971,7 @@ ir.cpp: # 1049| params: # 1049| [Destructor] void (void Lambda(int, String const&))::(lambda [] type at line 1049, col. 30)::~() # 1049| params: -#-----| body: [Block] { ... } +#-----| body: [BlockStmt] { ... } #-----| 0: [ReturnStmt] return ... # 1049| destructions: # 1049| 0: [DestructorFieldDestruction] destructor field destruction of s @@ -8987,7 +8987,7 @@ ir.cpp: # 1049| params: # 1049| 0: [Parameter] f # 1049| Type = [FloatType] float -# 1049| body: [Block] { ... } +# 1049| body: [BlockStmt] { ... } # 1049| 0: [ReturnStmt] return ... # 1049| 0: [ArrayExpr] access to array # 1049| Type = [PlainCharType] char @@ -9023,7 +9023,7 @@ ir.cpp: # 1051| params: # 1051| 0: [Parameter] f # 1051| Type = [FloatType] float -# 1051| body: [Block] { ... } +# 1051| body: [BlockStmt] { ... } # 1051| 0: [ReturnStmt] return ... # 1051| 0: [ArrayExpr] access to array # 1051| Type = [PlainCharType] char @@ -9064,7 +9064,7 @@ ir.cpp: # 1054| params: # 1054| 0: [Parameter] f # 1054| Type = [FloatType] float -# 1054| body: [Block] { ... } +# 1054| body: [BlockStmt] { ... } # 1054| 0: [ReturnStmt] return ... # 1054| 0: [ArrayExpr] access to array # 1054| Type = [PlainCharType] char @@ -9164,7 +9164,7 @@ ir.cpp: # 1077| params: # 1077| 0: [Parameter] v # 1077| Type = [LValueReferenceType] const vector & -# 1077| body: [Block] { ... } +# 1077| body: [BlockStmt] { ... } # 1078| 0: [RangeBasedForStmt] for(...:...) ... # 1078| 0: [DeclStmt] declaration # 1078| 1: [DeclStmt] declaration @@ -9191,7 +9191,7 @@ ir.cpp: # 1078| Type = [NestedStruct] iterator # 1078| ValueCategory = lvalue # 1078| 4: [DeclStmt] declaration -# 1078| 5: [Block] { ... } +# 1078| 5: [BlockStmt] { ... } # 1079| 0: [IfStmt] if (...) ... # 1079| 0: [GTExpr] ... > ... # 1079| Type = [BoolType] bool @@ -9203,7 +9203,7 @@ ir.cpp: # 1079| Type = [IntType] int # 1079| Value = [Literal] 0 # 1079| ValueCategory = prvalue -# 1079| 1: [Block] { ... } +# 1079| 1: [BlockStmt] { ... } # 1080| 0: [ContinueStmt] continue; # 1078| 1: [LabelStmt] label ...: # 1084| 1: [RangeBasedForStmt] for(...:...) ... @@ -9232,7 +9232,7 @@ ir.cpp: # 1084| Type = [NestedStruct] iterator # 1084| ValueCategory = lvalue # 1084| 4: [DeclStmt] declaration -# 1084| 5: [Block] { ... } +# 1084| 5: [BlockStmt] { ... } # 1085| 0: [IfStmt] if (...) ... # 1085| 0: [LTExpr] ... < ... # 1085| Type = [BoolType] bool @@ -9247,7 +9247,7 @@ ir.cpp: # 1085| Type = [IntType] int # 1085| Value = [Literal] 5 # 1085| ValueCategory = prvalue -# 1085| 1: [Block] { ... } +# 1085| 1: [BlockStmt] { ... } # 1086| 0: [BreakStmt] break; # 1088| 2: [LabelStmt] label ...: # 1089| 3: [ReturnStmt] return ... @@ -9255,7 +9255,7 @@ ir.cpp: # 1108| params: # 1108| 0: [Parameter] x # 1108| Type = [IntType] int -# 1108| body: [Block] { ... } +# 1108| body: [BlockStmt] { ... } # 1109| 0: [AsmStmt] asm statement # 1110| 1: [ReturnStmt] return ... # 1110| 0: [VariableAccess] x @@ -9271,7 +9271,7 @@ ir.cpp: # 1113| Type = [LValueReferenceType] unsigned int & # 1113| 3: [Parameter] d # 1113| Type = [IntType] unsigned int -# 1114| body: [Block] { ... } +# 1114| body: [BlockStmt] { ... } # 1115| 0: [AsmStmt] asm statement # 1118| 0: [ReferenceDereferenceExpr] (reference dereference) # 1118| Type = [IntType] unsigned int @@ -9294,7 +9294,7 @@ ir.cpp: # 1120| 1: [ReturnStmt] return ... # 1122| [TopLevelFunction] void ExternDeclarations() # 1122| params: -# 1123| body: [Block] { ... } +# 1123| body: [BlockStmt] { ... } # 1124| 0: [DeclStmt] declaration # 1124| 0: [VariableDeclarationEntry] declaration of g # 1124| Type = [IntType] int @@ -9331,7 +9331,7 @@ ir.cpp: # 1127| Type = [FloatType] float # 1137| [TopLevelFunction] void ExternDeclarationsInMacro() # 1137| params: -# 1138| body: [Block] { ... } +# 1138| body: [BlockStmt] { ... } # 1139| 0: [DeclStmt] declaration # 1139| 0: [VariableDeclarationEntry] declaration of g # 1139| Type = [IntType] int @@ -9360,7 +9360,7 @@ ir.cpp: # 1139| 0: [VariableAccess] i # 1139| Type = [IntType] int # 1139| ValueCategory = lvalue -# 1139| 3: [Block] { ... } +# 1139| 3: [BlockStmt] { ... } # 1139| 0: [DeclStmt] declaration # 1139| 0: [VariableDeclarationEntry] declaration of g # 1139| Type = [IntType] int @@ -9370,9 +9370,9 @@ ir.cpp: # 1142| params: # 1142| 0: [Parameter] b # 1142| Type = [BoolType] bool -# 1142| body: [Block] { ... } +# 1142| body: [BlockStmt] { ... } # 1143| 0: [TryStmt] try { ... } -# 1143| 0: [Block] { ... } +# 1143| 0: [BlockStmt] { ... } # 1144| 0: [DeclStmt] declaration # 1144| 0: [VariableDeclarationEntry] definition of x # 1144| Type = [IntType] int @@ -9385,7 +9385,7 @@ ir.cpp: # 1145| 0: [VariableAccess] b # 1145| Type = [BoolType] bool # 1145| ValueCategory = prvalue(load) -# 1145| 1: [Block] { ... } +# 1145| 1: [BlockStmt] { ... } # 1146| 0: [ExprStmt] ExprStmt # 1146| 0: [ThrowExpr] throw ... # 1146| Type = [PointerType] const char * @@ -9408,7 +9408,7 @@ ir.cpp: # 1148| Type = [IntType] int # 1148| Value = [Literal] 2 # 1148| ValueCategory = prvalue -# 1148| 1: [Block] { ... } +# 1148| 1: [BlockStmt] { ... } # 1149| 0: [ExprStmt] ExprStmt # 1149| 0: [AssignExpr] ... = ... # 1149| Type = [IntType] int @@ -9469,7 +9469,7 @@ ir.cpp: # 1162| params: # 1162| 0: [Parameter] i # 1162| Type = [IntType] int -# 1162| body: [Block] { ... } +# 1162| body: [BlockStmt] { ... } # 1163| 0: [DeclStmt] declaration # 1163| 0: [VariableDeclarationEntry] definition of vi4 # 1163| Type = [SpecifiedType] __attribute((vector_size(16UL))) int @@ -9588,7 +9588,7 @@ ir.cpp: # 1172| params: # 1172| 0: [Parameter] x # 1172| Type = [IntType] int -# 1172| body: [Block] { ... } +# 1172| body: [BlockStmt] { ... } # 1173| 0: [DeclStmt] declaration # 1173| 0: [VariableDeclarationEntry] definition of y # 1173| Type = [IntType] int @@ -9631,7 +9631,7 @@ ir.cpp: # 1175| ValueCategory = prvalue(load) # 1178| [TopLevelFunction] String ReturnObjectImpl() # 1178| params: -# 1178| body: [Block] { ... } +# 1178| body: [BlockStmt] { ... } # 1179| 0: [ReturnStmt] return ... # 1179| 0: [ConstructorCall] call to String # 1179| Type = [Struct] String @@ -9647,7 +9647,7 @@ ir.cpp: # 1182| params: # 1182| 0: [Parameter] x # 1182| Type = [IntType] int -# 1182| body: [Block] { ... } +# 1182| body: [BlockStmt] { ... } # 1183| 0: [DeclStmt] declaration # 1183| 0: [VariableDeclarationEntry] definition of y # 1183| Type = [IntType] int @@ -9660,7 +9660,7 @@ ir.cpp: # 1184| 0: [VariableAccess] x # 1184| Type = [IntType] int # 1184| ValueCategory = prvalue(load) -# 1184| 1: [Block] { ... } +# 1184| 1: [BlockStmt] { ... } # 1185| 0: [SwitchCase] case ...: # 1185| 0: [Literal] 1 # 1185| Type = [IntType] int @@ -9689,7 +9689,7 @@ ir.cpp: # 1191| params: # 1191| 0: [Parameter] x # 1191| Type = [IntType] int -# 1191| body: [Block] { ... } +# 1191| body: [BlockStmt] { ... } # 1192| 0: [DeclStmt] declaration # 1192| 0: [VariableDeclarationEntry] definition of y # 1192| Type = [IntType] int @@ -9702,7 +9702,7 @@ ir.cpp: # 1193| 0: [VariableAccess] x # 1193| Type = [IntType] int # 1193| ValueCategory = prvalue(load) -# 1193| 1: [Block] { ... } +# 1193| 1: [BlockStmt] { ... } # 1194| 0: [SwitchCase] case ...: # 1194| 0: [Literal] 1 # 1194| Type = [IntType] int @@ -9747,7 +9747,7 @@ ir.cpp: # 1202| params: # 1202| 0: [Parameter] x # 1202| Type = [IntType] int -# 1202| body: [Block] { ... } +# 1202| body: [BlockStmt] { ... } # 1203| 0: [DeclStmt] declaration # 1203| 0: [VariableDeclarationEntry] definition of y # 1203| Type = [IntType] int @@ -9760,7 +9760,7 @@ ir.cpp: # 1204| 0: [VariableAccess] x # 1204| Type = [IntType] int # 1204| ValueCategory = prvalue(load) -# 1204| 1: [Block] { ... } +# 1204| 1: [BlockStmt] { ... } # 1205| 0: [SwitchCase] case ...: # 1205| 0: [Literal] 1 # 1205| Type = [IntType] int @@ -9807,7 +9807,7 @@ ir.cpp: # 1214| params: # 1214| 0: [Parameter] x # 1214| Type = [IntType] int -# 1214| body: [Block] { ... } +# 1214| body: [BlockStmt] { ... } # 1215| 0: [DeclStmt] declaration # 1215| 0: [VariableDeclarationEntry] definition of y # 1215| Type = [IntType] int @@ -9820,7 +9820,7 @@ ir.cpp: # 1216| 0: [VariableAccess] x # 1216| Type = [IntType] int # 1216| ValueCategory = prvalue(load) -# 1216| 1: [Block] { ... } +# 1216| 1: [BlockStmt] { ... } # 1217| 0: [SwitchCase] case ...: # 1217| 0: [Literal] 1 # 1217| Type = [IntType] int @@ -9880,7 +9880,7 @@ ir.cpp: # 1231| params: # 1231| 0: [Parameter] x # 1231| Type = [IntType] int -# 1231| body: [Block] { ... } +# 1231| body: [BlockStmt] { ... } # 1232| 0: [DeclStmt] declaration # 1232| 0: [VariableDeclarationEntry] definition of a # 1232| Type = [IntType] int @@ -9944,7 +9944,7 @@ ir.cpp: # 1240| params: # 1240| 0: [Parameter] dynamic # 1240| Type = [PointerType] const char * -# 1240| body: [Block] { ... } +# 1240| body: [BlockStmt] { ... } # 1241| 0: [DeclStmt] declaration # 1241| 0: [VariableDeclarationEntry] definition of a # 1241| Type = [Struct] String @@ -9995,7 +9995,7 @@ ir.cpp: # 1251| Type = [CharPointerType] char * # 1251| 1: [Parameter] s2 # 1251| Type = [CharPointerType] char * -# 1251| body: [Block] { ... } +# 1251| body: [BlockStmt] { ... } # 1252| 0: [DeclStmt] declaration # 1252| 0: [VariableDeclarationEntry] definition of buffer # 1252| Type = [ArrayType] char[1024] @@ -10061,7 +10061,7 @@ ir.cpp: # 1261| Type = [PointerType] A * # 1261| 1: [Parameter] x # 1261| Type = [IntType] int -# 1261| body: [Block] { ... } +# 1261| body: [BlockStmt] { ... } # 1262| 0: [ExprStmt] ExprStmt # 1262| 0: [AssignExpr] ... = ... # 1262| Type = [IntType] int @@ -10086,7 +10086,7 @@ ir.cpp: # 1270| Type = [IntType] int # 1270| 1: [Parameter] a_arg # 1270| Type = [PointerType] A * -# 1270| body: [Block] { ... } +# 1270| body: [BlockStmt] { ... } # 1271| 0: [DeclStmt] declaration # 1271| 0: [VariableDeclarationEntry] definition of c # 1271| Type = [Class] C @@ -10237,12 +10237,12 @@ ir.cpp: # 1289| Type = [BoolType] bool # 1289| 1: [Parameter] x # 1289| Type = [IntType] int -# 1289| body: [Block] { ... } +# 1289| body: [BlockStmt] { ... } # 1290| 0: [IfStmt] if (...) ... # 1290| 0: [VariableAccess] b # 1290| Type = [BoolType] bool # 1290| ValueCategory = prvalue(load) -# 1290| 1: [Block] { ... } +# 1290| 1: [BlockStmt] { ... } # 1291| 0: [ReturnStmt] return ... # 1291| 0: [VariableAccess] x # 1291| Type = [IntType] int @@ -10254,7 +10254,7 @@ ir.cpp: # 1295| Type = [IntType] int # 1295| 1: [Parameter] y # 1295| Type = [IntType] int -# 1295| body: [Block] { ... } +# 1295| body: [BlockStmt] { ... } # 1296| 0: [ReturnStmt] return ... # 1296| 0: [FunctionCall] call to IntegerOps # 1296| Type = [VoidType] void @@ -10273,7 +10273,7 @@ ir.cpp: # 1299| Type = [IntType] int # 1299| 2: [Parameter] y # 1299| Type = [LongType] long -# 1299| body: [Block] { ... } +# 1299| body: [BlockStmt] { ... } # 1300| 0: [DeclStmt] declaration # 1300| 0: [VariableDeclarationEntry] definition of z # 1300| Type = [IntType] int @@ -10463,7 +10463,7 @@ ir.cpp: # 1314| Type = [IntType] int # 1314| 1: [Parameter] y # 1314| Type = [IntType] int -# 1314| body: [Block] { ... } +# 1314| body: [BlockStmt] { ... } # 1315| 0: [ReturnStmt] return ... # 1315| 0: [ConditionalExpr] ... ? ... : ... # 1315| Type = [IntType] int @@ -10493,7 +10493,7 @@ ir.cpp: # 1320| params: # 1320| 0: [Parameter] p # 1320| Type = [IntPointerType] int * -# 1321| body: [Block] { ... } +# 1321| body: [BlockStmt] { ... } # 1322| 0: [ExprStmt] ExprStmt # 1322| 0: [NewExpr] new # 1322| Type = [IntPointerType] int * @@ -10538,11 +10538,11 @@ perf-regression.cpp: # 6| 0: [ArrayAggregateLiteral] {...} # 6| Type = [ArrayType] char[1073741824] # 6| ValueCategory = prvalue -# 6| body: [Block] { ... } +# 6| body: [BlockStmt] { ... } # 6| 0: [ReturnStmt] return ... # 9| [TopLevelFunction] int main() # 9| params: -# 9| body: [Block] { ... } +# 9| body: [BlockStmt] { ... } # 10| 0: [DeclStmt] declaration # 10| 0: [VariableDeclarationEntry] definition of big # 10| Type = [PointerType] Big * @@ -10579,7 +10579,7 @@ struct_init.cpp: # 16| params: # 16| 0: [Parameter] info # 16| Type = [PointerType] Info * -# 16| body: [Block] { ... } +# 16| body: [BlockStmt] { ... } # 17| 0: [ExprStmt] ExprStmt # 17| 0: [AssignExpr] ... = ... # 17| Type = [PointerType] Info * @@ -10593,7 +10593,7 @@ struct_init.cpp: # 18| 1: [ReturnStmt] return ... # 20| [TopLevelFunction] void declare_static_infos() # 20| params: -# 20| body: [Block] { ... } +# 20| body: [BlockStmt] { ... } # 21| 0: [DeclStmt] declaration # 21| 0: [VariableDeclarationEntry] definition of static_infos # 21| Type = [ArrayType] Info[] @@ -10643,7 +10643,7 @@ struct_init.cpp: # 26| 2: [ReturnStmt] return ... # 28| [TopLevelFunction] void declare_local_infos() # 28| params: -# 28| body: [Block] { ... } +# 28| body: [BlockStmt] { ... } # 29| 0: [DeclStmt] declaration # 29| 0: [VariableDeclarationEntry] definition of local_infos # 29| Type = [ArrayType] Info[] @@ -10695,7 +10695,7 @@ struct_init.cpp: # 36| params: # 36| 0: [Parameter] name1 # 36| Type = [PointerType] const char * -# 36| body: [Block] { ... } +# 36| body: [BlockStmt] { ... } # 37| 0: [DeclStmt] declaration # 37| 0: [VariableDeclarationEntry] definition of static_infos # 37| Type = [ArrayType] Info[] diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected index 3a1a30265b2a..64172ad18738 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected @@ -1,8 +1,8 @@ missingOperand -| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | unexpectedOperand duplicateOperand missingPhiOperand @@ -24,6 +24,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected index 3a1a30265b2a..64172ad18738 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected @@ -1,8 +1,8 @@ missingOperand -| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | unexpectedOperand duplicateOperand missingPhiOperand @@ -24,6 +24,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected b/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected index 3a1a30265b2a..64172ad18738 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected @@ -1,8 +1,8 @@ missingOperand -| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | unexpectedOperand duplicateOperand missingPhiOperand @@ -24,6 +24,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType 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 6af78798ce04..a2be838ae483 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -21,10 +21,11 @@ bad_asts.cpp: # 10| r10_9(int) = Load : &:r10_8, ~m? # 10| r10_10(int) = Add : r10_7, r10_9 # 10| mu10_11(int) = Store : &:r10_1, r10_10 -# 9| r9_10(glval) = VariableAddress[#return] : -# 9| v9_11(void) = ReturnValue : &:r9_10, ~m? -# 9| v9_12(void) = AliasedUse : ~m? -# 9| v9_13(void) = ExitFunction : +# 9| v9_10(void) = ReturnIndirection[#this] : &:r9_6, ~m? +# 9| r9_11(glval) = VariableAddress[#return] : +# 9| v9_12(void) = ReturnValue : &:r9_11, ~m? +# 9| v9_13(void) = AliasedUse : ~m? +# 9| v9_14(void) = ExitFunction : # 14| void Bad::CallBadMemberFunction() # 14| Block 0 @@ -58,9 +59,10 @@ bad_asts.cpp: # 22| r22_6(glval) = Load : &:r22_4, ~m? # 22| mu22_7(Point) = InitializeIndirection[#this] : &:r22_6 # 23| v23_1(void) = NoOp : -# 22| v22_8(void) = ReturnVoid : -# 22| v22_9(void) = AliasedUse : ~m? -# 22| v22_10(void) = ExitFunction : +# 22| v22_8(void) = ReturnIndirection[#this] : &:r22_6, ~m? +# 22| v22_9(void) = ReturnVoid : +# 22| v22_10(void) = AliasedUse : ~m? +# 22| v22_11(void) = ExitFunction : # 26| void Bad::CallCopyConstructor(Bad::Point const&) # 26| Block 0 @@ -3448,9 +3450,10 @@ ir.cpp: # 628| r628_13(glval) = FunctionAddress[~String] : # 628| v628_14(void) = Call : func:r628_13, this:r628_12 # 628| mu628_15(unknown) = ^CallSideEffect : ~m? -# 628| v628_16(void) = ReturnVoid : -# 628| v628_17(void) = AliasedUse : ~m? -# 628| v628_18(void) = ExitFunction : +# 628| v628_16(void) = ReturnIndirection[#this] : &:r628_6, ~m? +# 628| v628_17(void) = ReturnVoid : +# 628| v628_18(void) = AliasedUse : ~m? +# 628| v628_19(void) = ExitFunction : # 630| int C::StaticMemberFunction(int) # 630| Block 0 @@ -3483,10 +3486,11 @@ ir.cpp: # 635| r635_2(glval) = VariableAddress[x] : # 635| r635_3(int) = Load : &:r635_2, ~m? # 635| mu635_4(int) = Store : &:r635_1, r635_3 -# 634| r634_10(glval) = VariableAddress[#return] : -# 634| v634_11(void) = ReturnValue : &:r634_10, ~m? -# 634| v634_12(void) = AliasedUse : ~m? -# 634| v634_13(void) = ExitFunction : +# 634| v634_10(void) = ReturnIndirection[#this] : &:r634_6, ~m? +# 634| r634_11(glval) = VariableAddress[#return] : +# 634| v634_12(void) = ReturnValue : &:r634_11, ~m? +# 634| v634_13(void) = AliasedUse : ~m? +# 634| v634_14(void) = ExitFunction : # 638| int C::VirtualMemberFunction(int) # 638| Block 0 @@ -3503,10 +3507,11 @@ ir.cpp: # 639| r639_2(glval) = VariableAddress[x] : # 639| r639_3(int) = Load : &:r639_2, ~m? # 639| mu639_4(int) = Store : &:r639_1, r639_3 -# 638| r638_10(glval) = VariableAddress[#return] : -# 638| v638_11(void) = ReturnValue : &:r638_10, ~m? -# 638| v638_12(void) = AliasedUse : ~m? -# 638| v638_13(void) = ExitFunction : +# 638| v638_10(void) = ReturnIndirection[#this] : &:r638_6, ~m? +# 638| r638_11(glval) = VariableAddress[#return] : +# 638| v638_12(void) = ReturnValue : &:r638_11, ~m? +# 638| v638_13(void) = AliasedUse : ~m? +# 638| v638_14(void) = ExitFunction : # 642| void C::FieldAccess() # 642| Block 0 @@ -3555,9 +3560,10 @@ ir.cpp: # 649| r649_5(glval) = VariableAddress[x] : # 649| mu649_6(int) = Store : &:r649_5, r649_4 # 650| v650_1(void) = NoOp : -# 642| v642_8(void) = ReturnVoid : -# 642| v642_9(void) = AliasedUse : ~m? -# 642| v642_10(void) = ExitFunction : +# 642| v642_8(void) = ReturnIndirection[#this] : &:r642_6, ~m? +# 642| v642_9(void) = ReturnVoid : +# 642| v642_10(void) = AliasedUse : ~m? +# 642| v642_11(void) = ExitFunction : # 652| void C::MethodCalls() # 652| Block 0 @@ -3594,9 +3600,10 @@ ir.cpp: # 655| v655_7(void) = ^BufferReadSideEffect[-1] : &:r655_2, ~m? # 655| mu655_8(C) = ^IndirectMayWriteSideEffect[-1] : &:r655_2 # 656| v656_1(void) = NoOp : -# 652| v652_8(void) = ReturnVoid : -# 652| v652_9(void) = AliasedUse : ~m? -# 652| v652_10(void) = ExitFunction : +# 652| v652_8(void) = ReturnIndirection[#this] : &:r652_6, ~m? +# 652| v652_9(void) = ReturnVoid : +# 652| v652_10(void) = AliasedUse : ~m? +# 652| v652_11(void) = ExitFunction : # 658| void C::C() # 658| Block 0 @@ -3631,9 +3638,10 @@ ir.cpp: # 662| v662_8(void) = ^BufferReadSideEffect[0] : &:r662_4, ~m? # 662| mu662_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r662_4 # 664| v664_1(void) = NoOp : -# 658| v658_8(void) = ReturnVoid : -# 658| v658_9(void) = AliasedUse : ~m? -# 658| v658_10(void) = ExitFunction : +# 658| v658_8(void) = ReturnIndirection[#this] : &:r658_6, ~m? +# 658| v658_9(void) = ReturnVoid : +# 658| v658_10(void) = AliasedUse : ~m? +# 658| v658_11(void) = ExitFunction : # 675| int DerefReference(int&) # 675| Block 0 @@ -4014,11 +4022,12 @@ ir.cpp: #-----| r0_13(glval) = CopyValue : r0_12 #-----| r0_14(Base &) = CopyValue : r0_13 #-----| mu0_15(Base &) = Store : &:r0_10, r0_14 +# 745| v745_20(void) = ReturnIndirection[#this] : &:r745_6, ~m? #-----| v0_16(void) = ReturnIndirection[p#0] : &:r0_3, ~m? -# 745| r745_20(glval) = VariableAddress[#return] : -# 745| v745_21(void) = ReturnValue : &:r745_20, ~m? -# 745| v745_22(void) = AliasedUse : ~m? -# 745| v745_23(void) = ExitFunction : +# 745| r745_21(glval) = VariableAddress[#return] : +# 745| v745_22(void) = ReturnValue : &:r745_21, ~m? +# 745| v745_23(void) = AliasedUse : ~m? +# 745| v745_24(void) = ExitFunction : # 745| void Base::Base(Base const&) # 745| Block 0 @@ -4039,10 +4048,11 @@ ir.cpp: # 745| mu745_11(unknown) = ^CallSideEffect : ~m? # 745| mu745_12(String) = ^IndirectMayWriteSideEffect[-1] : &:r745_8 # 745| v745_13(void) = NoOp : +# 745| v745_14(void) = ReturnIndirection[#this] : &:r745_6, ~m? #-----| v0_5(void) = ReturnIndirection[p#0] : &:r0_3, ~m? -# 745| v745_14(void) = ReturnVoid : -# 745| v745_15(void) = AliasedUse : ~m? -# 745| v745_16(void) = ExitFunction : +# 745| v745_15(void) = ReturnVoid : +# 745| v745_16(void) = AliasedUse : ~m? +# 745| v745_17(void) = ExitFunction : # 748| void Base::Base() # 748| Block 0 @@ -4059,9 +4069,10 @@ ir.cpp: # 748| mu748_11(unknown) = ^CallSideEffect : ~m? # 748| mu748_12(String) = ^IndirectMayWriteSideEffect[-1] : &:r748_8 # 749| v749_1(void) = NoOp : -# 748| v748_13(void) = ReturnVoid : -# 748| v748_14(void) = AliasedUse : ~m? -# 748| v748_15(void) = ExitFunction : +# 748| v748_13(void) = ReturnIndirection[#this] : &:r748_6, ~m? +# 748| v748_14(void) = ReturnVoid : +# 748| v748_15(void) = AliasedUse : ~m? +# 748| v748_16(void) = ExitFunction : # 750| void Base::~Base() # 750| Block 0 @@ -4077,9 +4088,10 @@ ir.cpp: # 751| r751_3(glval) = FunctionAddress[~String] : # 751| v751_4(void) = Call : func:r751_3, this:r751_2 # 751| mu751_5(unknown) = ^CallSideEffect : ~m? -# 750| v750_8(void) = ReturnVoid : -# 750| v750_9(void) = AliasedUse : ~m? -# 750| v750_10(void) = ExitFunction : +# 750| v750_8(void) = ReturnIndirection[#this] : &:r750_6, ~m? +# 750| v750_9(void) = ReturnVoid : +# 750| v750_10(void) = AliasedUse : ~m? +# 750| v750_11(void) = ExitFunction : # 754| Middle& Middle::operator=(Middle const&) # 754| Block 0 @@ -4135,11 +4147,12 @@ ir.cpp: #-----| r0_22(glval) = CopyValue : r0_21 #-----| r0_23(Middle &) = CopyValue : r0_22 #-----| mu0_24(Middle &) = Store : &:r0_19, r0_23 +# 754| v754_29(void) = ReturnIndirection[#this] : &:r754_6, ~m? #-----| v0_25(void) = ReturnIndirection[p#0] : &:r0_3, ~m? -# 754| r754_29(glval) = VariableAddress[#return] : -# 754| v754_30(void) = ReturnValue : &:r754_29, ~m? -# 754| v754_31(void) = AliasedUse : ~m? -# 754| v754_32(void) = ExitFunction : +# 754| r754_30(glval) = VariableAddress[#return] : +# 754| v754_31(void) = ReturnValue : &:r754_30, ~m? +# 754| v754_32(void) = AliasedUse : ~m? +# 754| v754_33(void) = ExitFunction : # 757| void Middle::Middle() # 757| Block 0 @@ -4161,9 +4174,10 @@ ir.cpp: # 757| mu757_16(unknown) = ^CallSideEffect : ~m? # 757| mu757_17(String) = ^IndirectMayWriteSideEffect[-1] : &:r757_13 # 758| v758_1(void) = NoOp : -# 757| v757_18(void) = ReturnVoid : -# 757| v757_19(void) = AliasedUse : ~m? -# 757| v757_20(void) = ExitFunction : +# 757| v757_18(void) = ReturnIndirection[#this] : &:r757_6, ~m? +# 757| v757_19(void) = ReturnVoid : +# 757| v757_20(void) = AliasedUse : ~m? +# 757| v757_21(void) = ExitFunction : # 759| void Middle::~Middle() # 759| Block 0 @@ -4183,9 +4197,10 @@ ir.cpp: # 760| r760_7(glval) = FunctionAddress[~Base] : # 760| v760_8(void) = Call : func:r760_7, this:r760_6 # 760| mu760_9(unknown) = ^CallSideEffect : ~m? -# 759| v759_8(void) = ReturnVoid : -# 759| v759_9(void) = AliasedUse : ~m? -# 759| v759_10(void) = ExitFunction : +# 759| v759_8(void) = ReturnIndirection[#this] : &:r759_6, ~m? +# 759| v759_9(void) = ReturnVoid : +# 759| v759_10(void) = AliasedUse : ~m? +# 759| v759_11(void) = ExitFunction : # 763| Derived& Derived::operator=(Derived const&) # 763| Block 0 @@ -4241,11 +4256,12 @@ ir.cpp: #-----| r0_22(glval) = CopyValue : r0_21 #-----| r0_23(Derived &) = CopyValue : r0_22 #-----| mu0_24(Derived &) = Store : &:r0_19, r0_23 +# 763| v763_29(void) = ReturnIndirection[#this] : &:r763_6, ~m? #-----| v0_25(void) = ReturnIndirection[p#0] : &:r0_3, ~m? -# 763| r763_29(glval) = VariableAddress[#return] : -# 763| v763_30(void) = ReturnValue : &:r763_29, ~m? -# 763| v763_31(void) = AliasedUse : ~m? -# 763| v763_32(void) = ExitFunction : +# 763| r763_30(glval) = VariableAddress[#return] : +# 763| v763_31(void) = ReturnValue : &:r763_30, ~m? +# 763| v763_32(void) = AliasedUse : ~m? +# 763| v763_33(void) = ExitFunction : # 766| void Derived::Derived() # 766| Block 0 @@ -4267,9 +4283,10 @@ ir.cpp: # 766| mu766_16(unknown) = ^CallSideEffect : ~m? # 766| mu766_17(String) = ^IndirectMayWriteSideEffect[-1] : &:r766_13 # 767| v767_1(void) = NoOp : -# 766| v766_18(void) = ReturnVoid : -# 766| v766_19(void) = AliasedUse : ~m? -# 766| v766_20(void) = ExitFunction : +# 766| v766_18(void) = ReturnIndirection[#this] : &:r766_6, ~m? +# 766| v766_19(void) = ReturnVoid : +# 766| v766_20(void) = AliasedUse : ~m? +# 766| v766_21(void) = ExitFunction : # 768| void Derived::~Derived() # 768| Block 0 @@ -4289,9 +4306,10 @@ ir.cpp: # 769| r769_7(glval) = FunctionAddress[~Middle] : # 769| v769_8(void) = Call : func:r769_7, this:r769_6 # 769| mu769_9(unknown) = ^CallSideEffect : ~m? -# 768| v768_8(void) = ReturnVoid : -# 768| v768_9(void) = AliasedUse : ~m? -# 768| v768_10(void) = ExitFunction : +# 768| v768_8(void) = ReturnIndirection[#this] : &:r768_6, ~m? +# 768| v768_9(void) = ReturnVoid : +# 768| v768_10(void) = AliasedUse : ~m? +# 768| v768_11(void) = ExitFunction : # 775| void MiddleVB1::MiddleVB1() # 775| Block 0 @@ -4313,9 +4331,10 @@ ir.cpp: # 775| mu775_16(unknown) = ^CallSideEffect : ~m? # 775| mu775_17(String) = ^IndirectMayWriteSideEffect[-1] : &:r775_13 # 776| v776_1(void) = NoOp : -# 775| v775_18(void) = ReturnVoid : -# 775| v775_19(void) = AliasedUse : ~m? -# 775| v775_20(void) = ExitFunction : +# 775| v775_18(void) = ReturnIndirection[#this] : &:r775_6, ~m? +# 775| v775_19(void) = ReturnVoid : +# 775| v775_20(void) = AliasedUse : ~m? +# 775| v775_21(void) = ExitFunction : # 777| void MiddleVB1::~MiddleVB1() # 777| Block 0 @@ -4335,9 +4354,10 @@ ir.cpp: # 778| r778_7(glval) = FunctionAddress[~Base] : # 778| v778_8(void) = Call : func:r778_7, this:r778_6 # 778| mu778_9(unknown) = ^CallSideEffect : ~m? -# 777| v777_8(void) = ReturnVoid : -# 777| v777_9(void) = AliasedUse : ~m? -# 777| v777_10(void) = ExitFunction : +# 777| v777_8(void) = ReturnIndirection[#this] : &:r777_6, ~m? +# 777| v777_9(void) = ReturnVoid : +# 777| v777_10(void) = AliasedUse : ~m? +# 777| v777_11(void) = ExitFunction : # 784| void MiddleVB2::MiddleVB2() # 784| Block 0 @@ -4359,9 +4379,10 @@ ir.cpp: # 784| mu784_16(unknown) = ^CallSideEffect : ~m? # 784| mu784_17(String) = ^IndirectMayWriteSideEffect[-1] : &:r784_13 # 785| v785_1(void) = NoOp : -# 784| v784_18(void) = ReturnVoid : -# 784| v784_19(void) = AliasedUse : ~m? -# 784| v784_20(void) = ExitFunction : +# 784| v784_18(void) = ReturnIndirection[#this] : &:r784_6, ~m? +# 784| v784_19(void) = ReturnVoid : +# 784| v784_20(void) = AliasedUse : ~m? +# 784| v784_21(void) = ExitFunction : # 786| void MiddleVB2::~MiddleVB2() # 786| Block 0 @@ -4381,9 +4402,10 @@ ir.cpp: # 787| r787_7(glval) = FunctionAddress[~Base] : # 787| v787_8(void) = Call : func:r787_7, this:r787_6 # 787| mu787_9(unknown) = ^CallSideEffect : ~m? -# 786| v786_8(void) = ReturnVoid : -# 786| v786_9(void) = AliasedUse : ~m? -# 786| v786_10(void) = ExitFunction : +# 786| v786_8(void) = ReturnIndirection[#this] : &:r786_6, ~m? +# 786| v786_9(void) = ReturnVoid : +# 786| v786_10(void) = AliasedUse : ~m? +# 786| v786_11(void) = ExitFunction : # 793| void DerivedVB::DerivedVB() # 793| Block 0 @@ -4415,9 +4437,10 @@ ir.cpp: # 793| mu793_26(unknown) = ^CallSideEffect : ~m? # 793| mu793_27(String) = ^IndirectMayWriteSideEffect[-1] : &:r793_23 # 794| v794_1(void) = NoOp : -# 793| v793_28(void) = ReturnVoid : -# 793| v793_29(void) = AliasedUse : ~m? -# 793| v793_30(void) = ExitFunction : +# 793| v793_28(void) = ReturnIndirection[#this] : &:r793_6, ~m? +# 793| v793_29(void) = ReturnVoid : +# 793| v793_30(void) = AliasedUse : ~m? +# 793| v793_31(void) = ExitFunction : # 795| void DerivedVB::~DerivedVB() # 795| Block 0 @@ -4445,9 +4468,10 @@ ir.cpp: # 796| r796_15(glval) = FunctionAddress[~Base] : # 796| v796_16(void) = Call : func:r796_15, this:r796_14 # 796| mu796_17(unknown) = ^CallSideEffect : ~m? -# 795| v795_8(void) = ReturnVoid : -# 795| v795_9(void) = AliasedUse : ~m? -# 795| v795_10(void) = ExitFunction : +# 795| v795_8(void) = ReturnIndirection[#this] : &:r795_6, ~m? +# 795| v795_9(void) = ReturnVoid : +# 795| v795_10(void) = AliasedUse : ~m? +# 795| v795_11(void) = ExitFunction : # 799| void HierarchyConversions() # 799| Block 0 @@ -4751,9 +4775,10 @@ ir.cpp: # 842| r842_6(glval) = Load : &:r842_4, ~m? # 842| mu842_7(PolymorphicBase) = InitializeIndirection[#this] : &:r842_6 # 842| v842_8(void) = NoOp : -# 842| v842_9(void) = ReturnVoid : -# 842| v842_10(void) = AliasedUse : ~m? -# 842| v842_11(void) = ExitFunction : +# 842| v842_9(void) = ReturnIndirection[#this] : &:r842_6, ~m? +# 842| v842_10(void) = ReturnVoid : +# 842| v842_11(void) = AliasedUse : ~m? +# 842| v842_12(void) = ExitFunction : # 846| void PolymorphicDerived::PolymorphicDerived() # 846| Block 0 @@ -4770,9 +4795,10 @@ ir.cpp: # 846| mu846_11(unknown) = ^CallSideEffect : ~m? # 846| mu846_12(PolymorphicBase) = ^IndirectMayWriteSideEffect[-1] : &:r846_8 # 846| v846_13(void) = NoOp : -# 846| v846_14(void) = ReturnVoid : -# 846| v846_15(void) = AliasedUse : ~m? -# 846| v846_16(void) = ExitFunction : +# 846| v846_14(void) = ReturnIndirection[#this] : &:r846_6, ~m? +# 846| v846_15(void) = ReturnVoid : +# 846| v846_16(void) = AliasedUse : ~m? +# 846| v846_17(void) = ExitFunction : # 846| void PolymorphicDerived::~PolymorphicDerived() # 846| Block 0 @@ -4788,9 +4814,10 @@ ir.cpp: # 846| r846_9(glval) = FunctionAddress[~PolymorphicBase] : # 846| v846_10(void) = Call : func:r846_9, this:r846_8 # 846| mu846_11(unknown) = ^CallSideEffect : ~m? -# 846| v846_12(void) = ReturnVoid : -# 846| v846_13(void) = AliasedUse : ~m? -# 846| v846_14(void) = ExitFunction : +# 846| v846_12(void) = ReturnIndirection[#this] : &:r846_6, ~m? +# 846| v846_13(void) = ReturnVoid : +# 846| v846_14(void) = AliasedUse : ~m? +# 846| v846_15(void) = ExitFunction : # 849| void DynamicCast() # 849| Block 0 @@ -4840,12 +4867,12 @@ ir.cpp: # 863| r863_1(glval) = VariableAddress[pv] : # 863| r863_2(glval) = VariableAddress[pb] : # 863| r863_3(PolymorphicBase *) = Load : &:r863_2, ~m? -# 863| r863_4(void *) = DynamicCastToVoid : r863_3 +# 863| r863_4(void *) = CompleteObjectAddress : r863_3 # 863| mu863_5(void *) = Store : &:r863_1, r863_4 # 864| r864_1(glval) = VariableAddress[pcv] : # 864| r864_2(glval) = VariableAddress[pd] : # 864| r864_3(PolymorphicDerived *) = Load : &:r864_2, ~m? -# 864| r864_4(void *) = DynamicCastToVoid : r864_3 +# 864| r864_4(void *) = CompleteObjectAddress : r864_3 # 864| mu864_5(void *) = Store : &:r864_1, r864_4 # 865| v865_1(void) = NoOp : # 849| v849_4(void) = ReturnVoid : @@ -4870,9 +4897,10 @@ ir.cpp: # 868| v868_7(void) = ^BufferReadSideEffect[0] : &:r868_3, ~m? # 868| mu868_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r868_3 # 869| v869_1(void) = NoOp : -# 867| v867_8(void) = ReturnVoid : -# 867| v867_9(void) = AliasedUse : ~m? -# 867| v867_10(void) = ExitFunction : +# 867| v867_8(void) = ReturnIndirection[#this] : &:r867_6, ~m? +# 867| v867_9(void) = ReturnVoid : +# 867| v867_10(void) = AliasedUse : ~m? +# 867| v867_11(void) = ExitFunction : # 871| void ArrayConversions() # 871| Block 0 @@ -5617,9 +5645,10 @@ ir.cpp: # 1038| r1038_6(glval) = Load : &:r1038_4, ~m? # 1038| mu1038_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1038_6 # 1038| v1038_8(void) = NoOp : -# 1038| v1038_9(void) = ReturnVoid : -# 1038| v1038_10(void) = AliasedUse : ~m? -# 1038| v1038_11(void) = ExitFunction : +# 1038| v1038_9(void) = ReturnIndirection[#this] : &:r1038_6, ~m? +# 1038| v1038_10(void) = ReturnVoid : +# 1038| v1038_11(void) = AliasedUse : ~m? +# 1038| v1038_12(void) = ExitFunction : # 1038| void(* (lambda [] type at line 1038, col. 12)::operator void (*)()() const)() # 1038| Block 0 @@ -5633,10 +5662,11 @@ ir.cpp: # 1038| r1038_8(glval<..(*)(..)>) = VariableAddress[#return] : # 1038| r1038_9(..(*)(..)) = FunctionAddress[_FUN] : # 1038| mu1038_10(..(*)(..)) = Store : &:r1038_8, r1038_9 -# 1038| r1038_11(glval<..(*)(..)>) = VariableAddress[#return] : -# 1038| v1038_12(void) = ReturnValue : &:r1038_11, ~m? -# 1038| v1038_13(void) = AliasedUse : ~m? -# 1038| v1038_14(void) = ExitFunction : +# 1038| v1038_11(void) = ReturnIndirection[#this] : &:r1038_6, ~m? +# 1038| r1038_12(glval<..(*)(..)>) = VariableAddress[#return] : +# 1038| v1038_13(void) = ReturnValue : &:r1038_12, ~m? +# 1038| v1038_14(void) = AliasedUse : ~m? +# 1038| v1038_15(void) = ExitFunction : # 1040| void Lambda(int, String const&) # 1040| Block 0 @@ -5819,10 +5849,11 @@ ir.cpp: # 1041| r1041_10(glval) = VariableAddress[#return] : # 1041| r1041_11(char) = Constant[65] : # 1041| mu1041_12(char) = Store : &:r1041_10, r1041_11 -# 1041| r1041_13(glval) = VariableAddress[#return] : -# 1041| v1041_14(void) = ReturnValue : &:r1041_13, ~m? -# 1041| v1041_15(void) = AliasedUse : ~m? -# 1041| v1041_16(void) = ExitFunction : +# 1041| v1041_13(void) = ReturnIndirection[#this] : &:r1041_6, ~m? +# 1041| r1041_14(glval) = VariableAddress[#return] : +# 1041| v1041_15(void) = ReturnValue : &:r1041_14, ~m? +# 1041| v1041_16(void) = AliasedUse : ~m? +# 1041| v1041_17(void) = ExitFunction : # 1041| char(* (void Lambda(int, String const&))::(lambda [] type at line 1041, col. 23)::operator char (*)(float)() const)(float) # 1041| Block 0 @@ -5836,10 +5867,11 @@ ir.cpp: # 1041| r1041_8(glval<..(*)(..)>) = VariableAddress[#return] : # 1041| r1041_9(..(*)(..)) = FunctionAddress[_FUN] : # 1041| mu1041_10(..(*)(..)) = Store : &:r1041_8, r1041_9 -# 1041| r1041_11(glval<..(*)(..)>) = VariableAddress[#return] : -# 1041| v1041_12(void) = ReturnValue : &:r1041_11, ~m? -# 1041| v1041_13(void) = AliasedUse : ~m? -# 1041| v1041_14(void) = ExitFunction : +# 1041| v1041_11(void) = ReturnIndirection[#this] : &:r1041_6, ~m? +# 1041| r1041_12(glval<..(*)(..)>) = VariableAddress[#return] : +# 1041| v1041_13(void) = ReturnValue : &:r1041_12, ~m? +# 1041| v1041_14(void) = AliasedUse : ~m? +# 1041| v1041_15(void) = ExitFunction : # 1043| char (void Lambda(int, String const&))::(lambda [] type at line 1043, col. 21)::operator()(float) const # 1043| Block 0 @@ -5871,10 +5903,11 @@ ir.cpp: # 1043| r1043_26(glval) = PointerAdd[1] : r1043_17, r1043_25 # 1043| r1043_27(char) = Load : &:r1043_26, ~m? # 1043| mu1043_28(char) = Store : &:r1043_10, r1043_27 -# 1043| r1043_29(glval) = VariableAddress[#return] : -# 1043| v1043_30(void) = ReturnValue : &:r1043_29, ~m? -# 1043| v1043_31(void) = AliasedUse : ~m? -# 1043| v1043_32(void) = ExitFunction : +# 1043| v1043_29(void) = ReturnIndirection[#this] : &:r1043_6, ~m? +# 1043| r1043_30(glval) = VariableAddress[#return] : +# 1043| v1043_31(void) = ReturnValue : &:r1043_30, ~m? +# 1043| v1043_32(void) = AliasedUse : ~m? +# 1043| v1043_33(void) = ExitFunction : # 1045| void (void Lambda(int, String const&))::(lambda [] type at line 1045, col. 21)::~() # 1045| Block 0 @@ -5890,9 +5923,10 @@ ir.cpp: # 1045| r1045_9(glval) = FunctionAddress[~String] : # 1045| v1045_10(void) = Call : func:r1045_9, this:r1045_8 # 1045| mu1045_11(unknown) = ^CallSideEffect : ~m? -# 1045| v1045_12(void) = ReturnVoid : -# 1045| v1045_13(void) = AliasedUse : ~m? -# 1045| v1045_14(void) = ExitFunction : +# 1045| v1045_12(void) = ReturnIndirection[#this] : &:r1045_6, ~m? +# 1045| v1045_13(void) = ReturnVoid : +# 1045| v1045_14(void) = AliasedUse : ~m? +# 1045| v1045_15(void) = ExitFunction : # 1045| char (void Lambda(int, String const&))::(lambda [] type at line 1045, col. 21)::operator()(float) const # 1045| Block 0 @@ -5921,10 +5955,11 @@ ir.cpp: # 1045| r1045_23(glval) = PointerAdd[1] : r1045_15, r1045_22 # 1045| r1045_24(char) = Load : &:r1045_23, ~m? # 1045| mu1045_25(char) = Store : &:r1045_10, r1045_24 -# 1045| r1045_26(glval) = VariableAddress[#return] : -# 1045| v1045_27(void) = ReturnValue : &:r1045_26, ~m? -# 1045| v1045_28(void) = AliasedUse : ~m? -# 1045| v1045_29(void) = ExitFunction : +# 1045| v1045_26(void) = ReturnIndirection[#this] : &:r1045_6, ~m? +# 1045| r1045_27(glval) = VariableAddress[#return] : +# 1045| v1045_28(void) = ReturnValue : &:r1045_27, ~m? +# 1045| v1045_29(void) = AliasedUse : ~m? +# 1045| v1045_30(void) = ExitFunction : # 1047| char (void Lambda(int, String const&))::(lambda [] type at line 1047, col. 30)::operator()(float) const # 1047| Block 0 @@ -5952,10 +5987,11 @@ ir.cpp: # 1047| r1047_22(glval) = PointerAdd[1] : r1047_17, r1047_21 # 1047| r1047_23(char) = Load : &:r1047_22, ~m? # 1047| mu1047_24(char) = Store : &:r1047_10, r1047_23 -# 1047| r1047_25(glval) = VariableAddress[#return] : -# 1047| v1047_26(void) = ReturnValue : &:r1047_25, ~m? -# 1047| v1047_27(void) = AliasedUse : ~m? -# 1047| v1047_28(void) = ExitFunction : +# 1047| v1047_25(void) = ReturnIndirection[#this] : &:r1047_6, ~m? +# 1047| r1047_26(glval) = VariableAddress[#return] : +# 1047| v1047_27(void) = ReturnValue : &:r1047_26, ~m? +# 1047| v1047_28(void) = AliasedUse : ~m? +# 1047| v1047_29(void) = ExitFunction : # 1049| void (void Lambda(int, String const&))::(lambda [] type at line 1049, col. 30)::~() # 1049| Block 0 @@ -5971,9 +6007,10 @@ ir.cpp: # 1049| r1049_9(glval) = FunctionAddress[~String] : # 1049| v1049_10(void) = Call : func:r1049_9, this:r1049_8 # 1049| mu1049_11(unknown) = ^CallSideEffect : ~m? -# 1049| v1049_12(void) = ReturnVoid : -# 1049| v1049_13(void) = AliasedUse : ~m? -# 1049| v1049_14(void) = ExitFunction : +# 1049| v1049_12(void) = ReturnIndirection[#this] : &:r1049_6, ~m? +# 1049| v1049_13(void) = ReturnVoid : +# 1049| v1049_14(void) = AliasedUse : ~m? +# 1049| v1049_15(void) = ExitFunction : # 1049| char (void Lambda(int, String const&))::(lambda [] type at line 1049, col. 30)::operator()(float) const # 1049| Block 0 @@ -5999,10 +6036,11 @@ ir.cpp: # 1049| r1049_20(glval) = PointerAdd[1] : r1049_15, r1049_19 # 1049| r1049_21(char) = Load : &:r1049_20, ~m? # 1049| mu1049_22(char) = Store : &:r1049_10, r1049_21 -# 1049| r1049_23(glval) = VariableAddress[#return] : -# 1049| v1049_24(void) = ReturnValue : &:r1049_23, ~m? -# 1049| v1049_25(void) = AliasedUse : ~m? -# 1049| v1049_26(void) = ExitFunction : +# 1049| v1049_23(void) = ReturnIndirection[#this] : &:r1049_6, ~m? +# 1049| r1049_24(glval) = VariableAddress[#return] : +# 1049| v1049_25(void) = ReturnValue : &:r1049_24, ~m? +# 1049| v1049_26(void) = AliasedUse : ~m? +# 1049| v1049_27(void) = ExitFunction : # 1051| char (void Lambda(int, String const&))::(lambda [] type at line 1051, col. 32)::operator()(float) const # 1051| Block 0 @@ -6033,10 +6071,11 @@ ir.cpp: # 1051| r1051_25(glval) = PointerAdd[1] : r1051_17, r1051_24 # 1051| r1051_26(char) = Load : &:r1051_25, ~m? # 1051| mu1051_27(char) = Store : &:r1051_10, r1051_26 -# 1051| r1051_28(glval) = VariableAddress[#return] : -# 1051| v1051_29(void) = ReturnValue : &:r1051_28, ~m? -# 1051| v1051_30(void) = AliasedUse : ~m? -# 1051| v1051_31(void) = ExitFunction : +# 1051| v1051_28(void) = ReturnIndirection[#this] : &:r1051_6, ~m? +# 1051| r1051_29(glval) = VariableAddress[#return] : +# 1051| v1051_30(void) = ReturnValue : &:r1051_29, ~m? +# 1051| v1051_31(void) = AliasedUse : ~m? +# 1051| v1051_32(void) = ExitFunction : # 1054| char (void Lambda(int, String const&))::(lambda [] type at line 1054, col. 23)::operator()(float) const # 1054| Block 0 @@ -6078,10 +6117,11 @@ ir.cpp: # 1054| r1054_36(glval) = PointerAdd[1] : r1054_17, r1054_35 # 1054| r1054_37(char) = Load : &:r1054_36, ~m? # 1054| mu1054_38(char) = Store : &:r1054_10, r1054_37 -# 1054| r1054_39(glval) = VariableAddress[#return] : -# 1054| v1054_40(void) = ReturnValue : &:r1054_39, ~m? -# 1054| v1054_41(void) = AliasedUse : ~m? -# 1054| v1054_42(void) = ExitFunction : +# 1054| v1054_39(void) = ReturnIndirection[#this] : &:r1054_6, ~m? +# 1054| r1054_40(glval) = VariableAddress[#return] : +# 1054| v1054_41(void) = ReturnValue : &:r1054_40, ~m? +# 1054| v1054_42(void) = AliasedUse : ~m? +# 1054| v1054_43(void) = ExitFunction : # 1077| void RangeBasedFor(vector const&) # 1077| Block 0 @@ -7409,9 +7449,10 @@ perf-regression.cpp: # 6| r6_11(unknown[1073741824]) = Constant[0] : # 6| mu6_12(unknown[1073741824]) = Store : &:r6_10, r6_11 # 6| v6_13(void) = NoOp : -# 6| v6_14(void) = ReturnVoid : -# 6| v6_15(void) = AliasedUse : ~m? -# 6| v6_16(void) = ExitFunction : +# 6| v6_14(void) = ReturnIndirection[#this] : &:r6_6, ~m? +# 6| v6_15(void) = ReturnVoid : +# 6| v6_16(void) = AliasedUse : ~m? +# 6| v6_17(void) = ExitFunction : # 9| int main() # 9| Block 0 diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected index 3a1a30265b2a..64172ad18738 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected @@ -1,8 +1,8 @@ missingOperand -| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | unexpectedOperand duplicateOperand missingPhiOperand @@ -24,6 +24,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected index 3a1a30265b2a..64172ad18738 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected @@ -1,8 +1,8 @@ missingOperand -| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | unexpectedOperand duplicateOperand missingPhiOperand @@ -24,6 +24,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency.expected index e2db1e65034c..1c41692bcaad 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency.expected @@ -20,6 +20,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.expected index e2db1e65034c..1c41692bcaad 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.expected @@ -20,6 +20,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected index 24b3ee459843..43b8116d85fa 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected @@ -1020,9 +1020,10 @@ ssa.cpp: # 235| r235_9(glval) = VariableAddress[x] : # 235| m235_10(int) = InitializeParameter[x] : &:r235_9 # 235| v235_11(void) = NoOp : -# 235| v235_12(void) = ReturnVoid : -# 235| v235_13(void) = AliasedUse : m235_3 -# 235| v235_14(void) = ExitFunction : +# 235| v235_12(void) = ReturnIndirection[#this] : &:r235_7, m235_8 +# 235| v235_13(void) = ReturnVoid : +# 235| v235_14(void) = AliasedUse : m235_3 +# 235| v235_15(void) = ExitFunction : # 236| void Constructible::g() # 236| Block 0 @@ -1035,9 +1036,10 @@ ssa.cpp: # 236| r236_7(glval) = Load : &:r236_5, m236_6 # 236| m236_8(Constructible) = InitializeIndirection[#this] : &:r236_7 # 236| v236_9(void) = NoOp : -# 236| v236_10(void) = ReturnVoid : -# 236| v236_11(void) = AliasedUse : m236_3 -# 236| v236_12(void) = ExitFunction : +# 236| v236_10(void) = ReturnIndirection[#this] : &:r236_7, m236_8 +# 236| v236_11(void) = ReturnVoid : +# 236| v236_12(void) = AliasedUse : m236_3 +# 236| v236_13(void) = ExitFunction : # 239| void ExplicitConstructorCalls() # 239| Block 0 @@ -1307,9 +1309,10 @@ ssa.cpp: # 286| r286_9(glval) = VariableAddress[x] : # 286| m286_10(int) = InitializeParameter[x] : &:r286_9 # 286| v286_11(void) = NoOp : -# 286| v286_12(void) = ReturnVoid : -# 286| v286_13(void) = AliasedUse : m286_3 -# 286| v286_14(void) = ExitFunction : +# 286| v286_12(void) = ReturnIndirection[#this] : &:r286_7, m286_8 +# 286| v286_13(void) = ReturnVoid : +# 286| v286_14(void) = AliasedUse : m286_3 +# 286| v286_15(void) = ExitFunction : # 287| void A::A(A*) # 287| Block 0 @@ -1326,10 +1329,11 @@ ssa.cpp: # 287| r287_11(A *) = Load : &:r287_9, m287_10 # 287| m287_12(unknown) = InitializeIndirection[p#0] : &:r287_11 # 287| v287_13(void) = NoOp : -# 287| v287_14(void) = ReturnIndirection[p#0] : &:r287_11, m287_12 -# 287| v287_15(void) = ReturnVoid : -# 287| v287_16(void) = AliasedUse : m287_3 -# 287| v287_17(void) = ExitFunction : +# 287| v287_14(void) = ReturnIndirection[#this] : &:r287_7, m287_8 +# 287| v287_15(void) = ReturnIndirection[p#0] : &:r287_11, m287_12 +# 287| v287_16(void) = ReturnVoid : +# 287| v287_17(void) = AliasedUse : m287_3 +# 287| v287_18(void) = ExitFunction : # 288| void A::A() # 288| Block 0 @@ -1342,9 +1346,10 @@ ssa.cpp: # 288| r288_7(glval) = Load : &:r288_5, m288_6 # 288| m288_8(A) = InitializeIndirection[#this] : &:r288_7 # 288| v288_9(void) = NoOp : -# 288| v288_10(void) = ReturnVoid : -# 288| v288_11(void) = AliasedUse : m288_3 -# 288| v288_12(void) = ExitFunction : +# 288| v288_10(void) = ReturnIndirection[#this] : &:r288_7, m288_8 +# 288| v288_11(void) = ReturnVoid : +# 288| v288_12(void) = AliasedUse : m288_3 +# 288| v288_13(void) = ExitFunction : # 291| Point* NewAliasing(int) # 291| Block 0 @@ -1499,6 +1504,7 @@ ssa.cpp: # 311| m311_6(int) = Store : &:r311_5, r311_2 # 311| m311_7(unknown) = Chi : total:m310_8, partial:m311_6 # 312| v312_1(void) = NoOp : -# 310| v310_11(void) = ReturnVoid : -# 310| v310_12(void) = AliasedUse : m310_3 -# 310| v310_13(void) = ExitFunction : +# 310| v310_11(void) = ReturnIndirection[#this] : &:r310_7, m311_7 +# 310| v310_12(void) = ReturnVoid : +# 310| v310_13(void) = AliasedUse : m310_3 +# 310| v310_14(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected index c7762fc5fdd5..ef07fde174d5 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected @@ -1013,9 +1013,10 @@ ssa.cpp: # 235| r235_9(glval) = VariableAddress[x] : # 235| m235_10(int) = InitializeParameter[x] : &:r235_9 # 235| v235_11(void) = NoOp : -# 235| v235_12(void) = ReturnVoid : -# 235| v235_13(void) = AliasedUse : m235_3 -# 235| v235_14(void) = ExitFunction : +# 235| v235_12(void) = ReturnIndirection[#this] : &:r235_7, m235_8 +# 235| v235_13(void) = ReturnVoid : +# 235| v235_14(void) = AliasedUse : m235_3 +# 235| v235_15(void) = ExitFunction : # 236| void Constructible::g() # 236| Block 0 @@ -1028,9 +1029,10 @@ ssa.cpp: # 236| r236_7(glval) = Load : &:r236_5, m236_6 # 236| m236_8(Constructible) = InitializeIndirection[#this] : &:r236_7 # 236| v236_9(void) = NoOp : -# 236| v236_10(void) = ReturnVoid : -# 236| v236_11(void) = AliasedUse : m236_3 -# 236| v236_12(void) = ExitFunction : +# 236| v236_10(void) = ReturnIndirection[#this] : &:r236_7, m236_8 +# 236| v236_11(void) = ReturnVoid : +# 236| v236_12(void) = AliasedUse : m236_3 +# 236| v236_13(void) = ExitFunction : # 239| void ExplicitConstructorCalls() # 239| Block 0 @@ -1295,9 +1297,10 @@ ssa.cpp: # 286| r286_9(glval) = VariableAddress[x] : # 286| m286_10(int) = InitializeParameter[x] : &:r286_9 # 286| v286_11(void) = NoOp : -# 286| v286_12(void) = ReturnVoid : -# 286| v286_13(void) = AliasedUse : m286_3 -# 286| v286_14(void) = ExitFunction : +# 286| v286_12(void) = ReturnIndirection[#this] : &:r286_7, m286_8 +# 286| v286_13(void) = ReturnVoid : +# 286| v286_14(void) = AliasedUse : m286_3 +# 286| v286_15(void) = ExitFunction : # 287| void A::A(A*) # 287| Block 0 @@ -1314,10 +1317,11 @@ ssa.cpp: # 287| r287_11(A *) = Load : &:r287_9, m287_10 # 287| m287_12(unknown) = InitializeIndirection[p#0] : &:r287_11 # 287| v287_13(void) = NoOp : -# 287| v287_14(void) = ReturnIndirection[p#0] : &:r287_11, m287_12 -# 287| v287_15(void) = ReturnVoid : -# 287| v287_16(void) = AliasedUse : m287_3 -# 287| v287_17(void) = ExitFunction : +# 287| v287_14(void) = ReturnIndirection[#this] : &:r287_7, m287_8 +# 287| v287_15(void) = ReturnIndirection[p#0] : &:r287_11, m287_12 +# 287| v287_16(void) = ReturnVoid : +# 287| v287_17(void) = AliasedUse : m287_3 +# 287| v287_18(void) = ExitFunction : # 288| void A::A() # 288| Block 0 @@ -1330,9 +1334,10 @@ ssa.cpp: # 288| r288_7(glval) = Load : &:r288_5, m288_6 # 288| m288_8(A) = InitializeIndirection[#this] : &:r288_7 # 288| v288_9(void) = NoOp : -# 288| v288_10(void) = ReturnVoid : -# 288| v288_11(void) = AliasedUse : m288_3 -# 288| v288_12(void) = ExitFunction : +# 288| v288_10(void) = ReturnIndirection[#this] : &:r288_7, m288_8 +# 288| v288_11(void) = ReturnVoid : +# 288| v288_12(void) = AliasedUse : m288_3 +# 288| v288_13(void) = ExitFunction : # 291| Point* NewAliasing(int) # 291| Block 0 @@ -1486,6 +1491,7 @@ ssa.cpp: # 311| m311_6(int) = Store : &:r311_5, r311_2 # 311| m311_7(unknown) = Chi : total:m310_8, partial:m311_6 # 312| v312_1(void) = NoOp : -# 310| v310_11(void) = ReturnVoid : -# 310| v310_12(void) = AliasedUse : m310_3 -# 310| v310_13(void) = ExitFunction : +# 310| v310_11(void) = ReturnIndirection[#this] : &:r310_7, m311_7 +# 310| v310_12(void) = ReturnVoid : +# 310| v310_13(void) = AliasedUse : m310_3 +# 310| v310_14(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/ssa.cpp b/cpp/ql/test/library-tests/ir/ssa/ssa.cpp index b8788c5c6aae..34886b1f3434 100644 --- a/cpp/ql/test/library-tests/ir/ssa/ssa.cpp +++ b/cpp/ql/test/library-tests/ir/ssa/ssa.cpp @@ -291,7 +291,7 @@ struct A { Point *NewAliasing(int x) { Point* p = new Point; Point* q = new Point; - int j = new A(new A(x))->i; + int j = (new A(new A(x)))->i; A* a = new A; return p; } @@ -310,4 +310,4 @@ class ThisAliasTest { void setX(int arg) { this->x = arg; } -}; \ No newline at end of file +}; diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency.expected index e2db1e65034c..1c41692bcaad 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency.expected @@ -20,6 +20,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency_unsound.expected index e2db1e65034c..1c41692bcaad 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency_unsound.expected @@ -20,6 +20,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected index 3180c9211a5e..1d155eaf30d6 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected @@ -947,9 +947,10 @@ ssa.cpp: # 235| r235_8(glval) = VariableAddress[x] : # 235| m235_9(int) = InitializeParameter[x] : &:r235_8 # 235| v235_10(void) = NoOp : -# 235| v235_11(void) = ReturnVoid : -# 235| v235_12(void) = AliasedUse : ~m? -# 235| v235_13(void) = ExitFunction : +# 235| v235_11(void) = ReturnIndirection[#this] : &:r235_6, ~m? +# 235| v235_12(void) = ReturnVoid : +# 235| v235_13(void) = AliasedUse : ~m? +# 235| v235_14(void) = ExitFunction : # 236| void Constructible::g() # 236| Block 0 @@ -961,9 +962,10 @@ ssa.cpp: # 236| r236_6(glval) = Load : &:r236_4, m236_5 # 236| mu236_7(Constructible) = InitializeIndirection[#this] : &:r236_6 # 236| v236_8(void) = NoOp : -# 236| v236_9(void) = ReturnVoid : -# 236| v236_10(void) = AliasedUse : ~m? -# 236| v236_11(void) = ExitFunction : +# 236| v236_9(void) = ReturnIndirection[#this] : &:r236_6, ~m? +# 236| v236_10(void) = ReturnVoid : +# 236| v236_11(void) = AliasedUse : ~m? +# 236| v236_12(void) = ExitFunction : # 239| void ExplicitConstructorCalls() # 239| Block 0 @@ -1198,9 +1200,10 @@ ssa.cpp: # 286| r286_8(glval) = VariableAddress[x] : # 286| m286_9(int) = InitializeParameter[x] : &:r286_8 # 286| v286_10(void) = NoOp : -# 286| v286_11(void) = ReturnVoid : -# 286| v286_12(void) = AliasedUse : ~m? -# 286| v286_13(void) = ExitFunction : +# 286| v286_11(void) = ReturnIndirection[#this] : &:r286_6, ~m? +# 286| v286_12(void) = ReturnVoid : +# 286| v286_13(void) = AliasedUse : ~m? +# 286| v286_14(void) = ExitFunction : # 287| void A::A(A*) # 287| Block 0 @@ -1216,10 +1219,11 @@ ssa.cpp: # 287| r287_10(A *) = Load : &:r287_8, m287_9 # 287| mu287_11(unknown) = InitializeIndirection[p#0] : &:r287_10 # 287| v287_12(void) = NoOp : -# 287| v287_13(void) = ReturnIndirection[p#0] : &:r287_10, ~m? -# 287| v287_14(void) = ReturnVoid : -# 287| v287_15(void) = AliasedUse : ~m? -# 287| v287_16(void) = ExitFunction : +# 287| v287_13(void) = ReturnIndirection[#this] : &:r287_6, ~m? +# 287| v287_14(void) = ReturnIndirection[p#0] : &:r287_10, ~m? +# 287| v287_15(void) = ReturnVoid : +# 287| v287_16(void) = AliasedUse : ~m? +# 287| v287_17(void) = ExitFunction : # 288| void A::A() # 288| Block 0 @@ -1231,9 +1235,10 @@ ssa.cpp: # 288| r288_6(glval) = Load : &:r288_4, m288_5 # 288| mu288_7(A) = InitializeIndirection[#this] : &:r288_6 # 288| v288_8(void) = NoOp : -# 288| v288_9(void) = ReturnVoid : -# 288| v288_10(void) = AliasedUse : ~m? -# 288| v288_11(void) = ExitFunction : +# 288| v288_9(void) = ReturnIndirection[#this] : &:r288_6, ~m? +# 288| v288_10(void) = ReturnVoid : +# 288| v288_11(void) = AliasedUse : ~m? +# 288| v288_12(void) = ExitFunction : # 291| Point* NewAliasing(int) # 291| Block 0 @@ -1367,6 +1372,7 @@ ssa.cpp: # 311| r311_5(glval) = FieldAddress[x] : r311_4 # 311| mu311_6(int) = Store : &:r311_5, r311_2 # 312| v312_1(void) = NoOp : -# 310| v310_10(void) = ReturnVoid : -# 310| v310_11(void) = AliasedUse : ~m? -# 310| v310_12(void) = ExitFunction : +# 310| v310_10(void) = ReturnIndirection[#this] : &:r310_6, ~m? +# 310| v310_11(void) = ReturnVoid : +# 310| v310_12(void) = AliasedUse : ~m? +# 310| v310_13(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected index 3180c9211a5e..1d155eaf30d6 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected @@ -947,9 +947,10 @@ ssa.cpp: # 235| r235_8(glval) = VariableAddress[x] : # 235| m235_9(int) = InitializeParameter[x] : &:r235_8 # 235| v235_10(void) = NoOp : -# 235| v235_11(void) = ReturnVoid : -# 235| v235_12(void) = AliasedUse : ~m? -# 235| v235_13(void) = ExitFunction : +# 235| v235_11(void) = ReturnIndirection[#this] : &:r235_6, ~m? +# 235| v235_12(void) = ReturnVoid : +# 235| v235_13(void) = AliasedUse : ~m? +# 235| v235_14(void) = ExitFunction : # 236| void Constructible::g() # 236| Block 0 @@ -961,9 +962,10 @@ ssa.cpp: # 236| r236_6(glval) = Load : &:r236_4, m236_5 # 236| mu236_7(Constructible) = InitializeIndirection[#this] : &:r236_6 # 236| v236_8(void) = NoOp : -# 236| v236_9(void) = ReturnVoid : -# 236| v236_10(void) = AliasedUse : ~m? -# 236| v236_11(void) = ExitFunction : +# 236| v236_9(void) = ReturnIndirection[#this] : &:r236_6, ~m? +# 236| v236_10(void) = ReturnVoid : +# 236| v236_11(void) = AliasedUse : ~m? +# 236| v236_12(void) = ExitFunction : # 239| void ExplicitConstructorCalls() # 239| Block 0 @@ -1198,9 +1200,10 @@ ssa.cpp: # 286| r286_8(glval) = VariableAddress[x] : # 286| m286_9(int) = InitializeParameter[x] : &:r286_8 # 286| v286_10(void) = NoOp : -# 286| v286_11(void) = ReturnVoid : -# 286| v286_12(void) = AliasedUse : ~m? -# 286| v286_13(void) = ExitFunction : +# 286| v286_11(void) = ReturnIndirection[#this] : &:r286_6, ~m? +# 286| v286_12(void) = ReturnVoid : +# 286| v286_13(void) = AliasedUse : ~m? +# 286| v286_14(void) = ExitFunction : # 287| void A::A(A*) # 287| Block 0 @@ -1216,10 +1219,11 @@ ssa.cpp: # 287| r287_10(A *) = Load : &:r287_8, m287_9 # 287| mu287_11(unknown) = InitializeIndirection[p#0] : &:r287_10 # 287| v287_12(void) = NoOp : -# 287| v287_13(void) = ReturnIndirection[p#0] : &:r287_10, ~m? -# 287| v287_14(void) = ReturnVoid : -# 287| v287_15(void) = AliasedUse : ~m? -# 287| v287_16(void) = ExitFunction : +# 287| v287_13(void) = ReturnIndirection[#this] : &:r287_6, ~m? +# 287| v287_14(void) = ReturnIndirection[p#0] : &:r287_10, ~m? +# 287| v287_15(void) = ReturnVoid : +# 287| v287_16(void) = AliasedUse : ~m? +# 287| v287_17(void) = ExitFunction : # 288| void A::A() # 288| Block 0 @@ -1231,9 +1235,10 @@ ssa.cpp: # 288| r288_6(glval) = Load : &:r288_4, m288_5 # 288| mu288_7(A) = InitializeIndirection[#this] : &:r288_6 # 288| v288_8(void) = NoOp : -# 288| v288_9(void) = ReturnVoid : -# 288| v288_10(void) = AliasedUse : ~m? -# 288| v288_11(void) = ExitFunction : +# 288| v288_9(void) = ReturnIndirection[#this] : &:r288_6, ~m? +# 288| v288_10(void) = ReturnVoid : +# 288| v288_11(void) = AliasedUse : ~m? +# 288| v288_12(void) = ExitFunction : # 291| Point* NewAliasing(int) # 291| Block 0 @@ -1367,6 +1372,7 @@ ssa.cpp: # 311| r311_5(glval) = FieldAddress[x] : r311_4 # 311| mu311_6(int) = Store : &:r311_5, r311_2 # 312| v312_1(void) = NoOp : -# 310| v310_10(void) = ReturnVoid : -# 310| v310_11(void) = AliasedUse : ~m? -# 310| v310_12(void) = ExitFunction : +# 310| v310_10(void) = ReturnIndirection[#this] : &:r310_6, ~m? +# 310| v310_11(void) = ReturnVoid : +# 310| v310_12(void) = AliasedUse : ~m? +# 310| v310_13(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/lambdas/captures/elements.expected b/cpp/ql/test/library-tests/lambdas/captures/elements.expected index feeadc7a6040..8ba9cad40096 100644 --- a/cpp/ql/test/library-tests/lambdas/captures/elements.expected +++ b/cpp/ql/test/library-tests/lambdas/captures/elements.expected @@ -13,9 +13,9 @@ | captures.cpp:3:5:3:5 | (constructor) | | captures.cpp:3:5:3:5 | (constructor) | | captures.cpp:3:5:3:5 | (constructor) | -| captures.cpp:3:5:3:5 | declaration of (null) | -| captures.cpp:3:5:3:5 | declaration of (null) | -| captures.cpp:3:5:3:5 | definition of (null) | +| captures.cpp:3:5:3:5 | declaration of (constructor) | +| captures.cpp:3:5:3:5 | declaration of (constructor) | +| captures.cpp:3:5:3:5 | definition of (constructor) | | captures.cpp:3:5:3:5 | definition of operator= | | captures.cpp:3:5:3:5 | operator= | | captures.cpp:3:5:5:5 | [...](...){...} | @@ -50,9 +50,9 @@ | captures.cpp:9:5:9:5 | (constructor) | | captures.cpp:9:5:9:5 | (constructor) | | captures.cpp:9:5:9:5 | (constructor) | -| captures.cpp:9:5:9:5 | declaration of (null) | -| captures.cpp:9:5:9:5 | declaration of (null) | -| captures.cpp:9:5:9:5 | definition of (null) | +| captures.cpp:9:5:9:5 | declaration of (constructor) | +| captures.cpp:9:5:9:5 | declaration of (constructor) | +| captures.cpp:9:5:9:5 | definition of (constructor) | | captures.cpp:9:5:9:5 | definition of operator= | | captures.cpp:9:5:9:5 | operator= | | captures.cpp:9:5:11:5 | [...](...){...} | @@ -87,9 +87,9 @@ | captures.cpp:15:5:15:5 | (constructor) | | captures.cpp:15:5:15:5 | (constructor) | | captures.cpp:15:5:15:5 | (constructor) | -| captures.cpp:15:5:15:5 | declaration of (null) | -| captures.cpp:15:5:15:5 | declaration of (null) | -| captures.cpp:15:5:15:5 | definition of (null) | +| captures.cpp:15:5:15:5 | declaration of (constructor) | +| captures.cpp:15:5:15:5 | declaration of (constructor) | +| captures.cpp:15:5:15:5 | definition of (constructor) | | captures.cpp:15:5:15:5 | definition of operator= | | captures.cpp:15:5:15:5 | operator= | | captures.cpp:15:5:17:5 | [...](...){...} | @@ -129,9 +129,9 @@ | captures.cpp:22:19:22:19 | Unknown literal | | captures.cpp:22:19:22:19 | constructor init of field x | | captures.cpp:22:19:22:19 | constructor init of field y | -| captures.cpp:22:19:22:19 | declaration of (null) | -| captures.cpp:22:19:22:19 | definition of (null) | -| captures.cpp:22:19:22:19 | definition of (null) | +| captures.cpp:22:19:22:19 | declaration of (constructor) | +| captures.cpp:22:19:22:19 | definition of (constructor) | +| captures.cpp:22:19:22:19 | definition of (constructor) | | captures.cpp:22:19:22:19 | definition of operator= | | captures.cpp:22:19:22:19 | operator= | | captures.cpp:22:19:22:19 | return ... | @@ -187,9 +187,9 @@ | end_pos.cpp:9:15:9:15 | (constructor) | | end_pos.cpp:9:15:9:15 | Unknown literal | | end_pos.cpp:9:15:9:15 | constructor init of field ii | -| end_pos.cpp:9:15:9:15 | declaration of (null) | -| end_pos.cpp:9:15:9:15 | definition of (null) | -| end_pos.cpp:9:15:9:15 | definition of (null) | +| end_pos.cpp:9:15:9:15 | declaration of (constructor) | +| end_pos.cpp:9:15:9:15 | definition of (constructor) | +| end_pos.cpp:9:15:9:15 | definition of (constructor) | | end_pos.cpp:9:15:9:15 | definition of operator= | | end_pos.cpp:9:15:9:15 | operator= | | end_pos.cpp:9:15:9:15 | return ... | @@ -231,8 +231,10 @@ | file://:0:0:0:0 | const lambda [] type at line 9, col. 5 * | | file://:0:0:0:0 | const lambda [] type at line 9, col. 15 | | file://:0:0:0:0 | const lambda [] type at line 9, col. 15 & | +| file://:0:0:0:0 | const lambda [] type at line 9, col. 15 * | | file://:0:0:0:0 | const lambda [] type at line 15, col. 5 | | file://:0:0:0:0 | const lambda [] type at line 15, col. 5 & | +| file://:0:0:0:0 | const lambda [] type at line 15, col. 5 * | | file://:0:0:0:0 | const lambda [] type at line 22, col. 19 | | file://:0:0:0:0 | const lambda [] type at line 22, col. 19 & | | file://:0:0:0:0 | const lambda [] type at line 22, col. 19 * | @@ -277,8 +279,10 @@ | file://:0:0:0:0 | lambda [] type at line 9, col. 5 * | | file://:0:0:0:0 | lambda [] type at line 9, col. 15 & | | file://:0:0:0:0 | lambda [] type at line 9, col. 15 && | +| file://:0:0:0:0 | lambda [] type at line 9, col. 15 * | | file://:0:0:0:0 | lambda [] type at line 15, col. 5 & | | file://:0:0:0:0 | lambda [] type at line 15, col. 5 && | +| file://:0:0:0:0 | lambda [] type at line 15, col. 5 * | | file://:0:0:0:0 | lambda [] type at line 22, col. 19 & | | file://:0:0:0:0 | lambda [] type at line 22, col. 19 && | | file://:0:0:0:0 | lambda [] type at line 22, col. 19 * | diff --git a/cpp/ql/test/library-tests/macros/inmacroexpansion/inmacroexpansion.expected b/cpp/ql/test/library-tests/macros/inmacroexpansion/inmacroexpansion.expected index b60d112c9177..7ace5811466b 100644 --- a/cpp/ql/test/library-tests/macros/inmacroexpansion/inmacroexpansion.expected +++ b/cpp/ql/test/library-tests/macros/inmacroexpansion/inmacroexpansion.expected @@ -6,6 +6,8 @@ | file://:0:0:0:0 | p#0 | false | | test.cpp:0:0:0:0 | test.cpp | false | | test.cpp:2:1:2:61 | #define FOO class S{int i; void f(void) { int j; return; } }; | false | +| test.cpp:4:1:4:1 | S | false | +| test.cpp:4:1:4:1 | declaration of S | false | | test.cpp:4:1:4:1 | declaration of operator= | false | | test.cpp:4:1:4:1 | declaration of operator= | false | | test.cpp:4:1:4:1 | operator= | false | diff --git a/cpp/ql/test/library-tests/macros/macros/affectedbymacroexpansion.ql b/cpp/ql/test/library-tests/macros/macros/affectedbymacroexpansion.ql index 4ba665e98cc0..1c5b1c4b2de8 100644 --- a/cpp/ql/test/library-tests/macros/macros/affectedbymacroexpansion.ql +++ b/cpp/ql/test/library-tests/macros/macros/affectedbymacroexpansion.ql @@ -1,5 +1,5 @@ import cpp -from Block b, MacroAccess m +from BlockStmt b, MacroAccess m where affectedbymacroexpansion(unresolveElement(b), unresolveElement(m)) select b, m diff --git a/cpp/ql/test/library-tests/macros/macros/inmacroexpansion.ql b/cpp/ql/test/library-tests/macros/macros/inmacroexpansion.ql index afed90b56a60..cfaae6f4e8c6 100644 --- a/cpp/ql/test/library-tests/macros/macros/inmacroexpansion.ql +++ b/cpp/ql/test/library-tests/macros/macros/inmacroexpansion.ql @@ -1,5 +1,5 @@ import cpp -from Block b, MacroAccess m +from BlockStmt b, MacroAccess m where inmacroexpansion(unresolveElement(b), unresolveElement(m)) select b, m diff --git a/cpp/ql/test/library-tests/members/getters/members.expected b/cpp/ql/test/library-tests/members/getters/members.expected index a14ce851457c..fac28f04077a 100644 --- a/cpp/ql/test/library-tests/members/getters/members.expected +++ b/cpp/ql/test/library-tests/members/getters/members.expected @@ -8,6 +8,7 @@ | test.cpp:2:7:2:7 | C | test.cpp:8:10:8:23 | f_template_C_D | C::f_template_C_D(T) | getAMember(), getAMember(1), getAMemberFunction(), getCanonicalMember(1), getDeclaringType() | | test.cpp:2:7:2:7 | C | test.cpp:10:10:10:12 | f_C | C::f_C() | getAMember(), getAMember(2), getAMemberFunction(), getCanonicalMember(2), getDeclaringType() | | test.cpp:2:7:2:7 | C | test.cpp:11:10:11:14 | f_C_D | C::f_C_D() | getAMember(), getAMember(3), getAMemberFunction(), getCanonicalMember(3), getDeclaringType() | +| test.cpp:14:7:14:7 | D | test.cpp:14:7:14:7 | D | D::D() | getAMember(), getAMember(6), getAMemberFunction(), getCanonicalMember(6), getDeclaringType() | | test.cpp:14:7:14:7 | D | test.cpp:14:7:14:7 | operator= | D::operator=(D &&) | getAMember(), getAMember(5), getAMemberFunction(), getCanonicalMember(5), getDeclaringType() | | test.cpp:14:7:14:7 | D | test.cpp:14:7:14:7 | operator= | D::operator=(const D &) | getAMember(), getAMember(4), getAMemberFunction(), getCanonicalMember(4), getDeclaringType() | | test.cpp:14:7:14:7 | D | test.cpp:17:10:17:10 | f_template_C_D | D::f_template_C_D(double) | getAMember(), getAMember(0), getAMemberFunction(), getDeclaringType() | diff --git a/cpp/ql/test/library-tests/members/this/test.cpp b/cpp/ql/test/library-tests/members/this/test.cpp new file mode 100644 index 000000000000..ae155e748450 --- /dev/null +++ b/cpp/ql/test/library-tests/members/this/test.cpp @@ -0,0 +1,129 @@ + +int global; + +class C { + int x; + +public: + + void f1() { + // Implicit dereference of `this.` + x++; + } + + void f2() { + // Explicit dereference of `this.` + this->x++; + } + + int f3() const { + // We expect the type of `this` to be const-qualified. + return x; + } + + int f4() volatile { + // We expect the type of `this` to be volatile-qualified. + return x; + } + + int f5() const volatile { + // We expect the type of `this` to be qualified as both const and volatile. + return x; + } + + void f6() { + // No use of `this`, but we still expect to be able to get its type. + global++; + } + + float f7() const & { + // We expect the type of `this` to be const-qualified. + return x; + } + + float f8() && { + // We expect the type of `this` to be unqualified. + return x; + } +}; + +// We want to test that D* is in the database even when there's no use of it, +// not even through an implicit dereference of `this`. +class D { + void f() { + global++; + } +}; + +template +class InstantiatedTemplateClass { + int x; + +public: + + void f1() { + // Implicit dereference of `this.` + x++; + } + + void f2() { + // Explicit dereference of `this.` + this->x++; + } + + int f3() const { + // We expect the type of `this` to be const-qualified. + return x; + } + + int f4() volatile { + // We expect the type of `this` to be volatile-qualified. + return x; + } + + int f5() const volatile { + // We expect the type of `this` to be qualified as both const and volatile. + return x; + } + + void f6() { + // No use of `this`, but we still expect to be able to get its type. + global++; + } + + float f7() const & { + // We expect the type of `this` to be const-qualified. + return x; + } + + float f8() && { + // We expect the type of `this` to be unqualified. + return x; + } +}; + +void instantiate() { + InstantiatedTemplateClass x; + x.f1(); + x.f2(); + x.f3(); + x.f4(); + x.f5(); + x.f6(); + x.f7(); + + float val = InstantiatedTemplateClass().f8(); +} + +// Since there are no instantiations of this class, we don't expect +// MemberFunction::getTypeOfThis() to hold. +template +class UninstantiatedTemplateClass { + int x; + +public: + + void f1() { + x++; + } +}; diff --git a/cpp/ql/test/library-tests/members/this/this.expected b/cpp/ql/test/library-tests/members/this/this.expected new file mode 100644 index 000000000000..d7f166e4898e --- /dev/null +++ b/cpp/ql/test/library-tests/members/this/this.expected @@ -0,0 +1,48 @@ +thisExprType +| test.cpp:11:5:11:5 | this | file://:0:0:0:0 | C * | +| test.cpp:16:5:16:8 | this | file://:0:0:0:0 | C * | +| test.cpp:21:12:21:12 | this | file://:0:0:0:0 | const C * | +| test.cpp:26:12:26:12 | this | file://:0:0:0:0 | volatile C * | +| test.cpp:31:12:31:12 | this | file://:0:0:0:0 | const volatile C * | +| test.cpp:41:12:41:12 | this | file://:0:0:0:0 | const C * | +| test.cpp:46:12:46:12 | this | file://:0:0:0:0 | C * | +| test.cpp:66:5:66:5 | this | file://:0:0:0:0 | InstantiatedTemplateClass * | +| test.cpp:66:5:66:5 | this | file://:0:0:0:0 | InstantiatedTemplateClass * | +| test.cpp:71:5:71:8 | this | file://:0:0:0:0 | InstantiatedTemplateClass * | +| test.cpp:71:5:71:8 | this | file://:0:0:0:0 | InstantiatedTemplateClass * | +| test.cpp:76:12:76:12 | this | file://:0:0:0:0 | const InstantiatedTemplateClass * | +| test.cpp:76:12:76:12 | this | file://:0:0:0:0 | const InstantiatedTemplateClass * | +| test.cpp:81:12:81:12 | this | file://:0:0:0:0 | volatile InstantiatedTemplateClass * | +| test.cpp:81:12:81:12 | this | file://:0:0:0:0 | volatile InstantiatedTemplateClass * | +| test.cpp:86:12:86:12 | this | file://:0:0:0:0 | const volatile InstantiatedTemplateClass * | +| test.cpp:86:12:86:12 | this | file://:0:0:0:0 | const volatile InstantiatedTemplateClass * | +| test.cpp:96:12:96:12 | this | file://:0:0:0:0 | const InstantiatedTemplateClass * | +| test.cpp:96:12:96:12 | this | file://:0:0:0:0 | const InstantiatedTemplateClass * | +| test.cpp:101:12:101:12 | this | file://:0:0:0:0 | InstantiatedTemplateClass * | +| test.cpp:101:12:101:12 | this | file://:0:0:0:0 | InstantiatedTemplateClass * | +#select +| test.cpp:9:8:9:9 | f1 | file://:0:0:0:0 | C * | +| test.cpp:14:8:14:9 | f2 | file://:0:0:0:0 | C * | +| test.cpp:19:7:19:8 | f3 | file://:0:0:0:0 | const C * | +| test.cpp:24:7:24:8 | f4 | file://:0:0:0:0 | volatile C * | +| test.cpp:29:7:29:8 | f5 | file://:0:0:0:0 | const volatile C * | +| test.cpp:34:8:34:9 | f6 | file://:0:0:0:0 | C * | +| test.cpp:39:9:39:10 | f7 | file://:0:0:0:0 | const C * | +| test.cpp:44:9:44:10 | f8 | file://:0:0:0:0 | C * | +| test.cpp:53:8:53:8 | f | file://:0:0:0:0 | D * | +| test.cpp:64:8:64:8 | f1 | file://:0:0:0:0 | InstantiatedTemplateClass * | +| test.cpp:64:8:64:9 | f1 | file://:0:0:0:0 | InstantiatedTemplateClass * | +| test.cpp:69:8:69:8 | f2 | file://:0:0:0:0 | InstantiatedTemplateClass * | +| test.cpp:69:8:69:9 | f2 | file://:0:0:0:0 | InstantiatedTemplateClass * | +| test.cpp:74:7:74:7 | f3 | file://:0:0:0:0 | const InstantiatedTemplateClass * | +| test.cpp:74:7:74:8 | f3 | file://:0:0:0:0 | const InstantiatedTemplateClass * | +| test.cpp:79:7:79:7 | f4 | file://:0:0:0:0 | volatile InstantiatedTemplateClass * | +| test.cpp:79:7:79:8 | f4 | file://:0:0:0:0 | volatile InstantiatedTemplateClass * | +| test.cpp:84:7:84:7 | f5 | file://:0:0:0:0 | const volatile InstantiatedTemplateClass * | +| test.cpp:84:7:84:8 | f5 | file://:0:0:0:0 | const volatile InstantiatedTemplateClass * | +| test.cpp:89:8:89:8 | f6 | file://:0:0:0:0 | InstantiatedTemplateClass * | +| test.cpp:89:8:89:9 | f6 | file://:0:0:0:0 | InstantiatedTemplateClass * | +| test.cpp:94:9:94:9 | f7 | file://:0:0:0:0 | const InstantiatedTemplateClass * | +| test.cpp:94:9:94:10 | f7 | file://:0:0:0:0 | const InstantiatedTemplateClass * | +| test.cpp:99:9:99:9 | f8 | file://:0:0:0:0 | InstantiatedTemplateClass * | +| test.cpp:99:9:99:10 | f8 | file://:0:0:0:0 | InstantiatedTemplateClass * | diff --git a/cpp/ql/test/library-tests/members/this/this.ql b/cpp/ql/test/library-tests/members/this/this.ql new file mode 100644 index 000000000000..b4ab73254d29 --- /dev/null +++ b/cpp/ql/test/library-tests/members/this/this.ql @@ -0,0 +1,6 @@ +import cpp + +query predicate thisExprType(ThisExpr e, Type t) { t = e.getType() } + +from MemberFunction f +select f, f.getTypeOfThis() diff --git a/cpp/ql/test/library-tests/noexcept/copy_from_prototype/copy_from_prototype.expected b/cpp/ql/test/library-tests/noexcept/copy_from_prototype/copy_from_prototype.expected index f5ef2d77c986..5488cf803e6b 100644 --- a/cpp/ql/test/library-tests/noexcept/copy_from_prototype/copy_from_prototype.expected +++ b/cpp/ql/test/library-tests/noexcept/copy_from_prototype/copy_from_prototype.expected @@ -2,8 +2,8 @@ | copy_from_prototype.cpp:3:7:3:7 | a | a::a(const a &) -> void | copy_from_prototype.cpp:3:7:3:7 | a | | | copy_from_prototype.cpp:3:7:3:7 | operator= | a::operator=(a &&) -> a & | copy_from_prototype.cpp:3:7:3:7 | a | | | copy_from_prototype.cpp:3:7:3:7 | operator= | a::operator=(const a &) -> a & | copy_from_prototype.cpp:3:7:3:7 | a | | -| copy_from_prototype.cpp:4:26:4:26 | a | a<>::a<(unnamed)>() -> void | copy_from_prototype.cpp:3:7:3:7 | a<> | 123 | -| copy_from_prototype.cpp:4:26:4:26 | a | a::a<(unnamed)>() -> void | copy_from_prototype.cpp:3:7:3:7 | a | | +| copy_from_prototype.cpp:4:26:4:26 | a | a<>::a<(unnamed template parameter)>() -> void | copy_from_prototype.cpp:3:7:3:7 | a<> | 123 | +| copy_from_prototype.cpp:4:26:4:26 | a | a::a<(unnamed template parameter)>() -> void | copy_from_prototype.cpp:3:7:3:7 | a | | | copy_from_prototype.cpp:7:7:7:7 | b | b::b() -> void | copy_from_prototype.cpp:7:7:7:7 | b | | | copy_from_prototype.cpp:7:7:7:7 | b | b::b(b &&) -> void | copy_from_prototype.cpp:7:7:7:7 | b | | | copy_from_prototype.cpp:7:7:7:7 | b | b::b(const b &) -> void | copy_from_prototype.cpp:7:7:7:7 | b | | @@ -13,8 +13,8 @@ | copy_from_prototype.cpp:13:7:13:7 | c | c::c(const c &) -> void | copy_from_prototype.cpp:13:7:13:7 | c | | | copy_from_prototype.cpp:13:7:13:7 | operator= | c::operator=(c &&) -> c & | copy_from_prototype.cpp:13:7:13:7 | c | | | copy_from_prototype.cpp:13:7:13:7 | operator= | c::operator=(const c &) -> c & | copy_from_prototype.cpp:13:7:13:7 | c | | -| copy_from_prototype.cpp:14:26:14:26 | c | c::c<(unnamed)>() -> void | copy_from_prototype.cpp:13:7:13:7 | c | X | -| copy_from_prototype.cpp:14:26:14:26 | c | c::c<(unnamed)>() -> void | copy_from_prototype.cpp:13:7:13:7 | c | | +| copy_from_prototype.cpp:14:26:14:26 | c | c::c<(unnamed template parameter)>() -> void | copy_from_prototype.cpp:13:7:13:7 | c | X | +| copy_from_prototype.cpp:14:26:14:26 | c | c::c<(unnamed template parameter)>() -> void | copy_from_prototype.cpp:13:7:13:7 | c | | | copy_from_prototype.cpp:17:7:17:7 | d | d::d() -> void | copy_from_prototype.cpp:17:7:17:7 | d | | | copy_from_prototype.cpp:17:7:17:7 | d | d::d(const d &) -> void | copy_from_prototype.cpp:17:7:17:7 | d | | | copy_from_prototype.cpp:17:7:17:7 | d | d::d(d &&) -> void | copy_from_prototype.cpp:17:7:17:7 | d | | @@ -24,7 +24,7 @@ | copy_from_prototype.cpp:22:8:22:8 | e | e::e(e &&) -> void | copy_from_prototype.cpp:22:8:22:8 | e | | | copy_from_prototype.cpp:22:8:22:8 | operator= | e::operator=(const e &) -> e & | copy_from_prototype.cpp:22:8:22:8 | e | | | copy_from_prototype.cpp:22:8:22:8 | operator= | e::operator=(e &&) -> e & | copy_from_prototype.cpp:22:8:22:8 | e | | -| copy_from_prototype.cpp:23:26:23:26 | e | e::e<(unnamed)>() -> void | copy_from_prototype.cpp:22:8:22:8 | e | 456 | -| copy_from_prototype.cpp:26:35:26:43 | e | e::e<(unnamed)>() -> void | copy_from_prototype.cpp:22:8:22:8 | e | 456 | +| copy_from_prototype.cpp:23:26:23:26 | e | e::e<(unnamed template parameter)>() -> void | copy_from_prototype.cpp:22:8:22:8 | e | 456 | +| copy_from_prototype.cpp:26:35:26:43 | e | e::e<(unnamed template parameter)>() -> void | copy_from_prototype.cpp:22:8:22:8 | e | 456 | | file://:0:0:0:0 | operator= | __va_list_tag::operator=(__va_list_tag &&) -> __va_list_tag & | file://:0:0:0:0 | __va_list_tag | | | file://:0:0:0:0 | operator= | __va_list_tag::operator=(const __va_list_tag &) -> __va_list_tag & | file://:0:0:0:0 | __va_list_tag | | diff --git a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/lowerBound.expected b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/lowerBound.expected index 2cc7f9a5386b..472ba0a1b7c7 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/lowerBound.expected +++ b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/lowerBound.expected @@ -1,483 +1,660 @@ -| inline_assembly.c:10:3:10:3 | y | 0.0 | -| inline_assembly.c:12:29:12:29 | x | 0.0 | -| inline_assembly.c:12:32:12:32 | y | 1.0 | -| inline_assembly.c:16:25:16:25 | x | 0.0 | -| inline_assembly.c:16:35:16:35 | y | 1.0 | -| inline_assembly.c:21:29:21:29 | x | 0.0 | -| inline_assembly.c:21:32:21:32 | y | 0.0 | -| minmax.c:18:37:18:37 | x | 1.0 | -| minmax.c:18:40:18:40 | y | 2.0 | -| minmax.c:18:43:18:43 | z | 3.0 | -| minmax.c:20:2:20:2 | z | -2.147483648E9 | -| minmax.c:22:8:22:8 | x | 1.0 | -| minmax.c:22:14:22:14 | y | 2.0 | -| minmax.c:22:18:22:18 | t | -2.147483648E9 | -| minmax.c:22:22:22:22 | x | 1.0 | -| minmax.c:23:3:23:3 | t | 0.0 | -| minmax.c:26:37:26:37 | x | 1.0 | -| minmax.c:26:40:26:40 | y | 2.0 | -| minmax.c:26:43:26:43 | z | 0.0 | -| test.c:8:5:8:9 | count | -2.147483648E9 | -| test.c:8:13:8:17 | count | -2.147483648E9 | -| test.c:10:10:10:14 | count | -2.147483648E9 | -| test.c:16:5:16:9 | count | -2.147483648E9 | -| test.c:16:14:16:18 | count | 0.0 | -| test.c:18:10:18:14 | count | 0.0 | -| test.c:24:5:24:9 | count | 0.0 | -| test.c:25:5:25:9 | count | -2.147483648E9 | -| test.c:25:13:25:17 | count | 1.0 | -| test.c:27:10:27:14 | count | 0.0 | -| test.c:33:8:33:8 | i | -2.147483648E9 | -| test.c:33:15:33:15 | i | 0.0 | -| test.c:33:22:33:22 | i | -2.147483648E9 | -| test.c:33:26:33:26 | i | 0.0 | -| test.c:34:5:34:9 | total | -2.147483648E9 | -| test.c:34:14:34:14 | i | 0.0 | -| test.c:36:10:36:14 | total | -2.147483648E9 | -| test.c:36:18:36:18 | i | 2.0 | -| test.c:42:8:42:8 | i | -2.147483648E9 | -| test.c:42:15:42:15 | i | 0.0 | -| test.c:42:22:42:22 | i | 0.0 | -| test.c:43:5:43:9 | total | -2.147483648E9 | -| test.c:43:14:43:14 | i | 0.0 | -| test.c:45:10:45:14 | total | -2.147483648E9 | -| test.c:45:18:45:18 | i | 2.0 | -| test.c:51:8:51:8 | i | -2.147483648E9 | -| test.c:51:15:51:15 | i | 0.0 | -| test.c:51:24:51:24 | i | -2.147483648E9 | -| test.c:51:28:51:28 | i | 0.0 | -| test.c:52:5:52:9 | total | -2.147483648E9 | -| test.c:52:14:52:14 | i | 0.0 | -| test.c:54:10:54:14 | total | -2.147483648E9 | -| test.c:54:18:54:18 | i | 2.0 | -| test.c:58:7:58:7 | i | -2.147483648E9 | -| test.c:59:9:59:9 | i | -2.147483648E9 | -| test.c:60:14:60:14 | i | -2.147483648E9 | -| test.c:67:15:67:15 | y | -2.147483648E9 | -| test.c:67:20:67:20 | y | -999.0 | -| test.c:68:9:68:9 | x | -2.147483648E9 | -| test.c:68:13:68:13 | y | -999.0 | -| test.c:69:14:69:14 | x | -2.147483648E9 | -| test.c:72:10:72:10 | y | -2.147483648E9 | -| test.c:76:7:76:7 | y | -2.147483648E9 | -| test.c:77:9:77:9 | x | -2.147483648E9 | -| test.c:81:9:81:9 | x | -2.147483648E9 | -| test.c:85:10:85:10 | x | 4.0 | -| test.c:89:7:89:7 | y | -2.147483648E9 | -| test.c:90:9:90:9 | x | -2.147483648E9 | -| test.c:90:13:90:13 | y | 8.0 | -| test.c:93:12:93:12 | x | 8.0 | -| test.c:100:3:100:3 | c | -128.0 | -| test.c:101:7:101:7 | c | -128.0 | -| test.c:104:7:104:7 | c | -128.0 | -| test.c:105:5:105:5 | c | -128.0 | -| test.c:106:9:106:9 | c | -128.0 | -| test.c:109:9:109:9 | c | -128.0 | -| test.c:119:10:119:10 | n | 0.0 | -| test.c:124:11:124:15 | Start | 0.0 | -| test.c:127:6:127:10 | Start | 0.0 | -| test.c:127:15:127:20 | Length | 0.0 | -| test.c:135:22:135:22 | c | -128.0 | -| test.c:137:20:137:20 | x | 0.0 | -| test.c:138:11:138:11 | i | -2.147483648E9 | -| test.c:139:19:139:19 | c | -128.0 | -| test.c:139:23:139:23 | i | -2.147483648E9 | -| test.c:139:27:139:28 | uc | 0.0 | -| test.c:139:32:139:32 | x | 0.0 | -| test.c:139:36:139:36 | y | 0.0 | -| test.c:139:40:139:40 | z | -2.147483648E9 | -| test.c:144:23:144:23 | x | -2.147483648E9 | -| test.c:145:32:145:32 | x | -2.147483648E9 | -| test.c:146:33:146:33 | x | -2.147483648E9 | -| test.c:147:31:147:31 | x | -2.147483648E9 | -| test.c:148:13:148:13 | x | -2.147483648E9 | -| test.c:149:23:149:23 | x | -2.147483648E9 | -| test.c:150:10:150:11 | x0 | -128.0 | -| test.c:150:15:150:16 | x1 | 0.0 | -| test.c:150:20:150:21 | x2 | 0.0 | -| test.c:150:25:150:26 | x3 | -2.147483648E9 | -| test.c:150:30:150:31 | c0 | -128.0 | -| test.c:150:35:150:36 | s0 | 0.0 | -| test.c:154:11:154:11 | x | -9.223372036854776E18 | -| test.c:154:20:154:20 | x | 1.0 | -| test.c:154:30:154:30 | x | 1.0 | -| test.c:154:35:154:35 | x | 1.0 | -| test.c:161:12:161:12 | a | -2.147483648E9 | -| test.c:161:17:161:17 | a | 3.0 | -| test.c:162:14:162:14 | a | 3.0 | -| test.c:163:14:163:14 | a | 3.0 | -| test.c:164:5:164:9 | total | 0.0 | -| test.c:164:14:164:14 | b | 3.0 | -| test.c:164:16:164:16 | c | -11.0 | -| test.c:166:12:166:12 | a | -2.147483648E9 | -| test.c:166:17:166:17 | a | 0.0 | -| test.c:167:14:167:14 | a | 0.0 | -| test.c:168:14:168:14 | a | 0.0 | -| test.c:169:5:169:9 | total | -8.0 | -| test.c:169:14:169:14 | b | 0.0 | -| test.c:169:16:169:16 | c | -11.0 | -| test.c:171:13:171:13 | a | -2.147483648E9 | -| test.c:171:18:171:18 | a | -7.0 | -| test.c:172:14:172:14 | a | -7.0 | -| test.c:173:14:173:14 | a | -7.0 | -| test.c:174:5:174:9 | total | -19.0 | -| test.c:174:14:174:14 | b | -7.0 | -| test.c:174:16:174:16 | c | -11.0 | -| test.c:176:13:176:13 | a | -2.147483648E9 | -| test.c:176:18:176:18 | a | -7.0 | -| test.c:177:14:177:14 | a | -7.0 | -| test.c:178:14:178:14 | a | -7.0 | -| test.c:179:5:179:9 | total | -37.0 | -| test.c:179:14:179:14 | b | -7.0 | -| test.c:179:16:179:16 | c | -1.0 | -| test.c:181:13:181:13 | a | -2.147483648E9 | -| test.c:181:18:181:18 | a | -7.0 | -| test.c:182:14:182:14 | a | -7.0 | -| test.c:183:14:183:14 | a | -7.0 | -| test.c:184:5:184:9 | total | -45.0 | -| test.c:184:14:184:14 | b | -7.0 | -| test.c:184:16:184:16 | c | -0.0 | -| test.c:186:13:186:13 | a | -2.147483648E9 | -| test.c:186:18:186:18 | a | -7.0 | -| test.c:187:14:187:14 | a | -7.0 | -| test.c:188:14:188:14 | a | -7.0 | -| test.c:189:5:189:9 | total | -52.0 | -| test.c:189:14:189:14 | b | -7.0 | -| test.c:189:16:189:16 | c | 2.0 | -| test.c:192:10:192:14 | total | -57.0 | -| test.c:200:12:200:12 | a | -2.147483648E9 | -| test.c:200:17:200:17 | a | 3.0 | -| test.c:200:33:200:33 | b | -2.147483648E9 | -| test.c:200:38:200:38 | b | 5.0 | -| test.c:201:13:201:13 | a | 3.0 | -| test.c:201:15:201:15 | b | 5.0 | -| test.c:202:5:202:9 | total | 0.0 | -| test.c:202:14:202:14 | r | -2.147483648E9 | -| test.c:204:12:204:12 | a | -2.147483648E9 | -| test.c:204:17:204:17 | a | 3.0 | -| test.c:204:33:204:33 | b | -2.147483648E9 | -| test.c:204:38:204:38 | b | 0.0 | -| test.c:205:13:205:13 | a | 3.0 | -| test.c:205:15:205:15 | b | 0.0 | -| test.c:206:5:206:9 | total | -2.147483648E9 | -| test.c:206:14:206:14 | r | -2.147483648E9 | -| test.c:208:12:208:12 | a | -2.147483648E9 | -| test.c:208:17:208:17 | a | 3.0 | -| test.c:208:35:208:35 | b | -2.147483648E9 | -| test.c:208:40:208:40 | b | -13.0 | -| test.c:209:13:209:13 | a | 3.0 | -| test.c:209:15:209:15 | b | -13.0 | -| test.c:210:5:210:9 | total | -2.147483648E9 | -| test.c:210:14:210:14 | r | -2.147483648E9 | -| test.c:212:12:212:12 | a | -2.147483648E9 | -| test.c:212:17:212:17 | a | 3.0 | -| test.c:212:35:212:35 | b | -2.147483648E9 | -| test.c:212:40:212:40 | b | -13.0 | -| test.c:213:13:213:13 | a | 3.0 | -| test.c:213:15:213:15 | b | -13.0 | -| test.c:214:5:214:9 | total | -2.147483648E9 | -| test.c:214:14:214:14 | r | -2.147483648E9 | -| test.c:216:12:216:12 | a | -2.147483648E9 | -| test.c:216:17:216:17 | a | 3.0 | -| test.c:216:35:216:35 | b | -2.147483648E9 | -| test.c:216:40:216:40 | b | -13.0 | -| test.c:217:13:217:13 | a | 3.0 | -| test.c:217:15:217:15 | b | -13.0 | -| test.c:218:5:218:9 | total | -2.147483648E9 | -| test.c:218:14:218:14 | r | -2.147483648E9 | -| test.c:221:10:221:14 | total | -2.147483648E9 | -| test.c:228:12:228:12 | a | -2.147483648E9 | -| test.c:228:17:228:17 | a | 0.0 | -| test.c:228:33:228:33 | b | -2.147483648E9 | -| test.c:228:38:228:38 | b | 5.0 | -| test.c:229:13:229:13 | a | 0.0 | -| test.c:229:15:229:15 | b | 5.0 | -| test.c:230:5:230:9 | total | 0.0 | -| test.c:230:14:230:14 | r | -2.147483648E9 | -| test.c:232:12:232:12 | a | -2.147483648E9 | -| test.c:232:17:232:17 | a | 0.0 | -| test.c:232:33:232:33 | b | -2.147483648E9 | -| test.c:232:38:232:38 | b | 0.0 | -| test.c:233:13:233:13 | a | 0.0 | -| test.c:233:15:233:15 | b | 0.0 | -| test.c:234:5:234:9 | total | -2.147483648E9 | -| test.c:234:14:234:14 | r | -2.147483648E9 | -| test.c:236:12:236:12 | a | -2.147483648E9 | -| test.c:236:17:236:17 | a | 0.0 | -| test.c:236:35:236:35 | b | -2.147483648E9 | -| test.c:236:40:236:40 | b | -13.0 | -| test.c:237:13:237:13 | a | 0.0 | -| test.c:237:15:237:15 | b | -13.0 | -| test.c:238:5:238:9 | total | -2.147483648E9 | -| test.c:238:14:238:14 | r | -2.147483648E9 | -| test.c:240:12:240:12 | a | -2.147483648E9 | -| test.c:240:17:240:17 | a | 0.0 | -| test.c:240:35:240:35 | b | -2.147483648E9 | -| test.c:240:40:240:40 | b | -13.0 | -| test.c:241:13:241:13 | a | 0.0 | -| test.c:241:15:241:15 | b | -13.0 | -| test.c:242:5:242:9 | total | -2.147483648E9 | -| test.c:242:14:242:14 | r | -2.147483648E9 | -| test.c:244:12:244:12 | a | -2.147483648E9 | -| test.c:244:17:244:17 | a | 0.0 | -| test.c:244:35:244:35 | b | -2.147483648E9 | -| test.c:244:40:244:40 | b | -13.0 | -| test.c:245:13:245:13 | a | 0.0 | -| test.c:245:15:245:15 | b | -13.0 | -| test.c:246:5:246:9 | total | -2.147483648E9 | -| test.c:246:14:246:14 | r | -2.147483648E9 | -| test.c:249:10:249:14 | total | -2.147483648E9 | -| test.c:256:14:256:14 | a | -2.147483648E9 | -| test.c:256:19:256:19 | a | -17.0 | -| test.c:256:35:256:35 | b | -2.147483648E9 | -| test.c:256:40:256:40 | b | 5.0 | -| test.c:257:13:257:13 | a | -17.0 | -| test.c:257:15:257:15 | b | 5.0 | -| test.c:258:5:258:9 | total | 0.0 | -| test.c:258:14:258:14 | r | -2.147483648E9 | -| test.c:260:14:260:14 | a | -2.147483648E9 | -| test.c:260:19:260:19 | a | -17.0 | -| test.c:260:35:260:35 | b | -2.147483648E9 | -| test.c:260:40:260:40 | b | 0.0 | -| test.c:261:13:261:13 | a | -17.0 | -| test.c:261:15:261:15 | b | 0.0 | -| test.c:262:5:262:9 | total | -2.147483648E9 | -| test.c:262:14:262:14 | r | -2.147483648E9 | -| test.c:264:14:264:14 | a | -2.147483648E9 | -| test.c:264:19:264:19 | a | -17.0 | -| test.c:264:37:264:37 | b | -2.147483648E9 | -| test.c:264:42:264:42 | b | -13.0 | -| test.c:265:13:265:13 | a | -17.0 | -| test.c:265:15:265:15 | b | -13.0 | -| test.c:266:5:266:9 | total | -2.147483648E9 | -| test.c:266:14:266:14 | r | -2.147483648E9 | -| test.c:268:14:268:14 | a | -2.147483648E9 | -| test.c:268:19:268:19 | a | -17.0 | -| test.c:268:37:268:37 | b | -2.147483648E9 | -| test.c:268:42:268:42 | b | -13.0 | -| test.c:269:13:269:13 | a | -17.0 | -| test.c:269:15:269:15 | b | -13.0 | -| test.c:270:5:270:9 | total | -2.147483648E9 | -| test.c:270:14:270:14 | r | -2.147483648E9 | -| test.c:272:14:272:14 | a | -2.147483648E9 | -| test.c:272:19:272:19 | a | -17.0 | -| test.c:272:37:272:37 | b | -2.147483648E9 | -| test.c:272:42:272:42 | b | -13.0 | -| test.c:273:13:273:13 | a | -17.0 | -| test.c:273:15:273:15 | b | -13.0 | -| test.c:274:5:274:9 | total | -2.147483648E9 | -| test.c:274:14:274:14 | r | -2.147483648E9 | -| test.c:277:10:277:14 | total | -2.147483648E9 | -| test.c:284:14:284:14 | a | -2.147483648E9 | -| test.c:284:19:284:19 | a | -17.0 | -| test.c:284:34:284:34 | b | -2.147483648E9 | -| test.c:284:39:284:39 | b | 5.0 | -| test.c:285:13:285:13 | a | -17.0 | -| test.c:285:15:285:15 | b | 5.0 | -| test.c:286:5:286:9 | total | 0.0 | -| test.c:286:14:286:14 | r | -2.147483648E9 | -| test.c:288:14:288:14 | a | -2.147483648E9 | -| test.c:288:19:288:19 | a | -17.0 | -| test.c:288:34:288:34 | b | -2.147483648E9 | -| test.c:288:39:288:39 | b | 0.0 | -| test.c:289:13:289:13 | a | -17.0 | -| test.c:289:15:289:15 | b | 0.0 | -| test.c:290:5:290:9 | total | -2.147483648E9 | -| test.c:290:14:290:14 | r | -2.147483648E9 | -| test.c:292:14:292:14 | a | -2.147483648E9 | -| test.c:292:19:292:19 | a | -17.0 | -| test.c:292:36:292:36 | b | -2.147483648E9 | -| test.c:292:41:292:41 | b | -13.0 | -| test.c:293:13:293:13 | a | -17.0 | -| test.c:293:15:293:15 | b | -13.0 | -| test.c:294:5:294:9 | total | -2.147483648E9 | -| test.c:294:14:294:14 | r | -2.147483648E9 | -| test.c:296:14:296:14 | a | -2.147483648E9 | -| test.c:296:19:296:19 | a | -17.0 | -| test.c:296:36:296:36 | b | -2.147483648E9 | -| test.c:296:41:296:41 | b | -13.0 | -| test.c:297:13:297:13 | a | -17.0 | -| test.c:297:15:297:15 | b | -13.0 | -| test.c:298:5:298:9 | total | -2.147483648E9 | -| test.c:298:14:298:14 | r | -2.147483648E9 | -| test.c:300:14:300:14 | a | -2.147483648E9 | -| test.c:300:19:300:19 | a | -17.0 | -| test.c:300:36:300:36 | b | -2.147483648E9 | -| test.c:300:41:300:41 | b | -13.0 | -| test.c:301:13:301:13 | a | -17.0 | -| test.c:301:15:301:15 | b | -13.0 | -| test.c:302:5:302:9 | total | -2.147483648E9 | -| test.c:302:14:302:14 | r | -2.147483648E9 | -| test.c:305:10:305:14 | total | -2.147483648E9 | -| test.c:312:14:312:14 | a | -2.147483648E9 | -| test.c:312:19:312:19 | a | -17.0 | -| test.c:312:35:312:35 | b | -2.147483648E9 | -| test.c:312:40:312:40 | b | 5.0 | -| test.c:313:13:313:13 | a | -17.0 | -| test.c:313:15:313:15 | b | 5.0 | -| test.c:314:5:314:9 | total | 0.0 | -| test.c:314:14:314:14 | r | -2.147483648E9 | -| test.c:316:14:316:14 | a | -2.147483648E9 | -| test.c:316:19:316:19 | a | -17.0 | -| test.c:316:35:316:35 | b | -2.147483648E9 | -| test.c:316:40:316:40 | b | 0.0 | -| test.c:317:13:317:13 | a | -17.0 | -| test.c:317:15:317:15 | b | 0.0 | -| test.c:318:5:318:9 | total | -2.147483648E9 | -| test.c:318:14:318:14 | r | -2.147483648E9 | -| test.c:320:14:320:14 | a | -2.147483648E9 | -| test.c:320:19:320:19 | a | -17.0 | -| test.c:320:37:320:37 | b | -2.147483648E9 | -| test.c:320:42:320:42 | b | -13.0 | -| test.c:321:13:321:13 | a | -17.0 | -| test.c:321:15:321:15 | b | -13.0 | -| test.c:322:5:322:9 | total | -2.147483648E9 | -| test.c:322:14:322:14 | r | -2.147483648E9 | -| test.c:324:14:324:14 | a | -2.147483648E9 | -| test.c:324:19:324:19 | a | -17.0 | -| test.c:324:37:324:37 | b | -2.147483648E9 | -| test.c:324:42:324:42 | b | -13.0 | -| test.c:325:13:325:13 | a | -17.0 | -| test.c:325:15:325:15 | b | -13.0 | -| test.c:326:5:326:9 | total | -2.147483648E9 | -| test.c:326:14:326:14 | r | -2.147483648E9 | -| test.c:328:14:328:14 | a | -2.147483648E9 | -| test.c:328:19:328:19 | a | -17.0 | -| test.c:328:37:328:37 | b | -2.147483648E9 | -| test.c:328:42:328:42 | b | -13.0 | -| test.c:329:13:329:13 | a | -17.0 | -| test.c:329:15:329:15 | b | -13.0 | -| test.c:330:5:330:9 | total | -2.147483648E9 | -| test.c:330:14:330:14 | r | -2.147483648E9 | -| test.c:333:10:333:14 | total | -2.147483648E9 | -| test.c:338:7:338:7 | x | -2.147483648E9 | -| test.c:342:10:342:10 | i | 0.0 | -| test.c:343:5:343:5 | i | 0.0 | -| test.c:345:3:345:3 | d | -2.147483648E9 | -| test.c:345:7:345:7 | i | 3.0 | -| test.c:346:7:346:7 | x | 0.0 | -| test.c:347:9:347:9 | d | 3.0 | -| test.c:347:14:347:14 | x | 0.0 | -| test.c:357:3:357:4 | y1 | 0.0 | -| test.c:357:8:357:8 | x | 0.0 | -| test.c:357:18:357:18 | x | 0.0 | -| test.c:358:3:358:4 | y2 | 0.0 | -| test.c:358:8:358:8 | x | 0.0 | -| test.c:358:24:358:24 | x | 0.0 | -| test.c:359:3:359:4 | y3 | 0.0 | -| test.c:360:3:360:4 | y4 | 0.0 | -| test.c:361:3:361:4 | y5 | 0.0 | -| test.c:362:3:362:4 | y6 | 0.0 | -| test.c:363:3:363:4 | y7 | 0.0 | -| test.c:364:3:364:4 | y8 | 0.0 | -| test.c:365:7:365:7 | x | 0.0 | -| test.c:366:5:366:6 | y3 | 0.0 | -| test.c:366:10:366:10 | x | 0.0 | -| test.c:367:5:367:6 | y4 | 0.0 | -| test.c:367:10:367:10 | x | 0.0 | -| test.c:368:5:368:6 | y5 | 0.0 | -| test.c:368:11:368:11 | x | 0.0 | -| test.c:369:5:369:6 | y6 | 0.0 | -| test.c:369:27:369:27 | x | 0.0 | -| test.c:370:5:370:6 | y7 | 0.0 | -| test.c:370:27:370:27 | x | 0.0 | -| test.c:371:5:371:6 | y8 | 0.0 | -| test.c:371:28:371:28 | x | 0.0 | -| test.c:373:10:373:11 | y1 | 0.0 | -| test.c:373:15:373:16 | y2 | 0.0 | -| test.c:373:20:373:21 | y3 | 0.0 | -| test.c:373:25:373:26 | y4 | 0.0 | -| test.c:373:30:373:31 | y5 | 0.0 | -| test.c:373:35:373:36 | y6 | 0.0 | -| test.c:373:40:373:41 | y7 | 0.0 | -| test.c:373:45:373:46 | y8 | 0.0 | -| test.c:379:3:379:4 | y1 | 0.0 | -| test.c:379:8:379:8 | x | 0.0 | -| test.c:379:18:379:18 | x | 101.0 | -| test.c:380:3:380:4 | y2 | 0.0 | -| test.c:380:8:380:8 | x | 0.0 | -| test.c:380:25:380:25 | x | 101.0 | -| test.c:381:3:381:4 | y3 | 0.0 | -| test.c:382:3:382:4 | y4 | 0.0 | -| test.c:383:3:383:4 | y5 | 0.0 | -| test.c:384:7:384:7 | x | 0.0 | -| test.c:385:5:385:6 | y3 | 0.0 | -| test.c:385:11:385:11 | x | 300.0 | -| test.c:386:5:386:6 | y4 | 0.0 | -| test.c:386:11:386:11 | x | 300.0 | -| test.c:387:5:387:6 | y5 | 0.0 | -| test.c:387:27:387:27 | x | 300.0 | -| test.c:389:10:389:11 | y1 | 101.0 | -| test.c:389:15:389:16 | y2 | 101.0 | -| test.c:389:20:389:21 | y3 | 0.0 | -| test.c:389:25:389:26 | y4 | 100.0 | -| test.c:389:30:389:31 | y5 | 0.0 | -| test.c:394:20:394:20 | x | 0.0 | -| test.c:394:30:394:30 | x | 0.0 | -| test.c:397:3:397:4 | y1 | 0.0 | -| test.c:397:11:397:11 | y | 0.0 | -| test.c:397:14:397:14 | y | 1.0 | -| test.c:398:3:398:4 | y2 | 0.0 | -| test.c:398:9:398:9 | y | 1.0 | -| test.c:398:14:398:14 | y | 2.0 | -| test.c:398:22:398:22 | y | 5.0 | -| test.c:399:10:399:11 | y1 | 1.0 | -| test.c:399:15:399:16 | y2 | 5.0 | -| test.c:407:3:407:3 | i | -2.147483648E9 | -| test.c:408:7:408:7 | i | 10.0 | -| test.c:410:3:410:3 | i | -2.147483648E9 | -| test.c:411:3:411:3 | i | 10.0 | -| test.c:412:7:412:7 | i | -2.147483648E9 | -| test.c:414:3:414:3 | i | -2.147483648E9 | -| test.c:415:3:415:3 | i | 40.0 | -| test.c:416:7:416:7 | i | -2.147483648E9 | -| test.c:418:3:418:3 | i | -2.147483648E9 | -| test.c:418:7:418:7 | j | -2.147483648E9 | -| test.c:419:7:419:7 | i | 40.0 | -| test.c:421:3:421:3 | i | -2.147483648E9 | -| test.c:421:8:421:8 | j | 40.0 | -| test.c:422:7:422:7 | i | 50.0 | -| test.c:424:3:424:3 | i | -2.147483648E9 | -| test.c:424:13:424:13 | j | -2.147483648E9 | -| test.c:425:7:425:7 | i | -2.147483648E9 | -| test.cpp:10:7:10:7 | b | -2.147483648E9 | -| test.cpp:11:5:11:5 | x | -2.147483648E9 | -| test.cpp:13:10:13:10 | x | -2.147483648E9 | -| test.cpp:18:30:18:30 | x | -2.147483648E9 | -| test.cpp:19:10:19:11 | x0 | -128.0 | -| test.cpp:27:7:27:7 | y | -2.147483648E9 | -| test.cpp:28:5:28:5 | x | -2.147483648E9 | -| test.cpp:30:7:30:7 | y | -2.147483648E9 | -| test.cpp:31:5:31:5 | x | -2.147483648E9 | -| test.cpp:33:7:33:7 | y | -2.147483648E9 | -| test.cpp:34:5:34:5 | x | -2.147483648E9 | -| test.cpp:36:7:36:7 | y | -2.147483648E9 | -| test.cpp:37:5:37:5 | x | -2.147483648E9 | -| test.cpp:39:7:39:7 | y | -2.147483648E9 | -| test.cpp:40:5:40:5 | x | -2.147483648E9 | -| test.cpp:42:7:42:7 | y | -2.147483648E9 | -| test.cpp:43:5:43:5 | x | -2.147483648E9 | -| test.cpp:45:7:45:7 | y | -2.147483648E9 | -| test.cpp:46:5:46:5 | x | -2.147483648E9 | -| test.cpp:51:7:51:7 | x | -2.147483648E9 | -| test.cpp:52:21:52:21 | x | 0.0 | -| test.cpp:53:5:53:5 | t | 0.0 | -| test.cpp:53:15:53:16 | xb | 0.0 | -| test.cpp:56:7:56:7 | x | -2.147483648E9 | -| test.cpp:57:21:57:21 | x | 1.0 | -| test.cpp:58:5:58:5 | t | 0.0 | -| test.cpp:58:15:58:16 | xb | 1.0 | -| test.cpp:61:7:61:7 | x | -2.147483648E9 | -| test.cpp:62:21:62:21 | x | -2.147483648E9 | -| test.cpp:63:5:63:5 | t | 0.0 | -| test.cpp:63:15:63:16 | xb | 1.0 | -| test.cpp:66:19:66:19 | x | -2.147483648E9 | -| test.cpp:67:3:67:3 | t | 0.0 | -| test.cpp:67:13:67:14 | xb | 0.0 | -| test.cpp:69:10:69:10 | b | 0.0 | -| test.cpp:69:21:69:21 | t | 0.0 | -| test.cpp:74:30:74:30 | c | 0.0 | -| test.cpp:74:34:74:34 | c | 0.0 | -| test.cpp:75:22:75:30 | c_times_2 | 0.0 | -| test.cpp:77:5:77:13 | c_times_2 | 0.0 | -| test.cpp:79:3:79:11 | c_times_2 | 0.0 | +| inline_assembly.c:10:3:10:3 | y | 0 | +| inline_assembly.c:12:29:12:29 | x | 0 | +| inline_assembly.c:12:32:12:32 | y | 1 | +| inline_assembly.c:16:25:16:25 | x | 0 | +| inline_assembly.c:16:35:16:35 | y | 1 | +| inline_assembly.c:21:29:21:29 | x | 0 | +| inline_assembly.c:21:32:21:32 | y | 0 | +| minmax.c:18:37:18:37 | x | 1 | +| minmax.c:18:40:18:40 | y | 2 | +| minmax.c:18:43:18:43 | z | 3 | +| minmax.c:20:2:20:2 | z | -2147483648 | +| minmax.c:22:8:22:8 | x | 1 | +| minmax.c:22:14:22:14 | y | 2 | +| minmax.c:22:18:22:18 | t | -2147483648 | +| minmax.c:22:22:22:22 | x | 1 | +| minmax.c:23:3:23:3 | t | 0 | +| minmax.c:26:37:26:37 | x | 1 | +| minmax.c:26:40:26:40 | y | 2 | +| minmax.c:26:43:26:43 | z | 0 | +| test.c:8:5:8:9 | count | -2147483648 | +| test.c:8:13:8:17 | count | -2147483648 | +| test.c:10:10:10:14 | count | -2147483648 | +| test.c:16:5:16:9 | count | -2147483648 | +| test.c:16:14:16:18 | count | 0 | +| test.c:18:10:18:14 | count | 0 | +| test.c:24:5:24:9 | count | 0 | +| test.c:25:5:25:9 | count | -2147483648 | +| test.c:25:13:25:17 | count | 1 | +| test.c:27:10:27:14 | count | 0 | +| test.c:33:8:33:8 | i | -2147483648 | +| test.c:33:15:33:15 | i | 0 | +| test.c:33:22:33:22 | i | -2147483648 | +| test.c:33:26:33:26 | i | 0 | +| test.c:34:5:34:9 | total | -2147483648 | +| test.c:34:14:34:14 | i | 0 | +| test.c:36:10:36:14 | total | -2147483648 | +| test.c:36:18:36:18 | i | 2 | +| test.c:42:8:42:8 | i | -2147483648 | +| test.c:42:15:42:15 | i | 0 | +| test.c:42:22:42:22 | i | 0 | +| test.c:43:5:43:9 | total | -2147483648 | +| test.c:43:14:43:14 | i | 0 | +| test.c:45:10:45:14 | total | -2147483648 | +| test.c:45:18:45:18 | i | 2 | +| test.c:51:8:51:8 | i | -2147483648 | +| test.c:51:15:51:15 | i | 0 | +| test.c:51:24:51:24 | i | -2147483648 | +| test.c:51:28:51:28 | i | 0 | +| test.c:52:5:52:9 | total | -2147483648 | +| test.c:52:14:52:14 | i | 0 | +| test.c:54:10:54:14 | total | -2147483648 | +| test.c:54:18:54:18 | i | 2 | +| test.c:58:7:58:7 | i | -2147483648 | +| test.c:59:9:59:9 | i | -2147483648 | +| test.c:60:14:60:14 | i | -2147483648 | +| test.c:67:15:67:15 | y | -2147483648 | +| test.c:67:20:67:20 | y | -999 | +| test.c:68:9:68:9 | x | -2147483648 | +| test.c:68:13:68:13 | y | -999 | +| test.c:69:14:69:14 | x | -2147483648 | +| test.c:72:10:72:10 | y | -2147483648 | +| test.c:76:7:76:7 | y | -2147483648 | +| test.c:77:9:77:9 | x | -2147483648 | +| test.c:81:9:81:9 | x | -2147483648 | +| test.c:85:10:85:10 | x | 4 | +| test.c:89:7:89:7 | y | -2147483648 | +| test.c:90:9:90:9 | x | -2147483648 | +| test.c:90:13:90:13 | y | 8 | +| test.c:93:12:93:12 | x | 8 | +| test.c:100:3:100:3 | c | -128 | +| test.c:101:7:101:7 | c | -128 | +| test.c:104:7:104:7 | c | -128 | +| test.c:105:5:105:5 | c | -128 | +| test.c:106:9:106:9 | c | -128 | +| test.c:109:9:109:9 | c | -128 | +| test.c:119:10:119:10 | n | 0 | +| test.c:124:11:124:15 | Start | 0 | +| test.c:127:6:127:10 | Start | 0 | +| test.c:127:15:127:20 | Length | 0 | +| test.c:135:22:135:22 | c | -128 | +| test.c:137:20:137:20 | x | 0 | +| test.c:138:11:138:11 | i | -2147483648 | +| test.c:139:19:139:19 | c | -128 | +| test.c:139:23:139:23 | i | -2147483648 | +| test.c:139:27:139:28 | uc | 0 | +| test.c:139:32:139:32 | x | 0 | +| test.c:139:36:139:36 | y | 0 | +| test.c:139:40:139:40 | z | -2147483648 | +| test.c:144:23:144:23 | x | -2147483648 | +| test.c:145:32:145:32 | x | -2147483648 | +| test.c:146:33:146:33 | x | -2147483648 | +| test.c:147:31:147:31 | x | -2147483648 | +| test.c:148:13:148:13 | x | -2147483648 | +| test.c:149:23:149:23 | x | -2147483648 | +| test.c:150:10:150:11 | x0 | -128 | +| test.c:150:15:150:16 | x1 | 0 | +| test.c:150:20:150:21 | x2 | 0 | +| test.c:150:25:150:26 | x3 | -2147483648 | +| test.c:150:30:150:31 | c0 | -128 | +| test.c:150:35:150:36 | s0 | 0 | +| test.c:154:11:154:11 | x | -9223372036854775808 | +| test.c:154:20:154:20 | x | 1 | +| test.c:154:30:154:30 | x | 1 | +| test.c:154:35:154:35 | x | 1 | +| test.c:161:12:161:12 | a | -2147483648 | +| test.c:161:17:161:17 | a | 3 | +| test.c:162:14:162:14 | a | 3 | +| test.c:163:14:163:14 | a | 3 | +| test.c:164:5:164:9 | total | 0 | +| test.c:164:14:164:14 | b | 3 | +| test.c:164:16:164:16 | c | -11 | +| test.c:166:12:166:12 | a | -2147483648 | +| test.c:166:17:166:17 | a | 0 | +| test.c:167:14:167:14 | a | 0 | +| test.c:168:14:168:14 | a | 0 | +| test.c:169:5:169:9 | total | -8 | +| test.c:169:14:169:14 | b | 0 | +| test.c:169:16:169:16 | c | -11 | +| test.c:171:13:171:13 | a | -2147483648 | +| test.c:171:18:171:18 | a | -7 | +| test.c:172:14:172:14 | a | -7 | +| test.c:173:14:173:14 | a | -7 | +| test.c:174:5:174:9 | total | -19 | +| test.c:174:14:174:14 | b | -7 | +| test.c:174:16:174:16 | c | -11 | +| test.c:176:13:176:13 | a | -2147483648 | +| test.c:176:18:176:18 | a | -7 | +| test.c:177:14:177:14 | a | -7 | +| test.c:178:14:178:14 | a | -7 | +| test.c:179:5:179:9 | total | -37 | +| test.c:179:14:179:14 | b | -7 | +| test.c:179:16:179:16 | c | -1 | +| test.c:181:13:181:13 | a | -2147483648 | +| test.c:181:18:181:18 | a | -7 | +| test.c:182:14:182:14 | a | -7 | +| test.c:183:14:183:14 | a | -7 | +| test.c:184:5:184:9 | total | -45 | +| test.c:184:14:184:14 | b | -7 | +| test.c:184:16:184:16 | c | 0 | +| test.c:186:13:186:13 | a | -2147483648 | +| test.c:186:18:186:18 | a | -7 | +| test.c:187:14:187:14 | a | -7 | +| test.c:188:14:188:14 | a | -7 | +| test.c:189:5:189:9 | total | -52 | +| test.c:189:14:189:14 | b | -7 | +| test.c:189:16:189:16 | c | 2 | +| test.c:192:10:192:14 | total | -57 | +| test.c:200:12:200:12 | a | -2147483648 | +| test.c:200:17:200:17 | a | 3 | +| test.c:200:33:200:33 | b | -2147483648 | +| test.c:200:38:200:38 | b | 5 | +| test.c:201:13:201:13 | a | 3 | +| test.c:201:15:201:15 | b | 5 | +| test.c:202:5:202:9 | total | 0 | +| test.c:202:14:202:14 | r | -2147483648 | +| test.c:204:12:204:12 | a | -2147483648 | +| test.c:204:17:204:17 | a | 3 | +| test.c:204:33:204:33 | b | -2147483648 | +| test.c:204:38:204:38 | b | 0 | +| test.c:205:13:205:13 | a | 3 | +| test.c:205:15:205:15 | b | 0 | +| test.c:206:5:206:9 | total | -2147483648 | +| test.c:206:14:206:14 | r | -2147483648 | +| test.c:208:12:208:12 | a | -2147483648 | +| test.c:208:17:208:17 | a | 3 | +| test.c:208:35:208:35 | b | -2147483648 | +| test.c:208:40:208:40 | b | -13 | +| test.c:209:13:209:13 | a | 3 | +| test.c:209:15:209:15 | b | -13 | +| test.c:210:5:210:9 | total | -2147483648 | +| test.c:210:14:210:14 | r | -2147483648 | +| test.c:212:12:212:12 | a | -2147483648 | +| test.c:212:17:212:17 | a | 3 | +| test.c:212:35:212:35 | b | -2147483648 | +| test.c:212:40:212:40 | b | -13 | +| test.c:213:13:213:13 | a | 3 | +| test.c:213:15:213:15 | b | -13 | +| test.c:214:5:214:9 | total | -2147483648 | +| test.c:214:14:214:14 | r | -2147483648 | +| test.c:216:12:216:12 | a | -2147483648 | +| test.c:216:17:216:17 | a | 3 | +| test.c:216:35:216:35 | b | -2147483648 | +| test.c:216:40:216:40 | b | -13 | +| test.c:217:13:217:13 | a | 3 | +| test.c:217:15:217:15 | b | -13 | +| test.c:218:5:218:9 | total | -2147483648 | +| test.c:218:14:218:14 | r | -2147483648 | +| test.c:221:10:221:14 | total | -2147483648 | +| test.c:228:12:228:12 | a | -2147483648 | +| test.c:228:17:228:17 | a | 0 | +| test.c:228:33:228:33 | b | -2147483648 | +| test.c:228:38:228:38 | b | 5 | +| test.c:229:13:229:13 | a | 0 | +| test.c:229:15:229:15 | b | 5 | +| test.c:230:5:230:9 | total | 0 | +| test.c:230:14:230:14 | r | -2147483648 | +| test.c:232:12:232:12 | a | -2147483648 | +| test.c:232:17:232:17 | a | 0 | +| test.c:232:33:232:33 | b | -2147483648 | +| test.c:232:38:232:38 | b | 0 | +| test.c:233:13:233:13 | a | 0 | +| test.c:233:15:233:15 | b | 0 | +| test.c:234:5:234:9 | total | -2147483648 | +| test.c:234:14:234:14 | r | -2147483648 | +| test.c:236:12:236:12 | a | -2147483648 | +| test.c:236:17:236:17 | a | 0 | +| test.c:236:35:236:35 | b | -2147483648 | +| test.c:236:40:236:40 | b | -13 | +| test.c:237:13:237:13 | a | 0 | +| test.c:237:15:237:15 | b | -13 | +| test.c:238:5:238:9 | total | -2147483648 | +| test.c:238:14:238:14 | r | -2147483648 | +| test.c:240:12:240:12 | a | -2147483648 | +| test.c:240:17:240:17 | a | 0 | +| test.c:240:35:240:35 | b | -2147483648 | +| test.c:240:40:240:40 | b | -13 | +| test.c:241:13:241:13 | a | 0 | +| test.c:241:15:241:15 | b | -13 | +| test.c:242:5:242:9 | total | -2147483648 | +| test.c:242:14:242:14 | r | -2147483648 | +| test.c:244:12:244:12 | a | -2147483648 | +| test.c:244:17:244:17 | a | 0 | +| test.c:244:35:244:35 | b | -2147483648 | +| test.c:244:40:244:40 | b | -13 | +| test.c:245:13:245:13 | a | 0 | +| test.c:245:15:245:15 | b | -13 | +| test.c:246:5:246:9 | total | -2147483648 | +| test.c:246:14:246:14 | r | -2147483648 | +| test.c:249:10:249:14 | total | -2147483648 | +| test.c:256:14:256:14 | a | -2147483648 | +| test.c:256:19:256:19 | a | -17 | +| test.c:256:35:256:35 | b | -2147483648 | +| test.c:256:40:256:40 | b | 5 | +| test.c:257:13:257:13 | a | -17 | +| test.c:257:15:257:15 | b | 5 | +| test.c:258:5:258:9 | total | 0 | +| test.c:258:14:258:14 | r | -2147483648 | +| test.c:260:14:260:14 | a | -2147483648 | +| test.c:260:19:260:19 | a | -17 | +| test.c:260:35:260:35 | b | -2147483648 | +| test.c:260:40:260:40 | b | 0 | +| test.c:261:13:261:13 | a | -17 | +| test.c:261:15:261:15 | b | 0 | +| test.c:262:5:262:9 | total | -2147483648 | +| test.c:262:14:262:14 | r | -2147483648 | +| test.c:264:14:264:14 | a | -2147483648 | +| test.c:264:19:264:19 | a | -17 | +| test.c:264:37:264:37 | b | -2147483648 | +| test.c:264:42:264:42 | b | -13 | +| test.c:265:13:265:13 | a | -17 | +| test.c:265:15:265:15 | b | -13 | +| test.c:266:5:266:9 | total | -2147483648 | +| test.c:266:14:266:14 | r | -2147483648 | +| test.c:268:14:268:14 | a | -2147483648 | +| test.c:268:19:268:19 | a | -17 | +| test.c:268:37:268:37 | b | -2147483648 | +| test.c:268:42:268:42 | b | -13 | +| test.c:269:13:269:13 | a | -17 | +| test.c:269:15:269:15 | b | -13 | +| test.c:270:5:270:9 | total | -2147483648 | +| test.c:270:14:270:14 | r | -2147483648 | +| test.c:272:14:272:14 | a | -2147483648 | +| test.c:272:19:272:19 | a | -17 | +| test.c:272:37:272:37 | b | -2147483648 | +| test.c:272:42:272:42 | b | -13 | +| test.c:273:13:273:13 | a | -17 | +| test.c:273:15:273:15 | b | -13 | +| test.c:274:5:274:9 | total | -2147483648 | +| test.c:274:14:274:14 | r | -2147483648 | +| test.c:277:10:277:14 | total | -2147483648 | +| test.c:284:14:284:14 | a | -2147483648 | +| test.c:284:19:284:19 | a | -17 | +| test.c:284:34:284:34 | b | -2147483648 | +| test.c:284:39:284:39 | b | 5 | +| test.c:285:13:285:13 | a | -17 | +| test.c:285:15:285:15 | b | 5 | +| test.c:286:5:286:9 | total | 0 | +| test.c:286:14:286:14 | r | -2147483648 | +| test.c:288:14:288:14 | a | -2147483648 | +| test.c:288:19:288:19 | a | -17 | +| test.c:288:34:288:34 | b | -2147483648 | +| test.c:288:39:288:39 | b | 0 | +| test.c:289:13:289:13 | a | -17 | +| test.c:289:15:289:15 | b | 0 | +| test.c:290:5:290:9 | total | -2147483648 | +| test.c:290:14:290:14 | r | -2147483648 | +| test.c:292:14:292:14 | a | -2147483648 | +| test.c:292:19:292:19 | a | -17 | +| test.c:292:36:292:36 | b | -2147483648 | +| test.c:292:41:292:41 | b | -13 | +| test.c:293:13:293:13 | a | -17 | +| test.c:293:15:293:15 | b | -13 | +| test.c:294:5:294:9 | total | -2147483648 | +| test.c:294:14:294:14 | r | -2147483648 | +| test.c:296:14:296:14 | a | -2147483648 | +| test.c:296:19:296:19 | a | -17 | +| test.c:296:36:296:36 | b | -2147483648 | +| test.c:296:41:296:41 | b | -13 | +| test.c:297:13:297:13 | a | -17 | +| test.c:297:15:297:15 | b | -13 | +| test.c:298:5:298:9 | total | -2147483648 | +| test.c:298:14:298:14 | r | -2147483648 | +| test.c:300:14:300:14 | a | -2147483648 | +| test.c:300:19:300:19 | a | -17 | +| test.c:300:36:300:36 | b | -2147483648 | +| test.c:300:41:300:41 | b | -13 | +| test.c:301:13:301:13 | a | -17 | +| test.c:301:15:301:15 | b | -13 | +| test.c:302:5:302:9 | total | -2147483648 | +| test.c:302:14:302:14 | r | -2147483648 | +| test.c:305:10:305:14 | total | -2147483648 | +| test.c:312:14:312:14 | a | -2147483648 | +| test.c:312:19:312:19 | a | -17 | +| test.c:312:35:312:35 | b | -2147483648 | +| test.c:312:40:312:40 | b | 5 | +| test.c:313:13:313:13 | a | -17 | +| test.c:313:15:313:15 | b | 5 | +| test.c:314:5:314:9 | total | 0 | +| test.c:314:14:314:14 | r | -2147483648 | +| test.c:316:14:316:14 | a | -2147483648 | +| test.c:316:19:316:19 | a | -17 | +| test.c:316:35:316:35 | b | -2147483648 | +| test.c:316:40:316:40 | b | 0 | +| test.c:317:13:317:13 | a | -17 | +| test.c:317:15:317:15 | b | 0 | +| test.c:318:5:318:9 | total | -2147483648 | +| test.c:318:14:318:14 | r | -2147483648 | +| test.c:320:14:320:14 | a | -2147483648 | +| test.c:320:19:320:19 | a | -17 | +| test.c:320:37:320:37 | b | -2147483648 | +| test.c:320:42:320:42 | b | -13 | +| test.c:321:13:321:13 | a | -17 | +| test.c:321:15:321:15 | b | -13 | +| test.c:322:5:322:9 | total | -2147483648 | +| test.c:322:14:322:14 | r | -2147483648 | +| test.c:324:14:324:14 | a | -2147483648 | +| test.c:324:19:324:19 | a | -17 | +| test.c:324:37:324:37 | b | -2147483648 | +| test.c:324:42:324:42 | b | -13 | +| test.c:325:13:325:13 | a | -17 | +| test.c:325:15:325:15 | b | -13 | +| test.c:326:5:326:9 | total | -2147483648 | +| test.c:326:14:326:14 | r | -2147483648 | +| test.c:328:14:328:14 | a | -2147483648 | +| test.c:328:19:328:19 | a | -17 | +| test.c:328:37:328:37 | b | -2147483648 | +| test.c:328:42:328:42 | b | -13 | +| test.c:329:13:329:13 | a | -17 | +| test.c:329:15:329:15 | b | -13 | +| test.c:330:5:330:9 | total | -2147483648 | +| test.c:330:14:330:14 | r | -2147483648 | +| test.c:333:10:333:14 | total | -2147483648 | +| test.c:338:7:338:7 | x | -2147483648 | +| test.c:342:10:342:10 | i | 0 | +| test.c:343:5:343:5 | i | 0 | +| test.c:345:3:345:3 | d | -2147483648 | +| test.c:345:7:345:7 | i | 3 | +| test.c:346:7:346:7 | x | 0 | +| test.c:347:9:347:9 | d | 3 | +| test.c:347:14:347:14 | x | 0 | +| test.c:357:3:357:4 | y1 | 0 | +| test.c:357:8:357:8 | x | 0 | +| test.c:357:18:357:18 | x | 0 | +| test.c:358:3:358:4 | y2 | 0 | +| test.c:358:8:358:8 | x | 0 | +| test.c:358:24:358:24 | x | 0 | +| test.c:359:3:359:4 | y3 | 0 | +| test.c:360:3:360:4 | y4 | 0 | +| test.c:361:3:361:4 | y5 | 0 | +| test.c:362:3:362:4 | y6 | 0 | +| test.c:363:3:363:4 | y7 | 0 | +| test.c:364:3:364:4 | y8 | 0 | +| test.c:365:7:365:7 | x | 0 | +| test.c:366:5:366:6 | y3 | 0 | +| test.c:366:10:366:10 | x | 0 | +| test.c:367:5:367:6 | y4 | 0 | +| test.c:367:10:367:10 | x | 0 | +| test.c:368:5:368:6 | y5 | 0 | +| test.c:368:11:368:11 | x | 0 | +| test.c:369:5:369:6 | y6 | 0 | +| test.c:369:27:369:27 | x | 0 | +| test.c:370:5:370:6 | y7 | 0 | +| test.c:370:27:370:27 | x | 0 | +| test.c:371:5:371:6 | y8 | 0 | +| test.c:371:28:371:28 | x | 0 | +| test.c:373:10:373:11 | y1 | 0 | +| test.c:373:15:373:16 | y2 | 0 | +| test.c:373:20:373:21 | y3 | 0 | +| test.c:373:25:373:26 | y4 | 0 | +| test.c:373:30:373:31 | y5 | 0 | +| test.c:373:35:373:36 | y6 | 0 | +| test.c:373:40:373:41 | y7 | 0 | +| test.c:373:45:373:46 | y8 | 0 | +| test.c:379:3:379:4 | y1 | 0 | +| test.c:379:8:379:8 | x | 0 | +| test.c:379:18:379:18 | x | 101 | +| test.c:380:3:380:4 | y2 | 0 | +| test.c:380:8:380:8 | x | 0 | +| test.c:380:25:380:25 | x | 101 | +| test.c:381:3:381:4 | y3 | 0 | +| test.c:382:3:382:4 | y4 | 0 | +| test.c:383:3:383:4 | y5 | 0 | +| test.c:384:7:384:7 | x | 0 | +| test.c:385:5:385:6 | y3 | 0 | +| test.c:385:11:385:11 | x | 300 | +| test.c:386:5:386:6 | y4 | 0 | +| test.c:386:11:386:11 | x | 300 | +| test.c:387:5:387:6 | y5 | 0 | +| test.c:387:27:387:27 | x | 300 | +| test.c:389:10:389:11 | y1 | 101 | +| test.c:389:15:389:16 | y2 | 101 | +| test.c:389:20:389:21 | y3 | 0 | +| test.c:389:25:389:26 | y4 | 100 | +| test.c:389:30:389:31 | y5 | 0 | +| test.c:394:20:394:20 | x | 0 | +| test.c:394:30:394:30 | x | 0 | +| test.c:397:3:397:4 | y1 | 0 | +| test.c:397:11:397:11 | y | 0 | +| test.c:397:14:397:14 | y | 1 | +| test.c:398:3:398:4 | y2 | 0 | +| test.c:398:9:398:9 | y | 1 | +| test.c:398:14:398:14 | y | 2 | +| test.c:398:22:398:22 | y | 5 | +| test.c:399:10:399:11 | y1 | 1 | +| test.c:399:15:399:16 | y2 | 5 | +| test.c:407:3:407:3 | i | -2147483648 | +| test.c:408:7:408:7 | i | 10 | +| test.c:410:3:410:3 | i | -2147483648 | +| test.c:411:3:411:3 | i | 10 | +| test.c:412:7:412:7 | i | 20 | +| test.c:414:3:414:3 | i | -2147483648 | +| test.c:415:3:415:3 | i | 40 | +| test.c:416:7:416:7 | i | 30 | +| test.c:418:3:418:3 | i | -2147483648 | +| test.c:418:7:418:7 | j | -2147483648 | +| test.c:419:7:419:7 | i | 40 | +| test.c:421:3:421:3 | i | -2147483648 | +| test.c:421:8:421:8 | j | 40 | +| test.c:422:7:422:7 | i | 50 | +| test.c:424:3:424:3 | i | -2147483648 | +| test.c:424:13:424:13 | j | 50 | +| test.c:425:7:425:7 | i | 60 | +| test.c:432:12:432:12 | a | 0 | +| test.c:432:17:432:17 | a | 3 | +| test.c:432:33:432:33 | b | 0 | +| test.c:432:38:432:38 | b | 5 | +| test.c:433:13:433:13 | a | 3 | +| test.c:433:15:433:15 | b | 5 | +| test.c:434:5:434:9 | total | 0 | +| test.c:434:14:434:14 | r | 15 | +| test.c:436:12:436:12 | a | 0 | +| test.c:436:17:436:17 | a | 3 | +| test.c:436:33:436:33 | b | 0 | +| test.c:436:38:436:38 | b | 0 | +| test.c:437:13:437:13 | a | 3 | +| test.c:437:15:437:15 | b | 0 | +| test.c:438:5:438:9 | total | 0 | +| test.c:438:14:438:14 | r | 0 | +| test.c:440:12:440:12 | a | 0 | +| test.c:440:17:440:17 | a | 3 | +| test.c:440:34:440:34 | b | 0 | +| test.c:440:39:440:39 | b | 13 | +| test.c:441:13:441:13 | a | 3 | +| test.c:441:15:441:15 | b | 13 | +| test.c:442:5:442:9 | total | 0 | +| test.c:442:14:442:14 | r | 39 | +| test.c:445:10:445:14 | total | 0 | +| test.c:451:12:451:12 | b | 0 | +| test.c:451:17:451:17 | b | 5 | +| test.c:452:16:452:16 | b | 5 | +| test.c:453:5:453:9 | total | 0 | +| test.c:453:14:453:14 | r | 55 | +| test.c:455:12:455:12 | b | 0 | +| test.c:455:17:455:17 | b | 0 | +| test.c:456:16:456:16 | b | 0 | +| test.c:457:5:457:9 | total | 0 | +| test.c:457:14:457:14 | r | 0 | +| test.c:459:13:459:13 | b | 0 | +| test.c:459:18:459:18 | b | 13 | +| test.c:460:16:460:16 | b | 13 | +| test.c:461:5:461:9 | total | 0 | +| test.c:461:14:461:14 | r | 143 | +| test.c:464:10:464:14 | total | 0 | +| test.c:469:3:469:3 | x | 0 | +| test.c:469:7:469:7 | y | 0 | +| test.c:470:3:470:4 | xy | 0 | +| test.c:470:8:470:8 | x | 1000000003 | +| test.c:470:12:470:12 | y | 1000000003 | +| test.c:471:10:471:11 | xy | 1000000006000000000 | +| test.c:476:3:476:3 | x | 0 | +| test.c:477:3:477:3 | y | 0 | +| test.c:478:3:478:4 | xy | 0 | +| test.c:478:8:478:8 | x | 274177 | +| test.c:478:12:478:12 | y | 67280421310721 | +| test.c:479:10:479:11 | xy | 18446744073709551616 | +| test.c:483:7:483:8 | ui | 0 | +| test.c:484:43:484:44 | ui | 10 | +| test.c:484:48:484:49 | ui | 10 | +| test.c:485:12:485:17 | result | 100 | +| test.c:487:7:487:8 | ul | 0 | +| test.c:488:28:488:29 | ul | 10 | +| test.c:488:33:488:34 | ul | 10 | +| test.c:489:12:489:17 | result | 0 | +| test.c:495:7:495:8 | ui | 0 | +| test.c:495:19:495:20 | ui | 0 | +| test.c:496:5:496:6 | ui | 2 | +| test.c:496:11:496:12 | ui | 2 | +| test.c:497:12:497:13 | ui | 4 | +| test.c:501:3:501:9 | uiconst | 10 | +| test.c:504:3:504:9 | ulconst | 10 | +| test.c:505:10:505:16 | uiconst | 40 | +| test.c:505:20:505:26 | ulconst | 40 | +| test.c:509:7:509:7 | i | -2147483648 | +| test.c:509:18:509:18 | i | -1 | +| test.c:510:5:510:5 | i | -2147483648 | +| test.c:510:13:510:13 | i | -1 | +| test.c:511:9:511:9 | i | -5 | +| test.c:513:5:513:5 | i | -2147483648 | +| test.c:513:9:513:9 | i | -5 | +| test.c:514:9:514:9 | i | -30 | +| test.c:516:5:516:5 | i | -30 | +| test.c:517:9:517:9 | i | -210 | +| test.c:519:5:519:5 | i | -210 | +| test.c:520:9:520:9 | i | -1155 | +| test.c:522:7:522:7 | i | -2147483648 | +| test.c:523:5:523:5 | i | -2147483648 | +| test.c:523:9:523:9 | i | -1 | +| test.c:524:9:524:9 | i | 1 | +| test.c:526:3:526:3 | i | -2147483648 | +| test.c:526:7:526:7 | i | -2147483648 | +| test.c:527:10:527:10 | i | -2147483648 | +| test.c:530:3:530:3 | i | -2147483648 | +| test.c:530:10:530:11 | sc | 1 | +| test.c:532:7:532:7 | i | -128 | +| test.c:539:7:539:7 | n | 0 | +| test.c:541:7:541:7 | n | 0 | +| test.c:542:9:542:9 | n | 1 | +| test.c:545:7:545:7 | n | 0 | +| test.c:546:9:546:9 | n | 1 | +| test.c:548:9:548:9 | n | 0 | +| test.c:551:8:551:8 | n | 0 | +| test.c:552:9:552:9 | n | 0 | +| test.c:554:9:554:9 | n | 1 | +| test.c:557:10:557:10 | n | 0 | +| test.c:558:5:558:5 | n | 1 | +| test.c:561:7:561:7 | n | 0 | +| test.c:565:7:565:7 | n | -32768 | +| test.c:568:7:568:7 | n | 0 | +| test.c:569:9:569:9 | n | 0 | +| test.c:571:9:571:9 | n | 1 | +| test.c:574:7:574:7 | n | 0 | +| test.c:575:9:575:9 | n | 1 | +| test.c:577:9:577:9 | n | 0 | +| test.c:580:10:580:10 | n | 0 | +| test.c:581:5:581:5 | n | 1 | +| test.c:584:7:584:7 | n | 0 | +| test.c:588:7:588:7 | n | -32768 | +| test.c:589:9:589:9 | n | -32768 | +| test.c:590:11:590:11 | n | 0 | +| test.c:594:7:594:7 | n | -32768 | +| test.c:595:13:595:13 | n | 5 | +| test.c:598:9:598:9 | n | 6 | +| test.c:601:7:601:7 | n | -32768 | +| test.c:601:22:601:22 | n | -32767 | +| test.c:602:9:602:9 | n | -32766 | +| test.c:605:7:605:7 | n | -32768 | +| test.c:606:5:606:5 | n | 0 | +| test.c:606:10:606:10 | n | 1 | +| test.c:606:14:606:14 | n | 0 | +| test.c:607:6:607:6 | n | 0 | +| test.c:607:10:607:10 | n | 0 | +| test.c:607:14:607:14 | n | 1 | +| test.c:618:7:618:8 | ss | -32768 | +| test.c:619:9:619:10 | ss | 0 | +| test.c:622:7:622:8 | ss | -32768 | +| test.c:623:9:623:10 | ss | -32768 | +| test.c:626:14:626:15 | us | 0 | +| test.c:627:9:627:10 | us | 0 | +| test.c:630:14:630:15 | us | 0 | +| test.c:631:9:631:10 | us | 0 | +| test.c:634:7:634:8 | ss | -32768 | +| test.c:635:9:635:10 | ss | -32768 | +| test.c:638:7:638:8 | ss | -32768 | +| test.c:639:9:639:10 | ss | -1 | +| test.c:645:8:645:8 | s | -2147483648 | +| test.c:645:15:645:15 | s | 0 | +| test.c:645:23:645:23 | s | 0 | +| test.c:646:18:646:18 | s | 0 | +| test.c:646:22:646:22 | s | 0 | +| test.c:647:9:647:14 | result | 0 | +| test.c:653:7:653:7 | i | 0 | +| test.c:654:9:654:9 | i | -2147483648 | +| test.c:658:7:658:7 | u | 0 | +| test.c:659:9:659:9 | u | 0 | +| test.cpp:10:7:10:7 | b | -2147483648 | +| test.cpp:11:5:11:5 | x | -2147483648 | +| test.cpp:13:10:13:10 | x | -2147483648 | +| test.cpp:18:30:18:30 | x | -2147483648 | +| test.cpp:19:10:19:11 | x0 | -128 | +| test.cpp:27:7:27:7 | y | -2147483648 | +| test.cpp:28:5:28:5 | x | -2147483648 | +| test.cpp:30:7:30:7 | y | -2147483648 | +| test.cpp:31:5:31:5 | x | -2147483648 | +| test.cpp:33:7:33:7 | y | -2147483648 | +| test.cpp:34:5:34:5 | x | -2147483648 | +| test.cpp:36:7:36:7 | y | -2147483648 | +| test.cpp:37:5:37:5 | x | -2147483648 | +| test.cpp:39:7:39:7 | y | -2147483648 | +| test.cpp:40:5:40:5 | x | -2147483648 | +| test.cpp:42:7:42:7 | y | -2147483648 | +| test.cpp:43:5:43:5 | x | -2147483648 | +| test.cpp:45:7:45:7 | y | -2147483648 | +| test.cpp:46:5:46:5 | x | -2147483648 | +| test.cpp:51:7:51:7 | x | -2147483648 | +| test.cpp:52:21:52:21 | x | 0 | +| test.cpp:53:5:53:5 | t | 0 | +| test.cpp:53:15:53:16 | xb | 0 | +| test.cpp:56:7:56:7 | x | -2147483648 | +| test.cpp:57:21:57:21 | x | 1 | +| test.cpp:58:5:58:5 | t | 0 | +| test.cpp:58:15:58:16 | xb | 1 | +| test.cpp:61:7:61:7 | x | -2147483648 | +| test.cpp:62:21:62:21 | x | -2147483648 | +| test.cpp:63:5:63:5 | t | 0 | +| test.cpp:63:15:63:16 | xb | 1 | +| test.cpp:66:19:66:19 | x | -2147483648 | +| test.cpp:67:3:67:3 | t | 0 | +| test.cpp:67:13:67:14 | xb | 0 | +| test.cpp:69:10:69:10 | b | 0 | +| test.cpp:69:21:69:21 | t | 0 | +| test.cpp:74:30:74:30 | c | 0 | +| test.cpp:74:34:74:34 | c | 0 | +| test.cpp:75:22:75:30 | c_times_2 | 0 | +| test.cpp:77:5:77:13 | c_times_2 | 0 | +| test.cpp:79:3:79:11 | c_times_2 | 0 | +| test.cpp:83:16:83:22 | aliased | -2147483648 | +| test.cpp:85:7:85:7 | i | -2147483648 | +| test.cpp:86:12:86:12 | i | 2 | +| test.cpp:88:7:88:8 | ci | -2147483648 | +| test.cpp:89:12:89:13 | ci | 2 | +| test.cpp:91:7:91:13 | aliased | -2147483648 | +| test.cpp:92:12:92:18 | aliased | -2147483648 | +| test.cpp:94:7:94:11 | alias | -2147483648 | +| test.cpp:95:12:95:16 | alias | -2147483648 | +| test.cpp:97:10:97:10 | i | -2147483648 | +| test.cpp:97:22:97:22 | i | -2147483648 | +| test.cpp:98:5:98:5 | i | -2147483648 | +| test.cpp:105:7:105:7 | n | -32768 | +| test.cpp:108:7:108:7 | n | 0 | +| test.cpp:109:5:109:5 | n | 1 | +| test.cpp:111:5:111:5 | n | 0 | +| test.cpp:114:8:114:8 | n | 0 | +| test.cpp:115:5:115:5 | n | 0 | +| test.cpp:117:5:117:5 | n | 1 | +| test.cpp:120:3:120:3 | n | 0 | +| test.cpp:120:8:120:8 | n | 1 | +| test.cpp:120:12:120:12 | n | 0 | +| test.cpp:121:4:121:4 | n | 0 | +| test.cpp:121:8:121:8 | n | 0 | +| test.cpp:121:12:121:12 | n | 1 | diff --git a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/lowerBound.ql b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/lowerBound.ql index 67da63679723..70c2d8590e9e 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/lowerBound.ql +++ b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/lowerBound.ql @@ -1,4 +1,4 @@ import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis from VariableAccess expr -select expr, lowerBound(expr) +select expr, lowerBound(expr).toString() diff --git a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/ternaryLower.expected b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/ternaryLower.expected index 7f0469925834..fedd3853ce2f 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/ternaryLower.expected +++ b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/ternaryLower.expected @@ -13,3 +13,7 @@ | test.c:386:10:386:21 | ... ? ... : ... | 100.0 | 100.0 | 5.0 | | test.c:387:10:387:38 | ... ? ... : ... | 0.0 | 100.0 | 5.0 | | test.c:394:20:394:36 | ... ? ... : ... | 0.0 | 0.0 | 100.0 | +| test.c:606:5:606:14 | ... ? ... : ... | 0.0 | 1.0 | 0.0 | +| test.c:607:5:607:14 | ... ? ... : ... | 0.0 | 0.0 | 1.0 | +| test.cpp:120:3:120:12 | ... ? ... : ... | 0.0 | 1.0 | 0.0 | +| test.cpp:121:3:121:12 | ... ? ... : ... | 0.0 | 0.0 | 1.0 | diff --git a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/ternaryUpper.expected b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/ternaryUpper.expected index e2c21e309ae5..0b8fe8c11648 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/ternaryUpper.expected +++ b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/ternaryUpper.expected @@ -13,3 +13,7 @@ | test.c:386:10:386:21 | ... ? ... : ... | 4.294967295E9 | 4.294967295E9 | 5.0 | | test.c:387:10:387:38 | ... ? ... : ... | 255.0 | 4.294967295E9 | 5.0 | | test.c:394:20:394:36 | ... ? ... : ... | 100.0 | 99.0 | 100.0 | +| test.c:606:5:606:14 | ... ? ... : ... | 32767.0 | 32767.0 | 0.0 | +| test.c:607:5:607:14 | ... ? ... : ... | 32767.0 | 0.0 | 32767.0 | +| test.cpp:120:3:120:12 | ... ? ... : ... | 32767.0 | 32767.0 | 0.0 | +| test.cpp:121:3:121:12 | ... ? ... : ... | 32767.0 | 0.0 | 32767.0 | diff --git a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/test.c b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/test.c index 692520051f89..28c9f94d959f 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/test.c +++ b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/test.c @@ -422,5 +422,240 @@ void test17() { out(i); // 50 i = 20 + (j -= 10); - out(i); // 60 [BUG: the analysis thinks it's 2^-31 .. 2^31-1] + out(i); // 60 +} + +// Tests for unsigned multiplication. +int test_unsigned_mult01(unsigned int a, unsigned b) { + int total = 0; + + if (3 <= a && a <= 11 && 5 <= b && b <= 23) { + int r = a*b; // 15 .. 253 + total += r; + } + if (3 <= a && a <= 11 && 0 <= b && b <= 23) { + int r = a*b; // 0 .. 253 + total += r; + } + if (3 <= a && a <= 11 && 13 <= b && b <= 23) { + int r = a*b; // 39 .. 253 + total += r; + } + + return total; +} + +int test_unsigned_mult02(unsigned b) { + int total = 0; + + if (5 <= b && b <= 23) { + int r = 11*b; // 55 .. 253 + total += r; + } + if (0 <= b && b <= 23) { + int r = 11*b; // 0 .. 253 + total += r; + } + if (13 <= b && b <= 23) { + int r = 11*b; // 143 .. 253 + total += r; + } + + return total; +} + +unsigned long mult_rounding() { + unsigned long x, y, xy; + x = y = 1000000003UL; // 1e9 + 3 + xy = x * y; + return xy; // BUG: upper bound should be >= 1000000006000000009UL +} + +unsigned long mult_overflow() { + unsigned long x, y, xy; + x = 274177UL; + y = 67280421310721UL; + xy = x * y; + return xy; // BUG: upper bound should be >= 18446744073709551617UL +} + +unsigned long mult_lower_bound(unsigned int ui, unsigned long ul) { + if (ui >= 10) { + unsigned long result = (unsigned long)ui * ui; + return result; // BUG: upper bound should be >= 18446744065119617025 + } + if (ul >= 10) { + unsigned long result = ul * ul; + return result; // lower bound is correctly 0 (overflow is possible) + } + return 0; +} + +unsigned long mul_assign(unsigned int ui) { + if (ui <= 10 && ui >= 2) { + ui *= ui + 0; + return ui; // 4 .. 100 + } + + unsigned int uiconst = 10; + uiconst *= 4; + + unsigned long ulconst = 10; + ulconst *= 4; + return uiconst + ulconst; // 40 .. 40 for both +} + +int mul_by_constant(int i, int j) { + if (i >= -1 && i <= 2) { + i = 5 * i; + out(i); // -5 .. 10 + + i = i * -3; + out(i); // -30 .. 15 + + i *= 7; + out(i); // -210 .. 105 + + i *= -11; + out(i); // -1155 .. 2310 + } + if (i == -1) { + i = i * (int)0xffFFffFF; // fully converted literal is -1 + out(i); // 1 .. 1 + } + i = i * -1; + out( i); // -2^31 .. 2^31-1 + + signed char sc = 1; + i = (*&sc *= 2); + out(sc); // demonstrate that we couldn't analyze the LHS of the `*=` above... + out(i); // -128 .. 127 // ... but we can still bound its result by its type. + + return 0; +} + + +int notequal_type_endpoint(unsigned n) { + out(n); // 0 .. + + if (n > 0) { + out(n); // 1 .. + } + + if (n != 0) { + out(n); // 1 .. + } else { + out(n); // 0 .. 0 + } + + if (!n) { + out(n); // 0 .. 0 + } else { + out(n); // 1 .. + } + + while (n != 0) { + n--; // 1 .. + } + + out(n); // 0 .. 0 +} + +void notequal_refinement(short n) { + if (n < 0) + return; + + if (n == 0) { + out(n); // 0 .. 0 + } else { + out(n); // 1 .. + } + + if (n) { + out(n); // 1 .. + } else { + out(n); // 0 .. 0 + } + + while (n != 0) { + n--; // 1 .. + } + + out(n); // 0 .. 0 +} + +void notequal_variations(short n, float f) { + if (n != 0) { + if (n >= 0) { + out(n); // 1 .. [BUG: we can't handle `!=` coming first] + } + } + + if (n >= 5) { + if (2 * n - 10 == 0) { // Same as `n == 10/2` (modulo overflow) + return; + } + out(n); // 6 .. + } + + if (n != -32768 && n != -32767) { + out(n); // -32766 .. + } + + if (n >= 0) { + n ? n : n; // ? 1.. : 0..0 + !n ? n : n; // ? 0..0 : 1.. + } +} + +void two_bounds_from_one_test(short ss, unsigned short us) { + // These tests demonstrate how the range analysis is often able to deduce + // both an upper bound and a lower bound even when there is only one + // inequality in the source. For example `signedInt < 4U` establishes that + // `signedInt >= 0` since if `signedInt` were negative then it would be + // greater than 4 in the unsigned comparison. + + if (ss < sizeof(int)) { // Lower bound added in `linearBoundFromGuard` + out(ss); // 0 .. 3 + } + + if (ss < 0x8001) { // Lower bound removed in `getDefLowerBounds` + out(ss); // -32768 .. 32767 + } + + if ((short)us >= 0) { + out(us); // 0 .. 32767 + } + + if ((short)us >= -1) { + out(us); // 0 .. 65535 + } + + if (ss >= sizeof(int)) { // test is true for negative numbers + out(ss); // -32768 .. 32767 + } + + if (ss + 1 < sizeof(int)) { + out(ss); // -1 .. 2 + } +} + +void widen_recursive_expr() { + int s; + for (s = 0; s < 10; s++) { + int result = s + s; // 0 .. 9 [BUG: upper bound is 15 due to widening] + out(result); // 0 .. 18 [BUG: upper bound is 127 due to double widening] + } +} + +void guard_bound_out_of_range(void) { + int i = 0; + if (i < 0) { + out(i); // unreachable [BUG: is -max .. +max] + } + + unsigned int u = 0; + if (u < 0) { + out(u); // unreachable [BUG: is 0 .. +max] + } } diff --git a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/test.cpp b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/test.cpp index e37f12c61cbf..515633f4f737 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/test.cpp +++ b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/test.cpp @@ -78,3 +78,45 @@ void use_after_cast(unsigned char c) } c_times_2; } + +int ref_to_number(int &i, const int &ci, int &aliased) { + int &alias = aliased; // no range analysis for either of the two aliased variables + + if (i >= 2) + return i; + + if (ci >= 2) + return ci; + + if (aliased >= 2) + return aliased; + + if (alias >= 2) + return alias; + + for (; i <= 12345; i++) { // test that widening works for references + i; + } + + return 0; +} + +void notequal_refinement(short n) { + if (n < 0) + return; + + if (n) { + n; // 1 .. + } else { + n; // 0 .. 0 + } + + if (!n) { + n; // 0 .. 0 + } else { + n; // 1 .. + } + + n ? n : n; // ? 1.. : 0..0 + !n ? n : n; // ? 0..0 : 1.. +} diff --git a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/upperBound.expected b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/upperBound.expected index d80c88e6a59a..0ea6a6ca311c 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/upperBound.expected +++ b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/upperBound.expected @@ -1,483 +1,660 @@ -| inline_assembly.c:10:3:10:3 | y | 4.294967295E9 | -| inline_assembly.c:12:29:12:29 | x | 0.0 | -| inline_assembly.c:12:32:12:32 | y | 1.0 | -| inline_assembly.c:16:25:16:25 | x | 0.0 | -| inline_assembly.c:16:35:16:35 | y | 1.0 | -| inline_assembly.c:21:29:21:29 | x | 4.294967295E9 | -| inline_assembly.c:21:32:21:32 | y | 4.294967295E9 | -| minmax.c:18:37:18:37 | x | 1.0 | -| minmax.c:18:40:18:40 | y | 2.0 | -| minmax.c:18:43:18:43 | z | 3.0 | -| minmax.c:20:2:20:2 | z | 2.147483647E9 | -| minmax.c:22:8:22:8 | x | 1.0 | -| minmax.c:22:14:22:14 | y | 2.0 | -| minmax.c:22:18:22:18 | t | 2.147483647E9 | -| minmax.c:22:22:22:22 | x | 1.0 | -| minmax.c:23:3:23:3 | t | 1.0 | -| minmax.c:26:37:26:37 | x | 1.0 | -| minmax.c:26:40:26:40 | y | 2.0 | -| minmax.c:26:43:26:43 | z | 1.0 | -| test.c:8:5:8:9 | count | 2.147483647E9 | -| test.c:8:13:8:17 | count | 2.147483647E9 | -| test.c:10:10:10:14 | count | 2.147483647E9 | -| test.c:16:5:16:9 | count | 2.147483647E9 | -| test.c:16:14:16:18 | count | 15.0 | -| test.c:18:10:18:14 | count | 15.0 | -| test.c:24:5:24:9 | count | 15.0 | -| test.c:25:5:25:9 | count | 2.147483647E9 | -| test.c:25:13:25:17 | count | 127.0 | -| test.c:27:10:27:14 | count | 15.0 | -| test.c:33:8:33:8 | i | 2.147483647E9 | -| test.c:33:15:33:15 | i | 2.0 | -| test.c:33:22:33:22 | i | 2.147483647E9 | -| test.c:33:26:33:26 | i | 1.0 | -| test.c:34:5:34:9 | total | 2.147483647E9 | -| test.c:34:14:34:14 | i | 1.0 | -| test.c:36:10:36:14 | total | 2.147483647E9 | -| test.c:36:18:36:18 | i | 2.0 | -| test.c:42:8:42:8 | i | 2.147483647E9 | -| test.c:42:15:42:15 | i | 2.0 | -| test.c:42:22:42:22 | i | 1.0 | -| test.c:43:5:43:9 | total | 2.147483647E9 | -| test.c:43:14:43:14 | i | 1.0 | -| test.c:45:10:45:14 | total | 2.147483647E9 | -| test.c:45:18:45:18 | i | 2.0 | -| test.c:51:8:51:8 | i | 2.147483647E9 | -| test.c:51:15:51:15 | i | 2.0 | -| test.c:51:24:51:24 | i | 2.147483647E9 | -| test.c:51:28:51:28 | i | 1.0 | -| test.c:52:5:52:9 | total | 2.147483647E9 | -| test.c:52:14:52:14 | i | 1.0 | -| test.c:54:10:54:14 | total | 2.147483647E9 | -| test.c:54:18:54:18 | i | 2.0 | -| test.c:58:7:58:7 | i | 2.147483647E9 | -| test.c:59:9:59:9 | i | 3.0 | -| test.c:60:14:60:14 | i | 3.0 | -| test.c:67:15:67:15 | y | 2.147483647E9 | -| test.c:67:20:67:20 | y | 2.147483647E9 | -| test.c:68:9:68:9 | x | 2.147483647E9 | -| test.c:68:13:68:13 | y | 9.0 | -| test.c:69:14:69:14 | x | 6.0 | -| test.c:72:10:72:10 | y | 2.147483647E9 | -| test.c:76:7:76:7 | y | 2.147483647E9 | -| test.c:77:9:77:9 | x | 2.147483647E9 | -| test.c:81:9:81:9 | x | 2.147483647E9 | -| test.c:85:10:85:10 | x | 2.147483647E9 | -| test.c:89:7:89:7 | y | 2.147483647E9 | -| test.c:90:9:90:9 | x | 2.147483647E9 | -| test.c:90:13:90:13 | y | 2.147483647E9 | -| test.c:93:12:93:12 | x | 2.147483647E9 | -| test.c:100:3:100:3 | c | 127.0 | -| test.c:101:7:101:7 | c | 127.0 | -| test.c:104:7:104:7 | c | 127.0 | -| test.c:105:5:105:5 | c | 127.0 | -| test.c:106:9:106:9 | c | 127.0 | -| test.c:109:9:109:9 | c | 127.0 | -| test.c:119:10:119:10 | n | 1.8446744073709552E19 | -| test.c:124:11:124:15 | Start | 1.8446744073709552E19 | -| test.c:127:6:127:10 | Start | 1.8446744073709552E19 | -| test.c:127:15:127:20 | Length | 1.8446744073709552E19 | -| test.c:135:22:135:22 | c | 127.0 | -| test.c:137:20:137:20 | x | 0.0 | -| test.c:138:11:138:11 | i | 2.147483647E9 | -| test.c:139:19:139:19 | c | 127.0 | -| test.c:139:23:139:23 | i | 2.147483647E9 | -| test.c:139:27:139:28 | uc | 255.0 | -| test.c:139:32:139:32 | x | 0.0 | -| test.c:139:36:139:36 | y | 4.294967295E9 | -| test.c:139:40:139:40 | z | 2.147483647E9 | -| test.c:144:23:144:23 | x | 2.147483647E9 | -| test.c:145:32:145:32 | x | 2.147483647E9 | -| test.c:146:33:146:33 | x | 2.147483647E9 | -| test.c:147:31:147:31 | x | 2.147483647E9 | -| test.c:148:13:148:13 | x | 2.147483647E9 | -| test.c:149:23:149:23 | x | 2.147483647E9 | -| test.c:150:10:150:11 | x0 | 127.0 | -| test.c:150:15:150:16 | x1 | 255.0 | -| test.c:150:20:150:21 | x2 | 65535.0 | -| test.c:150:25:150:26 | x3 | 2.147483647E9 | -| test.c:150:30:150:31 | c0 | 127.0 | -| test.c:150:35:150:36 | s0 | 65535.0 | -| test.c:154:11:154:11 | x | 9.223372036854776E18 | -| test.c:154:20:154:20 | x | 9.223372036854776E18 | -| test.c:154:30:154:30 | x | 9.223372036854776E18 | -| test.c:154:35:154:35 | x | 2.147483647E9 | -| test.c:161:12:161:12 | a | 2.147483647E9 | -| test.c:161:17:161:17 | a | 2.147483647E9 | -| test.c:162:14:162:14 | a | 11.0 | -| test.c:163:14:163:14 | a | 11.0 | -| test.c:164:5:164:9 | total | 0.0 | -| test.c:164:14:164:14 | b | 11.0 | -| test.c:164:16:164:16 | c | -3.0 | -| test.c:166:12:166:12 | a | 2.147483647E9 | -| test.c:166:17:166:17 | a | 2.147483647E9 | -| test.c:167:14:167:14 | a | 11.0 | -| test.c:168:14:168:14 | a | 11.0 | -| test.c:169:5:169:9 | total | 8.0 | -| test.c:169:14:169:14 | b | 11.0 | -| test.c:169:16:169:16 | c | -0.0 | -| test.c:171:13:171:13 | a | 2.147483647E9 | -| test.c:171:18:171:18 | a | 2.147483647E9 | -| test.c:172:14:172:14 | a | 11.0 | -| test.c:173:14:173:14 | a | 11.0 | -| test.c:174:5:174:9 | total | 19.0 | -| test.c:174:14:174:14 | b | 11.0 | -| test.c:174:16:174:16 | c | 7.0 | -| test.c:176:13:176:13 | a | 2.147483647E9 | -| test.c:176:18:176:18 | a | 2.147483647E9 | -| test.c:177:14:177:14 | a | 1.0 | -| test.c:178:14:178:14 | a | 1.0 | -| test.c:179:5:179:9 | total | 37.0 | -| test.c:179:14:179:14 | b | 1.0 | -| test.c:179:16:179:16 | c | 7.0 | -| test.c:181:13:181:13 | a | 2.147483647E9 | -| test.c:181:18:181:18 | a | 2.147483647E9 | -| test.c:182:14:182:14 | a | 0.0 | -| test.c:183:14:183:14 | a | 0.0 | -| test.c:184:5:184:9 | total | 45.0 | -| test.c:184:14:184:14 | b | 0.0 | -| test.c:184:16:184:16 | c | 7.0 | -| test.c:186:13:186:13 | a | 2.147483647E9 | -| test.c:186:18:186:18 | a | 2.147483647E9 | -| test.c:187:14:187:14 | a | -2.0 | -| test.c:188:14:188:14 | a | -2.0 | -| test.c:189:5:189:9 | total | 52.0 | -| test.c:189:14:189:14 | b | -2.0 | -| test.c:189:16:189:16 | c | 7.0 | -| test.c:192:10:192:14 | total | 57.0 | -| test.c:200:12:200:12 | a | 2.147483647E9 | -| test.c:200:17:200:17 | a | 2.147483647E9 | -| test.c:200:33:200:33 | b | 2.147483647E9 | -| test.c:200:38:200:38 | b | 2.147483647E9 | -| test.c:201:13:201:13 | a | 11.0 | -| test.c:201:15:201:15 | b | 23.0 | -| test.c:202:5:202:9 | total | 0.0 | -| test.c:202:14:202:14 | r | 2.147483647E9 | -| test.c:204:12:204:12 | a | 2.147483647E9 | -| test.c:204:17:204:17 | a | 2.147483647E9 | -| test.c:204:33:204:33 | b | 2.147483647E9 | -| test.c:204:38:204:38 | b | 2.147483647E9 | -| test.c:205:13:205:13 | a | 11.0 | -| test.c:205:15:205:15 | b | 23.0 | -| test.c:206:5:206:9 | total | 2.147483647E9 | -| test.c:206:14:206:14 | r | 2.147483647E9 | -| test.c:208:12:208:12 | a | 2.147483647E9 | -| test.c:208:17:208:17 | a | 2.147483647E9 | -| test.c:208:35:208:35 | b | 2.147483647E9 | -| test.c:208:40:208:40 | b | 2.147483647E9 | -| test.c:209:13:209:13 | a | 11.0 | -| test.c:209:15:209:15 | b | 23.0 | -| test.c:210:5:210:9 | total | 2.147483647E9 | -| test.c:210:14:210:14 | r | 2.147483647E9 | -| test.c:212:12:212:12 | a | 2.147483647E9 | -| test.c:212:17:212:17 | a | 2.147483647E9 | -| test.c:212:35:212:35 | b | 2.147483647E9 | -| test.c:212:40:212:40 | b | 2.147483647E9 | -| test.c:213:13:213:13 | a | 11.0 | -| test.c:213:15:213:15 | b | 0.0 | -| test.c:214:5:214:9 | total | 2.147483647E9 | -| test.c:214:14:214:14 | r | 2.147483647E9 | -| test.c:216:12:216:12 | a | 2.147483647E9 | -| test.c:216:17:216:17 | a | 2.147483647E9 | -| test.c:216:35:216:35 | b | 2.147483647E9 | -| test.c:216:40:216:40 | b | 2.147483647E9 | -| test.c:217:13:217:13 | a | 11.0 | -| test.c:217:15:217:15 | b | -7.0 | -| test.c:218:5:218:9 | total | 2.147483647E9 | -| test.c:218:14:218:14 | r | 2.147483647E9 | -| test.c:221:10:221:14 | total | 2.147483647E9 | -| test.c:228:12:228:12 | a | 2.147483647E9 | -| test.c:228:17:228:17 | a | 2.147483647E9 | -| test.c:228:33:228:33 | b | 2.147483647E9 | -| test.c:228:38:228:38 | b | 2.147483647E9 | -| test.c:229:13:229:13 | a | 11.0 | -| test.c:229:15:229:15 | b | 23.0 | -| test.c:230:5:230:9 | total | 0.0 | -| test.c:230:14:230:14 | r | 2.147483647E9 | -| test.c:232:12:232:12 | a | 2.147483647E9 | -| test.c:232:17:232:17 | a | 2.147483647E9 | -| test.c:232:33:232:33 | b | 2.147483647E9 | -| test.c:232:38:232:38 | b | 2.147483647E9 | -| test.c:233:13:233:13 | a | 11.0 | -| test.c:233:15:233:15 | b | 23.0 | -| test.c:234:5:234:9 | total | 2.147483647E9 | -| test.c:234:14:234:14 | r | 2.147483647E9 | -| test.c:236:12:236:12 | a | 2.147483647E9 | -| test.c:236:17:236:17 | a | 2.147483647E9 | -| test.c:236:35:236:35 | b | 2.147483647E9 | -| test.c:236:40:236:40 | b | 2.147483647E9 | -| test.c:237:13:237:13 | a | 11.0 | -| test.c:237:15:237:15 | b | 23.0 | -| test.c:238:5:238:9 | total | 2.147483647E9 | -| test.c:238:14:238:14 | r | 2.147483647E9 | -| test.c:240:12:240:12 | a | 2.147483647E9 | -| test.c:240:17:240:17 | a | 2.147483647E9 | -| test.c:240:35:240:35 | b | 2.147483647E9 | -| test.c:240:40:240:40 | b | 2.147483647E9 | -| test.c:241:13:241:13 | a | 11.0 | -| test.c:241:15:241:15 | b | 0.0 | -| test.c:242:5:242:9 | total | 2.147483647E9 | -| test.c:242:14:242:14 | r | 2.147483647E9 | -| test.c:244:12:244:12 | a | 2.147483647E9 | -| test.c:244:17:244:17 | a | 2.147483647E9 | -| test.c:244:35:244:35 | b | 2.147483647E9 | -| test.c:244:40:244:40 | b | 2.147483647E9 | -| test.c:245:13:245:13 | a | 11.0 | -| test.c:245:15:245:15 | b | -7.0 | -| test.c:246:5:246:9 | total | 2.147483647E9 | -| test.c:246:14:246:14 | r | 2.147483647E9 | -| test.c:249:10:249:14 | total | 2.147483647E9 | -| test.c:256:14:256:14 | a | 2.147483647E9 | -| test.c:256:19:256:19 | a | 2.147483647E9 | -| test.c:256:35:256:35 | b | 2.147483647E9 | -| test.c:256:40:256:40 | b | 2.147483647E9 | -| test.c:257:13:257:13 | a | 11.0 | -| test.c:257:15:257:15 | b | 23.0 | -| test.c:258:5:258:9 | total | 0.0 | -| test.c:258:14:258:14 | r | 2.147483647E9 | -| test.c:260:14:260:14 | a | 2.147483647E9 | -| test.c:260:19:260:19 | a | 2.147483647E9 | -| test.c:260:35:260:35 | b | 2.147483647E9 | -| test.c:260:40:260:40 | b | 2.147483647E9 | -| test.c:261:13:261:13 | a | 11.0 | -| test.c:261:15:261:15 | b | 23.0 | -| test.c:262:5:262:9 | total | 2.147483647E9 | -| test.c:262:14:262:14 | r | 2.147483647E9 | -| test.c:264:14:264:14 | a | 2.147483647E9 | -| test.c:264:19:264:19 | a | 2.147483647E9 | -| test.c:264:37:264:37 | b | 2.147483647E9 | -| test.c:264:42:264:42 | b | 2.147483647E9 | -| test.c:265:13:265:13 | a | 11.0 | -| test.c:265:15:265:15 | b | 23.0 | -| test.c:266:5:266:9 | total | 2.147483647E9 | -| test.c:266:14:266:14 | r | 2.147483647E9 | -| test.c:268:14:268:14 | a | 2.147483647E9 | -| test.c:268:19:268:19 | a | 2.147483647E9 | -| test.c:268:37:268:37 | b | 2.147483647E9 | -| test.c:268:42:268:42 | b | 2.147483647E9 | -| test.c:269:13:269:13 | a | 11.0 | -| test.c:269:15:269:15 | b | 0.0 | -| test.c:270:5:270:9 | total | 2.147483647E9 | -| test.c:270:14:270:14 | r | 2.147483647E9 | -| test.c:272:14:272:14 | a | 2.147483647E9 | -| test.c:272:19:272:19 | a | 2.147483647E9 | -| test.c:272:37:272:37 | b | 2.147483647E9 | -| test.c:272:42:272:42 | b | 2.147483647E9 | -| test.c:273:13:273:13 | a | 11.0 | -| test.c:273:15:273:15 | b | -7.0 | -| test.c:274:5:274:9 | total | 2.147483647E9 | -| test.c:274:14:274:14 | r | 2.147483647E9 | -| test.c:277:10:277:14 | total | 2.147483647E9 | -| test.c:284:14:284:14 | a | 2.147483647E9 | -| test.c:284:19:284:19 | a | 2.147483647E9 | -| test.c:284:34:284:34 | b | 2.147483647E9 | -| test.c:284:39:284:39 | b | 2.147483647E9 | -| test.c:285:13:285:13 | a | 0.0 | -| test.c:285:15:285:15 | b | 23.0 | -| test.c:286:5:286:9 | total | 0.0 | -| test.c:286:14:286:14 | r | 2.147483647E9 | -| test.c:288:14:288:14 | a | 2.147483647E9 | -| test.c:288:19:288:19 | a | 2.147483647E9 | -| test.c:288:34:288:34 | b | 2.147483647E9 | -| test.c:288:39:288:39 | b | 2.147483647E9 | -| test.c:289:13:289:13 | a | 0.0 | -| test.c:289:15:289:15 | b | 23.0 | -| test.c:290:5:290:9 | total | 2.147483647E9 | -| test.c:290:14:290:14 | r | 2.147483647E9 | -| test.c:292:14:292:14 | a | 2.147483647E9 | -| test.c:292:19:292:19 | a | 2.147483647E9 | -| test.c:292:36:292:36 | b | 2.147483647E9 | -| test.c:292:41:292:41 | b | 2.147483647E9 | -| test.c:293:13:293:13 | a | 0.0 | -| test.c:293:15:293:15 | b | 23.0 | -| test.c:294:5:294:9 | total | 2.147483647E9 | -| test.c:294:14:294:14 | r | 2.147483647E9 | -| test.c:296:14:296:14 | a | 2.147483647E9 | -| test.c:296:19:296:19 | a | 2.147483647E9 | -| test.c:296:36:296:36 | b | 2.147483647E9 | -| test.c:296:41:296:41 | b | 2.147483647E9 | -| test.c:297:13:297:13 | a | 0.0 | -| test.c:297:15:297:15 | b | 0.0 | -| test.c:298:5:298:9 | total | 2.147483647E9 | -| test.c:298:14:298:14 | r | 2.147483647E9 | -| test.c:300:14:300:14 | a | 2.147483647E9 | -| test.c:300:19:300:19 | a | 2.147483647E9 | -| test.c:300:36:300:36 | b | 2.147483647E9 | -| test.c:300:41:300:41 | b | 2.147483647E9 | -| test.c:301:13:301:13 | a | 0.0 | -| test.c:301:15:301:15 | b | -7.0 | -| test.c:302:5:302:9 | total | 2.147483647E9 | -| test.c:302:14:302:14 | r | 2.147483647E9 | -| test.c:305:10:305:14 | total | 2.147483647E9 | -| test.c:312:14:312:14 | a | 2.147483647E9 | -| test.c:312:19:312:19 | a | 2.147483647E9 | -| test.c:312:35:312:35 | b | 2.147483647E9 | -| test.c:312:40:312:40 | b | 2.147483647E9 | -| test.c:313:13:313:13 | a | -2.0 | -| test.c:313:15:313:15 | b | 23.0 | -| test.c:314:5:314:9 | total | 0.0 | -| test.c:314:14:314:14 | r | 2.147483647E9 | -| test.c:316:14:316:14 | a | 2.147483647E9 | -| test.c:316:19:316:19 | a | 2.147483647E9 | -| test.c:316:35:316:35 | b | 2.147483647E9 | -| test.c:316:40:316:40 | b | 2.147483647E9 | -| test.c:317:13:317:13 | a | -2.0 | -| test.c:317:15:317:15 | b | 23.0 | -| test.c:318:5:318:9 | total | 2.147483647E9 | -| test.c:318:14:318:14 | r | 2.147483647E9 | -| test.c:320:14:320:14 | a | 2.147483647E9 | -| test.c:320:19:320:19 | a | 2.147483647E9 | -| test.c:320:37:320:37 | b | 2.147483647E9 | -| test.c:320:42:320:42 | b | 2.147483647E9 | -| test.c:321:13:321:13 | a | -2.0 | -| test.c:321:15:321:15 | b | 23.0 | -| test.c:322:5:322:9 | total | 2.147483647E9 | -| test.c:322:14:322:14 | r | 2.147483647E9 | -| test.c:324:14:324:14 | a | 2.147483647E9 | -| test.c:324:19:324:19 | a | 2.147483647E9 | -| test.c:324:37:324:37 | b | 2.147483647E9 | -| test.c:324:42:324:42 | b | 2.147483647E9 | -| test.c:325:13:325:13 | a | -2.0 | -| test.c:325:15:325:15 | b | 0.0 | -| test.c:326:5:326:9 | total | 2.147483647E9 | -| test.c:326:14:326:14 | r | 2.147483647E9 | -| test.c:328:14:328:14 | a | 2.147483647E9 | -| test.c:328:19:328:19 | a | 2.147483647E9 | -| test.c:328:37:328:37 | b | 2.147483647E9 | -| test.c:328:42:328:42 | b | 2.147483647E9 | -| test.c:329:13:329:13 | a | -2.0 | -| test.c:329:15:329:15 | b | -7.0 | -| test.c:330:5:330:9 | total | 2.147483647E9 | -| test.c:330:14:330:14 | r | 2.147483647E9 | -| test.c:333:10:333:14 | total | 2.147483647E9 | -| test.c:338:7:338:7 | x | 2.147483647E9 | -| test.c:342:10:342:10 | i | 7.0 | -| test.c:343:5:343:5 | i | 2.0 | -| test.c:345:3:345:3 | d | 2.147483647E9 | -| test.c:345:7:345:7 | i | 7.0 | -| test.c:346:7:346:7 | x | 2.147483647E9 | -| test.c:347:9:347:9 | d | 7.0 | -| test.c:347:14:347:14 | x | -1.0 | -| test.c:357:3:357:4 | y1 | 4.294967295E9 | -| test.c:357:8:357:8 | x | 4.294967295E9 | -| test.c:357:18:357:18 | x | 99.0 | -| test.c:358:3:358:4 | y2 | 4.294967295E9 | -| test.c:358:8:358:8 | x | 4.294967295E9 | -| test.c:358:24:358:24 | x | 99.0 | -| test.c:359:3:359:4 | y3 | 4.294967295E9 | -| test.c:360:3:360:4 | y4 | 4.294967295E9 | -| test.c:361:3:361:4 | y5 | 4.294967295E9 | -| test.c:362:3:362:4 | y6 | 4.294967295E9 | -| test.c:363:3:363:4 | y7 | 4.294967295E9 | -| test.c:364:3:364:4 | y8 | 4.294967295E9 | -| test.c:365:7:365:7 | x | 4.294967295E9 | -| test.c:366:5:366:6 | y3 | 4.294967295E9 | -| test.c:366:10:366:10 | x | 299.0 | -| test.c:367:5:367:6 | y4 | 4.294967295E9 | -| test.c:367:10:367:10 | x | 299.0 | -| test.c:368:5:368:6 | y5 | 4.294967295E9 | -| test.c:368:11:368:11 | x | 299.0 | -| test.c:369:5:369:6 | y6 | 4.294967295E9 | -| test.c:369:27:369:27 | x | 299.0 | -| test.c:370:5:370:6 | y7 | 4.294967295E9 | -| test.c:370:27:370:27 | x | 299.0 | -| test.c:371:5:371:6 | y8 | 4.294967295E9 | -| test.c:371:28:371:28 | x | 299.0 | -| test.c:373:10:373:11 | y1 | 99.0 | -| test.c:373:15:373:16 | y2 | 99.0 | -| test.c:373:20:373:21 | y3 | 299.0 | -| test.c:373:25:373:26 | y4 | 500.0 | -| test.c:373:30:373:31 | y5 | 300.0 | -| test.c:373:35:373:36 | y6 | 255.0 | -| test.c:373:40:373:41 | y7 | 500.0 | -| test.c:373:45:373:46 | y8 | 300.0 | -| test.c:379:3:379:4 | y1 | 4.294967295E9 | -| test.c:379:8:379:8 | x | 4.294967295E9 | -| test.c:379:18:379:18 | x | 4.294967295E9 | -| test.c:380:3:380:4 | y2 | 4.294967295E9 | -| test.c:380:8:380:8 | x | 4.294967295E9 | -| test.c:380:25:380:25 | x | 4.294967295E9 | -| test.c:381:3:381:4 | y3 | 4.294967295E9 | -| test.c:382:3:382:4 | y4 | 4.294967295E9 | -| test.c:383:3:383:4 | y5 | 4.294967295E9 | -| test.c:384:7:384:7 | x | 4.294967295E9 | -| test.c:385:5:385:6 | y3 | 4.294967295E9 | -| test.c:385:11:385:11 | x | 4.294967295E9 | -| test.c:386:5:386:6 | y4 | 4.294967295E9 | -| test.c:386:11:386:11 | x | 4.294967295E9 | -| test.c:387:5:387:6 | y5 | 4.294967295E9 | -| test.c:387:27:387:27 | x | 4.294967295E9 | -| test.c:389:10:389:11 | y1 | 4.294967295E9 | -| test.c:389:15:389:16 | y2 | 4.294967295E9 | -| test.c:389:20:389:21 | y3 | 4.294967295E9 | -| test.c:389:25:389:26 | y4 | 4.294967295E9 | -| test.c:389:30:389:31 | y5 | 1000.0 | -| test.c:394:20:394:20 | x | 4.294967295E9 | -| test.c:394:30:394:30 | x | 99.0 | -| test.c:397:3:397:4 | y1 | 4.294967295E9 | -| test.c:397:11:397:11 | y | 100.0 | -| test.c:397:14:397:14 | y | 101.0 | -| test.c:398:3:398:4 | y2 | 4.294967295E9 | -| test.c:398:9:398:9 | y | 101.0 | -| test.c:398:14:398:14 | y | 102.0 | -| test.c:398:22:398:22 | y | 105.0 | -| test.c:399:10:399:11 | y1 | 101.0 | -| test.c:399:15:399:16 | y2 | 105.0 | -| test.c:407:3:407:3 | i | 2.147483647E9 | -| test.c:408:7:408:7 | i | 10.0 | -| test.c:410:3:410:3 | i | 2.147483647E9 | -| test.c:411:3:411:3 | i | 10.0 | -| test.c:412:7:412:7 | i | 2.147483647E9 | -| test.c:414:3:414:3 | i | 2.147483647E9 | -| test.c:415:3:415:3 | i | 40.0 | -| test.c:416:7:416:7 | i | 2.147483647E9 | -| test.c:418:3:418:3 | i | 2.147483647E9 | -| test.c:418:7:418:7 | j | 2.147483647E9 | -| test.c:419:7:419:7 | i | 40.0 | -| test.c:421:3:421:3 | i | 2.147483647E9 | -| test.c:421:8:421:8 | j | 40.0 | -| test.c:422:7:422:7 | i | 50.0 | -| test.c:424:3:424:3 | i | 2.147483647E9 | -| test.c:424:13:424:13 | j | 2.147483647E9 | -| test.c:425:7:425:7 | i | 2.147483647E9 | -| test.cpp:10:7:10:7 | b | 2.147483647E9 | -| test.cpp:11:5:11:5 | x | 2.147483647E9 | -| test.cpp:13:10:13:10 | x | 2.147483647E9 | -| test.cpp:18:30:18:30 | x | 2.147483647E9 | -| test.cpp:19:10:19:11 | x0 | 127.0 | -| test.cpp:27:7:27:7 | y | 2.147483647E9 | -| test.cpp:28:5:28:5 | x | 2.147483647E9 | -| test.cpp:30:7:30:7 | y | 2.147483647E9 | -| test.cpp:31:5:31:5 | x | 2.147483647E9 | -| test.cpp:33:7:33:7 | y | 2.147483647E9 | -| test.cpp:34:5:34:5 | x | 2.147483647E9 | -| test.cpp:36:7:36:7 | y | 2.147483647E9 | -| test.cpp:37:5:37:5 | x | 2.147483647E9 | -| test.cpp:39:7:39:7 | y | 2.147483647E9 | -| test.cpp:40:5:40:5 | x | 2.147483647E9 | -| test.cpp:42:7:42:7 | y | 2.147483647E9 | -| test.cpp:43:5:43:5 | x | 2.147483647E9 | -| test.cpp:45:7:45:7 | y | 2.147483647E9 | -| test.cpp:46:5:46:5 | x | 2.147483647E9 | -| test.cpp:51:7:51:7 | x | 2.147483647E9 | -| test.cpp:52:21:52:21 | x | 0.0 | -| test.cpp:53:5:53:5 | t | 0.0 | -| test.cpp:53:15:53:16 | xb | 0.0 | -| test.cpp:56:7:56:7 | x | 2.147483647E9 | -| test.cpp:57:21:57:21 | x | 2.147483647E9 | -| test.cpp:58:5:58:5 | t | 0.0 | -| test.cpp:58:15:58:16 | xb | 1.0 | -| test.cpp:61:7:61:7 | x | 2.147483647E9 | -| test.cpp:62:21:62:21 | x | -1.0 | -| test.cpp:63:5:63:5 | t | 1.0 | -| test.cpp:63:15:63:16 | xb | 1.0 | -| test.cpp:66:19:66:19 | x | 2.147483647E9 | -| test.cpp:67:3:67:3 | t | 2.0 | -| test.cpp:67:13:67:14 | xb | 1.0 | -| test.cpp:69:10:69:10 | b | 1.0 | -| test.cpp:69:21:69:21 | t | 3.0 | -| test.cpp:74:30:74:30 | c | 255.0 | -| test.cpp:74:34:74:34 | c | 255.0 | -| test.cpp:75:22:75:30 | c_times_2 | 510.0 | -| test.cpp:77:5:77:13 | c_times_2 | 510.0 | -| test.cpp:79:3:79:11 | c_times_2 | 510.0 | +| inline_assembly.c:10:3:10:3 | y | 4294967295 | +| inline_assembly.c:12:29:12:29 | x | 0 | +| inline_assembly.c:12:32:12:32 | y | 1 | +| inline_assembly.c:16:25:16:25 | x | 0 | +| inline_assembly.c:16:35:16:35 | y | 1 | +| inline_assembly.c:21:29:21:29 | x | 4294967295 | +| inline_assembly.c:21:32:21:32 | y | 4294967295 | +| minmax.c:18:37:18:37 | x | 1 | +| minmax.c:18:40:18:40 | y | 2 | +| minmax.c:18:43:18:43 | z | 3 | +| minmax.c:20:2:20:2 | z | 2147483647 | +| minmax.c:22:8:22:8 | x | 1 | +| minmax.c:22:14:22:14 | y | 2 | +| minmax.c:22:18:22:18 | t | 2147483647 | +| minmax.c:22:22:22:22 | x | 1 | +| minmax.c:23:3:23:3 | t | 1 | +| minmax.c:26:37:26:37 | x | 1 | +| minmax.c:26:40:26:40 | y | 2 | +| minmax.c:26:43:26:43 | z | 1 | +| test.c:8:5:8:9 | count | 2147483647 | +| test.c:8:13:8:17 | count | 2147483647 | +| test.c:10:10:10:14 | count | 2147483647 | +| test.c:16:5:16:9 | count | 2147483647 | +| test.c:16:14:16:18 | count | 15 | +| test.c:18:10:18:14 | count | 15 | +| test.c:24:5:24:9 | count | 15 | +| test.c:25:5:25:9 | count | 2147483647 | +| test.c:25:13:25:17 | count | 127 | +| test.c:27:10:27:14 | count | 15 | +| test.c:33:8:33:8 | i | 2147483647 | +| test.c:33:15:33:15 | i | 2 | +| test.c:33:22:33:22 | i | 2147483647 | +| test.c:33:26:33:26 | i | 1 | +| test.c:34:5:34:9 | total | 2147483647 | +| test.c:34:14:34:14 | i | 1 | +| test.c:36:10:36:14 | total | 2147483647 | +| test.c:36:18:36:18 | i | 2 | +| test.c:42:8:42:8 | i | 2147483647 | +| test.c:42:15:42:15 | i | 2 | +| test.c:42:22:42:22 | i | 1 | +| test.c:43:5:43:9 | total | 2147483647 | +| test.c:43:14:43:14 | i | 1 | +| test.c:45:10:45:14 | total | 2147483647 | +| test.c:45:18:45:18 | i | 2 | +| test.c:51:8:51:8 | i | 2147483647 | +| test.c:51:15:51:15 | i | 2 | +| test.c:51:24:51:24 | i | 2147483647 | +| test.c:51:28:51:28 | i | 1 | +| test.c:52:5:52:9 | total | 2147483647 | +| test.c:52:14:52:14 | i | 1 | +| test.c:54:10:54:14 | total | 2147483647 | +| test.c:54:18:54:18 | i | 2 | +| test.c:58:7:58:7 | i | 2147483647 | +| test.c:59:9:59:9 | i | 3 | +| test.c:60:14:60:14 | i | 3 | +| test.c:67:15:67:15 | y | 2147483647 | +| test.c:67:20:67:20 | y | 2147483647 | +| test.c:68:9:68:9 | x | 2147483647 | +| test.c:68:13:68:13 | y | 9 | +| test.c:69:14:69:14 | x | 6 | +| test.c:72:10:72:10 | y | 2147483647 | +| test.c:76:7:76:7 | y | 2147483647 | +| test.c:77:9:77:9 | x | 2147483647 | +| test.c:81:9:81:9 | x | 2147483647 | +| test.c:85:10:85:10 | x | 2147483647 | +| test.c:89:7:89:7 | y | 2147483647 | +| test.c:90:9:90:9 | x | 2147483647 | +| test.c:90:13:90:13 | y | 2147483647 | +| test.c:93:12:93:12 | x | 2147483647 | +| test.c:100:3:100:3 | c | 127 | +| test.c:101:7:101:7 | c | 127 | +| test.c:104:7:104:7 | c | 127 | +| test.c:105:5:105:5 | c | 127 | +| test.c:106:9:106:9 | c | 127 | +| test.c:109:9:109:9 | c | 127 | +| test.c:119:10:119:10 | n | 18446744073709551616 | +| test.c:124:11:124:15 | Start | 18446744073709551616 | +| test.c:127:6:127:10 | Start | 18446744073709551616 | +| test.c:127:15:127:20 | Length | 18446744073709551616 | +| test.c:135:22:135:22 | c | 127 | +| test.c:137:20:137:20 | x | 0 | +| test.c:138:11:138:11 | i | 2147483647 | +| test.c:139:19:139:19 | c | 127 | +| test.c:139:23:139:23 | i | 2147483647 | +| test.c:139:27:139:28 | uc | 255 | +| test.c:139:32:139:32 | x | 0 | +| test.c:139:36:139:36 | y | 4294967295 | +| test.c:139:40:139:40 | z | 2147483647 | +| test.c:144:23:144:23 | x | 2147483647 | +| test.c:145:32:145:32 | x | 2147483647 | +| test.c:146:33:146:33 | x | 2147483647 | +| test.c:147:31:147:31 | x | 2147483647 | +| test.c:148:13:148:13 | x | 2147483647 | +| test.c:149:23:149:23 | x | 2147483647 | +| test.c:150:10:150:11 | x0 | 127 | +| test.c:150:15:150:16 | x1 | 255 | +| test.c:150:20:150:21 | x2 | 65535 | +| test.c:150:25:150:26 | x3 | 2147483647 | +| test.c:150:30:150:31 | c0 | 127 | +| test.c:150:35:150:36 | s0 | 65535 | +| test.c:154:11:154:11 | x | 9223372036854775808 | +| test.c:154:20:154:20 | x | 9223372036854775808 | +| test.c:154:30:154:30 | x | 9223372036854775808 | +| test.c:154:35:154:35 | x | 2147483647 | +| test.c:161:12:161:12 | a | 2147483647 | +| test.c:161:17:161:17 | a | 2147483647 | +| test.c:162:14:162:14 | a | 11 | +| test.c:163:14:163:14 | a | 11 | +| test.c:164:5:164:9 | total | 0 | +| test.c:164:14:164:14 | b | 11 | +| test.c:164:16:164:16 | c | -3 | +| test.c:166:12:166:12 | a | 2147483647 | +| test.c:166:17:166:17 | a | 2147483647 | +| test.c:167:14:167:14 | a | 11 | +| test.c:168:14:168:14 | a | 11 | +| test.c:169:5:169:9 | total | 8 | +| test.c:169:14:169:14 | b | 11 | +| test.c:169:16:169:16 | c | 0 | +| test.c:171:13:171:13 | a | 2147483647 | +| test.c:171:18:171:18 | a | 2147483647 | +| test.c:172:14:172:14 | a | 11 | +| test.c:173:14:173:14 | a | 11 | +| test.c:174:5:174:9 | total | 19 | +| test.c:174:14:174:14 | b | 11 | +| test.c:174:16:174:16 | c | 7 | +| test.c:176:13:176:13 | a | 2147483647 | +| test.c:176:18:176:18 | a | 2147483647 | +| test.c:177:14:177:14 | a | 1 | +| test.c:178:14:178:14 | a | 1 | +| test.c:179:5:179:9 | total | 37 | +| test.c:179:14:179:14 | b | 1 | +| test.c:179:16:179:16 | c | 7 | +| test.c:181:13:181:13 | a | 2147483647 | +| test.c:181:18:181:18 | a | 2147483647 | +| test.c:182:14:182:14 | a | 0 | +| test.c:183:14:183:14 | a | 0 | +| test.c:184:5:184:9 | total | 45 | +| test.c:184:14:184:14 | b | 0 | +| test.c:184:16:184:16 | c | 7 | +| test.c:186:13:186:13 | a | 2147483647 | +| test.c:186:18:186:18 | a | 2147483647 | +| test.c:187:14:187:14 | a | -2 | +| test.c:188:14:188:14 | a | -2 | +| test.c:189:5:189:9 | total | 52 | +| test.c:189:14:189:14 | b | -2 | +| test.c:189:16:189:16 | c | 7 | +| test.c:192:10:192:14 | total | 57 | +| test.c:200:12:200:12 | a | 2147483647 | +| test.c:200:17:200:17 | a | 2147483647 | +| test.c:200:33:200:33 | b | 2147483647 | +| test.c:200:38:200:38 | b | 2147483647 | +| test.c:201:13:201:13 | a | 11 | +| test.c:201:15:201:15 | b | 23 | +| test.c:202:5:202:9 | total | 0 | +| test.c:202:14:202:14 | r | 2147483647 | +| test.c:204:12:204:12 | a | 2147483647 | +| test.c:204:17:204:17 | a | 2147483647 | +| test.c:204:33:204:33 | b | 2147483647 | +| test.c:204:38:204:38 | b | 2147483647 | +| test.c:205:13:205:13 | a | 11 | +| test.c:205:15:205:15 | b | 23 | +| test.c:206:5:206:9 | total | 2147483647 | +| test.c:206:14:206:14 | r | 2147483647 | +| test.c:208:12:208:12 | a | 2147483647 | +| test.c:208:17:208:17 | a | 2147483647 | +| test.c:208:35:208:35 | b | 2147483647 | +| test.c:208:40:208:40 | b | 2147483647 | +| test.c:209:13:209:13 | a | 11 | +| test.c:209:15:209:15 | b | 23 | +| test.c:210:5:210:9 | total | 2147483647 | +| test.c:210:14:210:14 | r | 2147483647 | +| test.c:212:12:212:12 | a | 2147483647 | +| test.c:212:17:212:17 | a | 2147483647 | +| test.c:212:35:212:35 | b | 2147483647 | +| test.c:212:40:212:40 | b | 2147483647 | +| test.c:213:13:213:13 | a | 11 | +| test.c:213:15:213:15 | b | 0 | +| test.c:214:5:214:9 | total | 2147483647 | +| test.c:214:14:214:14 | r | 2147483647 | +| test.c:216:12:216:12 | a | 2147483647 | +| test.c:216:17:216:17 | a | 2147483647 | +| test.c:216:35:216:35 | b | 2147483647 | +| test.c:216:40:216:40 | b | 2147483647 | +| test.c:217:13:217:13 | a | 11 | +| test.c:217:15:217:15 | b | -7 | +| test.c:218:5:218:9 | total | 2147483647 | +| test.c:218:14:218:14 | r | 2147483647 | +| test.c:221:10:221:14 | total | 2147483647 | +| test.c:228:12:228:12 | a | 2147483647 | +| test.c:228:17:228:17 | a | 2147483647 | +| test.c:228:33:228:33 | b | 2147483647 | +| test.c:228:38:228:38 | b | 2147483647 | +| test.c:229:13:229:13 | a | 11 | +| test.c:229:15:229:15 | b | 23 | +| test.c:230:5:230:9 | total | 0 | +| test.c:230:14:230:14 | r | 2147483647 | +| test.c:232:12:232:12 | a | 2147483647 | +| test.c:232:17:232:17 | a | 2147483647 | +| test.c:232:33:232:33 | b | 2147483647 | +| test.c:232:38:232:38 | b | 2147483647 | +| test.c:233:13:233:13 | a | 11 | +| test.c:233:15:233:15 | b | 23 | +| test.c:234:5:234:9 | total | 2147483647 | +| test.c:234:14:234:14 | r | 2147483647 | +| test.c:236:12:236:12 | a | 2147483647 | +| test.c:236:17:236:17 | a | 2147483647 | +| test.c:236:35:236:35 | b | 2147483647 | +| test.c:236:40:236:40 | b | 2147483647 | +| test.c:237:13:237:13 | a | 11 | +| test.c:237:15:237:15 | b | 23 | +| test.c:238:5:238:9 | total | 2147483647 | +| test.c:238:14:238:14 | r | 2147483647 | +| test.c:240:12:240:12 | a | 2147483647 | +| test.c:240:17:240:17 | a | 2147483647 | +| test.c:240:35:240:35 | b | 2147483647 | +| test.c:240:40:240:40 | b | 2147483647 | +| test.c:241:13:241:13 | a | 11 | +| test.c:241:15:241:15 | b | 0 | +| test.c:242:5:242:9 | total | 2147483647 | +| test.c:242:14:242:14 | r | 2147483647 | +| test.c:244:12:244:12 | a | 2147483647 | +| test.c:244:17:244:17 | a | 2147483647 | +| test.c:244:35:244:35 | b | 2147483647 | +| test.c:244:40:244:40 | b | 2147483647 | +| test.c:245:13:245:13 | a | 11 | +| test.c:245:15:245:15 | b | -7 | +| test.c:246:5:246:9 | total | 2147483647 | +| test.c:246:14:246:14 | r | 2147483647 | +| test.c:249:10:249:14 | total | 2147483647 | +| test.c:256:14:256:14 | a | 2147483647 | +| test.c:256:19:256:19 | a | 2147483647 | +| test.c:256:35:256:35 | b | 2147483647 | +| test.c:256:40:256:40 | b | 2147483647 | +| test.c:257:13:257:13 | a | 11 | +| test.c:257:15:257:15 | b | 23 | +| test.c:258:5:258:9 | total | 0 | +| test.c:258:14:258:14 | r | 2147483647 | +| test.c:260:14:260:14 | a | 2147483647 | +| test.c:260:19:260:19 | a | 2147483647 | +| test.c:260:35:260:35 | b | 2147483647 | +| test.c:260:40:260:40 | b | 2147483647 | +| test.c:261:13:261:13 | a | 11 | +| test.c:261:15:261:15 | b | 23 | +| test.c:262:5:262:9 | total | 2147483647 | +| test.c:262:14:262:14 | r | 2147483647 | +| test.c:264:14:264:14 | a | 2147483647 | +| test.c:264:19:264:19 | a | 2147483647 | +| test.c:264:37:264:37 | b | 2147483647 | +| test.c:264:42:264:42 | b | 2147483647 | +| test.c:265:13:265:13 | a | 11 | +| test.c:265:15:265:15 | b | 23 | +| test.c:266:5:266:9 | total | 2147483647 | +| test.c:266:14:266:14 | r | 2147483647 | +| test.c:268:14:268:14 | a | 2147483647 | +| test.c:268:19:268:19 | a | 2147483647 | +| test.c:268:37:268:37 | b | 2147483647 | +| test.c:268:42:268:42 | b | 2147483647 | +| test.c:269:13:269:13 | a | 11 | +| test.c:269:15:269:15 | b | 0 | +| test.c:270:5:270:9 | total | 2147483647 | +| test.c:270:14:270:14 | r | 2147483647 | +| test.c:272:14:272:14 | a | 2147483647 | +| test.c:272:19:272:19 | a | 2147483647 | +| test.c:272:37:272:37 | b | 2147483647 | +| test.c:272:42:272:42 | b | 2147483647 | +| test.c:273:13:273:13 | a | 11 | +| test.c:273:15:273:15 | b | -7 | +| test.c:274:5:274:9 | total | 2147483647 | +| test.c:274:14:274:14 | r | 2147483647 | +| test.c:277:10:277:14 | total | 2147483647 | +| test.c:284:14:284:14 | a | 2147483647 | +| test.c:284:19:284:19 | a | 2147483647 | +| test.c:284:34:284:34 | b | 2147483647 | +| test.c:284:39:284:39 | b | 2147483647 | +| test.c:285:13:285:13 | a | 0 | +| test.c:285:15:285:15 | b | 23 | +| test.c:286:5:286:9 | total | 0 | +| test.c:286:14:286:14 | r | 2147483647 | +| test.c:288:14:288:14 | a | 2147483647 | +| test.c:288:19:288:19 | a | 2147483647 | +| test.c:288:34:288:34 | b | 2147483647 | +| test.c:288:39:288:39 | b | 2147483647 | +| test.c:289:13:289:13 | a | 0 | +| test.c:289:15:289:15 | b | 23 | +| test.c:290:5:290:9 | total | 2147483647 | +| test.c:290:14:290:14 | r | 2147483647 | +| test.c:292:14:292:14 | a | 2147483647 | +| test.c:292:19:292:19 | a | 2147483647 | +| test.c:292:36:292:36 | b | 2147483647 | +| test.c:292:41:292:41 | b | 2147483647 | +| test.c:293:13:293:13 | a | 0 | +| test.c:293:15:293:15 | b | 23 | +| test.c:294:5:294:9 | total | 2147483647 | +| test.c:294:14:294:14 | r | 2147483647 | +| test.c:296:14:296:14 | a | 2147483647 | +| test.c:296:19:296:19 | a | 2147483647 | +| test.c:296:36:296:36 | b | 2147483647 | +| test.c:296:41:296:41 | b | 2147483647 | +| test.c:297:13:297:13 | a | 0 | +| test.c:297:15:297:15 | b | 0 | +| test.c:298:5:298:9 | total | 2147483647 | +| test.c:298:14:298:14 | r | 2147483647 | +| test.c:300:14:300:14 | a | 2147483647 | +| test.c:300:19:300:19 | a | 2147483647 | +| test.c:300:36:300:36 | b | 2147483647 | +| test.c:300:41:300:41 | b | 2147483647 | +| test.c:301:13:301:13 | a | 0 | +| test.c:301:15:301:15 | b | -7 | +| test.c:302:5:302:9 | total | 2147483647 | +| test.c:302:14:302:14 | r | 2147483647 | +| test.c:305:10:305:14 | total | 2147483647 | +| test.c:312:14:312:14 | a | 2147483647 | +| test.c:312:19:312:19 | a | 2147483647 | +| test.c:312:35:312:35 | b | 2147483647 | +| test.c:312:40:312:40 | b | 2147483647 | +| test.c:313:13:313:13 | a | -2 | +| test.c:313:15:313:15 | b | 23 | +| test.c:314:5:314:9 | total | 0 | +| test.c:314:14:314:14 | r | 2147483647 | +| test.c:316:14:316:14 | a | 2147483647 | +| test.c:316:19:316:19 | a | 2147483647 | +| test.c:316:35:316:35 | b | 2147483647 | +| test.c:316:40:316:40 | b | 2147483647 | +| test.c:317:13:317:13 | a | -2 | +| test.c:317:15:317:15 | b | 23 | +| test.c:318:5:318:9 | total | 2147483647 | +| test.c:318:14:318:14 | r | 2147483647 | +| test.c:320:14:320:14 | a | 2147483647 | +| test.c:320:19:320:19 | a | 2147483647 | +| test.c:320:37:320:37 | b | 2147483647 | +| test.c:320:42:320:42 | b | 2147483647 | +| test.c:321:13:321:13 | a | -2 | +| test.c:321:15:321:15 | b | 23 | +| test.c:322:5:322:9 | total | 2147483647 | +| test.c:322:14:322:14 | r | 2147483647 | +| test.c:324:14:324:14 | a | 2147483647 | +| test.c:324:19:324:19 | a | 2147483647 | +| test.c:324:37:324:37 | b | 2147483647 | +| test.c:324:42:324:42 | b | 2147483647 | +| test.c:325:13:325:13 | a | -2 | +| test.c:325:15:325:15 | b | 0 | +| test.c:326:5:326:9 | total | 2147483647 | +| test.c:326:14:326:14 | r | 2147483647 | +| test.c:328:14:328:14 | a | 2147483647 | +| test.c:328:19:328:19 | a | 2147483647 | +| test.c:328:37:328:37 | b | 2147483647 | +| test.c:328:42:328:42 | b | 2147483647 | +| test.c:329:13:329:13 | a | -2 | +| test.c:329:15:329:15 | b | -7 | +| test.c:330:5:330:9 | total | 2147483647 | +| test.c:330:14:330:14 | r | 2147483647 | +| test.c:333:10:333:14 | total | 2147483647 | +| test.c:338:7:338:7 | x | 2147483647 | +| test.c:342:10:342:10 | i | 7 | +| test.c:343:5:343:5 | i | 2 | +| test.c:345:3:345:3 | d | 2147483647 | +| test.c:345:7:345:7 | i | 7 | +| test.c:346:7:346:7 | x | 2147483647 | +| test.c:347:9:347:9 | d | 7 | +| test.c:347:14:347:14 | x | -1 | +| test.c:357:3:357:4 | y1 | 4294967295 | +| test.c:357:8:357:8 | x | 4294967295 | +| test.c:357:18:357:18 | x | 99 | +| test.c:358:3:358:4 | y2 | 4294967295 | +| test.c:358:8:358:8 | x | 4294967295 | +| test.c:358:24:358:24 | x | 99 | +| test.c:359:3:359:4 | y3 | 4294967295 | +| test.c:360:3:360:4 | y4 | 4294967295 | +| test.c:361:3:361:4 | y5 | 4294967295 | +| test.c:362:3:362:4 | y6 | 4294967295 | +| test.c:363:3:363:4 | y7 | 4294967295 | +| test.c:364:3:364:4 | y8 | 4294967295 | +| test.c:365:7:365:7 | x | 4294967295 | +| test.c:366:5:366:6 | y3 | 4294967295 | +| test.c:366:10:366:10 | x | 299 | +| test.c:367:5:367:6 | y4 | 4294967295 | +| test.c:367:10:367:10 | x | 299 | +| test.c:368:5:368:6 | y5 | 4294967295 | +| test.c:368:11:368:11 | x | 299 | +| test.c:369:5:369:6 | y6 | 4294967295 | +| test.c:369:27:369:27 | x | 299 | +| test.c:370:5:370:6 | y7 | 4294967295 | +| test.c:370:27:370:27 | x | 299 | +| test.c:371:5:371:6 | y8 | 4294967295 | +| test.c:371:28:371:28 | x | 299 | +| test.c:373:10:373:11 | y1 | 99 | +| test.c:373:15:373:16 | y2 | 99 | +| test.c:373:20:373:21 | y3 | 299 | +| test.c:373:25:373:26 | y4 | 500 | +| test.c:373:30:373:31 | y5 | 300 | +| test.c:373:35:373:36 | y6 | 255 | +| test.c:373:40:373:41 | y7 | 500 | +| test.c:373:45:373:46 | y8 | 300 | +| test.c:379:3:379:4 | y1 | 4294967295 | +| test.c:379:8:379:8 | x | 4294967295 | +| test.c:379:18:379:18 | x | 4294967295 | +| test.c:380:3:380:4 | y2 | 4294967295 | +| test.c:380:8:380:8 | x | 4294967295 | +| test.c:380:25:380:25 | x | 4294967295 | +| test.c:381:3:381:4 | y3 | 4294967295 | +| test.c:382:3:382:4 | y4 | 4294967295 | +| test.c:383:3:383:4 | y5 | 4294967295 | +| test.c:384:7:384:7 | x | 4294967295 | +| test.c:385:5:385:6 | y3 | 4294967295 | +| test.c:385:11:385:11 | x | 4294967295 | +| test.c:386:5:386:6 | y4 | 4294967295 | +| test.c:386:11:386:11 | x | 4294967295 | +| test.c:387:5:387:6 | y5 | 4294967295 | +| test.c:387:27:387:27 | x | 4294967295 | +| test.c:389:10:389:11 | y1 | 4294967295 | +| test.c:389:15:389:16 | y2 | 4294967295 | +| test.c:389:20:389:21 | y3 | 4294967295 | +| test.c:389:25:389:26 | y4 | 4294967295 | +| test.c:389:30:389:31 | y5 | 1000 | +| test.c:394:20:394:20 | x | 4294967295 | +| test.c:394:30:394:30 | x | 99 | +| test.c:397:3:397:4 | y1 | 4294967295 | +| test.c:397:11:397:11 | y | 100 | +| test.c:397:14:397:14 | y | 101 | +| test.c:398:3:398:4 | y2 | 4294967295 | +| test.c:398:9:398:9 | y | 101 | +| test.c:398:14:398:14 | y | 102 | +| test.c:398:22:398:22 | y | 105 | +| test.c:399:10:399:11 | y1 | 101 | +| test.c:399:15:399:16 | y2 | 105 | +| test.c:407:3:407:3 | i | 2147483647 | +| test.c:408:7:408:7 | i | 10 | +| test.c:410:3:410:3 | i | 2147483647 | +| test.c:411:3:411:3 | i | 10 | +| test.c:412:7:412:7 | i | 20 | +| test.c:414:3:414:3 | i | 2147483647 | +| test.c:415:3:415:3 | i | 40 | +| test.c:416:7:416:7 | i | 30 | +| test.c:418:3:418:3 | i | 2147483647 | +| test.c:418:7:418:7 | j | 2147483647 | +| test.c:419:7:419:7 | i | 40 | +| test.c:421:3:421:3 | i | 2147483647 | +| test.c:421:8:421:8 | j | 40 | +| test.c:422:7:422:7 | i | 50 | +| test.c:424:3:424:3 | i | 2147483647 | +| test.c:424:13:424:13 | j | 50 | +| test.c:425:7:425:7 | i | 60 | +| test.c:432:12:432:12 | a | 4294967295 | +| test.c:432:17:432:17 | a | 4294967295 | +| test.c:432:33:432:33 | b | 4294967295 | +| test.c:432:38:432:38 | b | 4294967295 | +| test.c:433:13:433:13 | a | 11 | +| test.c:433:15:433:15 | b | 23 | +| test.c:434:5:434:9 | total | 0 | +| test.c:434:14:434:14 | r | 253 | +| test.c:436:12:436:12 | a | 4294967295 | +| test.c:436:17:436:17 | a | 4294967295 | +| test.c:436:33:436:33 | b | 4294967295 | +| test.c:436:38:436:38 | b | 4294967295 | +| test.c:437:13:437:13 | a | 11 | +| test.c:437:15:437:15 | b | 23 | +| test.c:438:5:438:9 | total | 253 | +| test.c:438:14:438:14 | r | 253 | +| test.c:440:12:440:12 | a | 4294967295 | +| test.c:440:17:440:17 | a | 4294967295 | +| test.c:440:34:440:34 | b | 4294967295 | +| test.c:440:39:440:39 | b | 4294967295 | +| test.c:441:13:441:13 | a | 11 | +| test.c:441:15:441:15 | b | 23 | +| test.c:442:5:442:9 | total | 506 | +| test.c:442:14:442:14 | r | 253 | +| test.c:445:10:445:14 | total | 759 | +| test.c:451:12:451:12 | b | 4294967295 | +| test.c:451:17:451:17 | b | 4294967295 | +| test.c:452:16:452:16 | b | 23 | +| test.c:453:5:453:9 | total | 0 | +| test.c:453:14:453:14 | r | 253 | +| test.c:455:12:455:12 | b | 4294967295 | +| test.c:455:17:455:17 | b | 4294967295 | +| test.c:456:16:456:16 | b | 23 | +| test.c:457:5:457:9 | total | 253 | +| test.c:457:14:457:14 | r | 253 | +| test.c:459:13:459:13 | b | 4294967295 | +| test.c:459:18:459:18 | b | 4294967295 | +| test.c:460:16:460:16 | b | 23 | +| test.c:461:5:461:9 | total | 506 | +| test.c:461:14:461:14 | r | 253 | +| test.c:464:10:464:14 | total | 759 | +| test.c:469:3:469:3 | x | 18446744073709551616 | +| test.c:469:7:469:7 | y | 18446744073709551616 | +| test.c:470:3:470:4 | xy | 18446744073709551616 | +| test.c:470:8:470:8 | x | 1000000003 | +| test.c:470:12:470:12 | y | 1000000003 | +| test.c:471:10:471:11 | xy | 1000000006000000000 | +| test.c:476:3:476:3 | x | 18446744073709551616 | +| test.c:477:3:477:3 | y | 18446744073709551616 | +| test.c:478:3:478:4 | xy | 18446744073709551616 | +| test.c:478:8:478:8 | x | 274177 | +| test.c:478:12:478:12 | y | 67280421310721 | +| test.c:479:10:479:11 | xy | 18446744073709551616 | +| test.c:483:7:483:8 | ui | 4294967295 | +| test.c:484:43:484:44 | ui | 4294967295 | +| test.c:484:48:484:49 | ui | 4294967295 | +| test.c:485:12:485:17 | result | 18446744065119617024 | +| test.c:487:7:487:8 | ul | 18446744073709551616 | +| test.c:488:28:488:29 | ul | 18446744073709551616 | +| test.c:488:33:488:34 | ul | 18446744073709551616 | +| test.c:489:12:489:17 | result | 18446744073709551616 | +| test.c:495:7:495:8 | ui | 4294967295 | +| test.c:495:19:495:20 | ui | 10 | +| test.c:496:5:496:6 | ui | 10 | +| test.c:496:11:496:12 | ui | 10 | +| test.c:497:12:497:13 | ui | 100 | +| test.c:501:3:501:9 | uiconst | 10 | +| test.c:504:3:504:9 | ulconst | 10 | +| test.c:505:10:505:16 | uiconst | 40 | +| test.c:505:20:505:26 | ulconst | 40 | +| test.c:509:7:509:7 | i | 2147483647 | +| test.c:509:18:509:18 | i | 2147483647 | +| test.c:510:5:510:5 | i | 2147483647 | +| test.c:510:13:510:13 | i | 2 | +| test.c:511:9:511:9 | i | 10 | +| test.c:513:5:513:5 | i | 2147483647 | +| test.c:513:9:513:9 | i | 10 | +| test.c:514:9:514:9 | i | 15 | +| test.c:516:5:516:5 | i | 15 | +| test.c:517:9:517:9 | i | 105 | +| test.c:519:5:519:5 | i | 105 | +| test.c:520:9:520:9 | i | 2310 | +| test.c:522:7:522:7 | i | 2147483647 | +| test.c:523:5:523:5 | i | 2147483647 | +| test.c:523:9:523:9 | i | -1 | +| test.c:524:9:524:9 | i | 1 | +| test.c:526:3:526:3 | i | 2147483647 | +| test.c:526:7:526:7 | i | 2147483647 | +| test.c:527:10:527:10 | i | 2147483647 | +| test.c:530:3:530:3 | i | 2147483647 | +| test.c:530:10:530:11 | sc | 1 | +| test.c:532:7:532:7 | i | 127 | +| test.c:539:7:539:7 | n | 4294967295 | +| test.c:541:7:541:7 | n | 4294967295 | +| test.c:542:9:542:9 | n | 4294967295 | +| test.c:545:7:545:7 | n | 4294967295 | +| test.c:546:9:546:9 | n | 4294967295 | +| test.c:548:9:548:9 | n | 0 | +| test.c:551:8:551:8 | n | 4294967295 | +| test.c:552:9:552:9 | n | 0 | +| test.c:554:9:554:9 | n | 4294967295 | +| test.c:557:10:557:10 | n | 4294967295 | +| test.c:558:5:558:5 | n | 4294967295 | +| test.c:561:7:561:7 | n | 0 | +| test.c:565:7:565:7 | n | 32767 | +| test.c:568:7:568:7 | n | 32767 | +| test.c:569:9:569:9 | n | 0 | +| test.c:571:9:571:9 | n | 32767 | +| test.c:574:7:574:7 | n | 32767 | +| test.c:575:9:575:9 | n | 32767 | +| test.c:577:9:577:9 | n | 0 | +| test.c:580:10:580:10 | n | 32767 | +| test.c:581:5:581:5 | n | 32767 | +| test.c:584:7:584:7 | n | 0 | +| test.c:588:7:588:7 | n | 32767 | +| test.c:589:9:589:9 | n | 32767 | +| test.c:590:11:590:11 | n | 32767 | +| test.c:594:7:594:7 | n | 32767 | +| test.c:595:13:595:13 | n | 32767 | +| test.c:598:9:598:9 | n | 32767 | +| test.c:601:7:601:7 | n | 32767 | +| test.c:601:22:601:22 | n | 32767 | +| test.c:602:9:602:9 | n | 32767 | +| test.c:605:7:605:7 | n | 32767 | +| test.c:606:5:606:5 | n | 32767 | +| test.c:606:10:606:10 | n | 32767 | +| test.c:606:14:606:14 | n | 0 | +| test.c:607:6:607:6 | n | 32767 | +| test.c:607:10:607:10 | n | 0 | +| test.c:607:14:607:14 | n | 32767 | +| test.c:618:7:618:8 | ss | 32767 | +| test.c:619:9:619:10 | ss | 3 | +| test.c:622:7:622:8 | ss | 32767 | +| test.c:623:9:623:10 | ss | 32767 | +| test.c:626:14:626:15 | us | 65535 | +| test.c:627:9:627:10 | us | 32767 | +| test.c:630:14:630:15 | us | 65535 | +| test.c:631:9:631:10 | us | 65535 | +| test.c:634:7:634:8 | ss | 32767 | +| test.c:635:9:635:10 | ss | 32767 | +| test.c:638:7:638:8 | ss | 32767 | +| test.c:639:9:639:10 | ss | 2 | +| test.c:645:8:645:8 | s | 2147483647 | +| test.c:645:15:645:15 | s | 127 | +| test.c:645:23:645:23 | s | 15 | +| test.c:646:18:646:18 | s | 15 | +| test.c:646:22:646:22 | s | 15 | +| test.c:647:9:647:14 | result | 127 | +| test.c:653:7:653:7 | i | 0 | +| test.c:654:9:654:9 | i | 2147483647 | +| test.c:658:7:658:7 | u | 0 | +| test.c:659:9:659:9 | u | 4294967295 | +| test.cpp:10:7:10:7 | b | 2147483647 | +| test.cpp:11:5:11:5 | x | 2147483647 | +| test.cpp:13:10:13:10 | x | 2147483647 | +| test.cpp:18:30:18:30 | x | 2147483647 | +| test.cpp:19:10:19:11 | x0 | 127 | +| test.cpp:27:7:27:7 | y | 2147483647 | +| test.cpp:28:5:28:5 | x | 2147483647 | +| test.cpp:30:7:30:7 | y | 2147483647 | +| test.cpp:31:5:31:5 | x | 2147483647 | +| test.cpp:33:7:33:7 | y | 2147483647 | +| test.cpp:34:5:34:5 | x | 2147483647 | +| test.cpp:36:7:36:7 | y | 2147483647 | +| test.cpp:37:5:37:5 | x | 2147483647 | +| test.cpp:39:7:39:7 | y | 2147483647 | +| test.cpp:40:5:40:5 | x | 2147483647 | +| test.cpp:42:7:42:7 | y | 2147483647 | +| test.cpp:43:5:43:5 | x | 2147483647 | +| test.cpp:45:7:45:7 | y | 2147483647 | +| test.cpp:46:5:46:5 | x | 2147483647 | +| test.cpp:51:7:51:7 | x | 2147483647 | +| test.cpp:52:21:52:21 | x | 0 | +| test.cpp:53:5:53:5 | t | 0 | +| test.cpp:53:15:53:16 | xb | 0 | +| test.cpp:56:7:56:7 | x | 2147483647 | +| test.cpp:57:21:57:21 | x | 2147483647 | +| test.cpp:58:5:58:5 | t | 0 | +| test.cpp:58:15:58:16 | xb | 1 | +| test.cpp:61:7:61:7 | x | 2147483647 | +| test.cpp:62:21:62:21 | x | -1 | +| test.cpp:63:5:63:5 | t | 1 | +| test.cpp:63:15:63:16 | xb | 1 | +| test.cpp:66:19:66:19 | x | 2147483647 | +| test.cpp:67:3:67:3 | t | 2 | +| test.cpp:67:13:67:14 | xb | 1 | +| test.cpp:69:10:69:10 | b | 1 | +| test.cpp:69:21:69:21 | t | 3 | +| test.cpp:74:30:74:30 | c | 255 | +| test.cpp:74:34:74:34 | c | 255 | +| test.cpp:75:22:75:30 | c_times_2 | 510 | +| test.cpp:77:5:77:13 | c_times_2 | 510 | +| test.cpp:79:3:79:11 | c_times_2 | 510 | +| test.cpp:83:16:83:22 | aliased | 2147483647 | +| test.cpp:85:7:85:7 | i | 2147483647 | +| test.cpp:86:12:86:12 | i | 2147483647 | +| test.cpp:88:7:88:8 | ci | 2147483647 | +| test.cpp:89:12:89:13 | ci | 2147483647 | +| test.cpp:91:7:91:13 | aliased | 2147483647 | +| test.cpp:92:12:92:18 | aliased | 2147483647 | +| test.cpp:94:7:94:11 | alias | 2147483647 | +| test.cpp:95:12:95:16 | alias | 2147483647 | +| test.cpp:97:10:97:10 | i | 65535 | +| test.cpp:97:22:97:22 | i | 32767 | +| test.cpp:98:5:98:5 | i | 32767 | +| test.cpp:105:7:105:7 | n | 32767 | +| test.cpp:108:7:108:7 | n | 32767 | +| test.cpp:109:5:109:5 | n | 32767 | +| test.cpp:111:5:111:5 | n | 0 | +| test.cpp:114:8:114:8 | n | 32767 | +| test.cpp:115:5:115:5 | n | 0 | +| test.cpp:117:5:117:5 | n | 32767 | +| test.cpp:120:3:120:3 | n | 32767 | +| test.cpp:120:8:120:8 | n | 32767 | +| test.cpp:120:12:120:12 | n | 0 | +| test.cpp:121:4:121:4 | n | 32767 | +| test.cpp:121:8:121:8 | n | 0 | +| test.cpp:121:12:121:12 | n | 32767 | diff --git a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/upperBound.ql b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/upperBound.ql index 341e5784aa36..26d188ce89cb 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/upperBound.ql +++ b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/upperBound.ql @@ -1,4 +1,4 @@ import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis from VariableAccess expr -select expr, upperBound(expr) +select expr, upperBound(expr).toString() diff --git a/cpp/ql/test/library-tests/scopes/scopes/Scopes1.expected b/cpp/ql/test/library-tests/scopes/scopes/Scopes1.expected index 01915a9253ed..f89e8fbeb8bc 100644 --- a/cpp/ql/test/library-tests/scopes/scopes/Scopes1.expected +++ b/cpp/ql/test/library-tests/scopes/scopes/Scopes1.expected @@ -21,8 +21,10 @@ | scopes.cpp:2:7:2:7 | A | Class | scopes.cpp:2:7:2:7 | operator= | | | scopes.cpp:7:7:7:7 | B | Class | scopes.cpp:7:7:7:7 | operator= | | | scopes.cpp:7:7:7:7 | B | Class | scopes.cpp:7:7:7:7 | operator= | | +| scopes.cpp:11:7:11:7 | C | Class | scopes.cpp:11:7:11:7 | C | | | scopes.cpp:11:7:11:7 | C | Class | scopes.cpp:11:7:11:7 | operator= | | | scopes.cpp:11:7:11:7 | C | Class | scopes.cpp:11:7:11:7 | operator= | | +| scopes.cpp:15:7:15:7 | D | Class | scopes.cpp:15:7:15:7 | D | | | scopes.cpp:15:7:15:7 | D | Class | scopes.cpp:15:7:15:7 | operator= | | | scopes.cpp:15:7:15:7 | D | Class | scopes.cpp:15:7:15:7 | operator= | | | scopes.cpp:15:7:15:7 | D | Class | scopes.cpp:21:7:21:10 | E | NestedClass | @@ -32,6 +34,7 @@ | scopes.cpp:21:7:21:10 | E | NestedClass | scopes.cpp:31:7:31:13 | F | NestedClass | | scopes.cpp:25:8:25:8 | G | NestedClass | scopes.cpp:25:8:25:8 | operator= | | | scopes.cpp:25:8:25:8 | G | NestedClass | scopes.cpp:25:8:25:8 | operator= | | +| scopes.cpp:31:7:31:13 | F | NestedClass | scopes.cpp:31:13:31:13 | F | | | scopes.cpp:31:7:31:13 | F | NestedClass | scopes.cpp:31:13:31:13 | operator= | | | scopes.cpp:31:7:31:13 | F | NestedClass | scopes.cpp:31:13:31:13 | operator= | | | scopes.cpp:31:7:31:13 | F | NestedClass | scopes.cpp:32:8:32:27 | doubleNestedFunction | | @@ -39,6 +42,7 @@ | scopes.cpp:46:8:46:8 | S | Class | scopes.cpp:46:8:46:8 | operator= | | | scopes.cpp:46:8:46:8 | S | Class | scopes.cpp:47:7:47:8 | af | | | scopes.cpp:46:8:46:8 | S | Class | scopes.cpp:50:7:50:8 | ag | | +| scopes.cpp:58:7:58:10 | Name | Class | scopes.cpp:58:7:58:7 | Name | | | scopes.cpp:58:7:58:10 | Name | Class | scopes.cpp:58:7:58:7 | operator= | | | scopes.cpp:58:7:58:10 | Name | Class | scopes.cpp:58:7:58:7 | operator= | | | scopes.cpp:58:7:58:10 | Name | Class | scopes.cpp:59:14:59:14 | s | | @@ -59,9 +63,11 @@ | scopes.cpp:74:11:74:13 | One | Namespace | scopes.cpp:95:8:95:8 | I | Class | | scopes.cpp:77:8:77:8 | H | Class | scopes.cpp:76:18:76:18 | T | | | scopes.cpp:77:8:77:8 | H | Class | scopes.cpp:79:5:79:5 | t | | +| scopes.cpp:77:8:77:8 | H | Class | scopes.cpp:77:8:77:8 | H | | | scopes.cpp:77:8:77:8 | H | Class | scopes.cpp:77:8:77:8 | operator= | | | scopes.cpp:77:8:77:8 | H | Class | scopes.cpp:77:8:77:8 | operator= | | | scopes.cpp:77:8:77:8 | H | Class | scopes.cpp:79:5:79:5 | t | | +| scopes.cpp:77:8:77:8 | H | Class | scopes.cpp:77:8:77:8 | H | | | scopes.cpp:77:8:77:8 | H | Class | scopes.cpp:77:8:77:8 | operator= | | | scopes.cpp:77:8:77:8 | H | Class | scopes.cpp:77:8:77:8 | operator= | | | scopes.cpp:77:8:77:8 | H | Class | scopes.cpp:79:5:79:5 | t | | diff --git a/cpp/ql/test/library-tests/scopes/scopes/Scopes3.expected b/cpp/ql/test/library-tests/scopes/scopes/Scopes3.expected index af73b99dff8d..94f46c73f754 100644 --- a/cpp/ql/test/library-tests/scopes/scopes/Scopes3.expected +++ b/cpp/ql/test/library-tests/scopes/scopes/Scopes3.expected @@ -4,32 +4,38 @@ | scopes.cpp:2:7:2:7 | operator= | | scopes.cpp:2:7:2:7 | A | 2 | | scopes.cpp:7:7:7:7 | operator= | | scopes.cpp:7:7:7:7 | B | 2 | | scopes.cpp:7:7:7:7 | operator= | | scopes.cpp:7:7:7:7 | B | 2 | -| scopes.cpp:11:7:11:7 | operator= | | scopes.cpp:11:7:11:7 | C | 2 | -| scopes.cpp:11:7:11:7 | operator= | | scopes.cpp:11:7:11:7 | C | 2 | -| scopes.cpp:15:7:15:7 | operator= | | scopes.cpp:15:7:15:7 | D | 3 | -| scopes.cpp:15:7:15:7 | operator= | | scopes.cpp:15:7:15:7 | D | 3 | +| scopes.cpp:11:7:11:7 | C | Constructor | scopes.cpp:11:7:11:7 | C | 3 | +| scopes.cpp:11:7:11:7 | operator= | | scopes.cpp:11:7:11:7 | C | 3 | +| scopes.cpp:11:7:11:7 | operator= | | scopes.cpp:11:7:11:7 | C | 3 | +| scopes.cpp:15:7:15:7 | D | Constructor | scopes.cpp:15:7:15:7 | D | 4 | +| scopes.cpp:15:7:15:7 | operator= | | scopes.cpp:15:7:15:7 | D | 4 | +| scopes.cpp:15:7:15:7 | operator= | | scopes.cpp:15:7:15:7 | D | 4 | | scopes.cpp:21:10:21:10 | operator= | | scopes.cpp:21:7:21:10 | E | 4 | | scopes.cpp:21:10:21:10 | operator= | | scopes.cpp:21:7:21:10 | E | 4 | | scopes.cpp:25:8:25:8 | operator= | | scopes.cpp:25:8:25:8 | G | 2 | | scopes.cpp:25:8:25:8 | operator= | | scopes.cpp:25:8:25:8 | G | 2 | -| scopes.cpp:31:13:31:13 | operator= | | scopes.cpp:31:7:31:13 | F | 3 | -| scopes.cpp:31:13:31:13 | operator= | | scopes.cpp:31:7:31:13 | F | 3 | -| scopes.cpp:32:8:32:27 | doubleNestedFunction | | scopes.cpp:31:7:31:13 | F | 3 | +| scopes.cpp:31:13:31:13 | F | Constructor | scopes.cpp:31:7:31:13 | F | 4 | +| scopes.cpp:31:13:31:13 | operator= | | scopes.cpp:31:7:31:13 | F | 4 | +| scopes.cpp:31:13:31:13 | operator= | | scopes.cpp:31:7:31:13 | F | 4 | +| scopes.cpp:32:8:32:27 | doubleNestedFunction | | scopes.cpp:31:7:31:13 | F | 4 | | scopes.cpp:46:8:46:8 | operator= | | scopes.cpp:46:8:46:8 | S | 4 | | scopes.cpp:46:8:46:8 | operator= | | scopes.cpp:46:8:46:8 | S | 4 | | scopes.cpp:47:7:47:8 | af | | scopes.cpp:46:8:46:8 | S | 4 | | scopes.cpp:50:7:50:8 | ag | | scopes.cpp:46:8:46:8 | S | 4 | -| scopes.cpp:58:7:58:7 | operator= | | scopes.cpp:58:7:58:10 | Name | 3 | -| scopes.cpp:58:7:58:7 | operator= | | scopes.cpp:58:7:58:10 | Name | 3 | +| scopes.cpp:58:7:58:7 | Name | Constructor | scopes.cpp:58:7:58:10 | Name | 4 | +| scopes.cpp:58:7:58:7 | operator= | | scopes.cpp:58:7:58:10 | Name | 4 | +| scopes.cpp:58:7:58:7 | operator= | | scopes.cpp:58:7:58:10 | Name | 4 | | scopes.cpp:62:7:62:7 | Table | Constructor | scopes.cpp:62:7:62:11 | Table | 8 | | scopes.cpp:62:7:62:7 | operator= | | scopes.cpp:62:7:62:11 | Table | 8 | | scopes.cpp:66:3:66:7 | Table | Constructor | scopes.cpp:62:7:62:11 | Table | 8 | | scopes.cpp:67:3:67:8 | ~Table | | scopes.cpp:62:7:62:11 | Table | 8 | | scopes.cpp:68:9:68:14 | lookup | | scopes.cpp:62:7:62:11 | Table | 8 | | scopes.cpp:69:8:69:13 | insert | | scopes.cpp:62:7:62:11 | Table | 8 | -| scopes.cpp:77:8:77:8 | operator= | | scopes.cpp:77:8:77:8 | H | 3 | -| scopes.cpp:77:8:77:8 | operator= | | scopes.cpp:77:8:77:8 | H | 3 | -| scopes.cpp:77:8:77:8 | operator= | | scopes.cpp:77:8:77:8 | H | 3 | -| scopes.cpp:77:8:77:8 | operator= | | scopes.cpp:77:8:77:8 | H | 3 | +| scopes.cpp:77:8:77:8 | H | Constructor | scopes.cpp:77:8:77:8 | H | 4 | +| scopes.cpp:77:8:77:8 | H | Constructor | scopes.cpp:77:8:77:8 | H | 4 | +| scopes.cpp:77:8:77:8 | operator= | | scopes.cpp:77:8:77:8 | H | 4 | +| scopes.cpp:77:8:77:8 | operator= | | scopes.cpp:77:8:77:8 | H | 4 | +| scopes.cpp:77:8:77:8 | operator= | | scopes.cpp:77:8:77:8 | H | 4 | +| scopes.cpp:77:8:77:8 | operator= | | scopes.cpp:77:8:77:8 | H | 4 | | scopes.cpp:95:8:95:8 | operator= | | scopes.cpp:95:8:95:8 | I | 3 | | scopes.cpp:95:8:95:8 | operator= | | scopes.cpp:95:8:95:8 | I | 3 | diff --git a/cpp/ql/test/library-tests/scopes/scopes/Scopes4.expected b/cpp/ql/test/library-tests/scopes/scopes/Scopes4.expected index 5a4c8bcf4af7..fda8ff9a7d8d 100644 --- a/cpp/ql/test/library-tests/scopes/scopes/Scopes4.expected +++ b/cpp/ql/test/library-tests/scopes/scopes/Scopes4.expected @@ -6,14 +6,17 @@ | scopes.cpp:2:7:2:7 | operator= | | 1 | 1 | | scopes.cpp:7:7:7:7 | operator= | | 1 | 1 | | scopes.cpp:7:7:7:7 | operator= | | 1 | 1 | +| scopes.cpp:11:7:11:7 | C | | 1 | 1 | | scopes.cpp:11:7:11:7 | operator= | | 1 | 1 | | scopes.cpp:11:7:11:7 | operator= | | 1 | 1 | +| scopes.cpp:15:7:15:7 | D | | 1 | 1 | | scopes.cpp:15:7:15:7 | operator= | | 1 | 1 | | scopes.cpp:15:7:15:7 | operator= | | 1 | 1 | | scopes.cpp:21:10:21:10 | operator= | | 1 | 1 | | scopes.cpp:21:10:21:10 | operator= | | 1 | 1 | | scopes.cpp:25:8:25:8 | operator= | | 1 | 1 | | scopes.cpp:25:8:25:8 | operator= | | 1 | 1 | +| scopes.cpp:31:13:31:13 | F | | 1 | 1 | | scopes.cpp:31:13:31:13 | operator= | | 1 | 1 | | scopes.cpp:31:13:31:13 | operator= | | 1 | 1 | | scopes.cpp:32:8:32:27 | doubleNestedFunction | | 1 | 1 | @@ -23,6 +26,7 @@ | scopes.cpp:47:7:47:8 | af | | 1 | 1 | | scopes.cpp:50:7:50:8 | ag | | 1 | 1 | | scopes.cpp:53:6:53:6 | g | isTopLevel() | 1 | 1 | +| scopes.cpp:58:7:58:7 | Name | | 1 | 1 | | scopes.cpp:58:7:58:7 | operator= | | 1 | 1 | | scopes.cpp:58:7:58:7 | operator= | | 1 | 1 | | scopes.cpp:62:7:62:7 | Table | | 1 | 1 | @@ -32,6 +36,8 @@ | scopes.cpp:68:9:68:14 | lookup | | 1 | 1 | | scopes.cpp:69:8:69:13 | insert | | 1 | 1 | | scopes.cpp:72:16:72:21 | strlen | isTopLevel() | 1 | 1 | +| scopes.cpp:77:8:77:8 | H | | 1 | 0 | +| scopes.cpp:77:8:77:8 | H | | 1 | 0 | | scopes.cpp:77:8:77:8 | operator= | | 1 | 0 | | scopes.cpp:77:8:77:8 | operator= | | 1 | 0 | | scopes.cpp:77:8:77:8 | operator= | | 1 | 0 | diff --git a/cpp/ql/test/library-tests/security/encryption/test.cpp b/cpp/ql/test/library-tests/security/encryption/test.cpp new file mode 100644 index 000000000000..0e4f8292eb5c --- /dev/null +++ b/cpp/ql/test/library-tests/security/encryption/test.cpp @@ -0,0 +1,12 @@ + +void des_function(); // insecure +void function_using_des(); // insecure +void EncryptWithDES(); // insecure + +void aes_function(); // secure +void function_using_aes(); // secure +void EncryptionWithAES(); // secure + +void abc_function(); +void function_using_abc(); +void EncryptionWithABC(); diff --git a/cpp/ql/test/library-tests/security/encryption/test.expected b/cpp/ql/test/library-tests/security/encryption/test.expected new file mode 100644 index 000000000000..a497544d029f --- /dev/null +++ b/cpp/ql/test/library-tests/security/encryption/test.expected @@ -0,0 +1,9 @@ +| test.cpp:2:6:2:17 | des_function | getInsecureAlgorithmRegex | +| test.cpp:3:6:3:23 | function_using_des | getInsecureAlgorithmRegex | +| test.cpp:4:6:4:19 | EncryptWithDES | getInsecureAlgorithmRegex | +| test.cpp:6:6:6:17 | aes_function | getSecureAlgorithmRegex | +| test.cpp:7:6:7:23 | function_using_aes | getSecureAlgorithmRegex | +| test.cpp:8:6:8:22 | EncryptionWithAES | getSecureAlgorithmRegex | +| test.cpp:10:6:10:17 | abc_function | | +| test.cpp:11:6:11:23 | function_using_abc | | +| test.cpp:12:6:12:22 | EncryptionWithABC | | diff --git a/cpp/ql/test/library-tests/security/encryption/test.ql b/cpp/ql/test/library-tests/security/encryption/test.ql new file mode 100644 index 000000000000..6539611aa3a2 --- /dev/null +++ b/cpp/ql/test/library-tests/security/encryption/test.ql @@ -0,0 +1,14 @@ +import default +import semmle.code.cpp.security.Encryption + +string describe(Function f) { + f.getName().regexpMatch(getSecureAlgorithmRegex()) and + result = "getSecureAlgorithmRegex" + or + f.getName().regexpMatch(getInsecureAlgorithmRegex()) and + result = "getInsecureAlgorithmRegex" +} + +from Function f +where exists(f.getLocation().getFile()) +select f, concat(describe(f), ", ") diff --git a/cpp/ql/test/library-tests/sideEffects/functions/sideEffects.expected b/cpp/ql/test/library-tests/sideEffects/functions/sideEffects.expected index 264bb16db99b..d2b316e22119 100644 --- a/cpp/ql/test/library-tests/sideEffects/functions/sideEffects.expected +++ b/cpp/ql/test/library-tests/sideEffects/functions/sideEffects.expected @@ -25,12 +25,16 @@ | cpp.cpp:30:5:30:7 | Bar | int -> int -> int -> int -> void | true | | cpp.cpp:31:5:31:7 | Bar | int -> int -> int -> int -> int -> void | false | | cpp.cpp:32:5:32:7 | Bar | int -> int -> int -> int -> int -> int -> void | false | +| cpp.cpp:35:7:35:7 | PurelyDestructible | void | false | | cpp.cpp:35:7:35:7 | operator= | const PurelyDestructible & -> PurelyDestructible & | false | | cpp.cpp:37:5:37:23 | ~PurelyDestructible | void | true | +| cpp.cpp:40:7:40:7 | ImpurelyDestructible | void | false | | cpp.cpp:40:7:40:7 | operator= | const ImpurelyDestructible & -> ImpurelyDestructible & | false | | cpp.cpp:42:5:42:25 | ~ImpurelyDestructible | void | false | +| cpp.cpp:45:7:45:7 | SuperPurelyDestructible | void | false | | cpp.cpp:45:7:45:7 | operator= | const SuperPurelyDestructible & -> SuperPurelyDestructible & | false | | cpp.cpp:47:5:47:28 | ~SuperPurelyDestructible | void | true | +| cpp.cpp:50:7:50:7 | SuperImpurelyDestructible | void | false | | cpp.cpp:50:7:50:7 | operator= | const SuperImpurelyDestructible & -> SuperImpurelyDestructible & | false | | cpp.cpp:52:5:52:30 | ~SuperImpurelyDestructible | void | false | | cpp.cpp:55:7:55:7 | operator= | const someClass & -> someClass & | false | diff --git a/cpp/ql/test/library-tests/special_members/generated_copy/functions.expected b/cpp/ql/test/library-tests/special_members/generated_copy/functions.expected index bb28af216711..22282641b373 100644 --- a/cpp/ql/test/library-tests/special_members/generated_copy/functions.expected +++ b/cpp/ql/test/library-tests/special_members/generated_copy/functions.expected @@ -24,6 +24,7 @@ | copy.cpp:38:8:38:16 | operator= | | defaulted | | copy.cpp:41:9:41:9 | operator= | | | | copy.cpp:46:5:46:7 | Sub | deleted | defaulted | +| copy.cpp:49:9:49:9 | HasPointer | | | | copy.cpp:49:9:49:9 | operator= | | | | copy.cpp:49:9:49:9 | operator= | | | | copy.cpp:54:9:54:9 | HasArray | deleted | | @@ -35,6 +36,7 @@ | copy.cpp:59:9:59:9 | operator= | | | | copy.cpp:59:9:59:9 | operator= | | | | copy.cpp:67:9:67:9 | Wrapper | | | +| copy.cpp:67:9:67:9 | Wrapper | | | | copy.cpp:67:9:67:9 | Wrapper | deleted | | | copy.cpp:67:9:67:9 | Wrapper | deleted | | | copy.cpp:67:9:67:9 | operator= | | | @@ -46,12 +48,14 @@ | copy.cpp:72:9:72:9 | NotCopyable | deleted | | | copy.cpp:72:9:72:9 | NotCopyable | deleted | | | copy.cpp:72:9:72:9 | operator= | deleted | | +| copy.cpp:76:9:76:9 | CopyableComposition | | | | copy.cpp:76:9:76:9 | operator= | | | | copy.cpp:76:9:76:9 | operator= | | | | copy.cpp:80:9:80:9 | NotCopyableComposition | | | | copy.cpp:80:9:80:9 | NotCopyableComposition | deleted | | | copy.cpp:80:9:80:9 | NotCopyableComposition | deleted | | | copy.cpp:80:9:80:9 | operator= | deleted | | +| copy.cpp:84:9:84:9 | CopyableInheritance | | | | copy.cpp:84:9:84:9 | operator= | | | | copy.cpp:84:9:84:9 | operator= | | | | copy.cpp:86:9:86:9 | NotCopyableInheritance | | | @@ -64,16 +68,16 @@ | copy.cpp:91:11:91:11 | operator= | | | | copy.cpp:95:9:95:9 | operator= | | | | copy.cpp:95:9:95:9 | operator= | | | +| copy.cpp:100:9:100:9 | Derived | | | | copy.cpp:100:9:100:9 | operator= | | | | copy.cpp:100:9:100:9 | operator= | | | | copy.cpp:106:9:106:9 | MoveCtor | deleted | | | copy.cpp:106:9:106:9 | operator= | deleted | | | copy.cpp:108:5:108:12 | MoveCtor | | | +| copy.cpp:111:9:111:9 | MoveAssign | | | | copy.cpp:111:9:111:9 | MoveAssign | deleted | | | copy.cpp:111:9:111:9 | operator= | deleted | | | copy.cpp:113:17:113:25 | operator= | | | -| copy.cpp:120:9:120:9 | OnlyCtor | | | -| copy.cpp:120:9:120:9 | OnlyCtor | | | | copy.cpp:120:9:120:9 | OnlyCtor | deleted | | | copy.cpp:120:9:120:9 | operator= | deleted | | | copy.cpp:126:11:126:19 | operator= | | | diff --git a/cpp/ql/test/library-tests/specifiers2/cpp20.cpp b/cpp/ql/test/library-tests/specifiers2/cpp20.cpp new file mode 100644 index 000000000000..d260eaecf813 --- /dev/null +++ b/cpp/ql/test/library-tests/specifiers2/cpp20.cpp @@ -0,0 +1,10 @@ +// semmle-extractor-options: --edg --clang --edg --c++20 + +namespace cpp20 { + +class TestConstexpr { + constexpr int member_constexpr() { return 0; } // not const in C++ >= 14 + constexpr int member_const_constexpr() const { return 0; } +}; + +} // namespace cpp20 diff --git a/cpp/ql/test/library-tests/specifiers2/specifiers2.expected b/cpp/ql/test/library-tests/specifiers2/specifiers2.expected index 26c72b4e3196..2ccfc7b84a02 100644 --- a/cpp/ql/test/library-tests/specifiers2/specifiers2.expected +++ b/cpp/ql/test/library-tests/specifiers2/specifiers2.expected @@ -1,5 +1,22 @@ | Class | specifiers2pp.cpp:8:7:8:13 | MyClass | MyClass | abstract | | Class | specifiers2pp.cpp:24:7:24:14 | MyClass2 | MyClass2 | abstract | +| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | extern | +| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | extern | +| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | inline | +| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | inline | +| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | is_constexpr | +| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | is_constexpr | +| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | public | +| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | public | +| Function | cpp20.cpp:6:19:6:34 | member_constexpr | member_constexpr | declared_constexpr | +| Function | cpp20.cpp:6:19:6:34 | member_constexpr | member_constexpr | inline | +| Function | cpp20.cpp:6:19:6:34 | member_constexpr | member_constexpr | is_constexpr | +| Function | cpp20.cpp:6:19:6:34 | member_constexpr | member_constexpr | private | +| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | const | +| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | declared_constexpr | +| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | inline | +| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | is_constexpr | +| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | private | | Function | specifiers2.c:11:6:11:6 | f | f | extern | | Function | specifiers2.c:12:13:12:13 | f | f | extern | | Function | specifiers2.c:13:13:13:13 | f | f | extern | @@ -62,6 +79,8 @@ | Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | extern | | Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | inline | | Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | inline | +| Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | is_constexpr | +| Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | is_constexpr | | Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | public | | Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | public | | Function | specifiers2pp.cpp:33:5:33:18 | fun | fun | public | @@ -69,12 +88,32 @@ | Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | extern | | Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | inline | | Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | inline | +| Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | is_constexpr | +| Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | is_constexpr | | Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | public | | Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | public | | Function | specifiers2pp.cpp:40:12:40:18 | someFun | someFun | extern | | Function | specifiers2pp.cpp:41:16:41:23 | someFun2 | someFun2 | extern | | Function | specifiers2pp.cpp:43:9:43:16 | someFun3 | someFun3 | extern | | Function | specifiers2pp.cpp:44:16:44:23 | someFun4 | someFun4 | static | +| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | extern | +| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | extern | +| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | inline | +| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | inline | +| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | is_constexpr | +| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | is_constexpr | +| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | public | +| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | public | +| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | const | +| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | declared_constexpr | +| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | inline | +| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | is_constexpr | +| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | private | +| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | const | +| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | declared_constexpr | +| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | inline | +| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | is_constexpr | +| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | private | | FunctionDeclarationEntry | specifiers2.c:11:6:11:6 | declaration of f | f | c_linkage | | FunctionDeclarationEntry | specifiers2.c:11:6:11:6 | declaration of f | f | void_param_list | | FunctionDeclarationEntry | specifiers2.c:12:13:12:13 | declaration of f | f | c_linkage | diff --git a/cpp/ql/test/library-tests/specifiers2/specifiers2pp.cpp b/cpp/ql/test/library-tests/specifiers2/specifiers2pp.cpp index 7bceb782ecaf..37d5e894c889 100644 --- a/cpp/ql/test/library-tests/specifiers2/specifiers2pp.cpp +++ b/cpp/ql/test/library-tests/specifiers2/specifiers2pp.cpp @@ -58,3 +58,8 @@ template using Const = const T; using Const_int = Const; typedef volatile Const_int volatile_Const_int; + +class TestConstexpr { + constexpr int member_constexpr() { return 0; } // const in C++11 + constexpr int member_const_constexpr() const { return 0; } +}; diff --git a/cpp/ql/test/library-tests/structs/compatible_cpp/compatible.expected b/cpp/ql/test/library-tests/structs/compatible_cpp/compatible.expected index e33f5f851cd9..14648db75c59 100644 --- a/cpp/ql/test/library-tests/structs/compatible_cpp/compatible.expected +++ b/cpp/ql/test/library-tests/structs/compatible_cpp/compatible.expected @@ -18,37 +18,46 @@ | a2.cpp:10:8:10:10 | Bar | 5 members | 2 locations | 2 | i | | a2.cpp:10:8:10:10 | Bar | 5 members | 2 locations | 3 | operator= | | a2.cpp:10:8:10:10 | Bar | 5 members | 2 locations | 4 | operator= | -| b1.cpp:6:7:6:21 | AppleCompatible | 3 members | 2 locations | 0 | apple_x | -| b1.cpp:6:7:6:21 | AppleCompatible | 3 members | 2 locations | 1 | operator= | -| b1.cpp:6:7:6:21 | AppleCompatible | 3 members | 2 locations | 2 | operator= | -| b1.cpp:11:7:11:22 | BananaCompatible | 3 members | 2 locations | 0 | banana_x | -| b1.cpp:11:7:11:22 | BananaCompatible | 3 members | 2 locations | 1 | operator= | -| b1.cpp:11:7:11:22 | BananaCompatible | 3 members | 2 locations | 2 | operator= | -| b1.cpp:16:7:16:12 | Cherry | 3 members | 1 locations | 0 | cherry_x | -| b1.cpp:16:7:16:12 | Cherry | 3 members | 1 locations | 1 | operator= | -| b1.cpp:16:7:16:12 | Cherry | 3 members | 1 locations | 2 | operator= | -| b1.cpp:23:7:23:12 | Damson | 5 members | 2 locations | 0 | damson_x | -| b1.cpp:23:7:23:12 | Damson | 5 members | 2 locations | 1 | bar | -| b1.cpp:23:7:23:12 | Damson | 5 members | 2 locations | 1 | foo | -| b1.cpp:23:7:23:12 | Damson | 5 members | 2 locations | 2 | operator= | -| b1.cpp:23:7:23:12 | Damson | 5 members | 2 locations | 3 | operator= | -| b1.cpp:29:9:29:23 | AppleCompatible | 3 members | 1 locations | 0 | apple_x | -| b1.cpp:29:9:29:23 | AppleCompatible | 3 members | 1 locations | 1 | operator= | -| b1.cpp:29:9:29:23 | AppleCompatible | 3 members | 1 locations | 2 | operator= | -| b2.cpp:2:7:2:21 | AppleCompatible | 3 members | 2 locations | 0 | apple_x | -| b2.cpp:2:7:2:21 | AppleCompatible | 3 members | 2 locations | 1 | operator= | -| b2.cpp:2:7:2:21 | AppleCompatible | 3 members | 2 locations | 2 | operator= | -| b2.cpp:9:7:9:22 | BananaCompatible | 3 members | 2 locations | 0 | banana_x | -| b2.cpp:9:7:9:22 | BananaCompatible | 3 members | 2 locations | 1 | operator= | -| b2.cpp:9:7:9:22 | BananaCompatible | 3 members | 2 locations | 2 | operator= | -| b2.cpp:14:7:14:12 | Cherry | 3 members | 1 locations | 0 | cherry_x | -| b2.cpp:14:7:14:12 | Cherry | 3 members | 1 locations | 1 | operator= | -| b2.cpp:14:7:14:12 | Cherry | 3 members | 1 locations | 2 | operator= | -| b2.cpp:21:7:21:12 | Damson | 5 members | 2 locations | 0 | damson_x | -| b2.cpp:21:7:21:12 | Damson | 5 members | 2 locations | 1 | bar | -| b2.cpp:21:7:21:12 | Damson | 5 members | 2 locations | 1 | foo | -| b2.cpp:21:7:21:12 | Damson | 5 members | 2 locations | 2 | operator= | -| b2.cpp:21:7:21:12 | Damson | 5 members | 2 locations | 3 | operator= | +| b1.cpp:6:7:6:21 | AppleCompatible | 4 members | 2 locations | 0 | apple_x | +| b1.cpp:6:7:6:21 | AppleCompatible | 4 members | 2 locations | 1 | operator= | +| b1.cpp:6:7:6:21 | AppleCompatible | 4 members | 2 locations | 2 | operator= | +| b1.cpp:6:7:6:21 | AppleCompatible | 4 members | 2 locations | 3 | AppleCompatible | +| b1.cpp:11:7:11:22 | BananaCompatible | 4 members | 2 locations | 0 | banana_x | +| b1.cpp:11:7:11:22 | BananaCompatible | 4 members | 2 locations | 1 | operator= | +| b1.cpp:11:7:11:22 | BananaCompatible | 4 members | 2 locations | 2 | operator= | +| b1.cpp:11:7:11:22 | BananaCompatible | 4 members | 2 locations | 3 | BananaCompatible | +| b1.cpp:16:7:16:12 | Cherry | 4 members | 1 locations | 0 | cherry_x | +| b1.cpp:16:7:16:12 | Cherry | 4 members | 1 locations | 1 | operator= | +| b1.cpp:16:7:16:12 | Cherry | 4 members | 1 locations | 2 | operator= | +| b1.cpp:16:7:16:12 | Cherry | 4 members | 1 locations | 3 | Cherry | +| b1.cpp:23:7:23:12 | Damson | 6 members | 2 locations | 0 | damson_x | +| b1.cpp:23:7:23:12 | Damson | 6 members | 2 locations | 1 | bar | +| b1.cpp:23:7:23:12 | Damson | 6 members | 2 locations | 1 | foo | +| b1.cpp:23:7:23:12 | Damson | 6 members | 2 locations | 2 | operator= | +| b1.cpp:23:7:23:12 | Damson | 6 members | 2 locations | 3 | operator= | +| b1.cpp:23:7:23:12 | Damson | 6 members | 2 locations | 4 | Damson | +| b1.cpp:29:9:29:23 | AppleCompatible | 4 members | 1 locations | 0 | apple_x | +| b1.cpp:29:9:29:23 | AppleCompatible | 4 members | 1 locations | 1 | operator= | +| b1.cpp:29:9:29:23 | AppleCompatible | 4 members | 1 locations | 2 | operator= | +| b1.cpp:29:9:29:23 | AppleCompatible | 4 members | 1 locations | 3 | AppleCompatible | +| b2.cpp:2:7:2:21 | AppleCompatible | 4 members | 2 locations | 0 | apple_x | +| b2.cpp:2:7:2:21 | AppleCompatible | 4 members | 2 locations | 1 | operator= | +| b2.cpp:2:7:2:21 | AppleCompatible | 4 members | 2 locations | 2 | operator= | +| b2.cpp:2:7:2:21 | AppleCompatible | 4 members | 2 locations | 3 | AppleCompatible | +| b2.cpp:9:7:9:22 | BananaCompatible | 4 members | 2 locations | 0 | banana_x | +| b2.cpp:9:7:9:22 | BananaCompatible | 4 members | 2 locations | 1 | operator= | +| b2.cpp:9:7:9:22 | BananaCompatible | 4 members | 2 locations | 2 | operator= | +| b2.cpp:9:7:9:22 | BananaCompatible | 4 members | 2 locations | 3 | BananaCompatible | +| b2.cpp:14:7:14:12 | Cherry | 4 members | 1 locations | 0 | cherry_x | +| b2.cpp:14:7:14:12 | Cherry | 4 members | 1 locations | 1 | operator= | +| b2.cpp:14:7:14:12 | Cherry | 4 members | 1 locations | 2 | operator= | +| b2.cpp:14:7:14:12 | Cherry | 4 members | 1 locations | 3 | Cherry | +| b2.cpp:21:7:21:12 | Damson | 6 members | 2 locations | 0 | damson_x | +| b2.cpp:21:7:21:12 | Damson | 6 members | 2 locations | 1 | bar | +| b2.cpp:21:7:21:12 | Damson | 6 members | 2 locations | 1 | foo | +| b2.cpp:21:7:21:12 | Damson | 6 members | 2 locations | 2 | operator= | +| b2.cpp:21:7:21:12 | Damson | 6 members | 2 locations | 3 | operator= | +| b2.cpp:21:7:21:12 | Damson | 6 members | 2 locations | 4 | Damson | | file://:0:0:0:0 | __va_list_tag | 6 members | 0 locations | 0 | gp_offset | | file://:0:0:0:0 | __va_list_tag | 6 members | 0 locations | 1 | fp_offset | | file://:0:0:0:0 | __va_list_tag | 6 members | 0 locations | 2 | overflow_arg_area | diff --git a/cpp/ql/test/library-tests/structs/incomplete_definition/pointerbasetype.expected b/cpp/ql/test/library-tests/structs/incomplete_definition/pointerbasetype.expected index 801306a572ab..29af417fe988 100644 --- a/cpp/ql/test/library-tests/structs/incomplete_definition/pointerbasetype.expected +++ b/cpp/ql/test/library-tests/structs/incomplete_definition/pointerbasetype.expected @@ -2,5 +2,5 @@ | x.cpp:3:6:3:10 | bar_x | a.h:4:8:4:10 | Bar | 3 | | x.cpp:19:6:19:10 | foo_x | y.cpp:4:8:4:10 | Foo | 3 | | x.cpp:23:5:23:17 | templateField | x.cpp:6:10:6:12 | Foo | 3 | -| x.cpp:23:5:23:17 | templateField | x.cpp:12:9:12:11 | Foo | 3 | +| x.cpp:23:5:23:17 | templateField | x.cpp:12:9:12:11 | Foo | 4 | | x.cpp:26:18:26:29 | template_foo | x.cpp:22:7:22:14 | Template | 0 | diff --git a/cpp/ql/test/library-tests/switch/blocks.ql b/cpp/ql/test/library-tests/switch/blocks.ql index 794c597d9a90..0c97f65ec3d8 100644 --- a/cpp/ql/test/library-tests/switch/blocks.ql +++ b/cpp/ql/test/library-tests/switch/blocks.ql @@ -1,5 +1,5 @@ import cpp -from Function f, Block b +from Function f, BlockStmt b where b = f.getEntryPoint() select f, b, b.getAStmt() diff --git a/cpp/ql/test/library-tests/syntax-zoo/Compare.qll b/cpp/ql/test/library-tests/syntax-zoo/Compare.qll deleted file mode 100644 index 536dd9f7108a..000000000000 --- a/cpp/ql/test/library-tests/syntax-zoo/Compare.qll +++ /dev/null @@ -1,148 +0,0 @@ -import cpp -import semmle.code.cpp.controlflow.internal.CFG - -class DestructorCallEnhanced extends DestructorCall { - override string toString() { - if exists(this.getQualifier().(VariableAccess).getTarget().getName()) - then - result = - "call to " + this.getQualifier().(VariableAccess).getTarget().getName() + "." + - this.getTarget().getName() - else result = super.toString() - } -} - -predicate differentEdge(ControlFlowNode n1, ControlFlowNode n2, string msg) { - successors(n1, n2) and - not qlCFGSuccessor(n1, n2) and - msg = "Standard edge, only from extractor" - or - not successors(n1, n2) and - qlCFGSuccessor(n1, n2) and - msg = "Standard edge, only from QL" - or - truecond_base(n1, n2) and - not qlCFGTrueSuccessor(n1, n2) and - msg = "True edge, only from extractor" - or - not truecond_base(n1, n2) and - qlCFGTrueSuccessor(n1, n2) and - msg = "True edge, only from QL" - or - falsecond_base(n1, n2) and - not qlCFGFalseSuccessor(n1, n2) and - msg = "False edge, only from extractor" - or - not falsecond_base(n1, n2) and - qlCFGFalseSuccessor(n1, n2) and - msg = "False edge, only from QL" -} - -predicate differentScope(Element e) { - exists(ControlFlowNode n1 | - getScopeElement(n1) = e and - differentEdge(n1, _, _) - ) -} - -private predicate isInFunction(ControlFlowNode x, Function f) { - f = x.getControlFlowScope() - or - exists(ControlFlowNode y | - successors(unresolveElement(x), unresolveElement(y)) - or - successors(unresolveElement(y), unresolveElement(x)) - | - isInFunction(y, f) - ) -} - -Element getScopeElement(ControlFlowNode x) { - isInFunction(x, result) - or - not isInFunction(x, _) and - result = x.getFile() -} - -string getScopeName(ControlFlowNode x) { - exists(Function scope | scope = getScopeElement(x) | - differentScope(scope) and - result = - scope.getFile().getBaseName().splitAt(".", 0) + "__" + - scope.getQualifiedName().replaceAll("::", "_") - ) - or - exists(File scope | scope = getScopeElement(x) | - differentScope(scope) and - result = scope.getBaseName() - ) -} - -module QLCFG { - private predicate isNode(boolean isEdge, ControlFlowNode x, ControlFlowNode y, string label) { - isEdge = false and x = y and label = x.toString() - } - - private predicate isSuccessor(boolean isEdge, ControlFlowNode x, ControlFlowNode y, string label) { - exists(string truelabel, string falselabel | - isEdge = true and - qlCFGSuccessor(x, y) and - (if qlCFGTrueSuccessor(x, y) then truelabel = "T" else truelabel = "") and - (if qlCFGFalseSuccessor(x, y) then falselabel = "F" else falselabel = "") and - label = truelabel + falselabel - ) - } - - predicate qltestGraph( - Element scopeElement, string scopeString, boolean isEdge, ControlFlowNode x, ControlFlowNode y, - string label - ) { - scopeElement = getScopeElement(x) and - scopeString = getScopeName(x) + "_ql" and - ( - isNode(isEdge, x, y, label) - or - isSuccessor(isEdge, x, y, label) - ) - } -} - -module ExtractorCFG { - predicate isNode(boolean isEdge, ControlFlowNode x, ControlFlowNode y, string label) { - isEdge = false and x = y and label = x.toString() - } - - predicate isSuccessor(boolean isEdge, ControlFlowNode x, ControlFlowNode y, string label) { - exists(string truelabel, string falselabel | - isEdge = true and - successors(x, y) and - (if truecond_base(x, y) then truelabel = "T" else truelabel = "") and - (if falsecond_base(x, y) then falselabel = "F" else falselabel = "") and - label = truelabel + falselabel - ) - } - - predicate qltestGraph( - Element scopeElement, string scopeString, boolean isEdge, ControlFlowNode x, ControlFlowNode y, - string label - ) { - scopeElement = getScopeElement(x) and - scopeString = getScopeName(x) + "_extractor" and - ( - isNode(isEdge, x, y, label) - or - isSuccessor(isEdge, x, y, label) - ) - } -} - -module AllCFG { - predicate qltestGraph( - Element scopeElement, string scopeString, boolean isEdge, ControlFlowNode x, ControlFlowNode y, - string label - ) { - QLCFG::qltestGraph(scopeElement, scopeString, isEdge, x, y, label) - or - ExtractorCFG::qltestGraph(scopeElement, scopeString, isEdge, x, y, label) - } -} diff --git a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_consistency.expected index 4d951d3f1d0c..389b3a9496d3 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_consistency.expected @@ -1,32 +1,24 @@ missingOperand -| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| cpp11.cpp:77:19:77:21 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:76:8:76:8 | IR: apply | void lambda::apply<(void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | -| cpp11.cpp:82:11:82:14 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | IR: apply2 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | -| cpp11.cpp:82:45:82:48 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | -| cpp11.cpp:82:51:82:51 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | -| cpp11.cpp:88:25:88:30 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | -| cpp11.cpp:88:33:88:38 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | -| destructors.cpp:51:36:51:38 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | IR: f | int cond_destruct::f(int) | -| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | IR: misc3 | void misc3() | +| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| cpp11.cpp:77:19:77:21 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:76:8:76:8 | void lambda::apply<(void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | void lambda::apply<(void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | +| cpp11.cpp:82:11:82:14 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | +| cpp11.cpp:82:45:82:48 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:82:51:82:51 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:88:25:88:30 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | void lambda::main() | void lambda::main() | +| cpp11.cpp:88:33:88:38 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | void lambda::main() | void lambda::main() | +| destructors.cpp:51:36:51:38 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | int cond_destruct::f(int) | int cond_destruct::f(int) | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | void misc3() | void misc3() | unexpectedOperand duplicateOperand missingPhiOperand @@ -34,475 +26,79 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| VacuousDestructorCall.cpp:2:29:2:29 | InitializeIndirection: y | -| condition_decls.cpp:16:19:16:20 | Chi: call to BoxedInt | -| condition_decls.cpp:26:23:26:24 | Chi: call to BoxedInt | -| condition_decls.cpp:41:22:41:23 | Chi: call to BoxedInt | -| condition_decls.cpp:48:52:48:53 | Chi: call to BoxedInt | -| misc.c:171:10:171:13 | Uninitialized: definition of str2 | -| misc.c:219:47:219:48 | InitializeIndirection: sp | -| ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | -| ms_try_mix.cpp:11:12:11:15 | Chi: call to C | -| ms_try_mix.cpp:28:12:28:15 | Chi: call to C | -| ms_try_mix.cpp:48:10:48:13 | Chi: call to C | -| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | -| vla.c:5:9:5:14 | Uninitialized: definition of matrix | -| vla.c:11:6:11:16 | Chi: vla_typedef | +| VacuousDestructorCall.cpp:2:29:2:29 | InitializeIndirection: y | Instruction 'InitializeIndirection: y' has no successors in function '$@'. | VacuousDestructorCall.cpp:2:6:2:6 | void CallDestructor(int, int*) | void CallDestructor(int, int*) | +| condition_decls.cpp:16:19:16:20 | Chi: call to BoxedInt | Instruction 'Chi: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:15:6:15:17 | void if_decl_bind(int) | void if_decl_bind(int) | +| condition_decls.cpp:26:23:26:24 | Chi: call to BoxedInt | Instruction 'Chi: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:25:6:25:21 | void switch_decl_bind(int) | void switch_decl_bind(int) | +| condition_decls.cpp:41:22:41:23 | Chi: call to BoxedInt | Instruction 'Chi: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:40:6:40:20 | void while_decl_bind(int) | void while_decl_bind(int) | +| condition_decls.cpp:48:52:48:53 | Chi: call to BoxedInt | Instruction 'Chi: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:47:6:47:18 | void for_decl_bind(int) | void for_decl_bind(int) | +| misc.c:171:10:171:13 | Uninitialized: definition of str2 | Instruction 'Uninitialized: definition of str2' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | +| misc.c:219:47:219:48 | InitializeIndirection: sp | Instruction 'InitializeIndirection: sp' has no successors in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) | +| ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | Instruction 'Uninitialized: definition of x' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | +| ms_try_mix.cpp:11:12:11:15 | Chi: call to C | Instruction 'Chi: call to C' has no successors in function '$@'. | ms_try_mix.cpp:10:6:10:18 | void ms_except_mix(int) | void ms_except_mix(int) | +| ms_try_mix.cpp:28:12:28:15 | Chi: call to C | Instruction 'Chi: call to C' has no successors in function '$@'. | ms_try_mix.cpp:27:6:27:19 | void ms_finally_mix(int) | void ms_finally_mix(int) | +| ms_try_mix.cpp:48:10:48:13 | Chi: call to C | Instruction 'Chi: call to C' has no successors in function '$@'. | ms_try_mix.cpp:47:6:47:28 | void ms_empty_finally_at_end() | void ms_empty_finally_at_end() | +| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | stmt_expr.cpp:21:6:21:6 | void stmtexpr::g(int) | void stmtexpr::g(int) | +| vla.c:5:9:5:14 | Uninitialized: definition of matrix | Instruction 'Uninitialized: definition of matrix' has no successors in function '$@'. | vla.c:3:5:3:8 | int main(int, char**) | int main(int, char**) | +| vla.c:11:6:11:16 | Chi: vla_typedef | Instruction 'Chi: vla_typedef' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | ambiguousSuccessors -| allocators.cpp:14:5:14:8 | Chi: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| allocators.cpp:14:5:14:8 | Chi: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| allocators.cpp:14:5:14:8 | Chi: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| allocators.cpp:14:5:14:8 | Chi: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| conditional_destructors.cpp:29:6:29:7 | Chi: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | -| conditional_destructors.cpp:29:6:29:7 | Chi: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | -| conditional_destructors.cpp:38:6:38:7 | Chi: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | -| conditional_destructors.cpp:38:6:38:7 | Chi: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| dostmt.c:8:6:8:18 | Chi: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| dostmt.c:8:6:8:18 | Chi: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| dostmt.c:8:6:8:18 | Chi: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| dostmt.c:8:6:8:18 | Chi: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| dostmt.c:16:6:16:18 | Chi: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| dostmt.c:16:6:16:18 | Chi: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| dostmt.c:16:6:16:18 | Chi: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| dostmt.c:16:6:16:18 | Chi: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| dostmt.c:25:6:25:18 | Chi: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | -| dostmt.c:25:6:25:18 | Chi: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| forstmt.cpp:1:6:1:7 | Chi: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | -| forstmt.cpp:1:6:1:7 | Chi: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | -| forstmt.cpp:8:6:8:7 | Chi: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | -| forstmt.cpp:8:6:8:7 | Chi: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | -| ifelsestmt.c:1:6:1:19 | Chi: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| ifelsestmt.c:1:6:1:19 | Chi: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| ifelsestmt.c:1:6:1:19 | Chi: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | Chi: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | Chi: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | Chi: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| ifelsestmt.c:19:6:19:18 | Chi: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| ifelsestmt.c:19:6:19:18 | Chi: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| ifelsestmt.c:19:6:19:18 | Chi: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| ifelsestmt.c:19:6:19:18 | Chi: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | Chi: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| ifelsestmt.c:29:6:29:18 | Chi: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | Chi: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | Chi: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | dostmt.c:33:7:33:7 | VariableAddress: definition of i | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | ifelsestmt.c:38:6:38:6 | VariableAddress: x | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | ifstmt.c:28:6:28:6 | VariableAddress: x | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | whilestmt.c:40:7:40:7 | VariableAddress: definition of i | -| ifstmt.c:1:6:1:19 | Chi: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| ifstmt.c:1:6:1:19 | Chi: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| ifstmt.c:1:6:1:19 | Chi: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| ifstmt.c:8:6:8:19 | Chi: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| ifstmt.c:8:6:8:19 | Chi: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| ifstmt.c:8:6:8:19 | Chi: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| ifstmt.c:14:6:14:18 | Chi: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| ifstmt.c:14:6:14:18 | Chi: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| ifstmt.c:14:6:14:18 | Chi: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| ifstmt.c:14:6:14:18 | Chi: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| ifstmt.c:21:6:21:18 | Chi: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| ifstmt.c:21:6:21:18 | Chi: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| ifstmt.c:21:6:21:18 | Chi: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| ifstmt.c:21:6:21:18 | Chi: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | dostmt.c:33:7:33:7 | VariableAddress: definition of i | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | ifelsestmt.c:38:6:38:6 | VariableAddress: x | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | ifstmt.c:28:6:28:6 | VariableAddress: x | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | whilestmt.c:40:7:40:7 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| no_dynamic_init.cpp:9:5:9:8 | Chi: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| no_dynamic_init.cpp:9:5:9:8 | Chi: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| no_dynamic_init.cpp:9:5:9:8 | Chi: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| no_dynamic_init.cpp:9:5:9:8 | Chi: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nonmembercallexpr.c:1:6:1:6 | Chi: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | -| nonmembercallexpr.c:1:6:1:6 | Chi: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| parameterinitializer.cpp:18:5:18:8 | Chi: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| parameterinitializer.cpp:18:5:18:8 | Chi: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| parameterinitializer.cpp:18:5:18:8 | Chi: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| parameterinitializer.cpp:18:5:18:8 | Chi: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| revsubscriptexpr.c:1:6:1:6 | Chi: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | -| revsubscriptexpr.c:1:6:1:6 | Chi: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| stream_it.cpp:16:5:16:8 | Chi: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| stream_it.cpp:16:5:16:8 | Chi: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| stream_it.cpp:16:5:16:8 | Chi: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| stream_it.cpp:16:5:16:8 | Chi: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| whilestmt.c:1:6:1:19 | Chi: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| whilestmt.c:1:6:1:19 | Chi: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| whilestmt.c:1:6:1:19 | Chi: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| whilestmt.c:8:6:8:19 | Chi: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| whilestmt.c:8:6:8:19 | Chi: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| whilestmt.c:8:6:8:19 | Chi: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| whilestmt.c:15:6:15:18 | Chi: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| whilestmt.c:15:6:15:18 | Chi: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| whilestmt.c:15:6:15:18 | Chi: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| whilestmt.c:15:6:15:18 | Chi: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| whilestmt.c:23:6:23:18 | Chi: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| whilestmt.c:23:6:23:18 | Chi: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| whilestmt.c:23:6:23:18 | Chi: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| whilestmt.c:23:6:23:18 | Chi: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| whilestmt.c:32:6:32:18 | Chi: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | -| whilestmt.c:32:6:32:18 | Chi: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | +| allocators.cpp:14:5:14:8 | Chi: main | Instruction 'Chi: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| array_delete.cpp:5:6:5:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| assignexpr.cpp:6:6:6:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| conditional_destructors.cpp:29:6:29:7 | Chi: f1 | Instruction 'Chi: f1' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:38:6:38:7 | Chi: f2 | Instruction 'Chi: f2' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| constmemberaccess.cpp:6:6:6:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| constructorinitializer.cpp:6:6:6:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| deleteexpr.cpp:6:6:6:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| dostmt.c:8:6:8:18 | Chi: always_true_1 | Instruction 'Chi: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| dostmt.c:16:6:16:18 | Chi: always_true_2 | Instruction 'Chi: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| dostmt.c:25:6:25:18 | Chi: always_true_3 | Instruction 'Chi: always_true_3' has 2 successors of kind 'Goto' in function '$@'. | dostmt.c:25:6:25:18 | void always_true_3() | void always_true_3() | +| duff.c:2:12:2:12 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| duff.c:2:12:2:12 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| duff.c:2:12:2:12 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| duff.c:2:12:2:12 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| fieldaccess.cpp:6:6:6:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| forstmt.cpp:1:6:1:7 | Chi: f1 | Instruction 'Chi: f1' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| forstmt.cpp:8:6:8:7 | Chi: f2 | Instruction 'Chi: f2' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| ifelsestmt.c:1:6:1:19 | Chi: always_false_1 | Instruction 'Chi: always_false_1' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:1:6:1:19 | void always_false_1() | void always_false_1() | +| ifelsestmt.c:11:6:11:19 | Chi: always_false_2 | Instruction 'Chi: always_false_2' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:11:6:11:19 | void always_false_2() | void always_false_2() | +| ifelsestmt.c:19:6:19:18 | Chi: always_true_1 | Instruction 'Chi: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| ifelsestmt.c:29:6:29:18 | Chi: always_true_2 | Instruction 'Chi: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Instruction 'InitializeParameter: y' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:32:6:32:11 | void normal(int, int) | void normal(int, int) | +| ifstmt.c:1:6:1:19 | Chi: always_false_1 | Instruction 'Chi: always_false_1' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:1:6:1:19 | void always_false_1() | void always_false_1() | +| ifstmt.c:8:6:8:19 | Chi: always_false_2 | Instruction 'Chi: always_false_2' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:11:6:11:19 | void always_false_2() | void always_false_2() | +| ifstmt.c:14:6:14:18 | Chi: always_true_1 | Instruction 'Chi: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| ifstmt.c:21:6:21:18 | Chi: always_true_2 | Instruction 'Chi: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| ifstmt.c:27:24:27:24 | InitializeParameter: y | Instruction 'InitializeParameter: y' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:32:6:32:11 | void normal(int, int) | void normal(int, int) | +| membercallexpr.cpp:6:6:6:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| newexpr.cpp:6:6:6:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| no_dynamic_init.cpp:9:5:9:8 | Chi: main | Instruction 'Chi: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nonmembercallexpr.c:1:6:1:6 | Chi: g | Instruction 'Chi: g' has 2 successors of kind 'Goto' in function '$@'. | nonmembercallexpr.c:1:6:1:6 | void g(); void g())(); void(* g(); void(* g())() | void g(); void g())(); void(* g(); void(* g())() | +| parameterinitializer.cpp:18:5:18:8 | Chi: main | Instruction 'Chi: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| pmcallexpr.cpp:6:6:6:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| revsubscriptexpr.c:1:6:1:6 | Chi: g | Instruction 'Chi: g' has 2 successors of kind 'Goto' in function '$@'. | nonmembercallexpr.c:1:6:1:6 | void g(); void g())(); void(* g(); void(* g())() | void g(); void g())(); void(* g(); void(* g())() | +| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| stream_it.cpp:16:5:16:8 | Chi: main | Instruction 'Chi: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| whilestmt.c:1:6:1:19 | Chi: always_false_1 | Instruction 'Chi: always_false_1' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:1:6:1:19 | void always_false_1() | void always_false_1() | +| whilestmt.c:8:6:8:19 | Chi: always_false_2 | Instruction 'Chi: always_false_2' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:11:6:11:19 | void always_false_2() | void always_false_2() | +| whilestmt.c:15:6:15:18 | Chi: always_true_1 | Instruction 'Chi: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| whilestmt.c:23:6:23:18 | Chi: always_true_2 | Instruction 'Chi: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| whilestmt.c:32:6:32:18 | Chi: always_true_3 | Instruction 'Chi: always_true_3' has 2 successors of kind 'Goto' in function '$@'. | dostmt.c:25:6:25:18 | void always_true_3() | void always_true_3() | unexplainedLoop unnecessaryPhiInstruction memoryOperandDefinitionIsUnmodeled @@ -516,6 +112,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected index 6b0256c95f58..19478a17a16e 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected @@ -8,26 +8,7 @@ uniqueEnclosingCallable | misc.c:210:24:210:24 | 0 | Node should have one enclosing callable but has 0. | | misc.c:210:24:210:28 | ... + ... | Node should have one enclosing callable but has 0. | | misc.c:210:28:210:28 | 1 | Node should have one enclosing callable but has 0. | -uniqueTypeBound -| bad_asts.cpp:19:10:19:10 | constructor init of field x [post-this] | Node should have one type bound but has 0. | -| bad_asts.cpp:19:10:19:10 | constructor init of field x [pre-this] | Node should have one type bound but has 0. | -| bad_asts.cpp:19:10:19:10 | constructor init of field y [post-this] | Node should have one type bound but has 0. | -| bad_asts.cpp:19:10:19:10 | constructor init of field y [pre-this] | Node should have one type bound but has 0. | -| cpp17.cpp:15:5:15:45 | call to unknown function | Node should have one type bound but has 0. | -| ir.cpp:784:15:784:15 | constructor init of field middlevb2_s [post-this] | Node should have one type bound but has 0. | -| ir.cpp:784:15:784:15 | constructor init of field middlevb2_s [pre-this] | Node should have one type bound but has 0. | -| static_init_templates.cpp:240:7:240:7 | constructor init of field mcc [post-this] | Node should have one type bound but has 0. | -| static_init_templates.cpp:240:7:240:7 | constructor init of field mcc [pre-this] | Node should have one type bound but has 0. | -uniqueTypeRepr -| bad_asts.cpp:19:10:19:10 | constructor init of field x [post-this] | Node should have one type representation but has 0. | -| bad_asts.cpp:19:10:19:10 | constructor init of field x [pre-this] | Node should have one type representation but has 0. | -| bad_asts.cpp:19:10:19:10 | constructor init of field y [post-this] | Node should have one type representation but has 0. | -| bad_asts.cpp:19:10:19:10 | constructor init of field y [pre-this] | Node should have one type representation but has 0. | -| cpp17.cpp:15:5:15:45 | call to unknown function | Node should have one type representation but has 0. | -| ir.cpp:784:15:784:15 | constructor init of field middlevb2_s [post-this] | Node should have one type representation but has 0. | -| ir.cpp:784:15:784:15 | constructor init of field middlevb2_s [pre-this] | Node should have one type representation but has 0. | -| static_init_templates.cpp:240:7:240:7 | constructor init of field mcc [post-this] | Node should have one type representation but has 0. | -| static_init_templates.cpp:240:7:240:7 | constructor init of field mcc [pre-this] | Node should have one type representation but has 0. | +uniqueType uniqueNodeLocation | break_labels.c:2:11:2:11 | i | Node should have one location but has 4. | | break_labels.c:2:11:2:11 | x | Node should have one location but has 4. | @@ -79,7 +60,6 @@ postHasUniquePre uniquePostUpdate postIsInSameCallable reverseRead -storeIsPostUpdate argHasPostUpdate | builtin.cpp:15:31:15:35 | * ... | ArgumentNode is missing PostUpdateNode. | | conditional_destructors.cpp:30:9:30:13 | call to C1 | ArgumentNode is missing PostUpdateNode. | @@ -90,3 +70,56 @@ argHasPostUpdate | destructors.cpp:52:14:52:16 | ref | ArgumentNode is missing PostUpdateNode. | | ir.cpp:623:5:623:5 | r | ArgumentNode is missing PostUpdateNode. | | ir.cpp:625:5:625:5 | s | ArgumentNode is missing PostUpdateNode. | +postWithInFlow +| VacuousDestructorCall.cpp:10:22:10:22 | i [inner post update] | PostUpdateNode should not be the target of local flow. | +| allocators.cpp:4:11:4:13 | m_x [post update] | PostUpdateNode should not be the target of local flow. | +| allocators.cpp:4:17:4:19 | m_y [post update] | PostUpdateNode should not be the target of local flow. | +| assignexpr.cpp:9:4:9:4 | i [post update] | PostUpdateNode should not be the target of local flow. | +| builtin.c:34:23:34:31 | staticint [inner post update] | PostUpdateNode should not be the target of local flow. | +| builtin.c:39:37:39:45 | carry_out [inner post update] | PostUpdateNode should not be the target of local flow. | +| builtin.c:43:41:43:49 | staticint [inner post update] | PostUpdateNode should not be the target of local flow. | +| builtin.c:51:30:51:38 | staticint [inner post update] | PostUpdateNode should not be the target of local flow. | +| builtin.c:54:29:54:38 | atomic_int [inner post update] | PostUpdateNode should not be the target of local flow. | +| condition_decls.cpp:3:5:3:9 | m_ptr [post update] | PostUpdateNode should not be the target of local flow. | +| condition_decls.cpp:17:11:17:15 | m_ptr [inner post update] | PostUpdateNode should not be the target of local flow. | +| condition_decls.cpp:20:11:20:15 | m_ptr [inner post update] | PostUpdateNode should not be the target of local flow. | +| condition_decls.cpp:28:11:28:15 | m_ptr [inner post update] | PostUpdateNode should not be the target of local flow. | +| condition_decls.cpp:31:11:31:15 | m_ptr [inner post update] | PostUpdateNode should not be the target of local flow. | +| condition_decls.cpp:34:9:34:13 | m_ptr [inner post update] | PostUpdateNode should not be the target of local flow. | +| conditional_destructors.cpp:6:13:6:15 | val [post update] | PostUpdateNode should not be the target of local flow. | +| conditional_destructors.cpp:18:13:18:15 | val [post update] | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:7:7:7:8 | el [post update] | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:77:19:77:21 | call to Val | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:82:11:82:14 | call to Val | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:82:45:82:48 | call to Val | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:82:51:82:51 | call to Val | PostUpdateNode should not be the target of local flow. | +| ir.cpp:177:5:177:5 | p [inner post update] | PostUpdateNode should not be the target of local flow. | +| ir.cpp:177:5:177:8 | access to array [post update] | PostUpdateNode should not be the target of local flow. | +| ir.cpp:178:5:178:8 | access to array [post update] | PostUpdateNode should not be the target of local flow. | +| ir.cpp:178:7:178:7 | p [inner post update] | PostUpdateNode should not be the target of local flow. | +| ir.cpp:183:5:183:5 | a [inner post update] | PostUpdateNode should not be the target of local flow. | +| ir.cpp:183:5:183:8 | access to array [post update] | PostUpdateNode should not be the target of local flow. | +| ir.cpp:184:5:184:8 | access to array [post update] | PostUpdateNode should not be the target of local flow. | +| ir.cpp:184:7:184:7 | a [inner post update] | PostUpdateNode should not be the target of local flow. | +| ir.cpp:342:5:342:6 | * ... [post update] | PostUpdateNode should not be the target of local flow. | +| ir.cpp:342:6:342:6 | p [inner post update] | PostUpdateNode should not be the target of local flow. | +| ir.cpp:428:8:428:8 | x [post update] | PostUpdateNode should not be the target of local flow. | +| ir.cpp:429:8:429:8 | y [post update] | PostUpdateNode should not be the target of local flow. | +| ir.cpp:643:15:643:17 | m_a [post update] | PostUpdateNode should not be the target of local flow. | +| ir.cpp:644:11:644:14 | this [inner post update] | PostUpdateNode should not be the target of local flow. | +| ir.cpp:644:17:644:19 | m_a [post update] | PostUpdateNode should not be the target of local flow. | +| ir.cpp:645:9:645:11 | m_a [post update] | PostUpdateNode should not be the target of local flow. | +| ir.cpp:654:11:654:14 | this [inner post update] | PostUpdateNode should not be the target of local flow. | +| ir.cpp:745:8:745:8 | base_s [inner post update] | PostUpdateNode should not be the target of local flow. | +| ir.cpp:754:8:754:8 | middle_s [inner post update] | PostUpdateNode should not be the target of local flow. | +| ir.cpp:763:8:763:8 | derived_s [inner post update] | PostUpdateNode should not be the target of local flow. | +| ir.cpp:809:7:809:13 | call to Base | PostUpdateNode should not be the target of local flow. | +| ir.cpp:810:7:810:26 | call to Base | PostUpdateNode should not be the target of local flow. | +| ir.cpp:823:7:823:13 | call to Base | PostUpdateNode should not be the target of local flow. | +| ir.cpp:824:7:824:26 | call to Base | PostUpdateNode should not be the target of local flow. | +| misc.c:130:7:130:7 | i [post update] | PostUpdateNode should not be the target of local flow. | +| misc.c:131:9:131:9 | i [post update] | PostUpdateNode should not be the target of local flow. | +| misc.c:220:3:220:5 | * ... [post update] | PostUpdateNode should not be the target of local flow. | +| misc.c:220:4:220:5 | sp [inner post update] | PostUpdateNode should not be the target of local flow. | +| static_init_templates.cpp:3:2:3:4 | ref [post update] | PostUpdateNode should not be the target of local flow. | +| static_init_templates.cpp:21:2:21:4 | val [post update] | PostUpdateNode should not be the target of local flow. | diff --git a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected index dd2598dc9f86..fc13d6d8a42e 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected @@ -1,51 +1,140 @@ uniqueEnclosingCallable -uniqueTypeBound -uniqueTypeRepr +uniqueType uniqueNodeLocation | aggregateinitializer.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | Unreached | Node should have one location but has 20. | +| allocators.cpp:14:5:14:8 | Address | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | AliasedDefinition | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | AliasedUse | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | Chi | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | ChiPartial | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | ChiTotal | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | EnterFunction | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | ExitFunction | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | InitializeNonLocal | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | Load | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | ReturnValue | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | SideEffect | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | VariableAddress | Node should have one location but has 4. | | array_delete.cpp:5:6:5:6 | AliasedDefinition | Node should have one location but has 14. | | array_delete.cpp:5:6:5:6 | AliasedUse | Node should have one location but has 14. | | array_delete.cpp:5:6:5:6 | Chi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | ChiPartial | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | ChiTotal | Node should have one location but has 14. | | array_delete.cpp:5:6:5:6 | EnterFunction | Node should have one location but has 14. | | array_delete.cpp:5:6:5:6 | ExitFunction | Node should have one location but has 14. | | array_delete.cpp:5:6:5:6 | InitializeNonLocal | Node should have one location but has 14. | | array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | | array_delete.cpp:5:6:5:6 | ReturnVoid | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | SideEffect | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | ChiPartial | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | ChiTotal | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | EnterFunction | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | ExitFunction | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | SideEffect | Node should have one location but has 14. | | break_labels.c:2:5:2:5 | AliasedDefinition | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | AliasedUse | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | Chi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | ChiPartial | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | ChiTotal | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | EnterFunction | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | ExitFunction | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | InitializeNonLocal | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | ReturnVoid | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | SideEffect | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | Unreached | Node should have one location but has 20. | +| break_labels.c:2:11:2:11 | Address | Node should have one location but has 4. | | break_labels.c:2:11:2:11 | VariableAddress | Node should have one location but has 4. | | break_labels.c:2:11:2:11 | i | Node should have one location but has 4. | | break_labels.c:2:11:2:11 | i | Node should have one location but has 4. | @@ -54,29 +143,56 @@ uniqueNodeLocation | conditional_destructors.cpp:29:6:29:7 | AliasedDefinition | Node should have one location but has 2. | | conditional_destructors.cpp:29:6:29:7 | AliasedUse | Node should have one location but has 2. | | conditional_destructors.cpp:29:6:29:7 | Chi | Node should have one location but has 2. | +| conditional_destructors.cpp:29:6:29:7 | ChiPartial | Node should have one location but has 2. | +| conditional_destructors.cpp:29:6:29:7 | ChiTotal | Node should have one location but has 2. | | conditional_destructors.cpp:29:6:29:7 | EnterFunction | Node should have one location but has 2. | | conditional_destructors.cpp:29:6:29:7 | ExitFunction | Node should have one location but has 2. | | conditional_destructors.cpp:29:6:29:7 | InitializeNonLocal | Node should have one location but has 2. | | conditional_destructors.cpp:29:6:29:7 | Phi | Node should have one location but has 2. | +| conditional_destructors.cpp:29:6:29:7 | Phi | Node should have one location but has 2. | +| conditional_destructors.cpp:29:6:29:7 | Phi | Node should have one location but has 2. | | conditional_destructors.cpp:29:6:29:7 | ReturnVoid | Node should have one location but has 2. | +| conditional_destructors.cpp:29:6:29:7 | SideEffect | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | AliasedDefinition | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | AliasedUse | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | Chi | Node should have one location but has 2. | +| conditional_destructors.cpp:38:6:38:7 | ChiPartial | Node should have one location but has 2. | +| conditional_destructors.cpp:38:6:38:7 | ChiTotal | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | EnterFunction | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | ExitFunction | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | InitializeNonLocal | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | Phi | Node should have one location but has 2. | +| conditional_destructors.cpp:38:6:38:7 | Phi | Node should have one location but has 2. | +| conditional_destructors.cpp:38:6:38:7 | Phi | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | ReturnVoid | Node should have one location but has 2. | +| conditional_destructors.cpp:38:6:38:7 | SideEffect | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | Unreached | Node should have one location but has 2. | | constmemberaccess.cpp:3:7:3:7 | x | Node should have one location but has 2. | | constmemberaccess.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | constmemberaccess.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | constmemberaccess.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | ChiPartial | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | ChiTotal | Node should have one location but has 14. | | constmemberaccess.cpp:6:6:6:6 | EnterFunction | Node should have one location but has 14. | | constmemberaccess.cpp:6:6:6:6 | ExitFunction | Node should have one location but has 14. | | constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | constmemberaccess.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | SideEffect | Node should have one location but has 14. | | constructorinitializer.cpp:3:9:3:9 | i | Node should have one location but has 2. | | constructorinitializer.cpp:3:9:3:9 | x | Node should have one location but has 2. | | constructorinitializer.cpp:3:16:3:16 | j | Node should have one location but has 2. | @@ -84,72 +200,173 @@ uniqueNodeLocation | constructorinitializer.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | constructorinitializer.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | constructorinitializer.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | ChiPartial | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | ChiTotal | Node should have one location but has 14. | | constructorinitializer.cpp:6:6:6:6 | EnterFunction | Node should have one location but has 14. | | constructorinitializer.cpp:6:6:6:6 | ExitFunction | Node should have one location but has 14. | | constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | constructorinitializer.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | SideEffect | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | AliasedDefinition | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | AliasedUse | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | Chi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | ChiPartial | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | ChiTotal | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | EnterFunction | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | ExitFunction | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | ReturnVoid | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | SideEffect | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | AliasedDefinition | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | AliasedUse | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | Chi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | ChiPartial | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | ChiTotal | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | EnterFunction | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | ExitFunction | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | ReturnVoid | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | SideEffect | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | ChiPartial | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | ChiTotal | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | EnterFunction | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | ExitFunction | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | SideEffect | Node should have one location but has 14. | | dostmt.c:8:6:8:18 | AliasedDefinition | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | AliasedUse | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | Chi | Node should have one location but has 4. | +| dostmt.c:8:6:8:18 | ChiPartial | Node should have one location but has 4. | +| dostmt.c:8:6:8:18 | ChiTotal | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | EnterFunction | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | ExitFunction | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | InitializeNonLocal | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | ReturnVoid | Node should have one location but has 4. | +| dostmt.c:8:6:8:18 | SideEffect | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | Unreached | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | AliasedDefinition | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | AliasedUse | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | Chi | Node should have one location but has 4. | +| dostmt.c:16:6:16:18 | ChiPartial | Node should have one location but has 4. | +| dostmt.c:16:6:16:18 | ChiTotal | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | EnterFunction | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | ExitFunction | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | InitializeNonLocal | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | ReturnVoid | Node should have one location but has 4. | +| dostmt.c:16:6:16:18 | SideEffect | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | Unreached | Node should have one location but has 4. | | dostmt.c:25:6:25:18 | AliasedDefinition | Node should have one location but has 2. | | dostmt.c:25:6:25:18 | Chi | Node should have one location but has 2. | +| dostmt.c:25:6:25:18 | ChiPartial | Node should have one location but has 2. | +| dostmt.c:25:6:25:18 | ChiTotal | Node should have one location but has 2. | | dostmt.c:25:6:25:18 | EnterFunction | Node should have one location but has 2. | | dostmt.c:25:6:25:18 | InitializeNonLocal | Node should have one location but has 2. | | dostmt.c:25:6:25:18 | Unreached | Node should have one location but has 2. | | dostmt.c:32:6:32:11 | AliasedDefinition | Node should have one location but has 4. | | dostmt.c:32:6:32:11 | AliasedUse | Node should have one location but has 4. | | dostmt.c:32:6:32:11 | Chi | Node should have one location but has 4. | +| dostmt.c:32:6:32:11 | ChiPartial | Node should have one location but has 4. | +| dostmt.c:32:6:32:11 | ChiTotal | Node should have one location but has 4. | | dostmt.c:32:6:32:11 | EnterFunction | Node should have one location but has 4. | | dostmt.c:32:6:32:11 | ExitFunction | Node should have one location but has 4. | | dostmt.c:32:6:32:11 | InitializeNonLocal | Node should have one location but has 4. | | dostmt.c:32:6:32:11 | ReturnVoid | Node should have one location but has 4. | +| dostmt.c:32:6:32:11 | SideEffect | Node should have one location but has 4. | | duff.c:2:6:2:6 | AliasedDefinition | Node should have one location but has 20. | | duff.c:2:6:2:6 | AliasedUse | Node should have one location but has 20. | | duff.c:2:6:2:6 | Chi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | ChiPartial | Node should have one location but has 20. | +| duff.c:2:6:2:6 | ChiTotal | Node should have one location but has 20. | | duff.c:2:6:2:6 | EnterFunction | Node should have one location but has 20. | | duff.c:2:6:2:6 | ExitFunction | Node should have one location but has 20. | | duff.c:2:6:2:6 | InitializeNonLocal | Node should have one location but has 20. | | duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | | duff.c:2:6:2:6 | ReturnVoid | Node should have one location but has 20. | +| duff.c:2:6:2:6 | SideEffect | Node should have one location but has 20. | | duff.c:2:6:2:6 | Unreached | Node should have one location but has 20. | +| duff.c:2:12:2:12 | Address | Node should have one location but has 4. | | duff.c:2:12:2:12 | VariableAddress | Node should have one location but has 4. | | duff.c:2:12:2:12 | i | Node should have one location but has 4. | | duff.c:2:12:2:12 | i | Node should have one location but has 4. | @@ -158,51 +375,158 @@ uniqueNodeLocation | dummyblock.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | enum.c:5:5:5:5 | AliasedDefinition | Node should have one location but has 20. | | enum.c:5:5:5:5 | AliasedUse | Node should have one location but has 20. | | enum.c:5:5:5:5 | Chi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | ChiPartial | Node should have one location but has 20. | +| enum.c:5:5:5:5 | ChiTotal | Node should have one location but has 20. | | enum.c:5:5:5:5 | EnterFunction | Node should have one location but has 20. | | enum.c:5:5:5:5 | ExitFunction | Node should have one location but has 20. | | enum.c:5:5:5:5 | InitializeNonLocal | Node should have one location but has 20. | | enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | | enum.c:5:5:5:5 | ReturnVoid | Node should have one location but has 20. | +| enum.c:5:5:5:5 | SideEffect | Node should have one location but has 20. | | enum.c:5:5:5:5 | Unreached | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | fieldaccess.cpp:3:7:3:7 | x | Node should have one location but has 2. | | fieldaccess.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | fieldaccess.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | fieldaccess.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | ChiPartial | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | ChiTotal | Node should have one location but has 14. | | fieldaccess.cpp:6:6:6:6 | EnterFunction | Node should have one location but has 14. | | fieldaccess.cpp:6:6:6:6 | ExitFunction | Node should have one location but has 14. | | fieldaccess.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | fieldaccess.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | SideEffect | Node should have one location but has 14. | | file://:0:0:0:0 | *p#2 | Node should have one location but has 0. | +| file://:0:0:0:0 | Address | Node should have one location but has 0. | +| file://:0:0:0:0 | Address | Node should have one location but has 0. | +| file://:0:0:0:0 | Address | Node should have one location but has 0. | +| file://:0:0:0:0 | Address | Node should have one location but has 0. | +| file://:0:0:0:0 | Load | Node should have one location but has 0. | | file://:0:0:0:0 | Load | Node should have one location but has 0. | | file://:0:0:0:0 | ReturnIndirection | Node should have one location but has 0. | +| file://:0:0:0:0 | SideEffect | Node should have one location but has 0. | | file://:0:0:0:0 | VariableAddress | Node should have one location but has 0. | | file://:0:0:0:0 | p#0 | Node should have one location but has 0. | | file://:0:0:0:0 | p#0 | Node should have one location but has 0. | @@ -215,8 +539,6 @@ uniqueNodeLocation | file://:0:0:0:0 | p#0 | Node should have one location but has 0. | | file://:0:0:0:0 | p#0 | Node should have one location but has 0. | | file://:0:0:0:0 | p#0 | Node should have one location but has 0. | -| file://:0:0:0:0 | p#0 | Node should have one location but has 0. | -| file://:0:0:0:0 | p#0 | Node should have one location but has 0. | | file://:0:0:0:0 | p#1 | Node should have one location but has 0. | | file://:0:0:0:0 | p#1 | Node should have one location but has 0. | | file://:0:0:0:0 | p#1 | Node should have one location but has 0. | @@ -233,165 +555,327 @@ uniqueNodeLocation | forstmt.cpp:1:6:1:7 | AliasedDefinition | Node should have one location but has 2. | | forstmt.cpp:1:6:1:7 | AliasedUse | Node should have one location but has 2. | | forstmt.cpp:1:6:1:7 | Chi | Node should have one location but has 2. | +| forstmt.cpp:1:6:1:7 | ChiPartial | Node should have one location but has 2. | +| forstmt.cpp:1:6:1:7 | ChiTotal | Node should have one location but has 2. | | forstmt.cpp:1:6:1:7 | EnterFunction | Node should have one location but has 2. | | forstmt.cpp:1:6:1:7 | ExitFunction | Node should have one location but has 2. | | forstmt.cpp:1:6:1:7 | InitializeNonLocal | Node should have one location but has 2. | | forstmt.cpp:1:6:1:7 | Phi | Node should have one location but has 2. | +| forstmt.cpp:1:6:1:7 | Phi | Node should have one location but has 2. | +| forstmt.cpp:1:6:1:7 | Phi | Node should have one location but has 2. | | forstmt.cpp:1:6:1:7 | ReturnVoid | Node should have one location but has 2. | +| forstmt.cpp:1:6:1:7 | SideEffect | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | AliasedDefinition | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | AliasedUse | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | Chi | Node should have one location but has 2. | +| forstmt.cpp:8:6:8:7 | ChiPartial | Node should have one location but has 2. | +| forstmt.cpp:8:6:8:7 | ChiTotal | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | EnterFunction | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | ExitFunction | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | InitializeNonLocal | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | Phi | Node should have one location but has 2. | -| forstmt.cpp:8:6:8:7 | ReturnVoid | Node should have one location but has 2. | +| forstmt.cpp:8:6:8:7 | Phi | Node should have one location but has 2. | +| forstmt.cpp:8:6:8:7 | Phi | Node should have one location but has 2. | +| forstmt.cpp:8:6:8:7 | ReturnVoid | Node should have one location but has 2. | +| forstmt.cpp:8:6:8:7 | SideEffect | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | Unreached | Node should have one location but has 2. | | ifelsestmt.c:1:6:1:19 | AliasedDefinition | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | AliasedUse | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | Chi | Node should have one location but has 3. | +| ifelsestmt.c:1:6:1:19 | ChiPartial | Node should have one location but has 3. | +| ifelsestmt.c:1:6:1:19 | ChiTotal | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | EnterFunction | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | ExitFunction | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | InitializeNonLocal | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | ReturnVoid | Node should have one location but has 3. | +| ifelsestmt.c:1:6:1:19 | SideEffect | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | Unreached | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | AliasedDefinition | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | AliasedUse | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | Chi | Node should have one location but has 3. | +| ifelsestmt.c:11:6:11:19 | ChiPartial | Node should have one location but has 3. | +| ifelsestmt.c:11:6:11:19 | ChiTotal | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | EnterFunction | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | ExitFunction | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | InitializeNonLocal | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | ReturnVoid | Node should have one location but has 3. | +| ifelsestmt.c:11:6:11:19 | SideEffect | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | Unreached | Node should have one location but has 3. | | ifelsestmt.c:19:6:19:18 | AliasedDefinition | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | AliasedUse | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | Chi | Node should have one location but has 4. | +| ifelsestmt.c:19:6:19:18 | ChiPartial | Node should have one location but has 4. | +| ifelsestmt.c:19:6:19:18 | ChiTotal | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | EnterFunction | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | ExitFunction | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | InitializeNonLocal | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | ReturnVoid | Node should have one location but has 4. | +| ifelsestmt.c:19:6:19:18 | SideEffect | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | Unreached | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | AliasedDefinition | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | AliasedUse | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | Chi | Node should have one location but has 4. | +| ifelsestmt.c:29:6:29:18 | ChiPartial | Node should have one location but has 4. | +| ifelsestmt.c:29:6:29:18 | ChiTotal | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | EnterFunction | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | ExitFunction | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | InitializeNonLocal | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | ReturnVoid | Node should have one location but has 4. | +| ifelsestmt.c:29:6:29:18 | SideEffect | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | Unreached | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | AliasedDefinition | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | AliasedUse | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | Chi | Node should have one location but has 4. | +| ifelsestmt.c:37:6:37:11 | ChiPartial | Node should have one location but has 4. | +| ifelsestmt.c:37:6:37:11 | ChiTotal | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | EnterFunction | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | ExitFunction | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | InitializeNonLocal | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | ReturnVoid | Node should have one location but has 4. | +| ifelsestmt.c:37:6:37:11 | SideEffect | Node should have one location but has 4. | +| ifelsestmt.c:37:17:37:17 | Address | Node should have one location but has 2. | | ifelsestmt.c:37:17:37:17 | VariableAddress | Node should have one location but has 2. | | ifelsestmt.c:37:17:37:17 | x | Node should have one location but has 2. | | ifelsestmt.c:37:17:37:17 | x | Node should have one location but has 2. | +| ifelsestmt.c:37:24:37:24 | Address | Node should have one location but has 2. | | ifelsestmt.c:37:24:37:24 | VariableAddress | Node should have one location but has 2. | | ifelsestmt.c:37:24:37:24 | y | Node should have one location but has 2. | | ifelsestmt.c:37:24:37:24 | y | Node should have one location but has 2. | | ifstmt.c:1:6:1:19 | AliasedDefinition | Node should have one location but has 3. | | ifstmt.c:1:6:1:19 | AliasedUse | Node should have one location but has 3. | | ifstmt.c:1:6:1:19 | Chi | Node should have one location but has 3. | +| ifstmt.c:1:6:1:19 | ChiPartial | Node should have one location but has 3. | +| ifstmt.c:1:6:1:19 | ChiTotal | Node should have one location but has 3. | | ifstmt.c:1:6:1:19 | EnterFunction | Node should have one location but has 3. | | ifstmt.c:1:6:1:19 | ExitFunction | Node should have one location but has 3. | | ifstmt.c:1:6:1:19 | InitializeNonLocal | Node should have one location but has 3. | | ifstmt.c:1:6:1:19 | ReturnVoid | Node should have one location but has 3. | +| ifstmt.c:1:6:1:19 | SideEffect | Node should have one location but has 3. | | ifstmt.c:1:6:1:19 | Unreached | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | AliasedDefinition | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | AliasedUse | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | Chi | Node should have one location but has 3. | +| ifstmt.c:8:6:8:19 | ChiPartial | Node should have one location but has 3. | +| ifstmt.c:8:6:8:19 | ChiTotal | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | EnterFunction | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | ExitFunction | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | InitializeNonLocal | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | ReturnVoid | Node should have one location but has 3. | +| ifstmt.c:8:6:8:19 | SideEffect | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | Unreached | Node should have one location but has 3. | | ifstmt.c:14:6:14:18 | AliasedDefinition | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | AliasedUse | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | Chi | Node should have one location but has 4. | +| ifstmt.c:14:6:14:18 | ChiPartial | Node should have one location but has 4. | +| ifstmt.c:14:6:14:18 | ChiTotal | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | EnterFunction | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | ExitFunction | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | InitializeNonLocal | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | ReturnVoid | Node should have one location but has 4. | +| ifstmt.c:14:6:14:18 | SideEffect | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | Unreached | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | AliasedDefinition | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | AliasedUse | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | Chi | Node should have one location but has 4. | +| ifstmt.c:21:6:21:18 | ChiPartial | Node should have one location but has 4. | +| ifstmt.c:21:6:21:18 | ChiTotal | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | EnterFunction | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | ExitFunction | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | InitializeNonLocal | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | ReturnVoid | Node should have one location but has 4. | +| ifstmt.c:21:6:21:18 | SideEffect | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | Unreached | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | AliasedDefinition | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | AliasedUse | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | Chi | Node should have one location but has 4. | +| ifstmt.c:27:6:27:11 | ChiPartial | Node should have one location but has 4. | +| ifstmt.c:27:6:27:11 | ChiTotal | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | EnterFunction | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | ExitFunction | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | InitializeNonLocal | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | ReturnVoid | Node should have one location but has 4. | +| ifstmt.c:27:6:27:11 | SideEffect | Node should have one location but has 4. | +| ifstmt.c:27:17:27:17 | Address | Node should have one location but has 2. | | ifstmt.c:27:17:27:17 | VariableAddress | Node should have one location but has 2. | | ifstmt.c:27:17:27:17 | x | Node should have one location but has 2. | | ifstmt.c:27:17:27:17 | x | Node should have one location but has 2. | +| ifstmt.c:27:24:27:24 | Address | Node should have one location but has 2. | | ifstmt.c:27:24:27:24 | VariableAddress | Node should have one location but has 2. | | ifstmt.c:27:24:27:24 | y | Node should have one location but has 2. | | ifstmt.c:27:24:27:24 | y | Node should have one location but has 2. | | initializer.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | initializer.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | initializer.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | initializer.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | initializer.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | initializer.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | | initializer.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | initializer.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | membercallexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | membercallexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | membercallexpr.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | ChiPartial | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | ChiTotal | Node should have one location but has 14. | | membercallexpr.cpp:6:6:6:6 | EnterFunction | Node should have one location but has 14. | | membercallexpr.cpp:6:6:6:6 | ExitFunction | Node should have one location but has 14. | | membercallexpr.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | membercallexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | SideEffect | Node should have one location but has 14. | | membercallexpr_args.cpp:3:6:3:6 | d | Node should have one location but has 2. | | membercallexpr_args.cpp:4:14:4:14 | x | Node should have one location but has 2. | | membercallexpr_args.cpp:4:21:4:21 | y | Node should have one location but has 2. | | membercallexpr_args.cpp:7:6:7:6 | AliasedDefinition | Node should have one location but has 14. | | membercallexpr_args.cpp:7:6:7:6 | AliasedUse | Node should have one location but has 14. | | membercallexpr_args.cpp:7:6:7:6 | Chi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | ChiPartial | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | ChiTotal | Node should have one location but has 14. | | membercallexpr_args.cpp:7:6:7:6 | EnterFunction | Node should have one location but has 14. | | membercallexpr_args.cpp:7:6:7:6 | ExitFunction | Node should have one location but has 14. | | membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal | Node should have one location but has 14. | | membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | | membercallexpr_args.cpp:7:6:7:6 | ReturnVoid | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | SideEffect | Node should have one location but has 14. | | newexpr.cpp:3:9:3:9 | i | Node should have one location but has 2. | | newexpr.cpp:3:9:3:9 | x | Node should have one location but has 2. | | newexpr.cpp:3:16:3:16 | j | Node should have one location but has 2. | @@ -399,30 +883,82 @@ uniqueNodeLocation | newexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | newexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | newexpr.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | ChiPartial | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | ChiTotal | Node should have one location but has 14. | | newexpr.cpp:6:6:6:6 | EnterFunction | Node should have one location but has 14. | | newexpr.cpp:6:6:6:6 | ExitFunction | Node should have one location but has 14. | | newexpr.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | newexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | SideEffect | Node should have one location but has 14. | +| no_dynamic_init.cpp:9:5:9:8 | Address | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | AliasedDefinition | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | AliasedUse | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | Chi | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | ChiPartial | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | ChiTotal | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | EnterFunction | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | ExitFunction | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | Load | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | ReturnValue | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | SideEffect | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | VariableAddress | Node should have one location but has 4. | | nodefaultswitchstmt.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | Unreached | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:12:1:12 | Address | Node should have one location but has 4. | | nodefaultswitchstmt.c:1:12:1:12 | VariableAddress | Node should have one location but has 4. | | nodefaultswitchstmt.c:1:12:1:12 | i | Node should have one location but has 4. | | nodefaultswitchstmt.c:1:12:1:12 | i | Node should have one location but has 4. | @@ -431,118 +967,328 @@ uniqueNodeLocation | nonmembercallexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 2. | | nonmembercallexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 2. | | nonmembercallexpr.c:1:6:1:6 | Chi | Node should have one location but has 2. | +| nonmembercallexpr.c:1:6:1:6 | ChiPartial | Node should have one location but has 2. | +| nonmembercallexpr.c:1:6:1:6 | ChiTotal | Node should have one location but has 2. | | nonmembercallexpr.c:1:6:1:6 | EnterFunction | Node should have one location but has 2. | | nonmembercallexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 2. | | nonmembercallexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 2. | | nonmembercallexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 2. | +| nonmembercallexpr.c:1:6:1:6 | SideEffect | Node should have one location but has 2. | | nonmembercallexpr.c:3:6:3:6 | AliasedDefinition | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | AliasedUse | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | Chi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | ChiPartial | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | ChiTotal | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | EnterFunction | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | ExitFunction | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | InitializeNonLocal | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | ReturnVoid | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | SideEffect | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | Unreached | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | AliasedDefinition | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | AliasedUse | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | Chi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | ChiPartial | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | ChiTotal | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | EnterFunction | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | ExitFunction | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | InitializeNonLocal | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | ReturnVoid | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | SideEffect | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | Unreached | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | +| parameterinitializer.cpp:18:5:18:8 | Address | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | AliasedDefinition | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | AliasedUse | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | Chi | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | ChiPartial | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | ChiTotal | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | EnterFunction | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | ExitFunction | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | Load | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | ReturnValue | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | SideEffect | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | VariableAddress | Node should have one location but has 4. | | pmcallexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | pmcallexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | pmcallexpr.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | ChiPartial | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | ChiTotal | Node should have one location but has 14. | | pmcallexpr.cpp:6:6:6:6 | EnterFunction | Node should have one location but has 14. | | pmcallexpr.cpp:6:6:6:6 | ExitFunction | Node should have one location but has 14. | | pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | pmcallexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | SideEffect | Node should have one location but has 14. | | questionexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | revsubscriptexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 2. | | revsubscriptexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 2. | | revsubscriptexpr.c:1:6:1:6 | Chi | Node should have one location but has 2. | +| revsubscriptexpr.c:1:6:1:6 | ChiPartial | Node should have one location but has 2. | +| revsubscriptexpr.c:1:6:1:6 | ChiTotal | Node should have one location but has 2. | | revsubscriptexpr.c:1:6:1:6 | EnterFunction | Node should have one location but has 2. | | revsubscriptexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 2. | | revsubscriptexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 2. | | revsubscriptexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 2. | +| revsubscriptexpr.c:1:6:1:6 | SideEffect | Node should have one location but has 2. | | staticmembercallexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | ChiPartial | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | ChiTotal | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | EnterFunction | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | ExitFunction | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | SideEffect | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:3:6:3:6 | d | Node should have one location but has 2. | | staticmembercallexpr_args.cpp:4:21:4:21 | x | Node should have one location but has 2. | | staticmembercallexpr_args.cpp:4:28:4:28 | y | Node should have one location but has 2. | | staticmembercallexpr_args.cpp:7:6:7:6 | AliasedDefinition | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:7:6:7:6 | AliasedUse | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:7:6:7:6 | Chi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | ChiPartial | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | ChiTotal | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:7:6:7:6 | EnterFunction | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:7:6:7:6 | ExitFunction | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:7:6:7:6 | ReturnVoid | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | SideEffect | Node should have one location but has 14. | +| stream_it.cpp:16:5:16:8 | Address | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | AliasedDefinition | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | AliasedUse | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | Chi | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | ChiPartial | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | ChiTotal | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | EnterFunction | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | ExitFunction | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | InitializeNonLocal | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | Load | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | ReturnValue | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | SideEffect | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | VariableAddress | Node should have one location but has 4. | | subscriptexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | Unreached | Node should have one location but has 20. | +| switchstmt.c:1:12:1:12 | Address | Node should have one location but has 4. | | switchstmt.c:1:12:1:12 | VariableAddress | Node should have one location but has 4. | | switchstmt.c:1:12:1:12 | i | Node should have one location but has 4. | | switchstmt.c:1:12:1:12 | i | Node should have one location but has 4. | @@ -551,67 +1297,126 @@ uniqueNodeLocation | tinyforstmt.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | whilestmt.c:1:6:1:19 | AliasedDefinition | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | AliasedUse | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | Chi | Node should have one location but has 3. | +| whilestmt.c:1:6:1:19 | ChiPartial | Node should have one location but has 3. | +| whilestmt.c:1:6:1:19 | ChiTotal | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | EnterFunction | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | ExitFunction | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | InitializeNonLocal | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | ReturnVoid | Node should have one location but has 3. | +| whilestmt.c:1:6:1:19 | SideEffect | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | Unreached | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | AliasedDefinition | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | AliasedUse | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | Chi | Node should have one location but has 3. | +| whilestmt.c:8:6:8:19 | ChiPartial | Node should have one location but has 3. | +| whilestmt.c:8:6:8:19 | ChiTotal | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | EnterFunction | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | ExitFunction | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | InitializeNonLocal | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | ReturnVoid | Node should have one location but has 3. | +| whilestmt.c:8:6:8:19 | SideEffect | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | Unreached | Node should have one location but has 3. | | whilestmt.c:15:6:15:18 | AliasedDefinition | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | AliasedUse | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | Chi | Node should have one location but has 4. | +| whilestmt.c:15:6:15:18 | ChiPartial | Node should have one location but has 4. | +| whilestmt.c:15:6:15:18 | ChiTotal | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | EnterFunction | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | ExitFunction | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | InitializeNonLocal | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | ReturnVoid | Node should have one location but has 4. | +| whilestmt.c:15:6:15:18 | SideEffect | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | Unreached | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | AliasedDefinition | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | AliasedUse | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | Chi | Node should have one location but has 4. | +| whilestmt.c:23:6:23:18 | ChiPartial | Node should have one location but has 4. | +| whilestmt.c:23:6:23:18 | ChiTotal | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | EnterFunction | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | ExitFunction | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | InitializeNonLocal | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | ReturnVoid | Node should have one location but has 4. | +| whilestmt.c:23:6:23:18 | SideEffect | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | Unreached | Node should have one location but has 4. | | whilestmt.c:32:6:32:18 | AliasedDefinition | Node should have one location but has 2. | | whilestmt.c:32:6:32:18 | Chi | Node should have one location but has 2. | +| whilestmt.c:32:6:32:18 | ChiPartial | Node should have one location but has 2. | +| whilestmt.c:32:6:32:18 | ChiTotal | Node should have one location but has 2. | | whilestmt.c:32:6:32:18 | EnterFunction | Node should have one location but has 2. | | whilestmt.c:32:6:32:18 | InitializeNonLocal | Node should have one location but has 2. | | whilestmt.c:32:6:32:18 | Unreached | Node should have one location but has 2. | | whilestmt.c:39:6:39:11 | AliasedDefinition | Node should have one location but has 4. | | whilestmt.c:39:6:39:11 | AliasedUse | Node should have one location but has 4. | | whilestmt.c:39:6:39:11 | Chi | Node should have one location but has 4. | +| whilestmt.c:39:6:39:11 | ChiPartial | Node should have one location but has 4. | +| whilestmt.c:39:6:39:11 | ChiTotal | Node should have one location but has 4. | | whilestmt.c:39:6:39:11 | EnterFunction | Node should have one location but has 4. | | whilestmt.c:39:6:39:11 | ExitFunction | Node should have one location but has 4. | | whilestmt.c:39:6:39:11 | InitializeNonLocal | Node should have one location but has 4. | | whilestmt.c:39:6:39:11 | ReturnVoid | Node should have one location but has 4. | +| whilestmt.c:39:6:39:11 | SideEffect | Node should have one location but has 4. | missingLocation -| Nodes without location: 30 | +| Nodes without location: 34 | uniqueNodeToString | break_labels.c:2:11:2:11 | i | Node should have one toString but has 2. | | break_labels.c:2:11:2:11 | i | Node should have one toString but has 2. | @@ -666,5 +1471,93 @@ postHasUniquePre uniquePostUpdate postIsInSameCallable reverseRead -storeIsPostUpdate argHasPostUpdate +postWithInFlow +| aggregateinitializer.c:3:14:3:18 | Chi | PostUpdateNode should not be the target of local flow. | +| aggregateinitializer.c:3:21:3:25 | Chi | PostUpdateNode should not be the target of local flow. | +| allocators.cpp:3:27:3:27 | Chi | PostUpdateNode should not be the target of local flow. | +| allocators.cpp:3:35:3:35 | Chi | PostUpdateNode should not be the target of local flow. | +| allocators.cpp:4:11:4:23 | Chi | PostUpdateNode should not be the target of local flow. | +| allocators.cpp:4:17:4:23 | Chi | PostUpdateNode should not be the target of local flow. | +| assignexpr.cpp:9:2:9:12 | Store | PostUpdateNode should not be the target of local flow. | +| bad_asts.cpp:15:10:15:12 | Store | PostUpdateNode should not be the target of local flow. | +| builtin.c:14:26:14:26 | Chi | PostUpdateNode should not be the target of local flow. | +| builtin.c:14:29:14:29 | Chi | PostUpdateNode should not be the target of local flow. | +| builtin.c:14:32:14:32 | Chi | PostUpdateNode should not be the target of local flow. | +| builtin.c:14:35:14:35 | Chi | PostUpdateNode should not be the target of local flow. | +| condition_decls.cpp:3:5:3:22 | Chi | PostUpdateNode should not be the target of local flow. | +| condition_decls.cpp:3:21:3:21 | Chi | PostUpdateNode should not be the target of local flow. | +| conditional_destructors.cpp:6:13:6:19 | Chi | PostUpdateNode should not be the target of local flow. | +| conditional_destructors.cpp:18:13:18:19 | Chi | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:65:19:65:45 | Store | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:82:17:82:55 | Chi | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:82:45:82:48 | Chi | PostUpdateNode should not be the target of local flow. | +| defdestructordeleteexpr.cpp:4:9:4:15 | Chi | PostUpdateNode should not be the target of local flow. | +| deleteexpr.cpp:7:9:7:15 | Chi | PostUpdateNode should not be the target of local flow. | +| file://:0:0:0:0 | Chi | PostUpdateNode should not be the target of local flow. | +| file://:0:0:0:0 | Chi | PostUpdateNode should not be the target of local flow. | +| file://:0:0:0:0 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:177:5:177:12 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:178:5:178:12 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:183:5:183:12 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:184:5:184:12 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:342:5:342:10 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:428:5:428:12 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:429:5:429:15 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:504:19:504:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:504:22:504:22 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:505:16:505:21 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:505:19:505:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:506:16:506:18 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:506:16:506:18 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:513:14:513:16 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:513:14:513:16 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:514:14:514:26 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:514:19:514:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:514:22:514:22 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:515:19:515:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:515:22:515:22 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:515:29:515:29 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:515:32:515:32 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:516:17:516:21 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:516:19:516:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:516:24:516:28 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:516:26:516:26 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:521:19:521:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:521:22:521:22 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:521:25:521:25 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:522:16:522:21 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:522:19:522:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:531:14:531:14 | Store | PostUpdateNode should not be the target of local flow. | +| ir.cpp:577:16:577:21 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:577:19:577:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:578:19:578:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:578:22:578:22 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:579:16:579:21 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:579:19:579:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:643:9:643:21 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:644:9:644:23 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:645:9:645:15 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:659:9:659:14 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:660:13:660:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:661:9:661:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:943:3:943:11 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:947:3:947:25 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:962:17:962:47 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:962:17:962:47 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:962:17:962:47 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:962:26:962:30 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:962:41:962:45 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:130:5:130:11 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:131:5:131:13 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:154:32:154:32 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:154:35:154:35 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:154:40:154:40 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:154:43:154:43 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:157:14:157:18 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:158:14:158:18 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:160:31:160:33 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:160:31:160:33 | Chi | PostUpdateNode should not be the target of local flow. | +| range_analysis.c:102:5:102:15 | Chi | PostUpdateNode should not be the target of local flow. | +| static_init_templates.cpp:3:2:3:8 | Chi | PostUpdateNode should not be the target of local flow. | +| static_init_templates.cpp:21:2:21:12 | Chi | PostUpdateNode should not be the target of local flow. | diff --git a/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected index 7039bed7dd7d..61da658e201c 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected @@ -1,40 +1,32 @@ missingOperand -| condition_decls.cpp:16:6:16:20 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:15:6:15:17 | IR: if_decl_bind | void if_decl_bind(int) | -| condition_decls.cpp:26:10:26:24 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:25:6:25:21 | IR: switch_decl_bind | void switch_decl_bind(int) | -| condition_decls.cpp:41:9:41:23 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:40:6:40:20 | IR: while_decl_bind | void while_decl_bind(int) | -| condition_decls.cpp:48:39:48:53 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:47:6:47:18 | IR: for_decl_bind | void for_decl_bind(int) | -| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| cpp11.cpp:77:19:77:21 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:76:8:76:8 | IR: apply | void lambda::apply<(void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | -| cpp11.cpp:82:11:82:14 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | IR: apply2 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | -| cpp11.cpp:82:45:82:48 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | -| cpp11.cpp:82:51:82:51 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | -| cpp11.cpp:88:25:88:30 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | -| cpp11.cpp:88:33:88:38 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | -| destructors.cpp:51:36:51:38 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | IR: f | int cond_destruct::f(int) | -| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | IR: misc3 | void misc3() | -| misc.c:220:3:223:3 | Store: ... = ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) | -| misc.c:220:9:223:3 | FieldAddress: {...} | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) | -| misc.c:220:9:223:3 | FieldAddress: {...} | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) | -| try_catch.cpp:23:5:23:18 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | try_catch.cpp:19:6:19:23 | IR: throw_from_nonstmt | void throw_from_nonstmt(int) | +| condition_decls.cpp:16:6:16:20 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:15:6:15:17 | void if_decl_bind(int) | void if_decl_bind(int) | +| condition_decls.cpp:26:10:26:24 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:25:6:25:21 | void switch_decl_bind(int) | void switch_decl_bind(int) | +| condition_decls.cpp:41:9:41:23 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:40:6:40:20 | void while_decl_bind(int) | void while_decl_bind(int) | +| condition_decls.cpp:48:39:48:53 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:47:6:47:18 | void for_decl_bind(int) | void for_decl_bind(int) | +| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| cpp11.cpp:77:19:77:21 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:76:8:76:8 | void lambda::apply<(void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | void lambda::apply<(void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | +| cpp11.cpp:82:11:82:14 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | +| cpp11.cpp:82:45:82:48 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:82:51:82:51 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:88:25:88:30 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | void lambda::main() | void lambda::main() | +| cpp11.cpp:88:33:88:38 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | void lambda::main() | void lambda::main() | +| destructors.cpp:51:36:51:38 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | int cond_destruct::f(int) | int cond_destruct::f(int) | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | void misc3() | void misc3() | +| misc.c:220:3:223:3 | Store: ... = ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) | +| misc.c:220:9:223:3 | FieldAddress: {...} | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) | +| misc.c:220:9:223:3 | FieldAddress: {...} | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) | +| try_catch.cpp:23:5:23:18 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | try_catch.cpp:19:6:19:23 | void throw_from_nonstmt(int) | void throw_from_nonstmt(int) | unexpectedOperand duplicateOperand missingPhiOperand @@ -42,519 +34,121 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| CPP-309.cpp:7:5:7:20 | InitializeDynamicAllocation: new[] | -| VacuousDestructorCall.cpp:2:29:2:29 | InitializeIndirection: y | -| VacuousDestructorCall.cpp:3:3:3:3 | VariableAddress: x | -| VacuousDestructorCall.cpp:4:3:4:3 | Load: y | -| condition_decls.cpp:16:19:16:20 | IndirectMayWriteSideEffect: call to BoxedInt | -| condition_decls.cpp:26:19:26:20 | IndirectMayWriteSideEffect: bi | -| condition_decls.cpp:26:23:26:24 | IndirectMayWriteSideEffect: call to BoxedInt | -| condition_decls.cpp:41:22:41:23 | IndirectMayWriteSideEffect: call to BoxedInt | -| condition_decls.cpp:48:52:48:53 | IndirectMayWriteSideEffect: call to BoxedInt | -| cpp17.cpp:15:5:15:45 | InitializeDynamicAllocation: new | -| enum.c:6:9:6:9 | Constant: (int)... | -| file://:0:0:0:0 | CompareNE: (bool)... | -| file://:0:0:0:0 | CompareNE: (bool)... | -| file://:0:0:0:0 | CompareNE: (bool)... | -| misc.c:171:10:171:13 | Uninitialized: definition of str2 | -| misc.c:171:15:171:31 | Add: ... + ... | -| misc.c:173:14:173:26 | Mul: ... * ... | -| misc.c:173:37:173:39 | Store: array to pointer conversion | -| misc.c:174:17:174:22 | CallSideEffect: call to getInt | -| misc.c:174:30:174:35 | CallSideEffect: call to getInt | -| misc.c:174:55:174:60 | Store: (char ****)... | -| misc.c:219:47:219:48 | InitializeIndirection: sp | -| misc.c:221:10:221:10 | Store: 1 | -| misc.c:222:10:222:10 | Store: 2 | -| ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | -| ms_try_except.cpp:7:13:7:17 | Store: ... = ... | -| ms_try_except.cpp:9:19:9:19 | Load: j | -| ms_try_except.cpp:10:13:10:17 | Store: ... = ... | -| ms_try_except.cpp:14:13:14:17 | Store: ... = ... | -| ms_try_except.cpp:17:13:17:17 | Store: ... = ... | -| ms_try_except.cpp:19:17:19:21 | Sub: ... - ... | -| ms_try_except.cpp:20:9:20:13 | Store: ... = ... | -| ms_try_mix.cpp:11:12:11:15 | IndirectMayWriteSideEffect: call to C | -| ms_try_mix.cpp:16:13:16:19 | ThrowValue: throw ... | -| ms_try_mix.cpp:18:16:18:19 | IndirectMayWriteSideEffect: call to C | -| ms_try_mix.cpp:20:15:20:39 | Constant: 1 | -| ms_try_mix.cpp:21:16:21:19 | IndirectMayWriteSideEffect: call to C | -| ms_try_mix.cpp:28:12:28:15 | IndirectMayWriteSideEffect: call to C | -| ms_try_mix.cpp:33:13:33:19 | ThrowValue: throw ... | -| ms_try_mix.cpp:35:16:35:19 | IndirectMayWriteSideEffect: call to C | -| ms_try_mix.cpp:38:16:38:19 | IndirectMayWriteSideEffect: call to C | -| ms_try_mix.cpp:48:10:48:13 | IndirectMayWriteSideEffect: call to C | -| ms_try_mix.cpp:51:5:51:11 | ThrowValue: throw ... | -| ms_try_mix.cpp:53:13:54:3 | NoOp: { ... } | -| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | -| stmt_expr.cpp:29:11:32:11 | CopyValue: (statement expression) | -| stmt_in_type.cpp:5:53:5:53 | Constant: 1 | -| vla.c:5:9:5:14 | Uninitialized: definition of matrix | -| vla.c:5:16:5:19 | Load: argc | -| vla.c:5:27:5:33 | BufferReadSideEffect: (const char *)... | -| vla.c:11:6:11:16 | InitializeNonLocal: vla_typedef | -| vla.c:12:33:12:44 | Add: ... + ... | -| vla.c:12:50:12:62 | Mul: ... * ... | -| vla.c:13:12:13:14 | Uninitialized: definition of var | -| vla.c:14:36:14:47 | Add: ... + ... | -| vla.c:14:53:14:65 | Mul: ... * ... | -| vla.c:14:74:14:79 | CallSideEffect: call to getInt | -| vla.c:14:92:14:94 | Store: (char *)... | +| VacuousDestructorCall.cpp:2:29:2:29 | InitializeIndirection: y | Instruction 'InitializeIndirection: y' has no successors in function '$@'. | VacuousDestructorCall.cpp:2:6:2:6 | void CallDestructor(int, int*) | void CallDestructor(int, int*) | +| VacuousDestructorCall.cpp:3:3:3:3 | VariableAddress: x | Instruction 'VariableAddress: x' has no successors in function '$@'. | VacuousDestructorCall.cpp:2:6:2:6 | void CallDestructor(int, int*) | void CallDestructor(int, int*) | +| VacuousDestructorCall.cpp:4:3:4:3 | Load: y | Instruction 'Load: y' has no successors in function '$@'. | VacuousDestructorCall.cpp:2:6:2:6 | void CallDestructor(int, int*) | void CallDestructor(int, int*) | +| condition_decls.cpp:16:19:16:20 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:15:6:15:17 | void if_decl_bind(int) | void if_decl_bind(int) | +| condition_decls.cpp:26:19:26:20 | IndirectMayWriteSideEffect: bi | Instruction 'IndirectMayWriteSideEffect: bi' has no successors in function '$@'. | condition_decls.cpp:25:6:25:21 | void switch_decl_bind(int) | void switch_decl_bind(int) | +| condition_decls.cpp:26:23:26:24 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:25:6:25:21 | void switch_decl_bind(int) | void switch_decl_bind(int) | +| condition_decls.cpp:41:22:41:23 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:40:6:40:20 | void while_decl_bind(int) | void while_decl_bind(int) | +| condition_decls.cpp:48:52:48:53 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:47:6:47:18 | void for_decl_bind(int) | void for_decl_bind(int) | +| enum.c:6:9:6:9 | Constant: (int)... | Instruction 'Constant: (int)...' has no successors in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| file://:0:0:0:0 | CompareNE: (bool)... | Instruction 'CompareNE: (bool)...' has no successors in function '$@'. | condition_decls.cpp:15:6:15:17 | void if_decl_bind(int) | void if_decl_bind(int) | +| file://:0:0:0:0 | CompareNE: (bool)... | Instruction 'CompareNE: (bool)...' has no successors in function '$@'. | condition_decls.cpp:40:6:40:20 | void while_decl_bind(int) | void while_decl_bind(int) | +| file://:0:0:0:0 | CompareNE: (bool)... | Instruction 'CompareNE: (bool)...' has no successors in function '$@'. | condition_decls.cpp:47:6:47:18 | void for_decl_bind(int) | void for_decl_bind(int) | +| misc.c:171:10:171:13 | Uninitialized: definition of str2 | Instruction 'Uninitialized: definition of str2' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | +| misc.c:171:15:171:31 | Add: ... + ... | Instruction 'Add: ... + ...' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | +| misc.c:173:14:173:26 | Mul: ... * ... | Instruction 'Mul: ... * ...' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | +| misc.c:173:37:173:39 | Store: array to pointer conversion | Instruction 'Store: array to pointer conversion' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | +| misc.c:174:17:174:22 | CallSideEffect: call to getInt | Instruction 'CallSideEffect: call to getInt' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | +| misc.c:174:30:174:35 | CallSideEffect: call to getInt | Instruction 'CallSideEffect: call to getInt' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | +| misc.c:174:55:174:60 | Store: (char ****)... | Instruction 'Store: (char ****)...' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | +| misc.c:219:47:219:48 | InitializeIndirection: sp | Instruction 'InitializeIndirection: sp' has no successors in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) | +| misc.c:221:10:221:10 | Store: 1 | Instruction 'Store: 1' has no successors in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) | +| misc.c:222:10:222:10 | Store: 2 | Instruction 'Store: 2' has no successors in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) | +| ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | Instruction 'Uninitialized: definition of x' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | +| ms_try_except.cpp:7:13:7:17 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | +| ms_try_except.cpp:9:19:9:19 | Load: j | Instruction 'Load: j' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | +| ms_try_except.cpp:10:13:10:17 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | +| ms_try_except.cpp:14:13:14:17 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | +| ms_try_except.cpp:17:13:17:17 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | +| ms_try_except.cpp:19:17:19:21 | Sub: ... - ... | Instruction 'Sub: ... - ...' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | +| ms_try_except.cpp:20:9:20:13 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | +| ms_try_mix.cpp:11:12:11:15 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect: call to C' has no successors in function '$@'. | ms_try_mix.cpp:10:6:10:18 | void ms_except_mix(int) | void ms_except_mix(int) | +| ms_try_mix.cpp:16:13:16:19 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:10:6:10:18 | void ms_except_mix(int) | void ms_except_mix(int) | +| ms_try_mix.cpp:18:16:18:19 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect: call to C' has no successors in function '$@'. | ms_try_mix.cpp:10:6:10:18 | void ms_except_mix(int) | void ms_except_mix(int) | +| ms_try_mix.cpp:20:15:20:39 | Constant: 1 | Instruction 'Constant: 1' has no successors in function '$@'. | ms_try_mix.cpp:10:6:10:18 | void ms_except_mix(int) | void ms_except_mix(int) | +| ms_try_mix.cpp:21:16:21:19 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect: call to C' has no successors in function '$@'. | ms_try_mix.cpp:10:6:10:18 | void ms_except_mix(int) | void ms_except_mix(int) | +| ms_try_mix.cpp:28:12:28:15 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect: call to C' has no successors in function '$@'. | ms_try_mix.cpp:27:6:27:19 | void ms_finally_mix(int) | void ms_finally_mix(int) | +| ms_try_mix.cpp:33:13:33:19 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:27:6:27:19 | void ms_finally_mix(int) | void ms_finally_mix(int) | +| ms_try_mix.cpp:35:16:35:19 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect: call to C' has no successors in function '$@'. | ms_try_mix.cpp:27:6:27:19 | void ms_finally_mix(int) | void ms_finally_mix(int) | +| ms_try_mix.cpp:38:16:38:19 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect: call to C' has no successors in function '$@'. | ms_try_mix.cpp:27:6:27:19 | void ms_finally_mix(int) | void ms_finally_mix(int) | +| ms_try_mix.cpp:48:10:48:13 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect: call to C' has no successors in function '$@'. | ms_try_mix.cpp:47:6:47:28 | void ms_empty_finally_at_end() | void ms_empty_finally_at_end() | +| ms_try_mix.cpp:51:5:51:11 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:47:6:47:28 | void ms_empty_finally_at_end() | void ms_empty_finally_at_end() | +| ms_try_mix.cpp:53:13:54:3 | NoOp: { ... } | Instruction 'NoOp: { ... }' has no successors in function '$@'. | ms_try_mix.cpp:47:6:47:28 | void ms_empty_finally_at_end() | void ms_empty_finally_at_end() | +| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | stmt_expr.cpp:21:6:21:6 | void stmtexpr::g(int) | void stmtexpr::g(int) | +| stmt_expr.cpp:29:11:32:11 | CopyValue: (statement expression) | Instruction 'CopyValue: (statement expression)' has no successors in function '$@'. | stmt_expr.cpp:21:6:21:6 | void stmtexpr::g(int) | void stmtexpr::g(int) | +| stmt_in_type.cpp:5:53:5:53 | Constant: 1 | Instruction 'Constant: 1' has no successors in function '$@'. | stmt_in_type.cpp:2:6:2:12 | void cpp_fun() | void cpp_fun() | +| vla.c:5:9:5:14 | Uninitialized: definition of matrix | Instruction 'Uninitialized: definition of matrix' has no successors in function '$@'. | vla.c:3:5:3:8 | int main(int, char**) | int main(int, char**) | +| vla.c:5:16:5:19 | Load: argc | Instruction 'Load: argc' has no successors in function '$@'. | vla.c:3:5:3:8 | int main(int, char**) | int main(int, char**) | +| vla.c:5:27:5:33 | BufferReadSideEffect: (const char *)... | Instruction 'BufferReadSideEffect: (const char *)...' has no successors in function '$@'. | vla.c:3:5:3:8 | int main(int, char**) | int main(int, char**) | +| vla.c:11:6:11:16 | InitializeNonLocal: vla_typedef | Instruction 'InitializeNonLocal: vla_typedef' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | +| vla.c:12:33:12:44 | Add: ... + ... | Instruction 'Add: ... + ...' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | +| vla.c:12:50:12:62 | Mul: ... * ... | Instruction 'Mul: ... * ...' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | +| vla.c:13:12:13:14 | Uninitialized: definition of var | Instruction 'Uninitialized: definition of var' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | +| vla.c:14:36:14:47 | Add: ... + ... | Instruction 'Add: ... + ...' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | +| vla.c:14:53:14:65 | Mul: ... * ... | Instruction 'Mul: ... * ...' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | +| vla.c:14:74:14:79 | CallSideEffect: call to getInt | Instruction 'CallSideEffect: call to getInt' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | +| vla.c:14:92:14:94 | Store: (char *)... | Instruction 'Store: (char *)...' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | ambiguousSuccessors -| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| conditional_destructors.cpp:29:6:29:7 | InitializeNonLocal: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | -| conditional_destructors.cpp:29:6:29:7 | InitializeNonLocal: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | -| conditional_destructors.cpp:38:6:38:7 | InitializeNonLocal: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | -| conditional_destructors.cpp:38:6:38:7 | InitializeNonLocal: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| dostmt.c:25:6:25:18 | InitializeNonLocal: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | -| dostmt.c:25:6:25:18 | InitializeNonLocal: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| forstmt.cpp:1:6:1:7 | InitializeNonLocal: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | -| forstmt.cpp:1:6:1:7 | InitializeNonLocal: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | -| forstmt.cpp:8:6:8:7 | InitializeNonLocal: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | -| forstmt.cpp:8:6:8:7 | InitializeNonLocal: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | -| ifelsestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| ifelsestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| ifelsestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | InitializeNonLocal: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | dostmt.c:33:7:33:7 | VariableAddress: definition of i | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | ifelsestmt.c:38:6:38:6 | VariableAddress: x | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | ifstmt.c:28:6:28:6 | VariableAddress: x | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | whilestmt.c:40:7:40:7 | VariableAddress: definition of i | -| ifstmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| ifstmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| ifstmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| ifstmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| ifstmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| ifstmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | dostmt.c:33:7:33:7 | VariableAddress: definition of i | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | ifelsestmt.c:38:6:38:6 | VariableAddress: x | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | ifstmt.c:28:6:28:6 | VariableAddress: x | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | whilestmt.c:40:7:40:7 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nonmembercallexpr.c:1:6:1:6 | InitializeNonLocal: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | -| nonmembercallexpr.c:1:6:1:6 | InitializeNonLocal: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| revsubscriptexpr.c:1:6:1:6 | InitializeNonLocal: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | -| revsubscriptexpr.c:1:6:1:6 | InitializeNonLocal: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| whilestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| whilestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| whilestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| whilestmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| whilestmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| whilestmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| whilestmt.c:32:6:32:18 | InitializeNonLocal: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | -| whilestmt.c:32:6:32:18 | InitializeNonLocal: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | +| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Instruction 'InitializeNonLocal: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| conditional_destructors.cpp:29:6:29:7 | InitializeNonLocal: f1 | Instruction 'InitializeNonLocal: f1' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:38:6:38:7 | InitializeNonLocal: f2 | Instruction 'InitializeNonLocal: f2' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Instruction 'InitializeNonLocal: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Instruction 'InitializeNonLocal: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| dostmt.c:25:6:25:18 | InitializeNonLocal: always_true_3 | Instruction 'InitializeNonLocal: always_true_3' has 2 successors of kind 'Goto' in function '$@'. | dostmt.c:25:6:25:18 | void always_true_3() | void always_true_3() | +| duff.c:2:12:2:12 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| duff.c:2:12:2:12 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| duff.c:2:12:2:12 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| duff.c:2:12:2:12 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| forstmt.cpp:1:6:1:7 | InitializeNonLocal: f1 | Instruction 'InitializeNonLocal: f1' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| forstmt.cpp:8:6:8:7 | InitializeNonLocal: f2 | Instruction 'InitializeNonLocal: f2' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| ifelsestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Instruction 'InitializeNonLocal: always_false_1' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:1:6:1:19 | void always_false_1() | void always_false_1() | +| ifelsestmt.c:11:6:11:19 | InitializeNonLocal: always_false_2 | Instruction 'InitializeNonLocal: always_false_2' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:11:6:11:19 | void always_false_2() | void always_false_2() | +| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Instruction 'InitializeNonLocal: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Instruction 'InitializeNonLocal: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Instruction 'InitializeParameter: y' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:32:6:32:11 | void normal(int, int) | void normal(int, int) | +| ifstmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Instruction 'InitializeNonLocal: always_false_1' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:1:6:1:19 | void always_false_1() | void always_false_1() | +| ifstmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Instruction 'InitializeNonLocal: always_false_2' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:11:6:11:19 | void always_false_2() | void always_false_2() | +| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Instruction 'InitializeNonLocal: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Instruction 'InitializeNonLocal: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| ifstmt.c:27:24:27:24 | InitializeParameter: y | Instruction 'InitializeParameter: y' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:32:6:32:11 | void normal(int, int) | void normal(int, int) | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Instruction 'InitializeNonLocal: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nonmembercallexpr.c:1:6:1:6 | InitializeNonLocal: g | Instruction 'InitializeNonLocal: g' has 2 successors of kind 'Goto' in function '$@'. | nonmembercallexpr.c:1:6:1:6 | void g(); void g())(); void(* g(); void(* g())() | void g(); void g())(); void(* g(); void(* g())() | +| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Instruction 'InitializeNonLocal: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| revsubscriptexpr.c:1:6:1:6 | InitializeNonLocal: g | Instruction 'InitializeNonLocal: g' has 2 successors of kind 'Goto' in function '$@'. | nonmembercallexpr.c:1:6:1:6 | void g(); void g())(); void(* g(); void(* g())() | void g(); void g())(); void(* g(); void(* g())() | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Instruction 'InitializeNonLocal: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| whilestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Instruction 'InitializeNonLocal: always_false_1' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:1:6:1:19 | void always_false_1() | void always_false_1() | +| whilestmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Instruction 'InitializeNonLocal: always_false_2' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:11:6:11:19 | void always_false_2() | void always_false_2() | +| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Instruction 'InitializeNonLocal: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Instruction 'InitializeNonLocal: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| whilestmt.c:32:6:32:18 | InitializeNonLocal: always_true_3 | Instruction 'InitializeNonLocal: always_true_3' has 2 successors of kind 'Goto' in function '$@'. | dostmt.c:25:6:25:18 | void always_true_3() | void always_true_3() | unexplainedLoop unnecessaryPhiInstruction memoryOperandDefinitionIsUnmodeled @@ -564,14 +158,16 @@ containsLoopOfForwardEdges lostReachability backEdgeCountMismatch useNotDominatedByDefinition -| VacuousDestructorCall.cpp:2:29:2:29 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | VacuousDestructorCall.cpp:2:6:2:6 | IR: CallDestructor | void CallDestructor(int, int*) | -| misc.c:219:47:219:48 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) | -| try_catch.cpp:21:13:21:24 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | try_catch.cpp:19:6:19:23 | IR: throw_from_nonstmt | void throw_from_nonstmt(int) | -| vla.c:3:27:3:30 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | vla.c:3:5:3:8 | IR: main | int main(int, char**) | +| VacuousDestructorCall.cpp:2:29:2:29 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | VacuousDestructorCall.cpp:2:6:2:6 | void CallDestructor(int, int*) | void CallDestructor(int, int*) | +| misc.c:219:47:219:48 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) | +| static_init_templates.cpp:15:1:15:18 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | static_init_templates.cpp:15:1:15:18 | void MyClass::MyClass() | void MyClass::MyClass() | +| try_catch.cpp:21:13:21:24 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | try_catch.cpp:19:6:19:23 | void throw_from_nonstmt(int) | void throw_from_nonstmt(int) | +| vla.c:3:27:3:30 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | vla.c:3:5:3:8 | int main(int, char**) | int main(int, char**) | switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_consistency.expected index 4964664c579e..4307483dfee4 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_consistency.expected @@ -1,32 +1,24 @@ missingOperand -| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| cpp11.cpp:77:19:77:21 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:76:8:76:8 | IR: apply | void lambda::apply<(void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | -| cpp11.cpp:82:11:82:14 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | IR: apply2 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | -| cpp11.cpp:82:45:82:48 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | -| cpp11.cpp:82:51:82:51 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | -| cpp11.cpp:88:25:88:30 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | -| cpp11.cpp:88:33:88:38 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | -| destructors.cpp:51:36:51:38 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | IR: f | int cond_destruct::f(int) | -| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | IR: misc3 | void misc3() | +| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| cpp11.cpp:77:19:77:21 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:76:8:76:8 | void lambda::apply<(void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | void lambda::apply<(void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | +| cpp11.cpp:82:11:82:14 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | +| cpp11.cpp:82:45:82:48 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:82:51:82:51 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:88:25:88:30 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | void lambda::main() | void lambda::main() | +| cpp11.cpp:88:33:88:38 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | void lambda::main() | void lambda::main() | +| destructors.cpp:51:36:51:38 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | int cond_destruct::f(int) | int cond_destruct::f(int) | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | void misc3() | void misc3() | unexpectedOperand duplicateOperand missingPhiOperand @@ -34,475 +26,79 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| VacuousDestructorCall.cpp:2:29:2:29 | InitializeIndirection: y | -| condition_decls.cpp:16:19:16:20 | IndirectMayWriteSideEffect: call to BoxedInt | -| condition_decls.cpp:26:23:26:24 | IndirectMayWriteSideEffect: call to BoxedInt | -| condition_decls.cpp:41:22:41:23 | IndirectMayWriteSideEffect: call to BoxedInt | -| condition_decls.cpp:48:52:48:53 | IndirectMayWriteSideEffect: call to BoxedInt | -| misc.c:171:10:171:13 | Uninitialized: definition of str2 | -| misc.c:219:47:219:48 | InitializeIndirection: sp | -| ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | -| ms_try_mix.cpp:11:12:11:15 | IndirectMayWriteSideEffect: call to C | -| ms_try_mix.cpp:28:12:28:15 | IndirectMayWriteSideEffect: call to C | -| ms_try_mix.cpp:48:10:48:13 | IndirectMayWriteSideEffect: call to C | -| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | -| vla.c:5:9:5:14 | Uninitialized: definition of matrix | -| vla.c:11:6:11:16 | InitializeNonLocal: vla_typedef | +| VacuousDestructorCall.cpp:2:29:2:29 | InitializeIndirection: y | Instruction 'InitializeIndirection: y' has no successors in function '$@'. | VacuousDestructorCall.cpp:2:6:2:6 | void CallDestructor(int, int*) | void CallDestructor(int, int*) | +| condition_decls.cpp:16:19:16:20 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:15:6:15:17 | void if_decl_bind(int) | void if_decl_bind(int) | +| condition_decls.cpp:26:23:26:24 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:25:6:25:21 | void switch_decl_bind(int) | void switch_decl_bind(int) | +| condition_decls.cpp:41:22:41:23 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:40:6:40:20 | void while_decl_bind(int) | void while_decl_bind(int) | +| condition_decls.cpp:48:52:48:53 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:47:6:47:18 | void for_decl_bind(int) | void for_decl_bind(int) | +| misc.c:171:10:171:13 | Uninitialized: definition of str2 | Instruction 'Uninitialized: definition of str2' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | +| misc.c:219:47:219:48 | InitializeIndirection: sp | Instruction 'InitializeIndirection: sp' has no successors in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) | +| ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | Instruction 'Uninitialized: definition of x' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | +| ms_try_mix.cpp:11:12:11:15 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect: call to C' has no successors in function '$@'. | ms_try_mix.cpp:10:6:10:18 | void ms_except_mix(int) | void ms_except_mix(int) | +| ms_try_mix.cpp:28:12:28:15 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect: call to C' has no successors in function '$@'. | ms_try_mix.cpp:27:6:27:19 | void ms_finally_mix(int) | void ms_finally_mix(int) | +| ms_try_mix.cpp:48:10:48:13 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect: call to C' has no successors in function '$@'. | ms_try_mix.cpp:47:6:47:28 | void ms_empty_finally_at_end() | void ms_empty_finally_at_end() | +| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | stmt_expr.cpp:21:6:21:6 | void stmtexpr::g(int) | void stmtexpr::g(int) | +| vla.c:5:9:5:14 | Uninitialized: definition of matrix | Instruction 'Uninitialized: definition of matrix' has no successors in function '$@'. | vla.c:3:5:3:8 | int main(int, char**) | int main(int, char**) | +| vla.c:11:6:11:16 | InitializeNonLocal: vla_typedef | Instruction 'InitializeNonLocal: vla_typedef' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | ambiguousSuccessors -| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| conditional_destructors.cpp:29:6:29:7 | InitializeNonLocal: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | -| conditional_destructors.cpp:29:6:29:7 | InitializeNonLocal: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | -| conditional_destructors.cpp:38:6:38:7 | InitializeNonLocal: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | -| conditional_destructors.cpp:38:6:38:7 | InitializeNonLocal: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| dostmt.c:25:6:25:18 | InitializeNonLocal: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | -| dostmt.c:25:6:25:18 | InitializeNonLocal: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| forstmt.cpp:1:6:1:7 | InitializeNonLocal: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | -| forstmt.cpp:1:6:1:7 | InitializeNonLocal: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | -| forstmt.cpp:8:6:8:7 | InitializeNonLocal: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | -| forstmt.cpp:8:6:8:7 | InitializeNonLocal: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | -| ifelsestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| ifelsestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| ifelsestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | InitializeNonLocal: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | dostmt.c:33:7:33:7 | VariableAddress: definition of i | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | ifelsestmt.c:38:6:38:6 | VariableAddress: x | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | ifstmt.c:28:6:28:6 | VariableAddress: x | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | whilestmt.c:40:7:40:7 | VariableAddress: definition of i | -| ifstmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| ifstmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| ifstmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| ifstmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| ifstmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| ifstmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | dostmt.c:33:7:33:7 | VariableAddress: definition of i | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | ifelsestmt.c:38:6:38:6 | VariableAddress: x | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | ifstmt.c:28:6:28:6 | VariableAddress: x | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | whilestmt.c:40:7:40:7 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nonmembercallexpr.c:1:6:1:6 | InitializeNonLocal: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | -| nonmembercallexpr.c:1:6:1:6 | InitializeNonLocal: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| revsubscriptexpr.c:1:6:1:6 | InitializeNonLocal: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | -| revsubscriptexpr.c:1:6:1:6 | InitializeNonLocal: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| whilestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| whilestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| whilestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| whilestmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| whilestmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| whilestmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| whilestmt.c:32:6:32:18 | InitializeNonLocal: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | -| whilestmt.c:32:6:32:18 | InitializeNonLocal: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | +| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Instruction 'InitializeNonLocal: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| conditional_destructors.cpp:29:6:29:7 | InitializeNonLocal: f1 | Instruction 'InitializeNonLocal: f1' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:38:6:38:7 | InitializeNonLocal: f2 | Instruction 'InitializeNonLocal: f2' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Instruction 'InitializeNonLocal: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Instruction 'InitializeNonLocal: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| dostmt.c:25:6:25:18 | InitializeNonLocal: always_true_3 | Instruction 'InitializeNonLocal: always_true_3' has 2 successors of kind 'Goto' in function '$@'. | dostmt.c:25:6:25:18 | void always_true_3() | void always_true_3() | +| duff.c:2:12:2:12 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| duff.c:2:12:2:12 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| duff.c:2:12:2:12 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| duff.c:2:12:2:12 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| forstmt.cpp:1:6:1:7 | InitializeNonLocal: f1 | Instruction 'InitializeNonLocal: f1' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| forstmt.cpp:8:6:8:7 | InitializeNonLocal: f2 | Instruction 'InitializeNonLocal: f2' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| ifelsestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Instruction 'InitializeNonLocal: always_false_1' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:1:6:1:19 | void always_false_1() | void always_false_1() | +| ifelsestmt.c:11:6:11:19 | InitializeNonLocal: always_false_2 | Instruction 'InitializeNonLocal: always_false_2' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:11:6:11:19 | void always_false_2() | void always_false_2() | +| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Instruction 'InitializeNonLocal: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Instruction 'InitializeNonLocal: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Instruction 'InitializeParameter: y' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:32:6:32:11 | void normal(int, int) | void normal(int, int) | +| ifstmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Instruction 'InitializeNonLocal: always_false_1' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:1:6:1:19 | void always_false_1() | void always_false_1() | +| ifstmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Instruction 'InitializeNonLocal: always_false_2' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:11:6:11:19 | void always_false_2() | void always_false_2() | +| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Instruction 'InitializeNonLocal: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Instruction 'InitializeNonLocal: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| ifstmt.c:27:24:27:24 | InitializeParameter: y | Instruction 'InitializeParameter: y' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:32:6:32:11 | void normal(int, int) | void normal(int, int) | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Instruction 'InitializeNonLocal: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nonmembercallexpr.c:1:6:1:6 | InitializeNonLocal: g | Instruction 'InitializeNonLocal: g' has 2 successors of kind 'Goto' in function '$@'. | nonmembercallexpr.c:1:6:1:6 | void g(); void g())(); void(* g(); void(* g())() | void g(); void g())(); void(* g(); void(* g())() | +| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Instruction 'InitializeNonLocal: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| revsubscriptexpr.c:1:6:1:6 | InitializeNonLocal: g | Instruction 'InitializeNonLocal: g' has 2 successors of kind 'Goto' in function '$@'. | nonmembercallexpr.c:1:6:1:6 | void g(); void g())(); void(* g(); void(* g())() | void g(); void g())(); void(* g(); void(* g())() | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Instruction 'InitializeNonLocal: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| whilestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Instruction 'InitializeNonLocal: always_false_1' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:1:6:1:19 | void always_false_1() | void always_false_1() | +| whilestmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Instruction 'InitializeNonLocal: always_false_2' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:11:6:11:19 | void always_false_2() | void always_false_2() | +| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Instruction 'InitializeNonLocal: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Instruction 'InitializeNonLocal: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| whilestmt.c:32:6:32:18 | InitializeNonLocal: always_true_3 | Instruction 'InitializeNonLocal: always_true_3' has 2 successors of kind 'Goto' in function '$@'. | dostmt.c:25:6:25:18 | void always_true_3() | void always_true_3() | unexplainedLoop unnecessaryPhiInstruction memoryOperandDefinitionIsUnmodeled @@ -516,6 +112,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/templates/CPP-202/template_args.expected b/cpp/ql/test/library-tests/templates/CPP-202/template_args.expected index f38eef610e44..c1d6e7fe9fa8 100644 --- a/cpp/ql/test/library-tests/templates/CPP-202/template_args.expected +++ b/cpp/ql/test/library-tests/templates/CPP-202/template_args.expected @@ -1,7 +1,7 @@ | file://:0:0:0:0 | __va_list_tag | | | test.cpp:3:8:3:9 | s1<> | {...} | -| test.cpp:3:8:3:9 | s1<> | (null) | +| test.cpp:3:8:3:9 | s1<> | (unnamed template parameter constant) | | test.cpp:5:8:5:9 | s2 | T | | test.cpp:5:8:5:9 | s2 | T | -| test.cpp:7:8:7:9 | s3> | (unnamed) | +| test.cpp:7:8:7:9 | s3> | (unnamed template parameter) | | test.cpp:7:8:7:9 | s3> | T | diff --git a/cpp/ql/test/library-tests/templates/decls/decls.expected b/cpp/ql/test/library-tests/templates/decls/decls.expected index 43a691e53c9c..cfb16b638281 100644 --- a/cpp/ql/test/library-tests/templates/decls/decls.expected +++ b/cpp/ql/test/library-tests/templates/decls/decls.expected @@ -7,7 +7,7 @@ | decls.cpp:4:30:4:34 | p#0 | | decls.cpp:4:30:4:34 | p#0 | | decls.cpp:6:17:6:17 | f | -| decls.cpp:8:18:8:18 | (unnamed) | +| decls.cpp:8:18:8:18 | (unnamed template parameter) | | decls.cpp:8:25:8:25 | g | | file://:0:0:0:0 | __va_list_tag | | file://:0:0:0:0 | auto | diff --git a/cpp/ql/test/library-tests/templates/instantiations_functions/elements.expected b/cpp/ql/test/library-tests/templates/instantiations_functions/elements.expected index 516e1067f782..5f066a7e4fde 100644 --- a/cpp/ql/test/library-tests/templates/instantiations_functions/elements.expected +++ b/cpp/ql/test/library-tests/templates/instantiations_functions/elements.expected @@ -54,6 +54,7 @@ | file://:0:0:0:0 | char8_t | | file://:0:0:0:0 | char16_t | | file://:0:0:0:0 | char32_t | +| file://:0:0:0:0 | composite * | | file://:0:0:0:0 | composite & | | file://:0:0:0:0 | composite && | | file://:0:0:0:0 | composite * | @@ -156,6 +157,7 @@ | file://:0:0:0:0 | restrict | | file://:0:0:0:0 | rule & | | file://:0:0:0:0 | rule && | +| file://:0:0:0:0 | rule * | | file://:0:0:0:0 | sealed | | file://:0:0:0:0 | selectany | | file://:0:0:0:0 | short | diff --git a/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromtemplateinstantiation.expected b/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromtemplateinstantiation.expected index a97246dd8991..d064fd7c8218 100644 --- a/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromtemplateinstantiation.expected +++ b/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromtemplateinstantiation.expected @@ -47,8 +47,10 @@ | isfromtemplateinstantiation.cpp:40:2:40:2 | return ... | isfromtemplateinstantiation.cpp:38:26:38:26 | normal_class::a_template_method() | | isfromtemplateinstantiation.cpp:44:26:44:26 | declaration of operator= | isfromtemplateinstantiation.cpp:44:26:44:39 | template_class | | isfromtemplateinstantiation.cpp:44:26:44:26 | declaration of operator= | isfromtemplateinstantiation.cpp:44:26:44:39 | template_class | +| isfromtemplateinstantiation.cpp:44:26:44:26 | definition of template_class | isfromtemplateinstantiation.cpp:44:26:44:39 | template_class | | isfromtemplateinstantiation.cpp:44:26:44:26 | template_class::operator=(const template_class &) | isfromtemplateinstantiation.cpp:44:26:44:39 | template_class | | isfromtemplateinstantiation.cpp:44:26:44:26 | template_class::operator=(template_class &&) | isfromtemplateinstantiation.cpp:44:26:44:39 | template_class | +| isfromtemplateinstantiation.cpp:44:26:44:26 | template_class::template_class() | isfromtemplateinstantiation.cpp:44:26:44:39 | template_class | | isfromtemplateinstantiation.cpp:46:4:46:4 | definition of t | isfromtemplateinstantiation.cpp:44:26:44:39 | template_class | | isfromtemplateinstantiation.cpp:46:4:46:4 | t | isfromtemplateinstantiation.cpp:44:26:44:39 | template_class | | isfromtemplateinstantiation.cpp:49:7:49:7 | definition of b_method | isfromtemplateinstantiation.cpp:44:26:44:39 | template_class | diff --git a/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromuninstantiatedtemplate.expected b/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromuninstantiatedtemplate.expected index d1e3cb3de156..f4f3321a90bd 100644 --- a/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromuninstantiatedtemplate.expected +++ b/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromuninstantiatedtemplate.expected @@ -347,6 +347,7 @@ isFromUninstantiatedTemplate | isfromtemplateinstantiation.cpp:26:1:26:1 | return ... | I | | Stmt | | | isfromtemplateinstantiation.cpp:29:7:29:7 | declaration of operator= | | | DeclarationEntry | | | isfromtemplateinstantiation.cpp:29:7:29:7 | declaration of operator= | | | DeclarationEntry | | +| isfromtemplateinstantiation.cpp:29:7:29:7 | normal_class | | | Declaration | | | isfromtemplateinstantiation.cpp:29:7:29:7 | operator= | | | Declaration | | | isfromtemplateinstantiation.cpp:29:7:29:7 | operator= | | | Declaration | | | isfromtemplateinstantiation.cpp:29:7:29:18 | normal_class | | | Declaration | | @@ -361,6 +362,7 @@ isFromUninstantiatedTemplate | isfromtemplateinstantiation.cpp:44:26:44:26 | declaration of operator= | I | | DeclarationEntry | | | isfromtemplateinstantiation.cpp:44:26:44:26 | operator= | I | | Declaration | | | isfromtemplateinstantiation.cpp:44:26:44:26 | operator= | I | | Declaration | | +| isfromtemplateinstantiation.cpp:44:26:44:26 | template_class | I | | Declaration | | | isfromtemplateinstantiation.cpp:44:26:44:39 | template_class | | T | Declaration | | | isfromtemplateinstantiation.cpp:44:26:44:39 | template_class | I | | Declaration | | | isfromtemplateinstantiation.cpp:46:4:46:4 | definition of t | | T | Definition | | diff --git a/cpp/ql/test/library-tests/typedefs/Typedefs2.ql b/cpp/ql/test/library-tests/typedefs/Typedefs2.ql index 11c7e075909e..122b826b556b 100644 --- a/cpp/ql/test/library-tests/typedefs/Typedefs2.ql +++ b/cpp/ql/test/library-tests/typedefs/Typedefs2.ql @@ -1,6 +1,6 @@ import cpp -from Function f1, Block body, Declaration d +from Function f1, BlockStmt body, Declaration d where body = f1.getBlock() and d = body.getADeclaration() diff --git a/cpp/ql/test/library-tests/unions/Unions1.expected b/cpp/ql/test/library-tests/unions/Unions1.expected index 440e9f8f1b9e..386f03d82de1 100644 --- a/cpp/ql/test/library-tests/unions/Unions1.expected +++ b/cpp/ql/test/library-tests/unions/Unions1.expected @@ -1,6 +1,6 @@ | unions.cpp:4:8:4:12 | Entry | Struct | | operator= | | unions.cpp:13:7:13:11 | Value | Struct, Union | | operator= | -| unions.cpp:19:8:19:22 | EntryWithMethod | Struct | Entry | getAsInt, operator= | +| unions.cpp:19:8:19:22 | EntryWithMethod | Struct | Entry | EntryWithMethod, getAsInt, operator= | | unions.cpp:27:9:27:20 | MyLocalUnion | LocalUnion, Struct, Union | | operator= | | unions.cpp:33:7:33:13 | MyClass | | | operator= | | unions.cpp:36:9:36:21 | MyNestedUnion | NestedUnion, Struct, Union | | operator= | diff --git a/cpp/ql/test/library-tests/unnamed/elements.expected b/cpp/ql/test/library-tests/unnamed/elements.expected index 8df7d4578a22..52176aa66df7 100644 --- a/cpp/ql/test/library-tests/unnamed/elements.expected +++ b/cpp/ql/test/library-tests/unnamed/elements.expected @@ -1,6 +1,6 @@ | file://:0:0:0:0 | | Other | | file://:0:0:0:0 | (global namespace) | Other | -| file://:0:0:0:0 | | Other | +| file://:0:0:0:0 | (unnamed global/namespace variable) | Other | | file://:0:0:0:0 | _Complex __float128 | Other | | file://:0:0:0:0 | _Complex double | Other | | file://:0:0:0:0 | _Complex float | Other | @@ -111,8 +111,8 @@ | test.c:0:0:0:0 | test.c | Other | | test.c:2:6:2:6 | a | Other | | test.c:2:6:2:6 | definition of a | Other | -| test.c:2:10:2:18 | | Variable access | +| test.c:2:10:2:18 | (unnamed global/namespace variable) | Variable access | | test.c:2:10:2:18 | array to pointer conversion | Other | | test.c:2:10:2:18 | initializer for a | Other | -| test.c:2:17:2:18 | initializer for | Other | +| test.c:2:17:2:18 | initializer for (unnamed global/namespace variable) | Other | | test.c:2:17:2:18 | {...} | Other | diff --git a/cpp/ql/test/library-tests/using-aliases/using-alias.ql b/cpp/ql/test/library-tests/using-aliases/using-alias.ql index 79287777e4b1..65a628996be3 100644 --- a/cpp/ql/test/library-tests/using-aliases/using-alias.ql +++ b/cpp/ql/test/library-tests/using-aliases/using-alias.ql @@ -1,4 +1,4 @@ import cpp from TypedefType t -select t, t.getCanonicalQLClass(), t.getUnderlyingType() +select t, t.getAPrimaryQlClass(), t.getUnderlyingType() diff --git a/cpp/ql/test/library-tests/variables/global/vardecl.expected b/cpp/ql/test/library-tests/variables/global/vardecl.expected new file mode 100644 index 000000000000..34339189e485 --- /dev/null +++ b/cpp/ql/test/library-tests/variables/global/vardecl.expected @@ -0,0 +1,6 @@ +| a.c:4:5:4:6 | definition of is | array of {int} | 1 | +| a.h:2:12:2:13 | declaration of is | array of 4 {int} | 1 | +| file://:0:0:0:0 | definition of fp_offset | unsigned int | 1 | +| file://:0:0:0:0 | definition of gp_offset | unsigned int | 1 | +| file://:0:0:0:0 | definition of overflow_arg_area | pointer to {void} | 1 | +| file://:0:0:0:0 | definition of reg_save_area | pointer to {void} | 1 | diff --git a/cpp/ql/test/library-tests/variables/global/vardecl.ql b/cpp/ql/test/library-tests/variables/global/vardecl.ql new file mode 100644 index 000000000000..52f902e1064c --- /dev/null +++ b/cpp/ql/test/library-tests/variables/global/vardecl.ql @@ -0,0 +1,5 @@ +import cpp + +from VariableDeclarationEntry vd, Type t +where t = vd.getType() +select vd, t.explain(), count(Type u | u = vd.getType()) diff --git a/cpp/ql/test/library-tests/variables/global/variables.expected b/cpp/ql/test/library-tests/variables/global/variables.expected index 7907cdb755a4..01ef82a0dcb8 100644 --- a/cpp/ql/test/library-tests/variables/global/variables.expected +++ b/cpp/ql/test/library-tests/variables/global/variables.expected @@ -1,5 +1,4 @@ -| a.c:4:5:4:6 | is | array of 4 {int} | 2 | -| a.c:4:5:4:6 | is | array of {int} | 2 | +| a.c:4:5:4:6 | is | array of {int} | 1 | | file://:0:0:0:0 | fp_offset | unsigned int | 1 | | file://:0:0:0:0 | gp_offset | unsigned int | 1 | | file://:0:0:0:0 | overflow_arg_area | pointer to {void} | 1 | diff --git a/cpp/ql/test/library-tests/vla/blocks.ql b/cpp/ql/test/library-tests/vla/blocks.ql index 4de353e388cd..bfd541e0162a 100644 --- a/cpp/ql/test/library-tests/vla/blocks.ql +++ b/cpp/ql/test/library-tests/vla/blocks.ql @@ -1,4 +1,4 @@ import cpp -from Block b, int i +from BlockStmt b, int i select b, i, b.getStmt(i) diff --git a/cpp/ql/test/query-tests/Best Practices/Hiding/DeclarationHidesParameter/DeclarationHidesParameter.expected b/cpp/ql/test/query-tests/Best Practices/Hiding/DeclarationHidesParameter/DeclarationHidesParameter.expected index a42d9db0c7a3..0e21d90fbcc4 100644 --- a/cpp/ql/test/query-tests/Best Practices/Hiding/DeclarationHidesParameter/DeclarationHidesParameter.expected +++ b/cpp/ql/test/query-tests/Best Practices/Hiding/DeclarationHidesParameter/DeclarationHidesParameter.expected @@ -1,2 +1,7 @@ | hiding.cpp:4:17:4:18 | ii | Local variable 'ii' hides a $@. | hiding.cpp:2:12:2:13 | definition of ii | parameter of the same name | | hiding.cpp:15:15:15:16 | kk | Local variable 'kk' hides a $@. | hiding.cpp:12:25:12:26 | definition of kk | parameter of the same name | +| hiding.cpp:28:7:28:7 | a | Local variable 'a' hides a $@. | hiding.cpp:26:21:26:21 | definition of a | parameter of the same name | +| hiding.cpp:45:7:45:7 | a | Local variable 'a' hides a $@. | hiding.cpp:43:41:43:41 | definition of a | parameter of the same name | +| hiding.cpp:64:11:64:11 | i | Local variable 'i' hides a $@. | hiding.cpp:61:20:61:20 | definition of i | parameter of the same name | +| hiding.cpp:78:7:78:10 | arg1 | Local variable 'arg1' hides a $@. | hiding.cpp:74:28:74:31 | definition of arg1 | parameter of the same name | +| hiding.cpp:79:5:79:8 | arg2 | Local variable 'arg2' hides a $@. | hiding.cpp:74:36:74:39 | definition of arg2 | parameter of the same name | diff --git a/cpp/ql/test/query-tests/Best Practices/Hiding/DeclarationHidesParameter/hiding.cpp b/cpp/ql/test/query-tests/Best Practices/Hiding/DeclarationHidesParameter/hiding.cpp index 8503155db4fb..0b08a0ae612f 100644 --- a/cpp/ql/test/query-tests/Best Practices/Hiding/DeclarationHidesParameter/hiding.cpp +++ b/cpp/ql/test/query-tests/Best Practices/Hiding/DeclarationHidesParameter/hiding.cpp @@ -1,7 +1,7 @@ void f(int ii) { if (1) { - for(int ii = 1; ii < 10; ii++) { + for(int ii = 1; ii < 10; ii++) { // local variable hides parameter of the same name ; } } @@ -12,7 +12,7 @@ namespace foo { void f2(int ii, int kk) { try { for (ii = 0; ii < 3; ii++) { - int kk; + int kk; // local variable hides parameter of the same name } } catch (int ee) { @@ -21,4 +21,61 @@ namespace foo { } } +void myFunction(int a, int b, int c); +void myFunction(int a, int b, int _c) { + { + int a = a; // local variable hides parameter of the same name + int _b = b; + int c = _c; + + // ... + } +} + +template +class MyTemplateClass { +public: + void myMethod(int a, int b, int c); +}; + +template +void MyTemplateClass :: myMethod(int a, int b, int _c) { + { + int a = a; // local variable hides parameter of the same name + int _b = b; + int c = _c; + + // ... + } +} + +MyTemplateClass mtc_i; + +void test() { + mtc_i.myMethod(0, 0, 0); +} + +#define MYMACRO for (int i = 0; i < 10; i++) {} + +void testMacro(int i) { + MYMACRO; + + for (int i = 0; i < 10; i++) {}; // local variable hides parameter of the same name +} + +#include "hiding.h" + +void myClass::myCaller(void) { + this->myMethod(5, 6); +} + +template +void myClass::myMethod(int arg1, T arg2) { + { + int protoArg1; + T protoArg2; + int arg1; // local variable hides parameter of the same name + T arg2; // local variable hides parameter of the same name + } +} diff --git a/cpp/ql/test/query-tests/Best Practices/Hiding/DeclarationHidesParameter/hiding.h b/cpp/ql/test/query-tests/Best Practices/Hiding/DeclarationHidesParameter/hiding.h new file mode 100644 index 000000000000..ee5d1b8f3a8e --- /dev/null +++ b/cpp/ql/test/query-tests/Best Practices/Hiding/DeclarationHidesParameter/hiding.h @@ -0,0 +1,7 @@ + +class myClass { +public: + template + void myMethod(int protoArg1, T protoArg2); + void myCaller(void); +}; diff --git a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.c b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.c index 9c56fda859c3..9fc257e3eebf 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.c @@ -365,7 +365,7 @@ int callCommand(void) return 0; } -int shifts(void) +void shifts(void) { unsigned int x = 3; @@ -374,7 +374,7 @@ int shifts(void) if (x >> 1 == 1) {} // always true [NOT DETECTED] } -int bitwise_ands() +void bitwise_ands() { unsigned int x = 0xFF; @@ -382,3 +382,42 @@ int bitwise_ands() if ((x & 2) >= 2) {} if ((x & 2) >= 3) {} // always false } + +void unsigned_mult(unsigned int x, unsigned int y) { + if(x < 13 && y < 35) { + if(x * y > 1024) {} // always false + if(x * y < 204) {} + if(x >= 3 && y >= 2) { + if(x * y < 5) {} // always false + } + } +} + +void mult_rounding() { + unsigned long x, y, xy; + x = y = 1000000003UL; // 1e9 + 3 + xy = 1000000006000000009UL; // x * y, precisely + // Even though the range analysis wrongly considers x*y to be xy - 9, there + // are no PointlessComparison false positives in these tests because alerts + // are suppressed when ulp() < 1, which roughly means that the number is + // larger than 2^53. + if (x * y < xy) {} // always false [NOT DETECTED] + if (x * y > xy) {} // always false [NOT DETECTED] +} + +void mult_overflow() { + unsigned long x, y; + // The following two numbers multiply to 2^64 + 1, which is 1 when truncated + // to 64-bit unsigned. + x = 274177UL; + y = 67280421310721UL; + if (x * y == 1) {} // always true [BUG: reported as always false] + + // This bug appears to be caused by + // `RangeAnalysisUtils::typeUpperBound(unsigned long)` having a result of + // 2**64 + 384, making the range analysis think that the multiplication can't + // overflow. The correct `typeUpperBound` would be 2**64 - 1, but we can't + // represent that with a QL float or int. We could make `typeUpperBound` + // exclusive instead of inclusive, but there is no exclusive upper bound for + // floats. +} diff --git a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.expected b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.expected index c2c6cf6f14df..6c273b985eeb 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.expected @@ -31,7 +31,7 @@ | PointlessComparison.c:126:12:126:18 | ... >= ... | Comparison is always true because a >= 20. | | PointlessComparison.c:129:12:129:16 | ... > ... | Comparison is always false because a <= 3. | | PointlessComparison.c:197:7:197:11 | ... < ... | Comparison is always false because x >= 0. | -| PointlessComparison.c:264:12:264:22 | ... >= ... | Comparison is always true because dbl >= 0 and -0 >= - .... | +| PointlessComparison.c:264:12:264:22 | ... >= ... | Comparison is always true because dbl >= 0 and 0 >= - .... | | PointlessComparison.c:273:9:273:18 | ... > ... | Comparison is always false because c <= 0. | | PointlessComparison.c:283:13:283:19 | ... >= ... | Comparison is always true because c >= 11. | | PointlessComparison.c:294:9:294:16 | ... >= ... | Comparison is always false because ui1 <= 0. | @@ -41,7 +41,10 @@ | PointlessComparison.c:372:6:372:16 | ... >= ... | Comparison is always true because ... >> ... >= 1. | | PointlessComparison.c:373:6:373:16 | ... >= ... | Comparison is always false because ... >> ... <= 1. | | PointlessComparison.c:383:6:383:17 | ... >= ... | Comparison is always false because ... & ... <= 2. | -| PointlessComparison.cpp:36:6:36:33 | ... >= ... | Comparison is always false because ... >> ... <= 9223372036854776000. | +| PointlessComparison.c:388:10:388:21 | ... > ... | Comparison is always false because ... * ... <= 408. | +| PointlessComparison.c:391:12:391:20 | ... < ... | Comparison is always false because ... * ... >= 6. | +| PointlessComparison.c:414:7:414:16 | ... == ... | Comparison is always false because ... * ... >= 18446744073709551616. | +| PointlessComparison.cpp:36:6:36:33 | ... >= ... | Comparison is always false because ... >> ... <= 9223372036854775808. | | PointlessComparison.cpp:41:6:41:29 | ... >= ... | Comparison is always false because ... >> ... <= 140737488355327.5. | | PointlessComparison.cpp:42:6:42:29 | ... >= ... | Comparison is always false because ... >> ... <= 140737488355327.5. | | PointlessComparison.cpp:43:6:43:29 | ... >= ... | Comparison is always true because ... >> ... >= 140737488355327.5. | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/RegressionTests.cpp b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/RegressionTests.cpp index ce12aa7d0efc..28d211a129ea 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/RegressionTests.cpp +++ b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/RegressionTests.cpp @@ -79,4 +79,40 @@ int containsIfDef(int x) { #endif return result >= 0; -} \ No newline at end of file +} + +void negativeZero1(int val) { + if (val >= 0) + { + val = -val; + } + if (val == 0) // GOOD [NO LONGER REPORTED] + ; +} + +void negativeZero2(int val) { + if (val >= 0) + { + val = 0 - val; + } + if (val == 0) // GOOD + ; +} + +void negativeZero3(int val) { + if (val >= 0) + { + val *= -1; + } + if (val == 0) // GOOD [NO LONGER REPORTED] + ; +} + +void negativeZero4(int val) { + if (val >= 0) + { + val = val * -1; + } + if (val == 0) // GOOD [NO LONGER REPORTED] + ; +} diff --git a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/inconsistentLoopDirection/inconsistentLoopDirection.cpp b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/inconsistentLoopDirection/inconsistentLoopDirection.cpp index e6e743382ed8..0642eb747c41 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/inconsistentLoopDirection/inconsistentLoopDirection.cpp +++ b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/inconsistentLoopDirection/inconsistentLoopDirection.cpp @@ -177,4 +177,43 @@ void FalseNegativeTestCases() for (int i = 100; i > 0; i += 2) {} // For comparison for (int i = 100; i > 0; i ++ ) {} // BUG -} \ No newline at end of file +} + +void IntendedOverflow(unsigned char p) +{ + const unsigned char m = 10; + unsigned char i; + signed char s; + + for (i = 63; i < 64; i--) {} // GOOD (legitimate way to count down with an unsigned) + for (i = 63; i < 128; i--) {} // DUBIOUS (could still be a typo?) + for (i = 63; i < 255; i--) {} // GOOD + + for (i = m - 1; i < m; i--) {} // GOOD + for (i = m - 2; i < m; i--) {} // DUBIOUS + for (i = m; i < m + 1; i--) {} // GOOD + + for (s = 63; s < 64; s--) {} // BAD (signed numbers don't wrap at 0 / at all) + for (s = m + 1; s < m; s--) {} // BAD (never runs) + + for (i = p - 1; i < p; i--) {} // GOOD + for (s = p - 1; s < p; s--) {} // BAD [NOT DETECTED] + + { + int n; + + n = 64; + for (i = n - 1; i < n; i--) {} // GOOD + n = 64; + for (i = n - 1; i < 64; i--) {} // GOOD + n = 64; + for (i = 63; i < n; i--) {} // GOOD + + n = 64; + for (s = n - 1; s < n; s--) {} // BAD [NOT DETECTED] + n = 64; + for (s = n - 1; s < 64; s--) {} // BAD + n = 64; + for (s = 63; s < n; s--) {} // BAD [NOT DETECTED] + } +} diff --git a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/inconsistentLoopDirection/inconsistentLoopDirection.expected b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/inconsistentLoopDirection/inconsistentLoopDirection.expected index f5ff346271f0..310a6d725f58 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/inconsistentLoopDirection/inconsistentLoopDirection.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/inconsistentLoopDirection/inconsistentLoopDirection.expected @@ -20,3 +20,6 @@ | inconsistentLoopDirection.cpp:140:5:142:5 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "i" counts upward from a value (200), but the terminal condition is lower (0). | | inconsistentLoopDirection.cpp:175:5:175:36 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "i" counts downward from a value (0), but the terminal condition is higher (10). | | inconsistentLoopDirection.cpp:179:5:179:38 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "i" counts upward from a value (100), but the terminal condition is lower (0). | +| inconsistentLoopDirection.cpp:196:5:196:32 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "s" counts downward from a value (63), but the terminal condition is higher (64). | +| inconsistentLoopDirection.cpp:197:5:197:34 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "s" counts downward from a value (... + ...), but the terminal condition is always false. | +| inconsistentLoopDirection.cpp:215:3:215:33 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "s" counts downward from a value (... - ...), but the terminal condition is higher (64). | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected index 14dedbdebed8..dcc6ba8be889 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected @@ -1,6 +1,4 @@ -| test.c:33:3:33:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:32:3:32:3 | not_yet_declared2 | not_yet_declared2 | test.c:33:21:33:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:76:24:76:26 | p#0 | int p#0 | | test.c:33:3:33:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:32:3:32:3 | not_yet_declared2 | not_yet_declared2 | test.c:33:21:33:22 | ca | ca | file://:0:0:0:0 | int[4] | int[4] | test.c:76:24:76:26 | p#0 | int p#0 | -| test.c:33:3:33:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:76:6:76:22 | not_yet_declared2 | not_yet_declared2 | test.c:33:21:33:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:76:24:76:26 | p#0 | int p#0 | | test.c:33:3:33:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:76:6:76:22 | not_yet_declared2 | not_yet_declared2 | test.c:33:21:33:22 | ca | ca | file://:0:0:0:0 | int[4] | int[4] | test.c:76:24:76:26 | p#0 | int p#0 | | test.c:40:3:40:29 | call to declared_empty_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:77:6:77:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:40:31:40:32 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:77:38:77:38 | x | int x | | test.c:44:3:44:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:80:6:80:30 | not_declared_defined_with | not_declared_defined_with | test.c:44:29:44:31 | 4 | 4 | file://:0:0:0:0 | long long | long long | test.c:80:36:80:36 | x | int x | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected index 17bb67fdc082..20bb97a9f663 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected @@ -4,12 +4,10 @@ edges | search.c:14:24:14:28 | query | search.c:17:8:17:12 | query | | search.c:22:24:22:28 | query | search.c:23:39:23:43 | query | | search.c:22:24:22:28 | query | search.c:23:39:23:43 | query | -| search.c:41:21:41:26 | call to getenv | search.c:45:17:45:25 | raw_query | -| search.c:41:21:41:26 | call to getenv | search.c:45:17:45:25 | raw_query | -| search.c:41:21:41:26 | call to getenv | search.c:47:17:47:25 | raw_query | -| search.c:41:21:41:26 | call to getenv | search.c:47:17:47:25 | raw_query | -| search.c:45:17:45:25 | raw_query | search.c:14:24:14:28 | query | -| search.c:47:17:47:25 | raw_query | search.c:22:24:22:28 | query | +| search.c:41:21:41:26 | call to getenv | search.c:14:24:14:28 | query | +| search.c:41:21:41:26 | call to getenv | search.c:14:24:14:28 | query | +| search.c:41:21:41:26 | call to getenv | search.c:22:24:22:28 | query | +| search.c:41:21:41:26 | call to getenv | search.c:22:24:22:28 | query | nodes | search.c:14:24:14:28 | query | semmle.label | query | | search.c:17:8:17:12 | (const char *)... | semmle.label | (const char *)... | @@ -23,8 +21,8 @@ nodes | search.c:23:39:23:43 | query | semmle.label | query | | search.c:41:21:41:26 | call to getenv | semmle.label | call to getenv | | search.c:41:21:41:26 | call to getenv | semmle.label | call to getenv | -| search.c:45:17:45:25 | raw_query | semmle.label | raw_query | -| search.c:47:17:47:25 | raw_query | semmle.label | raw_query | +| search.c:45:5:45:15 | Argument 0 | semmle.label | Argument 0 | +| search.c:47:5:47:15 | Argument 0 | semmle.label | Argument 0 | #select | search.c:17:8:17:12 | query | search.c:41:21:41:26 | call to getenv | search.c:17:8:17:12 | query | Cross-site scripting vulnerability due to $@. | search.c:41:21:41:26 | call to getenv | this query data | | search.c:23:39:23:43 | query | search.c:41:21:41:26 | call to getenv | search.c:23:39:23:43 | query | Cross-site scripting vulnerability due to $@. | search.c:41:21:41:26 | call to getenv | this query data | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected index f84c6719157a..94c1e3383fee 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected @@ -7,6 +7,22 @@ edges | test.cpp:42:18:42:34 | (const char *)... | test.cpp:24:30:24:36 | command | | test.cpp:43:18:43:23 | call to getenv | test.cpp:29:30:29:36 | command | | test.cpp:43:18:43:34 | (const char *)... | test.cpp:29:30:29:36 | command | +| test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | (const char *)... | +| test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer | +| test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | (const char *)... | +| test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | data | +| test.cpp:56:12:56:17 | fgets output argument | test.cpp:62:10:62:15 | (const char *)... | +| test.cpp:56:12:56:17 | fgets output argument | test.cpp:62:10:62:15 | buffer | +| test.cpp:56:12:56:17 | fgets output argument | test.cpp:63:10:63:13 | (const char *)... | +| test.cpp:56:12:56:17 | fgets output argument | test.cpp:63:10:63:13 | data | +| test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | (const char *)... | +| test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer | +| test.cpp:76:12:76:17 | buffer | test.cpp:79:10:79:13 | (const char *)... | +| test.cpp:76:12:76:17 | buffer | test.cpp:79:10:79:13 | data | +| test.cpp:76:12:76:17 | fgets output argument | test.cpp:78:10:78:15 | (const char *)... | +| test.cpp:76:12:76:17 | fgets output argument | test.cpp:78:10:78:15 | buffer | +| test.cpp:76:12:76:17 | fgets output argument | test.cpp:79:10:79:13 | (const char *)... | +| test.cpp:76:12:76:17 | fgets output argument | test.cpp:79:10:79:13 | data | nodes | test.cpp:24:30:24:36 | command | semmle.label | command | | test.cpp:26:10:26:16 | command | semmle.label | command | @@ -16,10 +32,32 @@ nodes | test.cpp:31:10:31:16 | command | semmle.label | command | | test.cpp:31:10:31:16 | command | semmle.label | command | | test.cpp:31:10:31:16 | command | semmle.label | command | +| test.cpp:42:7:42:16 | Argument 0 | semmle.label | Argument 0 | | test.cpp:42:18:42:23 | call to getenv | semmle.label | call to getenv | | test.cpp:42:18:42:34 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:43:7:43:16 | Argument 0 | semmle.label | Argument 0 | | test.cpp:43:18:43:23 | call to getenv | semmle.label | call to getenv | | test.cpp:43:18:43:34 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:56:12:56:17 | buffer | semmle.label | buffer | +| test.cpp:56:12:56:17 | fgets output argument | semmle.label | fgets output argument | +| test.cpp:62:10:62:15 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:62:10:62:15 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:62:10:62:15 | buffer | semmle.label | buffer | +| test.cpp:63:10:63:13 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:63:10:63:13 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:63:10:63:13 | data | semmle.label | data | +| test.cpp:76:12:76:17 | buffer | semmle.label | buffer | +| test.cpp:76:12:76:17 | fgets output argument | semmle.label | fgets output argument | +| test.cpp:78:10:78:15 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:78:10:78:15 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:78:10:78:15 | buffer | semmle.label | buffer | +| test.cpp:79:10:79:13 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:79:10:79:13 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:79:10:79:13 | data | semmle.label | data | #select | test.cpp:26:10:26:16 | command | test.cpp:42:18:42:23 | call to getenv | test.cpp:26:10:26:16 | command | The value of this argument may come from $@ and is being passed to system | test.cpp:42:18:42:23 | call to getenv | call to getenv | | test.cpp:31:10:31:16 | command | test.cpp:43:18:43:23 | call to getenv | test.cpp:31:10:31:16 | command | The value of this argument may come from $@ and is being passed to system | test.cpp:43:18:43:23 | call to getenv | call to getenv | +| test.cpp:62:10:62:15 | buffer | test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer | The value of this argument may come from $@ and is being passed to system | test.cpp:56:12:56:17 | buffer | buffer | +| test.cpp:63:10:63:13 | data | test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | data | The value of this argument may come from $@ and is being passed to system | test.cpp:56:12:56:17 | buffer | buffer | +| test.cpp:78:10:78:15 | buffer | test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer | The value of this argument may come from $@ and is being passed to system | test.cpp:76:12:76:17 | buffer | buffer | +| test.cpp:79:10:79:13 | data | test.cpp:76:12:76:17 | buffer | test.cpp:79:10:79:13 | data | The value of this argument may come from $@ and is being passed to system | test.cpp:76:12:76:17 | buffer | buffer | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/test.cpp index 83a67f44417c..eb9436bcadb3 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/test.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/test.cpp @@ -42,3 +42,42 @@ void testMyDerived() md2->doCommand2(getenv("varname")); md3->doCommand3(getenv("varname")); } + +// --- + +typedef struct {} FILE; +char *fgets(char *s, int n, FILE *stream); +FILE *stdin; + +void testReferencePointer1() +{ + char buffer[1024]; + + if (fgets(buffer, 1024, stdin) != 0) + { + char *data = buffer; + char *&dataref = data; + char *data2 = dataref; + + system(buffer); // BAD + system(data); // BAD + system(dataref); // BAD [NOT DETECTED] + system(data2); // BAD [NOT DETECTED] + } +} + +void testReferencePointer2() +{ + char buffer[1024]; + char *data = buffer; + char *&dataref = data; + char *data2 = dataref; + + if (fgets(buffer, 1024, stdin) != 0) + { + system(buffer); // BAD + system(data); // BAD + system(dataref); // BAD [NOT DETECTED] + system(data2); // BAD [NOT DETECTED] + } +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/UnboundedWrite.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/UnboundedWrite.expected index 291c1cb3a716..365f9ed0aa97 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/UnboundedWrite.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/UnboundedWrite.expected @@ -5,6 +5,10 @@ edges | tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | | tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | | tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | +| tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | +| tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | +| tests.c:28:22:28:28 | access to array | tests.c:28:22:28:28 | (const char *)... | +| tests.c:28:22:28:28 | access to array | tests.c:28:22:28:28 | access to array | | tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array | | tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array | | tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array | @@ -15,6 +19,10 @@ edges | tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array | | tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array | | tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array | +| tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array | +| tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array | +| tests.c:34:10:34:16 | access to array | tests.c:34:10:34:16 | (const char *)... | +| tests.c:34:10:34:16 | access to array | tests.c:34:10:34:16 | access to array | nodes | tests.c:28:22:28:25 | argv | semmle.label | argv | | tests.c:28:22:28:25 | argv | semmle.label | argv | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected index 1d92afdeb040..ac52436676c5 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected @@ -5,6 +5,10 @@ edges | argvLocal.c:95:9:95:12 | argv | argvLocal.c:95:9:95:15 | access to array | | argvLocal.c:95:9:95:12 | argv | argvLocal.c:95:9:95:15 | access to array | | argvLocal.c:95:9:95:12 | argv | argvLocal.c:95:9:95:15 | access to array | +| argvLocal.c:95:9:95:12 | argv | argvLocal.c:95:9:95:15 | access to array | +| argvLocal.c:95:9:95:12 | argv | argvLocal.c:95:9:95:15 | access to array | +| argvLocal.c:95:9:95:15 | access to array | argvLocal.c:95:9:95:15 | (const char *)... | +| argvLocal.c:95:9:95:15 | access to array | argvLocal.c:95:9:95:15 | access to array | | argvLocal.c:96:15:96:18 | argv | argvLocal.c:96:15:96:21 | access to array | | argvLocal.c:96:15:96:18 | argv | argvLocal.c:96:15:96:21 | access to array | | argvLocal.c:96:15:96:18 | argv | argvLocal.c:96:15:96:21 | access to array | @@ -35,6 +39,8 @@ edges | argvLocal.c:105:14:105:17 | argv | argvLocal.c:106:9:106:13 | access to array | | argvLocal.c:105:14:105:17 | argv | argvLocal.c:106:9:106:13 | access to array | | argvLocal.c:105:14:105:17 | argv | argvLocal.c:106:9:106:13 | access to array | +| argvLocal.c:105:14:105:17 | argv | argvLocal.c:106:9:106:13 | access to array | +| argvLocal.c:105:14:105:17 | argv | argvLocal.c:106:9:106:13 | access to array | | argvLocal.c:105:14:105:17 | argv | argvLocal.c:107:15:107:19 | access to array | | argvLocal.c:105:14:105:17 | argv | argvLocal.c:107:15:107:19 | access to array | | argvLocal.c:105:14:105:17 | argv | argvLocal.c:107:15:107:19 | access to array | @@ -45,34 +51,36 @@ edges | argvLocal.c:105:14:105:17 | argv | argvLocal.c:110:9:110:11 | * ... | | argvLocal.c:105:14:105:17 | argv | argvLocal.c:110:9:110:11 | * ... | | argvLocal.c:105:14:105:17 | argv | argvLocal.c:110:9:110:11 | * ... | +| argvLocal.c:105:14:105:17 | argv | argvLocal.c:110:9:110:11 | * ... | +| argvLocal.c:105:14:105:17 | argv | argvLocal.c:110:9:110:11 | * ... | | argvLocal.c:105:14:105:17 | argv | argvLocal.c:111:15:111:17 | * ... | | argvLocal.c:105:14:105:17 | argv | argvLocal.c:111:15:111:17 | * ... | | argvLocal.c:105:14:105:17 | argv | argvLocal.c:111:15:111:17 | * ... | | argvLocal.c:105:14:105:17 | argv | argvLocal.c:111:15:111:17 | * ... | +| argvLocal.c:106:9:106:13 | access to array | argvLocal.c:106:9:106:13 | (const char *)... | +| argvLocal.c:106:9:106:13 | access to array | argvLocal.c:106:9:106:13 | access to array | +| argvLocal.c:110:9:110:11 | * ... | argvLocal.c:110:9:110:11 | (const char *)... | +| argvLocal.c:110:9:110:11 | * ... | argvLocal.c:110:9:110:11 | * ... | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:116:9:116:10 | (const char *)... | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:116:9:116:10 | (const char *)... | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:116:9:116:10 | i3 | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:116:9:116:10 | i3 | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | Argument 0 indirection | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | Argument 0 indirection | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | array to pointer conversion | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | array to pointer conversion | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | array to pointer conversion | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | array to pointer conversion | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | i3 | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | i3 | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | printWrapper output argument | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | printWrapper output argument | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:121:9:121:10 | (const char *)... | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:121:9:121:10 | (const char *)... | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:121:9:121:10 | i4 | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:121:9:121:10 | i4 | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | Argument 0 indirection | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | Argument 0 indirection | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | i4 | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | i4 | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | i4 | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | i4 | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | i4 | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | i4 | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | printWrapper output argument | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | printWrapper output argument | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:135:9:135:12 | (const char *)... | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:135:9:135:12 | (const char *)... | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:135:9:135:12 | ... ++ | @@ -81,20 +89,15 @@ edges | argvLocal.c:115:13:115:16 | argv | argvLocal.c:136:15:136:18 | -- ... | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:136:15:136:18 | -- ... | | argvLocal.c:115:13:115:16 | argv | argvLocal.c:136:15:136:18 | -- ... | -| argvLocal.c:117:15:117:16 | Argument 0 indirection | argvLocal.c:117:15:117:16 | printWrapper output argument | -| argvLocal.c:117:15:117:16 | array to pointer conversion | argvLocal.c:117:15:117:16 | printWrapper output argument | | argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:121:9:121:10 | (const char *)... | | argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:121:9:121:10 | i4 | -| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:122:15:122:16 | Argument 0 indirection | -| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:122:15:122:16 | i4 | | argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:122:15:122:16 | i4 | | argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:122:15:122:16 | i4 | +| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:122:15:122:16 | printWrapper output argument | | argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:135:9:135:12 | (const char *)... | | argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:135:9:135:12 | ... ++ | | argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:136:15:136:18 | -- ... | | argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:136:15:136:18 | -- ... | -| argvLocal.c:122:15:122:16 | Argument 0 indirection | argvLocal.c:122:15:122:16 | printWrapper output argument | -| argvLocal.c:122:15:122:16 | i4 | argvLocal.c:122:15:122:16 | printWrapper output argument | | argvLocal.c:122:15:122:16 | printWrapper output argument | argvLocal.c:135:9:135:12 | (const char *)... | | argvLocal.c:122:15:122:16 | printWrapper output argument | argvLocal.c:135:9:135:12 | ... ++ | | argvLocal.c:122:15:122:16 | printWrapper output argument | argvLocal.c:136:15:136:18 | -- ... | @@ -103,14 +106,12 @@ edges | argvLocal.c:126:10:126:13 | argv | argvLocal.c:127:9:127:10 | (const char *)... | | argvLocal.c:126:10:126:13 | argv | argvLocal.c:127:9:127:10 | i5 | | argvLocal.c:126:10:126:13 | argv | argvLocal.c:127:9:127:10 | i5 | -| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | Argument 0 indirection | -| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | Argument 0 indirection | -| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | array to pointer conversion | -| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | array to pointer conversion | | argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | array to pointer conversion | | argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | array to pointer conversion | | argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | i5 | | argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | i5 | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | printWrapper output argument | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | printWrapper output argument | | argvLocal.c:126:10:126:13 | argv | argvLocal.c:131:9:131:14 | (const char *)... | | argvLocal.c:126:10:126:13 | argv | argvLocal.c:131:9:131:14 | (const char *)... | | argvLocal.c:126:10:126:13 | argv | argvLocal.c:131:9:131:14 | ... + ... | @@ -119,8 +120,6 @@ edges | argvLocal.c:126:10:126:13 | argv | argvLocal.c:132:15:132:20 | ... + ... | | argvLocal.c:126:10:126:13 | argv | argvLocal.c:132:15:132:20 | ... + ... | | argvLocal.c:126:10:126:13 | argv | argvLocal.c:132:15:132:20 | ... + ... | -| argvLocal.c:128:15:128:16 | Argument 0 indirection | argvLocal.c:128:15:128:16 | printWrapper output argument | -| argvLocal.c:128:15:128:16 | array to pointer conversion | argvLocal.c:128:15:128:16 | printWrapper output argument | | argvLocal.c:128:15:128:16 | printWrapper output argument | argvLocal.c:131:9:131:14 | (const char *)... | | argvLocal.c:128:15:128:16 | printWrapper output argument | argvLocal.c:131:9:131:14 | ... + ... | | argvLocal.c:128:15:128:16 | printWrapper output argument | argvLocal.c:132:15:132:20 | ... + ... | @@ -215,6 +214,7 @@ nodes | argvLocal.c:116:9:116:10 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:116:9:116:10 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:116:9:116:10 | i3 | semmle.label | i3 | +| argvLocal.c:117:2:117:13 | Argument 0 | semmle.label | Argument 0 | | argvLocal.c:117:15:117:16 | Argument 0 indirection | semmle.label | Argument 0 indirection | | argvLocal.c:117:15:117:16 | array to pointer conversion | semmle.label | array to pointer conversion | | argvLocal.c:117:15:117:16 | array to pointer conversion | semmle.label | array to pointer conversion | @@ -223,6 +223,7 @@ nodes | argvLocal.c:121:9:121:10 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:121:9:121:10 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:121:9:121:10 | i4 | semmle.label | i4 | +| argvLocal.c:122:2:122:13 | Argument 0 | semmle.label | Argument 0 | | argvLocal.c:122:15:122:16 | Argument 0 indirection | semmle.label | Argument 0 indirection | | argvLocal.c:122:15:122:16 | i4 | semmle.label | i4 | | argvLocal.c:122:15:122:16 | i4 | semmle.label | i4 | @@ -233,6 +234,7 @@ nodes | argvLocal.c:127:9:127:10 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:127:9:127:10 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:127:9:127:10 | i5 | semmle.label | i5 | +| argvLocal.c:128:2:128:13 | Argument 0 | semmle.label | Argument 0 | | argvLocal.c:128:15:128:16 | Argument 0 indirection | semmle.label | Argument 0 indirection | | argvLocal.c:128:15:128:16 | array to pointer conversion | semmle.label | array to pointer conversion | | argvLocal.c:128:15:128:16 | array to pointer conversion | semmle.label | array to pointer conversion | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected index ba735a3e140a..00f98ac48be7 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected @@ -13,6 +13,8 @@ edges | globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 | | globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 | | globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 | +| globalVars.c:11:22:11:25 | *argv | globalVars.c:12:2:12:15 | Store | +| globalVars.c:11:22:11:25 | argv | globalVars.c:11:22:11:25 | *argv | | globalVars.c:11:22:11:25 | argv | globalVars.c:12:2:12:15 | Store | | globalVars.c:12:2:12:15 | Store | globalVars.c:8:7:8:10 | copy | | globalVars.c:15:21:15:23 | val | globalVars.c:16:2:16:12 | Store | @@ -29,10 +31,12 @@ edges nodes | globalVars.c:8:7:8:10 | copy | semmle.label | copy | | globalVars.c:9:7:9:11 | copy2 | semmle.label | copy2 | +| globalVars.c:11:22:11:25 | *argv | semmle.label | *argv | | globalVars.c:11:22:11:25 | argv | semmle.label | argv | | globalVars.c:12:2:12:15 | Store | semmle.label | Store | | globalVars.c:15:21:15:23 | val | semmle.label | val | | globalVars.c:16:2:16:12 | Store | semmle.label | Store | +| globalVars.c:24:2:24:9 | Argument 0 | semmle.label | Argument 0 | | globalVars.c:24:11:24:14 | argv | semmle.label | argv | | globalVars.c:24:11:24:14 | argv | semmle.label | argv | | globalVars.c:27:9:27:12 | (const char *)... | semmle.label | (const char *)... | @@ -43,6 +47,7 @@ nodes | globalVars.c:30:15:30:18 | copy | semmle.label | copy | | globalVars.c:30:15:30:18 | copy | semmle.label | copy | | globalVars.c:30:15:30:18 | copy | semmle.label | copy | +| globalVars.c:35:2:35:9 | Argument 0 | semmle.label | Argument 0 | | globalVars.c:35:11:35:14 | copy | semmle.label | copy | | globalVars.c:38:9:38:13 | (const char *)... | semmle.label | (const char *)... | | globalVars.c:38:9:38:13 | (const char *)... | semmle.label | (const char *)... | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected index 8aa79b5bb6d9..a60e361fc1e6 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected @@ -47,30 +47,31 @@ edges | test.cpp:214:23:214:23 | s | test.cpp:215:21:215:21 | s | | test.cpp:220:21:220:21 | s | test.cpp:221:21:221:21 | s | | test.cpp:220:21:220:21 | s | test.cpp:221:21:221:21 | s | +| test.cpp:227:24:227:29 | call to getenv | test.cpp:214:23:214:23 | s | +| test.cpp:227:24:227:29 | call to getenv | test.cpp:220:21:220:21 | s | | test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | (size_t)... | | test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | local_size | | test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | local_size | -| test.cpp:227:24:227:29 | call to getenv | test.cpp:235:11:235:20 | (size_t)... | -| test.cpp:227:24:227:29 | call to getenv | test.cpp:237:10:237:19 | (size_t)... | +| test.cpp:227:24:227:37 | (const char *)... | test.cpp:214:23:214:23 | s | +| test.cpp:227:24:227:37 | (const char *)... | test.cpp:220:21:220:21 | s | | test.cpp:227:24:227:37 | (const char *)... | test.cpp:229:9:229:18 | (size_t)... | | test.cpp:227:24:227:37 | (const char *)... | test.cpp:229:9:229:18 | local_size | | test.cpp:227:24:227:37 | (const char *)... | test.cpp:229:9:229:18 | local_size | -| test.cpp:227:24:227:37 | (const char *)... | test.cpp:235:11:235:20 | (size_t)... | -| test.cpp:227:24:227:37 | (const char *)... | test.cpp:237:10:237:19 | (size_t)... | -| test.cpp:235:11:235:20 | (size_t)... | test.cpp:214:23:214:23 | s | -| test.cpp:237:10:237:19 | (size_t)... | test.cpp:220:21:220:21 | s | -| test.cpp:241:2:241:32 | Chi | test.cpp:279:17:279:20 | get_size output argument | -| test.cpp:241:2:241:32 | Chi | test.cpp:295:18:295:21 | get_size output argument | -| test.cpp:241:18:241:23 | call to getenv | test.cpp:241:2:241:32 | Chi | -| test.cpp:241:18:241:31 | (const char *)... | test.cpp:241:2:241:32 | Chi | +| test.cpp:241:2:241:32 | Chi [array content] | test.cpp:279:17:279:20 | get_size output argument [array content] | +| test.cpp:241:2:241:32 | Chi [array content] | test.cpp:295:18:295:21 | get_size output argument [array content] | +| test.cpp:241:2:241:32 | Store | test.cpp:241:2:241:32 | Chi [array content] | +| test.cpp:241:18:241:23 | call to getenv | test.cpp:241:2:241:32 | Store | +| test.cpp:241:18:241:31 | (const char *)... | test.cpp:241:2:241:32 | Store | | test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | | test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | | test.cpp:249:20:249:33 | (const char *)... | test.cpp:253:11:253:29 | ... * ... | | test.cpp:249:20:249:33 | (const char *)... | test.cpp:253:11:253:29 | ... * ... | -| test.cpp:279:17:279:20 | get_size output argument | test.cpp:281:11:281:28 | ... * ... | -| test.cpp:279:17:279:20 | get_size output argument | test.cpp:281:11:281:28 | ... * ... | -| test.cpp:295:18:295:21 | get_size output argument | test.cpp:298:10:298:27 | ... * ... | -| test.cpp:295:18:295:21 | get_size output argument | test.cpp:298:10:298:27 | ... * ... | +| test.cpp:279:17:279:20 | Chi | test.cpp:281:11:281:28 | ... * ... | +| test.cpp:279:17:279:20 | Chi | test.cpp:281:11:281:28 | ... * ... | +| test.cpp:279:17:279:20 | get_size output argument [array content] | test.cpp:279:17:279:20 | Chi | +| test.cpp:295:18:295:21 | Chi | test.cpp:298:10:298:27 | ... * ... | +| test.cpp:295:18:295:21 | Chi | test.cpp:298:10:298:27 | ... * ... | +| test.cpp:295:18:295:21 | get_size output argument [array content] | test.cpp:295:18:295:21 | Chi | | test.cpp:301:19:301:24 | call to getenv | test.cpp:305:11:305:28 | ... * ... | | test.cpp:301:19:301:24 | call to getenv | test.cpp:305:11:305:28 | ... * ... | | test.cpp:301:19:301:32 | (const char *)... | test.cpp:305:11:305:28 | ... * ... | @@ -140,9 +141,10 @@ nodes | test.cpp:231:9:231:24 | call to get_tainted_size | semmle.label | call to get_tainted_size | | test.cpp:231:9:231:24 | call to get_tainted_size | semmle.label | call to get_tainted_size | | test.cpp:231:9:231:24 | call to get_tainted_size | semmle.label | call to get_tainted_size | -| test.cpp:235:11:235:20 | (size_t)... | semmle.label | (size_t)... | -| test.cpp:237:10:237:19 | (size_t)... | semmle.label | (size_t)... | -| test.cpp:241:2:241:32 | Chi | semmle.label | Chi | +| test.cpp:235:2:235:9 | Argument 0 | semmle.label | Argument 0 | +| test.cpp:237:2:237:8 | Argument 0 | semmle.label | Argument 0 | +| test.cpp:241:2:241:32 | Chi [array content] | semmle.label | Chi [array content] | +| test.cpp:241:2:241:32 | Store | semmle.label | Store | | test.cpp:241:18:241:23 | call to getenv | semmle.label | call to getenv | | test.cpp:241:18:241:31 | (const char *)... | semmle.label | (const char *)... | | test.cpp:249:20:249:25 | call to getenv | semmle.label | call to getenv | @@ -150,11 +152,13 @@ nodes | test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | | test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | | test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | -| test.cpp:279:17:279:20 | get_size output argument | semmle.label | get_size output argument | +| test.cpp:279:17:279:20 | Chi | semmle.label | Chi | +| test.cpp:279:17:279:20 | get_size output argument [array content] | semmle.label | get_size output argument [array content] | | test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | | test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | | test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | -| test.cpp:295:18:295:21 | get_size output argument | semmle.label | get_size output argument | +| test.cpp:295:18:295:21 | Chi | semmle.label | Chi | +| test.cpp:295:18:295:21 | get_size output argument [array content] | semmle.label | get_size output argument [array content] | | test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | | test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | | test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/ArithmeticTainted.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/ArithmeticTainted.expected index b74dd08dd76e..8bb25025b868 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/ArithmeticTainted.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/ArithmeticTainted.expected @@ -1,3 +1,5 @@ +| test2.cpp:14:11:14:11 | v | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test2.cpp:25:22:25:23 | & ... | User-provided value | +| test2.cpp:14:11:14:11 | v | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test2.cpp:25:22:25:23 | & ... | User-provided value | | test3.c:15:10:15:10 | x | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test3.c:11:15:11:18 | argv | User-provided value | | test3.c:15:14:15:14 | y | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test3.c:11:15:11:18 | argv | User-provided value | | test3.c:15:18:15:18 | z | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test3.c:11:15:11:18 | argv | User-provided value | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/IntegerOverflowTainted.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/IntegerOverflowTainted.expected index d2b6499d40e2..e71cacde76ce 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/IntegerOverflowTainted.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/IntegerOverflowTainted.expected @@ -1,6 +1,16 @@ +| test2.cpp:14:11:14:15 | ... * ... | $@ flows to here and is used in an expression which might overflow. | test2.cpp:25:22:25:23 | & ... | User-provided value | +| test2.cpp:15:11:15:19 | ... * ... | $@ flows to here and is used in an expression which might overflow. | test2.cpp:25:22:25:23 | & ... | User-provided value | +| test2.cpp:16:11:16:21 | ... * ... | $@ flows to here and is used in an expression which might overflow. | test2.cpp:25:22:25:23 | & ... | User-provided value | +| test2.cpp:17:11:17:22 | ... * ... | $@ flows to here and is used in an expression which might overflow. | test2.cpp:25:22:25:23 | & ... | User-provided value | | test3.c:12:31:12:34 | * ... | $@ flows to here and is used in an expression which might overflow negatively. | test3.c:11:15:11:18 | argv | User-provided value | | test3.c:13:16:13:19 | * ... | $@ flows to here and is used in an expression which might overflow negatively. | test3.c:11:15:11:18 | argv | User-provided value | | test4.cpp:13:17:13:20 | access to array | $@ flows to here and is used in an expression which might overflow negatively. | test4.cpp:9:13:9:16 | argv | User-provided value | | test5.cpp:10:9:10:15 | call to strtoul | $@ flows to here and is used in an expression which might overflow. | test5.cpp:9:7:9:9 | buf | User-provided value | +| test5.cpp:17:6:17:27 | ... * ... | $@ flows to here and is used in an expression which might overflow. | test5.cpp:9:7:9:9 | buf | User-provided value | +| test5.cpp:19:6:19:13 | ... * ... | $@ flows to here and is used in an expression which might overflow. | test5.cpp:9:7:9:9 | buf | User-provided value | +| test6.cpp:11:15:11:15 | s | $@ flows to here and is used in an expression which might overflow. | test6.cpp:39:23:39:24 | & ... | User-provided value | +| test6.cpp:16:15:16:15 | s | $@ flows to here and is used in an expression which might overflow. | test6.cpp:39:23:39:24 | & ... | User-provided value | +| test6.cpp:30:16:30:16 | s | $@ flows to here and is used in an expression which might overflow. | test6.cpp:39:23:39:24 | & ... | User-provided value | +| test.c:14:15:14:35 | ... * ... | $@ flows to here and is used in an expression which might overflow. | test.c:11:29:11:32 | argv | User-provided value | | test.c:44:7:44:12 | ... -- | $@ flows to here and is used in an expression which might overflow negatively. | test.c:41:17:41:20 | argv | User-provided value | | test.c:54:7:54:12 | ... -- | $@ flows to here and is used in an expression which might overflow negatively. | test.c:51:17:51:20 | argv | User-provided value | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/test2.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/test2.cpp new file mode 100644 index 000000000000..eabbd2747033 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/test2.cpp @@ -0,0 +1,28 @@ + +typedef signed long long int s64; + +typedef struct {} FILE; +int fscanf(FILE *stream, const char *format, ...); +FILE *stdin; + +typedef struct _myStruct { + s64 val; +} MyStruct; + +void test2_sink(s64 v, MyStruct s, MyStruct &s_r, MyStruct *s_p) +{ + s64 v1 = v * 2; // bad + s64 v2 = s.val * 2; // bad + s64 v3 = s_r.val * 2; // bad + s64 v4 = s_p->val * 2; // bad +} + +void test2_source() +{ + MyStruct ms; + s64 v; + + fscanf(stdin, "%i", &v); + ms.val = v; + test2_sink(v, ms, ms, &ms); +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/test6.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/test6.cpp new file mode 100644 index 000000000000..c7034e6cd0ea --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/test6.cpp @@ -0,0 +1,54 @@ + +typedef unsigned short u16; +typedef unsigned int u32; + +typedef struct {} FILE; +int fscanf(FILE *stream, const char *format, ...); +FILE *stdin; + +void docast1(u32 s) +{ + u16 c = (u16)s; // bad +} + +void docast2(u32 s) +{ + u16 c = (u16)s; // bad +} + +class MyBaseClass +{ +public: + virtual void docast(u32 s) = 0; +}; + +class MyDerivedClass : public MyBaseClass +{ +public: + void docast(u32 s) + { + u16 c = (u16)s; // bad + } +}; + +void test6() +{ + u32 s; + + s = -1; + fscanf(stdin, "%hd", &s); + + docast1(s); + { + void (*docast2_ptr)(u32) = &docast2; + + docast2_ptr(s); + } + { + MyBaseClass *mbc = new MyDerivedClass; + + mbc->docast(s); + + delete mbc; + } +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/ArithmeticUncontrolled.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/ArithmeticUncontrolled.expected index f68464b6b38f..6a8976532654 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/ArithmeticUncontrolled.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/ArithmeticUncontrolled.expected @@ -42,18 +42,22 @@ edges | test.cpp:8:9:8:12 | Store | test.cpp:24:11:24:18 | call to get_rand | | test.cpp:8:9:8:12 | call to rand | test.cpp:8:9:8:12 | Store | | test.cpp:8:9:8:12 | call to rand | test.cpp:8:9:8:12 | Store | -| test.cpp:13:2:13:15 | Chi | test.cpp:30:13:30:14 | get_rand2 output argument | -| test.cpp:13:10:13:13 | call to rand | test.cpp:13:2:13:15 | Chi | -| test.cpp:13:10:13:13 | call to rand | test.cpp:13:2:13:15 | Chi | -| test.cpp:18:2:18:14 | Chi | test.cpp:36:13:36:13 | get_rand3 output argument | -| test.cpp:18:9:18:12 | call to rand | test.cpp:18:2:18:14 | Chi | -| test.cpp:18:9:18:12 | call to rand | test.cpp:18:2:18:14 | Chi | +| test.cpp:13:2:13:15 | Chi [array content] | test.cpp:30:13:30:14 | get_rand2 output argument [array content] | +| test.cpp:13:2:13:15 | Store | test.cpp:13:2:13:15 | Chi [array content] | +| test.cpp:13:10:13:13 | call to rand | test.cpp:13:2:13:15 | Store | +| test.cpp:13:10:13:13 | call to rand | test.cpp:13:2:13:15 | Store | +| test.cpp:18:2:18:14 | Chi [array content] | test.cpp:36:13:36:13 | get_rand3 output argument [array content] | +| test.cpp:18:2:18:14 | Store | test.cpp:18:2:18:14 | Chi [array content] | +| test.cpp:18:9:18:12 | call to rand | test.cpp:18:2:18:14 | Store | +| test.cpp:18:9:18:12 | call to rand | test.cpp:18:2:18:14 | Store | | test.cpp:24:11:24:18 | call to get_rand | test.cpp:25:7:25:7 | r | | test.cpp:24:11:24:18 | call to get_rand | test.cpp:25:7:25:7 | r | -| test.cpp:30:13:30:14 | get_rand2 output argument | test.cpp:31:7:31:7 | r | -| test.cpp:30:13:30:14 | get_rand2 output argument | test.cpp:31:7:31:7 | r | -| test.cpp:36:13:36:13 | get_rand3 output argument | test.cpp:37:7:37:7 | r | -| test.cpp:36:13:36:13 | get_rand3 output argument | test.cpp:37:7:37:7 | r | +| test.cpp:30:13:30:14 | Chi | test.cpp:31:7:31:7 | r | +| test.cpp:30:13:30:14 | Chi | test.cpp:31:7:31:7 | r | +| test.cpp:30:13:30:14 | get_rand2 output argument [array content] | test.cpp:30:13:30:14 | Chi | +| test.cpp:36:13:36:13 | Chi | test.cpp:37:7:37:7 | r | +| test.cpp:36:13:36:13 | Chi | test.cpp:37:7:37:7 | r | +| test.cpp:36:13:36:13 | get_rand3 output argument [array content] | test.cpp:36:13:36:13 | Chi | nodes | test.c:18:13:18:16 | call to rand | semmle.label | call to rand | | test.c:18:13:18:16 | call to rand | semmle.label | call to rand | @@ -106,21 +110,25 @@ nodes | test.cpp:8:9:8:12 | Store | semmle.label | Store | | test.cpp:8:9:8:12 | call to rand | semmle.label | call to rand | | test.cpp:8:9:8:12 | call to rand | semmle.label | call to rand | -| test.cpp:13:2:13:15 | Chi | semmle.label | Chi | +| test.cpp:13:2:13:15 | Chi [array content] | semmle.label | Chi [array content] | +| test.cpp:13:2:13:15 | Store | semmle.label | Store | | test.cpp:13:10:13:13 | call to rand | semmle.label | call to rand | | test.cpp:13:10:13:13 | call to rand | semmle.label | call to rand | -| test.cpp:18:2:18:14 | Chi | semmle.label | Chi | +| test.cpp:18:2:18:14 | Chi [array content] | semmle.label | Chi [array content] | +| test.cpp:18:2:18:14 | Store | semmle.label | Store | | test.cpp:18:9:18:12 | call to rand | semmle.label | call to rand | | test.cpp:18:9:18:12 | call to rand | semmle.label | call to rand | | test.cpp:24:11:24:18 | call to get_rand | semmle.label | call to get_rand | | test.cpp:25:7:25:7 | r | semmle.label | r | | test.cpp:25:7:25:7 | r | semmle.label | r | | test.cpp:25:7:25:7 | r | semmle.label | r | -| test.cpp:30:13:30:14 | get_rand2 output argument | semmle.label | get_rand2 output argument | +| test.cpp:30:13:30:14 | Chi | semmle.label | Chi | +| test.cpp:30:13:30:14 | get_rand2 output argument [array content] | semmle.label | get_rand2 output argument [array content] | | test.cpp:31:7:31:7 | r | semmle.label | r | | test.cpp:31:7:31:7 | r | semmle.label | r | | test.cpp:31:7:31:7 | r | semmle.label | r | -| test.cpp:36:13:36:13 | get_rand3 output argument | semmle.label | get_rand3 output argument | +| test.cpp:36:13:36:13 | Chi | semmle.label | Chi | +| test.cpp:36:13:36:13 | get_rand3 output argument [array content] | semmle.label | get_rand3 output argument [array content] | | test.cpp:37:7:37:7 | r | semmle.label | r | | test.cpp:37:7:37:7 | r | semmle.label | r | | test.cpp:37:7:37:7 | r | semmle.label | r | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-242/semmle/tests/OverrunWrite.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-242/semmle/tests/OverrunWrite.expected index 0467d3509c95..6c978fc972ce 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-242/semmle/tests/OverrunWrite.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-242/semmle/tests/OverrunWrite.expected @@ -2,3 +2,4 @@ | tests.cpp:259:2:259:8 | call to sprintf | This 'call to sprintf' operation requires 17 bytes but the destination is only 10 bytes. | | tests.cpp:272:2:272:8 | call to sprintf | This 'call to sprintf' operation requires 9 bytes but the destination is only 8 bytes. | | tests.cpp:273:2:273:8 | call to sprintf | This 'call to sprintf' operation requires 9 bytes but the destination is only 8 bytes. | +| tests.cpp:308:3:308:9 | call to sprintf | This 'call to sprintf' operation requires 9 bytes but the destination is only 8 bytes. | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-242/semmle/tests/tests.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-242/semmle/tests/tests.cpp index 5cf53554a272..72b0d1afec70 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-242/semmle/tests/tests.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-242/semmle/tests/tests.cpp @@ -289,3 +289,22 @@ void test5(va_list args, float f) vsprintf(buffer4, "123", args); // GOOD vsprintf(buffer4, "1234", args); // BAD: buffer overflow [NOT DETECTED] } + +namespace custom_sprintf_impl { + int sprintf(char *buf, const char *format, ...) + { + __builtin_va_list args; + int i; + + __builtin_va_start(args, format); + i = vsprintf(buf, format, args); + __builtin_va_end(args); + return i; + } + + void regression_test1() + { + char buffer8[8]; + sprintf(buffer8, "12345678"); // BAD: potential buffer overflow + } +} \ No newline at end of file diff --git a/cpp/ql/test/successor-tests/block/emptyblock/emptyblock01.ql b/cpp/ql/test/successor-tests/block/emptyblock/emptyblock01.ql index ecadf57692ec..e2a1da4e2ed5 100644 --- a/cpp/ql/test/successor-tests/block/emptyblock/emptyblock01.ql +++ b/cpp/ql/test/successor-tests/block/emptyblock/emptyblock01.ql @@ -1,6 +1,6 @@ import cpp -from Block s, int i, Stmt f, boolean succ +from BlockStmt s, int i, Stmt f, boolean succ where s.getParentStmt().hasChild(s, i) and s.getParentStmt().hasChild(f, i + 1) and diff --git a/cpp/ql/test/successor-tests/dostmt/dostmt04.ql b/cpp/ql/test/successor-tests/dostmt/dostmt04.ql index 61c1bb80f265..6b7a8a071788 100644 --- a/cpp/ql/test/successor-tests/dostmt/dostmt04.ql +++ b/cpp/ql/test/successor-tests/dostmt/dostmt04.ql @@ -8,7 +8,7 @@ import cpp from DoStmt ds, ExprStmt last, Expr succ where ds.getEnclosingFunction().hasName("normal") and - last = ds.getStmt().(Block).getLastStmt() and + last = ds.getStmt().(BlockStmt).getLastStmt() and succ = last.getExpr().getASuccessor() and succ = ds.getCondition().getAChild*() and count(last.getExpr().getASuccessor()) = 1 diff --git a/cpp/ql/test/successor-tests/forstmt/shortforstmt/shortforstmt04.ql b/cpp/ql/test/successor-tests/forstmt/shortforstmt/shortforstmt04.ql index a33bcb898086..3e5f4bfbbbef 100644 --- a/cpp/ql/test/successor-tests/forstmt/shortforstmt/shortforstmt04.ql +++ b/cpp/ql/test/successor-tests/forstmt/shortforstmt/shortforstmt04.ql @@ -9,7 +9,7 @@ import cpp from ForStmt fs, ExprStmt last, Expr succ where fs.getEnclosingFunction().hasName("normal") and - last = fs.getStmt().(Block).getLastStmt() and + last = fs.getStmt().(BlockStmt).getLastStmt() and succ = fs.getCondition().getAChild*() and succ = last.getExpr().getASuccessor() and count(last.getExpr().getASuccessor()) = 1 diff --git a/cpp/ql/test/successor-tests/ifstmt/ifelsestmt/ifelsestmt04.ql b/cpp/ql/test/successor-tests/ifstmt/ifelsestmt/ifelsestmt04.ql index c6fbf3c99f71..73f49a135c4e 100644 --- a/cpp/ql/test/successor-tests/ifstmt/ifelsestmt/ifelsestmt04.ql +++ b/cpp/ql/test/successor-tests/ifstmt/ifelsestmt/ifelsestmt04.ql @@ -10,7 +10,7 @@ where is.getEnclosingFunction().hasName("normal") and is.getParentStmt().hasChild(is, k) and is.getParentStmt().hasChild(l3, k + 1) and - last = is.getThen().(Block).getLastStmt() and + last = is.getThen().(BlockStmt).getLastStmt() and l3 = last.getASuccessor() and count(last.getASuccessor()) = 1 select last, l3.getName() diff --git a/cpp/ql/test/successor-tests/ifstmt/ifelsestmt/ifelsestmt06.ql b/cpp/ql/test/successor-tests/ifstmt/ifelsestmt/ifelsestmt06.ql index fc6ae7d3bc87..31f213558f09 100644 --- a/cpp/ql/test/successor-tests/ifstmt/ifelsestmt/ifelsestmt06.ql +++ b/cpp/ql/test/successor-tests/ifstmt/ifelsestmt/ifelsestmt06.ql @@ -10,7 +10,7 @@ where is.getEnclosingFunction().hasName("normal") and is.getParentStmt().hasChild(is, k) and is.getParentStmt().hasChild(l3, k + 1) and - last = is.getElse().(Block).getLastStmt() and + last = is.getElse().(BlockStmt).getLastStmt() and l3 = last.getASuccessor() and count(last.getASuccessor()) = 1 select last, l3.getName() diff --git a/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt02.ql b/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt02.ql index 90cfc707daa4..d3dc2521aa77 100644 --- a/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt02.ql +++ b/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt02.ql @@ -5,7 +5,7 @@ import cpp -from IfStmt is, Block t +from IfStmt is, BlockStmt t where is.getEnclosingFunction().hasName("normal") and t = is.getThen() and diff --git a/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt04.ql b/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt04.ql index f203b5f0ea29..7051192159cc 100644 --- a/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt04.ql +++ b/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt04.ql @@ -10,7 +10,7 @@ where is.getEnclosingFunction().hasName("normal") and is.getParentStmt().hasChild(is, k) and is.getParentStmt().hasChild(l2, k + 1) and - last = is.getThen().(Block).getLastStmt() and + last = is.getThen().(BlockStmt).getLastStmt() and l2 = last.getASuccessor() and count(last.getASuccessor()) = 1 select last, l2.getName() diff --git a/cpp/ql/test/successor-tests/stackvariables/stackvariables/graphable.expected b/cpp/ql/test/successor-tests/stackvariables/stackvariables/graphable.expected index 03f49c4b623b..04ab93f13b6a 100644 --- a/cpp/ql/test/successor-tests/stackvariables/stackvariables/graphable.expected +++ b/cpp/ql/test/successor-tests/stackvariables/stackvariables/graphable.expected @@ -1,512 +1,513 @@ -| BoxedInt::BoxedInt | false | 196 | 196 | BoxedInt | -| BoxedInt::BoxedInt | false | 484 | 484 | BoxedInt | -| BoxedInt::BoxedInt | false | 527 | 527 | this | -| BoxedInt::BoxedInt | false | 528 | 528 | m_ptr | -| BoxedInt::BoxedInt | false | 532 | 532 | x | -| BoxedInt::BoxedInt | false | 534 | 534 | new | -| BoxedInt::BoxedInt | false | 536 | 536 | ... = ... | -| BoxedInt::BoxedInt | false | 538 | 538 | ExprStmt | -| BoxedInt::BoxedInt | false | 540 | 540 | return ... | -| BoxedInt::BoxedInt | false | 542 | 542 | { ... } | -| BoxedInt::BoxedInt | true | 527 | 528 | | -| BoxedInt::BoxedInt | true | 528 | 536 | | -| BoxedInt::BoxedInt | true | 532 | 534 | | -| BoxedInt::BoxedInt | true | 534 | 527 | | -| BoxedInt::BoxedInt | true | 536 | 540 | | -| BoxedInt::BoxedInt | true | 538 | 532 | | -| BoxedInt::BoxedInt | true | 540 | 196 | | -| BoxedInt::BoxedInt | true | 542 | 538 | | -| BoxedInt::operator int | false | 204 | 204 | operator int | -| BoxedInt::operator int | false | 494 | 494 | this | -| BoxedInt::operator int | false | 495 | 495 | m_ptr | -| BoxedInt::operator int | false | 497 | 497 | * ... | -| BoxedInt::operator int | false | 499 | 499 | return ... | -| BoxedInt::operator int | false | 501 | 501 | { ... } | -| BoxedInt::operator int | true | 494 | 495 | | -| BoxedInt::operator int | true | 495 | 497 | | -| BoxedInt::operator int | true | 497 | 204 | | -| BoxedInt::operator int | true | 499 | 494 | | -| BoxedInt::operator int | true | 501 | 499 | | -| BoxedInt::operator= | false | 477 | 477 | operator= | -| BoxedInt::~BoxedInt | false | 254 | 254 | ~BoxedInt | -| BoxedInt::~BoxedInt | false | 509 | 509 | this | -| BoxedInt::~BoxedInt | false | 510 | 510 | m_ptr | -| BoxedInt::~BoxedInt | false | 512 | 512 | delete | -| BoxedInt::~BoxedInt | false | 514 | 514 | ExprStmt | -| BoxedInt::~BoxedInt | false | 516 | 516 | return ... | -| BoxedInt::~BoxedInt | false | 518 | 518 | { ... } | -| BoxedInt::~BoxedInt | true | 509 | 510 | | -| BoxedInt::~BoxedInt | true | 510 | 512 | | -| BoxedInt::~BoxedInt | true | 512 | 516 | | -| BoxedInt::~BoxedInt | true | 514 | 509 | | -| BoxedInt::~BoxedInt | true | 516 | 254 | | -| BoxedInt::~BoxedInt | true | 518 | 514 | | -| NonTrivial::operator= | false | 875 | 875 | operator= | -| NonTrivial::~NonTrivial | false | 649 | 649 | ~NonTrivial | -| NonTrivial::~NonTrivial | false | 886 | 886 | return ... | -| NonTrivial::~NonTrivial | false | 888 | 888 | { ... } | -| NonTrivial::~NonTrivial | true | 886 | 649 | | -| NonTrivial::~NonTrivial | true | 888 | 886 | | -| __va_list_tag::operator= | false | 95 | 95 | operator= | -| __va_list_tag::operator= | false | 102 | 102 | operator= | -| early_return | false | 777 | 777 | early_return | -| early_return | false | 785 | 785 | declaration | -| early_return | false | 787 | 787 | x | -| early_return | false | 789 | 789 | (bool)... | -| early_return | false | 793 | 793 | declaration | -| early_return | false | 795 | 795 | return ... | -| early_return | false | 797 | 797 | { ... } | -| early_return | false | 799 | 799 | if (...) ... | -| early_return | false | 801 | 801 | declaration | -| early_return | false | 803 | 803 | return ... | -| early_return | false | 805 | 805 | { ... } | -| early_return | false | 807 | 807 | before | -| early_return | false | 809 | 809 | call to before.~NonTrivial | -| early_return | false | 810 | 810 | after | -| early_return | false | 811 | 811 | call to after.~NonTrivial | -| early_return | false | 812 | 812 | inner | -| early_return | false | 814 | 814 | call to inner.~NonTrivial | -| early_return | false | 815 | 815 | inner | -| early_return | false | 816 | 816 | call to inner.~NonTrivial | -| early_return | true | 785 | 799 | | -| early_return | true | 787 | 797 | T | -| early_return | true | 787 | 801 | F | -| early_return | true | 793 | 795 | | -| early_return | true | 795 | 815 | | -| early_return | true | 797 | 793 | | -| early_return | true | 799 | 787 | | -| early_return | true | 801 | 803 | | -| early_return | true | 803 | 810 | | -| early_return | true | 805 | 785 | | -| early_return | true | 807 | 809 | | -| early_return | true | 809 | 777 | | -| early_return | true | 810 | 811 | | -| early_return | true | 811 | 807 | | -| early_return | true | 812 | 814 | | -| early_return | true | 814 | 801 | | -| early_return | true | 815 | 816 | | -| early_return | true | 816 | 807 | | -| early_throw | false | 727 | 727 | early_throw | -| early_throw | false | 735 | 735 | declaration | -| early_throw | false | 737 | 737 | x | -| early_throw | false | 739 | 739 | (bool)... | -| early_throw | false | 743 | 743 | declaration | -| early_throw | false | 745 | 745 | re-throw exception | -| early_throw | false | 747 | 747 | ExprStmt | -| early_throw | false | 749 | 749 | { ... } | -| early_throw | false | 751 | 751 | if (...) ... | -| early_throw | false | 753 | 753 | declaration | -| early_throw | false | 755 | 755 | return ... | -| early_throw | false | 757 | 757 | { ... } | -| early_throw | false | 759 | 759 | before | -| early_throw | false | 761 | 761 | call to before.~NonTrivial | -| early_throw | false | 762 | 762 | after | -| early_throw | false | 763 | 763 | call to after.~NonTrivial | -| early_throw | false | 764 | 764 | inner | -| early_throw | false | 766 | 766 | call to inner.~NonTrivial | -| early_throw | false | 767 | 767 | before | -| early_throw | false | 768 | 768 | call to before.~NonTrivial | -| early_throw | false | 769 | 769 | inner | -| early_throw | false | 770 | 770 | call to inner.~NonTrivial | -| early_throw | true | 735 | 751 | | -| early_throw | true | 737 | 749 | T | -| early_throw | true | 737 | 753 | F | -| early_throw | true | 743 | 747 | | -| early_throw | true | 745 | 769 | | -| early_throw | true | 747 | 745 | | -| early_throw | true | 749 | 743 | | -| early_throw | true | 751 | 737 | | -| early_throw | true | 753 | 755 | | -| early_throw | true | 755 | 762 | | -| early_throw | true | 757 | 735 | | -| early_throw | true | 759 | 761 | | -| early_throw | true | 761 | 727 | | -| early_throw | true | 762 | 763 | | -| early_throw | true | 763 | 759 | | -| early_throw | true | 764 | 766 | | -| early_throw | true | 766 | 753 | | -| early_throw | true | 767 | 768 | | -| early_throw | true | 768 | 727 | | -| early_throw | true | 769 | 770 | | -| early_throw | true | 770 | 767 | | -| for_decl_bind | false | 185 | 185 | for_decl_bind | -| for_decl_bind | false | 194 | 194 | call to BoxedInt | -| for_decl_bind | false | 197 | 197 | x | -| for_decl_bind | false | 199 | 199 | - ... | -| for_decl_bind | false | 201 | 201 | initializer for init | -| for_decl_bind | false | 208 | 208 | call to operator int | -| for_decl_bind | false | 210 | 210 | call to BoxedInt | -| for_decl_bind | false | 212 | 212 | x | -| for_decl_bind | false | 214 | 214 | initializer for bi | -| for_decl_bind | false | 217 | 217 | bi | -| for_decl_bind | false | 219 | 219 | (bool)... | -| for_decl_bind | false | 220 | 220 | (condition decl) | -| for_decl_bind | false | 222 | 222 | x | -| for_decl_bind | false | 224 | 224 | ++ ... | -| for_decl_bind | false | 226 | 226 | ExprStmt | -| for_decl_bind | false | 228 | 228 | { ... } | -| for_decl_bind | false | 230 | 230 | declaration | -| for_decl_bind | false | 232 | 232 | x | -| for_decl_bind | false | 236 | 236 | 2 | -| for_decl_bind | false | 237 | 237 | ... *= ... | -| for_decl_bind | false | 239 | 239 | for(...;...;...) ... | -| for_decl_bind | false | 241 | 241 | x | -| for_decl_bind | false | 243 | 243 | -- ... | -| for_decl_bind | false | 245 | 245 | ExprStmt | -| for_decl_bind | false | 247 | 247 | return ... | -| for_decl_bind | false | 249 | 249 | { ... } | -| for_decl_bind | false | 251 | 251 | init | -| for_decl_bind | false | 253 | 253 | call to init.~BoxedInt | -| for_decl_bind | false | 255 | 255 | bi | -| for_decl_bind | false | 257 | 257 | call to bi.~BoxedInt | -| for_decl_bind | false | 258 | 258 | bi | -| for_decl_bind | false | 259 | 259 | call to bi.~BoxedInt | -| for_decl_bind | true | 194 | 212 | | -| for_decl_bind | true | 197 | 199 | | -| for_decl_bind | true | 199 | 194 | | -| for_decl_bind | true | 201 | 197 | | -| for_decl_bind | true | 210 | 220 | | -| for_decl_bind | true | 212 | 210 | | -| for_decl_bind | true | 220 | 228 | T | -| for_decl_bind | true | 220 | 255 | F | -| for_decl_bind | true | 222 | 224 | | -| for_decl_bind | true | 224 | 232 | | -| for_decl_bind | true | 226 | 222 | | -| for_decl_bind | true | 228 | 226 | | -| for_decl_bind | true | 230 | 201 | | -| for_decl_bind | true | 232 | 236 | | -| for_decl_bind | true | 236 | 237 | | -| for_decl_bind | true | 237 | 258 | | -| for_decl_bind | true | 239 | 230 | | -| for_decl_bind | true | 241 | 243 | | -| for_decl_bind | true | 243 | 247 | | -| for_decl_bind | true | 245 | 241 | | -| for_decl_bind | true | 247 | 185 | | -| for_decl_bind | true | 249 | 239 | | -| for_decl_bind | true | 251 | 253 | | -| for_decl_bind | true | 253 | 245 | | -| for_decl_bind | true | 255 | 257 | | -| for_decl_bind | true | 257 | 251 | | -| for_decl_bind | true | 258 | 259 | | -| for_decl_bind | true | 259 | 212 | | -| for_loop_scope | false | 676 | 676 | for_loop_scope | -| for_loop_scope | false | 684 | 684 | declaration | -| for_loop_scope | false | 689 | 689 | x | -| for_loop_scope | false | 693 | 693 | 10 | -| for_loop_scope | false | 694 | 694 | ... < ... | -| for_loop_scope | false | 699 | 699 | declaration | -| for_loop_scope | false | 701 | 701 | { ... } | -| for_loop_scope | false | 703 | 703 | declaration | -| for_loop_scope | false | 705 | 705 | x | -| for_loop_scope | false | 707 | 707 | ++ ... | -| for_loop_scope | false | 709 | 709 | for(...;...;...) ... | -| for_loop_scope | false | 711 | 711 | return ... | -| for_loop_scope | false | 713 | 713 | { ... } | -| for_loop_scope | false | 715 | 715 | outer_scope | -| for_loop_scope | false | 717 | 717 | call to outer_scope.~NonTrivial | -| for_loop_scope | false | 718 | 718 | for_scope | -| for_loop_scope | false | 720 | 720 | call to for_scope.~NonTrivial | -| for_loop_scope | false | 721 | 721 | inner_scope | -| for_loop_scope | false | 723 | 723 | call to inner_scope.~NonTrivial | -| for_loop_scope | true | 684 | 709 | | -| for_loop_scope | true | 689 | 693 | | -| for_loop_scope | true | 693 | 694 | | -| for_loop_scope | true | 694 | 701 | T | -| for_loop_scope | true | 694 | 718 | F | -| for_loop_scope | true | 699 | 721 | | -| for_loop_scope | true | 701 | 699 | | -| for_loop_scope | true | 703 | 689 | | -| for_loop_scope | true | 705 | 707 | | -| for_loop_scope | true | 707 | 689 | | -| for_loop_scope | true | 709 | 703 | | -| for_loop_scope | true | 711 | 715 | | -| for_loop_scope | true | 713 | 684 | | -| for_loop_scope | true | 715 | 717 | | -| for_loop_scope | true | 717 | 676 | | -| for_loop_scope | true | 718 | 720 | | -| for_loop_scope | true | 720 | 711 | | -| for_loop_scope | true | 721 | 723 | | -| for_loop_scope | true | 723 | 705 | | -| gotos | false | 585 | 585 | gotos | -| gotos | false | 593 | 593 | declaration | -| gotos | false | 595 | 595 | x | -| gotos | false | 597 | 597 | (bool)... | -| gotos | false | 598 | 598 | goto ... | -| gotos | false | 600 | 600 | if (...) ... | -| gotos | false | 602 | 602 | x | -| gotos | false | 604 | 604 | ++ ... | -| gotos | false | 606 | 606 | initializer for y | -| gotos | false | 617 | 617 | declaration | -| gotos | false | 619 | 619 | label ...: | -| gotos | false | 621 | 621 | declaration | -| gotos | false | 623 | 623 | y | -| gotos | false | 625 | 625 | (bool)... | -| gotos | false | 626 | 626 | goto ... | -| gotos | false | 628 | 628 | if (...) ... | -| gotos | false | 630 | 630 | declaration | -| gotos | false | 632 | 632 | { ... } | -| gotos | false | 634 | 634 | label ...: | -| gotos | false | 636 | 636 | x | -| gotos | false | 638 | 638 | -- ... | -| gotos | false | 640 | 640 | ExprStmt | -| gotos | false | 642 | 642 | return ... | -| gotos | false | 644 | 644 | { ... } | -| gotos | false | 646 | 646 | nt1 | -| gotos | false | 648 | 648 | call to nt1.~NonTrivial | -| gotos | false | 650 | 650 | nt2 | -| gotos | false | 652 | 652 | call to nt2.~NonTrivial | -| gotos | false | 653 | 653 | nt3 | -| gotos | false | 654 | 654 | call to nt3.~NonTrivial | -| gotos | false | 655 | 655 | nt2 | -| gotos | false | 656 | 656 | call to nt2.~NonTrivial | -| gotos | true | 593 | 600 | | -| gotos | true | 595 | 598 | T | -| gotos | true | 595 | 632 | F | -| gotos | true | 598 | 619 | | -| gotos | true | 600 | 595 | | -| gotos | true | 602 | 604 | | -| gotos | true | 604 | 619 | | -| gotos | true | 606 | 602 | | -| gotos | true | 617 | 606 | | -| gotos | true | 617 | 619 | | -| gotos | true | 619 | 621 | | -| gotos | true | 621 | 628 | | -| gotos | true | 623 | 626 | T | -| gotos | true | 623 | 630 | F | -| gotos | true | 626 | 655 | | -| gotos | true | 628 | 623 | | -| gotos | true | 630 | 653 | | -| gotos | true | 632 | 617 | | -| gotos | true | 634 | 640 | | -| gotos | true | 636 | 638 | | -| gotos | true | 638 | 642 | | -| gotos | true | 640 | 636 | | -| gotos | true | 642 | 646 | | -| gotos | true | 644 | 593 | | -| gotos | true | 646 | 648 | | -| gotos | true | 648 | 585 | | -| gotos | true | 650 | 652 | | -| gotos | true | 652 | 634 | | -| gotos | true | 653 | 654 | | -| gotos | true | 654 | 650 | | -| gotos | true | 655 | 656 | | -| gotos | true | 656 | 634 | | -| if_decl_bind | false | 407 | 407 | if_decl_bind | -| if_decl_bind | false | 416 | 416 | call to operator int | -| if_decl_bind | false | 418 | 418 | call to BoxedInt | -| if_decl_bind | false | 420 | 420 | x | -| if_decl_bind | false | 422 | 422 | initializer for bi | -| if_decl_bind | false | 425 | 425 | bi | -| if_decl_bind | false | 427 | 427 | (bool)... | -| if_decl_bind | false | 428 | 428 | (condition decl) | -| if_decl_bind | false | 430 | 430 | bi | -| if_decl_bind | false | 432 | 432 | m_ptr | -| if_decl_bind | false | 434 | 434 | * ... | -| if_decl_bind | false | 436 | 436 | ++ ... | -| if_decl_bind | false | 438 | 438 | ExprStmt | -| if_decl_bind | false | 440 | 440 | { ... } | -| if_decl_bind | false | 442 | 442 | bi | -| if_decl_bind | false | 444 | 444 | m_ptr | -| if_decl_bind | false | 446 | 446 | * ... | -| if_decl_bind | false | 448 | 448 | -- ... | -| if_decl_bind | false | 450 | 450 | ExprStmt | -| if_decl_bind | false | 452 | 452 | { ... } | -| if_decl_bind | false | 454 | 454 | if (...) ... | -| if_decl_bind | false | 456 | 456 | x | -| if_decl_bind | false | 460 | 460 | 1 | -| if_decl_bind | false | 461 | 461 | ... = ... | -| if_decl_bind | false | 463 | 463 | ExprStmt | -| if_decl_bind | false | 465 | 465 | return ... | -| if_decl_bind | false | 467 | 467 | { ... } | -| if_decl_bind | false | 469 | 469 | bi | -| if_decl_bind | false | 471 | 471 | call to bi.~BoxedInt | -| if_decl_bind | true | 418 | 428 | | -| if_decl_bind | true | 420 | 418 | | -| if_decl_bind | true | 428 | 440 | T | -| if_decl_bind | true | 428 | 452 | F | -| if_decl_bind | true | 430 | 432 | | -| if_decl_bind | true | 432 | 434 | | -| if_decl_bind | true | 434 | 436 | | -| if_decl_bind | true | 436 | 469 | | -| if_decl_bind | true | 438 | 430 | | -| if_decl_bind | true | 440 | 438 | | -| if_decl_bind | true | 442 | 444 | | -| if_decl_bind | true | 444 | 446 | | -| if_decl_bind | true | 446 | 448 | | -| if_decl_bind | true | 448 | 469 | | -| if_decl_bind | true | 450 | 442 | | -| if_decl_bind | true | 452 | 450 | | -| if_decl_bind | true | 454 | 420 | | -| if_decl_bind | true | 456 | 461 | | -| if_decl_bind | true | 460 | 456 | | -| if_decl_bind | true | 461 | 465 | | -| if_decl_bind | true | 463 | 460 | | -| if_decl_bind | true | 465 | 407 | | -| if_decl_bind | true | 467 | 454 | | -| if_decl_bind | true | 469 | 471 | | -| if_decl_bind | true | 471 | 463 | | -| never_destructs | false | 660 | 660 | never_destructs | -| never_destructs | false | 665 | 665 | declaration | -| never_destructs | false | 667 | 667 | label ...: | -| never_destructs | false | 669 | 669 | goto ... | -| never_destructs | false | 671 | 671 | { ... } | -| never_destructs | true | 665 | 667 | | -| never_destructs | true | 667 | 669 | | -| never_destructs | true | 669 | 667 | | -| never_destructs | true | 671 | 665 | | -| operator delete | false | 507 | 507 | operator delete | -| operator new | false | 530 | 530 | operator new | -| simple | false | 847 | 847 | simple | -| simple | false | 852 | 852 | declaration | -| simple | false | 854 | 854 | return ... | -| simple | false | 856 | 856 | { ... } | -| simple | false | 858 | 858 | nt | -| simple | false | 860 | 860 | call to nt.~NonTrivial | -| simple | true | 852 | 854 | | -| simple | true | 854 | 858 | | -| simple | true | 856 | 852 | | -| simple | true | 858 | 860 | | -| simple | true | 860 | 847 | | -| simple2 | false | 823 | 823 | simple2 | -| simple2 | false | 828 | 828 | declaration | -| simple2 | false | 830 | 830 | declaration | -| simple2 | false | 832 | 832 | return ... | -| simple2 | false | 834 | 834 | { ... } | -| simple2 | false | 836 | 836 | one | -| simple2 | false | 838 | 838 | call to one.~NonTrivial | -| simple2 | false | 839 | 839 | two | -| simple2 | false | 840 | 840 | call to two.~NonTrivial | -| simple2 | true | 828 | 830 | | -| simple2 | true | 830 | 832 | | -| simple2 | true | 832 | 839 | | -| simple2 | true | 834 | 828 | | -| simple2 | true | 836 | 838 | | -| simple2 | true | 838 | 823 | | -| simple2 | true | 839 | 840 | | -| simple2 | true | 840 | 836 | | -| switch_decl_bind | false | 308 | 308 | switch_decl_bind | -| switch_decl_bind | false | 317 | 317 | call to operator int | -| switch_decl_bind | false | 319 | 319 | call to BoxedInt | -| switch_decl_bind | false | 321 | 321 | x | -| switch_decl_bind | false | 323 | 323 | initializer for bi | -| switch_decl_bind | false | 326 | 326 | bi | -| switch_decl_bind | false | 328 | 328 | (condition decl) | -| switch_decl_bind | false | 332 | 332 | 0 | -| switch_decl_bind | false | 333 | 333 | case ...: | -| switch_decl_bind | false | 336 | 336 | bi | -| switch_decl_bind | false | 339 | 339 | m_ptr | -| switch_decl_bind | false | 341 | 341 | * ... | -| switch_decl_bind | false | 343 | 343 | -- ... | -| switch_decl_bind | false | 345 | 345 | ExprStmt | -| switch_decl_bind | false | 347 | 347 | break; | -| switch_decl_bind | false | 351 | 351 | 1 | -| switch_decl_bind | false | 352 | 352 | case ...: | -| switch_decl_bind | false | 354 | 354 | bi | -| switch_decl_bind | false | 356 | 356 | m_ptr | -| switch_decl_bind | false | 358 | 358 | * ... | -| switch_decl_bind | false | 360 | 360 | ++ ... | -| switch_decl_bind | false | 362 | 362 | ExprStmt | -| switch_decl_bind | false | 364 | 364 | break; | -| switch_decl_bind | false | 366 | 366 | default: | -| switch_decl_bind | false | 368 | 368 | bi | -| switch_decl_bind | false | 370 | 370 | m_ptr | -| switch_decl_bind | false | 372 | 372 | * ... | -| switch_decl_bind | false | 376 | 376 | 2 | -| switch_decl_bind | false | 377 | 377 | ... /= ... | -| switch_decl_bind | false | 379 | 379 | ExprStmt | -| switch_decl_bind | false | 381 | 381 | { ... } | -| switch_decl_bind | false | 383 | 383 | switch (...) ... | -| switch_decl_bind | false | 385 | 385 | label ...: | -| switch_decl_bind | false | 387 | 387 | x | -| switch_decl_bind | false | 391 | 391 | 1 | -| switch_decl_bind | false | 392 | 392 | ... = ... | -| switch_decl_bind | false | 394 | 394 | ExprStmt | -| switch_decl_bind | false | 396 | 396 | return ... | -| switch_decl_bind | false | 398 | 398 | { ... } | -| switch_decl_bind | false | 400 | 400 | bi | -| switch_decl_bind | false | 402 | 402 | call to bi.~BoxedInt | -| switch_decl_bind | false | 403 | 403 | bi | -| switch_decl_bind | false | 404 | 404 | call to bi.~BoxedInt | -| switch_decl_bind | false | 405 | 405 | bi | -| switch_decl_bind | false | 406 | 406 | call to bi.~BoxedInt | -| switch_decl_bind | true | 319 | 328 | | -| switch_decl_bind | true | 321 | 319 | | -| switch_decl_bind | true | 328 | 381 | | -| switch_decl_bind | true | 333 | 345 | | -| switch_decl_bind | true | 336 | 339 | | -| switch_decl_bind | true | 339 | 341 | | -| switch_decl_bind | true | 341 | 343 | | -| switch_decl_bind | true | 343 | 347 | | -| switch_decl_bind | true | 345 | 336 | | -| switch_decl_bind | true | 347 | 405 | | -| switch_decl_bind | true | 352 | 362 | | -| switch_decl_bind | true | 354 | 356 | | -| switch_decl_bind | true | 356 | 358 | | -| switch_decl_bind | true | 358 | 360 | | +| BoxedInt::BoxedInt | false | 153 | 153 | BoxedInt | +| BoxedInt::BoxedInt | false | 571 | 571 | BoxedInt | +| BoxedInt::BoxedInt | false | 625 | 625 | ExprStmt | +| BoxedInt::BoxedInt | false | 628 | 628 | this | +| BoxedInt::BoxedInt | false | 630 | 630 | m_ptr | +| BoxedInt::BoxedInt | false | 635 | 635 | x | +| BoxedInt::BoxedInt | false | 638 | 638 | new | +| BoxedInt::BoxedInt | false | 641 | 641 | ... = ... | +| BoxedInt::BoxedInt | false | 644 | 644 | return ... | +| BoxedInt::BoxedInt | false | 647 | 647 | { ... } | +| BoxedInt::BoxedInt | true | 625 | 635 | | +| BoxedInt::BoxedInt | true | 628 | 630 | | +| BoxedInt::BoxedInt | true | 630 | 641 | | +| BoxedInt::BoxedInt | true | 635 | 638 | | +| BoxedInt::BoxedInt | true | 638 | 628 | | +| BoxedInt::BoxedInt | true | 641 | 644 | | +| BoxedInt::BoxedInt | true | 644 | 153 | | +| BoxedInt::BoxedInt | true | 647 | 625 | | +| BoxedInt::operator int | false | 165 | 165 | operator int | +| BoxedInt::operator int | false | 581 | 581 | return ... | +| BoxedInt::operator int | false | 584 | 584 | this | +| BoxedInt::operator int | false | 586 | 586 | m_ptr | +| BoxedInt::operator int | false | 589 | 589 | * ... | +| BoxedInt::operator int | false | 592 | 592 | { ... } | +| BoxedInt::operator int | true | 581 | 584 | | +| BoxedInt::operator int | true | 584 | 586 | | +| BoxedInt::operator int | true | 586 | 589 | | +| BoxedInt::operator int | true | 589 | 165 | | +| BoxedInt::operator int | true | 592 | 581 | | +| BoxedInt::operator= | false | 562 | 562 | operator= | +| BoxedInt::~BoxedInt | false | 236 | 236 | ~BoxedInt | +| BoxedInt::~BoxedInt | false | 599 | 599 | ExprStmt | +| BoxedInt::~BoxedInt | false | 604 | 604 | this | +| BoxedInt::~BoxedInt | false | 606 | 606 | m_ptr | +| BoxedInt::~BoxedInt | false | 609 | 609 | delete | +| BoxedInt::~BoxedInt | false | 612 | 612 | return ... | +| BoxedInt::~BoxedInt | false | 615 | 615 | { ... } | +| BoxedInt::~BoxedInt | true | 599 | 604 | | +| BoxedInt::~BoxedInt | true | 604 | 606 | | +| BoxedInt::~BoxedInt | true | 606 | 609 | | +| BoxedInt::~BoxedInt | true | 609 | 612 | | +| BoxedInt::~BoxedInt | true | 612 | 236 | | +| BoxedInt::~BoxedInt | true | 615 | 599 | | +| NonTrivial::NonTrivial | false | 707 | 707 | NonTrivial | +| NonTrivial::operator= | false | 686 | 686 | operator= | +| NonTrivial::~NonTrivial | false | 695 | 695 | ~NonTrivial | +| NonTrivial::~NonTrivial | false | 702 | 702 | return ... | +| NonTrivial::~NonTrivial | false | 705 | 705 | { ... } | +| NonTrivial::~NonTrivial | true | 702 | 695 | | +| NonTrivial::~NonTrivial | true | 705 | 702 | | +| __va_list_tag::operator= | false | 65 | 65 | operator= | +| __va_list_tag::operator= | false | 71 | 71 | operator= | +| early_return | false | 1025 | 1025 | early_return | +| early_return | false | 1034 | 1034 | declaration | +| early_return | false | 1041 | 1041 | if (...) ... | +| early_return | false | 1044 | 1044 | x | +| early_return | false | 1047 | 1047 | (bool)... | +| early_return | false | 1053 | 1053 | declaration | +| early_return | false | 1056 | 1056 | return ... | +| early_return | false | 1059 | 1059 | { ... } | +| early_return | false | 1062 | 1062 | declaration | +| early_return | false | 1069 | 1069 | return ... | +| early_return | false | 1072 | 1072 | { ... } | +| early_return | false | 1075 | 1075 | inner | +| early_return | false | 1078 | 1078 | call to inner.~NonTrivial | +| early_return | false | 1080 | 1080 | before | +| early_return | false | 1083 | 1083 | call to before.~NonTrivial | +| early_return | false | 1085 | 1085 | inner | +| early_return | false | 1087 | 1087 | call to inner.~NonTrivial | +| early_return | false | 1089 | 1089 | after | +| early_return | false | 1091 | 1091 | call to after.~NonTrivial | +| early_return | true | 1034 | 1041 | | +| early_return | true | 1041 | 1044 | | +| early_return | true | 1044 | 1059 | T | +| early_return | true | 1044 | 1062 | F | +| early_return | true | 1053 | 1056 | | +| early_return | true | 1056 | 1085 | | +| early_return | true | 1059 | 1053 | | +| early_return | true | 1062 | 1069 | | +| early_return | true | 1069 | 1089 | | +| early_return | true | 1072 | 1034 | | +| early_return | true | 1075 | 1078 | | +| early_return | true | 1078 | 1062 | | +| early_return | true | 1080 | 1083 | | +| early_return | true | 1083 | 1025 | | +| early_return | true | 1085 | 1087 | | +| early_return | true | 1087 | 1080 | | +| early_return | true | 1089 | 1091 | | +| early_return | true | 1091 | 1080 | | +| early_throw | false | 951 | 951 | early_throw | +| early_throw | false | 960 | 960 | declaration | +| early_throw | false | 967 | 967 | if (...) ... | +| early_throw | false | 970 | 970 | x | +| early_throw | false | 973 | 973 | (bool)... | +| early_throw | false | 979 | 979 | declaration | +| early_throw | false | 982 | 982 | ExprStmt | +| early_throw | false | 985 | 985 | re-throw exception | +| early_throw | false | 988 | 988 | { ... } | +| early_throw | false | 991 | 991 | declaration | +| early_throw | false | 998 | 998 | return ... | +| early_throw | false | 1001 | 1001 | { ... } | +| early_throw | false | 1004 | 1004 | inner | +| early_throw | false | 1007 | 1007 | call to inner.~NonTrivial | +| early_throw | false | 1009 | 1009 | before | +| early_throw | false | 1012 | 1012 | call to before.~NonTrivial | +| early_throw | false | 1014 | 1014 | inner | +| early_throw | false | 1016 | 1016 | call to inner.~NonTrivial | +| early_throw | false | 1018 | 1018 | before | +| early_throw | false | 1020 | 1020 | call to before.~NonTrivial | +| early_throw | false | 1022 | 1022 | after | +| early_throw | false | 1024 | 1024 | call to after.~NonTrivial | +| early_throw | true | 960 | 967 | | +| early_throw | true | 967 | 970 | | +| early_throw | true | 970 | 988 | T | +| early_throw | true | 970 | 991 | F | +| early_throw | true | 979 | 982 | | +| early_throw | true | 982 | 985 | | +| early_throw | true | 985 | 1014 | | +| early_throw | true | 988 | 979 | | +| early_throw | true | 991 | 998 | | +| early_throw | true | 998 | 1022 | | +| early_throw | true | 1001 | 960 | | +| early_throw | true | 1004 | 1007 | | +| early_throw | true | 1007 | 991 | | +| early_throw | true | 1009 | 1012 | | +| early_throw | true | 1012 | 951 | | +| early_throw | true | 1014 | 1016 | | +| early_throw | true | 1016 | 1009 | | +| early_throw | true | 1018 | 1020 | | +| early_throw | true | 1020 | 951 | | +| early_throw | true | 1022 | 1024 | | +| early_throw | true | 1024 | 1018 | | +| for_decl_bind | false | 137 | 137 | for_decl_bind | +| for_decl_bind | false | 146 | 146 | for(...;...;...) ... | +| for_decl_bind | false | 151 | 151 | call to BoxedInt | +| for_decl_bind | false | 155 | 155 | x | +| for_decl_bind | false | 158 | 158 | - ... | +| for_decl_bind | false | 161 | 161 | initializer for init | +| for_decl_bind | false | 169 | 169 | call to operator int | +| for_decl_bind | false | 173 | 173 | call to BoxedInt | +| for_decl_bind | false | 176 | 176 | x | +| for_decl_bind | false | 179 | 179 | initializer for bi | +| for_decl_bind | false | 183 | 183 | bi | +| for_decl_bind | false | 186 | 186 | (bool)... | +| for_decl_bind | false | 188 | 188 | (condition decl) | +| for_decl_bind | false | 191 | 191 | ExprStmt | +| for_decl_bind | false | 194 | 194 | x | +| for_decl_bind | false | 197 | 197 | ++ ... | +| for_decl_bind | false | 200 | 200 | { ... } | +| for_decl_bind | false | 203 | 203 | declaration | +| for_decl_bind | false | 206 | 206 | x | +| for_decl_bind | false | 212 | 212 | 2 | +| for_decl_bind | false | 214 | 214 | ... *= ... | +| for_decl_bind | false | 217 | 217 | ExprStmt | +| for_decl_bind | false | 220 | 220 | x | +| for_decl_bind | false | 223 | 223 | -- ... | +| for_decl_bind | false | 226 | 226 | return ... | +| for_decl_bind | false | 229 | 229 | { ... } | +| for_decl_bind | false | 232 | 232 | init | +| for_decl_bind | false | 235 | 235 | call to init.~BoxedInt | +| for_decl_bind | false | 238 | 238 | bi | +| for_decl_bind | false | 241 | 241 | call to bi.~BoxedInt | +| for_decl_bind | false | 243 | 243 | bi | +| for_decl_bind | false | 245 | 245 | call to bi.~BoxedInt | +| for_decl_bind | true | 146 | 203 | | +| for_decl_bind | true | 151 | 176 | | +| for_decl_bind | true | 155 | 158 | | +| for_decl_bind | true | 158 | 151 | | +| for_decl_bind | true | 161 | 155 | | +| for_decl_bind | true | 173 | 188 | | +| for_decl_bind | true | 176 | 173 | | +| for_decl_bind | true | 188 | 200 | T | +| for_decl_bind | true | 188 | 238 | F | +| for_decl_bind | true | 191 | 194 | | +| for_decl_bind | true | 194 | 197 | | +| for_decl_bind | true | 197 | 206 | | +| for_decl_bind | true | 200 | 191 | | +| for_decl_bind | true | 203 | 161 | | +| for_decl_bind | true | 206 | 212 | | +| for_decl_bind | true | 212 | 214 | | +| for_decl_bind | true | 214 | 243 | | +| for_decl_bind | true | 217 | 220 | | +| for_decl_bind | true | 220 | 223 | | +| for_decl_bind | true | 223 | 226 | | +| for_decl_bind | true | 226 | 137 | | +| for_decl_bind | true | 229 | 146 | | +| for_decl_bind | true | 232 | 235 | | +| for_decl_bind | true | 235 | 217 | | +| for_decl_bind | true | 238 | 241 | | +| for_decl_bind | true | 241 | 232 | | +| for_decl_bind | true | 243 | 245 | | +| for_decl_bind | true | 245 | 176 | | +| for_loop_scope | false | 878 | 878 | for_loop_scope | +| for_loop_scope | false | 887 | 887 | declaration | +| for_loop_scope | false | 894 | 894 | for(...;...;...) ... | +| for_loop_scope | false | 901 | 901 | x | +| for_loop_scope | false | 907 | 907 | 10 | +| for_loop_scope | false | 909 | 909 | ... < ... | +| for_loop_scope | false | 916 | 916 | declaration | +| for_loop_scope | false | 919 | 919 | { ... } | +| for_loop_scope | false | 922 | 922 | declaration | +| for_loop_scope | false | 925 | 925 | x | +| for_loop_scope | false | 928 | 928 | ++ ... | +| for_loop_scope | false | 931 | 931 | return ... | +| for_loop_scope | false | 934 | 934 | { ... } | +| for_loop_scope | false | 937 | 937 | for_scope | +| for_loop_scope | false | 940 | 940 | call to for_scope.~NonTrivial | +| for_loop_scope | false | 942 | 942 | inner_scope | +| for_loop_scope | false | 945 | 945 | call to inner_scope.~NonTrivial | +| for_loop_scope | false | 947 | 947 | outer_scope | +| for_loop_scope | false | 950 | 950 | call to outer_scope.~NonTrivial | +| for_loop_scope | true | 887 | 894 | | +| for_loop_scope | true | 894 | 922 | | +| for_loop_scope | true | 901 | 907 | | +| for_loop_scope | true | 907 | 909 | | +| for_loop_scope | true | 909 | 919 | T | +| for_loop_scope | true | 909 | 937 | F | +| for_loop_scope | true | 916 | 942 | | +| for_loop_scope | true | 919 | 916 | | +| for_loop_scope | true | 922 | 901 | | +| for_loop_scope | true | 925 | 928 | | +| for_loop_scope | true | 928 | 901 | | +| for_loop_scope | true | 931 | 947 | | +| for_loop_scope | true | 934 | 887 | | +| for_loop_scope | true | 937 | 940 | | +| for_loop_scope | true | 940 | 931 | | +| for_loop_scope | true | 942 | 945 | | +| for_loop_scope | true | 945 | 925 | | +| for_loop_scope | true | 947 | 950 | | +| for_loop_scope | true | 950 | 878 | | +| gotos | false | 748 | 748 | gotos | +| gotos | false | 757 | 757 | declaration | +| gotos | false | 764 | 764 | if (...) ... | +| gotos | false | 767 | 767 | x | +| gotos | false | 770 | 770 | (bool)... | +| gotos | false | 772 | 772 | goto ... | +| gotos | false | 775 | 775 | x | +| gotos | false | 778 | 778 | ++ ... | +| gotos | false | 781 | 781 | initializer for y | +| gotos | false | 796 | 796 | declaration | +| gotos | false | 799 | 799 | label ...: | +| gotos | false | 802 | 802 | declaration | +| gotos | false | 805 | 805 | if (...) ... | +| gotos | false | 808 | 808 | y | +| gotos | false | 811 | 811 | (bool)... | +| gotos | false | 813 | 813 | goto ... | +| gotos | false | 816 | 816 | declaration | +| gotos | false | 819 | 819 | { ... } | +| gotos | false | 822 | 822 | label ...: | +| gotos | false | 825 | 825 | ExprStmt | +| gotos | false | 828 | 828 | x | +| gotos | false | 831 | 831 | -- ... | +| gotos | false | 834 | 834 | return ... | +| gotos | false | 837 | 837 | { ... } | +| gotos | false | 840 | 840 | nt2 | +| gotos | false | 843 | 843 | call to nt2.~NonTrivial | +| gotos | false | 845 | 845 | nt3 | +| gotos | false | 847 | 847 | call to nt3.~NonTrivial | +| gotos | false | 849 | 849 | nt2 | +| gotos | false | 851 | 851 | call to nt2.~NonTrivial | +| gotos | false | 853 | 853 | nt1 | +| gotos | false | 856 | 856 | call to nt1.~NonTrivial | +| gotos | true | 757 | 764 | | +| gotos | true | 764 | 767 | | +| gotos | true | 767 | 772 | T | +| gotos | true | 767 | 819 | F | +| gotos | true | 772 | 799 | | +| gotos | true | 775 | 778 | | +| gotos | true | 778 | 799 | | +| gotos | true | 781 | 775 | | +| gotos | true | 796 | 781 | | +| gotos | true | 796 | 799 | | +| gotos | true | 799 | 802 | | +| gotos | true | 802 | 805 | | +| gotos | true | 805 | 808 | | +| gotos | true | 808 | 813 | T | +| gotos | true | 808 | 816 | F | +| gotos | true | 813 | 849 | | +| gotos | true | 816 | 845 | | +| gotos | true | 819 | 796 | | +| gotos | true | 822 | 825 | | +| gotos | true | 825 | 828 | | +| gotos | true | 828 | 831 | | +| gotos | true | 831 | 834 | | +| gotos | true | 834 | 853 | | +| gotos | true | 837 | 757 | | +| gotos | true | 840 | 843 | | +| gotos | true | 843 | 822 | | +| gotos | true | 845 | 847 | | +| gotos | true | 847 | 840 | | +| gotos | true | 849 | 851 | | +| gotos | true | 851 | 822 | | +| gotos | true | 853 | 856 | | +| gotos | true | 856 | 748 | | +| if_decl_bind | false | 464 | 464 | if_decl_bind | +| if_decl_bind | false | 473 | 473 | if (...) ... | +| if_decl_bind | false | 477 | 477 | call to operator int | +| if_decl_bind | false | 481 | 481 | call to BoxedInt | +| if_decl_bind | false | 484 | 484 | x | +| if_decl_bind | false | 487 | 487 | initializer for bi | +| if_decl_bind | false | 491 | 491 | bi | +| if_decl_bind | false | 494 | 494 | (bool)... | +| if_decl_bind | false | 496 | 496 | (condition decl) | +| if_decl_bind | false | 499 | 499 | ExprStmt | +| if_decl_bind | false | 502 | 502 | bi | +| if_decl_bind | false | 505 | 505 | m_ptr | +| if_decl_bind | false | 508 | 508 | * ... | +| if_decl_bind | false | 511 | 511 | ++ ... | +| if_decl_bind | false | 514 | 514 | { ... } | +| if_decl_bind | false | 517 | 517 | ExprStmt | +| if_decl_bind | false | 520 | 520 | bi | +| if_decl_bind | false | 523 | 523 | m_ptr | +| if_decl_bind | false | 526 | 526 | * ... | +| if_decl_bind | false | 529 | 529 | -- ... | +| if_decl_bind | false | 532 | 532 | { ... } | +| if_decl_bind | false | 535 | 535 | ExprStmt | +| if_decl_bind | false | 538 | 538 | x | +| if_decl_bind | false | 544 | 544 | 1 | +| if_decl_bind | false | 546 | 546 | ... = ... | +| if_decl_bind | false | 549 | 549 | return ... | +| if_decl_bind | false | 552 | 552 | { ... } | +| if_decl_bind | false | 555 | 555 | bi | +| if_decl_bind | false | 558 | 558 | call to bi.~BoxedInt | +| if_decl_bind | true | 473 | 484 | | +| if_decl_bind | true | 481 | 496 | | +| if_decl_bind | true | 484 | 481 | | +| if_decl_bind | true | 496 | 514 | T | +| if_decl_bind | true | 496 | 532 | F | +| if_decl_bind | true | 499 | 502 | | +| if_decl_bind | true | 502 | 505 | | +| if_decl_bind | true | 505 | 508 | | +| if_decl_bind | true | 508 | 511 | | +| if_decl_bind | true | 511 | 555 | | +| if_decl_bind | true | 514 | 499 | | +| if_decl_bind | true | 517 | 520 | | +| if_decl_bind | true | 520 | 523 | | +| if_decl_bind | true | 523 | 526 | | +| if_decl_bind | true | 526 | 529 | | +| if_decl_bind | true | 529 | 555 | | +| if_decl_bind | true | 532 | 517 | | +| if_decl_bind | true | 535 | 544 | | +| if_decl_bind | true | 538 | 546 | | +| if_decl_bind | true | 544 | 538 | | +| if_decl_bind | true | 546 | 549 | | +| if_decl_bind | true | 549 | 464 | | +| if_decl_bind | true | 552 | 473 | | +| if_decl_bind | true | 555 | 558 | | +| if_decl_bind | true | 558 | 535 | | +| never_destructs | false | 857 | 857 | never_destructs | +| never_destructs | false | 863 | 863 | declaration | +| never_destructs | false | 870 | 870 | label ...: | +| never_destructs | false | 873 | 873 | goto ... | +| never_destructs | false | 876 | 876 | { ... } | +| never_destructs | true | 863 | 870 | | +| never_destructs | true | 870 | 873 | | +| never_destructs | true | 873 | 870 | | +| never_destructs | true | 876 | 863 | | +| operator delete | false | 601 | 601 | operator delete | +| operator new | false | 632 | 632 | operator new | +| simple | false | 1126 | 1126 | simple | +| simple | false | 1132 | 1132 | declaration | +| simple | false | 1139 | 1139 | return ... | +| simple | false | 1142 | 1142 | { ... } | +| simple | false | 1145 | 1145 | nt | +| simple | false | 1148 | 1148 | call to nt.~NonTrivial | +| simple | true | 1132 | 1139 | | +| simple | true | 1139 | 1145 | | +| simple | true | 1142 | 1132 | | +| simple | true | 1145 | 1148 | | +| simple | true | 1148 | 1126 | | +| simple2 | false | 1092 | 1092 | simple2 | +| simple2 | false | 1098 | 1098 | declaration | +| simple2 | false | 1105 | 1105 | declaration | +| simple2 | false | 1112 | 1112 | return ... | +| simple2 | false | 1115 | 1115 | { ... } | +| simple2 | false | 1118 | 1118 | one | +| simple2 | false | 1121 | 1121 | call to one.~NonTrivial | +| simple2 | false | 1123 | 1123 | two | +| simple2 | false | 1125 | 1125 | call to two.~NonTrivial | +| simple2 | true | 1098 | 1105 | | +| simple2 | true | 1105 | 1112 | | +| simple2 | true | 1112 | 1123 | | +| simple2 | true | 1115 | 1098 | | +| simple2 | true | 1118 | 1121 | | +| simple2 | true | 1121 | 1092 | | +| simple2 | true | 1123 | 1125 | | +| simple2 | true | 1125 | 1118 | | +| switch_decl_bind | false | 316 | 316 | switch_decl_bind | +| switch_decl_bind | false | 325 | 325 | switch (...) ... | +| switch_decl_bind | false | 329 | 329 | call to operator int | +| switch_decl_bind | false | 333 | 333 | call to BoxedInt | +| switch_decl_bind | false | 336 | 336 | x | +| switch_decl_bind | false | 339 | 339 | initializer for bi | +| switch_decl_bind | false | 343 | 343 | bi | +| switch_decl_bind | false | 346 | 346 | (condition decl) | +| switch_decl_bind | false | 349 | 349 | case ...: | +| switch_decl_bind | false | 355 | 355 | 0 | +| switch_decl_bind | false | 357 | 357 | ExprStmt | +| switch_decl_bind | false | 360 | 360 | bi | +| switch_decl_bind | false | 364 | 364 | m_ptr | +| switch_decl_bind | false | 368 | 368 | * ... | +| switch_decl_bind | false | 371 | 371 | -- ... | +| switch_decl_bind | false | 374 | 374 | break; | +| switch_decl_bind | false | 377 | 377 | case ...: | +| switch_decl_bind | false | 383 | 383 | 1 | +| switch_decl_bind | false | 385 | 385 | ExprStmt | +| switch_decl_bind | false | 388 | 388 | bi | +| switch_decl_bind | false | 391 | 391 | m_ptr | +| switch_decl_bind | false | 394 | 394 | * ... | +| switch_decl_bind | false | 397 | 397 | ++ ... | +| switch_decl_bind | false | 400 | 400 | break; | +| switch_decl_bind | false | 403 | 403 | default: | +| switch_decl_bind | false | 406 | 406 | ExprStmt | +| switch_decl_bind | false | 409 | 409 | bi | +| switch_decl_bind | false | 412 | 412 | m_ptr | +| switch_decl_bind | false | 415 | 415 | * ... | +| switch_decl_bind | false | 421 | 421 | 2 | +| switch_decl_bind | false | 423 | 423 | ... /= ... | +| switch_decl_bind | false | 426 | 426 | { ... } | +| switch_decl_bind | false | 429 | 429 | label ...: | +| switch_decl_bind | false | 432 | 432 | ExprStmt | +| switch_decl_bind | false | 435 | 435 | x | +| switch_decl_bind | false | 441 | 441 | 1 | +| switch_decl_bind | false | 443 | 443 | ... = ... | +| switch_decl_bind | false | 446 | 446 | return ... | +| switch_decl_bind | false | 449 | 449 | { ... } | +| switch_decl_bind | false | 452 | 452 | bi | +| switch_decl_bind | false | 455 | 455 | call to bi.~BoxedInt | +| switch_decl_bind | false | 457 | 457 | bi | +| switch_decl_bind | false | 459 | 459 | call to bi.~BoxedInt | +| switch_decl_bind | false | 461 | 461 | bi | +| switch_decl_bind | false | 463 | 463 | call to bi.~BoxedInt | +| switch_decl_bind | true | 325 | 336 | | +| switch_decl_bind | true | 333 | 346 | | +| switch_decl_bind | true | 336 | 333 | | +| switch_decl_bind | true | 346 | 426 | | +| switch_decl_bind | true | 349 | 357 | | +| switch_decl_bind | true | 357 | 360 | | | switch_decl_bind | true | 360 | 364 | | -| switch_decl_bind | true | 362 | 354 | | -| switch_decl_bind | true | 364 | 403 | | -| switch_decl_bind | true | 366 | 379 | | -| switch_decl_bind | true | 368 | 370 | | -| switch_decl_bind | true | 370 | 372 | | -| switch_decl_bind | true | 372 | 376 | | -| switch_decl_bind | true | 376 | 377 | | -| switch_decl_bind | true | 377 | 400 | | -| switch_decl_bind | true | 379 | 368 | | -| switch_decl_bind | true | 381 | 333 | | -| switch_decl_bind | true | 381 | 352 | | -| switch_decl_bind | true | 381 | 366 | | -| switch_decl_bind | true | 383 | 321 | | -| switch_decl_bind | true | 385 | 394 | | -| switch_decl_bind | true | 387 | 392 | | -| switch_decl_bind | true | 391 | 387 | | -| switch_decl_bind | true | 392 | 396 | | -| switch_decl_bind | true | 394 | 391 | | -| switch_decl_bind | true | 396 | 308 | | -| switch_decl_bind | true | 398 | 383 | | -| switch_decl_bind | true | 400 | 402 | | -| switch_decl_bind | true | 402 | 385 | | -| switch_decl_bind | true | 403 | 404 | | -| switch_decl_bind | true | 404 | 385 | | -| switch_decl_bind | true | 405 | 406 | | -| switch_decl_bind | true | 406 | 385 | | -| while_decl_bind | false | 260 | 260 | while_decl_bind | -| while_decl_bind | false | 269 | 269 | call to operator int | -| while_decl_bind | false | 271 | 271 | call to BoxedInt | -| while_decl_bind | false | 273 | 273 | x | -| while_decl_bind | false | 275 | 275 | initializer for bi | -| while_decl_bind | false | 278 | 278 | bi | -| while_decl_bind | false | 280 | 280 | (bool)... | -| while_decl_bind | false | 281 | 281 | (condition decl) | -| while_decl_bind | false | 283 | 283 | x | -| while_decl_bind | false | 285 | 285 | -- ... | -| while_decl_bind | false | 287 | 287 | ExprStmt | -| while_decl_bind | false | 289 | 289 | { ... } | -| while_decl_bind | false | 291 | 291 | while (...) ... | -| while_decl_bind | false | 293 | 293 | x | -| while_decl_bind | false | 295 | 295 | ++ ... | -| while_decl_bind | false | 297 | 297 | ExprStmt | -| while_decl_bind | false | 299 | 299 | return ... | -| while_decl_bind | false | 301 | 301 | { ... } | -| while_decl_bind | false | 303 | 303 | bi | -| while_decl_bind | false | 305 | 305 | call to bi.~BoxedInt | -| while_decl_bind | false | 306 | 306 | bi | -| while_decl_bind | false | 307 | 307 | call to bi.~BoxedInt | -| while_decl_bind | true | 271 | 281 | | -| while_decl_bind | true | 273 | 271 | | -| while_decl_bind | true | 281 | 289 | T | -| while_decl_bind | true | 281 | 303 | F | -| while_decl_bind | true | 283 | 285 | | -| while_decl_bind | true | 285 | 306 | | -| while_decl_bind | true | 287 | 283 | | -| while_decl_bind | true | 289 | 287 | | -| while_decl_bind | true | 291 | 273 | | -| while_decl_bind | true | 293 | 295 | | -| while_decl_bind | true | 295 | 299 | | -| while_decl_bind | true | 297 | 293 | | -| while_decl_bind | true | 299 | 260 | | -| while_decl_bind | true | 301 | 291 | | -| while_decl_bind | true | 303 | 305 | | -| while_decl_bind | true | 305 | 297 | | -| while_decl_bind | true | 306 | 307 | | -| while_decl_bind | true | 307 | 273 | | +| switch_decl_bind | true | 364 | 368 | | +| switch_decl_bind | true | 368 | 371 | | +| switch_decl_bind | true | 371 | 374 | | +| switch_decl_bind | true | 374 | 457 | | +| switch_decl_bind | true | 377 | 385 | | +| switch_decl_bind | true | 385 | 388 | | +| switch_decl_bind | true | 388 | 391 | | +| switch_decl_bind | true | 391 | 394 | | +| switch_decl_bind | true | 394 | 397 | | +| switch_decl_bind | true | 397 | 400 | | +| switch_decl_bind | true | 400 | 461 | | +| switch_decl_bind | true | 403 | 406 | | +| switch_decl_bind | true | 406 | 409 | | +| switch_decl_bind | true | 409 | 412 | | +| switch_decl_bind | true | 412 | 415 | | +| switch_decl_bind | true | 415 | 421 | | +| switch_decl_bind | true | 421 | 423 | | +| switch_decl_bind | true | 423 | 452 | | +| switch_decl_bind | true | 426 | 349 | | +| switch_decl_bind | true | 426 | 377 | | +| switch_decl_bind | true | 426 | 403 | | +| switch_decl_bind | true | 429 | 432 | | +| switch_decl_bind | true | 432 | 441 | | +| switch_decl_bind | true | 435 | 443 | | +| switch_decl_bind | true | 441 | 435 | | +| switch_decl_bind | true | 443 | 446 | | +| switch_decl_bind | true | 446 | 316 | | +| switch_decl_bind | true | 449 | 325 | | +| switch_decl_bind | true | 452 | 455 | | +| switch_decl_bind | true | 455 | 429 | | +| switch_decl_bind | true | 457 | 459 | | +| switch_decl_bind | true | 459 | 429 | | +| switch_decl_bind | true | 461 | 463 | | +| switch_decl_bind | true | 463 | 429 | | +| while_decl_bind | false | 246 | 246 | while_decl_bind | +| while_decl_bind | false | 255 | 255 | while (...) ... | +| while_decl_bind | false | 259 | 259 | call to operator int | +| while_decl_bind | false | 263 | 263 | call to BoxedInt | +| while_decl_bind | false | 266 | 266 | x | +| while_decl_bind | false | 269 | 269 | initializer for bi | +| while_decl_bind | false | 273 | 273 | bi | +| while_decl_bind | false | 276 | 276 | (bool)... | +| while_decl_bind | false | 278 | 278 | (condition decl) | +| while_decl_bind | false | 281 | 281 | ExprStmt | +| while_decl_bind | false | 284 | 284 | x | +| while_decl_bind | false | 287 | 287 | -- ... | +| while_decl_bind | false | 290 | 290 | { ... } | +| while_decl_bind | false | 293 | 293 | ExprStmt | +| while_decl_bind | false | 296 | 296 | x | +| while_decl_bind | false | 299 | 299 | ++ ... | +| while_decl_bind | false | 302 | 302 | return ... | +| while_decl_bind | false | 305 | 305 | { ... } | +| while_decl_bind | false | 308 | 308 | bi | +| while_decl_bind | false | 311 | 311 | call to bi.~BoxedInt | +| while_decl_bind | false | 313 | 313 | bi | +| while_decl_bind | false | 315 | 315 | call to bi.~BoxedInt | +| while_decl_bind | true | 255 | 266 | | +| while_decl_bind | true | 263 | 278 | | +| while_decl_bind | true | 266 | 263 | | +| while_decl_bind | true | 278 | 290 | T | +| while_decl_bind | true | 278 | 308 | F | +| while_decl_bind | true | 281 | 284 | | +| while_decl_bind | true | 284 | 287 | | +| while_decl_bind | true | 287 | 313 | | +| while_decl_bind | true | 290 | 281 | | +| while_decl_bind | true | 293 | 296 | | +| while_decl_bind | true | 296 | 299 | | +| while_decl_bind | true | 299 | 302 | | +| while_decl_bind | true | 302 | 246 | | +| while_decl_bind | true | 305 | 255 | | +| while_decl_bind | true | 308 | 311 | | +| while_decl_bind | true | 311 | 293 | | +| while_decl_bind | true | 313 | 315 | | +| while_decl_bind | true | 315 | 266 | | diff --git a/cpp/ql/test/successor-tests/whilestmt/whilestmt04.ql b/cpp/ql/test/successor-tests/whilestmt/whilestmt04.ql index 1ae9f4931a57..1e7c43de9931 100644 --- a/cpp/ql/test/successor-tests/whilestmt/whilestmt04.ql +++ b/cpp/ql/test/successor-tests/whilestmt/whilestmt04.ql @@ -8,7 +8,7 @@ import cpp from WhileStmt ws, ExprStmt last, Expr succ where ws.getEnclosingFunction().hasName("normal") and - last = ws.getStmt().(Block).getLastStmt() and + last = ws.getStmt().(BlockStmt).getLastStmt() and succ = last.getExpr().getASuccessor() and succ = ws.getCondition().getAChild*() and count(last.getExpr().getASuccessor()) = 1 diff --git a/cpp/upgrades/025827d85c3f44a7fd52d4fad636e9a4141f12dd/old.dbscheme b/cpp/upgrades/025827d85c3f44a7fd52d4fad636e9a4141f12dd/old.dbscheme new file mode 100644 index 000000000000..025827d85c3f --- /dev/null +++ b/cpp/upgrades/025827d85c3f44a7fd52d4fad636e9a4141f12dd/old.dbscheme @@ -0,0 +1,2109 @@ + +/** + * 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 date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int 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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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 +); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: 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); + +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 +) + +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 +); + +// 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 +); + +decltypes( + unique 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, + unique 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 + ; + +/* +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 + ; + +@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 +; + +@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 +; + +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 ; +successors( + int from: @cfgnode ref, + int to: @cfgnode ref +); + +truecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +falsecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +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/upgrades/025827d85c3f44a7fd52d4fad636e9a4141f12dd/semmlecode.cpp.dbscheme b/cpp/upgrades/025827d85c3f44a7fd52d4fad636e9a4141f12dd/semmlecode.cpp.dbscheme new file mode 100644 index 000000000000..098850d25c4e --- /dev/null +++ b/cpp/upgrades/025827d85c3f44a7fd52d4fad636e9a4141f12dd/semmlecode.cpp.dbscheme @@ -0,0 +1,2110 @@ + +/** + * 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 date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int 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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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 +); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: 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); + +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 +) + +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 +); + +decltypes( + unique 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, + unique 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 + ; + +/* +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 + ; + +@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 +; + +@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 +; + +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 ; +successors( + int from: @cfgnode ref, + int to: @cfgnode ref +); + +truecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +falsecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +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/upgrades/025827d85c3f44a7fd52d4fad636e9a4141f12dd/static_asserts.ql b/cpp/upgrades/025827d85c3f44a7fd52d4fad636e9a4141f12dd/static_asserts.ql new file mode 100644 index 000000000000..e5ec84fd76e4 --- /dev/null +++ b/cpp/upgrades/025827d85c3f44a7fd52d4fad636e9a4141f12dd/static_asserts.ql @@ -0,0 +1,21 @@ +class StaticAssert extends @static_assert { + string toString() { none() } +} + +class Expr extends @expr { + string toString() { none() } +} + +class Location extends @location_default { + string toString() { none() } +} + +class NameSpace extends @namespace { + string toString() { none() } +} + +from StaticAssert sa, Expr condition, string message, Location loc, NameSpace ns +where + static_asserts(sa, condition, message, loc) and + namespaces(ns, "") +select sa, condition, message, loc, ns diff --git a/cpp/upgrades/025827d85c3f44a7fd52d4fad636e9a4141f12dd/upgrade.properties b/cpp/upgrades/025827d85c3f44a7fd52d4fad636e9a4141f12dd/upgrade.properties new file mode 100644 index 000000000000..ca1074f5a4de --- /dev/null +++ b/cpp/upgrades/025827d85c3f44a7fd52d4fad636e9a4141f12dd/upgrade.properties @@ -0,0 +1,4 @@ +description: Give static_assert's an enclosing element +compatibility: partial +static_asserts.rel: run static_asserts.qlo + diff --git a/cpp/upgrades/098850d25c4e9d417eb74c1bef9deb2f9d2dc417/old.dbscheme b/cpp/upgrades/098850d25c4e9d417eb74c1bef9deb2f9d2dc417/old.dbscheme new file mode 100644 index 000000000000..098850d25c4e --- /dev/null +++ b/cpp/upgrades/098850d25c4e9d417eb74c1bef9deb2f9d2dc417/old.dbscheme @@ -0,0 +1,2110 @@ + +/** + * 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 date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int 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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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 +); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: 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); + +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 +) + +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 +); + +decltypes( + unique 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, + unique 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 + ; + +/* +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 + ; + +@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 +; + +@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 +; + +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 ; +successors( + int from: @cfgnode ref, + int to: @cfgnode ref +); + +truecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +falsecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +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/upgrades/098850d25c4e9d417eb74c1bef9deb2f9d2dc417/semmlecode.cpp.dbscheme b/cpp/upgrades/098850d25c4e9d417eb74c1bef9deb2f9d2dc417/semmlecode.cpp.dbscheme new file mode 100644 index 000000000000..75da61c94e19 --- /dev/null +++ b/cpp/upgrades/098850d25c4e9d417eb74c1bef9deb2f9d2dc417/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 date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int 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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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 +); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: 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); + +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 +) + +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 +); + +decltypes( + unique 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, + unique 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 + ; + +/* +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 + ; + +@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 +; + +@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 +; + +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/upgrades/098850d25c4e9d417eb74c1bef9deb2f9d2dc417/upgrade.properties b/cpp/upgrades/098850d25c4e9d417eb74c1bef9deb2f9d2dc417/upgrade.properties new file mode 100644 index 000000000000..474d82826f82 --- /dev/null +++ b/cpp/upgrades/098850d25c4e9d417eb74c1bef9deb2f9d2dc417/upgrade.properties @@ -0,0 +1,3 @@ +description: Remove the old CFG tables +compatibility: full + diff --git a/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/member_function_this_type.ql b/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/member_function_this_type.ql new file mode 100644 index 000000000000..2e99f1ed5f00 --- /dev/null +++ b/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/member_function_this_type.ql @@ -0,0 +1,48 @@ +/* + * Upgrade script to populate the member_function_this_type table. It's a rough + * approximation of what the extractor would do - for a member function C::f, + * we say its type is C* (if that pointer type exists in the database). + * CV-qualifiers are ignored. + */ + +class Class extends @usertype { + Class() { + usertypes(this, _, 1) or + usertypes(this, _, 2) or + usertypes(this, _, 3) or + usertypes(this, _, 6) or + usertypes(this, _, 10) or + usertypes(this, _, 11) or + usertypes(this, _, 12) + } + + string toString() { usertypes(this, result, _) } +} + +class ClassPointerType extends @derivedtype { + ClassPointerType() { derivedtypes(this, _, 1, _) } + + Class getBaseType() { derivedtypes(this, _, _, result) } + + string toString() { result = getBaseType().toString() + "*" } +} + +class DefinedMemberFunction extends @function { + DefinedMemberFunction() { + exists(@fun_decl fd | + fun_def(fd) and + ( + fun_decls(fd, this, _, _, _) + or + exists(@function f | function_instantiation(this, f) and fun_decls(fd, f, _, _, _)) + ) + ) + } + + ClassPointerType getTypeOfThis() { member(result.getBaseType(), _, this) } + + string toString() { functions(this, result, _) } +} + +from DefinedMemberFunction f +select f, f.getTypeOfThis() diff --git a/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/old.dbscheme b/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/old.dbscheme new file mode 100644 index 000000000000..282c13bfdbcb --- /dev/null +++ b/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/old.dbscheme @@ -0,0 +1,2109 @@ + +/** + * 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 date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int 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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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 +); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: 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); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function 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 +) + +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 +); + +// 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 +); + +decltypes( + unique 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, + unique 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 + ; + +/* +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 + ; + +@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 +; + +@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 +; + +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 ; +successors( + int from: @cfgnode ref, + int to: @cfgnode ref +); + +truecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +falsecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +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/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/semmlecode.cpp.dbscheme b/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/semmlecode.cpp.dbscheme new file mode 100644 index 000000000000..025827d85c3f --- /dev/null +++ b/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/semmlecode.cpp.dbscheme @@ -0,0 +1,2109 @@ + +/** + * 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 date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int 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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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 +); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: 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); + +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 +) + +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 +); + +// 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 +); + +decltypes( + unique 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, + unique 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 + ; + +/* +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 + ; + +@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 +; + +@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 +; + +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 ; +successors( + int from: @cfgnode ref, + int to: @cfgnode ref +); + +truecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +falsecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +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/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/upgrade.properties b/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/upgrade.properties new file mode 100644 index 000000000000..018a42e6dc19 --- /dev/null +++ b/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/upgrade.properties @@ -0,0 +1,3 @@ +description: Add table relating a member function to the type of `this`. +compatibility: partial +member_function_this_type.rel: run member_function_this_type.qlo diff --git a/cpp/upgrades/75da61c94e19ae80a142f03a877ab9d0728752bc/old.dbscheme b/cpp/upgrades/75da61c94e19ae80a142f03a877ab9d0728752bc/old.dbscheme new file mode 100644 index 000000000000..75da61c94e19 --- /dev/null +++ b/cpp/upgrades/75da61c94e19ae80a142f03a877ab9d0728752bc/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 date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int 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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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 +); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: 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); + +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 +) + +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 +); + +decltypes( + unique 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, + unique 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 + ; + +/* +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 + ; + +@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 +; + +@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 +; + +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/upgrades/75da61c94e19ae80a142f03a877ab9d0728752bc/semmlecode.cpp.dbscheme b/cpp/upgrades/75da61c94e19ae80a142f03a877ab9d0728752bc/semmlecode.cpp.dbscheme new file mode 100644 index 000000000000..b5fa4fb0283c --- /dev/null +++ b/cpp/upgrades/75da61c94e19ae80a142f03a877ab9d0728752bc/semmlecode.cpp.dbscheme @@ -0,0 +1,2101 @@ + +/** + * 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 date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int 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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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 +); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: 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); + +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 +) + +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 +); + +decltypes( + unique 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, + unique 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 + ; + +/* +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 +; + +@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/upgrades/75da61c94e19ae80a142f03a877ab9d0728752bc/upgrade.properties b/cpp/upgrades/75da61c94e19ae80a142f03a877ab9d0728752bc/upgrade.properties new file mode 100644 index 000000000000..c935a87cb40c --- /dev/null +++ b/cpp/upgrades/75da61c94e19ae80a142f03a877ab9d0728752bc/upgrade.properties @@ -0,0 +1,3 @@ +description: Add some coroutines types (@co_await, @co_yield, @stmt_co_return) +compatibility: backwards + diff --git a/cpp/upgrades/b5fa4fb0283c4accf2d85d559aeb2bba914c102b/old.dbscheme b/cpp/upgrades/b5fa4fb0283c4accf2d85d559aeb2bba914c102b/old.dbscheme new file mode 100644 index 000000000000..b5fa4fb0283c --- /dev/null +++ b/cpp/upgrades/b5fa4fb0283c4accf2d85d559aeb2bba914c102b/old.dbscheme @@ -0,0 +1,2101 @@ + +/** + * 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 date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int 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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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 +); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: 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); + +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 +) + +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 +); + +decltypes( + unique 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, + unique 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 + ; + +/* +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 +; + +@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/upgrades/b5fa4fb0283c4accf2d85d559aeb2bba914c102b/semmlecode.cpp.dbscheme b/cpp/upgrades/b5fa4fb0283c4accf2d85d559aeb2bba914c102b/semmlecode.cpp.dbscheme new file mode 100644 index 000000000000..ef73d8cf906d --- /dev/null +++ b/cpp/upgrades/b5fa4fb0283c4accf2d85d559aeb2bba914c102b/semmlecode.cpp.dbscheme @@ -0,0 +1,2123 @@ + +/** + * 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 date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int 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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +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 +); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: 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 +) + +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 +); + +decltypes( + unique 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, + unique 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 + ; + +/* +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 +; + +@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/upgrades/b5fa4fb0283c4accf2d85d559aeb2bba914c102b/upgrade.properties b/cpp/upgrades/b5fa4fb0283c4accf2d85d559aeb2bba914c102b/upgrade.properties new file mode 100644 index 000000000000..d089781baafc --- /dev/null +++ b/cpp/upgrades/b5fa4fb0283c4accf2d85d559aeb2bba914c102b/upgrade.properties @@ -0,0 +1,3 @@ +description: Add coroutines metadata tables +compatibility: backwards + diff --git a/csharp/.editorconfig b/csharp/.editorconfig new file mode 100644 index 000000000000..3705b7144e33 --- /dev/null +++ b/csharp/.editorconfig @@ -0,0 +1,273 @@ +# Taken as is from https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference?view=vs-2019 +# Naming rules are removed. +# Customizations are added at the bottom of the file. + +# Remove the line below if you want to inherit .editorconfig settings from higher directories +root = true + +# C# files +[*.cs] + +#### Core EditorConfig Options #### + +# Indentation and spacing +indent_size = 4 +indent_style = space +tab_width = 4 + +# New line preferences +end_of_line = {cr|lf|crlf} # we should use what git uses +insert_final_newline = true + +#### .NET Coding Conventions #### + +# Organize usings - not specified +# dotnet_separate_import_directive_groups = false +# dotnet_sort_system_directives_first = false + +# this. and Me. preferences +dotnet_style_qualification_for_event = false:silent +dotnet_style_qualification_for_field = false:silent +dotnet_style_qualification_for_method = false:silent +dotnet_style_qualification_for_property = false:silent + +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true:silent +dotnet_style_predefined_type_for_member_access = true:silent + +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent + +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent + +# Expression-level preferences +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_object_initializer = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_prefer_conditional_expression_over_return = true:silent +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_simplified_interpolation = true:suggestion + +# Field preferences +dotnet_style_readonly_field = true:suggestion + +# Parameter preferences +dotnet_code_quality_unused_parameters = all:suggestion + +#### C# Coding Conventions #### + +# var preferences +csharp_style_var_elsewhere = false:silent +csharp_style_var_for_built_in_types = false:silent +csharp_style_var_when_type_is_apparent = false:silent + +# Expression-bodied members +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent + +# Pattern matching preferences +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_prefer_switch_expression = true:suggestion + +# Null-checking preferences +csharp_style_conditional_delegate_call = true:suggestion + +# Modifier preferences +csharp_prefer_static_local_function = true:suggestion +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent + +# Code-block preferences +csharp_prefer_braces = true:silent +csharp_prefer_simple_using_statement = true:suggestion + +# Expression-level preferences +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_pattern_local_over_anonymous_function = true:suggestion +csharp_style_prefer_index_operator = true:suggestion +csharp_style_prefer_range_operator = true:suggestion +csharp_style_throw_expression = true:suggestion +csharp_style_unused_value_assignment_preference = discard_variable:suggestion +csharp_style_unused_value_expression_statement_preference = discard_variable:silent + +# 'using' directive preferences +csharp_using_directive_placement = outside_namespace:silent + +#### C# Formatting Rules #### + +# New line preferences +csharp_new_line_before_catch = true +csharp_new_line_before_else = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_open_brace = all +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_labels = one_less_than_current +csharp_indent_switch_labels = true + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +# Wrapping preferences +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true + + +#### Naming rules #### + +dotnet_naming_style.camel_case_style.capitalization = camel_case + +# Private fields are camelCase +dotnet_naming_rule.private_fields_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.private_fields_should_be_pascal_case.symbols = private_fields +dotnet_naming_rule.private_fields_should_be_pascal_case.style = camel_case_style + +dotnet_naming_symbols.private_fields.applicable_kinds = field +dotnet_naming_symbols.private_fields.applicable_accessibilities = private + +# Locals and parameters are camelCase +dotnet_naming_rule.locals_should_be_camel_case.severity = suggestion +dotnet_naming_rule.locals_should_be_camel_case.symbols = locals_and_parameters +dotnet_naming_rule.locals_should_be_camel_case.style = camel_case_style + +dotnet_naming_symbols.locals_and_parameters.applicable_kinds = parameter, local + +# Interfaces are PascalCase, prefixed with I + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = * + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +# Type parameters are PascalCase, prefixed with T + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = type_parameter +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_t + +dotnet_naming_symbols.type_parameter.applicable_kinds = type_parameter +dotnet_naming_symbols.type_parameter.applicable_accessibilities = * + +dotnet_naming_style.begins_with_t.required_prefix = T +dotnet_naming_style.begins_with_t.capitalization = pascal_case + +# By default, name items with PascalCase +dotnet_naming_rule.members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.members_should_be_pascal_case.symbols = all_members +dotnet_naming_rule.members_should_be_pascal_case.style = pascal_case_style + +dotnet_naming_symbols.all_members.applicable_kinds = * + +dotnet_naming_style.pascal_case_style.capitalization = pascal_case + +#### End naming rules #### + + + +## The below are taken from Roslyn: https://github.com/dotnet/roslyn/blob/master/.editorconfig + +# IDE0055: Fix formatting +dotnet_diagnostic.IDE0055.severity = warning + +# IDE0011: Add braces +csharp_prefer_braces = when_multiline:warning +# NOTE: We need the below severity entry for Add Braces due to https://github.com/dotnet/roslyn/issues/44201 +dotnet_diagnostic.IDE0011.severity = warning + +# IDE0040: Add accessibility modifiers +dotnet_diagnostic.IDE0040.severity = warning + +# CONSIDER: Are IDE0051 and IDE0052 too noisy to be warnings for IDE editing scenarios? Should they be made build-only warnings? +# IDE0051: Remove unused private member +dotnet_diagnostic.IDE0051.severity = warning + +# IDE0052: Remove unread private member +dotnet_diagnostic.IDE0052.severity = warning + +# IDE0059: Unnecessary assignment to a value +dotnet_diagnostic.IDE0059.severity = warning + +# IDE0060: Remove unused parameter +dotnet_diagnostic.IDE0060.severity = warning + +# CA1822: Make member static +dotnet_diagnostic.CA1822.severity = warning + +# IDE0035: Remove unreachable code +dotnet_diagnostic.IDE0035.severity = warning + +# IDE0036: Order modifiers +dotnet_diagnostic.IDE0036.severity = warning + +# IDE0043: Format string contains invalid placeholder +dotnet_diagnostic.IDE0043.severity = warning + +# IDE0044: Make field readonly +dotnet_diagnostic.IDE0044.severity = warning + +# Prefer "var" everywhere +dotnet_diagnostic.IDE0007.severity = suggestion +csharp_style_var_for_built_in_types = true:suggestion +csharp_style_var_when_type_is_apparent = true:suggestion +csharp_style_var_elsewhere = true:suggestion + +# +# Customizations +# + +[extractor/Semmle.Extraction/Tuples.cs, + extractor/Semmle.Extraction.CSharp/Tuples.cs, + extractor/Semmle.Extraction.CIL/Tuples.cs] +dotnet_naming_rule.members_should_be_pascal_case.severity = none \ No newline at end of file diff --git a/csharp/.gitignore b/csharp/.gitignore index f81ecc73dffa..0701c11fe1d8 100644 --- a/csharp/.gitignore +++ b/csharp/.gitignore @@ -10,4 +10,5 @@ csharp.log **/bin/Release *.tlog .vs -*.user \ No newline at end of file +*.user +.vscode/launch.json \ No newline at end of file diff --git a/csharp/.vscode/extensions.json b/csharp/.vscode/extensions.json new file mode 100644 index 000000000000..f05b9cdf715c --- /dev/null +++ b/csharp/.vscode/extensions.json @@ -0,0 +1,9 @@ +{ + "recommendations": [ + "github.vscode-codeql", + "ms-dotnettools.csharp", + "formulahendry.dotnet-test-explorer", + "hbenl.vscode-test-explorer" + ], + "unwantedRecommendations": [] +} \ No newline at end of file diff --git a/csharp/.vscode/settings.json b/csharp/.vscode/settings.json new file mode 100644 index 000000000000..dd6b2b3baf88 --- /dev/null +++ b/csharp/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "dotnet-test-explorer.enableTelemetry": false, + "dotnet-test-explorer.testProjectPath": "**/*Tests.@(csproj|vbproj|fsproj)", + "dotnet-test-explorer.testArguments": "/property:GenerateTargetFrameworkAttribute=false", + "csharp.suppressDotnetRestoreNotification": true, + "[csharp]": { + "editor.defaultFormatter": "ms-dotnettools.csharp" + }, + "omnisharp.enableEditorConfigSupport": true, + "omnisharp.enableRoslynAnalyzers": true +} \ No newline at end of file diff --git a/csharp/.vscode/tasks.json b/csharp/.vscode/tasks.json new file mode 100644 index 000000000000..d3a0553dc440 --- /dev/null +++ b/csharp/.vscode/tasks.json @@ -0,0 +1,53 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "dotnet build", + "command": "dotnet", + "type": "shell", + "args": [ + "build", + // Ask dotnet build to generate full paths for file names. + "/property:GenerateFullPaths=true", + // Do not generate summary otherwise it leads to duplicate errors in Problems panel + "/consoleloggerparameters:NoSummary" + ], + "group": "build", + "presentation": { + "reveal": "always" + }, + "problemMatcher": "$msCompile" + }, + { + "label": "dotnet rebuild", + "command": "dotnet", + "type": "shell", + "args": [ + "build", + "--no-incremental", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "group": "build", + "presentation": { + "reveal": "always" + }, + "problemMatcher": "$msCompile" + }, + { + "label": "dotnet test", + "command": "dotnet", + "type": "shell", + "args": [ + "test", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "group": "test", + "presentation": { + "reveal": "always" + }, + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/csharp/CSharp.sln b/csharp/CSharp.sln index 78d853a5bbea..7762dd469b90 100644 --- a/csharp/CSharp.sln +++ b/csharp/CSharp.sln @@ -11,8 +11,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CSharp", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CIL", "extractor\Semmle.Extraction.CIL\Semmle.Extraction.CIL.csproj", "{399A1579-68F0-40F4-9A23-F241BA697F9C}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Autobuild", "autobuilder\Semmle.Autobuild\Semmle.Autobuild.csproj", "{5131EF00-0BA9-4436-A3B0-C5CDAB4B194C}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CSharp.Standalone", "extractor\Semmle.Extraction.CSharp.Standalone\Semmle.Extraction.CSharp.Standalone.csproj", "{D00E7D25-0FA0-48EC-B048-CD60CE1B30D8}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CIL.Driver", "extractor\Semmle.Extraction.CIL.Driver\Semmle.Extraction.CIL.Driver.csproj", "{EFA400B3-C1CE-446F-A4E2-8B44E61EF47C}" @@ -23,7 +21,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.Tests", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Util.Tests", "extractor\Semmle.Util.Tests\Semmle.Util.Tests.csproj", "{55A620F0-23F6-440D-A5BA-0567613B3C0F}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Autobuild.Tests", "autobuilder\Semmle.Autobuild.Tests\Semmle.Autobuild.Tests.csproj", "{CE267461-D762-4F53-A275-685A0A4EC48D}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Semmle.Autobuild.Shared", "autobuilder\Semmle.Autobuild.Shared\Semmle.Autobuild.Shared.csproj", "{133F2B5B-FD25-4BD9-B34C-062CC6BB4178}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Semmle.Autobuild.CSharp", "autobuilder\Semmle.Autobuild.CSharp\Semmle.Autobuild.CSharp.csproj", "{F3C07863-3759-4A0B-B777-8A0E0FDB1A41}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Semmle.Autobuild.CSharp.Tests", "autobuilder\Semmle.Autobuild.CSharp.Tests\Semmle.Autobuild.CSharp.Tests.csproj", "{34256E8F-866A-46C1-800E-3DF69FD1DCB7}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -47,10 +49,6 @@ Global {399A1579-68F0-40F4-9A23-F241BA697F9C}.Debug|Any CPU.Build.0 = Debug|Any CPU {399A1579-68F0-40F4-9A23-F241BA697F9C}.Release|Any CPU.ActiveCfg = Release|Any CPU {399A1579-68F0-40F4-9A23-F241BA697F9C}.Release|Any CPU.Build.0 = Release|Any CPU - {5131EF00-0BA9-4436-A3B0-C5CDAB4B194C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5131EF00-0BA9-4436-A3B0-C5CDAB4B194C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5131EF00-0BA9-4436-A3B0-C5CDAB4B194C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5131EF00-0BA9-4436-A3B0-C5CDAB4B194C}.Release|Any CPU.Build.0 = Release|Any CPU {D00E7D25-0FA0-48EC-B048-CD60CE1B30D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D00E7D25-0FA0-48EC-B048-CD60CE1B30D8}.Debug|Any CPU.Build.0 = Debug|Any CPU {D00E7D25-0FA0-48EC-B048-CD60CE1B30D8}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -69,10 +67,18 @@ Global {55A620F0-23F6-440D-A5BA-0567613B3C0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {55A620F0-23F6-440D-A5BA-0567613B3C0F}.Debug|Any CPU.Build.0 = Debug|Any CPU {55A620F0-23F6-440D-A5BA-0567613B3C0F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CE267461-D762-4F53-A275-685A0A4EC48D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CE267461-D762-4F53-A275-685A0A4EC48D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CE267461-D762-4F53-A275-685A0A4EC48D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CE267461-D762-4F53-A275-685A0A4EC48D}.Release|Any CPU.Build.0 = Release|Any CPU + {133F2B5B-FD25-4BD9-B34C-062CC6BB4178}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {133F2B5B-FD25-4BD9-B34C-062CC6BB4178}.Debug|Any CPU.Build.0 = Debug|Any CPU + {133F2B5B-FD25-4BD9-B34C-062CC6BB4178}.Release|Any CPU.ActiveCfg = Release|Any CPU + {133F2B5B-FD25-4BD9-B34C-062CC6BB4178}.Release|Any CPU.Build.0 = Release|Any CPU + {F3C07863-3759-4A0B-B777-8A0E0FDB1A41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F3C07863-3759-4A0B-B777-8A0E0FDB1A41}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F3C07863-3759-4A0B-B777-8A0E0FDB1A41}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F3C07863-3759-4A0B-B777-8A0E0FDB1A41}.Release|Any CPU.Build.0 = Release|Any CPU + {34256E8F-866A-46C1-800E-3DF69FD1DCB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {34256E8F-866A-46C1-800E-3DF69FD1DCB7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {34256E8F-866A-46C1-800E-3DF69FD1DCB7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {34256E8F-866A-46C1-800E-3DF69FD1DCB7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs new file mode 100644 index 000000000000..7b9f2e788811 --- /dev/null +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs @@ -0,0 +1,1130 @@ +using Xunit; +using Semmle.Autobuild.Shared; +using System.Collections.Generic; +using System; +using System.Linq; +using Microsoft.Build.Construction; +using System.Xml; +using System.IO; + +namespace Semmle.Autobuild.CSharp.Tests +{ + /// + /// Test class to script Autobuilder scenarios. + /// For most methods, it uses two fields: + /// - an IList to capture the the arguments passed to it + /// - an IDictionary of possible return values. + /// + internal class TestActions : IBuildActions + { + /// + /// List of strings passed to FileDelete. + /// + public IList FileDeleteIn { get; } = new List(); + + void IBuildActions.FileDelete(string file) + { + FileDeleteIn.Add(file); + } + + public IList FileExistsIn { get; } = new List(); + public IDictionary FileExists { get; } = new Dictionary(); + + bool IBuildActions.FileExists(string file) + { + FileExistsIn.Add(file); + if (FileExists.TryGetValue(file, out var ret)) + return ret; + + if (FileExists.TryGetValue(Path.GetFileName(file), out ret)) + return ret; + + throw new ArgumentException("Missing FileExists " + file); + } + + public IList RunProcessIn { get; } = new List(); + public IDictionary RunProcess { get; } = new Dictionary(); + public IDictionary RunProcessOut { get; } = new Dictionary(); + public IDictionary RunProcessWorkingDirectory { get; } = new Dictionary(); + public HashSet CreateDirectories { get; } = new HashSet(); + public HashSet<(string, string)> DownloadFiles { get; } = new HashSet<(string, string)>(); + + int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary? env, out IList stdOut) + { + var pattern = cmd + " " + args; + RunProcessIn.Add(pattern); + + if (!RunProcessOut.TryGetValue(pattern, out var str)) + throw new ArgumentException("Missing RunProcessOut " + pattern); + + stdOut = str.Split("\n"); + + RunProcessWorkingDirectory.TryGetValue(pattern, out var wd); + + if (wd != workingDirectory) + throw new ArgumentException("Missing RunProcessWorkingDirectory " + pattern); + + if (!RunProcess.TryGetValue(pattern, out var ret)) + throw new ArgumentException("Missing RunProcess " + pattern); + + return ret; + } + + int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary? env) + { + var pattern = cmd + " " + args; + RunProcessIn.Add(pattern); + RunProcessWorkingDirectory.TryGetValue(pattern, out var wd); + + if (wd != workingDirectory) + throw new ArgumentException("Missing RunProcessWorkingDirectory " + pattern); + + if (!RunProcess.TryGetValue(pattern, out var ret)) + throw new ArgumentException("Missing RunProcess " + pattern); + + return ret; + } + + public IList DirectoryDeleteIn { get; } = new List(); + + void IBuildActions.DirectoryDelete(string dir, bool recursive) + { + DirectoryDeleteIn.Add(dir); + } + + public IDictionary DirectoryExists { get; } = new Dictionary(); + + bool IBuildActions.DirectoryExists(string dir) + { + if (!DirectoryExists.TryGetValue(dir, out var ret)) + throw new ArgumentException("Missing DirectoryExists " + dir); + + return ret; + } + + public IDictionary GetEnvironmentVariable { get; } = new Dictionary(); + + string? IBuildActions.GetEnvironmentVariable(string name) + { + if (!GetEnvironmentVariable.TryGetValue(name, out var ret)) + throw new ArgumentException("Missing GetEnvironmentVariable " + name); + + return ret; + } + + public string GetCurrentDirectory { get; set; } = ""; + + string IBuildActions.GetCurrentDirectory() + { + return GetCurrentDirectory; + } + + public IDictionary EnumerateFiles { get; } = new Dictionary(); + + IEnumerable IBuildActions.EnumerateFiles(string dir) + { + if (!EnumerateFiles.TryGetValue(dir, out var str)) + throw new ArgumentException("Missing EnumerateFiles " + dir); + + return str.Split("\n").Select(p => PathCombine(dir, p)); + } + + public IDictionary EnumerateDirectories { get; } = new Dictionary(); + + IEnumerable IBuildActions.EnumerateDirectories(string dir) + { + if (!EnumerateDirectories.TryGetValue(dir, out var str)) + throw new ArgumentException("Missing EnumerateDirectories " + dir); + + return string.IsNullOrEmpty(str) + ? Enumerable.Empty() + : str.Split("\n").Select(p => PathCombine(dir, p)); + } + + public bool IsWindows { get; set; } + + bool IBuildActions.IsWindows() => IsWindows; + + public string PathCombine(params string[] parts) + { + return string.Join(IsWindows ? '\\' : '/', parts.Where(p => !string.IsNullOrWhiteSpace(p))); + } + + string IBuildActions.GetFullPath(string path) => path; + + string? IBuildActions.GetFileName(string? path) => Path.GetFileName(path?.Replace('\\', '/')); + + public string? GetDirectoryName(string? path) + { + var dir = Path.GetDirectoryName(path?.Replace('\\', '/')); + return dir is null ? path : path?.Substring(0, dir.Length); + } + + void IBuildActions.WriteAllText(string filename, string contents) + { + } + + public IDictionary LoadXml { get; } = new Dictionary(); + + XmlDocument IBuildActions.LoadXml(string filename) + { + if (!LoadXml.TryGetValue(filename, out var xml)) + throw new ArgumentException("Missing LoadXml " + filename); + return xml; + } + + public string EnvironmentExpandEnvironmentVariables(string s) + { + foreach (var kvp in GetEnvironmentVariable) + s = s.Replace($"%{kvp.Key}%", kvp.Value); + + return s; + } + + public void CreateDirectory(string path) + { + if (!CreateDirectories.Contains(path)) + throw new ArgumentException($"Missing CreateDirectory, {path}"); + } + + public void DownloadFile(string address, string fileName) + { + if (!DownloadFiles.Contains((address, fileName))) + throw new ArgumentException($"Missing DownloadFile, {address}, {fileName}"); + } + } + + /// + /// A fake solution to build. + /// + internal class TestSolution : ISolution + { + public IEnumerable Configurations => throw new NotImplementedException(); + + public string DefaultConfigurationName => "Release"; + + public string DefaultPlatformName => "x86"; + + public string FullPath { get; set; } + + public Version ToolsVersion => new Version("14.0"); + + public IEnumerable IncludedProjects => throw new NotImplementedException(); + + public TestSolution(string path) + { + FullPath = path; + } + } + + public class BuildScriptTests + { + private readonly TestActions actions = new TestActions(); + + // Records the arguments passed to StartCallback. + private readonly IList startCallbackIn = new List(); + + private void StartCallback(string s, bool silent) + { + startCallbackIn.Add(s); + } + + // Records the arguments passed to EndCallback + private readonly IList endCallbackIn = new List(); + private readonly IList endCallbackReturn = new List(); + + private void EndCallback(int ret, string s, bool silent) + { + endCallbackReturn.Add(ret); + endCallbackIn.Add(s); + } + + [Fact] + public void TestBuildCommand() + { + var cmd = BuildScript.Create("abc", "def ghi", false, null, null); + + actions.RunProcess["abc def ghi"] = 1; + cmd.Run(actions, StartCallback, EndCallback); + Assert.Equal("abc def ghi", actions.RunProcessIn[0]); + Assert.Equal("abc def ghi", startCallbackIn[0]); + Assert.Equal("", endCallbackIn[0]); + Assert.Equal(1, endCallbackReturn[0]); + } + + [Fact] + public void TestAnd1() + { + var cmd = BuildScript.Create("abc", "def ghi", false, null, null) & BuildScript.Create("odasa", null, false, null, null); + + actions.RunProcess["abc def ghi"] = 1; + cmd.Run(actions, StartCallback, EndCallback); + + Assert.Equal("abc def ghi", actions.RunProcessIn[0]); + Assert.Equal("abc def ghi", startCallbackIn[0]); + Assert.Equal("", endCallbackIn[0]); + Assert.Equal(1, endCallbackReturn[0]); + } + + [Fact] + public void TestAnd2() + { + var cmd = BuildScript.Create("odasa", null, false, null, null) & BuildScript.Create("abc", "def ghi", false, null, null); + + actions.RunProcess["abc def ghi"] = 1; + actions.RunProcess["odasa "] = 0; + cmd.Run(actions, StartCallback, EndCallback); + + Assert.Equal("odasa ", actions.RunProcessIn[0]); + Assert.Equal("odasa ", startCallbackIn[0]); + Assert.Equal("", endCallbackIn[0]); + Assert.Equal(0, endCallbackReturn[0]); + + Assert.Equal("abc def ghi", actions.RunProcessIn[1]); + Assert.Equal("abc def ghi", startCallbackIn[1]); + Assert.Equal("", endCallbackIn[1]); + Assert.Equal(1, endCallbackReturn[1]); + } + + [Fact] + public void TestOr1() + { + var cmd = BuildScript.Create("odasa", null, false, null, null) | BuildScript.Create("abc", "def ghi", false, null, null); + + actions.RunProcess["abc def ghi"] = 1; + actions.RunProcess["odasa "] = 0; + cmd.Run(actions, StartCallback, EndCallback); + + Assert.Equal("odasa ", actions.RunProcessIn[0]); + Assert.Equal("odasa ", startCallbackIn[0]); + Assert.Equal("", endCallbackIn[0]); + Assert.Equal(0, endCallbackReturn[0]); + Assert.Equal(1, endCallbackReturn.Count); + } + + [Fact] + public void TestOr2() + { + var cmd = BuildScript.Create("abc", "def ghi", false, null, null) | BuildScript.Create("odasa", null, false, null, null); + + actions.RunProcess["abc def ghi"] = 1; + actions.RunProcess["odasa "] = 0; + cmd.Run(actions, StartCallback, EndCallback); + + Assert.Equal("abc def ghi", actions.RunProcessIn[0]); + Assert.Equal("abc def ghi", startCallbackIn[0]); + Assert.Equal("", endCallbackIn[0]); + Assert.Equal(1, endCallbackReturn[0]); + + Assert.Equal("odasa ", actions.RunProcessIn[1]); + Assert.Equal("odasa ", startCallbackIn[1]); + Assert.Equal("", endCallbackIn[1]); + Assert.Equal(0, endCallbackReturn[1]); + } + + [Fact] + public void TestSuccess() + { + Assert.Equal(0, BuildScript.Success.Run(actions, StartCallback, EndCallback)); + } + + [Fact] + public void TestFailure() + { + Assert.NotEqual(0, BuildScript.Failure.Run(actions, StartCallback, EndCallback)); + } + + [Fact] + public void TestDeleteDirectorySuccess() + { + actions.DirectoryExists["trap"] = true; + Assert.Equal(0, BuildScript.DeleteDirectory("trap").Run(actions, StartCallback, EndCallback)); + Assert.Equal("trap", actions.DirectoryDeleteIn[0]); + } + + [Fact] + public void TestDeleteDirectoryFailure() + { + actions.DirectoryExists["trap"] = false; + Assert.NotEqual(0, BuildScript.DeleteDirectory("trap").Run(actions, StartCallback, EndCallback)); + } + + [Fact] + public void TestDeleteFileSuccess() + { + actions.FileExists["csharp.log"] = true; + Assert.Equal(0, BuildScript.DeleteFile("csharp.log").Run(actions, StartCallback, EndCallback)); + Assert.Equal("csharp.log", actions.FileExistsIn[0]); + Assert.Equal("csharp.log", actions.FileDeleteIn[0]); + } + + [Fact] + public void TestDeleteFileFailure() + { + actions.FileExists["csharp.log"] = false; + Assert.NotEqual(0, BuildScript.DeleteFile("csharp.log").Run(actions, StartCallback, EndCallback)); + Assert.Equal("csharp.log", actions.FileExistsIn[0]); + } + + [Fact] + public void TestTry() + { + Assert.Equal(0, BuildScript.Try(BuildScript.Failure).Run(actions, StartCallback, EndCallback)); + } + + private CSharpAutobuilder CreateAutoBuilder(bool isWindows, + string? buildless = null, string? solution = null, string? buildCommand = null, string? ignoreErrors = null, + string? msBuildArguments = null, string? msBuildPlatform = null, string? msBuildConfiguration = null, string? msBuildTarget = null, + string? dotnetArguments = null, string? dotnetVersion = null, string? vsToolsVersion = null, + string? nugetRestore = null, string? allSolutions = null, + string cwd = @"C:\Project") + { + var codeqlUpperLanguage = Language.CSharp.UpperCaseName; + actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_TRAP_DIR"] = ""; + actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_SOURCE_ARCHIVE_DIR"] = ""; + actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_ROOT"] = $@"C:\codeql\{codeqlUpperLanguage.ToLowerInvariant()}"; + actions.GetEnvironmentVariable["CODEQL_JAVA_HOME"] = @"C:\codeql\tools\java"; + actions.GetEnvironmentVariable["CODEQL_PLATFORM"] = isWindows ? "win64" : "linux64"; + actions.GetEnvironmentVariable["SEMMLE_DIST"] = @"C:\odasa"; + actions.GetEnvironmentVariable["SEMMLE_JAVA_HOME"] = @"C:\odasa\tools\java"; + actions.GetEnvironmentVariable["SEMMLE_PLATFORM_TOOLS"] = @"C:\odasa\tools"; + actions.GetEnvironmentVariable["LGTM_INDEX_VSTOOLS_VERSION"] = vsToolsVersion; + actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_ARGUMENTS"] = msBuildArguments; + actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_PLATFORM"] = msBuildPlatform; + actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_CONFIGURATION"] = msBuildConfiguration; + actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_TARGET"] = msBuildTarget; + actions.GetEnvironmentVariable["LGTM_INDEX_DOTNET_ARGUMENTS"] = dotnetArguments; + actions.GetEnvironmentVariable["LGTM_INDEX_DOTNET_VERSION"] = dotnetVersion; + actions.GetEnvironmentVariable["LGTM_INDEX_BUILD_COMMAND"] = buildCommand; + actions.GetEnvironmentVariable["LGTM_INDEX_SOLUTION"] = solution; + actions.GetEnvironmentVariable["LGTM_INDEX_IGNORE_ERRORS"] = ignoreErrors; + actions.GetEnvironmentVariable["LGTM_INDEX_BUILDLESS"] = buildless; + actions.GetEnvironmentVariable["LGTM_INDEX_ALL_SOLUTIONS"] = allSolutions; + actions.GetEnvironmentVariable["LGTM_INDEX_NUGET_RESTORE"] = nugetRestore; + actions.GetEnvironmentVariable["ProgramFiles(x86)"] = isWindows ? @"C:\Program Files (x86)" : null; + actions.GetCurrentDirectory = cwd; + actions.IsWindows = isWindows; + + var options = new AutobuildOptions(actions, Language.CSharp); + return new CSharpAutobuilder(actions, options); + } + + [Fact] + public void TestDefaultCSharpAutoBuilder() + { + actions.RunProcess["cmd.exe /C dotnet --info"] = 0; + actions.RunProcess[@"cmd.exe /C dotnet clean C:\Project\test.csproj"] = 0; + actions.RunProcess[@"cmd.exe /C dotnet restore C:\Project\test.csproj"] = 0; + actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --auto dotnet build --no-incremental C:\Project\test.csproj"] = 0; + actions.FileExists["csharp.log"] = true; + actions.FileExists[@"C:\Project\test.csproj"] = true; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; + actions.EnumerateFiles[@"C:\Project"] = "foo.cs\nbar.cs\ntest.csproj"; + actions.EnumerateDirectories[@"C:\Project"] = ""; + var xml = new XmlDocument(); + xml.LoadXml(@" + + Exe + netcoreapp2.1 + + +"); + actions.LoadXml[@"C:\Project\test.csproj"] = xml; + + var autobuilder = CreateAutoBuilder(true); + TestAutobuilderScript(autobuilder, 0, 4); + } + + [Fact] + public void TestLinuxCSharpAutoBuilder() + { + actions.RunProcess["dotnet --list-runtimes"] = 0; + actions.RunProcessOut["dotnet --list-runtimes"] = @"Microsoft.AspNetCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App] +Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]"; + actions.RunProcess["dotnet --info"] = 0; + actions.RunProcess[@"dotnet clean C:\Project/test.csproj"] = 0; + actions.RunProcess[@"dotnet restore C:\Project/test.csproj"] = 0; + actions.RunProcess[@"C:\odasa/tools/odasa index --auto dotnet build --no-incremental /p:UseSharedCompilation=false C:\Project/test.csproj"] = 0; + actions.FileExists["csharp.log"] = true; + actions.FileExists[@"C:\Project/test.csproj"] = true; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; + actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.cs\ntest.csproj"; + actions.EnumerateDirectories[@"C:\Project"] = ""; + var xml = new XmlDocument(); + xml.LoadXml(@" + + Exe + netcoreapp2.1 + + +"); + actions.LoadXml[@"C:\Project/test.csproj"] = xml; + + var autobuilder = CreateAutoBuilder(false); + TestAutobuilderScript(autobuilder, 0, 5); + } + + [Fact] + public void TestLinuxCSharpAutoBuilderExtractorFailed() + { + actions.FileExists["csharp.log"] = false; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; + actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.cs"; + actions.EnumerateDirectories[@"C:\Project"] = ""; + + var autobuilder = CreateAutoBuilder(false); + TestAutobuilderScript(autobuilder, 1, 0); + } + + [Fact] + public void TestVsWhereSucceeded() + { + actions.IsWindows = true; + actions.GetEnvironmentVariable["ProgramFiles(x86)"] = @"C:\Program Files (x86)"; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = true; + actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = 0; + actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = "C:\\VS1\nC:\\VS2\nC:\\VS3"; + actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = 0; + actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = "10.0\n11.0\n16.0"; + + var candidates = BuildTools.GetCandidateVcVarsFiles(actions).ToArray(); + Assert.Equal("C:\\VS1\\VC\\vcvarsall.bat", candidates[0].Path); + Assert.Equal(10, candidates[0].ToolsVersion); + Assert.Equal("C:\\VS2\\VC\\vcvarsall.bat", candidates[1].Path); + Assert.Equal(11, candidates[1].ToolsVersion); + Assert.Equal(@"C:\VS3\VC\Auxiliary\Build\vcvars32.bat", candidates[2].Path); + Assert.Equal(16, candidates[2].ToolsVersion); + Assert.Equal(@"C:\VS3\VC\Auxiliary\Build\vcvars64.bat", candidates[3].Path); + Assert.Equal(16, candidates[3].ToolsVersion); + Assert.Equal(@"C:\VS3\Common7\Tools\VsDevCmd.bat", candidates[4].Path); + Assert.Equal(16, candidates[4].ToolsVersion); + Assert.Equal(5, candidates.Length); + } + + [Fact] + public void TestVsWhereNotExist() + { + actions.IsWindows = true; + actions.GetEnvironmentVariable["ProgramFiles(x86)"] = @"C:\Program Files (x86)"; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false; + + var candidates = BuildTools.GetCandidateVcVarsFiles(actions).ToArray(); + Assert.Equal(4, candidates.Length); + } + + [Fact] + public void TestVcVarsAllBatFiles() + { + actions.IsWindows = true; + actions.GetEnvironmentVariable["ProgramFiles(x86)"] = @"C:\Program Files (x86)"; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = true; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = false; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = true; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = false; + + var vcvarsfiles = BuildTools.VcVarsAllBatFiles(actions).ToArray(); + Assert.Equal(2, vcvarsfiles.Length); + } + + [Fact] + public void TestLinuxBuildlessExtractionSuccess() + { + actions.RunProcess[@"C:\codeql\csharp/tools/linux64/Semmle.Extraction.CSharp.Standalone --references:."] = 0; + actions.FileExists["csharp.log"] = true; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; + actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln"; + actions.EnumerateDirectories[@"C:\Project"] = ""; + + var autobuilder = CreateAutoBuilder(false, buildless: "true"); + TestAutobuilderScript(autobuilder, 0, 1); + } + + [Fact] + public void TestLinuxBuildlessExtractionFailed() + { + actions.RunProcess[@"C:\codeql\csharp/tools/linux64/Semmle.Extraction.CSharp.Standalone --references:."] = 10; + actions.FileExists["csharp.log"] = true; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; + actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln"; + actions.EnumerateDirectories[@"C:\Project"] = ""; + + var autobuilder = CreateAutoBuilder(false, buildless: "true"); + TestAutobuilderScript(autobuilder, 10, 1); + } + + [Fact] + public void TestLinuxBuildlessExtractionSolution() + { + actions.RunProcess[@"C:\codeql\csharp/tools/linux64/Semmle.Extraction.CSharp.Standalone foo.sln --references:."] = 0; + actions.FileExists["csharp.log"] = true; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; + actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln"; + actions.EnumerateDirectories[@"C:\Project"] = ""; + + var autobuilder = CreateAutoBuilder(false, buildless: "true", solution: "foo.sln"); + TestAutobuilderScript(autobuilder, 0, 1); + } + + private void SkipVsWhere() + { + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = false; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = false; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = false; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = false; + } + + private void TestAutobuilderScript(Autobuilder autobuilder, int expectedOutput, int commandsRun) + { + Assert.Equal(expectedOutput, autobuilder.GetBuildScript().Run(actions, StartCallback, EndCallback)); + + // Check expected commands actually ran + Assert.Equal(commandsRun, startCallbackIn.Count); + Assert.Equal(commandsRun, endCallbackIn.Count); + Assert.Equal(commandsRun, endCallbackReturn.Count); + + var action = actions.RunProcess.GetEnumerator(); + for (var cmd = 0; cmd < commandsRun; ++cmd) + { + Assert.True(action.MoveNext()); + + Assert.Equal(action.Current.Key, startCallbackIn[cmd]); + Assert.Equal(action.Current.Value, endCallbackReturn[cmd]); + } + } + + [Fact] + public void TestLinuxBuildCommand() + { + actions.RunProcess["dotnet --list-runtimes"] = 1; + actions.RunProcessOut["dotnet --list-runtimes"] = ""; + actions.RunProcess[@"C:\odasa/tools/odasa index --auto ""./build.sh --skip-tests"""] = 0; + actions.FileExists["csharp.log"] = true; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; + actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln"; + actions.EnumerateDirectories[@"C:\Project"] = ""; + + SkipVsWhere(); + + var autobuilder = CreateAutoBuilder(false, buildCommand: "./build.sh --skip-tests"); + TestAutobuilderScript(autobuilder, 0, 2); + } + + [Fact] + public void TestLinuxBuildSh() + { + actions.EnumerateFiles[@"C:\Project"] = "foo.cs\nbuild/build.sh"; + actions.EnumerateDirectories[@"C:\Project"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; + actions.RunProcess[@"/bin/chmod u+x C:\Project/build/build.sh"] = 0; + actions.RunProcess["dotnet --list-runtimes"] = 1; + actions.RunProcessOut["dotnet --list-runtimes"] = ""; + actions.RunProcess[@"C:\odasa/tools/odasa index --auto C:\Project/build/build.sh"] = 0; + actions.RunProcessWorkingDirectory[@"C:\odasa/tools/odasa index --auto C:\Project/build/build.sh"] = @"C:\Project/build"; + actions.FileExists["csharp.log"] = true; + + var autobuilder = CreateAutoBuilder(false); + TestAutobuilderScript(autobuilder, 0, 3); + } + + [Fact] + public void TestLinuxBuildShCSharpLogMissing() + { + actions.EnumerateFiles[@"C:\Project"] = "foo.cs\nbuild.sh"; + actions.EnumerateDirectories[@"C:\Project"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; + + actions.RunProcess[@"/bin/chmod u+x C:\Project/build.sh"] = 0; + actions.RunProcess["dotnet --list-runtimes"] = 1; + actions.RunProcessOut["dotnet --list-runtimes"] = ""; + actions.RunProcess[@"C:\odasa/tools/odasa index --auto C:\Project/build.sh"] = 0; + actions.RunProcessWorkingDirectory[@"C:\odasa/tools/odasa index --auto C:\Project/build.sh"] = @"C:\Project"; + actions.FileExists["csharp.log"] = false; + + var autobuilder = CreateAutoBuilder(false); + TestAutobuilderScript(autobuilder, 1, 3); + } + + [Fact] + public void TestLinuxBuildShFailed() + { + actions.EnumerateFiles[@"C:\Project"] = "foo.cs\nbuild.sh"; + actions.EnumerateDirectories[@"C:\Project"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; + + actions.RunProcess[@"/bin/chmod u+x C:\Project/build.sh"] = 0; + actions.RunProcess["dotnet --list-runtimes"] = 1; + actions.RunProcessOut["dotnet --list-runtimes"] = ""; + actions.RunProcess[@"C:\odasa/tools/odasa index --auto C:\Project/build.sh"] = 5; + actions.RunProcessWorkingDirectory[@"C:\odasa/tools/odasa index --auto C:\Project/build.sh"] = @"C:\Project"; + actions.FileExists["csharp.log"] = true; + + var autobuilder = CreateAutoBuilder(false); + TestAutobuilderScript(autobuilder, 1, 3); + } + + [Fact] + public void TestWindowsBuildBat() + { + actions.EnumerateFiles[@"C:\Project"] = "foo.cs\nbuild.bat"; + actions.EnumerateDirectories[@"C:\Project"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; + actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --auto C:\Project\build.bat"] = 0; + actions.RunProcessWorkingDirectory[@"cmd.exe /C C:\odasa\tools\odasa index --auto C:\Project\build.bat"] = @"C:\Project"; + actions.FileExists["csharp.log"] = true; + + var autobuilder = CreateAutoBuilder(true); + TestAutobuilderScript(autobuilder, 0, 1); + } + + [Fact] + public void TestWindowsBuildBatIgnoreErrors() + { + actions.EnumerateFiles[@"C:\Project"] = "foo.cs\nbuild.bat"; + actions.EnumerateDirectories[@"C:\Project"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; + actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --auto C:\Project\build.bat"] = 1; + actions.RunProcessWorkingDirectory[@"cmd.exe /C C:\odasa\tools\odasa index --auto C:\Project\build.bat"] = @"C:\Project"; + actions.RunProcess[@"cmd.exe /C C:\codeql\tools\java\bin\java -jar C:\codeql\csharp\tools\extractor-asp.jar ."] = 0; + actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config"] = 0; + actions.FileExists["csharp.log"] = true; + + var autobuilder = CreateAutoBuilder(true, ignoreErrors: "true"); + TestAutobuilderScript(autobuilder, 1, 1); + } + + [Fact] + public void TestWindowsCmdIgnoreErrors() + { + actions.RunProcess["cmd.exe /C C:\\odasa\\tools\\odasa index --auto ^\"build.cmd --skip-tests^\""] = 3; + actions.RunProcess[@"cmd.exe /C C:\codeql\tools\java\bin\java -jar C:\codeql\csharp\tools\extractor-asp.jar ."] = 0; + actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config"] = 0; + actions.FileExists["csharp.log"] = true; + SkipVsWhere(); + + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; + actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln"; + actions.EnumerateDirectories[@"C:\Project"] = ""; + + var autobuilder = CreateAutoBuilder(true, buildCommand: "build.cmd --skip-tests", ignoreErrors: "true"); + TestAutobuilderScript(autobuilder, 3, 1); + } + + [Fact] + public void TestWindowCSharpMsBuild() + { + actions.RunProcess[@"cmd.exe /C C:\Project\.nuget\nuget.exe restore C:\Project\test1.sln -DisableParallelProcessing"] = 0; + actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test1.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; + actions.RunProcess[@"cmd.exe /C C:\Project\.nuget\nuget.exe restore C:\Project\test2.sln -DisableParallelProcessing"] = 0; + actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test2.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; + actions.FileExists["csharp.log"] = true; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = false; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = true; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = false; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = true; + + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; + actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest1.cs\ntest2.cs"; + actions.EnumerateFiles[@"C:\Project\.nuget"] = "nuget.exe"; + actions.EnumerateDirectories[@"C:\Project"] = @".nuget"; + actions.EnumerateDirectories[@"C:\Project\.nuget"] = ""; + + var autobuilder = CreateAutoBuilder(true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug", + vsToolsVersion: "12", allSolutions: "true"); + var testSolution1 = new TestSolution(@"C:\Project\test1.sln"); + var testSolution2 = new TestSolution(@"C:\Project\test2.sln"); + autobuilder.ProjectsOrSolutionsToBuild.Add(testSolution1); + autobuilder.ProjectsOrSolutionsToBuild.Add(testSolution2); + + TestAutobuilderScript(autobuilder, 0, 4); + } + + [Fact] + public void TestWindowCSharpMsBuildMultipleSolutions() + { + actions.RunProcess[@"cmd.exe /C nuget restore C:\Project\test1.csproj -DisableParallelProcessing"] = 0; + actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test1.csproj /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; + actions.RunProcess[@"cmd.exe /C nuget restore C:\Project\test2.csproj -DisableParallelProcessing"] = 0; + actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test2.csproj /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; + actions.FileExists["csharp.log"] = true; + actions.FileExists[@"C:\Project\test1.csproj"] = true; + actions.FileExists[@"C:\Project\test2.csproj"] = true; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = false; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = true; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = false; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = true; + + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; + actions.EnumerateFiles[@"C:\Project"] = "test1.csproj\ntest2.csproj\ntest1.cs\ntest2.cs"; + actions.EnumerateDirectories[@"C:\Project"] = ""; + + var csproj1 = new XmlDocument(); + csproj1.LoadXml(@" + + + + + "); + actions.LoadXml[@"C:\Project\test1.csproj"] = csproj1; + + var csproj2 = new XmlDocument(); + csproj2.LoadXml(@" + + + + + "); + actions.LoadXml[@"C:\Project\test2.csproj"] = csproj2; + + var autobuilder = CreateAutoBuilder(true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug", + vsToolsVersion: "12"); + + TestAutobuilderScript(autobuilder, 0, 4); + } + + [Fact] + public void TestWindowCSharpMsBuildFailed() + { + actions.RunProcess[@"cmd.exe /C nuget restore C:\Project\test1.sln -DisableParallelProcessing"] = 0; + actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test1.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 1; + actions.FileExists["csharp.log"] = true; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = false; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = true; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = false; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = true; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; + actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest1.cs\ntest2.cs"; + actions.EnumerateDirectories[@"C:\Project"] = ""; + + var autobuilder = CreateAutoBuilder(true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug", + vsToolsVersion: "12", allSolutions: "true"); + var testSolution1 = new TestSolution(@"C:\Project\test1.sln"); + var testSolution2 = new TestSolution(@"C:\Project\test2.sln"); + autobuilder.ProjectsOrSolutionsToBuild.Add(testSolution1); + autobuilder.ProjectsOrSolutionsToBuild.Add(testSolution2); + + TestAutobuilderScript(autobuilder, 1, 2); + } + + + [Fact] + public void TestSkipNugetMsBuild() + { + actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test1.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; + actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test2.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; + actions.FileExists["csharp.log"] = true; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = false; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = true; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = false; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = true; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; + actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest1.cs\ntest2.cs"; + actions.EnumerateDirectories[@"C:\Project"] = ""; + + var autobuilder = CreateAutoBuilder(true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", + msBuildPlatform: "x86", msBuildConfiguration: "Debug", vsToolsVersion: "12", + allSolutions: "true", nugetRestore: "false"); + var testSolution1 = new TestSolution(@"C:\Project\test1.sln"); + var testSolution2 = new TestSolution(@"C:\Project\test2.sln"); + autobuilder.ProjectsOrSolutionsToBuild.Add(testSolution1); + autobuilder.ProjectsOrSolutionsToBuild.Add(testSolution2); + + TestAutobuilderScript(autobuilder, 0, 2); + } + + [Fact] + public void TestSkipNugetBuildless() + { + actions.RunProcess[@"C:\codeql\csharp/tools/linux64/Semmle.Extraction.CSharp.Standalone foo.sln --references:. --skip-nuget"] = 0; + actions.FileExists["csharp.log"] = true; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; + actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln"; + actions.EnumerateDirectories[@"C:\Project"] = ""; + + var autobuilder = CreateAutoBuilder(false, buildless: "true", solution: "foo.sln", nugetRestore: "false"); + TestAutobuilderScript(autobuilder, 0, 1); + } + + + [Fact] + public void TestSkipNugetDotnet() + { + actions.RunProcess["dotnet --list-runtimes"] = 0; + actions.RunProcessOut["dotnet --list-runtimes"] = @"Microsoft.AspNetCore.App 2.1.3 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App] +Microsoft.NETCore.App 2.1.3 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]"; + actions.RunProcess["dotnet --info"] = 0; + actions.RunProcess[@"dotnet clean C:\Project/test.csproj"] = 0; + actions.RunProcess[@"dotnet restore C:\Project/test.csproj"] = 0; + actions.RunProcess[@"C:\odasa/tools/odasa index --auto dotnet build --no-incremental /p:UseSharedCompilation=false --no-restore C:\Project/test.csproj"] = 0; + actions.FileExists["csharp.log"] = true; + actions.FileExists[@"C:\Project/test.csproj"] = true; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; + actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.cs\ntest.csproj"; + actions.EnumerateDirectories[@"C:\Project"] = ""; + var xml = new XmlDocument(); + xml.LoadXml(@" + + Exe + netcoreapp2.1 + + +"); + actions.LoadXml[@"C:\Project/test.csproj"] = xml; + + var autobuilder = CreateAutoBuilder(false, dotnetArguments: "--no-restore"); // nugetRestore=false does not work for now. + TestAutobuilderScript(autobuilder, 0, 5); + } + + [Fact] + public void TestDotnetVersionNotInstalled() + { + actions.RunProcess["dotnet --list-sdks"] = 0; + actions.RunProcessOut["dotnet --list-sdks"] = "2.1.2 [C:\\Program Files\\dotnet\\sdks]\n2.1.4 [C:\\Program Files\\dotnet\\sdks]"; + actions.RunProcess[@"chmod u+x dotnet-install.sh"] = 0; + actions.RunProcess[@"./dotnet-install.sh --channel release --version 2.1.3 --install-dir C:\Project/.dotnet"] = 0; + actions.RunProcess[@"rm dotnet-install.sh"] = 0; + actions.RunProcess[@"C:\Project/.dotnet/dotnet --list-runtimes"] = 0; + actions.RunProcessOut[@"C:\Project/.dotnet/dotnet --list-runtimes"] = @"Microsoft.AspNetCore.App 3.0.0 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App] +Microsoft.NETCore.App 3.0.0 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]"; + actions.RunProcess[@"C:\Project/.dotnet/dotnet --info"] = 0; + actions.RunProcess[@"C:\Project/.dotnet/dotnet clean C:\Project/test.csproj"] = 0; + actions.RunProcess[@"C:\Project/.dotnet/dotnet restore C:\Project/test.csproj"] = 0; + actions.RunProcess[@"C:\odasa/tools/odasa index --auto C:\Project/.dotnet/dotnet build --no-incremental C:\Project/test.csproj"] = 0; + actions.FileExists["csharp.log"] = true; + actions.FileExists["test.csproj"] = true; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; + actions.GetEnvironmentVariable["PATH"] = "/bin:/usr/bin"; + actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.cs\ntest.csproj"; + actions.EnumerateDirectories[@"C:\Project"] = ""; + var xml = new XmlDocument(); + xml.LoadXml(@" + + Exe + netcoreapp2.1 + + +"); + actions.LoadXml[@"C:\Project/test.csproj"] = xml; + actions.DownloadFiles.Add(("https://dot.net/v1/dotnet-install.sh", "dotnet-install.sh")); + + var autobuilder = CreateAutoBuilder(false, dotnetVersion: "2.1.3"); + TestAutobuilderScript(autobuilder, 0, 9); + } + + [Fact] + public void TestDotnetVersionAlreadyInstalled() + { + actions.RunProcess["dotnet --list-sdks"] = 0; + actions.RunProcessOut["dotnet --list-sdks"] = @"2.1.3 [C:\Program Files\dotnet\sdks] +2.1.4 [C:\Program Files\dotnet\sdks]"; + actions.RunProcess[@"chmod u+x dotnet-install.sh"] = 0; + actions.RunProcess[@"./dotnet-install.sh --channel release --version 2.1.3 --install-dir C:\Project/.dotnet"] = 0; + actions.RunProcess[@"rm dotnet-install.sh"] = 0; + actions.RunProcess[@"C:\Project/.dotnet/dotnet --list-runtimes"] = 0; + actions.RunProcessOut[@"C:\Project/.dotnet/dotnet --list-runtimes"] = @"Microsoft.AspNetCore.App 2.1.3 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App] +Microsoft.AspNetCore.App 2.1.4 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App] +Microsoft.NETCore.App 2.1.3 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App] +Microsoft.NETCore.App 2.1.4 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]"; + actions.RunProcess[@"C:\Project/.dotnet/dotnet --info"] = 0; + actions.RunProcess[@"C:\Project/.dotnet/dotnet clean C:\Project/test.csproj"] = 0; + actions.RunProcess[@"C:\Project/.dotnet/dotnet restore C:\Project/test.csproj"] = 0; + actions.RunProcess[@"C:\odasa/tools/odasa index --auto C:\Project/.dotnet/dotnet build --no-incremental /p:UseSharedCompilation=false C:\Project/test.csproj"] = 0; + actions.FileExists["csharp.log"] = true; + actions.FileExists["test.csproj"] = true; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; + actions.GetEnvironmentVariable["PATH"] = "/bin:/usr/bin"; + actions.EnumerateFiles[@"C:\Project"] = "foo.cs\nbar.cs\ntest.csproj"; + actions.EnumerateDirectories[@"C:\Project"] = ""; + var xml = new XmlDocument(); + xml.LoadXml(@" + + Exe + netcoreapp2.1 + + +"); + actions.LoadXml[@"C:\Project/test.csproj"] = xml; + actions.DownloadFiles.Add(("https://dot.net/v1/dotnet-install.sh", "dotnet-install.sh")); + + var autobuilder = CreateAutoBuilder(false, dotnetVersion: "2.1.3"); + TestAutobuilderScript(autobuilder, 0, 9); + } + + [Fact] + public void TestDotnetVersionWindows() + { + actions.RunProcess["cmd.exe /C dotnet --list-sdks"] = 0; + actions.RunProcessOut["cmd.exe /C dotnet --list-sdks"] = "2.1.3 [C:\\Program Files\\dotnet\\sdks]\n2.1.4 [C:\\Program Files\\dotnet\\sdks]"; + actions.RunProcess[@"cmd.exe /C powershell -NoProfile -ExecutionPolicy unrestricted -file C:\Project\install-dotnet.ps1 -Version 2.1.3 -InstallDir C:\Project\.dotnet"] = 0; + actions.RunProcess[@"cmd.exe /C del C:\Project\install-dotnet.ps1"] = 0; + actions.RunProcess[@"cmd.exe /C C:\Project\.dotnet\dotnet --info"] = 0; + actions.RunProcess[@"cmd.exe /C C:\Project\.dotnet\dotnet clean C:\Project\test.csproj"] = 0; + actions.RunProcess[@"cmd.exe /C C:\Project\.dotnet\dotnet restore C:\Project\test.csproj"] = 0; + actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --auto C:\Project\.dotnet\dotnet build --no-incremental C:\Project\test.csproj"] = 0; + actions.FileExists["csharp.log"] = true; + actions.FileExists[@"C:\Project\test.csproj"] = true; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; + actions.GetEnvironmentVariable["PATH"] = "/bin:/usr/bin"; + actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.cs\ntest.csproj"; + actions.EnumerateDirectories[@"C:\Project"] = ""; + var xml = new XmlDocument(); + xml.LoadXml(@" + + Exe + netcoreapp2.1 + + +"); + actions.LoadXml[@"C:\Project\test.csproj"] = xml; + + var autobuilder = CreateAutoBuilder(true, dotnetVersion: "2.1.3"); + TestAutobuilderScript(autobuilder, 0, 7); + } + + [Fact] + public void TestDirsProjWindows() + { + actions.RunProcess[@"cmd.exe /C nuget restore C:\Project\dirs.proj -DisableParallelProcessing"] = 1; + actions.RunProcess[@"cmd.exe /C C:\Project\.nuget\nuget.exe restore C:\Project\dirs.proj -DisableParallelProcessing"] = 0; + actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\dirs.proj /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; + actions.FileExists["csharp.log"] = true; + actions.FileExists[@"C:\Project\a\test.csproj"] = true; + actions.FileExists[@"C:\Project\dirs.proj"] = true; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = false; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = true; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = false; + actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = true; + + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; + actions.EnumerateFiles[@"C:\Project"] = "a\\test.cs\na\\test.csproj\ndirs.proj"; + actions.EnumerateDirectories[@"C:\Project"] = ""; + actions.CreateDirectories.Add(@"C:\Project\.nuget"); + actions.DownloadFiles.Add(("https://dist.nuget.org/win-x86-commandline/latest/nuget.exe", @"C:\Project\.nuget\nuget.exe")); + + var csproj = new XmlDocument(); + csproj.LoadXml(@" + + + + + "); + actions.LoadXml[@"C:\Project\a\test.csproj"] = csproj; + + var dirsproj = new XmlDocument(); + dirsproj.LoadXml(@" + + + +"); + actions.LoadXml[@"C:\Project\dirs.proj"] = dirsproj; + + var autobuilder = CreateAutoBuilder(true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug", + vsToolsVersion: "12", allSolutions: "true"); + TestAutobuilderScript(autobuilder, 0, 3); + } + + [Fact] + public void TestDirsProjLinux() + { + actions.RunProcess[@"nuget restore C:\Project/dirs.proj -DisableParallelProcessing"] = 1; + actions.RunProcess[@"mono C:\Project/.nuget/nuget.exe restore C:\Project/dirs.proj -DisableParallelProcessing"] = 0; + actions.RunProcess[@"C:\odasa/tools/odasa index --auto msbuild C:\Project/dirs.proj /p:UseSharedCompilation=false /t:rebuild /p:MvcBuildViews=true"] = 0; + actions.FileExists["csharp.log"] = true; + actions.FileExists[@"C:\Project/a/test.csproj"] = true; + actions.FileExists[@"C:\Project/dirs.proj"] = true; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; + actions.EnumerateFiles[@"C:\Project"] = "a/test.cs\na/test.csproj\ndirs.proj"; + actions.EnumerateDirectories[@"C:\Project"] = ""; + actions.CreateDirectories.Add(@"C:\Project/.nuget"); + actions.DownloadFiles.Add(("https://dist.nuget.org/win-x86-commandline/latest/nuget.exe", @"C:\Project/.nuget/nuget.exe")); + + var csproj = new XmlDocument(); + csproj.LoadXml(@" + + + + + "); + actions.LoadXml[@"C:\Project/a/test.csproj"] = csproj; + + var dirsproj = new XmlDocument(); + dirsproj.LoadXml(@" + + + +"); + actions.LoadXml[@"C:\Project/dirs.proj"] = dirsproj; + + var autobuilder = CreateAutoBuilder(false); + TestAutobuilderScript(autobuilder, 0, 3); + } + + [Fact] + public void TestCyclicDirsProj() + { + actions.FileExists["dirs.proj"] = true; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; + actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; + actions.FileExists["csharp.log"] = false; + actions.EnumerateFiles[@"C:\Project"] = "dirs.proj"; + actions.EnumerateDirectories[@"C:\Project"] = ""; + + var dirsproj1 = new XmlDocument(); + dirsproj1.LoadXml(@" + + + +"); + actions.LoadXml[@"C:\Project/dirs.proj"] = dirsproj1; + + var autobuilder = CreateAutoBuilder(false); + TestAutobuilderScript(autobuilder, 1, 0); + } + + [Fact] + public void TestAsStringWithExpandedEnvVarsWindows() + { + actions.IsWindows = true; + actions.GetEnvironmentVariable["LGTM_SRC"] = @"C:\repo"; + Assert.Equal(@"C:\repo\test", @"%LGTM_SRC%\test".AsStringWithExpandedEnvVars(actions)); + } + + [Fact] + public void TestAsStringWithExpandedEnvVarsLinux() + { + actions.IsWindows = false; + actions.GetEnvironmentVariable["LGTM_SRC"] = "/tmp/repo"; + Assert.Equal("/tmp/repo/test", "$LGTM_SRC/test".AsStringWithExpandedEnvVars(actions)); + } + } +} diff --git a/csharp/autobuilder/Semmle.Autobuild.Tests/Semmle.Autobuild.Tests.csproj b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/Semmle.Autobuild.CSharp.Tests.csproj similarity index 76% rename from csharp/autobuilder/Semmle.Autobuild.Tests/Semmle.Autobuild.Tests.csproj rename to csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/Semmle.Autobuild.CSharp.Tests.csproj index 1f0016fc9b0b..ee3324eb6398 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Tests/Semmle.Autobuild.Tests.csproj +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/Semmle.Autobuild.CSharp.Tests.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp3.0 + netcoreapp3.1 false win-x64;linux-x64;osx-x64 enable @@ -19,7 +19,7 @@ - + + - diff --git a/csharp/autobuilder/Semmle.Autobuild.CSharp/CSharpAutobuilder.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp/CSharpAutobuilder.cs new file mode 100644 index 000000000000..5f29771c11b2 --- /dev/null +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/CSharpAutobuilder.cs @@ -0,0 +1,129 @@ +using Semmle.Extraction.CSharp; +using Semmle.Util.Logging; +using Semmle.Autobuild.Shared; + +namespace Semmle.Autobuild.CSharp +{ + public class CSharpAutobuilder : Autobuilder + { + public CSharpAutobuilder(IBuildActions actions, AutobuildOptions options) : base(actions, options) { } + + public override BuildScript GetBuildScript() + { + /// + /// A script that checks that the C# extractor has been executed. + /// + BuildScript CheckExtractorRun(bool warnOnFailure) => + BuildScript.Create(actions => + { + if (actions.FileExists(Extractor.GetCSharpLogPath())) + return 0; + + if (warnOnFailure) + Log(Severity.Error, "No C# code detected during build."); + + return 1; + }); + + var attempt = BuildScript.Failure; + switch (GetCSharpBuildStrategy()) + { + case CSharpBuildStrategy.CustomBuildCommand: + attempt = new BuildCommandRule(DotNetRule.WithDotNet).Analyse(this, false) & CheckExtractorRun(true); + break; + case CSharpBuildStrategy.Buildless: + // No need to check that the extractor has been executed in buildless mode + attempt = new StandaloneBuildRule().Analyse(this, false); + break; + case CSharpBuildStrategy.MSBuild: + attempt = new MsBuildRule().Analyse(this, false) & CheckExtractorRun(true); + break; + case CSharpBuildStrategy.DotNet: + attempt = new DotNetRule().Analyse(this, false) & CheckExtractorRun(true); + break; + case CSharpBuildStrategy.Auto: + var cleanTrapFolder = + BuildScript.DeleteDirectory(TrapDir); + var cleanSourceArchive = + BuildScript.DeleteDirectory(SourceArchiveDir); + var tryCleanExtractorArgsLogs = + BuildScript.Create(actions => + { + foreach (var file in Extractor.GetCSharpArgsLogs()) + { + try + { + actions.FileDelete(file); + } + catch // lgtm[cs/catch-of-all-exceptions] lgtm[cs/empty-catch-block] + { } + } + + return 0; + }); + var attemptExtractorCleanup = + BuildScript.Try(cleanTrapFolder) & + BuildScript.Try(cleanSourceArchive) & + tryCleanExtractorArgsLogs & + BuildScript.DeleteFile(Extractor.GetCSharpLogPath()); + + /// + /// Execute script `s` and check that the C# extractor has been executed. + /// If either fails, attempt to cleanup any artifacts produced by the extractor, + /// and exit with code 1, in order to proceed to the next attempt. + /// + BuildScript IntermediateAttempt(BuildScript s) => + (s & CheckExtractorRun(false)) | + (attemptExtractorCleanup & BuildScript.Failure); + + attempt = + // First try .NET Core + IntermediateAttempt(new DotNetRule().Analyse(this, true)) | + // Then MSBuild + (() => IntermediateAttempt(new MsBuildRule().Analyse(this, true))) | + // And finally look for a script that might be a build script + (() => new BuildCommandAutoRule(DotNetRule.WithDotNet).Analyse(this, true) & CheckExtractorRun(true)) | + // All attempts failed: print message + AutobuildFailure(); + break; + } + + return attempt; + } + + /// + /// Gets the build strategy that the autobuilder should apply, based on the + /// options in the `lgtm.yml` file. + /// + private CSharpBuildStrategy GetCSharpBuildStrategy() + { + if (Options.BuildCommand != null) + return CSharpBuildStrategy.CustomBuildCommand; + + if (Options.Buildless) + return CSharpBuildStrategy.Buildless; + + if (Options.MsBuildArguments != null + || Options.MsBuildConfiguration != null + || Options.MsBuildPlatform != null + || Options.MsBuildTarget != null) + { + return CSharpBuildStrategy.MSBuild; + } + + if (Options.DotNetArguments != null || Options.DotNetVersion != null) + return CSharpBuildStrategy.DotNet; + + return CSharpBuildStrategy.Auto; + } + + private enum CSharpBuildStrategy + { + CustomBuildCommand, + Buildless, + MSBuild, + DotNet, + Auto + } + } +} diff --git a/csharp/autobuilder/Semmle.Autobuild/DotNetRule.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp/DotNetRule.cs similarity index 83% rename from csharp/autobuilder/Semmle.Autobuild/DotNetRule.cs rename to csharp/autobuilder/Semmle.Autobuild.CSharp/DotNetRule.cs index 21215af84345..0af1026e35ac 100644 --- a/csharp/autobuilder/Semmle.Autobuild/DotNetRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/DotNetRule.cs @@ -6,14 +6,15 @@ using System.IO; using Semmle.Util; using System.Text.RegularExpressions; +using Semmle.Autobuild.Shared; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.CSharp { /// /// A build rule where the build command is of the form "dotnet build". /// Currently unused because the tracer does not work with dotnet. /// - class DotNetRule : IBuildRule + internal class DotNetRule : IBuildRule { public BuildScript Analyse(Autobuilder builder, bool auto) { @@ -22,10 +23,10 @@ public BuildScript Analyse(Autobuilder builder, bool auto) if (auto) { - var notDotNetProject = builder.ProjectsOrSolutionsToBuild. - SelectMany(p => Enumerators.Singleton(p).Concat(p.IncludedProjects)). - OfType(). - FirstOrDefault(p => !p.DotNetProject); + var notDotNetProject = builder.ProjectsOrSolutionsToBuild + .SelectMany(p => Enumerators.Singleton(p).Concat(p.IncludedProjects)) + .OfType() + .FirstOrDefault(p => !p.DotNetProject); if (notDotNetProject != null) { builder.Log(Severity.Info, "Not using .NET Core because of incompatible project {0}", notDotNetProject); @@ -56,9 +57,9 @@ public BuildScript Analyse(Autobuilder builder, bool auto) }); } - static BuildScript WithDotNet(Autobuilder builder, Func?, bool, BuildScript> f) + private static BuildScript WithDotNet(Autobuilder builder, Func?, bool, BuildScript> f) { - string? installDir = builder.Actions.PathCombine(builder.Options.RootDirectory, ".dotnet"); + var installDir = builder.Actions.PathCombine(builder.Options.RootDirectory, ".dotnet"); var installScript = DownloadDotNet(builder, installDir); return BuildScript.Bind(installScript, installed => { @@ -93,11 +94,11 @@ static BuildScript WithDotNet(Autobuilder builder, Func regex.Match(runtime)). - Where(m => m.Success). - Select(m => m.Groups[1].Value). - Any(m => Version.TryParse(m, out var v) && v >= minimumVersion); + compatibleClr = runtimes + .Select(runtime => regex.Match(runtime)) + .Where(m => m.Success) + .Select(m => m.Groups[1].Value) + .Any(m => Version.TryParse(m, out var v) && v >= minimumVersion); } if (!compatibleClr) @@ -128,7 +129,7 @@ public static BuildScript WithDotNet(Autobuilder builder, FuncinstallDir /// (provided that the script succeeds). /// - static BuildScript DownloadDotNet(Autobuilder builder, string installDir) + private static BuildScript DownloadDotNet(Autobuilder builder, string installDir) { if (!string.IsNullOrEmpty(builder.Options.DotNetVersion)) // Specific version supplied in configuration: always use that @@ -165,11 +166,11 @@ static BuildScript DownloadDotNet(Autobuilder builder, string installDir) /// /// See https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-install-script. /// - static BuildScript DownloadDotNetVersion(Autobuilder builder, string path, string version) + private static BuildScript DownloadDotNetVersion(Autobuilder builder, string path, string version) { return BuildScript.Bind(GetInstalledSdksScript(builder.Actions), (sdks, sdksRet) => { - if (sdksRet == 0 && sdks.Count() == 1 && sdks[0].StartsWith(version + " ", StringComparison.Ordinal)) + if (sdksRet == 0 && sdks.Count == 1 && sdks[0].StartsWith(version + " ", StringComparison.Ordinal)) // The requested SDK is already installed (and no other SDKs are installed), so // no need to reinstall return BuildScript.Failure; @@ -228,11 +229,10 @@ public bool CheckValidationResult(ServicePoint srvPoint, X509Certificate certifi } else { - var curl = new CommandBuilder(builder.Actions). - RunCommand("curl"). - Argument("-L"). - Argument("-sO"). - Argument("https://dot.net/v1/dotnet-install.sh"); + var downloadDotNetInstallSh = BuildScript.DownloadFile( + "https://dot.net/v1/dotnet-install.sh", + "dotnet-install.sh", + e => builder.Log(Severity.Warning, $"Failed to download 'dotnet-install.sh': {e.Message}")); var chmod = new CommandBuilder(builder.Actions). RunCommand("chmod"). @@ -252,12 +252,12 @@ public bool CheckValidationResult(ServicePoint srvPoint, X509Certificate certifi RunCommand("rm"). Argument("dotnet-install.sh"); - return curl.Script & chmod.Script & install.Script & BuildScript.Try(removeScript.Script); + return downloadDotNetInstallSh & chmod.Script & install.Script & BuildScript.Try(removeScript.Script); } }); } - static BuildScript GetInstalledSdksScript(IBuildActions actions) + private static BuildScript GetInstalledSdksScript(IBuildActions actions) { var listSdks = new CommandBuilder(actions, silent: true). RunCommand("dotnet"). @@ -265,10 +265,10 @@ static BuildScript GetInstalledSdksScript(IBuildActions actions) return listSdks.Script; } - static string DotNetCommand(IBuildActions actions, string? dotNetPath) => + private static string DotNetCommand(IBuildActions actions, string? dotNetPath) => dotNetPath != null ? actions.PathCombine(dotNetPath, "dotnet") : "dotnet"; - BuildScript GetInfoCommand(IBuildActions actions, string? dotNetPath, IDictionary? environment) + private static BuildScript GetInfoCommand(IBuildActions actions, string? dotNetPath, IDictionary? environment) { var info = new CommandBuilder(actions, null, environment). RunCommand(DotNetCommand(actions, dotNetPath)). @@ -276,7 +276,7 @@ BuildScript GetInfoCommand(IBuildActions actions, string? dotNetPath, IDictionar return info.Script; } - CommandBuilder GetCleanCommand(IBuildActions actions, string? dotNetPath, IDictionary? environment) + private static CommandBuilder GetCleanCommand(IBuildActions actions, string? dotNetPath, IDictionary? environment) { var clean = new CommandBuilder(actions, null, environment). RunCommand(DotNetCommand(actions, dotNetPath)). @@ -284,7 +284,7 @@ CommandBuilder GetCleanCommand(IBuildActions actions, string? dotNetPath, IDicti return clean; } - CommandBuilder GetRestoreCommand(IBuildActions actions, string? dotNetPath, IDictionary? environment) + private static CommandBuilder GetRestoreCommand(IBuildActions actions, string? dotNetPath, IDictionary? environment) { var restore = new CommandBuilder(actions, null, environment). RunCommand(DotNetCommand(actions, dotNetPath)). @@ -292,7 +292,7 @@ CommandBuilder GetRestoreCommand(IBuildActions actions, string? dotNetPath, IDic return restore; } - static BuildScript GetInstalledRuntimesScript(IBuildActions actions, string? dotNetPath, IDictionary? environment) + private static BuildScript GetInstalledRuntimesScript(IBuildActions actions, string? dotNetPath, IDictionary? environment) { var listSdks = new CommandBuilder(actions, environment: environment, silent: true). RunCommand(DotNetCommand(actions, dotNetPath)). @@ -309,7 +309,7 @@ static BuildScript GetInstalledRuntimesScript(IBuildActions actions, string? dot /// hence the need for CLR tracing), by adding a /// `/p:UseSharedCompilation=false` argument. /// - BuildScript GetBuildScript(Autobuilder builder, string? dotNetPath, IDictionary? environment, bool compatibleClr, string projOrSln) + private static BuildScript GetBuildScript(Autobuilder builder, string? dotNetPath, IDictionary? environment, bool compatibleClr, string projOrSln) { var build = new CommandBuilder(builder.Actions, null, environment); var script = builder.MaybeIndex(build, DotNetCommand(builder.Actions, dotNetPath)). diff --git a/csharp/autobuilder/Semmle.Autobuild.CSharp/Program.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp/Program.cs new file mode 100644 index 000000000000..2233557af16d --- /dev/null +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/Program.cs @@ -0,0 +1,33 @@ +using System; +using Semmle.Autobuild.Shared; + +namespace Semmle.Autobuild.CSharp +{ + public static class Program + { + public static int Main() + { + + try + { + var actions = SystemBuildActions.Instance; + var options = new AutobuildOptions(actions, Language.CSharp); + try + { + Console.WriteLine("CodeQL C# autobuilder"); + var builder = new CSharpAutobuilder(actions, options); + return builder.AttemptBuild(); + } + catch (InvalidEnvironmentException ex) + { + Console.WriteLine("The environment is invalid: {0}", ex.Message); + } + } + catch (ArgumentOutOfRangeException ex) + { + Console.WriteLine("The value \"{0}\" for parameter \"{1}\" is invalid", ex.ActualValue, ex.ParamName); + } + return 1; + } + } +} diff --git a/csharp/autobuilder/Semmle.Autobuild.CSharp/Properties/AssemblyInfo.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp/Properties/AssemblyInfo.cs new file mode 100644 index 000000000000..7314539ace49 --- /dev/null +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Semmle.Autobuild.CSharp")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("GitHub")] +[assembly: AssemblyProduct("CodeQL autobuilder for C#")] +[assembly: AssemblyCopyright("Copyright © GitHub 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/csharp/autobuilder/Semmle.Autobuild/Semmle.Autobuild.csproj b/csharp/autobuilder/Semmle.Autobuild.CSharp/Semmle.Autobuild.CSharp.csproj similarity index 74% rename from csharp/autobuilder/Semmle.Autobuild/Semmle.Autobuild.csproj rename to csharp/autobuilder/Semmle.Autobuild.CSharp/Semmle.Autobuild.CSharp.csproj index 63aab3b29fbb..82ca05504bca 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Semmle.Autobuild.csproj +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/Semmle.Autobuild.CSharp.csproj @@ -1,9 +1,9 @@ - netcoreapp3.0 - Semmle.Autobuild - Semmle.Autobuild + netcoreapp3.1 + Semmle.Autobuild.CSharp + Semmle.Autobuild.CSharp Exe @@ -24,6 +24,7 @@ + diff --git a/csharp/autobuilder/Semmle.Autobuild/StandaloneBuildRule.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp/StandaloneBuildRule.cs similarity index 60% rename from csharp/autobuilder/Semmle.Autobuild/StandaloneBuildRule.cs rename to csharp/autobuilder/Semmle.Autobuild.CSharp/StandaloneBuildRule.cs index 26bc84bb6015..997d1db55228 100644 --- a/csharp/autobuilder/Semmle.Autobuild/StandaloneBuildRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/StandaloneBuildRule.cs @@ -1,18 +1,31 @@ -namespace Semmle.Autobuild +using System.Linq; +using Semmle.Autobuild.Shared; + +namespace Semmle.Autobuild.CSharp { /// /// Build using standalone extraction. /// - class StandaloneBuildRule : IBuildRule + internal class StandaloneBuildRule : IBuildRule { public BuildScript Analyse(Autobuilder builder, bool auto) { BuildScript GetCommand(string? solution) { - if (builder.SemmlePlatformTools is null) + string standalone; + if (builder.CodeQLExtractorLangRoot is object && builder.CodeQlPlatform is object) + { + standalone = builder.Actions.PathCombine(builder.CodeQLExtractorLangRoot, "tools", builder.CodeQlPlatform, "Semmle.Extraction.CSharp.Standalone"); + } + else if (builder.SemmlePlatformTools is object) + { + standalone = builder.Actions.PathCombine(builder.SemmlePlatformTools, "csharp", "Semmle.Extraction.CSharp.Standalone"); + } + else + { return BuildScript.Failure; + } - var standalone = builder.Actions.PathCombine(builder.SemmlePlatformTools, "csharp", "Semmle.Extraction.CSharp.Standalone"); var cmd = new CommandBuilder(builder.Actions); cmd.RunCommand(standalone); @@ -32,9 +45,7 @@ BuildScript GetCommand(string? solution) if (!builder.Options.Buildless) return BuildScript.Failure; - var solutions = builder.Options.Solution.Length; - - if (solutions == 0) + if (!builder.Options.Solution.Any()) return GetCommand(null); var script = BuildScript.Success; diff --git a/csharp/autobuilder/Semmle.Autobuild/AutobuildOptions.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/AutobuildOptions.cs similarity index 65% rename from csharp/autobuilder/Semmle.Autobuild/AutobuildOptions.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/AutobuildOptions.cs index 9786e4dcca65..0bcffa684962 100644 --- a/csharp/autobuilder/Semmle.Autobuild/AutobuildOptions.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/AutobuildOptions.cs @@ -1,41 +1,39 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// /// Encapsulates build options. /// public class AutobuildOptions { - public readonly int SearchDepth = 3; - public readonly string RootDirectory; private const string prefix = "LGTM_INDEX_"; - public readonly string? VsToolsVersion; - public readonly string? MsBuildArguments; - public readonly string? MsBuildPlatform; - public readonly string? MsBuildConfiguration; - public readonly string? MsBuildTarget; - public readonly string? DotNetArguments; - public readonly string? DotNetVersion; - public readonly string? BuildCommand; - public readonly string[] Solution; - - public readonly bool IgnoreErrors; - public readonly bool Buildless; - public readonly bool AllSolutions; - public readonly bool NugetRestore; - - public readonly Language Language; - public readonly bool Indexing; + public int SearchDepth { get; } = 3; + public string RootDirectory { get; } + public string? VsToolsVersion { get; } + public string? MsBuildArguments { get; } + public string? MsBuildPlatform { get; } + public string? MsBuildConfiguration { get; } + public string? MsBuildTarget { get; } + public string? DotNetArguments { get; } + public string? DotNetVersion { get; } + public string? BuildCommand { get; } + public IEnumerable Solution { get; } + public bool IgnoreErrors { get; } + public bool Buildless { get; } + public bool AllSolutions { get; } + public bool NugetRestore { get; } + public Language Language { get; } /// /// Reads options from environment variables. /// Throws ArgumentOutOfRangeException for invalid arguments. /// - public AutobuildOptions(IBuildActions actions) + public AutobuildOptions(IBuildActions actions, Language language) { RootDirectory = actions.GetCurrentDirectory(); VsToolsVersion = actions.GetEnvironmentVariable(prefix + "VSTOOLS_VERSION"); @@ -46,15 +44,14 @@ public AutobuildOptions(IBuildActions actions) DotNetArguments = actions.GetEnvironmentVariable(prefix + "DOTNET_ARGUMENTS")?.AsStringWithExpandedEnvVars(actions); DotNetVersion = actions.GetEnvironmentVariable(prefix + "DOTNET_VERSION"); BuildCommand = actions.GetEnvironmentVariable(prefix + "BUILD_COMMAND"); - Solution = actions.GetEnvironmentVariable(prefix + "SOLUTION").AsListWithExpandedEnvVars(actions, new string[0]); + Solution = actions.GetEnvironmentVariable(prefix + "SOLUTION").AsListWithExpandedEnvVars(actions, Array.Empty()); IgnoreErrors = actions.GetEnvironmentVariable(prefix + "IGNORE_ERRORS").AsBool("ignore_errors", false); Buildless = actions.GetEnvironmentVariable(prefix + "BUILDLESS").AsBool("buildless", false); AllSolutions = actions.GetEnvironmentVariable(prefix + "ALL_SOLUTIONS").AsBool("all_solutions", false); NugetRestore = actions.GetEnvironmentVariable(prefix + "NUGET_RESTORE").AsBool("nuget_restore", true); - Language = actions.GetEnvironmentVariable("LGTM_PROJECT_LANGUAGE").AsLanguage(); - Indexing = !actions.GetEnvironmentVariable("CODEQL_AUTOBUILDER_CSHARP_NO_INDEXING").AsBool("no_indexing", false); + Language = language; } } @@ -62,7 +59,9 @@ public static class OptionsExtensions { public static bool AsBool(this string? value, string param, bool defaultValue) { - if (value == null) return defaultValue; + if (value == null) + return defaultValue; + switch (value.ToLower()) { case "on": @@ -80,21 +79,6 @@ public static bool AsBool(this string? value, string param, bool defaultValue) } } - public static Language AsLanguage(this string? key) - { - switch (key) - { - case null: - throw new ArgumentException("Environment variable required: LGTM_PROJECT_LANGUAGE"); - case "csharp": - return Language.CSharp; - case "cpp": - return Language.Cpp; - default: - throw new ArgumentException("Language key not understood: '" + key + "'"); - } - } - public static string[] AsListWithExpandedEnvVars(this string? value, IBuildActions actions, string[] defaultValue) { if (value == null) @@ -105,7 +89,7 @@ public static string[] AsListWithExpandedEnvVars(this string? value, IBuildActio Select(s => AsStringWithExpandedEnvVars(s, actions)).ToArray(); } - static readonly Regex linuxEnvRegEx = new Regex(@"\$([a-zA-Z_][a-zA-Z_0-9]*)", RegexOptions.Compiled); + private static readonly Regex linuxEnvRegEx = new Regex(@"\$([a-zA-Z_][a-zA-Z_0-9]*)", RegexOptions.Compiled); public static string AsStringWithExpandedEnvVars(this string value, IBuildActions actions) { diff --git a/csharp/autobuilder/Semmle.Autobuild.Shared/Autobuilder.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/Autobuilder.cs new file mode 100644 index 000000000000..29465bde90aa --- /dev/null +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Autobuilder.cs @@ -0,0 +1,297 @@ +using Semmle.Util.Logging; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Semmle.Autobuild.Shared +{ + /// + /// A build rule analyses the files in "builder" and outputs a build script. + /// + public interface IBuildRule + { + /// + /// Analyse the files and produce a build script. + /// + /// The files and options relating to the build. + /// Whether this build rule is being automatically applied. + BuildScript Analyse(Autobuilder builder, bool auto); + } + + /// + /// A delegate used to wrap a build script in an environment where an appropriate + /// version of .NET Core is automatically installed. + /// + public delegate BuildScript WithDotNet(Autobuilder builder, Func?, BuildScript> f); + + /// + /// Exception indicating that environment variables are missing or invalid. + /// + public class InvalidEnvironmentException : Exception + { + public InvalidEnvironmentException(string m) : base(m) { } + } + + /// + /// Main application logic, containing all data + /// gathered from the project and filesystem. + /// + /// The overall design is intended to be extensible so that in theory, + /// it should be possible to add new build rules without touching this code. + /// + public abstract class Autobuilder + { + /// + /// Full file paths of files found in the project directory, as well as + /// their distance from the project root folder. The list is sorted + /// by distance in ascending order. + /// + public IEnumerable<(string, int)> Paths => pathsLazy.Value; + private readonly Lazy> pathsLazy; + + /// + /// Gets a list of paths matching a set of extensions (including the "."), + /// as well as their distance from the project root folder. + /// The list is sorted by distance in ascending order. + /// + /// The extensions to find. + /// The files matching the extension. + public IEnumerable<(string, int)> GetExtensions(params string[] extensions) => + Paths.Where(p => extensions.Contains(Path.GetExtension(p.Item1))); + + /// + /// Gets all paths matching a particular filename, as well as + /// their distance from the project root folder. The list is sorted + /// by distance in ascending order. + /// + /// The filename to find. + /// Possibly empty sequence of paths with the given filename. + public IEnumerable<(string, int)> GetFilename(string name) => + Paths.Where(p => Actions.GetFileName(p.Item1) == name); + + /// + /// Holds if a given path, relative to the root of the source directory + /// was found. + /// + /// The relative path. + /// True iff the path was found. + public bool HasRelativePath(string path) => HasPath(Actions.PathCombine(RootDirectory, path)); + + /// + /// List of project/solution files to build. + /// + public IList ProjectsOrSolutionsToBuild => projectsOrSolutionsToBuildLazy.Value; + private readonly Lazy> projectsOrSolutionsToBuildLazy; + + /// + /// Holds if a given path was found. + /// + /// The path of the file. + /// True iff the path was found. + public bool HasPath(string path) => Paths.Any(p => path == p.Item1); + + private void FindFiles(string dir, int depth, int maxDepth, IList<(string, int)> results) + { + foreach (var f in Actions.EnumerateFiles(dir)) + { + results.Add((f, depth)); + } + + if (depth < maxDepth) + { + foreach (var d in Actions.EnumerateDirectories(dir)) + { + FindFiles(d, depth + 1, maxDepth, results); + } + } + } + + /// + /// The root of the source directory. + /// + private string RootDirectory => Options.RootDirectory; + + /// + /// Gets the supplied build configuration. + /// + public AutobuildOptions Options { get; } + + /// + /// The set of build actions used during the autobuilder. + /// Could be real system operations, or a stub for testing. + /// + public IBuildActions Actions { get; } + + private IEnumerable? FindFiles(string extension, Func create) + { + var matchingFiles = GetExtensions(extension) + .Select(p => (ProjectOrSolution: create(p.Item1), DistanceFromRoot: p.Item2)) + .Where(p => p.ProjectOrSolution.HasLanguage(this.Options.Language)) + .ToArray(); + + if (matchingFiles.Length == 0) + return null; + + if (Options.AllSolutions) + return matchingFiles.Select(p => p.ProjectOrSolution); + + return matchingFiles + .Where(f => f.DistanceFromRoot == matchingFiles[0].DistanceFromRoot) + .Select(f => f.ProjectOrSolution); + } + + /// + /// Find all the relevant files and picks the best + /// solution file and tools. + /// + /// The command line options. + protected Autobuilder(IBuildActions actions, AutobuildOptions options) + { + Actions = actions; + Options = options; + + pathsLazy = new Lazy>(() => + { + var files = new List<(string, int)>(); + FindFiles(options.RootDirectory, 0, options.SearchDepth, files); + return files.OrderBy(f => f.Item2).ToArray(); + }); + + projectsOrSolutionsToBuildLazy = new Lazy>(() => + { + List? ret; + if (options.Solution.Any()) + { + ret = new List(); + foreach (var solution in options.Solution) + { + if (actions.FileExists(solution)) + ret.Add(new Solution(this, solution, true)); + else + Log(Severity.Error, $"The specified project or solution file {solution} was not found"); + } + return ret; + } + + // First look for `.proj` files + ret = FindFiles(".proj", f => new Project(this, f))?.ToList(); + if (ret != null) + return ret; + + // Then look for `.sln` files + ret = FindFiles(".sln", f => new Solution(this, f, false))?.ToList(); + if (ret != null) + return ret; + + // Finally look for language specific project files, e.g. `.csproj` files + ret = FindFiles(this.Options.Language.ProjectExtension, f => new Project(this, f))?.ToList(); + return ret ?? new List(); + }); + + CodeQLExtractorLangRoot = Actions.GetEnvironmentVariable($"CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_ROOT"); + SemmlePlatformTools = Actions.GetEnvironmentVariable("SEMMLE_PLATFORM_TOOLS"); + + CodeQlPlatform = Actions.GetEnvironmentVariable("CODEQL_PLATFORM"); + + TrapDir = + Actions.GetEnvironmentVariable($"CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_TRAP_DIR") ?? + Actions.GetEnvironmentVariable("TRAP_FOLDER") ?? + throw new InvalidEnvironmentException($"The environment variable CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_TRAP_DIR or TRAP_FOLDER has not been set."); + + SourceArchiveDir = + Actions.GetEnvironmentVariable($"CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_SOURCE_ARCHIVE_DIR") ?? + Actions.GetEnvironmentVariable("SOURCE_ARCHIVE") ?? + throw new InvalidEnvironmentException($"The environment variable CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_SOURCE_ARCHIVE_DIR or SOURCE_ARCHIVE has not been set."); + } + + protected string TrapDir { get; } + + protected string SourceArchiveDir { get; } + + private readonly ILogger logger = new ConsoleLogger(Verbosity.Info); + + /// + /// Log a given build event to the console. + /// + /// The format string. + /// Inserts to the format string. + public void Log(Severity severity, string format, params object[] args) + { + logger.Log(severity, format, args); + } + + /// + /// Attempt to build this project. + /// + /// The exit code, 0 for success and non-zero for failures. + public int AttemptBuild() + { + Log(Severity.Info, $"Working directory: {Options.RootDirectory}"); + + var script = GetBuildScript(); + + if (Options.IgnoreErrors) + script |= BuildScript.Success; + + void startCallback(string s, bool silent) + { + Log(silent ? Severity.Debug : Severity.Info, $"\nRunning {s}"); + } + + void exitCallback(int ret, string msg, bool silent) + { + Log(silent ? Severity.Debug : Severity.Info, $"Exit code {ret}{(string.IsNullOrEmpty(msg) ? "" : $": {msg}")}"); + } + + return script.Run(Actions, startCallback, exitCallback); + } + + /// + /// Returns the build script to use for this project. + /// + public abstract BuildScript GetBuildScript(); + + protected BuildScript AutobuildFailure() => + BuildScript.Create(actions => + { + Log(Severity.Error, "Could not auto-detect a suitable build method"); + return 1; + }); + + /// + /// Value of CODEQL_EXTRACTOR__ROOT environment variable. + /// + public string? CodeQLExtractorLangRoot { get; } + + /// + /// Value of SEMMLE_PLATFORM_TOOLS environment variable. + /// + public string? SemmlePlatformTools { get; } + + /// + /// Value of CODEQL_PLATFORM environment variable. + /// + public string? CodeQlPlatform { get; } + + /// + /// The absolute path of the odasa executable. + /// null if we are running in CodeQL. + /// + public string? Odasa + { + get + { + var semmleDist = Actions.GetEnvironmentVariable("SEMMLE_DIST"); + return semmleDist is null ? null : Actions.PathCombine(semmleDist, "tools", "odasa"); + } + } + + /// + /// Construct a command that executed the given wrapped in + /// an odasa --index, unless indexing has been disabled, in which case + /// is run directly. + /// + public CommandBuilder MaybeIndex(CommandBuilder builder, string cmd) => Odasa is null ? builder.RunCommand(cmd) : builder.IndexCommand(Odasa, cmd); + } +} diff --git a/csharp/autobuilder/Semmle.Autobuild/BuildActions.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildActions.cs similarity index 77% rename from csharp/autobuilder/Semmle.Autobuild/BuildActions.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/BuildActions.cs index 7bc4b9b7591b..b9a5c9c17c35 100644 --- a/csharp/autobuilder/Semmle.Autobuild/BuildActions.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildActions.cs @@ -4,8 +4,11 @@ using System.Diagnostics; using System.IO; using System.Xml; +using System.Net.Http; +using System.Diagnostics.CodeAnalysis; +using System.Threading.Tasks; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// /// Wrapper around system calls so that the build scripts can be unit-tested. @@ -58,6 +61,11 @@ public interface IBuildActions /// void DirectoryDelete(string dir, bool recursive); + /// + /// Creates all directories and subdirectories in the specified path unless they already exist. + /// + void CreateDirectory(string path); + /// /// Gets an environment variable, Environment.GetEnvironmentVariable(). /// @@ -102,6 +110,17 @@ public interface IBuildActions /// string GetFullPath(string path); + /// + /// Returns the file name and extension of the specified path string. + /// + [return: NotNullIfNotNull("path")] + string? GetFileName(string? path); + + /// + /// Returns the directory information for the specified path string. + /// + string? GetDirectoryName(string? path); + /// /// Writes contents to file, File.WriteAllText(). /// @@ -114,23 +133,24 @@ public interface IBuildActions /// XmlDocument LoadXml(string filename); + string EnvironmentExpandEnvironmentVariables(string s); + /// - /// Expand all Windows-style environment variables in , - /// Environment.ExpandEnvironmentVariables() + /// Downloads the resource with the specified URI to a local file. /// - string EnvironmentExpandEnvironmentVariables(string s); + void DownloadFile(string address, string fileName); } /// /// An implementation of IBuildActions that actually performs the requested operations. /// - class SystemBuildActions : IBuildActions + public class SystemBuildActions : IBuildActions { void IBuildActions.FileDelete(string file) => File.Delete(file); bool IBuildActions.FileExists(string file) => File.Exists(file); - ProcessStartInfo GetProcessStartInfo(string exe, string arguments, string? workingDirectory, IDictionary? environment, bool redirectStandardOutput) + private static ProcessStartInfo GetProcessStartInfo(string exe, string arguments, string? workingDirectory, IDictionary? environment, bool redirectStandardOutput) { var pi = new ProcessStartInfo(exe, arguments) { @@ -149,11 +169,9 @@ ProcessStartInfo GetProcessStartInfo(string exe, string arguments, string? worki int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary? environment) { var pi = GetProcessStartInfo(cmd, args, workingDirectory, environment, false); - using (var p = Process.Start(pi)) - { - p.WaitForExit(); - return p.ExitCode; - } + using var p = Process.Start(pi); + p.WaitForExit(); + return p.ExitCode; } int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary? environment, out IList stdOut) @@ -166,6 +184,8 @@ int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, bool IBuildActions.DirectoryExists(string dir) => Directory.Exists(dir); + void IBuildActions.CreateDirectory(string path) => Directory.CreateDirectory(path); + string? IBuildActions.GetEnvironmentVariable(string name) => Environment.GetEnvironmentVariable(name); string IBuildActions.GetCurrentDirectory() => Directory.GetCurrentDirectory(); @@ -189,8 +209,24 @@ XmlDocument IBuildActions.LoadXml(string filename) string IBuildActions.GetFullPath(string path) => Path.GetFullPath(path); + string? IBuildActions.GetFileName(string? path) => Path.GetFileName(path); + + string? IBuildActions.GetDirectoryName(string? path) => Path.GetDirectoryName(path); + public string EnvironmentExpandEnvironmentVariables(string s) => Environment.ExpandEnvironmentVariables(s); - public static readonly IBuildActions Instance = new SystemBuildActions(); + private static async Task DownloadFileAsync(string address, string filename) + { + using var httpClient = new HttpClient(); + using var request = new HttpRequestMessage(HttpMethod.Get, address); + using var contentStream = await (await httpClient.SendAsync(request)).Content.ReadAsStreamAsync(); + using var stream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None, 4096, true); + await contentStream.CopyToAsync(stream); + } + + public void DownloadFile(string address, string fileName) => + DownloadFileAsync(address, fileName).Wait(); + + public static IBuildActions Instance { get; } = new SystemBuildActions(); } } diff --git a/csharp/autobuilder/Semmle.Autobuild/BuildCommandAutoRule.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildCommandAutoRule.cs similarity index 72% rename from csharp/autobuilder/Semmle.Autobuild/BuildCommandAutoRule.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/BuildCommandAutoRule.cs index 80a819f403e4..dfbed17b2d75 100644 --- a/csharp/autobuilder/Semmle.Autobuild/BuildCommandAutoRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildCommandAutoRule.cs @@ -1,27 +1,33 @@ using System.Collections.Generic; -using System.IO; using System.Linq; using Semmle.Util.Logging; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// /// Auto-detection of build scripts. /// - class BuildCommandAutoRule : IBuildRule + public class BuildCommandAutoRule : IBuildRule { - readonly IEnumerable winExtensions = new List { + private readonly WithDotNet withDotNet; + + public BuildCommandAutoRule(WithDotNet withDotNet) + { + this.withDotNet = withDotNet; + } + + private readonly IEnumerable winExtensions = new List { ".bat", ".cmd", ".exe" }; - readonly IEnumerable linuxExtensions = new List { + private readonly IEnumerable linuxExtensions = new List { "", ".sh" }; - readonly IEnumerable buildScripts = new List { + private readonly IEnumerable buildScripts = new List { "build" }; @@ -40,10 +46,10 @@ public BuildScript Analyse(Autobuilder builder, bool auto) chmod.RunCommand("/bin/chmod", $"u+x {scriptPath}"); var chmodScript = builder.Actions.IsWindows() ? BuildScript.Success : BuildScript.Try(chmod.Script); - string? dir = Path.GetDirectoryName(scriptPath); + var dir = builder.Actions.GetDirectoryName(scriptPath); // A specific .NET Core version may be required - return chmodScript & DotNetRule.WithDotNet(builder, environment => + return chmodScript & withDotNet(builder, environment => { var command = new CommandBuilder(builder.Actions, dir, environment); diff --git a/csharp/autobuilder/Semmle.Autobuild/BuildCommandRule.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildCommandRule.cs similarity index 74% rename from csharp/autobuilder/Semmle.Autobuild/BuildCommandRule.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/BuildCommandRule.cs index fe91503ec8fb..daccb41d96c5 100644 --- a/csharp/autobuilder/Semmle.Autobuild/BuildCommandRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildCommandRule.cs @@ -1,17 +1,24 @@ -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// /// Execute the build_command rule. /// - class BuildCommandRule : IBuildRule + public class BuildCommandRule : IBuildRule { + private readonly WithDotNet withDotNet; + + public BuildCommandRule(WithDotNet withDotNet) + { + this.withDotNet = withDotNet; + } + public BuildScript Analyse(Autobuilder builder, bool auto) { if (builder.Options.BuildCommand == null) return BuildScript.Failure; // Custom build commands may require a specific .NET Core version - return DotNetRule.WithDotNet(builder, environment => + return withDotNet(builder, environment => { var command = new CommandBuilder(builder.Actions, null, environment); diff --git a/csharp/autobuilder/Semmle.Autobuild/BuildScript.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildScript.cs similarity index 84% rename from csharp/autobuilder/Semmle.Autobuild/BuildScript.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/BuildScript.cs index e441030ff77e..954befd2c05e 100644 --- a/csharp/autobuilder/Semmle.Autobuild/BuildScript.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildScript.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.IO; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// /// A build script. @@ -46,12 +46,12 @@ public abstract class BuildScript /// The exit code from this build script. public abstract int Run(IBuildActions actions, Action startCallback, Action exitCallBack, out IList stdout); - class BuildCommand : BuildScript + private class BuildCommand : BuildScript { - readonly string exe, arguments; - readonly string? workingDirectory; - readonly IDictionary? environment; - readonly bool silent; + private readonly string exe, arguments; + private readonly string? workingDirectory; + private readonly IDictionary? environment; + private readonly bool silent; /// /// Create a simple build command. @@ -104,7 +104,7 @@ public override int Run(IBuildActions actions, Action startCallbac when (ex is System.ComponentModel.Win32Exception || ex is FileNotFoundException) { retMessage = ex.Message; - stdout = new string[0]; + stdout = Array.Empty(); } exitCallBack(ret, retMessage, silent); return ret; @@ -112,9 +112,9 @@ public override int Run(IBuildActions actions, Action startCallbac } - class ReturnBuildCommand : BuildScript + private class ReturnBuildCommand : BuildScript { - readonly Func func; + private readonly Func func; public ReturnBuildCommand(Func func) { this.func = func; @@ -124,16 +124,17 @@ public ReturnBuildCommand(Func func) public override int Run(IBuildActions actions, Action startCallback, Action exitCallBack, out IList stdout) { - stdout = new string[0]; + stdout = Array.Empty(); return func(actions); } } - class BindBuildScript : BuildScript + private class BindBuildScript : BuildScript { - readonly BuildScript s1; - readonly Func, int, BuildScript>? s2a; - readonly Func? s2b; + private readonly BuildScript s1; + private readonly Func, int, BuildScript>? s2a; + private readonly Func? s2b; + public BindBuildScript(BuildScript s1, Func, int, BuildScript> s2) { this.s1 = s1; @@ -192,6 +193,26 @@ public static BuildScript Create(string exe, string? argumentsOpt, bool silent, public static BuildScript Create(Func func) => new ReturnBuildCommand(func); + /// + /// Creates a build script that downloads the specified file. + /// + public static BuildScript DownloadFile(string address, string fileName, Action exceptionCallback) => + Create(actions => + { + if (actions.GetDirectoryName(fileName) is string dir && !string.IsNullOrWhiteSpace(dir)) + actions.CreateDirectory(dir); + try + { + actions.DownloadFile(address, fileName); + return 0; + } + catch (Exception e) + { + exceptionCallback(e); + return 1; + } + }); + /// /// Creates a build script that runs , followed by running the script /// produced by on the exit code from . @@ -207,19 +228,19 @@ public static BuildScript Bind(BuildScript s1, Func s2) => public static BuildScript Bind(BuildScript s1, Func, int, BuildScript> s2) => new BindBuildScript(s1, s2); - const int SuccessCode = 0; + private const int successCode = 0; /// /// The empty build script that always returns exit code 0. /// - public static readonly BuildScript Success = Create(actions => SuccessCode); + public static BuildScript Success { get; } = Create(actions => successCode); - const int FailureCode = 1; + private const int failureCode = 1; /// /// The empty build script that always returns exit code 1. /// - public static readonly BuildScript Failure = Create(actions => FailureCode); + public static BuildScript Failure { get; } = Create(actions => failureCode); - static bool Succeeded(int i) => i == SuccessCode; + private static bool Succeeded(int i) => i == successCode; public static BuildScript operator &(BuildScript s1, BuildScript s2) => new BindBuildScript(s1, ret1 => Succeeded(ret1) ? s2 : Create(actions => ret1)); @@ -246,7 +267,7 @@ public static BuildScript DeleteDirectory(string dir) => Create(actions => { if (string.IsNullOrEmpty(dir) || !actions.DirectoryExists(dir)) - return FailureCode; + return failureCode; try { @@ -254,9 +275,9 @@ public static BuildScript DeleteDirectory(string dir) => } catch // lgtm[cs/catch-of-all-exceptions] { - return FailureCode; + return failureCode; } - return SuccessCode; + return successCode; }); /// @@ -266,7 +287,7 @@ public static BuildScript DeleteFile(string file) => Create(actions => { if (string.IsNullOrEmpty(file) || !actions.FileExists(file)) - return FailureCode; + return failureCode; try { @@ -274,9 +295,9 @@ public static BuildScript DeleteFile(string file) => } catch // lgtm[cs/catch-of-all-exceptions] { - return FailureCode; + return failureCode; } - return SuccessCode; + return successCode; }); } } diff --git a/csharp/autobuilder/Semmle.Autobuild/BuildTools.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildTools.cs similarity index 83% rename from csharp/autobuilder/Semmle.Autobuild/BuildTools.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/BuildTools.cs index ca9285d2c9c1..79367c90d8e6 100644 --- a/csharp/autobuilder/Semmle.Autobuild/BuildTools.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildTools.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Linq; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// /// A BAT file used to initialise the appropriate @@ -9,15 +9,13 @@ namespace Semmle.Autobuild /// public class VcVarsBatFile { - public readonly int ToolsVersion; - public readonly string Path; - public readonly string[] Platform; + public int ToolsVersion { get; } + public string Path { get; } - public VcVarsBatFile(string path, int version, params string[] platform) + public VcVarsBatFile(string path, int version) { Path = path; ToolsVersion = version; - Platform = platform; } }; @@ -33,12 +31,12 @@ public static IEnumerable GetCandidateVcVarsFiles(IBuildActions a yield break; // Attempt to use vswhere to find installations of Visual Studio - string vswhere = actions.PathCombine(programFilesx86, "Microsoft Visual Studio", "Installer", "vswhere.exe"); + var vswhere = actions.PathCombine(programFilesx86, "Microsoft Visual Studio", "Installer", "vswhere.exe"); if (actions.FileExists(vswhere)) { - int exitCode1 = actions.RunProcess(vswhere, "-prerelease -legacy -property installationPath", null, null, out var installationList); - int exitCode2 = actions.RunProcess(vswhere, "-prerelease -legacy -property installationVersion", null, null, out var versionList); + var exitCode1 = actions.RunProcess(vswhere, "-prerelease -legacy -property installationPath", null, null, out var installationList); + var exitCode2 = actions.RunProcess(vswhere, "-prerelease -legacy -property installationVersion", null, null, out var versionList); if (exitCode1 == 0 && exitCode2 == 0 && versionList.Count == installationList.Count) { @@ -47,16 +45,19 @@ public static IEnumerable GetCandidateVcVarsFiles(IBuildActions a { var dot = vsInstallation.Version.IndexOf('.'); var majorVersionString = dot == -1 ? vsInstallation.Version : vsInstallation.Version.Substring(0, dot); - if (int.TryParse(majorVersionString, out int majorVersion)) + if (int.TryParse(majorVersionString, out var majorVersion)) { if (majorVersion < 15) { - yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"VC\vcvarsall.bat"), majorVersion, "x86"); + // Visual Studio 2015 and below + yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"VC\vcvarsall.bat"), majorVersion); } else { - yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"VC\Auxiliary\Build\vcvars32.bat"), majorVersion, "x86"); - yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"VC\Auxiliary\Build\vcvars64.bat"), majorVersion, "x64"); + // Visual Studio 2017 and above + yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"VC\Auxiliary\Build\vcvars32.bat"), majorVersion); + yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"VC\Auxiliary\Build\vcvars64.bat"), majorVersion); + yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"Common7\Tools\VsDevCmd.bat"), majorVersion); } } // else: Skip installation without a version @@ -66,10 +67,10 @@ public static IEnumerable GetCandidateVcVarsFiles(IBuildActions a } // vswhere not installed or didn't run correctly - return legacy Visual Studio versions - yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 14.0\VC\vcvarsall.bat"), 14, "x86"); - yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 12.0\VC\vcvarsall.bat"), 12, "x86"); - yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 11.0\VC\vcvarsall.bat"), 11, "x86"); - yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 10.0\VC\vcvarsall.bat"), 10, "x86"); + yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 14.0\VC\vcvarsall.bat"), 14); + yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 12.0\VC\vcvarsall.bat"), 12); + yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 11.0\VC\vcvarsall.bat"), 11); + yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 10.0\VC\vcvarsall.bat"), 10); } /// diff --git a/csharp/autobuilder/Semmle.Autobuild/CommandBuilder.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/CommandBuilder.cs similarity index 83% rename from csharp/autobuilder/Semmle.Autobuild/CommandBuilder.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/CommandBuilder.cs index 353f132c6ecc..a5f49d4f4358 100644 --- a/csharp/autobuilder/Semmle.Autobuild/CommandBuilder.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/CommandBuilder.cs @@ -2,22 +2,22 @@ using System.Linq; using System.Text; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// /// Utility to construct a build command. /// - class CommandBuilder + public class CommandBuilder { - enum EscapeMode { Process, Cmd }; + private enum EscapeMode { Process, Cmd }; - readonly StringBuilder arguments; - bool firstCommand; - string? executable; - readonly EscapeMode escapingMode; - readonly string? workingDirectory; - readonly IDictionary? environment; - readonly bool silent; + private readonly StringBuilder arguments; + private bool firstCommand; + private string? executable; + private readonly EscapeMode escapingMode; + private readonly string? workingDirectory; + private readonly IDictionary? environment; + private readonly bool silent; /// /// Initializes a new instance of the class. @@ -45,7 +45,7 @@ public CommandBuilder(IBuildActions actions, string? workingDirectory = null, ID this.silent = silent; } - void OdasaIndex(string odasa) + private void OdasaIndex(string odasa) { RunCommand(odasa, "index --auto"); } @@ -74,8 +74,8 @@ public CommandBuilder IndexCommand(string odasa, string command, string? argumen return this; } - static readonly char[] specialChars = { ' ', '\t', '\n', '\v', '\"' }; - static readonly char[] cmdMetacharacter = { '(', ')', '%', '!', '^', '\"', '<', '>', '&', '|' }; + private static readonly char[] specialChars = { ' ', '\t', '\n', '\v', '\"' }; + private static readonly char[] cmdMetacharacter = { '(', ')', '%', '!', '^', '\"', '<', '>', '&', '|' }; /// /// Appends the given argument to the command line. @@ -88,9 +88,9 @@ public CommandBuilder IndexCommand(string odasa, string command, string? argumen /// This implementation is copied from /// https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/ /// - void ArgvQuote(string argument, bool force) + private void ArgvQuote(string argument, bool force) { - bool cmd = escapingMode == EscapeMode.Cmd; + var cmd = escapingMode == EscapeMode.Cmd; if (!force && !string.IsNullOrEmpty(argument) && argument.IndexOfAny(specialChars) == -1) @@ -99,9 +99,12 @@ void ArgvQuote(string argument, bool force) } else { - if (cmd) arguments.Append('^'); + if (cmd) + arguments.Append('^'); + arguments.Append('\"'); - for (int it = 0; ; ++it) + + for (var it = 0; ; ++it) { var numBackslashes = 0; while (it != argument.Length && argument[it] == '\\') @@ -115,10 +118,12 @@ void ArgvQuote(string argument, bool force) arguments.Append('\\', numBackslashes * 2); break; } - else if (argument[it] == '\"') + + if (argument[it] == '\"') { arguments.Append('\\', numBackslashes * 2 + 1); - if (cmd) arguments.Append('^'); + if (cmd) + arguments.Append('^'); arguments.Append(arguments[it]); } else @@ -130,7 +135,10 @@ void ArgvQuote(string argument, bool force) arguments.Append(argument[it]); } } - if (cmd) arguments.Append('^'); + + if (cmd) + arguments.Append('^'); + arguments.Append('\"'); } } @@ -145,7 +153,7 @@ public CommandBuilder QuoteArgument(string argumentsOpt) return this; } - void NextArgument() + private void NextArgument() { if (arguments.Length > 0) arguments.Append(' '); @@ -161,7 +169,7 @@ public CommandBuilder Argument(string? argumentsOpt) return this; } - void NextCommand() + private void NextCommand() { if (firstCommand) firstCommand = false; diff --git a/csharp/autobuilder/Semmle.Autobuild.Shared/Language.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/Language.cs new file mode 100644 index 000000000000..c53eb7e592d3 --- /dev/null +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Language.cs @@ -0,0 +1,23 @@ +namespace Semmle.Autobuild.Shared +{ + public sealed class Language + { + public static Language Cpp { get; } = new Language(".vcxproj", "CPP"); + public static Language CSharp { get; } = new Language(".csproj", "CSHARP"); + + public bool ProjectFileHasThisLanguage(string path) => + System.IO.Path.GetExtension(path) == ProjectExtension; + + public string ProjectExtension { get; } + public string UpperCaseName { get; } + + private Language(string extension, string name) + { + ProjectExtension = extension; + UpperCaseName = name; + } + + public override string ToString() => + ProjectExtension == Cpp.ProjectExtension ? "C/C++" : "C#"; + } +} diff --git a/csharp/autobuilder/Semmle.Autobuild/MsBuildRule.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/MsBuildRule.cs similarity index 54% rename from csharp/autobuilder/Semmle.Autobuild/MsBuildRule.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/MsBuildRule.cs index 569f9f183eba..30b7e0476132 100644 --- a/csharp/autobuilder/Semmle.Autobuild/MsBuildRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/MsBuildRule.cs @@ -1,17 +1,17 @@ using Semmle.Util.Logging; using System.Linq; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// /// A build rule using msbuild. /// - class MsBuildRule : IBuildRule + public class MsBuildRule : IBuildRule { /// /// The name of the msbuild command. /// - const string MsBuild = "msbuild"; + private const string msBuild = "msbuild"; public BuildScript Analyse(Autobuilder builder, bool auto) { @@ -33,13 +33,14 @@ public BuildScript Analyse(Autobuilder builder, bool auto) if (vsTools == null && builder.Actions.IsWindows()) { - builder.Log(Severity.Warning, "Could not find a suitable version of vcvarsall.bat"); + builder.Log(Severity.Warning, "Could not find a suitable version of VsDevCmd.bat/vcvarsall.bat"); } - var nuget = - builder.SemmlePlatformTools != null ? - builder.Actions.PathCombine(builder.SemmlePlatformTools, "csharp", "nuget", "nuget.exe") : - "nuget"; + // Use `nuget.exe` from source code repo, if present, otherwise first attempt with global + // `nuget` command, and if that fails, attempt to download `nuget.exe` from nuget.org + var nuget = builder.GetFilename("nuget.exe").Select(t => t.Item1).FirstOrDefault() ?? "nuget"; + var nugetDownload = builder.Actions.PathCombine(builder.Options.RootDirectory, ".nuget", "nuget.exe"); + var nugetDownloaded = false; var ret = BuildScript.Success; @@ -47,11 +48,39 @@ public BuildScript Analyse(Autobuilder builder, bool auto) { if (builder.Options.NugetRestore) { - var nugetCommand = new CommandBuilder(builder.Actions). - RunCommand(nuget). - Argument("restore"). + BuildScript GetNugetRestoreScript() => + new CommandBuilder(builder.Actions). + RunCommand(nuget). + Argument("restore"). + QuoteArgument(projectOrSolution.FullPath). + Argument("-DisableParallelProcessing"). + Script; + var nugetRestore = GetNugetRestoreScript(); + var msbuildRestoreCommand = new CommandBuilder(builder.Actions). + RunCommand(msBuild). + Argument("/t:restore"). QuoteArgument(projectOrSolution.FullPath); - ret &= BuildScript.Try(nugetCommand.Script); + + if (nugetDownloaded) + { + ret &= BuildScript.Try(nugetRestore | msbuildRestoreCommand.Script); + } + else + { + // If `nuget restore` fails, and we have not already attempted to download `nuget.exe`, + // download it and reattempt `nuget restore`. + var nugetDownloadAndRestore = + BuildScript.Bind(DownloadNugetExe(builder, nugetDownload), exitCode => + { + nugetDownloaded = true; + if (exitCode != 0) + return BuildScript.Failure; + + nuget = nugetDownload; + return GetNugetRestoreScript(); + }); + ret &= BuildScript.Try(nugetRestore | nugetDownloadAndRestore | msbuildRestoreCommand.Script); + } } var command = new CommandBuilder(builder.Actions); @@ -66,20 +95,14 @@ public BuildScript Analyse(Autobuilder builder, bool auto) command.RunCommand("set Platform=&& type NUL", quoteExe: false); } - builder.MaybeIndex(command, MsBuild); + builder.MaybeIndex(command, msBuild); command.QuoteArgument(projectOrSolution.FullPath); command.Argument("/p:UseSharedCompilation=false"); - string target = builder.Options.MsBuildTarget != null - ? builder.Options.MsBuildTarget - : "rebuild"; - string? platform = builder.Options.MsBuildPlatform != null - ? builder.Options.MsBuildPlatform - : projectOrSolution is ISolution s1 ? s1.DefaultPlatformName : null; - string? configuration = builder.Options.MsBuildConfiguration != null - ? builder.Options.MsBuildConfiguration - : projectOrSolution is ISolution s2 ? s2.DefaultConfigurationName : null; + var target = builder.Options.MsBuildTarget ?? "rebuild"; + var platform = builder.Options.MsBuildPlatform ?? (projectOrSolution is ISolution s1 ? s1.DefaultPlatformName : null); + var configuration = builder.Options.MsBuildConfiguration ?? (projectOrSolution is ISolution s2 ? s2.DefaultConfigurationName : null); command.Argument("/t:" + target); if (platform != null) @@ -130,5 +153,26 @@ public BuildScript Analyse(Autobuilder builder, bool auto) return vsTools; } + + /// + /// Returns a script for downloading `nuget.exe` from nuget.org. + /// + private static BuildScript DownloadNugetExe(Autobuilder builder, string path) => + BuildScript.Create(_ => + { + builder.Log(Severity.Info, "Attempting to download nuget.exe"); + return 0; + }) + & + BuildScript.DownloadFile( + "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe", + path, + e => builder.Log(Severity.Warning, $"Failed to download 'nuget.exe': {e.Message}")) + & + BuildScript.Create(_ => + { + builder.Log(Severity.Info, $"Successfully downloaded {path}"); + return 0; + }); } } diff --git a/csharp/autobuilder/Semmle.Autobuild/Project.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/Project.cs similarity index 97% rename from csharp/autobuilder/Semmle.Autobuild/Project.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/Project.cs index 415ddcbc0f0b..aaaa7cdac566 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Project.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Project.cs @@ -5,7 +5,7 @@ using System.Xml; using Semmle.Util.Logging; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// /// Representation of a .proj file, a .csproj file (C#), or a .vcxproj file (C++). @@ -23,7 +23,7 @@ public class Project : ProjectOrSolution public Version ToolsVersion { get; private set; } - readonly Lazy> includedProjectsLazy; + private readonly Lazy> includedProjectsLazy; public override IEnumerable IncludedProjects => includedProjectsLazy.Value; public Project(Autobuilder builder, string path) : base(builder, path) diff --git a/csharp/autobuilder/Semmle.Autobuild/ProjectOrSolution.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/ProjectOrSolution.cs similarity index 90% rename from csharp/autobuilder/Semmle.Autobuild/ProjectOrSolution.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/ProjectOrSolution.cs index 13859a8c0eb6..5e4d6c05248a 100644 --- a/csharp/autobuilder/Semmle.Autobuild/ProjectOrSolution.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/ProjectOrSolution.cs @@ -1,8 +1,7 @@ using System.Collections.Generic; -using System.IO; using System.Linq; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// /// A file that can be the target in an invocation of `msbuild` or `dotnet build`. @@ -23,13 +22,14 @@ public interface IProjectOrSolution public abstract class ProjectOrSolution : IProjectOrSolution { - public string FullPath { get; private set; } + public string FullPath { get; } - public string DirectoryName => Path.GetDirectoryName(FullPath) ?? ""; + public string DirectoryName { get; } protected ProjectOrSolution(Autobuilder builder, string path) { FullPath = builder.Actions.GetFullPath(path); + DirectoryName = builder.Actions.GetDirectoryName(path) ?? ""; } public abstract IEnumerable IncludedProjects { get; } diff --git a/csharp/autobuilder/Semmle.Autobuild/Properties/AssemblyInfo.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/Properties/AssemblyInfo.cs similarity index 85% rename from csharp/autobuilder/Semmle.Autobuild/Properties/AssemblyInfo.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/Properties/AssemblyInfo.cs index e3da7ca22e9e..2eecfca8f52b 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Properties/AssemblyInfo.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Properties/AssemblyInfo.cs @@ -4,12 +4,12 @@ // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("Semmle.Autobuild")] +[assembly: AssemblyTitle("Semmle.Autobuild.Shared")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Semmle")] -[assembly: AssemblyProduct("Semmle Visual Studio Autobuild")] -[assembly: AssemblyCopyright("Copyright © Semmle 2017")] +[assembly: AssemblyCompany("GitHub")] +[assembly: AssemblyProduct("CodeQL autobuilder")] +[assembly: AssemblyCopyright("Copyright © GitHub 2020")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/csharp/autobuilder/Semmle.Autobuild.Shared/Semmle.Autobuild.Shared.csproj b/csharp/autobuilder/Semmle.Autobuild.Shared/Semmle.Autobuild.Shared.csproj new file mode 100644 index 000000000000..6663c428b036 --- /dev/null +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Semmle.Autobuild.Shared.csproj @@ -0,0 +1,24 @@ + + + + netcoreapp3.1 + Semmle.Autobuild.Shared + Semmle.Autobuild.Shared + false + win-x64;linux-x64;osx-x64 + enable + + + + + + + + + + + + + + + diff --git a/csharp/autobuilder/Semmle.Autobuild/Solution.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/Solution.cs similarity index 77% rename from csharp/autobuilder/Semmle.Autobuild/Solution.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/Solution.cs index 0429b9f420cc..2f16872dd749 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Solution.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Solution.cs @@ -3,11 +3,10 @@ using System; using System.Collections.Generic; using System.Linq; -using Semmle.Util; using System.IO; using Semmle.Util.Logging; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// /// A solution file, extension .sln. @@ -41,11 +40,11 @@ public interface ISolution : IProjectOrSolution /// /// A solution file on the filesystem, read using Microsoft.Build. /// - class Solution : ProjectOrSolution, ISolution + internal class Solution : ProjectOrSolution, ISolution { - readonly SolutionFile? solution; + private readonly SolutionFile? solution; - readonly IEnumerable includedProjects; + private readonly IEnumerable includedProjects; public override IEnumerable IncludedProjects => includedProjects; public IEnumerable Configurations => @@ -74,19 +73,18 @@ public Solution(Autobuilder builder, string path, bool allowProject) : base(buil } builder.Log(Severity.Info, $"Unable to read solution file {path}."); - includedProjects = new Project[0]; + includedProjects = Array.Empty(); return; } - includedProjects = - solution.ProjectsInOrder. - Where(p => p.ProjectType == SolutionProjectType.KnownToBeMSBuildFormat). - Select(p => builder.Actions.PathCombine(DirectoryName, builder.Actions.PathCombine(p.RelativePath.Split('\\', StringSplitOptions.RemoveEmptyEntries)))). - Select(p => new Project(builder, p)). - ToArray(); + includedProjects = solution.ProjectsInOrder + .Where(p => p.ProjectType == SolutionProjectType.KnownToBeMSBuildFormat) + .Select(p => builder.Actions.PathCombine(DirectoryName, builder.Actions.PathCombine(p.RelativePath.Split('\\', StringSplitOptions.RemoveEmptyEntries)))) + .Select(p => new Project(builder, p)) + .ToArray(); } - IEnumerable ToolsVersions => includedProjects.Where(p => p.ValidToolsVersion).Select(p => p.ToolsVersion); + private IEnumerable ToolsVersions => includedProjects.Where(p => p.ValidToolsVersion).Select(p => p.ToolsVersion); public Version ToolsVersion => ToolsVersions.Any() ? ToolsVersions.Max() : new Version(); } diff --git a/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs b/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs deleted file mode 100644 index 93b498912258..000000000000 --- a/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs +++ /dev/null @@ -1,1147 +0,0 @@ -using Xunit; -using Semmle.Autobuild; -using System.Collections.Generic; -using System; -using System.Linq; -using Microsoft.Build.Construction; -using System.Xml; - -namespace Semmle.Extraction.Tests -{ - /// - /// Test class to script Autobuilder scenarios. - /// For most methods, it uses two fields: - /// - an IList to capture the the arguments passed to it - /// - an IDictionary of possible return values. - /// - class TestActions : IBuildActions - { - /// - /// List of strings passed to FileDelete. - /// - public IList FileDeleteIn = new List(); - - void IBuildActions.FileDelete(string file) - { - FileDeleteIn.Add(file); - } - - public IList FileExistsIn = new List(); - public IDictionary FileExists = new Dictionary(); - - bool IBuildActions.FileExists(string file) - { - FileExistsIn.Add(file); - if (FileExists.TryGetValue(file, out var ret)) - return ret; - if (FileExists.TryGetValue(System.IO.Path.GetFileName(file), out ret)) - return ret; - throw new ArgumentException("Missing FileExists " + file); - } - - public IList RunProcessIn = new List(); - public IDictionary RunProcess = new Dictionary(); - public IDictionary RunProcessOut = new Dictionary(); - public IDictionary RunProcessWorkingDirectory = new Dictionary(); - - int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary? env, out IList stdOut) - { - var pattern = cmd + " " + args; - RunProcessIn.Add(pattern); - if (RunProcessOut.TryGetValue(pattern, out var str)) - stdOut = str.Split("\n"); - else - throw new ArgumentException("Missing RunProcessOut " + pattern); - RunProcessWorkingDirectory.TryGetValue(pattern, out var wd); - if (wd != workingDirectory) - throw new ArgumentException("Missing RunProcessWorkingDirectory " + pattern); - if (RunProcess.TryGetValue(pattern, out var ret)) - return ret; - throw new ArgumentException("Missing RunProcess " + pattern); - } - - int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary? env) - { - var pattern = cmd + " " + args; - RunProcessIn.Add(pattern); - RunProcessWorkingDirectory.TryGetValue(pattern, out var wd); - if (wd != workingDirectory) - throw new ArgumentException("Missing RunProcessWorkingDirectory " + pattern); - if (RunProcess.TryGetValue(pattern, out var ret)) - return ret; - throw new ArgumentException("Missing RunProcess " + pattern); - } - - public IList DirectoryDeleteIn = new List(); - - void IBuildActions.DirectoryDelete(string dir, bool recursive) - { - DirectoryDeleteIn.Add(dir); - } - - public IDictionary DirectoryExists = new Dictionary(); - public IList DirectoryExistsIn = new List(); - - bool IBuildActions.DirectoryExists(string dir) - { - DirectoryExistsIn.Add(dir); - if (DirectoryExists.TryGetValue(dir, out var ret)) - return ret; - throw new ArgumentException("Missing DirectoryExists " + dir); - } - - public IDictionary GetEnvironmentVariable = new Dictionary(); - - string? IBuildActions.GetEnvironmentVariable(string name) - { - if (GetEnvironmentVariable.TryGetValue(name, out var ret)) - return ret; - throw new ArgumentException("Missing GetEnvironmentVariable " + name); - } - - public string GetCurrentDirectory = ""; - - string IBuildActions.GetCurrentDirectory() - { - return GetCurrentDirectory; - } - - public IDictionary EnumerateFiles = new Dictionary(); - - IEnumerable IBuildActions.EnumerateFiles(string dir) - { - if (EnumerateFiles.TryGetValue(dir, out var str)) - return str.Split("\n"); - throw new ArgumentException("Missing EnumerateFiles " + dir); - } - - public IDictionary EnumerateDirectories = new Dictionary(); - - IEnumerable IBuildActions.EnumerateDirectories(string dir) - { - if (EnumerateDirectories.TryGetValue(dir, out var str)) - return string.IsNullOrEmpty(str) ? Enumerable.Empty() : str.Split("\n"); - throw new ArgumentException("Missing EnumerateDirectories " + dir); - } - - public bool IsWindows; - - bool IBuildActions.IsWindows() => IsWindows; - - string IBuildActions.PathCombine(params string[] parts) - { - return string.Join(IsWindows ? '\\' : '/', parts.Where(p => !string.IsNullOrWhiteSpace(p))); - } - - string IBuildActions.GetFullPath(string path) => path; - - void IBuildActions.WriteAllText(string filename, string contents) - { - } - - public IDictionary LoadXml = new Dictionary(); - XmlDocument IBuildActions.LoadXml(string filename) - { - if (LoadXml.TryGetValue(filename, out var xml)) - return xml; - throw new ArgumentException("Missing LoadXml " + filename); - } - - public string EnvironmentExpandEnvironmentVariables(string s) - { - foreach (var kvp in GetEnvironmentVariable) - s = s.Replace($"%{kvp.Key}%", kvp.Value); - return s; - } - } - - /// - /// A fake solution to build. - /// - class TestSolution : ISolution - { - public IEnumerable Configurations => throw new NotImplementedException(); - - public string DefaultConfigurationName => "Release"; - - public string DefaultPlatformName => "x86"; - - public string FullPath { get; set; } - - public Version ToolsVersion => new Version("14.0"); - - public IEnumerable IncludedProjects => throw new NotImplementedException(); - - public TestSolution(string path) - { - FullPath = path; - } - } - - public class BuildScriptTests - { - TestActions Actions = new TestActions(); - - // Records the arguments passed to StartCallback. - IList StartCallbackIn = new List(); - - void StartCallback(string s, bool silent) - { - StartCallbackIn.Add(s); - } - - // Records the arguments passed to EndCallback - IList EndCallbackIn = new List(); - IList EndCallbackReturn = new List(); - - void EndCallback(int ret, string s, bool silent) - { - EndCallbackReturn.Add(ret); - EndCallbackIn.Add(s); - } - - [Fact] - public void TestBuildCommand() - { - var cmd = BuildScript.Create("abc", "def ghi", false, null, null); - - Actions.RunProcess["abc def ghi"] = 1; - cmd.Run(Actions, StartCallback, EndCallback); - Assert.Equal("abc def ghi", Actions.RunProcessIn[0]); - Assert.Equal("abc def ghi", StartCallbackIn[0]); - Assert.Equal("", EndCallbackIn[0]); - Assert.Equal(1, EndCallbackReturn[0]); - } - - [Fact] - public void TestAnd1() - { - var cmd = BuildScript.Create("abc", "def ghi", false, null, null) & BuildScript.Create("odasa", null, false, null, null); - - Actions.RunProcess["abc def ghi"] = 1; - cmd.Run(Actions, StartCallback, EndCallback); - - Assert.Equal("abc def ghi", Actions.RunProcessIn[0]); - Assert.Equal("abc def ghi", StartCallbackIn[0]); - Assert.Equal("", EndCallbackIn[0]); - Assert.Equal(1, EndCallbackReturn[0]); - } - - [Fact] - public void TestAnd2() - { - var cmd = BuildScript.Create("odasa", null, false, null, null) & BuildScript.Create("abc", "def ghi", false, null, null); - - Actions.RunProcess["abc def ghi"] = 1; - Actions.RunProcess["odasa "] = 0; - cmd.Run(Actions, StartCallback, EndCallback); - - Assert.Equal("odasa ", Actions.RunProcessIn[0]); - Assert.Equal("odasa ", StartCallbackIn[0]); - Assert.Equal("", EndCallbackIn[0]); - Assert.Equal(0, EndCallbackReturn[0]); - - Assert.Equal("abc def ghi", Actions.RunProcessIn[1]); - Assert.Equal("abc def ghi", StartCallbackIn[1]); - Assert.Equal("", EndCallbackIn[1]); - Assert.Equal(1, EndCallbackReturn[1]); - } - - [Fact] - public void TestOr1() - { - var cmd = BuildScript.Create("odasa", null, false, null, null) | BuildScript.Create("abc", "def ghi", false, null, null); - - Actions.RunProcess["abc def ghi"] = 1; - Actions.RunProcess["odasa "] = 0; - cmd.Run(Actions, StartCallback, EndCallback); - - Assert.Equal("odasa ", Actions.RunProcessIn[0]); - Assert.Equal("odasa ", StartCallbackIn[0]); - Assert.Equal("", EndCallbackIn[0]); - Assert.Equal(0, EndCallbackReturn[0]); - Assert.Equal(1, EndCallbackReturn.Count); - } - - [Fact] - public void TestOr2() - { - var cmd = BuildScript.Create("abc", "def ghi", false, null, null) | BuildScript.Create("odasa", null, false, null, null); - - Actions.RunProcess["abc def ghi"] = 1; - Actions.RunProcess["odasa "] = 0; - cmd.Run(Actions, StartCallback, EndCallback); - - Assert.Equal("abc def ghi", Actions.RunProcessIn[0]); - Assert.Equal("abc def ghi", StartCallbackIn[0]); - Assert.Equal("", EndCallbackIn[0]); - Assert.Equal(1, EndCallbackReturn[0]); - - Assert.Equal("odasa ", Actions.RunProcessIn[1]); - Assert.Equal("odasa ", StartCallbackIn[1]); - Assert.Equal("", EndCallbackIn[1]); - Assert.Equal(0, EndCallbackReturn[1]); - } - - [Fact] - public void TestSuccess() - { - Assert.Equal(0, BuildScript.Success.Run(Actions, StartCallback, EndCallback)); - } - - [Fact] - public void TestFailure() - { - Assert.NotEqual(0, BuildScript.Failure.Run(Actions, StartCallback, EndCallback)); - } - - [Fact] - public void TestDeleteDirectorySuccess() - { - Actions.DirectoryExists["trap"] = true; - Assert.Equal(0, BuildScript.DeleteDirectory("trap").Run(Actions, StartCallback, EndCallback)); - Assert.Equal("trap", Actions.DirectoryDeleteIn[0]); - } - - [Fact] - public void TestDeleteDirectoryFailure() - { - Actions.DirectoryExists["trap"] = false; - Assert.NotEqual(0, BuildScript.DeleteDirectory("trap").Run(Actions, StartCallback, EndCallback)); - } - - [Fact] - public void TestDeleteFileSuccess() - { - Actions.FileExists["csharp.log"] = true; - Assert.Equal(0, BuildScript.DeleteFile("csharp.log").Run(Actions, StartCallback, EndCallback)); - Assert.Equal("csharp.log", Actions.FileExistsIn[0]); - Assert.Equal("csharp.log", Actions.FileDeleteIn[0]); - } - - [Fact] - public void TestDeleteFileFailure() - { - Actions.FileExists["csharp.log"] = false; - Assert.NotEqual(0, BuildScript.DeleteFile("csharp.log").Run(Actions, StartCallback, EndCallback)); - Assert.Equal("csharp.log", Actions.FileExistsIn[0]); - } - - [Fact] - public void TestTry() - { - Assert.Equal(0, BuildScript.Try(BuildScript.Failure).Run(Actions, StartCallback, EndCallback)); - } - - Autobuilder CreateAutoBuilder(string lgtmLanguage, bool isWindows, - string? buildless = null, string? solution = null, string? buildCommand = null, string? ignoreErrors = null, - string? msBuildArguments = null, string? msBuildPlatform = null, string? msBuildConfiguration = null, string? msBuildTarget = null, - string? dotnetArguments = null, string? dotnetVersion = null, string? vsToolsVersion = null, - string? nugetRestore = null, string? allSolutions = null, - string cwd = @"C:\Project") - { - Actions.GetEnvironmentVariable["CODEQL_AUTOBUILDER_CSHARP_NO_INDEXING"] = "false"; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_ROOT"] = @"C:\codeql\csharp"; - Actions.GetEnvironmentVariable["CODEQL_JAVA_HOME"] = @"C:\codeql\tools\java"; - Actions.GetEnvironmentVariable["SEMMLE_DIST"] = @"C:\odasa"; - Actions.GetEnvironmentVariable["SEMMLE_JAVA_HOME"] = @"C:\odasa\tools\java"; - Actions.GetEnvironmentVariable["LGTM_PROJECT_LANGUAGE"] = lgtmLanguage; - Actions.GetEnvironmentVariable["SEMMLE_PLATFORM_TOOLS"] = @"C:\odasa\tools"; - Actions.GetEnvironmentVariable["LGTM_INDEX_VSTOOLS_VERSION"] = vsToolsVersion; - Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_ARGUMENTS"] = msBuildArguments; - Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_PLATFORM"] = msBuildPlatform; - Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_CONFIGURATION"] = msBuildConfiguration; - Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_TARGET"] = msBuildTarget; - Actions.GetEnvironmentVariable["LGTM_INDEX_DOTNET_ARGUMENTS"] = dotnetArguments; - Actions.GetEnvironmentVariable["LGTM_INDEX_DOTNET_VERSION"] = dotnetVersion; - Actions.GetEnvironmentVariable["LGTM_INDEX_BUILD_COMMAND"] = buildCommand; - Actions.GetEnvironmentVariable["LGTM_INDEX_SOLUTION"] = solution; - Actions.GetEnvironmentVariable["LGTM_INDEX_IGNORE_ERRORS"] = ignoreErrors; - Actions.GetEnvironmentVariable["LGTM_INDEX_BUILDLESS"] = buildless; - Actions.GetEnvironmentVariable["LGTM_INDEX_ALL_SOLUTIONS"] = allSolutions; - Actions.GetEnvironmentVariable["LGTM_INDEX_NUGET_RESTORE"] = nugetRestore; - Actions.GetEnvironmentVariable["ProgramFiles(x86)"] = isWindows ? @"C:\Program Files (x86)" : null; - Actions.GetCurrentDirectory = cwd; - Actions.IsWindows = isWindows; - - var options = new AutobuildOptions(Actions); - return new Autobuilder(Actions, options); - } - - [Fact] - public void TestDefaultCSharpAutoBuilder() - { - Actions.RunProcess["cmd.exe /C dotnet --info"] = 0; - Actions.RunProcess["cmd.exe /C dotnet clean test.csproj"] = 0; - Actions.RunProcess["cmd.exe /C dotnet restore test.csproj"] = 0; - Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --auto dotnet build --no-incremental test.csproj"] = 0; - Actions.RunProcess[@"cmd.exe /C C:\codeql\tools\java\bin\java -jar C:\codeql\csharp\tools\extractor-asp.jar ."] = 0; - Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config csproj props xml"] = 0; - Actions.FileExists["csharp.log"] = true; - Actions.FileExists["test.csproj"] = true; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; - Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\nbar.cs\ntest.csproj"; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - var xml = new XmlDocument(); - xml.LoadXml(@" - - Exe - netcoreapp2.1 - - -"); - Actions.LoadXml["test.csproj"] = xml; - - var autobuilder = CreateAutoBuilder("csharp", true); - TestAutobuilderScript(autobuilder, 0, 6); - } - - [Fact] - public void TestLinuxCSharpAutoBuilder() - { - Actions.RunProcess["dotnet --list-runtimes"] = 0; - Actions.RunProcessOut["dotnet --list-runtimes"] = @"Microsoft.AspNetCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App] -Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]"; - Actions.RunProcess["dotnet --info"] = 0; - Actions.RunProcess["dotnet clean test.csproj"] = 0; - Actions.RunProcess["dotnet restore test.csproj"] = 0; - Actions.RunProcess[@"C:\odasa/tools/odasa index --auto dotnet build --no-incremental /p:UseSharedCompilation=false test.csproj"] = 0; - Actions.RunProcess[@"C:\codeql\tools\java/bin/java -jar C:\codeql\csharp/tools/extractor-asp.jar ."] = 0; - Actions.RunProcess[@"C:\odasa/tools/odasa index --xml --extensions config csproj props xml"] = 0; - Actions.FileExists["csharp.log"] = true; - Actions.FileExists["test.csproj"] = true; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; - Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.cs\ntest.csproj"; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - var xml = new XmlDocument(); - xml.LoadXml(@" - - Exe - netcoreapp2.1 - - -"); - Actions.LoadXml["test.csproj"] = xml; - - var autobuilder = CreateAutoBuilder("csharp", false); - TestAutobuilderScript(autobuilder, 0, 7); - } - - [Fact] - public void TestLinuxCSharpAutoBuilderExtractorFailed() - { - Actions.FileExists["csharp.log"] = false; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; - Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.cs"; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - - var autobuilder = CreateAutoBuilder("csharp", false); - TestAutobuilderScript(autobuilder, 1, 0); - } - - - [Fact] - public void TestDefaultCppAutobuilder() - { - Actions.EnumerateFiles[@"C:\Project"] = ""; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - - var autobuilder = CreateAutoBuilder("cpp", true); - var script = autobuilder.GetBuildScript(); - - // Fails due to no solutions present. - Assert.NotEqual(0, script.Run(Actions, StartCallback, EndCallback)); - } - - [Fact] - public void TestCppAutobuilderSuccess() - { - Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\csharp\nuget\nuget.exe restore C:\Project\test.sln"] = 1; - Actions.RunProcess[@"cmd.exe /C CALL ^""C:\Program Files ^(x86^)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat^"" && set Platform=&& type NUL && C:\odasa\tools\odasa index --auto msbuild C:\Project\test.sln /p:UseSharedCompilation=false /t:rebuild /p:Platform=""x86"" /p:Configuration=""Release"" /p:MvcBuildViews=true"] = 0; - Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = ""; - Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = 1; - Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = 0; - Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = ""; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = true; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = true; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = true; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = true; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = true; - Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.slx"; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - - var autobuilder = CreateAutoBuilder("cpp", true); - var solution = new TestSolution(@"C:\Project\test.sln"); - autobuilder.ProjectsOrSolutionsToBuild.Add(solution); - TestAutobuilderScript(autobuilder, 0, 2); - } - - [Fact] - public void TestVsWhereSucceeded() - { - Actions.IsWindows = true; - Actions.GetEnvironmentVariable["ProgramFiles(x86)"] = @"C:\Program Files (x86)"; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = true; - Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = 0; - Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = "C:\\VS1\nC:\\VS2"; - Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = "10.0\n11.0"; - Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = 0; - - var candidates = BuildTools.GetCandidateVcVarsFiles(Actions).ToArray(); - Assert.Equal("C:\\VS1\\VC\\vcvarsall.bat", candidates[0].Path); - Assert.Equal(10, candidates[0].ToolsVersion); - Assert.Equal("C:\\VS2\\VC\\vcvarsall.bat", candidates[1].Path); - Assert.Equal(11, candidates[1].ToolsVersion); - } - - [Fact] - public void TestVsWhereNotExist() - { - Actions.IsWindows = true; - Actions.GetEnvironmentVariable["ProgramFiles(x86)"] = @"C:\Program Files (x86)"; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false; - - var candidates = BuildTools.GetCandidateVcVarsFiles(Actions).ToArray(); - Assert.Equal(4, candidates.Length); - } - - [Fact] - public void TestVcVarsAllBatFiles() - { - Actions.IsWindows = true; - Actions.GetEnvironmentVariable["ProgramFiles(x86)"] = @"C:\Program Files (x86)"; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = true; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = false; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = true; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = false; - - var vcvarsfiles = BuildTools.VcVarsAllBatFiles(Actions).ToArray(); - Assert.Equal(2, vcvarsfiles.Length); - } - - [Fact] - public void TestLinuxBuildlessExtractionSuccess() - { - Actions.RunProcess[@"C:\odasa\tools/csharp/Semmle.Extraction.CSharp.Standalone --references:."] = 0; - Actions.RunProcess[@"C:\codeql\tools\java/bin/java -jar C:\codeql\csharp/tools/extractor-asp.jar ."] = 0; - Actions.RunProcess[@"C:\odasa/tools/odasa index --xml --extensions config csproj props xml"] = 0; - Actions.FileExists["csharp.log"] = true; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; - Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln"; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - - var autobuilder = CreateAutoBuilder("csharp", false, buildless: "true"); - TestAutobuilderScript(autobuilder, 0, 3); - } - - [Fact] - public void TestLinuxBuildlessExtractionFailed() - { - Actions.RunProcess[@"C:\odasa\tools/csharp/Semmle.Extraction.CSharp.Standalone --references:."] = 10; - Actions.FileExists["csharp.log"] = true; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; - Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln"; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - - var autobuilder = CreateAutoBuilder("csharp", false, buildless: "true"); - TestAutobuilderScript(autobuilder, 10, 1); - } - - [Fact] - public void TestLinuxBuildlessExtractionSolution() - { - Actions.RunProcess[@"C:\odasa\tools/csharp/Semmle.Extraction.CSharp.Standalone foo.sln --references:."] = 0; - Actions.RunProcess[@"C:\codeql\tools\java/bin/java -jar C:\codeql\csharp/tools/extractor-asp.jar ."] = 0; - Actions.RunProcess[@"C:\odasa/tools/odasa index --xml --extensions config csproj props xml"] = 0; - Actions.FileExists["csharp.log"] = true; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; - Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln"; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - - var autobuilder = CreateAutoBuilder("csharp", false, buildless: "true", solution: "foo.sln"); - TestAutobuilderScript(autobuilder, 0, 3); - } - - void SkipVsWhere() - { - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = false; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = false; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = false; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = false; - } - - void TestAutobuilderScript(Autobuilder autobuilder, int expectedOutput, int commandsRun) - { - Assert.Equal(expectedOutput, autobuilder.GetBuildScript().Run(Actions, StartCallback, EndCallback)); - - // Check expected commands actually ran - Assert.Equal(commandsRun, StartCallbackIn.Count); - Assert.Equal(commandsRun, EndCallbackIn.Count); - Assert.Equal(commandsRun, EndCallbackReturn.Count); - - var action = Actions.RunProcess.GetEnumerator(); - for (int cmd = 0; cmd < commandsRun; ++cmd) - { - Assert.True(action.MoveNext()); - - Assert.Equal(action.Current.Key, StartCallbackIn[cmd]); - Assert.Equal(action.Current.Value, EndCallbackReturn[cmd]); - } - } - - [Fact] - public void TestLinuxBuildCommand() - { - Actions.RunProcess["dotnet --list-runtimes"] = 1; - Actions.RunProcessOut["dotnet --list-runtimes"] = ""; - Actions.RunProcess[@"C:\odasa/tools/odasa index --auto ""./build.sh --skip-tests"""] = 0; - Actions.RunProcess[@"C:\codeql\tools\java/bin/java -jar C:\codeql\csharp/tools/extractor-asp.jar ."] = 0; - Actions.RunProcess[@"C:\odasa/tools/odasa index --xml --extensions config csproj props xml"] = 0; - Actions.FileExists["csharp.log"] = true; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; - Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln"; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - - SkipVsWhere(); - - var autobuilder = CreateAutoBuilder("csharp", false, buildCommand: "./build.sh --skip-tests"); - TestAutobuilderScript(autobuilder, 0, 4); - } - - [Fact] - public void TestLinuxBuildSh() - { - Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\nbuild/build.sh"; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; - Actions.RunProcess["/bin/chmod u+x build/build.sh"] = 0; - Actions.RunProcess["dotnet --list-runtimes"] = 1; - Actions.RunProcessOut["dotnet --list-runtimes"] = ""; - Actions.RunProcess[@"C:\odasa/tools/odasa index --auto build/build.sh"] = 0; - Actions.RunProcessWorkingDirectory[@"C:\odasa/tools/odasa index --auto build/build.sh"] = "build"; - Actions.RunProcess[@"C:\codeql\tools\java/bin/java -jar C:\codeql\csharp/tools/extractor-asp.jar ."] = 0; - Actions.RunProcess[@"C:\odasa/tools/odasa index --xml --extensions config csproj props xml"] = 0; - Actions.FileExists["csharp.log"] = true; - - var autobuilder = CreateAutoBuilder("csharp", false); - TestAutobuilderScript(autobuilder, 0, 5); - } - - [Fact] - public void TestLinuxBuildShCSharpLogMissing() - { - Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\nbuild.sh"; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; - - Actions.RunProcess["/bin/chmod u+x build.sh"] = 0; - Actions.RunProcess["dotnet --list-runtimes"] = 1; - Actions.RunProcessOut["dotnet --list-runtimes"] = ""; - Actions.RunProcess[@"C:\odasa/tools/odasa index --auto build.sh"] = 0; - Actions.RunProcessWorkingDirectory[@"C:\odasa/tools/odasa index --auto build.sh"] = ""; - Actions.FileExists["csharp.log"] = false; - - var autobuilder = CreateAutoBuilder("csharp", false); - TestAutobuilderScript(autobuilder, 1, 3); - } - - [Fact] - public void TestLinuxBuildShFailed() - { - Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\nbuild.sh"; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; - - Actions.RunProcess["/bin/chmod u+x build.sh"] = 0; - Actions.RunProcess["dotnet --list-runtimes"] = 1; - Actions.RunProcessOut["dotnet --list-runtimes"] = ""; - Actions.RunProcess[@"C:\odasa/tools/odasa index --auto build.sh"] = 5; - Actions.RunProcessWorkingDirectory[@"C:\odasa/tools/odasa index --auto build.sh"] = ""; - Actions.FileExists["csharp.log"] = true; - - var autobuilder = CreateAutoBuilder("csharp", false); - TestAutobuilderScript(autobuilder, 1, 3); - } - - [Fact] - public void TestWindowsBuildBat() - { - Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\nbuild.bat"; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; - Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --auto build.bat"] = 0; - Actions.RunProcessWorkingDirectory[@"cmd.exe /C C:\odasa\tools\odasa index --auto build.bat"] = ""; - Actions.RunProcess[@"cmd.exe /C C:\codeql\tools\java\bin\java -jar C:\codeql\csharp\tools\extractor-asp.jar ."] = 0; - Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config csproj props xml"] = 0; - Actions.FileExists["csharp.log"] = true; - - var autobuilder = CreateAutoBuilder("csharp", true); - TestAutobuilderScript(autobuilder, 0, 3); - } - - [Fact] - public void TestWindowsBuildBatIgnoreErrors() - { - Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\nbuild.bat"; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; - Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --auto build.bat"] = 1; - Actions.RunProcessWorkingDirectory[@"cmd.exe /C C:\odasa\tools\odasa index --auto build.bat"] = ""; - Actions.RunProcess[@"cmd.exe /C C:\codeql\tools\java\bin\java -jar C:\codeql\csharp\tools\extractor-asp.jar ."] = 0; - Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config"] = 0; - Actions.FileExists["csharp.log"] = true; - - var autobuilder = CreateAutoBuilder("csharp", true, ignoreErrors: "true"); - TestAutobuilderScript(autobuilder, 1, 1); - } - - [Fact] - public void TestWindowsCmdIgnoreErrors() - { - Actions.RunProcess["cmd.exe /C C:\\odasa\\tools\\odasa index --auto ^\"build.cmd --skip-tests^\""] = 3; - Actions.RunProcess[@"cmd.exe /C C:\codeql\tools\java\bin\java -jar C:\codeql\csharp\tools\extractor-asp.jar ."] = 0; - Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config"] = 0; - Actions.FileExists["csharp.log"] = true; - SkipVsWhere(); - - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; - Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln"; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - - var autobuilder = CreateAutoBuilder("csharp", true, buildCommand: "build.cmd --skip-tests", ignoreErrors: "true"); - TestAutobuilderScript(autobuilder, 3, 1); - } - - [Fact] - public void TestWindowCSharpMsBuild() - { - Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\csharp\nuget\nuget.exe restore C:\Project\test1.sln"] = 0; - Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test1.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; - Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\csharp\nuget\nuget.exe restore C:\Project\test2.sln"] = 0; - Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test2.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; - Actions.RunProcess[@"cmd.exe /C C:\codeql\tools\java\bin\java -jar C:\codeql\csharp\tools\extractor-asp.jar ."] = 0; - Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config csproj props xml"] = 0; - Actions.FileExists["csharp.log"] = true; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = false; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = true; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = false; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = true; - - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; - Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest1.cs\ntest2.cs"; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - - var autobuilder = CreateAutoBuilder("csharp", true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug", - vsToolsVersion: "12", allSolutions: "true"); - var testSolution1 = new TestSolution(@"C:\Project\test1.sln"); - var testSolution2 = new TestSolution(@"C:\Project\test2.sln"); - autobuilder.ProjectsOrSolutionsToBuild.Add(testSolution1); - autobuilder.ProjectsOrSolutionsToBuild.Add(testSolution2); - - TestAutobuilderScript(autobuilder, 0, 6); - } - - [Fact] - public void TestWindowCSharpMsBuildMultipleSolutions() - { - Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\csharp\nuget\nuget.exe restore test1.csproj"] = 0; - Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild test1.csproj /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; - Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\csharp\nuget\nuget.exe restore test2.csproj"] = 0; - Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild test2.csproj /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; - Actions.RunProcess[@"cmd.exe /C C:\codeql\tools\java\bin\java -jar C:\codeql\csharp\tools\extractor-asp.jar ."] = 0; - Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config csproj props xml"] = 0; - Actions.FileExists["csharp.log"] = true; - Actions.FileExists[@"test1.csproj"] = true; - Actions.FileExists[@"test2.csproj"] = true; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = false; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = true; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = false; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = true; - - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; - Actions.EnumerateFiles[@"C:\Project"] = "test1.csproj\ntest2.csproj\ntest1.cs\ntest2.cs"; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - - var csproj1 = new XmlDocument(); - csproj1.LoadXml(@" - - - - - "); - Actions.LoadXml["test1.csproj"] = csproj1; - - var csproj2 = new XmlDocument(); - csproj2.LoadXml(@" - - - - - "); - Actions.LoadXml["test2.csproj"] = csproj2; - - var autobuilder = CreateAutoBuilder("csharp", true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug", - vsToolsVersion: "12"); - - TestAutobuilderScript(autobuilder, 0, 6); - } - - [Fact] - public void TestWindowCSharpMsBuildFailed() - { - Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\csharp\nuget\nuget.exe restore C:\Project\test1.sln"] = 0; - Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test1.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 1; - Actions.FileExists["csharp.log"] = true; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = false; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = true; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = false; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = true; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; - Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest1.cs\ntest2.cs"; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - - var autobuilder = CreateAutoBuilder("csharp", true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug", - vsToolsVersion: "12", allSolutions: "true"); - var testSolution1 = new TestSolution(@"C:\Project\test1.sln"); - var testSolution2 = new TestSolution(@"C:\Project\test2.sln"); - autobuilder.ProjectsOrSolutionsToBuild.Add(testSolution1); - autobuilder.ProjectsOrSolutionsToBuild.Add(testSolution2); - - TestAutobuilderScript(autobuilder, 1, 2); - } - - - [Fact] - public void TestSkipNugetMsBuild() - { - Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test1.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; - Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test2.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; - Actions.RunProcess[@"cmd.exe /C C:\codeql\tools\java\bin\java -jar C:\codeql\csharp\tools\extractor-asp.jar ."] = 0; - Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config csproj props xml"] = 0; - Actions.FileExists["csharp.log"] = true; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = false; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = true; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = false; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = true; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; - Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest1.cs\ntest2.cs"; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - - var autobuilder = CreateAutoBuilder("csharp", true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", - msBuildPlatform: "x86", msBuildConfiguration: "Debug", vsToolsVersion: "12", - allSolutions: "true", nugetRestore: "false"); - var testSolution1 = new TestSolution(@"C:\Project\test1.sln"); - var testSolution2 = new TestSolution(@"C:\Project\test2.sln"); - autobuilder.ProjectsOrSolutionsToBuild.Add(testSolution1); - autobuilder.ProjectsOrSolutionsToBuild.Add(testSolution2); - - TestAutobuilderScript(autobuilder, 0, 4); - } - - [Fact] - public void TestSkipNugetBuildless() - { - Actions.RunProcess[@"C:\odasa\tools/csharp/Semmle.Extraction.CSharp.Standalone foo.sln --references:. --skip-nuget"] = 0; - Actions.RunProcess[@"C:\codeql\tools\java/bin/java -jar C:\codeql\csharp/tools/extractor-asp.jar ."] = 0; - Actions.RunProcess[@"C:\odasa/tools/odasa index --xml --extensions config csproj props xml"] = 0; - Actions.FileExists["csharp.log"] = true; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; - Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln"; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - - var autobuilder = CreateAutoBuilder("csharp", false, buildless: "true", solution: "foo.sln", nugetRestore: "false"); - TestAutobuilderScript(autobuilder, 0, 3); - } - - - [Fact] - public void TestSkipNugetDotnet() - { - Actions.RunProcess["dotnet --list-runtimes"] = 0; - Actions.RunProcessOut["dotnet --list-runtimes"] = @"Microsoft.AspNetCore.App 2.1.3 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App] -Microsoft.NETCore.App 2.1.3 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]"; - Actions.RunProcess["dotnet --info"] = 0; - Actions.RunProcess["dotnet clean test.csproj"] = 0; - Actions.RunProcess["dotnet restore test.csproj"] = 0; - Actions.RunProcess[@"C:\odasa/tools/odasa index --auto dotnet build --no-incremental /p:UseSharedCompilation=false --no-restore test.csproj"] = 0; - Actions.RunProcess[@"C:\codeql\tools\java/bin/java -jar C:\codeql\csharp/tools/extractor-asp.jar ."] = 0; - Actions.RunProcess[@"C:\odasa/tools/odasa index --xml --extensions config csproj props xml"] = 0; - Actions.FileExists["csharp.log"] = true; - Actions.FileExists["test.csproj"] = true; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; - Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.cs\ntest.csproj"; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - var xml = new XmlDocument(); - xml.LoadXml(@" - - Exe - netcoreapp2.1 - - -"); - Actions.LoadXml["test.csproj"] = xml; - - var autobuilder = CreateAutoBuilder("csharp", false, dotnetArguments: "--no-restore"); // nugetRestore=false does not work for now. - TestAutobuilderScript(autobuilder, 0, 7); - } - - [Fact] - public void TestDotnetVersionNotInstalled() - { - Actions.RunProcess["dotnet --list-sdks"] = 0; - Actions.RunProcessOut["dotnet --list-sdks"] = "2.1.2 [C:\\Program Files\\dotnet\\sdks]\n2.1.4 [C:\\Program Files\\dotnet\\sdks]"; - Actions.RunProcess[@"curl -L -sO https://dot.net/v1/dotnet-install.sh"] = 0; - Actions.RunProcess[@"chmod u+x dotnet-install.sh"] = 0; - Actions.RunProcess[@"./dotnet-install.sh --channel release --version 2.1.3 --install-dir C:\Project/.dotnet"] = 0; - Actions.RunProcess[@"rm dotnet-install.sh"] = 0; - Actions.RunProcess[@"C:\Project/.dotnet/dotnet --list-runtimes"] = 0; - Actions.RunProcessOut[@"C:\Project/.dotnet/dotnet --list-runtimes"] = @"Microsoft.AspNetCore.App 3.0.0 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App] -Microsoft.NETCore.App 3.0.0 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]"; - Actions.RunProcess[@"C:\Project/.dotnet/dotnet --info"] = 0; - Actions.RunProcess[@"C:\Project/.dotnet/dotnet clean test.csproj"] = 0; - Actions.RunProcess[@"C:\Project/.dotnet/dotnet restore test.csproj"] = 0; - Actions.RunProcess[@"C:\odasa/tools/odasa index --auto C:\Project/.dotnet/dotnet build --no-incremental test.csproj"] = 0; - Actions.RunProcess[@"C:\codeql\tools\java/bin/java -jar C:\codeql\csharp/tools/extractor-asp.jar ."] = 0; - Actions.RunProcess[@"C:\odasa/tools/odasa index --xml --extensions config csproj props xml"] = 0; - Actions.FileExists["csharp.log"] = true; - Actions.FileExists["test.csproj"] = true; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; - Actions.GetEnvironmentVariable["PATH"] = "/bin:/usr/bin"; - Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.cs\ntest.csproj"; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - var xml = new XmlDocument(); - xml.LoadXml(@" - - Exe - netcoreapp2.1 - - -"); - Actions.LoadXml["test.csproj"] = xml; - - var autobuilder = CreateAutoBuilder("csharp", false, dotnetVersion: "2.1.3"); - TestAutobuilderScript(autobuilder, 0, 12); - } - - [Fact] - public void TestDotnetVersionAlreadyInstalled() - { - Actions.RunProcess["dotnet --list-sdks"] = 0; - Actions.RunProcessOut["dotnet --list-sdks"] = @"2.1.3 [C:\Program Files\dotnet\sdks] -2.1.4 [C:\Program Files\dotnet\sdks]"; - Actions.RunProcess[@"curl -L -sO https://dot.net/v1/dotnet-install.sh"] = 0; - Actions.RunProcess[@"chmod u+x dotnet-install.sh"] = 0; - Actions.RunProcess[@"./dotnet-install.sh --channel release --version 2.1.3 --install-dir C:\Project/.dotnet"] = 0; - Actions.RunProcess[@"rm dotnet-install.sh"] = 0; - Actions.RunProcess[@"C:\Project/.dotnet/dotnet --list-runtimes"] = 0; - Actions.RunProcessOut[@"C:\Project/.dotnet/dotnet --list-runtimes"] = @"Microsoft.AspNetCore.App 2.1.3 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App] -Microsoft.AspNetCore.App 2.1.4 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App] -Microsoft.NETCore.App 2.1.3 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App] -Microsoft.NETCore.App 2.1.4 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]"; - Actions.RunProcess[@"C:\Project/.dotnet/dotnet --info"] = 0; - Actions.RunProcess[@"C:\Project/.dotnet/dotnet clean test.csproj"] = 0; - Actions.RunProcess[@"C:\Project/.dotnet/dotnet restore test.csproj"] = 0; - Actions.RunProcess[@"C:\odasa/tools/odasa index --auto C:\Project/.dotnet/dotnet build --no-incremental /p:UseSharedCompilation=false test.csproj"] = 0; - Actions.RunProcess[@"C:\codeql\tools\java/bin/java -jar C:\codeql\csharp/tools/extractor-asp.jar ."] = 0; - Actions.RunProcess[@"C:\odasa/tools/odasa index --xml --extensions config csproj props xml"] = 0; - Actions.FileExists["csharp.log"] = true; - Actions.FileExists["test.csproj"] = true; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; - Actions.GetEnvironmentVariable["PATH"] = "/bin:/usr/bin"; - Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\nbar.cs\ntest.csproj"; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - var xml = new XmlDocument(); - xml.LoadXml(@" - - Exe - netcoreapp2.1 - - -"); - Actions.LoadXml["test.csproj"] = xml; - - var autobuilder = CreateAutoBuilder("csharp", false, dotnetVersion: "2.1.3"); - TestAutobuilderScript(autobuilder, 0, 12); - } - - [Fact] - public void TestDotnetVersionWindows() - { - Actions.RunProcess["cmd.exe /C dotnet --list-sdks"] = 0; - Actions.RunProcessOut["cmd.exe /C dotnet --list-sdks"] = "2.1.3 [C:\\Program Files\\dotnet\\sdks]\n2.1.4 [C:\\Program Files\\dotnet\\sdks]"; - Actions.RunProcess[@"cmd.exe /C powershell -NoProfile -ExecutionPolicy unrestricted -file C:\Project\install-dotnet.ps1 -Version 2.1.3 -InstallDir C:\Project\.dotnet"] = 0; - Actions.RunProcess[@"cmd.exe /C del C:\Project\install-dotnet.ps1"] = 0; - Actions.RunProcess[@"cmd.exe /C C:\Project\.dotnet\dotnet --info"] = 0; - Actions.RunProcess[@"cmd.exe /C C:\Project\.dotnet\dotnet clean test.csproj"] = 0; - Actions.RunProcess[@"cmd.exe /C C:\Project\.dotnet\dotnet restore test.csproj"] = 0; - Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --auto C:\Project\.dotnet\dotnet build --no-incremental test.csproj"] = 0; - Actions.RunProcess[@"cmd.exe /C C:\codeql\tools\java\bin\java -jar C:\codeql\csharp\tools\extractor-asp.jar ."] = 0; - Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config csproj props xml"] = 0; - Actions.FileExists["csharp.log"] = true; - Actions.FileExists["test.csproj"] = true; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; - Actions.GetEnvironmentVariable["PATH"] = "/bin:/usr/bin"; - Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.cs\ntest.csproj"; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - var xml = new XmlDocument(); - xml.LoadXml(@" - - Exe - netcoreapp2.1 - - -"); - Actions.LoadXml["test.csproj"] = xml; - - var autobuilder = CreateAutoBuilder("csharp", true, dotnetVersion: "2.1.3"); - TestAutobuilderScript(autobuilder, 0, 9); - } - - [Fact] - public void TestDirsProjWindows() - { - Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\csharp\nuget\nuget.exe restore dirs.proj"] = 1; - Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild dirs.proj /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; - Actions.RunProcess[@"cmd.exe /C C:\codeql\tools\java\bin\java -jar C:\codeql\csharp\tools\extractor-asp.jar ."] = 0; - Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config csproj props xml"] = 0; - Actions.FileExists["csharp.log"] = true; - Actions.FileExists[@"a\test.csproj"] = true; - Actions.FileExists["dirs.proj"] = true; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = false; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = true; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = false; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = true; - - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; - Actions.EnumerateFiles[@"C:\Project"] = "a\\test.cs\na\\test.csproj\ndirs.proj"; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - - var csproj = new XmlDocument(); - csproj.LoadXml(@" - - - - - "); - Actions.LoadXml["a\\test.csproj"] = csproj; - - var dirsproj = new XmlDocument(); - dirsproj.LoadXml(@" - - - -"); - Actions.LoadXml["dirs.proj"] = dirsproj; - - var autobuilder = CreateAutoBuilder("csharp", true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug", - vsToolsVersion: "12", allSolutions: "true"); - TestAutobuilderScript(autobuilder, 0, 4); - } - - [Fact] - public void TestDirsProjLinux() - { - Actions.RunProcess[@"mono C:\odasa\tools/csharp/nuget/nuget.exe restore dirs.proj"] = 1; - Actions.RunProcess[@"C:\odasa/tools/odasa index --auto msbuild dirs.proj /p:UseSharedCompilation=false /t:rebuild /p:MvcBuildViews=true"] = 0; - Actions.RunProcess[@"C:\codeql\tools\java/bin/java -jar C:\codeql\csharp/tools/extractor-asp.jar ."] = 0; - Actions.RunProcess[@"C:\odasa/tools/odasa index --xml --extensions config csproj props xml"] = 0; - Actions.FileExists["csharp.log"] = true; - Actions.FileExists["a/test.csproj"] = true; - Actions.FileExists["dirs.proj"] = true; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; - Actions.EnumerateFiles[@"C:\Project"] = "a/test.cs\na/test.csproj\ndirs.proj"; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - - var csproj = new XmlDocument(); - csproj.LoadXml(@" - - - - - "); - Actions.LoadXml["a/test.csproj"] = csproj; - - var dirsproj = new XmlDocument(); - dirsproj.LoadXml(@" - - - -"); - Actions.LoadXml["dirs.proj"] = dirsproj; - - var autobuilder = CreateAutoBuilder("csharp", false); - TestAutobuilderScript(autobuilder, 0, 4); - } - - [Fact] - public void TestCyclicDirsProj() - { - Actions.FileExists["dirs.proj"] = true; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; - Actions.FileExists["csharp.log"] = false; - Actions.EnumerateFiles[@"C:\Project"] = "dirs.proj"; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - - var dirsproj1 = new XmlDocument(); - dirsproj1.LoadXml(@" - - - -"); - Actions.LoadXml["dirs.proj"] = dirsproj1; - - var autobuilder = CreateAutoBuilder("csharp", false); - TestAutobuilderScript(autobuilder, 1, 0); - } - - [Fact] - public void TestAsStringWithExpandedEnvVarsWindows() - { - Actions.IsWindows = true; - Actions.GetEnvironmentVariable["LGTM_SRC"] = @"C:\repo"; - Assert.Equal(@"C:\repo\test", @"%LGTM_SRC%\test".AsStringWithExpandedEnvVars(Actions)); - } - - [Fact] - public void TestAsStringWithExpandedEnvVarsLinux() - { - Actions.IsWindows = false; - Actions.GetEnvironmentVariable["LGTM_SRC"] = "/tmp/repo"; - Assert.Equal("/tmp/repo/test", "$LGTM_SRC/test".AsStringWithExpandedEnvVars(Actions)); - } - } -} diff --git a/csharp/autobuilder/Semmle.Autobuild/AspBuildRule.cs b/csharp/autobuilder/Semmle.Autobuild/AspBuildRule.cs deleted file mode 100644 index f9c690c273b8..000000000000 --- a/csharp/autobuilder/Semmle.Autobuild/AspBuildRule.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace Semmle.Autobuild -{ - /// - /// ASP extraction. - /// - class AspBuildRule : IBuildRule - { - public BuildScript Analyse(Autobuilder builder, bool auto) - { - var javaHome = builder.JavaHome; - var dist = builder.Distribution; - - var command = new CommandBuilder(builder.Actions). - RunCommand(builder.Actions.PathCombine(javaHome, "bin", "java")). - Argument("-jar"). - QuoteArgument(builder.Actions.PathCombine(dist, "tools", "extractor-asp.jar")). - Argument("."); - return command.Script; - } - } -} diff --git a/csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs b/csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs deleted file mode 100644 index a882f5bb80c7..000000000000 --- a/csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs +++ /dev/null @@ -1,431 +0,0 @@ -using Semmle.Extraction.CSharp; -using Semmle.Util.Logging; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -namespace Semmle.Autobuild -{ - /// - /// A build rule analyses the files in "builder" and outputs a build script. - /// - interface IBuildRule - { - /// - /// Analyse the files and produce a build script. - /// - /// The files and options relating to the build. - /// Whether this build rule is being automatically applied. - BuildScript Analyse(Autobuilder builder, bool auto); - } - - /// - /// Exception indicating that environment variables are missing or invalid. - /// - class InvalidEnvironmentException : Exception - { - public InvalidEnvironmentException(string m) : base(m) { } - } - - /// - /// Main application logic, containing all data - /// gathered from the project and filesystem. - /// - /// The overall design is intended to be extensible so that in theory, - /// it should be possible to add new build rules without touching this code. - /// - public class Autobuilder - { - /// - /// Full file paths of files found in the project directory, as well as - /// their distance from the project root folder. The list is sorted - /// by distance in ascending order. - /// - public IEnumerable<(string, int)> Paths => pathsLazy.Value; - readonly Lazy> pathsLazy; - - /// - /// Gets a list of paths matching a set of extensions (including the "."), - /// as well as their distance from the project root folder. - /// The list is sorted by distance in ascending order. - /// - /// The extensions to find. - /// The files matching the extension. - public IEnumerable<(string, int)> GetExtensions(params string[] extensions) => - Paths.Where(p => extensions.Contains(Path.GetExtension(p.Item1))); - - /// - /// Gets all paths matching a particular filename, as well as - /// their distance from the project root folder. The list is sorted - /// by distance in ascending order. - /// - /// The filename to find. - /// Possibly empty sequence of paths with the given filename. - public IEnumerable<(string, int)> GetFilename(string name) => - Paths.Where(p => Path.GetFileName(p.Item1) == name); - - /// - /// Holds if a given path, relative to the root of the source directory - /// was found. - /// - /// The relative path. - /// True iff the path was found. - public bool HasRelativePath(string path) => HasPath(Actions.PathCombine(RootDirectory, path)); - - /// - /// List of project/solution files to build. - /// - public IList ProjectsOrSolutionsToBuild => projectsOrSolutionsToBuildLazy.Value; - private readonly Lazy> projectsOrSolutionsToBuildLazy; - - /// - /// Holds if a given path was found. - /// - /// The path of the file. - /// True iff the path was found. - public bool HasPath(string path) => Paths.Any(p => path == p.Item1); - - void FindFiles(string dir, int depth, int maxDepth, IList<(string, int)> results) - { - foreach (var f in Actions.EnumerateFiles(dir)) - { - results.Add((f, depth)); - } - - if (depth < maxDepth) - { - foreach (var d in Actions.EnumerateDirectories(dir)) - { - FindFiles(d, depth + 1, maxDepth, results); - } - } - } - - /// - /// The root of the source directory. - /// - string RootDirectory => Options.RootDirectory; - - /// - /// Gets the supplied build configuration. - /// - public AutobuildOptions Options { get; } - - /// - /// The set of build actions used during the autobuilder. - /// Could be real system operations, or a stub for testing. - /// - public IBuildActions Actions { get; } - - IEnumerable? FindFiles(string extension, Func create) - { - var matchingFiles = GetExtensions(extension). - Select(p => (ProjectOrSolution: create(p.Item1), DistanceFromRoot: p.Item2)). - Where(p => p.ProjectOrSolution.HasLanguage(this.Options.Language)). - ToArray(); - - if (matchingFiles.Length == 0) - return null; - - if (Options.AllSolutions) - return matchingFiles.Select(p => p.ProjectOrSolution); - - return matchingFiles. - Where(f => f.DistanceFromRoot == matchingFiles[0].DistanceFromRoot). - Select(f => f.ProjectOrSolution); - } - - /// - /// Find all the relevant files and picks the best - /// solution file and tools. - /// - /// The command line options. - public Autobuilder(IBuildActions actions, AutobuildOptions options) - { - Actions = actions; - Options = options; - - pathsLazy = new Lazy>(() => - { - var files = new List<(string, int)>(); - FindFiles(options.RootDirectory, 0, options.SearchDepth, files); - return files.OrderBy(f => f.Item2).ToArray(); - }); - - projectsOrSolutionsToBuildLazy = new Lazy>(() => - { - List? ret; - if (options.Solution.Any()) - { - ret = new List(); - foreach (var solution in options.Solution) - { - if (actions.FileExists(solution)) - ret.Add(new Solution(this, solution, true)); - else - Log(Severity.Error, $"The specified project or solution file {solution} was not found"); - } - return ret; - } - - // First look for `.proj` files - ret = FindFiles(".proj", f => new Project(this, f))?.ToList(); - if (ret != null) - return ret; - - // Then look for `.sln` files - ret = FindFiles(".sln", f => new Solution(this, f, false))?.ToList(); - if (ret != null) - return ret; - - // Finally look for language specific project files, e.g. `.csproj` files - ret = FindFiles(this.Options.Language.ProjectExtension, f => new Project(this, f))?.ToList(); - return ret ?? new List(); - }); - - CodeQLExtractorCSharpRoot = Actions.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_ROOT"); - SemmleDist = Actions.GetEnvironmentVariable("SEMMLE_DIST"); - SemmlePlatformTools = Actions.GetEnvironmentVariable("SEMMLE_PLATFORM_TOOLS"); - - JavaHome = - Actions.GetEnvironmentVariable("CODEQL_JAVA_HOME") ?? - Actions.GetEnvironmentVariable("SEMMLE_JAVA_HOME") ?? - throw new InvalidEnvironmentException("The environment variable CODEQL_JAVA_HOME or SEMMLE_JAVA_HOME has not been set."); - - Distribution = - CodeQLExtractorCSharpRoot ?? - SemmleDist ?? - throw new InvalidEnvironmentException("The environment variable CODEQL_EXTRACTOR_CSHARP_ROOT or SEMMLE_DIST has not been set."); - - TrapDir = - Actions.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_TRAP_DIR") ?? - Actions.GetEnvironmentVariable("TRAP_FOLDER") ?? - throw new InvalidEnvironmentException("The environment variable CODEQL_EXTRACTOR_CSHARP_TRAP_DIR or TRAP_FOLDER has not been set."); - - SourceArchiveDir = - Actions.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR") ?? - Actions.GetEnvironmentVariable("SOURCE_ARCHIVE") ?? - throw new InvalidEnvironmentException("The environment variable CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR or SOURCE_ARCHIVE has not been set."); - } - - private string TrapDir { get; } - - private string SourceArchiveDir { get; } - - readonly ILogger logger = new ConsoleLogger(Verbosity.Info); - - /// - /// Log a given build event to the console. - /// - /// The format string. - /// Inserts to the format string. - public void Log(Severity severity, string format, params object[] args) - { - logger.Log(severity, format, args); - } - - /// - /// Attempt to build this project. - /// - /// The exit code, 0 for success and non-zero for failures. - public int AttemptBuild() - { - Log(Severity.Info, $"Working directory: {Options.RootDirectory}"); - - var script = GetBuildScript(); - if (Options.IgnoreErrors) - script |= BuildScript.Success; - - void startCallback(string s, bool silent) - { - Log(silent ? Severity.Debug : Severity.Info, $"\nRunning {s}"); - } - - void exitCallback(int ret, string msg, bool silent) - { - Log(silent ? Severity.Debug : Severity.Info, $"Exit code {ret}{(string.IsNullOrEmpty(msg) ? "" : $": {msg}")}"); - } - - return script.Run(Actions, startCallback, exitCallback); - } - - /// - /// Returns the build script to use for this project. - /// - public BuildScript GetBuildScript() - { - var isCSharp = Options.Language == Language.CSharp; - return isCSharp ? GetCSharpBuildScript() : GetCppBuildScript(); - } - - BuildScript GetCSharpBuildScript() - { - /// - /// A script that checks that the C# extractor has been executed. - /// - BuildScript CheckExtractorRun(bool warnOnFailure) => - BuildScript.Create(actions => - { - if (actions.FileExists(Extractor.GetCSharpLogPath())) - return 0; - - if (warnOnFailure) - Log(Severity.Error, "No C# code detected during build."); - - return 1; - }); - - var attempt = BuildScript.Failure; - switch (GetCSharpBuildStrategy()) - { - case CSharpBuildStrategy.CustomBuildCommand: - attempt = new BuildCommandRule().Analyse(this, false) & CheckExtractorRun(true); - break; - case CSharpBuildStrategy.Buildless: - // No need to check that the extractor has been executed in buildless mode - attempt = new StandaloneBuildRule().Analyse(this, false); - break; - case CSharpBuildStrategy.MSBuild: - attempt = new MsBuildRule().Analyse(this, false) & CheckExtractorRun(true); - break; - case CSharpBuildStrategy.DotNet: - attempt = new DotNetRule().Analyse(this, false) & CheckExtractorRun(true); - break; - case CSharpBuildStrategy.Auto: - var cleanTrapFolder = - BuildScript.DeleteDirectory(TrapDir); - var cleanSourceArchive = - BuildScript.DeleteDirectory(SourceArchiveDir); - var tryCleanExtractorArgsLogs = - BuildScript.Create(actions => - { - foreach (var file in Extractor.GetCSharpArgsLogs()) - try - { - actions.FileDelete(file); - } - catch // lgtm[cs/catch-of-all-exceptions] lgtm[cs/empty-catch-block] - { } - return 0; - }); - var attemptExtractorCleanup = - BuildScript.Try(cleanTrapFolder) & - BuildScript.Try(cleanSourceArchive) & - tryCleanExtractorArgsLogs & - BuildScript.DeleteFile(Extractor.GetCSharpLogPath()); - - /// - /// Execute script `s` and check that the C# extractor has been executed. - /// If either fails, attempt to cleanup any artifacts produced by the extractor, - /// and exit with code 1, in order to proceed to the next attempt. - /// - BuildScript IntermediateAttempt(BuildScript s) => - (s & CheckExtractorRun(false)) | - (attemptExtractorCleanup & BuildScript.Failure); - - attempt = - // First try .NET Core - IntermediateAttempt(new DotNetRule().Analyse(this, true)) | - // Then MSBuild - (() => IntermediateAttempt(new MsBuildRule().Analyse(this, true))) | - // And finally look for a script that might be a build script - (() => new BuildCommandAutoRule().Analyse(this, true) & CheckExtractorRun(true)) | - // All attempts failed: print message - AutobuildFailure(); - break; - } - - return - attempt & - (() => new AspBuildRule().Analyse(this, false)) & - (() => new XmlBuildRule().Analyse(this, false)); - } - - /// - /// Gets the build strategy that the autobuilder should apply, based on the - /// options in the `lgtm.yml` file. - /// - CSharpBuildStrategy GetCSharpBuildStrategy() - { - if (Options.BuildCommand != null) - return CSharpBuildStrategy.CustomBuildCommand; - - if (Options.Buildless) - return CSharpBuildStrategy.Buildless; - - if (Options.MsBuildArguments != null - || Options.MsBuildConfiguration != null - || Options.MsBuildPlatform != null - || Options.MsBuildTarget != null) - return CSharpBuildStrategy.MSBuild; - - if (Options.DotNetArguments != null || Options.DotNetVersion != null) - return CSharpBuildStrategy.DotNet; - - return CSharpBuildStrategy.Auto; - } - - enum CSharpBuildStrategy - { - CustomBuildCommand, - Buildless, - MSBuild, - DotNet, - Auto - } - - BuildScript GetCppBuildScript() - { - if (Options.BuildCommand != null) - return new BuildCommandRule().Analyse(this, false); - - return - // First try MSBuild - new MsBuildRule().Analyse(this, true) | - // Then look for a script that might be a build script - (() => new BuildCommandAutoRule().Analyse(this, true)) | - // All attempts failed: print message - AutobuildFailure(); - } - - BuildScript AutobuildFailure() => - BuildScript.Create(actions => - { - Log(Severity.Error, "Could not auto-detect a suitable build method"); - return 1; - }); - - /// - /// Value of CODEQL_EXTRACTOR_CSHARP_ROOT environment variable. - /// - private string? CodeQLExtractorCSharpRoot { get; } - - /// - /// Value of SEMMLE_DIST environment variable. - /// - private string? SemmleDist { get; } - - public string Distribution { get; } - - public string JavaHome { get; } - - /// - /// Value of SEMMLE_PLATFORM_TOOLS environment variable. - /// - public string? SemmlePlatformTools { get; } - - /// - /// The absolute path of the odasa executable. - /// null if we are running in CodeQL. - /// - public string? Odasa => SemmleDist is null ? null : Actions.PathCombine(SemmleDist, "tools", "odasa"); - - /// - /// Construct a command that executed the given wrapped in - /// an odasa --index, unless indexing has been disabled, in which case - /// is run directly. - /// - internal CommandBuilder MaybeIndex(CommandBuilder builder, string cmd) => Options.Indexing && !(Odasa is null) ? builder.IndexCommand(Odasa, cmd) : builder.RunCommand(cmd); - } -} diff --git a/csharp/autobuilder/Semmle.Autobuild/Language.cs b/csharp/autobuilder/Semmle.Autobuild/Language.cs deleted file mode 100644 index 5049506be57a..000000000000 --- a/csharp/autobuilder/Semmle.Autobuild/Language.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace Semmle.Autobuild -{ - public sealed class Language - { - public static readonly Language Cpp = new Language(".vcxproj"); - public static readonly Language CSharp = new Language(".csproj"); - - public bool ProjectFileHasThisLanguage(string path) => - System.IO.Path.GetExtension(path) == ProjectExtension; - - public readonly string ProjectExtension; - - private Language(string extension) - { - ProjectExtension = extension; - } - - public override string ToString() => - ProjectExtension == Cpp.ProjectExtension ? "C/C++" : "C#"; - } -} diff --git a/csharp/autobuilder/Semmle.Autobuild/XmlBuildRule.cs b/csharp/autobuilder/Semmle.Autobuild/XmlBuildRule.cs deleted file mode 100644 index d9b05dbe0a99..000000000000 --- a/csharp/autobuilder/Semmle.Autobuild/XmlBuildRule.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Semmle.Autobuild -{ - /// - /// XML extraction. - /// - class XmlBuildRule : IBuildRule - { - public BuildScript Analyse(Autobuilder builder, bool auto) - { - if (!builder.Options.Indexing || builder.Odasa is null) - return BuildScript.Success; - - var command = new CommandBuilder(builder.Actions). - RunCommand(builder.Odasa). - Argument("index --xml --extensions config csproj props xml"); - return command.Script; - } - } -} diff --git a/csharp/codeql-extractor.yml b/csharp/codeql-extractor.yml new file mode 100644 index 000000000000..f346663157a1 --- /dev/null +++ b/csharp/codeql-extractor.yml @@ -0,0 +1,18 @@ +name: "csharp" +display_name: "C#" +version: 1.22.1 +column_kind: "utf16" +extra_env_vars: + DOTNET_GENERATE_ASPNET_CERTIFICATE: "false" + COR_ENABLE_PROFILING: "1" + COR_PROFILER: "{A3C70A64-7D41-4A94-A3F6-FD47D9259997}" + COR_PROFILER_PATH_64: "${env.CODEQL_EXTRACTOR_CSHARP_ROOT}/tools/${env.CODEQL_PLATFORM}/clrtracer64${env.CODEQL_PLATFORM_DLL_EXTENSION}" + CORECLR_ENABLE_PROFILING: "1" + CORECLR_PROFILER: "{A3C70A64-7D41-4A94-A3F6-FD47D9259997}" + CORECLR_PROFILER_PATH_64: "${env.CODEQL_EXTRACTOR_CSHARP_ROOT}/tools/${env.CODEQL_PLATFORM}/clrtracer64${env.CODEQL_PLATFORM_DLL_EXTENSION}" +file_types: + - name: cs + display_name: C# sources + extensions: + - .cs +legacy_qltest_extraction: true diff --git a/csharp/extractor/Semmle.Extraction.CIL.Driver/ExtractorOptions.cs b/csharp/extractor/Semmle.Extraction.CIL.Driver/ExtractorOptions.cs index 2c032c699f34..9964ff5bf0cd 100644 --- a/csharp/extractor/Semmle.Extraction.CIL.Driver/ExtractorOptions.cs +++ b/csharp/extractor/Semmle.Extraction.CIL.Driver/ExtractorOptions.cs @@ -14,11 +14,11 @@ namespace Semmle.Extraction.CIL.Driver /// Information about a single assembly. /// In particular, provides references between assemblies. /// - class AssemblyInfo + internal class AssemblyInfo { - public override string ToString() => filename; + public override string ToString() => Filename; - static AssemblyName CreateAssemblyName(MetadataReader mdReader, StringHandle name, System.Version version, StringHandle culture) + private static AssemblyName CreateAssemblyName(MetadataReader mdReader, StringHandle name, System.Version version, StringHandle culture) { var cultureString = mdReader.GetString(culture); @@ -34,7 +34,7 @@ static AssemblyName CreateAssemblyName(MetadataReader mdReader, StringHandle nam return assemblyName; } - static AssemblyName CreateAssemblyName(MetadataReader mdReader, AssemblyReference ar) + private static AssemblyName CreateAssemblyName(MetadataReader mdReader, AssemblyReference ar) { var an = CreateAssemblyName(mdReader, ar.Name, ar.Version, ar.Culture); if (!ar.PublicKeyOrToken.IsNil) @@ -42,7 +42,7 @@ static AssemblyName CreateAssemblyName(MetadataReader mdReader, AssemblyReferenc return an; } - static AssemblyName CreateAssemblyName(MetadataReader mdReader, AssemblyDefinition ad) + private static AssemblyName CreateAssemblyName(MetadataReader mdReader, AssemblyDefinition ad) { var an = CreateAssemblyName(mdReader, ad.Name, ad.Version, ad.Culture); if (!ad.PublicKey.IsNil) @@ -50,47 +50,51 @@ static AssemblyName CreateAssemblyName(MetadataReader mdReader, AssemblyDefiniti return an; } + /// + /// Initializes a new instance of the class. + /// + /// Path of the assembly. + /// + /// Thrown when the input file is not a valid assembly. + /// public AssemblyInfo(string path) { - filename = path; + Filename = path; // Attempt to open the file and see if it's a valid assembly. - using (var stream = File.OpenRead(path)) - using (var peReader = new PEReader(stream)) + using var stream = File.OpenRead(path); + using var peReader = new PEReader(stream); + try { - try - { - isAssembly = peReader.HasMetadata; - if (!isAssembly) return; + if (!peReader.HasMetadata) + throw new InvalidAssemblyException(); - var mdReader = peReader.GetMetadataReader(); + var mdReader = peReader.GetMetadataReader(); - isAssembly = mdReader.IsAssembly; - if (!mdReader.IsAssembly) return; + if (!mdReader.IsAssembly) + throw new InvalidAssemblyException(); - // Get our own assembly name - name = CreateAssemblyName(mdReader, mdReader.GetAssemblyDefinition()); + // Get our own assembly name + Name = CreateAssemblyName(mdReader, mdReader.GetAssemblyDefinition()); - references = mdReader.AssemblyReferences. - Select(r => mdReader.GetAssemblyReference(r)). - Select(ar => CreateAssemblyName(mdReader, ar)). - ToArray(); - } - catch (System.BadImageFormatException) - { - // This failed on one of the Roslyn tests that includes - // a deliberately malformed assembly. - // In this case, we just skip the extraction of this assembly. - isAssembly = false; - } + References = mdReader.AssemblyReferences + .Select(r => mdReader.GetAssemblyReference(r)) + .Select(ar => CreateAssemblyName(mdReader, ar)) + .ToArray(); + } + catch (System.BadImageFormatException) + { + // This failed on one of the Roslyn tests that includes + // a deliberately malformed assembly. + // In this case, we just skip the extraction of this assembly. + throw new InvalidAssemblyException(); } } - public readonly AssemblyName name; - public readonly string filename; - public bool extract; - public readonly bool isAssembly; - public readonly AssemblyName[] references; + public AssemblyName Name { get; } + public string Filename { get; } + public bool Extract { get; set; } + public AssemblyName[] References { get; } } /// @@ -98,37 +102,42 @@ public AssemblyInfo(string path) /// Resolves references between assemblies and determines which /// additional assemblies need to be extracted. /// - class AssemblyList + internal class AssemblyList { - class AssemblyNameComparer : IEqualityComparer + private class AssemblyNameComparer : IEqualityComparer { - bool IEqualityComparer.Equals(AssemblyName x, AssemblyName y) => - x.Name == y.Name && x.Version == y.Version; + bool IEqualityComparer.Equals(AssemblyName? x, AssemblyName? y) => + object.ReferenceEquals(x, y) || + x?.Name == y?.Name && x?.Version == y?.Version; int IEqualityComparer.GetHashCode(AssemblyName obj) => - obj.Name.GetHashCode() + 7 * obj.Version.GetHashCode(); + (obj.Name, obj.Version).GetHashCode(); } - readonly Dictionary assembliesRead = new Dictionary(new AssemblyNameComparer()); + private readonly Dictionary assembliesRead = new Dictionary(new AssemblyNameComparer()); public void AddFile(string assemblyPath, bool extractAll) { if (!filesAnalyzed.Contains(assemblyPath)) { filesAnalyzed.Add(assemblyPath); - var info = new AssemblyInfo(assemblyPath); - if (info.isAssembly) + try { - info.extract = extractAll; - if (!assembliesRead.ContainsKey(info.name)) - assembliesRead.Add(info.name, info); + var info = new AssemblyInfo(assemblyPath) + { + Extract = extractAll + }; + if (!assembliesRead.ContainsKey(info.Name)) + assembliesRead.Add(info.Name, info); } + catch (InvalidAssemblyException) + { } } } - public IEnumerable AssembliesToExtract => assembliesRead.Values.Where(info => info.extract); + public IEnumerable AssembliesToExtract => assembliesRead.Values.Where(info => info.Extract); - IEnumerable AssembliesToReference => AssembliesToExtract.SelectMany(info => info.references); + private IEnumerable AssembliesToReference => AssembliesToExtract.SelectMany(info => info.References); public void ResolveReferences() { @@ -137,33 +146,47 @@ public void ResolveReferences() while (assembliesToReference.Any()) { var item = assembliesToReference.Pop(); - AssemblyInfo info; - if (assembliesRead.TryGetValue(item, out info)) + if (assembliesRead.TryGetValue(item, out var info)) { - if (!info.extract) + if (!info.Extract) { - info.extract = true; - foreach (var reference in info.references) + info.Extract = true; + foreach (var reference in info.References) assembliesToReference.Push(reference); } } else { - missingReferences.Add(item); + MissingReferences.Add(item); } } } - readonly HashSet filesAnalyzed = new HashSet(); - public readonly HashSet missingReferences = new HashSet(); + private readonly HashSet filesAnalyzed = new HashSet(); + public HashSet MissingReferences {get;} = new HashSet(); } /// /// Parses the command line and collates a list of DLLs/EXEs to extract. /// - class ExtractorOptions + internal class ExtractorOptions { - readonly AssemblyList assemblyList = new AssemblyList(); + private readonly AssemblyList assemblyList = new AssemblyList(); + + public ExtractorOptions(string[] args) + { + Verbosity = Verbosity.Info; + Threads = System.Environment.ProcessorCount; + PDB = true; + TrapCompression = TrapWriter.CompressionMode.Gzip; + + ParseArgs(args); + + AddFrameworkDirectories(false); + + assemblyList.ResolveReferences(); + AssembliesToExtract = assemblyList.AssembliesToExtract.ToArray(); + } public void AddDirectory(string directory, bool extractAll) { @@ -175,7 +198,7 @@ public void AddDirectory(string directory, bool extractAll) } } - void AddFrameworkDirectories(bool extractAll) + private void AddFrameworkDirectories(bool extractAll) { AddDirectory(RuntimeEnvironment.GetRuntimeDirectory(), extractAll); } @@ -186,13 +209,18 @@ void AddFrameworkDirectories(bool extractAll) public bool PDB { get; private set; } public TrapWriter.CompressionMode TrapCompression { get; private set; } - void AddFileOrDirectory(string path) + private void AddFileOrDirectory(string path) { path = Path.GetFullPath(path); if (File.Exists(path)) { assemblyList.AddFile(path, true); - AddDirectory(Path.GetDirectoryName(path), false); + var directory = Path.GetDirectoryName(path); + if (directory is null) + { + throw new InternalError($"Directory of path '{path}' is null"); + } + AddDirectory(directory, false); } else if (Directory.Exists(path)) { @@ -200,70 +228,52 @@ void AddFileOrDirectory(string path) } } - void ResolveReferences() - { - assemblyList.ResolveReferences(); - AssembliesToExtract = assemblyList.AssembliesToExtract.ToArray(); - } - - public IEnumerable AssembliesToExtract { get; private set; } + public IEnumerable AssembliesToExtract { get; } /// /// Gets the assemblies that were referenced but were not available to be /// extracted. This is not an error, it just means that the database is not /// as complete as it could be. /// - public IEnumerable MissingReferences => assemblyList.missingReferences; + public IEnumerable MissingReferences => assemblyList.MissingReferences; - public static ExtractorOptions ParseCommandLine(string[] args) + private void ParseArgs(string[] args) { - var options = new ExtractorOptions(); - options.Verbosity = Verbosity.Info; - options.Threads = System.Environment.ProcessorCount; - options.PDB = true; - options.TrapCompression = TrapWriter.CompressionMode.Gzip; - foreach (var arg in args) { if (arg == "--verbose") { - options.Verbosity = Verbosity.All; + Verbosity = Verbosity.All; } else if (arg == "--silent") { - options.Verbosity = Verbosity.Off; + Verbosity = Verbosity.Off; } else if (arg.StartsWith("--verbosity:")) { - options.Verbosity = (Verbosity)int.Parse(arg.Substring(12)); + Verbosity = (Verbosity)int.Parse(arg.Substring(12)); } else if (arg == "--dotnet") { - options.AddFrameworkDirectories(true); + AddFrameworkDirectories(true); } else if (arg == "--nocache") { - options.NoCache = true; + NoCache = true; } else if (arg.StartsWith("--threads:")) { - options.Threads = int.Parse(arg.Substring(10)); + Threads = int.Parse(arg.Substring(10)); } else if (arg == "--no-pdb") { - options.PDB = false; + PDB = false; } else { - options.AddFileOrDirectory(arg); + AddFileOrDirectory(arg); } } - - options.AddFrameworkDirectories(false); - options.ResolveReferences(); - - return options; } - } } diff --git a/csharp/extractor/Semmle.Extraction.CIL.Driver/InvalidAssemblyException.cs b/csharp/extractor/Semmle.Extraction.CIL.Driver/InvalidAssemblyException.cs new file mode 100644 index 000000000000..2686442a08d5 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CIL.Driver/InvalidAssemblyException.cs @@ -0,0 +1,7 @@ +using System; + +namespace Semmle.Extraction.CIL.Driver +{ + public class InvalidAssemblyException : Exception + { } +} diff --git a/csharp/extractor/Semmle.Extraction.CIL.Driver/Program.cs b/csharp/extractor/Semmle.Extraction.CIL.Driver/Program.cs index 5a63425ea5e4..53542c970e9d 100644 --- a/csharp/extractor/Semmle.Extraction.CIL.Driver/Program.cs +++ b/csharp/extractor/Semmle.Extraction.CIL.Driver/Program.cs @@ -1,15 +1,14 @@ using System; using System.Linq; using System.Threading.Tasks; -using System.IO; using Semmle.Util.Logging; using System.Diagnostics; namespace Semmle.Extraction.CIL.Driver { - class Program + public static class Program { - static void DisplayHelp() + private static void DisplayHelp() { Console.WriteLine("CIL command line extractor"); Console.WriteLine(); @@ -21,18 +20,16 @@ static void DisplayHelp() Console.WriteLine(" path A directory/dll/exe to analyze"); } - static void ExtractAssembly(Layout layout, string assemblyPath, ILogger logger, bool nocache, bool extractPdbs, TrapWriter.CompressionMode trapCompression) + private static void ExtractAssembly(Layout layout, string assemblyPath, ILogger logger, bool nocache, bool extractPdbs, TrapWriter.CompressionMode trapCompression) { - string trapFile; - bool extracted; var sw = new Stopwatch(); sw.Start(); - Entities.Assembly.ExtractCIL(layout, assemblyPath, logger, nocache, extractPdbs, trapCompression, out trapFile, out extracted); + Entities.Assembly.ExtractCIL(layout, assemblyPath, logger, nocache, extractPdbs, trapCompression, out _, out _); sw.Stop(); logger.Log(Severity.Info, " {0} ({1})", assemblyPath, sw.Elapsed); } - static void Main(string[] args) + public static void Main(string[] args) { if (args.Length == 0) { @@ -40,14 +37,15 @@ static void Main(string[] args) return; } - var options = ExtractorOptions.ParseCommandLine(args); + var options = new ExtractorOptions(args); var layout = new Layout(); - var logger = new ConsoleLogger(options.Verbosity); + using var logger = new ConsoleLogger(options.Verbosity); - var actions = options. - AssembliesToExtract.Select(asm => asm.filename). - Select(filename => () => ExtractAssembly(layout, filename, logger, options.NoCache, options.PDB, options.TrapCompression)). - ToArray(); + var actions = options.AssembliesToExtract + .Select(asm => asm.Filename) + .Select(filename => + () => ExtractAssembly(layout, filename, logger, options.NoCache, options.PDB, options.TrapCompression)) + .ToArray(); foreach (var missingRef in options.MissingReferences) logger.Log(Severity.Info, " Missing assembly " + missingRef); diff --git a/csharp/extractor/Semmle.Extraction.CIL.Driver/Semmle.Extraction.CIL.Driver.csproj b/csharp/extractor/Semmle.Extraction.CIL.Driver/Semmle.Extraction.CIL.Driver.csproj index e7f87c7b36b3..67e40dae2d87 100644 --- a/csharp/extractor/Semmle.Extraction.CIL.Driver/Semmle.Extraction.CIL.Driver.csproj +++ b/csharp/extractor/Semmle.Extraction.CIL.Driver/Semmle.Extraction.CIL.Driver.csproj @@ -2,11 +2,12 @@ Exe - netcoreapp3.0 + netcoreapp3.1 Semmle.Extraction.CIL.Driver Semmle.Extraction.CIL.Driver false win-x64;linux-x64;osx-x64 + enable diff --git a/csharp/extractor/Semmle.Extraction.CIL/CachedFunction.cs b/csharp/extractor/Semmle.Extraction.CIL/CachedFunction.cs index 3bbc386a691e..4f7ce5a7ef18 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/CachedFunction.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/CachedFunction.cs @@ -7,21 +7,21 @@ namespace Semmle.Extraction.CIL /// A factory and a cache for mapping source entities to target entities. /// Could be considered as a memoizer. /// - /// The type of the source. - /// The type of the generated object. - public class CachedFunction + /// The type of the source. + /// The type of the generated object. + public class CachedFunction where TSrc : notnull { - readonly Func generator; - readonly Dictionary cache; + private readonly Func generator; + private readonly Dictionary cache; /// /// Initializes the factory with a given mapping. /// /// The mapping. - public CachedFunction(Func g) + public CachedFunction(Func g) { generator = g; - cache = new Dictionary(); + cache = new Dictionary(); } /// @@ -30,12 +30,11 @@ public CachedFunction(Func g) /// /// The source object. /// The created object. - public TargetType this[SrcType src] + public TTarget this[TSrc src] { get { - TargetType result; - if (!cache.TryGetValue(src, out result)) + if (!cache.TryGetValue(src, out var result)) { result = generator(src); cache[src] = result; @@ -48,22 +47,22 @@ public TargetType this[SrcType src] /// /// A factory for mapping a pair of source entities to a target entity. /// - /// Source entity type 1. - /// Source entity type 2. - /// The target type. - public class CachedFunction + /// Source entity type 1. + /// Source entity type 2. + /// The target type. + public class CachedFunction { - readonly CachedFunction<(Src1, Src2), Target> factory; + private readonly CachedFunction<(TSrcEntity1, TSrcEntity2), TTarget> factory; /// /// Initializes the factory with a given mapping. /// /// The mapping. - public CachedFunction(Func g) + public CachedFunction(Func g) { - factory = new CachedFunction<(Src1, Src2), Target>(p => g(p.Item1, p.Item2)); + factory = new CachedFunction<(TSrcEntity1, TSrcEntity2), TTarget>(p => g(p.Item1, p.Item2)); } - public Target this[Src1 s1, Src2 s2] => factory[(s1, s2)]; + public TTarget this[TSrcEntity1 s1, TSrcEntity2 s2] => factory[(s1, s2)]; } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Context.cs b/csharp/extractor/Semmle.Extraction.CIL/Context.cs index 79fb8b7a8d49..ac6a5f52dd96 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Context.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Context.cs @@ -12,51 +12,57 @@ namespace Semmle.Extraction.CIL /// Adds additional context that is specific for CIL extraction. /// One context = one DLL/EXE. /// - partial class Context : IDisposable + public sealed partial class Context : IDisposable { - public Extraction.Context cx; - readonly FileStream stream; - public readonly MetadataReader mdReader; - public readonly PEReader peReader; - public readonly string assemblyPath; - public Entities.Assembly assembly; - public PDB.IPdb pdb; + private readonly FileStream stream; + private Entities.Assembly? assemblyNull; + + public Extraction.Context Cx { get; } + public MetadataReader MdReader { get; } + public PEReader PeReader { get; } + public string AssemblyPath { get; } + public Entities.Assembly Assembly + { + get { return assemblyNull!; } + set { assemblyNull = value; } + } + public PDB.IPdb? Pdb { get; } public Context(Extraction.Context cx, string assemblyPath, bool extractPdbs) { - this.cx = cx; - this.assemblyPath = assemblyPath; + this.Cx = cx; + this.AssemblyPath = assemblyPath; stream = File.OpenRead(assemblyPath); - peReader = new PEReader(stream, PEStreamOptions.PrefetchEntireImage); - mdReader = peReader.GetMetadataReader(); + PeReader = new PEReader(stream, PEStreamOptions.PrefetchEntireImage); + MdReader = PeReader.GetMetadataReader(); TypeSignatureDecoder = new Entities.TypeSignatureDecoder(this); globalNamespace = new Lazy(() => Populate(new Entities.Namespace(this, "", null))); systemNamespace = new Lazy(() => Populate(new Entities.Namespace(this, "System"))); genericHandleFactory = new CachedFunction(CreateGenericHandle); - namespaceFactory = new CachedFunction(n => CreateNamespace(mdReader.GetString(n))); + namespaceFactory = new CachedFunction(n => CreateNamespace(MdReader.GetString(n))); namespaceDefinitionFactory = new CachedFunction(CreateNamespace); sourceFiles = new CachedFunction(path => new Entities.PdbSourceFile(this, path)); - folders = new CachedFunction(path => new Entities.Folder(this, path)); + folders = new CachedFunction(path => new Entities.Folder(this, path)); sourceLocations = new CachedFunction(location => new Entities.PdbSourceLocation(this, location)); defaultGenericContext = new EmptyContext(this); if (extractPdbs) { - pdb = PDB.PdbReader.Create(assemblyPath, peReader); - if (pdb != null) + Pdb = PDB.PdbReader.Create(assemblyPath, PeReader); + if (Pdb != null) { cx.Extractor.Logger.Log(Util.Logging.Severity.Info, string.Format("Found PDB information for {0}", assemblyPath)); } } } - void IDisposable.Dispose() + public void Dispose() { - if (pdb != null) - pdb.Dispose(); - peReader.Dispose(); + if (Pdb != null) + Pdb.Dispose(); + PeReader.Dispose(); stream.Dispose(); } @@ -74,14 +80,14 @@ public void Extract(IExtractedEntity entity) public void WriteAssemblyPrefix(TextWriter trapFile) { - var def = mdReader.GetAssemblyDefinition(); + var def = MdReader.GetAssemblyDefinition(); trapFile.Write(GetString(def.Name)); trapFile.Write('_'); trapFile.Write(def.Version.ToString()); trapFile.Write("::"); } - public readonly Entities.TypeSignatureDecoder TypeSignatureDecoder; + public Entities.TypeSignatureDecoder TypeSignatureDecoder { get; } /// /// A type used to signify something we can't handle yet. @@ -105,9 +111,9 @@ public Entities.Type ErrorType /// /// The handle of the method. /// The debugging information, or null if the information could not be located. - public PDB.IMethod GetMethodDebugInformation(MethodDefinitionHandle handle) + public PDB.IMethod? GetMethodDebugInformation(MethodDefinitionHandle handle) { - return pdb == null ? null : pdb.GetMethod(handle.ToDebugInformationHandle()); + return Pdb?.GetMethod(handle.ToDebugInformationHandle()); } } @@ -117,15 +123,16 @@ public PDB.IMethod GetMethodDebugInformation(MethodDefinitionHandle handle) /// public abstract class GenericContext { - public Context cx; + public Context Cx { get; } - public GenericContext(Context cx) + protected GenericContext(Context cx) { - this.cx = cx; + this.Cx = cx; } /// - /// The list of generic type parameters. + /// The list of generic type parameters, including type parameters of + /// containing types. /// public abstract IEnumerable TypeParameters { get; } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Assembly.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Assembly.cs index 255d37699f24..6842577ce879 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Assembly.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Assembly.cs @@ -5,6 +5,7 @@ using System; using Semmle.Extraction.Entities; using System.IO; +using Semmle.Util; namespace Semmle.Extraction.CIL.Entities { @@ -12,7 +13,7 @@ public interface ILocation : IEntity { } - interface IAssembly : ILocation + internal interface IAssembly : ILocation { } @@ -21,68 +22,70 @@ interface IAssembly : ILocation /// public class Assembly : LabelledEntity, IAssembly { - readonly File file; - readonly AssemblyName assemblyName; + private readonly File file; + private readonly AssemblyName assemblyName; public Assembly(Context cx) : base(cx) { - cx.assembly = this; - var def = cx.mdReader.GetAssemblyDefinition(); + cx.Assembly = this; + var def = cx.MdReader.GetAssemblyDefinition(); - assemblyName = new AssemblyName(); - assemblyName.Name = cx.mdReader.GetString(def.Name); - assemblyName.Version = def.Version; - assemblyName.CultureInfo = new CultureInfo(cx.mdReader.GetString(def.Culture)); + assemblyName = new AssemblyName + { + Name = cx.MdReader.GetString(def.Name), + Version = def.Version, + CultureInfo = new CultureInfo(cx.MdReader.GetString(def.Culture)) + }; if (!def.PublicKey.IsNil) - assemblyName.SetPublicKey(cx.mdReader.GetBlobBytes(def.PublicKey)); + assemblyName.SetPublicKey(cx.MdReader.GetBlobBytes(def.PublicKey)); - file = new File(cx, cx.assemblyPath); + file = new File(cx, cx.AssemblyPath); } public override void WriteId(TextWriter trapFile) { trapFile.Write(FullName); trapFile.Write("#file:///"); - trapFile.Write(cx.assemblyPath.Replace("\\", "/")); + trapFile.Write(Cx.AssemblyPath.Replace("\\", "/")); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - return GetType() == obj.GetType() && Equals(file, ((Assembly)obj).file); + return GetType() == obj?.GetType() && Equals(file, ((Assembly)obj).file); } public override int GetHashCode() => 7 * file.GetHashCode(); public override string IdSuffix => ";assembly"; - string FullName => assemblyName.GetPublicKey() is null ? assemblyName.FullName + ", PublicKeyToken=null" : assemblyName.FullName; + private string FullName => assemblyName.GetPublicKey() is null ? assemblyName.FullName + ", PublicKeyToken=null" : assemblyName.FullName; public override IEnumerable Contents { get { yield return file; - yield return Tuples.assemblies(this, file, FullName, assemblyName.Name, assemblyName.Version.ToString()); + yield return Tuples.assemblies(this, file, FullName, assemblyName.Name ?? string.Empty, assemblyName.Version?.ToString() ?? string.Empty); - if (cx.pdb != null) + if (Cx.Pdb != null) { - foreach (var f in cx.pdb.SourceFiles) + foreach (var f in Cx.Pdb.SourceFiles) { - yield return cx.CreateSourceFile(f); + yield return Cx.CreateSourceFile(f); } } - foreach (var handle in cx.mdReader.TypeDefinitions) + foreach (var handle in Cx.MdReader.TypeDefinitions) { - IExtractionProduct product = null; + IExtractionProduct? product = null; try { - product = cx.Create(handle); + product = Cx.Create(handle); } catch (InternalError e) { - cx.cx.ExtractionError("Error processing type definition", e.Message, GeneratedLocation.Create(cx.cx), e.StackTrace); + Cx.Cx.ExtractionError("Error processing type definition", e.Message, GeneratedLocation.Create(Cx.Cx), e.StackTrace); } // Limitation of C#: Cannot yield return inside a try-catch. @@ -90,16 +93,16 @@ public override IEnumerable Contents yield return product; } - foreach (var handle in cx.mdReader.MethodDefinitions) + foreach (var handle in Cx.MdReader.MethodDefinitions) { - IExtractionProduct product = null; + IExtractionProduct? product = null; try { - product = cx.Create(handle); + product = Cx.Create(handle); } catch (InternalError e) { - cx.cx.ExtractionError("Error processing bytecode", e.Message, GeneratedLocation.Create(cx.cx), e.StackTrace); + Cx.Cx.ExtractionError("Error processing bytecode", e.Message, GeneratedLocation.Create(Cx.Cx), e.StackTrace); } if (product != null) @@ -108,13 +111,11 @@ public override IEnumerable Contents } } - static void ExtractCIL(Extraction.Context cx, string assemblyPath, bool extractPdbs) + private static void ExtractCIL(Extraction.Context cx, string assemblyPath, bool extractPdbs) { - using (var cilContext = new Context(cx, assemblyPath, extractPdbs)) - { - cilContext.Populate(new Assembly(cilContext)); - cilContext.cx.PopulateAll(); - } + using var cilContext = new Context(cx, assemblyPath, extractPdbs); + cilContext.Populate(new Assembly(cilContext)); + cilContext.Cx.PopulateAll(); } /// @@ -134,17 +135,18 @@ public static void ExtractCIL(Layout layout, string assemblyPath, ILogger logger extracted = false; try { - var extractor = new Extractor(false, assemblyPath, logger); - var project = layout.LookupProjectOrDefault(assemblyPath); - using (var trapWriter = project.CreateTrapWriter(logger, assemblyPath + ".cil", true, trapCompression)) + var canonicalPathCache = CanonicalPathCache.Create(logger, 1000); + var pathTransformer = new PathTransformer(canonicalPathCache); + var extractor = new Extractor(false, assemblyPath, logger, pathTransformer); + var transformedAssemblyPath = pathTransformer.Transform(assemblyPath); + var project = layout.LookupProjectOrDefault(transformedAssemblyPath); + using var trapWriter = project.CreateTrapWriter(logger, transformedAssemblyPath.WithSuffix(".cil"), true, trapCompression); + trapFile = trapWriter.TrapFile; + if (nocache || !System.IO.File.Exists(trapFile)) { - trapFile = trapWriter.TrapFile; - if (nocache || !System.IO.File.Exists(trapFile)) - { - var cx = extractor.CreateContext(null, trapWriter, null); - ExtractCIL(cx, assemblyPath, extractPdbs); - extracted = true; - } + var cx = extractor.CreateContext(null, trapWriter, null, false); + ExtractCIL(cx, assemblyPath, extractPdbs); + extracted = true; } } catch (Exception ex) // lgtm[cs/catch-of-all-exceptions] diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Attribute.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Attribute.cs index ed3e866c16fb..d199fb31195a 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Attribute.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Attribute.cs @@ -7,27 +7,27 @@ namespace Semmle.Extraction.CIL.Entities /// /// A CIL attribute. /// - interface IAttribute : IExtractedEntity + internal interface IAttribute : IExtractedEntity { } /// /// Entity representing a CIL attribute. /// - sealed class Attribute : UnlabelledEntity, IAttribute + internal sealed class Attribute : UnlabelledEntity, IAttribute { - readonly CustomAttributeHandle handle; - readonly CustomAttribute attrib; - readonly IEntity @object; + private readonly CustomAttributeHandle handle; + private readonly CustomAttribute attrib; + private readonly IEntity @object; public Attribute(Context cx, IEntity @object, CustomAttributeHandle handle) : base(cx) { - attrib = cx.mdReader.GetCustomAttribute(handle); + attrib = cx.MdReader.GetCustomAttribute(handle); this.handle = handle; this.@object = @object; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is Attribute attribute && handle.Equals(attribute.handle); } @@ -38,7 +38,7 @@ public override IEnumerable Contents { get { - var constructor = (Method)cx.Create(attrib.Constructor); + var constructor = (Method)Cx.Create(attrib.Constructor); yield return constructor; yield return Tuples.cil_attribute(this, @object, constructor); @@ -47,7 +47,7 @@ public override IEnumerable Contents try { - decoded = attrib.DecodeValue(new CustomAttributeDecoder(cx)); + decoded = attrib.DecodeValue(new CustomAttributeDecoder(Cx)); } catch (NotImplementedException) { @@ -55,16 +55,18 @@ public override IEnumerable Contents yield break; } - for (int index = 0; index < decoded.FixedArguments.Length; ++index) + for (var index = 0; index < decoded.FixedArguments.Length; ++index) { - object value = decoded.FixedArguments[index].Value; - yield return Tuples.cil_attribute_positional_argument(this, index, value == null ? "null" : value.ToString()); + var value = decoded.FixedArguments[index].Value; + var stringValue = value?.ToString(); + yield return Tuples.cil_attribute_positional_argument(this, index, stringValue ?? "null"); } foreach (var p in decoded.NamedArguments) { - object value = p.Value; - yield return Tuples.cil_attribute_named_argument(this, p.Name, value == null ? "null" : value.ToString()); + var value = p.Value; + var stringValue = value?.ToString(); + yield return Tuples.cil_attribute_named_argument(this, p.Name, stringValue ?? "null"); } } } @@ -82,9 +84,9 @@ public static IEnumerable Populate(Context cx, IEntity @obje /// Helper class to decode the attribute structure. /// Note that there are some unhandled cases that should be fixed in due course. /// - class CustomAttributeDecoder : ICustomAttributeTypeProvider + internal class CustomAttributeDecoder : ICustomAttributeTypeProvider { - readonly Context cx; + private readonly Context cx; public CustomAttributeDecoder(Context cx) { this.cx = cx; } public Type GetPrimitiveType(PrimitiveTypeCode typeCode) => cx.Create(typeCode); diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Event.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Event.cs index da33b9a63d5c..e9a87c3c96c1 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Event.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Event.cs @@ -7,36 +7,36 @@ namespace Semmle.Extraction.CIL.Entities /// /// An event. /// - interface IEvent : IExtractedEntity + internal interface IEvent : IExtractedEntity { } /// /// An event entity. /// - sealed class Event : LabelledEntity, IEvent + internal sealed class Event : LabelledEntity, IEvent { - readonly EventDefinitionHandle handle; - readonly Type parent; - readonly EventDefinition ed; + private readonly EventDefinitionHandle handle; + private readonly Type parent; + private readonly EventDefinition ed; public Event(Context cx, Type parent, EventDefinitionHandle handle) : base(cx) { this.handle = handle; this.parent = parent; - ed = cx.mdReader.GetEventDefinition(handle); + ed = cx.MdReader.GetEventDefinition(handle); } public override void WriteId(TextWriter trapFile) { parent.WriteId(trapFile); trapFile.Write('.'); - trapFile.Write(cx.ShortName(ed.Name)); + trapFile.Write(Cx.ShortName(ed.Name)); } public override string IdSuffix => ";cil-event"; - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is Event e && handle.Equals(e.handle); } @@ -47,34 +47,34 @@ public override IEnumerable Contents { get { - var signature = (Type)cx.CreateGeneric(parent, ed.Type); + var signature = (Type)Cx.CreateGeneric(parent, ed.Type); yield return signature; - yield return Tuples.cil_event(this, parent, cx.ShortName(ed.Name), signature); + yield return Tuples.cil_event(this, parent, Cx.ShortName(ed.Name), signature); var accessors = ed.GetAccessors(); if (!accessors.Adder.IsNil) { - var adder = (Method)cx.CreateGeneric(parent, accessors.Adder); + var adder = (Method)Cx.CreateGeneric(parent, accessors.Adder); yield return adder; yield return Tuples.cil_adder(this, adder); } if (!accessors.Remover.IsNil) { - var remover = (Method)cx.CreateGeneric(parent, accessors.Remover); + var remover = (Method)Cx.CreateGeneric(parent, accessors.Remover); yield return remover; yield return Tuples.cil_remover(this, remover); } if (!accessors.Raiser.IsNil) { - var raiser = (Method)cx.CreateGeneric(parent, accessors.Raiser); + var raiser = (Method)Cx.CreateGeneric(parent, accessors.Raiser); yield return raiser; yield return Tuples.cil_raiser(this, raiser); } - foreach (var c in Attribute.Populate(cx, this, ed.GetCustomAttributes())) + foreach (var c in Attribute.Populate(Cx, this, ed.GetCustomAttributes())) yield return c; } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/ExceptionRegion.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/ExceptionRegion.cs index 57035d993af0..e775ba56dd48 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/ExceptionRegion.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/ExceptionRegion.cs @@ -2,22 +2,22 @@ namespace Semmle.Extraction.CIL.Entities { - interface IExceptionRegion : IExtractedEntity + internal interface IExceptionRegion : IExtractedEntity { } /// /// An exception region entity. /// - class ExceptionRegion : UnlabelledEntity, IExceptionRegion + internal class ExceptionRegion : UnlabelledEntity, IExceptionRegion { - readonly GenericContext gc; - readonly MethodImplementation method; - readonly int index; - readonly System.Reflection.Metadata.ExceptionRegion r; - readonly Dictionary jump_table; + private readonly GenericContext gc; + private readonly MethodImplementation method; + private readonly int index; + private readonly System.Reflection.Metadata.ExceptionRegion r; + private readonly Dictionary jump_table; - public ExceptionRegion(GenericContext gc, MethodImplementation method, int index, System.Reflection.Metadata.ExceptionRegion r, Dictionary jump_table) : base(gc.cx) + public ExceptionRegion(GenericContext gc, MethodImplementation method, int index, System.Reflection.Metadata.ExceptionRegion r, Dictionary jump_table) : base(gc.Cx) { this.gc = gc; this.method = method; @@ -30,22 +30,19 @@ public override IEnumerable Contents { get { - IInstruction try_start, try_end, handler_start; - if (!jump_table.TryGetValue(r.TryOffset, out try_start)) + if (!jump_table.TryGetValue(r.TryOffset, out var try_start)) throw new InternalError("Failed to retrieve handler"); - if (!jump_table.TryGetValue(r.TryOffset + r.TryLength, out try_end)) + if (!jump_table.TryGetValue(r.TryOffset + r.TryLength, out var try_end)) throw new InternalError("Failed to retrieve handler"); - if (!jump_table.TryGetValue(r.HandlerOffset, out handler_start)) + if (!jump_table.TryGetValue(r.HandlerOffset, out var handler_start)) throw new InternalError("Failed to retrieve handler"); - yield return Tuples.cil_handler(this, method, index, (int)r.Kind, try_start, try_end, handler_start); if (r.FilterOffset != -1) { - IInstruction filter_start; - if (!jump_table.TryGetValue(r.FilterOffset, out filter_start)) + if (!jump_table.TryGetValue(r.FilterOffset, out var filter_start)) throw new InternalError("ExceptionRegion filter clause"); yield return Tuples.cil_handler_filter(this, filter_start); @@ -53,7 +50,7 @@ public override IEnumerable Contents if (!r.CatchType.IsNil) { - var catchType = (Type)cx.CreateGeneric(gc, r.CatchType); + var catchType = (Type)Cx.CreateGeneric(gc, r.CatchType); yield return catchType; yield return Tuples.cil_handler_type(this, catchType); } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Field.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Field.cs index 400b48fc07ea..de34a28e0d4a 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Field.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Field.cs @@ -13,28 +13,26 @@ namespace Semmle.Extraction.CIL.Entities /// An entity represting a member. /// Used to type tuples correctly. /// - interface IMember : IExtractedEntity + internal interface IMember : IExtractedEntity { } /// /// An entity representing a field. /// - interface IField : IMember + internal interface IField : IMember { } /// /// An entity representing a field. /// - abstract class Field : GenericContext, IField + internal abstract class Field : GenericContext, IField { protected Field(Context cx) : base(cx) { } - public bool NeedsPopulation { get { return true; } } - public Label Label { get; set; } public void WriteId(TextWriter trapFile) @@ -48,11 +46,11 @@ public void WriteQuotedId(TextWriter trapFile) { trapFile.Write("@\""); WriteId(trapFile); - trapFile.Write(IdSuffix); + trapFile.Write(idSuffix); trapFile.Write('\"'); } - public string IdSuffix => ";cil-field"; + private const string idSuffix = ";cil-field"; public abstract string Name { get; } @@ -60,7 +58,7 @@ public void WriteQuotedId(TextWriter trapFile) public Location ReportingLocation => throw new NotImplementedException(); - abstract public Type Type { get; } + public abstract Type Type { get; } public virtual IEnumerable Contents { @@ -78,20 +76,18 @@ public void Extract(Context cx2) TrapStackBehaviour IEntity.TrapStackBehaviour => TrapStackBehaviour.NoLabel; } - sealed class DefinitionField : Field + internal sealed class DefinitionField : Field { - readonly Handle handle; - readonly FieldDefinition fd; - readonly GenericContext gc; + private readonly Handle handle; + private readonly FieldDefinition fd; - public DefinitionField(GenericContext gc, FieldDefinitionHandle handle) : base(gc.cx) + public DefinitionField(Context cx, FieldDefinitionHandle handle) : base(cx) { this.handle = handle; - this.gc = gc; - fd = cx.mdReader.GetFieldDefinition(handle); + fd = Cx.MdReader.GetFieldDefinition(handle); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is DefinitionField field && handle.Equals(field.handle); } @@ -102,7 +98,7 @@ public override IEnumerable Contents { get { - yield return Tuples.metadata_handle(this, cx.assembly, MetadataTokens.GetToken(handle)); + yield return Tuples.metadata_handle(this, Cx.Assembly, MetadataTokens.GetToken(handle)); foreach (var c in base.Contents) yield return c; @@ -122,52 +118,52 @@ public override IEnumerable Contents if (fd.Attributes.HasFlag(FieldAttributes.Assembly)) yield return Tuples.cil_internal(this); - foreach (var c in Attribute.Populate(cx, this, fd.GetCustomAttributes())) + foreach (var c in Attribute.Populate(Cx, this, fd.GetCustomAttributes())) yield return c; } } - public override string Name => cx.GetString(fd.Name); + public override string Name => Cx.GetString(fd.Name); - public override Type DeclaringType => (Type)cx.Create(fd.GetDeclaringType()); + public override Type DeclaringType => (Type)Cx.Create(fd.GetDeclaringType()); - public override Type Type => fd.DecodeSignature(cx.TypeSignatureDecoder, DeclaringType); + public override Type Type => fd.DecodeSignature(Cx.TypeSignatureDecoder, DeclaringType); public override IEnumerable TypeParameters => throw new NotImplementedException(); public override IEnumerable MethodParameters => throw new NotImplementedException(); } - sealed class MemberReferenceField : Field + internal sealed class MemberReferenceField : Field { - readonly MemberReferenceHandle Handle; - readonly MemberReference mr; - readonly GenericContext gc; - readonly Type declType; + private readonly MemberReferenceHandle handle; + private readonly MemberReference mr; + private readonly GenericContext gc; + private readonly Type declType; - public MemberReferenceField(GenericContext gc, MemberReferenceHandle handle) : base(gc.cx) + public MemberReferenceField(GenericContext gc, MemberReferenceHandle handle) : base(gc.Cx) { - Handle = handle; + this.handle = handle; this.gc = gc; - mr = cx.mdReader.GetMemberReference(handle); - declType = (Type)cx.CreateGeneric(gc, mr.Parent); + mr = Cx.MdReader.GetMemberReference(handle); + declType = (Type)Cx.CreateGeneric(gc, mr.Parent); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - return obj is MemberReferenceField field && Handle.Equals(field.Handle); + return obj is MemberReferenceField field && handle.Equals(field.handle); } public override int GetHashCode() { - return Handle.GetHashCode(); + return handle.GetHashCode(); } - public override string Name => cx.GetString(mr.Name); + public override string Name => Cx.GetString(mr.Name); public override Type DeclaringType => declType; - public override Type Type => mr.DecodeFieldSignature(cx.TypeSignatureDecoder, this); + public override Type Type => mr.DecodeFieldSignature(Cx.TypeSignatureDecoder, this); public override IEnumerable TypeParameters => gc.TypeParameters.Concat(declType.TypeParameters); diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/File.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/File.cs index bc8c4c8c76dd..02bba3f04270 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/File.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/File.cs @@ -1,45 +1,50 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; namespace Semmle.Extraction.CIL.Entities { - interface IFileOrFolder : IEntity + internal interface IFileOrFolder : IEntity { } - interface IFile : IFileOrFolder + internal interface IFile : IFileOrFolder { } public class File : LabelledEntity, IFile { - protected readonly string path; + protected string OriginalPath { get; } + protected PathTransformer.ITransformedPath TransformedPath { get; } public File(Context cx, string path) : base(cx) { - this.path = Semmle.Extraction.Entities.File.PathAsDatabaseString(path); + this.OriginalPath = path; + TransformedPath = cx.Cx.Extractor.PathTransformer.Transform(OriginalPath); } public override void WriteId(TextWriter trapFile) { - trapFile.Write(Semmle.Extraction.Entities.File.PathAsDatabaseId(path)); + trapFile.Write(TransformedPath.DatabaseId); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - return GetType() == obj.GetType() && path == ((File)obj).path; + return GetType() == obj?.GetType() && OriginalPath == ((File)obj).OriginalPath; } - public override int GetHashCode() => 11 * path.GetHashCode(); + public override int GetHashCode() => 11 * OriginalPath.GetHashCode(); public override IEnumerable Contents { get { - var parent = cx.CreateFolder(System.IO.Path.GetDirectoryName(path)); - yield return parent; - yield return Tuples.containerparent(parent, this); - yield return Tuples.files(this, path, System.IO.Path.GetFileNameWithoutExtension(path), System.IO.Path.GetExtension(path).Substring(1)); + if (TransformedPath.ParentDirectory is PathTransformer.ITransformedPath dir) + { + var parent = Cx.CreateFolder(dir); + yield return parent; + yield return Tuples.containerparent(parent, this); + } + yield return Tuples.files(this, TransformedPath.Value, TransformedPath.NameWithoutExtension, TransformedPath.Extension); } } @@ -48,7 +53,7 @@ public override IEnumerable Contents public class PdbSourceFile : File { - readonly PDB.ISourceFile file; + private readonly PDB.ISourceFile file; public PdbSourceFile(Context cx, PDB.ISourceFile file) : base(cx, file.Path) { @@ -65,9 +70,9 @@ public override IEnumerable Contents var text = file.Contents; if (text == null) - cx.cx.Extractor.Logger.Log(Util.Logging.Severity.Warning, string.Format("PDB source file {0} could not be found", path)); + Cx.Cx.Extractor.Logger.Log(Util.Logging.Severity.Warning, string.Format("PDB source file {0} could not be found", OriginalPath)); else - cx.cx.TrapWriter.Archive(path, text); + Cx.Cx.TrapWriter.Archive(TransformedPath, text); yield return Tuples.file_extraction_mode(this, 2); } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Folder.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Folder.cs index 48ebe6a19d1d..98a30dd0ad19 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Folder.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Folder.cs @@ -3,22 +3,22 @@ namespace Semmle.Extraction.CIL.Entities { - interface IFolder : IFileOrFolder + internal interface IFolder : IFileOrFolder { } public sealed class Folder : LabelledEntity, IFolder { - readonly string path; + private readonly PathTransformer.ITransformedPath transformedPath; - public Folder(Context cx, string path) : base(cx) + public Folder(Context cx, PathTransformer.ITransformedPath path) : base(cx) { - this.path = path; + this.transformedPath = path; } public override void WriteId(TextWriter trapFile) { - trapFile.Write(Semmle.Extraction.Entities.File.PathAsDatabaseId(path)); + trapFile.Write(transformedPath.DatabaseId); } public override string IdSuffix => ";folder"; @@ -27,25 +27,21 @@ public override IEnumerable Contents { get { - // On Posix, we could get a Windows directory of the form "C:" - bool windowsDriveLetter = path.Length == 2 && char.IsLetter(path[0]) && path[1] == ':'; - - var parent = Path.GetDirectoryName(path); - if (parent != null && !windowsDriveLetter) + if (transformedPath.ParentDirectory is PathTransformer.ITransformedPath parent) { - var parentFolder = cx.CreateFolder(parent); + var parentFolder = Cx.CreateFolder(parent); yield return parentFolder; yield return Tuples.containerparent(parentFolder, this); } - yield return Tuples.folders(this, Semmle.Extraction.Entities.File.PathAsDatabaseString(path), Path.GetFileName(path)); + yield return Tuples.folders(this, transformedPath.Value, transformedPath.NameWithoutExtension); } } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - return obj is Folder folder && path == folder.path; + return obj is Folder folder && transformedPath == folder.transformedPath; } - public override int GetHashCode() => path.GetHashCode(); + public override int GetHashCode() => transformedPath.GetHashCode(); } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs index 925dea6e7110..9718e01be808 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs @@ -8,7 +8,7 @@ namespace Semmle.Extraction.CIL.Entities /// /// A CIL instruction. /// - interface IInstruction : IExtractedEntity + internal interface IInstruction : IExtractedEntity { /// /// Gets the extraction products for branches. @@ -21,7 +21,7 @@ interface IInstruction : IExtractedEntity /// /// A CIL instruction. /// - class Instruction : UnlabelledEntity, IInstruction + internal class Instruction : UnlabelledEntity, IInstruction { /// /// The additional data following the opcode, if any. @@ -38,7 +38,7 @@ public enum Payload /// /// For each Payload, how many additional bytes in the bytestream need to be read. /// - internal static readonly int[] payloadSizes = { + private static readonly int[] payloadSizes = { 0, 4, 4, 1, 4, 4, 1, 1, 4, 1, 2, 4, 8, 4, 8, @@ -46,7 +46,7 @@ public enum Payload 4, 2, 1, 4, 2, 4 }; // Maps opcodes to payloads for each instruction. - public static readonly Dictionary opPayload = new Dictionary() + private static readonly Dictionary opPayload = new Dictionary() { { ILOpCode.Nop, Payload.None }, { ILOpCode.Break, Payload.None }, @@ -268,19 +268,18 @@ public enum Payload { ILOpCode.Readonly, Payload.None } }; - public readonly DefinitionMethod Method; - public readonly ILOpCode OpCode; - public readonly int Offset; - public readonly int Index; - readonly int PayloadValue; - readonly uint UnsignedPayloadValue; + public DefinitionMethod Method { get; } + public ILOpCode OpCode { get; } + public int Offset { get; } + public int Index { get; } + private readonly int payloadValue; + private readonly uint unsignedPayloadValue; public Payload PayloadType { get { - Payload result; - if (!opPayload.TryGetValue(OpCode, out result)) + if (!opPayload.TryGetValue(OpCode, out var result)) throw new InternalError("Unknown op code " + OpCode); return result; } @@ -296,7 +295,8 @@ public int Width { get { - if (OpCode == ILOpCode.Switch) return 5 + 4 * PayloadValue; + if (OpCode == ILOpCode.Switch) + return 5 + 4 * payloadValue; return ((int)OpCode > 255 ? 2 : 1) + PayloadSize; } @@ -307,10 +307,9 @@ Label IEntity.Label get; set; } + private readonly byte[] data; - readonly byte[] data; - - int PayloadSize => payloadSizes[(int)PayloadType]; + private int PayloadSize => payloadSizes[(int)PayloadType]; /// /// Reads the instruction from a byte stream. @@ -338,19 +337,19 @@ public Instruction(Context cx, DefinitionMethod method, byte[] data, int offset, switch (PayloadSize) { case 0: - PayloadValue = 0; + payloadValue = 0; break; case 1: - PayloadValue = (sbyte)data[offset]; - UnsignedPayloadValue = data[offset]; + payloadValue = (sbyte)data[offset]; + unsignedPayloadValue = data[offset]; break; case 2: - PayloadValue = BitConverter.ToInt16(data, offset); - UnsignedPayloadValue = BitConverter.ToUInt16(data, offset); + payloadValue = BitConverter.ToInt16(data, offset); + unsignedPayloadValue = BitConverter.ToUInt16(data, offset); break; case -1: // Switch case 4: - PayloadValue = BitConverter.ToInt32(data, offset); + payloadValue = BitConverter.ToInt32(data, offset); break; case 8: // Not handled here. break; @@ -363,14 +362,19 @@ public override IEnumerable Contents { get { - int offset = Offset; + var offset = Offset; + + if (Method.Implementation is null) + { + yield break; + } yield return Tuples.cil_instruction(this, (int)OpCode, Index, Method.Implementation); switch (PayloadType) { case Payload.String: - yield return Tuples.cil_value(this, cx.mdReader.GetUserString(MetadataTokens.UserStringHandle(PayloadValue))); + yield return Tuples.cil_value(this, Cx.MdReader.GetUserString(MetadataTokens.UserStringHandle(payloadValue))); break; case Payload.Float32: yield return Tuples.cil_value(this, BitConverter.ToSingle(data, offset).ToString()); @@ -400,8 +404,8 @@ public override IEnumerable Contents case Payload.Field: case Payload.ValueType: // A generic EntityHandle. - var handle = MetadataTokens.EntityHandle(PayloadValue); - var target = cx.CreateGeneric(Method, handle); + var handle = MetadataTokens.EntityHandle(payloadValue); + var target = Cx.CreateGeneric(Method, handle); yield return target; if (target != null) { @@ -414,11 +418,17 @@ public override IEnumerable Contents break; case Payload.Arg8: case Payload.Arg16: - yield return Tuples.cil_access(this, Method.Parameters[(int)UnsignedPayloadValue]); + if (Method.Parameters is object) + { + yield return Tuples.cil_access(this, Method.Parameters[(int)unsignedPayloadValue]); + } break; case Payload.Local8: case Payload.Local16: - yield return Tuples.cil_access(this, Method.LocalVariables[(int)UnsignedPayloadValue]); + if (Method.LocalVariables is object) + { + yield return Tuples.cil_access(this, Method.LocalVariables[(int)unsignedPayloadValue]); + } break; case Payload.None: case Payload.Target8: @@ -439,27 +449,32 @@ public override IEnumerable Contents public IEnumerable JumpContents(Dictionary jump_table) { int target; - IInstruction inst; + IInstruction? inst; switch (PayloadType) { case Payload.Target8: - target = Offset + PayloadValue + 2; + target = Offset + payloadValue + 2; break; case Payload.Target32: - target = Offset + PayloadValue + 5; + target = Offset + payloadValue + 5; break; case Payload.Switch: - int end = Offset + Width; + var end = Offset + Width; - int offset = Offset + 5; + var offset = Offset + 5; - for (int b = 0; b < PayloadValue; ++b, offset += 4) + for (var b = 0; b < payloadValue; ++b, offset += 4) { target = BitConverter.ToInt32(data, offset) + end; - if (!jump_table.TryGetValue(target, out inst)) + if (jump_table.TryGetValue(target, out inst)) + { + yield return Tuples.cil_switch(this, b, inst); + } + else + { throw new InternalError("Invalid jump target"); - yield return Tuples.cil_switch(this, b, inst); + } } yield break; @@ -479,7 +494,7 @@ public IEnumerable JumpContents(Dictionary /// A method entity. /// - interface IMethod : IMember + internal interface IMethod : IMember { } /// /// A method entity. /// - abstract class Method : TypeContainer, IMethod + internal abstract class Method : TypeContainer, IMethod { - protected Method(GenericContext gc) : base(gc.cx) + protected MethodTypeParameter[]? genericParams; + protected GenericContext gc; + protected MethodSignature signature; + + protected Method(GenericContext gc) : base(gc.Cx) { this.gc = gc; } - public override IEnumerable TypeParameters => gc.TypeParameters.Concat(declaringType.TypeParameters); + public override IEnumerable TypeParameters => gc.TypeParameters.Concat(DeclaringType.TypeParameters); public override IEnumerable MethodParameters => genericParams == null ? gc.MethodParameters : gc.MethodParameters.Concat(genericParams); public int GenericParameterCount => signature.GenericParameterCount; - public virtual Method SourceDeclaration => this; + public virtual Method? SourceDeclaration => this; public abstract Type DeclaringType { get; } public abstract string Name { get; } - public virtual IList LocalVariables => throw new NotImplementedException(); - public IList Parameters { get; private set; } + public virtual IList? LocalVariables => throw new NotImplementedException(); + public IList? Parameters { get; protected set; } public override void WriteId(TextWriter trapFile) => WriteMethodId(trapFile, DeclaringType, NameLabel); public abstract string NameLabel { get; } - internal protected void WriteMethodId(TextWriter trapFile, Type parent, string methodName) + protected internal void WriteMethodId(TextWriter trapFile, Type parent, string methodName) { signature.ReturnType.WriteId(trapFile, this); trapFile.Write(' '); @@ -61,7 +64,7 @@ internal protected void WriteMethodId(TextWriter trapFile, Type parent, string m trapFile.Write(signature.GenericParameterCount); } trapFile.Write('('); - int index = 0; + var index = 0; foreach (var param in signature.ParameterTypes) { trapFile.WriteSeparator(",", ref index); @@ -70,19 +73,8 @@ internal protected void WriteMethodId(TextWriter trapFile, Type parent, string m trapFile.Write(')'); } - protected MethodTypeParameter[] genericParams; - protected Type declaringType; - protected GenericContext gc; - protected MethodSignature signature; - protected string name; - public override string IdSuffix => ";cil-method"; - protected void PopulateParameters(IEnumerable parameterTypes) - { - Parameters = MakeParameters(parameterTypes).ToArray(); - } - protected IEnumerable PopulateFlags { get @@ -94,24 +86,24 @@ protected IEnumerable PopulateFlags public abstract bool IsStatic { get; } - private IEnumerable MakeParameters(IEnumerable parameterTypes) + protected IEnumerable MakeParameters(IEnumerable parameterTypes) { - int i = 0; + var i = 0; if (!IsStatic) { - yield return cx.Populate(new Parameter(cx, this, i++, DeclaringType)); + yield return Cx.Populate(new Parameter(Cx, this, i++, DeclaringType)); } foreach (var p in parameterTypes) - yield return cx.Populate(new Parameter(cx, this, i++, p)); + yield return Cx.Populate(new Parameter(Cx, this, i++, p)); } } /// /// A method implementation entity. /// - interface IMethodImplementation : IExtractedEntity + internal interface IMethodImplementation : IExtractedEntity { } @@ -119,11 +111,11 @@ interface IMethodImplementation : IExtractedEntity /// A method implementation entity. /// In the database, the same method could in principle have multiple implementations. /// - class MethodImplementation : UnlabelledEntity, IMethodImplementation + internal class MethodImplementation : UnlabelledEntity, IMethodImplementation { - readonly Method m; + private readonly Method m; - public MethodImplementation(Method m) : base(m.cx) + public MethodImplementation(Method m) : base(m.Cx) { this.m = m; } @@ -132,7 +124,7 @@ public override IEnumerable Contents { get { - yield return Tuples.cil_method_implementation(this, m, cx.assembly); + yield return Tuples.cil_method_implementation(this, m, Cx.Assembly); } } } @@ -141,33 +133,35 @@ public override IEnumerable Contents /// /// A definition method - a method defined in the current assembly. /// - sealed class DefinitionMethod : Method, IMember + internal sealed class DefinitionMethod : Method, IMember { - readonly Handle handle; - readonly MethodDefinition md; - readonly PDB.IMethod methodDebugInformation; + private readonly Handle handle; + private readonly MethodDefinition md; + private readonly PDB.IMethod? methodDebugInformation; + private readonly Type declaringType; - LocalVariable[] locals; + private readonly string name; + private LocalVariable[]? locals; - public MethodImplementation Implementation { get; private set; } + public MethodImplementation? Implementation { get; private set; } - public override IList LocalVariables => locals; + public override IList? LocalVariables => locals; public DefinitionMethod(GenericContext gc, MethodDefinitionHandle handle) : base(gc) { - md = cx.mdReader.GetMethodDefinition(handle); + md = Cx.MdReader.GetMethodDefinition(handle); this.gc = gc; this.handle = handle; - name = cx.GetString(md.Name); + name = Cx.GetString(md.Name); - declaringType = (Type)cx.CreateGeneric(this, md.GetDeclaringType()); + declaringType = (Type)Cx.CreateGeneric(this, md.GetDeclaringType()); signature = md.DecodeSignature(new SignatureDecoder(), this); - methodDebugInformation = cx.GetMethodDebugInformation(handle); + methodDebugInformation = Cx.GetMethodDebugInformation(handle); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is DefinitionMethod method && handle.Equals(method.handle); } @@ -178,7 +172,7 @@ public override bool Equals(object obj) public override Type DeclaringType => declaringType; - public override string Name => cx.ShortName(md.Name); + public override string Name => Cx.ShortName(md.Name); public override string NameLabel => name; @@ -196,17 +190,17 @@ public override IEnumerable Contents // We need to perform a 2-phase population because some type parameters can // depend on other type parameters (as a constraint). genericParams = new MethodTypeParameter[md.GetGenericParameters().Count]; - for (int i = 0; i < genericParams.Length; ++i) - genericParams[i] = cx.Populate(new MethodTypeParameter(this, this, i)); - for (int i = 0; i < genericParams.Length; ++i) - genericParams[i].PopulateHandle(this, md.GetGenericParameters()[i]); + for (var i = 0; i < genericParams.Length; ++i) + genericParams[i] = Cx.Populate(new MethodTypeParameter(this, this, i)); + for (var i = 0; i < genericParams.Length; ++i) + genericParams[i].PopulateHandle(md.GetGenericParameters()[i]); foreach (var p in genericParams) yield return p; } - var typeSignature = md.DecodeSignature(cx.TypeSignatureDecoder, this); + var typeSignature = md.DecodeSignature(Cx.TypeSignatureDecoder, this); - PopulateParameters(typeSignature.ParameterTypes); + Parameters = MakeParameters(typeSignature.ParameterTypes).ToArray(); foreach (var c in Parameters) yield return c; @@ -214,38 +208,38 @@ public override IEnumerable Contents foreach (var c in PopulateFlags) yield return c; - foreach (var p in md.GetParameters().Select(h => cx.mdReader.GetParameter(h)).Where(p => p.SequenceNumber > 0)) + foreach (var p in md.GetParameters().Select(h => Cx.MdReader.GetParameter(h)).Where(p => p.SequenceNumber > 0)) { var pe = Parameters[IsStatic ? p.SequenceNumber - 1 : p.SequenceNumber]; if (p.Attributes.HasFlag(ParameterAttributes.Out)) yield return Tuples.cil_parameter_out(pe); if (p.Attributes.HasFlag(ParameterAttributes.In)) yield return Tuples.cil_parameter_in(pe); - Attribute.Populate(cx, pe, p.GetCustomAttributes()); + Attribute.Populate(Cx, pe, p.GetCustomAttributes()); } - yield return Tuples.metadata_handle(this, cx.assembly, MetadataTokens.GetToken(handle)); + yield return Tuples.metadata_handle(this, Cx.Assembly, MetadataTokens.GetToken(handle)); yield return Tuples.cil_method(this, Name, declaringType, typeSignature.ReturnType); yield return Tuples.cil_method_source_declaration(this, this); - yield return Tuples.cil_method_location(this, cx.assembly); + yield return Tuples.cil_method_location(this, Cx.Assembly); if (HasBytecode) { Implementation = new MethodImplementation(this); yield return Implementation; - var body = cx.peReader.GetMethodBody(md.RelativeVirtualAddress); + var body = Cx.PeReader.GetMethodBody(md.RelativeVirtualAddress); if (!body.LocalSignature.IsNil) { - var locals = cx.mdReader.GetStandaloneSignature(body.LocalSignature); - var localVariableTypes = locals.DecodeLocalSignature(cx.TypeSignatureDecoder, this); + var locals = Cx.MdReader.GetStandaloneSignature(body.LocalSignature); + var localVariableTypes = locals.DecodeLocalSignature(Cx.TypeSignatureDecoder, this); this.locals = new LocalVariable[localVariableTypes.Length]; - for (int l = 0; l < this.locals.Length; ++l) + for (var l = 0; l < this.locals.Length; ++l) { - this.locals[l] = cx.Populate(new LocalVariable(cx, Implementation, l, localVariableTypes[l])); + this.locals[l] = Cx.Populate(new LocalVariable(Cx, Implementation, l, localVariableTypes[l])); yield return this.locals[l]; } } @@ -255,7 +249,7 @@ public override IEnumerable Contents foreach (var c in Decode(body.GetILBytes(), jump_table)) yield return c; - int filter_index = 0; + var filter_index = 0; foreach (var region in body.ExceptionRegions) { yield return new ExceptionRegion(this, Implementation, filter_index++, region, jump_table); @@ -265,7 +259,7 @@ public override IEnumerable Contents if (methodDebugInformation != null) { - var sourceLocation = cx.CreateSourceLocation(methodDebugInformation.Location); + var sourceLocation = Cx.CreateSourceLocation(methodDebugInformation.Location); yield return sourceLocation; yield return Tuples.cil_method_location(this, sourceLocation); } @@ -304,26 +298,26 @@ public override IEnumerable Contents yield return Tuples.cil_newslot(this); // Populate attributes - Attribute.Populate(cx, this, md.GetCustomAttributes()); + Attribute.Populate(Cx, this, md.GetCustomAttributes()); } } - IEnumerable Decode(byte[] ilbytes, Dictionary jump_table) + private IEnumerable Decode(byte[] ilbytes, Dictionary jump_table) { // Sequence points are stored in order of offset. // We use an enumerator to locate the correct sequence point for each instruction. // The sequence point gives the location of each instruction. // The location of an instruction is given by the sequence point *after* the // instruction. - IEnumerator nextSequencePoint = null; - PdbSourceLocation instructionLocation = null; + IEnumerator? nextSequencePoint = null; + PdbSourceLocation? instructionLocation = null; if (methodDebugInformation != null) { nextSequencePoint = methodDebugInformation.SequencePoints.GetEnumerator(); if (nextSequencePoint.MoveNext()) { - instructionLocation = cx.CreateSourceLocation(nextSequencePoint.Current.Location); + instructionLocation = Cx.CreateSourceLocation(nextSequencePoint.Current.Location); yield return instructionLocation; } else @@ -332,15 +326,15 @@ IEnumerable Decode(byte[] ilbytes, Dictionary= nextSequencePoint.Current.Offset) { - instructionLocation = cx.CreateSourceLocation(nextSequencePoint.Current.Location); + instructionLocation = Cx.CreateSourceLocation(nextSequencePoint.Current.Location); yield return instructionLocation; if (!nextSequencePoint.MoveNext()) nextSequencePoint = null; @@ -370,17 +364,17 @@ public IEnumerable DebugInstructions { if (md.ImplAttributes == MethodImplAttributes.IL && md.RelativeVirtualAddress != 0) { - var body = cx.peReader.GetMethodBody(md.RelativeVirtualAddress); + var body = Cx.PeReader.GetMethodBody(md.RelativeVirtualAddress); var ilbytes = body.GetILBytes(); - int child = 0; - for (int offset = 0; offset < ilbytes.Length;) + var child = 0; + for (var offset = 0; offset < ilbytes.Length;) { Instruction decoded; try { - decoded = new Instruction(cx, this, ilbytes, offset, child++); + decoded = new Instruction(Cx, this, ilbytes, offset, child++); offset += decoded.Width; } catch // lgtm[cs/catch-of-all-exceptions] @@ -397,41 +391,43 @@ public IEnumerable DebugInstructions /// /// This is a late-bound reference to a method. /// - sealed class MemberReferenceMethod : Method + internal sealed class MemberReferenceMethod : Method { - readonly MemberReferenceHandle handle; - readonly MemberReference mr; - readonly Type declType; - readonly GenericContext parent; - readonly Method sourceDeclaration; + private readonly MemberReferenceHandle handle; + private readonly MemberReference mr; + private readonly Type declaringType; + private readonly GenericContext parent; + private readonly Method? sourceDeclaration; public MemberReferenceMethod(GenericContext gc, MemberReferenceHandle handle) : base(gc) { this.handle = handle; this.gc = gc; - mr = cx.mdReader.GetMemberReference(handle); + mr = Cx.MdReader.GetMemberReference(handle); signature = mr.DecodeMethodSignature(new SignatureDecoder(), gc); - parent = (GenericContext)cx.CreateGeneric(gc, mr.Parent); + parent = (GenericContext)Cx.CreateGeneric(gc, mr.Parent); - var parentMethod = parent as Method; - nameLabel = cx.GetString(mr.Name); - - declType = parentMethod == null ? parent as Type : parentMethod.DeclaringType; + var declType = parent is Method parentMethod + ? parentMethod.DeclaringType + : parent as Type; if (declType is null) throw new InternalError("Parent context of method is not a type"); - var typeSourceDeclaration = declType.SourceDeclaration; - sourceDeclaration = typeSourceDeclaration == declType ? (Method)this : typeSourceDeclaration.LookupMethod(mr.Name, mr.Signature); + declaringType = declType; + nameLabel = Cx.GetString(mr.Name); + + var typeSourceDeclaration = declaringType.SourceDeclaration; + sourceDeclaration = typeSourceDeclaration == declaringType ? (Method)this : typeSourceDeclaration.LookupMethod(mr.Name, mr.Signature); } private readonly string nameLabel; public override string NameLabel => nameLabel; - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is MemberReferenceMethod method && handle.Equals(method.handle); } @@ -441,13 +437,13 @@ public override int GetHashCode() return handle.GetHashCode(); } - public override Method SourceDeclaration => sourceDeclaration; + public override Method? SourceDeclaration => sourceDeclaration; public override bool IsStatic => !signature.Header.IsInstance; - public override Type DeclaringType => declType; + public override Type DeclaringType => declaringType; - public override string Name => cx.ShortName(mr.Name); + public override string Name => Cx.ShortName(mr.Name); public override IEnumerable TypeParameters => parent.TypeParameters.Concat(gc.TypeParameters); @@ -456,15 +452,15 @@ public override IEnumerable Contents get { genericParams = new MethodTypeParameter[signature.GenericParameterCount]; - for (int p = 0; p < genericParams.Length; ++p) - genericParams[p] = cx.Populate(new MethodTypeParameter(this, this, p)); + for (var p = 0; p < genericParams.Length; ++p) + genericParams[p] = Cx.Populate(new MethodTypeParameter(this, this, p)); foreach (var p in genericParams) yield return p; - var typeSignature = mr.DecodeMethodSignature(cx.TypeSignatureDecoder, this); + var typeSignature = mr.DecodeMethodSignature(Cx.TypeSignatureDecoder, this); - PopulateParameters(typeSignature.ParameterTypes); + Parameters = MakeParameters(typeSignature.ParameterTypes).ToArray(); foreach (var p in Parameters) yield return p; foreach (var f in PopulateFlags) yield return f; @@ -480,28 +476,27 @@ public override IEnumerable Contents /// /// A constructed method. /// - sealed class MethodSpecificationMethod : Method + internal sealed class MethodSpecificationMethod : Method { - readonly MethodSpecificationHandle handle; - readonly MethodSpecification ms; - readonly Method unboundMethod; - readonly ImmutableArray typeParams; + private readonly MethodSpecificationHandle handle; + private readonly MethodSpecification ms; + private readonly Method unboundMethod; + private readonly ImmutableArray typeParams; public MethodSpecificationMethod(GenericContext gc, MethodSpecificationHandle handle) : base(gc) { this.handle = handle; - ms = cx.mdReader.GetMethodSpecification(handle); - typeParams = ms.DecodeSignature(cx.TypeSignatureDecoder, gc); - unboundMethod = (Method)cx.CreateGeneric(gc, ms.Method); - declaringType = unboundMethod.DeclaringType; + ms = Cx.MdReader.GetMethodSpecification(handle); + typeParams = ms.DecodeSignature(Cx.TypeSignatureDecoder, gc); + unboundMethod = (Method)Cx.CreateGeneric(gc, ms.Method); } public override void WriteId(TextWriter trapFile) { unboundMethod.WriteId(trapFile); trapFile.Write('<'); - int index = 0; - foreach(var param in typeParams) + var index = 0; + foreach (var param in typeParams) { trapFile.WriteSeparator(",", ref index); trapFile.WriteSubId(param); @@ -511,7 +506,7 @@ public override void WriteId(TextWriter trapFile) public override string NameLabel => throw new NotImplementedException(); - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is MethodSpecificationMethod method && handle.Equals(method.handle) && typeParams.SequenceEqual(method.typeParams); } @@ -536,18 +531,18 @@ public override IEnumerable Contents switch (ms.Method.Kind) { case HandleKind.MemberReference: - var mr = cx.mdReader.GetMemberReference((MemberReferenceHandle)ms.Method); - constructedTypeSignature = mr.DecodeMethodSignature(cx.TypeSignatureDecoder, this); + var mr = Cx.MdReader.GetMemberReference((MemberReferenceHandle)ms.Method); + constructedTypeSignature = mr.DecodeMethodSignature(Cx.TypeSignatureDecoder, this); break; case HandleKind.MethodDefinition: - var md = cx.mdReader.GetMethodDefinition((MethodDefinitionHandle)ms.Method); - constructedTypeSignature = md.DecodeSignature(cx.TypeSignatureDecoder, this); + var md = Cx.MdReader.GetMethodDefinition((MethodDefinitionHandle)ms.Method); + constructedTypeSignature = md.DecodeSignature(Cx.TypeSignatureDecoder, this); break; default: throw new InternalError($"Unexpected constructed method handle kind {ms.Method.Kind}"); } - PopulateParameters(constructedTypeSignature.ParameterTypes); + Parameters = MakeParameters(constructedTypeSignature.ParameterTypes).ToArray(); foreach (var p in Parameters) yield return p; @@ -557,10 +552,10 @@ public override IEnumerable Contents yield return Tuples.cil_method(this, Name, DeclaringType, constructedTypeSignature.ReturnType); yield return Tuples.cil_method_source_declaration(this, SourceDeclaration); - if (typeParams.Count() != unboundMethod.GenericParameterCount) + if (typeParams.Length != unboundMethod.GenericParameterCount) throw new InternalError("Method type parameter mismatch"); - for (int p = 0; p < typeParams.Length; ++p) + for (var p = 0; p < typeParams.Length; ++p) { yield return Tuples.cil_type_argument(this, p, typeParams[p]); } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Namespace.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Namespace.cs index 6a7943c8bd1d..2e19eb3dd4c6 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Namespace.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Namespace.cs @@ -1,14 +1,13 @@ using System; using System.Collections.Generic; using System.IO; -using Semmle.Extraction.Entities; namespace Semmle.Extraction.CIL.Entities { /// /// A namespace. /// - interface INamespace : ITypeContainer + internal interface INamespace : ITypeContainer { } @@ -17,10 +16,10 @@ interface INamespace : ITypeContainer /// public sealed class Namespace : TypeContainer, INamespace { - public Namespace ParentNamespace; - public readonly string Name; + public Namespace? ParentNamespace { get; } + public string Name { get; } - public bool IsGlobalNamespace => ParentNamespace == null; + public bool IsGlobalNamespace => ParentNamespace is null; public override string IdSuffix => ";namespace"; @@ -35,7 +34,7 @@ public override void WriteId(TextWriter trapFile) trapFile.Write(Name); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (obj is Namespace ns && Name == ns.Name) { @@ -49,7 +48,7 @@ public override bool Equals(object obj) public override int GetHashCode() { - int h = ParentNamespace is null ? 19 : ParentNamespace.GetHashCode(); + var h = ParentNamespace is null ? 19 : ParentNamespace.GetHashCode(); return 13 * h + Name.GetHashCode(); } @@ -57,15 +56,16 @@ public override int GetHashCode() public override IEnumerable MethodParameters => throw new NotImplementedException(); - static string parseNamespaceName(string fqn) + private static string parseNamespaceName(string fqn) { var i = fqn.LastIndexOf('.'); return i == -1 ? fqn : fqn.Substring(i + 1); } - static Namespace createParentNamespace(Context cx, string fqn) + private static Namespace? createParentNamespace(Context cx, string fqn) { - if (fqn == "") return null; + if (fqn.Length == 0) + return null; var i = fqn.LastIndexOf('.'); return i == -1 ? cx.GlobalNamespace : cx.Populate(new Namespace(cx, fqn.Substring(0, i))); } @@ -74,7 +74,7 @@ public Namespace(Context cx, string fqn) : this(cx, parseNamespaceName(fqn), cre { } - public Namespace(Context cx, string name, Namespace parent) : base(cx) + public Namespace(Context cx, string name, Namespace? parent) : base(cx) { Name = name; ParentNamespace = parent; @@ -85,7 +85,7 @@ public override IEnumerable Contents get { yield return Tuples.namespaces(this, Name); - if (!IsGlobalNamespace) + if (ParentNamespace is object) yield return Tuples.parent_namespace(this, ParentNamespace); } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Parameter.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Parameter.cs index f48a88bcf82e..9295327de083 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Parameter.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Parameter.cs @@ -6,18 +6,18 @@ namespace Semmle.Extraction.CIL.Entities /// /// A parameter entity. /// - interface IParameter : IExtractedEntity + internal interface IParameter : IExtractedEntity { } /// /// A parameter entity. /// - sealed class Parameter : LabelledEntity, IParameter + internal sealed class Parameter : LabelledEntity, IParameter { - readonly Method method; - readonly int index; - readonly Type type; + private readonly Method method; + private readonly int index; + private readonly Type type; public Parameter(Context cx, Method m, int i, Type t) : base(cx) { @@ -33,7 +33,7 @@ public override void WriteId(TextWriter trapFile) trapFile.Write(index); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is Parameter param && method.Equals(param.method) && index == param.index; } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Property.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Property.cs index 4149baf5e429..65c5dc4cc3b1 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Property.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Property.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.Reflection.Metadata; -using System.Linq; using System.Reflection.Metadata.Ecma335; using System.IO; @@ -9,26 +8,26 @@ namespace Semmle.Extraction.CIL.Entities /// /// A property. /// - interface IProperty : IExtractedEntity + internal interface IProperty : IExtractedEntity { } /// /// A property. /// - sealed class Property : LabelledEntity, IProperty + internal sealed class Property : LabelledEntity, IProperty { - readonly Handle handle; - readonly Type type; - readonly PropertyDefinition pd; + private readonly Handle handle; + private readonly Type type; + private readonly PropertyDefinition pd; public override string IdSuffix => ";cil-property"; - readonly GenericContext gc; + private readonly GenericContext gc; - public Property(GenericContext gc, Type type, PropertyDefinitionHandle handle) : base(gc.cx) + public Property(GenericContext gc, Type type, PropertyDefinitionHandle handle) : base(gc.Cx) { this.gc = gc; this.handle = handle; - pd = cx.mdReader.GetPropertyDefinition(handle); + pd = Cx.MdReader.GetPropertyDefinition(handle); this.type = type; } @@ -36,9 +35,9 @@ public override void WriteId(TextWriter trapFile) { trapFile.WriteSubId(type); trapFile.Write('.'); - trapFile.Write(cx.GetString(pd.Name)); + trapFile.Write(Cx.GetString(pd.Name)); trapFile.Write("("); - int index=0; + var index = 0; var signature = pd.DecodeSignature(new SignatureDecoder(), gc); foreach (var param in signature.ParameterTypes) { @@ -48,7 +47,7 @@ public override void WriteId(TextWriter trapFile) trapFile.Write(")"); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is Property property && Equals(handle, property.handle); } @@ -59,27 +58,27 @@ public override IEnumerable Contents { get { - yield return Tuples.metadata_handle(this, cx.assembly, MetadataTokens.GetToken(handle)); - var sig = pd.DecodeSignature(cx.TypeSignatureDecoder, type); + yield return Tuples.metadata_handle(this, Cx.Assembly, MetadataTokens.GetToken(handle)); + var sig = pd.DecodeSignature(Cx.TypeSignatureDecoder, type); - yield return Tuples.cil_property(this, type, cx.ShortName(pd.Name), sig.ReturnType); + yield return Tuples.cil_property(this, type, Cx.ShortName(pd.Name), sig.ReturnType); var accessors = pd.GetAccessors(); if (!accessors.Getter.IsNil) { - var getter = (Method)cx.CreateGeneric(type, accessors.Getter); + var getter = (Method)Cx.CreateGeneric(type, accessors.Getter); yield return getter; yield return Tuples.cil_getter(this, getter); } if (!accessors.Setter.IsNil) { - var setter = (Method)cx.CreateGeneric(type, accessors.Setter); + var setter = (Method)Cx.CreateGeneric(type, accessors.Setter); yield return setter; yield return Tuples.cil_setter(this, setter); } - foreach (var c in Attribute.Populate(cx, this, pd.GetCustomAttributes())) + foreach (var c in Attribute.Populate(Cx, this, pd.GetCustomAttributes())) yield return c; } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/SourceLocation.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/SourceLocation.cs index ade644fbb1c9..230a856ed2d1 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/SourceLocation.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/SourceLocation.cs @@ -10,8 +10,8 @@ public interface ISourceLocation : ILocation public sealed class PdbSourceLocation : LabelledEntity, ISourceLocation { - readonly Location location; - readonly PdbSourceFile file; + private readonly Location location; + private readonly PdbSourceFile file; public PdbSourceLocation(Context cx, PDB.Location location) : base(cx) { @@ -32,7 +32,7 @@ public override void WriteId(TextWriter trapFile) trapFile.Write(location.EndColumn); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is PdbSourceLocation l && location.Equals(l.location); } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs index 04b25553b6b7..d3378b7c3f12 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs @@ -7,21 +7,21 @@ using System.Reflection; using Semmle.Util; using System.IO; -using System.Text; +using System.Diagnostics.CodeAnalysis; namespace Semmle.Extraction.CIL.Entities { /// /// A type. /// - interface IType : IEntity + internal interface IType : IEntity { } /// /// An array type. /// - interface IArrayType : IType + internal interface IArrayType : IType { } @@ -39,18 +39,17 @@ public enum CilTypeKind /// /// A type container (namespace/types/method). /// - interface ITypeContainer : IExtractedEntity + internal interface ITypeContainer : IExtractedEntity { } /// /// Base class for all type containers (namespaces, types, methods). /// - abstract public class TypeContainer : GenericContext, ITypeContainer + public abstract class TypeContainer : GenericContext, ITypeContainer { protected TypeContainer(Context cx) : base(cx) { - this.cx = cx; } public virtual Label Label { get; set; } @@ -75,11 +74,9 @@ public void WriteQuotedId(TextWriter trapFile) public override string ToString() { - using (var writer = new StringWriter()) - { - WriteQuotedId(writer); - return writer.ToString(); - } + using var writer = new StringWriter(); + WriteQuotedId(writer); + return writer.ToString(); } TrapStackBehaviour IEntity.TrapStackBehaviour => TrapStackBehaviour.NoLabel; @@ -103,7 +100,7 @@ public abstract class Type : TypeContainer, IMember, IType /// shortcut to comparing the signature bytes since handles are unique. /// /// The method, or 'null' if not found or not supported. - internal virtual Method LookupMethod(StringHandle methodName, BlobHandle signature) + internal virtual Method? LookupMethod(StringHandle methodName, BlobHandle signature) { return null; } @@ -113,9 +110,10 @@ public IEnumerable TypeArguments get { if (ContainingType != null) + { foreach (var t in ContainingType.TypeArguments) yield return t; - + } foreach (var t in ThisTypeArguments) yield return t; @@ -160,7 +158,7 @@ public abstract CilTypeKind Kind get; } - public virtual TypeContainer Parent => (TypeContainer)ContainingType ?? Namespace; + public virtual TypeContainer Parent => (TypeContainer?)ContainingType ?? Namespace!; public override IEnumerable Contents { @@ -177,9 +175,9 @@ public override IEnumerable Contents public abstract string Name { get; } - public abstract Namespace Namespace { get; } + public abstract Namespace? Namespace { get; } - public abstract Type ContainingType { get; } + public abstract Type? ContainingType { get; } public abstract Type Construct(IEnumerable typeArguments); @@ -213,8 +211,10 @@ public virtual IEnumerable GenericArguments get { if (ContainingType != null) + { foreach (var t in ContainingType.GenericArguments) yield return t; + } foreach (var t in ThisGenericArguments) yield return t; } @@ -233,23 +233,21 @@ public void PrimitiveTypeId(TextWriter trapFile) /// /// The resulting primitive type, or null. /// True if this type is a primitive type. - public bool TryGetPrimitiveType(out PrimitiveType t) + public bool TryGetPrimitiveType([NotNullWhen(true)] out PrimitiveType? t) { if (TryGetPrimitiveTypeCode(out var code)) { - t = cx.Create(code); + t = Cx.Create(code); return true; } - else - { - t = null; - return false; - } + + t = null; + return false; } private bool TryGetPrimitiveTypeCode(out PrimitiveTypeCode code) { - if (ContainingType == null && Namespace.Name == cx.SystemNamespace.Name) + if (ContainingType == null && Namespace?.Name == Cx.SystemNamespace.Name) { switch (Name) { @@ -317,7 +315,7 @@ private bool TryGetPrimitiveTypeCode(out PrimitiveTypeCode code) protected bool IsPrimitiveType => TryGetPrimitiveTypeCode(out _); public static Type DecodeType(GenericContext gc, TypeSpecificationHandle handle) => - gc.cx.mdReader.GetTypeSpecification(handle).DecodeSignature(gc.cx.TypeSignatureDecoder, gc); + gc.Cx.MdReader.GetTypeSpecification(handle).DecodeSignature(gc.Cx.TypeSignatureDecoder, gc); } /// @@ -325,12 +323,12 @@ public static Type DecodeType(GenericContext gc, TypeSpecificationHandle handle) /// public sealed class TypeDefinitionType : Type { - readonly Handle handle; - readonly TypeDefinition td; + private readonly Handle handle; + private readonly TypeDefinition td; public TypeDefinitionType(Context cx, TypeDefinitionHandle handle) : base(cx) { - td = cx.mdReader.GetTypeDefinition(handle); + td = cx.MdReader.GetTypeDefinition(handle); this.handle = handle; declType = @@ -341,7 +339,7 @@ public TypeDefinitionType(Context cx, TypeDefinitionHandle handle) : base(cx) typeParams = new Lazy>(MakeTypeParameters); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is TypeDefinitionType t && handle.Equals(t.handle); } @@ -356,7 +354,7 @@ public override void WriteId(TextWriter trapFile, bool inContext) return; } - var name = cx.GetString(td.Name); + var name = Cx.GetString(td.Name); if (ContainingType != null) { @@ -382,17 +380,17 @@ public override string Name { get { - var name = cx.GetString(td.Name); + var name = Cx.GetString(td.Name); var tick = name.IndexOf('`'); return tick == -1 ? name : name.Substring(0, tick); } } - public override Namespace Namespace => cx.Create(td.NamespaceDefinition); + public override Namespace Namespace => Cx.Create(td.NamespaceDefinition); - readonly Type declType; + private readonly Type? declType; - public override Type ContainingType => declType; + public override Type? ContainingType => declType; public override int ThisTypeParameters { @@ -400,7 +398,7 @@ public override int ThisTypeParameters { var containingType = td.GetDeclaringType(); var parentTypeParameters = containingType.IsNil ? 0 : - cx.mdReader.GetTypeDefinition(containingType).GetGenericParameters().Count; + Cx.MdReader.GetTypeDefinition(containingType).GetGenericParameters().Count; return td.GetGenericParameters().Count - parentTypeParameters; } @@ -410,38 +408,38 @@ public override int ThisTypeParameters public override Type Construct(IEnumerable typeArguments) { - return cx.Populate(new ConstructedType(cx, this, typeArguments)); + return Cx.Populate(new ConstructedType(Cx, this, typeArguments)); } public override void WriteAssemblyPrefix(TextWriter trapFile) { var ct = ContainingType; if (ct is null) - cx.WriteAssemblyPrefix(trapFile); + Cx.WriteAssemblyPrefix(trapFile); else if (IsPrimitiveType) trapFile.Write("builtin:"); else ct.WriteAssemblyPrefix(trapFile); } - IEnumerable MakeTypeParameters() + private IEnumerable MakeTypeParameters() { if (ThisTypeParameters == 0) return Enumerable.Empty(); var newTypeParams = new TypeTypeParameter[ThisTypeParameters]; var genericParams = td.GetGenericParameters(); - int toSkip = genericParams.Count - newTypeParams.Length; + var toSkip = genericParams.Count - newTypeParams.Length; // Two-phase population because type parameters can be mutually dependent - for (int i = 0; i < newTypeParams.Length; ++i) - newTypeParams[i] = cx.Populate(new TypeTypeParameter(this, this, i)); - for (int i = 0; i < newTypeParams.Length; ++i) - newTypeParams[i].PopulateHandle(this, genericParams[i + toSkip]); + for (var i = 0; i < newTypeParams.Length; ++i) + newTypeParams[i] = Cx.Populate(new TypeTypeParameter(this, this, i)); + for (var i = 0; i < newTypeParams.Length; ++i) + newTypeParams[i].PopulateHandle(genericParams[i + toSkip]); return newTypeParams; } - readonly Lazy> typeParams; + private readonly Lazy> typeParams; public override IEnumerable MethodParameters => Enumerable.Empty(); @@ -464,7 +462,7 @@ public override IEnumerable Contents { get { - yield return Tuples.metadata_handle(this, cx.assembly, handle.GetHashCode()); + yield return Tuples.metadata_handle(this, Cx.Assembly, handle.GetHashCode()); foreach (var c in base.Contents) yield return c; @@ -473,7 +471,7 @@ public override IEnumerable Contents foreach (var f in td.GetFields()) { // Populate field if needed - yield return cx.CreateGeneric(this, f); + yield return Cx.CreateGeneric(this, f); } foreach (var prop in td.GetProperties()) @@ -483,16 +481,16 @@ public override IEnumerable Contents foreach (var @event in td.GetEvents()) { - yield return new Event(cx, this, @event); + yield return new Event(Cx, this, @event); } - foreach (var a in Attribute.Populate(cx, this, td.GetCustomAttributes())) + foreach (var a in Attribute.Populate(Cx, this, td.GetCustomAttributes())) yield return a; - foreach (var impl in td.GetMethodImplementations().Select(i => cx.mdReader.GetMethodImplementation(i))) + foreach (var impl in td.GetMethodImplementations().Select(i => Cx.MdReader.GetMethodImplementation(i))) { - var m = (Method)cx.CreateGeneric(this, impl.MethodBody); - var decl = (Method)cx.CreateGeneric(this, impl.MethodDeclaration); + var m = (Method)Cx.CreateGeneric(this, impl.MethodBody); + var decl = (Method)Cx.CreateGeneric(this, impl.MethodDeclaration); yield return m; yield return decl; @@ -520,20 +518,20 @@ public override IEnumerable Contents if (!td.BaseType.IsNil) { - var @base = (Type)cx.CreateGeneric(this, td.BaseType); + var @base = (Type)Cx.CreateGeneric(this, td.BaseType); yield return @base; yield return Tuples.cil_base_class(this, @base); } - foreach (var @interface in td.GetInterfaceImplementations().Select(i => cx.mdReader.GetInterfaceImplementation(i))) + foreach (var @interface in td.GetInterfaceImplementations().Select(i => Cx.MdReader.GetInterfaceImplementation(i))) { - var t = (Type)cx.CreateGeneric(this, @interface.Interface); + var t = (Type)Cx.CreateGeneric(this, @interface.Interface); yield return t; yield return Tuples.cil_base_interface(this, t); } // Only type definitions have locations. - yield return Tuples.cil_type_location(this, cx.assembly); + yield return Tuples.cil_type_location(this, Cx.Assembly); } } @@ -541,11 +539,11 @@ internal override Method LookupMethod(StringHandle name, BlobHandle signature) { foreach (var h in td.GetMethods()) { - var md = cx.mdReader.GetMethodDefinition(h); + var md = Cx.MdReader.GetMethodDefinition(h); if (md.Name == name && md.Signature == signature) { - return (Method)cx.Create(h); + return (Method)Cx.Create(h); } } @@ -558,22 +556,18 @@ internal override Method LookupMethod(StringHandle name, BlobHandle signature) /// public sealed class TypeReferenceType : Type { - readonly TypeReferenceHandle handle; - readonly TypeReference tr; - readonly Lazy typeParams; + private readonly TypeReferenceHandle handle; + private readonly TypeReference tr; + private readonly Lazy typeParams; - public TypeReferenceType(Context cx, TypeReferenceHandle handle) : this(cx, handle, cx.mdReader.GetTypeReference(handle)) - { - typeParams = new Lazy(MakeTypeParameters); - } - - public TypeReferenceType(Context cx, TypeReferenceHandle handle, TypeReference tr) : base(cx) + public TypeReferenceType(Context cx, TypeReferenceHandle handle) : base(cx) { + this.typeParams = new Lazy(MakeTypeParameters); this.handle = handle; - this.tr = tr; + this.tr = cx.MdReader.GetTypeReference(handle); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is TypeReferenceType t && handle.Equals(t.handle); } @@ -583,10 +577,10 @@ public override int GetHashCode() return handle.GetHashCode(); } - TypeTypeParameter[] MakeTypeParameters() + private TypeTypeParameter[] MakeTypeParameters() { var newTypeParams = new TypeTypeParameter[ThisTypeParameters]; - for (int i = 0; i < newTypeParams.Length; ++i) + for (var i = 0; i < newTypeParams.Length; ++i) { newTypeParams[i] = new TypeTypeParameter(this, this, i); } @@ -609,20 +603,20 @@ public override string Name { get { - var name = cx.GetString(tr.Name); + var name = Cx.GetString(tr.Name); var tick = name.IndexOf('`'); return tick == -1 ? name : name.Substring(0, tick); } } - public override Namespace Namespace => cx.CreateNamespace(tr.Namespace); + public override Namespace Namespace => Cx.CreateNamespace(tr.Namespace); public override int ThisTypeParameters { get { // Parse the name - var name = cx.GetString(tr.Name); + var name = Cx.GetString(tr.Name); var tick = name.IndexOf('`'); return tick == -1 ? 0 : int.Parse(name.Substring(tick + 1)); } @@ -637,12 +631,12 @@ public override IEnumerable ThisGenericArguments } } - public override Type ContainingType + public override Type? ContainingType { get { if (tr.ResolutionScope.Kind == HandleKind.TypeReference) - return (Type)cx.Create((TypeReferenceHandle)tr.ResolutionScope); + return (Type)Cx.Create((TypeReferenceHandle)tr.ResolutionScope); return null; } } @@ -654,17 +648,17 @@ public override void WriteAssemblyPrefix(TextWriter trapFile) switch (tr.ResolutionScope.Kind) { case HandleKind.TypeReference: - ContainingType.WriteAssemblyPrefix(trapFile); + ContainingType!.WriteAssemblyPrefix(trapFile); break; case HandleKind.AssemblyReference: - var assemblyDef = cx.mdReader.GetAssemblyReference((AssemblyReferenceHandle)tr.ResolutionScope); - trapFile.Write(cx.GetString(assemblyDef.Name)); + var assemblyDef = Cx.MdReader.GetAssemblyReference((AssemblyReferenceHandle)tr.ResolutionScope); + trapFile.Write(Cx.GetString(assemblyDef.Name)); trapFile.Write('_'); trapFile.Write(assemblyDef.Version.ToString()); trapFile.Write("::"); break; default: - cx.WriteAssemblyPrefix(trapFile); + Cx.WriteAssemblyPrefix(trapFile); break; } } @@ -684,7 +678,7 @@ public override void WriteId(TextWriter trapFile, bool inContext) var ct = ContainingType; if (ct != null) { - ContainingType.GetId(trapFile, inContext); + ct.GetId(trapFile, inContext); } else { @@ -700,7 +694,7 @@ public override void WriteId(TextWriter trapFile, bool inContext) } trapFile.Write('.'); - trapFile.Write(cx.GetString(tr.Name)); + trapFile.Write(Cx.GetString(tr.Name)); } public override Type Construct(IEnumerable typeArguments) @@ -708,7 +702,7 @@ public override Type Construct(IEnumerable typeArguments) if (TotalTypeParametersCheck != typeArguments.Count()) throw new InternalError("Mismatched type arguments"); - return cx.Populate(new ConstructedType(cx, this, typeArguments)); + return Cx.Populate(new ConstructedType(Cx, this, typeArguments)); } } @@ -718,10 +712,12 @@ public override Type Construct(IEnumerable typeArguments) /// public sealed class ConstructedType : Type { - readonly Type unboundGenericType; - readonly Type[] thisTypeArguments; + private readonly Type unboundGenericType; - public override IEnumerable ThisTypeArguments => thisTypeArguments; + // Either null or notEmpty + private readonly Type[]? thisTypeArguments; + + public override IEnumerable ThisTypeArguments => thisTypeArguments.EnumerateNull(); public override IEnumerable ThisGenericArguments => thisTypeArguments.EnumerateNull(); @@ -732,7 +728,7 @@ public override IEnumerable Contents foreach (var c in base.Contents) yield return c; - int i = 0; + var i = 0; foreach (var type in ThisGenericArguments) { yield return type; @@ -751,7 +747,6 @@ public ConstructedType(Context cx, Type unboundType, IEnumerable typeArgum unboundGenericType = unboundType; var thisParams = unboundType.ThisTypeParameters; - var parentParams = suppliedArgs - thisParams; if (typeArguments.Count() == thisParams) { @@ -760,40 +755,45 @@ public ConstructedType(Context cx, Type unboundType, IEnumerable typeArgum } else if (thisParams == 0) { - containingType = unboundType.ContainingType.Construct(typeArguments); + // all type arguments belong to containing type + containingType = unboundType.ContainingType!.Construct(typeArguments); } else { - containingType = unboundType.ContainingType.Construct(typeArguments.Take(parentParams)); + // some type arguments belong to containing type + var parentParams = suppliedArgs - thisParams; + containingType = unboundType.ContainingType!.Construct(typeArguments.Take(parentParams)); thisTypeArguments = typeArguments.Skip(parentParams).ToArray(); } } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - if(obj is ConstructedType t && Equals(unboundGenericType, t.unboundGenericType) && Equals(containingType, t.containingType)) + if (obj is ConstructedType t && Equals(unboundGenericType, t.unboundGenericType) && Equals(containingType, t.containingType)) { - if (thisTypeArguments is null) return t.thisTypeArguments is null; - if (!(t.thisTypeArguments is null)) return thisTypeArguments.SequenceEqual(t.thisTypeArguments); + if (thisTypeArguments is null) + return t.thisTypeArguments is null; + if (!(t.thisTypeArguments is null)) + return thisTypeArguments.SequenceEqual(t.thisTypeArguments); } return false; } public override int GetHashCode() { - int h = unboundGenericType.GetHashCode(); + var h = unboundGenericType.GetHashCode(); h = 13 * h + (containingType is null ? 0 : containingType.GetHashCode()); if (!(thisTypeArguments is null)) h = h * 13 + thisTypeArguments.SequenceHash(); return h; } - readonly Type containingType; - public override Type ContainingType => containingType; + private readonly Type? containingType; + public override Type? ContainingType => containingType; public override string Name => unboundGenericType.Name; - public override Namespace Namespace => unboundGenericType.Namespace; + public override Namespace Namespace => unboundGenericType.Namespace!; public override int ThisTypeParameters => thisTypeArguments == null ? 0 : thisTypeArguments.Length; @@ -826,7 +826,7 @@ public override void WriteId(TextWriter trapFile, bool inContext) if (thisTypeArguments != null && thisTypeArguments.Any()) { trapFile.Write('<'); - int index = 0; + var index = 0; foreach (var t in thisTypeArguments) { trapFile.WriteSeparator(",", ref index); @@ -845,13 +845,13 @@ public override void WriteId(TextWriter trapFile, bool inContext) public sealed class PrimitiveType : Type { - readonly PrimitiveTypeCode typeCode; + private readonly PrimitiveTypeCode typeCode; public PrimitiveType(Context cx, PrimitiveTypeCode tc) : base(cx) { typeCode = tc; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is PrimitiveType pt && typeCode == pt.typeCode; } @@ -869,9 +869,9 @@ public override void WriteId(TextWriter trapFile, bool inContext) public override string Name => typeCode.Id(); - public override Namespace Namespace => cx.SystemNamespace; + public override Namespace Namespace => Cx.SystemNamespace; - public override Type ContainingType => null; + public override Type? ContainingType => null; public override int ThisTypeParameters => 0; @@ -889,24 +889,22 @@ public override void WriteAssemblyPrefix(TextWriter trapFile) { } /// /// An array type. /// - sealed class ArrayType : Type, IArrayType + internal sealed class ArrayType : Type, IArrayType { - readonly Type elementType; - readonly int rank; + private readonly Type elementType; + private readonly int rank; - public ArrayType(Context cx, Type element, ArrayShape shape) : base(cx) + public ArrayType(Context cx, Type elementType, int rank) : base(cx) { - rank = shape.Rank; - elementType = element; + this.rank = rank; + this.elementType = elementType; } - public ArrayType(Context cx, Type element) : base(cx) + public ArrayType(Context cx, Type elementType) : this(cx, elementType, 1) { - rank = 1; - elementType = element; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is ArrayType array && elementType.Equals(array.elementType) && rank == array.rank; } @@ -920,24 +918,24 @@ public override void WriteId(TextWriter trapFile, bool inContext) { elementType.GetId(trapFile, inContext); trapFile.Write('['); - for (int i = 1; i < rank; ++i) + for (var i = 1; i < rank; ++i) trapFile.Write(','); trapFile.Write(']'); } public override string Name => elementType.Name + "[]"; - public override Namespace Namespace => cx.SystemNamespace; + public override Namespace Namespace => Cx.SystemNamespace; - public override Type ContainingType => null; + public override Type? ContainingType => null; public override int ThisTypeParameters => elementType.ThisTypeParameters; public override CilTypeKind Kind => CilTypeKind.Array; - public override Type Construct(IEnumerable typeArguments) => cx.Populate(new ArrayType(cx, elementType.Construct(typeArguments))); + public override Type Construct(IEnumerable typeArguments) => Cx.Populate(new ArrayType(Cx, elementType.Construct(typeArguments))); - public override Type SourceDeclaration => cx.Populate(new ArrayType(cx, elementType.SourceDeclaration)); + public override Type SourceDeclaration => Cx.Populate(new ArrayType(Cx, elementType.SourceDeclaration)); public override IEnumerable Contents { @@ -959,22 +957,22 @@ public override IEnumerable Contents public override IEnumerable MethodParameters => throw new NotImplementedException(); } - interface ITypeParameter : IType + internal interface ITypeParameter : IType { } - abstract class TypeParameter : Type, ITypeParameter + internal abstract class TypeParameter : Type, ITypeParameter { protected readonly GenericContext gc; - public TypeParameter(GenericContext gc) : base(gc.cx) + protected TypeParameter(GenericContext gc) : base(gc.Cx) { this.gc = gc; } - public override Namespace Namespace => null; + public override Namespace? Namespace => null; - public override Type ContainingType => null; + public override Type? ContainingType => null; public override int ThisTypeParameters => 0; @@ -984,11 +982,11 @@ public TypeParameter(GenericContext gc) : base(gc.cx) public override Type Construct(IEnumerable typeArguments) => throw new InternalError("Attempt to construct a type parameter"); - public IEnumerable PopulateHandle(GenericContext gc, GenericParameterHandle parameterHandle) + public IEnumerable PopulateHandle(GenericParameterHandle parameterHandle) { if (!parameterHandle.IsNil) { - var tp = cx.mdReader.GetGenericParameter(parameterHandle); + var tp = Cx.MdReader.GetGenericParameter(parameterHandle); if (tp.Attributes.HasFlag(GenericParameterAttributes.Contravariant)) yield return Tuples.cil_typeparam_contravariant(this); @@ -1001,9 +999,9 @@ public IEnumerable PopulateHandle(GenericContext gc, Generic if (tp.Attributes.HasFlag(GenericParameterAttributes.NotNullableValueTypeConstraint)) yield return Tuples.cil_typeparam_struct(this); - foreach (var constraint in tp.GetConstraints().Select(h => cx.mdReader.GetGenericParameterConstraint(h))) + foreach (var constraint in tp.GetConstraints().Select(h => Cx.MdReader.GetGenericParameterConstraint(h))) { - var t = (Type)cx.CreateGeneric(this.gc, constraint.Type); + var t = (Type)Cx.CreateGeneric(this.gc, constraint.Type); yield return t; yield return Tuples.cil_typeparam_constraint(this, t); } @@ -1011,10 +1009,10 @@ public IEnumerable PopulateHandle(GenericContext gc, Generic } } - sealed class MethodTypeParameter : TypeParameter + internal sealed class MethodTypeParameter : TypeParameter { - readonly Method method; - readonly int index; + private readonly Method method; + private readonly int index; public override void WriteId(TextWriter trapFile, bool inContext) { @@ -1034,7 +1032,7 @@ public MethodTypeParameter(GenericContext gc, Method m, int index) : base(gc) this.index = index; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is MethodTypeParameter tp && method.Equals(tp.method) && index == tp.index; } @@ -1061,10 +1059,10 @@ public override IEnumerable Contents } - sealed class TypeTypeParameter : TypeParameter + internal sealed class TypeTypeParameter : TypeParameter { - readonly Type type; - readonly int index; + private readonly Type type; + private readonly int index; public TypeTypeParameter(GenericContext cx, Type t, int i) : base(cx) { @@ -1072,7 +1070,7 @@ public TypeTypeParameter(GenericContext cx, Type t, int i) : base(cx) type = t; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is TypeTypeParameter tp && type.Equals(tp.type) && index == tp.index; } @@ -1089,7 +1087,7 @@ public override void WriteId(TextWriter trapFile, bool inContext) trapFile.Write(index); } - public override TypeContainer Parent => type ?? gc as TypeContainer; + public override TypeContainer Parent => type; public override string Name => "!" + index; public override IEnumerable TypeParameters => Enumerable.Empty(); @@ -1106,20 +1104,20 @@ public override IEnumerable Contents } } - interface IPointerType : IType + internal interface IPointerType : IType { } - sealed class PointerType : Type, IPointerType + internal sealed class PointerType : Type, IPointerType { - readonly Type pointee; + private readonly Type pointee; public PointerType(Context cx, Type pointee) : base(cx) { this.pointee = pointee; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is PointerType pt && pointee.Equals(pt.pointee); } @@ -1138,9 +1136,9 @@ public override void WriteId(TextWriter trapFile, bool inContext) public override string Name => pointee.Name + "*"; - public override Namespace Namespace => pointee.Namespace; + public override Namespace? Namespace => pointee.Namespace; - public override Type ContainingType => pointee.ContainingType; + public override Type? ContainingType => pointee.ContainingType; public override TypeContainer Parent => pointee.Parent; @@ -1166,7 +1164,7 @@ public override IEnumerable Contents } } - sealed class ErrorType : Type + internal sealed class ErrorType : Type { public ErrorType(Context cx) : base(cx) { @@ -1178,9 +1176,9 @@ public ErrorType(Context cx) : base(cx) public override string Name => "!error"; - public override Namespace Namespace => cx.GlobalNamespace; + public override Namespace Namespace => Cx.GlobalNamespace; - public override Type ContainingType => null; + public override Type? ContainingType => null; public override int ThisTypeParameters => 0; @@ -1193,30 +1191,42 @@ public ErrorType(Context cx) : base(cx) public override Type Construct(IEnumerable typeArguments) => throw new NotImplementedException(); } - interface ITypeSignature + internal interface ITypeSignature { void WriteId(TextWriter trapFile, GenericContext gc); } public class SignatureDecoder : ISignatureTypeProvider { - struct Array : ITypeSignature + private struct Array : ITypeSignature { - public ITypeSignature elementType; - public ArrayShape shape; + private readonly ITypeSignature elementType; + private readonly ArrayShape shape; + + public Array(ITypeSignature elementType, ArrayShape shape) : this() + { + this.elementType = elementType; + this.shape = shape; + } + public void WriteId(TextWriter trapFile, GenericContext gc) { elementType.WriteId(trapFile, gc); trapFile.Write('['); - for (int i=1; i signature; public void WriteId(TextWriter trapFile, GenericContext gc) { @@ -1236,25 +1245,31 @@ public void WriteId(TextWriter trapFile, GenericContext gc) } ITypeSignature IConstructedTypeProvider.GetArrayType(ITypeSignature elementType, ArrayShape shape) => - new Array { elementType = elementType, shape = shape }; + new Array(elementType, shape); ITypeSignature IConstructedTypeProvider.GetByReferenceType(ITypeSignature elementType) => - new ByRef { elementType = elementType }; + new ByRef(elementType); ITypeSignature ISignatureTypeProvider.GetFunctionPointerType(MethodSignature signature) => - new FnPtr { signature = signature }; + new FnPtr(); - class Instantiation : ITypeSignature + private class Instantiation : ITypeSignature { - public ITypeSignature genericType; - public ImmutableArray typeArguments; + private readonly ITypeSignature genericType; + private readonly ImmutableArray typeArguments; + + public Instantiation(ITypeSignature genericType, ImmutableArray typeArguments) + { + this.genericType = genericType; + this.typeArguments = typeArguments; + } public void WriteId(TextWriter trapFile, GenericContext gc) { genericType.WriteId(trapFile, gc); trapFile.Write('<'); - int index = 0; - foreach(var arg in typeArguments) + var index = 0; + foreach (var arg in typeArguments) { trapFile.WriteSeparator(",", ref index); arg.WriteId(trapFile, gc); @@ -1264,12 +1279,18 @@ public void WriteId(TextWriter trapFile, GenericContext gc) } ITypeSignature IConstructedTypeProvider.GetGenericInstantiation(ITypeSignature genericType, ImmutableArray typeArguments) => - new Instantiation { genericType = genericType, typeArguments = typeArguments }; + new Instantiation(genericType, typeArguments); - class GenericMethodParameter : ITypeSignature + private class GenericMethodParameter : ITypeSignature { - public object innerGc; - public int index; + private readonly object innerGc; + private readonly int index; + + public GenericMethodParameter(object innerGc, int index) + { + this.innerGc = innerGc; + this.index = index; + } public void WriteId(TextWriter trapFile, GenericContext outerGc) { @@ -1282,9 +1303,14 @@ public void WriteId(TextWriter trapFile, GenericContext outerGc) } } - class GenericTypeParameter : ITypeSignature + private class GenericTypeParameter : ITypeSignature { - public int index; + private readonly int index; + + public GenericTypeParameter(int index) + { + this.index = index; + } public void WriteId(TextWriter trapFile, GenericContext gc) { @@ -1294,16 +1320,19 @@ public void WriteId(TextWriter trapFile, GenericContext gc) } ITypeSignature ISignatureTypeProvider.GetGenericMethodParameter(object genericContext, int index) => - new GenericMethodParameter { innerGc = genericContext, index = index }; + new GenericMethodParameter(genericContext, index); ITypeSignature ISignatureTypeProvider.GetGenericTypeParameter(object genericContext, int index) => - new GenericTypeParameter { index = index }; + new GenericTypeParameter(index); - class Modified : ITypeSignature + private class Modified : ITypeSignature { - public ITypeSignature modifier; - public ITypeSignature unmodifiedType; - public bool isRequired; + private readonly ITypeSignature unmodifiedType; + + public Modified(ITypeSignature unmodifiedType) + { + this.unmodifiedType = unmodifiedType; + } public void WriteId(TextWriter trapFile, GenericContext gc) { @@ -1313,12 +1342,17 @@ public void WriteId(TextWriter trapFile, GenericContext gc) ITypeSignature ISignatureTypeProvider.GetModifiedType(ITypeSignature modifier, ITypeSignature unmodifiedType, bool isRequired) { - return new Modified { modifier = modifier, unmodifiedType = unmodifiedType, isRequired = isRequired }; + return new Modified(unmodifiedType); } - class Pinned : ITypeSignature + private class Pinned : ITypeSignature { - public ITypeSignature elementType; + private readonly ITypeSignature elementType; + + public Pinned(ITypeSignature elementType) + { + this.elementType = elementType; + } public void WriteId(TextWriter trapFile, GenericContext gc) { @@ -1329,12 +1363,17 @@ public void WriteId(TextWriter trapFile, GenericContext gc) ITypeSignature ISignatureTypeProvider.GetPinnedType(ITypeSignature elementType) { - return new Pinned { elementType = elementType }; + return new Pinned(elementType); } - class PointerType : ITypeSignature + private class PointerType : ITypeSignature { - public ITypeSignature elementType; + private readonly ITypeSignature elementType; + + public PointerType(ITypeSignature elementType) + { + this.elementType = elementType; + } public void WriteId(TextWriter trapFile, GenericContext gc) { @@ -1345,12 +1384,17 @@ public void WriteId(TextWriter trapFile, GenericContext gc) ITypeSignature IConstructedTypeProvider.GetPointerType(ITypeSignature elementType) { - return new PointerType { elementType = elementType }; + return new PointerType(elementType); } - class Primitive : ITypeSignature + private class Primitive : ITypeSignature { - public PrimitiveTypeCode typeCode; + private readonly PrimitiveTypeCode typeCode; + + public Primitive(PrimitiveTypeCode typeCode) + { + this.typeCode = typeCode; + } public void WriteId(TextWriter trapFile, GenericContext gc) { @@ -1360,12 +1404,18 @@ public void WriteId(TextWriter trapFile, GenericContext gc) ITypeSignature ISimpleTypeProvider.GetPrimitiveType(PrimitiveTypeCode typeCode) { - return new Primitive { typeCode = typeCode }; + return new Primitive(typeCode); } - class SzArrayType : ITypeSignature + private class SzArrayType : ITypeSignature { - public ITypeSignature elementType; + private readonly ITypeSignature elementType; + + public SzArrayType(ITypeSignature elementType) + { + this.elementType = elementType; + } + public void WriteId(TextWriter trapFile, GenericContext gc) { elementType.WriteId(trapFile, gc); @@ -1375,41 +1425,49 @@ public void WriteId(TextWriter trapFile, GenericContext gc) ITypeSignature ISZArrayTypeProvider.GetSZArrayType(ITypeSignature elementType) { - return new SzArrayType { elementType = elementType }; + return new SzArrayType(elementType); } - class TypeDefinition : ITypeSignature + private class TypeDefinition : ITypeSignature { - public TypeDefinitionHandle handle; - public byte rawTypeKind; - Type type; + private readonly TypeDefinitionHandle handle; + + public TypeDefinition(TypeDefinitionHandle handle) + { + this.handle = handle; + } + public void WriteId(TextWriter trapFile, GenericContext gc) { - type = (Type)gc.cx.Create(handle); + var type = (Type)gc.Cx.Create(handle); type.WriteId(trapFile); } } ITypeSignature ISimpleTypeProvider.GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) { - return new TypeDefinition { handle = handle, rawTypeKind = rawTypeKind }; + return new TypeDefinition(handle); } - class TypeReference : ITypeSignature + private class TypeReference : ITypeSignature { - public TypeReferenceHandle handle; - public byte rawTypeKind; // struct/class (not used) - Type type; + private readonly TypeReferenceHandle handle; + + public TypeReference(TypeReferenceHandle handle) + { + this.handle = handle; + } + public void WriteId(TextWriter trapFile, GenericContext gc) { - type = (Type)gc.cx.Create(handle); + var type = (Type)gc.Cx.Create(handle); type.WriteId(trapFile); } } ITypeSignature ISimpleTypeProvider.GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) { - return new TypeReference { handle = handle, rawTypeKind = rawTypeKind }; + return new TypeReference(handle); } ITypeSignature ISignatureTypeProvider.GetTypeFromSpecification(MetadataReader reader, object genericContext, TypeSpecificationHandle handle, byte rawTypeKind) @@ -1425,7 +1483,7 @@ ITypeSignature ISignatureTypeProvider.GetTypeFromSpecifi /// public class TypeSignatureDecoder : ISignatureTypeProvider { - readonly Context cx; + private readonly Context cx; public TypeSignatureDecoder(Context cx) { @@ -1433,7 +1491,7 @@ public TypeSignatureDecoder(Context cx) } Type IConstructedTypeProvider.GetArrayType(Type elementType, ArrayShape shape) => - cx.Populate(new ArrayType(cx, elementType, shape)); + cx.Populate(new ArrayType(cx, elementType, shape.Rank)); Type IConstructedTypeProvider.GetByReferenceType(Type elementType) => elementType; // ?? @@ -1451,8 +1509,7 @@ Type ISignatureTypeProvider.GetGenericTypeParameter(Generi genericContext.GetGenericTypeParameter(index); Type ISignatureTypeProvider.GetModifiedType(Type modifier, Type unmodifiedType, bool isRequired) => - // !! Not implemented properly - unmodifiedType; + unmodifiedType; // !! Not implemented properly Type ISignatureTypeProvider.GetPinnedType(Type elementType) => cx.Populate(new PointerType(cx, elementType)); diff --git a/csharp/extractor/Semmle.Extraction.CIL/ExtractionProduct.cs b/csharp/extractor/Semmle.Extraction.CIL/ExtractionProduct.cs index f0e85057903b..52415af93493 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/ExtractionProduct.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/ExtractionProduct.cs @@ -63,12 +63,12 @@ public virtual void Extract(Context cx2) cx2.Extract(this); } - public readonly Context cx; + public Context Cx { get; } protected UnlabelledEntity(Context cx) { - this.cx = cx; - cx.cx.AddFreshLabel(this); + this.Cx = cx; + cx.Cx.AddFreshLabel(this); } TrapStackBehaviour IEntity.TrapStackBehaviour => TrapStackBehaviour.NoLabel; @@ -101,20 +101,18 @@ public void Extract(Context cx2) cx2.Populate(this); } - public readonly Context cx; + public Context Cx { get; } protected LabelledEntity(Context cx) { - this.cx = cx; + this.Cx = cx; } public override string ToString() { - using (var writer = new StringWriter()) - { - WriteQuotedId(writer); - return writer.ToString(); - } + using var writer = new StringWriter(); + WriteQuotedId(writer); + return writer.ToString(); } TrapStackBehaviour IEntity.TrapStackBehaviour => TrapStackBehaviour.NoLabel; @@ -123,9 +121,9 @@ public override string ToString() /// /// A tuple that is an extraction product. /// - class Tuple : IExtractionProduct + internal class Tuple : IExtractionProduct { - readonly Extraction.Tuple tuple; + private readonly Extraction.Tuple tuple; public Tuple(string name, params object[] args) { @@ -134,7 +132,7 @@ public Tuple(string name, params object[] args) public void Extract(Context cx) { - cx.cx.Emit(tuple); + cx.Cx.Emit(tuple); } public override string ToString() => tuple.ToString(); diff --git a/csharp/extractor/Semmle.Extraction.CIL/Factories.cs b/csharp/extractor/Semmle.Extraction.CIL/Factories.cs index f522521a8456..dd09727f3c0d 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Factories.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Factories.cs @@ -9,9 +9,9 @@ namespace Semmle.Extraction.CIL /// /// Provides methods for creating and caching various entities. /// - public partial class Context + public sealed partial class Context { - readonly Dictionary ids = new Dictionary(); + private readonly Dictionary ids = new Dictionary(); public T Populate(T e) where T : IExtractedEntity { @@ -27,28 +27,26 @@ public T Populate(T e) where T : IExtractedEntity } else { - e.Label = cx.GetNewLabel(); - cx.DefineLabel(e, cx.TrapWriter.Writer, cx.Extractor); + e.Label = Cx.GetNewLabel(); + Cx.DefineLabel(e, Cx.TrapWriter.Writer, Cx.Extractor); ids.Add(e, e.Label); - cx.PopulateLater(() => + Cx.PopulateLater(() => { foreach (var c in e.Contents) c.Extract(this); }); #if DEBUG_LABELS - using (var writer = new StringWriter()) + using var writer = new StringWriter(); + e.WriteId(writer); + var id = writer.ToString(); + + if (debugLabels.TryGetValue(id, out var previousEntity)) + { + Cx.Extractor.Message(new Message("Duplicate trap ID", id, null, severity: Util.Logging.Severity.Warning)); + } + else { - e.WriteId(writer); - var id = writer.ToString(); - - if (debugLabels.TryGetValue(id, out IExtractedEntity previousEntity)) - { - cx.Extractor.Message(new Message("Duplicate trap ID", id, null, severity: Util.Logging.Severity.Warning)); - } - else - { - debugLabels.Add(id, e); - } + debugLabels.Add(id, e); } #endif } @@ -70,13 +68,15 @@ public IExtractedEntity Create(Handle h) public PrimitiveType Create(PrimitiveTypeCode code) { - PrimitiveType e = primitiveTypes[(int)code]; + var e = primitiveTypes[(int)code]; if (e is null) { - e = new PrimitiveType(this, code); - e.Label = cx.GetNewLabel(); - cx.DefineLabel(e, cx.TrapWriter.Writer, cx.Extractor); + e = new PrimitiveType(this, code) + { + Label = Cx.GetNewLabel() + }; + Cx.DefineLabel(e, Cx.TrapWriter.Writer, Cx.Extractor); primitiveTypes[(int)code] = e; } @@ -97,9 +97,9 @@ public PrimitiveType Create(PrimitiveTypeCode code) /// public IExtractedEntity CreateGeneric(GenericContext genericContext, Handle h) => genericHandleFactory[genericContext, h]; - readonly GenericContext defaultGenericContext; + private readonly GenericContext defaultGenericContext; - IExtractedEntity CreateGenericHandle(GenericContext gc, Handle handle) + private IExtractedEntity CreateGenericHandle(GenericContext gc, Handle handle) { IExtractedEntity entity; switch (handle.Kind) @@ -114,7 +114,7 @@ IExtractedEntity CreateGenericHandle(GenericContext gc, Handle handle) entity = new MethodSpecificationMethod(gc, (MethodSpecificationHandle)handle); break; case HandleKind.FieldDefinition: - entity = new DefinitionField(gc, (FieldDefinitionHandle)handle); + entity = new DefinitionField(gc.Cx, (FieldDefinitionHandle)handle); break; case HandleKind.TypeReference: var tr = new TypeReferenceType(this, (TypeReferenceHandle)handle); @@ -136,9 +136,9 @@ IExtractedEntity CreateGenericHandle(GenericContext gc, Handle handle) return entity; } - IExtractedEntity Create(GenericContext gc, MemberReferenceHandle handle) + private IExtractedEntity Create(GenericContext gc, MemberReferenceHandle handle) { - var mr = mdReader.GetMemberReference(handle); + var mr = MdReader.GetMemberReference(handle); switch (mr.GetKind()) { case MemberReferenceKind.Method: @@ -155,15 +155,15 @@ IExtractedEntity Create(GenericContext gc, MemberReferenceHandle handle) /// /// The string handle. /// The string. - public string GetString(StringHandle h) => mdReader.GetString(h); + public string GetString(StringHandle h) => MdReader.GetString(h); #region Namespaces - readonly CachedFunction namespaceFactory; + private readonly CachedFunction namespaceFactory; public Namespace CreateNamespace(StringHandle fqn) => namespaceFactory[fqn]; - readonly Lazy globalNamespace, systemNamespace; + private readonly Lazy globalNamespace, systemNamespace; /// /// The entity representing the global namespace. @@ -180,9 +180,9 @@ IExtractedEntity Create(GenericContext gc, MemberReferenceHandle handle) /// /// The fully-qualified namespace name. /// The namespace entity. - Namespace CreateNamespace(string fqn) => Populate(new Namespace(this, fqn)); + private Namespace CreateNamespace(string fqn) => Populate(new Namespace(this, fqn)); - readonly CachedFunction namespaceDefinitionFactory; + private readonly CachedFunction namespaceDefinitionFactory; /// /// Creates a namespace from a namespace handle. @@ -191,18 +191,19 @@ IExtractedEntity Create(GenericContext gc, MemberReferenceHandle handle) /// The namespace entity. public Namespace Create(NamespaceDefinitionHandle handle) => namespaceDefinitionFactory[handle]; - Namespace CreateNamespace(NamespaceDefinitionHandle handle) + private Namespace CreateNamespace(NamespaceDefinitionHandle handle) { - if (handle.IsNil) return GlobalNamespace; - NamespaceDefinition nd = mdReader.GetNamespaceDefinition(handle); + if (handle.IsNil) + return GlobalNamespace; + var nd = MdReader.GetNamespaceDefinition(handle); return Populate(new Namespace(this, GetString(nd.Name), Create(nd.Parent))); } #endregion #region Locations - readonly CachedFunction sourceFiles; - readonly CachedFunction folders; - readonly CachedFunction sourceLocations; + private readonly CachedFunction sourceFiles; + private readonly CachedFunction folders; + private readonly CachedFunction sourceLocations; /// /// Creates a source file entity from a PDB source file. @@ -216,7 +217,7 @@ Namespace CreateNamespace(NamespaceDefinitionHandle handle) /// /// The path of the folder. /// A folder entity. - public Folder CreateFolder(string path) => folders[path]; + public Folder CreateFolder(PathTransformer.ITransformedPath path) => folders[path]; /// /// Creates a source location. @@ -227,7 +228,7 @@ Namespace CreateNamespace(NamespaceDefinitionHandle handle) #endregion - readonly CachedFunction genericHandleFactory; + private readonly CachedFunction genericHandleFactory; /// /// Gets the short name of a member, without the preceding interface qualifier. @@ -236,9 +237,11 @@ Namespace CreateNamespace(NamespaceDefinitionHandle handle) /// The short name. public string ShortName(StringHandle handle) { - string str = mdReader.GetString(handle); - if (str.EndsWith(".ctor")) return ".ctor"; - if (str.EndsWith(".cctor")) return ".cctor"; + var str = MdReader.GetString(handle); + if (str.EndsWith(".ctor")) + return ".ctor"; + if (str.EndsWith(".cctor")) + return ".cctor"; var dot = str.LastIndexOf('.'); return dot == -1 ? str : str.Substring(dot + 1); } diff --git a/csharp/extractor/Semmle.Extraction.CIL/PDB/MetadataPdbReader.cs b/csharp/extractor/Semmle.Extraction.CIL/PDB/MetadataPdbReader.cs index 33e8460090d8..2384bb3e2e13 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/PDB/MetadataPdbReader.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/PDB/MetadataPdbReader.cs @@ -13,9 +13,9 @@ namespace Semmle.Extraction.PDB /// /// PDB information can be in a separate PDB file, or embedded in the DLL. /// - class MetadataPdbReader : IPdb + internal sealed class MetadataPdbReader : IPdb { - class SourceFile : ISourceFile + private class SourceFile : ISourceFile { public SourceFile(MetadataReader reader, DocumentHandle handle) { @@ -25,13 +25,13 @@ public SourceFile(MetadataReader reader, DocumentHandle handle) public string Path { get; private set; } - public string Contents => File.Exists(Path) ? File.ReadAllText(Path, System.Text.Encoding.Default) : null; + public string? Contents => File.Exists(Path) ? File.ReadAllText(Path, System.Text.Encoding.Default) : null; } // Turns out to be very important to keep the MetadataReaderProvider live // or the reader will crash. - readonly MetadataReaderProvider provider; - readonly MetadataReader reader; + private readonly MetadataReaderProvider provider; + private readonly MetadataReader reader; public MetadataPdbReader(MetadataReaderProvider provider) { @@ -41,34 +41,40 @@ public MetadataPdbReader(MetadataReaderProvider provider) public IEnumerable SourceFiles => reader.Documents.Select(handle => new SourceFile(reader, handle)); - public IMethod GetMethod(MethodDebugInformationHandle handle) + public IMethod? GetMethod(MethodDebugInformationHandle handle) { var debugInfo = reader.GetMethodDebugInformation(handle); - var sequencePoints = debugInfo.GetSequencePoints(). - Where(p => !p.Document.IsNil && !p.IsHidden). - Select(p => new SequencePoint(p.Offset, new Location(new SourceFile(reader, p.Document), p.StartLine, p.StartColumn, p.EndLine, p.EndColumn))). - Where(p => p.Location.File.Path != null). - ToArray(); + var sequencePoints = debugInfo.GetSequencePoints() + .Where(p => !p.Document.IsNil && !p.IsHidden) + .Select(p => new SequencePoint(p.Offset, new Location( + new SourceFile(reader, p.Document), p.StartLine, p.StartColumn, p.EndLine, p.EndColumn))) + .Where(p => p.Location.File.Path != null) + .ToArray(); - return sequencePoints.Any() ? new Method() { SequencePoints = sequencePoints } : null; + return sequencePoints.Any() ? new Method(sequencePoints) : null; } - public static MetadataPdbReader CreateFromAssembly(string assemblyPath, PEReader peReader) + public static MetadataPdbReader? CreateFromAssembly(string assemblyPath, PEReader peReader) { - foreach (var provider in peReader. - ReadDebugDirectory(). - Where(d => d.Type == DebugDirectoryEntryType.EmbeddedPortablePdb). - Select(dirEntry => peReader.ReadEmbeddedPortablePdbDebugDirectoryData(dirEntry))) + var provider = peReader + .ReadDebugDirectory() + .Where(d => d.Type == DebugDirectoryEntryType.EmbeddedPortablePdb) + .Select(dirEntry => peReader.ReadEmbeddedPortablePdbDebugDirectoryData(dirEntry)) + .FirstOrDefault(); + + if (provider is object) { return new MetadataPdbReader(provider); } try { - MetadataReaderProvider provider; - string pdbPath; - if (peReader.TryOpenAssociatedPortablePdb(assemblyPath, s => new FileStream(s, FileMode.Open, FileAccess.Read, FileShare.Read), out provider, out pdbPath)) + if (peReader.TryOpenAssociatedPortablePdb( + assemblyPath, + s => new FileStream(s, FileMode.Open, FileAccess.Read, FileShare.Read), + out provider, + out _)) { return new MetadataPdbReader(provider); } diff --git a/csharp/extractor/Semmle.Extraction.CIL/PDB/NativePdbReader.cs b/csharp/extractor/Semmle.Extraction.CIL/PDB/NativePdbReader.cs index 0f25b281aab4..a9a504596219 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/PDB/NativePdbReader.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/PDB/NativePdbReader.cs @@ -14,34 +14,33 @@ namespace Semmle.Extraction.PDB /// A PDB reader using Microsoft.DiaSymReader.Native. /// This is an unmanaged Windows DLL, which therefore only works on Windows. /// - class NativePdbReader : IPdb + internal sealed class NativePdbReader : IPdb { - sealed class Document : ISourceFile + private sealed class Document : ISourceFile { - readonly ISymUnmanagedDocument document; + private readonly ISymUnmanagedDocument document; public Document(ISymUnmanagedDocument doc) { document = doc; - contents = new Lazy(() => + contents = new Lazy(() => { - bool isEmbedded; - if (document.HasEmbeddedSource(out isEmbedded) == 0 && isEmbedded) + if (document.HasEmbeddedSource(out var isEmbedded) == 0 && isEmbedded) { var rawContents = document.GetEmbeddedSource().ToArray(); return System.Text.Encoding.Default.GetString(rawContents); } - else - { - return File.Exists(Path) ? File.ReadAllText(Path) : null; - } + + return File.Exists(Path) + ? File.ReadAllText(Path) + : null; + }); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - var otherDoc = obj as Document; - return otherDoc != null && Path.Equals(otherDoc.Path); + return obj is Document otherDoc && Path.Equals(otherDoc.Path); } public override int GetHashCode() => Path.GetHashCode(); @@ -50,44 +49,44 @@ public override bool Equals(object obj) public override string ToString() => Path; - readonly Lazy contents; + private readonly Lazy contents; - public string Contents => contents.Value; + public string? Contents => contents.Value; } public IEnumerable SourceFiles => reader.GetDocuments().Select(d => new Document(d)); - public IMethod GetMethod(MethodDebugInformationHandle h) + public IMethod? GetMethod(MethodDebugInformationHandle h) { - int methodToken = MetadataTokens.GetToken(h.ToDefinitionHandle()); + var methodToken = MetadataTokens.GetToken(h.ToDefinitionHandle()); var method = reader.GetMethod(methodToken); if (method != null) { - int count; - if (method.GetSequencePointCount(out count) != 0 || count == 0) + if (method.GetSequencePointCount(out var count) != 0 || count == 0) return null; - var s = method.GetSequencePoints(). - Where(sp => !sp.IsHidden). - Select(sp => new SequencePoint(sp.Offset, new Location(new Document(sp.Document), sp.StartLine, sp.StartColumn, sp.EndLine, sp.EndColumn))). - ToArray(); + var s = method.GetSequencePoints() + .Where(sp => !sp.IsHidden) + .Select(sp => new SequencePoint(sp.Offset, new Location( + new Document(sp.Document), sp.StartLine, sp.StartColumn, sp.EndLine, sp.EndColumn))) + .ToArray(); - return s.Any() ? new Method { SequencePoints = s } : null; + return s.Any() ? new Method(s) : null; } return null; } - NativePdbReader(string path) + private NativePdbReader(string path) { pdbStream = new FileStream(path, FileMode.Open); var metadataProvider = new MdProvider(); reader = SymUnmanagedReaderFactory.CreateReader(pdbStream, metadataProvider); } - readonly ISymUnmanagedReader5 reader; - readonly FileStream pdbStream; + private readonly ISymUnmanagedReader5 reader; + private readonly FileStream pdbStream; - public static NativePdbReader CreateFromAssembly(string assemblyPath, PEReader peReader) + public static NativePdbReader? CreateFromAssembly(PEReader peReader) { // The Native PDB reader uses an unmanaged Windows DLL // so only works on Windows. @@ -96,11 +95,13 @@ public static NativePdbReader CreateFromAssembly(string assemblyPath, PEReader p var debugDirectory = peReader.ReadDebugDirectory(); - foreach (var path in debugDirectory. - Where(d => d.Type == DebugDirectoryEntryType.CodeView). - Select(peReader.ReadCodeViewDebugDirectoryData). - Select(cv => cv.Path). - Where(path => File.Exists(path))) + var path = debugDirectory + .Where(d => d.Type == DebugDirectoryEntryType.CodeView) + .Select(peReader.ReadCodeViewDebugDirectoryData) + .Select(cv => cv.Path) + .FirstOrDefault(File.Exists); + + if (path is object) { return new NativePdbReader(path); } @@ -117,13 +118,13 @@ public void Dispose() /// /// This is not used but is seemingly needed in order to use DiaSymReader. /// - class MdProvider : ISymReaderMetadataProvider + internal class MdProvider : ISymReaderMetadataProvider { public MdProvider() { } - public object GetMetadataImport() => null; + public object? GetMetadataImport() => null; public unsafe bool TryGetStandaloneSignature(int standaloneSignatureToken, out byte* signature, out int length) => throw new NotImplementedException(); diff --git a/csharp/extractor/Semmle.Extraction.CIL/PDB/PdbReader.cs b/csharp/extractor/Semmle.Extraction.CIL/PDB/PdbReader.cs index c2f4f94f59f1..cfdddca8de8e 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/PDB/PdbReader.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/PDB/PdbReader.cs @@ -1,5 +1,4 @@ -using Microsoft.DiaSymReader; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Reflection.Metadata; @@ -16,12 +15,12 @@ public struct SequencePoint /// /// The byte-offset of the instruction. /// - public readonly int Offset; + public int Offset { get; } /// /// The source location of the instruction. /// - public readonly Location Location; + public Location Location { get; } public override string ToString() { @@ -43,23 +42,36 @@ public sealed class Location /// /// The file containing the code. /// - public readonly ISourceFile File; + public ISourceFile File { get; } /// - /// The span of text within the text file. + /// The start line of text within the source file. /// - public readonly int StartLine, StartColumn, EndLine, EndColumn; + public int StartLine { get; } + + /// + /// The start column of text within the source file. + /// + public int StartColumn { get; } + + /// + /// The end line of text within the source file. + /// + public int EndLine { get; } + + /// + /// The end column of text within the source file. + /// + public int EndColumn { get; } public override string ToString() { return string.Format("({0},{1})-({2},{3})", StartLine, StartColumn, EndLine, EndColumn); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - var otherLocation = obj as Location; - - return otherLocation != null && + return obj is Location otherLocation && File.Equals(otherLocation.File) && StartLine == otherLocation.StartLine && StartColumn == otherLocation.StartColumn && @@ -89,9 +101,14 @@ public interface IMethod Location Location { get; } } - class Method : IMethod + internal class Method : IMethod { - public IEnumerable SequencePoints { get; set; } + public IEnumerable SequencePoints { get; } + + public Method(IEnumerable sequencePoints) + { + SequencePoints = sequencePoints; + } public Location Location => SequencePoints.First().Location; } @@ -111,7 +128,7 @@ public interface ISourceFile /// null if the contents are unavailable. /// E.g. if the PDB file exists but the corresponding source files are missing. /// - string Contents { get; } + string? Contents { get; } } /// @@ -131,21 +148,21 @@ public interface IPdb : IDisposable /// /// The handle to query. /// The method information, or null if the method does not have debug information. - IMethod GetMethod(MethodDebugInformationHandle methodHandle); + IMethod? GetMethod(MethodDebugInformationHandle methodHandle); } - class PdbReader + internal class PdbReader { /// /// Returns the PDB information associated with an assembly. /// /// The path to the assembly. - /// The PE reader for the assembky. + /// The PE reader for the assembly. /// A PdbReader, or null if no PDB information is available. - public static IPdb Create(string assemblyPath, PEReader peReader) + public static IPdb? Create(string assemblyPath, PEReader peReader) { - return (IPdb)MetadataPdbReader.CreateFromAssembly(assemblyPath, peReader) ?? - NativePdbReader.CreateFromAssembly(assemblyPath, peReader); + return (IPdb?)MetadataPdbReader.CreateFromAssembly(assemblyPath, peReader) ?? + NativePdbReader.CreateFromAssembly(peReader); } } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Semmle.Extraction.CIL.csproj b/csharp/extractor/Semmle.Extraction.CIL/Semmle.Extraction.CIL.csproj index 9db880787b0a..eb90b909b81c 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Semmle.Extraction.CIL.csproj +++ b/csharp/extractor/Semmle.Extraction.CIL/Semmle.Extraction.CIL.csproj @@ -1,12 +1,13 @@  - netcoreapp3.0 + netcoreapp3.1 Semmle.Extraction.CIL Semmle.Extraction.CIL false true win-x64;linux-x64;osx-x64 + enable diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Driver/Driver.cs b/csharp/extractor/Semmle.Extraction.CSharp.Driver/Driver.cs index e2892678041f..5806bd375b1d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Driver/Driver.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Driver/Driver.cs @@ -5,7 +5,7 @@ namespace Semmle.Extraction.CSharp /// public class Driver { - static int Main(string[] args) + public static int Main(string[] args) { return (int)Extractor.Run(args); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Driver/Semmle.Extraction.CSharp.Driver.csproj b/csharp/extractor/Semmle.Extraction.CSharp.Driver/Semmle.Extraction.CSharp.Driver.csproj index 7475350f9931..3ec25c498fed 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Driver/Semmle.Extraction.CSharp.Driver.csproj +++ b/csharp/extractor/Semmle.Extraction.CSharp.Driver/Semmle.Extraction.CSharp.Driver.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp3.0 + netcoreapp3.1 Semmle.Extraction.CSharp.Driver Semmle.Extraction.CSharp.Driver false diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/AssemblyCache.cs b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/AssemblyCache.cs index f93911b8a383..597ff6f2165d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/AssemblyCache.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/AssemblyCache.cs @@ -10,7 +10,7 @@ namespace Semmle.BuildAnalyser /// Searches for assembly DLLs, indexes them and provides /// a lookup facility from assembly ID to filename. /// - class AssemblyCache + internal class AssemblyCache { /// /// Locate all reference files and index them. @@ -33,57 +33,57 @@ public AssemblyCache(IEnumerable dirs, IProgressMonitor progress) /// (Indexing is performed at a later stage by IndexReferences()). /// /// The directory to index. - /// The number of DLLs within this directory. - int AddReferenceDirectory(string dir) + private void AddReferenceDirectory(string dir) { - int count = 0; foreach (var dll in new DirectoryInfo(dir).EnumerateFiles("*.dll", SearchOption.AllDirectories)) { - dlls.Add(dll.FullName); - ++count; + pendingDllsToIndex.Enqueue(dll.FullName); } - return count; } /// /// Indexes all DLLs we have located. /// Because this is a potentially time-consuming operation, it is put into a separate stage. /// - void IndexReferences() + private void IndexReferences() { // Read all of the files - foreach (var filename in dlls) + foreach (var filename in pendingDllsToIndex) { - var info = AssemblyInfo.ReadFromFile(filename); - - if (info.Valid) - { - assemblyInfo[filename] = info; - } - else - { - failedDlls.Add(filename); - } + IndexReference(filename); } // Index "assemblyInfo" by version string // The OrderBy is used to ensure that we by default select the highest version number. - foreach (var info in assemblyInfo.Values.OrderBy(info => info.Id)) + foreach (var info in assemblyInfoByFileName.Values.OrderBy(info => info.Id)) { foreach (var index in info.IndexStrings) - references[index] = info; + assemblyInfoById[index] = info; + } + } + + private void IndexReference(string filename) + { + try + { + var info = AssemblyInfo.ReadFromFile(filename); + assemblyInfoByFileName[filename] = info; + } + catch (AssemblyLoadException) + { + failedAssemblyInfoFileNames.Add(filename); } } /// /// The number of DLLs which are assemblies. /// - public int AssemblyCount => assemblyInfo.Count; + public int AssemblyCount => assemblyInfoByFileName.Count; /// /// The number of DLLs which weren't assemblies. (E.g. C++). /// - public int NonAssemblyCount => failedDlls.Count; + public int NonAssemblyCount => failedAssemblyInfoFileNames.Count; /// /// Given an assembly id, determine its full info. @@ -93,70 +93,67 @@ void IndexReferences() public AssemblyInfo ResolveReference(string id) { // Fast path if we've already seen this before. - if (failedReferences.Contains(id)) - return AssemblyInfo.Invalid; + if (failedAssemblyInfoIds.Contains(id)) + throw new AssemblyLoadException(); - var query = AssemblyInfo.MakeFromId(id); - id = query.Id; // Sanitise the id. + string assemblyName; + (id, assemblyName) = AssemblyInfo.ComputeSanitizedAssemblyInfo(id); // Look up the id in our references map. - AssemblyInfo result; - if (references.TryGetValue(id, out result)) + if (assemblyInfoById.TryGetValue(id, out var result)) { // The string is in the references map. return result; } - else - { - // Attempt to load the reference from the GAC. - try - { - var loadedAssembly = System.Reflection.Assembly.ReflectionOnlyLoad(id); - - if (loadedAssembly != null) - { - // The assembly was somewhere we haven't indexed before. - // Add this assembly to our index so that subsequent lookups are faster. - - result = AssemblyInfo.MakeFromAssembly(loadedAssembly); - references[id] = result; - assemblyInfo[loadedAssembly.Location] = result; - return result; - } - } - catch (FileNotFoundException) - { - // A suitable assembly could not be found - } - catch (FileLoadException) - { - // The assembly cannot be loaded for some reason - // e.g. The name is malformed. - } - catch (PlatformNotSupportedException) - { - // .NET Core does not have a GAC. - } - // Fallback position - locate the assembly by its lower-case name only. - var asmName = query.Name.ToLowerInvariant(); + // Attempt to load the reference from the GAC. + try + { + var loadedAssembly = System.Reflection.Assembly.ReflectionOnlyLoad(id); - if (references.TryGetValue(asmName, out result)) + if (loadedAssembly != null) { - references[asmName] = result; // Speed up the next time the same string is resolved + // The assembly was somewhere we haven't indexed before. + // Add this assembly to our index so that subsequent lookups are faster. + + result = AssemblyInfo.MakeFromAssembly(loadedAssembly); + assemblyInfoById[id] = result; + assemblyInfoByFileName[loadedAssembly.Location] = result; return result; } + } + catch (FileNotFoundException) + { + // A suitable assembly could not be found + } + catch (FileLoadException) + { + // The assembly cannot be loaded for some reason + // e.g. The name is malformed. + } + catch (PlatformNotSupportedException) + { + // .NET Core does not have a GAC. + } - failedReferences.Add(id); // Fail early next time + // Fallback position - locate the assembly by its lower-case name only. + var asmName = assemblyName.ToLowerInvariant(); - return AssemblyInfo.Invalid; + if (assemblyInfoById.TryGetValue(asmName, out result)) + { + assemblyInfoById[asmName] = result; // Speed up the next time the same string is resolved + return result; } + + failedAssemblyInfoIds.Add(id); // Fail early next time + + throw new AssemblyLoadException(); } /// /// All the assemblies we have indexed. /// - public IEnumerable AllAssemblies => assemblyInfo.Select(a => a.Value); + public IEnumerable AllAssemblies => assemblyInfoByFileName.Select(a => a.Value); /// /// Retrieve the assembly info of a pre-cached assembly. @@ -165,32 +162,32 @@ public AssemblyInfo ResolveReference(string id) /// The assembly info. public AssemblyInfo GetAssemblyInfo(string filepath) { - if(assemblyInfo.TryGetValue(filepath, out var info)) + if (assemblyInfoByFileName.TryGetValue(filepath, out var info)) { return info; } - else + + IndexReference(filepath); + + if (assemblyInfoByFileName.TryGetValue(filepath, out info)) { - info = AssemblyInfo.ReadFromFile(filepath); - assemblyInfo.Add(filepath, info); return info; } + + throw new AssemblyLoadException(); } - // List of pending DLLs to index. - readonly List dlls = new List(); + private readonly Queue pendingDllsToIndex = new Queue(); - // Map from filename to assembly info. - readonly Dictionary assemblyInfo = new Dictionary(); + private readonly Dictionary assemblyInfoByFileName = new Dictionary(); // List of DLLs which are not assemblies. // We probably don't need to keep this - readonly List failedDlls = new List(); + private readonly List failedAssemblyInfoFileNames = new List(); // Map from assembly id (in various formats) to the full info. - readonly Dictionary references = new Dictionary(); + private readonly Dictionary assemblyInfoById = new Dictionary(); - // Set of failed assembly ids. - readonly HashSet failedReferences = new HashSet(); + private readonly HashSet failedAssemblyInfoIds = new HashSet(); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/AssemblyInfo.cs b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/AssemblyInfo.cs index 29115d4a4499..15d29ed7b100 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/AssemblyInfo.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/AssemblyInfo.cs @@ -11,40 +11,35 @@ namespace Semmle.BuildAnalyser /// /// Stores information about an assembly file (DLL). /// - sealed class AssemblyInfo + internal sealed class AssemblyInfo { /// /// The file containing the assembly. /// - public string Filename { get; private set; } - - /// - /// Was the information correctly determined? - /// - public bool Valid { get; private set; } + public string Filename { get; } /// /// The short name of this assembly. /// - public string Name { get; private set; } + public string Name { get; } /// /// The version number of this assembly. /// - public System.Version Version { get; private set; } + public System.Version? Version { get; } /// /// The public key token of the assembly. /// - public string PublicKeyToken { get; private set; } + public string? PublicKeyToken { get; } /// /// The culture. /// - public string Culture { get; private set; } + public string? Culture { get; } /// - /// Get/parse a canonical ID of this assembly. + /// Gets the canonical ID of this assembly. /// public string Id { @@ -59,25 +54,6 @@ public string Id result = string.Format("{0}, PublicKeyToken={1}", result, PublicKeyToken); return result; } - - private set - { - var sections = value.Split(new string[] { ", " }, StringSplitOptions.None); - - Name = sections.First(); - - foreach (var section in sections.Skip(1)) - { - if (section.StartsWith("Version=")) - Version = new Version(section.Substring(8)); - else if (section.StartsWith("Culture=")) - Culture = section.Substring(8); - else if (section.StartsWith("PublicKeyToken=")) - PublicKeyToken = section.Substring(15); - // else: Some other field like processorArchitecture - ignore. - } - - } } public override string ToString() => Id; @@ -92,7 +68,8 @@ public IEnumerable IndexStrings yield return Id; if (Version != null) { - if (Culture != null) yield return string.Format("{0}, Version={1}, Culture={2}", Name, Version, Culture); + if (Culture != null) + yield return string.Format("{0}, Version={1}, Culture={2}", Name, Version, Culture); yield return string.Format("{0}, Version={1}", Name, Version); } yield return Name; @@ -100,27 +77,58 @@ public IEnumerable IndexStrings } } - /// - /// Get an invalid assembly info (Valid==false). - /// - public static AssemblyInfo Invalid { get; } = new AssemblyInfo(); + private AssemblyInfo(string id, string filename) + { + var sections = id.Split(new string[] { ", " }, StringSplitOptions.None); - private AssemblyInfo() { } + Name = sections.First(); + + foreach (var section in sections.Skip(1)) + { + if (section.StartsWith("Version=")) + Version = new Version(section.Substring(8)); + else if (section.StartsWith("Culture=")) + Culture = section.Substring(8); + else if (section.StartsWith("PublicKeyToken=")) + PublicKeyToken = section.Substring(15); + // else: Some other field like processorArchitecture - ignore. + } + + Filename = filename; + } + + private AssemblyInfo(string filename, string name, Version version, string culture, string publicKeyToken) + { + Filename = filename; + Name = name; + Version = version; + Culture = culture; + PublicKeyToken = publicKeyToken; + } /// /// Get AssemblyInfo from a loaded Assembly. /// /// The assembly. /// Info about the assembly. - public static AssemblyInfo MakeFromAssembly(Assembly assembly) => new AssemblyInfo() { Valid = true, Filename = assembly.Location, Id = assembly.FullName }; + public static AssemblyInfo MakeFromAssembly(Assembly assembly) + { + if (assembly.FullName is null) + { + throw new InvalidOperationException("Assembly with empty full name is not expected."); + } + + return new AssemblyInfo(assembly.FullName, assembly.Location); + } /// - /// Parse an assembly name/Id into an AssemblyInfo, - /// populating the available fields and leaving the others null. + /// Returns the id and name of the assembly that would be created from the received id. /// - /// The assembly name/Id. - /// The deconstructed assembly info. - public static AssemblyInfo MakeFromId(string id) => new AssemblyInfo() { Valid = true, Id = id }; + public static (string id, string name) ComputeSanitizedAssemblyInfo(string id) + { + var assembly = new AssemblyInfo(id, string.Empty); + return (assembly.Id, assembly.Name); + } /// /// Reads the assembly info from a file. @@ -131,48 +139,42 @@ private AssemblyInfo() { } /// The information about the assembly. public static AssemblyInfo ReadFromFile(string filename) { - var result = new AssemblyInfo() { Filename = filename }; try { /* This method is significantly faster and more lightweight than using * System.Reflection.Assembly.ReflectionOnlyLoadFrom. It also allows * loading the same assembly from different locations. */ - using (var pereader = new System.Reflection.PortableExecutable.PEReader(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))) - using (var sha1 = new SHA1CryptoServiceProvider()) + using var pereader = new System.Reflection.PortableExecutable.PEReader(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read)); + using var sha1 = new SHA1CryptoServiceProvider(); + var metadata = pereader.GetMetadata(); + unsafe { - var metadata = pereader.GetMetadata(); - unsafe - { - var reader = new System.Reflection.Metadata.MetadataReader(metadata.Pointer, metadata.Length); - var def = reader.GetAssemblyDefinition(); - - // This is how you compute the public key token from the full public key. - // The last 8 bytes of the SHA1 of the public key. - var publicKey = reader.GetBlobBytes(def.PublicKey); - var publicKeyToken = sha1.ComputeHash(publicKey); - var publicKeyString = new StringBuilder(); - foreach (var b in publicKeyToken.Skip(12).Reverse()) - publicKeyString.AppendFormat("{0:x2}", b); - - result.Name = reader.GetString(def.Name); - result.Version = def.Version; - result.Culture = def.Culture.IsNil ? "neutral" : reader.GetString(def.Culture); - result.PublicKeyToken = publicKeyString.ToString(); - result.Valid = true; - } + var reader = new System.Reflection.Metadata.MetadataReader(metadata.Pointer, metadata.Length); + var def = reader.GetAssemblyDefinition(); + + // This is how you compute the public key token from the full public key. + // The last 8 bytes of the SHA1 of the public key. + var publicKey = reader.GetBlobBytes(def.PublicKey); + var publicKeyToken = sha1.ComputeHash(publicKey); + var publicKeyString = new StringBuilder(); + foreach (var b in publicKeyToken.Skip(12).Reverse()) + publicKeyString.AppendFormat("{0:x2}", b); + + var culture = def.Culture.IsNil ? "neutral" : reader.GetString(def.Culture); + return new AssemblyInfo(filename, reader.GetString(def.Name), def.Version, culture, publicKeyString.ToString()); } } catch (BadImageFormatException) { - // The DLL wasn't an assembly -> result.Valid = false. + // The DLL wasn't an assembly } catch (InvalidOperationException) { - // Some other failure -> result.Valid = false. + // Some other failure } - return result; + throw new AssemblyLoadException(); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/AssemblyLoadException.cs b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/AssemblyLoadException.cs new file mode 100644 index 000000000000..cdb1380e291c --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/AssemblyLoadException.cs @@ -0,0 +1,6 @@ +using System; + +namespace Semmle.BuildAnalyser +{ + public class AssemblyLoadException : Exception { } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/BuildAnalysis.cs b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/BuildAnalysis.cs index 2894222ca891..bb779a313739 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/BuildAnalysis.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/BuildAnalysis.cs @@ -14,7 +14,7 @@ namespace Semmle.BuildAnalyser /// /// The output of a build analysis. /// - interface IBuildAnalysis + internal interface IBuildAnalysis { /// /// Full filepaths of external references. @@ -46,15 +46,13 @@ interface IBuildAnalysis /// /// Main implementation of the build analysis. /// - class BuildAnalysis : IBuildAnalysis, IDisposable + internal sealed class BuildAnalysis : IBuildAnalysis, IDisposable { private readonly AssemblyCache assemblyCache; - private readonly NugetPackages nuget; private readonly IProgressMonitor progressMonitor; private readonly IDictionary usedReferences = new ConcurrentDictionary(); private readonly IDictionary sources = new ConcurrentDictionary(); private readonly IDictionary unresolvedReferences = new ConcurrentDictionary(); - private readonly DirectoryInfo sourceDir; private int failedProjects, succeededProjects; private readonly string[] allSources; private int conflictedReferences = 0; @@ -69,26 +67,26 @@ public BuildAnalysis(Options options, IProgressMonitor progress) var startTime = DateTime.Now; progressMonitor = progress; - sourceDir = new DirectoryInfo(options.SrcDir); + var sourceDir = new DirectoryInfo(options.SrcDir); progressMonitor.FindingFiles(options.SrcDir); - allSources = sourceDir.GetFiles("*.cs", SearchOption.AllDirectories). - Select(d => d.FullName). - Where(d => !options.ExcludesFile(d)). - ToArray(); + allSources = sourceDir.GetFiles("*.cs", SearchOption.AllDirectories) + .Select(d => d.FullName) + .Where(d => !options.ExcludesFile(d)) + .ToArray(); var dllDirNames = options.DllDirs.Select(Path.GetFullPath).ToList(); - PackageDirectory = new TemporaryDirectory(ComputeTempDirectory(sourceDir.FullName)); + packageDirectory = new TemporaryDirectory(ComputeTempDirectory(sourceDir.FullName)); if (options.UseNuGet) { try { - nuget = new NugetPackages(sourceDir.FullName, PackageDirectory); - ReadNugetFiles(); + var nuget = new NugetPackages(sourceDir.FullName, packageDirectory); + nuget.InstallPackages(progressMonitor); } - catch(FileNotFoundException) + catch (FileNotFoundException) { progressMonitor.MissingNuGet(); } @@ -97,7 +95,9 @@ public BuildAnalysis(Options options, IProgressMonitor progress) // Find DLLs in the .Net Framework if (options.ScanNetFrameworkDlls) { - dllDirNames.Add(Runtime.Runtimes.First()); + var runtimeLocation = Runtime.GetRuntime(options.UseSelfContainedDotnet); + progressMonitor.Log(Util.Logging.Severity.Debug, $"Runtime location selected: {runtimeLocation}"); + dllDirNames.Add(runtimeLocation); } // These files can sometimes prevent `dotnet restore` from working correctly. @@ -109,7 +109,7 @@ public BuildAnalysis(Options options, IProgressMonitor progress) sourceDir.GetFiles("*.sln", SearchOption.AllDirectories).Select(d => d.FullName); RestoreSolutions(solutions); - dllDirNames.Add(PackageDirectory.DirInfo.FullName); + dllDirNames.Add(packageDirectory.DirInfo.FullName); assemblyCache = new BuildAnalyser.AssemblyCache(dllDirNames, progress); AnalyseSolutions(solutions); @@ -171,14 +171,25 @@ private static string ComputeTempDirectory(string srcDir) /// If the same assembly name is duplicated with different versions, /// resolve to the higher version number. /// - void ResolveConflicts() + private void ResolveConflicts() { - var sortedReferences = usedReferences. - Select(r => assemblyCache.GetAssemblyInfo(r.Key)). - OrderBy(r => r.Version). - ToArray(); + var sortedReferences = new List(); + foreach (var usedReference in usedReferences) + { + try + { + var assemblyInfo = assemblyCache.GetAssemblyInfo(usedReference.Key); + sortedReferences.Add(assemblyInfo); + } + catch (AssemblyLoadException) + { + progressMonitor.Log(Util.Logging.Severity.Warning, $"Could not load assembly information from {usedReference.Key}"); + } + } - Dictionary finalAssemblyList = new Dictionary(); + sortedReferences = sortedReferences.OrderBy(r => r.Version).ToList(); + + var finalAssemblyList = new Dictionary(); // Pick the highest version for each assembly name foreach (var r in sortedReferences) @@ -201,20 +212,11 @@ void ResolveConflicts() } } - /// - /// Find and restore NuGet packages. - /// - void ReadNugetFiles() - { - nuget.FindPackages(); - nuget.InstallPackages(progressMonitor); - } - /// /// Store that a particular reference file is used. /// /// The filename of the reference. - void UseReference(string reference) + private void UseReference(string reference) { usedReferences[reference] = true; } @@ -223,7 +225,7 @@ void UseReference(string reference) /// Store that a particular source file is used (by a project file). /// /// The source file. - void UseSource(FileInfo sourceFile) + private void UseSource(FileInfo sourceFile) { sources[sourceFile.FullName] = sourceFile.Exists; } @@ -260,26 +262,26 @@ void UseSource(FileInfo sourceFile) /// /// The assembly ID. /// The project file making the reference. - void UnresolvedReference(string id, string projectFile) + private void UnresolvedReference(string id, string projectFile) { unresolvedReferences[id] = projectFile; } - readonly TemporaryDirectory PackageDirectory; + private readonly TemporaryDirectory packageDirectory; /// /// Reads all the source files and references from the given list of projects. /// /// The list of projects to analyse. - void AnalyseProjectFiles(IEnumerable projectFiles) + private void AnalyseProjectFiles(IEnumerable projectFiles) { foreach (var proj in projectFiles) AnalyseProject(proj); } - void AnalyseProject(FileInfo project) + private void AnalyseProject(FileInfo project) { - if(!project.Exists) + if (!project.Exists) { progressMonitor.MissingProject(project.FullName); return; @@ -291,14 +293,14 @@ void AnalyseProject(FileInfo project) foreach (var @ref in csProj.References) { - AssemblyInfo resolved = assemblyCache.ResolveReference(@ref); - if (!resolved.Valid) + try { - UnresolvedReference(@ref, project.FullName); + var resolved = assemblyCache.ResolveReference(@ref); + UseReference(resolved.Filename); } - else + catch (AssemblyLoadException) { - UseReference(resolved.Filename); + UnresolvedReference(@ref, project.FullName); } } @@ -320,10 +322,10 @@ void AnalyseProject(FileInfo project) } - void Restore(string projectOrSolution) + private void Restore(string projectOrSolution) { - int exit = DotNet.RestoreToDirectory(projectOrSolution, PackageDirectory.DirInfo.FullName); - switch(exit) + var exit = DotNet.RestoreToDirectory(projectOrSolution, packageDirectory.DirInfo.FullName); + switch (exit) { case 0: case 1: @@ -342,7 +344,7 @@ public void RestoreSolutions(IEnumerable solutions) public void AnalyseSolutions(IEnumerable solutions) { - Parallel.ForEach(solutions, new ParallelOptions { MaxDegreeOfParallelism = 4 } , solutionFile => + Parallel.ForEach(solutions, new ParallelOptions { MaxDegreeOfParallelism = 4 }, solutionFile => { try { @@ -359,7 +361,7 @@ public void AnalyseSolutions(IEnumerable solutions) public void Dispose() { - PackageDirectory?.Dispose(); + packageDirectory?.Dispose(); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/CsProjFile.cs b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/CsProjFile.cs index 1083c9b6257c..dfbe8df2f06b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/CsProjFile.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/CsProjFile.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Xml; @@ -8,11 +9,11 @@ namespace Semmle.BuildAnalyser /// /// Represents a .csproj file and reads information from it. /// - class CsProjFile + internal class CsProjFile { private string Filename { get; } - private string Directory => Path.GetDirectoryName(Filename); + private string Directory { get; } /// /// Reads the .csproj file. @@ -22,20 +23,29 @@ public CsProjFile(FileInfo filename) { Filename = filename.FullName; + var directoryName = Path.GetDirectoryName(Filename); + + if (directoryName is null) + { + throw new Extraction.InternalError($"Directory of file '{Filename}' is null"); + } + + Directory = directoryName; + try { // This can fail if the .csproj is invalid or has // unrecognised content or is the wrong version. // This currently always fails on Linux because // Microsoft.Build is not cross platform. - ReadMsBuildProject(filename); + (csFiles, references) = ReadMsBuildProject(filename); } catch // lgtm[cs/catch-of-all-exceptions] { // There was some reason why the project couldn't be loaded. // Fall back to reading the Xml document directly. // This method however doesn't handle variable expansion. - ReadProjectFileAsXml(filename); + (csFiles, references) = ReadProjectFileAsXml(filename, Directory); } } @@ -45,21 +55,22 @@ public CsProjFile(FileInfo filename) /// and there seems to be no way to make it succeed. Fails on Linux. /// /// The file to read. - private void ReadMsBuildProject(FileInfo filename) + private static (string[] csFiles, string[] references) ReadMsBuildProject(FileInfo filename) { var msbuildProject = new Microsoft.Build.Execution.ProjectInstance(filename.FullName); - references = msbuildProject. - Items. - Where(item => item.ItemType == "Reference"). - Select(item => item.EvaluatedInclude). - ToArray(); + var references = msbuildProject.Items + .Where(item => item.ItemType == "Reference") + .Select(item => item.EvaluatedInclude) + .ToArray(); - csFiles = msbuildProject.Items + var csFiles = msbuildProject.Items .Where(item => item.ItemType == "Compile") .Select(item => item.GetMetadataValue("FullPath")) .Where(fn => fn.EndsWith(".cs")) .ToArray(); + + return (csFiles, references); } /// @@ -67,62 +78,56 @@ private void ReadMsBuildProject(FileInfo filename) /// This doesn't handle variables etc, and should only used as a /// fallback if ReadMsBuildProject() fails. /// - /// The .csproj file. - private void ReadProjectFileAsXml(FileInfo filename) + /// The .csproj file. + private static (string[] csFiles, string[] references) ReadProjectFileAsXml(FileInfo fileName, string directoryName) { var projFile = new XmlDocument(); var mgr = new XmlNamespaceManager(projFile.NameTable); mgr.AddNamespace("msbuild", "http://schemas.microsoft.com/developer/msbuild/2003"); - projFile.Load(filename.FullName); - var projDir = filename.Directory; + projFile.Load(fileName.FullName); + var projDir = fileName.Directory; var root = projFile.DocumentElement; // Figure out if it's dotnet core - bool netCoreProjectFile = root.GetAttribute("Sdk") == "Microsoft.NET.Sdk"; + var netCoreProjectFile = root.GetAttribute("Sdk") == "Microsoft.NET.Sdk"; if (netCoreProjectFile) { - var relativeCsIncludes = - root.SelectNodes("/Project/ItemGroup/Compile/@Include", mgr). - NodeList(). - Select(node => node.Value). - ToArray(); + var explicitCsFiles = root + .SelectNodes("/Project/ItemGroup/Compile/@Include", mgr) + .NodeList() + .Select(node => node.Value) + .Select(cs => Path.DirectorySeparatorChar == '/' ? cs.Replace("\\", "/") : cs) + .Select(f => Path.GetFullPath(Path.Combine(projDir.FullName, f))); - var explicitCsFiles = relativeCsIncludes. - Select(cs => Path.DirectorySeparatorChar == '/' ? cs.Replace("\\", "/") : cs). - Select(f => Path.GetFullPath(Path.Combine(projDir.FullName, f))); + var additionalCsFiles = System.IO.Directory.GetFiles(directoryName, "*.cs", SearchOption.AllDirectories); - var additionalCsFiles = System.IO.Directory.GetFiles(Directory, "*.cs", SearchOption.AllDirectories); + return (explicitCsFiles.Concat(additionalCsFiles).ToArray(), Array.Empty()); + } - csFiles = explicitCsFiles.Concat(additionalCsFiles).ToArray(); + var references = root + .SelectNodes("/msbuild:Project/msbuild:ItemGroup/msbuild:Reference/@Include", mgr) + .NodeList() + .Select(node => node.Value) + .ToArray(); - references = new string[0]; - } - else - { + var relativeCsIncludes = root + .SelectNodes("/msbuild:Project/msbuild:ItemGroup/msbuild:Compile/@Include", mgr) + .NodeList() + .Select(node => node.Value) + .ToArray(); - references = - root.SelectNodes("/msbuild:Project/msbuild:ItemGroup/msbuild:Reference/@Include", mgr). - NodeList(). - Select(node => node.Value). - ToArray(); - - var relativeCsIncludes = - root.SelectNodes("/msbuild:Project/msbuild:ItemGroup/msbuild:Compile/@Include", mgr). - NodeList(). - Select(node => node.Value). - ToArray(); - - csFiles = relativeCsIncludes. - Select(cs => Path.DirectorySeparatorChar == '/' ? cs.Replace("\\", "/") : cs). - Select(f => Path.GetFullPath(Path.Combine(projDir.FullName, f))). - ToArray(); - } + var csFiles = relativeCsIncludes + .Select(cs => Path.DirectorySeparatorChar == '/' ? cs.Replace("\\", "/") : cs) + .Select(f => Path.GetFullPath(Path.Combine(projDir.FullName, f))) + .ToArray(); + + return (csFiles, references); } - string[] references; - string[] csFiles; + private readonly string[] references; + private readonly string[] csFiles; /// /// The list of references as a list of assembly IDs. @@ -135,7 +140,7 @@ private void ReadProjectFileAsXml(FileInfo filename) public IEnumerable Sources => csFiles; } - static class XmlNodeHelper + internal static class XmlNodeHelper { /// /// Helper to convert an XmlNodeList into an IEnumerable. @@ -145,8 +150,7 @@ static class XmlNodeHelper /// A more useful data type. public static IEnumerable NodeList(this XmlNodeList list) { - foreach (var i in list) - yield return i as XmlNode; + return list.OfType(); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/DotNet.cs b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/DotNet.cs index 6edd217af8dc..4045519d3e0d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/DotNet.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/DotNet.cs @@ -1,15 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; +using System.Diagnostics; namespace Semmle.BuildAnalyser { /// /// Utilities to run the "dotnet" command. /// - static class DotNet + internal static class DotNet { public static int RestoreToDirectory(string projectOrSolutionFile, string packageDirectory) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/NugetPackages.cs b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/NugetPackages.cs index 2ea3afb6c691..e29b1b4ac1ec 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/NugetPackages.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/NugetPackages.cs @@ -12,7 +12,7 @@ namespace Semmle.BuildAnalyser /// Locates packages in a source tree and downloads all of the /// referenced assemblies to a temp folder. /// - class NugetPackages + internal class NugetPackages { /// /// Create the package manager for a specified source tree. @@ -25,24 +25,22 @@ public NugetPackages(string sourceDir, TemporaryDirectory packageDirectory) // Expect nuget.exe to be in a `nuget` directory under the directory containing this exe. var currentAssembly = System.Reflection.Assembly.GetExecutingAssembly().Location; - nugetExe = Path.Combine(Path.GetDirectoryName(currentAssembly), "nuget", "nuget.exe"); + var directory = Path.GetDirectoryName(currentAssembly); + if (directory is null) + throw new FileNotFoundException($"Directory path '{currentAssembly}' of current assembly is null"); + + nugetExe = Path.Combine(directory, "nuget", "nuget.exe"); if (!File.Exists(nugetExe)) throw new FileNotFoundException(string.Format("NuGet could not be found at {0}", nugetExe)); - } - /// - /// Locate all NuGet packages but don't download them yet. - /// - public void FindPackages() - { packages = new DirectoryInfo(SourceDirectory). EnumerateFiles("packages.config", SearchOption.AllDirectories). ToArray(); } // List of package files to download. - FileInfo[] packages; + private readonly FileInfo[] packages; /// /// The list of package files. @@ -82,7 +80,7 @@ public string SourceDirectory /// /// The package file. /// Where to log progress/errors. - void RestoreNugetPackage(string package, IProgressMonitor pm) + private void RestoreNugetPackage(string package, IProgressMonitor pm) { pm.NugetInstall(package); @@ -115,8 +113,8 @@ void RestoreNugetPackage(string package, IProgressMonitor pm) { using var p = Process.Start(pi); - string output = p.StandardOutput.ReadToEnd(); - string error = p.StandardError.ReadToEnd(); + var output = p.StandardOutput.ReadToEnd(); + var error = p.StandardError.ReadToEnd(); p.WaitForExit(); if (p.ExitCode != 0) @@ -131,6 +129,6 @@ void RestoreNugetPackage(string package, IProgressMonitor pm) } } - readonly string nugetExe; + private readonly string nugetExe; } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Options.cs b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Options.cs index 89cc18007f0e..fedcf909c0c8 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Options.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Options.cs @@ -11,9 +11,9 @@ namespace Semmle.Extraction.CSharp.Standalone /// public sealed class Options : CommonOptions { - public override bool handleFlag(string key, bool value) + public override bool HandleFlag(string key, bool value) { - switch(key) + switch (key) { case "silent": Verbosity = value ? Verbosity.Off : Verbosity.Info; @@ -36,14 +36,17 @@ public override bool handleFlag(string key, bool value) case "skip-dotnet": ScanNetFrameworkDlls = !value; return true; + case "self-contained-dotnet": + UseSelfContainedDotnet = value; + return true; default: - return base.handleFlag(key, value); + return base.HandleFlag(key, value); } } - public override bool handleOption(string key, string value) + public override bool HandleOption(string key, string value) { - switch(key) + switch (key) { case "exclude": Excludes.Add(value); @@ -52,11 +55,11 @@ public override bool handleOption(string key, string value) DllDirs.Add(value); return true; default: - return base.handleOption(key, value); + return base.HandleOption(key, value); } } - public override bool handleArgument(string arg) + public override bool HandleArgument(string arg) { SolutionFile = arg; var fi = new FileInfo(SolutionFile); @@ -68,7 +71,7 @@ public override bool handleArgument(string arg) return true; } - public override void invalidArgument(string argument) + public override void InvalidArgument(string argument) { System.Console.WriteLine($"Error: Invalid argument {argument}"); Errors = true; @@ -77,62 +80,63 @@ public override void invalidArgument(string argument) /// /// Files/patterns to exclude. /// - public IList Excludes = new List(); + public IList Excludes { get; } = new List(); - /// - /// The number of concurrent threads to use. - /// - public int NumberOfThreads = Semmle.Extraction.Extractor.DefaultNumberOfThreads; /// /// The directory containing the source code; /// - public readonly string SrcDir = System.IO.Directory.GetCurrentDirectory(); + public string SrcDir { get; } = System.IO.Directory.GetCurrentDirectory(); /// /// Whether to analyse NuGet packages. /// - public bool UseNuGet = true; + public bool UseNuGet { get; private set; } = true; /// /// Directories to search DLLs in. /// - public IList DllDirs = new List(); + public IList DllDirs { get; } = new List(); /// /// Whether to search the .Net framework directory. /// - public bool ScanNetFrameworkDlls = true; + public bool ScanNetFrameworkDlls { get; private set; } = true; /// /// Whether to use mscorlib as a reference. /// - public bool UseMscorlib = true; + public bool UseMscorlib { get; private set; } = true; /// /// Whether to search .csproj files. /// - public bool AnalyseCsProjFiles = true; + public bool AnalyseCsProjFiles { get; private set; } = true; /// /// The solution file to analyse, or null if not specified. /// - public string SolutionFile; + public string? SolutionFile { get; private set; } /// /// Whether the extraction phase should be skipped (dry-run). /// - public bool SkipExtraction = false; + public bool SkipExtraction { get; private set; } = false; /// /// Whether errors were encountered parsing the arguments. /// - public bool Errors = false; + public bool Errors { get; private set; } = false; /// /// Whether to show help. /// - public bool Help = false; + public bool Help { get; private set; } = false; + + /// + /// Whether to use the packaged dotnet runtime. + /// + public bool UseSelfContainedDotnet { get; private set; } = false; /// /// Determine whether the given path should be excluded. @@ -147,7 +151,7 @@ public bool ExcludesFile(string path) /// /// Outputs the command line options to the console. /// - public void ShowHelp(System.IO.TextWriter output) + public static void ShowHelp(System.IO.TextWriter output) { output.WriteLine("C# standalone extractor\n\nExtracts a C# project in the current directory without performing a build.\n"); output.WriteLine("Additional options:\n"); @@ -162,6 +166,7 @@ public void ShowHelp(System.IO.TextWriter output) output.WriteLine(" --threads:nnn Specify number of threads (default=CPU cores)"); output.WriteLine(" --verbose Produce more output"); output.WriteLine(" --pdb Cross-reference information from PDBs where available"); + output.WriteLine(" --self-contained-dotnet Use the .Net Framework packaged with the extractor"); } private Options() diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Program.cs b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Program.cs index 106771faef2f..dc67a7679e8a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Program.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Program.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Semmle.BuildAnalyser; using Semmle.Util.Logging; @@ -9,67 +8,39 @@ namespace Semmle.Extraction.CSharp.Standalone /// /// One independent run of the extractor. /// - class Extraction + internal class Extraction { public Extraction(string directory) { - this.directory = directory; + Directory = directory; } - public readonly string directory; - public readonly List Sources = new List(); + public string Directory { get; } + public List Sources { get; } = new List(); }; /// /// Searches for source/references and creates separate extractions. /// - class Analysis : IDisposable + internal sealed class Analysis : IDisposable { - readonly ILogger logger; - - public Analysis(ILogger logger) + public Analysis(ILogger logger, Options options) { - this.logger = logger; + var progressMonitor = new ProgressMonitor(logger); + buildAnalysis = new BuildAnalysis(options, progressMonitor); + References = buildAnalysis.ReferenceFiles; + Extraction = new Extraction(options.SrcDir); + Extraction.Sources.AddRange(options.SolutionFile == null ? buildAnalysis.AllSourceFiles : buildAnalysis.ProjectSourceFiles); } - // The extraction configuration for the entire project. - Extraction projectExtraction; - - public IEnumerable References - { - get; private set; - } + public IEnumerable References { get; } /// /// The extraction configuration. /// - public Extraction Extraction => projectExtraction; + public Extraction Extraction { get; } - /// - /// Creates an extraction for the current directory - /// and adds it to the list of all extractions. - /// - /// The directory of the extraction. - /// The extraction. - void CreateExtraction(string dir) - { - projectExtraction = new Extraction(dir); - } - - BuildAnalysis buildAnalysis; - - /// - /// Analyse projects/solution and resolves references. - /// - /// The build analysis options. - public void AnalyseProjects(Options options) - { - CreateExtraction(options.SrcDir); - var progressMonitor = new ProgressMonitor(logger); - buildAnalysis = new BuildAnalysis(options, progressMonitor); - References = buildAnalysis.ReferenceFiles; - projectExtraction.Sources.AddRange(options.SolutionFile == null ? buildAnalysis.AllSourceFiles : buildAnalysis.ProjectSourceFiles); - } + private readonly BuildAnalysis buildAnalysis; public void Dispose() { @@ -79,16 +50,15 @@ public void Dispose() public class Program { - static int Main(string[] args) + public static int Main(string[] args) { var options = Options.Create(args); // options.CIL = true; // To do: Enable this - var output = new ConsoleLogger(options.Verbosity); - using var a = new Analysis(output); + using var output = new ConsoleLogger(options.Verbosity); if (options.Help) { - options.ShowHelp(System.Console.Out); + Options.ShowHelp(System.Console.Out); return 0; } @@ -98,10 +68,10 @@ static int Main(string[] args) var start = DateTime.Now; output.Log(Severity.Info, "Running C# standalone extractor"); - a.AnalyseProjects(options); - int sourceFiles = a.Extraction.Sources.Count(); + using var a = new Analysis(output, options); + var sourceFileCount = a.Extraction.Sources.Count; - if (sourceFiles == 0) + if (sourceFileCount == 0) { output.Log(Severity.Error, "No source files found"); return 1; @@ -109,33 +79,39 @@ static int Main(string[] args) if (!options.SkipExtraction) { + using var fileLogger = new FileLogger(options.Verbosity, Extractor.GetCSharpLogPath()); + output.Log(Severity.Info, ""); output.Log(Severity.Info, "Extracting..."); Extractor.ExtractStandalone( a.Extraction.Sources, a.References, new ExtractionProgress(output), - new FileLogger(options.Verbosity, Extractor.GetCSharpLogPath()), + fileLogger, options); - output.Log(Severity.Info, $"Extraction completed in {DateTime.Now-start}"); + output.Log(Severity.Info, $"Extraction completed in {DateTime.Now - start}"); } return 0; } - class ExtractionProgress : IProgressMonitor + private class ExtractionProgress : IProgressMonitor { public ExtractionProgress(ILogger output) { logger = output; } - readonly ILogger logger; + private readonly ILogger logger; public void Analysed(int item, int total, string source, string output, TimeSpan time, AnalysisAction action) { logger.Log(Severity.Info, "[{0}/{1}] {2} ({3})", item, total, source, - action == AnalysisAction.Extracted ? time.ToString() : action == AnalysisAction.Excluded ? "excluded" : "up to date"); + action == AnalysisAction.Extracted + ? time.ToString() + : action == AnalysisAction.Excluded + ? "excluded" + : "up to date"); } public void MissingType(string type) diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/ProgressMonitor.cs b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/ProgressMonitor.cs index 5bbe1e3a5b28..5b1da9292512 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/ProgressMonitor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/ProgressMonitor.cs @@ -6,7 +6,7 @@ namespace Semmle.BuildAnalyser /// /// Callback for various events that may happen during the build analysis. /// - interface IProgressMonitor + internal interface IProgressMonitor { void FindingFiles(string dir); void UnresolvedReference(string id, string project); @@ -16,16 +16,16 @@ interface IProgressMonitor void NugetInstall(string package); void ResolvedReference(string filename); void Summary(int existingSources, int usedSources, int missingSources, int references, int unresolvedReferences, int resolvedConflicts, int totalProjects, int failedProjects, TimeSpan analysisTime); - void Warning(string message); + void Log(Severity severity, string message); void ResolvedConflict(string asm1, string asm2); void MissingProject(string projectFile); void CommandFailed(string exe, string arguments, int exitCode); void MissingNuGet(); } - class ProgressMonitor : IProgressMonitor + internal class ProgressMonitor : IProgressMonitor { - readonly ILogger logger; + private readonly ILogger logger; public ProgressMonitor(ILogger logger) { @@ -93,9 +93,9 @@ public void Summary(int existingSources, int usedSources, int missingSources, logger.Log(Severity.Info, "Build analysis completed in {0}", analysisTime); } - public void Warning(string message) + public void Log(Severity severity, string message) { - logger.Log(Severity.Warning, message); + logger.Log(severity, message); } public void ResolvedConflict(string asm1, string asm2) diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Runtime.cs b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Runtime.cs index 489d7f95140b..a922a3bf07a3 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Runtime.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Runtime.cs @@ -10,14 +10,14 @@ namespace Semmle.Extraction.CSharp.Standalone /// /// Locates .NET Runtimes. /// - static class Runtime + internal static class Runtime { - static string ExecutingRuntime => RuntimeEnvironment.GetRuntimeDirectory(); + private static string ExecutingRuntime => RuntimeEnvironment.GetRuntimeDirectory(); /// /// Locates .NET Core Runtimes. /// - public static IEnumerable CoreRuntimes + private static IEnumerable CoreRuntimes { get { @@ -27,8 +27,12 @@ public static IEnumerable CoreRuntimes : new[] { "/usr/share/dotnet", @"C:\Program Files\dotnet" }; var coreDirs = dotnetDirs.Select(d => Path.Combine(d, "shared", "Microsoft.NETCore.App")); - foreach (var dir in coreDirs.Where(Directory.Exists)) + var dir = coreDirs.FirstOrDefault(Directory.Exists); + if (dir is object) + { return Directory.EnumerateDirectories(dir).OrderByDescending(Path.GetFileName); + } + return Enumerable.Empty(); } } @@ -37,7 +41,7 @@ public static IEnumerable CoreRuntimes /// Locates .NET Desktop Runtimes. /// This includes Mono and Microsoft.NET. /// - public static IEnumerable DesktopRuntimes + private static IEnumerable DesktopRuntimes { get { @@ -48,22 +52,29 @@ public static IEnumerable DesktopRuntimes if (Directory.Exists(@"C:\Windows\Microsoft.NET\Framework64")) { - return Directory.EnumerateDirectories(@"C:\Windows\Microsoft.NET\Framework64", "v*"). - OrderByDescending(Path.GetFileName); + return Directory.EnumerateDirectories(@"C:\Windows\Microsoft.NET\Framework64", "v*") + .OrderByDescending(Path.GetFileName); } - foreach (var dir in monoDirs.Where(Directory.Exists)) + var dir = monoDirs.FirstOrDefault(Directory.Exists); + + if (dir is object) { - return Directory.EnumerateDirectories(dir). - Where(d => Char.IsDigit(Path.GetFileName(d)[0])). - OrderByDescending(Path.GetFileName); + return Directory.EnumerateDirectories(dir) + .Where(d => Char.IsDigit(Path.GetFileName(d)[0])) + .OrderByDescending(Path.GetFileName); } return Enumerable.Empty(); } } - public static IEnumerable Runtimes + /// + /// Gets the .NET runtime location to use for extraction + /// + public static string GetRuntime(bool useSelfContained) => useSelfContained ? ExecutingRuntime : Runtimes.First(); + + private static IEnumerable Runtimes { get { diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Semmle.Extraction.CSharp.Standalone.csproj b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Semmle.Extraction.CSharp.Standalone.csproj index f9efd0d9ebbb..277310cc3413 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Semmle.Extraction.CSharp.Standalone.csproj +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Semmle.Extraction.CSharp.Standalone.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp3.0 + netcoreapp3.1 Semmle.Extraction.CSharp.Standalone Semmle.Extraction.CSharp.Standalone false @@ -10,6 +10,7 @@ false win-x64;linux-x64;osx-x64 + enable diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/SolutionFile.cs b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/SolutionFile.cs index b4551dd80243..8fbe706aa452 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/SolutionFile.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/SolutionFile.cs @@ -8,9 +8,9 @@ namespace Semmle.BuildAnalyser /// /// Access data in a .sln file. /// - class SolutionFile + internal class SolutionFile { - readonly Microsoft.Build.Construction.SolutionFile solutionFile; + private readonly Microsoft.Build.Construction.SolutionFile solutionFile; private string FullPath { get; } @@ -32,10 +32,10 @@ public IEnumerable MsBuildProjects { get { - return solutionFile.ProjectsInOrder. - Where(p => p.ProjectType == SolutionProjectType.KnownToBeMSBuildFormat). - Select(p => p.AbsolutePath). - Select(p => Path.DirectorySeparatorChar == '/' ? p.Replace("\\", "/") : p); + return solutionFile.ProjectsInOrder + .Where(p => p.ProjectType == SolutionProjectType.KnownToBeMSBuildFormat) + .Select(p => p.AbsolutePath) + .Select(p => Path.DirectorySeparatorChar == '/' ? p.Replace("\\", "/") : p); } } @@ -46,21 +46,26 @@ public IEnumerable NestedProjects { get { - return solutionFile.ProjectsInOrder. - Where(p => p.ProjectType == SolutionProjectType.SolutionFolder). - Where(p => Directory.Exists(p.AbsolutePath)). - SelectMany(p => new DirectoryInfo(p.AbsolutePath).EnumerateFiles("*.csproj", SearchOption.AllDirectories)). - Select(f => f.FullName); + return solutionFile.ProjectsInOrder + .Where(p => p.ProjectType == SolutionProjectType.SolutionFolder) + .Where(p => Directory.Exists(p.AbsolutePath)) + .SelectMany(p => new DirectoryInfo(p.AbsolutePath).EnumerateFiles("*.csproj", SearchOption.AllDirectories)) + .Select(f => f.FullName); } } /// /// List of projects which were mentioned but don't exist on disk. /// - public IEnumerable MissingProjects => + public IEnumerable MissingProjects + { + get + { // Only projects in the solution file can be missing. // (NestedProjects are located on disk so always exist.) - MsBuildProjects.Where(p => !File.Exists(p)); + return MsBuildProjects.Where(p => !File.Exists(p)); + } + } /// /// The list of project files. diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs b/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs index 544a1819117a..88087c1580c3 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs @@ -15,34 +15,44 @@ namespace Semmle.Extraction.CSharp /// /// Encapsulates a C# analysis task. /// - public class Analyser : IDisposable + public sealed class Analyser : IDisposable { - IExtractor extractor; + private IExtractor extractor; + private CSharpCompilation compilation; + private Layout layout; + private bool init; + private readonly object progressMutex = new object(); + private int taskCount = 0; + private CommonOptions options; + private Entities.Compilation compilationEntity; + private IDisposable compilationTrapFile; + + private readonly Stopwatch stopWatch = new Stopwatch(); + + private readonly IProgressMonitor progressMonitor; - readonly Stopwatch stopWatch = new Stopwatch(); + public ILogger Logger { get; } - readonly IProgressMonitor progressMonitor; + public bool AddAssemblyTrapPrefix { get; } - public readonly ILogger Logger; + public PathTransformer PathTransformer { get; } - public Analyser(IProgressMonitor pm, ILogger logger) + public Analyser(IProgressMonitor pm, ILogger logger, bool addAssemblyTrapPrefix, PathTransformer pathTransformer) { Logger = logger; + AddAssemblyTrapPrefix = addAssemblyTrapPrefix; Logger.Log(Severity.Info, "EXTRACTION STARTING at {0}", DateTime.Now); stopWatch.Start(); progressMonitor = pm; + PathTransformer = pathTransformer; } - CSharpCompilation compilation; - Layout layout; - - private bool init; /// /// Start initialization of the analyser. /// /// The arguments passed to Roslyn. /// A Boolean indicating whether to proceed with extraction. - public bool BeginInitialize(string[] roslynArgs) + public bool BeginInitialize(IEnumerable roslynArgs) { return init = LogRoslynArgs(roslynArgs, Extraction.Extractor.Version); } @@ -64,7 +74,7 @@ public void EndInitialize( layout = new Layout(); this.options = options; this.compilation = compilation; - extractor = new Extraction.Extractor(false, GetOutputName(compilation, commandLineArguments), Logger); + extractor = new Extraction.Extractor(false, GetOutputName(compilation, commandLineArguments), Logger, PathTransformer); LogDiagnostics(); SetReferencePaths(); @@ -78,7 +88,7 @@ public void EndInitialize( /// Roslyn doesn't record the relationship between a filename and its assembly /// information, so we need to retrieve this information manually. /// - void SetReferencePaths() + private void SetReferencePaths() { foreach (var reference in compilation.References.OfType()) { @@ -90,18 +100,18 @@ void SetReferencePaths() * System.Reflection.Assembly.ReflectionOnlyLoadFrom. It is also allows * loading the same assembly from different locations. */ - using (var pereader = new System.Reflection.PortableExecutable.PEReader(new FileStream(refPath, FileMode.Open, FileAccess.Read, FileShare.Read))) + using var pereader = new System.Reflection.PortableExecutable.PEReader(new FileStream(refPath, FileMode.Open, FileAccess.Read, FileShare.Read)); + + var metadata = pereader.GetMetadata(); + string assemblyIdentity; + unsafe { - var metadata = pereader.GetMetadata(); - string assemblyIdentity; - unsafe - { - var reader = new System.Reflection.Metadata.MetadataReader(metadata.Pointer, metadata.Length); - var def = reader.GetAssemblyDefinition(); - assemblyIdentity = reader.GetString(def.Name) + " " + def.Version; - } - extractor.SetAssemblyFile(assemblyIdentity, refPath); + var reader = new System.Reflection.Metadata.MetadataReader(metadata.Pointer, metadata.Length); + var def = reader.GetAssemblyDefinition(); + assemblyIdentity = reader.GetString(def.Name) + " " + def.Version; } + extractor.SetAssemblyFile(assemblyIdentity, refPath); + } catch (Exception ex) // lgtm[cs/catch-of-all-exceptions] { @@ -114,20 +124,20 @@ public void InitializeStandalone(CSharpCompilation compilationIn, CommonOptions { compilation = compilationIn; layout = new Layout(); - extractor = new Extraction.Extractor(true, null, Logger); + extractor = new Extraction.Extractor(true, null, Logger, PathTransformer); this.options = options; LogExtractorInfo(Extraction.Extractor.Version); SetReferencePaths(); } - readonly HashSet errorsToIgnore = new HashSet + private readonly HashSet errorsToIgnore = new HashSet { "CS7027", // Code signing failure "CS1589", // XML referencing not supported "CS1569" // Error writing XML documentation }; - IEnumerable FilteredDiagnostics + private IEnumerable FilteredDiagnostics { get { @@ -148,7 +158,7 @@ IEnumerable FilteredDiagnostics /// Information about the compilation. /// Cancellation token required. /// The filename. - static string GetOutputName(CSharpCompilation compilation, + private static string GetOutputName(CSharpCompilation compilation, CSharpCommandLineArguments commandLineArguments) { // There's no apparent way to access the output filename from the compilation, @@ -161,22 +171,18 @@ static string GetOutputName(CSharpCompilation compilation, if (entry == null) { if (compilation.SyntaxTrees.Length == 0) - throw new ArgumentNullException("No source files seen"); + throw new InvalidOperationException("No source files seen"); // Probably invalid, but have a go anyway. var entryPointFile = compilation.SyntaxTrees.First().FilePath; return Path.ChangeExtension(entryPointFile, ".exe"); } - else - { - var entryPointFilename = entry.Locations.First().SourceTree.FilePath; - return Path.ChangeExtension(entryPointFilename, ".exe"); - } - } - else - { - return Path.Combine(commandLineArguments.OutputDirectory, commandLineArguments.OutputFileName); + + var entryPointFilename = entry.Locations.First().SourceTree.FilePath; + return Path.ChangeExtension(entryPointFilename, ".exe"); } + + return Path.Combine(commandLineArguments.OutputDirectory, commandLineArguments.OutputFileName); } /// @@ -192,7 +198,7 @@ public void AnalyseTree(SyntaxTree tree) /// Perform an analysis on an assembly. /// /// Assembly to analyse. - void AnalyseAssembly(PortableExecutableReference assembly) + private void AnalyseAssembly(PortableExecutableReference assembly) { // CIL first - it takes longer. if (options.CIL) @@ -200,12 +206,7 @@ void AnalyseAssembly(PortableExecutableReference assembly) extractionTasks.Add(() => DoAnalyseAssembly(assembly)); } - readonly object progressMutex = new object(); - int taskCount = 0; - - CommonOptions options; - - static bool FileIsUpToDate(string src, string dest) + private static bool FileIsUpToDate(string src, string dest) { return File.Exists(dest) && File.GetLastWriteTime(dest) >= File.GetLastWriteTime(src); @@ -219,19 +220,19 @@ public void AnalyseCompilation(string cwd, string[] args) extractionTasks.Add(() => DoAnalyseCompilation(cwd, args)); } - Entities.Compilation compilationEntity; - IDisposable compilationTrapFile; - void DoAnalyseCompilation(string cwd, string[] args) + + private void DoAnalyseCompilation(string cwd, string[] args) { try { var assemblyPath = extractor.OutputPath; + var transformedAssemblyPath = PathTransformer.Transform(assemblyPath); var assembly = compilation.Assembly; - var projectLayout = layout.LookupProjectOrDefault(assemblyPath); - var trapWriter = projectLayout.CreateTrapWriter(Logger, assemblyPath, true, options.TrapCompression); + var projectLayout = layout.LookupProjectOrDefault(transformedAssemblyPath); + var trapWriter = projectLayout.CreateTrapWriter(Logger, transformedAssemblyPath, true, options.TrapCompression); compilationTrapFile = trapWriter; // Dispose later - var cx = extractor.CreateContext(compilation.Clone(), trapWriter, new AssemblyScope(assembly, assemblyPath, true)); + var cx = extractor.CreateContext(compilation.Clone(), trapWriter, new AssemblyScope(assembly, assemblyPath, true), AddAssemblyTrapPrefix); compilationEntity = new Entities.Compilation(cx, cwd, args); } @@ -249,7 +250,7 @@ void DoAnalyseCompilation(string cwd, string[] args) /// extraction within the snapshot. /// /// The assembly to extract. - void DoAnalyseAssembly(PortableExecutableReference r) + private void DoAnalyseAssembly(PortableExecutableReference r) { try { @@ -257,48 +258,47 @@ void DoAnalyseAssembly(PortableExecutableReference r) stopwatch.Start(); var assemblyPath = r.FilePath; - var projectLayout = layout.LookupProjectOrDefault(assemblyPath); - using (var trapWriter = projectLayout.CreateTrapWriter(Logger, assemblyPath, true, options.TrapCompression)) + var transformedAssemblyPath = PathTransformer.Transform(assemblyPath); + var projectLayout = layout.LookupProjectOrDefault(transformedAssemblyPath); + using var trapWriter = projectLayout.CreateTrapWriter(Logger, transformedAssemblyPath, true, options.TrapCompression); + + var skipExtraction = options.Cache && File.Exists(trapWriter.TrapFile); + + if (!skipExtraction) { - var skipExtraction = options.Cache && File.Exists(trapWriter.TrapFile); + /* Note on parallel builds: + * + * The trap writer and source archiver both perform atomic moves + * of the file to the final destination. + * + * If the same source file or trap file are generated concurrently + * (by different parallel invocations of the extractor), then + * last one wins. + * + * Specifically, if two assemblies are analysed concurrently in a build, + * then there is a small amount of duplicated work but the output should + * still be correct. + */ + + // compilation.Clone() reduces memory footprint by allowing the symbols + // in c to be garbage collected. + Compilation c = compilation.Clone(); - if (!skipExtraction) - { - /* Note on parallel builds: - * - * The trap writer and source archiver both perform atomic moves - * of the file to the final destination. - * - * If the same source file or trap file are generated concurrently - * (by different parallel invocations of the extractor), then - * last one wins. - * - * Specifically, if two assemblies are analysed concurrently in a build, - * then there is a small amount of duplicated work but the output should - * still be correct. - */ - - // compilation.Clone() reduces memory footprint by allowing the symbols - // in c to be garbage collected. - Compilation c = compilation.Clone(); - - var assembly = c.GetAssemblyOrModuleSymbol(r) as IAssemblySymbol; - - if (assembly != null) - { - var cx = extractor.CreateContext(c, trapWriter, new AssemblyScope(assembly, assemblyPath, false)); - foreach (var module in assembly.Modules) - { - AnalyseNamespace(cx, module.GlobalNamespace); - } + if (c.GetAssemblyOrModuleSymbol(r) is IAssemblySymbol assembly) + { + var cx = extractor.CreateContext(c, trapWriter, new AssemblyScope(assembly, assemblyPath, false), AddAssemblyTrapPrefix); - cx.PopulateAll(); + foreach (var module in assembly.Modules) + { + AnalyseNamespace(cx, module.GlobalNamespace); } - } - ReportProgress(assemblyPath, trapWriter.TrapFile, stopwatch.Elapsed, skipExtraction ? AnalysisAction.UpToDate : AnalysisAction.Extracted); + cx.PopulateAll(); + } } + + ReportProgress(assemblyPath, trapWriter.TrapFile, stopwatch.Elapsed, skipExtraction ? AnalysisAction.UpToDate : AnalysisAction.Extracted); } catch (Exception ex) // lgtm[cs/catch-of-all-exceptions] { @@ -306,18 +306,16 @@ void DoAnalyseAssembly(PortableExecutableReference r) } } - void DoExtractCIL(PortableExecutableReference r) + private void DoExtractCIL(PortableExecutableReference r) { var stopwatch = new Stopwatch(); stopwatch.Start(); - string trapFile; - bool extracted; - CIL.Entities.Assembly.ExtractCIL(layout, r.FilePath, Logger, !options.Cache, options.PDB, options.TrapCompression, out trapFile, out extracted); + CIL.Entities.Assembly.ExtractCIL(layout, r.FilePath, Logger, !options.Cache, options.PDB, options.TrapCompression, out var trapFile, out var extracted); stopwatch.Stop(); ReportProgress(r.FilePath, trapFile, stopwatch.Elapsed, extracted ? AnalysisAction.Extracted : AnalysisAction.UpToDate); } - void AnalyseNamespace(Context cx, INamespaceSymbol ns) + private void AnalyseNamespace(Context cx, INamespaceSymbol ns) { foreach (var memberNamespace in ns.GetNamespaceMembers()) { @@ -342,46 +340,50 @@ public void AnalyseReferences() } // The bulk of the extraction work, potentially executed in parallel. - readonly List extractionTasks = new List(); + private readonly List extractionTasks = new List(); - void ReportProgress(string src, string output, TimeSpan time, AnalysisAction action) + private void ReportProgress(string src, string output, TimeSpan time, AnalysisAction action) { lock (progressMutex) progressMonitor.Analysed(++taskCount, extractionTasks.Count, src, output, time, action); } - void DoExtractTree(SyntaxTree tree) + private void DoExtractTree(SyntaxTree tree) { try { var stopwatch = new Stopwatch(); stopwatch.Start(); var sourcePath = tree.FilePath; + var transformedSourcePath = PathTransformer.Transform(sourcePath); - var projectLayout = layout.LookupProjectOrNull(sourcePath); - bool excluded = projectLayout == null; - string trapPath = excluded ? "" : projectLayout.GetTrapPath(Logger, sourcePath, options.TrapCompression); - bool upToDate = false; + var projectLayout = layout.LookupProjectOrNull(transformedSourcePath); + var excluded = projectLayout == null; + var trapPath = excluded ? "" : projectLayout.GetTrapPath(Logger, transformedSourcePath, options.TrapCompression); + var upToDate = false; if (!excluded) { // compilation.Clone() is used to allow symbols to be garbage collected. - using (var trapWriter = projectLayout.CreateTrapWriter(Logger, sourcePath, false, options.TrapCompression)) - { - upToDate = options.Fast && FileIsUpToDate(sourcePath, trapWriter.TrapFile); + using var trapWriter = projectLayout.CreateTrapWriter(Logger, transformedSourcePath, false, options.TrapCompression); - if (!upToDate) - { - Context cx = extractor.CreateContext(compilation.Clone(), trapWriter, new SourceScope(tree)); - Populators.CompilationUnit.Extract(cx, tree.GetRoot()); - cx.PopulateAll(); - cx.ExtractComments(cx.CommentGenerator); - cx.PopulateAll(); - } + upToDate = options.Fast && FileIsUpToDate(sourcePath, trapWriter.TrapFile); + + if (!upToDate) + { + var cx = extractor.CreateContext(compilation.Clone(), trapWriter, new SourceScope(tree), AddAssemblyTrapPrefix); + Populators.CompilationUnit.Extract(cx, tree.GetRoot()); + cx.PopulateAll(); + cx.ExtractComments(cx.CommentGenerator); + cx.PopulateAll(); } } - ReportProgress(sourcePath, trapPath, stopwatch.Elapsed, excluded ? AnalysisAction.Excluded : upToDate ? AnalysisAction.UpToDate : AnalysisAction.Extracted); + ReportProgress(sourcePath, trapPath, stopwatch.Elapsed, excluded + ? AnalysisAction.Excluded + : upToDate + ? AnalysisAction.UpToDate + : AnalysisAction.Extracted); } catch (Exception ex) // lgtm[cs/catch-of-all-exceptions] { @@ -445,7 +447,7 @@ public void LogExtractorInfo(string extractorVersion) /// /// The arguments passed to Roslyn. /// A Boolean indicating whether the same arguments have been logged previously. - public bool LogRoslynArgs(string[] roslynArgs, string extractorVersion) + private bool LogRoslynArgs(IEnumerable roslynArgs, string extractorVersion) { LogExtractorInfo(extractorVersion); Logger.Log(Severity.Info, $" Arguments to Roslyn: {string.Join(' ', roslynArgs)}"); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/CompilerVersion.cs b/csharp/extractor/Semmle.Extraction.CSharp/CompilerVersion.cs index c39052726559..f8da28affc44 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/CompilerVersion.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/CompilerVersion.cs @@ -13,8 +13,8 @@ namespace Semmle.Extraction.CSharp /// public class CompilerVersion { - const string csc_rsp = "csc.rsp"; - readonly string specifiedFramework = null; + private const string csc_rsp = "csc.rsp"; + private readonly string specifiedFramework = null; /// /// The value specified by --compiler, or null. @@ -85,7 +85,7 @@ public CompilerVersion(Options options) ArgsWithResponse = AddDefaultResponse(CscRsp, options.CompilerArguments).ToArray(); } - void SkipExtractionBecause(string reason) + private void SkipExtractionBecause(string reason) { SkipExtraction = true; SkipReason = reason; @@ -99,7 +99,7 @@ void SkipExtractionBecause(string reason) /// /// The file csc.rsp. /// - string CscRsp => Path.Combine(FrameworkPath, csc_rsp); + private string CscRsp => Path.Combine(FrameworkPath, csc_rsp); /// /// Should we skip extraction? @@ -122,18 +122,18 @@ public bool SkipExtraction /// The full pathname of csc.rsp. /// The other command line arguments. /// Modified list of arguments. - static IEnumerable AddDefaultResponse(string responseFile, IEnumerable args) + private static IEnumerable AddDefaultResponse(string responseFile, IEnumerable args) { return SuppressDefaultResponseFile(args) || !File.Exists(responseFile) ? args : new[] { "@" + responseFile }.Concat(args); } - static bool SuppressDefaultResponseFile(IEnumerable args) + private static bool SuppressDefaultResponseFile(IEnumerable args) { return args.Any(arg => new[] { "/noconfig", "-noconfig" }.Contains(arg.ToLowerInvariant())); } - public readonly string[] ArgsWithResponse; + public IEnumerable ArgsWithResponse { get; } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Accessor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Accessor.cs index 98c021c8a6d6..c53a2c402e01 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Accessor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Accessor.cs @@ -4,31 +4,33 @@ namespace Semmle.Extraction.CSharp.Entities { - class Accessor : Method + internal class Accessor : Method { protected Accessor(Context cx, IMethodSymbol init) : base(cx, init) { } /// - /// Gets the property symbol associated with this accessor. + /// Gets the property symbol associated accessor `symbol`, or `null` + /// if there is no associated symbol. /// - IPropertySymbol PropertySymbol + public static IPropertySymbol GetPropertySymbol(IMethodSymbol symbol) { - get - { - // Usually, the property/indexer can be fetched from the associated symbol - var prop = symbol.AssociatedSymbol as IPropertySymbol; - if (prop != null) - return prop; + // Usually, the property/indexer can be fetched from the associated symbol + if (symbol.AssociatedSymbol is IPropertySymbol prop) + return prop; - // But for properties/indexers that implement explicit interfaces, Roslyn - // does not properly populate `AssociatedSymbol` - var props = symbol.ContainingType.GetMembers().OfType(); - props = props.Where(p => SymbolEqualityComparer.Default.Equals(symbol, p.GetMethod) || SymbolEqualityComparer.Default.Equals(symbol, p.SetMethod)); - return props.SingleOrDefault(); - } + // But for properties/indexers that implement explicit interfaces, Roslyn + // does not properly populate `AssociatedSymbol` + var props = symbol.ContainingType.GetMembers().OfType(); + props = props.Where(p => SymbolEqualityComparer.Default.Equals(symbol, p.GetMethod) || SymbolEqualityComparer.Default.Equals(symbol, p.SetMethod)); + return props.SingleOrDefault(); } + /// + /// Gets the property symbol associated with this accessor. + /// + private IPropertySymbol PropertySymbol => GetPropertySymbol(symbol); + public new Accessor OriginalDefinition => Create(Context, symbol.OriginalDefinition); public override void Populate(TextWriter trapFile) @@ -76,12 +78,12 @@ public override void Populate(TextWriter trapFile) } } - public new static Accessor Create(Context cx, IMethodSymbol symbol) => - AccessorFactory.Instance.CreateEntity(cx, symbol); + public static new Accessor Create(Context cx, IMethodSymbol symbol) => + AccessorFactory.Instance.CreateEntityFromSymbol(cx, symbol); - class AccessorFactory : ICachedEntityFactory + private class AccessorFactory : ICachedEntityFactory { - public static readonly AccessorFactory Instance = new AccessorFactory(); + public static AccessorFactory Instance { get; } = new AccessorFactory(); public Accessor Create(Context cx, IMethodSymbol init) => new Accessor(cx, init); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Attribute.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Attribute.cs index 93b9c6fad5e9..ea2d798e6052 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Attribute.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Attribute.cs @@ -1,38 +1,35 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Semmle.Extraction.CSharp.Populators; using Semmle.Extraction.Entities; -using System.Collections.Generic; using System.IO; -using System.Linq; namespace Semmle.Extraction.CSharp.Entities { - class Attribute : FreshEntity, IExpressionParentEntity + internal class Attribute : FreshEntity, IExpressionParentEntity { bool IExpressionParentEntity.IsTopLevelParent => true; - private readonly AttributeData AttributeData; - private readonly IEntity Entity; + private readonly AttributeData attribute; + private readonly IEntity entity; public Attribute(Context cx, AttributeData attribute, IEntity entity) : base(cx) { - AttributeData = attribute; - Entity = entity; + this.attribute = attribute; + this.entity = entity; TryPopulate(); } protected override void Populate(TextWriter trapFile) { - if (AttributeData.ApplicationSyntaxReference != null) + if (attribute.ApplicationSyntaxReference != null) { // !! Extract attributes from assemblies. // This is harder because the "expression" entities presume the // existence of a syntax tree. This is not the case for compiled // attributes. - var syntax = AttributeData.ApplicationSyntaxReference.GetSyntax() as AttributeSyntax; - ExtractAttribute(cx.TrapWriter.Writer, syntax, AttributeData.AttributeClass, Entity); + var syntax = attribute.ApplicationSyntaxReference.GetSyntax() as AttributeSyntax; + ExtractAttribute(cx.TrapWriter.Writer, syntax, attribute.AttributeClass, entity); } } @@ -43,7 +40,7 @@ public Attribute(Context cx, AttributeSyntax attribute, IEntity entity) ExtractAttribute(cx.TrapWriter.Writer, attribute, info.Symbol.ContainingType, entity); } - void ExtractAttribute(System.IO.TextWriter trapFile, AttributeSyntax syntax, ITypeSymbol attributeClass, IEntity entity) + private void ExtractAttribute(System.IO.TextWriter trapFile, AttributeSyntax syntax, ITypeSymbol attributeClass, IEntity entity) { var type = Type.Create(cx, attributeClass); trapFile.attributes(this, type.TypeRef, entity); @@ -59,7 +56,7 @@ void ExtractAttribute(System.IO.TextWriter trapFile, AttributeSyntax syntax, ITy { cx.PopulateLater(() => { - int child = 0; + var child = 0; foreach (var arg in syntax.ArgumentList.Arguments) { var expr = Expression.Create(cx, arg.Expression, this, child++); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentBlock.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentBlock.cs index 0e851df1e6b2..ab6802cf4570 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentBlock.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentBlock.cs @@ -4,15 +4,15 @@ namespace Semmle.Extraction.CSharp.Entities { - class CommentBlock : CachedEntity + internal class CommentBlock : CachedEntity { - CommentBlock(Context cx, ICommentBlock init) + private CommentBlock(Context cx, ICommentBlock init) : base(cx, init) { } public override void Populate(TextWriter trapFile) { trapFile.commentblock(this); - int child = 0; + var child = 0; trapFile.commentblock_location(this, Context.Create(symbol.Location)); foreach (var l in symbol.CommentLines) { @@ -35,11 +35,11 @@ public void BindTo(Label entity, CommentBinding binding) Context.TrapWriter.Writer.commentblock_binding(this, entity, binding); } - public static CommentBlock Create(Context cx, ICommentBlock block) => CommentBlockFactory.Instance.CreateEntity(cx, block); + public static CommentBlock Create(Context cx, ICommentBlock block) => CommentBlockFactory.Instance.CreateEntity(cx, block, block); - class CommentBlockFactory : ICachedEntityFactory + private class CommentBlockFactory : ICachedEntityFactory { - public static readonly CommentBlockFactory Instance = new CommentBlockFactory(); + public static CommentBlockFactory Instance { get; } = new CommentBlockFactory(); public CommentBlock Create(Context cx, ICommentBlock init) => new CommentBlock(cx, init); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentLine.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentLine.cs index a3ba9896ef1c..ba1770f20e52 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentLine.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentLine.cs @@ -6,9 +6,9 @@ namespace Semmle.Extraction.CSharp.Entities { - class CommentLine : CachedEntity<(Microsoft.CodeAnalysis.Location, string)>, ICommentLine + internal class CommentLine : CachedEntity<(Microsoft.CodeAnalysis.Location, string)>, ICommentLine { - CommentLine(Context cx, Microsoft.CodeAnalysis.Location loc, CommentLineType type, string text, string raw) + private CommentLine(Context cx, Microsoft.CodeAnalysis.Location loc, CommentLineType type, string text, string raw) : base(cx, (loc, text)) { Type = type; @@ -36,14 +36,14 @@ So split it up. var split = text.Split('\n'); var currentLocation = trivia.GetLocation().SourceSpan.Start - 3; - for (int line = 0; line < split.Length - 1; ++line) + for (var line = 0; line < split.Length - 1; ++line) { - string fullLine = split[line]; + var fullLine = split[line]; var nextLineLocation = currentLocation + fullLine.Length + 1; fullLine = fullLine.TrimEnd('\r'); - string trimmedLine = fullLine; + var trimmedLine = fullLine; - int leadingSpaces = trimmedLine.IndexOf('/'); + var leadingSpaces = trimmedLine.IndexOf('/'); if (leadingSpaces != -1) { fullLine = fullLine.Substring(leadingSpaces); @@ -66,7 +66,7 @@ So split it up. case SyntaxKind.SingleLineCommentTrivia: { - string contents = trivia.ToString().Substring(2); + var contents = trivia.ToString().Substring(2); var commentType = CommentLineType.Singleline; if (contents.Length > 0 && contents[0] == '/') { @@ -86,14 +86,16 @@ So we split it into separate lines split = text.Split('\n'); currentLocation = trivia.GetLocation().SourceSpan.Start; - for (int line = 0; line < split.Length; ++line) + for (var line = 0; line < split.Length; ++line) { - string fullLine = split[line]; + var fullLine = split[line]; var nextLineLocation = currentLocation + fullLine.Length + 1; fullLine = fullLine.TrimEnd('\r'); - string trimmedLine = fullLine; - if (line == 0) trimmedLine = trimmedLine.Substring(2); - if (line == split.Length - 1) trimmedLine = trimmedLine.Substring(0, trimmedLine.Length - 2); + var trimmedLine = fullLine; + if (line == 0) + trimmedLine = trimmedLine.Substring(2); + if (line == split.Length - 1) + trimmedLine = trimmedLine.Substring(0, trimmedLine.Length - 2); trimmedLine = trimmedLine.Trim(); var span = Microsoft.CodeAnalysis.Text.TextSpan.FromBounds(currentLocation, currentLocation + fullLine.Length); @@ -110,7 +112,7 @@ So we split it into separate lines } } - Extraction.Entities.Location location; + private Extraction.Entities.Location location; public override void Populate(TextWriter trapFile) { @@ -129,11 +131,15 @@ public override void WriteId(TextWriter trapFile) trapFile.Write(";commentline"); } - static CommentLine Create(Context cx, Microsoft.CodeAnalysis.Location loc, CommentLineType type, string text, string raw) => CommentLineFactory.Instance.CreateEntity(cx, loc, type, text, raw); + private static CommentLine Create(Context cx, Microsoft.CodeAnalysis.Location loc, CommentLineType type, string text, string raw) + { + var init = (loc, type, text, raw); + return CommentLineFactory.Instance.CreateEntity(cx, init, init); + } - class CommentLineFactory : ICachedEntityFactory<(Microsoft.CodeAnalysis.Location, CommentLineType, string, string), CommentLine> + private class CommentLineFactory : ICachedEntityFactory<(Microsoft.CodeAnalysis.Location, CommentLineType, string, string), CommentLine> { - public static readonly CommentLineFactory Instance = new CommentLineFactory(); + public static CommentLineFactory Instance { get; } = new CommentLineFactory(); public CommentLine Create(Context cx, (Microsoft.CodeAnalysis.Location, CommentLineType, string, string) init) => new CommentLine(cx, init.Item1, init.Item2, init.Item3, init.Item4); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilation.cs index b6ff91f5988e..67a4325ce35e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilation.cs @@ -3,10 +3,11 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using Semmle.Util; namespace Semmle.Extraction.CSharp.Entities { - class Compilation : FreshEntity + internal class Compilation : FreshEntity { private readonly string cwd; private readonly string[] args; @@ -22,32 +23,32 @@ protected override void Populate(TextWriter trapFile) { Extraction.Entities.Assembly.CreateOutputAssembly(cx); - trapFile.compilations(this, Extraction.Entities.File.PathAsDatabaseString(cwd)); + trapFile.compilations(this, FileUtils.ConvertToUnix(cwd)); // Arguments - int index = 0; - foreach(var arg in args) + var index = 0; + foreach (var arg in args) { trapFile.compilation_args(this, index++, arg); } // Files index = 0; - foreach(var file in cx.Compilation.SyntaxTrees.Select(tree => Extraction.Entities.File.Create(cx, tree.FilePath))) + foreach (var file in cx.Compilation.SyntaxTrees.Select(tree => Extraction.Entities.File.Create(cx, tree.FilePath))) { trapFile.compilation_compiling_files(this, index++, file); } // References index = 0; - foreach(var file in cx.Compilation.References.OfType().Select(r => Extraction.Entities.File.Create(cx, r.FilePath))) + foreach (var file in cx.Compilation.References.OfType().Select(r => Extraction.Entities.File.Create(cx, r.FilePath))) { trapFile.compilation_referencing_files(this, index++, file); } // Diagnostics index = 0; - foreach(var diag in cx.Compilation.GetDiagnostics().Select(d => new Diagnostic(cx, d))) + foreach (var diag in cx.Compilation.GetDiagnostics().Select(d => new Diagnostic(cx, d))) { trapFile.diagnostic_for(diag, this, 0, index++); } @@ -56,8 +57,8 @@ protected override void Populate(TextWriter trapFile) public void PopulatePerformance(PerformanceMetrics p) { var trapFile = cx.TrapWriter.Writer; - int index = 0; - foreach(float metric in p.Metrics) + var index = 0; + foreach (var metric in p.Metrics) { trapFile.compilation_time(this, -1, index++, metric); } @@ -67,11 +68,11 @@ public void PopulatePerformance(PerformanceMetrics p) public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; } - class Diagnostic : FreshEntity + internal class Diagnostic : FreshEntity { public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; - readonly Microsoft.CodeAnalysis.Diagnostic diagnostic; + private readonly Microsoft.CodeAnalysis.Diagnostic diagnostic; public Diagnostic(Context cx, Microsoft.CodeAnalysis.Diagnostic diag) : base(cx) { @@ -88,7 +89,9 @@ protected override void Populate(TextWriter trapFile) public struct Timings { - public TimeSpan Elapsed, Cpu, User; + public TimeSpan Elapsed { get; set; } + public TimeSpan Cpu { get; set; } + public TimeSpan User { get; set; } } /// @@ -96,8 +99,10 @@ public struct Timings /// public struct PerformanceMetrics { - public Timings Frontend, Extractor, Total; - public long PeakWorkingSet; + public Timings Frontend { get; set; } + public Timings Extractor { get; set; } + public Timings Total { get; set; } + public long PeakWorkingSet { get; set; } /// /// These are in database order (0 indexed) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs index 298f838cfb93..35b3f2eb8086 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs @@ -1,6 +1,5 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Semmle.Extraction.CSharp.Populators; using Semmle.Util; using System.Linq; using Microsoft.CodeAnalysis.CSharp; @@ -11,7 +10,7 @@ namespace Semmle.Extraction.CSharp.Entities { public class Constructor : Method { - Constructor(Context cx, IMethodSymbol init) + private Constructor(Context cx, IMethodSymbol init) : base(cx, init) { } public override void Populate(TextWriter trapFile) @@ -34,12 +33,14 @@ public override void Populate(TextWriter trapFile) protected override void ExtractInitializers(TextWriter trapFile) { // Do not extract initializers for constructed types. - if (!IsSourceDeclaration) return; + if (!IsSourceDeclaration) + return; var syntax = Syntax; - var initializer = syntax == null ? null : syntax.Initializer; + var initializer = syntax?.Initializer; - if (initializer == null) return; + if (initializer == null) + return; Type initializerType; var symbolInfo = Context.GetSymbolInfo(initializer); @@ -78,33 +79,34 @@ protected override void ExtractInitializers(TextWriter trapFile) trapFile.expr_call(init, target); - int child = 0; + var child = 0; foreach (var arg in initializer.ArgumentList.Arguments) { Expression.Create(Context, arg.Expression, init, child++); } } - ConstructorDeclarationSyntax Syntax + private ConstructorDeclarationSyntax Syntax { get { - return symbol.DeclaringSyntaxReferences. - Select(r => r.GetSyntax()). - OfType(). - FirstOrDefault(); + return symbol.DeclaringSyntaxReferences + .Select(r => r.GetSyntax()) + .OfType() + .FirstOrDefault(); } } - public new static Constructor Create(Context cx, IMethodSymbol constructor) + public static new Constructor Create(Context cx, IMethodSymbol constructor) { - if (constructor == null) return null; + if (constructor == null) + return null; switch (constructor.MethodKind) { case MethodKind.StaticConstructor: case MethodKind.Constructor: - return ConstructorFactory.Instance.CreateEntity(cx, constructor); + return ConstructorFactory.Instance.CreateEntityFromSymbol(cx, constructor); default: throw new InternalError(constructor, "Attempt to create a Constructor from a symbol that isn't a constructor"); } @@ -112,13 +114,14 @@ ConstructorDeclarationSyntax Syntax public override void WriteId(TextWriter trapFile) { - if (symbol.IsStatic) trapFile.Write("static"); + if (symbol.IsStatic) + trapFile.Write("static"); trapFile.WriteSubId(ContainingType); AddParametersToId(Context, trapFile, symbol); trapFile.Write(";constructor"); } - ConstructorDeclarationSyntax GetSyntax() => + private ConstructorDeclarationSyntax GetSyntax() => symbol.DeclaringSyntaxReferences.Select(r => r.GetSyntax()).OfType().FirstOrDefault(); public override Microsoft.CodeAnalysis.Location FullLocation => ReportingLocation; @@ -132,20 +135,19 @@ public override Microsoft.CodeAnalysis.Location ReportingLocation { return syn.Identifier.GetLocation(); } - else if (symbol.IsImplicitlyDeclared) + + if (symbol.IsImplicitlyDeclared) { return ContainingType.ReportingLocation; } - else - { - return symbol.ContainingType.Locations.FirstOrDefault(); - } + + return symbol.ContainingType.Locations.FirstOrDefault(); } } - class ConstructorFactory : ICachedEntityFactory + private class ConstructorFactory : ICachedEntityFactory { - public static readonly ConstructorFactory Instance = new ConstructorFactory(); + public static ConstructorFactory Instance { get; } = new ConstructorFactory(); public Constructor Create(Context cx, IMethodSymbol init) => new Constructor(cx, init); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Conversion.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Conversion.cs index e365ca53ae0c..aa125cae0a17 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Conversion.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Conversion.cs @@ -5,31 +5,30 @@ namespace Semmle.Extraction.CSharp.Entities { - class Conversion : UserOperator + internal class Conversion : UserOperator { - Conversion(Context cx, IMethodSymbol init) + private Conversion(Context cx, IMethodSymbol init) : base(cx, init) { } - public new static Conversion Create(Context cx, IMethodSymbol symbol) => - ConversionFactory.Instance.CreateEntity(cx, symbol); + public static new Conversion Create(Context cx, IMethodSymbol symbol) => + ConversionFactory.Instance.CreateEntityFromSymbol(cx, symbol); public override Microsoft.CodeAnalysis.Location ReportingLocation { get { - return symbol. - DeclaringSyntaxReferences. - Select(r => r.GetSyntax()). - OfType(). - Select(s => s.FixedLocation()). - Concat(symbol.Locations). - FirstOrDefault(); + return symbol.DeclaringSyntaxReferences + .Select(r => r.GetSyntax()) + .OfType() + .Select(s => s.FixedLocation()) + .Concat(symbol.Locations) + .FirstOrDefault(); } } - class ConversionFactory : ICachedEntityFactory + private class ConversionFactory : ICachedEntityFactory { - public static readonly ConversionFactory Instance = new ConversionFactory(); + public static ConversionFactory Instance { get; } = new ConversionFactory(); public Conversion Create(Context cx, IMethodSymbol init) => new Conversion(cx, init); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Destructor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Destructor.cs index 33f3a330f944..a5c4acc3c03b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Destructor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Destructor.cs @@ -3,9 +3,9 @@ namespace Semmle.Extraction.CSharp.Entities { - class Destructor : Method + internal class Destructor : Method { - Destructor(Context cx, IMethodSymbol init) + private Destructor(Context cx, IMethodSymbol init) : base(cx, init) { } public override void Populate(TextWriter trapFile) @@ -18,17 +18,17 @@ public override void Populate(TextWriter trapFile) trapFile.destructor_location(this, Location); } - static new Destructor OriginalDefinition(Context cx, Destructor original, IMethodSymbol symbol) + private static new Destructor OriginalDefinition(Context cx, Destructor original, IMethodSymbol symbol) { return symbol.OriginalDefinition == null || SymbolEqualityComparer.Default.Equals(symbol.OriginalDefinition, symbol) ? original : Create(cx, symbol.OriginalDefinition); } - public new static Destructor Create(Context cx, IMethodSymbol symbol) => - DestructorFactory.Instance.CreateEntity(cx, symbol); + public static new Destructor Create(Context cx, IMethodSymbol symbol) => + DestructorFactory.Instance.CreateEntityFromSymbol(cx, symbol); - class DestructorFactory : ICachedEntityFactory + private class DestructorFactory : ICachedEntityFactory { - public static readonly DestructorFactory Instance = new DestructorFactory(); + public static DestructorFactory Instance { get; } = new DestructorFactory(); public Destructor Create(Context cx, IMethodSymbol init) => new Destructor(cx, init); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Event.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Event.cs index 224c81b9524b..5c24cf97655c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Event.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Event.cs @@ -5,9 +5,9 @@ namespace Semmle.Extraction.CSharp.Entities { - class Event : CachedSymbol + internal class Event : CachedSymbol { - Event(Context cx, IEventSymbol init) + private Event(Context cx, IEventSymbol init) : base(cx, init) { } public override void WriteId(TextWriter trapFile) @@ -53,18 +53,21 @@ public override void Populate(TextWriter trapFile) foreach (var l in Locations) trapFile.event_location(this, l); - foreach (var syntaxType in declSyntaxReferences.OfType(). - Select(d => d.Parent). - OfType(). - Select(syntax => syntax.Type)) + foreach (var syntaxType in declSyntaxReferences + .OfType() + .Select(d => d.Parent) + .OfType() + .Select(syntax => syntax.Type)) + { TypeMention.Create(Context, syntaxType, this, type); + } } - public static Event Create(Context cx, IEventSymbol symbol) => EventFactory.Instance.CreateEntity(cx, symbol); + public static Event Create(Context cx, IEventSymbol symbol) => EventFactory.Instance.CreateEntityFromSymbol(cx, symbol); - class EventFactory : ICachedEntityFactory + private class EventFactory : ICachedEntityFactory { - public static readonly EventFactory Instance = new EventFactory(); + public static EventFactory Instance { get; } = new EventFactory(); public Event Create(Context cx, IEventSymbol init) => new Event(cx, init); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/EventAccessor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/EventAccessor.cs index 7dc0a4dfcffa..c75b6766dc7b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/EventAccessor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/EventAccessor.cs @@ -3,15 +3,15 @@ namespace Semmle.Extraction.CSharp.Entities { - class EventAccessor : Accessor + internal class EventAccessor : Accessor { - EventAccessor(Context cx, IMethodSymbol init) + private EventAccessor(Context cx, IMethodSymbol init) : base(cx, init) { } /// /// Gets the event symbol associated with this accessor. /// - IEventSymbol EventSymbol => symbol.AssociatedSymbol as IEventSymbol; + private IEventSymbol EventSymbol => symbol.AssociatedSymbol as IEventSymbol; public override void Populate(TextWriter trapFile) { @@ -52,12 +52,12 @@ public override void Populate(TextWriter trapFile) Overrides(trapFile); } - public new static EventAccessor Create(Context cx, IMethodSymbol symbol) => - EventAccessorFactory.Instance.CreateEntity(cx, symbol); + public static new EventAccessor Create(Context cx, IMethodSymbol symbol) => + EventAccessorFactory.Instance.CreateEntityFromSymbol(cx, symbol); - class EventAccessorFactory : ICachedEntityFactory + private class EventAccessorFactory : ICachedEntityFactory { - public static readonly EventAccessorFactory Instance = new EventAccessorFactory(); + public static EventAccessorFactory Instance { get; } = new EventAccessorFactory(); public EventAccessor Create(Context cx, IMethodSymbol init) => new EventAccessor(cx, init); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs index 7e57ca9cddc9..5a7a4962f3b3 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs @@ -17,17 +17,17 @@ public interface IExpressionParentEntity : IEntity bool IsTopLevelParent { get; } } - class Expression : FreshEntity, IExpressionParentEntity + internal class Expression : FreshEntity, IExpressionParentEntity { - private readonly IExpressionInfo Info; - public readonly AnnotatedType Type; - public readonly Extraction.Entities.Location Location; - public readonly ExprKind Kind; + private readonly IExpressionInfo info; + public AnnotatedType Type { get; } + public Extraction.Entities.Location Location { get; } + public ExprKind Kind { get; } internal Expression(IExpressionInfo info) : base(info.Context) { - Info = info; + this.info = info; Location = info.Location; Kind = info.Kind; Type = info.Type; @@ -40,10 +40,10 @@ internal Expression(IExpressionInfo info) protected sealed override void Populate(TextWriter trapFile) { trapFile.expressions(this, Kind, Type.Type.TypeRef); - if (Info.Parent.IsTopLevelParent) - trapFile.expr_parent_top_level(this, Info.Child, Info.Parent); + if (info.Parent.IsTopLevelParent) + trapFile.expr_parent_top_level(this, info.Child, info.Parent); else - trapFile.expr_parent(this, Info.Child, Info.Parent); + trapFile.expr_parent(this, info.Child, info.Parent); trapFile.expr_location(this, Location); var annotatedType = Type.Symbol; @@ -53,15 +53,15 @@ protected sealed override void Populate(TextWriter trapFile) trapFile.type_nullability(this, n); } - if(Info.FlowState != NullableFlowState.None) + if (info.FlowState != NullableFlowState.None) { - trapFile.expr_flowstate(this, (int)Info.FlowState); + trapFile.expr_flowstate(this, (int)info.FlowState); } - if (Info.IsCompilerGenerated) + if (info.IsCompilerGenerated) trapFile.expr_compiler_generated(this); - if (Info.ExprValue is string value) + if (info.ExprValue is string value) trapFile.expr_value(this, value); Type.Type.PopulateGenerics(); @@ -78,7 +78,13 @@ protected sealed override void Populate(TextWriter trapFile) /// The string representation. public static string ValueAsString(object value) { - return value == null ? "null" : value is bool ? ((bool)value ? "true" : "false") : value.ToString(); + return value == null + ? "null" + : value is bool b + ? b + ? "true" + : "false" + : value.ToString(); } /// @@ -116,7 +122,7 @@ public static void CreateDeferred(Context cx, ExpressionSyntax node, IExpression cx.PopulateLater(() => Create(cx, node, parent, child)); } - static bool ContainsPattern(SyntaxNode node) => + private static bool ContainsPattern(SyntaxNode node) => node is PatternSyntax || node is VariableDesignationSyntax || node.ChildNodes().Any(ContainsPattern); /// @@ -144,7 +150,7 @@ public void OperatorCall(TextWriter trapFile, ExpressionSyntax node) var callType = GetCallType(cx, node); if (callType == CallType.Dynamic) { - UserOperator.OperatorSymbol(method.Name, out string operatorName); + UserOperator.OperatorSymbol(method.Name, out var operatorName); trapFile.dynamic_member_name(this, operatorName); return; } @@ -212,10 +218,11 @@ protected static ExpressionSyntax FindConditionalQualifier(ExpressionSyntax node { for (SyntaxNode n = node; n != null; n = n.Parent) { - var conditionalAccess = n.Parent as ConditionalAccessExpressionSyntax; - - if (conditionalAccess != null && conditionalAccess.WhenNotNull == n) + if (n.Parent is ConditionalAccessExpressionSyntax conditionalAccess && + conditionalAccess.WhenNotNull == n) + { return conditionalAccess.Expression; + } } throw new InternalError(node, "Unable to locate a ConditionalAccessExpression"); @@ -266,7 +273,7 @@ private void PopulateArgument(TextWriter trapFile, ArgumentSyntax arg, int child public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel; } - static class CallTypeExtensions + internal static class CallTypeExtensions { /// /// Adjust the expression kind to match this call type. @@ -284,15 +291,15 @@ public static ExprKind AdjustKind(this Expression.CallType ct, ExprKind k) } } - abstract class Expression : Expression - where SyntaxNode : ExpressionSyntax + internal abstract class Expression : Expression + where TExpressionSyntax : ExpressionSyntax { - public readonly SyntaxNode Syntax; + public TExpressionSyntax Syntax { get; } protected Expression(ExpressionNodeInfo info) : base(info) { - Syntax = (SyntaxNode)info.Node; + Syntax = (TExpressionSyntax)info.Node; } /// @@ -307,7 +314,7 @@ protected Expression(ExpressionNodeInfo info) protected new Expression TryPopulate() { - cx.Try(Syntax, null, ()=>PopulateExpression(cx.TrapWriter.Writer)); + cx.Try(Syntax, null, () => PopulateExpression(cx.TrapWriter.Writer)); return this; } } @@ -315,7 +322,7 @@ protected Expression(ExpressionNodeInfo info) /// /// Holds all information required to create an Expression entity. /// - interface IExpressionInfo + internal interface IExpressionInfo { Context Context { get; } @@ -363,7 +370,7 @@ interface IExpressionInfo /// /// Explicitly constructed expression information. /// - class ExpressionInfo : IExpressionInfo + internal class ExpressionInfo : IExpressionInfo { public Context Context { get; } public AnnotatedType Type { get; } @@ -394,7 +401,7 @@ public ExpressionInfo(Context cx, AnnotatedType type, Extraction.Entities.Locati /// /// Expression information constructed from a syntax node. /// - class ExpressionNodeInfo : IExpressionInfo + internal class ExpressionNodeInfo : IExpressionInfo { public ExpressionNodeInfo(Context cx, ExpressionSyntax node, IExpressionParentEntity parent, int child) : this(cx, node, parent, child, cx.GetTypeInfo(node)) @@ -434,8 +441,7 @@ public AnnotatedTypeSymbol ExpressionType // Clearly a bug. if (type.Symbol?.TypeKind == Microsoft.CodeAnalysis.TypeKind.Error) { - var arrayCreation = Node as ArrayCreationExpressionSyntax; - if (arrayCreation != null) + if (Node is ArrayCreationExpressionSyntax arrayCreation) { var elementType = Context.GetType(arrayCreation.Type.ElementType); @@ -451,7 +457,7 @@ public AnnotatedTypeSymbol ExpressionType } } - Microsoft.CodeAnalysis.Location location; + private Microsoft.CodeAnalysis.Location location; public Microsoft.CodeAnalysis.Location CodeAnalysisLocation { @@ -478,7 +484,7 @@ public string ExprValue } } - AnnotatedType cachedType; + private AnnotatedType cachedType; public AnnotatedType Type { @@ -494,7 +500,7 @@ public AnnotatedType Type } } - Extraction.Entities.Location cachedLocation; + private Extraction.Entities.Location cachedLocation; public Extraction.Entities.Location Location { @@ -540,7 +546,7 @@ public ExpressionNodeInfo SetNode(ExpressionSyntax node) return this; } - SymbolInfo cachedSymbolInfo; + private SymbolInfo cachedSymbolInfo; public SymbolInfo SymbolInfo { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Access.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Access.cs index dca2a2b96bbe..e91b81a3d77d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Access.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Access.cs @@ -1,12 +1,11 @@ using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.Kinds; namespace Semmle.Extraction.CSharp.Entities.Expressions { - class Access : Expression + internal class Access : Expression { - static ExprKind AccessKind(Context cx, ISymbol symbol) + private static ExprKind AccessKind(Context cx, ISymbol symbol) { switch (symbol.Kind) { @@ -43,7 +42,7 @@ static ExprKind AccessKind(Context cx, ISymbol symbol) } } - Access(ExpressionNodeInfo info, ISymbol symbol, bool implicitThis, IEntity target) + private Access(ExpressionNodeInfo info, ISymbol symbol, bool implicitThis, IEntity target) : base(info.SetKind(AccessKind(info.Context, symbol))) { if (!(target is null)) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArgList.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArgList.cs index cb45b7593894..bd96850bbe13 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArgList.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArgList.cs @@ -5,9 +5,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - class ArgList : Expression + internal class ArgList : Expression { - ArgList(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.UNKNOWN)) { } + private ArgList(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.UNKNOWN)) { } protected override void PopulateExpression(TextWriter trapFile) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArrayCreation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArrayCreation.cs index a4b1a4beb093..adb7644e9195 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArrayCreation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArrayCreation.cs @@ -1,4 +1,5 @@ using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.Kinds; using System.IO; @@ -6,22 +7,24 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - abstract class ArrayCreation : Expression where SyntaxNode : ExpressionSyntax + internal abstract class ArrayCreation : Expression + where TSyntaxNode : ExpressionSyntax { protected ArrayCreation(ExpressionNodeInfo info) : base(info) { } } - abstract class ExplicitArrayCreation : ArrayCreation where SyntaxNode : ExpressionSyntax + internal abstract class ExplicitArrayCreation : ArrayCreation + where TSyntaxNode : ExpressionSyntax { protected ExplicitArrayCreation(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.ARRAY_CREATION)) { } protected abstract ArrayTypeSyntax TypeSyntax { get; } - public abstract InitializerExpressionSyntax Initializer { get; } + public abstract InitializerExpressionSyntax Initializer { get; } protected override void PopulateExpression(TextWriter trapFile) { - var child = 0; + var explicitlySized = false; if (TypeSyntax is null) @@ -29,38 +32,21 @@ protected override void PopulateExpression(TextWriter trapFile) cx.ModelError(Syntax, "Array has unexpected type syntax"); } - foreach (var rank in TypeSyntax.RankSpecifiers.SelectMany(rs => rs.Sizes)) + var firstLevelSizes = TypeSyntax.RankSpecifiers.First()?.Sizes ?? SyntaxFactory.SeparatedList(); + + if (firstLevelSizes.OfType().Any(s => s is OmittedArraySizeExpressionSyntax)) { - if (rank is OmittedArraySizeExpressionSyntax) - { - // Create an expression which simulates the explicit size of the array - - if (!(Initializer is null)) - { - // An implicitly-sized array must have an initializer. - // Guard it just in case. - var size = Initializer.Expressions.Count; - - var info = new ExpressionInfo( - cx, - new AnnotatedType(Entities.Type.Create(cx, cx.Compilation.GetSpecialType(Microsoft.CodeAnalysis.SpecialType.System_Int32)), NullableAnnotation.None), - Location, - ExprKind.INT_LITERAL, - this, - child, - false, - size.ToString()); - - new Expression(info); - } - } - else + SetArraySizes(Initializer, firstLevelSizes.Count); + } + else + { + for (var sizeIndex = 0; sizeIndex < firstLevelSizes.Count; sizeIndex++) { - Create(cx, rank, this, child); - explicitlySized = true; + Create(cx, firstLevelSizes[sizeIndex], this, sizeIndex); } - child++; + explicitlySized = true; } + if (!(Initializer is null)) { ArrayInitializer.Create(new ExpressionNodeInfo(cx, Initializer, this, -1)); @@ -69,9 +55,34 @@ protected override void PopulateExpression(TextWriter trapFile) if (explicitlySized) trapFile.explicitly_sized_array_creation(this); } + + private void SetArraySizes(InitializerExpressionSyntax initializer, int rank) + { + for (var level = 0; level < rank; level++) + { + if (initializer is null) + { + return; + } + + var info = new ExpressionInfo( + cx, + new AnnotatedType(Entities.Type.Create(cx, cx.Compilation.GetSpecialType(Microsoft.CodeAnalysis.SpecialType.System_Int32)), NullableAnnotation.None), + Location, + ExprKind.INT_LITERAL, + this, + level, + true, + initializer.Expressions.Count.ToString()); + + new Expression(info); + + initializer = initializer.Expressions.FirstOrDefault() as InitializerExpressionSyntax; + } + } } - class NormalArrayCreation : ExplicitArrayCreation + internal class NormalArrayCreation : ExplicitArrayCreation { private NormalArrayCreation(ExpressionNodeInfo info) : base(info) { } @@ -82,9 +93,9 @@ private NormalArrayCreation(ExpressionNodeInfo info) : base(info) { } public static Expression Create(ExpressionNodeInfo info) => new NormalArrayCreation(info).TryPopulate(); } - class StackAllocArrayCreation : ExplicitArrayCreation + internal class StackAllocArrayCreation : ExplicitArrayCreation { - StackAllocArrayCreation(ExpressionNodeInfo info) : base(info) { } + private StackAllocArrayCreation(ExpressionNodeInfo info) : base(info) { } protected override ArrayTypeSyntax TypeSyntax => Syntax.Type as ArrayTypeSyntax; @@ -99,9 +110,9 @@ protected override void PopulateExpression(TextWriter trapFile) public static Expression Create(ExpressionNodeInfo info) => new StackAllocArrayCreation(info).TryPopulate(); } - class ImplicitStackAllocArrayCreation : ArrayCreation + internal class ImplicitStackAllocArrayCreation : ArrayCreation { - ImplicitStackAllocArrayCreation(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.ARRAY_CREATION)) { } + private ImplicitStackAllocArrayCreation(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.ARRAY_CREATION)) { } public static Expression Create(ExpressionNodeInfo info) => new ImplicitStackAllocArrayCreation(info).TryPopulate(); @@ -113,9 +124,9 @@ protected override void PopulateExpression(TextWriter trapFile) } } - class ImplicitArrayCreation : ArrayCreation + internal class ImplicitArrayCreation : ArrayCreation { - ImplicitArrayCreation(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.ARRAY_CREATION)) { } + private ImplicitArrayCreation(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.ARRAY_CREATION)) { } public static Expression Create(ExpressionNodeInfo info) => new ImplicitArrayCreation(info).TryPopulate(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs index d82fc1160eac..f785ce65da32 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs @@ -1,15 +1,14 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp; -using Semmle.Extraction.CSharp.Populators; using Semmle.Extraction.Kinds; using Microsoft.CodeAnalysis; using System.IO; namespace Semmle.Extraction.CSharp.Entities.Expressions { - class Assignment : Expression + internal class Assignment : Expression { - Assignment(ExpressionNodeInfo info) + private Assignment(ExpressionNodeInfo info) : base(info.SetKind(GetKind(info.Context, (AssignmentExpressionSyntax)info.Node))) { } @@ -46,7 +45,7 @@ protected override void PopulateExpression(TextWriter trapFile) } } - static ExprKind GetAssignmentOperation(Context cx, AssignmentExpressionSyntax syntax) + private static ExprKind GetAssignmentOperation(Context cx, AssignmentExpressionSyntax syntax) { switch (syntax.OperatorToken.Kind()) { @@ -80,10 +79,8 @@ static ExprKind GetAssignmentOperation(Context cx, AssignmentExpressionSyntax sy } } - static ExprKind GetKind(Context cx, AssignmentExpressionSyntax syntax) + private static ExprKind GetKind(Context cx, AssignmentExpressionSyntax syntax) { - var leftSymbol = cx.GetSymbolInfo(syntax.Left); - bool assignEvent = leftSymbol.Symbol != null && leftSymbol.Symbol is IEventSymbol; var kind = GetAssignmentOperation(cx, syntax); var leftType = cx.GetType(syntax.Left); @@ -94,6 +91,9 @@ static ExprKind GetKind(Context cx, AssignmentExpressionSyntax syntax) return kind; } + var leftSymbol = cx.GetSymbolInfo(syntax.Left); + var assignEvent = leftSymbol.Symbol is IEventSymbol; + if (kind == ExprKind.ASSIGN_ADD && assignEvent) { return ExprKind.ADD_EVENT; @@ -112,7 +112,7 @@ static ExprKind GetKind(Context cx, AssignmentExpressionSyntax syntax) /// assignment is not an assignment operator). For example, the operator /// kind of `*=` is `*`. /// - ExprKind? OperatorKind + private ExprKind? OperatorKind { get { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Await.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Await.cs index 4a0d8eac0dd6..2f8726c80706 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Await.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Await.cs @@ -4,9 +4,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - class Await : Expression + internal class Await : Expression { - Await(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.AWAIT)) { } + private Await(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.AWAIT)) { } public static Expression Create(ExpressionNodeInfo info) => new Await(info).TryPopulate(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Base.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Base.cs index e67c18245f65..cfee9aa2e7cf 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Base.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Base.cs @@ -1,11 +1,10 @@ -using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.Kinds; namespace Semmle.Extraction.CSharp.Entities.Expressions { - class Base : Expression + internal class Base : Expression { - Base(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.BASE_ACCESS)) { } + private Base(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.BASE_ACCESS)) { } public static Base Create(ExpressionNodeInfo info) => new Base(info); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Binary.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Binary.cs index 938a21d7642e..32ee3be5f735 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Binary.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Binary.cs @@ -5,9 +5,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - class Binary : Expression + internal class Binary : Expression { - Binary(ExpressionNodeInfo info) + private Binary(ExpressionNodeInfo info) : base(info.SetKind(GetKind(info.Context, (BinaryExpressionSyntax)info.Node))) { } @@ -21,13 +21,13 @@ protected override void PopulateExpression(TextWriter trapFile) CreateDeferred(cx, Syntax.Right, this, 1); } - static ExprKind GetKind(Context cx, BinaryExpressionSyntax node) + private static ExprKind GetKind(Context cx, BinaryExpressionSyntax node) { var k = GetBinaryTokenKind(cx, node.OperatorToken.Kind()); return GetCallType(cx, node).AdjustKind(k); } - static ExprKind GetBinaryTokenKind(Context cx, SyntaxKind kind) + private static ExprKind GetBinaryTokenKind(Context cx, SyntaxKind kind) { switch (kind) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs index 9af08f696e35..52e2529b54ff 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs @@ -4,9 +4,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - class Cast : Expression + internal class Cast : Expression { - Cast(ExpressionNodeInfo info) : base(info.SetKind(UnaryOperatorKind(info.Context, ExprKind.CAST, info.Node))) { } + private Cast(ExpressionNodeInfo info) : base(info.SetKind(UnaryOperatorKind(info.Context, ExprKind.CAST, info.Node))) { } public static Expression Create(ExpressionNodeInfo info) => new Cast(info).TryPopulate(); @@ -15,8 +15,9 @@ protected override void PopulateExpression(TextWriter trapFile) Create(cx, Syntax.Expression, this, 0); if (Kind == ExprKind.CAST) - // Type cast + { // Type cast TypeAccess.Create(new ExpressionNodeInfo(cx, Syntax.Type, this, 1)); + } else { // Type conversion diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Checked.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Checked.cs index 4988a3c469d3..e6958c4511cc 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Checked.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Checked.cs @@ -4,9 +4,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - class Checked : Expression + internal class Checked : Expression { - Checked(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.CHECKED)) { } + private Checked(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.CHECKED)) { } public static Expression Create(ExpressionNodeInfo info) => new Checked(info).TryPopulate(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Conditional.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Conditional.cs index 48b5031cdd25..bfa4a836feb2 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Conditional.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Conditional.cs @@ -4,9 +4,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - class Conditional : Expression + internal class Conditional : Expression { - Conditional(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.CONDITIONAL)) { } + private Conditional(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.CONDITIONAL)) { } public static Expression Create(ExpressionNodeInfo info) => new Conditional(info).TryPopulate(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Default.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Default.cs index 460dd65d2d6a..326516bba1b1 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Default.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Default.cs @@ -4,9 +4,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - class Default : Expression + internal class Default : Expression { - Default(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.DEFAULT)) { } + private Default(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.DEFAULT)) { } public static Expression Create(ExpressionNodeInfo info) => new Default(info).TryPopulate(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Discard.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Discard.cs index d812c19496f2..194261c46141 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Discard.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Discard.cs @@ -1,18 +1,17 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.Entities; using Semmle.Extraction.Kinds; namespace Semmle.Extraction.CSharp.Entities.Expressions { - class Discard : Expression + internal class Discard : Expression { public Discard(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.DISCARD)) { } - Discard(Context cx, CSharpSyntaxNode syntax, IExpressionParentEntity parent, int child) : + private Discard(Context cx, CSharpSyntaxNode syntax, IExpressionParentEntity parent, int child) : base(new ExpressionInfo(cx, Entities.Type.Create(cx, cx.GetType(syntax)), cx.Create(syntax.GetLocation()), ExprKind.DISCARD, parent, child, false, null)) { } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs index b0252f9f8de5..afc4cd2cd93d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs @@ -1,48 +1,45 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.CSharp.Populators; using Semmle.Extraction.Kinds; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis; -using Semmle.Extraction.Entities; using System.IO; namespace Semmle.Extraction.CSharp.Entities.Expressions { - abstract class ElementAccess : Expression + internal abstract class ElementAccess : Expression { protected ElementAccess(ExpressionNodeInfo info, ExpressionSyntax qualifier, BracketedArgumentListSyntax argumentList) : base(info.SetKind(GetKind(info.Context, qualifier))) { - Qualifier = qualifier; - ArgumentList = argumentList; + this.qualifier = qualifier; + this.argumentList = argumentList; } - readonly ExpressionSyntax Qualifier; - readonly BracketedArgumentListSyntax ArgumentList; + private readonly ExpressionSyntax qualifier; + private readonly BracketedArgumentListSyntax argumentList; protected override void PopulateExpression(TextWriter trapFile) { if (Kind == ExprKind.POINTER_INDIRECTION) { - var qualifierInfo = new ExpressionNodeInfo(cx, Qualifier, this, 0); + var qualifierInfo = new ExpressionNodeInfo(cx, qualifier, this, 0); var add = new Expression(new ExpressionInfo(cx, qualifierInfo.Type, Location, ExprKind.ADD, this, 0, false, null)); qualifierInfo.SetParent(add, 0); CreateFromNode(qualifierInfo); - PopulateArguments(trapFile, ArgumentList, 1); + PopulateArguments(trapFile, argumentList, 1); } else { var child = -1; - Create(cx, Qualifier, this, child++); - foreach (var a in ArgumentList.Arguments) + Create(cx, qualifier, this, child++); + foreach (var a in argumentList.Arguments) { cx.Extract(a, this, child++); } var symbolInfo = cx.GetSymbolInfo(base.Syntax); - var indexer = symbolInfo.Symbol as IPropertySymbol; - if (indexer != null) + if (symbolInfo.Symbol is IPropertySymbol indexer) { trapFile.expr_access(this, Indexer.Create(cx, indexer)); } @@ -51,12 +48,13 @@ protected override void PopulateExpression(TextWriter trapFile) public sealed override Microsoft.CodeAnalysis.Location ReportingLocation => base.ReportingLocation; - static ExprKind GetKind(Context cx, ExpressionSyntax qualifier) + private static ExprKind GetKind(Context cx, ExpressionSyntax qualifier) { var qualifierType = cx.GetType(qualifier); // This is a compilation error, so make a guess and continue. - if (qualifierType.Symbol == null) return ExprKind.ARRAY_ACCESS; + if (qualifierType.Symbol == null) + return ExprKind.ARRAY_ACCESS; if (qualifierType.Symbol.TypeKind == Microsoft.CodeAnalysis.TypeKind.Pointer) { @@ -64,25 +62,25 @@ static ExprKind GetKind(Context cx, ExpressionSyntax qualifier) return ExprKind.POINTER_INDIRECTION; } - return IsDynamic(cx, qualifier) ? - ExprKind.DYNAMIC_ELEMENT_ACCESS : - qualifierType.Symbol.TypeKind == Microsoft.CodeAnalysis.TypeKind.Array ? - ExprKind.ARRAY_ACCESS : - ExprKind.INDEXER_ACCESS; + return IsDynamic(cx, qualifier) + ? ExprKind.DYNAMIC_ELEMENT_ACCESS + : qualifierType.Symbol.TypeKind == Microsoft.CodeAnalysis.TypeKind.Array + ? ExprKind.ARRAY_ACCESS + : ExprKind.INDEXER_ACCESS; } } - class NormalElementAccess : ElementAccess + internal class NormalElementAccess : ElementAccess { - NormalElementAccess(ExpressionNodeInfo info) + private NormalElementAccess(ExpressionNodeInfo info) : base(info, ((ElementAccessExpressionSyntax)info.Node).Expression, ((ElementAccessExpressionSyntax)info.Node).ArgumentList) { } public static Expression Create(ExpressionNodeInfo info) => new NormalElementAccess(info).TryPopulate(); } - class BindingElementAccess : ElementAccess + internal class BindingElementAccess : ElementAccess { - BindingElementAccess(ExpressionNodeInfo info) + private BindingElementAccess(ExpressionNodeInfo info) : base(info, FindConditionalQualifier(info.Node), ((ElementBindingExpressionSyntax)info.Node).ArgumentList) { } public static Expression Create(ExpressionNodeInfo info) => new BindingElementAccess(info).TryPopulate(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Factory.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Factory.cs index eb0cd847295b..889dbfd378bc 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Factory.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Factory.cs @@ -1,7 +1,5 @@ -using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Semmle.Extraction.CSharp.Populators; using Semmle.Extraction.Kinds; namespace Semmle.Extraction.CSharp.Entities.Expressions diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs index 503136fa22fb..a9884a5df5d8 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs @@ -1,13 +1,9 @@ using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Semmle.Extraction.CSharp.Populators; using Semmle.Extraction.Kinds; -using System.IO; namespace Semmle.Extraction.CSharp.Entities.Expressions { - class ImplicitCast : Expression + internal class ImplicitCast : Expression { public Expression Expr { @@ -22,7 +18,7 @@ public ImplicitCast(ExpressionNodeInfo info) } public ImplicitCast(ExpressionNodeInfo info, IMethodSymbol method) - : base(new ExpressionInfo(info.Context, Entities.Type.Create(info.Context, info.ConvertedType), info.Location, ExprKind.OPERATOR_INVOCATION, info.Parent, info.Child, true, info.ExprValue) ) + : base(new ExpressionInfo(info.Context, Entities.Type.Create(info.Context, info.ConvertedType), info.Location, ExprKind.OPERATOR_INVOCATION, info.Parent, info.Child, true, info.ExprValue)) { Expr = Factory.Create(info.SetParent(this, 0)); @@ -50,12 +46,13 @@ public static Expression Create(ExpressionNodeInfo info) if (conversion.MethodSymbol != null) { - bool convertedToDelegate = Entities.Type.IsDelegate(convertedType.Symbol); + var convertedToDelegate = Entities.Type.IsDelegate(convertedType.Symbol); if (convertedToDelegate) { - var objectCreation = info.Parent as ExplicitObjectCreation; - bool isExplicitConversion = objectCreation != null && objectCreation.Kind == ExprKind.EXPLICIT_DELEGATE_CREATION; + var isExplicitConversion = + info.Parent is ExplicitObjectCreation objectCreation && + objectCreation.Kind == ExprKind.EXPLICIT_DELEGATE_CREATION; if (!isExplicitConversion) { @@ -72,7 +69,7 @@ public static Expression Create(ExpressionNodeInfo info) return new ImplicitCast(info, conversion.MethodSymbol); } - bool implicitUpcast = conversion.IsImplicit && + var implicitUpcast = conversion.IsImplicit && convertedType.Symbol != null && !conversion.IsBoxing && ( @@ -86,6 +83,15 @@ public static Expression Create(ExpressionNodeInfo info) return new ImplicitCast(info); } + if (conversion.IsIdentity && conversion.IsImplicit && + convertedType.Symbol is IPointerTypeSymbol && + !(resolvedType.Symbol is IPointerTypeSymbol)) + { + // int[] -> int* + // string -> char* + return new ImplicitCast(info); + } + // Default: Just create the expression without a conversion. return Factory.Create(info); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs index 6af92a0d8cb4..cec690ea79d1 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs @@ -1,21 +1,20 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Semmle.Extraction.CSharp.Populators; using Semmle.Extraction.Entities; using Semmle.Extraction.Kinds; using System.IO; namespace Semmle.Extraction.CSharp.Entities.Expressions { - abstract class Initializer : Expression + internal abstract class Initializer : Expression { protected Initializer(ExpressionNodeInfo info) : base(info) { } } - class ArrayInitializer : Expression + internal class ArrayInitializer : Expression { - ArrayInitializer(ExpressionNodeInfo info) : base(info.SetType(NullType.Create(info.Context)).SetKind(ExprKind.ARRAY_INIT)) { } + private ArrayInitializer(ExpressionNodeInfo info) : base(info.SetType(NullType.Create(info.Context)).SetKind(ExprKind.ARRAY_INIT)) { } public static Expression Create(ExpressionNodeInfo info) => new ArrayInitializer(info).TryPopulate(); @@ -39,9 +38,9 @@ protected override void PopulateExpression(TextWriter trapFile) } // Array initializer { ..., ... }. - class ImplicitArrayInitializer : Initializer + internal class ImplicitArrayInitializer : Initializer { - ImplicitArrayInitializer(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.ARRAY_CREATION)) { } + private ImplicitArrayInitializer(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.ARRAY_CREATION)) { } public static Expression Create(ExpressionNodeInfo info) => new ImplicitArrayInitializer(info).TryPopulate(); @@ -52,9 +51,9 @@ protected override void PopulateExpression(TextWriter trapFile) } } - class ObjectInitializer : Initializer + internal class ObjectInitializer : Initializer { - ObjectInitializer(ExpressionNodeInfo info) + private ObjectInitializer(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.OBJECT_INIT)) { } public static Expression Create(ExpressionNodeInfo info) => new ObjectInitializer(info).TryPopulate(); @@ -65,16 +64,14 @@ protected override void PopulateExpression(TextWriter trapFile) foreach (var init in Syntax.Expressions) { - var assignment = init as AssignmentExpressionSyntax; - - if (assignment != null) + if (init is AssignmentExpressionSyntax assignment) { var assignmentInfo = new ExpressionNodeInfo(cx, init, this, child++).SetKind(ExprKind.SIMPLE_ASSIGN); var assignmentEntity = new Expression(assignmentInfo); var typeInfoRight = cx.GetTypeInfo(assignment.Right); if (typeInfoRight.Type is null) // The type may be null for nested initializers such as - // ``` + // ```csharp // new ClassWithArrayField() { As = { [0] = a } } // ``` // In this case we take the type from the assignment @@ -86,7 +83,7 @@ protected override void PopulateExpression(TextWriter trapFile) // If the target is null, then assume that this is an array initializer (of the form `[...] = ...`) - Expression access = target.Symbol is null ? + var access = target.Symbol is null ? new Expression(new ExpressionNodeInfo(cx, assignment.Left, assignmentEntity, 1).SetKind(ExprKind.ARRAY_ACCESS)) : Access.Create(new ExpressionNodeInfo(cx, assignment.Left, assignmentEntity, 1), target.Symbol, false, cx.CreateEntity(target.Symbol)); @@ -94,7 +91,7 @@ protected override void PopulateExpression(TextWriter trapFile) { // An array/indexer initializer of the form `[...] = ...` - int indexChild = 0; + var indexChild = 0; foreach (var arg in iea.ArgumentList.Arguments) { Expression.Create(cx, arg.Expression, access, indexChild++); @@ -110,9 +107,9 @@ protected override void PopulateExpression(TextWriter trapFile) } } - class CollectionInitializer : Initializer + internal class CollectionInitializer : Initializer { - CollectionInitializer(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.COLLECTION_INIT)) { } + private CollectionInitializer(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.COLLECTION_INIT)) { } public static Expression Create(ExpressionNodeInfo info) => new CollectionInitializer(info).TryPopulate(); @@ -139,7 +136,7 @@ protected override void PopulateExpression(TextWriter trapFile) var init = (InitializerExpressionSyntax)i; - int addChild = 0; + var addChild = 0; foreach (var arg in init.Expressions) { Create(cx, arg, invocation, addChild++); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/InterpolatedString.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/InterpolatedString.cs index b333e8d00484..152ff145897c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/InterpolatedString.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/InterpolatedString.cs @@ -7,9 +7,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - class InterpolatedString : Expression + internal class InterpolatedString : Expression { - InterpolatedString(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.INTERPOLATED_STRING)) { } + private InterpolatedString(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.INTERPOLATED_STRING)) { } public static Expression Create(ExpressionNodeInfo info) => new InterpolatedString(info).TryPopulate(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs index 50aede6e52cb..7a0e2fcc6836 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs @@ -7,15 +7,15 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - class Invocation : Expression + internal class Invocation : Expression { - Invocation(ExpressionNodeInfo info) + private Invocation(ExpressionNodeInfo info) : base(info.SetKind(GetKind(info))) { this.info = info; } - readonly ExpressionNodeInfo info; + private readonly ExpressionNodeInfo info; public static Expression Create(ExpressionNodeInfo info) => new Invocation(info).TryPopulate(); @@ -53,12 +53,11 @@ protected override void PopulateExpression(TextWriter trapFile) if (target != null && !target.IsStatic) { // Implicit `this` qualifier; add explicitly - var callingMethod = cx.GetModel(Syntax).GetEnclosingSymbol(Location.symbol.SourceSpan.Start) as IMethodSymbol; - if (callingMethod == null) - cx.ModelError(Syntax, "Couldn't determine implicit this type"); - else + if (cx.GetModel(Syntax).GetEnclosingSymbol(Location.symbol.SourceSpan.Start) is IMethodSymbol callingMethod) This.CreateImplicit(cx, Entities.Type.Create(cx, callingMethod.ContainingType), Location, this, child++); + else + cx.ModelError(Syntax, "Couldn't determine implicit this type"); } else { @@ -94,7 +93,7 @@ protected override void PopulateExpression(TextWriter trapFile) trapFile.expr_call(this, targetKey); } - static bool IsDynamicCall(ExpressionNodeInfo info) + private static bool IsDynamicCall(ExpressionNodeInfo info) { // Either the qualifier (Expression) is dynamic, // or one of the arguments is dynamic. @@ -111,7 +110,8 @@ public IMethodSymbol TargetSymbol { var si = SymbolInfo; - if (si.Symbol != null) return si.Symbol as IMethodSymbol; + if (si.Symbol != null) + return si.Symbol as IMethodSymbol; if (si.CandidateReason == CandidateReason.OverloadResolutionFailure) { @@ -119,10 +119,10 @@ public IMethodSymbol TargetSymbol // For some reason, typeof(X).InvokeMember(...) fails to resolve the correct // InvokeMember() method, even though the number of parameters clearly identifies the correct method - var candidates = si.CandidateSymbols. - OfType(). - Where(method => method.Parameters.Length >= Syntax.ArgumentList.Arguments.Count). - Where(method => method.Parameters.Count(p => !p.HasExplicitDefaultValue) <= Syntax.ArgumentList.Arguments.Count); + var candidates = si.CandidateSymbols + .OfType() + .Where(method => method.Parameters.Length >= Syntax.ArgumentList.Arguments.Count) + .Where(method => method.Parameters.Count(p => !p.HasExplicitDefaultValue) <= Syntax.ArgumentList.Arguments.Count); return cx.Extractor.Standalone ? candidates.FirstOrDefault() : @@ -133,13 +133,15 @@ public IMethodSymbol TargetSymbol } } - static bool IsDelegateCall(ExpressionNodeInfo info) + private static bool IsDelegateCall(ExpressionNodeInfo info) { var si = info.SymbolInfo; if (si.CandidateReason == CandidateReason.OverloadResolutionFailure && si.CandidateSymbols.OfType().All(s => s.MethodKind == MethodKind.DelegateInvoke)) + { return true; + } // Delegate variable is a dynamic var node = (InvocationExpressionSyntax)info.Node; @@ -147,36 +149,37 @@ static bool IsDelegateCall(ExpressionNodeInfo info) node.Expression is IdentifierNameSyntax && IsDynamic(info.Context, node.Expression) && si.Symbol == null) + { return true; + } return si.Symbol != null && si.Symbol.Kind == SymbolKind.Method && ((IMethodSymbol)si.Symbol).MethodKind == MethodKind.DelegateInvoke; } - static bool IsLocalFunctionInvocation(ExpressionNodeInfo info) + private static bool IsLocalFunctionInvocation(ExpressionNodeInfo info) { - var target = info.SymbolInfo.Symbol as IMethodSymbol; - return target != null && target.MethodKind == MethodKind.LocalFunction; + return info.SymbolInfo.Symbol is IMethodSymbol target && + target.MethodKind == MethodKind.LocalFunction; } - static ExprKind GetKind(ExpressionNodeInfo info) + private static ExprKind GetKind(ExpressionNodeInfo info) { - return IsNameof((InvocationExpressionSyntax)info.Node) ? - ExprKind.NAMEOF : - IsDelegateCall(info) ? - ExprKind.DELEGATE_INVOCATION : - IsLocalFunctionInvocation(info) ? - ExprKind.LOCAL_FUNCTION_INVOCATION : - ExprKind.METHOD_INVOCATION; + return IsNameof((InvocationExpressionSyntax)info.Node) + ? ExprKind.NAMEOF + : IsDelegateCall(info) + ? ExprKind.DELEGATE_INVOCATION + : IsLocalFunctionInvocation(info) + ? ExprKind.LOCAL_FUNCTION_INVOCATION + : ExprKind.METHOD_INVOCATION; } - static bool IsNameof(InvocationExpressionSyntax syntax) + private static bool IsNameof(InvocationExpressionSyntax syntax) { // Odd that this is not a separate expression type. // Maybe it will be in the future. - var id = syntax.Expression as IdentifierNameSyntax; - return id != null && id.Identifier.Text == "nameof"; + return syntax.Expression is IdentifierNameSyntax id && id.Identifier.Text == "nameof"; } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/IsPattern.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/IsPattern.cs index 637e0dee84d1..5bdb02f5ac35 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/IsPattern.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/IsPattern.cs @@ -7,7 +7,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - static class PatternExtensions + internal static class PatternExtensions { public static Expression CreatePattern(this Context cx, PatternSyntax syntax, IExpressionParentEntity parent, int child) { @@ -50,10 +50,8 @@ public static Expression CreatePattern(this Context cx, PatternSyntax syntax, IE return VariableDeclaration.Create(cx, symbol, type, null, cx.Create(syntax.GetLocation()), true, parent, child); } - else - { - throw new InternalError(varPattern, "Unable to get the declared symbol of the var pattern designation."); - } + + throw new InternalError(varPattern, "Unable to get the declared symbol of the var pattern designation."); default: throw new InternalError("var pattern designation is unhandled"); } @@ -67,7 +65,7 @@ public static Expression CreatePattern(this Context cx, PatternSyntax syntax, IE } } - class PropertyPattern : Expression + internal class PropertyPattern : Expression { internal PropertyPattern(Context cx, PropertyPatternClauseSyntax pp, IExpressionParentEntity parent, int child) : base(new ExpressionInfo(cx, Entities.NullType.Create(cx), cx.Create(pp.GetLocation()), ExprKind.PROPERTY_PATTERN, parent, child, false, null)) @@ -82,7 +80,7 @@ internal PropertyPattern(Context cx, PropertyPatternClauseSyntax pp, IExpression } } - class PositionalPattern : Expression + internal class PositionalPattern : Expression { internal PositionalPattern(Context cx, PositionalPatternClauseSyntax posPc, IExpressionParentEntity parent, int child) : base(new ExpressionInfo(cx, Entities.NullType.Create(cx), cx.Create(posPc.GetLocation()), ExprKind.POSITIONAL_PATTERN, parent, child, false, null)) @@ -95,7 +93,7 @@ internal PositionalPattern(Context cx, PositionalPatternClauseSyntax posPc, IExp } } - class RecursivePattern : Expression + internal class RecursivePattern : Expression { /// /// Creates and populates a recursive pattern. @@ -132,7 +130,7 @@ public RecursivePattern(Context cx, RecursivePatternSyntax syntax, IExpressionPa } } - class IsPattern : Expression + internal class IsPattern : Expression { private IsPattern(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.IS)) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Lambda.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Lambda.cs index 27fb113f9acd..28e2b3b7601d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Lambda.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Lambda.cs @@ -9,19 +9,19 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - class Lambda : Expression, IStatementParentEntity + internal class Lambda : Expression, IStatementParentEntity { bool IStatementParentEntity.IsTopLevelParent => false; protected override void PopulateExpression(TextWriter trapFile) { } - void VisitParameter(ParameterSyntax p) + private void VisitParameter(ParameterSyntax p) { var symbol = cx.GetModel(p).GetDeclaredSymbol(p); Parameter.Create(cx, symbol, this); } - Lambda(ExpressionNodeInfo info, CSharpSyntaxNode body, IEnumerable @params) + private Lambda(ExpressionNodeInfo info, CSharpSyntaxNode body, IEnumerable @params) : base(info) { // No need to use `Populate` as the population happens later @@ -30,27 +30,28 @@ void VisitParameter(ParameterSyntax p) foreach (var param in @params) VisitParameter(param); - if (body is ExpressionSyntax) - Create(cx, (ExpressionSyntax)body, this, 0); - else if (body is BlockSyntax) - Statements.Block.Create(cx, (BlockSyntax)body, this, 0); + if (body is ExpressionSyntax exprBody) + Create(cx, exprBody, this, 0); + else if (body is BlockSyntax blockBody) + Statements.Block.Create(cx, blockBody, this, 0); else cx.ModelError(body, "Unhandled lambda body"); }); } - Lambda(ExpressionNodeInfo info, ParenthesizedLambdaExpressionSyntax node) + private Lambda(ExpressionNodeInfo info, ParenthesizedLambdaExpressionSyntax node) : this(info.SetKind(ExprKind.LAMBDA), node.Body, node.ParameterList.Parameters) { } public static Lambda Create(ExpressionNodeInfo info, ParenthesizedLambdaExpressionSyntax node) => new Lambda(info, node); - Lambda(ExpressionNodeInfo info, SimpleLambdaExpressionSyntax node) + private Lambda(ExpressionNodeInfo info, SimpleLambdaExpressionSyntax node) : this(info.SetKind(ExprKind.LAMBDA), node.Body, Enumerators.Singleton(node.Parameter)) { } public static Lambda Create(ExpressionNodeInfo info, SimpleLambdaExpressionSyntax node) => new Lambda(info, node); - Lambda(ExpressionNodeInfo info, AnonymousMethodExpressionSyntax node) : - this(info.SetKind(ExprKind.ANONYMOUS_METHOD), node.Body, node.ParameterList == null ? Enumerable.Empty() : node.ParameterList.Parameters) { } + private Lambda(ExpressionNodeInfo info, AnonymousMethodExpressionSyntax node) : + this(info.SetKind(ExprKind.ANONYMOUS_METHOD), node.Body, node.ParameterList == null ? Enumerable.Empty() : node.ParameterList.Parameters) + { } public static Lambda Create(ExpressionNodeInfo info, AnonymousMethodExpressionSyntax node) => new Lambda(info, node); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Literal.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Literal.cs index 528c6a8a9f52..7afd4ee55ae9 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Literal.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Literal.cs @@ -1,23 +1,22 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.Kinds; using Microsoft.CodeAnalysis; -using Semmle.Extraction.CSharp.Populators; using Microsoft.CodeAnalysis.CSharp; using System.IO; namespace Semmle.Extraction.CSharp.Entities.Expressions { - class Literal : Expression + internal class Literal : Expression { - Literal(ExpressionNodeInfo info) : base(info.SetKind(GetKind(info)) ) { } + private Literal(ExpressionNodeInfo info) : base(info.SetKind(GetKind(info))) { } public static Expression Create(ExpressionNodeInfo info) => new Literal(info).TryPopulate(); protected override void PopulateExpression(TextWriter trapFile) { } - static ExprKind GetKind(ExpressionNodeInfo info) + private static ExprKind GetKind(ExpressionNodeInfo info) { - switch(info.Node.Kind()) + switch (info.Node.Kind()) { case SyntaxKind.DefaultLiteralExpression: return ExprKind.DEFAULT; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MakeRef.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MakeRef.cs index bc8630609f00..751d6b6e92c3 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MakeRef.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MakeRef.cs @@ -4,9 +4,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - class MakeRef : Expression + internal class MakeRef : Expression { - MakeRef(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.REF)) { } + private MakeRef(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.REF)) { } public static Expression Create(ExpressionNodeInfo info) => new MakeRef(info).TryPopulate(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MemberAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MemberAccess.cs index 0bc84ca9c0c3..7d2777540f0f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MemberAccess.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MemberAccess.cs @@ -1,15 +1,11 @@ using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Semmle.Extraction.CSharp.Populators; using Semmle.Extraction.Kinds; namespace Semmle.Extraction.CSharp.Entities.Expressions { - class MemberAccess : Expression + internal class MemberAccess : Expression { - readonly IEntity Target; - private MemberAccess(ExpressionNodeInfo info, ExpressionSyntax qualifier, ISymbol target) : base(info) { var trapFile = info.Context.TrapWriter.Writer; @@ -22,15 +18,17 @@ private MemberAccess(ExpressionNodeInfo info, ExpressionSyntax qualifier, ISymbo } else { - Target = cx.CreateEntity(target); - trapFile.expr_access(this, Target); + var t = cx.CreateEntity(target); + trapFile.expr_access(this, t); } } - public static Expression Create(ExpressionNodeInfo info, ConditionalAccessExpressionSyntax node) => + public static Expression Create(ExpressionNodeInfo info, ConditionalAccessExpressionSyntax node) + { // The qualifier is located by walking the syntax tree. // `node.WhenNotNull` will contain a MemberBindingExpressionSyntax, calling the method below. - CreateFromNode(new ExpressionNodeInfo(info.Context, node.WhenNotNull, info.Parent, info.Child, info.TypeInfo)); + return CreateFromNode(new ExpressionNodeInfo(info.Context, node.WhenNotNull, info.Parent, info.Child, info.TypeInfo)); + } public static Expression Create(ExpressionNodeInfo info, MemberBindingExpressionSyntax node) { @@ -42,7 +40,7 @@ public static Expression Create(ExpressionNodeInfo info, MemberBindingExpression public static Expression Create(ExpressionNodeInfo info, MemberAccessExpressionSyntax node) => Create(info, node.Expression, node.Name); - static Expression Create(ExpressionNodeInfo info, ExpressionSyntax expression, SimpleNameSyntax name) + private static Expression Create(ExpressionNodeInfo info, ExpressionSyntax expression, SimpleNameSyntax name) { if (IsDynamic(info.Context, expression)) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Name.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Name.cs index 931b3a740fda..d44c85d6ddc0 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Name.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Name.cs @@ -1,12 +1,10 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Semmle.Extraction.CSharp.Populators; using System.Linq; namespace Semmle.Extraction.CSharp.Entities.Expressions { - static class Name + internal static class Name { public static Expression Create(ExpressionNodeInfo info) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation.cs index 98723d6111c2..ae3d0f105068 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation.cs @@ -1,7 +1,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Semmle.Extraction.CSharp.Populators; using Semmle.Extraction.Entities; using Semmle.Extraction.Kinds; using System.IO; @@ -9,27 +8,28 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - abstract class ObjectCreation : Expression where SyntaxNode : ExpressionSyntax + internal abstract class ObjectCreation : Expression + where TExpressionSyntax : ExpressionSyntax { protected ObjectCreation(ExpressionNodeInfo info) : base(info) { } } // new Foo(...) { ... }. - class ExplicitObjectCreation : ObjectCreation + internal class ExplicitObjectCreation : ObjectCreation { - static bool IsDynamicObjectCreation(Context cx, ObjectCreationExpressionSyntax node) + private static bool IsDynamicObjectCreation(Context cx, ObjectCreationExpressionSyntax node) { return node.ArgumentList != null && node.ArgumentList.Arguments.Any(arg => IsDynamic(cx, arg.Expression)); } - static ExprKind GetKind(Context cx, ObjectCreationExpressionSyntax node) + private static ExprKind GetKind(Context cx, ObjectCreationExpressionSyntax node) { var si = cx.GetModel(node).GetSymbolInfo(node.Type); return Entities.Type.IsDelegate(si.Symbol as INamedTypeSymbol) ? ExprKind.EXPLICIT_DELEGATE_CREATION : ExprKind.OBJECT_CREATION; } - ExplicitObjectCreation(ExpressionNodeInfo info) + private ExplicitObjectCreation(ExpressionNodeInfo info) : base(info.SetKind(GetKind(info.Context, (ObjectCreationExpressionSyntax)info.Node))) { } public static Expression Create(ExpressionNodeInfo info) => new ExplicitObjectCreation(info).TryPopulate(); @@ -77,7 +77,7 @@ protected override void PopulateExpression(TextWriter trapFile) TypeMention.Create(cx, Syntax.Type, this, Type); } - static SyntaxToken? GetDynamicName(CSharpSyntaxNode name) + private static SyntaxToken? GetDynamicName(CSharpSyntaxNode name) { switch (name.Kind()) { @@ -94,7 +94,7 @@ protected override void PopulateExpression(TextWriter trapFile) } } - class ImplicitObjectCreation : ObjectCreation + internal class ImplicitObjectCreation : ObjectCreation { public ImplicitObjectCreation(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.OBJECT_CREATION)) { } @@ -113,7 +113,7 @@ protected override void PopulateExpression(TextWriter trapFile) } var child = 0; - Expression objectInitializer = Syntax.Initializers.Any() ? + var objectInitializer = Syntax.Initializers.Any() ? new Expression(new ExpressionInfo(cx, Type, Location, ExprKind.OBJECT_INIT, this, -1, false, null)) : null; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PointerMemberAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PointerMemberAccess.cs index 61ee4a8ef9af..01df338d1b33 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PointerMemberAccess.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PointerMemberAccess.cs @@ -4,9 +4,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - class PointerMemberAccess : Expression + internal class PointerMemberAccess : Expression { - PointerMemberAccess(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.POINTER_INDIRECTION)) { } + private PointerMemberAccess(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.POINTER_INDIRECTION)) { } public static Expression Create(ExpressionNodeInfo info) => new PointerMemberAccess(info).TryPopulate(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PostfixUnary.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PostfixUnary.cs index 71f0d8e0378e..30c6058d95ff 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PostfixUnary.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PostfixUnary.cs @@ -4,26 +4,26 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - class PostfixUnary : Expression + internal class PostfixUnary : Expression { - PostfixUnary(ExpressionNodeInfo info, ExprKind kind, ExpressionSyntax operand) + private PostfixUnary(ExpressionNodeInfo info, ExprKind kind, ExpressionSyntax operand) : base(info.SetKind(UnaryOperatorKind(info.Context, kind, info.Node))) { - Operand = operand; - OperatorKind = kind; + this.operand = operand; + operatorKind = kind; } - readonly ExpressionSyntax Operand; - readonly ExprKind OperatorKind; + private readonly ExpressionSyntax operand; + private readonly ExprKind operatorKind; public static Expression Create(ExpressionNodeInfo info, ExpressionSyntax operand) => new PostfixUnary(info, info.Kind, operand).TryPopulate(); protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, Operand, this, 0); + Create(cx, operand, this, 0); OperatorCall(trapFile, Syntax); - if ((OperatorKind == ExprKind.POST_INCR || OperatorKind == ExprKind.POST_DECR) && + if ((operatorKind == ExprKind.POST_INCR || operatorKind == ExprKind.POST_DECR) && Kind == ExprKind.OPERATOR_INVOCATION) { trapFile.mutator_invocation_mode(this, 2); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Query.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Query.cs index 03cd8545a76a..83c4a25d3a4e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Query.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Query.cs @@ -4,12 +4,11 @@ using System.Linq; using Semmle.Extraction.Kinds; using System.Collections.Generic; -using Semmle.Extraction.CSharp.Populators; using Semmle.Extraction.Entities; namespace Semmle.Extraction.CSharp.Entities.Expressions { - static class Query + internal static class Query { /// /// An expression representing a call in a LINQ query. @@ -35,7 +34,7 @@ public QueryCall(Context cx, IMethodSymbol method, SyntaxNode clause, IExpressio /// /// Represents a chain of method calls (the operand being recursive). /// - abstract class Clause + private abstract class Clause { protected readonly IMethodSymbol method; protected readonly List arguments = new List(); @@ -82,7 +81,9 @@ protected Expression DeclareRangeVariable(Context cx, IExpressionParentEntity pa } } else + { declType = type; + } var decl = VariableDeclaration.Create(cx, variableSymbol, @@ -114,10 +115,10 @@ protected void PopulateArguments(Context cx, QueryCall callExpr, int child) public abstract Expression Populate(Context cx, IExpressionParentEntity parent, int child); } - class RangeClause : Clause + private class RangeClause : Clause { - readonly ISymbol declaration; - readonly SyntaxToken name; + private readonly ISymbol declaration; + private readonly SyntaxToken name; public RangeClause(IMethodSymbol method, SyntaxNode node, ISymbol declaration, SyntaxToken name) : base(method, node) { @@ -129,12 +130,12 @@ public override Expression Populate(Context cx, IExpressionParentEntity parent, DeclareRangeVariable(cx, parent, child, true, declaration, name); } - class LetClause : Clause + private class LetClause : Clause { - readonly Clause operand; - readonly ISymbol declaration; - readonly SyntaxToken name; - ISymbol intoDeclaration; + private readonly Clause operand; + private readonly ISymbol declaration; + private readonly SyntaxToken name; + private ISymbol intoDeclaration; public LetClause(Clause operand, IMethodSymbol method, SyntaxNode node, ISymbol declaration, SyntaxToken name) : base(method, node) { @@ -149,7 +150,7 @@ public Clause WithInto(ISymbol into) return this; } - void DeclareIntoVariable(Context cx, IExpressionParentEntity parent, int intoChild, bool getElement) + private void DeclareIntoVariable(Context cx, IExpressionParentEntity parent, int intoChild, bool getElement) { if (intoDeclaration != null) DeclareRangeVariable(cx, parent, intoChild, getElement, intoDeclaration, name); @@ -169,9 +170,9 @@ public override Expression Populate(Context cx, IExpressionParentEntity parent, } } - class CallClause : Clause + private class CallClause : Clause { - readonly Clause operand; + private readonly Clause operand; public CallClause(Clause operand, IMethodSymbol method, SyntaxNode node) : base(method, node) { @@ -194,12 +195,12 @@ public override Expression Populate(Context cx, IExpressionParentEntity parent, /// The extraction context. /// The query expression. /// A "syntax tree" of the query. - static Clause ConstructQueryExpression(Context cx, QueryExpressionSyntax node) + private static Clause ConstructQueryExpression(Context cx, QueryExpressionSyntax node) { var info = cx.GetModel(node).GetQueryClauseInfo(node.FromClause); var method = info.OperationInfo.Symbol as IMethodSymbol; - Clause clauseExpr = new RangeClause(method, node.FromClause, cx.GetModel(node).GetDeclaredSymbol(node.FromClause), node.FromClause.Identifier).AddArgument(node.FromClause.Expression); + var clauseExpr = new RangeClause(method, node.FromClause, cx.GetModel(node).GetDeclaredSymbol(node.FromClause), node.FromClause.Identifier).AddArgument(node.FromClause.Expression); foreach (var qc in node.Body.Clauses) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RangeExpression.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RangeExpression.cs index c9c00b2a76c3..db5cd1381553 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RangeExpression.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RangeExpression.cs @@ -4,7 +4,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - class RangeExpression : Expression + internal class RangeExpression : Expression { private RangeExpression(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.RANGE)) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Ref.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Ref.cs index e916259e772f..5b38b9b8ee61 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Ref.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Ref.cs @@ -4,9 +4,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - class Ref : Expression + internal class Ref : Expression { - Ref(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.REF)) { } + private Ref(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.REF)) { } public static Expression Create(ExpressionNodeInfo info) => new Ref(info).TryPopulate(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefType.cs index ed2049c27f99..37f7e2a3f760 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefType.cs @@ -4,9 +4,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - class RefType : Expression + internal class RefType : Expression { - RefType(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.UNKNOWN)) { } + private RefType(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.UNKNOWN)) { } public static Expression Create(ExpressionNodeInfo info) => new RefType(info).TryPopulate(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefValue.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefValue.cs index 93c2542c3135..2372cc4bb09e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefValue.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefValue.cs @@ -4,9 +4,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - class RefValue : Expression + internal class RefValue : Expression { - RefValue(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.REF)) { } + private RefValue(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.REF)) { } public static Expression Create(ExpressionNodeInfo info) => new RefValue(info).TryPopulate(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Sizeof.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Sizeof.cs index 1e06cfa72e4b..a4b89928e001 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Sizeof.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Sizeof.cs @@ -4,9 +4,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - class SizeOf : Expression + internal class SizeOf : Expression { - SizeOf(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.SIZEOF)) { } + private SizeOf(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.SIZEOF)) { } public static Expression Create(ExpressionNodeInfo info) => new SizeOf(info).TryPopulate(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Switch.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Switch.cs index 5316998a38f6..b5bfebea92ec 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Switch.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Switch.cs @@ -5,7 +5,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - class Switch : Expression + internal class Switch : Expression { private Switch(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.SWITCH)) { @@ -18,18 +18,19 @@ private Switch(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.SWITCH)) protected override void PopulateExpression(TextWriter trapFile) { SwitchedExpr = Expression.Create(cx, Syntax.GoverningExpression, this, -1); - int child = 0; - foreach (var arm in Syntax.Arms) + for (var i = 0; i < Syntax.Arms.Count; i++) { - new SwitchCase(cx, arm, this, child++); + new SwitchCase(cx, Syntax.Arms[i], this, i); } } } - class SwitchCase : Expression + internal class SwitchCase : Expression { internal SwitchCase(Context cx, SwitchExpressionArmSyntax arm, Switch parent, int child) : - base(new ExpressionInfo(cx, parent.SwitchedExpr.Type, cx.Create(arm.GetLocation()), ExprKind.SWITCH_CASE, parent, child, false, null)) + base(new ExpressionInfo( + cx, Entities.Type.Create(cx, cx.GetType(arm.Expression)), cx.Create(arm.GetLocation()), + ExprKind.SWITCH_CASE, parent, child, false, null)) { cx.CreatePattern(arm.Pattern, this, 0); if (arm.WhenClause is WhenClauseSyntax when) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/This.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/This.cs index 490bd8b56e4c..838e494ff00f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/This.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/This.cs @@ -3,9 +3,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - class This : Expression + internal class This : Expression { - This(IExpressionInfo info) : base(info) { } + private This(IExpressionInfo info) : base(info) { } public static This CreateImplicit(Context cx, Type @class, Extraction.Entities.Location loc, IExpressionParentEntity parent, int child) => new This(new ExpressionInfo(cx, new AnnotatedType(@class, NullableAnnotation.None), loc, Kinds.ExprKind.THIS_ACCESS, parent, child, true, null)); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Throw.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Throw.cs index d64113cdad29..5ef8feaebb6f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Throw.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Throw.cs @@ -4,9 +4,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - class Throw : Expression + internal class Throw : Expression { - Throw(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.THROW)) { } + private Throw(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.THROW)) { } public static Expression Create(ExpressionNodeInfo info) => new Throw(info).TryPopulate(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Tuple.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Tuple.cs index d38685d2cd6a..f2911bdcf754 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Tuple.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Tuple.cs @@ -5,17 +5,17 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - class Tuple : Expression + internal class Tuple : Expression { public static Expression Create(ExpressionNodeInfo info) => new Tuple(info).TryPopulate(); - Tuple(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.TUPLE)) + private Tuple(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.TUPLE)) { } protected override void PopulateExpression(TextWriter trapFile) { - int child = 0; + var child = 0; foreach (var argument in Syntax.Arguments.Select(a => a.Expression)) { Expression.Create(cx, argument, this, child++); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeAccess.cs index ab5915aa274b..e87c63047f11 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeAccess.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeAccess.cs @@ -5,9 +5,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - class TypeAccess : Expression + internal class TypeAccess : Expression { - TypeAccess(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.TYPE_ACCESS)) { } + private TypeAccess(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.TYPE_ACCESS)) { } protected override void PopulateExpression(TextWriter trapFile) { @@ -36,4 +36,3 @@ protected override void PopulateExpression(TextWriter trapFile) public static Expression Create(ExpressionNodeInfo info) => new TypeAccess(info).TryPopulate(); } } - diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeOf.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeOf.cs index d4f5e91fbea0..fa46ef8c6642 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeOf.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeOf.cs @@ -4,9 +4,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - class TypeOf : Expression + internal class TypeOf : Expression { - TypeOf(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.TYPEOF)) { } + private TypeOf(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.TYPEOF)) { } public static Expression Create(ExpressionNodeInfo info) => new TypeOf(info).TryPopulate(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unary.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unary.cs index 98023028d75f..f3c2c73b074e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unary.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unary.cs @@ -4,15 +4,15 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - class Unary : Expression + internal class Unary : Expression { - Unary(ExpressionNodeInfo info, ExprKind kind) + private Unary(ExpressionNodeInfo info, ExprKind kind) : base(info.SetKind(UnaryOperatorKind(info.Context, info.Kind, info.Node))) { - OperatorKind = kind; + operatorKind = kind; } - readonly ExprKind OperatorKind; + private readonly ExprKind operatorKind; public static Unary Create(ExpressionNodeInfo info) { @@ -26,7 +26,7 @@ protected override void PopulateExpression(TextWriter trapFile) Create(cx, Syntax.Operand, this, 0); OperatorCall(trapFile, Syntax); - if ((OperatorKind == ExprKind.PRE_INCR || OperatorKind == ExprKind.PRE_DECR) && + if ((operatorKind == ExprKind.PRE_INCR || operatorKind == ExprKind.PRE_DECR) && Kind == ExprKind.OPERATOR_INVOCATION) { trapFile.mutator_invocation_mode(this, 1); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unchecked.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unchecked.cs index c4a46a7d74d3..5ffcf414132b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unchecked.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unchecked.cs @@ -4,9 +4,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - class Unchecked : Expression + internal class Unchecked : Expression { - Unchecked(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.UNCHECKED)) { } + private Unchecked(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.UNCHECKED)) { } public static Expression Create(ExpressionNodeInfo info) => new Unchecked(info).TryPopulate(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unknown.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unknown.cs index c547626e6393..6df1e6ad040b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unknown.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unknown.cs @@ -1,9 +1,8 @@ -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Semmle.Extraction.Kinds; +using Semmle.Extraction.Kinds; namespace Semmle.Extraction.CSharp.Entities.Expressions { - class Unknown : Expression + internal class Unknown : Expression { public Unknown(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.UNKNOWN)) { } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs index 21780a6ca756..c0b561dd8430 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs @@ -7,9 +7,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { - class VariableDeclaration : Expression + internal class VariableDeclaration : Expression { - VariableDeclaration(IExpressionInfo info) : base(info) { } + private VariableDeclaration(IExpressionInfo info) : base(info) { } public static VariableDeclaration Create(Context cx, ISymbol symbol, AnnotatedType type, TypeSyntax optionalSyntax, Extraction.Entities.Location exprLocation, bool isVar, IExpressionParentEntity parent, int child) { @@ -24,7 +24,7 @@ public static VariableDeclaration Create(Context cx, ISymbol symbol, AnnotatedTy return ret; } - static VariableDeclaration CreateSingle(Context cx, DeclarationExpressionSyntax node, SingleVariableDesignationSyntax designation, IExpressionParentEntity parent, int child) + private static VariableDeclaration CreateSingle(Context cx, DeclarationExpressionSyntax node, SingleVariableDesignationSyntax designation, IExpressionParentEntity parent, int child) { var variableSymbol = cx.GetModel(designation).GetDeclaredSymbol(designation) as ILocalSymbol; if (variableSymbol == null) @@ -71,6 +71,7 @@ public static Expression CreateParenthesized(Context cx, VarPatternSyntax varPat { var child0 = 0; foreach (var variable in designation.Variables) + { switch (variable) { case ParenthesizedVariableDesignationSyntax paren: @@ -94,13 +95,14 @@ public static Expression CreateParenthesized(Context cx, VarPatternSyntax varPat default: throw new InternalError(variable, "Unhandled designation type"); } + } }); return tuple; } - static Expression Create(Context cx, DeclarationExpressionSyntax node, VariableDesignationSyntax designation, IExpressionParentEntity parent, int child) + private static Expression Create(Context cx, DeclarationExpressionSyntax node, VariableDesignationSyntax designation, IExpressionParentEntity parent, int child) { switch (designation) { @@ -157,15 +159,14 @@ public static VariableDeclaration CreateDeclarator(Context cx, VariableDeclarato cx.TrapWriter.Writer.expr_access(access, localVar); } - var decl = d.Parent as VariableDeclarationSyntax; - if (decl != null) + if (d.Parent is VariableDeclarationSyntax decl) TypeMention.Create(cx, decl.Type, ret, type); }); return ret; } } - static class VariableDeclarations + internal static class VariableDeclarations { public static void Populate(Context cx, VariableDeclarationSyntax decl, IExpressionParentEntity parent, int child, int childIncrement = 1) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs index 7ae4572cd7d0..2990332648d8 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs @@ -1,5 +1,4 @@ using Microsoft.CodeAnalysis; -using Semmle.Extraction.CSharp.Populators; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Syntax; using System; @@ -10,15 +9,15 @@ namespace Semmle.Extraction.CSharp.Entities { - class Field : CachedSymbol, IExpressionParentEntity + internal class Field : CachedSymbol, IExpressionParentEntity { - Field(Context cx, IFieldSymbol init) + private Field(Context cx, IFieldSymbol init) : base(cx, init) { type = new Lazy(() => Entities.Type.Create(cx, symbol.GetAnnotatedType())); } - public static Field Create(Context cx, IFieldSymbol field) => FieldFactory.Instance.CreateEntity(cx, field); + public static Field Create(Context cx, IFieldSymbol field) => FieldFactory.Instance.CreateEntityFromSymbol(cx, field); // Do not populate backing fields. // Populate Tuple fields. @@ -32,7 +31,7 @@ public override void Populate(TextWriter trapFile) ContainingType.PopulateGenerics(); PopulateNullability(trapFile, symbol.GetAnnotatedType()); - Field unboundFieldKey = Field.Create(Context, symbol.OriginalDefinition); + var unboundFieldKey = Field.Create(Context, symbol.OriginalDefinition); trapFile.fields(this, (symbol.IsConst ? 2 : 1), symbol.Name, ContainingType, Type.Type.TypeRef, unboundFieldKey); PopulateModifiers(trapFile); @@ -58,49 +57,70 @@ public override void Populate(TextWriter trapFile) Context.BindComments(this, Location.symbol); - int child = 0; - foreach (var initializer in - symbol.DeclaringSyntaxReferences. - Select(n => n.GetSyntax()). - OfType(). - Where(n => n.Initializer != null)) + var child = 0; + foreach (var initializer in symbol.DeclaringSyntaxReferences + .Select(n => n.GetSyntax()) + .OfType() + .Where(n => n.Initializer != null)) { Context.PopulateLater(() => { var loc = Context.Create(initializer.GetLocation()); - var simpleAssignExpr = new Expression(new ExpressionInfo(Context, Type, loc, ExprKind.SIMPLE_ASSIGN, this, child++, false, null)); - Expression.CreateFromNode(new ExpressionNodeInfo(Context, initializer.Initializer.Value, simpleAssignExpr, 0)); - var access = new Expression(new ExpressionInfo(Context, Type, Location, ExprKind.FIELD_ACCESS, simpleAssignExpr, 1, false, null)); - trapFile.expr_access(access, this); + + var fieldAccess = AddInitializerAssignment(trapFile, initializer.Initializer.Value, loc, null, ref child); + if (!symbol.IsStatic) { - This.CreateImplicit(Context, Entities.Type.Create(Context, symbol.ContainingType), Location, access, -1); + This.CreateImplicit(Context, Entities.Type.Create(Context, symbol.ContainingType), Location, fieldAccess, -1); } }); } - foreach (var initializer in symbol.DeclaringSyntaxReferences. - Select(n => n.GetSyntax()). - OfType(). - Where(n => n.EqualsValue != null)) + foreach (var initializer in symbol.DeclaringSyntaxReferences + .Select(n => n.GetSyntax()) + .OfType() + .Where(n => n.EqualsValue != null)) { // Mark fields that have explicit initializers. - var expr = new Expression(new ExpressionInfo(Context, Type, Context.Create(initializer.EqualsValue.Value.FixedLocation()), Kinds.ExprKind.FIELD_ACCESS, this, child++, false, null)); - trapFile.expr_access(expr, this); + var constValue = symbol.HasConstantValue + ? Expression.ValueAsString(symbol.ConstantValue) + : null; + + var loc = Context.Create(initializer.GetLocation()); + + AddInitializerAssignment(trapFile, initializer.EqualsValue.Value, loc, constValue, ref child); } if (IsSourceDeclaration) - foreach (var syntax in symbol.DeclaringSyntaxReferences. - Select(d => d.GetSyntax()).OfType(). - Select(d => d.Parent).OfType()) + { + foreach (var syntax in symbol.DeclaringSyntaxReferences + .Select(d => d.GetSyntax()) + .OfType() + .Select(d => d.Parent) + .OfType()) + { TypeMention.Create(Context, syntax.Type, this, Type); + } + } + } + + private Expression AddInitializerAssignment(TextWriter trapFile, ExpressionSyntax initializer, Extraction.Entities.Location loc, + string constValue, ref int child) + { + var simpleAssignExpr = new Expression(new ExpressionInfo(Context, Type, loc, ExprKind.SIMPLE_ASSIGN, this, child++, false, constValue)); + Expression.CreateFromNode(new ExpressionNodeInfo(Context, initializer, simpleAssignExpr, 0)); + var access = new Expression(new ExpressionInfo(Context, Type, Location, ExprKind.FIELD_ACCESS, simpleAssignExpr, 1, false, constValue)); + trapFile.expr_access(access, this); + return access; } - readonly Lazy type; + private readonly Lazy type; public AnnotatedType Type => type.Value; public override void WriteId(TextWriter trapFile) { + trapFile.WriteSubId(Type.Type); + trapFile.Write(" "); trapFile.WriteSubId(ContainingType); trapFile.Write('.'); trapFile.Write(symbol.Name); @@ -109,9 +129,9 @@ public override void WriteId(TextWriter trapFile) bool IExpressionParentEntity.IsTopLevelParent => true; - class FieldFactory : ICachedEntityFactory + private class FieldFactory : ICachedEntityFactory { - public static readonly FieldFactory Instance = new FieldFactory(); + public static FieldFactory Instance { get; } = new FieldFactory(); public Field Create(Context cx, IFieldSymbol init) => new Field(cx, init); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Indexer.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Indexer.cs index b9ece3d8c8e1..5873d3e19f48 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Indexer.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Indexer.cs @@ -5,12 +5,12 @@ namespace Semmle.Extraction.CSharp.Entities { - class Indexer : Property, IExpressionParentEntity + internal class Indexer : Property, IExpressionParentEntity { protected Indexer(Context cx, IPropertySymbol init) : base(cx, init) { } - Indexer OriginalDefinition => IsSourceDeclaration ? this : Create(Context, symbol.OriginalDefinition); + private Indexer OriginalDefinition => IsSourceDeclaration ? this : Create(Context, symbol.OriginalDefinition); public override void Populate(TextWriter trapFile) { @@ -71,7 +71,7 @@ public override void Populate(TextWriter trapFile) TypeMention.Create(Context, syntax.Type, this, type); } - public static new Indexer Create(Context cx, IPropertySymbol prop) => IndexerFactory.Instance.CreateEntity(cx, prop); + public static new Indexer Create(Context cx, IPropertySymbol prop) => IndexerFactory.Instance.CreateEntityFromSymbol(cx, prop); public override void WriteId(TextWriter trapFile) { @@ -87,22 +87,20 @@ public override Microsoft.CodeAnalysis.Location FullLocation { get { - return - symbol. - DeclaringSyntaxReferences. - Select(r => r.GetSyntax()). - OfType(). - Select(s => s.GetLocation()). - Concat(symbol.Locations). - First(); + return symbol.DeclaringSyntaxReferences + .Select(r => r.GetSyntax()) + .OfType() + .Select(s => s.GetLocation()) + .Concat(symbol.Locations) + .First(); } } bool IExpressionParentEntity.IsTopLevelParent => true; - class IndexerFactory : ICachedEntityFactory + private class IndexerFactory : ICachedEntityFactory { - public static readonly IndexerFactory Instance = new IndexerFactory(); + public static IndexerFactory Instance { get; } = new IndexerFactory(); public Indexer Create(Context cx, IPropertySymbol init) => new Indexer(cx, init); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs index e570802ab3d8..8b072a04bd9d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs @@ -6,9 +6,9 @@ namespace Semmle.Extraction.CSharp.Entities { - class LocalFunction : Method + internal class LocalFunction : Method { - LocalFunction(Context cx, IMethodSymbol init) : base(cx, init) + private LocalFunction(Context cx, IMethodSymbol init) : base(cx, init) { } @@ -22,11 +22,11 @@ public override void WriteQuotedId(TextWriter trapFile) trapFile.Write('*'); } - public static new LocalFunction Create(Context cx, IMethodSymbol field) => LocalFunctionFactory.Instance.CreateEntity(cx, field); + public static new LocalFunction Create(Context cx, IMethodSymbol field) => LocalFunctionFactory.Instance.CreateEntityFromSymbol(cx, field); - class LocalFunctionFactory : ICachedEntityFactory + private class LocalFunctionFactory : ICachedEntityFactory { - public static readonly LocalFunctionFactory Instance = new LocalFunctionFactory(); + public static LocalFunctionFactory Instance { get; } = new LocalFunctionFactory(); public LocalFunction Create(Context cx, IMethodSymbol init) => new LocalFunction(cx, init); } @@ -51,5 +51,7 @@ public override void Populate(TextWriter trapFile) trapFile.local_functions(this, symbol.Name, returnType, originalDefinition); ExtractRefReturn(trapFile); } + + public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NeedsLabel; } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalVariable.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalVariable.cs index 6d0f14a014eb..de44b16d69f0 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalVariable.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalVariable.cs @@ -4,9 +4,9 @@ namespace Semmle.Extraction.CSharp.Entities { - class LocalVariable : CachedSymbol + internal class LocalVariable : CachedSymbol { - LocalVariable(Context cx, ISymbol init) : base(cx, init) { } + private LocalVariable(Context cx, ISymbol init) : base(cx, init) { } public override void WriteId(TextWriter trapFile) { @@ -23,10 +23,9 @@ public override void Populate(TextWriter trapFile) { } public void PopulateManual(Expression parent, bool isVar) { var trapFile = Context.TrapWriter.Writer; - var (kind, type) = - symbol is ILocalSymbol l ? - (l.IsRef ? 3 : l.IsConst ? 2 : 1, Type.Create(Context, l.GetAnnotatedType())) : - (1, parent.Type); + var (kind, type) = symbol is ILocalSymbol l + ? (l.IsRef ? 3 : l.IsConst ? 2 : 1, Type.Create(Context, l.GetAnnotatedType())) + : (1, parent.Type); trapFile.localvars(this, kind, symbol.Name, isVar ? 1 : 0, type.Type.TypeRef, parent); if (symbol is ILocalSymbol local) @@ -43,21 +42,20 @@ symbol is ILocalSymbol l ? public static LocalVariable Create(Context cx, ISymbol local) { - return LocalVariableFactory.Instance.CreateEntity(cx, local); + return LocalVariableFactory.Instance.CreateEntityFromSymbol(cx, local); } - void DefineConstantValue(TextWriter trapFile) + private void DefineConstantValue(TextWriter trapFile) { - var local = symbol as ILocalSymbol; - if (local != null && local.HasConstantValue) + if (symbol is ILocalSymbol local && local.HasConstantValue) { trapFile.constant_value(this, Expression.ValueAsString(local.ConstantValue)); } } - class LocalVariableFactory : ICachedEntityFactory + private class LocalVariableFactory : ICachedEntityFactory { - public static readonly LocalVariableFactory Instance = new LocalVariableFactory(); + public static LocalVariableFactory Instance { get; } = new LocalVariableFactory(); public LocalVariable Create(Context cx, ISymbol init) => new LocalVariable(cx, init); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs index 982d21b25698..94e8c838e7be 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs @@ -9,10 +9,10 @@ namespace Semmle.Extraction.CSharp.Entities { public abstract class Method : CachedSymbol, IExpressionParentEntity, IStatementParentEntity { - public Method(Context cx, IMethodSymbol init) + protected Method(Context cx, IMethodSymbol init) : base(cx, init) { } - protected void PopulateParameters(TextWriter trapFile) + protected void PopulateParameters() { var originalMethod = OriginalDefinition; IEnumerable parameters = symbol.Parameters; @@ -62,7 +62,7 @@ protected virtual void ExtractInitializers(TextWriter trapFile) // so there's nothing to extract. } - void PopulateMethodBody(TextWriter trapFile) + private void PopulateMethodBody(TextWriter trapFile) { if (!IsSourceDeclaration) return; @@ -71,30 +71,34 @@ void PopulateMethodBody(TextWriter trapFile) var expr = ExpressionBody; if (block != null || expr != null) + { Context.PopulateLater( - () => - { - ExtractInitializers(trapFile); - if (block != null) - Statements.Block.Create(Context, block, this, 0); - else - Expression.Create(Context, expr, this, 0); - - Context.NumberOfLines(trapFile, symbol, this); - }); + () => + { + ExtractInitializers(trapFile); + if (block != null) + Statements.Block.Create(Context, block, this, 0); + else + Expression.Create(Context, expr, this, 0); + + Context.NumberOfLines(trapFile, BodyDeclaringSymbol, this); + }); + } } public void Overrides(TextWriter trapFile) { - foreach (var explicitInterface in symbol.ExplicitInterfaceImplementations. - Where(sym => sym.MethodKind == MethodKind.Ordinary). - Select(impl => Type.Create(Context, impl.ContainingType))) + foreach (var explicitInterface in symbol.ExplicitInterfaceImplementations + .Where(sym => sym.MethodKind == MethodKind.Ordinary) + .Select(impl => Type.Create(Context, impl.ContainingType))) { trapFile.explicitly_implements(this, explicitInterface.TypeRef); if (IsSourceDeclaration) + { foreach (var syntax in symbol.DeclaringSyntaxReferences.Select(d => d.GetSyntax()).OfType()) TypeMention.Create(Context, syntax.ExplicitInterfaceSpecifier.Name, this, explicitInterface); + } } if (symbol.OverriddenMethod != null) @@ -108,6 +112,9 @@ public void Overrides(TextWriter trapFile) /// protected static void BuildMethodId(Method m, TextWriter trapFile) { + m.symbol.ReturnType.BuildOrWriteId(m.Context, trapFile, m.symbol); + trapFile.Write(" "); + trapFile.WriteSubId(m.ContainingType); AddExplicitInterfaceQualifierToId(m.Context, trapFile, m.symbol.ExplicitInterfaceImplementations); @@ -126,10 +133,10 @@ protected static void BuildMethodId(Method m, TextWriter trapFile) { trapFile.Write('<'); // Encode the nullability of the type arguments in the label. - // Type arguments with different nullability can result in + // Type arguments with different nullability can result in // a constructed method with different nullability of its parameters and return type, // so we need to create a distinct database entity for it. - trapFile.BuildList(",", m.symbol.GetAnnotatedTypeArguments(), (ta, tb0) => { AddSignatureTypeToId(m.Context, tb0, m.symbol, ta.Symbol); trapFile.Write((int)ta.Nullability); }); + trapFile.BuildList(",", m.symbol.GetAnnotatedTypeArguments(), (ta, tb0) => { ta.Symbol.BuildOrWriteId(m.Context, tb0, m.symbol); trapFile.Write((int)ta.Nullability); }); trapFile.Write('>'); } } @@ -163,65 +170,21 @@ public override void WriteId(TextWriter trapFile) BuildMethodId(this, trapFile); } - /// - /// Adds an appropriate label ID to the trap builder - /// for the type belonging to the signature of method - /// . - /// - /// For methods without type parameters this will always add the key of the - /// corresponding type. - /// - /// For methods with type parameters, this will add the key of the - /// corresponding type if the type does *not* contain one of the method - /// type parameters, otherwise it will add a textual representation of - /// the type. This distinction is required because type parameter IDs - /// refer to their declaring methods. - /// - /// Example: - /// - /// - /// int Count<T>(IEnumerable items) - /// - /// - /// The label definitions for Count (#4) and T - /// (#5) will look like: - /// - /// - /// #1=<label for System.Int32> - /// #2=<label for type containing Count> - /// #3=<label for IEnumerable`1> - /// #4=@"{#1} {#2}.Count`2(#3);method" - /// #5=@"{#4}T;typeparameter" - /// - /// - /// Note how int is referenced in the label definition #3 for - /// Count, while T[] is represented textually in order - /// to make the reference to #3 in the label definition #4 for - /// T valid. - /// - protected static void AddSignatureTypeToId(Context cx, TextWriter trapFile, IMethodSymbol method, ITypeSymbol type) - { - if (type.ContainsTypeParameters(cx, method)) - type.BuildTypeId(cx, trapFile, (cx0, tb0, type0) => AddSignatureTypeToId(cx, tb0, method, type0)); - else - trapFile.WriteSubId(Type.Create(cx, type)); - } - protected static void AddParametersToId(Context cx, TextWriter trapFile, IMethodSymbol method) { trapFile.Write('('); - int index = 0; + var index = 0; - if (method.MethodKind == MethodKind.ReducedExtension) - { - trapFile.WriteSeparator(",", ref index); - AddSignatureTypeToId(cx, trapFile, method, method.ReceiverType); - } + var @params = method.MethodKind == MethodKind.ReducedExtension + ? method.ReducedFrom.Parameters + : method.Parameters; - foreach (var param in method.Parameters) + foreach (var param in @params) { trapFile.WriteSeparator(",", ref index); - AddSignatureTypeToId(cx, trapFile, method, param.Type); + param.Type.BuildOrWriteId(cx, trapFile, method); + trapFile.Write(" "); + trapFile.Write(param.Name); switch (param.RefKind) { case RefKind.Out: @@ -245,9 +208,7 @@ protected static void AddParametersToId(Context cx, TextWriter trapFile, IMethod public static void AddExplicitInterfaceQualifierToId(Context cx, System.IO.TextWriter trapFile, IEnumerable explicitInterfaceImplementations) { if (explicitInterfaceImplementations.Any()) - { trapFile.AppendList(",", explicitInterfaceImplementations.Select(impl => cx.CreateEntity(impl.ContainingType))); - } } public virtual string Name => symbol.Name; @@ -260,7 +221,8 @@ public static void AddExplicitInterfaceQualifierToId(Context cx, System.IO.TextW /// public static Method Create(Context cx, IMethodSymbol methodDecl) { - if (methodDecl == null) return null; + if (methodDecl == null) + return null; var methodKind = methodDecl.MethodKind; @@ -283,7 +245,7 @@ public static Method Create(Context cx, IMethodSymbol methodDecl) return Destructor.Create(cx, methodDecl); case MethodKind.PropertyGet: case MethodKind.PropertySet: - return methodDecl.AssociatedSymbol is null ? OrdinaryMethod.Create(cx, methodDecl) : (Method)Accessor.Create(cx, methodDecl); + return Accessor.GetPropertySymbol(methodDecl) is null ? OrdinaryMethod.Create(cx, methodDecl) : (Method)Accessor.Create(cx, methodDecl); case MethodKind.EventAdd: case MethodKind.EventRemove: return EventAccessor.Create(cx, methodDecl); @@ -322,7 +284,7 @@ public static Method Create(Context cx, IMethodSymbol methodDecl) public bool IsBoundGeneric => IsGeneric && !IsUnboundGeneric; - bool IsReducedExtension => symbol.MethodKind == MethodKind.ReducedExtension; + private bool IsReducedExtension => symbol.MethodKind == MethodKind.ReducedExtension; protected IMethodSymbol ConstructedFromSymbol => symbol.ConstructedFrom.ReducedFrom ?? symbol.ConstructedFrom; @@ -336,7 +298,7 @@ protected void PopulateGenerics(TextWriter trapFile) if (IsGeneric) { - int child = 0; + var child = 0; if (isFullyConstructed) { @@ -375,7 +337,7 @@ protected void PopulateMethod(TextWriter trapFile) // Common population code for all callables BindComments(); PopulateAttributes(); - PopulateParameters(trapFile); + PopulateParameters(); PopulateMethodBody(trapFile); PopulateGenerics(trapFile); PopulateMetadataHandle(trapFile); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Modifier.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Modifier.cs index 4de6318786ce..4b2725b89f30 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Modifier.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Modifier.cs @@ -1,41 +1,18 @@ using Microsoft.CodeAnalysis; -using System; using System.IO; -using System.Reflection; namespace Semmle.Extraction.CSharp.Entities { - /// - /// Provide a "Key" object to allow modifiers to exist as entities in the extractor - /// hash map. (Raw strings would work as keys but might clash with other types). - /// - class ModifierKey : Object + internal class Modifier : Extraction.CachedEntity { - public readonly string name; - - public ModifierKey(string m) - { - name = m; - } - - public override bool Equals(Object obj) - { - return obj.GetType() == GetType() && name == ((ModifierKey)obj).name; - } - - public override int GetHashCode() => 13 * name.GetHashCode(); - } - - class Modifier : Extraction.CachedEntity - { - Modifier(Context cx, ModifierKey init) + private Modifier(Context cx, string init) : base(cx, init) { } public override Microsoft.CodeAnalysis.Location ReportingLocation => null; public override void WriteId(TextWriter trapFile) { - trapFile.Write(symbol.name); + trapFile.Write(symbol); trapFile.Write(";modifier"); } @@ -43,7 +20,7 @@ public override void WriteId(TextWriter trapFile) public override void Populate(TextWriter trapFile) { - trapFile.modifiers(Label, symbol.name); + trapFile.modifiers(Label, symbol); } public static string AccessbilityModifier(Accessibility access) @@ -95,7 +72,7 @@ public static void HasModifier(Context cx, TextWriter trapFile, IEntity target, public static void ExtractModifiers(Context cx, TextWriter trapFile, IEntity key, ISymbol symbol) { - bool interfaceDefinition = symbol.ContainingType != null + var interfaceDefinition = symbol.ContainingType != null && symbol.ContainingType.Kind == SymbolKind.NamedType && symbol.ContainingType.TypeKind == TypeKind.Interface; @@ -109,7 +86,7 @@ public static void ExtractModifiers(Context cx, TextWriter trapFile, IEntity key if (symbol.IsSealed) HasModifier(cx, trapFile, key, "sealed"); - bool fromSource = symbol.DeclaringSyntaxReferences.Length > 0; + var fromSource = symbol.DeclaringSyntaxReferences.Length > 0; if (symbol.IsStatic && !(symbol.Kind == SymbolKind.Field && ((IFieldSymbol)symbol).IsConst && !fromSource)) HasModifier(cx, trapFile, key, "static"); @@ -138,7 +115,7 @@ public static void ExtractModifiers(Context cx, TextWriter trapFile, IEntity key if (symbol.Kind == SymbolKind.NamedType) { - INamedTypeSymbol nt = symbol as INamedTypeSymbol; + var nt = symbol as INamedTypeSymbol; if (nt is null) throw new InternalError(symbol, "Symbol kind is inconsistent with its type"); @@ -152,17 +129,22 @@ public static void ExtractModifiers(Context cx, TextWriter trapFile, IEntity key } } - public static Modifier Create(Context cx, string modifier) => - ModifierFactory.Instance.CreateEntity(cx, new ModifierKey(modifier)); + public static Modifier Create(Context cx, string modifier) + { + return ModifierFactory.Instance.CreateEntity(cx, (typeof(Modifier), modifier), modifier); + } - public static Modifier Create(Context cx, Accessibility access) => - ModifierFactory.Instance.CreateEntity(cx, new ModifierKey(AccessbilityModifier(access))); + public static Modifier Create(Context cx, Accessibility access) + { + var modifier = AccessbilityModifier(access); + return ModifierFactory.Instance.CreateEntity(cx, (typeof(Modifier), modifier), modifier); + } - class ModifierFactory : ICachedEntityFactory + private class ModifierFactory : ICachedEntityFactory { - public static readonly ModifierFactory Instance = new ModifierFactory(); + public static ModifierFactory Instance { get; } = new ModifierFactory(); - public Modifier Create(Context cx, ModifierKey init) => new Modifier(cx, init); + public Modifier Create(Context cx, string init) => new Modifier(cx, init); } public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel; } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Namespace.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Namespace.cs index 1d663b1b5616..6ae31c82b649 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Namespace.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Namespace.cs @@ -3,9 +3,9 @@ namespace Semmle.Extraction.CSharp.Entities { - sealed class Namespace : CachedEntity + internal sealed class Namespace : CachedEntity { - Namespace(Context cx, INamespaceSymbol init) + private Namespace(Context cx, INamespaceSymbol init) : base(cx, init) { } public override Microsoft.CodeAnalysis.Location ReportingLocation => null; @@ -16,7 +16,7 @@ public override void Populate(TextWriter trapFile) if (symbol.ContainingNamespace != null) { - Namespace parent = Create(Context, symbol.ContainingNamespace); + var parent = Create(Context, symbol.ContainingNamespace); trapFile.parent_namespace(this, parent); } } @@ -34,11 +34,11 @@ public override void WriteId(TextWriter trapFile) trapFile.Write(";namespace"); } - public static Namespace Create(Context cx, INamespaceSymbol ns) => NamespaceFactory.Instance.CreateEntity2(cx, ns); + public static Namespace Create(Context cx, INamespaceSymbol ns) => NamespaceFactory.Instance.CreateEntityFromSymbol(cx, ns); - class NamespaceFactory : ICachedEntityFactory + private class NamespaceFactory : ICachedEntityFactory { - public static readonly NamespaceFactory Instance = new NamespaceFactory(); + public static NamespaceFactory Instance { get; } = new NamespaceFactory(); public Namespace Create(Context cx, INamespaceSymbol init) => new Namespace(cx, init); } @@ -47,7 +47,7 @@ class NamespaceFactory : ICachedEntityFactory public override int GetHashCode() => QualifiedName.GetHashCode(); - string QualifiedName => symbol.ToDisplayString(); + private string QualifiedName => symbol.ToDisplayString(); public override bool Equals(object obj) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/NamespaceDeclaration.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/NamespaceDeclaration.cs index 7a14bb719fc1..de07d82ac822 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/NamespaceDeclaration.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/NamespaceDeclaration.cs @@ -8,36 +8,36 @@ namespace Semmle.Extraction.CSharp.Entities { - class NamespaceDeclaration : FreshEntity + internal class NamespaceDeclaration : FreshEntity { - private readonly NamespaceDeclaration Parent; - private readonly NamespaceDeclarationSyntax Node; + private readonly NamespaceDeclaration parent; + private readonly NamespaceDeclarationSyntax node; public NamespaceDeclaration(Context cx, NamespaceDeclarationSyntax node, NamespaceDeclaration parent) : base(cx) { - Node = node; - Parent = parent; + this.node = node; + this.parent = parent; TryPopulate(); } protected override void Populate(TextWriter trapFile) { - var @namespace = (INamespaceSymbol) cx.GetModel(Node).GetSymbolInfo(Node.Name).Symbol; + var @namespace = (INamespaceSymbol)cx.GetModel(node).GetSymbolInfo(node.Name).Symbol; var ns = Namespace.Create(cx, @namespace); trapFile.namespace_declarations(this, ns); - trapFile.namespace_declaration_location(this, cx.Create(Node.Name.GetLocation())); + trapFile.namespace_declaration_location(this, cx.Create(node.Name.GetLocation())); var visitor = new Populators.TypeOrNamespaceVisitor(cx, trapFile, this); - foreach (var member in Node.Members.Cast().Concat(Node.Usings)) + foreach (var member in node.Members.Cast().Concat(node.Usings)) { member.Accept(visitor); } - if (Parent != null) + if (parent != null) { - trapFile.parent_namespace_declaration(this, Parent); + trapFile.parent_namespace_declaration(this, parent); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs index cb12918e72e7..dbeab838b25c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs @@ -6,13 +6,15 @@ namespace Semmle.Extraction.CSharp.Entities { - class OrdinaryMethod : Method + internal class OrdinaryMethod : Method { - OrdinaryMethod(Context cx, IMethodSymbol init) + private OrdinaryMethod(Context cx, IMethodSymbol init) : base(cx, init) { } public override string Name => symbol.GetName(); + protected override IMethodSymbol BodyDeclaringSymbol => symbol.PartialImplementationPart ?? symbol; + public IMethodSymbol SourceDeclaration { get @@ -34,11 +36,13 @@ public override void Populate(TextWriter trapFile) trapFile.methods(this, Name, ContainingType, returnType.TypeRef, OriginalDefinition); if (IsSourceDeclaration) + { foreach (var declaration in symbol.DeclaringSyntaxReferences.Select(s => s.GetSyntax()).OfType()) { Context.BindComments(this, declaration.Identifier.GetLocation()); TypeMention.Create(Context, declaration.ReturnType, this, returnType); } + } foreach (var l in Locations) trapFile.method_location(this, l); @@ -49,11 +53,11 @@ public override void Populate(TextWriter trapFile) ExtractCompilerGenerated(trapFile); } - public new static OrdinaryMethod Create(Context cx, IMethodSymbol method) => OrdinaryMethodFactory.Instance.CreateEntity(cx, method); + public static new OrdinaryMethod Create(Context cx, IMethodSymbol method) => OrdinaryMethodFactory.Instance.CreateEntityFromSymbol(cx, method); - class OrdinaryMethodFactory : ICachedEntityFactory + private class OrdinaryMethodFactory : ICachedEntityFactory { - public static readonly OrdinaryMethodFactory Instance = new OrdinaryMethodFactory(); + public static OrdinaryMethodFactory Instance { get; } = new OrdinaryMethodFactory(); public OrdinaryMethod Create(Context cx, IMethodSymbol init) => new OrdinaryMethod(cx, init); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs index 9a64115f24b2..c42a3edd2366 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs @@ -9,8 +9,8 @@ namespace Semmle.Extraction.CSharp.Entities { public class Parameter : CachedSymbol, IExpressionParentEntity { - protected IEntity Parent; - protected readonly Parameter Original; + protected IEntity Parent { get; set; } + protected Parameter Original { get; } protected Parameter(Context cx, IParameterSymbol init, IEntity parent, Parameter original) : base(cx, init) @@ -34,13 +34,14 @@ protected virtual int Ordinal // omit the "this" parameter, so the parameters are // actually numbered from 1. // This is to be consistent from the original (unreduced) extension method. - var method = symbol.ContainingSymbol as IMethodSymbol; - bool isReducedExtension = method != null && method.MethodKind == MethodKind.ReducedExtension; + var isReducedExtension = + symbol.ContainingSymbol is IMethodSymbol method && + method.MethodKind == MethodKind.ReducedExtension; return symbol.Ordinal + (isReducedExtension ? 1 : 0); } } - Kind ParamKind + private Kind ParamKind { get { @@ -53,12 +54,13 @@ Kind ParamKind case RefKind.In: return Kind.In; default: - if (symbol.IsParams) return Kind.Params; + if (symbol.IsParams) + return Kind.Params; if (Ordinal == 0) { - var method = symbol.ContainingSymbol as IMethodSymbol; - if (method != null && method.IsExtensionMethod) return Kind.This; + if (symbol.ContainingSymbol is IMethodSymbol method && method.IsExtensionMethod) + return Kind.This; } return Kind.None; } @@ -66,10 +68,10 @@ Kind ParamKind } public static Parameter Create(Context cx, IParameterSymbol param, IEntity parent, Parameter original = null) => - ParameterFactory.Instance.CreateEntity(cx, param, parent, original); + ParameterFactory.Instance.CreateEntity(cx, param, (param, parent, original)); public static Parameter Create(Context cx, IParameterSymbol param) => - ParameterFactory.Instance.CreateEntity(cx, param, null, null); + ParameterFactory.Instance.CreateEntity(cx, param, (param, null, null)); public override void WriteId(TextWriter trapFile) { @@ -83,14 +85,14 @@ public override void WriteId(TextWriter trapFile) public override bool NeedsPopulation => true; - string Name + private string Name { get { // Very rarely, two parameters have the same name according to the data model. // This breaks our database constraints. // Generate an impossible name to ensure that it doesn't conflict. - int conflictingCount = symbol.ContainingSymbol.GetParameters().Count(p => p.Ordinal < symbol.Ordinal && p.Name == symbol.Name); + var conflictingCount = symbol.ContainingSymbol.GetParameters().Count(p => p.Ordinal < symbol.Ordinal && p.Name == symbol.Name); return conflictingCount > 0 ? symbol.Name + "`" + conflictingCount : symbol.Name; } } @@ -116,11 +118,15 @@ public override void Populate(TextWriter trapFile) BindComments(); if (IsSourceDeclaration) - foreach (var syntax in symbol.DeclaringSyntaxReferences. - Select(d => d.GetSyntax()). - OfType(). - Where(s => s.Type != null)) + { + foreach (var syntax in symbol.DeclaringSyntaxReferences + .Select(d => d.GetSyntax()) + .OfType() + .Where(s => s.Type != null)) + { TypeMention.Create(Context, syntax.Type, this, type); + } + } if (symbol.HasExplicitDefaultValue && Context.Defines(symbol)) { @@ -157,15 +163,15 @@ public override void Populate(TextWriter trapFile) bool IExpressionParentEntity.IsTopLevelParent => true; - static EqualsValueClauseSyntax GetParameterDefaultValue(IParameterSymbol parameter) + private static EqualsValueClauseSyntax GetParameterDefaultValue(IParameterSymbol parameter) { var syntax = parameter.DeclaringSyntaxReferences.Select(@ref => @ref.GetSyntax()).OfType().FirstOrDefault(); - return syntax != null ? syntax.Default : null; + return syntax?.Default; } - class ParameterFactory : ICachedEntityFactory<(IParameterSymbol, IEntity, Parameter), Parameter> + private class ParameterFactory : ICachedEntityFactory<(IParameterSymbol, IEntity, Parameter), Parameter> { - public static readonly ParameterFactory Instance = new ParameterFactory(); + public static ParameterFactory Instance { get; } = new ParameterFactory(); public Parameter Create(Context cx, (IParameterSymbol, IEntity, Parameter) init) => new Parameter(cx, init.Item1, init.Item2, init.Item3); } @@ -173,9 +179,9 @@ class ParameterFactory : ICachedEntityFactory<(IParameterSymbol, IEntity, Parame public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel; } - class VarargsType : Type + internal class VarargsType : Type { - VarargsType(Context cx) + private VarargsType(Context cx) : base(cx, null) { } public override void Populate(TextWriter trapFile) @@ -202,19 +208,19 @@ public override bool Equals(object obj) return obj != null && obj.GetType() == typeof(VarargsType); } - public static VarargsType Create(Context cx) => VarargsTypeFactory.Instance.CreateNullableEntity(cx, null); + public static VarargsType Create(Context cx) => VarargsTypeFactory.Instance.CreateEntity(cx, typeof(VarargsType), null); - class VarargsTypeFactory : ICachedEntityFactory + private class VarargsTypeFactory : ICachedEntityFactory { - public static readonly VarargsTypeFactory Instance = new VarargsTypeFactory(); + public static VarargsTypeFactory Instance { get; } = new VarargsTypeFactory(); public VarargsType Create(Context cx, string init) => new VarargsType(cx); } } - class VarargsParam : Parameter + internal class VarargsParam : Parameter { - VarargsParam(Context cx, Method methodKey) + private VarargsParam(Context cx, Method methodKey) : base(cx, null, methodKey, null) { } public override void Populate(TextWriter trapFile) @@ -237,50 +243,39 @@ public override bool Equals(object obj) return obj != null && obj.GetType() == typeof(VarargsParam); } - public static VarargsParam Create(Context cx, Method method) => VarargsParamFactory.Instance.CreateEntity(cx, method); + public static VarargsParam Create(Context cx, Method method) => VarargsParamFactory.Instance.CreateEntity(cx, typeof(VarargsParam), method); - class VarargsParamFactory : ICachedEntityFactory + private class VarargsParamFactory : ICachedEntityFactory { - public static readonly VarargsParamFactory Instance = new VarargsParamFactory(); + public static VarargsParamFactory Instance { get; } = new VarargsParamFactory(); public VarargsParam Create(Context cx, Method init) => new VarargsParam(cx, init); } } - class ConstructedExtensionParameter : Parameter + internal class ConstructedExtensionParameter : Parameter { - readonly ITypeSymbol ConstructedType; + private readonly ITypeSymbol constructedType; - ConstructedExtensionParameter(Context cx, Method method, Parameter original) + private ConstructedExtensionParameter(Context cx, Method method, Parameter original) : base(cx, original.symbol, method, original) { - ConstructedType = method.symbol.ReceiverType; + constructedType = method.symbol.ReceiverType; } public override void Populate(TextWriter trapFile) { - var typeKey = Type.Create(Context, ConstructedType); + var typeKey = Type.Create(Context, constructedType); trapFile.@params(this, Original.symbol.Name, typeKey.TypeRef, 0, Kind.This, Parent, Original); trapFile.param_location(this, Original.Location); } - public override int GetHashCode() => symbol.GetHashCode() + 31 * ConstructedType.GetHashCode(); - - public override bool Equals(object obj) - { - var other = obj as ConstructedExtensionParameter; - if (other == null || other.GetType() != typeof(ConstructedExtensionParameter)) - return false; - - return SymbolEqualityComparer.Default.Equals(symbol, other.symbol) && SymbolEqualityComparer.Default.Equals(ConstructedType, other.ConstructedType); - } - public static ConstructedExtensionParameter Create(Context cx, Method method, Parameter parameter) => - ExtensionParamFactory.Instance.CreateEntity(cx, (method, parameter)); + ExtensionParamFactory.Instance.CreateEntity(cx, (new SymbolEqualityWrapper(parameter.symbol), new SymbolEqualityWrapper(method.symbol.ReceiverType)), (method, parameter)); - class ExtensionParamFactory : ICachedEntityFactory<(Method, Parameter), ConstructedExtensionParameter> + private class ExtensionParamFactory : ICachedEntityFactory<(Method, Parameter), ConstructedExtensionParameter> { - public static readonly ExtensionParamFactory Instance = new ExtensionParamFactory(); + public static ExtensionParamFactory Instance { get; } = new ExtensionParamFactory(); public ConstructedExtensionParameter Create(Context cx, (Method, Parameter) init) => new ConstructedExtensionParameter(cx, init.Item1, init.Item2); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs index e5e2cc8ab261..739708138adc 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs @@ -1,3 +1,4 @@ +using System; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.CSharp.Entities.Expressions; @@ -8,13 +9,22 @@ namespace Semmle.Extraction.CSharp.Entities { - class Property : CachedSymbol, IExpressionParentEntity + internal class Property : CachedSymbol, IExpressionParentEntity { protected Property(Context cx, IPropertySymbol init) - : base(cx, init) { } + : base(cx, init) + { + type = new Lazy(() => Type.Create(Context, symbol.Type)); + } + + private readonly Lazy type; + + private Type Type => type.Value; public override void WriteId(TextWriter trapFile) { + trapFile.WriteSubId(Type); + trapFile.Write(" "); trapFile.WriteSubId(ContainingType); trapFile.Write('.'); Method.AddExplicitInterfaceQualifierToId(Context, trapFile, symbol.ExplicitInterfaceImplementations); @@ -31,7 +41,7 @@ public override void Populate(TextWriter trapFile) PopulateNullability(trapFile, symbol.GetAnnotatedType()); PopulateRefKind(trapFile, symbol.RefKind); - var type = Type.Create(Context, symbol.Type); + var type = Type; trapFile.properties(this, symbol.GetName(), ContainingType, type.TypeRef, Create(Context, symbol.OriginalDefinition)); var getter = symbol.GetMethod; @@ -67,10 +77,10 @@ public override void Populate(TextWriter trapFile) Context.PopulateLater(() => Expression.Create(Context, expressionBody, this, 0)); } - int child = 1; - foreach (var initializer in declSyntaxReferences. - Select(n => n.Initializer). - Where(i => i != null)) + var child = 1; + foreach (var initializer in declSyntaxReferences + .Select(n => n.Initializer) + .Where(i => i != null)) { Context.PopulateLater(() => { @@ -96,14 +106,12 @@ public override Microsoft.CodeAnalysis.Location FullLocation { get { - return - symbol. - DeclaringSyntaxReferences. - Select(r => r.GetSyntax()). - OfType(). - Select(s => s.GetLocation()). - Concat(symbol.Locations). - First(); + return symbol.DeclaringSyntaxReferences + .Select(r => r.GetSyntax()) + .OfType() + .Select(s => s.GetLocation()) + .Concat(symbol.Locations) + .First(); } } @@ -111,18 +119,14 @@ public override Microsoft.CodeAnalysis.Location FullLocation public static Property Create(Context cx, IPropertySymbol prop) { - bool isIndexer = prop.IsIndexer || prop.Parameters.Any(); + var isIndexer = prop.IsIndexer || prop.Parameters.Any(); - return isIndexer ? Indexer.Create(cx, prop) : PropertyFactory.Instance.CreateEntity(cx, prop); - } - - public void VisitDeclaration(Context cx, PropertyDeclarationSyntax p) - { + return isIndexer ? Indexer.Create(cx, prop) : PropertyFactory.Instance.CreateEntityFromSymbol(cx, prop); } - class PropertyFactory : ICachedEntityFactory + private class PropertyFactory : ICachedEntityFactory { - public static readonly PropertyFactory Instance = new PropertyFactory(); + public static PropertyFactory Instance { get; } = new PropertyFactory(); public Property Create(Context cx, IPropertySymbol init) => new Property(cx, init); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement.cs index 790ff96d70fc..44bd7f80583f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement.cs @@ -14,7 +14,7 @@ public interface IStatementParentEntity : IEntity bool IsTopLevelParent { get; } } - abstract class Statement : FreshEntity, IExpressionParentEntity, IStatementParentEntity + internal abstract class Statement : FreshEntity, IExpressionParentEntity, IStatementParentEntity { protected Statement(Context cx) : base(cx) { } @@ -38,13 +38,13 @@ public static Statement Create(Context cx, StatementSyntax node, Statement paren public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NeedsLabel; } - abstract class Statement : Statement where TSyntax : CSharpSyntaxNode + internal abstract class Statement : Statement where TSyntax : CSharpSyntaxNode { protected readonly TSyntax Stmt; - private readonly int Child; - private readonly Kinds.StmtKind Kind; - private readonly IStatementParentEntity Parent; - private readonly Location Location; + private readonly int child; + private readonly Kinds.StmtKind kind; + private readonly IStatementParentEntity parent; + private readonly Location location; protected override CSharpSyntaxNode GetStatementSyntax() => Stmt; @@ -52,21 +52,21 @@ protected Statement(Context cx, TSyntax stmt, Kinds.StmtKind kind, IStatementPar : base(cx) { Stmt = stmt; - Parent = parent; - Child = child; - Location = location; - Kind = kind; + this.parent = parent; + this.child = child; + this.location = location; + this.kind = kind; cx.BindComments(this, location.symbol); } protected sealed override void Populate(TextWriter trapFile) { - trapFile.statements(this, Kind); - if (Parent.IsTopLevelParent) - trapFile.stmt_parent_top_level(this, Child, Parent); + trapFile.statements(this, kind); + if (parent.IsTopLevelParent) + trapFile.stmt_parent_top_level(this, child, parent); else - trapFile.stmt_parent(this, Child, Parent); - trapFile.stmt_location(this, Location); + trapFile.stmt_parent(this, child, parent); + trapFile.stmt_location(this, location); PopulateStatement(trapFile); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Block.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Block.cs index f9358216848f..c3e2e15baf3f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Block.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Block.cs @@ -5,9 +5,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { - class Block : Statement + internal class Block : Statement { - Block(Context cx, BlockSyntax block, IStatementParentEntity parent, int child) + private Block(Context cx, BlockSyntax block, IStatementParentEntity parent, int child) : base(cx, block, StmtKind.BLOCK, parent, child) { } public static Block Create(Context cx, BlockSyntax node, IStatementParentEntity parent, int child) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Break.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Break.cs index 8ce111634b5a..22428be6f04c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Break.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Break.cs @@ -4,9 +4,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { - class Break : Statement + internal class Break : Statement { - Break(Context cx, BreakStatementSyntax node, IStatementParentEntity parent, int child) + private Break(Context cx, BreakStatementSyntax node, IStatementParentEntity parent, int child) : base(cx, node, StmtKind.BREAK, parent, child) { } public static Break Create(Context cx, BreakStatementSyntax node, IStatementParentEntity parent, int child) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Case.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Case.cs index da7d86dae815..fe91851193b4 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Case.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Case.cs @@ -7,7 +7,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { - abstract class Case : Statement where TSyntax : SwitchLabelSyntax + internal abstract class Case : Statement where TSyntax : SwitchLabelSyntax { protected Case(Context cx, TSyntax node, Switch parent, int child) : base(cx, node, StmtKind.CASE, parent, child, cx.Create(node.GetLocation())) { } @@ -28,9 +28,9 @@ public static Statement Create(Context cx, SwitchLabelSyntax node, Switch parent } } - class CaseLabel : Case + internal class CaseLabel : Case { - CaseLabel(Context cx, CaseSwitchLabelSyntax node, Switch parent, int child) + private CaseLabel(Context cx, CaseSwitchLabelSyntax node, Switch parent, int child) : base(cx, node, parent, child) { } protected override void PopulateStatement(TextWriter trapFile) @@ -48,9 +48,9 @@ public static CaseLabel Create(Context cx, CaseSwitchLabelSyntax node, Switch pa } } - class CaseDefault : Case + internal class CaseDefault : Case { - CaseDefault(Context cx, DefaultSwitchLabelSyntax node, Switch parent, int child) + private CaseDefault(Context cx, DefaultSwitchLabelSyntax node, Switch parent, int child) : base(cx, node, parent, child) { } protected override void PopulateStatement(TextWriter trapFile) { } @@ -63,7 +63,7 @@ public static CaseDefault Create(Context cx, DefaultSwitchLabelSyntax node, Swit } } - class CasePattern : Case + internal class CasePattern : Case { private CasePattern(Context cx, CasePatternSwitchLabelSyntax node, Switch parent, int child) : base(cx, node, parent, child) { } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Catch.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Catch.cs index 85e9e85f5b3d..13cc39f7fea9 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Catch.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Catch.cs @@ -1,22 +1,21 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.Kinds; -using Semmle.Extraction.CSharp.Populators; using Semmle.Extraction.Entities; using System.IO; namespace Semmle.Extraction.CSharp.Entities.Statements { - class Catch : Statement + internal class Catch : Statement { - static readonly string SystemExceptionName = typeof(System.Exception).ToString(); + private static readonly string systemExceptionName = typeof(System.Exception).ToString(); - Catch(Context cx, CatchClauseSyntax node, Try parent, int child) + private Catch(Context cx, CatchClauseSyntax node, Try parent, int child) : base(cx, node, StmtKind.CATCH, parent, child, cx.Create(node.GetLocation())) { } protected override void PopulateStatement(TextWriter trapFile) { - bool isSpecificCatchClause = Stmt.Declaration != null; - bool hasVariableDeclaration = isSpecificCatchClause && Stmt.Declaration.Identifier.RawKind != 0; + var isSpecificCatchClause = Stmt.Declaration != null; + var hasVariableDeclaration = isSpecificCatchClause && Stmt.Declaration.Identifier.RawKind != 0; if (hasVariableDeclaration) // A catch clause of the form 'catch(Ex ex) { ... }' { @@ -29,7 +28,7 @@ protected override void PopulateStatement(TextWriter trapFile) } else // A catch clause of the form 'catch { ... }' { - var exception = Type.Create(cx, cx.Compilation.GetTypeByMetadataName(SystemExceptionName)); + var exception = Type.Create(cx, cx.Compilation.GetTypeByMetadataName(systemExceptionName)); trapFile.catch_type(this, exception, false); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Checked.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Checked.cs index b2523eeb5a13..4ce000bed3fd 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Checked.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Checked.cs @@ -4,9 +4,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { - class Checked : Statement + internal class Checked : Statement { - Checked(Context cx, CheckedStatementSyntax stmt, IStatementParentEntity parent, int child) + private Checked(Context cx, CheckedStatementSyntax stmt, IStatementParentEntity parent, int child) : base(cx, stmt, StmtKind.CHECKED, parent, child) { } public static Checked Create(Context cx, CheckedStatementSyntax node, IStatementParentEntity parent, int child) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Continue.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Continue.cs index c7cf7261acae..3e819eeff0cc 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Continue.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Continue.cs @@ -4,9 +4,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { - class Continue : Statement + internal class Continue : Statement { - Continue(Context cx, ContinueStatementSyntax stmt, IStatementParentEntity parent, int child) + private Continue(Context cx, ContinueStatementSyntax stmt, IStatementParentEntity parent, int child) : base(cx, stmt, StmtKind.CONTINUE, parent, child) { } public static Continue Create(Context cx, ContinueStatementSyntax node, IStatementParentEntity parent, int child) @@ -19,4 +19,3 @@ public static Continue Create(Context cx, ContinueStatementSyntax node, IStateme protected override void PopulateStatement(TextWriter trapFile) { } } } - diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Do.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Do.cs index 26a46730967d..a0cd9da7372d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Do.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Do.cs @@ -5,9 +5,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { - class Do : Statement + internal class Do : Statement { - Do(Context cx, DoStatementSyntax node, IStatementParentEntity parent, int child) + private Do(Context cx, DoStatementSyntax node, IStatementParentEntity parent, int child) : base(cx, node, StmtKind.DO, parent, child, cx.Create(node.GetLocation())) { } public static Do Create(Context cx, DoStatementSyntax node, IStatementParentEntity parent, int child) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Empty.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Empty.cs index 8d9a6acedae4..8611727ddecc 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Empty.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Empty.cs @@ -4,9 +4,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { - class Empty : Statement + internal class Empty : Statement { - Empty(Context cx, EmptyStatementSyntax block, IStatementParentEntity parent, int child) + private Empty(Context cx, EmptyStatementSyntax block, IStatementParentEntity parent, int child) : base(cx, block, StmtKind.EMPTY, parent, child) { } public static Empty Create(Context cx, EmptyStatementSyntax node, IStatementParentEntity parent, int child) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ExpressionStatement.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ExpressionStatement.cs index cdbc15e9699e..252e867efa98 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ExpressionStatement.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ExpressionStatement.cs @@ -3,9 +3,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { - class ExpressionStatement : Statement + internal class ExpressionStatement : Statement { - ExpressionStatement(Context cx, ExpressionStatementSyntax node, IStatementParentEntity parent, int child) + private ExpressionStatement(Context cx, ExpressionStatementSyntax node, IStatementParentEntity parent, int child) : base(cx, node, Kinds.StmtKind.EXPR, parent, child) { } public static ExpressionStatement Create(Context cx, ExpressionStatementSyntax node, IStatementParentEntity parent, int child) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Factory.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Factory.cs index 0b5057f7d855..69ebdca1c168 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Factory.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Factory.cs @@ -3,7 +3,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { - static class Factory + internal static class Factory { internal static Statement Create(Context cx, StatementSyntax node, Statement parent, int child) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Fixed.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Fixed.cs index 6cabf07591df..7cd8350c7d10 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Fixed.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Fixed.cs @@ -5,9 +5,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { - class Fixed : Statement + internal class Fixed : Statement { - Fixed(Context cx, FixedStatementSyntax @fixed, IStatementParentEntity parent, int child) + private Fixed(Context cx, FixedStatementSyntax @fixed, IStatementParentEntity parent, int child) : base(cx, @fixed, StmtKind.FIXED, parent, child) { } public static Fixed Create(Context cx, FixedStatementSyntax node, IStatementParentEntity parent, int child) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/For.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/For.cs index 7e21cd6b5c2c..15c7151a8a62 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/For.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/For.cs @@ -5,9 +5,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { - class For : Statement + internal class For : Statement { - For(Context cx, ForStatementSyntax node, IStatementParentEntity parent, int child) + private For(Context cx, ForStatementSyntax node, IStatementParentEntity parent, int child) : base(cx, node, StmtKind.FOR, parent, child) { } public static For Create(Context cx, ForStatementSyntax node, IStatementParentEntity parent, int child) @@ -19,7 +19,7 @@ public static For Create(Context cx, ForStatementSyntax node, IStatementParentEn protected override void PopulateStatement(TextWriter trapFile) { - int child = -1; + var child = -1; if (Stmt.Declaration != null) VariableDeclarations.Populate(cx, Stmt.Declaration, this, child, childIncrement: -1); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs index 9758fee7743a..653ed384e7b8 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs @@ -6,9 +6,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { - class ForEach : Statement + internal class ForEach : Statement { - ForEach(Context cx, ForEachStatementSyntax stmt, IStatementParentEntity parent, int child) + private ForEach(Context cx, ForEachStatementSyntax stmt, IStatementParentEntity parent, int child) : base(cx, stmt, StmtKind.FOREACH, parent, child) { } public static ForEach Create(Context cx, ForEachStatementSyntax node, IStatementParentEntity parent, int child) @@ -33,9 +33,9 @@ protected override void PopulateStatement(TextWriter _) } } - class ForEachVariable : Statement + internal class ForEachVariable : Statement { - ForEachVariable(Context cx, ForEachVariableStatementSyntax stmt, IStatementParentEntity parent, int child) + private ForEachVariable(Context cx, ForEachVariableStatementSyntax stmt, IStatementParentEntity parent, int child) : base(cx, stmt, StmtKind.FOREACH, parent, child) { } public static ForEachVariable Create(Context cx, ForEachVariableStatementSyntax node, IStatementParentEntity parent, int child) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Goto.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Goto.cs index 76d00e81f05d..772d69cff7c4 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Goto.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Goto.cs @@ -8,9 +8,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements /// /// A goto, goto case or goto default. /// - class Goto : Statement + internal class Goto : Statement { - static StmtKind GetKind(GotoStatementSyntax node) + private static StmtKind GetKind(GotoStatementSyntax node) { switch (node.CaseOrDefaultKeyword.Kind()) { @@ -21,7 +21,7 @@ static StmtKind GetKind(GotoStatementSyntax node) } } - Goto(Context cx, GotoStatementSyntax node, IStatementParentEntity parent, int child) + private Goto(Context cx, GotoStatementSyntax node, IStatementParentEntity parent, int child) : base(cx, node, GetKind(node), parent, child) { } public static Goto Create(Context cx, GotoStatementSyntax node, IStatementParentEntity parent, int child) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/If.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/If.cs index a038f60c9987..b132c6ebe547 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/If.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/If.cs @@ -4,9 +4,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { - class If : Statement + internal class If : Statement { - If(Context cx, IfStatementSyntax node, IStatementParentEntity parent, int child) + private If(Context cx, IfStatementSyntax node, IStatementParentEntity parent, int child) : base(cx, node, StmtKind.IF, parent, child) { } public static If Create(Context cx, IfStatementSyntax node, IStatementParentEntity parent, int child) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Labeled.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Labeled.cs index 2ef376c5e6f7..1fce622b3477 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Labeled.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Labeled.cs @@ -4,16 +4,16 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { - class Labeled : Statement + internal class Labeled : Statement { - readonly Statement Parent; - readonly int Child; + private readonly Statement parent; + private readonly int child; - Labeled(Context cx, LabeledStatementSyntax stmt, Statement parent, int child) + private Labeled(Context cx, LabeledStatementSyntax stmt, Statement parent, int child) : base(cx, stmt, StmtKind.LABEL, parent, child) { - Parent = parent; - Child = child; + this.parent = parent; + this.child = child; } public static Labeled Create(Context cx, LabeledStatementSyntax node, Statement parent, int child) @@ -29,10 +29,10 @@ protected override void PopulateStatement(TextWriter trapFile) // For compatilibty with the Mono extractor, make insert the labelled statement into the same block // as this one. The parent MUST be a block statement. - labelledStmt = Statement.Create(cx, Stmt.Statement, Parent, Child + 1); + labelledStmt = Statement.Create(cx, Stmt.Statement, parent, child + 1); } - Statement labelledStmt; + private Statement labelledStmt; public override int NumberOfStatements => 1 + labelledStmt.NumberOfStatements; } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalDeclaration.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalDeclaration.cs index 3eeb962ac7a0..87559681fd8a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalDeclaration.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalDeclaration.cs @@ -5,9 +5,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { - class LocalDeclaration : Statement + internal class LocalDeclaration : Statement { - static StmtKind GetKind(LocalDeclarationStatementSyntax declStmt) + private static StmtKind GetKind(LocalDeclarationStatementSyntax declStmt) { if (declStmt.UsingKeyword.RawKind != 0) return StmtKind.USING_DECL; @@ -18,7 +18,7 @@ static StmtKind GetKind(LocalDeclarationStatementSyntax declStmt) return StmtKind.VAR_DECL; } - LocalDeclaration(Context cx, LocalDeclarationStatementSyntax declStmt, IStatementParentEntity parent, int child) + private LocalDeclaration(Context cx, LocalDeclarationStatementSyntax declStmt, IStatementParentEntity parent, int child) : base(cx, declStmt, GetKind(declStmt), parent, child) { } public static LocalDeclaration Create(Context cx, LocalDeclarationStatementSyntax node, IStatementParentEntity parent, int child) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalFunction.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalFunction.cs index 8cda84c68f26..66f4e5ac41f3 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalFunction.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalFunction.cs @@ -7,9 +7,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { - class LocalFunction : Statement + internal class LocalFunction : Statement { - LocalFunction(Context cx, LocalFunctionStatementSyntax node, IStatementParentEntity parent, int child) + private LocalFunction(Context cx, LocalFunctionStatementSyntax node, IStatementParentEntity parent, int child) : base(cx, node, StmtKind.LOCAL_FUNCTION, parent, child, cx.Create(node.GetLocation())) { } public static LocalFunction Create(Context cx, LocalFunctionStatementSyntax node, IStatementParentEntity parent, int child) @@ -22,7 +22,7 @@ public static LocalFunction Create(Context cx, LocalFunctionStatementSyntax node /// /// Gets the IMethodSymbol for this local function statement. /// - IMethodSymbol Symbol + private IMethodSymbol Symbol { get { @@ -39,7 +39,7 @@ IMethodSymbol Symbol /// /// Gets the function defined by this local statement. /// - Entities.LocalFunction Function => Entities.LocalFunction.Create(cx, Symbol); + private Entities.LocalFunction Function => Entities.LocalFunction.Create(cx, Symbol); protected override void PopulateStatement(TextWriter trapFile) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Lock.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Lock.cs index 314b675866e0..fbcb346b367f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Lock.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Lock.cs @@ -4,9 +4,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { - class Lock : Statement + internal class Lock : Statement { - Lock(Context cx, LockStatementSyntax @lock, IStatementParentEntity parent, int child) + private Lock(Context cx, LockStatementSyntax @lock, IStatementParentEntity parent, int child) : base(cx, @lock, StmtKind.LOCK, parent, child) { } public static Lock Create(Context cx, LockStatementSyntax node, IStatementParentEntity parent, int child) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Return.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Return.cs index 69688a8e6f12..2ff04b82b87a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Return.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Return.cs @@ -4,9 +4,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { - class Return : Statement + internal class Return : Statement { - Return(Context cx, ReturnStatementSyntax node, IStatementParentEntity parent, int child) + private Return(Context cx, ReturnStatementSyntax node, IStatementParentEntity parent, int child) : base(cx, node, StmtKind.RETURN, parent, child) { } public static Return Create(Context cx, ReturnStatementSyntax node, IStatementParentEntity parent, int child) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Switch.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Switch.cs index 95c88ac7d280..f64067be9c4a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Switch.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Switch.cs @@ -5,20 +5,20 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { - class Switch : Statement + internal class Switch : Statement { - static readonly object NullLabel = new object(); - public static readonly object DefaultLabel = new object(); + private static readonly object nullLabel = new object(); + public static object DefaultLabel { get; } = new object(); // Sometimes, the literal "null" is used as a label. // This is inconveniently represented by the "null" object. // This cannot be stored in a Dictionary<>, so substitute an object which can be. public static object LabelForValue(object label) { - return label ?? NullLabel; + return label ?? nullLabel; } - Switch(Context cx, SwitchStatementSyntax node, IStatementParentEntity parent, int child) + private Switch(Context cx, SwitchStatementSyntax node, IStatementParentEntity parent, int child) : base(cx, node, StmtKind.SWITCH, parent, child) { } public static Switch Create(Context cx, SwitchStatementSyntax node, IStatementParentEntity parent, int child) @@ -31,7 +31,7 @@ public static Switch Create(Context cx, SwitchStatementSyntax node, IStatementPa protected override void PopulateStatement(TextWriter trapFile) { Expression.Create(cx, Stmt.Expression, this, 0); - int childIndex = 0; + var childIndex = 0; foreach (var section in Stmt.Sections) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Throw.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Throw.cs index cafc769cc883..c550b1f1e39a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Throw.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Throw.cs @@ -4,9 +4,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { - class Throw : Statement + internal class Throw : Statement { - Throw(Context cx, ThrowStatementSyntax node, IStatementParentEntity parent, int child) + private Throw(Context cx, ThrowStatementSyntax node, IStatementParentEntity parent, int child) : base(cx, node, StmtKind.THROW, parent, child) { } public static Throw Create(Context cx, ThrowStatementSyntax node, IStatementParentEntity parent, int child) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Try.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Try.cs index 2262b404011c..5a6937790c26 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Try.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Try.cs @@ -5,9 +5,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { - class Try : Statement + internal class Try : Statement { - Try(Context cx, TryStatementSyntax node, IStatementParentEntity parent, int child) + private Try(Context cx, TryStatementSyntax node, IStatementParentEntity parent, int child) : base(cx, node, StmtKind.TRY, parent, child) { } public static Try Create(Context cx, TryStatementSyntax node, IStatementParentEntity parent, int child) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Unchecked.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Unchecked.cs index 6151cae5d9ea..2d69bdc8d4cb 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Unchecked.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Unchecked.cs @@ -4,9 +4,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { - class Unchecked : Statement + internal class Unchecked : Statement { - Unchecked(Context cx, CheckedStatementSyntax stmt, IStatementParentEntity parent, int child) + private Unchecked(Context cx, CheckedStatementSyntax stmt, IStatementParentEntity parent, int child) : base(cx, stmt, StmtKind.UNCHECKED, parent, child) { } public static Unchecked Create(Context cx, CheckedStatementSyntax node, IStatementParentEntity parent, int child) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Unsafe.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Unsafe.cs index 1bd9ce48411e..4e371604333c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Unsafe.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Unsafe.cs @@ -4,9 +4,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { - class Unsafe : Statement + internal class Unsafe : Statement { - Unsafe(Context cx, UnsafeStatementSyntax node, IStatementParentEntity parent, int child) + private Unsafe(Context cx, UnsafeStatementSyntax node, IStatementParentEntity parent, int child) : base(cx, node, StmtKind.UNSAFE, parent, child) { } public static Unsafe Create(Context cx, UnsafeStatementSyntax node, IStatementParentEntity parent, int child) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Using.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Using.cs index b1aa2de2e764..93d0f6a88ff6 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Using.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Using.cs @@ -5,9 +5,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { - class Using : Statement + internal class Using : Statement { - Using(Context cx, UsingStatementSyntax node, IStatementParentEntity parent, int child) + private Using(Context cx, UsingStatementSyntax node, IStatementParentEntity parent, int child) : base(cx, node, StmtKind.USING, parent, child) { } public static Using Create(Context cx, UsingStatementSyntax node, IStatementParentEntity parent, int child) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/While.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/While.cs index 6fa739a45a2c..8def91a84182 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/While.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/While.cs @@ -4,9 +4,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { - class While : Statement + internal class While : Statement { - While(Context cx, WhileStatementSyntax node, IStatementParentEntity parent, int child) + private While(Context cx, WhileStatementSyntax node, IStatementParentEntity parent, int child) : base(cx, node, StmtKind.WHILE, parent, child) { } public static While Create(Context cx, WhileStatementSyntax node, IStatementParentEntity parent, int child) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Yield.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Yield.cs index 0e65c69ee34e..9aace8e0b834 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Yield.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Yield.cs @@ -4,9 +4,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { - class Yield : Statement + internal class Yield : Statement { - Yield(Context cx, YieldStatementSyntax node, IStatementParentEntity parent, int child) + private Yield(Context cx, YieldStatementSyntax node, IStatementParentEntity parent, int child) : base(cx, node, StmtKind.YIELD, parent, child) { } public static Yield Create(Context cx, YieldStatementSyntax node, IStatementParentEntity parent, int child) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Symbol.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Symbol.cs index 4f239083d24f..5e0850ba8c8d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Symbol.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Symbol.cs @@ -11,7 +11,7 @@ namespace Semmle.Extraction.CSharp.Entities { public abstract class CachedSymbol : CachedEntity where T : ISymbol { - public CachedSymbol(Context cx, T init) + protected CachedSymbol(Context cx, T init) : base(cx, init) { } public virtual Type ContainingType => symbol.ContainingType != null ? Type.Create(Context, symbol.ContainingType) : null; @@ -95,16 +95,16 @@ protected void BindComments() Context.BindComments(this, FullLocation); } + protected virtual T BodyDeclaringSymbol => symbol; + public BlockSyntax Block { get { - return symbol. - DeclaringSyntaxReferences. - Select(r => r.GetSyntax()). - SelectMany(n => n.ChildNodes()). - OfType(). - FirstOrDefault(); + return BodyDeclaringSymbol.DeclaringSyntaxReferences + .SelectMany(r => r.GetSyntax().ChildNodes()) + .OfType() + .FirstOrDefault(); } } @@ -112,12 +112,11 @@ public ExpressionSyntax ExpressionBody { get { - return symbol. - DeclaringSyntaxReferences. - SelectMany(r => r.GetSyntax().ChildNodes()). - OfType(). - Select(arrow => arrow.Expression). - FirstOrDefault(); + return BodyDeclaringSymbol.DeclaringSyntaxReferences + .SelectMany(r => r.GetSyntax().ChildNodes()) + .OfType() + .Select(arrow => arrow.Expression) + .FirstOrDefault(); } } @@ -135,16 +134,34 @@ protected void PopulateMetadataHandle(TextWriter trapFile) trapFile.metadata_handle(this, Location, MetadataTokens.GetToken(handle.Value)); } + private static System.Reflection.PropertyInfo GetPropertyInfo(object o, string name) + { + return o.GetType().GetProperty(name, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetProperty); + } + public Handle? MetadataHandle { get { - var propertyInfo = symbol.GetType().GetProperty("Handle", - System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetProperty); + var handleProp = GetPropertyInfo(symbol, "Handle"); + object handleObj = symbol; + + if (handleProp is null) + { + var underlyingSymbolProp = GetPropertyInfo(symbol, "UnderlyingSymbol"); + if (underlyingSymbolProp is object) + { + if (underlyingSymbolProp.GetValue(symbol) is object underlying) + { + handleProp = GetPropertyInfo(underlying, "Handle"); + handleObj = underlying; + } + } + } - if (propertyInfo != null) + if (handleProp is object) { - switch (propertyInfo.GetValue(symbol)) + switch (handleProp.GetValue(handleObj)) { case MethodDefinitionHandle md: return md; case TypeDefinitionHandle td: return td; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/TypeMention.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/TypeMention.cs index 69836af5ca26..b2f0419f8008 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/TypeMention.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/TypeMention.cs @@ -7,23 +7,23 @@ namespace Semmle.Extraction.CSharp.Entities { - class TypeMention : FreshEntity + internal class TypeMention : FreshEntity { - readonly TypeSyntax Syntax; - readonly IEntity Parent; - readonly Type Type; - readonly Microsoft.CodeAnalysis.Location Loc; + private readonly TypeSyntax syntax; + private readonly IEntity parent; + private readonly Type type; + private readonly Microsoft.CodeAnalysis.Location loc; - TypeMention(Context cx, TypeSyntax syntax, IEntity parent, Type type, Microsoft.CodeAnalysis.Location loc = null) + private TypeMention(Context cx, TypeSyntax syntax, IEntity parent, Type type, Microsoft.CodeAnalysis.Location loc = null) : base(cx) { - Syntax = syntax; - Parent = parent; - Type = type; - Loc = loc; + this.syntax = syntax; + this.parent = parent; + this.type = type; + this.loc = loc; } - static TypeSyntax GetElementType(TypeSyntax type) + private static TypeSyntax GetElementType(TypeSyntax type) { switch (type) { @@ -36,7 +36,7 @@ static TypeSyntax GetElementType(TypeSyntax type) } } - static Type GetElementType(Type type) + private static Type GetElementType(Type type) { switch (type) { @@ -51,62 +51,62 @@ static Type GetElementType(Type type) protected override void Populate(TextWriter trapFile) { - switch (Syntax.Kind()) + switch (syntax.Kind()) { case SyntaxKind.ArrayType: - Emit(trapFile, Loc ?? Syntax.GetLocation(), Parent, Type); - Create(cx, GetElementType(Syntax), this, GetElementType(Type)); + Emit(trapFile, loc ?? syntax.GetLocation(), parent, type); + Create(cx, GetElementType(syntax), this, GetElementType(type)); return; case SyntaxKind.NullableType: - var nts = (NullableTypeSyntax)Syntax; - if (Type is NamedType nt) + var nts = (NullableTypeSyntax)syntax; + if (type is NamedType nt) { - Emit(trapFile, Loc ?? Syntax.GetLocation(), Parent, Type); + Emit(trapFile, loc ?? syntax.GetLocation(), parent, type); Create(cx, nts.ElementType, this, nt.symbol.IsReferenceType ? nt : nt.TypeArguments[0]); } - else if(Type is ArrayType array) + else if (type is ArrayType array) { - Create(cx, nts.ElementType, Parent, array); + Create(cx, nts.ElementType, parent, array); } return; case SyntaxKind.TupleType: - var tts = (TupleTypeSyntax)Syntax; - var tt = (TupleType)Type; - Emit(trapFile, Loc ?? Syntax.GetLocation(), Parent, Type); + var tts = (TupleTypeSyntax)syntax; + var tt = (TupleType)type; + Emit(trapFile, loc ?? syntax.GetLocation(), parent, type); tts.Elements.Zip(tt.TupleElements, (s, t) => Create(cx, s.Type, this, t.Type)).Enumerate(); return; case SyntaxKind.PointerType: - var pts = (PointerTypeSyntax)Syntax; - var pt = (PointerType)Type; - Emit(trapFile, Loc ?? Syntax.GetLocation(), Parent, Type); + var pts = (PointerTypeSyntax)syntax; + var pt = (PointerType)type; + Emit(trapFile, loc ?? syntax.GetLocation(), parent, type); Create(cx, pts.ElementType, this, pt.PointedAtType); return; case SyntaxKind.GenericName: - var gns = (GenericNameSyntax)Syntax; - Emit(trapFile, Loc ?? gns.Identifier.GetLocation(), Parent, Type); - cx.PopulateLater(() => gns.TypeArgumentList.Arguments.Zip(Type.TypeMentions, (s, t) => Create(cx, s, this, t)).Enumerate()); + var gns = (GenericNameSyntax)syntax; + Emit(trapFile, loc ?? gns.Identifier.GetLocation(), parent, type); + cx.PopulateLater(() => gns.TypeArgumentList.Arguments.Zip(type.TypeMentions, (s, t) => Create(cx, s, this, t)).Enumerate()); return; case SyntaxKind.QualifiedName: - if (Type.ContainingType == null) + if (type.ContainingType == null) { // namespace qualifier - Emit(trapFile, Loc ?? Syntax.GetLocation(), Parent, Type); + Emit(trapFile, loc ?? syntax.GetLocation(), parent, type); } else { // Type qualifier - var qns = (QualifiedNameSyntax)Syntax; - var right = Create(cx, qns.Right, Parent, Type); - Create(cx, qns.Left, right, Type.ContainingType); + var qns = (QualifiedNameSyntax)syntax; + var right = Create(cx, qns.Right, parent, type); + Create(cx, qns.Left, right, type.ContainingType); } return; default: - Emit(trapFile, Loc ?? Syntax.GetLocation(), Parent, Type); + Emit(trapFile, loc ?? syntax.GetLocation(), parent, type); return; } } - void Emit(TextWriter trapFile, Microsoft.CodeAnalysis.Location loc, IEntity parent, Type type) + private void Emit(TextWriter trapFile, Microsoft.CodeAnalysis.Location loc, IEntity parent, Type type) { trapFile.type_mention(this, type.TypeRef, parent); trapFile.type_mention_location(this, cx.Create(loc)); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/ArrayType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/ArrayType.cs index c4a79a7764b0..2c617158219d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/ArrayType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/ArrayType.cs @@ -3,15 +3,15 @@ namespace Semmle.Extraction.CSharp.Entities { - class ArrayType : Type + internal class ArrayType : Type { - ArrayType(Context cx, IArrayTypeSymbol init) + private ArrayType(Context cx, IArrayTypeSymbol init) : base(cx, init) { element = Create(cx, symbol.GetAnnotatedElementType()); } - readonly AnnotatedType element; + private readonly AnnotatedType element; public int Rank => symbol.Rank; @@ -36,11 +36,11 @@ public override void WriteId(TextWriter trapFile) trapFile.Write(";type"); } - public static ArrayType Create(Context cx, IArrayTypeSymbol symbol) => ArrayTypeFactory.Instance.CreateEntity(cx, symbol); + public static ArrayType Create(Context cx, IArrayTypeSymbol symbol) => ArrayTypeFactory.Instance.CreateEntityFromSymbol(cx, symbol); - class ArrayTypeFactory : ICachedEntityFactory + private class ArrayTypeFactory : ICachedEntityFactory { - public static readonly ArrayTypeFactory Instance = new ArrayTypeFactory(); + public static ArrayTypeFactory Instance { get; } = new ArrayTypeFactory(); public ArrayType Create(Context cx, IArrayTypeSymbol init) => new ArrayType(cx, init); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/DynamicType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/DynamicType.cs index f5b6bf36c440..2516afe037bc 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/DynamicType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/DynamicType.cs @@ -4,12 +4,12 @@ namespace Semmle.Extraction.CSharp.Entities { - class DynamicType : Type + internal class DynamicType : Type { - DynamicType(Context cx, IDynamicTypeSymbol init) + private DynamicType(Context cx, IDynamicTypeSymbol init) : base(cx, init) { } - public static DynamicType Create(Context cx, IDynamicTypeSymbol type) => DynamicTypeFactory.Instance.CreateEntity(cx, type); + public static DynamicType Create(Context cx, IDynamicTypeSymbol type) => DynamicTypeFactory.Instance.CreateEntityFromSymbol(cx, type); public override Microsoft.CodeAnalysis.Location ReportingLocation => Context.Compilation.ObjectType.Locations.FirstOrDefault(); @@ -27,9 +27,9 @@ public override void WriteId(TextWriter trapFile) trapFile.Write("dynamic;type"); } - class DynamicTypeFactory : ICachedEntityFactory + private class DynamicTypeFactory : ICachedEntityFactory { - public static readonly DynamicTypeFactory Instance = new DynamicTypeFactory(); + public static DynamicTypeFactory Instance { get; } = new DynamicTypeFactory(); public DynamicType Create(Context cx, IDynamicTypeSymbol init) => new DynamicType(cx, init); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs index 93c13726750e..5812c4a93032 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs @@ -9,15 +9,26 @@ namespace Semmle.Extraction.CSharp.Entities { - class NamedType : Type + internal class NamedType : Type { - NamedType(Context cx, INamedTypeSymbol init) + private NamedType(Context cx, INamedTypeSymbol init, bool constructUnderlyingTupleType) : base(cx, init) { typeArgumentsLazy = new Lazy(() => symbol.TypeArguments.Select(t => Create(cx, t)).ToArray()); + this.constructUnderlyingTupleType = constructUnderlyingTupleType; } - public static NamedType Create(Context cx, INamedTypeSymbol type) => NamedTypeFactory.Instance.CreateEntity(cx, type); + public static NamedType Create(Context cx, INamedTypeSymbol type) => + NamedTypeFactory.Instance.CreateEntityFromSymbol(cx, type); + + /// + /// Creates a named type entity from a tuple type. Unlike `Create`, this + /// will create an entity for the underlying `System.ValueTuple` struct. + /// For example, `(int, string)` will result in an entity for + /// `System.ValueTuple`. + /// + public static NamedType CreateNamedTypeFromTupleType(Context cx, INamedTypeSymbol type) => + UnderlyingTupleTypeFactory.Instance.CreateEntity(cx, (new SymbolEqualityWrapper(type), typeof(TupleType)), type); public override bool NeedsPopulation => base.NeedsPopulation || symbol.TypeKind == TypeKind.Error; @@ -29,7 +40,8 @@ public override void Populate(TextWriter trapFile) return; } - trapFile.typeref_type((NamedTypeRef)TypeRef, this); + if (UsesTypeRef) + trapFile.typeref_type((NamedTypeRef)TypeRef, this); if (symbol.IsGenericType) { @@ -40,7 +52,7 @@ public override void Populate(TextWriter trapFile) } else if (symbol.IsReallyUnbound()) { - for (int i = 0; i < symbol.TypeParameters.Length; ++i) + for (var i = 0; i < symbol.TypeParameters.Length; ++i) { TypeParameter.Create(Context, symbol.TypeParameters[i]); var param = symbol.TypeParameters[i]; @@ -50,16 +62,19 @@ public override void Populate(TextWriter trapFile) } else { - trapFile.constructed_generic(this, Type.Create(Context, symbol.ConstructedFrom).TypeRef); + var unbound = constructUnderlyingTupleType + ? CreateNamedTypeFromTupleType(Context, symbol.ConstructedFrom) + : Type.Create(Context, symbol.ConstructedFrom); + trapFile.constructed_generic(this, unbound.TypeRef); - for (int i = 0; i < symbol.TypeArguments.Length; ++i) + for (var i = 0; i < symbol.TypeArguments.Length; ++i) { trapFile.type_arguments(TypeArguments[i].TypeRef, i, this); } } } - PopulateType(trapFile); + PopulateType(trapFile, constructUnderlyingTupleType); if (symbol.EnumUnderlyingType != null) { @@ -74,7 +89,9 @@ public override void Populate(TextWriter trapFile) } } - readonly Lazy typeArgumentsLazy; + private readonly Lazy typeArgumentsLazy; + private readonly bool constructUnderlyingTupleType; + public Type[] TypeArguments => typeArgumentsLazy.Value; public override IEnumerable TypeMentions => TypeArguments; @@ -91,25 +108,40 @@ public override IEnumerable Locations } } - static IEnumerable GetLocations(INamedTypeSymbol type) + private static IEnumerable GetLocations(INamedTypeSymbol type) { - return type.Locations. - Where(l => l.IsInMetadata). - Concat( - type. - DeclaringSyntaxReferences. - Select(loc => loc.GetSyntax()). - OfType(). - Select(l => l.FixedLocation()) + return type.Locations + .Where(l => l.IsInMetadata) + .Concat(type.DeclaringSyntaxReferences + .Select(loc => loc.GetSyntax()) + .OfType() + .Select(l => l.FixedLocation()) ); } public override Microsoft.CodeAnalysis.Location ReportingLocation => GetLocations(symbol).FirstOrDefault(); + private bool IsAnonymousType() => symbol.IsAnonymousType || symbol.Name.Contains("__AnonymousType"); + public override void WriteId(TextWriter trapFile) { - symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub))); - trapFile.Write(";type"); + if (IsAnonymousType()) + { + trapFile.Write('*'); + } + else + { + symbol.BuildTypeId(Context, trapFile, symbol, constructUnderlyingTupleType); + trapFile.Write(";type"); + } + } + + public override void WriteQuotedId(TextWriter trapFile) + { + if (IsAnonymousType()) + trapFile.Write('*'); + else + base.WriteQuotedId(trapFile); } /// @@ -118,42 +150,56 @@ public override void WriteId(TextWriter trapFile) /// Extraction context. /// The enumerable type. /// The element type, or null. - static AnnotatedTypeSymbol GetElementType(Context cx, INamedTypeSymbol type) + private static AnnotatedTypeSymbol GetElementType(Context cx, INamedTypeSymbol type) { var et = GetEnumerableType(cx, type); - if (et.Symbol != null) return et; - - return type.AllInterfaces. - Where(i => i.OriginalDefinition.SpecialType == SpecialType.System_Collections_Generic_IEnumerable_T). - Concat(type.AllInterfaces.Where(i => i.SpecialType == SpecialType.System_Collections_IEnumerable)). - Select(i => GetEnumerableType(cx, i)). - FirstOrDefault(); + if (et.Symbol != null) + return et; + + return type.AllInterfaces + .Where(i => i.OriginalDefinition.SpecialType == SpecialType.System_Collections_Generic_IEnumerable_T) + .Concat(type.AllInterfaces.Where(i => i.SpecialType == SpecialType.System_Collections_IEnumerable)) + .Select(i => GetEnumerableType(cx, i)) + .FirstOrDefault(); } - static AnnotatedTypeSymbol GetEnumerableType(Context cx, INamedTypeSymbol type) + private static AnnotatedTypeSymbol GetEnumerableType(Context cx, INamedTypeSymbol type) { - return type.SpecialType == SpecialType.System_Collections_IEnumerable ? - cx.Compilation.ObjectType.WithAnnotation(NullableAnnotation.NotAnnotated) : - type.OriginalDefinition.SpecialType == SpecialType.System_Collections_Generic_IEnumerable_T ? - type.GetAnnotatedTypeArguments().First() : - default(AnnotatedTypeSymbol); + return type.SpecialType == SpecialType.System_Collections_IEnumerable + ? cx.Compilation.ObjectType.WithAnnotation(NullableAnnotation.NotAnnotated) + : type.OriginalDefinition.SpecialType == SpecialType.System_Collections_Generic_IEnumerable_T + ? type.GetAnnotatedTypeArguments().First() + : default(AnnotatedTypeSymbol); } public override AnnotatedType ElementType => Type.Create(Context, GetElementType(Context, symbol)); - class NamedTypeFactory : ICachedEntityFactory + private class NamedTypeFactory : ICachedEntityFactory { - public static readonly NamedTypeFactory Instance = new NamedTypeFactory(); + public static NamedTypeFactory Instance { get; } = new NamedTypeFactory(); - public NamedType Create(Context cx, INamedTypeSymbol init) => new NamedType(cx, init); + public NamedType Create(Context cx, INamedTypeSymbol init) => new NamedType(cx, init, false); } - public override Type TypeRef => NamedTypeRef.Create(Context, symbol); + private class UnderlyingTupleTypeFactory : ICachedEntityFactory + { + public static UnderlyingTupleTypeFactory Instance { get; } = new UnderlyingTupleTypeFactory(); + + public NamedType Create(Context cx, INamedTypeSymbol init) => new NamedType(cx, init, true); + } + + // Do not create typerefs of constructed generics as they are always in the current trap file. + // Create typerefs for constructed error types in case they are fully defined elsewhere. + // We cannot use `!this.NeedsPopulation` because this would not be stable as it would depend on + // the assembly that was being extracted at the time. + private bool UsesTypeRef => symbol.TypeKind == TypeKind.Error || SymbolEqualityComparer.Default.Equals(symbol.OriginalDefinition, symbol); + + public override Type TypeRef => UsesTypeRef ? (Type)NamedTypeRef.Create(Context, symbol) : this; } - class NamedTypeRef : Type + internal class NamedTypeRef : Type { - readonly Type referencedType; + private readonly Type referencedType; public NamedTypeRef(Context cx, INamedTypeSymbol symbol) : base(cx, symbol) { @@ -161,11 +207,13 @@ public NamedTypeRef(Context cx, INamedTypeSymbol symbol) : base(cx, symbol) } public static NamedTypeRef Create(Context cx, INamedTypeSymbol type) => - NamedTypeRefFactory.Instance.CreateEntity2(cx, type); + // We need to use a different cache key than `type` to avoid mixing up + // `NamedType`s and `NamedTypeRef`s + NamedTypeRefFactory.Instance.CreateEntity(cx, (typeof(NamedTypeRef), new SymbolEqualityWrapper(type)), type); - class NamedTypeRefFactory : ICachedEntityFactory + private class NamedTypeRefFactory : ICachedEntityFactory { - public static readonly NamedTypeRefFactory Instance = new NamedTypeRefFactory(); + public static NamedTypeRefFactory Instance { get; } = new NamedTypeRefFactory(); public NamedTypeRef Create(Context cx, INamedTypeSymbol init) => new NamedTypeRef(cx, init); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NullType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NullType.cs index 7ef079b932e4..2822e346384f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NullType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NullType.cs @@ -3,9 +3,9 @@ namespace Semmle.Extraction.CSharp.Entities { - class NullType : Type + internal class NullType : Type { - NullType(Context cx) + private NullType(Context cx) : base(cx, null) { } public override void Populate(TextWriter trapFile) @@ -27,11 +27,11 @@ public override bool Equals(object obj) return obj != null && obj.GetType() == typeof(NullType); } - public static AnnotatedType Create(Context cx) => new AnnotatedType(NullTypeFactory.Instance.CreateNullableEntity(cx, null), NullableAnnotation.None); + public static AnnotatedType Create(Context cx) => new AnnotatedType(NullTypeFactory.Instance.CreateEntity(cx, typeof(NullType), null), NullableAnnotation.None); - class NullTypeFactory : ICachedEntityFactory + private class NullTypeFactory : ICachedEntityFactory { - public static readonly NullTypeFactory Instance = new NullTypeFactory(); + public static NullTypeFactory Instance { get; } = new NullTypeFactory(); public NullType Create(Context cx, ITypeSymbol init) => new NullType(cx); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs index 05a4300133a4..106efdd0cde4 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs @@ -9,8 +9,8 @@ public sealed class Nullability { public int Annotation { get; } - static readonly Nullability[] EmptyArray = new Nullability[0]; - public readonly Nullability[] NullableParameters; + private static readonly Nullability[] emptyArray = System.Array.Empty(); + public IEnumerable NullableParameters { get; } public static Nullability Create(AnnotatedTypeSymbol ts) { @@ -30,11 +30,11 @@ public static Nullability Create(AnnotatedTypeSymbol ts) return new Nullability(ts); } - public bool IsOblivious => Annotation == 0 && NullableParameters.Length == 0; + public bool IsOblivious => Annotation == 0 && !NullableParameters.Any(); - static readonly Nullability oblivious = new Nullability(NullableAnnotation.None); - static readonly Nullability annotated = new Nullability(NullableAnnotation.Annotated); - static readonly Nullability notannotated = new Nullability(NullableAnnotation.NotAnnotated); + private static readonly Nullability oblivious = new Nullability(NullableAnnotation.None); + private static readonly Nullability annotated = new Nullability(NullableAnnotation.Annotated); + private static readonly Nullability notannotated = new Nullability(NullableAnnotation.NotAnnotated); private Nullability(NullableAnnotation n) { @@ -50,12 +50,12 @@ private Nullability(NullableAnnotation n) Annotation = 0; break; } - NullableParameters = EmptyArray; + NullableParameters = emptyArray; } private Nullability(AnnotatedTypeSymbol ts) : this(ts.Nullability) { - NullableParameters = ts.HasConsistentNullability() ? EmptyArray : ts.GetAnnotatedTypeArguments().Select(Create).ToArray(); + NullableParameters = ts.HasConsistentNullability() ? emptyArray : ts.GetAnnotatedTypeArguments().Select(Create).ToArray(); } public Nullability(IMethodSymbol method) @@ -71,7 +71,7 @@ public override bool Equals(object other) public override int GetHashCode() { - int h = Annotation; + var h = Annotation; foreach (var t in NullableParameters) h = h * 5 + t.GetHashCode(); @@ -90,11 +90,9 @@ public void WriteId(TextWriter trapFile) public override string ToString() { - using (var w = new StringWriter()) - { - WriteId(w); - return w.ToString(); - } + using var w = new StringWriter(); + WriteId(w); + return w.ToString(); } } @@ -114,7 +112,7 @@ public override void Populate(TextWriter trapFile) { trapFile.nullability(this, symbol.Annotation); - int i = 0; + var i = 0; foreach (var s in symbol.NullableParameters) { trapFile.nullability_parent(Create(Context, s), i, this); @@ -127,11 +125,11 @@ public override void WriteId(TextWriter trapFile) symbol.WriteId(trapFile); } - public static NullabilityEntity Create(Context cx, Nullability init) => NullabilityFactory.Instance.CreateEntity(cx, init); + public static NullabilityEntity Create(Context cx, Nullability init) => NullabilityFactory.Instance.CreateEntity(cx, init, init); - class NullabilityFactory : ICachedEntityFactory + private class NullabilityFactory : ICachedEntityFactory { - public static readonly NullabilityFactory Instance = new NullabilityFactory(); + public static NullabilityFactory Instance { get; } = new NullabilityFactory(); public NullabilityEntity Create(Context cx, Nullability init) => new NullabilityEntity(cx, init); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/PointerType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/PointerType.cs index db8b5ff8c23b..e2fbb8677cc8 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/PointerType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/PointerType.cs @@ -3,9 +3,9 @@ namespace Semmle.Extraction.CSharp.Entities { - class PointerType : Type + internal class PointerType : Type { - PointerType(Context cx, IPointerTypeSymbol init) + private PointerType(Context cx, IPointerTypeSymbol init) : base(cx, init) { PointedAtType = Create(cx, symbol.PointedAtType); @@ -29,11 +29,11 @@ public override void Populate(TextWriter trapFile) public Type PointedAtType { get; private set; } - public static PointerType Create(Context cx, IPointerTypeSymbol symbol) => PointerTypeFactory.Instance.CreateEntity(cx, symbol); + public static PointerType Create(Context cx, IPointerTypeSymbol symbol) => PointerTypeFactory.Instance.CreateEntityFromSymbol(cx, symbol); - class PointerTypeFactory : ICachedEntityFactory + private class PointerTypeFactory : ICachedEntityFactory { - public static readonly PointerTypeFactory Instance = new PointerTypeFactory(); + public static PointerTypeFactory Instance { get; } = new PointerTypeFactory(); public PointerType Create(Context cx, IPointerTypeSymbol init) => new PointerType(cx, init); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs index de6ea2170849..af9c4bf4fa64 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs @@ -11,18 +11,18 @@ namespace Semmle.Extraction.CSharp.Entities /// A tuple type, which is a C# type but not a .Net type. /// Tuples have the underlying type System.ValueTuple. /// - class TupleType : Type + internal class TupleType : Type { - public static TupleType Create(Context cx, INamedTypeSymbol type) => TupleTypeFactory.Instance.CreateEntity(cx, type); + public static TupleType Create(Context cx, INamedTypeSymbol type) => TupleTypeFactory.Instance.CreateEntityFromSymbol(cx, type); - class TupleTypeFactory : ICachedEntityFactory + private class TupleTypeFactory : ICachedEntityFactory { - public static readonly TupleTypeFactory Instance = new TupleTypeFactory(); + public static TupleTypeFactory Instance { get; } = new TupleTypeFactory(); public TupleType Create(Context cx, INamedTypeSymbol init) => new TupleType(cx, init); } - TupleType(Context cx, INamedTypeSymbol init) : base(cx, init) + private TupleType(Context cx, INamedTypeSymbol init) : base(cx, init) { tupleElementsLazy = new Lazy(() => symbol.TupleElements.Select(t => Field.Create(cx, t)).ToArray()); } @@ -32,7 +32,7 @@ class TupleTypeFactory : ICachedEntityFactory public override void WriteId(TextWriter trapFile) { - symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub))); + symbol.BuildTypeId(Context, trapFile, symbol); trapFile.Write(";tuple"); } @@ -41,10 +41,11 @@ public override void Populate(TextWriter trapFile) PopulateType(trapFile); PopulateGenerics(); - var underlyingType = NamedType.Create(Context, symbol.TupleUnderlyingType); + var underlyingType = NamedType.CreateNamedTypeFromTupleType(Context, symbol.TupleUnderlyingType ?? symbol); + trapFile.tuple_underlying_type(this, underlyingType); - int index = 0; + var index = 0; foreach (var element in TupleElements) trapFile.tuple_element(this, index++, element); @@ -55,7 +56,7 @@ public override void Populate(TextWriter trapFile) trapFile.type_location(this, Context.Create(l)); } - readonly Lazy tupleElementsLazy; + private readonly Lazy tupleElementsLazy; public Field[] TupleElements => tupleElementsLazy.Value; public override IEnumerable TypeMentions => TupleElements.Select(e => e.Type.Type); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs index 7d9f5e3651e8..1b1d205b3d72 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs @@ -21,9 +21,9 @@ public AnnotatedType(Type t, NullableAnnotation n) /// /// The underlying type. /// - public Type Type; + public Type Type { get; private set; } - readonly private NullableAnnotation annotation; + private readonly NullableAnnotation annotation; /// /// Gets the annotated type symbol of this annotated type. @@ -33,7 +33,7 @@ public AnnotatedType(Type t, NullableAnnotation n) public abstract class Type : CachedSymbol { - public Type(Context cx, ITypeSymbol init) + protected Type(Context cx, ITypeSymbol init) : base(cx, init) { } public virtual AnnotatedType ElementType => default(AnnotatedType); @@ -47,7 +47,7 @@ public static bool ConstructedOrParentIsConstructed(INamedTypeSymbol symbol) symbol.ContainingType != null && ConstructedOrParentIsConstructed(symbol.ContainingType); } - static Kinds.TypeKind GetClassType(Context cx, ITypeSymbol t) + private static Kinds.TypeKind GetClassType(Context cx, ITypeSymbol t, bool constructUnderlyingTupleType) { switch (t.SpecialType) { @@ -67,17 +67,22 @@ static Kinds.TypeKind GetClassType(Context cx, ITypeSymbol t) case SpecialType.System_Single: return Kinds.TypeKind.FLOAT; case SpecialType.System_IntPtr: return Kinds.TypeKind.INT_PTR; default: - if (t.IsBoundNullable()) return Kinds.TypeKind.NULLABLE; + if (t.IsBoundNullable()) + return Kinds.TypeKind.NULLABLE; + switch (t.TypeKind) { case TypeKind.Class: return Kinds.TypeKind.CLASS; case TypeKind.Struct: - return ((INamedTypeSymbol)t).IsTupleType ? Kinds.TypeKind.TUPLE : Kinds.TypeKind.STRUCT; + return ((INamedTypeSymbol)t).IsTupleType && !constructUnderlyingTupleType + ? Kinds.TypeKind.TUPLE + : Kinds.TypeKind.STRUCT; case TypeKind.Interface: return Kinds.TypeKind.INTERFACE; case TypeKind.Array: return Kinds.TypeKind.ARRAY; case TypeKind.Enum: return Kinds.TypeKind.ENUM; case TypeKind.Delegate: return Kinds.TypeKind.DELEGATE; case TypeKind.Pointer: return Kinds.TypeKind.POINTER; + case TypeKind.Error: return Kinds.TypeKind.UNKNOWN; default: cx.ModelError(t, $"Unhandled type kind '{t.TypeKind}'"); return Kinds.TypeKind.UNKNOWN; @@ -85,7 +90,7 @@ static Kinds.TypeKind GetClassType(Context cx, ITypeSymbol t) } } - protected void PopulateType(TextWriter trapFile) + protected void PopulateType(TextWriter trapFile, bool constructUnderlyingTupleType = false) { PopulateMetadataHandle(trapFile); PopulateAttributes(); @@ -93,26 +98,21 @@ protected void PopulateType(TextWriter trapFile) trapFile.Write("types("); trapFile.WriteColumn(this); trapFile.Write(','); - trapFile.WriteColumn((int)GetClassType(Context, symbol)); + trapFile.WriteColumn((int)GetClassType(Context, symbol, constructUnderlyingTupleType)); trapFile.Write(",\""); - symbol.BuildDisplayName(Context, trapFile); + symbol.BuildDisplayName(Context, trapFile, constructUnderlyingTupleType); trapFile.WriteLine("\")"); // Visit base types var baseTypes = new List(); - if (symbol.BaseType != null) + if (symbol.GetNonObjectBaseType(Context) is INamedTypeSymbol @base) { - Type baseKey = Create(Context, symbol.BaseType); + var baseKey = Create(Context, @base); trapFile.extend(this, baseKey.TypeRef); if (symbol.TypeKind != TypeKind.Struct) baseTypes.Add(baseKey); } - if (symbol.TypeKind == TypeKind.Interface) - { - trapFile.extend(this, Create(Context, Context.Compilation.ObjectType)); - } - if (!(base.symbol is IArrayTypeSymbol)) { foreach (var t in base.symbol.Interfaces.Select(i => Create(Context, i))) @@ -125,7 +125,7 @@ protected void PopulateType(TextWriter trapFile) var containingType = ContainingType; if (containingType != null && symbol.Kind != SymbolKind.TypeParameter) { - Type originalDefinition = symbol.TypeKind == TypeKind.Error ? this : Create(Context, symbol.OriginalDefinition); + var originalDefinition = symbol.TypeKind == TypeKind.Error ? this : Create(Context, symbol.OriginalDefinition); trapFile.nested_types(this, containingType, originalDefinition); } else if (symbol.ContainingNamespace != null) @@ -133,19 +133,19 @@ protected void PopulateType(TextWriter trapFile) trapFile.parent_namespace(this, Namespace.Create(Context, symbol.ContainingNamespace)); } - if (symbol is IArrayTypeSymbol) + if (symbol is IArrayTypeSymbol array) { // They are in the namespace of the original object - ITypeSymbol elementType = ((IArrayTypeSymbol)symbol).ElementType; - INamespaceSymbol ns = elementType.TypeKind == TypeKind.TypeParameter ? Context.Compilation.GlobalNamespace : elementType.ContainingNamespace; + var elementType = array.ElementType; + var ns = elementType.TypeKind == TypeKind.TypeParameter ? Context.Compilation.GlobalNamespace : elementType.ContainingNamespace; if (ns != null) trapFile.parent_namespace(this, Namespace.Create(Context, ns)); } - if (symbol is IPointerTypeSymbol) + if (symbol is IPointerTypeSymbol pointer) { - ITypeSymbol elementType = ((IPointerTypeSymbol)symbol).PointedAtType; - INamespaceSymbol ns = elementType.TypeKind == TypeKind.TypeParameter ? Context.Compilation.GlobalNamespace : elementType.ContainingNamespace; + var elementType = pointer.PointedAtType; + var ns = elementType.TypeKind == TypeKind.TypeParameter ? Context.Compilation.GlobalNamespace : elementType.ContainingNamespace; if (ns != null) trapFile.parent_namespace(this, Namespace.Create(Context, ns)); @@ -185,12 +185,13 @@ protected void PopulateType(TextWriter trapFile) baseLists = baseLists.Concat(declSyntaxReferences.OfType().Select(c => c.BaseList)); baseLists = baseLists.Concat(declSyntaxReferences.OfType().Select(c => c.BaseList)); - baseLists. - Where(bl => bl != null). - SelectMany(bl => bl.Types). - Zip(baseTypes.Where(bt => bt.symbol.SpecialType != SpecialType.System_Object), - (s, t) => TypeMention.Create(Context, s.Type, this, t)). - Enumerate(); + baseLists + .Where(bl => bl != null) + .SelectMany(bl => bl.Types) + .Zip( + baseTypes.Where(bt => bt.symbol.SpecialType != SpecialType.System_Object), + (s, t) => TypeMention.Create(Context, s.Type, this, t)) + .Enumerate(); } } @@ -275,9 +276,9 @@ public void ExtractRecursive(TextWriter trapFile, IEntity parent) public static Type Create(Context cx, ITypeSymbol type) { type = type.DisambiguateType(); - const bool errorTypeIsNull = false; - return type == null || (errorTypeIsNull && type.TypeKind == TypeKind.Error) ? - NullType.Create(cx).Type : (Type)cx.CreateEntity(type); + return type == null + ? NullType.Create(cx).Type + : (Type)cx.CreateEntity(type); } public static AnnotatedType Create(Context cx, AnnotatedTypeSymbol type) => @@ -292,17 +293,19 @@ public static bool IsDelegate(ITypeSymbol symbol) => /// A copy of a delegate "Invoke" method parameter used for the delgate /// type. /// - class DelegateTypeParameter : Parameter + private class DelegateTypeParameter : Parameter { - DelegateTypeParameter(Context cx, IParameterSymbol init, IEntity parent, Parameter original) + private DelegateTypeParameter(Context cx, IParameterSymbol init, IEntity parent, Parameter original) : base(cx, init, parent, original) { } - new public static DelegateTypeParameter Create(Context cx, IParameterSymbol param, IEntity parent, Parameter original = null) => - DelegateTypeParameterFactory.Instance.CreateEntity(cx, (param, parent, original)); + public static new DelegateTypeParameter Create(Context cx, IParameterSymbol param, IEntity parent, Parameter original = null) => + // We need to use a different cache key than `param` to avoid mixing up + // `DelegateTypeParameter`s and `Parameter`s + DelegateTypeParameterFactory.Instance.CreateEntity(cx, (typeof(DelegateTypeParameter), new SymbolEqualityWrapper(param)), (param, parent, original)); - class DelegateTypeParameterFactory : ICachedEntityFactory<(IParameterSymbol, IEntity, Parameter), DelegateTypeParameter> + private class DelegateTypeParameterFactory : ICachedEntityFactory<(IParameterSymbol, IEntity, Parameter), DelegateTypeParameter> { - public static readonly DelegateTypeParameterFactory Instance = new DelegateTypeParameterFactory(); + public static DelegateTypeParameterFactory Instance { get; } = new DelegateTypeParameterFactory(); public DelegateTypeParameter Create(Context cx, (IParameterSymbol, IEntity, Parameter) init) => new DelegateTypeParameter(cx, init.Item1, init.Item2, init.Item3); @@ -324,11 +327,19 @@ public virtual IEnumerable TypeMentions } public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; + + public override bool Equals(object obj) + { + var other = obj as Type; + return other?.GetType() == GetType() && SymbolEqualityComparer.IncludeNullability.Equals(other.symbol, symbol); + } + + public override int GetHashCode() => SymbolEqualityComparer.IncludeNullability.GetHashCode(symbol); } - abstract class Type : Type where T : ITypeSymbol + internal abstract class Type : Type where T : ITypeSymbol { - public Type(Context cx, T init) + protected Type(Context cx, T init) : base(cx, init) { } public new T symbol => (T)base.symbol; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs index 2fdb8cd3a834..b4d35f7b5067 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs @@ -7,20 +7,18 @@ namespace Semmle.Extraction.CSharp.Entities { - enum Variance + internal enum Variance { None = 0, Out = 1, In = 2 } - class TypeParameter : Type + internal class TypeParameter : Type { - TypeParameter(Context cx, ITypeParameterSymbol init) + private TypeParameter(Context cx, ITypeParameterSymbol init) : base(cx, init) { } - static readonly string valueTypeName = typeof(System.ValueType).ToString(); - public override void Populate(TextWriter trapFile) { var constraints = new TypeParameterConstraints(Context); @@ -35,20 +33,14 @@ public override void Populate(TextWriter trapFile) if (symbol.HasConstructorConstraint) trapFile.general_type_parameter_constraints(constraints, 3); - if(symbol.HasUnmanagedTypeConstraint) + if (symbol.HasUnmanagedTypeConstraint) trapFile.general_type_parameter_constraints(constraints, 4); - ITypeSymbol baseType = symbol.HasValueTypeConstraint ? - Context.Compilation.GetTypeByMetadataName(valueTypeName) : - Context.Compilation.ObjectType; - - if(symbol.ReferenceTypeConstraintNullableAnnotation == NullableAnnotation.Annotated) + if (symbol.ReferenceTypeConstraintNullableAnnotation == NullableAnnotation.Annotated) trapFile.general_type_parameter_constraints(constraints, 5); foreach (var abase in symbol.GetAnnotatedTypeConstraints()) { - if (abase.Symbol.TypeKind != TypeKind.Interface) - baseType = abase.Symbol; var t = Create(Context, abase.Symbol); trapFile.specific_type_parameter_constraints(constraints, t.TypeRef); if (!abase.HasObliviousNullability()) @@ -56,9 +48,8 @@ public override void Populate(TextWriter trapFile) } trapFile.types(this, Kinds.TypeKind.TYPE_PARAMETER, symbol.Name); - trapFile.extend(this, Create(Context, baseType).TypeRef); - Namespace parentNs = Namespace.Create(Context, symbol.TypeParameterKind == TypeParameterKind.Method ? Context.Compilation.GlobalNamespace : symbol.ContainingNamespace); + var parentNs = Namespace.Create(Context, symbol.TypeParameterKind == TypeParameterKind.Method ? Context.Compilation.GlobalNamespace : symbol.ContainingNamespace); trapFile.parent_namespace(this, parentNs); foreach (var l in symbol.Locations) @@ -68,8 +59,12 @@ public override void Populate(TextWriter trapFile) if (IsSourceDeclaration) { - var declSyntaxReferences = symbol.DeclaringSyntaxReferences.Select(d => d.GetSyntax()). - Select(s => s.Parent).Where(p => p != null).Select(p => p.Parent).ToArray(); + var declSyntaxReferences = symbol.DeclaringSyntaxReferences + .Select(d => d.GetSyntax()) + .Select(s => s.Parent) + .Where(p => p != null) + .Select(p => p.Parent) + .ToArray(); var clauses = declSyntaxReferences.OfType().SelectMany(m => m.ConstraintClauses); clauses = clauses.Concat(declSyntaxReferences.OfType().SelectMany(c => c.ConstraintClauses)); clauses = clauses.Concat(declSyntaxReferences.OfType().SelectMany(c => c.ConstraintClauses)); @@ -87,8 +82,8 @@ public override void Populate(TextWriter trapFile) } } - static public TypeParameter Create(Context cx, ITypeParameterSymbol p) => - TypeParameterFactory.Instance.CreateEntity(cx, p); + public static TypeParameter Create(Context cx, ITypeParameterSymbol p) => + TypeParameterFactory.Instance.CreateEntityFromSymbol(cx, p); /// /// The variance of this type parameter. @@ -132,9 +127,9 @@ public override void WriteId(TextWriter trapFile) trapFile.Write(kind); } - class TypeParameterFactory : ICachedEntityFactory + private class TypeParameterFactory : ICachedEntityFactory { - public static readonly TypeParameterFactory Instance = new TypeParameterFactory(); + public static TypeParameterFactory Instance { get; } = new TypeParameterFactory(); public TypeParameter Create(Context cx, ITypeParameterSymbol init) => new TypeParameter(cx, init); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameterConstraints.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameterConstraints.cs index 8d70741a70a3..04ab78a0f547 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameterConstraints.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameterConstraints.cs @@ -2,7 +2,7 @@ namespace Semmle.Extraction.CSharp.Entities { - class TypeParameterConstraints : FreshEntity + internal class TypeParameterConstraints : FreshEntity { public TypeParameterConstraints(Context cx) : base(cx) { } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs index 2a64a29fa0d2..d4c6fa457c1f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs @@ -5,7 +5,7 @@ namespace Semmle.Extraction.CSharp.Entities { - class UserOperator : Method + internal class UserOperator : Method { protected UserOperator(Context cx, IMethodSymbol init) : base(cx, init) { } @@ -49,26 +49,20 @@ public override Type ContainingType } } - public override void WriteId(TextWriter trapFile) - { - AddSignatureTypeToId(Context, trapFile, symbol, symbol.ReturnType); // Needed for op_explicit(), which differs only by return type. - trapFile.Write(' '); - BuildMethodId(this, trapFile); - } - /// /// For some reason, some operators are missing from the Roslyn database of mscorlib. /// This method returns true for such operators. /// /// The type containing this operator. /// - bool IsImplicitOperator(out ITypeSymbol containingType) + private bool IsImplicitOperator(out ITypeSymbol containingType) { containingType = symbol.ContainingType; if (containingType != null) { var containingNamedType = containingType as INamedTypeSymbol; - return containingNamedType == null || !containingNamedType.MemberNames.Contains(symbol.Name); + return containingNamedType == null || + !containingNamedType.GetMembers(symbol.Name).Contains(symbol); } var pointerType = symbol.Parameters.Select(p => p.Type).OfType().FirstOrDefault(); @@ -184,17 +178,16 @@ public static bool OperatorSymbol(string methodName, out string operatorName) /// The converted name. public static string OperatorSymbol(Context cx, string methodName) { - string result; - if (!OperatorSymbol(methodName, out result)) + if (!OperatorSymbol(methodName, out var result)) cx.ModelError($"Unhandled operator name in OperatorSymbol(): '{methodName}'"); return result; } - public new static UserOperator Create(Context cx, IMethodSymbol symbol) => UserOperatorFactory.Instance.CreateEntity(cx, symbol); + public static new UserOperator Create(Context cx, IMethodSymbol symbol) => UserOperatorFactory.Instance.CreateEntityFromSymbol(cx, symbol); - class UserOperatorFactory : ICachedEntityFactory + private class UserOperatorFactory : ICachedEntityFactory { - public static readonly UserOperatorFactory Instance = new UserOperatorFactory(); + public static UserOperatorFactory Instance { get; } = new UserOperatorFactory(); public UserOperator Create(Context cx, IMethodSymbol init) => new UserOperator(cx, init); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UsingDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UsingDirective.cs index 02b67efc1642..caa12ab0082f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UsingDirective.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UsingDirective.cs @@ -1,68 +1,59 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Semmle.Extraction.CSharp.Populators; using Semmle.Extraction.Entities; -using System.Collections.Generic; using System.IO; namespace Semmle.Extraction.CSharp.Entities { - class UsingDirective : FreshEntity + internal class UsingDirective : FreshEntity { - readonly UsingDirectiveSyntax Node; - readonly NamespaceDeclaration Parent; + private readonly UsingDirectiveSyntax node; + private readonly NamespaceDeclaration parent; public UsingDirective(Context cx, UsingDirectiveSyntax usingDirective, NamespaceDeclaration parent) : base(cx) { - Node = usingDirective; - Parent = parent; + node = usingDirective; + this.parent = parent; TryPopulate(); } protected override void Populate(TextWriter trapFile) { - var info = cx.GetModel(Node).GetSymbolInfo(Node.Name); + var info = cx.GetModel(node).GetSymbolInfo(node.Name); - if (Node.StaticKeyword.Kind() == SyntaxKind.None) + if (node.StaticKeyword.Kind() == SyntaxKind.None) { // A normal using - var namespaceSymbol = info.Symbol as INamespaceSymbol; - - if (namespaceSymbol == null) - { - cx.Extractor.MissingNamespace(Node.Name.ToFullString(), cx.FromSource); - cx.ModelError(Node, "Namespace not found"); - return; - } - else + if (info.Symbol is INamespaceSymbol namespaceSymbol) { var ns = Namespace.Create(cx, namespaceSymbol); trapFile.using_namespace_directives(this, ns); trapFile.using_directive_location(this, cx.Create(ReportingLocation)); } + else + { + cx.Extractor.MissingNamespace(node.Name.ToFullString(), cx.FromSource); + cx.ModelError(node, "Namespace not found"); + return; + } } else { // A "using static" - Type m = Type.Create(cx, (ITypeSymbol)info.Symbol); + var m = Type.Create(cx, (ITypeSymbol)info.Symbol); trapFile.using_static_directives(this, m.TypeRef); trapFile.using_directive_location(this, cx.Create(ReportingLocation)); } - if (Parent != null) + if (parent != null) { - trapFile.parent_namespace_declaration(this, Parent); + trapFile.parent_namespace_declaration(this, parent); } } - public sealed override Microsoft.CodeAnalysis.Location ReportingLocation => Node.GetLocation(); - - public IEnumerable GetTuples() - { - yield break; - } + public sealed override Microsoft.CodeAnalysis.Location ReportingLocation => node.GetLocation(); public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Extractor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor.cs index 7ca12e00f26b..cf991e0930a4 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Extractor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor.cs @@ -23,21 +23,25 @@ public enum ExitCode Failed // Trap could not be generated } - class LogProgressMonitor : IProgressMonitor + private class LogProgressMonitor : IProgressMonitor { - readonly ILogger Logger; + private readonly ILogger logger; public LogProgressMonitor(ILogger logger) { - Logger = logger; + this.logger = logger; } public void Analysed(int item, int total, string source, string output, TimeSpan time, AnalysisAction action) { if (action != AnalysisAction.UpToDate) { - Logger.Log(Severity.Info, " {0} ({1})", source, - action == AnalysisAction.Extracted ? time.ToString() : action == AnalysisAction.Excluded ? "excluded" : "up to date"); + logger.Log(Severity.Info, " {0} ({1})", source, + action == AnalysisAction.Extracted + ? time.ToString() + : action == AnalysisAction.Excluded + ? "excluded" + : "up to date"); } } @@ -66,7 +70,7 @@ public static ExitCode Run(string[] args) stopwatch.Start(); var commandLineArguments = Options.CreateWithEnvironment(args); var fileLogger = new FileLogger(commandLineArguments.Verbosity, GetCSharpLogPath()); - var logger = commandLineArguments.Console + using var logger = commandLineArguments.Console ? new CombinedLogger(new ConsoleLogger(commandLineArguments.Verbosity), fileLogger) : (ILogger)fileLogger; @@ -76,124 +80,123 @@ public static ExitCode Run(string[] args) return ExitCode.Ok; } - using (var analyser = new Analyser(new LogProgressMonitor(logger), logger)) - using (var references = new BlockingCollection()) - { - try - { - var compilerVersion = new CompilerVersion(commandLineArguments); + var canonicalPathCache = CanonicalPathCache.Create(logger, 1000); + var pathTransformer = new PathTransformer(canonicalPathCache); - bool preserveSymlinks = Environment.GetEnvironmentVariable("SEMMLE_PRESERVE_SYMLINKS") == "true"; - var canonicalPathCache = CanonicalPathCache.Create(logger, 1000, preserveSymlinks ? CanonicalPathCache.Symlinks.Preserve : CanonicalPathCache.Symlinks.Follow); + using var analyser = new Analyser(new LogProgressMonitor(logger), logger, commandLineArguments.AssemblySensitiveTrap, pathTransformer); + using var references = new BlockingCollection(); + try + { + var compilerVersion = new CompilerVersion(commandLineArguments); - if (compilerVersion.SkipExtraction) - { - logger.Log(Severity.Warning, " Unrecognized compiler '{0}' because {1}", compilerVersion.SpecifiedCompiler, compilerVersion.SkipReason); - return ExitCode.Ok; - } + if (compilerVersion.SkipExtraction) + { + logger.Log(Severity.Warning, " Unrecognized compiler '{0}' because {1}", compilerVersion.SpecifiedCompiler, compilerVersion.SkipReason); + return ExitCode.Ok; + } - var cwd = Directory.GetCurrentDirectory(); - var compilerArguments = CSharpCommandLineParser.Default.Parse( - compilerVersion.ArgsWithResponse, - cwd, - compilerVersion.FrameworkPath, - compilerVersion.AdditionalReferenceDirectories - ); + var cwd = Directory.GetCurrentDirectory(); + var compilerArguments = CSharpCommandLineParser.Default.Parse( + compilerVersion.ArgsWithResponse, + cwd, + compilerVersion.FrameworkPath, + compilerVersion.AdditionalReferenceDirectories + ); - if (compilerArguments == null) - { - var sb = new StringBuilder(); - sb.Append(" Failed to parse command line: ").AppendList(" ", args); - logger.Log(Severity.Error, sb.ToString()); - ++analyser.CompilationErrors; - return ExitCode.Failed; - } + if (compilerArguments == null) + { + var sb = new StringBuilder(); + sb.Append(" Failed to parse command line: ").AppendList(" ", args); + logger.Log(Severity.Error, sb.ToString()); + ++analyser.CompilationErrors; + return ExitCode.Failed; + } - if (!analyser.BeginInitialize(compilerVersion.ArgsWithResponse)) - { - logger.Log(Severity.Info, "Skipping extraction since files have already been extracted"); - return ExitCode.Ok; - } + if (!analyser.BeginInitialize(compilerVersion.ArgsWithResponse)) + { + logger.Log(Severity.Info, "Skipping extraction since files have already been extracted"); + return ExitCode.Ok; + } - var referenceTasks = ResolveReferences(compilerArguments, analyser, canonicalPathCache, references); + var referenceTasks = ResolveReferences(compilerArguments, analyser, canonicalPathCache, references); - var syntaxTrees = new List(); - var syntaxTreeTasks = ReadSyntaxTrees( - compilerArguments.SourceFiles. - Select(src => canonicalPathCache.GetCanonicalPath(src.Path)), - analyser, - compilerArguments.ParseOptions, - compilerArguments.Encoding, - syntaxTrees); + var syntaxTrees = new List(); + var syntaxTreeTasks = ReadSyntaxTrees( + compilerArguments.SourceFiles. + Select(src => canonicalPathCache.GetCanonicalPath(src.Path)), + analyser, + compilerArguments.ParseOptions, + compilerArguments.Encoding, + syntaxTrees); - var sw1 = new Stopwatch(); - sw1.Start(); + var sw1 = new Stopwatch(); + sw1.Start(); - Parallel.Invoke( - new ParallelOptions { MaxDegreeOfParallelism = commandLineArguments.Threads }, - referenceTasks.Interleave(syntaxTreeTasks).ToArray()); + Parallel.Invoke( + new ParallelOptions { MaxDegreeOfParallelism = commandLineArguments.Threads }, + referenceTasks.Interleave(syntaxTreeTasks).ToArray()); - if (syntaxTrees.Count == 0) - { - logger.Log(Severity.Error, " No source files"); - ++analyser.CompilationErrors; - return ExitCode.Failed; - } + if (syntaxTrees.Count == 0) + { + logger.Log(Severity.Error, " No source files"); + ++analyser.CompilationErrors; + return ExitCode.Failed; + } - var compilation = CSharpCompilation.Create( - compilerArguments.CompilationName, - syntaxTrees, - references, - compilerArguments.CompilationOptions. - WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default). - WithStrongNameProvider(new DesktopStrongNameProvider(compilerArguments.KeyFileSearchPaths)) - // csc.exe (CSharpCompiler.cs) also provides WithMetadataReferenceResolver, - // WithXmlReferenceResolver and - // WithSourceReferenceResolver. - // These would be needed if we hadn't explicitly provided the source/references - // already. - ); - - analyser.EndInitialize(compilerArguments, commandLineArguments, compilation); - analyser.AnalyseCompilation(cwd, args); - analyser.AnalyseReferences(); - - foreach (var tree in compilation.SyntaxTrees) - { - analyser.AnalyseTree(tree); - } + // csc.exe (CSharpCompiler.cs) also provides CompilationOptions + // .WithMetadataReferenceResolver(), + // .WithXmlReferenceResolver() and + // .WithSourceReferenceResolver(). + // These would be needed if we hadn't explicitly provided the source/references + // already. + var compilation = CSharpCompilation.Create( + compilerArguments.CompilationName, + syntaxTrees, + references, + compilerArguments.CompilationOptions. + WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default). + WithStrongNameProvider(new DesktopStrongNameProvider(compilerArguments.KeyFileSearchPaths)) + ); + + analyser.EndInitialize(compilerArguments, commandLineArguments, compilation); + analyser.AnalyseCompilation(cwd, args); + analyser.AnalyseReferences(); + + foreach (var tree in compilation.SyntaxTrees) + { + analyser.AnalyseTree(tree); + } - var currentProcess = Process.GetCurrentProcess(); - var cpuTime1 = currentProcess.TotalProcessorTime; - var userTime1 = currentProcess.UserProcessorTime; - sw1.Stop(); - logger.Log(Severity.Info, " Models constructed in {0}", sw1.Elapsed); + var currentProcess = Process.GetCurrentProcess(); + var cpuTime1 = currentProcess.TotalProcessorTime; + var userTime1 = currentProcess.UserProcessorTime; + sw1.Stop(); + logger.Log(Severity.Info, " Models constructed in {0}", sw1.Elapsed); - var sw2 = new Stopwatch(); - sw2.Start(); - analyser.PerformExtraction(commandLineArguments.Threads); - sw2.Stop(); - var cpuTime2 = currentProcess.TotalProcessorTime; - var userTime2 = currentProcess.UserProcessorTime; + var sw2 = new Stopwatch(); + sw2.Start(); + analyser.PerformExtraction(commandLineArguments.Threads); + sw2.Stop(); + var cpuTime2 = currentProcess.TotalProcessorTime; + var userTime2 = currentProcess.UserProcessorTime; - var performance = new Entities.PerformanceMetrics() - { - Frontend = new Entities.Timings() { Elapsed = sw1.Elapsed, Cpu = cpuTime1, User = userTime1 }, - Extractor = new Entities.Timings() { Elapsed = sw2.Elapsed, Cpu = cpuTime2 - cpuTime1, User = userTime2 - userTime1 }, - Total = new Entities.Timings() { Elapsed = stopwatch.Elapsed, Cpu = cpuTime2, User = userTime2 }, - PeakWorkingSet = currentProcess.PeakWorkingSet64 - }; + var performance = new Entities.PerformanceMetrics() + { + Frontend = new Entities.Timings() { Elapsed = sw1.Elapsed, Cpu = cpuTime1, User = userTime1 }, + Extractor = new Entities.Timings() { Elapsed = sw2.Elapsed, Cpu = cpuTime2 - cpuTime1, User = userTime2 - userTime1 }, + Total = new Entities.Timings() { Elapsed = stopwatch.Elapsed, Cpu = cpuTime2, User = userTime2 }, + PeakWorkingSet = currentProcess.PeakWorkingSet64 + }; - analyser.LogPerformance(performance); - logger.Log(Severity.Info, " Extraction took {0}", sw2.Elapsed); + analyser.LogPerformance(performance); + logger.Log(Severity.Info, " Extraction took {0}", sw2.Elapsed); - return analyser.TotalErrors == 0 ? ExitCode.Ok : ExitCode.Errors; - } - catch (Exception ex) // lgtm[cs/catch-of-all-exceptions] - { - logger.Log(Severity.Error, " Unhandled exception: {0}", ex); - return ExitCode.Errors; - } + return analyser.TotalErrors == 0 ? ExitCode.Ok : ExitCode.Errors; + } + catch (Exception ex) // lgtm[cs/catch-of-all-exceptions] + { + logger.Log(Severity.Error, " Unhandled exception: {0}", ex); + return ExitCode.Errors; } } @@ -202,7 +205,7 @@ public static ExitCode Run(string[] args) /// /// Command line arguments. /// List of directories. - static IEnumerable FixedReferencePaths(Microsoft.CodeAnalysis.CommandLineArguments args) + private static IEnumerable FixedReferencePaths(Microsoft.CodeAnalysis.CommandLineArguments args) { // See https://msdn.microsoft.com/en-us/library/s5bac5fx.aspx // on how csc resolves references. Basically, @@ -221,7 +224,7 @@ static IEnumerable FixedReferencePaths(Microsoft.CodeAnalysis.CommandLin yield return lib; } - static MetadataReference MakeReference(CommandLineReference reference, string path) + private static MetadataReference MakeReference(CommandLineReference reference, string path) { return MetadataReference.CreateFromFile(path).WithProperties(reference.Properties); } @@ -232,7 +235,7 @@ static MetadataReference MakeReference(CommandLineReference reference, string pa /// The resolved references will be added (thread-safely) to the supplied /// list . /// - static IEnumerable ResolveReferences(Microsoft.CodeAnalysis.CommandLineArguments args, Analyser analyser, CanonicalPathCache canonicalPathCache, BlockingCollection ret) + private static IEnumerable ResolveReferences(Microsoft.CodeAnalysis.CommandLineArguments args, Analyser analyser, CanonicalPathCache canonicalPathCache, BlockingCollection ret) { var referencePaths = new Lazy(() => FixedReferencePaths(args).ToArray()); return args.MetadataReferences.Select(clref => () => @@ -255,25 +258,23 @@ static IEnumerable ResolveReferences(Microsoft.CodeAnalysis.CommandLineA } else { - bool referenceFound = false; + var composed = referencePaths.Value + .Select(path => Path.Combine(path, clref.Reference)) + .Where(path => File.Exists(path)) + .Select(path => canonicalPathCache.GetCanonicalPath(path)) + .FirstOrDefault(); + + if (composed is object) { - foreach (var composed in referencePaths.Value. - Select(path => Path.Combine(path, clref.Reference)). - Where(path => File.Exists(path)). - Select(path => canonicalPathCache.GetCanonicalPath(path))) - { - referenceFound = true; - var reference = MakeReference(clref, composed); - ret.Add(reference); - break; - } - if (!referenceFound) + var reference = MakeReference(clref, composed); + ret.Add(reference); + } + else + { + lock (analyser) { - lock (analyser) - { - analyser.Logger.Log(Severity.Error, " Unable to resolve reference '{0}'", clref.Reference); - ++analyser.CompilationErrors; - } + analyser.Logger.Log(Severity.Error, " Unable to resolve reference '{0}'", clref.Reference); + ++analyser.CompilationErrors; } } } @@ -286,18 +287,16 @@ static IEnumerable ResolveReferences(Microsoft.CodeAnalysis.CommandLineA /// The constructed syntax trees will be added (thread-safely) to the supplied /// list . /// - static IEnumerable ReadSyntaxTrees(IEnumerable sources, Analyser analyser, CSharpParseOptions parseOptions, Encoding encoding, IList ret) + private static IEnumerable ReadSyntaxTrees(IEnumerable sources, Analyser analyser, CSharpParseOptions parseOptions, Encoding encoding, IList ret) { return sources.Select(path => () => { try { - using (var file = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - var st = CSharpSyntaxTree.ParseText(SourceText.From(file, encoding), parseOptions, path); - lock (ret) - ret.Add(st); - } + using var file = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read); + var st = CSharpSyntaxTree.ParseText(SourceText.From(file, encoding), parseOptions, path); + lock (ret) + ret.Add(st); } catch (IOException ex) { @@ -317,71 +316,72 @@ public static void ExtractStandalone( ILogger logger, CommonOptions options) { - using (var analyser = new Analyser(pm, logger)) - using (var references = new BlockingCollection()) + var canonicalPathCache = CanonicalPathCache.Create(logger, 1000); + var pathTransformer = new PathTransformer(canonicalPathCache); + + using var analyser = new Analyser(pm, logger, false, pathTransformer); + using var references = new BlockingCollection(); + try { - try + var referenceTasks = referencePaths.Select(path => () => { - var referenceTasks = referencePaths.Select(path => () => - { - var reference = MetadataReference.CreateFromFile(path); - references.Add(reference); - }); + var reference = MetadataReference.CreateFromFile(path); + references.Add(reference); + }); - var syntaxTrees = new List(); - var syntaxTreeTasks = ReadSyntaxTrees(sources, analyser, null, null, syntaxTrees); + var syntaxTrees = new List(); + var syntaxTreeTasks = ReadSyntaxTrees(sources, analyser, null, null, syntaxTrees); - var sw = new Stopwatch(); - sw.Start(); + var sw = new Stopwatch(); + sw.Start(); - Parallel.Invoke( - new ParallelOptions { MaxDegreeOfParallelism = options.Threads }, - referenceTasks.Interleave(syntaxTreeTasks).ToArray()); - - if (syntaxTrees.Count == 0) - { - analyser.Logger.Log(Severity.Error, " No source files"); - ++analyser.CompilationErrors; - } + Parallel.Invoke( + new ParallelOptions { MaxDegreeOfParallelism = options.Threads }, + referenceTasks.Interleave(syntaxTreeTasks).ToArray()); - var compilation = CSharpCompilation.Create( - "csharp.dll", - syntaxTrees, - references - ); - - analyser.InitializeStandalone(compilation, options); - analyser.AnalyseReferences(); + if (syntaxTrees.Count == 0) + { + analyser.Logger.Log(Severity.Error, " No source files"); + ++analyser.CompilationErrors; + } - foreach (var tree in compilation.SyntaxTrees) - { - analyser.AnalyseTree(tree); - } + var compilation = CSharpCompilation.Create( + "csharp.dll", + syntaxTrees, + references + ); - sw.Stop(); - analyser.Logger.Log(Severity.Info, " Models constructed in {0}", sw.Elapsed); + analyser.InitializeStandalone(compilation, options); + analyser.AnalyseReferences(); - sw.Restart(); - analyser.PerformExtraction(options.Threads); - sw.Stop(); - analyser.Logger.Log(Severity.Info, " Extraction took {0}", sw.Elapsed); + foreach (var tree in compilation.SyntaxTrees) + { + analyser.AnalyseTree(tree); + } - foreach (var type in analyser.MissingNamespaces) - { - pm.MissingNamespace(type); - } + sw.Stop(); + analyser.Logger.Log(Severity.Info, " Models constructed in {0}", sw.Elapsed); - foreach (var type in analyser.MissingTypes) - { - pm.MissingType(type); - } + sw.Restart(); + analyser.PerformExtraction(options.Threads); + sw.Stop(); + analyser.Logger.Log(Severity.Info, " Extraction took {0}", sw.Elapsed); - pm.MissingSummary(analyser.MissingTypes.Count(), analyser.MissingNamespaces.Count()); + foreach (var type in analyser.MissingNamespaces) + { + pm.MissingNamespace(type); } - catch (Exception ex) // lgtm[cs/catch-of-all-exceptions] + + foreach (var type in analyser.MissingTypes) { - analyser.Logger.Log(Severity.Error, " Unhandled exception: {0}", ex); + pm.MissingType(type); } + + pm.MissingSummary(analyser.MissingTypes.Count(), analyser.MissingNamespaces.Count()); + } + catch (Exception ex) // lgtm[cs/catch-of-all-exceptions] + { + analyser.Logger.Log(Severity.Error, " Unhandled exception: {0}", ex); } } @@ -403,7 +403,7 @@ public static string GetCSharpArgsLogPath(string hash) => public static IEnumerable GetCSharpArgsLogs() => Directory.EnumerateFiles(GetCSharpLogDirectory(), "csharp.*.txt"); - static string GetCSharpLogDirectory() + private static string GetCSharpLogDirectory() { var codeQlLogDir = Environment.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_LOG_DIR"); if (!string.IsNullOrEmpty(codeQlLogDir)) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Options.cs b/csharp/extractor/Semmle.Extraction.CSharp/Options.cs index 8fa7be08b675..e20d4e846d44 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Options.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Options.cs @@ -9,22 +9,27 @@ public sealed class Options : CommonOptions /// /// The compiler exe, or null if unspecified. /// - public string CompilerName; + public string CompilerName { get; set; } /// /// Specified .Net Framework dir, or null if unspecified. /// - public string Framework; + public string Framework { get; set; } /// /// All other arguments passed to the compilation. /// - public IList CompilerArguments = new List(); + public IList CompilerArguments { get; } = new List(); /// /// Holds if the extractor was launched from the CLR tracer. /// - public bool ClrTracer = false; + public bool ClrTracer { get; private set; } = false; + + /// + /// Holds if assembly information should be prefixed to TRAP labels. + /// + public bool AssemblySensitiveTrap { get; private set; } = false; public static Options CreateWithEnvironment(string[] arguments) { @@ -41,19 +46,19 @@ public static Options CreateWithEnvironment(string[] arguments) return options; } - public override bool handleArgument(string argument) + public override bool HandleArgument(string argument) { CompilerArguments.Add(argument); return true; } - public override void invalidArgument(string argument) + public override void InvalidArgument(string argument) { // Unrecognised arguments are passed to the compiler. CompilerArguments.Add(argument); } - public override bool handleOption(string key, string value) + public override bool HandleOption(string key, string value) { switch (key) { @@ -64,19 +69,22 @@ public override bool handleOption(string key, string value) Framework = value; return true; default: - return base.handleOption(key, value); + return base.HandleOption(key, value); } } - public override bool handleFlag(string flag, bool value) + public override bool HandleFlag(string flag, bool value) { switch (flag) { case "clrtracer": ClrTracer = value; return true; + case "assemblysensitivetrap": + AssemblySensitiveTrap = value; + return true; default: - return base.handleFlag(flag, value); + return base.HandleFlag(flag, value); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/Ast.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/Ast.cs index 469034024fec..866d436bda13 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/Ast.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/Ast.cs @@ -5,11 +5,11 @@ namespace Semmle.Extraction.CSharp.Populators { - class Ast : CSharpSyntaxVisitor + internal class Ast : CSharpSyntaxVisitor { - readonly Context cx; - readonly IExpressionParentEntity parent; - readonly int child; + private readonly Context cx; + private readonly IExpressionParentEntity parent; + private readonly int child; public Ast(Context cx, IExpressionParentEntity parent, int child) { @@ -23,15 +23,9 @@ public override void DefaultVisit(SyntaxNode node) cx.ModelError(node, $"Unhandled syntax node {node.Kind()}"); } - public override void VisitPropertyDeclaration(PropertyDeclarationSyntax node) - { - ((Property)parent).VisitDeclaration(cx, node); - } - - public override void VisitArgumentList(ArgumentListSyntax node) { - int c = 0; + var c = 0; foreach (var m in node.Arguments) { cx.Extract(m, parent, c++); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnit.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnit.cs index 7b1cd245fd5c..333ebabc2dc9 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnit.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnit.cs @@ -10,9 +10,9 @@ namespace Semmle.Extraction.CSharp.Populators { public class TypeContainerVisitor : CSharpSyntaxVisitor { - protected readonly Context cx; - protected readonly IEntity parent; - protected readonly TextWriter trapFile; + protected Context cx { get; } + protected IEntity parent { get; } + protected TextWriter trapFile { get; } public TypeContainerVisitor(Context cx, TextWriter trapFile, IEntity parent) { @@ -53,7 +53,8 @@ public override void VisitInterfaceDeclaration(InterfaceDeclarationSyntax node) public override void VisitAttributeList(AttributeListSyntax node) { - if (cx.Extractor.Standalone) return; + if (cx.Extractor.Standalone) + return; var outputAssembly = Assembly.CreateOutputAssembly(cx); foreach (var attribute in node.Attributes) @@ -64,7 +65,7 @@ public override void VisitAttributeList(AttributeListSyntax node) } } - class TypeOrNamespaceVisitor : TypeContainerVisitor + internal class TypeOrNamespaceVisitor : TypeContainerVisitor { public TypeOrNamespaceVisitor(Context cx, TextWriter trapFile, IEntity parent) : base(cx, trapFile, parent) { } @@ -82,7 +83,7 @@ public override void VisitNamespaceDeclaration(NamespaceDeclarationSyntax node) } } - class CompilationUnitVisitor : TypeOrNamespaceVisitor + internal class CompilationUnitVisitor : TypeOrNamespaceVisitor { public CompilationUnitVisitor(Context cx) : base(cx, cx.TrapWriter.Writer, null) { } @@ -101,7 +102,7 @@ public override void VisitCompilationUnit(CompilationUnitSyntax compilationUnit) } // Gather comments: - foreach (SyntaxTrivia trivia in compilationUnit.DescendantTrivia(compilationUnit.Span)) + foreach (var trivia in compilationUnit.DescendantTrivia(compilationUnit.Span)) { CommentLine.Extract(cx, trivia); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/Locations.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/Locations.cs index a9a4863a2e44..22f6c8ec6a96 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/Locations.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/Locations.cs @@ -19,13 +19,11 @@ public static Location ExtendLocation(this Location l1, SyntaxNode n2) { return l1; } - else - { - var l2 = n2.FixedLocation(); - int start = System.Math.Min(l1.SourceSpan.Start, l2.SourceSpan.Start); - int end = System.Math.Max(l1.SourceSpan.End, l2.SourceSpan.End); - return Location.Create(n2.SyntaxTree, new Microsoft.CodeAnalysis.Text.TextSpan(start, end - start)); - } + + var l2 = n2.FixedLocation(); + var start = System.Math.Min(l1.SourceSpan.Start, l2.SourceSpan.Start); + var end = System.Math.Max(l1.SourceSpan.End, l2.SourceSpan.End); + return Location.Create(n2.SyntaxTree, new Microsoft.CodeAnalysis.Text.TextSpan(start, end - start)); } /// diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/Methods.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/Methods.cs index b889ef0af2b4..148160b8815e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/Methods.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/Methods.cs @@ -8,11 +8,11 @@ namespace Semmle.Extraction.CSharp.Populators { public static class MethodExtensions { - class AstLineCounter : CSharpSyntaxVisitor + private class AstLineCounter : CSharpSyntaxVisitor { public override LineCounts DefaultVisit(SyntaxNode node) { - string text = node.SyntaxTree.GetText().GetSubText(node.GetLocation().SourceSpan).ToString(); + var text = node.SyntaxTree.GetText().GetSubText(node.GetLocation().SourceSpan).ToString(); return Semmle.Util.LineCounter.ComputeLineCounts(text); } @@ -21,14 +21,14 @@ public override LineCounts VisitMethodDeclaration(MethodDeclarationSyntax method return Visit(method.Identifier, method.Body ?? (SyntaxNode)method.ExpressionBody); } - public LineCounts Visit(SyntaxToken identifier, SyntaxNode body) + public static LineCounts Visit(SyntaxToken identifier, SyntaxNode body) { - int start = identifier.GetLocation().SourceSpan.Start; - int end = body.GetLocation().SourceSpan.End - 1; + var start = identifier.GetLocation().SourceSpan.Start; + var end = body.GetLocation().SourceSpan.End - 1; var textSpan = new Microsoft.CodeAnalysis.Text.TextSpan(start, end - start); - string text = body.SyntaxTree.GetText().GetSubText(textSpan) + "\r\n"; + var text = body.SyntaxTree.GetText().GetSubText(textSpan) + "\r\n"; return Semmle.Util.LineCounter.ComputeLineCounts(text); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/Symbols.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/Symbols.cs index 4e3d495776c3..ddf64257cbe4 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/Symbols.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/Symbols.cs @@ -1,13 +1,11 @@ -using System; -using System.Linq; using Microsoft.CodeAnalysis; using Semmle.Extraction.CSharp.Entities; namespace Semmle.Extraction.CSharp.Populators { - class Symbols : SymbolVisitor + internal class Symbols : SymbolVisitor { - readonly Context cx; + private readonly Context cx; public Symbols(Context cx) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Semmle.Extraction.CSharp.csproj b/csharp/extractor/Semmle.Extraction.CSharp/Semmle.Extraction.CSharp.csproj index 87234841c5ff..905af7f616a8 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Semmle.Extraction.CSharp.csproj +++ b/csharp/extractor/Semmle.Extraction.CSharp/Semmle.Extraction.CSharp.csproj @@ -1,7 +1,7 @@ - netcoreapp3.0 + netcoreapp3.1 Semmle.Extraction.CSharp Semmle.Extraction.CSharp false @@ -20,7 +20,7 @@ - + diff --git a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs index 6050ad910a52..5732fe60b26e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs @@ -15,8 +15,8 @@ namespace Semmle.Extraction.CSharp /// public struct AnnotatedTypeSymbol { - public ITypeSymbol Symbol; - public NullableAnnotation Nullability; + public ITypeSymbol Symbol { get; set; } + public NullableAnnotation Nullability { get; } public AnnotatedTypeSymbol(ITypeSymbol symbol, NullableAnnotation nullability) { @@ -25,7 +25,7 @@ public AnnotatedTypeSymbol(ITypeSymbol symbol, NullableAnnotation nullability) } } - static class SymbolExtensions + internal static class SymbolExtensions { /// /// Tries to recover from an ErrorType. @@ -46,11 +46,10 @@ public static ITypeSymbol DisambiguateType(this ITypeSymbol type) * The conservative option would be to resolve all error types as null. */ - var errorType = type as IErrorTypeSymbol; - return errorType != null && errorType.CandidateSymbols.Any() ? - errorType.CandidateSymbols.First() as ITypeSymbol : - type; + return type is IErrorTypeSymbol errorType && errorType.CandidateSymbols.Any() + ? errorType.CandidateSymbols.First() as ITypeSymbol + : type; } /// @@ -71,55 +70,74 @@ public static string GetName(this ISymbol symbol, bool useMetadataName = false) /// public static IEnumerable GetSourceLevelModifiers(this ISymbol symbol) { - var methodModifiers = - symbol.DeclaringSyntaxReferences. - Select(r => r.GetSyntax()). - OfType(). - SelectMany(md => md.Modifiers); - var typeModifers = - symbol.DeclaringSyntaxReferences. - Select(r => r.GetSyntax()). - OfType(). - SelectMany(cd => cd.Modifiers); + var methodModifiers = symbol.DeclaringSyntaxReferences + .Select(r => r.GetSyntax()) + .OfType() + .SelectMany(md => md.Modifiers); + var typeModifers = symbol.DeclaringSyntaxReferences + .Select(r => r.GetSyntax()) + .OfType() + .SelectMany(cd => cd.Modifiers); return methodModifiers.Concat(typeModifers).Select(m => m.Text); } /// - /// Holds if this type symbol contains a type parameter from the - /// declaring generic . + /// Holds if the ID generated for `dependant` will contain a reference to + /// the ID for `symbol`. If this is the case, then the ID for `symbol` must + /// not contain a reference back to `dependant`. /// - public static bool ContainsTypeParameters(this ITypeSymbol type, Context cx, ISymbol declaringGeneric) + public static bool IdDependsOn(this ITypeSymbol dependant, Context cx, ISymbol symbol) { - using (cx.StackGuard) + var seen = new HashSet(SymbolEqualityComparer.Default); + + bool IdDependsOnImpl(ITypeSymbol type) { - switch (type.TypeKind) + if (SymbolEqualityComparer.Default.Equals(type, symbol)) + return true; + + if (type is null || seen.Contains(type)) + return false; + + seen.Add(type); + + using (cx.StackGuard) { - case TypeKind.Array: - var array = (IArrayTypeSymbol)type; - return array.ElementType.ContainsTypeParameters(cx, declaringGeneric); - case TypeKind.Class: - case TypeKind.Interface: - case TypeKind.Struct: - case TypeKind.Enum: - case TypeKind.Delegate: - case TypeKind.Error: - var named = (INamedTypeSymbol)type; - if (named.IsTupleType) - named = named.TupleUnderlyingType; - if (named.ContainingType != null && named.ContainingType.ContainsTypeParameters(cx, declaringGeneric)) - return true; - return named.TypeArguments.Any(arg => arg.ContainsTypeParameters(cx, declaringGeneric)); - case TypeKind.Pointer: - var ptr = (IPointerTypeSymbol)type; - return ptr.PointedAtType.ContainsTypeParameters(cx, declaringGeneric); - case TypeKind.TypeParameter: - var tp = (ITypeParameterSymbol)type; - var declaringGen = tp.TypeParameterKind == TypeParameterKind.Method ? tp.DeclaringMethod : (ISymbol)tp.DeclaringType; - return SymbolEqualityComparer.Default.Equals(declaringGen, declaringGeneric); - default: - return false; + switch (type.TypeKind) + { + case TypeKind.Array: + var array = (IArrayTypeSymbol)type; + return IdDependsOnImpl(array.ElementType); + case TypeKind.Class: + case TypeKind.Interface: + case TypeKind.Struct: + case TypeKind.Enum: + case TypeKind.Delegate: + case TypeKind.Error: + var named = (INamedTypeSymbol)type; + if (named.IsTupleType && named.TupleUnderlyingType is object) + named = named.TupleUnderlyingType; + if (IdDependsOnImpl(named.ContainingType)) + return true; + if (IdDependsOnImpl(named.GetNonObjectBaseType(cx))) + return true; + if (IdDependsOnImpl(named.ConstructedFrom)) + return true; + return named.TypeArguments.Any(IdDependsOnImpl); + case TypeKind.Pointer: + var ptr = (IPointerTypeSymbol)type; + return IdDependsOnImpl(ptr.PointedAtType); + case TypeKind.TypeParameter: + var tp = (ITypeParameterSymbol)type; + return tp.ContainingSymbol is ITypeSymbol cont + ? IdDependsOnImpl(cont) + : SymbolEqualityComparer.Default.Equals(tp.ContainingSymbol, symbol); + default: + return false; + } } } + + return IdDependsOnImpl(dependant); } /// @@ -130,27 +148,20 @@ public static bool ContainsTypeParameters(this ITypeSymbol type, Context cx, ISy /// /// The extraction context. /// The trap builder used to store the result. - /// The action to apply to syntactic sub terms of this type. - public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, Action subTermAction) - { - if (type.SpecialType != SpecialType.None) - { - /* - * Use the keyword ("int" etc) for the built-in types. - * This makes the IDs shorter and means that all built-in types map to - * the same entities (even when using multiple versions of mscorlib). - */ - trapFile.Write(type.ToDisplayString()); - return; - } + /// The outer symbol being defined (to avoid recursive ids). + /// Whether to build a type ID for the underlying `System.ValueTuple` struct in the case of tuple types. + public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, ISymbol symbolBeingDefined, bool constructUnderlyingTupleType = false) => + type.BuildTypeId(cx, trapFile, symbolBeingDefined, true, constructUnderlyingTupleType); + private static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, ISymbol symbolBeingDefined, bool addBaseClass, bool constructUnderlyingTupleType) + { using (cx.StackGuard) { switch (type.TypeKind) { case TypeKind.Array: var array = (IArrayTypeSymbol)type; - subTermAction(cx, trapFile, array.ElementType); + array.ElementType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass); array.BuildArraySuffix(trapFile); return; case TypeKind.Class: @@ -160,15 +171,17 @@ public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter tra case TypeKind.Delegate: case TypeKind.Error: var named = (INamedTypeSymbol)type; - named.BuildNamedTypeId(cx, trapFile, subTermAction); + named.BuildNamedTypeId(cx, trapFile, symbolBeingDefined, addBaseClass, constructUnderlyingTupleType); return; case TypeKind.Pointer: var ptr = (IPointerTypeSymbol)type; - subTermAction(cx, trapFile, ptr.PointedAtType); + ptr.PointedAtType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass); trapFile.Write('*'); return; case TypeKind.TypeParameter: var tp = (ITypeParameterSymbol)type; + tp.ContainingSymbol.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass); + trapFile.Write('_'); trapFile.Write(tp.Name); return; case TypeKind.Dynamic: @@ -180,6 +193,44 @@ public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter tra } } + private static void BuildOrWriteId(this ISymbol symbol, Context cx, TextWriter trapFile, ISymbol symbolBeingDefined, bool addBaseClass, bool constructUnderlyingTupleType = false) + { + // We need to keep track of the symbol being defined in order to avoid cyclic labels. + // For example, in + // + // ```csharp + // class C : IEnumerable { } + // ``` + // + // when we generate the label for ``C`1``, the base class `IEnumerable` has `T` as a type + // argument, which will be qualified with `__self__` instead of the label we are defining. + // In effect, the label will (simplified) look like + // + // ``` + // #123 = @"C`1 : IEnumerable<__self___T>" + // ``` + if (SymbolEqualityComparer.Default.Equals(symbol, symbolBeingDefined)) + trapFile.Write("__self__"); + else if (symbol is ITypeSymbol type && type.IdDependsOn(cx, symbolBeingDefined)) + type.BuildTypeId(cx, trapFile, symbolBeingDefined, addBaseClass, constructUnderlyingTupleType); + else if (symbol is INamedTypeSymbol namedType && namedType.IsTupleType && constructUnderlyingTupleType) + trapFile.WriteSubId(NamedType.CreateNamedTypeFromTupleType(cx, namedType)); + else + trapFile.WriteSubId(CreateEntity(cx, symbol)); + } + + /// + /// Adds an appropriate ID to the trap builder + /// for the symbol belonging to + /// . + /// + /// This will either write a reference to the ID of the entity belonging to + /// (`{#label}`), or if that will lead to cyclic IDs, + /// it will generate an appropriate ID that encodes the signature of + /// . + /// + public static void BuildOrWriteId(this ISymbol symbol, Context cx, TextWriter trapFile, ISymbol symbolBeingDefined) => + symbol.BuildOrWriteId(cx, trapFile, symbolBeingDefined, true); /// /// Constructs an array suffix string for this array type symbol. @@ -188,7 +239,7 @@ public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter tra public static void BuildArraySuffix(this IArrayTypeSymbol array, TextWriter trapFile) { trapFile.Write('['); - for (int i = 0; i < array.Rank - 1; i++) + for (var i = 0; i < array.Rank - 1; i++) trapFile.Write(','); trapFile.Write(']'); } @@ -211,12 +262,9 @@ private static void BuildAssembly(IAssemblySymbol asm, TextWriter trapFile, bool trapFile.Write("::"); } - static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, Action subTermAction) + private static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, ISymbol symbolBeingDefined, bool addBaseClass, bool constructUnderlyingTupleType) { - bool prefixAssembly = true; - if (named.ContainingAssembly is null) prefixAssembly = false; - - if (named.IsTupleType) + if (!constructUnderlyingTupleType && named.IsTupleType) { trapFile.Write('('); trapFile.BuildList(",", named.TupleElements, @@ -224,72 +272,87 @@ static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter { trapFile.Write(f.Name); trapFile.Write(":"); - subTermAction(cx, tb0, f.Type); + f.Type.BuildOrWriteId(cx, tb0, symbolBeingDefined, addBaseClass); } ); trapFile.Write(")"); return; } - if (named.ContainingType != null) + void AddContaining() { - subTermAction(cx, trapFile, named.ContainingType); - trapFile.Write('.'); - } - else if (named.ContainingNamespace != null) - { - if (prefixAssembly) - BuildAssembly(named.ContainingAssembly, trapFile); - named.ContainingNamespace.BuildNamespace(cx, trapFile); + if (named.ContainingType != null) + { + named.ContainingType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass); + trapFile.Write('.'); + } + else if (named.ContainingNamespace != null) + { + if (cx.ShouldAddAssemblyTrapPrefix && named.ContainingAssembly is object) + BuildAssembly(named.ContainingAssembly, trapFile); + named.ContainingNamespace.BuildNamespace(cx, trapFile); + } } - if (named.IsAnonymousType) - named.BuildAnonymousName(cx, trapFile, subTermAction, true); - else if (named.TypeParameters.IsEmpty) + if (named.TypeParameters.IsEmpty) + { + AddContaining(); trapFile.Write(named.Name); - else if (IsReallyUnbound(named)) + } + else if (named.IsReallyUnbound()) { + AddContaining(); trapFile.Write(named.Name); trapFile.Write("`"); trapFile.Write(named.TypeParameters.Length); } else { - subTermAction(cx, trapFile, named.ConstructedFrom); + named.ConstructedFrom.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass, constructUnderlyingTupleType); trapFile.Write('<'); // Encode the nullability of the type arguments in the label. - // Type arguments with different nullability can result in + // Type arguments with different nullability can result in // a constructed type with different nullability of its members and methods, // so we need to create a distinct database entity for it. trapFile.BuildList(",", named.GetAnnotatedTypeArguments(), - (ta, tb0) => subTermAction(cx, tb0, ta.Symbol) + (ta, tb0) => ta.Symbol.BuildOrWriteId(cx, tb0, symbolBeingDefined, addBaseClass) ); trapFile.Write('>'); } + + if (addBaseClass && named.GetNonObjectBaseType(cx) is INamedTypeSymbol @base) + { + // We need to limit unfolding of base classes. For example, in + // + // ```csharp + // class C1 { } + // class C2 : C1> { } + // class C3 : C1> { } + // class C4 : C3 { } + // ``` + // + // when we generate the label for `C4`, the base class `C3` has itself `C1>` as + // a base class, which in turn has `C1>` as a base class. The latter has the original + // base class `C3` as a type argument, which would lead to infinite unfolding. + trapFile.Write(" : "); + @base.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass: false); + } } - static void BuildNamespace(this INamespaceSymbol ns, Context cx, TextWriter trapFile) + private static void BuildNamespace(this INamespaceSymbol ns, Context cx, TextWriter trapFile) { trapFile.WriteSubId(Namespace.Create(cx, ns)); trapFile.Write('.'); } - static void BuildAnonymousName(this ITypeSymbol type, Context cx, TextWriter trapFile, Action subTermAction, bool includeParamName) + private static void BuildAnonymousName(this INamedTypeSymbol type, Context cx, TextWriter trapFile) { - var buildParam = includeParamName - ? (prop, tb0) => - { - tb0.Write(prop.Name); - tb0.Write(' '); - subTermAction(cx, tb0, prop.Type); - } - : (Action)((prop, tb0) => subTermAction(cx, tb0, prop.Type)); - int memberCount = type.GetMembers().OfType().Count(); - int hackTypeNumber = memberCount == 1 ? 1 : 0; + var memberCount = type.GetMembers().OfType().Count(); + var hackTypeNumber = memberCount == 1 ? 1 : 0; trapFile.Write("<>__AnonType"); trapFile.Write(hackTypeNumber); trapFile.Write('<'); - trapFile.BuildList(",", type.GetMembers().OfType(), buildParam); + trapFile.BuildList(",", type.GetMembers().OfType(), (prop, tb0) => BuildDisplayName(prop.Type, cx, tb0)); trapFile.Write('>'); } @@ -297,7 +360,7 @@ static void BuildAnonymousName(this ITypeSymbol type, Context cx, TextWriter tra /// Constructs a display name string for this type symbol. /// /// The trap builder used to store the result. - public static void BuildDisplayName(this ITypeSymbol type, Context cx, TextWriter trapFile) + public static void BuildDisplayName(this ITypeSymbol type, Context cx, TextWriter trapFile, bool constructUnderlyingTupleType = false) { using (cx.StackGuard) { @@ -306,7 +369,7 @@ public static void BuildDisplayName(this ITypeSymbol type, Context cx, TextWrite case TypeKind.Array: var array = (IArrayTypeSymbol)type; var elementType = array.ElementType; - if (elementType.MetadataName.IndexOf("`") >= 0) + if (elementType.MetadataName.Contains("`")) { trapFile.Write(elementType.Name); return; @@ -321,7 +384,7 @@ public static void BuildDisplayName(this ITypeSymbol type, Context cx, TextWrite case TypeKind.Delegate: case TypeKind.Error: var named = (INamedTypeSymbol)type; - named.BuildNamedTypeDisplayName(cx, trapFile); + named.BuildNamedTypeDisplayName(cx, trapFile, constructUnderlyingTupleType); return; case TypeKind.Pointer: var ptr = (IPointerTypeSymbol)type; @@ -340,9 +403,9 @@ public static void BuildDisplayName(this ITypeSymbol type, Context cx, TextWrite } } - public static void BuildNamedTypeDisplayName(this INamedTypeSymbol namedType, Context cx, TextWriter trapFile) + public static void BuildNamedTypeDisplayName(this INamedTypeSymbol namedType, Context cx, TextWriter trapFile, bool constructUnderlyingTupleType) { - if (namedType.IsTupleType) + if (!constructUnderlyingTupleType && namedType.IsTupleType) { trapFile.Write('('); trapFile.BuildList(",", namedType.TupleElements.Select(f => f.Type), @@ -354,11 +417,9 @@ public static void BuildNamedTypeDisplayName(this INamedTypeSymbol namedType, Co } if (namedType.IsAnonymousType) - { - namedType.BuildAnonymousName(cx, trapFile, (cx0, tb0, sub) => sub.BuildDisplayName(cx0, tb0), false); - } - - trapFile.Write(namedType.Name); + namedType.BuildAnonymousName(cx, trapFile); + else + trapFile.Write(namedType.Name); if (namedType.IsGenericType && namedType.TypeKind != TypeKind.Error && namedType.TypeArguments.Any()) { trapFile.Write('<'); @@ -395,11 +456,11 @@ public static bool IsUnboundNullable(this ITypeSymbol type) => /// The list of parameters, or an empty list. public static IEnumerable GetParameters(this ISymbol parameterizable) { - if (parameterizable is IMethodSymbol) - return ((IMethodSymbol)parameterizable).Parameters; + if (parameterizable is IMethodSymbol meth) + return meth.Parameters; - if (parameterizable is IPropertySymbol) - return ((IPropertySymbol)parameterizable).Parameters; + if (parameterizable is IPropertySymbol prop) + return prop.Parameters; return Enumerable.Empty(); } @@ -425,18 +486,24 @@ public static bool IsSourceDeclaration(this IMethodSymbol method) => /// public static bool IsSourceDeclaration(this IParameterSymbol parameter) { - var method = parameter.ContainingSymbol as IMethodSymbol; - if (method != null) + if (parameter.ContainingSymbol is IMethodSymbol method) return method.IsSourceDeclaration(); - var property = parameter.ContainingSymbol as IPropertySymbol; - if (property != null && property.IsIndexer) + if (parameter.ContainingSymbol is IPropertySymbol property && property.IsIndexer) return property.IsSourceDeclaration(); return true; } + /// + /// Gets the base type of `symbol`. Unlike `symbol.BaseType`, this excludes effective base + /// types of type parameters as well as `object` base types. + /// + public static INamedTypeSymbol GetNonObjectBaseType(this ITypeSymbol symbol, Context cx) => + symbol is ITypeParameterSymbol || SymbolEqualityComparer.Default.Equals(symbol.BaseType, cx.Compilation.ObjectType) ? null : symbol.BaseType; + public static IEntity CreateEntity(this Context cx, ISymbol symbol) { - if (symbol == null) return null; + if (symbol == null) + return null; using (cx.StackGuard) { diff --git a/csharp/extractor/Semmle.Extraction.Tests/FilePattern.cs b/csharp/extractor/Semmle.Extraction.Tests/FilePattern.cs new file mode 100644 index 000000000000..a4b2214b5e86 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.Tests/FilePattern.cs @@ -0,0 +1,48 @@ +using Xunit; + +namespace Semmle.Extraction.Tests +{ + public class FilePatternTests + { + [Fact] + public void TestRegexCompilation() + { + var fp = new FilePattern("/hadoop*"); + Assert.Equal("^hadoop[^/]*.*", fp.RegexPattern); + fp = new FilePattern("**/org/apache/hadoop"); + Assert.Equal("^.*/org/apache/hadoop.*", fp.RegexPattern); + fp = new FilePattern("hadoop-common/**/test// "); + Assert.Equal("^hadoop-common/.*/test(?/).*", fp.RegexPattern); + fp = new FilePattern(@"-C:\agent\root\asdf//"); + Assert.Equal("^C:/agent/root/asdf(?/).*", fp.RegexPattern); + fp = new FilePattern(@"-C:\agent+\[root]\asdf//"); + Assert.Equal(@"^C:/agent\+/\[root]/asdf(?/).*", fp.RegexPattern); + } + + [Fact] + public void TestMatching() + { + var fp1 = new FilePattern(@"C:\agent\root\abc//"); + var fp2 = new FilePattern(@"C:\agent\root\def//ghi"); + var patterns = new[] { fp1, fp2 }; + + var success = FilePattern.Matches(patterns, @"C:\agent\root\abc\file.cs", out var s); + Assert.True(success); + Assert.Equal("/file.cs", s); + + success = FilePattern.Matches(patterns, @"C:\agent\root\def\ghi\file.cs", out s); + Assert.True(success); + Assert.Equal("/ghi/file.cs", s); + + success = FilePattern.Matches(patterns, @"C:\agent\root\def\file.cs", out _); + Assert.False(success); + } + + [Fact] + public void TestInvalidPatterns() + { + Assert.Throws(() => new FilePattern("/abc//def//ghi")); + Assert.Throws(() => new FilePattern("/abc**def")); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.Tests/Layout.cs b/csharp/extractor/Semmle.Extraction.Tests/Layout.cs index 303ea5bf71e6..ceb83019ba9c 100644 --- a/csharp/extractor/Semmle.Extraction.Tests/Layout.cs +++ b/csharp/extractor/Semmle.Extraction.Tests/Layout.cs @@ -1,40 +1,66 @@ -using System.IO; +using System.IO; using Xunit; using Semmle.Util.Logging; using System.Runtime.InteropServices; namespace Semmle.Extraction.Tests { + internal struct TransformedPathStub : PathTransformer.ITransformedPath + { + private readonly string value; + public TransformedPathStub(string value) => this.value = value; + public string Value => value; + + public string Extension => throw new System.NotImplementedException(); + + public string NameWithoutExtension => throw new System.NotImplementedException(); + + public PathTransformer.ITransformedPath ParentDirectory => throw new System.NotImplementedException(); + + public string DatabaseId => throw new System.NotImplementedException(); + + public PathTransformer.ITransformedPath WithSuffix(string suffix) + { + throw new System.NotImplementedException(); + } + } + public class Layout { - readonly ILogger Logger = new LoggerMock(); + private readonly ILogger logger = new LoggerMock(); [Fact] public void TestDefaultLayout() { var layout = new Semmle.Extraction.Layout(null, null, null); - var project = layout.LookupProjectOrNull("foo.cs"); + var project = layout.LookupProjectOrNull(new TransformedPathStub("foo.cs")); + + Assert.NotNull(project); // All files are mapped when there's no layout file. - Assert.True(layout.FileInLayout("foo.cs")); + Assert.True(layout.FileInLayout(new TransformedPathStub("foo.cs"))); // Test trap filename var tmpDir = Path.GetTempPath(); Directory.SetCurrentDirectory(tmpDir); if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { - // `Directory.SetCurrentDirectory()` doesn't seem to work on macOS, - // so disable this test on macOS, for now + // `Directory.SetCurrentDirectory()` seems to slightly change the path on macOS, + // so adjusting it: Assert.NotEqual(Directory.GetCurrentDirectory(), tmpDir); - return; + tmpDir = "/private" + tmpDir; + // Remove trailing slash: + Assert.Equal('/', tmpDir[tmpDir.Length - 1]); + tmpDir = tmpDir.Substring(0, tmpDir.Length - 1); + Assert.Equal(Directory.GetCurrentDirectory(), tmpDir); } - var f1 = project.GetTrapPath(Logger, "foo.cs", TrapWriter.CompressionMode.Gzip); - var g1 = TrapWriter.NestPaths(Logger, tmpDir, "foo.cs.trap.gz", TrapWriter.InnerPathComputation.ABSOLUTE); + var f1 = project!.GetTrapPath(logger, new TransformedPathStub("foo.cs"), TrapWriter.CompressionMode.Gzip); + var g1 = TrapWriter.NestPaths(logger, tmpDir, "foo.cs.trap.gz"); Assert.Equal(f1, g1); // Test trap file generation - var trapwriterFilename = project.GetTrapPath(Logger, "foo.cs", TrapWriter.CompressionMode.Gzip); - using (var trapwriter = project.CreateTrapWriter(Logger, "foo.cs", false, TrapWriter.CompressionMode.Gzip)) + var trapwriterFilename = project.GetTrapPath(logger, new TransformedPathStub("foo.cs"), TrapWriter.CompressionMode.Gzip); + using (var trapwriter = project.CreateTrapWriter(logger, new TransformedPathStub("foo.cs"), false, TrapWriter.CompressionMode.Gzip)) { trapwriter.Emit("1=*"); Assert.False(File.Exists(trapwriterFilename)); @@ -63,23 +89,24 @@ public void TestLayoutFile() var layout = new Semmle.Extraction.Layout(null, null, "layout.txt"); // Test general pattern matching - Assert.True(layout.FileInLayout("bar.cs")); - Assert.False(layout.FileInLayout("foo.cs")); - Assert.False(layout.FileInLayout("goo.cs")); - Assert.False(layout.FileInLayout("excluded/bar.cs")); - Assert.True(layout.FileInLayout("excluded/foo.cs")); - Assert.True(layout.FileInLayout("included/foo.cs")); + Assert.True(layout.FileInLayout(new TransformedPathStub("bar.cs"))); + Assert.False(layout.FileInLayout(new TransformedPathStub("foo.cs"))); + Assert.False(layout.FileInLayout(new TransformedPathStub("goo.cs"))); + Assert.False(layout.FileInLayout(new TransformedPathStub("excluded/bar.cs"))); + Assert.True(layout.FileInLayout(new TransformedPathStub("excluded/foo.cs"))); + Assert.True(layout.FileInLayout(new TransformedPathStub("included/foo.cs"))); // Test the trap file - var project = layout.LookupProjectOrNull("bar.cs"); - var trapwriterFilename = project.GetTrapPath(Logger, "bar.cs", TrapWriter.CompressionMode.Gzip); - Assert.Equal(TrapWriter.NestPaths(Logger, Path.GetFullPath("snapshot\\trap"), "bar.cs.trap.gz", TrapWriter.InnerPathComputation.ABSOLUTE), + var project = layout.LookupProjectOrNull(new TransformedPathStub("bar.cs")); + Assert.NotNull(project); + var trapwriterFilename = project!.GetTrapPath(logger, new TransformedPathStub("bar.cs"), TrapWriter.CompressionMode.Gzip); + Assert.Equal(TrapWriter.NestPaths(logger, Path.GetFullPath("snapshot\\trap"), "bar.cs.trap.gz"), trapwriterFilename); // Test the source archive - var trapWriter = project.CreateTrapWriter(Logger, "bar.cs", false, TrapWriter.CompressionMode.Gzip); - trapWriter.Archive("layout.txt", System.Text.Encoding.ASCII); - var writtenFile = TrapWriter.NestPaths(Logger, Path.GetFullPath("snapshot\\archive"), "layout.txt", TrapWriter.InnerPathComputation.ABSOLUTE); + var trapWriter = project.CreateTrapWriter(logger, new TransformedPathStub("bar.cs"), false, TrapWriter.CompressionMode.Gzip); + trapWriter.Archive("layout.txt", new TransformedPathStub("layout.txt"), System.Text.Encoding.ASCII); + var writtenFile = TrapWriter.NestPaths(logger, Path.GetFullPath("snapshot\\archive"), "layout.txt"); Assert.True(File.Exists(writtenFile)); File.Delete("layout.txt"); } @@ -89,9 +116,11 @@ public void TestTrapOverridesLayout() { // When you specify both a trap file and a layout, use the trap file. var layout = new Semmle.Extraction.Layout(Path.GetFullPath("snapshot\\trap"), null, "something.txt"); - Assert.True(layout.FileInLayout("bar.cs")); - var f1 = layout.LookupProjectOrNull("foo.cs").GetTrapPath(Logger, "foo.cs", TrapWriter.CompressionMode.Gzip); - var g1 = TrapWriter.NestPaths(Logger, Path.GetFullPath("snapshot\\trap"), "foo.cs.trap.gz", TrapWriter.InnerPathComputation.ABSOLUTE); + Assert.True(layout.FileInLayout(new TransformedPathStub("bar.cs"))); + var subProject = layout.LookupProjectOrNull(new TransformedPathStub("foo.cs")); + Assert.NotNull(subProject); + var f1 = subProject!.GetTrapPath(logger, new TransformedPathStub("foo.cs"), TrapWriter.CompressionMode.Gzip); + var g1 = TrapWriter.NestPaths(logger, Path.GetFullPath("snapshot\\trap"), "foo.cs.trap.gz"); Assert.Equal(f1, g1); } @@ -117,26 +146,30 @@ public void TestMultipleSections() var layout = new Semmle.Extraction.Layout(null, null, "layout.txt"); // Use Section 2 - Assert.True(layout.FileInLayout("bar.cs")); - var f1 = layout.LookupProjectOrNull("bar.cs").GetTrapPath(Logger, "bar.cs", TrapWriter.CompressionMode.Gzip); - var g1 = TrapWriter.NestPaths(Logger, Path.GetFullPath("snapshot\\trap2"), "bar.cs.trap.gz", TrapWriter.InnerPathComputation.ABSOLUTE); + Assert.True(layout.FileInLayout(new TransformedPathStub("bar.cs"))); + var subProject = layout.LookupProjectOrNull(new TransformedPathStub("bar.cs")); + Assert.NotNull(subProject); + var f1 = subProject!.GetTrapPath(logger, new TransformedPathStub("bar.cs"), TrapWriter.CompressionMode.Gzip); + var g1 = TrapWriter.NestPaths(logger, Path.GetFullPath("snapshot\\trap2"), "bar.cs.trap.gz"); Assert.Equal(f1, g1); // Use Section 1 - Assert.True(layout.FileInLayout("foo.cs")); - var f2 = layout.LookupProjectOrNull("foo.cs").GetTrapPath(Logger, "foo.cs", TrapWriter.CompressionMode.Gzip); - var g2 = TrapWriter.NestPaths(Logger, Path.GetFullPath("snapshot\\trap1"), "foo.cs.trap.gz", TrapWriter.InnerPathComputation.ABSOLUTE); + Assert.True(layout.FileInLayout(new TransformedPathStub("foo.cs"))); + subProject = layout.LookupProjectOrNull(new TransformedPathStub("foo.cs")); + Assert.NotNull(subProject); + var f2 = subProject!.GetTrapPath(logger, new TransformedPathStub("foo.cs"), TrapWriter.CompressionMode.Gzip); + var g2 = TrapWriter.NestPaths(logger, Path.GetFullPath("snapshot\\trap1"), "foo.cs.trap.gz"); Assert.Equal(f2, g2); // boo.dll is not in the layout, so use layout from first section. - Assert.False(layout.FileInLayout("boo.dll")); - var f3 = layout.LookupProjectOrDefault("boo.dll").GetTrapPath(Logger, "boo.dll", TrapWriter.CompressionMode.Gzip); - var g3 = TrapWriter.NestPaths(Logger, Path.GetFullPath("snapshot\\trap1"), "boo.dll.trap.gz", TrapWriter.InnerPathComputation.ABSOLUTE); + Assert.False(layout.FileInLayout(new TransformedPathStub("boo.dll"))); + var f3 = layout.LookupProjectOrDefault(new TransformedPathStub("boo.dll")).GetTrapPath(logger, new TransformedPathStub("boo.dll"), TrapWriter.CompressionMode.Gzip); + var g3 = TrapWriter.NestPaths(logger, Path.GetFullPath("snapshot\\trap1"), "boo.dll.trap.gz"); Assert.Equal(f3, g3); // boo.cs is not in the layout, so return null - Assert.False(layout.FileInLayout("boo.cs")); - Assert.Null(layout.LookupProjectOrNull("boo.cs")); + Assert.False(layout.FileInLayout(new TransformedPathStub("boo.cs"))); + Assert.Null(layout.LookupProjectOrNull(new TransformedPathStub("boo.cs"))); } [Fact] @@ -166,34 +199,32 @@ public void InvalidLayout() new Semmle.Extraction.Layout(null, null, "layout.txt")); } - class LoggerMock : ILogger + private sealed class LoggerMock : ILogger { public void Dispose() { } public void Log(Severity s, string text) { } - - public void Log(Severity s, string text, params object[] args) { } } } - static class TrapWriterTestExtensions + internal static class TrapWriterTestExtensions { public static void Emit(this TrapWriter trapFile, string s) { trapFile.Emit(new StringTrapEmitter(s)); } - class StringTrapEmitter : ITrapEmitter + private class StringTrapEmitter : ITrapEmitter { - string Content; + private readonly string content; public StringTrapEmitter(string content) { - Content = content; + this.content = content; } public void EmitTrap(TextWriter trapFile) { - trapFile.Write(Content); + trapFile.Write(content); } } } diff --git a/csharp/extractor/Semmle.Extraction.Tests/Options.cs b/csharp/extractor/Semmle.Extraction.Tests/Options.cs index ce240ce146d9..f9a1c34e563d 100644 --- a/csharp/extractor/Semmle.Extraction.Tests/Options.cs +++ b/csharp/extractor/Semmle.Extraction.Tests/Options.cs @@ -9,8 +9,8 @@ namespace Semmle.Extraction.Tests { public class OptionsTests { - CSharp.Options options; - CSharp.Standalone.Options standaloneOptions; + private CSharp.Options? options; + private CSharp.Standalone.Options? standaloneOptions; public OptionsTests() { @@ -21,7 +21,7 @@ public OptionsTests() [Fact] public void DefaultOptions() { - options = CSharp.Options.CreateWithEnvironment(new string[] { }); + options = CSharp.Options.CreateWithEnvironment(Array.Empty()); Assert.True(options.Cache); Assert.False(options.CIL); Assert.Null(options.Framework); @@ -141,7 +141,7 @@ public void EnvironmentVariables() [Fact] public void StandaloneDefaults() { - standaloneOptions = CSharp.Standalone.Options.Create(new string[] { }); + standaloneOptions = CSharp.Standalone.Options.Create(Array.Empty()); Assert.Equal(0, standaloneOptions.DllDirs.Count); Assert.True(standaloneOptions.UseNuGet); Assert.True(standaloneOptions.UseMscorlib); @@ -184,14 +184,14 @@ public void ShowingHelp() public void Fast() { Environment.SetEnvironmentVariable("LGTM_INDEX_EXTRACTOR", "--fast"); - options = CSharp.Options.CreateWithEnvironment(new string[] { }); + options = CSharp.Options.CreateWithEnvironment(Array.Empty()); Assert.True(options.Fast); } [Fact] public void ArchiveArguments() { - var sw = new StringWriter(); + using var sw = new StringWriter(); var file = Path.GetTempFileName(); try diff --git a/csharp/extractor/Semmle.Extraction.Tests/PathTransformer.cs b/csharp/extractor/Semmle.Extraction.Tests/PathTransformer.cs new file mode 100644 index 000000000000..990644eb4b9b --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.Tests/PathTransformer.cs @@ -0,0 +1,45 @@ +using Semmle.Util; +using Xunit; + +namespace Semmle.Extraction.Tests +{ + internal class PathCacheStub : IPathCache + { + public string GetCanonicalPath(string path) => path; + } + + public class PathTransformerTests + { + [Fact] + public void TestTransformerFile() + { + var spec = new string[] + { + @"#D:\src", + @"C:\agent*\src//", + @"-C:\agent*\src\external", + @"", + @"#empty", + @"", + @"#src2", + @"/agent*//src", + @"", + @"#optsrc", + @"opt/src//" + }; + + var pathTransformer = new PathTransformer(new PathCacheStub(), spec); + + // Windows-style matching + Assert.Equal(@"C:/bar.cs", pathTransformer.Transform(@"C:\bar.cs").Value); + Assert.Equal("D:/src/file.cs", pathTransformer.Transform(@"C:\agent42\src\file.cs").Value); + Assert.Equal("D:/src/file.cs", pathTransformer.Transform(@"C:\agent43\src\file.cs").Value); + Assert.Equal(@"C:/agent43/src/external/file.cs", pathTransformer.Transform(@"C:\agent43\src\external\file.cs").Value); + + // Linux-style matching + Assert.Equal(@"src2/src/file.cs", pathTransformer.Transform(@"/agent/src/file.cs").Value); + Assert.Equal(@"src2/src/file.cs", pathTransformer.Transform(@"/agent42/src/file.cs").Value); + Assert.Equal(@"optsrc/file.cs", pathTransformer.Transform(@"/opt/src/file.cs").Value); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.Tests/Semmle.Extraction.Tests.csproj b/csharp/extractor/Semmle.Extraction.Tests/Semmle.Extraction.Tests.csproj index c101a5fba830..830529d3710e 100644 --- a/csharp/extractor/Semmle.Extraction.Tests/Semmle.Extraction.Tests.csproj +++ b/csharp/extractor/Semmle.Extraction.Tests/Semmle.Extraction.Tests.csproj @@ -2,9 +2,10 @@ Exe - netcoreapp3.0 + netcoreapp3.1 false win-x64;linux-x64;osx-x64 + enable diff --git a/csharp/extractor/Semmle.Extraction.Tests/TrapWriter.cs b/csharp/extractor/Semmle.Extraction.Tests/TrapWriter.cs index fd7f77f427b4..54e0a9db25a0 100644 --- a/csharp/extractor/Semmle.Extraction.Tests/TrapWriter.cs +++ b/csharp/extractor/Semmle.Extraction.Tests/TrapWriter.cs @@ -1,8 +1,6 @@ using Xunit; using Semmle.Util.Logging; using Semmle.Util; -using System.Runtime.InteropServices; -using System.IO; namespace Semmle.Extraction.Tests { @@ -14,7 +12,7 @@ public void NestedPaths() string tempDir = System.IO.Path.GetTempPath(); string root1, root2, root3; - if(Win32.IsWindows()) + if (Win32.IsWindows()) { root1 = "E:"; root2 = "e:"; @@ -27,41 +25,28 @@ public void NestedPaths() root3 = "/"; } - string formattedTempDir = tempDir.Replace('/', '\\').Replace(':', '_').Trim('\\'); + using var logger = new LoggerMock(); - var logger = new LoggerMock(); - System.IO.Directory.SetCurrentDirectory(tempDir); + Assert.Equal($@"C:\Temp\source_archive\def.cs", TrapWriter.NestPaths(logger, @"C:\Temp\source_archive", "def.cs").Replace('/', '\\')); - if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - // `Directory.SetCurrentDirectory()` doesn't seem to work on macOS, - // so disable this test on macOS, for now - Assert.NotEqual(Directory.GetCurrentDirectory(), tempDir); - return; - } - - Assert.Equal($@"C:\Temp\source_archive\{formattedTempDir}\def.cs", TrapWriter.NestPaths(logger, @"C:\Temp\source_archive", "def.cs", TrapWriter.InnerPathComputation.ABSOLUTE).Replace('/','\\')); + Assert.Equal(@"C:\Temp\source_archive\def.cs", TrapWriter.NestPaths(logger, @"C:\Temp\source_archive", "def.cs").Replace('/', '\\')); - Assert.Equal(@"C:\Temp\source_archive\def.cs", TrapWriter.NestPaths(logger, @"C:\Temp\source_archive", "def.cs", TrapWriter.InnerPathComputation.RELATIVE).Replace('/', '\\')); + Assert.Equal(@"C:\Temp\source_archive\E_\source\def.cs", TrapWriter.NestPaths(logger, @"C:\Temp\source_archive", $@"{root1}\source\def.cs").Replace('/', '\\')); - Assert.Equal(@"C:\Temp\source_archive\E_\source\def.cs", TrapWriter.NestPaths(logger, @"C:\Temp\source_archive", $@"{root1}\source\def.cs", TrapWriter.InnerPathComputation.ABSOLUTE).Replace('/', '\\')); + Assert.Equal(@"C:\Temp\source_archive\e_\source\def.cs", TrapWriter.NestPaths(logger, @"C:\Temp\source_archive", $@"{root2}\source\def.cs").Replace('/', '\\')); - Assert.Equal(@"C:\Temp\source_archive\e_\source\def.cs", TrapWriter.NestPaths(logger, @"C:\Temp\source_archive", $@"{root2}\source\def.cs", TrapWriter.InnerPathComputation.RELATIVE).Replace('/', '\\')); + Assert.Equal(@"C:\Temp\source_archive\source\def.cs", TrapWriter.NestPaths(logger, @"C:\Temp\source_archive", $@"{root3}source\def.cs").Replace('/', '\\')); - Assert.Equal(@"C:\Temp\source_archive\source\def.cs", TrapWriter.NestPaths(logger, @"C:\Temp\source_archive", $@"{root3}source\def.cs", TrapWriter.InnerPathComputation.ABSOLUTE).Replace('/', '\\')); + Assert.Equal(@"C:\Temp\source_archive\source\def.cs", TrapWriter.NestPaths(logger, @"C:\Temp\source_archive", $@"{root3}source\def.cs").Replace('/', '\\')); - Assert.Equal(@"C:\Temp\source_archive\source\def.cs", TrapWriter.NestPaths(logger, @"C:\Temp\source_archive", $@"{root3}source\def.cs", TrapWriter.InnerPathComputation.RELATIVE).Replace('/', '\\')); - - Assert.Equal(@"C:\Temp\source_archive\diskstation\share\source\def.cs", TrapWriter.NestPaths(logger, @"C:\Temp\source_archive", $@"{root3}{root3}diskstation\share\source\def.cs", TrapWriter.InnerPathComputation.ABSOLUTE).Replace('/', '\\')); + Assert.Equal(@"C:\Temp\source_archive\diskstation\share\source\def.cs", TrapWriter.NestPaths(logger, @"C:\Temp\source_archive", $@"{root3}{root3}diskstation\share\source\def.cs").Replace('/', '\\')); } - class LoggerMock : ILogger + private sealed class LoggerMock : ILogger { public void Dispose() { } public void Log(Severity s, string text) { } - - public void Log(Severity s, string text, params object[] args) { } } } } diff --git a/csharp/extractor/Semmle.Extraction/CommentProcessing.cs b/csharp/extractor/Semmle.Extraction/CommentProcessing.cs index 2067f8694717..f407f5703fec 100644 --- a/csharp/extractor/Semmle.Extraction/CommentProcessing.cs +++ b/csharp/extractor/Semmle.Extraction/CommentProcessing.cs @@ -11,7 +11,7 @@ namespace Semmle.Extraction.CommentProcessing /// Registers locations of comments and program elements, /// then generates binding information. /// - class CommentProcessor : ICommentGenerator + internal class CommentProcessor : ICommentGenerator { public void AddComment(ICommentLine comment) { @@ -33,9 +33,9 @@ public void AddComment(ICommentLine comment) return null; } - class LocationComparer : IComparer + private class LocationComparer : IComparer { - public int Compare(Location l1, Location l2) => CommentProcessor.Compare(l1, l2); + public int Compare(Location? l1, Location? l2) => CommentProcessor.Compare(l1, l2); } /// @@ -44,12 +44,21 @@ class LocationComparer : IComparer /// First location /// Second location /// <0 if l1 before l2, >0 if l1 after l2, else 0. - static int Compare(Location l1, Location l2) + private static int Compare(Location? l1, Location? l2) { - int diff = l1.SourceTree == l2.SourceTree ? 0 : l1.SourceTree.FilePath.CompareTo(l2.SourceTree.FilePath); - if (diff != 0) return diff; + if (object.ReferenceEquals(l1, l2)) + return 0; + if (l1 == null) + return -1; + if (l2 == null) + return 1; + + var diff = l1.SourceTree == l2.SourceTree ? 0 : l1.SourceTree.FilePath.CompareTo(l2.SourceTree.FilePath); + if (diff != 0) + return diff; diff = l1.SourceSpan.Start - l2.SourceSpan.Start; - if (diff != 0) return diff; + if (diff != 0) + return diff; return l1.SourceSpan.End - l2.SourceSpan.End; } @@ -69,7 +78,7 @@ public void AddElement(Label elementLabel, Key? duplicationGuardKey, Location lo // Ensure that commentBlock and element refer to the same file // which can happen when processing multiple files. - void EnsureSameFile(ICommentBlock commentBlock, ref KeyValuePair? element) + private static void EnsureSameFile(ICommentBlock commentBlock, ref KeyValuePair? element) { if (element != null && element.Value.Key.SourceTree != commentBlock.Location.SourceTree) element = null; @@ -85,7 +94,7 @@ void EnsureSameFile(ICommentBlock commentBlock, ref KeyValuePairThe element after the comment block. /// The parent element of the comment block. /// Output binding information. - void GenerateBindings( + private void GenerateBindings( ICommentBlock commentBlock, KeyValuePair? previousElement, KeyValuePair? nextElement, @@ -171,7 +180,7 @@ CommentBindingCallback callback private class ElementStack { // Invariant: the top of the stack must be contained by items below it. - readonly Stack> elementStack = new Stack>(); + private readonly Stack> elementStack = new Stack>(); /// /// Add a new element to the stack. @@ -202,9 +211,9 @@ public void Push(KeyValuePair value) /// The element before l, or null. public KeyValuePair? FindBefore(Location l) { - return elementStack. - Where(v => v.Key.SourceSpan.End < l.SourceSpan.Start). - LastOrNull(); + return elementStack + .Where(v => v.Key.SourceSpan.End < l.SourceSpan.Start) + .LastOrNull(); } /// @@ -243,13 +252,13 @@ CommentBindingCallback cb /// Process comments up until nextElement. /// Group comments into blocks, and associate blocks with elements. /// - /// + /// /// Enumerator for all comments in the program. /// The next element in the list. /// A stack of nested program elements. /// Where to send the results. /// true if there are more comments to process, false otherwise. - bool GenerateBindings( + private bool GenerateBindings( IEnumerator> commentEnumerator, KeyValuePair? nextElement, ElementStack elementStack, @@ -261,7 +270,7 @@ CommentBindingCallback cb // Iterate comments until the commentEnumerator has gone past nextElement while (nextElement == null || Compare(commentEnumerator.Current.Value.Location, nextElement.Value.Key) < 0) { - if(block is null) + if (block is null) block = new CommentBlock(commentEnumerator.Current.Value); if (!block.CombinesWith(commentEnumerator.Current.Value)) @@ -284,7 +293,7 @@ CommentBindingCallback cb } } - if(!(block is null)) + if (!(block is null)) GenerateBindings(block, elementStack, nextElement, cb); return true; @@ -308,35 +317,33 @@ public void GenerateBindings(CommentBindingCallback cb) * (Note that comment processing is O(n.log n) overall due to dictionary of elements and comments.) */ - ElementStack elementStack = new ElementStack(); + var elementStack = new ElementStack(); - using (IEnumerator> elementEnumerator = elements.GetEnumerator()) - using (IEnumerator> commentEnumerator = comments.GetEnumerator()) + using IEnumerator> elementEnumerator = elements.GetEnumerator(); + using IEnumerator> commentEnumerator = comments.GetEnumerator(); + if (!commentEnumerator.MoveNext()) { - if (!commentEnumerator.MoveNext()) - { - // There are no comments to process. - return; - } + // There are no comments to process. + return; + } - while (elementEnumerator.MoveNext()) + while (elementEnumerator.MoveNext()) + { + if (!GenerateBindings(commentEnumerator, elementEnumerator.Current, elementStack, cb)) { - if (!GenerateBindings(commentEnumerator, elementEnumerator.Current, elementStack, cb)) - { - // No more comments to process. - return; - } - - elementStack.Push(elementEnumerator.Current); + // No more comments to process. + return; } - // Generate remaining comments at end of file - GenerateBindings(commentEnumerator, null, elementStack, cb); + elementStack.Push(elementEnumerator.Current); } + + // Generate remaining comments at end of file + GenerateBindings(commentEnumerator, null, elementStack, cb); } } - class CommentBlock : ICommentBlock + internal class CommentBlock : ICommentBlock { private readonly List lines; @@ -357,13 +364,14 @@ public CommentBlock(ICommentLine firstLine) /// Whether the new line should be appended to this block. public bool CombinesWith(ICommentLine newLine) { - if (!CommentLines.Any()) return true; - - bool sameFile = Location.SourceTree == newLine.Location.SourceTree; - bool sameRow = Location.EndLine() == newLine.Location.StartLine(); - bool sameColumn = Location.EndLine() + 1 == newLine.Location.StartLine(); - bool nextRow = Location.StartColumn() == newLine.Location.StartColumn(); - bool adjacent = sameFile && (sameRow || (sameColumn && nextRow)); + if (!CommentLines.Any()) + return true; + + var sameFile = Location.SourceTree == newLine.Location.SourceTree; + var sameRow = Location.EndLine() == newLine.Location.StartLine(); + var sameColumn = Location.EndLine() + 1 == newLine.Location.StartLine(); + var nextRow = Location.StartColumn() == newLine.Location.StartColumn(); + var adjacent = sameFile && (sameRow || (sameColumn && nextRow)); return newLine.Type == CommentLineType.MultilineContinuation || diff --git a/csharp/extractor/Semmle.Extraction/Context.cs b/csharp/extractor/Semmle.Extraction/Context.cs index 3e55c1068e2c..0863f4624752 100644 --- a/csharp/extractor/Semmle.Extraction/Context.cs +++ b/csharp/extractor/Semmle.Extraction/Context.cs @@ -18,7 +18,7 @@ public class Context /// /// Access various extraction functions, e.g. logger, trap writer. /// - public readonly IExtractor Extractor; + public IExtractor Extractor { get; } /// /// The program database provided by Roslyn. @@ -39,51 +39,21 @@ public SemanticModel GetModel(SyntaxNode node) /// /// Access to the trap file. /// - public readonly TrapWriter TrapWriter; - - int GetNewId() => TrapWriter.IdCounter++; + public TrapWriter TrapWriter { get; } /// - /// Creates a new entity using the factory. + /// Holds if assembly information should be prefixed to TRAP labels. /// - /// The entity factory. - /// The initializer for the entity. - /// The new/existing entity. - public Entity CreateEntity(ICachedEntityFactory factory, Type init) where Entity : ICachedEntity where Type:struct - { - return CreateNonNullEntity(factory, init); - } + public bool ShouldAddAssemblyTrapPrefix { get; } - /// - /// Creates a new entity using the factory. - /// - /// The entity factory. - /// The initializer for the entity. - /// The new/existing entity. - public Entity CreateNullableEntity(ICachedEntityFactory factory, Type init) where Entity : ICachedEntity - { - return init == null ? CreateEntity2(factory, init) : CreateNonNullEntity(factory, init); - } - - /// - /// Creates a new entity using the factory. - /// - /// The entity factory. - /// The initializer for the entity. - /// The new/existing entity. - public Entity CreateEntityFromSymbol(ICachedEntityFactory factory, Type init) - where Entity : ICachedEntity - where Type: ISymbol - { - return init == null ? CreateEntity2(factory, init) : CreateNonNullEntity(factory, init); - } + private int GetNewId() => TrapWriter.IdCounter++; // A recursion guard against writing to the trap file whilst writing an id to the trap file. - bool WritingLabel = false; + private bool writingLabel = false; public void DefineLabel(IEntity entity, TextWriter trapFile, IExtractor extractor) { - if (WritingLabel) + if (writingLabel) { // Don't define a label whilst writing a label. PopulateLater(() => DefineLabel(entity, trapFile, extractor)); @@ -92,61 +62,20 @@ public void DefineLabel(IEntity entity, TextWriter trapFile, IExtractor extracto { try { - WritingLabel = true; + writingLabel = true; entity.DefineLabel(trapFile, extractor); } finally { - WritingLabel = false; - } - } - } - - /// - /// Creates a new entity using the factory. - /// Uses a different cache to , - /// and can store null values. - /// - /// The entity factory. - /// The initializer for the entity. - /// The new/existing entity. - public Entity CreateEntity2(ICachedEntityFactory factory, Type init) where Entity : ICachedEntity - { - using (StackGuard) - { - var entity = factory.Create(this, init); - - if (entityLabelCache.TryGetValue(entity, out var label)) - { - entity.Label = label; - } - else - { - label = GetNewLabel(); - entity.Label = label; - entityLabelCache[entity] = label; - - DefineLabel(entity, TrapWriter.Writer, Extractor); - - if (entity.NeedsPopulation) - Populate(init as ISymbol, entity); -#if DEBUG_LABELS - using (var id = new StringWriter()) - { - entity.WriteId(id); - CheckEntityHasUniqueLabel(id.ToString(), entity); - } -#endif - + writingLabel = false; } - return entity; } } #if DEBUG_LABELS private void CheckEntityHasUniqueLabel(string id, ICachedEntity entity) { - if (idLabelCache.TryGetValue(id, out var originalEntity)) + if (idLabelCache.ContainsKey(id)) { ExtractionError("Label collision for " + id, entity.Label.ToString(), Entities.Location.Create(this, entity.ReportingLocation), "", Severity.Warning); } @@ -159,13 +88,28 @@ private void CheckEntityHasUniqueLabel(string id, ICachedEntity entity) public Label GetNewLabel() => new Label(GetNewId()); - public Entity CreateNonNullEntity(ICachedEntityFactory factory, Type init) - where Entity : ICachedEntity - { - if (init is null) throw new ArgumentException("Unexpected null value", nameof(init)); + public TEntity CreateEntity(ICachedEntityFactory factory, object cacheKey, TInit init) + where TEntity : ICachedEntity => + cacheKey is ISymbol s ? CreateEntity(factory, s, init, symbolEntityCache) : CreateEntity(factory, cacheKey, init, objectEntityCache); - if (objectEntityCache.TryGetValue(init, out var cached)) - return (Entity)cached; + public TEntity CreateEntityFromSymbol(ICachedEntityFactory factory, TSymbol init) + where TSymbol : ISymbol + where TEntity : ICachedEntity => CreateEntity(factory, init, init, symbolEntityCache); + + /// + /// Creates and populates a new entity, or returns the existing one from the cache. + /// + /// The entity factory. + /// The key used for caching. + /// The initializer for the entity. + /// The dictionary to use for caching. + /// The new/existing entity. + private TEntity CreateEntity(ICachedEntityFactory factory, TCacheKey cacheKey, TInit init, IDictionary dictionary) + where TCacheKey : notnull + where TEntity : ICachedEntity + { + if (dictionary.TryGetValue(cacheKey, out var cached)) + return (TEntity)cached; using (StackGuard) { @@ -173,18 +117,16 @@ public Entity CreateNonNullEntity(ICachedEntityFactory @@ -225,18 +165,19 @@ public void AddFreshLabel(IEntity entity) } #if DEBUG_LABELS - readonly Dictionary idLabelCache = new Dictionary(); + private readonly Dictionary idLabelCache = new Dictionary(); #endif - readonly Dictionary objectEntityCache = new Dictionary(); - readonly Dictionary entityLabelCache = new Dictionary(); - readonly HashSet /// If the extraction is standalone. /// The name of the output DLL/EXE, or null if not specified (standalone extraction). - public Extractor(bool standalone, string outputPath, ILogger logger) + /// The object used for logging. + /// The object used for path transformations. + public Extractor(bool standalone, string outputPath, ILogger logger, PathTransformer pathTransformer) { Standalone = standalone; OutputPath = outputPath; Logger = logger; + PathTransformer = pathTransformer; } // Limit the number of error messages in the log file // to handle pathological cases. - const int maxErrors = 1000; + private const int maxErrors = 1000; - readonly object mutex = new object(); + private readonly object mutex = new object(); public void Message(Message msg) { @@ -149,7 +152,7 @@ public void Message(Message msg) // Roslyn framework has no apparent mechanism to associate assemblies with their files. // So this lookup table needs to be populated. - readonly Dictionary referenceFilenames = new Dictionary(); + private readonly Dictionary referenceFilenames = new Dictionary(); public void SetAssemblyFile(string assembly, string file) { @@ -166,8 +169,8 @@ public int Errors get; private set; } - readonly ISet missingTypes = new SortedSet(); - readonly ISet missingNamespaces = new SortedSet(); + private readonly ISet missingTypes = new SortedSet(); + private readonly ISet missingNamespaces = new SortedSet(); public void MissingType(string fqn, bool fromSource) { @@ -187,9 +190,9 @@ public void MissingNamespace(string fqdn, bool fromSource) } } - public Context CreateContext(Compilation c, TrapWriter trapWriter, IExtractionScope scope) + public Context CreateContext(Compilation c, TrapWriter trapWriter, IExtractionScope scope, bool addAssemblyTrapPrefix) { - return new Context(this, c, trapWriter, scope); + return new Context(this, c, trapWriter, scope, addAssemblyTrapPrefix); } public IEnumerable MissingTypes => missingTypes; @@ -205,5 +208,7 @@ public string OutputPath public ILogger Logger { get; private set; } public static string Version => $"{ThisAssembly.Git.BaseTag} ({ThisAssembly.Git.Sha})"; + + public PathTransformer PathTransformer { get; } } } diff --git a/csharp/extractor/Semmle.Extraction/FilePattern.cs b/csharp/extractor/Semmle.Extraction/FilePattern.cs new file mode 100644 index 000000000000..b2b6c01faded --- /dev/null +++ b/csharp/extractor/Semmle.Extraction/FilePattern.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Diagnostics.CodeAnalysis; +using Semmle.Util; + +namespace Semmle.Extraction +{ + public sealed class InvalidFilePatternException : Exception + { + public InvalidFilePatternException(string pattern, string message) : + base($"Invalid file pattern '{pattern}': {message}") + { } + } + + /// + /// A file pattern, as used in either an extractor layout file or + /// a path transformer file. + /// + public sealed class FilePattern + { + /// + /// Whether this is an inclusion pattern. + /// + public bool Include { get; } + + public FilePattern(string pattern) + { + Include = true; + if (pattern.StartsWith("-")) + { + pattern = pattern.Substring(1); + Include = false; + } + pattern = FileUtils.ConvertToUnix(pattern.Trim()).TrimStart('/'); + RegexPattern = BuildRegex(pattern).ToString(); + } + + /// + /// Constructs a regex string from a file pattern. Throws + /// `InvalidFilePatternException` for invalid patterns. + /// + private static StringBuilder BuildRegex(string pattern) + { + bool HasCharAt(int i, Predicate p) => + i >= 0 && i < pattern.Length && p(pattern[i]); + var sb = new StringBuilder(); + var i = 0; + var seenDoubleSlash = false; + sb.Append('^'); + while (i < pattern.Length) + { + if (pattern[i] == '/') + { + if (HasCharAt(i + 1, c => c == '/')) + { + if (seenDoubleSlash) + throw new InvalidFilePatternException(pattern, "'//' is allowed at most once."); + sb.Append("(?/)"); + i += 2; + seenDoubleSlash = true; + } + else + { + sb.Append('/'); + i++; + } + } + else if (pattern[i] == '*') + { + if (HasCharAt(i + 1, c => c == '*')) + { + if (HasCharAt(i - 1, c => c != '/')) + throw new InvalidFilePatternException(pattern, "'**' preceeded by non-`/` character."); + if (HasCharAt(i + 2, c => c != '/')) + throw new InvalidFilePatternException(pattern, "'**' succeeded by non-`/` character"); + sb.Append(".*"); + i += 2; + } + else + { + sb.Append("[^/]*"); + i++; + } + } + else + { + sb.Append(Regex.Escape(pattern[i++].ToString())); + } + } + return sb.Append(".*"); + } + + + /// + /// The regex pattern compiled from this file pattern. + /// + public string RegexPattern { get; } + + /// + /// Returns `true` if the set of file patterns `patterns` match the path `path`. + /// If so, `transformerSuffix` will contain the part of `path` that needs to be + /// suffixed when using path transformers. + /// + public static bool Matches(IEnumerable patterns, string path, [NotNullWhen(true)] out string? transformerSuffix) + { + path = FileUtils.ConvertToUnix(path).TrimStart('/'); + + foreach (var pattern in patterns.Reverse()) + { + var m = new Regex(pattern.RegexPattern).Match(path); + if (m.Success) + { + if (pattern.Include) + { + transformerSuffix = m.Groups.TryGetValue("doubleslash", out var group) + ? path.Substring(group.Index) + : path; + return true; + } + + transformerSuffix = null; + return false; + } + } + + transformerSuffix = null; + return false; + } + } +} diff --git a/csharp/extractor/Semmle.Extraction/FreshEntity.cs b/csharp/extractor/Semmle.Extraction/FreshEntity.cs index d117eefc5942..e8569cd9c918 100644 --- a/csharp/extractor/Semmle.Extraction/FreshEntity.cs +++ b/csharp/extractor/Semmle.Extraction/FreshEntity.cs @@ -1,5 +1,3 @@ -using Semmle.Extraction.Entities; -using System; using System.IO; namespace Semmle.Extraction @@ -9,9 +7,9 @@ namespace Semmle.Extraction /// public abstract class FreshEntity : IEntity { - protected readonly Context cx; + protected Context cx { get; } - public FreshEntity(Context cx) + protected FreshEntity(Context cx) { this.cx = cx; cx.AddFreshLabel(this); @@ -46,11 +44,9 @@ public string DebugContents { get { - using (var writer = new StringWriter()) - { - Populate(writer); - return writer.ToString(); - } + using var writer = new StringWriter(); + Populate(writer); + return writer.ToString(); } } diff --git a/csharp/extractor/Semmle.Extraction/Id.cs b/csharp/extractor/Semmle.Extraction/Id.cs index e2a65e5206ae..3843bfb4531e 100644 --- a/csharp/extractor/Semmle.Extraction/Id.cs +++ b/csharp/extractor/Semmle.Extraction/Id.cs @@ -1,7 +1,5 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Linq; namespace Semmle.Extraction { @@ -25,7 +23,7 @@ public interface IId /// public class FreshId : IId { - FreshId() { } + private FreshId() { } /// /// Gets the singleton instance. @@ -50,26 +48,27 @@ public void AppendTo(TextWriter trapFile) /// public class Key : IId { - readonly StringWriter TrapBuilder = new StringWriter(); + private readonly StringWriter trapBuilder = new StringWriter(); /// /// Creates a new key by concatenating the contents of the supplied arguments. /// public Key(params object[] args) { - TrapBuilder = new StringWriter(); + trapBuilder = new StringWriter(); foreach (var arg in args) { - if (arg is IEntity) + if (arg is IEntity entity) { - var key = ((IEntity)arg).Label; - TrapBuilder.Write("{#"); - TrapBuilder.Write(key.Value.ToString()); - TrapBuilder.Write("}"); + var key = entity.Label; + trapBuilder.Write("{#"); + trapBuilder.Write(key.Value.ToString()); + trapBuilder.Write("}"); } else - TrapBuilder.Write(arg.ToString()); - + { + trapBuilder.Write(arg.ToString()); + } } } @@ -79,12 +78,12 @@ public Key(params object[] args) /// public Key(Action action) { - action(TrapBuilder); + action(trapBuilder); } public override string ToString() { - return TrapBuilder.ToString(); + return trapBuilder.ToString(); } public override bool Equals(object? obj) @@ -92,15 +91,15 @@ public override bool Equals(object? obj) if (obj is null || obj.GetType() != GetType()) return false; var id = (Key)obj; - return TrapBuilder.ToString() == id.TrapBuilder.ToString(); + return trapBuilder.ToString() == id.trapBuilder.ToString(); } - public override int GetHashCode() => TrapBuilder.ToString().GetHashCode(); + public override int GetHashCode() => trapBuilder.ToString().GetHashCode(); public void AppendTo(TextWriter trapFile) { trapFile.Write("@\""); - trapFile.Write(TrapBuilder.ToString()); + trapFile.Write(trapBuilder.ToString()); trapFile.Write("\""); } } @@ -117,14 +116,14 @@ public Label(int value) : this() public int Value { get; private set; } - static public readonly Label InvalidLabel = new Label(0); + public static Label InvalidLabel { get; } = new Label(0); public bool Valid => Value > 0; public override string ToString() { if (!Valid) - throw new NullReferenceException("Attempt to use an invalid label"); + throw new InvalidOperationException("Attempt to use an invalid label"); return "#" + Value; } @@ -135,7 +134,8 @@ public override string ToString() public override bool Equals(object? other) { - if (other is null) return false; + if (other is null) + return false; return GetType() == other.GetType() && ((Label)other).Value == Value; } @@ -148,7 +148,7 @@ public override bool Equals(object? other) public void AppendTo(System.IO.TextWriter trapFile) { if (!Valid) - throw new NullReferenceException("Attempt to use an invalid label"); + throw new InvalidOperationException("Attempt to use an invalid label"); trapFile.Write('#'); trapFile.Write(Value); diff --git a/csharp/extractor/Semmle.Extraction/Layout.cs b/csharp/extractor/Semmle.Extraction/Layout.cs index 9ab7ed5738a1..4871f4c83aed 100644 --- a/csharp/extractor/Semmle.Extraction/Layout.cs +++ b/csharp/extractor/Semmle.Extraction/Layout.cs @@ -26,7 +26,7 @@ public InvalidLayoutException(string file, string message) : /// /// List of blocks in the layout file. /// - readonly List blocks; + private readonly List blocks; /// /// A subproject in the layout file. @@ -36,12 +36,12 @@ public class SubProject /// /// The trap folder, or null for current directory. /// - public readonly string? TRAP_FOLDER; + public string? TRAP_FOLDER { get; } /// /// The source archive, or null to skip. /// - public readonly string? SOURCE_ARCHIVE; + public string? SOURCE_ARCHIVE { get; } public SubProject(string? traps, string? archive) { @@ -54,18 +54,19 @@ public SubProject(string? traps, string? archive) /// /// The source file. /// The full filepath of the trap file. - public string GetTrapPath(ILogger logger, string srcFile, TrapWriter.CompressionMode trapCompression) => TrapWriter.TrapPath(logger, TRAP_FOLDER, srcFile, trapCompression); + public string GetTrapPath(ILogger logger, PathTransformer.ITransformedPath srcFile, TrapWriter.CompressionMode trapCompression) => + TrapWriter.TrapPath(logger, TRAP_FOLDER, srcFile, trapCompression); /// /// Creates a trap writer for a given source/assembly file. /// /// The source file. /// A newly created TrapWriter. - public TrapWriter CreateTrapWriter(ILogger logger, string srcFile, bool discardDuplicates, TrapWriter.CompressionMode trapCompression) => + public TrapWriter CreateTrapWriter(ILogger logger, PathTransformer.ITransformedPath srcFile, bool discardDuplicates, TrapWriter.CompressionMode trapCompression) => new TrapWriter(logger, srcFile, TRAP_FOLDER, SOURCE_ARCHIVE, discardDuplicates, trapCompression); } - readonly SubProject DefaultProject; + private readonly SubProject defaultProject; /// /// Finds the suitable directories for a given source file. @@ -73,14 +74,15 @@ public TrapWriter CreateTrapWriter(ILogger logger, string srcFile, bool discardD /// /// The file to look up. /// The relevant subproject, or null if not found. - public SubProject? LookupProjectOrNull(string sourceFile) + public SubProject? LookupProjectOrNull(PathTransformer.ITransformedPath sourceFile) { - if (!useLayoutFile) return DefaultProject; + if (!useLayoutFile) + return defaultProject; - return blocks. - Where(block => block.Matches(sourceFile)). - Select(block => block.Directories). - FirstOrDefault(); + return blocks + .Where(block => block.Matches(sourceFile)) + .Select(block => block.Directories) + .FirstOrDefault(); } /// @@ -89,12 +91,12 @@ public TrapWriter CreateTrapWriter(ILogger logger, string srcFile, bool discardD /// /// The file to look up. /// The relevant subproject, or DefaultProject if not found. - public SubProject LookupProjectOrDefault(string sourceFile) + public SubProject LookupProjectOrDefault(PathTransformer.ITransformedPath sourceFile) { - return LookupProjectOrNull(sourceFile) ?? DefaultProject; + return LookupProjectOrNull(sourceFile) ?? defaultProject; } - readonly bool useLayoutFile; + private readonly bool useLayoutFile; /// /// Default constructor reads parameters from the environment. @@ -121,11 +123,11 @@ public Layout(string? traps, string? archive, string? layout) if (useLayoutFile) { ReadLayoutFile(layout!); - DefaultProject = blocks[0].Directories; + defaultProject = blocks[0].Directories; } else { - DefaultProject = new SubProject(traps, archive); + defaultProject = new SubProject(traps, archive); } } @@ -134,20 +136,20 @@ public Layout(string? traps, string? archive, string? layout) /// /// The absolute path of the file to query. /// True iff there is no layout file or the layout file specifies the file. - public bool FileInLayout(string path) => LookupProjectOrNull(path) != null; + public bool FileInLayout(PathTransformer.ITransformedPath path) => LookupProjectOrNull(path) != null; - void ReadLayoutFile(string layout) + private void ReadLayoutFile(string layout) { try { var lines = File.ReadAllLines(layout); - int i = 0; + var i = 0; while (!lines[i].StartsWith("#")) i++; while (i < lines.Length) { - LayoutBlock block = new LayoutBlock(lines, ref i); + var block = new LayoutBlock(lines, ref i); blocks.Add(block); } @@ -165,41 +167,15 @@ void ReadLayoutFile(string layout) } } - sealed class LayoutBlock + internal sealed class LayoutBlock { - struct Condition - { - private readonly bool include; - private readonly string prefix; - - public bool Include => include; + private readonly List filePatterns = new List(); - public string Prefix => prefix; - - public Condition(string line) - { - include = false; - if (line.StartsWith("-")) - line = line.Substring(1); - else - include = true; - prefix = Normalise(line.Trim()); - } + public Layout.SubProject Directories { get; } - static public string Normalise(string path) - { - path = Path.GetFullPath(path); - return path.Replace('\\', '/'); - } - } - - private readonly List conditions = new List(); - - public readonly Layout.SubProject Directories; - - string? ReadVariable(string name, string line) + private static string? ReadVariable(string name, string line) { - string prefix = name + "="; + var prefix = name + "="; if (!line.StartsWith(prefix)) return null; return line.Substring(prefix.Length).Trim(); @@ -209,32 +185,20 @@ public LayoutBlock(string[] lines, ref int i) { // first line: #name i++; - string? TRAP_FOLDER = ReadVariable("TRAP_FOLDER", lines[i++]); + var trapFolder = ReadVariable("TRAP_FOLDER", lines[i++]); // Don't care about ODASA_DB. ReadVariable("ODASA_DB", lines[i++]); - string? SOURCE_ARCHIVE = ReadVariable("SOURCE_ARCHIVE", lines[i++]); + var sourceArchive = ReadVariable("SOURCE_ARCHIVE", lines[i++]); - Directories = new Layout.SubProject(TRAP_FOLDER, SOURCE_ARCHIVE); + Directories = new Layout.SubProject(trapFolder, sourceArchive); // Don't care about ODASA_BUILD_ERROR_DIR. ReadVariable("ODASA_BUILD_ERROR_DIR", lines[i++]); while (i < lines.Length && !lines[i].StartsWith("#")) { - conditions.Add(new Condition(lines[i++])); + filePatterns.Add(new FilePattern(lines[i++])); } } - public bool Matches(string path) - { - bool matches = false; - path = Condition.Normalise(path); - foreach (Condition condition in conditions) - { - if (condition.Include) - matches |= path.StartsWith(condition.Prefix); - else - matches &= !path.StartsWith(condition.Prefix); - } - return matches; - } + public bool Matches(PathTransformer.ITransformedPath path) => FilePattern.Matches(filePatterns, path.Value, out var _); } } diff --git a/csharp/extractor/Semmle.Extraction/LocationExtensions.cs b/csharp/extractor/Semmle.Extraction/LocationExtensions.cs index 339d1695b891..5ecaae8a3fed 100644 --- a/csharp/extractor/Semmle.Extraction/LocationExtensions.cs +++ b/csharp/extractor/Semmle.Extraction/LocationExtensions.cs @@ -18,9 +18,9 @@ public static class LocationExtensions /// Whether inner is completely container in outer. public static bool Contains(this Location outer, Location inner) { - bool sameFile = outer.SourceTree == inner.SourceTree; - bool startsBefore = outer.SourceSpan.Start <= inner.SourceSpan.Start; - bool endsAfter = outer.SourceSpan.End >= inner.SourceSpan.End; + var sameFile = outer.SourceTree == inner.SourceTree; + var startsBefore = outer.SourceSpan.Start <= inner.SourceSpan.Start; + var endsAfter = outer.SourceSpan.End >= inner.SourceSpan.End; return sameFile && startsBefore && endsAfter; } @@ -32,8 +32,8 @@ public static bool Contains(this Location outer, Location inner) /// Whether 'before' comes before 'after'. public static bool Before(this Location before, Location after) { - bool sameFile = before.SourceTree == after.SourceTree; - bool endsBefore = before.SourceSpan.End <= after.SourceSpan.Start; + var sameFile = before.SourceTree == after.SourceTree; + var endsBefore = before.SourceSpan.End <= after.SourceSpan.Start; return sameFile && endsBefore; } } diff --git a/csharp/extractor/Semmle.Extraction/Message.cs b/csharp/extractor/Semmle.Extraction/Message.cs index c617efaa5ba6..fbe91fb95e63 100644 --- a/csharp/extractor/Semmle.Extraction/Message.cs +++ b/csharp/extractor/Semmle.Extraction/Message.cs @@ -11,11 +11,11 @@ namespace Semmle.Extraction /// public class Message { - public readonly Severity Severity; - public readonly string Text; - public readonly string StackTrace; - public readonly string EntityText; - public readonly Entities.Location? Location; + public Severity Severity { get; } + public string Text { get; } + public string StackTrace { get; } + public string EntityText { get; } + public Entities.Location? Location { get; } public Message(string text, string entityText, Entities.Location? location, string? stackTrace = null, Severity severity = Severity.Error) { diff --git a/csharp/extractor/Semmle.Extraction/Options.cs b/csharp/extractor/Semmle.Extraction/Options.cs index a7d186f9e92f..fffe3c88b4bd 100644 --- a/csharp/extractor/Semmle.Extraction/Options.cs +++ b/csharp/extractor/Semmle.Extraction/Options.cs @@ -12,44 +12,44 @@ public abstract class CommonOptions : ICommandLineOptions /// /// The specified number of threads, or the default if unspecified. /// - public int Threads = Extractor.DefaultNumberOfThreads; + public int Threads { get; private set; } = System.Environment.ProcessorCount; /// /// The verbosity used in output and logging. /// - public Verbosity Verbosity = Verbosity.Info; + public Verbosity Verbosity { get; protected set; } = Verbosity.Info; /// /// Whether to output to the console. /// - public bool Console = false; + public bool Console { get; private set; } = false; /// /// Holds if CIL should be extracted. /// - public bool CIL = false; + public bool CIL { get; private set; } = false; /// /// Holds if assemblies shouldn't be extracted twice. /// - public bool Cache = true; + public bool Cache { get; private set; } = true; /// /// Whether to extract PDB information. /// - public bool PDB = false; + public bool PDB { get; private set; } = false; /// /// Whether "fast extraction mode" has been enabled. /// - public bool Fast = false; + public bool Fast { get; private set; } = false; /// /// The compression algorithm used for trap files. /// - public TrapWriter.CompressionMode TrapCompression = TrapWriter.CompressionMode.Gzip; + public TrapWriter.CompressionMode TrapCompression { get; set; } = TrapWriter.CompressionMode.Gzip; - public virtual bool handleOption(string key, string value) + public virtual bool HandleOption(string key, string value) { switch (key) { @@ -64,9 +64,9 @@ public virtual bool handleOption(string key, string value) } } - public abstract bool handleArgument(string argument); + public abstract bool HandleArgument(string argument); - public virtual bool handleFlag(string flag, bool value) + public virtual bool HandleFlag(string flag, bool value) { switch (flag) { @@ -98,6 +98,6 @@ public virtual bool handleFlag(string flag, bool value) } } - public abstract void invalidArgument(string argument); + public abstract void InvalidArgument(string argument); } } diff --git a/csharp/extractor/Semmle.Extraction/PathTransformer.cs b/csharp/extractor/Semmle.Extraction/PathTransformer.cs new file mode 100644 index 000000000000..31bcc4e0be6b --- /dev/null +++ b/csharp/extractor/Semmle.Extraction/PathTransformer.cs @@ -0,0 +1,177 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Diagnostics.CodeAnalysis; +using Semmle.Util; + +namespace Semmle.Extraction +{ + /// + /// A class for interpreting path transformers specified using the environment + /// variable `CODEQL_PATH_TRANSFORMER`. + /// + public sealed class PathTransformer + { + public class InvalidPathTransformerException : Exception + { + public InvalidPathTransformerException(string message) : + base($"Invalid path transformer specification: {message}") + { } + } + + /// + /// A transformed path. + /// + public interface ITransformedPath + { + string Value { get; } + + string Extension { get; } + + string NameWithoutExtension { get; } + + ITransformedPath? ParentDirectory { get; } + + ITransformedPath WithSuffix(string suffix); + + string DatabaseId { get; } + } + + private struct TransformedPath : ITransformedPath + { + public TransformedPath(string value) { this.value = value; } + private readonly string value; + + public string Value => value; + + public string Extension => Path.GetExtension(value)?.Substring(1) ?? ""; + + public string NameWithoutExtension => Path.GetFileNameWithoutExtension(value); + + public ITransformedPath? ParentDirectory + { + get + { + var dir = Path.GetDirectoryName(value); + if (dir is null) + return null; + var isWindowsDriveLetter = dir.Length == 2 && char.IsLetter(dir[0]) && dir[1] == ':'; + if (isWindowsDriveLetter) + return null; + return new TransformedPath(FileUtils.ConvertToUnix(dir)); + } + } + + public ITransformedPath WithSuffix(string suffix) => new TransformedPath(value + suffix); + + public string DatabaseId + { + get + { + var ret = value; + if (ret.Length >= 2 && ret[1] == ':' && Char.IsLower(ret[0])) + ret = Char.ToUpper(ret[0]) + "_" + ret.Substring(2); + return ret.Replace('\\', '/').Replace(":", "_"); + } + } + + public override int GetHashCode() => 11 * value.GetHashCode(); + + public override bool Equals(object? obj) => obj is TransformedPath tp && tp.value == value; + + public override string ToString() => value; + } + + private readonly Func transform; + + /// + /// Returns the path obtained by transforming `path`. + /// + public ITransformedPath Transform(string path) => new TransformedPath(transform(path)); + + /// + /// Default constructor reads parameters from the environment. + /// + public PathTransformer(IPathCache pathCache) : + this(pathCache, Environment.GetEnvironmentVariable("CODEQL_PATH_TRANSFORMER") is string file ? File.ReadAllLines(file) : null) + { + } + + /// + /// Creates a path transformer based on the specification in `lines`. + /// Throws `InvalidPathTransformerException` for invalid specifications. + /// + public PathTransformer(IPathCache pathCache, string[]? lines) + { + if (lines is null) + { + transform = path => FileUtils.ConvertToUnix(pathCache.GetCanonicalPath(path)); + return; + } + + var sections = ParsePathTransformerSpec(lines); + transform = path => + { + path = FileUtils.ConvertToUnix(pathCache.GetCanonicalPath(path)); + foreach (var section in sections) + { + if (section.Matches(path, out var transformed)) + return transformed; + } + return path; + }; + } + + private static IEnumerable ParsePathTransformerSpec(string[] lines) + { + var sections = new List(); + try + { + var i = 0; + while (i < lines.Length && !lines[i].StartsWith("#")) + i++; + while (i < lines.Length) + { + var section = new TransformerSection(lines, ref i); + sections.Add(section); + } + + if (sections.Count == 0) + throw new InvalidPathTransformerException("contains no sections."); + } + catch (InvalidFilePatternException ex) + { + throw new InvalidPathTransformerException(ex.Message); + } + return sections; + } + } + + internal sealed class TransformerSection + { + private readonly string name; + private readonly List filePatterns = new List(); + + public TransformerSection(string[] lines, ref int i) + { + name = lines[i++].Substring(1); // skip the '#' + for (; i < lines.Length && !lines[i].StartsWith("#"); i++) + { + var line = lines[i]; + if (!string.IsNullOrWhiteSpace(line)) + filePatterns.Add(new FilePattern(line)); + } + } + + public bool Matches(string path, [NotNullWhen(true)] out string? transformed) + { + if (FilePattern.Matches(filePatterns, path, out var suffix)) + { + transformed = FileUtils.ConvertToUnix(name) + suffix; + return true; + } + transformed = null; + return false; + } + } +} diff --git a/csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj b/csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj index b8a6d8be614b..cc32fc33b38c 100644 --- a/csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj +++ b/csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj @@ -1,7 +1,7 @@  - netcoreapp3.0 + netcoreapp3.1 Semmle.Extraction Semmle.Extraction false @@ -15,10 +15,11 @@ - - runtime; build; native; contentfiles; analyzers; buildtransitive -all - + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + diff --git a/csharp/extractor/Semmle.Extraction/Symbol.cs b/csharp/extractor/Semmle.Extraction/Symbol.cs index 925fba2e3fdb..4366cff7f06e 100644 --- a/csharp/extractor/Semmle.Extraction/Symbol.cs +++ b/csharp/extractor/Semmle.Extraction/Symbol.cs @@ -1,14 +1,15 @@ using System.IO; +using Microsoft.CodeAnalysis; namespace Semmle.Extraction { /// /// An abstract symbol, which encapsulates a data type (such as a C# symbol). /// - /// The type of the symbol. - public abstract class CachedEntity : ICachedEntity + /// The type of the symbol. + public abstract class CachedEntity : ICachedEntity { - public CachedEntity(Context context, Initializer init) + protected CachedEntity(Context context, TSymbol init) { Context = context; symbol = init; @@ -29,11 +30,9 @@ public string DebugContents { get { - using (var trap = new StringWriter()) - { - Populate(trap); - return trap.ToString(); - } + using var trap = new StringWriter(); + Populate(trap); + return trap.ToString(); } } @@ -42,14 +41,14 @@ public Context Context get; } - public Initializer symbol + public TSymbol symbol { get; } object? ICachedEntity.UnderlyingObject => symbol; - public Initializer UnderlyingObject => symbol; + public TSymbol UnderlyingObject => symbol; public abstract void WriteId(System.IO.TextWriter trapFile); @@ -65,24 +64,30 @@ public abstract bool NeedsPopulation get; } - /// - /// Runs the given action , guarding for trap duplication - /// based on the ID an location of this entity. - /// - protected void WithDuplicationGuard(System.Action a, IEntity location) - { - var key = new Key(this, location); - Context.WithDuplicationGuard(key, a); - } - public override int GetHashCode() => symbol is null ? 0 : symbol.GetHashCode(); public override bool Equals(object? obj) { - var other = obj as CachedEntity; + var other = obj as CachedEntity; return other?.GetType() == GetType() && Equals(other.symbol, symbol); } public abstract TrapStackBehaviour TrapStackBehaviour { get; } } + + /// + /// A class used to wrap an `ISymbol` object, which uses `SymbolEqualityComparer.Default` + /// for comparison. + /// + public sealed class SymbolEqualityWrapper + { + public ISymbol Symbol { get; } + + public SymbolEqualityWrapper(ISymbol symbol) { Symbol = symbol; } + + public override bool Equals(object? other) => + other is SymbolEqualityWrapper sew && SymbolEqualityComparer.Default.Equals(Symbol, sew.Symbol); + + public override int GetHashCode() => 11 * Symbol.GetHashCode(); + } } diff --git a/csharp/extractor/Semmle.Extraction/TrapExtensions.cs b/csharp/extractor/Semmle.Extraction/TrapExtensions.cs index 1a25f642e7ac..11111467147e 100644 --- a/csharp/extractor/Semmle.Extraction/TrapExtensions.cs +++ b/csharp/extractor/Semmle.Extraction/TrapExtensions.cs @@ -32,7 +32,8 @@ public static void WriteSubId(this TextWriter trapFile, IEntity entity) public static void WriteSeparator(this TextWriter trapFile, string separator, ref int index) { - if (index++ > 0) trapFile.Write(separator); + if (index++ > 0) + trapFile.Write(separator); } @@ -85,16 +86,16 @@ public static TextWriter WriteColumn(this TextWriter trapFile, object o) case Enum _: return trapFile.WriteColumn((int)o); default: - throw new ArgumentException(nameof(o)); + throw new NotSupportedException($"Unsupported object type '{o.GetType()}' received"); } } - const int maxStringBytes = 1 << 20; // 1MB - static readonly System.Text.Encoding encoding = System.Text.Encoding.UTF8; + private const int maxStringBytes = 1 << 20; // 1MB + private static readonly System.Text.Encoding encoding = System.Text.Encoding.UTF8; private static bool NeedsTruncation(string s) { - // Optimization: only count the actual number of bytes if there is the possibility + // Optimization: only count the actual number of bytes if there is the possibility // of the string exceeding maxStringBytes return encoding.GetMaxByteCount(s.Length) > maxStringBytes && encoding.GetByteCount(s) > maxStringBytes; @@ -110,7 +111,7 @@ private static bool NeedsTruncation(string s) /// The truncated string. private static string TruncateString(string s, ref int bytesRemaining) { - int outputLen = encoding.GetByteCount(s); + var outputLen = encoding.GetByteCount(s); if (outputLen > bytesRemaining) { outputLen = 0; @@ -149,7 +150,7 @@ public static void WriteTrapString(this TextWriter trapFile, string s) if (NeedsTruncation(s)) { // Slow path - int remaining = maxStringBytes; + var remaining = maxStringBytes; WriteTruncatedString(trapFile, s, ref remaining); } else @@ -169,7 +170,7 @@ public static void WriteTuple(this TextWriter trapFile, string name, params obje { trapFile.Write(name); trapFile.Write('('); - int index = 0; + var index = 0; foreach (var p in @params) { trapFile.WriteSeparator(",", ref index); @@ -246,10 +247,13 @@ public static TextWriter AppendList(this TextWriter trapFile, string separato /// The original trap builder (fluent interface). public static TextWriter BuildList(this TextWriter trapFile, string separator, IEnumerable items, Action action) { - bool first = true; + var first = true; foreach (var item in items) { - if (first) first = false; else trapFile.Write(separator); + if (first) + first = false; + else + trapFile.Write(separator); action(item, trapFile); } return trapFile; diff --git a/csharp/extractor/Semmle.Extraction/TrapWriter.cs b/csharp/extractor/Semmle.Extraction/TrapWriter.cs index 7ea08eafc1c1..af7259b64e81 100644 --- a/csharp/extractor/Semmle.Extraction/TrapWriter.cs +++ b/csharp/extractor/Semmle.Extraction/TrapWriter.cs @@ -14,12 +14,6 @@ public interface ITrapEmitter public sealed class TrapWriter : IDisposable { - public enum InnerPathComputation - { - ABSOLUTE, - RELATIVE - } - public enum CompressionMode { None, @@ -31,28 +25,28 @@ public enum CompressionMode /// The location of the src_archive directory. /// private readonly string? archive; - private static readonly Encoding UTF8 = new UTF8Encoding(false); + private static readonly Encoding utf8 = new UTF8Encoding(false); private readonly bool discardDuplicates; public int IdCounter { get; set; } = 1; - readonly Lazy WriterLazy; + private readonly Lazy writerLazy; - public StreamWriter Writer => WriterLazy.Value; + public StreamWriter Writer => writerLazy.Value; - readonly ILogger Logger; + private readonly ILogger logger; - readonly CompressionMode TrapCompression; + private readonly CompressionMode trapCompression; - public TrapWriter(ILogger logger, string outputfile, string? trap, string? archive, bool discardDuplicates, CompressionMode trapCompression) + public TrapWriter(ILogger logger, PathTransformer.ITransformedPath outputfile, string? trap, string? archive, bool discardDuplicates, CompressionMode trapCompression) { - Logger = logger; - TrapCompression = trapCompression; + this.logger = logger; + this.trapCompression = trapCompression; - TrapFile = TrapPath(Logger, trap, outputfile, trapCompression); + TrapFile = TrapPath(this.logger, trap, outputfile, trapCompression); - WriterLazy = new Lazy(() => + writerLazy = new Lazy(() => { var tempPath = trap ?? Path.GetTempPath(); @@ -87,11 +81,11 @@ public TrapWriter(ILogger logger, string outputfile, string? trap, string? archi compressionStream = fileStream; break; default: - throw new ArgumentException(nameof(trapCompression)); + throw new ArgumentOutOfRangeException(nameof(trapCompression), trapCompression, "Unsupported compression type"); } - return new StreamWriter(compressionStream, UTF8, 2000000); + return new StreamWriter(compressionStream, utf8, 2000000); }); this.archive = archive; this.discardDuplicates = discardDuplicates; @@ -100,23 +94,25 @@ public TrapWriter(ILogger logger, string outputfile, string? trap, string? archi /// /// The output filename of the trap. /// - public readonly string TrapFile; - string tmpFile = ""; // The temporary file which is moved to trapFile once written. + public string TrapFile { get; } + private string tmpFile = ""; // The temporary file which is moved to trapFile once written. /// /// Adds the specified input file to the source archive. It may end up in either the normal or long path area /// of the source archive, depending on the length of its full path. /// - /// The path to the input file. + /// The path to the input file. + /// The transformed path to the input file. /// The encoding used by the input file. - public void Archive(string inputPath, Encoding inputEncoding) + public void Archive(string originalPath, PathTransformer.ITransformedPath transformedPath, Encoding inputEncoding) { - if (string.IsNullOrEmpty(archive)) return; + if (string.IsNullOrEmpty(archive)) + return; // Calling GetFullPath makes this use the canonical capitalisation, if the file exists. - string fullInputPath = Path.GetFullPath(inputPath); + var fullInputPath = Path.GetFullPath(originalPath); - ArchivePath(fullInputPath, inputEncoding); + ArchivePath(fullInputPath, transformedPath, inputEncoding); } /// @@ -124,14 +120,12 @@ public void Archive(string inputPath, Encoding inputEncoding) /// /// The path of the file. /// The contents of the file. - public void Archive(string inputPath, string contents) + public void Archive(PathTransformer.ITransformedPath inputPath, string contents) { - if (string.IsNullOrEmpty(archive)) return; + if (string.IsNullOrEmpty(archive)) + return; - // Calling GetFullPath makes this use the canonical capitalisation, if the file exists. - string fullInputPath = Path.GetFullPath(inputPath); - - ArchiveContents(fullInputPath, contents); + ArchiveContents(inputPath, contents); } /// @@ -142,7 +136,7 @@ public void Archive(string inputPath, string contents) /// The source filename. /// The destination filename. /// true if the file was moved. - static bool TryMove(string sourceFile, string destFile) + private static bool TryMove(string sourceFile, string destFile) { try { @@ -169,9 +163,9 @@ public void Dispose() { try { - if (WriterLazy.IsValueCreated) + if (writerLazy.IsValueCreated) { - WriterLazy.Value.Close(); + writerLazy.Value.Close(); if (TryMove(tmpFile, TrapFile)) return; @@ -186,16 +180,16 @@ public void Dispose() if (existingHash != hash) { var root = TrapFile.Substring(0, TrapFile.Length - 8); // Remove trailing ".trap.gz" - if (TryMove(tmpFile, $"{root}-{hash}.trap{TrapExtension(TrapCompression)}")) + if (TryMove(tmpFile, $"{root}-{hash}.trap{TrapExtension(trapCompression)}")) return; } - Logger.Log(Severity.Info, "Identical trap file for {0} already exists", TrapFile); + logger.Log(Severity.Info, "Identical trap file for {0} already exists", TrapFile); FileUtils.TryDelete(tmpFile); } } catch (Exception ex) // lgtm[cs/catch-of-all-exceptions] { - Logger.Log(Severity.Error, "Failed to move the trap file from {0} to {1} because {2}", tmpFile, TrapFile, ex); + logger.Log(Severity.Error, "Failed to move the trap file from {0} to {1} because {2}", tmpFile, TrapFile, ex); } } @@ -210,20 +204,21 @@ public void Emit(ITrapEmitter emitter) /// source archive less than the system path limit of 260 characters. /// /// The full path to the input file. + /// The transformed path to the input file. /// The encoding used by the input file. /// If the output path in the source archive would /// exceed the system path limit of 260 characters. - private void ArchivePath(string fullInputPath, Encoding inputEncoding) + private void ArchivePath(string fullInputPath, PathTransformer.ITransformedPath transformedPath, Encoding inputEncoding) { - string contents = File.ReadAllText(fullInputPath, inputEncoding); - ArchiveContents(fullInputPath, contents); + var contents = File.ReadAllText(fullInputPath, inputEncoding); + ArchiveContents(transformedPath, contents); } - private void ArchiveContents(string fullInputPath, string contents) + private void ArchiveContents(PathTransformer.ITransformedPath transformedPath, string contents) { - string dest = NestPaths(Logger, archive, fullInputPath, InnerPathComputation.ABSOLUTE); - string tmpSrcFile = Path.GetTempFileName(); - File.WriteAllText(tmpSrcFile, contents, UTF8); + var dest = NestPaths(logger, archive, transformedPath.Value); + var tmpSrcFile = Path.GetTempFileName(); + File.WriteAllText(tmpSrcFile, contents, utf8); try { FileUtils.MoveOrReplace(tmpSrcFile, dest); @@ -232,18 +227,15 @@ private void ArchiveContents(string fullInputPath, string contents) { // If this happened, it was probably because the same file was compiled multiple times. // In any case, this is not a fatal error. - Logger.Log(Severity.Warning, "Problem archiving " + dest + ": " + ex); + logger.Log(Severity.Warning, "Problem archiving " + dest + ": " + ex); } } - public static string NestPaths(ILogger logger, string? outerpath, string innerpath, InnerPathComputation innerPathComputation) + public static string NestPaths(ILogger logger, string? outerpath, string innerpath) { - string nested = innerpath; + var nested = innerpath; if (!string.IsNullOrEmpty(outerpath)) { - if (!Path.IsPathRooted(innerpath) && innerPathComputation == InnerPathComputation.ABSOLUTE) - innerpath = Path.GetFullPath(innerpath); - // Remove all leading path separators / or \ // For example, UNC paths have two leading \\ innerpath = innerpath.TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); @@ -265,24 +257,24 @@ public static string NestPaths(ILogger logger, string? outerpath, string innerpa return nested; } - static string TrapExtension(CompressionMode compression) + private static string TrapExtension(CompressionMode compression) { switch (compression) { case CompressionMode.None: return ""; case CompressionMode.Gzip: return ".gz"; case CompressionMode.Brotli: return ".br"; - default: throw new ArgumentException(nameof(compression)); + default: throw new ArgumentOutOfRangeException(nameof(compression), compression, "Unsupported compression type"); } } - public static string TrapPath(ILogger logger, string? folder, string filename, TrapWriter.CompressionMode trapCompression) + public static string TrapPath(ILogger logger, string? folder, PathTransformer.ITransformedPath path, TrapWriter.CompressionMode trapCompression) { - filename = $"{Path.GetFullPath(filename)}.trap{TrapExtension(trapCompression)}"; + var filename = $"{path.Value}.trap{TrapExtension(trapCompression)}"; if (string.IsNullOrEmpty(folder)) folder = Directory.GetCurrentDirectory(); - return NestPaths(logger, folder, filename, InnerPathComputation.ABSOLUTE); ; + return NestPaths(logger, folder, filename); } } } diff --git a/csharp/extractor/Semmle.Extraction/Tuple.cs b/csharp/extractor/Semmle.Extraction/Tuple.cs index 85d95d7e031b..bfe660926d6d 100644 --- a/csharp/extractor/Semmle.Extraction/Tuple.cs +++ b/csharp/extractor/Semmle.Extraction/Tuple.cs @@ -7,13 +7,13 @@ namespace Semmle.Extraction /// public struct Tuple : ITrapEmitter { - readonly string Name; - readonly object[] Args; + private readonly string name; + private readonly object[] args; public Tuple(string name, params object[] args) { - Name = name; - Args = args; + this.name = name; + this.args = args; } /// @@ -22,17 +22,15 @@ public Tuple(string name, params object[] args) /// The trap file to write to. public void EmitTrap(TextWriter trapFile) { - trapFile.WriteTuple(Name, Args); + trapFile.WriteTuple(name, args); } public override string ToString() { // Only implemented for debugging purposes - using (var writer = new StringWriter()) - { - EmitTrap(writer); - return writer.ToString(); - } + using var writer = new StringWriter(); + EmitTrap(writer); + return writer.ToString(); } } } diff --git a/csharp/extractor/Semmle.Extraction/Tuples.cs b/csharp/extractor/Semmle.Extraction/Tuples.cs index 3297b705f585..0a71ba6b3d90 100644 --- a/csharp/extractor/Semmle.Extraction/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction/Tuples.cs @@ -6,7 +6,7 @@ namespace Semmle.Extraction /// /// Methods for creating DB tuples. /// - static class Tuples + internal static class Tuples { public static void assemblies(this System.IO.TextWriter trapFile, Assembly assembly, File file, string identifier, string name, string version) { diff --git a/csharp/extractor/Semmle.Util.Tests/ActionMap.cs b/csharp/extractor/Semmle.Util.Tests/ActionMap.cs index 0cc815a80c81..5c2b210834ae 100644 --- a/csharp/extractor/Semmle.Util.Tests/ActionMap.cs +++ b/csharp/extractor/Semmle.Util.Tests/ActionMap.cs @@ -51,5 +51,3 @@ public void TestMultipleActions() } } - - diff --git a/csharp/extractor/Semmle.Util.Tests/CanonicalPathCache.cs b/csharp/extractor/Semmle.Util.Tests/CanonicalPathCache.cs index c76256ef9b24..2fe8eb12d71d 100644 --- a/csharp/extractor/Semmle.Util.Tests/CanonicalPathCache.cs +++ b/csharp/extractor/Semmle.Util.Tests/CanonicalPathCache.cs @@ -6,12 +6,11 @@ namespace SemmleTests.Semmle.Util { - public class CanonicalPathCacheTest : IDisposable + public sealed class CanonicalPathCacheTest : IDisposable { - readonly ILogger Logger = new LoggerMock(); - readonly string root; - - CanonicalPathCache cache; + private readonly ILogger Logger = new LoggerMock(); + private readonly string root; + private CanonicalPathCache cache; public CanonicalPathCacheTest() { @@ -21,20 +20,13 @@ public CanonicalPathCacheTest() // Change directories to a directory that is in canonical form. Directory.SetCurrentDirectory(cache.GetCanonicalPath(Path.GetTempPath())); - if (Win32.IsWindows()) - { - root = @"X:\"; - } - else - { - root = "/"; - } - + root = Win32.IsWindows() ? @"X:\" : "/"; } - void IDisposable.Dispose() + public void Dispose() { File.Delete("abc"); + Logger.Dispose(); } [Fact] @@ -143,10 +135,10 @@ public void CanonicalPathCacheSize() Assert.Equal(0, cache.CacheSize); // The file "ABC" will fill the cache with parent directory info. - string cp = cache.GetCanonicalPath("ABC"); + cache.GetCanonicalPath("ABC"); Assert.True(cache.CacheSize == 2); - cp = cache.GetCanonicalPath("def"); + string cp = cache.GetCanonicalPath("def"); Assert.Equal(2, cache.CacheSize); Assert.Equal(Path.GetFullPath("def"), cp); } @@ -165,7 +157,7 @@ public void CanonicalPathPreserveLinksTests() RunAllTests(); } - void RunAllTests() + private void RunAllTests() { CanonicalPathRelativeFile(); CanonicalPathAbsoluteFile(); @@ -180,13 +172,11 @@ void RunAllTests() CanonicalPathDots(); } - class LoggerMock : ILogger + private sealed class LoggerMock : ILogger { public void Dispose() { } public void Log(Severity s, string text) { } - - public void Log(Severity s, string text, params object[] args) { } } } } diff --git a/csharp/extractor/Semmle.Util.Tests/LongPaths.cs b/csharp/extractor/Semmle.Util.Tests/LongPaths.cs index c2a3f500de6d..44b047b6d8dd 100644 --- a/csharp/extractor/Semmle.Util.Tests/LongPaths.cs +++ b/csharp/extractor/Semmle.Util.Tests/LongPaths.cs @@ -10,38 +10,38 @@ namespace SemmleTests.Semmle.Util /// Ensure that the Extractor works with long paths. /// These should be handled by .NET Core. /// - public class LongPaths : IDisposable + public sealed class LongPaths : IDisposable { - static readonly string tmpDir = Path.GetTempPath(); - static readonly string shortPath = Path.Combine(tmpDir, "test.txt"); - static readonly string longPath = Path.Combine(tmpDir, "aaaaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + private static readonly string tmpDir = Path.GetTempPath(); + private static readonly string shortPath = Path.Combine(tmpDir, "test.txt"); + private static readonly string longPath = Path.Combine(tmpDir, "aaaaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "ccccccccccccccccccccccccccccccc", "ddddddddddddddddddddddddddddddddddddd", "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "fffffffffffffffffffffffffffffffff", - "ggggggggggggggggggggggggggggggggggg","hhhhhhhhhhhhhhhhhhhhhhhhhhhhhh","iiiiiiiiiiiiiiii.txt"); + "ggggggggggggggggggggggggggggggggggg", "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", "iiiiiiiiiiiiiiii.txt"); public LongPaths() { CleanUp(); } - void IDisposable.Dispose() + public void Dispose() { CleanUp(); } - void CleanUp() + private static void CleanUp() { try { File.Delete(shortPath); } - catch(DirectoryNotFoundException) + catch (DirectoryNotFoundException) { } try { File.Delete(longPath); } - catch(DirectoryNotFoundException) + catch (DirectoryNotFoundException) { } } @@ -93,7 +93,7 @@ public void Replace() Assert.Equal("def", File.ReadAllText(shortPath)); } - byte[] buffer1 = new byte[10] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + private readonly byte[] buffer1 = new byte[10] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; [Fact] public void CreateShortStream() diff --git a/csharp/extractor/Semmle.Util.Tests/Semmle.Util.Tests.csproj b/csharp/extractor/Semmle.Util.Tests/Semmle.Util.Tests.csproj index a82997aea637..3acf1a1fa42b 100644 --- a/csharp/extractor/Semmle.Util.Tests/Semmle.Util.Tests.csproj +++ b/csharp/extractor/Semmle.Util.Tests/Semmle.Util.Tests.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp3.0 + netcoreapp3.1 false win-x64;linux-x64;osx-x64 enable diff --git a/csharp/extractor/Semmle.Util.Tests/TextTest.cs b/csharp/extractor/Semmle.Util.Tests/TextTest.cs index 618f1f1fede5..a24d20c06c54 100644 --- a/csharp/extractor/Semmle.Util.Tests/TextTest.cs +++ b/csharp/extractor/Semmle.Util.Tests/TextTest.cs @@ -62,7 +62,7 @@ public void GetPortionTest() Assert.Equal("poke" + NL + "Until something bad broke," + NL + "And then" + NL, text.GetPortion(2, 19, 4, 8)); // An invalid but recoverable range (to test that a best effort is made rather than crashing). - Assert.Equal(NL + "Who couldn't leave software to fester -" + NL, text.GetPortion(0, Int32.MaxValue, 1, Int32.MaxValue)); + Assert.Equal(NL + "Who couldn't leave software to fester -" + NL, text.GetPortion(0, int.MaxValue, 1, int.MaxValue)); // Some quite definitely dodgy ranges (to test that exceptions are thrown). Assert.Throws(() => text.GetPortion(-1, 0, 0, 0)); @@ -70,7 +70,7 @@ public void GetPortionTest() Assert.Throws(() => text.GetPortion(0, 0, -1, 0)); Assert.Throws(() => text.GetPortion(0, 0, 0, -1)); Assert.Throws(() => text.GetPortion(3, 5, 2, 5)); - Assert.Throws(() => text.GetPortion(2, 5, Int32.MaxValue, 5)); + Assert.Throws(() => text.GetPortion(2, 5, int.MaxValue, 5)); } #endregion diff --git a/csharp/extractor/Semmle.Util/ActionMap.cs b/csharp/extractor/Semmle.Util/ActionMap.cs index c9fecbf9da69..afcda9bb4944 100644 --- a/csharp/extractor/Semmle.Util/ActionMap.cs +++ b/csharp/extractor/Semmle.Util/ActionMap.cs @@ -7,11 +7,11 @@ namespace Semmle.Util /// A dictionary which performs an action when items are added to the dictionary. /// The order in which keys and actions are added does not matter. /// - /// - /// - public class ActionMap where Key : notnull + /// + /// + public class ActionMap where TKey : notnull { - public void Add(Key key, Value value) + public void Add(TKey key, TValue value) { if (actions.TryGetValue(key, out var a)) @@ -19,7 +19,7 @@ public void Add(Key key, Value value) values[key] = value; } - public void OnAdd(Key key, Action action) + public void OnAdd(TKey key, Action action) { if (actions.TryGetValue(key, out var a)) { @@ -30,17 +30,16 @@ public void OnAdd(Key key, Action action) actions.Add(key, action); } - Value val; - if (values.TryGetValue(key, out val)) + if (values.TryGetValue(key, out var val)) { action(val); } } // Action associated with each key. - readonly Dictionary> actions = new Dictionary>(); + private readonly Dictionary> actions = new Dictionary>(); // Values associated with each key. - readonly Dictionary values = new Dictionary(); + private readonly Dictionary values = new Dictionary(); } } diff --git a/csharp/extractor/Semmle.Util/CanonicalPathCache.cs b/csharp/extractor/Semmle.Util/CanonicalPathCache.cs index bbc8ab995b47..46759ad33477 100644 --- a/csharp/extractor/Semmle.Util/CanonicalPathCache.cs +++ b/csharp/extractor/Semmle.Util/CanonicalPathCache.cs @@ -40,7 +40,7 @@ public abstract class PathStrategy /// A canonical path. protected static string ConstructCanonicalPath(string path, IPathCache cache) { - DirectoryInfo parent = Directory.GetParent(path); + var parent = Directory.GetParent(path); return parent != null ? Path.Combine(cache.GetCanonicalPath(parent.FullName), Path.GetFileName(path)) : @@ -52,7 +52,7 @@ protected static string ConstructCanonicalPath(string path, IPathCache cache) /// Determine canonical paths using the Win32 function /// GetFinalPathNameByHandle(). Follows symlinks. /// - class GetFinalPathNameByHandleStrategy : PathStrategy + internal class GetFinalPathNameByHandleStrategy : PathStrategy { /// /// Call GetFinalPathNameByHandle() to get a canonical filename. @@ -70,48 +70,45 @@ class GetFinalPathNameByHandleStrategy : PathStrategy /// The canonical path. public override string GetCanonicalPath(string path, IPathCache cache) { - using (var hFile = Win32.CreateFile( // lgtm[cs/call-to-unmanaged-code] + using var hFile = Win32.CreateFile( // lgtm[cs/call-to-unmanaged-code] path, 0, Win32.FILE_SHARE_READ | Win32.FILE_SHARE_WRITE, IntPtr.Zero, Win32.OPEN_EXISTING, Win32.FILE_FLAG_BACKUP_SEMANTICS, - IntPtr.Zero)) - { + IntPtr.Zero); - if (hFile.IsInvalid) - { - // File/directory does not exist. - return ConstructCanonicalPath(path, cache); - } - else - { - StringBuilder outPath = new StringBuilder(Win32.MAX_PATH); - int length = Win32.GetFinalPathNameByHandle(hFile, outPath, outPath.Capacity, 0); // lgtm[cs/call-to-unmanaged-code] - if (length >= outPath.Capacity) - { - // Path length exceeded MAX_PATH. - // Possible if target has a long path. - outPath = new StringBuilder(length + 1); - length = Win32.GetFinalPathNameByHandle(hFile, outPath, outPath.Capacity, 0); // lgtm[cs/call-to-unmanaged-code] - } + if (hFile.IsInvalid) + { + // File/directory does not exist. + return ConstructCanonicalPath(path, cache); + } - const int PREAMBLE = 4; // outPath always starts \\?\ + var outPath = new StringBuilder(Win32.MAX_PATH); + var length = Win32.GetFinalPathNameByHandle(hFile, outPath, outPath.Capacity, 0); // lgtm[cs/call-to-unmanaged-code] - if (length <= PREAMBLE) - { - // Failed. GetFinalPathNameByHandle() failed somehow. - return ConstructCanonicalPath(path, cache); - } + if (length >= outPath.Capacity) + { + // Path length exceeded MAX_PATH. + // Possible if target has a long path. + outPath = new StringBuilder(length + 1); + length = Win32.GetFinalPathNameByHandle(hFile, outPath, outPath.Capacity, 0); // lgtm[cs/call-to-unmanaged-code] + } - string result = outPath.ToString(PREAMBLE, length - PREAMBLE); // Trim off leading \\?\ + const int preamble = 4; // outPath always starts \\?\ - return result.StartsWith("UNC") ? - @"\" + result.Substring(3) : - result; - } + if (length <= preamble) + { + // Failed. GetFinalPathNameByHandle() failed somehow. + return ConstructCanonicalPath(path, cache); } + + var result = outPath.ToString(preamble, length - preamble); // Trim off leading \\?\ + + return result.StartsWith("UNC") + ? @"\" + result.Substring(3) + : result; } } @@ -119,35 +116,34 @@ public override string GetCanonicalPath(string path, IPathCache cache) /// Determine file case by querying directory contents. /// Preserves symlinks. /// - class QueryDirectoryStrategy : PathStrategy + internal class QueryDirectoryStrategy : PathStrategy { public override string GetCanonicalPath(string path, IPathCache cache) { - DirectoryInfo parent = Directory.GetParent(path); + var parent = Directory.GetParent(path); - if (parent != null) - { - var name = Path.GetFileName(path); - var parentPath = cache.GetCanonicalPath(parent.FullName); - try - { - string[] entries = Directory.GetFileSystemEntries(parentPath, name); - return entries.Length == 1 ? - entries[0] : - Path.Combine(parentPath, name); - } - catch // lgtm[cs/catch-of-all-exceptions] - { - // IO error or security error querying directory. - return Path.Combine(parentPath, name); - } - } - else + if (parent == null) { // We are at a root of the filesystem. // Convert drive letters, UNC paths etc. to uppercase. // On UNIX, this should be "/" or "". return path.ToUpperInvariant(); + + } + + var name = Path.GetFileName(path); + var parentPath = cache.GetCanonicalPath(parent.FullName); + try + { + var entries = Directory.GetFileSystemEntries(parentPath, name); + return entries.Length == 1 + ? entries[0] + : Path.Combine(parentPath, name); + } + catch // lgtm[cs/catch-of-all-exceptions] + { + // IO error or security error querying directory. + return Path.Combine(parentPath, name); } } } @@ -156,14 +152,14 @@ public override string GetCanonicalPath(string path, IPathCache cache) /// Uses Mono.Unix.UnixPath to resolve symlinks. /// Not available on Windows. /// - class PosixSymlinkStrategy : PathStrategy + internal class PosixSymlinkStrategy : PathStrategy { public PosixSymlinkStrategy() { GetRealPath("."); // Test that it works } - string GetRealPath(string path) + private static string GetRealPath(string path) { path = UnixPath.GetFullPath(path); return UnixPath.GetCompleteRealPath(path); @@ -192,7 +188,7 @@ public class CanonicalPathCache : IPathCache /// /// The maximum number of items in the cache. /// - readonly int maxCapacity; + private readonly int maxCapacity; /// /// How to handle symlinks. @@ -206,7 +202,7 @@ public enum Symlinks /// /// Algorithm for computing the canonical path. /// - readonly PathStrategy pathStrategy; + private readonly PathStrategy pathStrategy; /// /// Create cache with a given capacity. @@ -216,12 +212,35 @@ public enum Symlinks public CanonicalPathCache(int maxCapacity, PathStrategy pathStrategy) { if (maxCapacity <= 0) - throw new ArgumentOutOfRangeException("Invalid cache size specified"); + throw new ArgumentOutOfRangeException(nameof(maxCapacity), maxCapacity, "Invalid cache size specified"); this.maxCapacity = maxCapacity; this.pathStrategy = pathStrategy; } + + /// + /// Create a CanonicalPathCache. + /// + /// + /// + /// Creates the appropriate PathStrategy object which encapsulates + /// the correct algorithm. Falls back to different implementations + /// depending on platform. + /// + /// + /// Size of the cache. + /// Policy for following symlinks. + /// A new CanonicalPathCache. + public static CanonicalPathCache Create(ILogger logger, int maxCapacity) + { + var preserveSymlinks = + Environment.GetEnvironmentVariable("CODEQL_PRESERVE_SYMLINKS") == "true" || + Environment.GetEnvironmentVariable("SEMMLE_PRESERVE_SYMLINKS") == "true"; + return Create(logger, maxCapacity, preserveSymlinks ? CanonicalPathCache.Symlinks.Preserve : CanonicalPathCache.Symlinks.Follow); + + } + /// /// Create a CanonicalPathCache. /// @@ -259,7 +278,7 @@ public static CanonicalPathCache Create(ILogger logger, int maxCapacity, Symlink pathStrategy = new QueryDirectoryStrategy(); break; default: - throw new ArgumentOutOfRangeException("Invalid symlinks option"); + throw new ArgumentOutOfRangeException(nameof(symlinks), symlinks, "Invalid symlinks option"); } return new CanonicalPathCache(maxCapacity, pathStrategy); @@ -268,12 +287,12 @@ public static CanonicalPathCache Create(ILogger logger, int maxCapacity, Symlink /// /// Map of path to canonical path. /// - readonly IDictionary cache = new Dictionary(); + private readonly IDictionary cache = new Dictionary(); /// /// Used to evict random cache items when the cache is full. /// - readonly Random random = new Random(); + private readonly Random random = new Random(); /// /// The current number of items in the cache. @@ -293,7 +312,7 @@ public int CacheSize /// /// The path. /// The canonical form of path. - void AddToCache(string path, string canonical) + private void AddToCache(string path, string canonical) { if (cache.Count >= maxCapacity) { diff --git a/csharp/extractor/Semmle.Util/CommandLineExtensions.cs b/csharp/extractor/Semmle.Util/CommandLineExtensions.cs index 01a581d612d9..884a00074183 100644 --- a/csharp/extractor/Semmle.Util/CommandLineExtensions.cs +++ b/csharp/extractor/Semmle.Util/CommandLineExtensions.cs @@ -19,9 +19,9 @@ public static bool WriteCommandLine(this IEnumerable commandLineArgument foreach (var arg in commandLineArguments.Where(arg => arg.StartsWith('@')).Select(arg => arg.Substring(1))) { string? line; - using (StreamReader file = new StreamReader(arg)) - while ((line = file.ReadLine()) != null) - textWriter.WriteLine(line); + using var file = new StreamReader(arg); + while ((line = file.ReadLine()) != null) + textWriter.WriteLine(line); found = true; } return found; diff --git a/csharp/extractor/Semmle.Util/CommandLineOptions.cs b/csharp/extractor/Semmle.Util/CommandLineOptions.cs index c85f68a8c6d5..8f148219ce4e 100644 --- a/csharp/extractor/Semmle.Util/CommandLineOptions.cs +++ b/csharp/extractor/Semmle.Util/CommandLineOptions.cs @@ -13,7 +13,7 @@ public interface ICommandLineOptions /// The name of the key. This is case sensitive. /// The supplied value. /// True if the option was handled, or false otherwise. - bool handleOption(string key, string value); + bool HandleOption(string key, string value); /// /// Handle a flag of the form "--cil" or "--nocil" @@ -21,52 +21,52 @@ public interface ICommandLineOptions /// The name of the flag. This is case sensitive. /// True if set, or false if prefixed by "--no" /// True if the flag was handled, or false otherwise. - bool handleFlag(string key, bool value); + bool HandleFlag(string key, bool value); /// /// Handle an argument, not prefixed by "--". /// /// The command line argument. /// True if the argument was handled, or false otherwise. - bool handleArgument(string argument); + bool HandleArgument(string argument); /// /// Process an unhandled option, or an unhandled argument. /// /// The argument. - void invalidArgument(string argument); + void InvalidArgument(string argument); } public static class OptionsExtensions { public static void ParseArguments(this ICommandLineOptions options, IReadOnlyList arguments) { - for (int i = 0; i < arguments.Count; ++i) + for (var i = 0; i < arguments.Count; ++i) { - string arg = arguments[i]; + var arg = arguments[i]; if (arg.StartsWith("--")) { var colon = arg.IndexOf(':'); - if (colon > 0 && options.handleOption(arg.Substring(2, colon - 2), arg.Substring(colon + 1))) + if (colon > 0 && options.HandleOption(arg.Substring(2, colon - 2), arg.Substring(colon + 1))) { } - else if (arg.StartsWith("--no") && options.handleFlag(arg.Substring(4), false)) + else if (arg.StartsWith("--no") && options.HandleFlag(arg.Substring(4), false)) { } - else if (options.handleFlag(arg.Substring(2), true)) + else if (options.HandleFlag(arg.Substring(2), true)) { } - else if (i + 1 < arguments.Count && options.handleOption(arg.Substring(2), arguments[i + 1])) + else if (i + 1 < arguments.Count && options.HandleOption(arg.Substring(2), arguments[i + 1])) { ++i; } else { - options.invalidArgument(arg); + options.InvalidArgument(arg); } } else { - if (!options.handleArgument(arg)) + if (!options.HandleArgument(arg)) { - options.invalidArgument(arg); + options.InvalidArgument(arg); } } } diff --git a/csharp/extractor/Semmle.Util/DictionaryExtensions.cs b/csharp/extractor/Semmle.Util/DictionaryExtensions.cs index bb0d732a17ff..95c5443585f3 100644 --- a/csharp/extractor/Semmle.Util/DictionaryExtensions.cs +++ b/csharp/extractor/Semmle.Util/DictionaryExtensions.cs @@ -9,7 +9,7 @@ public static class DictionaryExtensions /// dictionary. If a list does not already exist, a new list is /// created. /// - public static void AddAnother(this Dictionary> dict, T1 key, T2 element) where T1:notnull + public static void AddAnother(this Dictionary> dict, T1 key, T2 element) where T1 : notnull { if (!dict.TryGetValue(key, out var list)) { diff --git a/csharp/extractor/Semmle.Util/FileRenamer.cs b/csharp/extractor/Semmle.Util/FileRenamer.cs index ad5001f7e135..494e46856f83 100644 --- a/csharp/extractor/Semmle.Util/FileRenamer.cs +++ b/csharp/extractor/Semmle.Util/FileRenamer.cs @@ -10,8 +10,8 @@ namespace Semmle.Util /// public sealed class FileRenamer : IDisposable { - readonly string[] files; - const string suffix = ".codeqlhidden"; + private readonly string[] files; + private const string suffix = ".codeqlhidden"; public FileRenamer(IEnumerable oldFiles) { diff --git a/csharp/extractor/Semmle.Util/FileUtils.cs b/csharp/extractor/Semmle.Util/FileUtils.cs index 32e2ed88e601..89e35055fee8 100644 --- a/csharp/extractor/Semmle.Util/FileUtils.cs +++ b/csharp/extractor/Semmle.Util/FileUtils.cs @@ -86,15 +86,13 @@ public static void TryDelete(string file) /// public static string ComputeFileHash(string filePath) { - using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) - using (var shaAlg = new SHA256Managed()) - { - var sha = shaAlg.ComputeHash(fileStream); - var hex = new StringBuilder(sha.Length * 2); - foreach (var b in sha) - hex.AppendFormat("{0:x2}", b); - return hex.ToString(); - } + using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); + using var shaAlg = new SHA256Managed(); + var sha = shaAlg.ComputeHash(fileStream); + var hex = new StringBuilder(sha.Length * 2); + foreach (var b in sha) + hex.AppendFormat("{0:x2}", b); + return hex.ToString(); } } } diff --git a/csharp/extractor/Semmle.Util/FuzzyDictionary.cs b/csharp/extractor/Semmle.Util/FuzzyDictionary.cs index 6f364904b06b..9f61fa1ffa9e 100644 --- a/csharp/extractor/Semmle.Util/FuzzyDictionary.cs +++ b/csharp/extractor/Semmle.Util/FuzzyDictionary.cs @@ -37,10 +37,10 @@ namespace Semmle.Util /// /// /// The value type. - public class FuzzyDictionary where T:class + public class FuzzyDictionary where T : class { // All data items indexed by the "base string" (stripped of numbers) - readonly Dictionary>> index = new Dictionary>>(); + private readonly Dictionary>> index = new Dictionary>>(); /// /// Stores a new KeyValuePair in the data structure. @@ -51,7 +51,7 @@ public void Add(string k, T v) { var kv = new KeyValuePair(k, v); - string root = StripDigits(k); + var root = StripDigits(k); index.AddAnother(root, kv); } @@ -61,7 +61,7 @@ public void Add(string k, T v) /// Vector 1 /// Vector 2 /// The Hamming Distance. - static int HammingDistance(IEnumerable v1, IEnumerable v2) where U: notnull + private static int HammingDistance(IEnumerable v1, IEnumerable v2) where TElement : notnull { return v1.Zip(v2, (x, y) => x.Equals(y) ? 0 : 1).Sum(); } @@ -74,7 +74,7 @@ static int HammingDistance(IEnumerable v1, IEnumerable v2) where U: not /// The best match, or null (default). public T? FindMatch(string query, out int distance) { - string root = StripDigits(query); + var root = StripDigits(query); if (!index.TryGetValue(root, out var list)) { distance = 0; @@ -92,16 +92,17 @@ static int HammingDistance(IEnumerable v1, IEnumerable v2) where U: not /// The distance function. /// The distance between the query and the stored string. /// The stored value. - static T? BestMatch(string query, IEnumerable> candidates, Func distance, out int bestDistance) + private static T? BestMatch(string query, IEnumerable> candidates, Func distance, out int bestDistance) { - T? bestMatch = default(T); + var bestMatch = default(T); bestDistance = 0; - bool first = true; + var first = true; foreach (var candidate in candidates) { - int d = distance(query, candidate.Key); - if (d == 0) return candidate.Value; + var d = distance(query, candidate.Key); + if (d == 0) + return candidate.Value; if (first || d < bestDistance) { @@ -119,10 +120,10 @@ static int HammingDistance(IEnumerable v1, IEnumerable v2) where U: not /// /// The input string. /// String with digits removed. - static string StripDigits(string input) + private static string StripDigits(string input) { - StringBuilder result = new StringBuilder(); - foreach (char c in input.Where(c => !char.IsDigit(c))) + var result = new StringBuilder(); + foreach (var c in input.Where(c => !char.IsDigit(c))) result.Append(c); return result.ToString(); } @@ -132,11 +133,11 @@ static string StripDigits(string input) /// /// The string to enumerate. /// The sequence of integers. - public static IEnumerable ExtractIntegers(string input) + private static IEnumerable ExtractIntegers(string input) { - bool inNumber = false; - int value = 0; - foreach (char c in input) + var inNumber = false; + var value = 0; + foreach (var c in input) { if (char.IsDigit(c)) { diff --git a/csharp/extractor/Semmle.Util/IEnumerableExtensions.cs b/csharp/extractor/Semmle.Util/IEnumerableExtensions.cs index 7665dedfa70e..c97a4ffdb3d9 100644 --- a/csharp/extractor/Semmle.Util/IEnumerableExtensions.cs +++ b/csharp/extractor/Semmle.Util/IEnumerableExtensions.cs @@ -33,30 +33,29 @@ public static class IEnumerableExtensions /// public static IEnumerable Interleave(this IEnumerable first, IEnumerable second) { - using (IEnumerator enumerator1 = first.GetEnumerator(), enumerator2 = second.GetEnumerator()) + using var enumerator1 = first.GetEnumerator(); + using var enumerator2 = second.GetEnumerator(); + bool moveNext1; + while ((moveNext1 = enumerator1.MoveNext()) && enumerator2.MoveNext()) { - bool moveNext1; - while ((moveNext1 = enumerator1.MoveNext()) && enumerator2.MoveNext()) - { - yield return enumerator1.Current; - yield return enumerator2.Current; - } + yield return enumerator1.Current; + yield return enumerator2.Current; + } - if (moveNext1) + if (moveNext1) + { + // `first` has more elements than `second` + yield return enumerator1.Current; + while (enumerator1.MoveNext()) { - // `first` has more elements than `second` yield return enumerator1.Current; - while (enumerator1.MoveNext()) - { - yield return enumerator1.Current; - } } + } - while (enumerator2.MoveNext()) - { - // `second` has more elements than `first` - yield return enumerator2.Current; - } + while (enumerator2.MoveNext()) + { + // `second` has more elements than `first` + yield return enumerator2.Current; } } @@ -64,9 +63,10 @@ public static IEnumerable Interleave(this IEnumerable first, IEnumerabl /// Enumerates a possibly null enumerable. /// If the enumerable is null, the list is empty. /// - public static IEnumerable EnumerateNull(this IEnumerable items) + public static IEnumerable EnumerateNull(this IEnumerable? items) { - if (items == null) yield break; + if (items == null) + yield break; foreach (var item in items) yield return item; } @@ -93,9 +93,9 @@ public static void Enumerate(this IEnumerable items) /// The type of the item. /// The list of items to hash. /// The hash code. - public static int SequenceHash(this IEnumerable items) where T: notnull + public static int SequenceHash(this IEnumerable items) where T : notnull { - int h = 0; + var h = 0; foreach (var i in items) h = h * 7 + i.GetHashCode(); return h; diff --git a/csharp/extractor/Semmle.Util/LineCounter.cs b/csharp/extractor/Semmle.Util/LineCounter.cs index f4f6758a2500..d3add0c1b9df 100644 --- a/csharp/extractor/Semmle.Util/LineCounter.cs +++ b/csharp/extractor/Semmle.Util/LineCounter.cs @@ -33,8 +33,10 @@ public sealed class LineCounts public override bool Equals(object? other) { - var rhs = other as LineCounts; - return rhs != null && Total == rhs.Total && Code == rhs.Code && Comment == rhs.Comment; + return other is LineCounts rhs && + Total == rhs.Total && + Code == rhs.Code && + Comment == rhs.Comment; } public override int GetHashCode() @@ -194,7 +196,8 @@ private static void ReadEOLComment(string input, Context context) // If we reached the end of a line (as opposed to reaching the end of the text), // put the '\n' back so that it can be handled by the normal newline processing // code. - if (IsNewLine(c)) --context.CurIndex; + if (IsNewLine(c)) + --context.CurIndex; } /// @@ -240,11 +243,13 @@ private static void ReadRestOfChar(string input, Context context) private static void ReadRestOfString(string input, Context context) { char? cur = '\0'; - int numSlashes = 0; + var numSlashes = 0; while (cur != null && ((cur = GetNext(input, context)) != '"' || (numSlashes % 2 != 0))) { - if (cur == '\\') ++numSlashes; - else numSlashes = 0; + if (cur == '\\') + ++numSlashes; + else + numSlashes = 0; } } diff --git a/csharp/extractor/Semmle.Util/Logger.cs b/csharp/extractor/Semmle.Util/Logger.cs index cd353bd4f0fd..7e0bc34cc2f4 100644 --- a/csharp/extractor/Semmle.Util/Logger.cs +++ b/csharp/extractor/Semmle.Util/Logger.cs @@ -1,6 +1,5 @@ using System; using System.IO; -using System.Security.AccessControl; namespace Semmle.Util.Logging { @@ -56,10 +55,10 @@ public static void Log(this ILogger logger, Severity s, string text, params obje /// A logger that outputs to a csharp.log /// file. /// - public class FileLogger : ILogger + public sealed class FileLogger : ILogger { - readonly StreamWriter writer; - readonly Verbosity verbosity; + private readonly StreamWriter writer; + private readonly Verbosity verbosity; public FileLogger(Verbosity verbosity, string outputFile) { @@ -67,11 +66,11 @@ public FileLogger(Verbosity verbosity, string outputFile) try { - string? dir = Path.GetDirectoryName(outputFile); + var dir = Path.GetDirectoryName(outputFile); if (!string.IsNullOrEmpty(dir) && !System.IO.Directory.Exists(dir)) Directory.CreateDirectory(dir); - writer = new PidStreamWriter(new FileStream(outputFile, FileMode.Append, FileAccess.Write, - FileShare.ReadWrite, 8192)); + writer = new PidStreamWriter( + new FileStream(outputFile, FileMode.Append, FileAccess.Write, FileShare.ReadWrite, 8192)); } catch (Exception ex) // lgtm[cs/catch-of-all-exceptions] { @@ -86,7 +85,7 @@ public void Dispose() writer.Dispose(); } - static string GetSeverityPrefix(Severity s) + private static string GetSeverityPrefix(Severity s) { return "[" + s.ToString().ToUpper() + "] "; } @@ -101,9 +100,9 @@ public void Log(Severity s, string text) /// /// A logger that outputs to stdout/stderr. /// - public class ConsoleLogger : ILogger + public sealed class ConsoleLogger : ILogger { - readonly Verbosity verbosity; + private readonly Verbosity verbosity; public ConsoleLogger(Verbosity verbosity) { @@ -112,12 +111,12 @@ public ConsoleLogger(Verbosity verbosity) public void Dispose() { } - static TextWriter GetConsole(Severity s) + private static TextWriter GetConsole(Severity s) { return s == Severity.Error ? Console.Error : Console.Out; } - static string GetSeverityPrefix(Severity s) + private static string GetSeverityPrefix(Severity s) { switch (s) { @@ -130,7 +129,7 @@ static string GetSeverityPrefix(Severity s) case Severity.Error: return "Error: "; default: - throw new ArgumentOutOfRangeException("s"); + throw new ArgumentOutOfRangeException(nameof(s)); } } @@ -144,10 +143,10 @@ public void Log(Severity s, string text) /// /// A combined logger. /// - public class CombinedLogger : ILogger + public sealed class CombinedLogger : ILogger { - readonly ILogger logger1; - readonly ILogger logger2; + private readonly ILogger logger1; + private readonly ILogger logger2; public CombinedLogger(ILogger logger1, ILogger logger2) { @@ -168,7 +167,7 @@ public void Log(Severity s, string text) } } - static class VerbosityExtensions + internal static class VerbosityExtensions { /// /// Whether a message with the given severity must be included @@ -189,7 +188,7 @@ public static bool Includes(this Verbosity v, Severity s) case Severity.Error: return v >= Verbosity.Error; default: - throw new ArgumentOutOfRangeException("s"); + throw new ArgumentOutOfRangeException(nameof(s)); } } } diff --git a/csharp/extractor/Semmle.Util/LoggerUtils.cs b/csharp/extractor/Semmle.Util/LoggerUtils.cs index d94ff6f189f6..1ddbdf051e80 100644 --- a/csharp/extractor/Semmle.Util/LoggerUtils.cs +++ b/csharp/extractor/Semmle.Util/LoggerUtils.cs @@ -29,11 +29,11 @@ public override void WriteLine(string? value) } } - public override void WriteLine(string? value, object?[] args) + public override void WriteLine(string? format, params object?[] args) { - WriteLine(value is null ? value : String.Format(value, args)); + WriteLine(format is null ? format : string.Format(format, args)); } - readonly object mutex = new object(); + private readonly object mutex = new object(); } } diff --git a/csharp/extractor/Semmle.Util/ProcessStartInfoExtensions.cs b/csharp/extractor/Semmle.Util/ProcessStartInfoExtensions.cs index 5252372a58b2..998b6909e10a 100644 --- a/csharp/extractor/Semmle.Util/ProcessStartInfoExtensions.cs +++ b/csharp/extractor/Semmle.Util/ProcessStartInfoExtensions.cs @@ -12,18 +12,17 @@ public static class ProcessStartInfoExtensions public static int ReadOutput(this ProcessStartInfo pi, out IList stdout) { stdout = new List(); - using (var process = Process.Start(pi)) + using var process = Process.Start(pi); + string? s; + do { - string? s; - do - { - s = process.StandardOutput.ReadLine(); - if (s != null) stdout.Add(s); - } - while (s != null); - process.WaitForExit(); - return process.ExitCode; + s = process.StandardOutput.ReadLine(); + if (s != null) + stdout.Add(s); } + while (s != null); + process.WaitForExit(); + return process.ExitCode; } } } diff --git a/csharp/extractor/Semmle.Util/Semmle.Util.csproj b/csharp/extractor/Semmle.Util/Semmle.Util.csproj index 39f0c7cdedb5..fdcd0672395e 100644 --- a/csharp/extractor/Semmle.Util/Semmle.Util.csproj +++ b/csharp/extractor/Semmle.Util/Semmle.Util.csproj @@ -1,7 +1,7 @@ - netcoreapp3.0 + netcoreapp3.1 Semmle.Util Semmle.Util false diff --git a/csharp/extractor/Semmle.Util/StringBuilder.cs b/csharp/extractor/Semmle.Util/StringBuilder.cs index 85f9155f290e..468ce6a02206 100644 --- a/csharp/extractor/Semmle.Util/StringBuilder.cs +++ b/csharp/extractor/Semmle.Util/StringBuilder.cs @@ -30,10 +30,14 @@ public static StringBuilder AppendList(this StringBuilder builder, string sep /// The original StringBuilder (fluent interface). public static StringBuilder BuildList(this StringBuilder builder, string separator, IEnumerable items, Action action) { - bool first = true; + var first = true; foreach (var item in items) { - if (first) first = false; else builder.Append(separator); + if (first) + first = false; + else + builder.Append(separator); + action(item, builder); } return builder; diff --git a/csharp/extractor/Semmle.Util/TemporaryDirectory.cs b/csharp/extractor/Semmle.Util/TemporaryDirectory.cs index a155372c9d89..ac5653afc781 100644 --- a/csharp/extractor/Semmle.Util/TemporaryDirectory.cs +++ b/csharp/extractor/Semmle.Util/TemporaryDirectory.cs @@ -1,8 +1,5 @@ using System; using System.IO; -using System.Linq; -using System.Security.Cryptography; -using System.Text; namespace Semmle.Util { diff --git a/csharp/extractor/Semmle.Util/Text.cs b/csharp/extractor/Semmle.Util/Text.cs index ede910a0bdf1..38619fc0164d 100644 --- a/csharp/extractor/Semmle.Util/Text.cs +++ b/csharp/extractor/Semmle.Util/Text.cs @@ -41,14 +41,12 @@ public Text(string[] lines) /// The whole text. public string GetAll() { - using (var sw = new StringWriter()) + using var sw = new StringWriter(); + foreach (var s in lines) { - foreach (string s in lines) - { - sw.WriteLine(s); - } - return sw.ToString(); + sw.WriteLine(s); } + return sw.ToString(); } /// @@ -70,38 +68,36 @@ public string GetPortion(int startRow, int startColumn, int endRow, int endColum ); } - using (var sw = new StringWriter()) - { - string line; + using var sw = new StringWriter(); + string line; - for (int i = startRow; i <= endRow; ++i) + for (var i = startRow; i <= endRow; ++i) + { + if (i == startRow && i == endRow) { - if (i == startRow && i == endRow) - { - // This is a single-line range, so take the bit between "startColumn" and "endColumn". - line = startColumn <= lines[i].Length ? lines[i].Substring(startColumn, endColumn - startColumn) : ""; - } - else if (i == startRow) - { - // This is the first line of a multi-line range, so take the bit from "startColumn" onwards. - line = startColumn <= lines[i].Length ? lines[i].Substring(startColumn) : ""; - } - else if (i == endRow) - { - // This is the last line of a multi-line range, so take the bit up to "endColumn". - line = endColumn <= lines[i].Length ? lines[i].Substring(0, endColumn) : lines[i]; - } - else - { - // This is a line in the middle of a multi-line range, so take the whole line. - line = lines[i]; - } - - sw.WriteLine(line); + // This is a single-line range, so take the bit between "startColumn" and "endColumn". + line = startColumn <= lines[i].Length ? lines[i].Substring(startColumn, endColumn - startColumn) : ""; + } + else if (i == startRow) + { + // This is the first line of a multi-line range, so take the bit from "startColumn" onwards. + line = startColumn <= lines[i].Length ? lines[i].Substring(startColumn) : ""; + } + else if (i == endRow) + { + // This is the last line of a multi-line range, so take the bit up to "endColumn". + line = endColumn <= lines[i].Length ? lines[i].Substring(0, endColumn) : lines[i]; + } + else + { + // This is a line in the middle of a multi-line range, so take the whole line. + line = lines[i]; } - return sw.ToString(); + sw.WriteLine(line); } + + return sw.ToString(); } #endregion diff --git a/csharp/extractor/Semmle.Util/Worklist.cs b/csharp/extractor/Semmle.Util/Worklist.cs index f02a09a06f1b..0a71dbd4381e 100644 --- a/csharp/extractor/Semmle.Util/Worklist.cs +++ b/csharp/extractor/Semmle.Util/Worklist.cs @@ -48,11 +48,10 @@ public bool Add(T element) /// public LinkedList GetUnprocessedElements() { - LinkedList result = internalList; + var result = internalList; internalList = new LinkedList(); hasNewElements = false; return result; } } } - diff --git a/csharp/ql/examples/qlpack.yml b/csharp/ql/examples/qlpack.yml new file mode 100644 index 000000000000..f7b585db963e --- /dev/null +++ b/csharp/ql/examples/qlpack.yml @@ -0,0 +1,3 @@ +name: codeql-csharp-examples +version: 0.0.0 +libraryPathDependencies: codeql-csharp diff --git a/csharp/ql/src/Bad Practices/Comments/CommentedOutCode.qhelp b/csharp/ql/src/Bad Practices/Comments/CommentedOutCode.qhelp index 4ce0ee029b62..0997169f4dfc 100644 --- a/csharp/ql/src/Bad Practices/Comments/CommentedOutCode.qhelp +++ b/csharp/ql/src/Bad Practices/Comments/CommentedOutCode.qhelp @@ -3,5 +3,5 @@ "qhelp.dtd"> - + diff --git a/csharp/ql/src/Bad Practices/Comments/CommentedOutCodeQuery.qhelp b/csharp/ql/src/Bad Practices/Comments/CommentedOutCodeQuery.qhelp new file mode 100644 index 000000000000..eb40ecdb7088 --- /dev/null +++ b/csharp/ql/src/Bad Practices/Comments/CommentedOutCodeQuery.qhelp @@ -0,0 +1,25 @@ + + + + +

    +Commented-out code is distracting and confusing for developers who read the surrounding code, +and its significance is often unclear. It will not get compiled or tested when the code around +it changes, so it's likely to break over time. For these reasons, commented-out code should be +avoided. +

    + +
    + + + +

    +Remove or reinstate the commented-out code. If you want to include a snippet of example code +in a comment, consider enclosing it in quotes or marking it up as appropriate for the source +language. +

    + +
    +
    diff --git a/csharp/ql/src/Concurrency/Concurrency.qll b/csharp/ql/src/Concurrency/Concurrency.qll index d37b10e0301b..aacd83083061 100644 --- a/csharp/ql/src/Concurrency/Concurrency.qll +++ b/csharp/ql/src/Concurrency/Concurrency.qll @@ -1,7 +1,8 @@ -// Various utilities for writing concurrency queries. +/** Classes for concurrency queries. */ + import csharp -class WaitCall extends MethodCall { +private class WaitCall extends MethodCall { WaitCall() { getTarget().hasName("Wait") and getTarget().getDeclaringType().hasQualifiedName("System.Threading.Monitor") @@ -10,22 +11,24 @@ class WaitCall extends MethodCall { Expr getExpr() { result = getArgument(0) } } +/** An expression statement containing a `Wait` call. */ class WaitStmt extends ExprStmt { WaitStmt() { getExpr() instanceof WaitCall } + /** Gets the expression that this wait call is waiting on. */ Expr getLock() { result = getExpr().(WaitCall).getExpr() } - // If we are waiting on a variable + /** Gets the variable that this wait call is waiting on, if any. */ Variable getWaitVariable() { result.getAnAccess() = getLock() } - // If we are waiting on 'this' + /** Holds if this wait call waits on `this`. */ predicate isWaitThis() { getLock() instanceof ThisAccess } - // If we are waiting on a typeof() + /** Gets the type that this wait call waits on, if any. */ Type getWaitTypeObject() { result = getLock().(TypeofExpr).getTypeAccess().getTarget() } } -class SynchronizedMethodAttribute extends Attribute { +private class SynchronizedMethodAttribute extends Attribute { SynchronizedMethodAttribute() { getType().hasQualifiedName("System.Runtime.CompilerServices.MethodImplAttribute") and exists(MemberConstantAccess a, MemberConstant mc | @@ -37,22 +40,29 @@ class SynchronizedMethodAttribute extends Attribute { } } -// A method with attribute [MethodImpl(MethodImplOptions.Synchronized)] -class SynchronizedMethod extends Method { +/** A method with attribute `[MethodImpl(MethodImplOptions.Synchronized)]`. */ +private class SynchronizedMethod extends Method { SynchronizedMethod() { getAnAttribute() instanceof SynchronizedMethodAttribute } + /** Holds if this method locks `this`. */ predicate isLockThis() { not isStatic() } + /** Gets the type that is locked by this method, if any. */ Type getLockTypeObject() { isStatic() and result = getDeclaringType() } } +/** A block that is locked by a `lock` statement. */ abstract class LockedBlock extends BlockStmt { + /** Holds if the `lock` statement locks `this`. */ abstract predicate isLockThis(); + /** Gets the lock variable of the `lock` statement, if any. */ abstract Variable getLockVariable(); + /** Gets the locked type of the `lock` statement, if any. */ abstract Type getLockTypeObject(); + /** Gets a statement in the scope of this locked block. */ Stmt getALockedStmt() { // Do this instead of getParent+, because we don't want to escape // delegates and lambdas @@ -62,7 +72,7 @@ abstract class LockedBlock extends BlockStmt { } } -class LockStmtBlock extends LockedBlock { +private class LockStmtBlock extends LockedBlock { LockStmtBlock() { exists(LockStmt s | this = s.getBlock()) } override predicate isLockThis() { exists(LockStmt s | this = s.getBlock() and s.isLockThis()) } @@ -76,9 +86,7 @@ class LockStmtBlock extends LockedBlock { } } -/** - * A call which may take a lock using one of the standard library classes. - */ +/** A call that may take a lock using one of the standard library methods. */ class LockingCall extends MethodCall { LockingCall() { this.getTarget() = @@ -91,7 +99,7 @@ class LockingCall extends MethodCall { } } -class SynchronizedMethodBlock extends LockedBlock { +private class SynchronizedMethodBlock extends LockedBlock { SynchronizedMethodBlock() { exists(SynchronizedMethod m | this = m.getStatementBody()) } override predicate isLockThis() { diff --git a/csharp/ql/src/Documentation/Documentation.qll b/csharp/ql/src/Documentation/Documentation.qll index ed69cf150eac..041a385e7930 100644 --- a/csharp/ql/src/Documentation/Documentation.qll +++ b/csharp/ql/src/Documentation/Documentation.qll @@ -1,6 +1,8 @@ +/** Classes representing documentation comments. */ + import csharp -class SourceDeclaration extends Declaration { +private class SourceDeclaration extends Declaration { SourceDeclaration() { this.isSourceDeclaration() } } @@ -59,10 +61,13 @@ predicate isDocumentationNeeded(Modifiable decl) { class ReturnsXmlComment extends XmlComment { ReturnsXmlComment() { getOpenTag(_) = "returns" } + /** Holds if the element in this comment has a body at offset `offset`. */ predicate hasBody(int offset) { hasBody("returns", offset) } + /** Holds if the element in this comment is an opening tag at offset `offset`. */ predicate isOpenTag(int offset) { "returns" = getOpenTag(offset) } + /** Holds if the element in this comment is an empty tag at offset `offset`. */ predicate isEmptyTag(int offset) { "returns" = getEmptyTag(offset) } } @@ -70,8 +75,10 @@ class ReturnsXmlComment extends XmlComment { class ExceptionXmlComment extends XmlComment { ExceptionXmlComment() { getOpenTag(_) = "exception" } + /** Gets a `cref` attribute at offset `offset`, if any. */ string getCref(int offset) { result = getAttribute("exception", "cref", offset) } + /** Holds if the element in this comment has a body at offset `offset`. */ predicate hasBody(int offset) { hasBody("exception", offset) } } @@ -79,8 +86,10 @@ class ExceptionXmlComment extends XmlComment { class ParamXmlComment extends XmlComment { ParamXmlComment() { getOpenTag(_) = "param" } + /** Gets the name of this parameter at offset `offset`. */ string getName(int offset) { getAttribute("param", "name", offset) = result } + /** Holds if the element in this comment has a body at offset `offset`. */ predicate hasBody(int offset) { hasBody("param", offset) } } @@ -88,8 +97,10 @@ class ParamXmlComment extends XmlComment { class TypeparamXmlComment extends XmlComment { TypeparamXmlComment() { getOpenTag(_) = "typeparam" } + /** Gets the `name` attribute of this element at offset `offset`. */ string getName(int offset) { getAttribute("typeparam", "name", offset) = result } + /** Holds if the element in this comment has a body at offset `offset`. */ predicate hasBody(int offset) { hasBody("typeparam", offset) } } @@ -97,10 +108,13 @@ class TypeparamXmlComment extends XmlComment { class SummaryXmlComment extends XmlComment { SummaryXmlComment() { getOpenTag(_) = "summary" } + /** Holds if the element in this comment has a body at offset `offset`. */ predicate hasBody(int offset) { hasBody("summary", offset) } + /** Holds if the element in this comment has an open tag at offset `offset`. */ predicate isOpenTag(int offset) { "summary" = getOpenTag(offset) } + /** Holds if the element in this comment is empty at offset `offset`. */ predicate isEmptyTag(int offset) { "summary" = getEmptyTag(offset) } } diff --git a/csharp/ql/src/Language Abuse/ForeachCapture.ql b/csharp/ql/src/Language Abuse/ForeachCapture.ql index d4a97cdbc43a..803081dcb735 100644 --- a/csharp/ql/src/Language Abuse/ForeachCapture.ql +++ b/csharp/ql/src/Language Abuse/ForeachCapture.ql @@ -75,15 +75,13 @@ Element getAssignmentTarget(Expr e) { Element getCollectionAssignmentTarget(Expr e) { // Store into collection via method exists( - MethodCall mc, Method m, IEnumerableFlow ief, CallableFlowSourceArg source, - CallableFlowSinkQualifier sink, int i + MethodCall mc, Method m, LibraryTypeDataFlow ltdf, CallableFlowSource source, + CallableFlowSink sink | - mc.getQualifier() = result.(Variable).getAnAccess() and - ief = mc.getQualifier().getType().getSourceDeclaration() and m = mc.getTarget().getSourceDeclaration() and - ief.callableFlow(source, sink, m, _) and - source.getArgumentIndex() = i and - e = mc.getArgument(i) + ltdf.callableFlow(source, AccessPath::empty(), sink, AccessPath::element(), m, _) and + e = source.getSource(mc) and + result.(Variable).getAnAccess() = sink.getSink(mc) ) or // Array initializer diff --git a/csharp/ql/src/Language Abuse/UselessUpcast.ql b/csharp/ql/src/Language Abuse/UselessUpcast.ql index 334fd0bc1e80..3e42e0599905 100644 --- a/csharp/ql/src/Language Abuse/UselessUpcast.ql +++ b/csharp/ql/src/Language Abuse/UselessUpcast.ql @@ -31,14 +31,14 @@ class StaticCall extends Call { } /** Holds `t` has instance callable `c` as a member, with name `name`. */ -pragma[noinline] +pragma[nomagic] predicate hasInstanceCallable(ValueOrRefType t, InstanceCallable c, string name) { t.hasMember(c) and name = c.getName() } /** Holds if extension method `m` is a method on `t` with name `name`. */ -pragma[noinline] +pragma[nomagic] predicate hasExtensionMethod(ValueOrRefType t, ExtensionMethod m, string name) { t.isImplicitlyConvertibleTo(m.getExtendedType()) and name = m.getName() diff --git a/csharp/ql/src/Likely Bugs/SelfAssignment.ql b/csharp/ql/src/Likely Bugs/SelfAssignment.ql index 0f0e23e8629a..01c5d904cd40 100644 --- a/csharp/ql/src/Likely Bugs/SelfAssignment.ql +++ b/csharp/ql/src/Likely Bugs/SelfAssignment.ql @@ -20,7 +20,9 @@ class StructuralComparisonConfig extends StructuralComparisonConfiguration { exists(AssignExpr ae | // Member initializers are never self-assignments, in particular // not initializers such as `new C { F = F };` - not ae instanceof MemberInitializer + not ae instanceof MemberInitializer and + // Enum field initializers are never self assignments. `enum E { A = 42 }` + not ae.getParent().(Field).getDeclaringType() instanceof Enum | ae.getLValue() = x and ae.getRValue() = y diff --git a/csharp/ql/src/Linq/Helpers.qll b/csharp/ql/src/Linq/Helpers.qll index 09643be429a9..e1b1beb1222d 100644 --- a/csharp/ql/src/Linq/Helpers.qll +++ b/csharp/ql/src/Linq/Helpers.qll @@ -6,18 +6,32 @@ import csharp //#################### PREDICATES #################### -Stmt firstStmt(ForeachStmt fes) { +private Stmt firstStmt(ForeachStmt fes) { if fes.getBody() instanceof BlockStmt then result = fes.getBody().(BlockStmt).getStmt(0) else result = fes.getBody() } +private int numStmts(ForeachStmt fes) { + if fes.getBody() instanceof BlockStmt + then result = count(fes.getBody().(BlockStmt).getAStmt()) + else result = 1 +} + +/** Holds if the type's qualified name is "System.Linq.Enumerable" */ predicate isEnumerableType(ValueOrRefType t) { t.hasQualifiedName("System.Linq.Enumerable") } +/** Holds if the type's qualified name starts with "System.Collections.Generic.IEnumerable" */ predicate isIEnumerableType(ValueOrRefType t) { t.getQualifiedName().matches("System.Collections.Generic.IEnumerable%") } +/** + * Holds if `foreach` statement `fes` could be converted to a `.All()` call. + * That is, the `ForeachStmt` contains a single `if` with a condition that + * accesses the loop variable and with a body that assigns `false` to a variable + * and `break`s out of the `foreach`. + */ predicate missedAllOpportunity(ForeachStmt fes) { exists(IfStmt is | // The loop contains an if statement with no else case, and nothing else. @@ -36,6 +50,12 @@ predicate missedAllOpportunity(ForeachStmt fes) { ) } +/** + * Holds if `foreach` statement `fes` could be converted to a `.Cast()` call. + * That is, the loop variable is accessed only in the first statement of the + * block, and the access is a cast. The first statement needs to be a + * `LocalVariableDeclStmt`. + */ predicate missedCastOpportunity(ForeachStmt fes, LocalVariableDeclStmt s) { s = firstStmt(fes) and forex(VariableAccess va | va = fes.getVariable().getAnAccess() | @@ -47,6 +67,12 @@ predicate missedCastOpportunity(ForeachStmt fes, LocalVariableDeclStmt s) { ) } +/** + * Holds if `foreach` statement `fes` could be converted to an `.OfType()` call. + * That is, the loop variable is accessed only in the first statement of the + * block, and the access is a cast with the `as` operator. The first statement + * needs to be a `LocalVariableDeclStmt`. + */ predicate missedOfTypeOpportunity(ForeachStmt fes, LocalVariableDeclStmt s) { s = firstStmt(fes) and forex(VariableAccess va | va = fes.getVariable().getAnAccess() | @@ -58,6 +84,12 @@ predicate missedOfTypeOpportunity(ForeachStmt fes, LocalVariableDeclStmt s) { ) } +/** + * Holds if `foreach` statement `fes` could be converted to a `.Select()` call. + * That is, the loop variable is accessed only in the first statement of the + * block, and the access is not a cast. The first statement needs to be a + * `LocalVariableDeclStmt`. + */ predicate missedSelectOpportunity(ForeachStmt fes, LocalVariableDeclStmt s) { s = firstStmt(fes) and forex(VariableAccess va | va = fes.getVariable().getAnAccess() | @@ -66,6 +98,12 @@ predicate missedSelectOpportunity(ForeachStmt fes, LocalVariableDeclStmt s) { not s.getAVariableDeclExpr().getInitializer() instanceof Cast } +/** + * Holds if `foreach` statement `fes` could be converted to a `.Where()` call. + * That is, first statement of the loop is an `if`, which accesses the loop + * variable, and the body of the `if` is either a `continue` or there's nothing + * else in the loop than the `if`. + */ predicate missedWhereOpportunity(ForeachStmt fes, IfStmt is) { // The very first thing the foreach loop does is test its iteration variable. is = firstStmt(fes) and @@ -82,12 +120,6 @@ predicate missedWhereOpportunity(ForeachStmt fes, IfStmt is) { ) } -int numStmts(ForeachStmt fes) { - if fes.getBody() instanceof BlockStmt - then result = count(fes.getBody().(BlockStmt).getAStmt()) - else result = 1 -} - //#################### CLASSES #################### /** A LINQ Any(...) call. */ class AnyCall extends MethodCall { @@ -100,6 +132,17 @@ class AnyCall extends MethodCall { } } +/** A LINQ Count(...) call. */ +class CountCall extends MethodCall { + CountCall() { + exists(Method m | + m = getTarget() and + isEnumerableType(m.getDeclaringType()) and + m.hasName("Count") + ) + } +} + /** A variable of type IEnumerable<T>, for some T. */ class IEnumerableSequence extends Variable { IEnumerableSequence() { isIEnumerableType(getType()) } diff --git a/csharp/ql/src/Metrics/Dependencies/ExternalDependencies.ql b/csharp/ql/src/Metrics/Dependencies/ExternalDependencies.ql index 1c2e9aaa7210..6139262afd32 100644 --- a/csharp/ql/src/Metrics/Dependencies/ExternalDependencies.ql +++ b/csharp/ql/src/Metrics/Dependencies/ExternalDependencies.ql @@ -1,4 +1,5 @@ /** + * @deprecated * @name External dependencies * @description Count the number of dependencies a C# source file has on assembly files. * @kind treemap diff --git a/csharp/ql/src/Metrics/Dependencies/ExternalDependenciesSourceLinks.ql b/csharp/ql/src/Metrics/Dependencies/ExternalDependenciesSourceLinks.ql index e9cda4255920..59d2dbdf5866 100644 --- a/csharp/ql/src/Metrics/Dependencies/ExternalDependenciesSourceLinks.ql +++ b/csharp/ql/src/Metrics/Dependencies/ExternalDependenciesSourceLinks.ql @@ -1,4 +1,5 @@ /** + * @deprecated * @name External dependency source links * @kind source-link * @metricType externalDependency diff --git a/csharp/ql/src/Metrics/Files/CommentedOutCodeMetricOverview.qhelp b/csharp/ql/src/Metrics/Files/CommentedOutCodeMetricOverview.qhelp new file mode 100644 index 000000000000..217b6d175295 --- /dev/null +++ b/csharp/ql/src/Metrics/Files/CommentedOutCodeMetricOverview.qhelp @@ -0,0 +1,12 @@ + + + +

    +This metric counts the number of lines of commented-out code in each file. Large amounts of +commented-out code often indicate poorly maintained code. +

    + +
    +
    diff --git a/csharp/ql/src/Metrics/Files/CommentedOutCodeReferences.qhelp b/csharp/ql/src/Metrics/Files/CommentedOutCodeReferences.qhelp new file mode 100644 index 000000000000..462eb7795f91 --- /dev/null +++ b/csharp/ql/src/Metrics/Files/CommentedOutCodeReferences.qhelp @@ -0,0 +1,12 @@ + + + + +
  • Mark Needham: The danger of commenting out code.
  • +
  • Los Techies: Commented Code == Technical Debt.
  • +
  • High Integrity C++ Coding Standard: 2.3.2 Do not comment out code.
  • + + + diff --git a/csharp/ql/src/Metrics/Files/DuplicationProblems.qhelp b/csharp/ql/src/Metrics/Files/DuplicationProblems.qhelp new file mode 100644 index 000000000000..54397da6c994 --- /dev/null +++ b/csharp/ql/src/Metrics/Files/DuplicationProblems.qhelp @@ -0,0 +1,16 @@ + + + +

    +Duplicated code increases overall code size, making the code base +harder to maintain and harder to understand. It also becomes harder to fix bugs, +since a programmer applying a fix to one copy has to always remember to update +other copies accordingly. Finally, code duplication is generally an indication of +a poorly designed or hastily written code base, which typically suffers from other +problems as well. +

    + +
    +
    diff --git a/csharp/ql/src/Metrics/Files/FLinesOfDuplicatedCode.ql b/csharp/ql/src/Metrics/Files/FLinesOfDuplicatedCode.ql index 3237035f897c..bf3da5e1f80f 100644 --- a/csharp/ql/src/Metrics/Files/FLinesOfDuplicatedCode.ql +++ b/csharp/ql/src/Metrics/Files/FLinesOfDuplicatedCode.ql @@ -1,4 +1,5 @@ /** + * @deprecated * @name Duplicated lines in files * @description The number of lines in a file, including code, comment and whitespace lines, * which are duplicated in at least one other place. diff --git a/csharp/ql/src/Performance/UseTryGetValue.ql b/csharp/ql/src/Performance/UseTryGetValue.ql index dcc292ecce85..276901cf61a2 100644 --- a/csharp/ql/src/Performance/UseTryGetValue.ql +++ b/csharp/ql/src/Performance/UseTryGetValue.ql @@ -6,7 +6,7 @@ * @problem.severity recommendation * @precision high * @id cs/inefficient-containskey - * @tag maintainability efficiency + * @tags maintainability efficiency */ import csharp diff --git a/csharp/ql/src/Security Features/CWE-020/RuntimeChecksBypass.ql b/csharp/ql/src/Security Features/CWE-020/RuntimeChecksBypass.ql index 7b875faae67c..24de3f110757 100644 --- a/csharp/ql/src/Security Features/CWE-020/RuntimeChecksBypass.ql +++ b/csharp/ql/src/Security Features/CWE-020/RuntimeChecksBypass.ql @@ -27,6 +27,7 @@ GuardedExpr checkedWrite(Field f, Variable v, IfStmt check) { * The result is an unsafe write to the field `f`, where * there is no check performed within the (calling) scope of the method. */ +pragma[nomagic] Expr uncheckedWrite(Callable callable, Field f) { result = f.getAnAssignedValue() and result.getEnclosingCallable() = callable and diff --git a/csharp/ql/src/Security Features/CWE-022/TaintedPath.qhelp b/csharp/ql/src/Security Features/CWE-022/TaintedPath.qhelp index fec61771992f..e838d8c56a4d 100644 --- a/csharp/ql/src/Security Features/CWE-022/TaintedPath.qhelp +++ b/csharp/ql/src/Security Features/CWE-022/TaintedPath.qhelp @@ -41,7 +41,7 @@ sent back to the user, giving them access to all the system's passwords.

  • OWASP: -Path Traversal. +Path Traversal.
  • diff --git a/csharp/ql/src/Security Features/CWE-022/ZipSlip.qhelp b/csharp/ql/src/Security Features/CWE-022/ZipSlip.qhelp index 9ee9ce6d0a16..bee5d8198368 100644 --- a/csharp/ql/src/Security Features/CWE-022/ZipSlip.qhelp +++ b/csharp/ql/src/Security Features/CWE-022/ZipSlip.qhelp @@ -71,7 +71,7 @@ Snyk:
  • OWASP: -Path Traversal. +Path Traversal.
  • diff --git a/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.ql b/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.ql index bcb3b7c7a774..abf3f0a55ad9 100644 --- a/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.ql +++ b/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.ql @@ -20,7 +20,7 @@ import semmle.code.csharp.frameworks.system.Web */ predicate hasWebConfigXFrameOptions(WebConfigXML webConfig) { // Looking for an entry in `webConfig` that looks like this: - // ``` + // ```xml // // // diff --git a/csharp/ql/src/Security Features/CWE-643/XPathInjection.qhelp b/csharp/ql/src/Security Features/CWE-643/XPathInjection.qhelp index 7241f6f97c44..cf50b4ee1742 100644 --- a/csharp/ql/src/Security Features/CWE-643/XPathInjection.qhelp +++ b/csharp/ql/src/Security Features/CWE-643/XPathInjection.qhelp @@ -42,7 +42,7 @@ variables in an XsltArgumentList. -
  • OWASP: Testing for XPath Injection.
  • +
  • OWASP: Testing for XPath Injection.
  • OWASP: XPath Injection.
  • MSDN: User Defined Functions and Variables.
  • diff --git a/csharp/ql/src/Security Features/Encryption using ECB.qhelp b/csharp/ql/src/Security Features/Encryption using ECB.qhelp index 96bea263ff51..0315813d7bce 100644 --- a/csharp/ql/src/Security Features/Encryption using ECB.qhelp +++ b/csharp/ql/src/Security Features/Encryption using ECB.qhelp @@ -3,8 +3,8 @@ "qhelp.dtd"> -

    ECB should not be used as a mode for encryption. It has a dangerous weaknesses. Data is encrypted the same way every time -meaning the same plaintext input will always produce the same cyphertext. This makes encrypted messages very vulnerable +

    ECB should not be used as a mode for encryption. It has dangerous weaknesses. Data is encrypted the same way every time +meaning the same plaintext input will always produce the same cyphertext. This makes encrypted messages vulnerable to replay attacks.

    diff --git a/csharp/ql/src/Security Features/InsufficientKeySize.cs b/csharp/ql/src/Security Features/InsufficientKeySize.cs index 5a12d01c1a1a..9d12299dfb00 100644 --- a/csharp/ql/src/Security Features/InsufficientKeySize.cs +++ b/csharp/ql/src/Security Features/InsufficientKeySize.cs @@ -11,7 +11,7 @@ static public byte[] EncryptWithRSA(byte[] plaintext, RSAParameters key) { try { - RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(512); // BAD + RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1024); // BAD rsa.ImportParameters(key); return rsa.Encrypt(plaintext, true); } @@ -27,7 +27,7 @@ static public byte[] EncryptWithRSA2(byte[] plaintext, RSAParameters key) try { RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); // BAD - rsa = new RSACryptoServiceProvider(1024); // GOOD + rsa = new RSACryptoServiceProvider(2048); // GOOD rsa.ImportParameters(key); return rsa.Encrypt(plaintext, true); } @@ -58,7 +58,7 @@ static public byte[] EncryptWithDSA2(byte[] plaintext, DSAParameters key) try { DSACryptoServiceProvider dsa = new DSACryptoServiceProvider(); // BAD - dsa = new DSACryptoServiceProvider(1024); // GOOD + dsa = new DSACryptoServiceProvider(2048); // GOOD dsa.ImportParameters(key); return dsa.SignData(plaintext); } @@ -121,7 +121,7 @@ public static byte[] DSASignHash(byte[] HashToSign, DSAParameters DSAKeyInfo, try { // Create a new instance of DSACryptoServiceProvider. - using (DSACryptoServiceProvider DSA = new DSACryptoServiceProvider(1024)) // GOOD + using (DSACryptoServiceProvider DSA = new DSACryptoServiceProvider(2048)) // GOOD { // Import the key information. DSA.ImportParameters(DSAKeyInfo); diff --git a/csharp/ql/src/Security Features/InsufficientKeySize.qhelp b/csharp/ql/src/Security Features/InsufficientKeySize.qhelp index 2b9ee39c6108..906881cf0c25 100644 --- a/csharp/ql/src/Security Features/InsufficientKeySize.qhelp +++ b/csharp/ql/src/Security Features/InsufficientKeySize.qhelp @@ -8,7 +8,7 @@ are vulnerable to brute force attack when too small a key size is used.

    -

    The key should be at least 1024-bit long when using RSA encryption, and 128-bit long when using +

    The key should be at least 2048-bit long when using RSA encryption, and 128-bit long when using symmetric encryption.

    diff --git a/csharp/ql/src/Security Features/InsufficientKeySize.ql b/csharp/ql/src/Security Features/InsufficientKeySize.ql index 08bdcfd6724b..04623b1d4b01 100644 --- a/csharp/ql/src/Security Features/InsufficientKeySize.ql +++ b/csharp/ql/src/Security Features/InsufficientKeySize.ql @@ -29,8 +29,8 @@ predicate incorrectUseOfDSA(ObjectCreation e, string msg) { .getTarget() .getDeclaringType() .hasQualifiedName("System.Security.Cryptography", "DSACryptoServiceProvider") and - exists(Expr i | e.getArgument(0) = i and i.getValue().toInt() < 1024) and - msg = "Key size should be at least 1024 bits for DSA encryption." + exists(Expr i | e.getArgument(0) = i and i.getValue().toInt() < 2048) and + msg = "Key size should be at least 2048 bits for DSA encryption." } predicate incorrectUseOfRSA(ObjectCreation e, string msg) { @@ -38,8 +38,8 @@ predicate incorrectUseOfRSA(ObjectCreation e, string msg) { .getTarget() .getDeclaringType() .hasQualifiedName("System.Security.Cryptography", "RSACryptoServiceProvider") and - exists(Expr i | e.getArgument(0) = i and i.getValue().toInt() < 1024) and - msg = "Key size should be at least 1024 bits for RSA encryption." + exists(Expr i | e.getArgument(0) = i and i.getValue().toInt() < 2048) and + msg = "Key size should be at least 2048 bits for RSA encryption." } from Expr e, string msg diff --git a/csharp/ql/src/Stubs/Stubs.qll b/csharp/ql/src/Stubs/Stubs.qll index 97ae6b4fd267..f8b704cba8b5 100644 --- a/csharp/ql/src/Stubs/Stubs.qll +++ b/csharp/ql/src/Stubs/Stubs.qll @@ -5,7 +5,7 @@ * This will generate stubs for all the required dependencies as well. * * Use - * ``` + * ```ql * select generatedCode() * ``` * to retrieve the generated C# code. diff --git a/csharp/ql/src/cil.qll b/csharp/ql/src/cil.qll index 7252542414c5..b46c328ab914 100644 --- a/csharp/ql/src/cil.qll +++ b/csharp/ql/src/cil.qll @@ -1 +1,5 @@ +/** + * The default QL library for modeling the Common Intermediate Language (CIL). + */ + import semmle.code.cil.CIL as CIL diff --git a/csharp/ql/src/codeql-suites/csharp-code-scanning.qls b/csharp/ql/src/codeql-suites/csharp-code-scanning.qls index 3646204da7d7..44fe11937e48 100644 --- a/csharp/ql/src/codeql-suites/csharp-code-scanning.qls +++ b/csharp/ql/src/codeql-suites/csharp-code-scanning.qls @@ -2,3 +2,5 @@ - qlpack: codeql-csharp - apply: code-scanning-selectors.yml from: codeql-suite-helpers +- apply: codeql-suites/exclude-dependency-queries.yml + from: codeql-csharp diff --git a/csharp/ql/src/codeql-suites/csharp-lgtm-full.qls b/csharp/ql/src/codeql-suites/csharp-lgtm-full.qls index 9c811406eeb0..8ba077663d03 100644 --- a/csharp/ql/src/codeql-suites/csharp-lgtm-full.qls +++ b/csharp/ql/src/codeql-suites/csharp-lgtm-full.qls @@ -7,3 +7,7 @@ tags contain: - ide-contextual-queries/local-definitions - ide-contextual-queries/local-references +- query: Metrics/Files/FLinesOfCode.ql +- query: Metrics/Files/FLinesOfCommentedCode.ql +- query: Metrics/Files/FLinesOfComment.ql +- query: Metrics/Files/FNumberOfTests.ql diff --git a/csharp/ql/src/codeql-suites/csharp-security-and-quality.qls b/csharp/ql/src/codeql-suites/csharp-security-and-quality.qls new file mode 100644 index 000000000000..f5df6527965c --- /dev/null +++ b/csharp/ql/src/codeql-suites/csharp-security-and-quality.qls @@ -0,0 +1,6 @@ +- description: Security-and-quality queries for C# +- qlpack: codeql-csharp +- apply: security-and-quality-selectors.yml + from: codeql-suite-helpers +- apply: codeql-suites/exclude-dependency-queries.yml + from: codeql-csharp diff --git a/csharp/ql/src/codeql-suites/csharp-security-extended.qls b/csharp/ql/src/codeql-suites/csharp-security-extended.qls new file mode 100644 index 000000000000..f4efe70892c4 --- /dev/null +++ b/csharp/ql/src/codeql-suites/csharp-security-extended.qls @@ -0,0 +1,6 @@ +- description: Security-extended queries for C# +- qlpack: codeql-csharp +- apply: security-extended-selectors.yml + from: codeql-suite-helpers +- apply: codeql-suites/exclude-dependency-queries.yml + from: codeql-csharp diff --git a/csharp/ql/src/codeql-suites/exclude-dependency-queries.yml b/csharp/ql/src/codeql-suites/exclude-dependency-queries.yml new file mode 100644 index 000000000000..53ad48be212e --- /dev/null +++ b/csharp/ql/src/codeql-suites/exclude-dependency-queries.yml @@ -0,0 +1,4 @@ +- description: C# queries which overlap with dependency analysis +- exclude: + query path: + - Security Features/CWE-937/VulnerablePackage.ql diff --git a/csharp/ql/src/dotnet.qll b/csharp/ql/src/dotnet.qll index 510f69671275..b583edda18a7 100644 --- a/csharp/ql/src/dotnet.qll +++ b/csharp/ql/src/dotnet.qll @@ -1 +1,5 @@ +/** + * The default QL library for modeling .NET definitions for both C# and CIL code. + */ + import semmle.code.dotnet.DotNet as DotNet diff --git a/csharp/ql/src/experimental/CWE-099/TaintedWebClient.qhelp b/csharp/ql/src/experimental/CWE-099/TaintedWebClient.qhelp index 77721307eda9..d7f195905a84 100644 --- a/csharp/ql/src/experimental/CWE-099/TaintedWebClient.qhelp +++ b/csharp/ql/src/experimental/CWE-099/TaintedWebClient.qhelp @@ -51,7 +51,7 @@ system's passwords.

  • OWASP: -Path Traversal. +Path Traversal.
  • diff --git a/csharp/ql/src/experimental/Security Features/Serialization/DataSetSerialization.qhelp b/csharp/ql/src/experimental/Security Features/Serialization/DataSetSerialization.qhelp new file mode 100644 index 000000000000..7575352f4f16 --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/Serialization/DataSetSerialization.qhelp @@ -0,0 +1,23 @@ + + + +

    The DataSet and DataTable types are legacy .NET components that you can use to represent data sets as managed objects.

    + +

    While DataSet and DataTable do impose default limitations on the types that are allowed to be present while deserializing XML payloads, DataSet and DataTable are in general not safe when populated with untrusted input.

    + +

    Please visit DataSet and DataTable security guidance for more details.

    + +
    + + +

    Please review the DataSet and DataTable security guidance before making use of these types for serialization.

    + +
    + + +
  • Microsoft DocsDataSet and DataTable security guidance.
  • + +
    +
    diff --git a/csharp/ql/src/experimental/Security Features/Serialization/DataSetSerialization.qll b/csharp/ql/src/experimental/Security Features/Serialization/DataSetSerialization.qll new file mode 100644 index 000000000000..a6230b0ff596 --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/Serialization/DataSetSerialization.qll @@ -0,0 +1,100 @@ +/** + * Provides classes for `DataSet` or `DataTable` deserialization queries. + * + * Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. + */ + +import csharp + +/** + * Abstract class that depends or inherits from `DataSet` or `DataTable` types. + */ +abstract class DataSetOrTableRelatedClass extends Class { } + +/** + * `DataSet`, `DataTable` types, or any types derived from them. + */ +class DataSetOrTable extends DataSetOrTableRelatedClass { + DataSetOrTable() { + this.getABaseType*().getQualifiedName() = "System.Data.DataTable" or + this.getABaseType*().getQualifiedName() = "System.Data.DataSet" + } +} + +/** + * A Class that include a property or generic collection of type `DataSet` and `DataTable` + */ +class ClassWithDataSetOrTableMember extends DataSetOrTableRelatedClass { + ClassWithDataSetOrTableMember() { + this.getAMember().(AssignableMember).getType() instanceof DataSetOrTable + or + exists(Property p | p = this.getAProperty() | + p.getType() instanceof DataSetOrTable or + p.getType().(ConstructedGeneric).getATypeArgument() instanceof DataSetOrTable + ) + } +} + +/** + * Serializable types + */ +class SerializableClass extends Class { + SerializableClass() { + ( + this.getABaseType*().getQualifiedName() = "System.Xml.Serialization.XmlSerializer" or + this.getABaseType*().getQualifiedName() = "System.Runtime.Serialization.ISerializable" or + this.getABaseType*().getQualifiedName() = "System.Runtime.Serialization.XmlObjectSerializer" or + this.getABaseType*().getQualifiedName() = + "System.Runtime.Serialization.ISerializationSurrogateProvider" or + this.getABaseType*().getQualifiedName() = + "System.Runtime.Serialization.XmlSerializableServices" or + this.getABaseType*().getQualifiedName() = "System.Xml.Serialization.IXmlSerializable" + ) + or + exists(Attribute a | a = this.getAnAttribute() | + a.getType().getQualifiedName() = "System.SerializableAttribute" + ) + } +} + +/** + * Holds if the serializable class `c` has a property or field `m` that is of `DataSet` or `DataTable` related type + */ +predicate isClassUnsafeXmlSerializerImplementation(SerializableClass c, AssignableMember am) { + am = c.getAMember() and + am.getType() instanceof DataSetOrTableRelatedClass +} + +/** + * Serializable class that has a property or field that is of `DataSet` or `DataTable` related type + */ +class UnsafeXmlSerializerImplementation extends SerializableClass { + UnsafeXmlSerializerImplementation() { isClassUnsafeXmlSerializerImplementation(this, _) } +} + +/** + * Method that may be unsafe when used to deserialize DataSet and DataTable related types + */ +class UnsafeXmlReadMethod extends Method { + UnsafeXmlReadMethod() { + this.getQualifiedName() = "System.Data.DataTable.ReadXml" + or + this.getQualifiedName() = "System.Data.DataTable.ReadXmlSchema" + or + this.getQualifiedName() = "System.Data.DataSet.ReadXml" + or + this.getQualifiedName() = "System.Data.DataSet.ReadXmlSchema" + or + this.getName().matches("ReadXml%") and + exists(Class c | c.getAMethod() = this | + c.getABaseType*() instanceof DataSetOrTableRelatedClass + ) + } +} + +/** + * MethodCall that may be unsafe when used to deserialize DataSet and DataTable related types + */ +class UnsafeXmlReadMethodCall extends MethodCall { + UnsafeXmlReadMethodCall() { exists(UnsafeXmlReadMethod uxrm | uxrm.getACall() = this) } +} diff --git a/csharp/ql/src/experimental/Security Features/Serialization/DefiningDatasetRelatedType.qhelp b/csharp/ql/src/experimental/Security Features/Serialization/DefiningDatasetRelatedType.qhelp new file mode 100644 index 000000000000..af51bf311f1f --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/Serialization/DefiningDatasetRelatedType.qhelp @@ -0,0 +1,5 @@ + + + diff --git a/csharp/ql/src/experimental/Security Features/Serialization/DefiningDatasetRelatedType.ql b/csharp/ql/src/experimental/Security Features/Serialization/DefiningDatasetRelatedType.ql new file mode 100644 index 000000000000..be79f2849ad9 --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/Serialization/DefiningDatasetRelatedType.ql @@ -0,0 +1,16 @@ +/** + * @name Defining a class that inherits or has a property derived from the obsolete DataSet or DataTable types + * @description Defining a class that inherits or has a property derived from the obsolete DataSet or DataTable types may lead to the usage of dangerous functionality. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. + * @kind problem + * @problem.severity warning + * @id cs/dataset-serialization/defining-dataset-related-type + * @tags security + */ + +import csharp +import DataSetSerialization + +from DataSetOrTableRelatedClass dstc +where dstc.fromSource() +select dstc, + "Defining a class that inherits or has a property derived from the obsolete DataSet or DataTable types. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details." diff --git a/csharp/ql/src/experimental/Security Features/Serialization/DefiningPotentiallyUnsafeXmlSerialization.qhelp b/csharp/ql/src/experimental/Security Features/Serialization/DefiningPotentiallyUnsafeXmlSerialization.qhelp new file mode 100644 index 000000000000..af51bf311f1f --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/Serialization/DefiningPotentiallyUnsafeXmlSerialization.qhelp @@ -0,0 +1,5 @@ + + + diff --git a/csharp/ql/src/experimental/Security Features/Serialization/DefiningPotentiallyUnsafeXmlSerializer.ql b/csharp/ql/src/experimental/Security Features/Serialization/DefiningPotentiallyUnsafeXmlSerializer.ql new file mode 100644 index 000000000000..320096d63015 --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/Serialization/DefiningPotentiallyUnsafeXmlSerializer.ql @@ -0,0 +1,20 @@ +/** + * @name Defining a potentially unsafe XML serializer + * @description Defining an XML serializable class that includes members that derive from DataSet or DataTable type may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. + * @kind problem + * @problem.severity error + * @precision medium + * @id cs/dataset-serialization/defining-potentially-unsafe-xml-serializer + * @tags security + */ + +import csharp +import DataSetSerialization + +from UnsafeXmlSerializerImplementation c, Member m +where + c.fromSource() and + isClassUnsafeXmlSerializerImplementation(c, m) +select m, + "Defining an serializable class $@ that has member $@ of a type that is derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details.", + c, c.toString(), m, m.toString() diff --git a/csharp/ql/src/experimental/Security Features/Serialization/UnsafeTypeUsedDataContractSerializer.qhelp b/csharp/ql/src/experimental/Security Features/Serialization/UnsafeTypeUsedDataContractSerializer.qhelp new file mode 100644 index 000000000000..af51bf311f1f --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/Serialization/UnsafeTypeUsedDataContractSerializer.qhelp @@ -0,0 +1,5 @@ + + + diff --git a/csharp/ql/src/experimental/Security Features/Serialization/UnsafeTypeUsedDataContractSerializer.ql b/csharp/ql/src/experimental/Security Features/Serialization/UnsafeTypeUsedDataContractSerializer.ql new file mode 100644 index 000000000000..f3a83b679267 --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/Serialization/UnsafeTypeUsedDataContractSerializer.ql @@ -0,0 +1,43 @@ +/** + * @name Unsafe type is used in data contract serializer + * @description Unsafe type is used in data contract serializer. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details." + * @kind problem + * @problem.severity error + * @precision medium + * @id cs/dataset-serialization/unsafe-type-used-data-contract-serializer + * @tags security + */ + +import csharp +import DataSetSerialization + +predicate xmlSerializerConstructorArgument(Expr e) { + exists(ObjectCreation oc, Constructor c | e = oc.getArgument(0) | + c = oc.getTarget() and + c.getDeclaringType().getABaseType*().hasQualifiedName("System.Xml.Serialization.XmlSerializer") + ) +} + +predicate unsafeDataContractTypeCreation(Expr e) { + exists(MethodCall gt | + gt.getTarget().getName() = "GetType" and + e = gt and + gt.getQualifier().getType() instanceof DataSetOrTableRelatedClass + ) + or + e.(TypeofExpr).getTypeAccess().getTarget() instanceof DataSetOrTableRelatedClass +} + +class Conf extends DataFlow::Configuration { + Conf() { this = "FlowToDataSerializerConstructor" } + + override predicate isSource(DataFlow::Node node) { unsafeDataContractTypeCreation(node.asExpr()) } + + override predicate isSink(DataFlow::Node node) { xmlSerializerConstructorArgument(node.asExpr()) } +} + +from Conf conf, DataFlow::Node source, DataFlow::Node sink +where conf.hasFlow(source, sink) +select sink, + "Unsafe type is used in data contract serializer. Make sure $@ comes from the trusted source.", + source, source.toString() diff --git a/csharp/ql/src/experimental/Security Features/Serialization/XmlDeserializationWithDataSet.qhelp b/csharp/ql/src/experimental/Security Features/Serialization/XmlDeserializationWithDataSet.qhelp new file mode 100644 index 000000000000..af51bf311f1f --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/Serialization/XmlDeserializationWithDataSet.qhelp @@ -0,0 +1,5 @@ + + + diff --git a/csharp/ql/src/experimental/Security Features/Serialization/XmlDeserializationWithDataSet.ql b/csharp/ql/src/experimental/Security Features/Serialization/XmlDeserializationWithDataSet.ql new file mode 100644 index 000000000000..d4392ca4544b --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/Serialization/XmlDeserializationWithDataSet.ql @@ -0,0 +1,16 @@ +/** + * @name XML deserialization with a type type derived from DataSet or DataTable + * @description Making an XML deserialization call with a type derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details." + * @kind problem + * @problem.severity error + * @precision medium + * @id cs/dataset-serialization/xml-deserialization-with-dataset + * @tags security + */ + +import csharp +import DataSetSerialization + +from UnsafeXmlReadMethodCall mc +select mc, + "Making an XML deserialization call with a type derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details." diff --git a/csharp/ql/src/semmle/code/csharp/ir/IR.qll b/csharp/ql/src/experimental/ir/IR.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/IR.qll rename to csharp/ql/src/experimental/ir/IR.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/IRConfiguration.qll b/csharp/ql/src/experimental/ir/IRConfiguration.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/IRConfiguration.qll rename to csharp/ql/src/experimental/ir/IRConfiguration.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/IRConsistency.ql b/csharp/ql/src/experimental/ir/IRConsistency.ql similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/IRConsistency.ql rename to csharp/ql/src/experimental/ir/IRConsistency.ql diff --git a/csharp/ql/src/semmle/code/csharp/ir/PrintIR.ql b/csharp/ql/src/experimental/ir/PrintIR.ql similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/PrintIR.ql rename to csharp/ql/src/experimental/ir/PrintIR.ql diff --git a/csharp/ql/src/semmle/code/csharp/ir/PrintIR.qll b/csharp/ql/src/experimental/ir/PrintIR.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/PrintIR.qll rename to csharp/ql/src/experimental/ir/PrintIR.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/Util.qll b/csharp/ql/src/experimental/ir/Util.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/Util.qll rename to csharp/ql/src/experimental/ir/Util.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/ValueNumbering.qll b/csharp/ql/src/experimental/ir/ValueNumbering.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/ValueNumbering.qll rename to csharp/ql/src/experimental/ir/ValueNumbering.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll b/csharp/ql/src/experimental/ir/implementation/EdgeKind.qll similarity index 89% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll rename to csharp/ql/src/experimental/ir/implementation/EdgeKind.qll index 54059fb5b82f..32e36bb67876 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll +++ b/csharp/ql/src/experimental/ir/implementation/EdgeKind.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that specify the conditions under which control flows along a given edge. + */ + private import internal.EdgeKindInternal private newtype TEdgeKind = @@ -77,9 +81,15 @@ class CaseEdge extends EdgeKind, TCaseEdge { else result = "Case[" + minValue + ".." + maxValue + "]" } - string getMinValue() { result = minValue } + /** + * Gets the smallest value of the switch expression for which control will flow along this edge. + */ + final string getMinValue() { result = minValue } - string getMaxValue() { result = maxValue } + /** + * Gets the largest value of the switch expression for which control will flow along this edge. + */ + final string getMaxValue() { result = maxValue } } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRConfiguration.qll b/csharp/ql/src/experimental/ir/implementation/IRConfiguration.qll similarity index 70% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/IRConfiguration.qll rename to csharp/ql/src/experimental/ir/implementation/IRConfiguration.qll index 71bc8ec2b0f2..37ac2fccdd94 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRConfiguration.qll +++ b/csharp/ql/src/experimental/ir/implementation/IRConfiguration.qll @@ -10,6 +10,7 @@ private newtype TIRConfiguration = MkIRConfiguration() * The query can extend this class to control which functions have IR generated for them. */ class IRConfiguration extends TIRConfiguration { + /** Gets a textual representation of this element. */ string toString() { result = "IRConfiguration" } /** @@ -17,6 +18,13 @@ class IRConfiguration extends TIRConfiguration { */ predicate shouldCreateIRForFunction(Language::Function func) { any() } + /** + * Holds if the strings used as part of an IR dump should be generated for function `func`. + * + * This predicate is overridden in `PrintIR.qll` to avoid the expense of generating a large number + * of debug strings for IR that will not be dumped. We still generate the actual IR for these + * functions, however, to preserve the results of any interprocedural analysis. + */ predicate shouldEvaluateDebugStringsForFunction(Language::Function func) { any() } } @@ -26,6 +34,7 @@ private newtype TIREscapeAnalysisConfiguration = MkIREscapeAnalysisConfiguration * The query can extend this class to control what escape analysis is used when generating SSA. */ class IREscapeAnalysisConfiguration extends TIREscapeAnalysisConfiguration { + /** Gets a textual representation of this element. */ string toString() { result = "IREscapeAnalysisConfiguration" } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll b/csharp/ql/src/experimental/ir/implementation/IRType.qll similarity index 89% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll rename to csharp/ql/src/experimental/ir/implementation/IRType.qll index d196cdce0ab2..3bf3bf2e2766 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll +++ b/csharp/ql/src/experimental/ir/implementation/IRType.qll @@ -32,6 +32,7 @@ private newtype TIRType = * all pointer types map to the same instance of `IRAddressType`. */ class IRType extends TIRType { + /** Gets a textual representation of this type. */ string toString() { none() } /** @@ -111,6 +112,8 @@ private class IRSizedType extends IRType { this = TIRFunctionAddressType(byteSize) or this = TIROpaqueType(_, byteSize) } + // Don't override `getByteSize()` here. The optimizer seems to generate better code when this is + // overridden only in the leaf classes. } /** @@ -128,7 +131,7 @@ class IRBooleanType extends IRSizedType, TIRBooleanType { } /** - * A numberic type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and + * A numeric type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and * `IRFloatingPointType`. */ class IRNumericType extends IRSizedType { @@ -137,13 +140,33 @@ class IRNumericType extends IRSizedType { this = TIRUnsignedIntegerType(byteSize) or this = TIRFloatingPointType(byteSize, _, _) } + // Don't override `getByteSize()` here. The optimizer seems to generate better code when this is + // overridden only in the leaf classes. +} + +/** + * An integer type. This includes `IRSignedIntegerType` and `IRUnsignedIntegerType`. + */ +class IRIntegerType extends IRNumericType { + IRIntegerType() { + this = TIRSignedIntegerType(byteSize) or + this = TIRUnsignedIntegerType(byteSize) + } + + /** Holds if this integer type is signed. */ + predicate isSigned() { none() } + + /** Holds if this integer type is unsigned. */ + predicate isUnsigned() { none() } + // Don't override `getByteSize()` here. The optimizer seems to generate better code when this is + // overridden only in the leaf classes. } /** * A signed two's-complement integer. Also used to represent enums whose underlying type is a signed * integer, as well as character types whose representation is signed. */ -class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType { +class IRSignedIntegerType extends IRIntegerType, TIRSignedIntegerType { final override string toString() { result = "int" + byteSize.toString() } final override Language::LanguageType getCanonicalLanguageType() { @@ -152,13 +175,15 @@ class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType { pragma[noinline] final override int getByteSize() { result = byteSize } + + override predicate isSigned() { any() } } /** * An unsigned two's-complement integer. Also used to represent enums whose underlying type is an * unsigned integer, as well as character types whose representation is unsigned. */ -class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType { +class IRUnsignedIntegerType extends IRIntegerType, TIRUnsignedIntegerType { final override string toString() { result = "uint" + byteSize.toString() } final override Language::LanguageType getCanonicalLanguageType() { @@ -167,6 +192,8 @@ class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType { pragma[noinline] final override int getByteSize() { result = byteSize } + + override predicate isUnsigned() { any() } } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/MemoryAccessKind.qll b/csharp/ql/src/experimental/ir/implementation/MemoryAccessKind.qll similarity index 93% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/MemoryAccessKind.qll rename to csharp/ql/src/experimental/ir/implementation/MemoryAccessKind.qll index 6852a9654017..5e11a310e2fb 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/MemoryAccessKind.qll +++ b/csharp/ql/src/experimental/ir/implementation/MemoryAccessKind.qll @@ -1,3 +1,9 @@ +/** + * Provides classes that describe how a particular `Instruction` or its operands access memory. + */ + +private import IRConfiguration + private newtype TMemoryAccessKind = TIndirectMemoryAccess() or TBufferMemoryAccess() or @@ -14,6 +20,7 @@ private newtype TMemoryAccessKind = * memory result. */ class MemoryAccessKind extends TMemoryAccessKind { + /** Gets a textual representation of this access kind. */ string toString() { none() } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll b/csharp/ql/src/experimental/ir/implementation/Opcode.qll similarity index 59% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll rename to csharp/ql/src/experimental/ir/implementation/Opcode.qll index c0b8adbe56be..c4134d240aba 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll +++ b/csharp/ql/src/experimental/ir/implementation/Opcode.qll @@ -1,3 +1,8 @@ +/** + * Provides `Opcode`s that specify the operation performed by an `Instruction`, as well as metadata + * about those opcodes, such as operand kinds and memory accesses. + */ + private import internal.OpcodeImports as Imports private import internal.OperandTag import Imports::MemoryAccessKind @@ -45,7 +50,7 @@ private newtype TOpcode = TConvertToDerived() or TCheckedConvertOrNull() or TCheckedConvertOrThrow() or - TDynamicCastToVoid() or + TCompleteObjectAddress() or TVariableAddress() or TFieldAddress() or TFunctionAddress() or @@ -86,7 +91,11 @@ private newtype TOpcode = TUnreached() or TNewObj() +/** + * An opcode that specifies the operation performed by an `Instruction`. + */ class Opcode extends TOpcode { + /** Gets a textual representation of this element. */ string toString() { result = "UnknownOpcode" } /** @@ -139,10 +148,20 @@ class Opcode extends TOpcode { predicate hasOperandInternal(OperandTag tag) { none() } } +/** + * The `Opcode` for a `UnaryInstruction`. + * + * See the `UnaryInstruction` documentation for more details. + */ abstract class UnaryOpcode extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof UnaryOperandTag } } +/** + * The `Opcode` for a `BinaryInstruction`. + * + * See the `BinaryInstruction` documentation for more details. + */ abstract class BinaryOpcode extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof LeftOperandTag or @@ -150,44 +169,127 @@ abstract class BinaryOpcode extends Opcode { } } +/** + * The `Opcode` for a `PointerArithmeticInstruction`. + * + * See the `PointerArithmeticInstruction` documentation for more details. + */ abstract class PointerArithmeticOpcode extends BinaryOpcode { } +/** + * The `Opcode` for a `PointerOffsetInstruction`. + * + * See the `PointerOffsetInstruction` documentation for more details. + */ abstract class PointerOffsetOpcode extends PointerArithmeticOpcode { } +/** + * The `Opcode` for an `ArithmeticInstruction`. + * + * See the `ArithmeticInstruction` documentation for more details. + */ abstract class ArithmeticOpcode extends Opcode { } +/** + * The `Opcode` for a `BinaryArithmeticInstruction`. + * + * See the `BinaryArithmeticInstruction` documentation for more details. + */ abstract class BinaryArithmeticOpcode extends BinaryOpcode, ArithmeticOpcode { } +/** + * The `Opcode` for a `UnaryArithmeticInstruction`. + * + * See the `UnaryArithmeticInstruction` documentation for more details. + */ abstract class UnaryArithmeticOpcode extends UnaryOpcode, ArithmeticOpcode { } +/** + * The `Opcode` for a `BitwiseInstruction`. + * + * See the `BitwiseInstruction` documentation for more details. + */ abstract class BitwiseOpcode extends Opcode { } +/** + * The `Opcode` for a `BinaryBitwiseInstruction`. + * + * See the `BinaryBitwiseInstruction` documentation for more details. + */ abstract class BinaryBitwiseOpcode extends BinaryOpcode, BitwiseOpcode { } +/** + * The `Opcode` for a `UnaryBitwiseInstruction`. + * + * See the `UnaryBitwiseInstruction` documentation for more details. + */ abstract class UnaryBitwiseOpcode extends UnaryOpcode, BitwiseOpcode { } +/** + * The `Opcode` for a `CompareInstruction`. + * + * See the `CompareInstruction` documentation for more details. + */ abstract class CompareOpcode extends BinaryOpcode { } +/** + * The `Opcode` for a `RelationalInstruction`. + * + * See the `RelationalInstruction` documentation for more details. + */ abstract class RelationalOpcode extends CompareOpcode { } +/** + * The `Opcode` for a `CopyInstruction`. + * + * See the `CopyInstruction` documentation for more details. + */ abstract class CopyOpcode extends Opcode { } +/** + * The `Opcode` for a `ConvertToBaseInstruction`. + * + * See the `ConvertToBaseInstruction` documentation for more details. + */ abstract class ConvertToBaseOpcode extends UnaryOpcode { } -abstract class MemoryAccessOpcode extends Opcode { } - +/** + * The `Opcode` for a `ReturnInstruction`. + * + * See the `ReturnInstruction` documentation for more details. + */ abstract class ReturnOpcode extends Opcode { } +/** + * The `Opcode` for a `ThrowInstruction`. + * + * See the `ThrowInstruction` documentation for more details. + */ abstract class ThrowOpcode extends Opcode { } +/** + * The `Opcode` for a `CatchInstruction`. + * + * See the `CatchInstruction` documentation for more details. + */ abstract class CatchOpcode extends Opcode { } -abstract class OpcodeWithCondition extends Opcode { +abstract private class OpcodeWithCondition extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof ConditionOperandTag } } +/** + * The `Opcode` for a `BuiltInOperationInstruction`. + * + * See the `BuiltInOperationInstruction` documentation for more details. + */ abstract class BuiltInOperationOpcode extends Opcode { } +/** + * The `Opcode` for a `SideEffectInstruction`. + * + * See the `SideEffectInstruction` documentation for more details. + */ abstract class SideEffectOpcode extends Opcode { } /** @@ -323,7 +425,9 @@ abstract class OpcodeWithLoad extends IndirectReadOpcode { } /** - * An opcode that reads from a set of memory locations as a side effect. + * The `Opcode` for a `ReadSideEffectInstruction`. + * + * See the `ReadSideEffectInstruction` documentation for more details. */ abstract class ReadSideEffectOpcode extends SideEffectOpcode { final override predicate hasOperandInternal(OperandTag tag) { @@ -332,51 +436,111 @@ abstract class ReadSideEffectOpcode extends SideEffectOpcode { } /** - * An opcode that writes to a set of memory locations as a side effect. + * The `Opcode` for a `WriteSideEffectInstruction`. + * + * See the `WriteSideEffectInstruction` documentation for more details. */ abstract class WriteSideEffectOpcode extends SideEffectOpcode { } +/** + * Provides `Opcode`s that specify the operation performed by an `Instruction`. + */ module Opcode { + /** + * The `Opcode` for a `NoOpInstruction`. + * + * See the `NoOpInstruction` documentation for more details. + */ class NoOp extends Opcode, TNoOp { final override string toString() { result = "NoOp" } } + /** + * The `Opcode` for an `UninitializedInstruction`. + * + * See the `UninitializedInstruction` documentation for more details. + */ class Uninitialized extends IndirectWriteOpcode, TUninitialized { final override string toString() { result = "Uninitialized" } } + /** + * The `Opcode` for an `ErrorInstruction`. + * + * See the `ErrorInstruction` documentation for more details. + */ class Error extends Opcode, TError { final override string toString() { result = "Error" } } + /** + * The `Opcode` for an `InitializeParameterInstruction`. + * + * See the `InitializeParameterInstruction` documentation for more details. + */ class InitializeParameter extends IndirectWriteOpcode, TInitializeParameter { final override string toString() { result = "InitializeParameter" } } + /** + * The `Opcode` for an `InitializeIndirectionInstruction`. + * + * See the `InitializeIndirectionInstruction` documentation for more details. + */ class InitializeIndirection extends EntireAllocationWriteOpcode, TInitializeIndirection { final override string toString() { result = "InitializeIndirection" } } + /** + * The `Opcode` for an `InitializeThisInstruction`. + * + * See the `InitializeThisInstruction` documentation for more details. + */ class InitializeThis extends Opcode, TInitializeThis { final override string toString() { result = "InitializeThis" } } + /** + * The `Opcode` for an `EnterFunctionInstruction`. + * + * See the `EnterFunctionInstruction` documentation for more details. + */ class EnterFunction extends Opcode, TEnterFunction { final override string toString() { result = "EnterFunction" } } + /** + * The `Opcode` for an `ExitFunctionInstruction`. + * + * See the `ExitFunctionInstruction` documentation for more details. + */ class ExitFunction extends Opcode, TExitFunction { final override string toString() { result = "ExitFunction" } } + /** + * The `Opcode` for a `ReturnValueInstruction`. + * + * See the `ReturnValueInstruction` documentation for more details. + */ class ReturnValue extends ReturnOpcode, OpcodeWithLoad, TReturnValue { final override string toString() { result = "ReturnValue" } } + /** + * The `Opcode` for a `ReturnVoidInstruction`. + * + * See the `ReturnVoidInstruction` documentation for more details. + */ class ReturnVoid extends ReturnOpcode, TReturnVoid { final override string toString() { result = "ReturnVoid" } } + /** + * The `Opcode` for a `ReturnIndirectionInstruction`. + * + * See the `ReturnIndirectionInstruction` documentation for more details. + */ class ReturnIndirection extends EntireAllocationReadOpcode, TReturnIndirection { final override string toString() { result = "ReturnIndirection" } @@ -385,14 +549,29 @@ module Opcode { } } + /** + * The `Opcode` for a `CopyValueInstruction`. + * + * See the `CopyValueInstruction` documentation for more details. + */ class CopyValue extends UnaryOpcode, CopyOpcode, TCopyValue { final override string toString() { result = "CopyValue" } } + /** + * The `Opcode` for a `LoadInstruction`. + * + * See the `LoadInstruction` documentation for more details. + */ class Load extends CopyOpcode, OpcodeWithLoad, TLoad { final override string toString() { result = "Load" } } + /** + * The `Opcode` for a `StoreInstruction`. + * + * See the `StoreInstruction` documentation for more details. + */ class Store extends CopyOpcode, IndirectWriteOpcode, TStore { final override string toString() { result = "Store" } @@ -401,154 +580,344 @@ module Opcode { } } + /** + * The `Opcode` for an `AddInstruction`. + * + * See the `AddInstruction` documentation for more details. + */ class Add extends BinaryArithmeticOpcode, TAdd { final override string toString() { result = "Add" } } + /** + * The `Opcode` for a `SubInstruction`. + * + * See the `SubInstruction` documentation for more details. + */ class Sub extends BinaryArithmeticOpcode, TSub { final override string toString() { result = "Sub" } } + /** + * The `Opcode` for a `MulInstruction`. + * + * See the `MulInstruction` documentation for more details. + */ class Mul extends BinaryArithmeticOpcode, TMul { final override string toString() { result = "Mul" } } + /** + * The `Opcode` for a `DivInstruction`. + * + * See the `DivInstruction` documentation for more details. + */ class Div extends BinaryArithmeticOpcode, TDiv { final override string toString() { result = "Div" } } + /** + * The `Opcode` for a `RemInstruction`. + * + * See the `RemInstruction` documentation for more details. + */ class Rem extends BinaryArithmeticOpcode, TRem { final override string toString() { result = "Rem" } } + /** + * The `Opcode` for a `NegateInstruction`. + * + * See the `NegateInstruction` documentation for more details. + */ class Negate extends UnaryArithmeticOpcode, TNegate { final override string toString() { result = "Negate" } } + /** + * The `Opcode` for a `ShiftLeftInstruction`. + * + * See the `ShiftLeftInstruction` documentation for more details. + */ class ShiftLeft extends BinaryBitwiseOpcode, TShiftLeft { final override string toString() { result = "ShiftLeft" } } + /** + * The `Opcode` for a `ShiftRightInstruction`. + * + * See the `ShiftRightInstruction` documentation for more details. + */ class ShiftRight extends BinaryBitwiseOpcode, TShiftRight { final override string toString() { result = "ShiftRight" } } + /** + * The `Opcode` for a `BitAndInstruction`. + * + * See the `BitAndInstruction` documentation for more details. + */ class BitAnd extends BinaryBitwiseOpcode, TBitAnd { final override string toString() { result = "BitAnd" } } + /** + * The `Opcode` for a `BitOrInstruction`. + * + * See the `BitOrInstruction` documentation for more details. + */ class BitOr extends BinaryBitwiseOpcode, TBitOr { final override string toString() { result = "BitOr" } } + /** + * The `Opcode` for a `BitXorInstruction`. + * + * See the `BitXorInstruction` documentation for more details. + */ class BitXor extends BinaryBitwiseOpcode, TBitXor { final override string toString() { result = "BitXor" } } + /** + * The `Opcode` for a `BitComplementInstruction`. + * + * See the `BitComplementInstruction` documentation for more details. + */ class BitComplement extends UnaryBitwiseOpcode, TBitComplement { final override string toString() { result = "BitComplement" } } + /** + * The `Opcode` for a `LogicalNotInstruction`. + * + * See the `LogicalNotInstruction` documentation for more details. + */ class LogicalNot extends UnaryOpcode, TLogicalNot { final override string toString() { result = "LogicalNot" } } + /** + * The `Opcode` for a `CompareEQInstruction`. + * + * See the `CompareEQInstruction` documentation for more details. + */ class CompareEQ extends CompareOpcode, TCompareEQ { final override string toString() { result = "CompareEQ" } } + /** + * The `Opcode` for a `CompareNEInstruction`. + * + * See the `CompareNEInstruction` documentation for more details. + */ class CompareNE extends CompareOpcode, TCompareNE { final override string toString() { result = "CompareNE" } } + /** + * The `Opcode` for a `CompareLTInstruction`. + * + * See the `CompareLTInstruction` documentation for more details. + */ class CompareLT extends RelationalOpcode, TCompareLT { final override string toString() { result = "CompareLT" } } + /** + * The `Opcode` for a `CompareGTInstruction`. + * + * See the `CompareGTInstruction` documentation for more details. + */ class CompareGT extends RelationalOpcode, TCompareGT { final override string toString() { result = "CompareGT" } } + /** + * The `Opcode` for a `CompareLEInstruction`. + * + * See the `CompareLEInstruction` documentation for more details. + */ class CompareLE extends RelationalOpcode, TCompareLE { final override string toString() { result = "CompareLE" } } + /** + * The `Opcode` for a `CompareGEInstruction`. + * + * See the `CompareGEInstruction` documentation for more details. + */ class CompareGE extends RelationalOpcode, TCompareGE { final override string toString() { result = "CompareGE" } } + /** + * The `Opcode` for a `PointerAddInstruction`. + * + * See the `PointerAddInstruction` documentation for more details. + */ class PointerAdd extends PointerOffsetOpcode, TPointerAdd { final override string toString() { result = "PointerAdd" } } + /** + * The `Opcode` for a `PointerSubInstruction`. + * + * See the `PointerSubInstruction` documentation for more details. + */ class PointerSub extends PointerOffsetOpcode, TPointerSub { final override string toString() { result = "PointerSub" } } + /** + * The `Opcode` for a `PointerDiffInstruction`. + * + * See the `PointerDiffInstruction` documentation for more details. + */ class PointerDiff extends PointerArithmeticOpcode, TPointerDiff { final override string toString() { result = "PointerDiff" } } + /** + * The `Opcode` for a `ConvertInstruction`. + * + * See the `ConvertInstruction` documentation for more details. + */ class Convert extends UnaryOpcode, TConvert { final override string toString() { result = "Convert" } } + /** + * The `Opcode` for a `ConvertToNonVirtualBaseInstruction`. + * + * See the `ConvertToNonVirtualBaseInstruction` documentation for more details. + */ class ConvertToNonVirtualBase extends ConvertToBaseOpcode, TConvertToNonVirtualBase { final override string toString() { result = "ConvertToNonVirtualBase" } } + /** + * The `Opcode` for a `ConvertToVirtualBaseInstruction`. + * + * See the `ConvertToVirtualBaseInstruction` documentation for more details. + */ class ConvertToVirtualBase extends ConvertToBaseOpcode, TConvertToVirtualBase { final override string toString() { result = "ConvertToVirtualBase" } } + /** + * The `Opcode` for a `ConvertToDerivedInstruction`. + * + * See the `ConvertToDerivedInstruction` documentation for more details. + */ class ConvertToDerived extends UnaryOpcode, TConvertToDerived { final override string toString() { result = "ConvertToDerived" } } + /** + * The `Opcode` for a `CheckedConvertOrNullInstruction`. + * + * See the `CheckedConvertOrNullInstruction` documentation for more details. + */ class CheckedConvertOrNull extends UnaryOpcode, TCheckedConvertOrNull { final override string toString() { result = "CheckedConvertOrNull" } } + /** + * The `Opcode` for a `CheckedConvertOrThrowInstruction`. + * + * See the `CheckedConvertOrThrowInstruction` documentation for more details. + */ class CheckedConvertOrThrow extends UnaryOpcode, TCheckedConvertOrThrow { final override string toString() { result = "CheckedConvertOrThrow" } } - class DynamicCastToVoid extends UnaryOpcode, TDynamicCastToVoid { - final override string toString() { result = "DynamicCastToVoid" } + /** + * The `Opcode` for a `CompleteObjectAddressInstruction`. + * + * See the `CompleteObjectAddressInstruction` documentation for more details. + */ + class CompleteObjectAddress extends UnaryOpcode, TCompleteObjectAddress { + final override string toString() { result = "CompleteObjectAddress" } } + /** + * The `Opcode` for a `VariableAddressInstruction`. + * + * See the `VariableAddressInstruction` documentation for more details. + */ class VariableAddress extends Opcode, TVariableAddress { final override string toString() { result = "VariableAddress" } } + /** + * The `Opcode` for a `FieldAddressInstruction`. + * + * See the `FieldAddressInstruction` documentation for more details. + */ class FieldAddress extends UnaryOpcode, TFieldAddress { final override string toString() { result = "FieldAddress" } } + /** + * The `Opcode` for an `ElementsAddressInstruction`. + * + * See the `ElementsAddressInstruction` documentation for more details. + */ class ElementsAddress extends UnaryOpcode, TElementsAddress { final override string toString() { result = "ElementsAddress" } } + /** + * The `Opcode` for a `FunctionAddressInstruction`. + * + * See the `FunctionAddressInstruction` documentation for more details. + */ class FunctionAddress extends Opcode, TFunctionAddress { final override string toString() { result = "FunctionAddress" } } + /** + * The `Opcode` for a `ConstantInstruction`. + * + * See the `ConstantInstruction` documentation for more details. + */ class Constant extends Opcode, TConstant { final override string toString() { result = "Constant" } } + /** + * The `Opcode` for a `StringConstantInstruction`. + * + * See the `StringConstantInstruction` documentation for more details. + */ class StringConstant extends Opcode, TStringConstant { final override string toString() { result = "StringConstant" } } + /** + * The `Opcode` for a `ConditionalBranchInstruction`. + * + * See the `ConditionalBranchInstruction` documentation for more details. + */ class ConditionalBranch extends OpcodeWithCondition, TConditionalBranch { final override string toString() { result = "ConditionalBranch" } } + /** + * The `Opcode` for a `SwitchInstruction`. + * + * See the `SwitchInstruction` documentation for more details. + */ class Switch extends OpcodeWithCondition, TSwitch { final override string toString() { result = "Switch" } } + /** + * The `Opcode` for a `CallInstruction`. + * + * See the `CallInstruction` documentation for more details. + */ class Call extends Opcode, TCall { final override string toString() { result = "Call" } @@ -557,32 +926,67 @@ module Opcode { } } + /** + * The `Opcode` for a `CatchByTypeInstruction`. + * + * See the `CatchByTypeInstruction` documentation for more details. + */ class CatchByType extends CatchOpcode, TCatchByType { final override string toString() { result = "CatchByType" } } + /** + * The `Opcode` for a `CatchAnyInstruction`. + * + * See the `CatchAnyInstruction` documentation for more details. + */ class CatchAny extends CatchOpcode, TCatchAny { final override string toString() { result = "CatchAny" } } + /** + * The `Opcode` for a `ThrowValueInstruction`. + * + * See the `ThrowValueInstruction` documentation for more details. + */ class ThrowValue extends ThrowOpcode, OpcodeWithLoad, TThrowValue { final override string toString() { result = "ThrowValue" } } + /** + * The `Opcode` for a `ReThrowInstruction`. + * + * See the `ReThrowInstruction` documentation for more details. + */ class ReThrow extends ThrowOpcode, TReThrow { final override string toString() { result = "ReThrow" } } + /** + * The `Opcode` for an `UnwindInstruction`. + * + * See the `UnwindInstruction` documentation for more details. + */ class Unwind extends Opcode, TUnwind { final override string toString() { result = "Unwind" } } + /** + * The `Opcode` for an `AliasedDefinitionInstruction`. + * + * See the `AliasedDefinitionInstruction` documentation for more details. + */ class AliasedDefinition extends Opcode, TAliasedDefinition { final override string toString() { result = "AliasedDefinition" } final override MemoryAccessKind getWriteMemoryAccess() { result instanceof EscapedMemoryAccess } } + /** + * The `Opcode` for an `InitializeNonLocalInstruction`. + * + * See the `InitializeNonLocalInstruction` documentation for more details. + */ class InitializeNonLocal extends Opcode, TInitializeNonLocal { final override string toString() { result = "InitializeNonLocal" } @@ -591,6 +995,11 @@ module Opcode { } } + /** + * The `Opcode` for an `AliasedUseInstruction`. + * + * See the `AliasedUseInstruction` documentation for more details. + */ class AliasedUse extends Opcode, TAliasedUse { final override string toString() { result = "AliasedUse" } @@ -601,92 +1010,187 @@ module Opcode { } } + /** + * The `Opcode` for a `PhiInstruction`. + * + * See the `PhiInstruction` documentation for more details. + */ class Phi extends Opcode, TPhi { final override string toString() { result = "Phi" } final override MemoryAccessKind getWriteMemoryAccess() { result instanceof PhiMemoryAccess } } + /** + * The `Opcode` for a `BuiltInInstruction`. + * + * See the `BuiltInInstruction` documentation for more details. + */ class BuiltIn extends BuiltInOperationOpcode, TBuiltIn { final override string toString() { result = "BuiltIn" } } + /** + * The `Opcode` for a `VarArgsStartInstruction`. + * + * See the `VarArgsStartInstruction` documentation for more details. + */ class VarArgsStart extends UnaryOpcode, TVarArgsStart { final override string toString() { result = "VarArgsStart" } } + /** + * The `Opcode` for a `VarArgsEndInstruction`. + * + * See the `VarArgsEndInstruction` documentation for more details. + */ class VarArgsEnd extends UnaryOpcode, TVarArgsEnd { final override string toString() { result = "VarArgsEnd" } } + /** + * The `Opcode` for a `VarArgInstruction`. + * + * See the `VarArgInstruction` documentation for more details. + */ class VarArg extends UnaryOpcode, TVarArg { final override string toString() { result = "VarArg" } } + /** + * The `Opcode` for a `NextVarArgInstruction`. + * + * See the `NextVarArgInstruction` documentation for more details. + */ class NextVarArg extends UnaryOpcode, TNextVarArg { final override string toString() { result = "NextVarArg" } } + /** + * The `Opcode` for a `CallSideEffectInstruction`. + * + * See the `CallSideEffectInstruction` documentation for more details. + */ class CallSideEffect extends WriteSideEffectOpcode, EscapedWriteOpcode, MayWriteOpcode, ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallSideEffect { final override string toString() { result = "CallSideEffect" } } + /** + * The `Opcode` for a `CallReadSideEffectInstruction`. + * + * See the `CallReadSideEffectInstruction` documentation for more details. + */ class CallReadSideEffect extends ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallReadSideEffect { final override string toString() { result = "CallReadSideEffect" } } + /** + * The `Opcode` for an `IndirectReadSideEffectInstruction`. + * + * See the `IndirectReadSideEffectInstruction` documentation for more details. + */ class IndirectReadSideEffect extends ReadSideEffectOpcode, IndirectReadOpcode, TIndirectReadSideEffect { final override string toString() { result = "IndirectReadSideEffect" } } + /** + * The `Opcode` for an `IndirectMustWriteSideEffectInstruction`. + * + * See the `IndirectMustWriteSideEffectInstruction` documentation for more details. + */ class IndirectMustWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode, TIndirectMustWriteSideEffect { final override string toString() { result = "IndirectMustWriteSideEffect" } } + /** + * The `Opcode` for an `IndirectMayWriteSideEffectInstruction`. + * + * See the `IndirectMayWriteSideEffectInstruction` documentation for more details. + */ class IndirectMayWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode, MayWriteOpcode, TIndirectMayWriteSideEffect { final override string toString() { result = "IndirectMayWriteSideEffect" } } + /** + * The `Opcode` for a `BufferReadSideEffectInstruction`. + * + * See the `BufferReadSideEffectInstruction` documentation for more details. + */ class BufferReadSideEffect extends ReadSideEffectOpcode, UnsizedBufferReadOpcode, TBufferReadSideEffect { final override string toString() { result = "BufferReadSideEffect" } } + /** + * The `Opcode` for a `BufferMustWriteSideEffectInstruction`. + * + * See the `BufferMustWriteSideEffectInstruction` documentation for more details. + */ class BufferMustWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode, TBufferMustWriteSideEffect { final override string toString() { result = "BufferMustWriteSideEffect" } } + /** + * The `Opcode` for a `BufferMayWriteSideEffectInstruction`. + * + * See the `BufferMayWriteSideEffectInstruction` documentation for more details. + */ class BufferMayWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode, MayWriteOpcode, TBufferMayWriteSideEffect { final override string toString() { result = "BufferMayWriteSideEffect" } } + /** + * The `Opcode` for a `SizedBufferReadSideEffectInstruction`. + * + * See the `SizedBufferReadSideEffectInstruction` documentation for more details. + */ class SizedBufferReadSideEffect extends ReadSideEffectOpcode, SizedBufferReadOpcode, TSizedBufferReadSideEffect { final override string toString() { result = "SizedBufferReadSideEffect" } } + /** + * The `Opcode` for a `SizedBufferMustWriteSideEffectInstruction`. + * + * See the `SizedBufferMustWriteSideEffectInstruction` documentation for more details. + */ class SizedBufferMustWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode, TSizedBufferMustWriteSideEffect { final override string toString() { result = "SizedBufferMustWriteSideEffect" } } + /** + * The `Opcode` for a `SizedBufferMayWriteSideEffectInstruction`. + * + * See the `SizedBufferMayWriteSideEffectInstruction` documentation for more details. + */ class SizedBufferMayWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode, MayWriteOpcode, TSizedBufferMayWriteSideEffect { final override string toString() { result = "SizedBufferMayWriteSideEffect" } } + /** + * The `Opcode` for an `InitializeDynamicAllocationInstruction`. + * + * See the `InitializeDynamicAllocationInstruction` documentation for more details. + */ class InitializeDynamicAllocation extends SideEffectOpcode, EntireAllocationWriteOpcode, TInitializeDynamicAllocation { final override string toString() { result = "InitializeDynamicAllocation" } } + /** + * The `Opcode` for a `ChiInstruction`. + * + * See the `ChiInstruction` documentation for more details. + */ class Chi extends Opcode, TChi { final override string toString() { result = "Chi" } @@ -701,6 +1205,11 @@ module Opcode { } } + /** + * The `Opcode` for an `InlineAsmInstruction`. + * + * See the `InlineAsmInstruction` documentation for more details. + */ class InlineAsm extends Opcode, EscapedWriteOpcode, MayWriteOpcode, EscapedReadOpcode, MayReadOpcode, TInlineAsm { final override string toString() { result = "InlineAsm" } @@ -710,10 +1219,20 @@ module Opcode { } } + /** + * The `Opcode` for an `UnreachedInstruction`. + * + * See the `UnreachedInstruction` documentation for more details. + */ class Unreached extends Opcode, TUnreached { final override string toString() { result = "Unreached" } } + /** + * The `Opcode` for a `NewObjInstruction`. + * + * See the `NewObjInstruction` documentation for more details. + */ class NewObj extends Opcode, TNewObj { final override string toString() { result = "NewObj" } } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/TempVariableTag.qll b/csharp/ql/src/experimental/ir/implementation/TempVariableTag.qll similarity index 92% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/TempVariableTag.qll rename to csharp/ql/src/experimental/ir/implementation/TempVariableTag.qll index a0c0ca675307..5f230de560d6 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/TempVariableTag.qll +++ b/csharp/ql/src/experimental/ir/implementation/TempVariableTag.qll @@ -12,5 +12,6 @@ private import Imports::TempVariableTag * computed on each branch. The set of possible `TempVariableTag`s is language-dependent. */ class TempVariableTag extends TTempVariableTag { + /** Gets a textual representation of this tag. */ string toString() { result = getTempVariableTagId(this) } } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/UseSoundEscapeAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/UseSoundEscapeAnalysis.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/UseSoundEscapeAnalysis.qll rename to csharp/ql/src/experimental/ir/implementation/UseSoundEscapeAnalysis.qll diff --git a/csharp/ql/src/experimental/ir/implementation/internal/AliasedSSAStub.qll b/csharp/ql/src/experimental/ir/implementation/internal/AliasedSSAStub.qll new file mode 100644 index 000000000000..0fedd38bfbd2 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/internal/AliasedSSAStub.qll @@ -0,0 +1,19 @@ +/** + * Provides a stub implementation of the required aliased SSA interface until we implement aliased + * SSA construction for C#. + */ + +private import IRFunctionBase +private import TInstruction + +module SSA { + class MemoryLocation = boolean; + + predicate hasPhiInstruction(TRawInstruction blockStartInstr, MemoryLocation memoryLocation) { + none() + } + + predicate hasChiInstruction(TRawInstruction primaryInstruction) { none() } + + predicate hasUnreachedInstruction(IRFunctionBase irFunc) { none() } +} diff --git a/csharp/ql/src/experimental/ir/implementation/internal/EdgeKindInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/EdgeKindInternal.qll new file mode 100644 index 000000000000..ebcc9573bce2 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/internal/EdgeKindInternal.qll @@ -0,0 +1 @@ +import experimental.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/experimental/ir/implementation/internal/IRConfigurationInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/IRConfigurationInternal.qll new file mode 100644 index 000000000000..ebcc9573bce2 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/internal/IRConfigurationInternal.qll @@ -0,0 +1 @@ +import experimental.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBase.qll b/csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBase.qll new file mode 100644 index 000000000000..60895ce3d266 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBase.qll @@ -0,0 +1,27 @@ +/** + * Provides a base class, `IRFunctionBase`, for the stage-independent portions of `IRFunction`. + */ + +private import IRFunctionBaseInternal + +private newtype TIRFunction = + MkIRFunction(Language::Function func) { IRConstruction::Raw::functionHasIR(func) } + +/** + * The IR for a function. This base class contains only the predicates that are the same between all + * phases of the IR. Each instantiation of `IRFunction` extends this class. + */ +class IRFunctionBase extends TIRFunction { + Language::Function func; + + IRFunctionBase() { this = MkIRFunction(func) } + + /** Gets a textual representation of this element. */ + final string toString() { result = "IR: " + func.toString() } + + /** Gets the function whose IR is represented. */ + final Language::Function getFunction() { result = func } + + /** Gets the location of the function. */ + final Language::Location getLocation() { result = func.getLocation() } +} diff --git a/csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBaseInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBaseInternal.qll new file mode 100644 index 000000000000..f2da59bbb1d4 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBaseInternal.qll @@ -0,0 +1,2 @@ +import experimental.ir.internal.IRCSharpLanguage as Language +import experimental.ir.implementation.raw.internal.IRConstruction as IRConstruction diff --git a/csharp/ql/src/experimental/ir/implementation/internal/IRTypeInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/IRTypeInternal.qll new file mode 100644 index 000000000000..ebcc9573bce2 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/internal/IRTypeInternal.qll @@ -0,0 +1 @@ +import experimental.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/experimental/ir/implementation/internal/OpcodeImports.qll b/csharp/ql/src/experimental/ir/implementation/internal/OpcodeImports.qll new file mode 100644 index 000000000000..8bacf51d8a2b --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/internal/OpcodeImports.qll @@ -0,0 +1 @@ +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll b/csharp/ql/src/experimental/ir/implementation/internal/OperandTag.qll similarity index 82% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll rename to csharp/ql/src/experimental/ir/implementation/internal/OperandTag.qll index ac284440648d..21dfedd95cd4 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll +++ b/csharp/ql/src/experimental/ir/implementation/internal/OperandTag.qll @@ -40,7 +40,17 @@ abstract class OperandTag extends TOperandTag { /** * Gets a label that will appear before the operand when the IR is printed. */ - string getLabel() { result = "" } + final string getLabel() { if alwaysPrintLabel() then result = getId() + ":" else result = "" } + + /** + * Gets an identifier that uniquely identifies this operand within its instruction. + */ + abstract string getId(); + + /** + * Holds if the operand should always be prefixed with its label in the dump of its instruction. + */ + predicate alwaysPrintLabel() { none() } } /** @@ -69,7 +79,9 @@ class AddressOperandTag extends RegisterOperandTag, TAddressOperand { final override int getSortOrder() { result = 0 } - final override string getLabel() { result = "&:" } + final override predicate alwaysPrintLabel() { any() } + + final override string getId() { result = "&" } } AddressOperandTag addressOperand() { result = TAddressOperand() } @@ -82,6 +94,8 @@ class BufferSizeOperandTag extends RegisterOperandTag, TBufferSizeOperand { final override string toString() { result = "BufferSize" } final override int getSortOrder() { result = 1 } + + final override string getId() { result = "size" } } BufferSizeOperandTag bufferSizeOperand() { result = TBufferSizeOperand() } @@ -93,6 +107,8 @@ class SideEffectOperandTag extends TypedOperandTag, TSideEffectOperand { final override string toString() { result = "SideEffect" } final override int getSortOrder() { result = 2 } + + final override string getId() { result = "side_effect" } } SideEffectOperandTag sideEffectOperand() { result = TSideEffectOperand() } @@ -105,6 +121,8 @@ class LoadOperandTag extends TypedOperandTag, TLoadOperand { final override string toString() { result = "Load" } final override int getSortOrder() { result = 3 } + + final override string getId() { result = "load" } } LoadOperandTag loadOperand() { result = TLoadOperand() } @@ -116,6 +134,8 @@ class StoreValueOperandTag extends RegisterOperandTag, TStoreValueOperand { final override string toString() { result = "StoreValue" } final override int getSortOrder() { result = 4 } + + final override string getId() { result = "store" } } StoreValueOperandTag storeValueOperand() { result = TStoreValueOperand() } @@ -127,6 +147,8 @@ class UnaryOperandTag extends RegisterOperandTag, TUnaryOperand { final override string toString() { result = "Unary" } final override int getSortOrder() { result = 5 } + + final override string getId() { result = "unary" } } UnaryOperandTag unaryOperand() { result = TUnaryOperand() } @@ -138,6 +160,8 @@ class LeftOperandTag extends RegisterOperandTag, TLeftOperand { final override string toString() { result = "Left" } final override int getSortOrder() { result = 6 } + + final override string getId() { result = "left" } } LeftOperandTag leftOperand() { result = TLeftOperand() } @@ -149,6 +173,8 @@ class RightOperandTag extends RegisterOperandTag, TRightOperand { final override string toString() { result = "Right" } final override int getSortOrder() { result = 7 } + + final override string getId() { result = "right" } } RightOperandTag rightOperand() { result = TRightOperand() } @@ -160,6 +186,8 @@ class ConditionOperandTag extends RegisterOperandTag, TConditionOperand { final override string toString() { result = "Condition" } final override int getSortOrder() { result = 8 } + + final override string getId() { result = "cond" } } ConditionOperandTag conditionOperand() { result = TConditionOperand() } @@ -172,7 +200,9 @@ class CallTargetOperandTag extends RegisterOperandTag, TCallTargetOperand { final override int getSortOrder() { result = 10 } - final override string getLabel() { result = "func:" } + final override predicate alwaysPrintLabel() { any() } + + final override string getId() { result = "func" } } CallTargetOperandTag callTargetOperand() { result = TCallTargetOperand() } @@ -195,7 +225,9 @@ class ThisArgumentOperandTag extends ArgumentOperandTag, TThisArgumentOperand { final override int getSortOrder() { result = 11 } - final override string getLabel() { result = "this:" } + final override predicate alwaysPrintLabel() { any() } + + final override string getId() { result = "this" } } ThisArgumentOperandTag thisArgumentOperand() { result = TThisArgumentOperand() } @@ -212,9 +244,11 @@ class PositionalArgumentOperandTag extends ArgumentOperandTag, TPositionalArgume final override int getSortOrder() { result = 12 + argIndex } - final override string getLabel() { result = argIndex.toString() + ":" } + final override predicate alwaysPrintLabel() { any() } final int getArgIndex() { result = argIndex } + + final override string getId() { result = argIndex.toString() } } PositionalArgumentOperandTag positionalArgumentOperand(int argIndex) { @@ -228,7 +262,9 @@ class ChiTotalOperandTag extends ChiOperandTag, TChiTotalOperand { final override int getSortOrder() { result = 13 } - final override string getLabel() { result = "total:" } + final override predicate alwaysPrintLabel() { any() } + + final override string getId() { result = "total" } } ChiTotalOperandTag chiTotalOperand() { result = TChiTotalOperand() } @@ -238,7 +274,9 @@ class ChiPartialOperandTag extends ChiOperandTag, TChiPartialOperand { final override int getSortOrder() { result = 14 } - final override string getLabel() { result = "partial:" } + final override predicate alwaysPrintLabel() { any() } + + final override string getId() { result = "partial" } } ChiPartialOperandTag chiPartialOperand() { result = TChiPartialOperand() } @@ -252,7 +290,9 @@ class AsmOperandTag extends RegisterOperandTag, TAsmOperand { final override int getSortOrder() { result = 15 + index } - final override string getLabel() { result = index.toString() + ":" } + final override predicate alwaysPrintLabel() { any() } + + final override string getId() { result = index.toString() } } AsmOperandTag asmOperand(int index) { result = TAsmOperand(index) } diff --git a/csharp/ql/src/experimental/ir/implementation/internal/OperandTagInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/OperandTagInternal.qll new file mode 100644 index 000000000000..ebcc9573bce2 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/internal/OperandTagInternal.qll @@ -0,0 +1 @@ +import experimental.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariable.qll b/csharp/ql/src/experimental/ir/implementation/internal/TIRVariable.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariable.qll rename to csharp/ql/src/experimental/ir/implementation/internal/TIRVariable.qll diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TIRVariableInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/TIRVariableInternal.qll new file mode 100644 index 000000000000..e2b2c408a4f6 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/internal/TIRVariableInternal.qll @@ -0,0 +1,7 @@ +import experimental.ir.internal.IRCSharpLanguage as Language +import experimental.ir.implementation.raw.internal.IRConstruction::Raw as Construction +private import experimental.ir.implementation.TempVariableTag as TempVariableTag_ + +module Imports { + module TempVariableTag = TempVariableTag_; +} diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll b/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll new file mode 100644 index 000000000000..e16b71733b5a --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll @@ -0,0 +1,97 @@ +private import TInstructionInternal +private import IRFunctionBase +private import TInstructionImports as Imports +private import Imports::IRType +private import Imports::Opcode + +/** + * An IR instruction. `TInstruction` is shared across all phases of the IR. There are individual + * branches of this type for instructions created directly from the AST (`TRawInstruction`) and for + * instructions added by each stage of SSA construction (`T*PhiInstruction`, `T*ChiInstruction`, + * `T*UnreachedInstruction`). Each stage then defines a `TStageInstruction` type that is a union of + * all of the branches that can appear in that particular stage. The public `Instruction` class for + * each phase extends the `TStageInstruction` type for that stage. + */ +cached +newtype TInstruction = + TRawInstruction( + IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2 + ) { + IRConstruction::Raw::hasInstruction(tag1, tag2) + } or + TUnaliasedSSAPhiInstruction( + TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation + ) { + UnaliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation) + } or + TUnaliasedSSAChiInstruction(TRawInstruction primaryInstruction) { none() } or + TUnaliasedSSAUnreachedInstruction(IRFunctionBase irFunc) { + UnaliasedSSA::SSA::hasUnreachedInstruction(irFunc) + } or + TAliasedSSAPhiInstruction( + TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation + ) { + AliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation) + } or + TAliasedSSAChiInstruction(TRawInstruction primaryInstruction) { + AliasedSSA::SSA::hasChiInstruction(primaryInstruction) + } or + TAliasedSSAUnreachedInstruction(IRFunctionBase irFunc) { + AliasedSSA::SSA::hasUnreachedInstruction(irFunc) + } + +/** + * Provides wrappers for the constructors of each branch of `TInstruction` that is used by the + * unaliased SSA stage. + * These wrappers are not parameterized because it is not possible to invoke an IPA constructor via + * a class alias. + */ +module UnaliasedSSAInstructions { + class TPhiInstruction = TUnaliasedSSAPhiInstruction; + + TPhiInstruction phiInstruction( + TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation + ) { + result = TUnaliasedSSAPhiInstruction(blockStartInstr, memoryLocation) + } + + class TChiInstruction = TUnaliasedSSAChiInstruction; + + TChiInstruction chiInstruction(TRawInstruction primaryInstruction) { + result = TUnaliasedSSAChiInstruction(primaryInstruction) + } + + class TUnreachedInstruction = TUnaliasedSSAUnreachedInstruction; + + TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) { + result = TUnaliasedSSAUnreachedInstruction(irFunc) + } +} + +/** + * Provides wrappers for the constructors of each branch of `TInstruction` that is used by the + * aliased SSA stage. + * These wrappers are not parameterized because it is not possible to invoke an IPA constructor via + * a class alias. + */ +module AliasedSSAInstructions { + class TPhiInstruction = TAliasedSSAPhiInstruction; + + TPhiInstruction phiInstruction( + TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation + ) { + result = TAliasedSSAPhiInstruction(blockStartInstr, memoryLocation) + } + + class TChiInstruction = TAliasedSSAChiInstruction; + + TChiInstruction chiInstruction(TRawInstruction primaryInstruction) { + result = TAliasedSSAChiInstruction(primaryInstruction) + } + + class TUnreachedInstruction = TAliasedSSAUnreachedInstruction; + + TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) { + result = TAliasedSSAUnreachedInstruction(irFunc) + } +} diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TInstructionImports.qll b/csharp/ql/src/experimental/ir/implementation/internal/TInstructionImports.qll new file mode 100644 index 000000000000..6200f2a27966 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/internal/TInstructionImports.qll @@ -0,0 +1,2 @@ +import experimental.ir.implementation.IRType as IRType +import experimental.ir.implementation.Opcode as Opcode diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TInstructionInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/TInstructionInternal.qll new file mode 100644 index 000000000000..978d2c41aa79 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/internal/TInstructionInternal.qll @@ -0,0 +1,4 @@ +import experimental.ir.internal.IRCSharpLanguage as Language +import experimental.ir.implementation.raw.internal.IRConstruction as IRConstruction +import experimental.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedSSA +import AliasedSSAStub as AliasedSSA diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TempVariableTagInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/TempVariableTagInternal.qll new file mode 100644 index 000000000000..6d9f3e1e2db1 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/internal/TempVariableTagInternal.qll @@ -0,0 +1,6 @@ +import experimental.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.TempVariableTag as TempVariableTag_ + +module Imports { + module TempVariableTag = TempVariableTag_; +} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IR.qll b/csharp/ql/src/experimental/ir/implementation/raw/IR.qll new file mode 100644 index 000000000000..c96783fe6e81 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/IR.qll @@ -0,0 +1,80 @@ +/** + * Provides classes that describe the Intermediate Representation (IR) of the program. + * + * The IR is a representation of the semantics of the program, with very little dependence on the + * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, + * and `++i` all have the same semantic effect, but appear in the AST as three different types of + * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental + * operations similar to: + * + * ``` + * r1(int*) = VariableAddress[i] // Compute the address of variable `i` + * r2(int) = Load &:r1, m0 // Load the value of `i` + * r3(int) = Constant[1] // An integer constant with the value `1` + * r4(int) = Add r2, r3 // Add `1` to the value of `i` + * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` + * ``` + * + * This allows IR-based analysis to focus on the fundamental operations, rather than having to be + * concerned with the various ways of expressing those operations in source code. + * + * The key classes in the IR are: + * + * - `IRFunction` - Contains the IR for an entire function definition, including all of that + * function's `Instruction`s, `IRBlock`s, and `IRVariables`. + * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be + * performed, the operands that produce the inputs to that operation, and the type of the result + * of the operation. Control flows from an `Instruction` to one of a set of successor + * `Instruction`s. + * - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly + * represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has + * a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction` + * that produces its value (its "definition"). + * - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is + * created for each variable directly accessed by the function. In addition, `IRVariable`s are + * created to represent certain temporary storage locations that do not have explicitly declared + * variables in the source code, such as the return value of the function. + * - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a + * sequence of instructions such that control flow can only enter the block at the first + * instruction, and can only leave the block from the last instruction. + * - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType` + * is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all + * be represented as the `IRType` `uint4`, a four-byte unsigned integer. + */ + +import IRFunction +import Instruction +import IRBlock +import IRVariable +import Operand +private import internal.IRImports as Imports +import Imports::EdgeKind +import Imports::IRType +import Imports::MemoryAccessKind + +private newtype TIRPropertyProvider = MkIRPropertyProvider() + +/** + * A class that provides additional properties to be dumped for IR instructions and blocks when using + * the PrintIR module. Libraries that compute additional facts about IR elements can extend the + * single instance of this class to specify the additional properties computed by the library. + */ +class IRPropertyProvider extends TIRPropertyProvider { + /** Gets a textual representation of this element. */ + string toString() { result = "IRPropertyProvider" } + + /** + * Gets the value of the property named `key` for the specified instruction. + */ + string getInstructionProperty(Instruction instruction, string key) { none() } + + /** + * Gets the value of the property named `key` for the specified block. + */ + string getBlockProperty(IRBlock block, string key) { none() } + + /** + * Gets the value of the property named `key` for the specified operand. + */ + string getOperandProperty(Operand operand, string key) { none() } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRBlock.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll similarity index 75% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRBlock.qll rename to csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll index 94ef73b27692..d827ed3cf82d 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRBlock.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll @@ -1,3 +1,7 @@ +/** + * Provides classes describing basic blocks in the IR of a function. + */ + private import internal.IRInternal import Instruction private import internal.IRBlockImports as Imports @@ -16,15 +20,27 @@ private import Cached * Most consumers should use the class `IRBlock`. */ class IRBlockBase extends TIRBlock { + /** Gets a textual representation of this block. */ final string toString() { result = getFirstInstruction(this).toString() } + /** Gets the source location of the first non-`Phi` instruction in this block. */ final Language::Location getLocation() { result = getFirstInstruction().getLocation() } + /** + * INTERNAL: Do not use. + * + * Gets a string that uniquely identifies this block within its enclosing function. + * + * This predicate is used by debugging and printing code only. + */ final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() } /** - * Gets the zero-based index of the block within its function. This is used - * by debugging and printing code only. + * INTERNAL: Do not use. + * + * Gets the zero-based index of the block within its function. + * + * This predicate is used by debugging and printing code only. */ int getDisplayIndex() { exists(IRConfiguration::IRConfiguration config | @@ -42,27 +58,51 @@ class IRBlockBase extends TIRBlock { ) } + /** + * Gets the `index`th non-`Phi` instruction in this block. + */ final Instruction getInstruction(int index) { result = getInstruction(this, index) } + /** + * Get the `Phi` instructions that appear at the start of this block. + */ final PhiInstruction getAPhiInstruction() { Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() } + /** + * Gets an instruction in this block. This includes `Phi` instructions. + */ final Instruction getAnInstruction() { result = getInstruction(_) or result = getAPhiInstruction() } + /** + * Gets the first non-`Phi` instruction in this block. + */ final Instruction getFirstInstruction() { result = getFirstInstruction(this) } + /** + * Gets the last instruction in this block. + */ final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) } + /** + * Gets the number of non-`Phi` instructions in this block. + */ final int getInstructionCount() { result = getInstructionCount(this) } + /** + * Gets the `IRFunction` that contains this block. + */ final IRFunction getEnclosingIRFunction() { result = getFirstInstruction(this).getEnclosingIRFunction() } + /** + * Gets the `Function` that contains this block. + */ final Language::Function getEnclosingFunction() { result = getFirstInstruction(this).getEnclosingFunction() } @@ -74,20 +114,57 @@ class IRBlockBase extends TIRBlock { * instruction of another block. */ class IRBlock extends IRBlockBase { + /** + * Gets a block to which control flows directly from this block. + */ final IRBlock getASuccessor() { blockSuccessor(this, result) } + /** + * Gets a block from which control flows directly to this block. + */ final IRBlock getAPredecessor() { blockSuccessor(result, this) } + /** + * Gets the block to which control flows directly from this block along an edge of kind `kind`. + */ final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } + /** + * Gets the block to which control flows directly from this block along a back edge of kind + * `kind`. + */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } + /** + * Holds if this block immediately dominates `block`. + * + * Block `A` immediate dominates block `B` if block `A` strictly dominates block `B` and block `B` + * is a direct successor of block `A`. + */ final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) } + /** + * Holds if this block strictly dominates `block`. + * + * Block `A` strictly dominates block `B` if block `A` dominates block `B` and blocks `A` and `B` + * are not the same block. + */ final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) } + /** + * Holds if this block dominates `block`. + * + * Block `A` dominates block `B` if any control flow path from the entry block of the function to + * block `B` must pass through block `A`. A block always dominates itself. + */ final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } + /** + * Gets a block on the dominance frontier of this block. + * + * The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not + * dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`. + */ pragma[noinline] final IRBlock dominanceFrontier() { dominates(result.getAPredecessor()) and @@ -95,7 +172,7 @@ class IRBlock extends IRBlockBase { } /** - * Holds if this block is reachable from the entry point of its function + * Holds if this block is reachable from the entry block of its function. */ final predicate isReachableFromFunctionEntry() { this = getEnclosingIRFunction().getEntryBlock() or @@ -210,4 +287,4 @@ private module Cached { idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block) } -Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } +private Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.ql b/csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.ql similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.ql rename to csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.ql diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.qll new file mode 100644 index 000000000000..6a87b9b4b5fd --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.qll @@ -0,0 +1,497 @@ +private import IR +import InstructionConsistency // module is below +import IRTypeConsistency // module is in IRType.qll + +module InstructionConsistency { + private import internal.InstructionImports as Imports + private import Imports::OperandTag + private import Imports::Overlap + private import internal.IRInternal + + private newtype TOptionalIRFunction = + TPresentIRFunction(IRFunction irFunc) or + TMissingIRFunction() + + /** + * An `IRFunction` that might not exist. This is used so that we can produce consistency failures + * for IR that also incorrectly lacks a `getEnclosingIRFunction()`. + */ + abstract private class OptionalIRFunction extends TOptionalIRFunction { + abstract string toString(); + + abstract Language::Location getLocation(); + } + + private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction { + private IRFunction irFunc; + + PresentIRFunction() { this = TPresentIRFunction(irFunc) } + + override string toString() { + result = concat(Language::getIdentityString(irFunc.getFunction()), "; ") + } + + override Language::Location getLocation() { + // To avoid an overwhelming number of results when the extractor merges functions with the + // same name, just pick a single location. + result = + rank[1](Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString()) + } + } + + private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction { + override string toString() { result = "" } + + override Language::Location getLocation() { result instanceof Language::UnknownDefaultLocation } + } + + private OptionalIRFunction getInstructionIRFunction(Instruction instr) { + result = TPresentIRFunction(instr.getEnclosingIRFunction()) + or + not exists(instr.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getInstructionIRFunction(Instruction instr, string irFuncText) { + result = getInstructionIRFunction(instr) and + irFuncText = result.toString() + } + + private OptionalIRFunction getOperandIRFunction(Operand operand) { + result = TPresentIRFunction(operand.getEnclosingIRFunction()) + or + not exists(operand.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getOperandIRFunction(Operand operand, string irFuncText) { + result = getOperandIRFunction(operand) and + irFuncText = result.toString() + } + + private OptionalIRFunction getBlockIRFunction(IRBlock block) { + result = TPresentIRFunction(block.getEnclosingIRFunction()) + or + not exists(block.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + /** + * Holds if instruction `instr` is missing an expected operand with tag `tag`. + */ + query predicate missingOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(OperandTag tag | + instr.getOpcode().hasOperand(tag) and + not exists(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + message = + "Instruction '" + instr.getOpcode().toString() + + "' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if instruction `instr` has an unexpected operand with tag `tag`. + */ + query predicate unexpectedOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(OperandTag tag | + exists(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + not instr.getOpcode().hasOperand(tag) and + not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and + not ( + instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag + ) and + not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag) and + message = + "Instruction '" + instr.toString() + "' has unexpected operand '" + tag.toString() + + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if instruction `instr` has multiple operands with tag `tag`. + */ + query predicate duplicateOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(OperandTag tag, int operandCount | + operandCount = + strictcount(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + operandCount > 1 and + message = + "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + + " in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if `Phi` instruction `instr` is missing an operand corresponding to + * the predecessor block `pred`. + */ + query predicate missingPhiOperand( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRBlock pred | + pred = instr.getBlock().getAPredecessor() and + not exists(PhiInputOperand operand | + operand = instr.getAnOperand() and + operand.getPredecessorBlock() = pred + ) and + message = + "Instruction '" + instr.toString() + "' is missing an operand for predecessor block '" + + pred.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + query predicate missingOperandType( + Operand operand, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Instruction use | + not exists(operand.getType()) and + use = operand.getUse() and + message = + "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() + + "' is missing a type in function '$@'." and + irFunc = getOperandIRFunction(operand, irFuncText) + ) + } + + query predicate duplicateChiOperand( + ChiInstruction chi, string message, OptionalIRFunction irFunc, string irFuncText + ) { + chi.getTotal() = chi.getPartial() and + message = + "Chi instruction for " + chi.getPartial().toString() + + " has duplicate operands in function '$@'." and + irFunc = getInstructionIRFunction(chi, irFuncText) + } + + query predicate sideEffectWithoutPrimary( + SideEffectInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + not exists(instr.getPrimaryInstruction()) and + message = + "Side effect instruction '" + instr + "' is missing a primary instruction in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + /** + * Holds if an instruction, other than `ExitFunction`, has no successors. + */ + query predicate instructionWithoutSuccessor( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + not exists(instr.getASuccessor()) and + not instr instanceof ExitFunctionInstruction and + // Phi instructions aren't linked into the instruction-level flow graph. + not instr instanceof PhiInstruction and + not instr instanceof UnreachedInstruction and + message = "Instruction '" + instr.toString() + "' has no successors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + /** + * Holds if there are multiple edges of the same kind from `source`. + */ + query predicate ambiguousSuccessors( + Instruction source, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(EdgeKind kind, int n | + n = strictcount(Instruction t | source.getSuccessor(kind) = t) and + n > 1 and + message = + "Instruction '" + source.toString() + "' has " + n.toString() + " successors of kind '" + + kind.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(source, irFuncText) + ) + } + + /** + * Holds if `instr` is part of a loop even though the AST of `instr`'s enclosing function + * contains no element that can cause loops. + */ + query predicate unexplainedLoop( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Language::Function f | + exists(IRBlock block | + instr.getBlock() = block and + block.getEnclosingFunction() = f and + block.getASuccessor+() = block + ) and + not Language::hasPotentialLoop(f) and + message = + "Instruction '" + instr.toString() + "' is part of an unexplained loop in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if a `Phi` instruction is present in a block with fewer than two + * predecessors. + */ + query predicate unnecessaryPhiInstruction( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int n | + n = count(instr.getBlock().getAPredecessor()) and + n < 2 and + message = + "Instruction '" + instr.toString() + "' is in a block with only " + n.toString() + + " predecessors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if a memory operand is connected to a definition with an unmodeled result. + */ + query predicate memoryOperandDefinitionIsUnmodeled( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(MemoryOperand operand, Instruction def | + operand = instr.getAnOperand() and + def = operand.getAnyDef() and + not def.isResultModeled() and + message = + "Memory operand definition on instruction '" + instr.toString() + + "' has unmodeled result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if operand `operand` consumes a value that was defined in + * a different function. + */ + query predicate operandAcrossFunctions( + Operand operand, string message, OptionalIRFunction useIRFunc, string useIRFuncText, + OptionalIRFunction defIRFunc, string defIRFuncText + ) { + exists(Instruction useInstr, Instruction defInstr | + operand.getUse() = useInstr and + operand.getAnyDef() = defInstr and + useIRFunc = getInstructionIRFunction(useInstr, useIRFuncText) and + defIRFunc = getInstructionIRFunction(defInstr, defIRFuncText) and + useIRFunc != defIRFunc and + message = + "Operand '" + operand.toString() + "' is used on instruction '" + useInstr.toString() + + "' in function '$@', but is defined on instruction '" + defInstr.toString() + + "' in function '$@'." + ) + } + + /** + * Holds if instruction `instr` is not in exactly one block. + */ + query predicate instructionWithoutUniqueBlock( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int blockCount | + blockCount = count(instr.getBlock()) and + blockCount != 1 and + message = + "Instruction '" + instr.toString() + "' is a member of " + blockCount.toString() + + " blocks in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + private predicate forwardEdge(IRBlock b1, IRBlock b2) { + b1.getASuccessor() = b2 and + not b1.getBackEdgeSuccessor(_) = b2 + } + + /** + * Holds if `f` contains a loop in which no edge is a back edge. + * + * This check ensures we don't have too _few_ back edges. + */ + query predicate containsLoopOfForwardEdges(IRFunction f, string message) { + exists(IRBlock block | + forwardEdge+(block, block) and + block.getEnclosingIRFunction() = f and + message = "Function contains a loop consisting of only forward edges." + ) + } + + /** + * Holds if `block` is reachable from its function entry point but would not + * be reachable by traversing only forward edges. This check is skipped for + * functions containing `goto` statements as the property does not generally + * hold there. + * + * This check ensures we don't have too _many_ back edges. + */ + query predicate lostReachability( + IRBlock block, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRFunction f, IRBlock entry | + entry = f.getEntryBlock() and + entry.getASuccessor+() = block and + not forwardEdge+(entry, block) and + not Language::hasGoto(f.getFunction()) and + message = + "Block '" + block.toString() + + "' is not reachable by traversing only forward edges in function '$@'." and + irFunc = TPresentIRFunction(f) and + irFuncText = irFunc.toString() + ) + } + + /** + * Holds if the number of back edges differs between the `Instruction` graph + * and the `IRBlock` graph. + */ + query predicate backEdgeCountMismatch(OptionalIRFunction irFunc, string message) { + exists(int fromInstr, int fromBlock | + fromInstr = + count(Instruction i1, Instruction i2 | + getInstructionIRFunction(i1) = irFunc and i1.getBackEdgeSuccessor(_) = i2 + ) and + fromBlock = + count(IRBlock b1, IRBlock b2 | + getBlockIRFunction(b1) = irFunc and b1.getBackEdgeSuccessor(_) = b2 + ) and + fromInstr != fromBlock and + message = + "The instruction graph for function '" + irFunc.toString() + "' contains " + + fromInstr.toString() + " back edges, but the block graph contains " + fromBlock.toString() + + " back edges." + ) + } + + /** + * Gets the point in the function at which the specified operand is evaluated. For most operands, + * this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point + * of evaluation is at the end of the corresponding predecessor block. + */ + private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) { + block = operand.(PhiInputOperand).getPredecessorBlock() and + index = block.getInstructionCount() + or + exists(Instruction use | + use = operand.(NonPhiOperand).getUse() and + block.getInstruction(index) = use + ) + } + + /** + * Holds if `useOperand` has a definition that does not dominate the use. + */ + query predicate useNotDominatedByDefinition( + Operand useOperand, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | + pointOfEvaluation(useOperand, useBlock, useIndex) and + defInstr = useOperand.getAnyDef() and + ( + defInstr instanceof PhiInstruction and + defBlock = defInstr.getBlock() and + defIndex = -1 + or + defBlock.getInstruction(defIndex) = defInstr + ) and + not ( + defBlock.strictlyDominates(useBlock) + or + defBlock = useBlock and + defIndex < useIndex + ) and + message = + "Operand '" + useOperand.toString() + + "' is not dominated by its definition in function '$@'." and + irFunc = getOperandIRFunction(useOperand, irFuncText) + ) + } + + query predicate switchInstructionWithoutDefaultEdge( + SwitchInstruction switchInstr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + not exists(switchInstr.getDefaultSuccessor()) and + message = + "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and + irFunc = getInstructionIRFunction(switchInstr, irFuncText) + } + + /** + * Holds if `instr` is on the chain of chi/phi instructions for all aliased + * memory. + */ + private predicate isOnAliasedDefinitionChain(Instruction instr) { + instr instanceof AliasedDefinitionInstruction + or + isOnAliasedDefinitionChain(instr.(ChiInstruction).getTotal()) + or + isOnAliasedDefinitionChain(instr.(PhiInstruction).getAnInputOperand().getAnyDef()) + } + + private predicate shouldBeConflated(Instruction instr) { + isOnAliasedDefinitionChain(instr) + or + instr.getOpcode() instanceof Opcode::InitializeNonLocal + } + + query predicate notMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + shouldBeConflated(instr) and + not instr.isResultConflated() and + message = + "Instruction '" + instr.toString() + + "' should be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + query predicate wronglyMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + instr.isResultConflated() and + not shouldBeConflated(instr) and + message = + "Instruction '" + instr.toString() + + "' should not be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + query predicate invalidOverlap( + MemoryOperand useOperand, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Overlap overlap | + overlap = useOperand.getDefinitionOverlap() and + overlap instanceof MayPartiallyOverlap and + message = + "MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" + + overlap.toString() + "'." and + irFunc = getOperandIRFunction(useOperand, irFuncText) + ) + } + + query predicate nonUniqueEnclosingIRFunction( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int irFuncCount | + irFuncCount = count(instr.getEnclosingIRFunction()) and + irFuncCount != 1 and + message = + "Instruction '" + instr.toString() + "' has " + irFuncCount.toString() + + " results for `getEnclosingIRFunction()` in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRFunction.qll similarity index 70% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll rename to csharp/ql/src/experimental/ir/implementation/raw/IRFunction.qll index 9aea3e00d666..5968e58f90bf 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRFunction.qll @@ -1,29 +1,17 @@ +/** + * Provides the class `IRFunction`, which represents the Intermediate Representation for the + * definition of a function. + */ + private import internal.IRInternal +private import internal.IRFunctionImports as Imports +import Imports::IRFunctionBase import Instruction -private newtype TIRFunction = - MkIRFunction(Language::Function func) { Construction::functionHasIR(func) } - /** - * Represents the IR for a function. + * The IR for a function. */ -class IRFunction extends TIRFunction { - Language::Function func; - - IRFunction() { this = MkIRFunction(func) } - - final string toString() { result = "IR: " + func.toString() } - - /** - * Gets the function whose IR is represented. - */ - final Language::Function getFunction() { result = func } - - /** - * Gets the location of the function. - */ - final Language::Location getLocation() { result = func.getLocation() } - +class IRFunction extends IRFunctionBase { /** * Gets the entry point for this function. */ diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll similarity index 78% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll rename to csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll index 9f2a0d4ea281..146fc2707383 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent variables accessed by the IR. + */ + private import internal.IRInternal import IRFunction private import internal.IRVariableImports as Imports @@ -7,15 +11,11 @@ private import Imports::TTempVariableTag private import Imports::TIRVariable private import Imports::IRType -IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { - result.getVariable() = var and - result.getEnclosingFunction() = func -} - /** - * A variable referenced by the IR for a function. The variable may be a user-declared variable - * (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation - * (`IRTempVariable`). + * A variable referenced by the IR for a function. + * + * The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated + * by the AST-to-IR translation (`IRTempVariable`). */ class IRVariable extends TIRVariable { Language::Function func; @@ -27,6 +27,7 @@ class IRVariable extends TIRVariable { this = TIRDynamicInitializationFlag(func, _, _) } + /** Gets a textual representation of this element. */ string toString() { none() } /** @@ -162,20 +163,30 @@ class IRGeneratedVariable extends IRVariable { override string getUniqueId() { none() } + /** + * INTERNAL: Do not use. + * + * Gets a string containing the source code location of the AST that generated this variable. + * + * This is used by debugging and printing code only. + */ final string getLocationString() { result = ast.getLocation().getStartLine().toString() + ":" + ast.getLocation().getStartColumn().toString() } + /** + * INTERNAL: Do not use. + * + * Gets the string that is combined with the location of the variable to generate the string + * representation of this variable. + * + * This is used by debugging and printing code only. + */ string getBaseString() { none() } } -IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { - result.getAST() = ast and - result.getTag() = tag -} - /** * A temporary variable introduced by IR construction. The most common examples are the variable * generated to hold the return value of a function, or the variable generated to hold the result of @@ -190,6 +201,10 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa result = "Temp: " + Construction::getTempVariableUniqueId(this) } + /** + * Gets the "tag" object that differentiates this temporary variable from other temporary + * variables generated for the same AST. + */ final TempVariableTag getTag() { result = tag } override string getBaseString() { result = "#temp" } @@ -217,19 +232,23 @@ class IRThrowVariable extends IRTempVariable { * A temporary variable generated to hold the contents of all arguments passed to the `...` of a * function that accepts a variable number of arguments. */ -class IREllipsisVariable extends IRTempVariable { +class IREllipsisVariable extends IRTempVariable, IRParameter { IREllipsisVariable() { tag = EllipsisTempVar() } final override string toString() { result = "#ellipsis" } + + final override int getIndex() { result = func.getNumberOfParameters() } } /** * A temporary variable generated to hold the `this` pointer. */ -class IRThisVariable extends IRTempVariable { +class IRThisVariable extends IRTempVariable, IRParameter { IRThisVariable() { tag = ThisTempVar() } final override string toString() { result = "#this" } + + final override int getIndex() { result = -1 } } /** @@ -249,6 +268,9 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { final override string getBaseString() { result = "#string" } + /** + * Gets the AST of the string literal represented by this `IRStringLiteral`. + */ final Language::StringLiteral getLiteral() { result = literal } } @@ -266,6 +288,9 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string toString() { result = var.toString() + "#init" } + /** + * Gets variable whose initialization is guarded by this flag. + */ final Language::Variable getVariable() { result = var } final override string getUniqueId() { @@ -274,3 +299,29 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string getBaseString() { result = "#init:" + var.toString() + ":" } } + +/** + * An IR variable which acts like a function parameter, including positional parameters and the + * temporary variables generated for `this` and ellipsis parameters. + */ +class IRParameter extends IRAutomaticVariable { + IRParameter() { + this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter + or + this = TIRTempVariable(_, _, ThisTempVar(), _) + or + this = TIRTempVariable(_, _, EllipsisTempVar(), _) + } + + /** + * Gets the zero-based index of this parameter. The `this` parameter has index -1. + */ + int getIndex() { none() } +} + +/** + * An IR variable representing a positional parameter. + */ +class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable { + final override int getIndex() { result = getVariable().(Language::Parameter).getIndex() } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll similarity index 59% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll rename to csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll index 9c83a3d99f0c..620b23b942e0 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the individual instructions in the IR for a function. + */ + private import internal.IRInternal import IRFunction import IRBlock @@ -27,9 +31,16 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil } /** - * Represents a single operation in the IR. + * A single instruction in the IR. */ -class Instruction extends Construction::TInstruction { +class Instruction extends Construction::TStageInstruction { + Instruction() { + // The base `TStageInstruction` type is a superset of the actual instructions appearing in this + // stage. This call lets the stage filter out the ones that are not reused from raw IR. + Construction::hasInstruction(this) + } + + /** Gets a textual representation of this element. */ final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } /** @@ -194,16 +205,25 @@ class Instruction extends Construction::TInstruction { * conversion. */ final Language::Expr getConvertedResultExpression() { - result = Construction::getInstructionConvertedResultExpression(this) + result = Raw::getInstructionConvertedResultExpression(this) } /** * Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any. */ final Language::Expr getUnconvertedResultExpression() { - result = Construction::getInstructionUnconvertedResultExpression(this) + result = Raw::getInstructionUnconvertedResultExpression(this) } + /** + * Gets the language-specific type of the result produced by this instruction. + * + * Most consumers of the IR should use `getResultIRType()` instead. `getResultIRType()` uses a + * less complex, language-neutral type system in which all semantically equivalent types share the + * same `IRType` instance. For example, in C++, four different `Instruction`s might have three + * different values for `getResultLanguageType()`: `unsigned int`, `char32_t`, and `wchar_t`, + * whereas all four instructions would have the same value for `getResultIRType()`, `uint4`. + */ final Language::LanguageType getResultLanguageType() { result = Construction::getInstructionResultType(this) } @@ -212,6 +232,7 @@ class Instruction extends Construction::TInstruction { * Gets the type of the result produced by this instruction. If the instruction does not produce * a result, its result type will be `IRVoidType`. */ + cached final IRType getResultIRType() { result = getResultLanguageType().getIRType() } /** @@ -240,17 +261,19 @@ class Instruction extends Construction::TInstruction { * given by `getResultType()`. * * For example, the statement `y = x;` generates the following IR: + * ``` * r1_0(glval: int) = VariableAddress[x] * r1_1(int) = Load r1_0, mu0_1 * r1_2(glval: int) = VariableAddress[y] * mu1_3(int) = Store r1_2, r1_1 + * ``` * * The result of each `VariableAddress` instruction is a glvalue of type * `int`, representing the address of the corresponding integer variable. The * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) } + final predicate isGLValue() { getResultLanguageType().hasType(_, true) } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -259,7 +282,7 @@ class Instruction extends Construction::TInstruction { * If `this.isGLValue()` holds for this instruction, the value of * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() } + final int getResultSize() { result = getResultLanguageType().getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. @@ -392,13 +415,27 @@ class Instruction extends Construction::TInstruction { final Instruction getAPredecessor() { result = getPredecessor(_) } } +/** + * An instruction that refers to a variable. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * variable. For example, it is used for `VariableAddress`, which returns the address of a specific + * variable, and `InitializeParameter`, which returns the value that was passed to the specified + * parameter by the caller. `VariableInstruction` is not used for `Load` or `Store` instructions + * that happen to load from or store to a particular variable; in those cases, the memory location + * being accessed is specified by the `AddressOperand` on the instruction, which may or may not be + * defined by the result of a `VariableAddress` instruction. + */ class VariableInstruction extends Instruction { IRVariable var; - VariableInstruction() { var = Construction::getInstructionVariable(this) } + VariableInstruction() { var = Raw::getInstructionVariable(this) } override string getImmediateString() { result = var.toString() } + /** + * Gets the variable that this instruction references. + */ final IRVariable getIRVariable() { result = var } /** @@ -407,63 +444,156 @@ class VariableInstruction extends Instruction { final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that refers to a field of a class, struct, or union. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * field. For example, it is used for `FieldAddress`, which computes the address of a specific + * field on an object. `FieldInstruction` is not used for `Load` or `Store` instructions that happen + * to load from or store to a particular field; in those cases, the memory location being accessed + * is specified by the `AddressOperand` on the instruction, which may or may not be defined by the + * result of a `FieldAddress` instruction. + */ class FieldInstruction extends Instruction { Language::Field field; - FieldInstruction() { field = Construction::getInstructionField(this) } + FieldInstruction() { field = Raw::getInstructionField(this) } final override string getImmediateString() { result = field.toString() } + /** + * Gets the field that this instruction references. + */ final Language::Field getField() { result = field } } +/** + * An instruction that refers to a function. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * function. For example, it is used for `FunctionAddress`, which returns the address of a specific + * function. `FunctionInstruction` is not used for `Call` instructions that happen to call a + * particular function; in that case, the function being called is specified by the + * `CallTargetOperand` on the instruction, which may or may not be defined by the result of a + * `FunctionAddress` instruction. + */ class FunctionInstruction extends Instruction { Language::Function funcSymbol; - FunctionInstruction() { funcSymbol = Construction::getInstructionFunction(this) } + FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) } final override string getImmediateString() { result = funcSymbol.toString() } + /** + * Gets the function that this instruction references. + */ final Language::Function getFunctionSymbol() { result = funcSymbol } } +/** + * An instruction whose result is a compile-time constant value. + */ class ConstantValueInstruction extends Instruction { string value; - ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) } + ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) } final override string getImmediateString() { result = value } + /** + * Gets the constant value of this instruction's result. + */ final string getValue() { result = value } } +/** + * An instruction that refers to an argument of a `Call` instruction. + * + * This instruction is used for side effects of a `Call` instruction that read or write memory + * pointed to by one of the arguments of the call. + */ class IndexedInstruction extends Instruction { int index; - IndexedInstruction() { index = Construction::getInstructionIndex(this) } + IndexedInstruction() { index = Raw::getInstructionIndex(this) } final override string getImmediateString() { result = index.toString() } + /** + * Gets the zero-based index of the argument that this instruction references. + */ final int getIndex() { result = index } } +/** + * An instruction representing the entry point to a function. + * + * Each `IRFunction` has exactly one `EnterFunction` instruction. Execution of the function begins + * at this instruction. This instruction has no predecessors. + */ class EnterFunctionInstruction extends Instruction { EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction } } +/** + * An instruction that returns the address of a variable. + * + * This instruction returns the address of a local variable, parameter, static field, + * namespace-scope variable, or global variable. For the address of a non-static field of a class, + * struct, or union, see `FieldAddressInstruction`. + */ class VariableAddressInstruction extends VariableInstruction { VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } } +/** + * An instruction that returns the address of a function. + * + * This instruction returns the address of a function, including non-member functions, static member + * functions, and non-static member functions. + * + * The result has an `IRFunctionAddress` type. + */ +class FunctionAddressInstruction extends FunctionInstruction { + FunctionAddressInstruction() { getOpcode() instanceof Opcode::FunctionAddress } +} + +/** + * An instruction that initializes a parameter of the enclosing function with the value of the + * corresponding argument passed by the caller. + * + * Each parameter of a function will have exactly one `InitializeParameter` instruction that + * initializes that parameter. + */ class InitializeParameterInstruction extends VariableInstruction { InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that initializes all memory that existed before this function was called. + * + * This instruction provides a definition for memory that, because it was actually allocated and + * initialized elsewhere, would not otherwise have a definition in this function. + */ +class InitializeNonLocalInstruction extends Instruction { + InitializeNonLocalInstruction() { getOpcode() instanceof Opcode::InitializeNonLocal } +} + +/** + * An instruction that initializes the memory pointed to by a parameter of the enclosing function + * with the value of that memory on entry to the function. + */ class InitializeIndirectionInstruction extends VariableInstruction { InitializeIndirectionInstruction() { getOpcode() instanceof Opcode::InitializeIndirection } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } @@ -474,14 +604,42 @@ class InitializeThisInstruction extends Instruction { InitializeThisInstruction() { getOpcode() instanceof Opcode::InitializeThis } } +/** + * An instruction that computes the address of a non-static field of an object. + */ class FieldAddressInstruction extends FieldInstruction { FieldAddressInstruction() { getOpcode() instanceof Opcode::FieldAddress } + /** + * Gets the operand that provides the address of the object containing the field. + */ final UnaryOperand getObjectAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the object containing the field. + */ final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } } +/** + * An instruction that computes the address of the first element of a managed array. + * + * This instruction is used for element access to C# arrays. + */ +class ElementsAddressInstruction extends UnaryInstruction { + ElementsAddressInstruction() { getOpcode() instanceof Opcode::ElementsAddress } + + /** + * Gets the operand that provides the address of the array object. + */ + final UnaryOperand getArrayObjectAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the array object. + */ + final Instruction getArrayObjectAddress() { result = getArrayObjectAddressOperand().getDef() } +} + /** * An instruction that produces a well-defined but unknown result and has * unknown side effects, including side effects that are not conservatively @@ -496,6 +654,12 @@ class ErrorInstruction extends Instruction { ErrorInstruction() { getOpcode() instanceof Opcode::Error } } +/** + * An instruction that returns an uninitialized value. + * + * This instruction is used to provide an initial definition for a stack variable that does not have + * an initializer, or whose initializer only partially initializes the variable. + */ class UninitializedInstruction extends VariableInstruction { UninitializedInstruction() { getOpcode() instanceof Opcode::Uninitialized } @@ -505,35 +669,94 @@ class UninitializedInstruction extends VariableInstruction { final Language::Variable getLocalVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that has no effect. + * + * This instruction is typically inserted to ensure that a particular AST is associated with at + * least one instruction, even when the AST has no semantic effect. + */ class NoOpInstruction extends Instruction { NoOpInstruction() { getOpcode() instanceof Opcode::NoOp } } +/** + * An instruction that returns control to the caller of the function. + * + * This instruction represents the normal (non-exception) return from a function, either from an + * explicit `return` statement or from control flow reaching the end of the function's body. + * + * Each function has exactly one `ReturnInstruction`. Each `return` statement in a function is + * represented as an initialization of the temporary variable that holds the return value, with + * control then flowing to the common `ReturnInstruction` for that function. Exception: A function + * that never returns will not have a `ReturnInstruction`. + * + * The `ReturnInstruction` for a function will have a control-flow successor edge to a block + * containing the `ExitFunction` instruction for that function. + * + * There are two differet return instructions: `ReturnValueInstruction`, for returning a value from + * a non-`void`-returning function, and `ReturnVoidInstruction`, for returning from a + * `void`-returning function. + */ class ReturnInstruction extends Instruction { ReturnInstruction() { getOpcode() instanceof ReturnOpcode } } +/** + * An instruction that returns control to the caller of the function, without returning a value. + */ class ReturnVoidInstruction extends ReturnInstruction { ReturnVoidInstruction() { getOpcode() instanceof Opcode::ReturnVoid } } +/** + * An instruction that returns control to the caller of the function, including a return value. + */ class ReturnValueInstruction extends ReturnInstruction { ReturnValueInstruction() { getOpcode() instanceof Opcode::ReturnValue } + /** + * Gets the operand that provides the value being returned by the function. + */ final LoadOperand getReturnValueOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value being returned by the function, if an + * exact definition is available. + */ final Instruction getReturnValue() { result = getReturnValueOperand().getDef() } } +/** + * An instruction that represents the use of the value pointed to by a parameter of the function + * after the function returns control to its caller. + * + * This instruction does not itself return control to the caller. It merely represents the potential + * for a caller to use the memory pointed to by the parameter sometime after the call returns. This + * is the counterpart to the `InitializeIndirection` instruction, which represents the possibility + * that the caller initialized the memory pointed to by the parameter before the call. + */ class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } + /** + * Gets the operand that provides the value of the pointed-to memory. + */ final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the pointed-to memory, if an exact + * definition is available. + */ final Instruction getSideEffect() { result = getSideEffectOperand().getDef() } + /** + * Gets the operand that provides the address of the pointed-to memory. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the pointed-to memory. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } /** @@ -541,87 +764,191 @@ class ReturnIndirectionInstruction extends VariableInstruction { * function. */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } + + /** + * Holds if this instruction is the return indirection for `this`. + */ + final predicate isThisIndirection() { var instanceof IRThisVariable } } +/** + * An instruction that returns a copy of its operand. + * + * There are several different copy instructions, depending on the source and destination of the + * copy operation: + * - `CopyInstruction` - Copies a register operand to a register result. + * - `LoadInstruction` - Copies a memory operand to a register result. + * - `StoreInstruction` - Copies a register operand to a memory result. + */ class CopyInstruction extends Instruction { CopyInstruction() { getOpcode() instanceof CopyOpcode } + /** + * Gets the operand that provides the input value of the copy. + */ Operand getSourceValueOperand() { none() } + /** + * Gets the instruction whose result provides the input value of the copy, if an exact definition + * is available. + */ final Instruction getSourceValue() { result = getSourceValueOperand().getDef() } } +/** + * An instruction that returns a register result containing a copy of its register operand. + */ class CopyValueInstruction extends CopyInstruction, UnaryInstruction { CopyValueInstruction() { getOpcode() instanceof Opcode::CopyValue } final override UnaryOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a register result containing a copy of its memory operand. + */ class LoadInstruction extends CopyInstruction { LoadInstruction() { getOpcode() instanceof Opcode::Load } + /** + * Gets the operand that provides the address of the value being loaded. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the value being loaded. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } final override LoadOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a memory result containing a copy of its register operand. + */ class StoreInstruction extends CopyInstruction { StoreInstruction() { getOpcode() instanceof Opcode::Store } + /** + * Gets the operand that provides the address of the location to which the value will be stored. + */ final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the location to which the value will + * be stored, if an exact definition is available. + */ final Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } final override StoreValueOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that branches to one of two successor instructions based on the value of a Boolean + * operand. + */ class ConditionalBranchInstruction extends Instruction { ConditionalBranchInstruction() { getOpcode() instanceof Opcode::ConditionalBranch } + /** + * Gets the operand that provides the Boolean condition controlling the branch. + */ final ConditionOperand getConditionOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the Boolean condition controlling the branch. + */ final Instruction getCondition() { result = getConditionOperand().getDef() } + /** + * Gets the instruction to which control will flow if the condition is true. + */ final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } + /** + * Gets the instruction to which control will flow if the condition is false. + */ final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } } +/** + * An instruction representing the exit point of a function. + * + * Each `IRFunction` has exactly one `ExitFunction` instruction, unless the function neither returns + * nor throws an exception. Control flows to the `ExitFunction` instruction from both normal returns + * (`ReturnVoid`, `ReturnValue`) and propagated exceptions (`Unwind`). This instruction has no + * successors. + */ class ExitFunctionInstruction extends Instruction { ExitFunctionInstruction() { getOpcode() instanceof Opcode::ExitFunction } } +/** + * An instruction whose result is a constant value. + */ class ConstantInstruction extends ConstantValueInstruction { ConstantInstruction() { getOpcode() instanceof Opcode::Constant } } +/** + * An instruction whose result is a constant value of integer or Boolean type. + */ class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType } + IntegerConstantInstruction() { + exists(IRType resultType | + resultType = getResultIRType() and + (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType) + ) + } } +/** + * An instruction whose result is a constant value of floating-point type. + */ class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } + FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } +/** + * An instruction whose result is the address of a string literal. + */ class StringConstantInstruction extends VariableInstruction { override IRStringLiteral var; final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) } + /** + * Gets the string literal whose address is returned by this instruction. + */ final Language::StringLiteral getValue() { result = var.getLiteral() } } +/** + * An instruction whose result is computed from two operands. + */ class BinaryInstruction extends Instruction { BinaryInstruction() { getOpcode() instanceof BinaryOpcode } + /** + * Gets the left operand of this binary instruction. + */ final LeftOperand getLeftOperand() { result = getAnOperand() } + /** + * Gets the right operand of this binary instruction. + */ final RightOperand getRightOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the left operand of this binary + * instruction. + */ final Instruction getLeft() { result = getLeftOperand().getDef() } + /** + * Gets the instruction whose result provides the value of the right operand of this binary + * instruction. + */ final Instruction getRight() { result = getRightOperand().getDef() } /** @@ -634,121 +961,301 @@ class BinaryInstruction extends Instruction { } } +/** + * An instruction that computes the result of an arithmetic operation. + */ class ArithmeticInstruction extends Instruction { ArithmeticInstruction() { getOpcode() instanceof ArithmeticOpcode } } +/** + * An instruction that performs an arithmetic operation on two numeric operands. + */ class BinaryArithmeticInstruction extends ArithmeticInstruction, BinaryInstruction { } +/** + * An instruction whose result is computed by performing an arithmetic operation on a single + * numeric operand. + */ class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction { } +/** + * An instruction that computes the sum of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point addition is + * performed according to IEEE-754. + */ class AddInstruction extends BinaryArithmeticInstruction { AddInstruction() { getOpcode() instanceof Opcode::Add } } +/** + * An instruction that computes the difference of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point subtraction is performed + * according to IEEE-754. + */ class SubInstruction extends BinaryArithmeticInstruction { SubInstruction() { getOpcode() instanceof Opcode::Sub } } +/** + * An instruction that computes the product of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point multiplication is + * performed according to IEEE-754. + */ class MulInstruction extends BinaryArithmeticInstruction { MulInstruction() { getOpcode() instanceof Opcode::Mul } } +/** + * An instruction that computes the quotient of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. Floating-point division is performed according + * to IEEE-754. + */ class DivInstruction extends BinaryArithmeticInstruction { DivInstruction() { getOpcode() instanceof Opcode::Div } } +/** + * An instruction that computes the remainder of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. + */ class RemInstruction extends BinaryArithmeticInstruction { RemInstruction() { getOpcode() instanceof Opcode::Rem } } +/** + * An instruction that negates a single numeric operand. + * + * The operand must have a numeric type, which will also be the result type. The result of integer + * negation uses two's complement, and is computed modulo 2^n. The result of floating-point negation + * is performed according to IEEE-754. + */ class NegateInstruction extends UnaryArithmeticInstruction { NegateInstruction() { getOpcode() instanceof Opcode::Negate } } +/** + * An instruction that computes the result of a bitwise operation. + */ class BitwiseInstruction extends Instruction { BitwiseInstruction() { getOpcode() instanceof BitwiseOpcode } } +/** + * An instruction that performs a bitwise operation on two integer operands. + */ class BinaryBitwiseInstruction extends BitwiseInstruction, BinaryInstruction { } +/** + * An instruction that performs a bitwise operation on a single integer operand. + */ class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } +/** + * An instruction that computes the bitwise "and" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitAndInstruction extends BinaryBitwiseInstruction { BitAndInstruction() { getOpcode() instanceof Opcode::BitAnd } } +/** + * An instruction that computes the bitwise "or" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitOrInstruction extends BinaryBitwiseInstruction { BitOrInstruction() { getOpcode() instanceof Opcode::BitOr } } +/** + * An instruction that computes the bitwise "xor" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitXorInstruction extends BinaryBitwiseInstruction { BitXorInstruction() { getOpcode() instanceof Opcode::BitXor } } +/** + * An instruction that shifts its left operand to the left by the number of bits specified by its + * right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. The + * rightmost bits are zero-filled. + */ class ShiftLeftInstruction extends BinaryBitwiseInstruction { ShiftLeftInstruction() { getOpcode() instanceof Opcode::ShiftLeft } } +/** + * An instruction that shifts its left operand to the right by the number of bits specified by its + * right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. If the + * left operand has an unsigned integer type, the leftmost bits are zero-filled. If the left operand + * has a signed integer type, the leftmost bits are filled by duplicating the most significant bit + * of the left operand. + */ class ShiftRightInstruction extends BinaryBitwiseInstruction { ShiftRightInstruction() { getOpcode() instanceof Opcode::ShiftRight } } +/** + * An instruction that performs a binary arithmetic operation involving at least one pointer + * operand. + */ class PointerArithmeticInstruction extends BinaryInstruction { int elementSize; PointerArithmeticInstruction() { getOpcode() instanceof PointerArithmeticOpcode and - elementSize = Construction::getInstructionElementSize(this) + elementSize = Raw::getInstructionElementSize(this) } final override string getImmediateString() { result = elementSize.toString() } + /** + * Gets the size of the elements pointed to by the pointer operands, in bytes. + * + * When adding an integer offset to a pointer (`PointerAddInstruction`) or subtracting an integer + * offset from a pointer (`PointerSubInstruction`), the integer offset is multiplied by the + * element size to compute the actual number of bytes added to or subtracted from the pointer + * address. When computing the integer difference between two pointers (`PointerDiffInstruction`), + * the result is computed by computing the difference between the two pointer byte addresses, then + * dividing that byte count by the element size. + */ final int getElementSize() { result = elementSize } } +/** + * An instruction that adds or subtracts an integer offset from a pointer. + */ class PointerOffsetInstruction extends PointerArithmeticInstruction { PointerOffsetInstruction() { getOpcode() instanceof PointerOffsetOpcode } } +/** + * An instruction that adds an integer offset to a pointer. + * + * The result is the byte address computed by adding the value of the right (integer) operand, + * multiplied by the element size, to the value of the left (pointer) operand. The result of pointer + * overflow is undefined. + */ class PointerAddInstruction extends PointerOffsetInstruction { PointerAddInstruction() { getOpcode() instanceof Opcode::PointerAdd } } +/** + * An instruction that subtracts an integer offset from a pointer. + * + * The result is the byte address computed by subtracting the value of the right (integer) operand, + * multiplied by the element size, from the value of the left (pointer) operand. The result of + * pointer underflow is undefined. + */ class PointerSubInstruction extends PointerOffsetInstruction { PointerSubInstruction() { getOpcode() instanceof Opcode::PointerSub } } +/** + * An instruction that computes the difference between two pointers. + * + * Both operands must have the same pointer type. The result must have an integer type whose size is + * the same as that of the pointer operands. The result is computed by subtracting the byte address + * in the right operand from the byte address in the left operand, and dividing by the element size. + * If the difference in byte addresses is not divisible by the element size, the result is + * undefined. + */ class PointerDiffInstruction extends PointerArithmeticInstruction { PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff } } +/** + * An instruction whose result is computed from a single operand. + */ class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } + /** + * Gets the sole operand of this instruction. + */ final UnaryOperand getUnaryOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the sole operand of this instruction. + */ final Instruction getUnary() { result = getUnaryOperand().getDef() } } +/** + * An instruction that converts the value of its operand to a value of a different type. + */ class ConvertInstruction extends UnaryInstruction { ConvertInstruction() { getOpcode() instanceof Opcode::Convert } } +/** + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, returning a null address if the dynamic type of the + * object is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a pointer type, or a C# `is` or + * `as` expression. + */ class CheckedConvertOrNullInstruction extends UnaryInstruction { CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull } } /** - * Represents an instruction that converts between two addresses - * related by inheritance. + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, throwing an exception if the dynamic type of the object + * is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a reference type, or a C# cast + * expression. + */ +class CheckedConvertOrThrowInstruction extends UnaryInstruction { + CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } +} + +/** + * An instruction that returns the address of the complete object that contains the subobject + * pointed to by its operand. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent `dyanmic_cast` in C++, which returns the pointer to + * the most-derived object. + */ +class CompleteObjectAddressInstruction extends UnaryInstruction { + CompleteObjectAddressInstruction() { getOpcode() instanceof Opcode::CompleteObjectAddress } +} + +/** + * An instruction that converts the address of an object to the address of a different subobject of + * the same object, without any type checking at runtime. */ class InheritanceConversionInstruction extends UnaryInstruction { Language::Class baseClass; Language::Class derivedClass; InheritanceConversionInstruction() { - Construction::getInstructionInheritance(this, baseClass, derivedClass) + Raw::getInstructionInheritance(this, baseClass, derivedClass) } final override string getImmediateString() { @@ -778,59 +1285,91 @@ class InheritanceConversionInstruction extends UnaryInstruction { } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a base class. + * An instruction that converts from the address of a derived class to the address of a base class. */ class ConvertToBaseInstruction extends InheritanceConversionInstruction { ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a direct non-virtual base class. + * An instruction that converts from the address of a derived class to the address of a direct + * non-virtual base class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToNonVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToNonVirtualBase } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a virtual base class. + * An instruction that converts from the address of a derived class to the address of a virtual base + * class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToVirtualBase } } /** - * Represents an instruction that converts from the address of a base class - * to the address of a direct non-virtual derived class. + * An instruction that converts from the address of a base class to the address of a direct + * non-virtual derived class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToDerivedInstruction extends InheritanceConversionInstruction { ConvertToDerivedInstruction() { getOpcode() instanceof Opcode::ConvertToDerived } } +/** + * An instruction that computes the bitwise complement of its operand. + * + * The operand must have an integer type, which will also be the result type. + */ class BitComplementInstruction extends UnaryBitwiseInstruction { BitComplementInstruction() { getOpcode() instanceof Opcode::BitComplement } } +/** + * An instruction that computes the logical complement of its operand. + * + * The operand must have a Boolean type, which will also be the result type. + */ class LogicalNotInstruction extends UnaryInstruction { LogicalNotInstruction() { getOpcode() instanceof Opcode::LogicalNot } } +/** + * An instruction that compares two numeric operands. + */ class CompareInstruction extends BinaryInstruction { CompareInstruction() { getOpcode() instanceof CompareOpcode } } +/** + * An instruction that returns a `true` result if its operands are equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left == right`, and `false` if `left != right` or the two operands are + * unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareEQInstruction extends CompareInstruction { CompareEQInstruction() { getOpcode() instanceof Opcode::CompareEQ } } +/** + * An instruction that returns a `true` result if its operands are not equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left != right` or if the two operands are unordered, and `false` if + * `left == right`. Floating-point comparison is performed according to IEEE-754. + */ class CompareNEInstruction extends CompareInstruction { CompareNEInstruction() { getOpcode() instanceof Opcode::CompareNE } } /** - * Represents an instruction that does a relative comparison of two values, such as `<` or `>=`. + * An instruction that does a relative comparison of two values, such as `<` or `>=`. */ class RelationalInstruction extends CompareInstruction { RelationalInstruction() { getOpcode() instanceof RelationalOpcode } @@ -857,6 +1396,13 @@ class RelationalInstruction extends CompareInstruction { predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is less than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left < right`, and `false` if `left >= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLTInstruction extends RelationalInstruction { CompareLTInstruction() { getOpcode() instanceof Opcode::CompareLT } @@ -867,6 +1413,13 @@ class CompareLTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is greater than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left > right`, and `false` if `left <= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGTInstruction extends RelationalInstruction { CompareGTInstruction() { getOpcode() instanceof Opcode::CompareGT } @@ -877,6 +1430,14 @@ class CompareGTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is less than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left <= right`, and `false` if `left > right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLEInstruction extends RelationalInstruction { CompareLEInstruction() { getOpcode() instanceof Opcode::CompareLE } @@ -887,6 +1448,14 @@ class CompareLEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is greater than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left >= right`, and `false` if `left < right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGEInstruction extends RelationalInstruction { CompareGEInstruction() { getOpcode() instanceof Opcode::CompareGE } @@ -897,15 +1466,32 @@ class CompareGEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that branches to one of multiple successor instructions based on the value of an + * integer operand. + * + * This instruction will have zero or more successors whose edge kind is `CaseEdge`, each + * representing the branch that will be taken if the controlling expression is within the range + * specified for that case edge. The range of a case edge must be disjoint from the range of each + * other case edge. + * + * The instruction may optionally have a successor edge whose edge kind is `DefaultEdge`, + * representing the branch that will be taken if the controlling expression is not within the range + * of any case edge. + */ class SwitchInstruction extends Instruction { SwitchInstruction() { getOpcode() instanceof Opcode::Switch } + /** Gets the operand that provides the integer value controlling the switch. */ final ConditionOperand getExpressionOperand() { result = getAnOperand() } + /** Gets the instruction whose result provides the integer value controlling the switch. */ final Instruction getExpression() { result = getExpressionOperand().getDef() } + /** Gets the successor instructions along the case edges of the switch. */ final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } + /** Gets the successor instruction along the default edge of the switch, if any. */ final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } } @@ -936,7 +1522,7 @@ class CallInstruction extends Instruction { * Gets the `Function` that the call targets, if this is statically known. */ final Language::Function getStaticCallTarget() { - result = getCallTarget().(FunctionInstruction).getFunctionSymbol() + result = getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() } /** @@ -981,6 +1567,9 @@ class CallInstruction extends Instruction { class SideEffectInstruction extends Instruction { SideEffectInstruction() { getOpcode() instanceof SideEffectOpcode } + /** + * Gets the instruction whose execution causes this side effect. + */ final Instruction getPrimaryInstruction() { result = Construction::getPrimaryInstructionForSideEffect(this) } @@ -996,9 +1585,10 @@ class CallSideEffectInstruction extends SideEffectInstruction { /** * An instruction representing the side effect of a function call on any memory - * that might be read by that call. This instruction is emitted instead of - * `CallSideEffectInstruction` when it's certain that the call target cannot - * write to escaped memory. + * that might be read by that call. + * + * This instruction is emitted instead of `CallSideEffectInstruction` when it is certain that the + * call target cannot write to escaped memory. */ class CallReadSideEffectInstruction extends SideEffectInstruction { CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect } @@ -1046,7 +1636,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { getOpcode() instanceof Opcode::SizedBufferReadSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes read from the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes read from the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1056,7 +1654,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } + /** + * Get the operand that holds the address of the memory to be written. + */ + final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the memory to be written. + */ + Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } } /** @@ -1087,11 +1693,20 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** * An instruction representing the potential write of an indirect parameter within a function call. + * * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. * written. */ @@ -1103,6 +1718,7 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1111,6 +1727,7 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1118,11 +1735,19 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** - * An instruction representing the initial value of newly allocated memory, e.g. the result of a + * An instruction representing the initial value of newly allocated memory, such as the result of a * call to `malloc`. */ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { @@ -1211,7 +1836,7 @@ class CatchByTypeInstruction extends CatchInstruction { CatchByTypeInstruction() { getOpcode() instanceof Opcode::CatchByType and - exceptionType = Construction::getInstructionExceptionType(this) + exceptionType = Raw::getInstructionExceptionType(this) } final override string getImmediateString() { result = exceptionType.toString() } @@ -1337,29 +1962,43 @@ class ChiInstruction extends Instruction { * Gets the operand that represents the new value written by the memory write. */ final Instruction getPartial() { result = getPartialOperand().getDef() } + + /** + * Gets the bit range `[startBit, endBit)` updated by the partial operand of this `ChiInstruction`, relative to the start address of the total operand. + */ + final predicate getUpdatedInterval(int startBit, int endBit) { + Construction::getIntervalUpdatedByChi(this, startBit, endBit) + } } /** - * An instruction representing unreachable code. Inserted in place of the original target - * instruction of a `ConditionalBranch` or `Switch` instruction where that particular edge is - * infeasible. + * An instruction representing unreachable code. + * + * This instruction is inserted in place of the original target instruction of a `ConditionalBranch` + * or `Switch` instruction where that particular edge is infeasible. */ class UnreachedInstruction extends Instruction { UnreachedInstruction() { getOpcode() instanceof Opcode::Unreached } } /** - * An instruction representing a built-in operation. This is used to represent - * operations such as access to variable argument lists. + * An instruction representing a built-in operation. + * + * This is used to represent a variety of intrinsic operations provided by the compiler + * implementation, such as vector arithmetic. */ class BuiltInOperationInstruction extends Instruction { Language::BuiltInOperation operation; BuiltInOperationInstruction() { getOpcode() instanceof BuiltInOperationOpcode and - operation = Construction::getInstructionBuiltInOperation(this) + operation = Raw::getInstructionBuiltInOperation(this) } + /** + * Gets the language-specific `BuiltInOperation` object that specifies the operation that is + * performed by this instruction. + */ final Language::BuiltInOperation getBuiltInOperation() { result = operation } } @@ -1372,3 +2011,59 @@ class BuiltInInstruction extends BuiltInOperationInstruction { final override string getImmediateString() { result = getBuiltInOperation().toString() } } + +/** + * An instruction that returns a `va_list` to access the arguments passed to the `...` parameter. + * + * The operand specifies the address of the `IREllipsisVariable` used to represent the `...` + * parameter. The result is a `va_list` that initially refers to the first argument that was passed + * to the `...` parameter. + */ +class VarArgsStartInstruction extends UnaryInstruction { + VarArgsStartInstruction() { getOpcode() instanceof Opcode::VarArgsStart } +} + +/** + * An instruction that cleans up a `va_list` after it is no longer in use. + * + * The operand specifies the address of the `va_list` to clean up. This instruction does not return + * a result. + */ +class VarArgsEndInstruction extends UnaryInstruction { + VarArgsEndInstruction() { getOpcode() instanceof Opcode::VarArgsEnd } +} + +/** + * An instruction that returns the address of the argument currently pointed to by a `va_list`. + * + * The operand is the `va_list` that points to the argument. The result is the address of the + * argument. + */ +class VarArgInstruction extends UnaryInstruction { + VarArgInstruction() { getOpcode() instanceof Opcode::VarArg } +} + +/** + * An instruction that modifies a `va_list` to point to the next argument that was passed to the + * `...` parameter. + * + * The operand is the current `va_list`. The result is an updated `va_list` that points to the next + * argument of the `...` parameter. + */ +class NextVarArgInstruction extends UnaryInstruction { + NextVarArgInstruction() { getOpcode() instanceof Opcode::NextVarArg } +} + +/** + * An instruction that allocates a new object on the managed heap. + * + * This instruction is used to represent the allocation of a new object in C# using the `new` + * expression. This instruction does not invoke a constructor for the object. Instead, there will be + * a subsequent `Call` instruction to invoke the appropriate constructor directory, passing the + * result of the `NewObj` as the `this` argument. + * + * The result is the address of the newly allocated object. + */ +class NewObjInstruction extends Instruction { + NewObjInstruction() { getOpcode() instanceof Opcode::NewObj } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll b/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll similarity index 91% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll rename to csharp/ql/src/experimental/ir/implementation/raw/Operand.qll index f82704094c8e..a12e35d471b8 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the input values of IR instructions. + */ + private import internal.IRInternal private import Instruction private import IRBlock @@ -75,13 +79,21 @@ private PhiOperandBase phiOperand( } /** - * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. + * An operand of an `Instruction`. The operand represents a use of the result of one instruction + * (the defining instruction) in another instruction (the use instruction) */ class Operand extends TOperand { + /** Gets a textual representation of this element. */ string toString() { result = "Operand" } + /** + * Gets the location of the source code for this operand. + */ final Language::Location getLocation() { result = getUse().getLocation() } + /** + * Gets the function that contains this operand. + */ final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() } /** @@ -139,6 +151,11 @@ class Operand extends TOperand { */ string getDumpLabel() { result = "" } + /** + * Gets a string that uniquely identifies this operand on its use instruction. + */ + string getDumpId() { result = "" } + /** * Gets a string describing this operand, suitable for display in IR dumps. This consists of the * result ID of the instruction consumed by the operand, plus a label identifying the operand @@ -268,8 +285,13 @@ class NonPhiOperand extends Operand { final override string getDumpLabel() { result = tag.getLabel() } + final override string getDumpId() { result = tag.getId() } + final override int getDumpSortOrder() { result = tag.getSortOrder() } + /** + * Gets the `OperandTag` that specifies how this operand is used by its `Instruction`. + */ final OperandTag getOperandTag() { result = tag } } @@ -292,6 +314,9 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { } } +/** + * A memory operand other than the operand of a `Phi` instruction. + */ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; @@ -311,8 +336,19 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper not Construction::isInCycle(useInstr) and strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 } + + /** + * Holds if the operand totally overlaps with its definition and consumes the + * bit range `[startBitOffset, endBitOffset)` relative to the start address of the definition. + */ + predicate getUsedInterval(int startBitOffset, int endBitOffset) { + Construction::getUsedInterval(this, startBitOffset, endBitOffset) + } } +/** + * A memory operand whose type may be different from the type of the result of its definition. + */ class TypedOperand extends NonPhiMemoryOperand { override TypedOperandTag tag; @@ -416,6 +452,9 @@ class PositionalArgumentOperand extends ArgumentOperand { final int getIndex() { result = tag.getArgIndex() } } +/** + * An operand representing memory read as a side effect of evaluating another instruction. + */ class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; } @@ -445,6 +484,8 @@ class PhiInputOperand extends MemoryOperand, PhiOperandBase { result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":" } + final override string getDumpId() { result = getPredecessorBlock().getDisplayIndex().toString() } + /** * Gets the predecessor block from which this value comes. */ diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/PrintIR.ql b/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.ql similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/PrintIR.ql rename to csharp/ql/src/experimental/ir/implementation/raw/PrintIR.ql diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/PrintIR.qll b/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll similarity index 73% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/PrintIR.qll rename to csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll index d9c0df44e12e..59dadee71545 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/PrintIR.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll @@ -1,3 +1,13 @@ +/** + * Outputs a representation of the IR as a control flow graph. + * + * This file contains the actual implementation of `PrintIR.ql`. For test cases and very small + * databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintIR.qll`, extends + * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to + * dump. + */ + private import internal.IRInternal private import IR private import internal.PrintIRImports as Imports @@ -9,6 +19,7 @@ private newtype TPrintIRConfiguration = MkPrintIRConfiguration() * The query can extend this class to control which functions are printed. */ class PrintIRConfiguration extends TPrintIRConfiguration { + /** Gets a textual representation of this configuration. */ string toString() { result = "PrintIRConfiguration" } /** @@ -39,6 +50,37 @@ private string getAdditionalBlockProperty(IRBlock block, string key) { exists(IRPropertyProvider provider | result = provider.getBlockProperty(block, key)) } +/** + * Gets the properties of an operand from any active property providers. + */ +private string getAdditionalOperandProperty(Operand operand, string key) { + exists(IRPropertyProvider provider | result = provider.getOperandProperty(operand, key)) +} + +/** + * Gets a string listing the properties of the operand and their corresponding values. If the + * operand has no properties, this predicate has no result. + */ +private string getOperandPropertyListString(Operand operand) { + result = + strictconcat(string key, string value | + value = getAdditionalOperandProperty(operand, key) + | + key + ":" + value, ", " + ) +} + +/** + * Gets a string listing the properties of the operand and their corresponding values. The list is + * surrounded by curly braces. If the operand has no properties, this predicate returns an empty + * string. + */ +private string getOperandPropertyString(Operand operand) { + result = "{" + getOperandPropertyListString(operand) + "}" + or + not exists(getOperandPropertyListString(operand)) and result = "" +} + private newtype TPrintableIRNode = TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or @@ -47,7 +89,7 @@ private newtype TPrintableIRNode = /** * A node to be emitted in the IR graph. */ -abstract class PrintableIRNode extends TPrintableIRNode { +abstract private class PrintableIRNode extends TPrintableIRNode { abstract string toString(); /** @@ -98,7 +140,7 @@ abstract class PrintableIRNode extends TPrintableIRNode { /** * An IR graph node representing a `IRFunction` object. */ -class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { +private class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { IRFunction irFunc; PrintableIRFunction() { this = TPrintableIRFunction(irFunc) } @@ -129,7 +171,7 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { /** * An IR graph node representing an `IRBlock` object. */ -class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { +private class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { IRBlock block; PrintableIRBlock() { this = TPrintableIRBlock(block) } @@ -161,7 +203,7 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { /** * An IR graph node representing an `Instruction`. */ -class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { +private class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { Instruction instr; PrintableInstruction() { this = TPrintableInstruction(instr) } @@ -179,7 +221,7 @@ class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { | resultString = instr.getResultString() and operationString = instr.getOperationString() and - operandsString = instr.getOperandsString() and + operandsString = getOperandsString() and columnWidths(block, resultWidth, operationWidth) and result = resultString + getPaddingString(resultWidth - resultString.length()) + " = " + @@ -199,6 +241,22 @@ class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { result = PrintableIRNode.super.getProperty(key) or result = getAdditionalInstructionProperty(instr, key) } + + /** + * Gets the string representation of the operand list. This is the same as + * `Instruction::getOperandsString()`, except that each operand is annotated with any properties + * provided by active `IRPropertyProvider` instances. + */ + private string getOperandsString() { + result = + concat(Operand operand | + operand = instr.getAnOperand() + | + operand.getDumpString() + getOperandPropertyString(operand), ", " + order by + operand.getDumpSortOrder() + ) + } } private predicate columnWidths(IRBlock block, int resultWidth, int operationWidth) { @@ -224,6 +282,9 @@ private string getPaddingString(int n) { n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " " } +/** + * Holds if `node` belongs to the output graph, and its property `key` has the given `value`. + */ query predicate nodes(PrintableIRNode node, string key, string value) { value = node.getProperty(key) } @@ -237,6 +298,10 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) { ) } +/** + * Holds if the output graph contains an edge from `pred` to `succ`, and that edge's property `key` + * has the given `value`. + */ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | predBlock = pred.getBlock() and @@ -256,6 +321,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, ) } +/** + * Holds if `parent` is the parent node of `child` in the output graph. + */ query predicate parents(PrintableIRNode child, PrintableIRNode parent) { parent = child.getParent() } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/ConstantAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/raw/constant/ConstantAnalysis.qll similarity index 97% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/ConstantAnalysis.qll rename to csharp/ql/src/experimental/ir/implementation/raw/constant/ConstantAnalysis.qll index 196949579f72..aac2e679a97b 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/ConstantAnalysis.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/constant/ConstantAnalysis.qll @@ -1,5 +1,5 @@ private import internal.ConstantAnalysisInternal -private import semmle.code.csharp.ir.internal.IntegerPartial +private import experimental.ir.internal.IntegerPartial private import IR language[monotonicAggregates] diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/PrintConstantAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/raw/constant/PrintConstantAnalysis.qll similarity index 84% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/PrintConstantAnalysis.qll rename to csharp/ql/src/experimental/ir/implementation/raw/constant/PrintConstantAnalysis.qll index 1145d5bb2abb..53f9295be4f9 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/PrintConstantAnalysis.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/constant/PrintConstantAnalysis.qll @@ -1,5 +1,5 @@ private import internal.ConstantAnalysisInternal -private import semmle.code.csharp.ir.internal.IntegerConstant +private import experimental.ir.internal.IntegerConstant private import ConstantAnalysis import IR diff --git a/csharp/ql/src/experimental/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll b/csharp/ql/src/experimental/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll new file mode 100644 index 000000000000..6e2340af7eac --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll @@ -0,0 +1 @@ +import experimental.ir.implementation.raw.IR as IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/PrintValueNumbering.qll b/csharp/ql/src/experimental/ir/implementation/raw/gvn/PrintValueNumbering.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/PrintValueNumbering.qll rename to csharp/ql/src/experimental/ir/implementation/raw/gvn/PrintValueNumbering.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll b/csharp/ql/src/experimental/ir/implementation/raw/gvn/ValueNumbering.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll rename to csharp/ql/src/experimental/ir/implementation/raw/gvn/ValueNumbering.qll diff --git a/csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll new file mode 100644 index 000000000000..34bd754692d6 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll @@ -0,0 +1,3 @@ +import experimental.ir.internal.Overlap +import experimental.ir.internal.IRCSharpLanguage as Language +import experimental.ir.implementation.unaliased_ssa.IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll b/csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll rename to csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRBlockImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRBlockImports.qll new file mode 100644 index 000000000000..c80761a68cf8 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRBlockImports.qll @@ -0,0 +1 @@ +import experimental.ir.implementation.EdgeKind as EdgeKind diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll similarity index 84% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll index 47d9b5b973a4..c8c85acdd428 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll @@ -1,9 +1,11 @@ import csharp -import semmle.code.csharp.ir.implementation.raw.IR -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.Overlap -private import semmle.code.csharp.ir.internal.TempVariableTag +import experimental.ir.implementation.raw.IR +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.implementation.internal.IRFunctionBase +private import experimental.ir.implementation.internal.TInstruction +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.Overlap +private import experimental.ir.internal.TempVariableTag private import InstructionTag private import TranslatedCondition private import TranslatedElement @@ -11,30 +13,44 @@ private import TranslatedExpr private import TranslatedStmt private import desugar.Foreach private import TranslatedFunction -private import semmle.code.csharp.ir.Util -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.Util +private import experimental.ir.internal.IRCSharpLanguage as Language TranslatedElement getInstructionTranslatedElement(Instruction instruction) { - instruction = MkInstruction(result, _) + instruction = TRawInstruction(result, _) } -InstructionTag getInstructionTag(Instruction instruction) { instruction = MkInstruction(_, result) } +InstructionTag getInstructionTag(Instruction instruction) { + instruction = TRawInstruction(_, result) +} -import Cached +pragma[noinline] +private predicate instructionOrigin( + Instruction instruction, TranslatedElement element, InstructionTag tag +) { + element = getInstructionTranslatedElement(instruction) and + tag = getInstructionTag(instruction) +} +class TStageInstruction = TRawInstruction; + +/** + * Provides the portion of the parameterized IR interface that is used to construct the initial + * "raw" stage of the IR. The other stages of the IR do not expose these predicates. + */ cached -private module Cached { +module Raw { + class InstructionTag1 = TranslatedElement; + + class InstructionTag2 = InstructionTag; + cached - predicate functionHasIR(Callable callable) { - exists(getTranslatedFunction(callable)) and - callable.fromSource() - } + predicate functionHasIR(Callable callable) { exists(getTranslatedFunction(callable)) } cached - newtype TInstruction = - MkInstruction(TranslatedElement element, InstructionTag tag) { - element.hasInstruction(_, tag, _) - } + predicate hasInstruction(TranslatedElement element, InstructionTag tag) { + element.hasInstruction(_, tag, _) + } cached predicate hasUserVariable(Callable callable, Variable var, CSharpType type) { @@ -66,16 +82,6 @@ private module Cached { none() } - cached - predicate hasModeledMemoryResult(Instruction instruction) { none() } - - cached - predicate hasConflatedMemoryResult(Instruction instruction) { - instruction instanceof AliasedDefinitionInstruction - or - instruction.getOpcode() instanceof Opcode::InitializeNonLocal - } - cached Expr getInstructionConvertedResultExpression(Instruction instruction) { exists(TranslatedExpr translatedExpr | @@ -92,6 +98,98 @@ private module Cached { ) } + cached + IRVariable getInstructionVariable(Instruction instruction) { + exists(TranslatedElement element, InstructionTag tag | + element = getInstructionTranslatedElement(instruction) and + tag = getInstructionTag(instruction) and + ( + result = element.getInstructionVariable(tag) or + result.(IRStringLiteral).getAST() = element.getInstructionStringLiteral(tag) + ) + ) + } + + cached + Field getInstructionField(Instruction instruction) { + exists(TranslatedElement element, InstructionTag tag | + instructionOrigin(instruction, element, tag) and + result = element.getInstructionField(tag) + ) + } + + cached + int getInstructionIndex(Instruction instruction) { none() } + + cached + Callable getInstructionFunction(Instruction instruction) { + result = + getInstructionTranslatedElement(instruction) + .getInstructionFunction(getInstructionTag(instruction)) + } + + cached + string getInstructionConstantValue(Instruction instruction) { + result = + getInstructionTranslatedElement(instruction) + .getInstructionConstantValue(getInstructionTag(instruction)) + } + + cached + CSharpType getInstructionExceptionType(Instruction instruction) { + result = + getInstructionTranslatedElement(instruction) + .getInstructionExceptionType(getInstructionTag(instruction)) + } + + cached + predicate getInstructionInheritance(Instruction instruction, Class baseClass, Class derivedClass) { + getInstructionTranslatedElement(instruction) + .getInstructionInheritance(getInstructionTag(instruction), baseClass, derivedClass) + } + + cached + int getInstructionElementSize(Instruction instruction) { + exists(TranslatedElement element, InstructionTag tag | + instructionOrigin(instruction, element, tag) and + result = element.getInstructionElementSize(tag) + ) + } + + cached + Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instr) { none() } +} + +import Cached + +cached +private module Cached { + cached + Opcode getInstructionOpcode(TRawInstruction instr) { + exists(TranslatedElement element, InstructionTag tag | + instructionOrigin(instr, element, tag) and + element.hasInstruction(result, tag, _) + ) + } + + cached + IRFunctionBase getInstructionEnclosingIRFunction(TRawInstruction instr) { + result.getFunction() = getInstructionTranslatedElement(instr).getFunction() + } + + cached + predicate hasInstruction(TRawInstruction instr) { any() } + + cached + predicate hasModeledMemoryResult(Instruction instruction) { none() } + + cached + predicate hasConflatedMemoryResult(Instruction instruction) { + instruction instanceof AliasedDefinitionInstruction + or + instruction.getOpcode() instanceof Opcode::InitializeNonLocal + } + cached Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) { result = @@ -116,6 +214,20 @@ private module Cached { result = getMemoryOperandDefinition(instr, _, _) } + /** + * Holds if the partial operand of this `ChiInstruction` updates the bit range + * `[startBitOffset, endBitOffset)` of the total operand. + */ + cached + predicate getIntervalUpdatedByChi(ChiInstruction chi, int startBit, int endBit) { none() } + + /** + * Holds if the operand totally overlaps with its definition and consumes the + * bit range `[startBitOffset, endBitOffset)`. + */ + cached + predicate getUsedInterval(Operand operand, int startBit, int endBit) { none() } + /** * Holds if `instr` is part of a cycle in the operand graph that doesn't go * through a phi instruction and therefore should be impossible. @@ -267,37 +379,6 @@ private module Cached { .hasInstruction(_, getInstructionTag(instruction), result) } - cached - Opcode getInstructionOpcode(Instruction instruction) { - getInstructionTranslatedElement(instruction) - .hasInstruction(result, getInstructionTag(instruction), _) - } - - cached - IRFunction getInstructionEnclosingIRFunction(Instruction instruction) { - result.getFunction() = getInstructionTranslatedElement(instruction).getFunction() - } - - cached - IRVariable getInstructionVariable(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - element = getInstructionTranslatedElement(instruction) and - tag = getInstructionTag(instruction) and - ( - result = element.getInstructionVariable(tag) or - result.(IRStringLiteral).getAST() = element.getInstructionStringLiteral(tag) - ) - ) - } - - cached - Field getInstructionField(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and - result = element.getInstructionField(tag) - ) - } - cached ArrayAccess getInstructionArrayAccess(Instruction instruction) { result = @@ -305,52 +386,6 @@ private module Cached { .getInstructionArrayAccess(getInstructionTag(instruction)) } - cached - int getInstructionIndex(Instruction instruction) { none() } - - cached - Callable getInstructionFunction(Instruction instruction) { - result = - getInstructionTranslatedElement(instruction) - .getInstructionFunction(getInstructionTag(instruction)) - } - - cached - string getInstructionConstantValue(Instruction instruction) { - result = - getInstructionTranslatedElement(instruction) - .getInstructionConstantValue(getInstructionTag(instruction)) - } - - cached - CSharpType getInstructionExceptionType(Instruction instruction) { - result = - getInstructionTranslatedElement(instruction) - .getInstructionExceptionType(getInstructionTag(instruction)) - } - - cached - predicate getInstructionInheritance(Instruction instruction, Class baseClass, Class derivedClass) { - getInstructionTranslatedElement(instruction) - .getInstructionInheritance(getInstructionTag(instruction), baseClass, derivedClass) - } - - pragma[noinline] - private predicate instructionOrigin( - Instruction instruction, TranslatedElement element, InstructionTag tag - ) { - element = getInstructionTranslatedElement(instruction) and - tag = getInstructionTag(instruction) - } - - cached - int getInstructionElementSize(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and - result = element.getInstructionElementSize(tag) - ) - } - cached int getInstructionResultSize(Instruction instruction) { exists(TranslatedElement element, InstructionTag tag | @@ -366,9 +401,6 @@ private module Cached { result = element.getPrimaryInstructionForSideEffect(tag) ) } - - cached - Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instr) { none() } } import CachedForDebugging diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRFunctionImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRFunctionImports.qll new file mode 100644 index 000000000000..4e9a7d9f3aec --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRFunctionImports.qll @@ -0,0 +1 @@ +import experimental.ir.implementation.internal.IRFunctionBase as IRFunctionBase diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRImports.qll new file mode 100644 index 000000000000..14dad7400b22 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRImports.qll @@ -0,0 +1,3 @@ +import experimental.ir.implementation.EdgeKind as EdgeKind +import experimental.ir.implementation.IRType as IRType +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRInternal.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRInternal.qll new file mode 100644 index 000000000000..e44184dd76c2 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRInternal.qll @@ -0,0 +1,4 @@ +import experimental.ir.internal.IRCSharpLanguage as Language +import IRConstruction as Construction +import experimental.ir.implementation.IRConfiguration as IRConfiguration +import IRConstruction::Raw as Raw diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRVariableImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRVariableImports.qll new file mode 100644 index 000000000000..bdb4377cbdcc --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRVariableImports.qll @@ -0,0 +1,5 @@ +import experimental.ir.implementation.IRType as IRType +import experimental.ir.implementation.TempVariableTag as TempVariableTag +import experimental.ir.internal.IRUtilities as IRUtilities +import experimental.ir.internal.TempVariableTag as TTempVariableTag +import experimental.ir.implementation.internal.TIRVariable as TIRVariable diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionImports.qll new file mode 100644 index 000000000000..4bcd2e127c12 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionImports.qll @@ -0,0 +1,6 @@ +import experimental.ir.implementation.EdgeKind as EdgeKind +import experimental.ir.implementation.IRType as IRType +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind +import experimental.ir.implementation.Opcode as Opcode +import experimental.ir.implementation.internal.OperandTag as OperandTag +import experimental.ir.internal.Overlap as Overlap diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionTag.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionTag.qll similarity index 99% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionTag.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionTag.qll index c40ce195c1a7..b97981876d4e 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionTag.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionTag.qll @@ -1,5 +1,5 @@ import csharp -import semmle.code.csharp.ir.Util +import experimental.ir.Util private predicate elementIsInitialized(int elementIndex) { exists(ArrayInitWithMod initList | initList.isInitialized(elementIndex)) diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/OperandImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/OperandImports.qll new file mode 100644 index 000000000000..40af4631927a --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/OperandImports.qll @@ -0,0 +1,4 @@ +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind +import experimental.ir.implementation.IRType as IRType +import experimental.ir.internal.Overlap as Overlap +import experimental.ir.implementation.internal.OperandTag as OperandTag diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/PrintIRImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/PrintIRImports.qll new file mode 100644 index 000000000000..9a3e4c03646c --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/PrintIRImports.qll @@ -0,0 +1 @@ +import experimental.ir.IRConfiguration as IRConfiguration diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCall.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCall.qll similarity index 91% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCall.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCall.qll index 81f60fd1f805..a2c6a708c72a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCall.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCall.qll @@ -1,13 +1,13 @@ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag private import InstructionTag private import TranslatedElement private import TranslatedExpr private import TranslatedInitialization -private import semmle.code.csharp.ir.Util -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedCallBase -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.Util +private import experimental.ir.implementation.raw.internal.common.TranslatedCallBase +private import experimental.ir.internal.IRCSharpLanguage as Language /** * The IR translation of a call to a function. The function can be a normal function diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCondition.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCondition.qll similarity index 95% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCondition.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCondition.qll index cc398a86011f..a172800b3779 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCondition.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCondition.qll @@ -1,12 +1,12 @@ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.CSharpType +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType private import InstructionTag private import TranslatedElement private import TranslatedExpr private import common.TranslatedConditionBase -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.IRCSharpLanguage as Language TranslatedCondition getTranslatedCondition(Expr expr) { result.getExpr() = expr } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedDeclaration.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedDeclaration.qll similarity index 89% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedDeclaration.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedDeclaration.qll index 9cd0a0a34fce..86cbdbb4360c 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedDeclaration.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedDeclaration.qll @@ -1,12 +1,12 @@ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.internal.IRUtilities -private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import experimental.ir.implementation.Opcode +private import experimental.ir.internal.IRUtilities +private import experimental.ir.implementation.internal.OperandTag private import InstructionTag private import TranslatedElement private import TranslatedExpr private import TranslatedInitialization -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.IRCSharpLanguage as Language private import common.TranslatedDeclarationBase /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll similarity index 96% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll index 141c04b9927b..0022711f79eb 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll @@ -1,17 +1,17 @@ import csharp -import semmle.code.csharp.ir.implementation.raw.IR -private import semmle.code.csharp.ir.IRConfiguration -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.TempVariableTag +import experimental.ir.implementation.raw.IR +private import experimental.ir.IRConfiguration +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.TempVariableTag private import InstructionTag private import TranslatedCondition private import TranslatedFunction private import TranslatedStmt private import IRConstruction -private import semmle.code.csharp.ir.Util -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.Util +private import experimental.ir.internal.IRCSharpLanguage as Language private import desugar.Foreach private import desugar.Delegate private import desugar.Lock @@ -21,6 +21,16 @@ ArrayType getArrayOfDim(int dim, Type type) { result.getElementType() = type } +IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { + result.getVariable() = var and + result.getEnclosingFunction() = func +} + +IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { + result.getAST() = ast and + result.getTag() = tag +} + private predicate canCreateCompilerGeneratedElement(Element generatedBy, int nth) { generatedBy instanceof ForeachStmt and nth in [0 .. ForeachElements::noGeneratedElements() - 1] or @@ -117,6 +127,7 @@ private predicate ignoreExpr(Expr expr) { private predicate translateFunction(Callable callable) { // not isInvalidFunction(callable) exists(callable.getEntryPoint()) and + callable.fromSource() and exists(IRConfiguration config | config.shouldCreateIRForFunction(callable)) } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll similarity index 99% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll index 44689ba45f91..72c408a3f2ae 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll @@ -1,9 +1,9 @@ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.TempVariableTag -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.IRUtilities +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.TempVariableTag +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.IRUtilities private import InstructionTag private import TranslatedCondition private import TranslatedDeclaration @@ -16,8 +16,8 @@ private import common.TranslatedExprBase private import desugar.Delegate private import desugar.internal.TranslatedCompilerGeneratedCall import TranslatedCall -private import semmle.code.csharp.ir.Util -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.Util +private import experimental.ir.internal.IRCSharpLanguage as Language /** * Gets the TranslatedExpr for the specified expression. If `expr` is a load, diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedFunction.qll similarity index 96% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedFunction.qll index 81baffb4613c..65488a1b95d7 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedFunction.qll @@ -1,16 +1,16 @@ import csharp -import semmle.code.csharp.ir.implementation.raw.IR -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.IRUtilities -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.TempVariableTag +import experimental.ir.implementation.raw.IR +private import experimental.ir.implementation.Opcode +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.IRUtilities +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.TempVariableTag private import InstructionTag private import TranslatedElement private import TranslatedExpr private import TranslatedInitialization private import TranslatedStmt -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.IRCSharpLanguage as Language /** * Gets the `TranslatedFunction` that represents function `callable`. diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedInitialization.qll similarity index 98% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedInitialization.qll index c8576c42369a..cbe0e7c1d2a7 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedInitialization.qll @@ -4,14 +4,14 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.CSharpType +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType private import InstructionTag private import TranslatedElement private import TranslatedExpr private import TranslatedFunction -private import semmle.code.csharp.ir.Util +private import experimental.ir.Util private import IRInternal private import desugar.Delegate diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedStmt.qll similarity index 99% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedStmt.qll index 680d01cdcfc7..81de9a6b7c9b 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedStmt.qll @@ -1,7 +1,7 @@ import csharp -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.TempVariableTag -private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.TempVariableTag +private import experimental.ir.implementation.internal.OperandTag private import InstructionTag private import TranslatedCondition private import TranslatedDeclaration @@ -11,7 +11,7 @@ private import TranslatedFunction private import TranslatedInitialization private import common.TranslatedConditionBase private import IRInternal -private import semmle.code.csharp.ir.internal.IRUtilities +private import experimental.ir.internal.IRUtilities private import desugar.Foreach private import desugar.Lock diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedCallBase.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedCallBase.qll similarity index 90% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedCallBase.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedCallBase.qll index 2b9e039a22da..a870ed026483 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedCallBase.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedCallBase.qll @@ -4,14 +4,14 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr -private import semmle.code.csharp.ir.Util -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedExpr +private import experimental.ir.Util +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.IRCSharpLanguage as Language private import TranslatedExprBase abstract class TranslatedCallBase extends TranslatedElement { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedConditionBase.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedConditionBase.qll similarity index 80% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedConditionBase.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedConditionBase.qll index 8d4c5202d34a..6f8e2df02eec 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedConditionBase.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedConditionBase.qll @@ -3,14 +3,14 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedCondition -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedExpr +private import experimental.ir.implementation.raw.internal.TranslatedCondition +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.IRCSharpLanguage as Language /** * Represents the context of the condition, ie. provides diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll similarity index 81% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll index 549b554ee946..9fd47de90606 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll @@ -4,15 +4,15 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.internal.IRUtilities -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedInitialization -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.Opcode +private import experimental.ir.internal.IRUtilities +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedExpr +private import experimental.ir.implementation.raw.internal.TranslatedInitialization +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class LocalVariableDeclarationBase extends TranslatedElement { override TranslatedElement getChild(int id) { id = 0 and result = getInitialization() } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedExprBase.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedExprBase.qll similarity index 68% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedExprBase.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedExprBase.qll index d0046d0862ad..ec6a8c0ab00a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedExprBase.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedExprBase.qll @@ -3,8 +3,8 @@ * (both AST generated and compiler generated). */ -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class TranslatedExprBase extends TranslatedElement { /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Common.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Common.qll similarity index 90% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Common.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Common.qll index 492fd46e42b8..267cf903b00c 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Common.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Common.qll @@ -6,22 +6,22 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.TempVariableTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedFunction -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.TempVariableTag +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedFunction +private import experimental.ir.implementation.raw.internal.InstructionTag private import internal.TranslatedCompilerGeneratedStmt private import internal.TranslatedCompilerGeneratedExpr private import internal.TranslatedCompilerGeneratedCondition private import internal.TranslatedCompilerGeneratedCall private import internal.TranslatedCompilerGeneratedElement private import internal.TranslatedCompilerGeneratedDeclaration -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedConditionBase -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedExprBase -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.raw.internal.common.TranslatedConditionBase +private import experimental.ir.implementation.raw.internal.common.TranslatedExprBase +private import experimental.ir.internal.IRCSharpLanguage as Language /** * The general form of a compiler generated try stmt. diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Delegate.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Delegate.qll similarity index 81% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Delegate.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Delegate.qll index 99938ec14786..939f14ba8fec 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Delegate.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Delegate.qll @@ -9,18 +9,18 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.TempVariableTag -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedStmt -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedCondition -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.TempVariableTag +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.raw.internal.TranslatedExpr +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedStmt +private import experimental.ir.implementation.raw.internal.TranslatedCondition +private import experimental.ir.internal.IRCSharpLanguage as Language private import Common private import internal.TranslatedCompilerGeneratedCall -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedExprBase +private import experimental.ir.implementation.raw.internal.common.TranslatedExprBase /** * Module that exposes the functions needed for the translation of the delegate creation and call expressions. diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Foreach.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Foreach.qll similarity index 94% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Foreach.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Foreach.qll index 3d01b56e49eb..9dee82212350 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Foreach.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Foreach.qll @@ -5,13 +5,13 @@ * Also we only deal with foreach stmts where there is only * one declaration (see below). * For example the code: - * ``` + * ```csharp * foreach(var item in some_enumerable) { * // body * } * ``` * gets desugared to: - * ``` + * ```csharp * Enumerator e = some_enumerable.GetEnumerator(); * try * { @@ -34,17 +34,17 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.TempVariableTag -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedStmt -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedConditionBase -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedExprBase -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.TempVariableTag +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.raw.internal.TranslatedExpr +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedStmt +private import experimental.ir.implementation.raw.internal.common.TranslatedConditionBase +private import experimental.ir.implementation.raw.internal.common.TranslatedExprBase +private import experimental.ir.internal.IRCSharpLanguage as Language private import Common private import internal.TranslatedCompilerGeneratedStmt private import internal.TranslatedCompilerGeneratedCall diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Lock.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Lock.qll similarity index 93% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Lock.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Lock.qll index 7a0ec9d5cbca..c83957d9b944 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Lock.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Lock.qll @@ -1,11 +1,11 @@ /** * File that provides the desugaring of a `lock` stmt. * The statement: - * ``` + * ```csharp * lock (anExpr) ... * ``` * gets desugared to: - * ``` + * ```csharp * SomeRefType lockedVar = anExpr; * bool __lockWasTaken = false; * try { @@ -19,17 +19,17 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.TempVariableTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedStmt -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedExprBase -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedConditionBase -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.TempVariableTag +private import experimental.ir.implementation.raw.internal.TranslatedExpr +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedStmt +private import experimental.ir.implementation.raw.internal.common.TranslatedExprBase +private import experimental.ir.implementation.raw.internal.common.TranslatedConditionBase +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.internal.IRCSharpLanguage as Language private import Common private import internal.TranslatedCompilerGeneratedStmt private import internal.TranslatedCompilerGeneratedCall diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Using.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Using.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Using.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Using.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll similarity index 55% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll index a02ecd26f05b..28dfd2b4cc3c 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll @@ -3,11 +3,11 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedFunction -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedCallBase +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedFunction +private import experimental.ir.implementation.raw.internal.common.TranslatedCallBase private import TranslatedCompilerGeneratedElement -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class TranslatedCompilerGeneratedCall extends TranslatedCallBase, TranslatedCompilerGeneratedElement { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll similarity index 63% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll index 635db7670787..df0bf1b24c63 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll @@ -3,10 +3,10 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedConditionBase +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.common.TranslatedConditionBase private import TranslatedCompilerGeneratedElement -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class TranslatedCompilerGeneratedValueCondition extends TranslatedCompilerGeneratedElement, ValueConditionBase { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll similarity index 81% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll index b13702ac1680..273c99365885 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll @@ -5,15 +5,15 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedFunction -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedDeclarationBase +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedFunction +private import experimental.ir.implementation.raw.internal.common.TranslatedDeclarationBase private import TranslatedCompilerGeneratedElement -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class TranslatedCompilerGeneratedDeclaration extends LocalVariableDeclarationBase, TranslatedCompilerGeneratedElement { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll similarity index 81% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll index 299b2547c195..1eb7520eda4e 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll @@ -3,8 +3,8 @@ * which represents the element that generated the compiler generated element. */ -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class TranslatedCompilerGeneratedElement extends TranslatedElement, TTranslatedCompilerGeneratedElement { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll similarity index 65% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll index 1c0ad500fc65..b7988c3fde85 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll @@ -5,9 +5,9 @@ import csharp private import TranslatedCompilerGeneratedElement -private import semmle.code.csharp.ir.implementation.raw.Instruction -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedExprBase -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.raw.Instruction +private import experimental.ir.implementation.raw.internal.common.TranslatedExprBase +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class TranslatedCompilerGeneratedExpr extends TranslatedCompilerGeneratedElement, TranslatedExprBase { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll similarity index 84% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll index 68ec2f102fe1..70955e02c9b2 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll @@ -5,7 +5,7 @@ import csharp private import TranslatedCompilerGeneratedElement -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class TranslatedCompilerGeneratedStmt extends TranslatedCompilerGeneratedElement { final override string toString() { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/Dominance.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/Dominance.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/Dominance.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/Dominance.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/DominanceInternal.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/DominanceInternal.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/DominanceInternal.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/DominanceInternal.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/PrintDominance.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/PrintDominance.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/PrintDominance.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/PrintDominance.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/PrintReachableBlock.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/PrintReachableBlock.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/PrintReachableBlock.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/PrintReachableBlock.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/ReachableBlock.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/ReachableBlock.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/ReachableBlock.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/ReachableBlock.qll diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll new file mode 100644 index 000000000000..93131e2abb5b --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll @@ -0,0 +1,2 @@ +import experimental.ir.implementation.raw.IR as IR +import experimental.ir.implementation.raw.constant.ConstantAnalysis as ConstantAnalysis diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll new file mode 100644 index 000000000000..c96783fe6e81 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll @@ -0,0 +1,80 @@ +/** + * Provides classes that describe the Intermediate Representation (IR) of the program. + * + * The IR is a representation of the semantics of the program, with very little dependence on the + * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, + * and `++i` all have the same semantic effect, but appear in the AST as three different types of + * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental + * operations similar to: + * + * ``` + * r1(int*) = VariableAddress[i] // Compute the address of variable `i` + * r2(int) = Load &:r1, m0 // Load the value of `i` + * r3(int) = Constant[1] // An integer constant with the value `1` + * r4(int) = Add r2, r3 // Add `1` to the value of `i` + * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` + * ``` + * + * This allows IR-based analysis to focus on the fundamental operations, rather than having to be + * concerned with the various ways of expressing those operations in source code. + * + * The key classes in the IR are: + * + * - `IRFunction` - Contains the IR for an entire function definition, including all of that + * function's `Instruction`s, `IRBlock`s, and `IRVariables`. + * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be + * performed, the operands that produce the inputs to that operation, and the type of the result + * of the operation. Control flows from an `Instruction` to one of a set of successor + * `Instruction`s. + * - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly + * represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has + * a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction` + * that produces its value (its "definition"). + * - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is + * created for each variable directly accessed by the function. In addition, `IRVariable`s are + * created to represent certain temporary storage locations that do not have explicitly declared + * variables in the source code, such as the return value of the function. + * - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a + * sequence of instructions such that control flow can only enter the block at the first + * instruction, and can only leave the block from the last instruction. + * - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType` + * is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all + * be represented as the `IRType` `uint4`, a four-byte unsigned integer. + */ + +import IRFunction +import Instruction +import IRBlock +import IRVariable +import Operand +private import internal.IRImports as Imports +import Imports::EdgeKind +import Imports::IRType +import Imports::MemoryAccessKind + +private newtype TIRPropertyProvider = MkIRPropertyProvider() + +/** + * A class that provides additional properties to be dumped for IR instructions and blocks when using + * the PrintIR module. Libraries that compute additional facts about IR elements can extend the + * single instance of this class to specify the additional properties computed by the library. + */ +class IRPropertyProvider extends TIRPropertyProvider { + /** Gets a textual representation of this element. */ + string toString() { result = "IRPropertyProvider" } + + /** + * Gets the value of the property named `key` for the specified instruction. + */ + string getInstructionProperty(Instruction instruction, string key) { none() } + + /** + * Gets the value of the property named `key` for the specified block. + */ + string getBlockProperty(IRBlock block, string key) { none() } + + /** + * Gets the value of the property named `key` for the specified operand. + */ + string getOperandProperty(Operand operand, string key) { none() } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRBlock.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll similarity index 75% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRBlock.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll index 94ef73b27692..d827ed3cf82d 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll @@ -1,3 +1,7 @@ +/** + * Provides classes describing basic blocks in the IR of a function. + */ + private import internal.IRInternal import Instruction private import internal.IRBlockImports as Imports @@ -16,15 +20,27 @@ private import Cached * Most consumers should use the class `IRBlock`. */ class IRBlockBase extends TIRBlock { + /** Gets a textual representation of this block. */ final string toString() { result = getFirstInstruction(this).toString() } + /** Gets the source location of the first non-`Phi` instruction in this block. */ final Language::Location getLocation() { result = getFirstInstruction().getLocation() } + /** + * INTERNAL: Do not use. + * + * Gets a string that uniquely identifies this block within its enclosing function. + * + * This predicate is used by debugging and printing code only. + */ final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() } /** - * Gets the zero-based index of the block within its function. This is used - * by debugging and printing code only. + * INTERNAL: Do not use. + * + * Gets the zero-based index of the block within its function. + * + * This predicate is used by debugging and printing code only. */ int getDisplayIndex() { exists(IRConfiguration::IRConfiguration config | @@ -42,27 +58,51 @@ class IRBlockBase extends TIRBlock { ) } + /** + * Gets the `index`th non-`Phi` instruction in this block. + */ final Instruction getInstruction(int index) { result = getInstruction(this, index) } + /** + * Get the `Phi` instructions that appear at the start of this block. + */ final PhiInstruction getAPhiInstruction() { Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() } + /** + * Gets an instruction in this block. This includes `Phi` instructions. + */ final Instruction getAnInstruction() { result = getInstruction(_) or result = getAPhiInstruction() } + /** + * Gets the first non-`Phi` instruction in this block. + */ final Instruction getFirstInstruction() { result = getFirstInstruction(this) } + /** + * Gets the last instruction in this block. + */ final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) } + /** + * Gets the number of non-`Phi` instructions in this block. + */ final int getInstructionCount() { result = getInstructionCount(this) } + /** + * Gets the `IRFunction` that contains this block. + */ final IRFunction getEnclosingIRFunction() { result = getFirstInstruction(this).getEnclosingIRFunction() } + /** + * Gets the `Function` that contains this block. + */ final Language::Function getEnclosingFunction() { result = getFirstInstruction(this).getEnclosingFunction() } @@ -74,20 +114,57 @@ class IRBlockBase extends TIRBlock { * instruction of another block. */ class IRBlock extends IRBlockBase { + /** + * Gets a block to which control flows directly from this block. + */ final IRBlock getASuccessor() { blockSuccessor(this, result) } + /** + * Gets a block from which control flows directly to this block. + */ final IRBlock getAPredecessor() { blockSuccessor(result, this) } + /** + * Gets the block to which control flows directly from this block along an edge of kind `kind`. + */ final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } + /** + * Gets the block to which control flows directly from this block along a back edge of kind + * `kind`. + */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } + /** + * Holds if this block immediately dominates `block`. + * + * Block `A` immediate dominates block `B` if block `A` strictly dominates block `B` and block `B` + * is a direct successor of block `A`. + */ final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) } + /** + * Holds if this block strictly dominates `block`. + * + * Block `A` strictly dominates block `B` if block `A` dominates block `B` and blocks `A` and `B` + * are not the same block. + */ final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) } + /** + * Holds if this block dominates `block`. + * + * Block `A` dominates block `B` if any control flow path from the entry block of the function to + * block `B` must pass through block `A`. A block always dominates itself. + */ final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } + /** + * Gets a block on the dominance frontier of this block. + * + * The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not + * dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`. + */ pragma[noinline] final IRBlock dominanceFrontier() { dominates(result.getAPredecessor()) and @@ -95,7 +172,7 @@ class IRBlock extends IRBlockBase { } /** - * Holds if this block is reachable from the entry point of its function + * Holds if this block is reachable from the entry block of its function. */ final predicate isReachableFromFunctionEntry() { this = getEnclosingIRFunction().getEntryBlock() or @@ -210,4 +287,4 @@ private module Cached { idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block) } -Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } +private Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.ql b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.ql similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.ql rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.ql diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.qll new file mode 100644 index 000000000000..6a87b9b4b5fd --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.qll @@ -0,0 +1,497 @@ +private import IR +import InstructionConsistency // module is below +import IRTypeConsistency // module is in IRType.qll + +module InstructionConsistency { + private import internal.InstructionImports as Imports + private import Imports::OperandTag + private import Imports::Overlap + private import internal.IRInternal + + private newtype TOptionalIRFunction = + TPresentIRFunction(IRFunction irFunc) or + TMissingIRFunction() + + /** + * An `IRFunction` that might not exist. This is used so that we can produce consistency failures + * for IR that also incorrectly lacks a `getEnclosingIRFunction()`. + */ + abstract private class OptionalIRFunction extends TOptionalIRFunction { + abstract string toString(); + + abstract Language::Location getLocation(); + } + + private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction { + private IRFunction irFunc; + + PresentIRFunction() { this = TPresentIRFunction(irFunc) } + + override string toString() { + result = concat(Language::getIdentityString(irFunc.getFunction()), "; ") + } + + override Language::Location getLocation() { + // To avoid an overwhelming number of results when the extractor merges functions with the + // same name, just pick a single location. + result = + rank[1](Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString()) + } + } + + private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction { + override string toString() { result = "" } + + override Language::Location getLocation() { result instanceof Language::UnknownDefaultLocation } + } + + private OptionalIRFunction getInstructionIRFunction(Instruction instr) { + result = TPresentIRFunction(instr.getEnclosingIRFunction()) + or + not exists(instr.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getInstructionIRFunction(Instruction instr, string irFuncText) { + result = getInstructionIRFunction(instr) and + irFuncText = result.toString() + } + + private OptionalIRFunction getOperandIRFunction(Operand operand) { + result = TPresentIRFunction(operand.getEnclosingIRFunction()) + or + not exists(operand.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getOperandIRFunction(Operand operand, string irFuncText) { + result = getOperandIRFunction(operand) and + irFuncText = result.toString() + } + + private OptionalIRFunction getBlockIRFunction(IRBlock block) { + result = TPresentIRFunction(block.getEnclosingIRFunction()) + or + not exists(block.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + /** + * Holds if instruction `instr` is missing an expected operand with tag `tag`. + */ + query predicate missingOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(OperandTag tag | + instr.getOpcode().hasOperand(tag) and + not exists(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + message = + "Instruction '" + instr.getOpcode().toString() + + "' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if instruction `instr` has an unexpected operand with tag `tag`. + */ + query predicate unexpectedOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(OperandTag tag | + exists(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + not instr.getOpcode().hasOperand(tag) and + not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and + not ( + instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag + ) and + not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag) and + message = + "Instruction '" + instr.toString() + "' has unexpected operand '" + tag.toString() + + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if instruction `instr` has multiple operands with tag `tag`. + */ + query predicate duplicateOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(OperandTag tag, int operandCount | + operandCount = + strictcount(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + operandCount > 1 and + message = + "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + + " in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if `Phi` instruction `instr` is missing an operand corresponding to + * the predecessor block `pred`. + */ + query predicate missingPhiOperand( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRBlock pred | + pred = instr.getBlock().getAPredecessor() and + not exists(PhiInputOperand operand | + operand = instr.getAnOperand() and + operand.getPredecessorBlock() = pred + ) and + message = + "Instruction '" + instr.toString() + "' is missing an operand for predecessor block '" + + pred.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + query predicate missingOperandType( + Operand operand, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Instruction use | + not exists(operand.getType()) and + use = operand.getUse() and + message = + "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() + + "' is missing a type in function '$@'." and + irFunc = getOperandIRFunction(operand, irFuncText) + ) + } + + query predicate duplicateChiOperand( + ChiInstruction chi, string message, OptionalIRFunction irFunc, string irFuncText + ) { + chi.getTotal() = chi.getPartial() and + message = + "Chi instruction for " + chi.getPartial().toString() + + " has duplicate operands in function '$@'." and + irFunc = getInstructionIRFunction(chi, irFuncText) + } + + query predicate sideEffectWithoutPrimary( + SideEffectInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + not exists(instr.getPrimaryInstruction()) and + message = + "Side effect instruction '" + instr + "' is missing a primary instruction in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + /** + * Holds if an instruction, other than `ExitFunction`, has no successors. + */ + query predicate instructionWithoutSuccessor( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + not exists(instr.getASuccessor()) and + not instr instanceof ExitFunctionInstruction and + // Phi instructions aren't linked into the instruction-level flow graph. + not instr instanceof PhiInstruction and + not instr instanceof UnreachedInstruction and + message = "Instruction '" + instr.toString() + "' has no successors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + /** + * Holds if there are multiple edges of the same kind from `source`. + */ + query predicate ambiguousSuccessors( + Instruction source, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(EdgeKind kind, int n | + n = strictcount(Instruction t | source.getSuccessor(kind) = t) and + n > 1 and + message = + "Instruction '" + source.toString() + "' has " + n.toString() + " successors of kind '" + + kind.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(source, irFuncText) + ) + } + + /** + * Holds if `instr` is part of a loop even though the AST of `instr`'s enclosing function + * contains no element that can cause loops. + */ + query predicate unexplainedLoop( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Language::Function f | + exists(IRBlock block | + instr.getBlock() = block and + block.getEnclosingFunction() = f and + block.getASuccessor+() = block + ) and + not Language::hasPotentialLoop(f) and + message = + "Instruction '" + instr.toString() + "' is part of an unexplained loop in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if a `Phi` instruction is present in a block with fewer than two + * predecessors. + */ + query predicate unnecessaryPhiInstruction( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int n | + n = count(instr.getBlock().getAPredecessor()) and + n < 2 and + message = + "Instruction '" + instr.toString() + "' is in a block with only " + n.toString() + + " predecessors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if a memory operand is connected to a definition with an unmodeled result. + */ + query predicate memoryOperandDefinitionIsUnmodeled( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(MemoryOperand operand, Instruction def | + operand = instr.getAnOperand() and + def = operand.getAnyDef() and + not def.isResultModeled() and + message = + "Memory operand definition on instruction '" + instr.toString() + + "' has unmodeled result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + /** + * Holds if operand `operand` consumes a value that was defined in + * a different function. + */ + query predicate operandAcrossFunctions( + Operand operand, string message, OptionalIRFunction useIRFunc, string useIRFuncText, + OptionalIRFunction defIRFunc, string defIRFuncText + ) { + exists(Instruction useInstr, Instruction defInstr | + operand.getUse() = useInstr and + operand.getAnyDef() = defInstr and + useIRFunc = getInstructionIRFunction(useInstr, useIRFuncText) and + defIRFunc = getInstructionIRFunction(defInstr, defIRFuncText) and + useIRFunc != defIRFunc and + message = + "Operand '" + operand.toString() + "' is used on instruction '" + useInstr.toString() + + "' in function '$@', but is defined on instruction '" + defInstr.toString() + + "' in function '$@'." + ) + } + + /** + * Holds if instruction `instr` is not in exactly one block. + */ + query predicate instructionWithoutUniqueBlock( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int blockCount | + blockCount = count(instr.getBlock()) and + blockCount != 1 and + message = + "Instruction '" + instr.toString() + "' is a member of " + blockCount.toString() + + " blocks in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } + + private predicate forwardEdge(IRBlock b1, IRBlock b2) { + b1.getASuccessor() = b2 and + not b1.getBackEdgeSuccessor(_) = b2 + } + + /** + * Holds if `f` contains a loop in which no edge is a back edge. + * + * This check ensures we don't have too _few_ back edges. + */ + query predicate containsLoopOfForwardEdges(IRFunction f, string message) { + exists(IRBlock block | + forwardEdge+(block, block) and + block.getEnclosingIRFunction() = f and + message = "Function contains a loop consisting of only forward edges." + ) + } + + /** + * Holds if `block` is reachable from its function entry point but would not + * be reachable by traversing only forward edges. This check is skipped for + * functions containing `goto` statements as the property does not generally + * hold there. + * + * This check ensures we don't have too _many_ back edges. + */ + query predicate lostReachability( + IRBlock block, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRFunction f, IRBlock entry | + entry = f.getEntryBlock() and + entry.getASuccessor+() = block and + not forwardEdge+(entry, block) and + not Language::hasGoto(f.getFunction()) and + message = + "Block '" + block.toString() + + "' is not reachable by traversing only forward edges in function '$@'." and + irFunc = TPresentIRFunction(f) and + irFuncText = irFunc.toString() + ) + } + + /** + * Holds if the number of back edges differs between the `Instruction` graph + * and the `IRBlock` graph. + */ + query predicate backEdgeCountMismatch(OptionalIRFunction irFunc, string message) { + exists(int fromInstr, int fromBlock | + fromInstr = + count(Instruction i1, Instruction i2 | + getInstructionIRFunction(i1) = irFunc and i1.getBackEdgeSuccessor(_) = i2 + ) and + fromBlock = + count(IRBlock b1, IRBlock b2 | + getBlockIRFunction(b1) = irFunc and b1.getBackEdgeSuccessor(_) = b2 + ) and + fromInstr != fromBlock and + message = + "The instruction graph for function '" + irFunc.toString() + "' contains " + + fromInstr.toString() + " back edges, but the block graph contains " + fromBlock.toString() + + " back edges." + ) + } + + /** + * Gets the point in the function at which the specified operand is evaluated. For most operands, + * this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point + * of evaluation is at the end of the corresponding predecessor block. + */ + private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) { + block = operand.(PhiInputOperand).getPredecessorBlock() and + index = block.getInstructionCount() + or + exists(Instruction use | + use = operand.(NonPhiOperand).getUse() and + block.getInstruction(index) = use + ) + } + + /** + * Holds if `useOperand` has a definition that does not dominate the use. + */ + query predicate useNotDominatedByDefinition( + Operand useOperand, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | + pointOfEvaluation(useOperand, useBlock, useIndex) and + defInstr = useOperand.getAnyDef() and + ( + defInstr instanceof PhiInstruction and + defBlock = defInstr.getBlock() and + defIndex = -1 + or + defBlock.getInstruction(defIndex) = defInstr + ) and + not ( + defBlock.strictlyDominates(useBlock) + or + defBlock = useBlock and + defIndex < useIndex + ) and + message = + "Operand '" + useOperand.toString() + + "' is not dominated by its definition in function '$@'." and + irFunc = getOperandIRFunction(useOperand, irFuncText) + ) + } + + query predicate switchInstructionWithoutDefaultEdge( + SwitchInstruction switchInstr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + not exists(switchInstr.getDefaultSuccessor()) and + message = + "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and + irFunc = getInstructionIRFunction(switchInstr, irFuncText) + } + + /** + * Holds if `instr` is on the chain of chi/phi instructions for all aliased + * memory. + */ + private predicate isOnAliasedDefinitionChain(Instruction instr) { + instr instanceof AliasedDefinitionInstruction + or + isOnAliasedDefinitionChain(instr.(ChiInstruction).getTotal()) + or + isOnAliasedDefinitionChain(instr.(PhiInstruction).getAnInputOperand().getAnyDef()) + } + + private predicate shouldBeConflated(Instruction instr) { + isOnAliasedDefinitionChain(instr) + or + instr.getOpcode() instanceof Opcode::InitializeNonLocal + } + + query predicate notMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + shouldBeConflated(instr) and + not instr.isResultConflated() and + message = + "Instruction '" + instr.toString() + + "' should be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + query predicate wronglyMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + instr.isResultConflated() and + not shouldBeConflated(instr) and + message = + "Instruction '" + instr.toString() + + "' should not be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + } + + query predicate invalidOverlap( + MemoryOperand useOperand, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Overlap overlap | + overlap = useOperand.getDefinitionOverlap() and + overlap instanceof MayPartiallyOverlap and + message = + "MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" + + overlap.toString() + "'." and + irFunc = getOperandIRFunction(useOperand, irFuncText) + ) + } + + query predicate nonUniqueEnclosingIRFunction( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int irFuncCount | + irFuncCount = count(instr.getEnclosingIRFunction()) and + irFuncCount != 1 and + message = + "Instruction '" + instr.toString() + "' has " + irFuncCount.toString() + + " results for `getEnclosingIRFunction()` in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) + } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRFunction.qll similarity index 70% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRFunction.qll index 9aea3e00d666..5968e58f90bf 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRFunction.qll @@ -1,29 +1,17 @@ +/** + * Provides the class `IRFunction`, which represents the Intermediate Representation for the + * definition of a function. + */ + private import internal.IRInternal +private import internal.IRFunctionImports as Imports +import Imports::IRFunctionBase import Instruction -private newtype TIRFunction = - MkIRFunction(Language::Function func) { Construction::functionHasIR(func) } - /** - * Represents the IR for a function. + * The IR for a function. */ -class IRFunction extends TIRFunction { - Language::Function func; - - IRFunction() { this = MkIRFunction(func) } - - final string toString() { result = "IR: " + func.toString() } - - /** - * Gets the function whose IR is represented. - */ - final Language::Function getFunction() { result = func } - - /** - * Gets the location of the function. - */ - final Language::Location getLocation() { result = func.getLocation() } - +class IRFunction extends IRFunctionBase { /** * Gets the entry point for this function. */ diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll similarity index 78% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll index 9f2a0d4ea281..146fc2707383 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent variables accessed by the IR. + */ + private import internal.IRInternal import IRFunction private import internal.IRVariableImports as Imports @@ -7,15 +11,11 @@ private import Imports::TTempVariableTag private import Imports::TIRVariable private import Imports::IRType -IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { - result.getVariable() = var and - result.getEnclosingFunction() = func -} - /** - * A variable referenced by the IR for a function. The variable may be a user-declared variable - * (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation - * (`IRTempVariable`). + * A variable referenced by the IR for a function. + * + * The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated + * by the AST-to-IR translation (`IRTempVariable`). */ class IRVariable extends TIRVariable { Language::Function func; @@ -27,6 +27,7 @@ class IRVariable extends TIRVariable { this = TIRDynamicInitializationFlag(func, _, _) } + /** Gets a textual representation of this element. */ string toString() { none() } /** @@ -162,20 +163,30 @@ class IRGeneratedVariable extends IRVariable { override string getUniqueId() { none() } + /** + * INTERNAL: Do not use. + * + * Gets a string containing the source code location of the AST that generated this variable. + * + * This is used by debugging and printing code only. + */ final string getLocationString() { result = ast.getLocation().getStartLine().toString() + ":" + ast.getLocation().getStartColumn().toString() } + /** + * INTERNAL: Do not use. + * + * Gets the string that is combined with the location of the variable to generate the string + * representation of this variable. + * + * This is used by debugging and printing code only. + */ string getBaseString() { none() } } -IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { - result.getAST() = ast and - result.getTag() = tag -} - /** * A temporary variable introduced by IR construction. The most common examples are the variable * generated to hold the return value of a function, or the variable generated to hold the result of @@ -190,6 +201,10 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa result = "Temp: " + Construction::getTempVariableUniqueId(this) } + /** + * Gets the "tag" object that differentiates this temporary variable from other temporary + * variables generated for the same AST. + */ final TempVariableTag getTag() { result = tag } override string getBaseString() { result = "#temp" } @@ -217,19 +232,23 @@ class IRThrowVariable extends IRTempVariable { * A temporary variable generated to hold the contents of all arguments passed to the `...` of a * function that accepts a variable number of arguments. */ -class IREllipsisVariable extends IRTempVariable { +class IREllipsisVariable extends IRTempVariable, IRParameter { IREllipsisVariable() { tag = EllipsisTempVar() } final override string toString() { result = "#ellipsis" } + + final override int getIndex() { result = func.getNumberOfParameters() } } /** * A temporary variable generated to hold the `this` pointer. */ -class IRThisVariable extends IRTempVariable { +class IRThisVariable extends IRTempVariable, IRParameter { IRThisVariable() { tag = ThisTempVar() } final override string toString() { result = "#this" } + + final override int getIndex() { result = -1 } } /** @@ -249,6 +268,9 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { final override string getBaseString() { result = "#string" } + /** + * Gets the AST of the string literal represented by this `IRStringLiteral`. + */ final Language::StringLiteral getLiteral() { result = literal } } @@ -266,6 +288,9 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string toString() { result = var.toString() + "#init" } + /** + * Gets variable whose initialization is guarded by this flag. + */ final Language::Variable getVariable() { result = var } final override string getUniqueId() { @@ -274,3 +299,29 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string getBaseString() { result = "#init:" + var.toString() + ":" } } + +/** + * An IR variable which acts like a function parameter, including positional parameters and the + * temporary variables generated for `this` and ellipsis parameters. + */ +class IRParameter extends IRAutomaticVariable { + IRParameter() { + this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter + or + this = TIRTempVariable(_, _, ThisTempVar(), _) + or + this = TIRTempVariable(_, _, EllipsisTempVar(), _) + } + + /** + * Gets the zero-based index of this parameter. The `this` parameter has index -1. + */ + int getIndex() { none() } +} + +/** + * An IR variable representing a positional parameter. + */ +class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable { + final override int getIndex() { result = getVariable().(Language::Parameter).getIndex() } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll similarity index 59% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll index 9c83a3d99f0c..620b23b942e0 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the individual instructions in the IR for a function. + */ + private import internal.IRInternal import IRFunction import IRBlock @@ -27,9 +31,16 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil } /** - * Represents a single operation in the IR. + * A single instruction in the IR. */ -class Instruction extends Construction::TInstruction { +class Instruction extends Construction::TStageInstruction { + Instruction() { + // The base `TStageInstruction` type is a superset of the actual instructions appearing in this + // stage. This call lets the stage filter out the ones that are not reused from raw IR. + Construction::hasInstruction(this) + } + + /** Gets a textual representation of this element. */ final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } /** @@ -194,16 +205,25 @@ class Instruction extends Construction::TInstruction { * conversion. */ final Language::Expr getConvertedResultExpression() { - result = Construction::getInstructionConvertedResultExpression(this) + result = Raw::getInstructionConvertedResultExpression(this) } /** * Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any. */ final Language::Expr getUnconvertedResultExpression() { - result = Construction::getInstructionUnconvertedResultExpression(this) + result = Raw::getInstructionUnconvertedResultExpression(this) } + /** + * Gets the language-specific type of the result produced by this instruction. + * + * Most consumers of the IR should use `getResultIRType()` instead. `getResultIRType()` uses a + * less complex, language-neutral type system in which all semantically equivalent types share the + * same `IRType` instance. For example, in C++, four different `Instruction`s might have three + * different values for `getResultLanguageType()`: `unsigned int`, `char32_t`, and `wchar_t`, + * whereas all four instructions would have the same value for `getResultIRType()`, `uint4`. + */ final Language::LanguageType getResultLanguageType() { result = Construction::getInstructionResultType(this) } @@ -212,6 +232,7 @@ class Instruction extends Construction::TInstruction { * Gets the type of the result produced by this instruction. If the instruction does not produce * a result, its result type will be `IRVoidType`. */ + cached final IRType getResultIRType() { result = getResultLanguageType().getIRType() } /** @@ -240,17 +261,19 @@ class Instruction extends Construction::TInstruction { * given by `getResultType()`. * * For example, the statement `y = x;` generates the following IR: + * ``` * r1_0(glval: int) = VariableAddress[x] * r1_1(int) = Load r1_0, mu0_1 * r1_2(glval: int) = VariableAddress[y] * mu1_3(int) = Store r1_2, r1_1 + * ``` * * The result of each `VariableAddress` instruction is a glvalue of type * `int`, representing the address of the corresponding integer variable. The * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) } + final predicate isGLValue() { getResultLanguageType().hasType(_, true) } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -259,7 +282,7 @@ class Instruction extends Construction::TInstruction { * If `this.isGLValue()` holds for this instruction, the value of * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() } + final int getResultSize() { result = getResultLanguageType().getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. @@ -392,13 +415,27 @@ class Instruction extends Construction::TInstruction { final Instruction getAPredecessor() { result = getPredecessor(_) } } +/** + * An instruction that refers to a variable. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * variable. For example, it is used for `VariableAddress`, which returns the address of a specific + * variable, and `InitializeParameter`, which returns the value that was passed to the specified + * parameter by the caller. `VariableInstruction` is not used for `Load` or `Store` instructions + * that happen to load from or store to a particular variable; in those cases, the memory location + * being accessed is specified by the `AddressOperand` on the instruction, which may or may not be + * defined by the result of a `VariableAddress` instruction. + */ class VariableInstruction extends Instruction { IRVariable var; - VariableInstruction() { var = Construction::getInstructionVariable(this) } + VariableInstruction() { var = Raw::getInstructionVariable(this) } override string getImmediateString() { result = var.toString() } + /** + * Gets the variable that this instruction references. + */ final IRVariable getIRVariable() { result = var } /** @@ -407,63 +444,156 @@ class VariableInstruction extends Instruction { final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that refers to a field of a class, struct, or union. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * field. For example, it is used for `FieldAddress`, which computes the address of a specific + * field on an object. `FieldInstruction` is not used for `Load` or `Store` instructions that happen + * to load from or store to a particular field; in those cases, the memory location being accessed + * is specified by the `AddressOperand` on the instruction, which may or may not be defined by the + * result of a `FieldAddress` instruction. + */ class FieldInstruction extends Instruction { Language::Field field; - FieldInstruction() { field = Construction::getInstructionField(this) } + FieldInstruction() { field = Raw::getInstructionField(this) } final override string getImmediateString() { result = field.toString() } + /** + * Gets the field that this instruction references. + */ final Language::Field getField() { result = field } } +/** + * An instruction that refers to a function. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * function. For example, it is used for `FunctionAddress`, which returns the address of a specific + * function. `FunctionInstruction` is not used for `Call` instructions that happen to call a + * particular function; in that case, the function being called is specified by the + * `CallTargetOperand` on the instruction, which may or may not be defined by the result of a + * `FunctionAddress` instruction. + */ class FunctionInstruction extends Instruction { Language::Function funcSymbol; - FunctionInstruction() { funcSymbol = Construction::getInstructionFunction(this) } + FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) } final override string getImmediateString() { result = funcSymbol.toString() } + /** + * Gets the function that this instruction references. + */ final Language::Function getFunctionSymbol() { result = funcSymbol } } +/** + * An instruction whose result is a compile-time constant value. + */ class ConstantValueInstruction extends Instruction { string value; - ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) } + ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) } final override string getImmediateString() { result = value } + /** + * Gets the constant value of this instruction's result. + */ final string getValue() { result = value } } +/** + * An instruction that refers to an argument of a `Call` instruction. + * + * This instruction is used for side effects of a `Call` instruction that read or write memory + * pointed to by one of the arguments of the call. + */ class IndexedInstruction extends Instruction { int index; - IndexedInstruction() { index = Construction::getInstructionIndex(this) } + IndexedInstruction() { index = Raw::getInstructionIndex(this) } final override string getImmediateString() { result = index.toString() } + /** + * Gets the zero-based index of the argument that this instruction references. + */ final int getIndex() { result = index } } +/** + * An instruction representing the entry point to a function. + * + * Each `IRFunction` has exactly one `EnterFunction` instruction. Execution of the function begins + * at this instruction. This instruction has no predecessors. + */ class EnterFunctionInstruction extends Instruction { EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction } } +/** + * An instruction that returns the address of a variable. + * + * This instruction returns the address of a local variable, parameter, static field, + * namespace-scope variable, or global variable. For the address of a non-static field of a class, + * struct, or union, see `FieldAddressInstruction`. + */ class VariableAddressInstruction extends VariableInstruction { VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } } +/** + * An instruction that returns the address of a function. + * + * This instruction returns the address of a function, including non-member functions, static member + * functions, and non-static member functions. + * + * The result has an `IRFunctionAddress` type. + */ +class FunctionAddressInstruction extends FunctionInstruction { + FunctionAddressInstruction() { getOpcode() instanceof Opcode::FunctionAddress } +} + +/** + * An instruction that initializes a parameter of the enclosing function with the value of the + * corresponding argument passed by the caller. + * + * Each parameter of a function will have exactly one `InitializeParameter` instruction that + * initializes that parameter. + */ class InitializeParameterInstruction extends VariableInstruction { InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that initializes all memory that existed before this function was called. + * + * This instruction provides a definition for memory that, because it was actually allocated and + * initialized elsewhere, would not otherwise have a definition in this function. + */ +class InitializeNonLocalInstruction extends Instruction { + InitializeNonLocalInstruction() { getOpcode() instanceof Opcode::InitializeNonLocal } +} + +/** + * An instruction that initializes the memory pointed to by a parameter of the enclosing function + * with the value of that memory on entry to the function. + */ class InitializeIndirectionInstruction extends VariableInstruction { InitializeIndirectionInstruction() { getOpcode() instanceof Opcode::InitializeIndirection } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } @@ -474,14 +604,42 @@ class InitializeThisInstruction extends Instruction { InitializeThisInstruction() { getOpcode() instanceof Opcode::InitializeThis } } +/** + * An instruction that computes the address of a non-static field of an object. + */ class FieldAddressInstruction extends FieldInstruction { FieldAddressInstruction() { getOpcode() instanceof Opcode::FieldAddress } + /** + * Gets the operand that provides the address of the object containing the field. + */ final UnaryOperand getObjectAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the object containing the field. + */ final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } } +/** + * An instruction that computes the address of the first element of a managed array. + * + * This instruction is used for element access to C# arrays. + */ +class ElementsAddressInstruction extends UnaryInstruction { + ElementsAddressInstruction() { getOpcode() instanceof Opcode::ElementsAddress } + + /** + * Gets the operand that provides the address of the array object. + */ + final UnaryOperand getArrayObjectAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the array object. + */ + final Instruction getArrayObjectAddress() { result = getArrayObjectAddressOperand().getDef() } +} + /** * An instruction that produces a well-defined but unknown result and has * unknown side effects, including side effects that are not conservatively @@ -496,6 +654,12 @@ class ErrorInstruction extends Instruction { ErrorInstruction() { getOpcode() instanceof Opcode::Error } } +/** + * An instruction that returns an uninitialized value. + * + * This instruction is used to provide an initial definition for a stack variable that does not have + * an initializer, or whose initializer only partially initializes the variable. + */ class UninitializedInstruction extends VariableInstruction { UninitializedInstruction() { getOpcode() instanceof Opcode::Uninitialized } @@ -505,35 +669,94 @@ class UninitializedInstruction extends VariableInstruction { final Language::Variable getLocalVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that has no effect. + * + * This instruction is typically inserted to ensure that a particular AST is associated with at + * least one instruction, even when the AST has no semantic effect. + */ class NoOpInstruction extends Instruction { NoOpInstruction() { getOpcode() instanceof Opcode::NoOp } } +/** + * An instruction that returns control to the caller of the function. + * + * This instruction represents the normal (non-exception) return from a function, either from an + * explicit `return` statement or from control flow reaching the end of the function's body. + * + * Each function has exactly one `ReturnInstruction`. Each `return` statement in a function is + * represented as an initialization of the temporary variable that holds the return value, with + * control then flowing to the common `ReturnInstruction` for that function. Exception: A function + * that never returns will not have a `ReturnInstruction`. + * + * The `ReturnInstruction` for a function will have a control-flow successor edge to a block + * containing the `ExitFunction` instruction for that function. + * + * There are two differet return instructions: `ReturnValueInstruction`, for returning a value from + * a non-`void`-returning function, and `ReturnVoidInstruction`, for returning from a + * `void`-returning function. + */ class ReturnInstruction extends Instruction { ReturnInstruction() { getOpcode() instanceof ReturnOpcode } } +/** + * An instruction that returns control to the caller of the function, without returning a value. + */ class ReturnVoidInstruction extends ReturnInstruction { ReturnVoidInstruction() { getOpcode() instanceof Opcode::ReturnVoid } } +/** + * An instruction that returns control to the caller of the function, including a return value. + */ class ReturnValueInstruction extends ReturnInstruction { ReturnValueInstruction() { getOpcode() instanceof Opcode::ReturnValue } + /** + * Gets the operand that provides the value being returned by the function. + */ final LoadOperand getReturnValueOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value being returned by the function, if an + * exact definition is available. + */ final Instruction getReturnValue() { result = getReturnValueOperand().getDef() } } +/** + * An instruction that represents the use of the value pointed to by a parameter of the function + * after the function returns control to its caller. + * + * This instruction does not itself return control to the caller. It merely represents the potential + * for a caller to use the memory pointed to by the parameter sometime after the call returns. This + * is the counterpart to the `InitializeIndirection` instruction, which represents the possibility + * that the caller initialized the memory pointed to by the parameter before the call. + */ class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } + /** + * Gets the operand that provides the value of the pointed-to memory. + */ final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the pointed-to memory, if an exact + * definition is available. + */ final Instruction getSideEffect() { result = getSideEffectOperand().getDef() } + /** + * Gets the operand that provides the address of the pointed-to memory. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the pointed-to memory. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } /** @@ -541,87 +764,191 @@ class ReturnIndirectionInstruction extends VariableInstruction { * function. */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } + + /** + * Holds if this instruction is the return indirection for `this`. + */ + final predicate isThisIndirection() { var instanceof IRThisVariable } } +/** + * An instruction that returns a copy of its operand. + * + * There are several different copy instructions, depending on the source and destination of the + * copy operation: + * - `CopyInstruction` - Copies a register operand to a register result. + * - `LoadInstruction` - Copies a memory operand to a register result. + * - `StoreInstruction` - Copies a register operand to a memory result. + */ class CopyInstruction extends Instruction { CopyInstruction() { getOpcode() instanceof CopyOpcode } + /** + * Gets the operand that provides the input value of the copy. + */ Operand getSourceValueOperand() { none() } + /** + * Gets the instruction whose result provides the input value of the copy, if an exact definition + * is available. + */ final Instruction getSourceValue() { result = getSourceValueOperand().getDef() } } +/** + * An instruction that returns a register result containing a copy of its register operand. + */ class CopyValueInstruction extends CopyInstruction, UnaryInstruction { CopyValueInstruction() { getOpcode() instanceof Opcode::CopyValue } final override UnaryOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a register result containing a copy of its memory operand. + */ class LoadInstruction extends CopyInstruction { LoadInstruction() { getOpcode() instanceof Opcode::Load } + /** + * Gets the operand that provides the address of the value being loaded. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the value being loaded. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } final override LoadOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a memory result containing a copy of its register operand. + */ class StoreInstruction extends CopyInstruction { StoreInstruction() { getOpcode() instanceof Opcode::Store } + /** + * Gets the operand that provides the address of the location to which the value will be stored. + */ final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the location to which the value will + * be stored, if an exact definition is available. + */ final Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } final override StoreValueOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that branches to one of two successor instructions based on the value of a Boolean + * operand. + */ class ConditionalBranchInstruction extends Instruction { ConditionalBranchInstruction() { getOpcode() instanceof Opcode::ConditionalBranch } + /** + * Gets the operand that provides the Boolean condition controlling the branch. + */ final ConditionOperand getConditionOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the Boolean condition controlling the branch. + */ final Instruction getCondition() { result = getConditionOperand().getDef() } + /** + * Gets the instruction to which control will flow if the condition is true. + */ final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } + /** + * Gets the instruction to which control will flow if the condition is false. + */ final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } } +/** + * An instruction representing the exit point of a function. + * + * Each `IRFunction` has exactly one `ExitFunction` instruction, unless the function neither returns + * nor throws an exception. Control flows to the `ExitFunction` instruction from both normal returns + * (`ReturnVoid`, `ReturnValue`) and propagated exceptions (`Unwind`). This instruction has no + * successors. + */ class ExitFunctionInstruction extends Instruction { ExitFunctionInstruction() { getOpcode() instanceof Opcode::ExitFunction } } +/** + * An instruction whose result is a constant value. + */ class ConstantInstruction extends ConstantValueInstruction { ConstantInstruction() { getOpcode() instanceof Opcode::Constant } } +/** + * An instruction whose result is a constant value of integer or Boolean type. + */ class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType } + IntegerConstantInstruction() { + exists(IRType resultType | + resultType = getResultIRType() and + (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType) + ) + } } +/** + * An instruction whose result is a constant value of floating-point type. + */ class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } + FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } +/** + * An instruction whose result is the address of a string literal. + */ class StringConstantInstruction extends VariableInstruction { override IRStringLiteral var; final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) } + /** + * Gets the string literal whose address is returned by this instruction. + */ final Language::StringLiteral getValue() { result = var.getLiteral() } } +/** + * An instruction whose result is computed from two operands. + */ class BinaryInstruction extends Instruction { BinaryInstruction() { getOpcode() instanceof BinaryOpcode } + /** + * Gets the left operand of this binary instruction. + */ final LeftOperand getLeftOperand() { result = getAnOperand() } + /** + * Gets the right operand of this binary instruction. + */ final RightOperand getRightOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the left operand of this binary + * instruction. + */ final Instruction getLeft() { result = getLeftOperand().getDef() } + /** + * Gets the instruction whose result provides the value of the right operand of this binary + * instruction. + */ final Instruction getRight() { result = getRightOperand().getDef() } /** @@ -634,121 +961,301 @@ class BinaryInstruction extends Instruction { } } +/** + * An instruction that computes the result of an arithmetic operation. + */ class ArithmeticInstruction extends Instruction { ArithmeticInstruction() { getOpcode() instanceof ArithmeticOpcode } } +/** + * An instruction that performs an arithmetic operation on two numeric operands. + */ class BinaryArithmeticInstruction extends ArithmeticInstruction, BinaryInstruction { } +/** + * An instruction whose result is computed by performing an arithmetic operation on a single + * numeric operand. + */ class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction { } +/** + * An instruction that computes the sum of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point addition is + * performed according to IEEE-754. + */ class AddInstruction extends BinaryArithmeticInstruction { AddInstruction() { getOpcode() instanceof Opcode::Add } } +/** + * An instruction that computes the difference of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point subtraction is performed + * according to IEEE-754. + */ class SubInstruction extends BinaryArithmeticInstruction { SubInstruction() { getOpcode() instanceof Opcode::Sub } } +/** + * An instruction that computes the product of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point multiplication is + * performed according to IEEE-754. + */ class MulInstruction extends BinaryArithmeticInstruction { MulInstruction() { getOpcode() instanceof Opcode::Mul } } +/** + * An instruction that computes the quotient of two numeric operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. Floating-point division is performed according + * to IEEE-754. + */ class DivInstruction extends BinaryArithmeticInstruction { DivInstruction() { getOpcode() instanceof Opcode::Div } } +/** + * An instruction that computes the remainder of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. + */ class RemInstruction extends BinaryArithmeticInstruction { RemInstruction() { getOpcode() instanceof Opcode::Rem } } +/** + * An instruction that negates a single numeric operand. + * + * The operand must have a numeric type, which will also be the result type. The result of integer + * negation uses two's complement, and is computed modulo 2^n. The result of floating-point negation + * is performed according to IEEE-754. + */ class NegateInstruction extends UnaryArithmeticInstruction { NegateInstruction() { getOpcode() instanceof Opcode::Negate } } +/** + * An instruction that computes the result of a bitwise operation. + */ class BitwiseInstruction extends Instruction { BitwiseInstruction() { getOpcode() instanceof BitwiseOpcode } } +/** + * An instruction that performs a bitwise operation on two integer operands. + */ class BinaryBitwiseInstruction extends BitwiseInstruction, BinaryInstruction { } +/** + * An instruction that performs a bitwise operation on a single integer operand. + */ class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } +/** + * An instruction that computes the bitwise "and" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitAndInstruction extends BinaryBitwiseInstruction { BitAndInstruction() { getOpcode() instanceof Opcode::BitAnd } } +/** + * An instruction that computes the bitwise "or" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitOrInstruction extends BinaryBitwiseInstruction { BitOrInstruction() { getOpcode() instanceof Opcode::BitOr } } +/** + * An instruction that computes the bitwise "xor" of two integer operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitXorInstruction extends BinaryBitwiseInstruction { BitXorInstruction() { getOpcode() instanceof Opcode::BitXor } } +/** + * An instruction that shifts its left operand to the left by the number of bits specified by its + * right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. The + * rightmost bits are zero-filled. + */ class ShiftLeftInstruction extends BinaryBitwiseInstruction { ShiftLeftInstruction() { getOpcode() instanceof Opcode::ShiftLeft } } +/** + * An instruction that shifts its left operand to the right by the number of bits specified by its + * right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. If the + * left operand has an unsigned integer type, the leftmost bits are zero-filled. If the left operand + * has a signed integer type, the leftmost bits are filled by duplicating the most significant bit + * of the left operand. + */ class ShiftRightInstruction extends BinaryBitwiseInstruction { ShiftRightInstruction() { getOpcode() instanceof Opcode::ShiftRight } } +/** + * An instruction that performs a binary arithmetic operation involving at least one pointer + * operand. + */ class PointerArithmeticInstruction extends BinaryInstruction { int elementSize; PointerArithmeticInstruction() { getOpcode() instanceof PointerArithmeticOpcode and - elementSize = Construction::getInstructionElementSize(this) + elementSize = Raw::getInstructionElementSize(this) } final override string getImmediateString() { result = elementSize.toString() } + /** + * Gets the size of the elements pointed to by the pointer operands, in bytes. + * + * When adding an integer offset to a pointer (`PointerAddInstruction`) or subtracting an integer + * offset from a pointer (`PointerSubInstruction`), the integer offset is multiplied by the + * element size to compute the actual number of bytes added to or subtracted from the pointer + * address. When computing the integer difference between two pointers (`PointerDiffInstruction`), + * the result is computed by computing the difference between the two pointer byte addresses, then + * dividing that byte count by the element size. + */ final int getElementSize() { result = elementSize } } +/** + * An instruction that adds or subtracts an integer offset from a pointer. + */ class PointerOffsetInstruction extends PointerArithmeticInstruction { PointerOffsetInstruction() { getOpcode() instanceof PointerOffsetOpcode } } +/** + * An instruction that adds an integer offset to a pointer. + * + * The result is the byte address computed by adding the value of the right (integer) operand, + * multiplied by the element size, to the value of the left (pointer) operand. The result of pointer + * overflow is undefined. + */ class PointerAddInstruction extends PointerOffsetInstruction { PointerAddInstruction() { getOpcode() instanceof Opcode::PointerAdd } } +/** + * An instruction that subtracts an integer offset from a pointer. + * + * The result is the byte address computed by subtracting the value of the right (integer) operand, + * multiplied by the element size, from the value of the left (pointer) operand. The result of + * pointer underflow is undefined. + */ class PointerSubInstruction extends PointerOffsetInstruction { PointerSubInstruction() { getOpcode() instanceof Opcode::PointerSub } } +/** + * An instruction that computes the difference between two pointers. + * + * Both operands must have the same pointer type. The result must have an integer type whose size is + * the same as that of the pointer operands. The result is computed by subtracting the byte address + * in the right operand from the byte address in the left operand, and dividing by the element size. + * If the difference in byte addresses is not divisible by the element size, the result is + * undefined. + */ class PointerDiffInstruction extends PointerArithmeticInstruction { PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff } } +/** + * An instruction whose result is computed from a single operand. + */ class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } + /** + * Gets the sole operand of this instruction. + */ final UnaryOperand getUnaryOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the sole operand of this instruction. + */ final Instruction getUnary() { result = getUnaryOperand().getDef() } } +/** + * An instruction that converts the value of its operand to a value of a different type. + */ class ConvertInstruction extends UnaryInstruction { ConvertInstruction() { getOpcode() instanceof Opcode::Convert } } +/** + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, returning a null address if the dynamic type of the + * object is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a pointer type, or a C# `is` or + * `as` expression. + */ class CheckedConvertOrNullInstruction extends UnaryInstruction { CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull } } /** - * Represents an instruction that converts between two addresses - * related by inheritance. + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, throwing an exception if the dynamic type of the object + * is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a reference type, or a C# cast + * expression. + */ +class CheckedConvertOrThrowInstruction extends UnaryInstruction { + CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } +} + +/** + * An instruction that returns the address of the complete object that contains the subobject + * pointed to by its operand. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent `dyanmic_cast` in C++, which returns the pointer to + * the most-derived object. + */ +class CompleteObjectAddressInstruction extends UnaryInstruction { + CompleteObjectAddressInstruction() { getOpcode() instanceof Opcode::CompleteObjectAddress } +} + +/** + * An instruction that converts the address of an object to the address of a different subobject of + * the same object, without any type checking at runtime. */ class InheritanceConversionInstruction extends UnaryInstruction { Language::Class baseClass; Language::Class derivedClass; InheritanceConversionInstruction() { - Construction::getInstructionInheritance(this, baseClass, derivedClass) + Raw::getInstructionInheritance(this, baseClass, derivedClass) } final override string getImmediateString() { @@ -778,59 +1285,91 @@ class InheritanceConversionInstruction extends UnaryInstruction { } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a base class. + * An instruction that converts from the address of a derived class to the address of a base class. */ class ConvertToBaseInstruction extends InheritanceConversionInstruction { ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a direct non-virtual base class. + * An instruction that converts from the address of a derived class to the address of a direct + * non-virtual base class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToNonVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToNonVirtualBase } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a virtual base class. + * An instruction that converts from the address of a derived class to the address of a virtual base + * class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToVirtualBase } } /** - * Represents an instruction that converts from the address of a base class - * to the address of a direct non-virtual derived class. + * An instruction that converts from the address of a base class to the address of a direct + * non-virtual derived class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToDerivedInstruction extends InheritanceConversionInstruction { ConvertToDerivedInstruction() { getOpcode() instanceof Opcode::ConvertToDerived } } +/** + * An instruction that computes the bitwise complement of its operand. + * + * The operand must have an integer type, which will also be the result type. + */ class BitComplementInstruction extends UnaryBitwiseInstruction { BitComplementInstruction() { getOpcode() instanceof Opcode::BitComplement } } +/** + * An instruction that computes the logical complement of its operand. + * + * The operand must have a Boolean type, which will also be the result type. + */ class LogicalNotInstruction extends UnaryInstruction { LogicalNotInstruction() { getOpcode() instanceof Opcode::LogicalNot } } +/** + * An instruction that compares two numeric operands. + */ class CompareInstruction extends BinaryInstruction { CompareInstruction() { getOpcode() instanceof CompareOpcode } } +/** + * An instruction that returns a `true` result if its operands are equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left == right`, and `false` if `left != right` or the two operands are + * unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareEQInstruction extends CompareInstruction { CompareEQInstruction() { getOpcode() instanceof Opcode::CompareEQ } } +/** + * An instruction that returns a `true` result if its operands are not equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left != right` or if the two operands are unordered, and `false` if + * `left == right`. Floating-point comparison is performed according to IEEE-754. + */ class CompareNEInstruction extends CompareInstruction { CompareNEInstruction() { getOpcode() instanceof Opcode::CompareNE } } /** - * Represents an instruction that does a relative comparison of two values, such as `<` or `>=`. + * An instruction that does a relative comparison of two values, such as `<` or `>=`. */ class RelationalInstruction extends CompareInstruction { RelationalInstruction() { getOpcode() instanceof RelationalOpcode } @@ -857,6 +1396,13 @@ class RelationalInstruction extends CompareInstruction { predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is less than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left < right`, and `false` if `left >= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLTInstruction extends RelationalInstruction { CompareLTInstruction() { getOpcode() instanceof Opcode::CompareLT } @@ -867,6 +1413,13 @@ class CompareLTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is greater than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left > right`, and `false` if `left <= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGTInstruction extends RelationalInstruction { CompareGTInstruction() { getOpcode() instanceof Opcode::CompareGT } @@ -877,6 +1430,14 @@ class CompareGTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is less than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left <= right`, and `false` if `left > right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLEInstruction extends RelationalInstruction { CompareLEInstruction() { getOpcode() instanceof Opcode::CompareLE } @@ -887,6 +1448,14 @@ class CompareLEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is greater than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left >= right`, and `false` if `left < right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGEInstruction extends RelationalInstruction { CompareGEInstruction() { getOpcode() instanceof Opcode::CompareGE } @@ -897,15 +1466,32 @@ class CompareGEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that branches to one of multiple successor instructions based on the value of an + * integer operand. + * + * This instruction will have zero or more successors whose edge kind is `CaseEdge`, each + * representing the branch that will be taken if the controlling expression is within the range + * specified for that case edge. The range of a case edge must be disjoint from the range of each + * other case edge. + * + * The instruction may optionally have a successor edge whose edge kind is `DefaultEdge`, + * representing the branch that will be taken if the controlling expression is not within the range + * of any case edge. + */ class SwitchInstruction extends Instruction { SwitchInstruction() { getOpcode() instanceof Opcode::Switch } + /** Gets the operand that provides the integer value controlling the switch. */ final ConditionOperand getExpressionOperand() { result = getAnOperand() } + /** Gets the instruction whose result provides the integer value controlling the switch. */ final Instruction getExpression() { result = getExpressionOperand().getDef() } + /** Gets the successor instructions along the case edges of the switch. */ final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } + /** Gets the successor instruction along the default edge of the switch, if any. */ final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } } @@ -936,7 +1522,7 @@ class CallInstruction extends Instruction { * Gets the `Function` that the call targets, if this is statically known. */ final Language::Function getStaticCallTarget() { - result = getCallTarget().(FunctionInstruction).getFunctionSymbol() + result = getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() } /** @@ -981,6 +1567,9 @@ class CallInstruction extends Instruction { class SideEffectInstruction extends Instruction { SideEffectInstruction() { getOpcode() instanceof SideEffectOpcode } + /** + * Gets the instruction whose execution causes this side effect. + */ final Instruction getPrimaryInstruction() { result = Construction::getPrimaryInstructionForSideEffect(this) } @@ -996,9 +1585,10 @@ class CallSideEffectInstruction extends SideEffectInstruction { /** * An instruction representing the side effect of a function call on any memory - * that might be read by that call. This instruction is emitted instead of - * `CallSideEffectInstruction` when it's certain that the call target cannot - * write to escaped memory. + * that might be read by that call. + * + * This instruction is emitted instead of `CallSideEffectInstruction` when it is certain that the + * call target cannot write to escaped memory. */ class CallReadSideEffectInstruction extends SideEffectInstruction { CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect } @@ -1046,7 +1636,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { getOpcode() instanceof Opcode::SizedBufferReadSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes read from the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes read from the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1056,7 +1654,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } + /** + * Get the operand that holds the address of the memory to be written. + */ + final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the memory to be written. + */ + Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } } /** @@ -1087,11 +1693,20 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** * An instruction representing the potential write of an indirect parameter within a function call. + * * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. * written. */ @@ -1103,6 +1718,7 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1111,6 +1727,7 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1118,11 +1735,19 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** - * An instruction representing the initial value of newly allocated memory, e.g. the result of a + * An instruction representing the initial value of newly allocated memory, such as the result of a * call to `malloc`. */ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { @@ -1211,7 +1836,7 @@ class CatchByTypeInstruction extends CatchInstruction { CatchByTypeInstruction() { getOpcode() instanceof Opcode::CatchByType and - exceptionType = Construction::getInstructionExceptionType(this) + exceptionType = Raw::getInstructionExceptionType(this) } final override string getImmediateString() { result = exceptionType.toString() } @@ -1337,29 +1962,43 @@ class ChiInstruction extends Instruction { * Gets the operand that represents the new value written by the memory write. */ final Instruction getPartial() { result = getPartialOperand().getDef() } + + /** + * Gets the bit range `[startBit, endBit)` updated by the partial operand of this `ChiInstruction`, relative to the start address of the total operand. + */ + final predicate getUpdatedInterval(int startBit, int endBit) { + Construction::getIntervalUpdatedByChi(this, startBit, endBit) + } } /** - * An instruction representing unreachable code. Inserted in place of the original target - * instruction of a `ConditionalBranch` or `Switch` instruction where that particular edge is - * infeasible. + * An instruction representing unreachable code. + * + * This instruction is inserted in place of the original target instruction of a `ConditionalBranch` + * or `Switch` instruction where that particular edge is infeasible. */ class UnreachedInstruction extends Instruction { UnreachedInstruction() { getOpcode() instanceof Opcode::Unreached } } /** - * An instruction representing a built-in operation. This is used to represent - * operations such as access to variable argument lists. + * An instruction representing a built-in operation. + * + * This is used to represent a variety of intrinsic operations provided by the compiler + * implementation, such as vector arithmetic. */ class BuiltInOperationInstruction extends Instruction { Language::BuiltInOperation operation; BuiltInOperationInstruction() { getOpcode() instanceof BuiltInOperationOpcode and - operation = Construction::getInstructionBuiltInOperation(this) + operation = Raw::getInstructionBuiltInOperation(this) } + /** + * Gets the language-specific `BuiltInOperation` object that specifies the operation that is + * performed by this instruction. + */ final Language::BuiltInOperation getBuiltInOperation() { result = operation } } @@ -1372,3 +2011,59 @@ class BuiltInInstruction extends BuiltInOperationInstruction { final override string getImmediateString() { result = getBuiltInOperation().toString() } } + +/** + * An instruction that returns a `va_list` to access the arguments passed to the `...` parameter. + * + * The operand specifies the address of the `IREllipsisVariable` used to represent the `...` + * parameter. The result is a `va_list` that initially refers to the first argument that was passed + * to the `...` parameter. + */ +class VarArgsStartInstruction extends UnaryInstruction { + VarArgsStartInstruction() { getOpcode() instanceof Opcode::VarArgsStart } +} + +/** + * An instruction that cleans up a `va_list` after it is no longer in use. + * + * The operand specifies the address of the `va_list` to clean up. This instruction does not return + * a result. + */ +class VarArgsEndInstruction extends UnaryInstruction { + VarArgsEndInstruction() { getOpcode() instanceof Opcode::VarArgsEnd } +} + +/** + * An instruction that returns the address of the argument currently pointed to by a `va_list`. + * + * The operand is the `va_list` that points to the argument. The result is the address of the + * argument. + */ +class VarArgInstruction extends UnaryInstruction { + VarArgInstruction() { getOpcode() instanceof Opcode::VarArg } +} + +/** + * An instruction that modifies a `va_list` to point to the next argument that was passed to the + * `...` parameter. + * + * The operand is the current `va_list`. The result is an updated `va_list` that points to the next + * argument of the `...` parameter. + */ +class NextVarArgInstruction extends UnaryInstruction { + NextVarArgInstruction() { getOpcode() instanceof Opcode::NextVarArg } +} + +/** + * An instruction that allocates a new object on the managed heap. + * + * This instruction is used to represent the allocation of a new object in C# using the `new` + * expression. This instruction does not invoke a constructor for the object. Instead, there will be + * a subsequent `Call` instruction to invoke the appropriate constructor directory, passing the + * result of the `NewObj` as the `this` argument. + * + * The result is the address of the newly allocated object. + */ +class NewObjInstruction extends Instruction { + NewObjInstruction() { getOpcode() instanceof Opcode::NewObj } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll similarity index 91% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll index f82704094c8e..a12e35d471b8 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the input values of IR instructions. + */ + private import internal.IRInternal private import Instruction private import IRBlock @@ -75,13 +79,21 @@ private PhiOperandBase phiOperand( } /** - * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. + * An operand of an `Instruction`. The operand represents a use of the result of one instruction + * (the defining instruction) in another instruction (the use instruction) */ class Operand extends TOperand { + /** Gets a textual representation of this element. */ string toString() { result = "Operand" } + /** + * Gets the location of the source code for this operand. + */ final Language::Location getLocation() { result = getUse().getLocation() } + /** + * Gets the function that contains this operand. + */ final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() } /** @@ -139,6 +151,11 @@ class Operand extends TOperand { */ string getDumpLabel() { result = "" } + /** + * Gets a string that uniquely identifies this operand on its use instruction. + */ + string getDumpId() { result = "" } + /** * Gets a string describing this operand, suitable for display in IR dumps. This consists of the * result ID of the instruction consumed by the operand, plus a label identifying the operand @@ -268,8 +285,13 @@ class NonPhiOperand extends Operand { final override string getDumpLabel() { result = tag.getLabel() } + final override string getDumpId() { result = tag.getId() } + final override int getDumpSortOrder() { result = tag.getSortOrder() } + /** + * Gets the `OperandTag` that specifies how this operand is used by its `Instruction`. + */ final OperandTag getOperandTag() { result = tag } } @@ -292,6 +314,9 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { } } +/** + * A memory operand other than the operand of a `Phi` instruction. + */ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; @@ -311,8 +336,19 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper not Construction::isInCycle(useInstr) and strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 } + + /** + * Holds if the operand totally overlaps with its definition and consumes the + * bit range `[startBitOffset, endBitOffset)` relative to the start address of the definition. + */ + predicate getUsedInterval(int startBitOffset, int endBitOffset) { + Construction::getUsedInterval(this, startBitOffset, endBitOffset) + } } +/** + * A memory operand whose type may be different from the type of the result of its definition. + */ class TypedOperand extends NonPhiMemoryOperand { override TypedOperandTag tag; @@ -416,6 +452,9 @@ class PositionalArgumentOperand extends ArgumentOperand { final int getIndex() { result = tag.getArgIndex() } } +/** + * An operand representing memory read as a side effect of evaluating another instruction. + */ class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; } @@ -445,6 +484,8 @@ class PhiInputOperand extends MemoryOperand, PhiOperandBase { result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":" } + final override string getDumpId() { result = getPredecessorBlock().getDisplayIndex().toString() } + /** * Gets the predecessor block from which this value comes. */ diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.ql b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.ql similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.ql rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.ql diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll similarity index 73% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll index d9c0df44e12e..59dadee71545 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll @@ -1,3 +1,13 @@ +/** + * Outputs a representation of the IR as a control flow graph. + * + * This file contains the actual implementation of `PrintIR.ql`. For test cases and very small + * databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintIR.qll`, extends + * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to + * dump. + */ + private import internal.IRInternal private import IR private import internal.PrintIRImports as Imports @@ -9,6 +19,7 @@ private newtype TPrintIRConfiguration = MkPrintIRConfiguration() * The query can extend this class to control which functions are printed. */ class PrintIRConfiguration extends TPrintIRConfiguration { + /** Gets a textual representation of this configuration. */ string toString() { result = "PrintIRConfiguration" } /** @@ -39,6 +50,37 @@ private string getAdditionalBlockProperty(IRBlock block, string key) { exists(IRPropertyProvider provider | result = provider.getBlockProperty(block, key)) } +/** + * Gets the properties of an operand from any active property providers. + */ +private string getAdditionalOperandProperty(Operand operand, string key) { + exists(IRPropertyProvider provider | result = provider.getOperandProperty(operand, key)) +} + +/** + * Gets a string listing the properties of the operand and their corresponding values. If the + * operand has no properties, this predicate has no result. + */ +private string getOperandPropertyListString(Operand operand) { + result = + strictconcat(string key, string value | + value = getAdditionalOperandProperty(operand, key) + | + key + ":" + value, ", " + ) +} + +/** + * Gets a string listing the properties of the operand and their corresponding values. The list is + * surrounded by curly braces. If the operand has no properties, this predicate returns an empty + * string. + */ +private string getOperandPropertyString(Operand operand) { + result = "{" + getOperandPropertyListString(operand) + "}" + or + not exists(getOperandPropertyListString(operand)) and result = "" +} + private newtype TPrintableIRNode = TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or @@ -47,7 +89,7 @@ private newtype TPrintableIRNode = /** * A node to be emitted in the IR graph. */ -abstract class PrintableIRNode extends TPrintableIRNode { +abstract private class PrintableIRNode extends TPrintableIRNode { abstract string toString(); /** @@ -98,7 +140,7 @@ abstract class PrintableIRNode extends TPrintableIRNode { /** * An IR graph node representing a `IRFunction` object. */ -class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { +private class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { IRFunction irFunc; PrintableIRFunction() { this = TPrintableIRFunction(irFunc) } @@ -129,7 +171,7 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { /** * An IR graph node representing an `IRBlock` object. */ -class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { +private class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { IRBlock block; PrintableIRBlock() { this = TPrintableIRBlock(block) } @@ -161,7 +203,7 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { /** * An IR graph node representing an `Instruction`. */ -class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { +private class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { Instruction instr; PrintableInstruction() { this = TPrintableInstruction(instr) } @@ -179,7 +221,7 @@ class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { | resultString = instr.getResultString() and operationString = instr.getOperationString() and - operandsString = instr.getOperandsString() and + operandsString = getOperandsString() and columnWidths(block, resultWidth, operationWidth) and result = resultString + getPaddingString(resultWidth - resultString.length()) + " = " + @@ -199,6 +241,22 @@ class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { result = PrintableIRNode.super.getProperty(key) or result = getAdditionalInstructionProperty(instr, key) } + + /** + * Gets the string representation of the operand list. This is the same as + * `Instruction::getOperandsString()`, except that each operand is annotated with any properties + * provided by active `IRPropertyProvider` instances. + */ + private string getOperandsString() { + result = + concat(Operand operand | + operand = instr.getAnOperand() + | + operand.getDumpString() + getOperandPropertyString(operand), ", " + order by + operand.getDumpSortOrder() + ) + } } private predicate columnWidths(IRBlock block, int resultWidth, int operationWidth) { @@ -224,6 +282,9 @@ private string getPaddingString(int n) { n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " " } +/** + * Holds if `node` belongs to the output graph, and its property `key` has the given `value`. + */ query predicate nodes(PrintableIRNode node, string key, string value) { value = node.getProperty(key) } @@ -237,6 +298,10 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) { ) } +/** + * Holds if the output graph contains an edge from `pred` to `succ`, and that edge's property `key` + * has the given `value`. + */ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | predBlock = pred.getBlock() and @@ -256,6 +321,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, ) } +/** + * Holds if `parent` is the parent node of `child` in the output graph. + */ query predicate parents(PrintableIRNode child, PrintableIRNode parent) { parent = child.getParent() } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll similarity index 96% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll index f9e1cc7f4128..c50e8385c99a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll @@ -1,5 +1,5 @@ private import internal.ConstantAnalysisInternal -private import semmle.code.csharp.ir.internal.IntegerPartial +private import experimental.ir.internal.IntegerPartial private import IR language[monotonicAggregates] diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll similarity index 84% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll index 1145d5bb2abb..53f9295be4f9 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll @@ -1,5 +1,5 @@ private import internal.ConstantAnalysisInternal -private import semmle.code.csharp.ir.internal.IntegerConstant +private import experimental.ir.internal.IntegerConstant private import ConstantAnalysis import IR diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll new file mode 100644 index 000000000000..c70b240fe420 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll @@ -0,0 +1 @@ +import experimental.ir.implementation.unaliased_ssa.IR as IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll new file mode 100644 index 000000000000..34bd754692d6 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll @@ -0,0 +1,3 @@ +import experimental.ir.internal.Overlap +import experimental.ir.internal.IRCSharpLanguage as Language +import experimental.ir.implementation.unaliased_ssa.IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll similarity index 97% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll index 1612e0065b77..19fb0490f808 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll @@ -196,16 +196,17 @@ private predicate operandReturned(Operand operand, IntValue bitOffset) { bitOffset = Ints::unknown() } -private predicate isArgumentForParameter(CallInstruction ci, Operand operand, Instruction init) { +private predicate isArgumentForParameter( + CallInstruction ci, Operand operand, InitializeParameterInstruction init +) { exists(Language::Function f | ci = operand.getUse() and f = ci.getStaticCallTarget() and ( - init.(InitializeParameterInstruction).getParameter() = - f.getParameter(operand.(PositionalArgumentOperand).getIndex()) + init.getParameter() = f.getParameter(operand.(PositionalArgumentOperand).getIndex()) or - init.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable and - init.getEnclosingFunction() = f and + init.getIRVariable() instanceof IRThisVariable and + unique( | | init.getEnclosingFunction()) = f and operand instanceof ThisArgumentOperand ) and not Language::isFunctionVirtual(f) and diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll similarity index 91% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll index 11d7d37063ee..7992aa9ed146 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll @@ -1,6 +1,6 @@ private import csharp -import semmle.code.csharp.ir.implementation.IRConfiguration -import semmle.code.csharp.ir.internal.IntegerConstant as Ints +import experimental.ir.implementation.IRConfiguration +import experimental.ir.internal.IntegerConstant as Ints module AliasModels { /** @@ -12,7 +12,7 @@ module AliasModels { * the function returns. * * Example: - * ``` + * ```csharp * int* g; * int* func(int* p, int* q, int* r, int* s, int n) { * *s = 1; // `s` does not escape. diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll new file mode 100644 index 000000000000..f3f2d14ab437 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll @@ -0,0 +1,3 @@ +import experimental.ir.internal.IRCSharpLanguage as Language +import experimental.ir.implementation.raw.IR as InputIR +import AliasConfiguration as Configuration diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll new file mode 100644 index 000000000000..fc29c0d77dd0 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll @@ -0,0 +1 @@ +import experimental.ir.implementation.raw.IR diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll new file mode 100644 index 000000000000..c80761a68cf8 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll @@ -0,0 +1 @@ +import experimental.ir.implementation.EdgeKind as EdgeKind diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll new file mode 100644 index 000000000000..4e9a7d9f3aec --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll @@ -0,0 +1 @@ +import experimental.ir.implementation.internal.IRFunctionBase as IRFunctionBase diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRImports.qll new file mode 100644 index 000000000000..14dad7400b22 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRImports.qll @@ -0,0 +1,3 @@ +import experimental.ir.implementation.EdgeKind as EdgeKind +import experimental.ir.implementation.IRType as IRType +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRInternal.qll new file mode 100644 index 000000000000..eaf33e0800fb --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRInternal.qll @@ -0,0 +1,4 @@ +import experimental.ir.internal.IRCSharpLanguage as Language +import SSAConstruction as Construction +import experimental.ir.implementation.IRConfiguration as IRConfiguration +import experimental.ir.implementation.raw.internal.IRConstruction::Raw as Raw diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll new file mode 100644 index 000000000000..bdb4377cbdcc --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll @@ -0,0 +1,5 @@ +import experimental.ir.implementation.IRType as IRType +import experimental.ir.implementation.TempVariableTag as TempVariableTag +import experimental.ir.internal.IRUtilities as IRUtilities +import experimental.ir.internal.TempVariableTag as TTempVariableTag +import experimental.ir.implementation.internal.TIRVariable as TIRVariable diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/InstructionImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/InstructionImports.qll new file mode 100644 index 000000000000..4bcd2e127c12 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/InstructionImports.qll @@ -0,0 +1,6 @@ +import experimental.ir.implementation.EdgeKind as EdgeKind +import experimental.ir.implementation.IRType as IRType +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind +import experimental.ir.implementation.Opcode as Opcode +import experimental.ir.implementation.internal.OperandTag as OperandTag +import experimental.ir.internal.Overlap as Overlap diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandImports.qll new file mode 100644 index 000000000000..40af4631927a --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandImports.qll @@ -0,0 +1,4 @@ +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind +import experimental.ir.implementation.IRType as IRType +import experimental.ir.internal.Overlap as Overlap +import experimental.ir.implementation.internal.OperandTag as OperandTag diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll new file mode 100644 index 000000000000..9a3e4c03646c --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll @@ -0,0 +1 @@ +import experimental.ir.IRConfiguration as IRConfiguration diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintSSA.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintSSA.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll similarity index 84% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 30414bb5db3a..a6cb78b2b3a7 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -1,5 +1,11 @@ import SSAConstructionInternal -private import SSAConstructionImports +private import SSAConstructionImports as Imports +private import Imports::Opcode +private import Imports::OperandTag +private import Imports::Overlap +private import Imports::TInstruction +private import Imports::RawIR as RawIR +private import SSAInstructions private import NewIR private class OldBlock = Reachability::ReachableBlock; @@ -10,52 +16,45 @@ import Cached cached private module Cached { - private IRBlock getNewBlock(OldBlock oldBlock) { - result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction()) + cached + predicate hasPhiInstructionCached( + OldInstruction blockStartInstr, Alias::MemoryLocation defLocation + ) { + exists(OldBlock oldBlock | + definitionHasPhiNode(defLocation, oldBlock) and + blockStartInstr = oldBlock.getFirstInstruction() + ) } cached - predicate functionHasIR(Language::Function func) { - exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func) + predicate hasChiInstructionCached(OldInstruction primaryInstruction) { + hasChiNode(_, primaryInstruction) } cached - OldInstruction getOldInstruction(Instruction instr) { instr = WrappedInstruction(result) } - - private IRVariable getNewIRVariable(OldIR::IRVariable var) { - // This is just a type cast. Both classes derive from the same newtype. - result = var + predicate hasUnreachedInstructionCached(IRFunction irFunc) { + exists(OldInstruction oldInstruction | + irFunc = oldInstruction.getEnclosingIRFunction() and + Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) + ) } - cached - newtype TInstruction = - WrappedInstruction(OldInstruction oldInstruction) { - not oldInstruction instanceof OldIR::PhiInstruction - } or - Phi(OldBlock block, Alias::MemoryLocation defLocation) { - definitionHasPhiNode(defLocation, block) - } or - Chi(OldInstruction oldInstruction) { - not oldInstruction instanceof OldIR::PhiInstruction and - hasChiNode(_, oldInstruction) - } or - Unreached(Language::Function function) { - exists(OldInstruction oldInstruction | - function = oldInstruction.getEnclosingFunction() and - Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) - ) - } + class TStageInstruction = + TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction; cached - predicate hasTempVariable( - Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type - ) { - exists(OldIR::IRTempVariable var | - var.getEnclosingFunction() = func and - var.getAST() = ast and - var.getTag() = tag and - var.getLanguageType() = type - ) + predicate hasInstruction(TStageInstruction instr) { + instr instanceof TRawInstruction and instr instanceof OldInstruction + or + instr instanceof TPhiInstruction + or + instr instanceof TChiInstruction + or + instr instanceof TUnreachedInstruction + } + + private IRBlock getNewBlock(OldBlock oldBlock) { + result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction()) } cached @@ -73,7 +72,7 @@ private module Cached { or // Chi instructions track virtual variables, and therefore a chi instruction is // conflated if it's associated with the aliased virtual variable. - exists(OldInstruction oldInstruction | instruction = Chi(oldInstruction) | + exists(OldInstruction oldInstruction | instruction = getChi(oldInstruction) | Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof Alias::AliasedVirtualVariable ) @@ -81,7 +80,7 @@ private module Cached { // Phi instructions track locations, and therefore a phi instruction is // conflated if it's associated with a conflated location. exists(Alias::MemoryLocation location | - instruction = Phi(_, location) and + instruction = getPhi(_, location) and not exists(location.getAllocation()) ) } @@ -128,7 +127,7 @@ private module Cached { hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result) ) or - instruction = Chi(getOldInstruction(result)) and + instruction = getChi(getOldInstruction(result)) and tag instanceof ChiPartialOperandTag and overlap instanceof MustExactlyOverlap or @@ -150,6 +149,34 @@ private module Cached { ) } + /** + * Holds if the partial operand of this `ChiInstruction` updates the bit range + * `[startBitOffset, endBitOffset)` of the total operand. + */ + cached + predicate getIntervalUpdatedByChi(ChiInstruction chi, int startBitOffset, int endBitOffset) { + exists(Alias::MemoryLocation location, OldInstruction oldInstruction | + oldInstruction = getOldInstruction(chi.getPartial()) and + location = Alias::getResultMemoryLocation(oldInstruction) and + startBitOffset = Alias::getStartBitOffset(location) and + endBitOffset = Alias::getEndBitOffset(location) + ) + } + + /** + * Holds if `operand` totally overlaps with its definition and consumes the bit range + * `[startBitOffset, endBitOffset)`. + */ + cached + predicate getUsedInterval(NonPhiMemoryOperand operand, int startBitOffset, int endBitOffset) { + exists(Alias::MemoryLocation location, OldIR::NonPhiMemoryOperand oldOperand | + oldOperand = operand.getUse().(OldInstruction).getAnOperand() and + location = Alias::getOperandMemoryLocation(oldOperand) and + startBitOffset = Alias::getStartBitOffset(location) and + endBitOffset = Alias::getEndBitOffset(location) + ) + } + /** * Holds if `instr` is part of a cycle in the operand graph that doesn't go * through a phi instruction and therefore should be impossible. @@ -172,13 +199,15 @@ private module Cached { pragma[noopt] cached - Instruction getPhiOperandDefinition(Phi instr, IRBlock newPredecessorBlock, Overlap overlap) { + Instruction getPhiOperandDefinition( + PhiInstruction instr, IRBlock newPredecessorBlock, Overlap overlap + ) { exists( Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock, OldBlock predBlock, OldBlock defBlock, int defOffset, Alias::MemoryLocation actualDefLocation | hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset) and - instr = Phi(phiBlock, useLocation) and + instr = getPhi(phiBlock, useLocation) and newPredecessorBlock = getNewBlock(predBlock) and result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and overlap = Alias::getOverlap(actualDefLocation, useLocation) @@ -191,7 +220,7 @@ private module Cached { Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation, OldBlock defBlock, int defRank, int defOffset, OldBlock useBlock, int useRank | - chiInstr = Chi(oldInstr) and + chiInstr = getChi(oldInstr) and vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and hasUseAtRank(vvar, useBlock, useRank, oldInstr) and @@ -203,21 +232,11 @@ private module Cached { cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) { exists(OldBlock oldBlock | - instr = Phi(oldBlock, _) and + instr = getPhi(oldBlock, _) and result = getNewInstruction(oldBlock.getFirstInstruction()) ) } - cached - Language::Expr getInstructionConvertedResultExpression(Instruction instruction) { - result = getOldInstruction(instruction).getConvertedResultExpression() - } - - cached - Language::Expr getInstructionUnconvertedResultExpression(Instruction instruction) { - result = getOldInstruction(instruction).getUnconvertedResultExpression() - } - /* * This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node, * that node is its successor in the new successor relation, and the Chi node's successors are @@ -228,20 +247,20 @@ private module Cached { Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) { if hasChiNode(_, getOldInstruction(instruction)) then - result = Chi(getOldInstruction(instruction)) and + result = getChi(getOldInstruction(instruction)) and kind instanceof GotoEdge else ( exists(OldInstruction oldInstruction | oldInstruction = getOldInstruction(instruction) and ( if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind) - then result = Unreached(instruction.getEnclosingFunction()) + then result = unreachedInstruction(instruction.getEnclosingIRFunction()) else result = getNewInstruction(oldInstruction.getSuccessor(kind)) ) ) or exists(OldInstruction oldInstruction | - instruction = Chi(oldInstruction) and + instruction = getChi(oldInstruction) and result = getNewInstruction(oldInstruction.getSuccessor(kind)) ) ) @@ -260,137 +279,73 @@ private module Cached { // `oldInstruction`, in which case the back edge should come out of the // chi node instead. if hasChiNode(_, oldInstruction) - then instruction = Chi(oldInstruction) + then instruction = getChi(oldInstruction) else instruction = getNewInstruction(oldInstruction) ) } cached - Language::AST getInstructionAST(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) - or - instruction = Chi(oldInstruction) - | - result = oldInstruction.getAST() + Language::AST getInstructionAST(Instruction instr) { + result = getOldInstruction(instr).getAST() + or + exists(RawIR::Instruction blockStartInstr | + instr = phiInstruction(blockStartInstr, _) and + result = blockStartInstr.getAST() ) or - exists(OldBlock block | - instruction = Phi(block, _) and - result = block.getFirstInstruction().getAST() + exists(RawIR::Instruction primaryInstr | + instr = chiInstruction(primaryInstr) and + result = primaryInstr.getAST() ) or - instruction = Unreached(result) + exists(IRFunctionBase irFunc | + instr = unreachedInstruction(irFunc) and result = irFunc.getFunction() + ) } cached - Language::LanguageType getInstructionResultType(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) and - result = oldInstruction.getResultLanguageType() - ) + Language::LanguageType getInstructionResultType(Instruction instr) { + result = instr.(RawIR::Instruction).getResultLanguageType() or - exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar | - instruction = Chi(oldInstruction) and - hasChiNode(vvar, oldInstruction) and - result = vvar.getType() + exists(Alias::MemoryLocation defLocation | + instr = phiInstruction(_, defLocation) and + result = defLocation.getType() ) or - exists(Alias::MemoryLocation location | - instruction = Phi(_, location) and - result = location.getType() + exists(Instruction primaryInstr, Alias::VirtualVariable vvar | + instr = chiInstruction(primaryInstr) and + hasChiNode(vvar, primaryInstr) and + result = vvar.getType() ) or - instruction = Unreached(_) and - result = Language::getVoidType() + instr = unreachedInstruction(_) and result = Language::getVoidType() } cached - Opcode getInstructionOpcode(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) and - result = oldInstruction.getOpcode() - ) + Opcode getInstructionOpcode(Instruction instr) { + result = getOldInstruction(instr).getOpcode() or - instruction instanceof Chi and - result instanceof Opcode::Chi + instr = phiInstruction(_, _) and result instanceof Opcode::Phi or - instruction instanceof Phi and - result instanceof Opcode::Phi + instr = chiInstruction(_) and result instanceof Opcode::Chi or - instruction instanceof Unreached and - result instanceof Opcode::Unreached + instr = unreachedInstruction(_) and result instanceof Opcode::Unreached } cached - IRFunction getInstructionEnclosingIRFunction(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) - or - instruction = Chi(oldInstruction) - | - result.getFunction() = oldInstruction.getEnclosingFunction() - ) + IRFunctionBase getInstructionEnclosingIRFunction(Instruction instr) { + result = getOldInstruction(instr).getEnclosingIRFunction() or - exists(OldBlock block | - instruction = Phi(block, _) and - result.getFunction() = block.getEnclosingFunction() + exists(OldInstruction blockStartInstr | + instr = phiInstruction(blockStartInstr, _) and + result = blockStartInstr.getEnclosingIRFunction() ) or - instruction = Unreached(result.getFunction()) - } - - cached - IRVariable getInstructionVariable(Instruction instruction) { - result = - getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getIRVariable()) - } - - cached - Language::Field getInstructionField(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField() - } - - cached - int getInstructionIndex(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::IndexedInstruction).getIndex() - } - - cached - Language::Function getInstructionFunction(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol() - } - - cached - string getInstructionConstantValue(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue() - } - - cached - Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) { - result = - getOldInstruction(instruction).(OldIR::BuiltInOperationInstruction).getBuiltInOperation() - } - - cached - Language::LanguageType getInstructionExceptionType(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType() - } - - cached - int getInstructionElementSize(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::PointerArithmeticInstruction).getElementSize() - } - - cached - predicate getInstructionInheritance( - Instruction instruction, Language::Class baseClass, Language::Class derivedClass - ) { - exists(OldIR::InheritanceConversionInstruction oldInstr | - oldInstr = getOldInstruction(instruction) and - baseClass = oldInstr.getBaseClass() and - derivedClass = oldInstr.getDerivedClass() + exists(OldInstruction primaryInstr | + instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction() ) + or + instr = unreachedInstruction(result) } cached @@ -401,7 +356,7 @@ private module Cached { ) or exists(OldIR::Instruction oldInstruction | - instruction = Chi(oldInstruction) and + instruction = getChi(oldInstruction) and result = getNewInstruction(oldInstruction) ) } @@ -409,6 +364,14 @@ private module Cached { private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr } +private OldInstruction getOldInstruction(Instruction instr) { instr = result } + +private ChiInstruction getChi(OldInstruction primaryInstr) { result = chiInstruction(primaryInstr) } + +private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) { + result = phiInstruction(defBlock.getFirstInstruction(), defLocation) +} + /** * Holds if instruction `def` needs to have a `Chi` instruction inserted after it, to account for a partial definition * of a virtual variable. The `Chi` instruction provides a definition of the entire virtual variable of which the @@ -588,7 +551,7 @@ module DefUse { | // An odd offset corresponds to the `Chi` instruction. defOffset = oldOffset * 2 + 1 and - result = Chi(oldInstr) and + result = getChi(oldInstr) and ( defLocation = Alias::getResultMemoryLocation(oldInstr) or defLocation = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() @@ -607,7 +570,7 @@ module DefUse { or defOffset = -1 and hasDefinition(_, defLocation, defBlock, defOffset) and - result = Phi(defBlock, defLocation) and + result = getPhi(defBlock, defLocation) and actualDefLocation = defLocation } @@ -891,7 +854,7 @@ private module CachedForDebugging { ) or exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity | - instr = Phi(phiBlock, location) and + instr = getPhi(phiBlock, location) and result = "Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " + location.getUniqueId() and if location instanceof Alias::VirtualVariable @@ -901,7 +864,7 @@ private module CachedForDebugging { else specificity = "s" ) or - instr = Unreached(_) and + instr = unreachedInstruction(_) and result = "Unreached" } @@ -961,3 +924,19 @@ module SSAConsistency { ) } } + +/** + * Provides the portion of the parameterized IR interface that is used to construct the SSA stages + * of the IR. The raw stage of the IR does not expose these predicates. + * These predicates are all just aliases for predicates defined in the `Cached` module. This ensures + * that all of SSA construction will be evaluated in the same stage. + */ +module SSA { + class MemoryLocation = Alias::MemoryLocation; + + predicate hasPhiInstruction = Cached::hasPhiInstructionCached/2; + + predicate hasChiInstruction = Cached::hasChiInstructionCached/1; + + predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1; +} diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll new file mode 100644 index 000000000000..bf9b18d0b17b --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll @@ -0,0 +1,5 @@ +import experimental.ir.implementation.Opcode as Opcode +import experimental.ir.implementation.internal.OperandTag as OperandTag +import experimental.ir.internal.Overlap as Overlap +import experimental.ir.implementation.internal.TInstruction as TInstruction +import experimental.ir.implementation.raw.IR as RawIR diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll new file mode 100644 index 000000000000..15eaf8045a78 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll @@ -0,0 +1,8 @@ +import experimental.ir.implementation.raw.IR as OldIR +import experimental.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability +import experimental.ir.implementation.raw.internal.reachability.Dominance as Dominance +import experimental.ir.implementation.unaliased_ssa.IR as NewIR +import experimental.ir.implementation.raw.internal.IRConstruction as RawStage +import experimental.ir.implementation.internal.TInstruction::UnaliasedSSAInstructions as SSAInstructions +import experimental.ir.internal.IRCSharpLanguage as Language +import SimpleSSA as Alias diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll similarity index 85% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll index aee4959513ed..a7b9160bdc75 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll @@ -59,6 +59,12 @@ class MemoryLocation extends TMemoryLocation { final string getUniqueId() { result = var.getUniqueId() } } +/** + * Represents a set of `MemoryLocation`s that cannot overlap with + * `MemoryLocation`s outside of the set. The `VirtualVariable` will be + * represented by a `MemoryLocation` that totally overlaps all other + * `MemoryLocations` in the set. + */ class VirtualVariable extends MemoryLocation { } /** A virtual variable that groups all escaped memory within a function. */ @@ -79,3 +85,9 @@ MemoryLocation getResultMemoryLocation(Instruction instr) { MemoryLocation getOperandMemoryLocation(MemoryOperand operand) { result = getMemoryLocation(getAddressOperandAllocation(operand.getAddressOperand())) } + +/** Gets the start bit offset of a `MemoryLocation`, if any. */ +int getStartBitOffset(MemoryLocation location) { none() } + +/** Gets the end bit offset of a `MemoryLocation`, if any. */ +int getEndBitOffset(MemoryLocation location) { none() } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll new file mode 100644 index 000000000000..80a1c7c36fdb --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll @@ -0,0 +1,4 @@ +import experimental.ir.implementation.raw.IR +import experimental.ir.internal.IntegerConstant as Ints +import experimental.ir.implementation.internal.OperandTag +import experimental.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll new file mode 100644 index 000000000000..047d4923039b --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll @@ -0,0 +1 @@ +import experimental.ir.internal.Overlap diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/DominanceInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/DominanceInternal.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/DominanceInternal.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/DominanceInternal.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/PrintReachableBlock.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/PrintReachableBlock.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/PrintReachableBlock.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/PrintReachableBlock.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll new file mode 100644 index 000000000000..e435289cbfcb --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll @@ -0,0 +1,2 @@ +import experimental.ir.implementation.unaliased_ssa.IR as IR +import experimental.ir.implementation.unaliased_ssa.constant.ConstantAnalysis as ConstantAnalysis diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll b/csharp/ql/src/experimental/ir/internal/CSharpType.qll similarity index 99% rename from csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll rename to csharp/ql/src/experimental/ir/internal/CSharpType.qll index 5f966dd93a13..02dee3edff9a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll +++ b/csharp/ql/src/experimental/ir/internal/CSharpType.qll @@ -1,5 +1,5 @@ private import csharp -private import semmle.code.csharp.ir.implementation.IRType +private import experimental.ir.implementation.IRType private import IRCSharpLanguage as Language int getTypeSize(Type type) { diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll b/csharp/ql/src/experimental/ir/internal/IRCSharpLanguage.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll rename to csharp/ql/src/experimental/ir/internal/IRCSharpLanguage.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IRGuards.qll b/csharp/ql/src/experimental/ir/internal/IRGuards.qll similarity index 99% rename from csharp/ql/src/semmle/code/csharp/ir/internal/IRGuards.qll rename to csharp/ql/src/experimental/ir/internal/IRGuards.qll index 0cafb65d6f2f..a505e54c37e4 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/IRGuards.qll +++ b/csharp/ql/src/experimental/ir/internal/IRGuards.qll @@ -1,6 +1,6 @@ import csharp import semmle.code.csharp.controlflow.BasicBlocks -import semmle.code.csharp.ir.IR +import experimental.ir.IR /** * Holds if `block` consists of an `UnreachedInstruction`. @@ -93,7 +93,7 @@ class GuardCondition extends Expr { * implies that the truth of the child expression `part` has truth value `partIsTrue`. * * For example if the binary operation: - * ``` + * ```csharp * x && y * ``` * is true, `x` and `y` must also be true, so `impliesValue(x, true, true)` and @@ -341,7 +341,7 @@ class IRGuardCondition extends Instruction { * predecessors. For example, in the following situation, an inference can be made about the * value of `x` at the end of the `if` statement, but there is no block which is controlled by * the `if` statement when `x >= y`. - * ``` + * ```csharp * if (x < y) { * x = y; * } diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IRUtilities.qll b/csharp/ql/src/experimental/ir/internal/IRUtilities.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/internal/IRUtilities.qll rename to csharp/ql/src/experimental/ir/internal/IRUtilities.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll b/csharp/ql/src/experimental/ir/internal/IntegerConstant.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll rename to csharp/ql/src/experimental/ir/internal/IntegerConstant.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerInterval.qll b/csharp/ql/src/experimental/ir/internal/IntegerInterval.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/internal/IntegerInterval.qll rename to csharp/ql/src/experimental/ir/internal/IntegerInterval.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerPartial.qll b/csharp/ql/src/experimental/ir/internal/IntegerPartial.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/internal/IntegerPartial.qll rename to csharp/ql/src/experimental/ir/internal/IntegerPartial.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/Overlap.qll b/csharp/ql/src/experimental/ir/internal/Overlap.qll similarity index 56% rename from csharp/ql/src/semmle/code/csharp/ir/internal/Overlap.qll rename to csharp/ql/src/experimental/ir/internal/Overlap.qll index 8ce0549b2b4d..f9a0c574f8c3 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/Overlap.qll +++ b/csharp/ql/src/experimental/ir/internal/Overlap.qll @@ -3,18 +3,33 @@ private newtype TOverlap = TMustTotallyOverlap() or TMustExactlyOverlap() +/** + * Represents a possible overlap between two memory ranges. + */ abstract class Overlap extends TOverlap { abstract string toString(); } +/** + * Represents a partial overlap between two memory ranges, which may or may not + * actually occur in practice. + */ class MayPartiallyOverlap extends Overlap, TMayPartiallyOverlap { final override string toString() { result = "MayPartiallyOverlap" } } +/** + * Represents an overlap in which the first memory range is known to include all + * bits of the second memory range, but may be larger or have a different type. + */ class MustTotallyOverlap extends Overlap, TMustTotallyOverlap { final override string toString() { result = "MustTotallyOverlap" } } +/** + * Represents an overlap between two memory ranges that have the same extent and + * the same type. + */ class MustExactlyOverlap extends Overlap, TMustExactlyOverlap { final override string toString() { result = "MustExactlyOverlap" } } diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/TempVariableTag.qll b/csharp/ql/src/experimental/ir/internal/TempVariableTag.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/internal/TempVariableTag.qll rename to csharp/ql/src/experimental/ir/internal/TempVariableTag.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/Bound.qll b/csharp/ql/src/experimental/ir/rangeanalysis/Bound.qll similarity index 96% rename from csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/Bound.qll rename to csharp/ql/src/experimental/ir/rangeanalysis/Bound.qll index 8cde0baddfc5..c79c199832bc 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/Bound.qll +++ b/csharp/ql/src/experimental/ir/rangeanalysis/Bound.qll @@ -1,6 +1,6 @@ import csharp -private import semmle.code.csharp.ir.IR -private import semmle.code.csharp.ir.ValueNumbering +private import experimental.ir.IR +private import experimental.ir.ValueNumbering private newtype TBound = TBoundZero() or diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll b/csharp/ql/src/experimental/ir/rangeanalysis/RangeAnalysis.qll similarity index 99% rename from csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll rename to csharp/ql/src/experimental/ir/rangeanalysis/RangeAnalysis.qll index e3403728633d..ccc6b9ea30e4 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll +++ b/csharp/ql/src/experimental/ir/rangeanalysis/RangeAnalysis.qll @@ -10,7 +10,7 @@ /* * This library tackles range analysis as a flow problem. Consider e.g.: - * ``` + * ```csharp * len = arr.length; * if (x < len) { ... y = x-1; ... y ... } * ``` @@ -68,9 +68,9 @@ */ import csharp -private import semmle.code.csharp.ir.IR -private import semmle.code.csharp.ir.internal.IRGuards -private import semmle.code.csharp.ir.ValueNumbering +private import experimental.ir.IR +private import experimental.ir.internal.IRGuards +private import experimental.ir.ValueNumbering private import RangeUtils private import SignAnalysis import Bound diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeUtils.qll b/csharp/ql/src/experimental/ir/rangeanalysis/RangeUtils.qll similarity index 96% rename from csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeUtils.qll rename to csharp/ql/src/experimental/ir/rangeanalysis/RangeUtils.qll index f3b94c4ef011..4a7f1d698406 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeUtils.qll +++ b/csharp/ql/src/experimental/ir/rangeanalysis/RangeUtils.qll @@ -1,7 +1,7 @@ import csharp -private import semmle.code.csharp.ir.IR +private import experimental.ir.IR // TODO: move this dependency -import semmle.code.csharp.ir.internal.IntegerConstant +import experimental.ir.internal.IntegerConstant // TODO: move this out of test code language[monotonicAggregates] diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll b/csharp/ql/src/experimental/ir/rangeanalysis/SignAnalysis.qll similarity index 99% rename from csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll rename to csharp/ql/src/experimental/ir/rangeanalysis/SignAnalysis.qll index 366a1ca047c6..44548e0517a3 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll +++ b/csharp/ql/src/experimental/ir/rangeanalysis/SignAnalysis.qll @@ -7,9 +7,9 @@ */ import csharp -private import semmle.code.csharp.ir.IR -private import semmle.code.csharp.ir.internal.IRGuards -private import semmle.code.csharp.ir.ValueNumbering +private import experimental.ir.IR +private import experimental.ir.internal.IRGuards +private import experimental.ir.ValueNumbering private import SignAnalysisCached private newtype TSign = diff --git a/csharp/ql/src/external/CodeDuplication.qll b/csharp/ql/src/external/CodeDuplication.qll index 53ff9e91c1cc..f4165e599e8f 100644 --- a/csharp/ql/src/external/CodeDuplication.qll +++ b/csharp/ql/src/external/CodeDuplication.qll @@ -66,9 +66,9 @@ class SimilarBlock extends Copy, @similarity { } } -Method sourceMethod() { method_location(result, _) and numlines(result, _, _, _) } +private Method sourceMethod() { method_location(result, _) and numlines(result, _, _, _) } -int numberOfSourceMethods(Class c) { +private int numberOfSourceMethods(Class c) { result = count(Method m | m = sourceMethod() and m.getDeclaringType() = c) } @@ -97,6 +97,7 @@ private predicate duplicateStatement(Method m1, Method m2, Stmt s1, Stmt s2) { ) } +/** Holds if `duplicate` number of statements are duplicated in the methods. */ predicate duplicateStatements(Method m1, Method m2, int duplicate, int total) { duplicate = strictcount(Stmt s | duplicateStatement(m1, m2, s, _)) and total = strictcount(statementInMethod(m1)) @@ -109,7 +110,7 @@ predicate duplicateMethod(Method m, Method other) { exists(int total | duplicateStatements(m, other, total, total)) } -predicate similarLines(File f, int line) { +private predicate similarLines(File f, int line) { exists(SimilarBlock b | b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()]) } @@ -148,7 +149,7 @@ private predicate similarLinesCovered(File f, int coveredLines, File otherFile) ) } -predicate duplicateLines(File f, int line) { +private predicate duplicateLines(File f, int line) { exists(DuplicateBlock b | b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()] ) @@ -189,6 +190,7 @@ private predicate duplicateLinesCovered(File f, int coveredLines, File otherFile ) } +/** Holds if the two files are not duplicated but have more than 80% similar lines. */ predicate similarFiles(File f, File other, int percent) { exists(int covered, int total | similarLinesCovered(f, covered, other) and @@ -199,6 +201,7 @@ predicate similarFiles(File f, File other, int percent) { not duplicateFiles(f, other, _) } +/** Holds if the two files have more than 70% duplicated lines. */ predicate duplicateFiles(File f, File other, int percent) { exists(int covered, int total | duplicateLinesCovered(f, covered, other) and @@ -209,7 +212,7 @@ predicate duplicateFiles(File f, File other, int percent) { } pragma[noopt] -predicate duplicateAnonymousClass(AnonymousClass c, AnonymousClass other) { +private predicate duplicateAnonymousClass(AnonymousClass c, AnonymousClass other) { exists(int numDup | numDup = strictcount(Method m1 | @@ -248,6 +251,7 @@ private predicate mostlyDuplicateClassBase(Class c, Class other, int numDup, int not other instanceof AnonymousClass } +/** Holds if the methods in the two classes are more than 80% duplicated. */ predicate mostlyDuplicateClass(Class c, Class other, string message) { exists(int numDup, int total | mostlyDuplicateClassBase(c, other, numDup, total) and @@ -272,19 +276,28 @@ predicate mostlyDuplicateClass(Class c, Class other, string message) { ) } +/** Holds if the two files are similar or duplicated. */ predicate fileLevelDuplication(File f, File other) { similarFiles(f, other, _) or duplicateFiles(f, other, _) } +/** + * Holds if the two classes are duplicated anonymous classes or more than 80% of + * their methods are duplicated. + */ predicate classLevelDuplication(Class c, Class other) { duplicateAnonymousClass(c, other) or mostlyDuplicateClass(c, other, _) } -Element whitelistedDuplicateElement() { +private Element whitelistedDuplicateElement() { result instanceof UsingNamespaceDirective or result instanceof UsingStaticDirective } +/** + * Holds if the `line` in the `file` contains an element, such as a `using` + * directive, that is not considered for code duplication. + */ predicate whitelistedLineForDuplication(File file, int line) { exists(Location loc | loc = whitelistedDuplicateElement().getLocation() | line = loc.getStartLine() and file = loc.getFile() diff --git a/csharp/ql/src/external/DuplicateMethod.ql b/csharp/ql/src/external/DuplicateMethod.ql index 57255ce51d01..371315cd4e66 100644 --- a/csharp/ql/src/external/DuplicateMethod.ql +++ b/csharp/ql/src/external/DuplicateMethod.ql @@ -1,4 +1,5 @@ /** + * @deprecated * @name Duplicate method * @description There is another identical implementation of this method. Extract the code to a common superclass or delegate to improve sharing. * @kind problem diff --git a/csharp/ql/src/external/MostlyDuplicateClass.ql b/csharp/ql/src/external/MostlyDuplicateClass.ql index fd4fc87c176b..7b7d5ef3eff0 100644 --- a/csharp/ql/src/external/MostlyDuplicateClass.ql +++ b/csharp/ql/src/external/MostlyDuplicateClass.ql @@ -1,4 +1,5 @@ /** + * @deprecated * @name Duplicate class * @description More than 80% of the methods in this class are duplicated in another class. Create a common supertype to improve code sharing. * @kind problem diff --git a/csharp/ql/src/external/MostlyDuplicateFile.ql b/csharp/ql/src/external/MostlyDuplicateFile.ql index 0100e94bc7c2..2dbc2e17ffbe 100644 --- a/csharp/ql/src/external/MostlyDuplicateFile.ql +++ b/csharp/ql/src/external/MostlyDuplicateFile.ql @@ -1,4 +1,5 @@ /** + * @deprecated * @name Mostly duplicate file * @description There is another file that shares a lot of the code with this file. Merge the two files to improve maintainability. * @kind problem diff --git a/csharp/ql/src/external/MostlyDuplicateMethod.ql b/csharp/ql/src/external/MostlyDuplicateMethod.ql index a7d01ed0ed99..aa0003c113b7 100644 --- a/csharp/ql/src/external/MostlyDuplicateMethod.ql +++ b/csharp/ql/src/external/MostlyDuplicateMethod.ql @@ -1,4 +1,5 @@ /** + * @deprecated * @name Mostly duplicate method * @description There is another method that shares a lot of the code with this method. Extract the code to a common superclass or delegate to improve sharing. * @kind problem diff --git a/csharp/ql/src/external/MostlySimilarFile.ql b/csharp/ql/src/external/MostlySimilarFile.ql index 1c175a72bbd0..a66df834aca6 100644 --- a/csharp/ql/src/external/MostlySimilarFile.ql +++ b/csharp/ql/src/external/MostlySimilarFile.ql @@ -1,4 +1,5 @@ /** + * @deprecated * @name Mostly similar file * @description There is another file that shares a lot of the code with this file. Notice that names of variables and types may have been changed. Merge the two files to improve maintainability. * @kind problem diff --git a/csharp/ql/src/external/examples/filters/BumpMetricBy10.ql b/csharp/ql/src/external/examples/filters/BumpMetricBy10.ql deleted file mode 100644 index 209d580bc19b..000000000000 --- a/csharp/ql/src/external/examples/filters/BumpMetricBy10.ql +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @name Edit the value of a metric - * @description Add 10 to a metric's value - * @deprecated - */ - -import csharp -import external.MetricFilter - -from MetricResult res -select res, res.getValue() + 10 diff --git a/csharp/ql/src/external/examples/filters/EditDefectMessage.ql b/csharp/ql/src/external/examples/filters/EditDefectMessage.ql deleted file mode 100644 index 4fbf41465504..000000000000 --- a/csharp/ql/src/external/examples/filters/EditDefectMessage.ql +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @name Edit the message of a query - * @description Change the string in the select to edit the message - * @deprecated - */ - -import csharp -import external.DefectFilter - -from DefectResult res -select res, "Filtered query result: " + res.getMessage() diff --git a/csharp/ql/src/external/examples/filters/ExcludeGeneratedCode.ql b/csharp/ql/src/external/examples/filters/ExcludeGeneratedCode.ql deleted file mode 100644 index 2a1257427b25..000000000000 --- a/csharp/ql/src/external/examples/filters/ExcludeGeneratedCode.ql +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @name Filter: removed results from generated code - * @description Shows how to exclude certain files or folders from results. - * @deprecated - */ - -import csharp -import external.DefectFilter - -predicate generatedFile(File f) { f.getAbsolutePath().matches("%generated%") } - -from DefectResult res -where not generatedFile(res.getFile()) -select res, res.getMessage() diff --git a/csharp/ql/src/external/examples/filters/FromSource.ql b/csharp/ql/src/external/examples/filters/FromSource.ql deleted file mode 100644 index 2f714ec2225a..000000000000 --- a/csharp/ql/src/external/examples/filters/FromSource.ql +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @name Filter: only keep results from source - * @description Shows how to filter for only certain files - * @deprecated - */ - -import csharp -import external.DefectFilter - -from DefectResult res -where res.getFile().fromSource() -select res, res.getMessage() diff --git a/csharp/ql/src/external/tests/DefectFromExternalData.ql b/csharp/ql/src/external/tests/DefectFromExternalData.ql deleted file mode 100644 index 70557f357a38..000000000000 --- a/csharp/ql/src/external/tests/DefectFromExternalData.ql +++ /dev/null @@ -1,19 +0,0 @@ -/** - * @name Defect from external data - * @description Insert description here... - * @kind problem - * @problem.severity warning - * @deprecated - */ - -import csharp -import external.ExternalArtifact - -// custom://[FileUtil][2011-01-02][false][1.1][6][Message 2] -from ExternalData d, File u -where - d.getQueryPath() = "external-data.ql" and - u.getStem() = d.getField(0) -select u, - d.getField(5) + ", " + d.getFieldAsDate(1) + ", " + d.getField(2) + ", " + d.getFieldAsFloat(3) + - ", " + d.getFieldAsInt(4) + ": " + d.getNumFields() diff --git a/csharp/ql/src/external/tests/DefectFromExternalDefect.ql b/csharp/ql/src/external/tests/DefectFromExternalDefect.ql deleted file mode 100644 index 57138a6879ff..000000000000 --- a/csharp/ql/src/external/tests/DefectFromExternalDefect.ql +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @name Defect from external defect - * @description Create a defect from external data - * @kind problem - * @problem.severity warning - * @deprecated - */ - -import csharp -import external.ExternalArtifact - -class DuplicateCode extends ExternalDefect { - DuplicateCode() { getQueryPath() = "duplicate-code/duplicateCode.ql" } -} - -from DuplicateCode d -select d, "External Defect " + d.getMessage() diff --git a/csharp/ql/src/external/tests/DefectFromExternalMetric.ql b/csharp/ql/src/external/tests/DefectFromExternalMetric.ql deleted file mode 100644 index 88d38d5f00b6..000000000000 --- a/csharp/ql/src/external/tests/DefectFromExternalMetric.ql +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @name Defect from external metric - * @description Create a defect from external data - * @kind problem - * @problem.severity warning - * @deprecated - */ - -import csharp -import external.ExternalArtifact - -from ExternalMetric m, File f -where - m.getQueryPath() = "filesBuilt.ql" and - m.getValue() = 1.0 and - m.getFile() = f -select f, "File is built" diff --git a/csharp/ql/src/external/tests/MetricFilter.ql b/csharp/ql/src/external/tests/MetricFilter.ql deleted file mode 100644 index 9f79465be75e..000000000000 --- a/csharp/ql/src/external/tests/MetricFilter.ql +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @name Metric filter - * @description Only include results in large files (200) lines of code. - * @kind treemap - * @deprecated - */ - -import csharp -import external.MetricFilter - -from MetricResult res -where res.getFile().getNumberOfLinesOfCode() > 200 -select res, res.getValue() diff --git a/csharp/ql/src/external/tests/MetricFromExternalDefect.ql b/csharp/ql/src/external/tests/MetricFromExternalDefect.ql deleted file mode 100644 index 4894de287618..000000000000 --- a/csharp/ql/src/external/tests/MetricFromExternalDefect.ql +++ /dev/null @@ -1,21 +0,0 @@ -/** - * @name Metric from external defect - * @description Find number of duplicate code entries in a file - * @treemap.warnOn lowValues - * @metricType file - * @kind treemap - * @deprecated - */ - -import csharp -import external.ExternalArtifact - -class DuplicateCode extends ExternalDefect { - DuplicateCode() { getQueryPath() = "duplicate-code/duplicateCode.ql" } -} - -predicate numDuplicateEntries(File f, int i) { i = count(DuplicateCode d | d.getFile() = f) } - -from File f, int i -where numDuplicateEntries(f, i) -select f, i diff --git a/csharp/ql/src/external/tests/MetricFromExternalMetric.ql b/csharp/ql/src/external/tests/MetricFromExternalMetric.ql deleted file mode 100644 index 4d2ab4088ae5..000000000000 --- a/csharp/ql/src/external/tests/MetricFromExternalMetric.ql +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @name Metric from external metric - * @description Each file in a folder gets as metric value the number of files built in that folder - * @treemap.warnOn lowValues - * @metricType file - * @kind treemap - * @deprecated - */ - -import csharp -import external.ExternalArtifact - -predicate numBuiltFiles(Folder fold, int i) { - i = - count(File f | - exists(ExternalMetric m | - m.getQueryPath() = "filesBuilt.ql" and - m.getValue() = 1.0 and - m.getFile() = f - ) and - f.getParentContainer() = fold - ) -} - -from File f, int i -where numBuiltFiles(f.getParentContainer(), i) -select f, i diff --git a/csharp/ql/src/printAst.ql b/csharp/ql/src/printAst.ql new file mode 100644 index 000000000000..b02193b257ac --- /dev/null +++ b/csharp/ql/src/printAst.ql @@ -0,0 +1,28 @@ +/** + * @name Print AST + * @description Outputs a representation of a file's Abstract Syntax Tree. This + * query is used by the VS Code extension. + * @id csharp/print-ast + * @kind graph + * @tags ide-contextual-queries/print-ast + */ + +import csharp +import semmle.code.csharp.PrintAst +import definitions + +/** + * The source file to generate an AST from. + */ +external string selectedSourceFile(); + +class PrintAstConfigurationOverride extends PrintAstConfiguration { + /** + * Holds if the location matches the selected file in the VS Code extension and + * the element is `fromSource`. + */ + override predicate shouldPrint(Element e, Location l) { + super.shouldPrint(e, l) and + l.getFile() = getEncodedFile(selectedSourceFile()) + } +} diff --git a/csharp/ql/src/semmle/code/asp/AspNet.qll b/csharp/ql/src/semmle/code/asp/AspNet.qll index c7ed51bb4842..0666c5eb782d 100644 --- a/csharp/ql/src/semmle/code/asp/AspNet.qll +++ b/csharp/ql/src/semmle/code/asp/AspNet.qll @@ -32,7 +32,7 @@ class AspAttribute extends AspElement, @asp_attribute { } /** * An open tag, for example the tag on line 1 in * - * ``` + * ```html * @@ -67,7 +67,7 @@ class AspOpenTag extends AspElement, @asp_open_tag { /** * A close tag, for example the tag on line 3 in * - * ``` + * ```html * @@ -123,7 +123,7 @@ class AspServerComment extends AspComment { /** * A data-binding expression, for example `<%# myArray %>` in * - * ``` + * ```html * * ``` */ diff --git a/csharp/ql/src/semmle/code/cil/Access.qll b/csharp/ql/src/semmle/code/cil/Access.qll index 263e527dfec9..e42a883a2e5f 100644 --- a/csharp/ql/src/semmle/code/cil/Access.qll +++ b/csharp/ql/src/semmle/code/cil/Access.qll @@ -31,6 +31,7 @@ class ReadRefAccess extends ReadAccess, ReadRef { } /** An instruction that writes a variable. */ class WriteAccess extends VariableAccess, @cil_write_access { + /** Gets the expression whose value is used in this variable write. */ Expr getExpr() { none() } } diff --git a/csharp/ql/src/semmle/code/cil/BasicBlock.qll b/csharp/ql/src/semmle/code/cil/BasicBlock.qll index ef584e73bbee..459bb667e6f1 100644 --- a/csharp/ql/src/semmle/code/cil/BasicBlock.qll +++ b/csharp/ql/src/semmle/code/cil/BasicBlock.qll @@ -23,7 +23,7 @@ class BasicBlock extends Cached::TBasicBlockStart { * * Example: * - * ``` + * ```csharp * if (x < 0) * x = -x; * ``` @@ -41,7 +41,7 @@ class BasicBlock extends Cached::TBasicBlockStart { * * Example: * - * ``` + * ```csharp * if (!(x >= 0)) * x = -x; * ``` @@ -75,7 +75,7 @@ class BasicBlock extends Cached::TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * if (s == null) * throw new ArgumentNullException(nameof(s)); @@ -97,7 +97,7 @@ class BasicBlock extends Cached::TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * if (s == null) * throw new ArgumentNullException(nameof(s)); @@ -124,7 +124,7 @@ class BasicBlock extends Cached::TBasicBlockStart { * * Example: * - * ``` + * ```csharp * if (x < 0) { * x = -x; * if (x > 10) @@ -158,7 +158,7 @@ class BasicBlock extends Cached::TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * if (s == null) * throw new ArgumentNullException(nameof(s)); @@ -182,7 +182,7 @@ class BasicBlock extends Cached::TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * try { * return s.Length; @@ -207,7 +207,7 @@ class BasicBlock extends Cached::TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * try { * return s.Length; @@ -353,7 +353,7 @@ class ConditionBlock extends BasicBlock { * all predecessors of `this.getATrueSuccessor()` are either `this` or dominated by `this.getATrueSuccessor()`. * * For example, in the following C# snippet: - * ``` + * ```csharp * if (x) * controlled; * false_successor; @@ -361,7 +361,7 @@ class ConditionBlock extends BasicBlock { * ``` * `false_successor` dominates `uncontrolled`, but not all of its predecessors are `this` (`if (x)`) * or dominated by itself. Whereas in the following code: - * ``` + * ```csharp * if (x) * while (controlled) * also_controlled; diff --git a/csharp/ql/src/semmle/code/cil/Instructions.qll b/csharp/ql/src/semmle/code/cil/Instructions.qll index 3f3011f10b3d..438c16518f89 100644 --- a/csharp/ql/src/semmle/code/cil/Instructions.qll +++ b/csharp/ql/src/semmle/code/cil/Instructions.qll @@ -1,90 +1,106 @@ /** * Provides classes representing individual opcodes. + * + * See ECMA-335 (https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-335.pdf) + * pages 32-101 for a detailed explanation of these instructions. */ private import CIL private import semmle.code.dotnet.Variable as DotNet module Opcodes { - // Literals + /** An `ldc.i4.m1` instruction. */ class Ldc_i4_m1 extends IntLiteral, @cil_ldc_i4_m1 { override string getOpcodeName() { result = "ldc.i4.m1" } override string getValue() { result = "-1" } } + /** An `ldc.i4.0` instruction. */ class Ldc_i4_0 extends IntLiteral, @cil_ldc_i4_0 { override string getOpcodeName() { result = "ldc.i4.0" } override string getValue() { result = "0" } } + /** An `ldc.i4.1` instruction. */ class Ldc_i4_1 extends IntLiteral, @cil_ldc_i4_1 { override string getOpcodeName() { result = "ldc.i4.1" } override string getValue() { result = "1" } } + /** An `ldc.i4.2` instruction. */ class Ldc_i4_2 extends IntLiteral, @cil_ldc_i4_2 { override string getOpcodeName() { result = "ldc.i4.2" } override string getValue() { result = "2" } } + /** An `ldc.i4.3` instruction. */ class Ldc_i4_3 extends IntLiteral, @cil_ldc_i4_3 { override string getOpcodeName() { result = "ldc.i4.3" } override string getValue() { result = "3" } } + /** An `ldc.i4.4` instruction. */ class Ldc_i4_4 extends IntLiteral, @cil_ldc_i4_4 { override string getOpcodeName() { result = "ldc.i4.4" } override string getValue() { result = "4" } } + /** An `ldc.i4.5` instruction. */ class Ldc_i4_5 extends IntLiteral, @cil_ldc_i4_5 { override string getOpcodeName() { result = "ldc.i4.5" } override string getValue() { result = "5" } } + /** An `ldc.i4.6` instruction. */ class Ldc_i4_6 extends IntLiteral, @cil_ldc_i4_6 { override string getOpcodeName() { result = "ldc.i4.6" } override string getValue() { result = "6" } } + /** An `ldc.i4.7` instruction. */ class Ldc_i4_7 extends IntLiteral, @cil_ldc_i4_7 { override string getOpcodeName() { result = "ldc.i4.7" } override string getValue() { result = "7" } } + /** An `ldc.i4.8` instruction. */ class Ldc_i4_8 extends IntLiteral, @cil_ldc_i4_8 { override string getOpcodeName() { result = "ldc.i4.8" } override string getValue() { result = "8" } } + /** An `ldc.i4` instruction. */ class Ldc_i4 extends IntLiteral, @cil_ldc_i4 { override string getOpcodeName() { result = "ldc.i4" } override string getExtra() { result = getValue() } } + /** An `ldc.i8` instruction. */ class Ldc_i8 extends IntLiteral, @cil_ldc_i8 { override string getOpcodeName() { result = "ldc.i8" } override string getExtra() { result = getValue() } } + /** An `ldc.i4.s` instruction. */ class Ldc_i4_s extends IntLiteral, @cil_ldc_i4_s { override string getOpcodeName() { result = "ldc.i4.s" } override string getExtra() { result = getValue() } } + /** An `ldnull` instruction. */ class Ldnull extends Literal, @cil_ldnull { override string getOpcodeName() { result = "ldnull" } @@ -95,6 +111,7 @@ module Opcodes { override Type getType() { result instanceof ObjectType } } + /** An `ldc.r4` instruction. */ class Ldc_r4 extends FloatLiteral, @cil_ldc_r4 { override string getOpcodeName() { result = "ldc.r4" } @@ -103,6 +120,7 @@ module Opcodes { override Type getType() { result instanceof FloatType } } + /** An `ldc.r8` instruction. */ class Ldc_r8 extends FloatLiteral, @cil_ldc_r8 { override string getOpcodeName() { result = "ldc.r8" } @@ -111,59 +129,72 @@ module Opcodes { override Type getType() { result instanceof DoubleType } } - // Arithmetic operations + /** An `add` instruction. */ class Add extends BinaryArithmeticExpr, @cil_add { override string getOpcodeName() { result = "add" } } + /** An `add.ovf` instruction. */ class Add_ovf extends BinaryArithmeticExpr, @cil_add_ovf { override string getOpcodeName() { result = "add.ovf" } } + /** An `add.ovf.un` instruction. */ class Add_ovf_un extends BinaryArithmeticExpr, @cil_add_ovf_un { override string getOpcodeName() { result = "add.ovf.un" } } + /** A `sub` instruction. */ class Sub extends BinaryArithmeticExpr, @cil_sub { override string getOpcodeName() { result = "sub" } } + /** A `sub.ovf` instruction. */ class Sub_ovf extends BinaryArithmeticExpr, @cil_sub_ovf { override string getOpcodeName() { result = "sub.ovf" } } + /** A `sub.ovf.un` instruction. */ class Sub_ovf_un extends BinaryArithmeticExpr, @cil_sub_ovf_un { override string getOpcodeName() { result = "sub.ovf.un" } } + /** A `mul` instruction. */ class Mul extends BinaryArithmeticExpr, @cil_mul { override string getOpcodeName() { result = "mul" } } + /** A `mul.ovf` instruction. */ class Mul_ovf extends BinaryArithmeticExpr, @cil_mul_ovf { override string getOpcodeName() { result = "mul.ovf" } } + /** A `mul.ovf.un` instruction. */ class Mul_ovf_un extends BinaryArithmeticExpr, @cil_mul_ovf_un { override string getOpcodeName() { result = "mul.ovf.un" } } + /** A `div` instruction. */ class Div extends BinaryArithmeticExpr, @cil_div { override string getOpcodeName() { result = "div" } } + /** A `div.un` instruction. */ class Div_un extends BinaryArithmeticExpr, @cil_div_un { override string getOpcodeName() { result = "div.un" } } + /** A `rem` instruction. */ class Rem extends BinaryArithmeticExpr, @cil_rem { override string getOpcodeName() { result = "rem" } } + /** A `rem.un` instruction. */ class Rem_un extends BinaryArithmeticExpr, @cil_rem_un { override string getOpcodeName() { result = "rem.un" } } + /** A `neg` instruction. */ class Neg extends UnaryExpr, @cil_neg { override string getOpcodeName() { result = "neg" } @@ -174,46 +205,54 @@ module Opcodes { } } - // Binary operations + /** An `and` instruction. */ class And extends BinaryBitwiseOperation, @cil_and { override string getOpcodeName() { result = "and" } } + /** An `or` instruction. */ class Or extends BinaryBitwiseOperation, @cil_or { override string getOpcodeName() { result = "or" } } + /** An `xor` instruction. */ class Xor extends BinaryBitwiseOperation, @cil_xor { override string getOpcodeName() { result = "xor" } } + /** A `not` instruction. */ class Not extends UnaryBitwiseOperation, @cil_not { override string getOpcodeName() { result = "not" } } + /** A `shl` instruction. */ class Shl extends BinaryBitwiseOperation, @cil_shl { override string getOpcodeName() { result = "shl" } } + /** A `shr` instruction. */ class Shr extends BinaryBitwiseOperation, @cil_shr { override string getOpcodeName() { result = "shr" } } + /** A `shr.un` instruction. */ class Shr_un extends BinaryBitwiseOperation, @cil_shr_un { override string getOpcodeName() { result = "shr.un" } } - // Binary comparison operations + /** A `ceq` instruction. */ class Ceq extends ComparisonOperation, @cil_ceq { override string getOpcodeName() { result = "ceq" } } + /** A `pop` instruction. */ class Pop extends Instruction, @cil_pop { override string getOpcodeName() { result = "pop" } override int getPopCount() { result = 1 } } + /** A `dup` instruction. */ class Dup extends Expr, @cil_dup { override string getOpcodeName() { result = "dup" } @@ -224,6 +263,7 @@ module Opcodes { override Type getType() { result = getOperand(0).getType() } } + /** A `ret` instruction. */ class Ret extends Return, @cil_ret { override string getOpcodeName() { result = "ret" } @@ -234,10 +274,12 @@ module Opcodes { } } + /** A `nop` instruction. */ class Nop extends Instruction, @cil_nop { override string getOpcodeName() { result = "nop" } } + /** An `ldstr` instruction. */ class Ldstr extends StringLiteral, @cil_ldstr { override string getOpcodeName() { result = "ldstr" } @@ -246,111 +288,137 @@ module Opcodes { override Type getType() { result instanceof StringType } } - // Control flow + /** A `br` instruction. */ class Br extends UnconditionalBranch, @cil_br { override string getOpcodeName() { result = "br" } } + /** A `br.s` instruction. */ class Br_s extends UnconditionalBranch, @cil_br_s { override string getOpcodeName() { result = "br.s" } } + /** A `brfalse.s` instruction. */ class Brfalse_s extends UnaryBranch, @cil_brfalse_s { override string getOpcodeName() { result = "brfalse.s" } } + /** A `brfalse` instruction. */ class Brfalse extends UnaryBranch, @cil_brfalse { override string getOpcodeName() { result = "brfalse" } } + /** A `brtrue.s` instruction. */ class Brtrue_s extends UnaryBranch, @cil_brtrue_s { override string getOpcodeName() { result = "brtrue.s" } } + /** A `brtrue` instruction. */ class Brtrue extends UnaryBranch, @cil_brtrue { override string getOpcodeName() { result = "brtrue" } } + /** A `blt.s` instruction. */ class Blt_s extends BinaryBranch, @cil_blt_s { override string getOpcodeName() { result = "blt.s" } } + /** A `blt` instruction. */ class Blt extends BinaryBranch, @cil_blt { override string getOpcodeName() { result = "blt" } } + /** A `blt.un.s` instruction. */ class Blt_un_s extends BinaryBranch, @cil_blt_un_s { override string getOpcodeName() { result = "blt.un.s" } } + /** A `blt.un` instruction. */ class Blt_un extends BinaryBranch, @cil_blt_un { override string getOpcodeName() { result = "blt.un" } } + /** A `bgt.un` instruction. */ class Bgt_un extends BinaryBranch, @cil_bgt_un { override string getOpcodeName() { result = "bgt.un" } } + /** A `ble.un.s` instruction. */ class Ble_un_s extends BinaryBranch, @cil_ble_un_s { override string getOpcodeName() { result = "ble.un.s" } } + /** A `ble.un` instruction. */ class Ble_un extends BinaryBranch, @cil_ble_un { override string getOpcodeName() { result = "ble.un" } } + /** A `bge.s` instruction. */ class Bge_s extends BinaryBranch, @cil_bge_s { override string getOpcodeName() { result = "bge.s" } } + /** A `ble.un` instruction. */ class Bge_un extends BinaryBranch, @cil_bge_un { override string getOpcodeName() { result = "bge.un" } } + /** A `bge` instruction. */ class Bge extends BinaryBranch, @cil_bge { override string getOpcodeName() { result = "bge" } } + /** A `bne.un.s` instruction. */ class Bne_un_s extends BinaryBranch, @cil_bne_un_s { override string getOpcodeName() { result = "bne.un.s" } } + /** A `bne.un` instruction. */ class Bne_un extends BinaryBranch, @cil_bne_un { override string getOpcodeName() { result = "bne.un" } } + /** A `beq` instruction. */ class Beq extends BinaryBranch, @cil_beq { override string getOpcodeName() { result = "beq" } } + /** A `beq.s` instruction. */ class Beq_s extends BinaryBranch, @cil_beq_s { override string getOpcodeName() { result = "beq.s" } } + /** A `ble.s` instruction. */ class Ble_s extends BinaryBranch, @cil_ble_s { override string getOpcodeName() { result = "ble.s" } } + /** A `ble` instruction. */ class Ble extends BinaryBranch, @cil_ble { override string getOpcodeName() { result = "ble" } } + /** A `bgt.s` instruction. */ class Bgt_s extends BinaryBranch, @cil_bgt_s { override string getOpcodeName() { result = "bgt.s" } } + /** A `bgt` instruction. */ class Bgt extends BinaryBranch, @cil_bgt { override string getOpcodeName() { result = "bgt" } } + /** A `bgt.in.s` instruction. */ class Bgt_in_s extends BinaryBranch, @cil_bgt_un_s { - override string getOpcodeName() { result = "bgt.un.s" } + override string getOpcodeName() { result = "bgt.in.s" } } + /** A `bge.in.s` instruction. */ class Bge_in_s extends BinaryBranch, @cil_bge_un_s { override string getOpcodeName() { result = "bge.un.s" } } + /** A `switch` instruction. */ class Switch extends ConditionalBranch, @cil_switch { override string getOpcodeName() { result = "switch" } @@ -367,62 +435,73 @@ module Opcodes { } } + /** A `leave` instruction. */ class Leave_ extends Leave, @cil_leave { override string getOpcodeName() { result = "leave" } } + /** A `leave.s` instruction. */ class Leave_s extends Leave, @cil_leave_s { override string getOpcodeName() { result = "leave.s" } } + /** An `endfilter` instruction. */ class Endfilter extends Instruction, @cil_endfilter { override string getOpcodeName() { result = "endfilter" } } + /** An `endfinally` instruction. */ class Endfinally extends Instruction, @cil_endfinally { override string getOpcodeName() { result = "endfinally" } override predicate canFlowNext() { none() } } - // Comparisons (not jumps) + /** A `cgt.un` instruction. */ class Cgt_un extends ComparisonOperation, @cil_cgt_un { override string getOpcodeName() { result = "cgt.un" } } + /** A `cgt` instruction. */ class Cgt extends ComparisonOperation, @cil_cgt { override string getOpcodeName() { result = "cgt" } } + /** A `clt.un` instruction. */ class Clt_un extends ComparisonOperation, @cil_clt_un { - override string getOpcodeName() { result = "cgt.un" } + override string getOpcodeName() { result = "clt.un" } } + /** A `clt` instruction. */ class Clt extends ComparisonOperation, @cil_clt { override string getOpcodeName() { result = "clt" } } - // Calls + /** A `call` instruction. */ class Call_ extends Call, @cil_call { override string getOpcodeName() { result = "call" } } + /** A `callvirt` instruction. */ class Callvirt extends Call, @cil_callvirt { override string getOpcodeName() { result = "callvirt" } override predicate isVirtual() { any() } } + /** A `tail.` instruction. */ class Tail extends Instruction, @cil_tail { override string getOpcodeName() { result = "tail." } } + /** A `jmp` instruction. */ class Jmp extends Call, @cil_jmp { override string getOpcodeName() { result = "jmp" } override predicate isTailCall() { any() } } + /** An `isinst` instruction. */ class Isinst extends UnaryExpr, @cil_isinst { override string getOpcodeName() { result = "isinst" } @@ -434,6 +513,7 @@ module Opcodes { override string getExtra() { result = getTestedType().getQualifiedName() } } + /** A `castclass` instruction. */ class Castclass extends UnaryExpr, @cil_castclass { override string getOpcodeName() { result = "castclass" } @@ -445,67 +525,77 @@ module Opcodes { override string getExtra() { result = getTestedType().getQualifiedName() } } - // Locals + /** An `stloc.0` instruction. */ class Stloc_0 extends LocalVariableWriteAccess, @cil_stloc_0 { override string getOpcodeName() { result = "stloc.0" } override LocalVariable getTarget() { result = getImplementation().getLocalVariable(0) } } + /** An `stloc.1` instruction. */ class Stloc_1 extends LocalVariableWriteAccess, @cil_stloc_1 { override string getOpcodeName() { result = "stloc.1" } override LocalVariable getTarget() { result = getImplementation().getLocalVariable(1) } } + /** An `stloc.2` instruction. */ class Stloc_2 extends LocalVariableWriteAccess, @cil_stloc_2 { override string getOpcodeName() { result = "stloc.2" } override LocalVariable getTarget() { result = getImplementation().getLocalVariable(2) } } + /** An `stloc.3` instruction. */ class Stloc_3 extends LocalVariableWriteAccess, @cil_stloc_3 { override string getOpcodeName() { result = "stloc.3" } override LocalVariable getTarget() { result = getImplementation().getLocalVariable(3) } } + /** An `stloc.s` instruction. */ class Stloc_s extends LocalVariableWriteAccess, @cil_stloc_s { override string getOpcodeName() { result = "stloc.s" } override LocalVariable getTarget() { cil_access(this, result) } } + /** An `stloc` instruction. */ class Stloc extends LocalVariableWriteAccess, @cil_stloc { override string getOpcodeName() { result = "stloc" } override LocalVariable getTarget() { cil_access(this, result) } } + /** An `ldloc.0` instruction. */ class Ldloc_0 extends LocalVariableReadAccess, @cil_ldloc_0 { override string getOpcodeName() { result = "ldloc.0" } override LocalVariable getTarget() { result = getImplementation().getLocalVariable(0) } } + /** An `ldloc.1` instruction. */ class Ldloc_1 extends LocalVariableReadAccess, @cil_ldloc_1 { override string getOpcodeName() { result = "ldloc.1" } override LocalVariable getTarget() { result = getImplementation().getLocalVariable(1) } } + /** An `ldloc.2` instruction. */ class Ldloc_2 extends LocalVariableReadAccess, @cil_ldloc_2 { override string getOpcodeName() { result = "ldloc.2" } override LocalVariable getTarget() { result = getImplementation().getLocalVariable(2) } } + /** An `ldloc.3` instruction. */ class Ldloc_3 extends LocalVariableReadAccess, @cil_ldloc_3 { override string getOpcodeName() { result = "ldloc.3" } override LocalVariable getTarget() { result = getImplementation().getLocalVariable(3) } } + /** An `ldloc.s` instruction. */ class Ldloc_s extends LocalVariableReadAccess, @cil_ldloc_s { override string getOpcodeName() { result = "ldloc.s" } @@ -514,6 +604,7 @@ module Opcodes { override string getExtra() { result = "L" + getTarget().getIndex() } } + /** An `ldloca.s` instruction. */ class Ldloca_s extends LocalVariableReadAccess, ReadRefAccess, @cil_ldloca_s { override string getOpcodeName() { result = "ldloca.s" } @@ -522,6 +613,7 @@ module Opcodes { override string getExtra() { result = "L" + getTarget().getIndex() } } + /** An `ldloc` instruction. */ class Ldloc extends LocalVariableReadAccess, @cil_ldloc { override string getOpcodeName() { result = "ldloc" } @@ -530,31 +622,35 @@ module Opcodes { override string getExtra() { result = "L" + getTarget().getIndex() } } - // Arguments + /** An `ldarg.0` instruction. */ class Ldarg_0 extends ParameterReadAccess, @cil_ldarg_0 { override string getOpcodeName() { result = "ldarg.0" } override Parameter getTarget() { result = getImplementation().getMethod().getRawParameter(0) } } + /** An `ldarg.1` instruction. */ class Ldarg_1 extends ParameterReadAccess, @cil_ldarg_1 { override string getOpcodeName() { result = "ldarg.1" } override Parameter getTarget() { result = getImplementation().getMethod().getRawParameter(1) } } + /** An `ldarg.2` instruction. */ class Ldarg_2 extends ParameterReadAccess, @cil_ldarg_2 { override string getOpcodeName() { result = "ldarg.2" } override Parameter getTarget() { result = getImplementation().getMethod().getRawParameter(2) } } + /** An `ldarg.3` instruction. */ class Ldarg_3 extends ParameterReadAccess, @cil_ldarg_3 { override string getOpcodeName() { result = "ldarg.3" } override Parameter getTarget() { result = getImplementation().getMethod().getRawParameter(3) } } + /** An `ldarg.s` instruction. */ class Ldarg_s extends ParameterReadAccess, @cil_ldarg_s { override string getOpcodeName() { result = "ldarg.s" } @@ -563,25 +659,28 @@ module Opcodes { override string getExtra() { result = this.getTarget().getIndex().toString() } } + /** An `ldarg` instruction. */ class Ldarg extends ParameterReadAccess, @cil_ldarg { override string getOpcodeName() { result = "ldarg" } override Parameter getTarget() { cil_access(this, result) } } + /** An `ldarga.s` instruction. */ class Ldarga_s extends ParameterReadAccess, ReadRefAccess, @cil_ldarga_s { override string getOpcodeName() { result = "ldarga.s" } override Parameter getTarget() { cil_access(this, result) } } + /** An `starg.s` instruction. */ class Starg_s extends ParameterWriteAccess, @cil_starg_s { override string getOpcodeName() { result = "starg.s" } override Parameter getTarget() { cil_access(this, result) } } - // Fields + /** An `ldfld` instruction. */ class Ldfld extends FieldReadAccess, @cil_ldfld { override string getOpcodeName() { result = "ldfld" } @@ -590,6 +689,7 @@ module Opcodes { override Expr getQualifier() { result = getOperand(0) } } + /** An `ldflda` instruction. */ class Ldflda extends FieldReadAccess, ReadRefAccess, @cil_ldflda { override string getOpcodeName() { result = "ldflda" } @@ -598,6 +698,7 @@ module Opcodes { override Expr getQualifier() { result = getOperand(0) } } + /** An `ldsfld` instruction. */ class Ldsfld extends FieldReadAccess, @cil_ldsfld { override string getOpcodeName() { result = "ldsfld" } @@ -606,6 +707,7 @@ module Opcodes { override Expr getQualifier() { none() } } + /** An `ldsflda` instruction. */ class Ldsflda extends FieldReadAccess, ReadRefAccess, @cil_ldsflda { override string getOpcodeName() { result = "ldsflda" } @@ -614,6 +716,7 @@ module Opcodes { override Expr getQualifier() { none() } } + /** An `stfld` instruction. */ class Stfld extends FieldWriteAccess, @cil_stfld { override string getOpcodeName() { result = "stfld" } @@ -624,6 +727,7 @@ module Opcodes { override Expr getExpr() { result = getOperand(0) } } + /** An `stsfld` instruction. */ class Stsfld extends FieldWriteAccess, @cil_stsfld { override string getOpcodeName() { result = "stsfld" } @@ -634,6 +738,7 @@ module Opcodes { override Expr getExpr() { result = getOperand(0) } } + /** A `newobj` instruction. */ class Newobj extends Call, @cil_newobj { override string getOpcodeName() { result = "newobj" } @@ -656,30 +761,35 @@ module Opcodes { } } + /** An `initobj` instruction. */ class Initobj extends Instruction, @cil_initobj { override string getOpcodeName() { result = "initobj" } override int getPopCount() { result = 1 } // ?? } + /** A `box` instruction. */ class Box extends UnaryExpr, @cil_box { override string getOpcodeName() { result = "box" } override Type getType() { result = getAccess() } } + /** An `unbox.any` instruction. */ class Unbox_any extends UnaryExpr, @cil_unbox_any { override string getOpcodeName() { result = "unbox.any" } override Type getType() { result = getAccess() } } + /** An `unbox` instruction. */ class Unbox extends UnaryExpr, @cil_unbox { override string getOpcodeName() { result = "unbox" } override Type getType() { result = getAccess() } } + /** An `ldobj` instruction. */ class Ldobj extends UnaryExpr, @cil_ldobj { override string getOpcodeName() { result = "ldobj" } @@ -689,6 +799,7 @@ module Opcodes { override Type getType() { result = getAccess() } } + /** An `ldtoken` instruction. */ class Ldtoken extends Expr, @cil_ldtoken { override string getOpcodeName() { result = "ldtoken" } @@ -696,27 +807,31 @@ module Opcodes { override ObjectType getType() { exists(result) } } + /** A `constrained.` instruction. */ class Constrained extends Instruction, @cil_constrained { override string getOpcodeName() { result = "constrained." } } + /** A `throw` instruction. */ class Throw_ extends Throw, @cil_throw { override string getOpcodeName() { result = "throw" } override int getPopCount() { result = 1 } } + /** A `rethrow` instruction. */ class Rethrow extends Throw, @cil_rethrow { override string getOpcodeName() { result = "rethrow" } } + /** A `ldlen` instruction. */ class Ldlen extends UnaryExpr, @cil_ldlen { override string getOpcodeName() { result = "ldlen" } override IntType getType() { exists(result) } } - // Arrays + /** A `newarr` instruction. */ class Newarr extends Expr, @cil_newarr { override string getOpcodeName() { result = "newarr" } @@ -734,449 +849,524 @@ module Opcodes { override string getExtra() { result = getType().getQualifiedName() } } + /** An `ldelem` instruction. */ class Ldelem extends ReadArrayElement, @cil_ldelem { override string getOpcodeName() { result = "ldelem" } override Type getType() { result = getAccess() } } + /** An `ldelem.ref` instruction. */ class Ldelem_ref extends ReadArrayElement, @cil_ldelem_ref { override string getOpcodeName() { result = "ldelem.ref" } override Type getType() { result = getArray().getType() } } + /** An `ldelema` instruction. */ class Ldelema extends ReadArrayElement, ReadRef, @cil_ldelema { override string getOpcodeName() { result = "ldelema" } override Type getType() { result = getAccess() } } + /** An `stelem.ref` instruction. */ class Stelem_ref extends WriteArrayElement, @cil_stelem_ref { override string getOpcodeName() { result = "stelem.ref" } } + /** An `stelem` instruction. */ class Stelem extends WriteArrayElement, @cil_stelem { override string getOpcodeName() { result = "stelem" } } + /** An `stelem.i` instruction. */ class Stelem_i extends WriteArrayElement, @cil_stelem_i { override string getOpcodeName() { result = "stelem.i" } } + /** An `stelem.i1` instruction. */ class Stelem_i1 extends WriteArrayElement, @cil_stelem_i1 { override string getOpcodeName() { result = "stelem.i1" } } + /** An `stelem.i2` instruction. */ class Stelem_i2 extends WriteArrayElement, @cil_stelem_i2 { override string getOpcodeName() { result = "stelem.i2" } } + /** An `stelem.i4` instruction. */ class Stelem_i4 extends WriteArrayElement, @cil_stelem_i4 { override string getOpcodeName() { result = "stelem.i4" } } + /** An `stelem.i8` instruction. */ class Stelem_i8 extends WriteArrayElement, @cil_stelem_i8 { override string getOpcodeName() { result = "stelem.i8" } } + /** An `stelem.r4` instruction. */ class Stelem_r4 extends WriteArrayElement, @cil_stelem_r4 { override string getOpcodeName() { result = "stelem.r4" } } + /** An `stelem.r8` instruction. */ class Stelem_r8 extends WriteArrayElement, @cil_stelem_r8 { override string getOpcodeName() { result = "stelem.r8" } } + /** An `ldelem.i` instruction. */ class Ldelem_i extends ReadArrayElement, @cil_ldelem_i { override string getOpcodeName() { result = "ldelem.i" } override IntType getType() { exists(result) } } + /** An `ldelem.i1` instruction. */ class Ldelem_i1 extends ReadArrayElement, @cil_ldelem_i1 { override string getOpcodeName() { result = "ldelem.i1" } override SByteType getType() { exists(result) } } + /** An `ldelem.i2` instruction. */ class Ldelem_i2 extends ReadArrayElement, @cil_ldelem_i2 { override string getOpcodeName() { result = "ldelem.i2" } override ShortType getType() { exists(result) } } + /** An `ldelem.i4` instruction. */ class Ldelem_i4 extends ReadArrayElement, @cil_ldelem_i4 { override string getOpcodeName() { result = "ldelem.i4" } override IntType getType() { exists(result) } } + /** An `ldelem.i8` instruction. */ class Ldelem_i8 extends ReadArrayElement, @cil_ldelem_i8 { override string getOpcodeName() { result = "ldelem.i8" } override LongType getType() { exists(result) } } + /** An `ldelem.r4` instruction. */ class Ldelem_r4 extends ReadArrayElement, @cil_ldelem_r4 { override string getOpcodeName() { result = "ldelem.r4" } override FloatType getType() { exists(result) } } + /** An `ldelem.r8` instruction. */ class Ldelem_r8 extends ReadArrayElement, @cil_ldelem_r8 { override string getOpcodeName() { result = "ldelem.r8" } override DoubleType getType() { exists(result) } } + /** An `ldelem.u1` instruction. */ class Ldelem_u1 extends ReadArrayElement, @cil_ldelem_u1 { override string getOpcodeName() { result = "ldelem.u1" } override ByteType getType() { exists(result) } } + /** An `ldelem.u2` instruction. */ class Ldelem_u2 extends ReadArrayElement, @cil_ldelem_u2 { override string getOpcodeName() { result = "ldelem.u2" } override UShortType getType() { exists(result) } } + /** An `ldelem.u4` instruction. */ class Ldelem_u4 extends ReadArrayElement, @cil_ldelem_u4 { override string getOpcodeName() { result = "ldelem.u4" } override UIntType getType() { exists(result) } } - // Conversions + /** A `conv.i` instruction. */ class Conv_i extends Conversion, @cil_conv_i { override string getOpcodeName() { result = "conv.i" } override IntType getType() { exists(result) } } + /** A `conv.ovf.i` instruction. */ class Conv_ovf_i extends Conversion, @cil_conv_ovf_i { override string getOpcodeName() { result = "conv.ovf.i" } override IntType getType() { exists(result) } } + /** A `conv.ovf.i.un` instruction. */ class Conv_ovf_i_un extends Conversion, @cil_conv_ovf_i_un { override string getOpcodeName() { result = "conv.ovf.i.un" } override UIntType getType() { exists(result) } } + /** A `conv.i1` instruction. */ class Conv_i1 extends Conversion, @cil_conv_i1 { override string getOpcodeName() { result = "conv.i1" } override SByteType getType() { exists(result) } } + /** A `conv.ovf.i1` instruction. */ class Conv_ovf_i1 extends Conversion, @cil_conv_ovf_i1 { override string getOpcodeName() { result = "conv.ovf.i1" } override SByteType getType() { exists(result) } } + /** A `conv.ovf.i1.un` instruction. */ class Conv_ovf_i1_un extends Conversion, @cil_conv_ovf_i1_un { override string getOpcodeName() { result = "conv.ovf.i1.un" } override SByteType getType() { exists(result) } } + /** A `conv.i2` instruction. */ class Conv_i2 extends Conversion, @cil_conv_i2 { override string getOpcodeName() { result = "conv.i2" } override ShortType getType() { exists(result) } } + /** A `conv.ovf.i2` instruction. */ class Conv_ovf_i2 extends Conversion, @cil_conv_ovf_i2 { override string getOpcodeName() { result = "conv.ovf.i2" } override ShortType getType() { exists(result) } } + /** A `conv.ovf.i2.un` instruction. */ class Conv_ovf_i2_un extends Conversion, @cil_conv_ovf_i2_un { override string getOpcodeName() { result = "conv.ovf.i2.un" } override ShortType getType() { exists(result) } } + /** A `conv.i4` instruction. */ class Conv_i4 extends Conversion, @cil_conv_i4 { override string getOpcodeName() { result = "conv.i4" } override IntType getType() { exists(result) } } + /** A `conv.ovf.i4` instruction. */ class Conv_ovf_i4 extends Conversion, @cil_conv_ovf_i4 { override string getOpcodeName() { result = "conv.ovf.i4" } override IntType getType() { exists(result) } } + /** A `conv.ovf.i4.un` instruction. */ class Conv_ovf_i4_un extends Conversion, @cil_conv_ovf_i4_un { override string getOpcodeName() { result = "conv.ovf.i4.un" } override IntType getType() { exists(result) } } + /** A `conv.i8` instruction. */ class Conv_i8 extends Conversion, @cil_conv_i8 { override string getOpcodeName() { result = "conv.i8" } override LongType getType() { exists(result) } } + /** A `conv.ovf.i8` instruction. */ class Conv_ovf_i8 extends Conversion, @cil_conv_ovf_i8 { override string getOpcodeName() { result = "conv.ovf.i8" } override LongType getType() { exists(result) } } + /** A `conv.ovf.i8.un` instruction. */ class Conv_ovf_i8_un extends Conversion, @cil_conv_ovf_i8_un { override string getOpcodeName() { result = "conv.ovf.i8.un" } override LongType getType() { exists(result) } } - // Unsigned conversions + /** A `conv.u` instruction. */ class Conv_u extends Conversion, @cil_conv_u { override string getOpcodeName() { result = "conv.u" } override UIntType getType() { exists(result) } } + /** A `conv.ovf.u` instruction. */ class Conv_ovf_u extends Conversion, @cil_conv_ovf_u { override string getOpcodeName() { result = "conv.ovf.u" } override UIntType getType() { exists(result) } } + /** A `conv.ovf.u.un` instruction. */ class Conv_ovf_u_un extends Conversion, @cil_conv_ovf_u_un { override string getOpcodeName() { result = "conv.ovf.u.un" } override UIntType getType() { exists(result) } } + /** A `conv.u1` instruction. */ class Conv_u1 extends Conversion, @cil_conv_u1 { override string getOpcodeName() { result = "conv.u1" } override ByteType getType() { exists(result) } } + /** A `conv.ovf.u1` instruction. */ class Conv_ovf_u1 extends Conversion, @cil_conv_ovf_u1 { override string getOpcodeName() { result = "conv.ovf.u1" } override ByteType getType() { exists(result) } } + /** A `conv.ovf.u1.un` instruction. */ class Conv_ovf_u1_un extends Conversion, @cil_conv_ovf_u1_un { override string getOpcodeName() { result = "conv.ovf.u1.un" } override ByteType getType() { exists(result) } } + /** A `conv.u2` instruction. */ class Conv_u2 extends Conversion, @cil_conv_u2 { override string getOpcodeName() { result = "conv.u2" } override UShortType getType() { exists(result) } } + /** A `conv.ovf.u2` instruction. */ class Conv_ovf_u2 extends Conversion, @cil_conv_ovf_u2 { override string getOpcodeName() { result = "conv.ovf.u2" } override UShortType getType() { exists(result) } } + /** A `conv.ovf.u2.un` instruction. */ class Conv_ovf_u2_un extends Conversion, @cil_conv_ovf_u2_un { override string getOpcodeName() { result = "conv.ovf.u2.un" } override UShortType getType() { exists(result) } } + /** A `conv.u4` instruction. */ class Conv_u4 extends Conversion, @cil_conv_u4 { override string getOpcodeName() { result = "conv.u4" } override UIntType getType() { exists(result) } } + /** A `conv.ovf.u4` instruction. */ class Conv_ovf_u4 extends Conversion, @cil_conv_ovf_u4 { override string getOpcodeName() { result = "conv.ovf.u4" } override UIntType getType() { exists(result) } } + /** A `conv.ovf.u4.un` instruction. */ class Conv_ovf_u4_un extends Conversion, @cil_conv_ovf_u4_un { override string getOpcodeName() { result = "conv.ovf.u4.un" } override UIntType getType() { exists(result) } } + /** A `conv.u8` instruction. */ class Conv_u8 extends Conversion, @cil_conv_u8 { override string getOpcodeName() { result = "conv.u8" } override ULongType getType() { exists(result) } } + /** A `conv.ovf.u8` instruction. */ class Conv_ovf_u8 extends Conversion, @cil_conv_ovf_u8 { override string getOpcodeName() { result = "conv.ovf.u8" } override ULongType getType() { exists(result) } } + /** A `conv.ovf.u8.un` instruction. */ class Conv_ovf_u8_un extends Conversion, @cil_conv_ovf_u8_un { override string getOpcodeName() { result = "conv.ovf.u8.un" } override ULongType getType() { exists(result) } } - // Floating point conversions + /** A `conv.r4` instruction. */ class Conv_r4 extends Conversion, @cil_conv_r4 { override string getOpcodeName() { result = "conv.r4" } override FloatType getType() { exists(result) } } + /** A `conv.r8` instruction. */ class Conv_r8 extends Conversion, @cil_conv_r8 { override string getOpcodeName() { result = "conv.r8" } override DoubleType getType() { exists(result) } } + /** A `conv.r.un` instruction. */ class Conv_r_un extends Conversion, @cil_conv_r_un { override string getOpcodeName() { result = "conv.r.un" } override DoubleType getType() { exists(result) } // ?? } + /** A `volatile.` instruction. */ class Volatile extends Instruction, @cil_volatile { override string getOpcodeName() { result = "volatile." } } - // Indirections + /** An `ldind.i` instruction. */ class Ldind_i extends LoadIndirect, @cil_ldind_i { override string getOpcodeName() { result = "ldind.i" } override IntType getType() { exists(result) } } + /** An `ldind.i1` instruction. */ class Ldind_i1 extends LoadIndirect, @cil_ldind_i1 { override string getOpcodeName() { result = "ldind.i1" } override SByteType getType() { exists(result) } } + /** An `ldind.i2` instruction. */ class Ldind_i2 extends LoadIndirect, @cil_ldind_i2 { override string getOpcodeName() { result = "ldind.i2" } override ShortType getType() { exists(result) } } + /** An `ldind.i4` instruction. */ class Ldind_i4 extends LoadIndirect, @cil_ldind_i4 { override string getOpcodeName() { result = "ldind.i4" } override IntType getType() { exists(result) } } + /** An `ldind.i8` instruction. */ class Ldind_i8 extends LoadIndirect, @cil_ldind_i8 { override string getOpcodeName() { result = "ldind.i8" } override LongType getType() { exists(result) } } + /** An `ldind.r4` instruction. */ class Ldind_r4 extends LoadIndirect, @cil_ldind_r4 { override string getOpcodeName() { result = "ldind.r4" } override FloatType getType() { exists(result) } } + /** An `ldind.r8` instruction. */ class Ldind_r8 extends LoadIndirect, @cil_ldind_r8 { override string getOpcodeName() { result = "ldind.r8" } override DoubleType getType() { exists(result) } } + /** An `ldind.ref` instruction. */ class Ldind_ref extends LoadIndirect, @cil_ldind_ref { override string getOpcodeName() { result = "ldind.ref" } override ObjectType getType() { exists(result) } } + /** An `ldind.u1` instruction. */ class Ldind_u1 extends LoadIndirect, @cil_ldind_u1 { override string getOpcodeName() { result = "ldind.u1" } override ByteType getType() { exists(result) } } + /** An `ldind.u2` instruction. */ class Ldind_u2 extends LoadIndirect, @cil_ldind_u2 { override string getOpcodeName() { result = "ldind.u2" } override UShortType getType() { exists(result) } } + /** An `ldind.u4` instruction. */ class Ldind_u4 extends LoadIndirect, @cil_ldind_u4 { override string getOpcodeName() { result = "ldind.u4" } override UIntType getType() { exists(result) } } + /** An `stind.i` instruction. */ class Stind_i extends StoreIndirect, @cil_stind_i { override string getOpcodeName() { result = "stind.i" } } + /** An `stind.i1` instruction. */ class Stind_i1 extends StoreIndirect, @cil_stind_i1 { override string getOpcodeName() { result = "stind.i1" } } + /** An `stind.i2` instruction. */ class Stind_i2 extends StoreIndirect, @cil_stind_i2 { override string getOpcodeName() { result = "stind.i2" } } + /** An `stind.i4` instruction. */ class Stind_i4 extends StoreIndirect, @cil_stind_i4 { override string getOpcodeName() { result = "stind.i4" } } + /** An `stind.i8` instruction. */ class Stind_i8 extends StoreIndirect, @cil_stind_i8 { override string getOpcodeName() { result = "stind.i8" } } + /** An `stind.r4` instruction. */ class Stind_r4 extends StoreIndirect, @cil_stind_r4 { override string getOpcodeName() { result = "stind.r4" } } + /** An `stind.r8` instruction. */ class Stind_r8 extends StoreIndirect, @cil_stind_r8 { - override string getOpcodeName() { result = "stind.r4" } + override string getOpcodeName() { result = "stind.r8" } } + /** An `stind.ref` instruction. */ class Stind_ref extends StoreIndirect, @cil_stind_ref { override string getOpcodeName() { result = "stind.ref" } } - // Miscellaneous + /** An `stobj` instruction. */ class Stobj extends Instruction, @cil_stobj { override string getOpcodeName() { result = "stobj" } override int getPopCount() { result = 2 } } + /** An `ldftn` instruction. */ class Ldftn extends Expr, @cil_ldftn { override string getOpcodeName() { result = "ldftn" } override int getPopCount() { result = 0 } } + /** An `ldvirtftn` instruction. */ class Ldvirtftn extends Expr, @cil_ldvirtftn { override string getOpcodeName() { result = "ldvirtftn" } override int getPopCount() { result = 1 } } + /** A `sizeof` instruction. */ class Sizeof extends Expr, @cil_sizeof { override string getOpcodeName() { result = "sizeof" } override IntType getType() { exists(result) } } + /** A `localloc` instruction. */ class Localloc extends Expr, @cil_localloc { override string getOpcodeName() { result = "localloc" } @@ -1185,10 +1375,12 @@ module Opcodes { override PointerType getType() { result.getReferentType() instanceof ByteType } } + /** A `readonly.` instruction. */ class Readonly extends Instruction, @cil_readonly { override string getOpcodeName() { result = "readonly." } } + /** A `mkrefany` instruction. */ class Mkrefany extends Expr, @cil_mkrefany { override string getOpcodeName() { result = "mkrefany" } @@ -1197,6 +1389,7 @@ module Opcodes { override Type getType() { result = getAccess() } } + /** A `refanytype` instruction. */ class Refanytype extends Expr, @cil_refanytype { override string getOpcodeName() { result = "refanytype" } @@ -1205,6 +1398,7 @@ module Opcodes { override SystemType getType() { exists(result) } } + /** An `arglist` instruction. */ class Arglist extends Expr, @cil_arglist { override string getOpcodeName() { result = "arglist" } } diff --git a/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll b/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll index 413e04f50177..0e5c512057a7 100644 --- a/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll +++ b/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll @@ -7,6 +7,7 @@ */ import csharp +private import TypeRef private module Annotations { newtype TAnnotation = diff --git a/csharp/ql/src/semmle/code/csharp/Assignable.qll b/csharp/ql/src/semmle/code/csharp/Assignable.qll index 3dbcd7cbdc3e..42ae43c37481 100644 --- a/csharp/ql/src/semmle/code/csharp/Assignable.qll +++ b/csharp/ql/src/semmle/code/csharp/Assignable.qll @@ -29,8 +29,10 @@ class Assignable extends Declaration, @assignable { * An assignable that is also a member. Either a field (`Field`), a * property (`Property`), an indexer (`Indexer`), or an event (`Event`). */ -class AssignableMember extends Member, Assignable { +class AssignableMember extends Member, Assignable, Attributable { override AssignableMemberAccess getAnAccess() { result = Assignable.super.getAnAccess() } + + override string toString() { result = Assignable.super.toString() } } /** @@ -55,7 +57,7 @@ private predicate nameOfChild(NameOfExpr noe, Expr child) { * * For example, the last occurrence of `Length` in * - * ``` + * ```csharp * class C { * int Length; * @@ -89,7 +91,7 @@ class AssignableRead extends AssignableAccess { * that can be reached from this read without passing through any other reads, * and which is guaranteed to read the same value. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -131,7 +133,7 @@ class AssignableRead extends AssignableAccess { * * For example, the last occurrence of `Length` in * - * ``` + * ```csharp * class C { * int Length; * @@ -454,7 +456,7 @@ class AssignableDefinition extends TAssignableDefinition { * reads, and which is guaranteed to read the value assigned in this * definition. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -720,7 +722,7 @@ module AssignableDefinitions { * An initializer definition for a field or a property, for example * line 2 in * - * ``` + * ```csharp * class C { * int Field = 0; * } diff --git a/csharp/ql/src/semmle/code/csharp/Attribute.qll b/csharp/ql/src/semmle/code/csharp/Attribute.qll index a7d7729903a5..9ca168192a19 100644 --- a/csharp/ql/src/semmle/code/csharp/Attribute.qll +++ b/csharp/ql/src/semmle/code/csharp/Attribute.qll @@ -4,6 +4,7 @@ import Type private import semmle.code.csharp.ExprOrStmtParent +private import TypeRef /** * An element that can have attributes. Either an assembly (`Assembly`), a field (`Field`), @@ -38,7 +39,7 @@ class Attributable extends @attributable { /** * An attribute, for example `[...]` on line 1 in * - * ``` + * ```csharp * [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] * public static extern int GetFinalPathNameByHandle( * SafeHandle handle, @@ -64,7 +65,7 @@ class Attribute extends TopLevelExprParent, @attribute { * Gets the `i`th constructor argument of this attribute. For example, only * `true` is a constructor argument in * - * ``` + * ```csharp * MyAttribute[true, Foo = 0] * ``` */ @@ -76,7 +77,7 @@ class Attribute extends TopLevelExprParent, @attribute { * Gets the named argument `name` of this attribute. For example, only * `0` is a named argument in * - * ``` + * ```csharp * MyAttribute[true, Foo = 0] * ``` */ @@ -93,4 +94,6 @@ class Attribute extends TopLevelExprParent, @attribute { result = "[" + name + "(...)]" ) } + + override string getAPrimaryQlClass() { result = "Attribute" } } diff --git a/csharp/ql/src/semmle/code/csharp/Caching.qll b/csharp/ql/src/semmle/code/csharp/Caching.qll index 4443ec9bc7c8..95ffbf9ffc91 100644 --- a/csharp/ql/src/semmle/code/csharp/Caching.qll +++ b/csharp/ql/src/semmle/code/csharp/Caching.qll @@ -39,7 +39,7 @@ module Stages { cached private predicate forceCachingInSameStageRev() { - any(ControlFlowElement cfe).controlsBlock(_, _) + any(ControlFlowElement cfe).controlsBlock(_, _, _) or exists(GuardedExpr ge) or @@ -58,7 +58,7 @@ module Stages { cached private predicate forceCachingInSameStageRev() { - localAdditionalTaintStep(_, _) + defaultAdditionalTaintStep(_, _) or any(ArgumentNode n).argumentOf(_, _) or @@ -68,7 +68,7 @@ module Stages { or exists(any(DataFlow::Node n).getType()) or - exists(any(DataFlow::Node n).getTypeBound()) + exists(any(NodeImpl n).getDataFlowType()) or exists(any(DataFlow::Node n).getLocation()) or diff --git a/csharp/ql/src/semmle/code/csharp/Callable.qll b/csharp/ql/src/semmle/code/csharp/Callable.qll index 2ed9e5cf03a4..2153524ac9e4 100644 --- a/csharp/ql/src/semmle/code/csharp/Callable.qll +++ b/csharp/ql/src/semmle/code/csharp/Callable.qll @@ -3,13 +3,14 @@ * such as methods and operators. */ -import Type import Member import Stmt +import Type import exprs.Call private import dotnet private import semmle.code.csharp.ExprOrStmtParent private import semmle.code.csharp.metrics.Complexity +private import TypeRef /** * An element that can be called. @@ -31,45 +32,42 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal * Gets the body of this callable, if any. * * The body is either a `BlockStmt` or an `Expr`. - */ - final ControlFlowElement getBody() { - result = this.getStatementBody() or - result = this.getExpressionBody() - } - - /** - * Gets a body of this callable, if any. * - * Unlike `getBody()`, this predicate may return multiple bodies, in the case - * where the same callable is compiled multiple times. For example, if we - * compile both `A.cs` + * Normally, each callable will have at most one body, except in the case where + * the same callable is compiled multiple times. For example, if we compile + * both `A.cs` * - * ``` + * ```csharp * namespaces N { * public class C { - * public int M() => 0; + * public int M() { return 0; } * } * } * ``` * * and later `B.cs` * - * ``` + * ```csharp * namespaces N { * public class C { - * public int M() { return 1; } + * public int M() => 1; * } * } * ``` * - * to the same assembly, then both `0` and `{ return 1; }` are bodies of `N.C.M()`. + * then both `{ return 0; }` and `1` are bodies of `N.C.M()`. */ - final ControlFlowElement getABody() { - result = this.getAStatementBody() or - result = this.getAnExpressionBody() + final ControlFlowElement getBody() { + result = this.getStatementBody() or + result = this.getExpressionBody() } - override predicate hasBody() { exists(getBody()) } + /** + * DEPRECATED: Use `getBody()` instead. + */ + deprecated final ControlFlowElement getABody() { result = this.getBody() } + + override predicate hasBody() { exists(this.getBody()) } /** * Holds if this callable has a non-empty body. That is, either it has @@ -78,21 +76,17 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal predicate hasNonEmptyBody() { this.hasExpressionBody() or - this.hasStatementBody() and - not this.getStatementBody().stripSingletonBlocks().(BlockStmt).isEmpty() + this.getStatementBody().stripSingletonBlocks() = any(Stmt s | not s.(BlockStmt).isEmpty()) } - /** Gets the statement body of this callable, if any. */ - final BlockStmt getStatementBody() { result = this.getAChildStmt() } - /** - * Gets a statement body of this callable, if any. + * Gets the statement body of this callable, if any. * - * Unlike `getStatementBody()`, this predicate may return multiple bodies, in - * the case where the same callable is compiled multiple times. For example, - * if we compile both `A.cs` + * Normally, each callable will have at most one statement body, except in the + * case where the same callable is compiled multiple times. For example, if + * we compile both `A.cs` * - * ``` + * ```csharp * namespaces N { * public class C { * public int M() { return 0; } @@ -102,7 +96,7 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal * * and later `B.cs` * - * ``` + * ```csharp * namespaces N { * public class C { * public int M() { return 1; } @@ -110,25 +104,27 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal * } * ``` * - * to the same assembly, then both `{ return 0; }` and `{ return 1; }` are - * statement bodies of `N.C.M()`. + * then both `{ return 0; }` and `{ return 1; }` are statement bodies of + * `N.C.M()`. */ - final BlockStmt getAStatementBody() { stmt_parent_top_level(result, _, this) } + final BlockStmt getStatementBody() { result = this.getAChildStmt() } + + /** + * DEPRECATED: Use `getStatementBody` instead. + */ + final BlockStmt getAStatementBody() { result = this.getStatementBody() } /** Holds if this callable has a statement body. */ final predicate hasStatementBody() { exists(getStatementBody()) } - /** Gets the expression body of this callable (if any), specified by `=>`. */ - final Expr getExpressionBody() { result = this.getChildExpr(0) } - /** - * Gets an expression body of this callable (if any), specified by `=>`. + * Gets the expression body of this callable (if any), specified by `=>`. * - * Unlike `getExpressionBody()`, this predicate may return multiple bodies, in - * the case where the same callable is compiled multiple times. For example, - * if we compile both `A.cs` + * Normally, each callable will have at most one expression body, except in the + * case where the same callable is compiled multiple times. For example, if + * we compile both `A.cs` * - * ``` + * ```csharp * namespaces N { * public class C { * public int M() => 0; @@ -138,7 +134,7 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal * * and later `B.cs` * - * ``` + * ```csharp * namespaces N { * public class C { * public int M() => 1; @@ -146,9 +142,17 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal * } * ``` * - * to the same assembly, then both `0` and `1` are expression bodies of `N.C.M()`. + * then both `0` and `1` are expression bodies of `N.C.M()`. */ - final Expr getAnExpressionBody() { expr_parent_top_level_adjusted(result, 0, this) } + final Expr getExpressionBody() { + result = this.getAChildExpr() and + not result = this.(Constructor).getInitializer() + } + + /** + * DEPRECATED: Use `getExpressionBody()` instead. + */ + deprecated final Expr getAnExpressionBody() { result = this.getExpressionBody() } /** Holds if this callable has an expression body. */ final predicate hasExpressionBody() { exists(getExpressionBody()) } @@ -223,7 +227,7 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal /** * A method, for example * - * ``` + * ```csharp * public override bool Equals(object other) { * ... * } @@ -284,12 +288,14 @@ class Method extends Callable, Virtualizable, Attributable, @method { override Parameter getRawParameter(int i) { if this.isStatic() then result = this.getParameter(i) else result = this.getParameter(i - 1) } + + override string getAPrimaryQlClass() { result = "Method" } } /** * An extension method, for example * - * ``` + * ```csharp * static bool IsDefined(this Widget w) { * ... * } @@ -302,12 +308,14 @@ class ExtensionMethod extends Method { /** Gets the type being extended by this method. */ Type getExtendedType() { result = getParameter(0).getType() } + + override string getAPrimaryQlClass() { result = "ExtensionMethod" } } /** * A constructor, for example `public C() { }` on line 2 in * - * ``` + * ```csharp * class C { * public C() { } * } @@ -326,7 +334,7 @@ class Constructor extends DotNet::Constructor, Callable, Member, Attributable, @ * the initializer of the constructor on line 2 is `this(null)` * on line 3 in * - * ``` + * ```csharp * class C { * public C() * : this(null) { ... } @@ -361,7 +369,7 @@ class Constructor extends DotNet::Constructor, Callable, Member, Attributable, @ * A static constructor (as opposed to an instance constructor), * for example `static public C() { }` on line 2 in * - * ``` + * ```csharp * class C { * static public C() { } * } @@ -371,13 +379,15 @@ class StaticConstructor extends Constructor { StaticConstructor() { this.isStatic() } override string getUndecoratedName() { result = ".cctor" } + + override string getAPrimaryQlClass() { result = "StaticConstructor" } } /** * An instance constructor (as opposed to a static constructor), * for example `public C() { }` on line 2 in * - * ``` + * ```csharp * class C { * public C() { } * } @@ -385,12 +395,14 @@ class StaticConstructor extends Constructor { */ class InstanceConstructor extends Constructor { InstanceConstructor() { not this.isStatic() } + + override string getAPrimaryQlClass() { result = "InstanceConstructor" } } /** * A destructor, for example `~C() { }` on line 2 in * - * ``` + * ```csharp * class C { * ~C() { } * } @@ -413,6 +425,8 @@ class Destructor extends DotNet::Destructor, Callable, Member, Attributable, @de override Location getALocation() { destructor_location(this, result) } override string toString() { result = Callable.super.toString() } + + override string getAPrimaryQlClass() { result = "Destructor" } } /** @@ -427,6 +441,9 @@ class Operator extends Callable, Member, Attributable, @operator { override string getName() { operators(this, _, result, _, _, _) } + /** + * Gets the metadata name of the operator, such as `op_implicit` or `op_RightShift`. + */ string getFunctionName() { none() } override ValueOrRefType getDeclaringType() { operators(this, _, _, result, _, _) } @@ -461,7 +478,7 @@ class UnaryOperator extends Operator { /** * A user-defined plus operator (`+`), for example * - * ``` + * ```csharp * public static Widget operator +(Widget w) { * ... * } @@ -471,12 +488,14 @@ class PlusOperator extends UnaryOperator { PlusOperator() { this.getName() = "+" } override string getFunctionName() { result = "op_UnaryPlus" } + + override string getAPrimaryQlClass() { result = "PlusOperator" } } /** * A user-defined minus operator (`-`), for example * - * ``` + * ```csharp * public static Widget operator -(Widget w) { * ... * } @@ -486,12 +505,14 @@ class MinusOperator extends UnaryOperator { MinusOperator() { this.getName() = "-" } override string getFunctionName() { result = "op_UnaryNegation" } + + override string getAPrimaryQlClass() { result = "MinusOperator" } } /** * A user-defined not operator (`!`), for example * - * ``` + * ```csharp * public static bool operator !(Widget w) { * ... * } @@ -501,12 +522,14 @@ class NotOperator extends UnaryOperator { NotOperator() { this.getName() = "!" } override string getFunctionName() { result = "op_LogicalNot" } + + override string getAPrimaryQlClass() { result = "NotOperator" } } /** * A user-defined complement operator (`~`), for example * - * ``` + * ```csharp * public static Widget operator ~(Widget w) { * ... * } @@ -516,12 +539,14 @@ class ComplementOperator extends UnaryOperator { ComplementOperator() { this.getName() = "~" } override string getFunctionName() { result = "op_OnesComplement" } + + override string getAPrimaryQlClass() { result = "ComplementOperator" } } /** * A user-defined increment operator (`++`), for example * - * ``` + * ```csharp * public static Widget operator ++(Widget w) { * ... * } @@ -531,12 +556,14 @@ class IncrementOperator extends UnaryOperator { IncrementOperator() { this.getName() = "++" } override string getFunctionName() { result = "op_Increment" } + + override string getAPrimaryQlClass() { result = "IncrementOperator" } } /** * A user-defined decrement operator (`--`), for example * - * ``` + * ```csharp * public static Widget operator --(Widget w) { * ... * } @@ -546,12 +573,14 @@ class DecrementOperator extends UnaryOperator { DecrementOperator() { this.getName() = "--" } override string getFunctionName() { result = "op_Decrement" } + + override string getAPrimaryQlClass() { result = "DecrementOperator" } } /** * A user-defined false operator (`false`), for example * - * ``` + * ```csharp * public static bool operator false(Widget w) { * ... * } @@ -561,12 +590,14 @@ class FalseOperator extends UnaryOperator { FalseOperator() { this.getName() = "false" } override string getFunctionName() { result = "op_False" } + + override string getAPrimaryQlClass() { result = "FalseOperator" } } /** * A user-defined true operator (`true`), for example * - * ``` + * ```csharp * public static bool operator true(Widget w) { * ... * } @@ -576,6 +607,8 @@ class TrueOperator extends UnaryOperator { TrueOperator() { this.getName() = "true" } override string getFunctionName() { result = "op_True" } + + override string getAPrimaryQlClass() { result = "TrueOperator" } } /** @@ -598,7 +631,7 @@ class BinaryOperator extends Operator { /** * A user-defined addition operator (`+`), for example * - * ``` + * ```csharp * public static Widget operator +(Widget lhs, Widget rhs) { * ... * } @@ -608,12 +641,14 @@ class AddOperator extends BinaryOperator { AddOperator() { this.getName() = "+" } override string getFunctionName() { result = "op_Addition" } + + override string getAPrimaryQlClass() { result = "AddOperator" } } /** * A user-defined subtraction operator (`-`), for example * - * ``` + * ```csharp * public static Widget operator -(Widget lhs, Widget rhs) { * ... * } @@ -623,12 +658,14 @@ class SubOperator extends BinaryOperator { SubOperator() { this.getName() = "-" } override string getFunctionName() { result = "op_Subtraction" } + + override string getAPrimaryQlClass() { result = "SubOperator" } } /** * A user-defined multiplication operator (`*`), for example * - * ``` + * ```csharp * public static Widget operator *(Widget lhs, Widget rhs) { * ... * } @@ -638,12 +675,14 @@ class MulOperator extends BinaryOperator { MulOperator() { this.getName() = "*" } override string getFunctionName() { result = "op_Multiply" } + + override string getAPrimaryQlClass() { result = "MulOperator" } } /** * A user-defined division operator (`/`), for example * - * ``` + * ```csharp * public static Widget operator /(Widget lhs, Widget rhs) { * ... * } @@ -653,12 +692,14 @@ class DivOperator extends BinaryOperator { DivOperator() { this.getName() = "/" } override string getFunctionName() { result = "op_Division" } + + override string getAPrimaryQlClass() { result = "DivOperator" } } /** * A user-defined remainder operator (`%`), for example * - * ``` + * ```csharp * public static Widget operator %(Widget lhs, Widget rhs) { * ... * } @@ -668,12 +709,14 @@ class RemOperator extends BinaryOperator { RemOperator() { this.getName() = "%" } override string getFunctionName() { result = "op_Modulus" } + + override string getAPrimaryQlClass() { result = "RemOperator" } } /** * A user-defined and operator (`&`), for example * - * ``` + * ```csharp * public static Widget operator &(Widget lhs, Widget rhs) { * ... * } @@ -683,12 +726,14 @@ class AndOperator extends BinaryOperator { AndOperator() { this.getName() = "&" } override string getFunctionName() { result = "op_BitwiseAnd" } + + override string getAPrimaryQlClass() { result = "AndOperator" } } /** * A user-defined or operator (`|`), for example * - * ``` + * ```csharp * public static Widget operator |(Widget lhs, Widget rhs) { * ... * } @@ -698,12 +743,14 @@ class OrOperator extends BinaryOperator { OrOperator() { this.getName() = "|" } override string getFunctionName() { result = "op_BitwiseOr" } + + override string getAPrimaryQlClass() { result = "OrOperator" } } /** * A user-defined xor operator (`^`), for example * - * ``` + * ```csharp * public static Widget operator ^(Widget lhs, Widget rhs) { * ... * } @@ -713,12 +760,14 @@ class XorOperator extends BinaryOperator { XorOperator() { this.getName() = "^" } override string getFunctionName() { result = "op_ExclusiveOr" } + + override string getAPrimaryQlClass() { result = "XorOperator" } } /** * A user-defined left shift operator (`<<`), for example * - * ``` + * ```csharp * public static Widget operator <<(Widget lhs, Widget rhs) { * ... * } @@ -728,12 +777,14 @@ class LShiftOperator extends BinaryOperator { LShiftOperator() { this.getName() = "<<" } override string getFunctionName() { result = "op_LeftShift" } + + override string getAPrimaryQlClass() { result = "LShiftOperator" } } /** * A user-defined right shift operator (`>>`), for example * - * ``` + * ```csharp * public static Widget operator >>(Widget lhs, Widget rhs) { * ... * } @@ -743,12 +794,14 @@ class RShiftOperator extends BinaryOperator { RShiftOperator() { this.getName() = ">>" } override string getFunctionName() { result = "op_RightShift" } + + override string getAPrimaryQlClass() { result = "RShiftOperator" } } /** * A user-defined equals operator (`==`), for example * - * ``` + * ```csharp * public static bool operator ==(Widget lhs, Widget rhs) { * ... * } @@ -758,12 +811,14 @@ class EQOperator extends BinaryOperator { EQOperator() { this.getName() = "==" } override string getFunctionName() { result = "op_Equality" } + + override string getAPrimaryQlClass() { result = "EQOperator" } } /** * A user-defined not equals operator (`!=`), for example * - * ``` + * ```csharp * public static bool operator !=(Widget lhs, Widget rhs) { * ... * } @@ -773,12 +828,14 @@ class NEOperator extends BinaryOperator { NEOperator() { this.getName() = "!=" } override string getFunctionName() { result = "op_Inequality" } + + override string getAPrimaryQlClass() { result = "NEOperator" } } /** * A user-defined lesser than operator (`<`), for example * - * ``` + * ```csharp * public static bool operator <(Widget lhs, Widget rhs) { * ... * } @@ -788,12 +845,14 @@ class LTOperator extends BinaryOperator { LTOperator() { this.getName() = "<" } override string getFunctionName() { result = "op_LessThan" } + + override string getAPrimaryQlClass() { result = "LTOperator" } } /** * A user-defined greater than operator (`>`), for example * - * ``` + * ```csharp * public static bool operator >(Widget lhs, Widget rhs) { * ... * } @@ -803,12 +862,14 @@ class GTOperator extends BinaryOperator { GTOperator() { this.getName() = ">" } override string getFunctionName() { result = "op_GreaterThan" } + + override string getAPrimaryQlClass() { result = "GTOperator" } } /** * A user-defined less than or equals operator (`<=`), for example * - * ``` + * ```csharp * public static bool operator <=(Widget lhs, Widget rhs) { * ... * } @@ -818,12 +879,14 @@ class LEOperator extends BinaryOperator { LEOperator() { this.getName() = "<=" } override string getFunctionName() { result = "op_LessThanOrEqual" } + + override string getAPrimaryQlClass() { result = "LEOperator" } } /** * A user-defined greater than or equals operator (`>=`), for example * - * ``` + * ```csharp * public static bool operator >=(Widget lhs, Widget rhs) { * ... * } @@ -833,12 +896,14 @@ class GEOperator extends BinaryOperator { GEOperator() { this.getName() = ">=" } override string getFunctionName() { result = "op_GreaterThanOrEqual" } + + override string getAPrimaryQlClass() { result = "GEOperator" } } /** * A user-defined conversion operator, for example * - * ``` + * ```csharp * public static implicit operator int(BigInteger i) { * ... * } @@ -860,7 +925,7 @@ class ConversionOperator extends Operator { /** * A user-defined implicit conversion operator, for example * - * ``` + * ```csharp * public static implicit operator int(BigInteger i) { * ... * } @@ -870,12 +935,14 @@ class ImplicitConversionOperator extends ConversionOperator { ImplicitConversionOperator() { this.getName() = "implicit conversion" } override string getFunctionName() { result = "op_Implicit" } + + override string getAPrimaryQlClass() { result = "ImplicitConversionOperator" } } /** * A user-defined explicit conversion operator, for example * - * ``` + * ```csharp * public static explicit operator int(BigInteger i) { * ... * } @@ -885,13 +952,15 @@ class ExplicitConversionOperator extends ConversionOperator { ExplicitConversionOperator() { this.getName() = "explicit conversion" } override string getFunctionName() { result = "op_Explicit" } + + override string getAPrimaryQlClass() { result = "ExplicitConversionOperator" } } /** * A local function, defined within the scope of another callable. * For example, `Fac` on lines 2--4 in * - * ``` + * ```csharp * int Choose(int n, int m) { * int Fac(int x) { * return x > 1 ? x * Fac(x - 1) : 1; @@ -923,4 +992,6 @@ class LocalFunction extends Callable, Modifiable, @local_function { override Location getALocation() { result = getStatement().getALocation() } override Parameter getRawParameter(int i) { result = getParameter(i) } + + override string getAPrimaryQlClass() { result = "LocalFunction" } } diff --git a/csharp/ql/src/semmle/code/csharp/Comments.qll b/csharp/ql/src/semmle/code/csharp/Comments.qll index 1e81fb1fc1c9..41f4e5b0be89 100644 --- a/csharp/ql/src/semmle/code/csharp/Comments.qll +++ b/csharp/ql/src/semmle/code/csharp/Comments.qll @@ -34,7 +34,7 @@ class CommentLine extends @commentline { /** * A single-line comment, for example line 1 in * - * ``` + * ```csharp * // This method returns the successor of its argument * public int Succ(int x) => x + 1; * ``` @@ -47,7 +47,7 @@ class SinglelineComment extends CommentLine, @singlelinecomment { * A line of comment in a multiline style, for example each of the * lines in * - * ``` + * ```csharp * /* This is * a comment * / * ``` @@ -60,7 +60,7 @@ class MultilineComment extends CommentLine, @multilinecomment { * A line of XML documentation comment, for example each of the * lines in * - * ``` + * ```csharp * /// * /// This method ... * /// @@ -148,7 +148,7 @@ class XmlComment extends CommentLine, @xmldoccomment { /** * A collection of adjacent comment lines, for example * - * ``` + * ```csharp * /// * /// Represents a named tuple. * /// diff --git a/csharp/ql/src/semmle/code/csharp/Conversion.qll b/csharp/ql/src/semmle/code/csharp/Conversion.qll index 1bfc1eb8f615..75c24c896572 100644 --- a/csharp/ql/src/semmle/code/csharp/Conversion.qll +++ b/csharp/ql/src/semmle/code/csharp/Conversion.qll @@ -362,7 +362,7 @@ private module Identity { IdentityConvertibleGenericType fromType, IdentityConvertibleGenericType toType ) { // Semantically equivalent with - // ``` + // ```ql // ugt = fromType.getUnboundGeneric() // and // forex(int i | @@ -514,6 +514,11 @@ predicate convNullableType(ValueOrRefType fromType, NullableType toType) { ) } +/** + * Holds if `fromType` is `NullType`, and `toType` is a type that can represent + * the `null` value, such as a reference type, `Nullable` or a type parameter + * with contraints that restrict it to a reference type. + */ // This is a deliberate, small Cartesian product, so we have manually lifted it to force the // evaluator to evaluate it in its entirety, rather than trying to optimize it in context. pragma[noinline] @@ -773,7 +778,7 @@ predicate convConversionOperator(Type fromType, Type toType) { /** 13.1.3.2: Variance conversion. */ private predicate convVariance(GenericType fromType, GenericType toType) { // Semantically equivalent with - // ``` + // ```ql // ugt = fromType.getUnboundGeneric() // and // forex(int i | diff --git a/csharp/ql/src/semmle/code/csharp/Element.qll b/csharp/ql/src/semmle/code/csharp/Element.qll index 521138db1b50..f9ebbc5bef90 100644 --- a/csharp/ql/src/semmle/code/csharp/Element.qll +++ b/csharp/ql/src/semmle/code/csharp/Element.qll @@ -48,4 +48,17 @@ class Element extends DotNet::Element, @element { * other children (zero-based). */ int getIndex() { exists(Element parent | parent.getChild(result) = this) } + + /** + * Gets the name of a primary CodeQL class to which this element belongs. + * + * For most elements, this is simply the most precise syntactic category to + * which they belong; for example, `AddExpr` is a primary class, but + * `BinaryOperation` is not. + * + * This predicate always has a result. If no primary class can be + * determined, the result is `"???"`. If multiple primary classes match, + * this predicate can have multiple results. + */ + string getAPrimaryQlClass() { result = "???" } } diff --git a/csharp/ql/src/semmle/code/csharp/Event.qll b/csharp/ql/src/semmle/code/csharp/Event.qll index 38f89428b6f4..b2c624544fe2 100644 --- a/csharp/ql/src/semmle/code/csharp/Event.qll +++ b/csharp/ql/src/semmle/code/csharp/Event.qll @@ -4,11 +4,12 @@ import Member import Type +private import TypeRef /** * An event, for example `E` on line 3 in * - * ``` + * ```csharp * class C { * delegate void D(); * public event D E; @@ -61,13 +62,15 @@ class Event extends DeclarationWithAccessors, @event { } override Location getALocation() { event_location(this, result) } + + override string getAPrimaryQlClass() { result = "Event" } } /** * An event accessor, for example `add` on line 4 or `remove` * on line 5 in * - * ``` + * ```csharp * class C { * delegate void D(); * public event D E { @@ -95,7 +98,7 @@ class EventAccessor extends Accessor, @event_accessor { /** * An add event accessor, for example `add` on line 4 in * - * ``` + * ```csharp * class C { * delegate void D(); * public event D E { @@ -107,12 +110,14 @@ class EventAccessor extends Accessor, @event_accessor { */ class AddEventAccessor extends EventAccessor, @add_event_accessor { override string getName() { result = "add" + "_" + getDeclaration().getName() } + + override string getAPrimaryQlClass() { result = "AddEventAccessor" } } /** * A remove event accessor, for example `remove` on line 5 in * - * ``` + * ```csharp * class C { * delegate void D(); * public event D E { @@ -124,4 +129,6 @@ class AddEventAccessor extends EventAccessor, @add_event_accessor { */ class RemoveEventAccessor extends EventAccessor, @remove_event_accessor { override string getName() { result = "remove" + "_" + getDeclaration().getName() } + + override string getAPrimaryQlClass() { result = "RemoveEventAccessor" } } diff --git a/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll b/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll index 0cceb3cb8c24..80029612a7c5 100644 --- a/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll +++ b/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll @@ -6,74 +6,6 @@ import csharp -/** - * INTERNAL: Do not use. - * - * The `expr_parent_top_level()` relation extended to include a relation - * between getters and expression bodies in properties such as `int P => 0`. - */ -predicate expr_parent_top_level_adjusted(Expr child, int i, @top_level_exprorstmt_parent parent) { - expr_parent_top_level(child, i, parent) - or - parent = any(Getter g | expr_parent_top_level(child, i, g.getDeclaration())) and - i = 0 -} - -/** - * The `expr_parent()` relation adjusted for expandable assignments. For example, - * the assignment `x += y` is extracted as - * - * ``` - * += - * | - * 2 - * | - * = - * / \ - * 1 0 - * / \ - * x + - * / \ - * 1 0 - * / \ - * x y - * ``` - * - * in order to be able to retrieve the expanded assignment `x = x + y` as the 2nd - * child. This predicate changes the diagram above into - * - * ``` - * += - * / \ - * 1 0 - * / \ - * x y - * ``` - */ -private predicate expr_parent_adjusted(Expr child, int i, ControlFlowElement parent) { - if parent instanceof AssignOperation - then - parent = - any(AssignOperation ao | - exists(AssignExpr ae | ae = ao.getExpandedAssignment() | - i = 0 and - exists(Expr right | - // right = `x + y` - expr_parent(right, 0, ae) - | - expr_parent(child, 1, right) - ) - or - i = 1 and - expr_parent(child, 1, ae) - ) - or - not ao.hasExpandedAssignment() and - expr_parent(child, i, parent) - ) - else expr_parent(child, i, parent) -} - /** * INTERNAL: Do not use. * @@ -88,7 +20,7 @@ class ExprOrStmtParent extends Element, @exprorstmt_parent { /** Gets the `i`th child expression of this element (zero-based). */ final Expr getChildExpr(int i) { expr_parent_adjusted(result, i, this) or - result = getTopLevelChild(this, i) + expr_parent_top_level_adjusted(result, i, this) } /** Gets a child expression of this element, if any. */ @@ -97,7 +29,7 @@ class ExprOrStmtParent extends Element, @exprorstmt_parent { /** Gets the `i`th child statement of this element (zero-based). */ final Stmt getChildStmt(int i) { stmt_parent(result, i, this) or - result = getTopLevelChild(this, i) + stmt_parent_top_level(result, i, this) } /** Gets a child statement of this element, if any. */ @@ -113,242 +45,19 @@ class TopLevelExprParent extends Element, @top_level_expr_parent { final override Expr getChild(int i) { result = this.getChildExpr(i) } /** Gets the `i`th child expression of this element (zero-based). */ - final Expr getChildExpr(int i) { result = getTopLevelChild(this, i) } + final Expr getChildExpr(int i) { expr_parent_top_level_adjusted(result, i, this) } /** Gets a child expression of this element, if any. */ final Expr getAChildExpr() { result = this.getChildExpr(_) } } -/** - * INTERNAL: Do not use. - * - * An element that can have a child statement or expression, and where we have - * encountered multiple potential implementations at compile-time. For example, - * if we compile both `A.cs` - * - * ``` - * namespaces N { - * public class C { - * public int M() => 0; - * } - * } - * ``` - * - * and later `B.cs` - * - * ``` - * namespaces N { - * public class C { - * public int M() => 1; - * } - * } - * ``` - * - * then the method `N.C.M` has two implementations, returning `0` and `1`, - * respectively. - * - * The implementation used at run-time is in this case unknown (indeed, it could - * be a third implementation not encountered during compilation), so we make a - * guess for the "most likely" implementation in `getBestChild()`. - */ -class MultiImplementationsParent extends ExprOrStmtParent { - MultiImplementationsParent() { - exists(int i | - strictcount(File f | - exists(ControlFlowElement implementation, Location l | f = l.getFile() | - stmt_parent_top_level(implementation, i, this) and - stmt_location(implementation, l) - or - expr_parent_top_level_adjusted(implementation, i, this) and - expr_location(implementation, l) - ) - or - hasAccessorAutoImplementation(this, f) and - i = 0 - ) > 1 - ) - } - - /** - * Gets a file that contains an implementation `cfe` for the `i`th child of this - * element. - */ - private File getAnImplementation(int i, ControlFlowElement cfe) { - exists(Location l | result = l.getFile() | - stmt_parent_top_level(cfe, i, this) and - stmt_location(cfe, l) - or - expr_parent_top_level_adjusted(cfe, i, this) and - expr_location(cfe, l) - ) - } - - /** - * Gets a file that contains an implementation `cfe` for the `i`th child of this - * element, where `t` is the top-level type containing this element (that is, - * `t` is not a nested type). - */ - File getAnImplementationInTopLevelType(int i, ControlFlowElement cfe, ValueOrRefType t) { - result = this.getAnImplementation(i, cfe) and - t = getTopLevelDeclaringType(this) - } - - /** - * Gets a file that contains an auto-implementation for this element, where - * `t` is the top-level type containing this element (that is, `t` is not a - * nested type). - */ - File getAnAutoImplementationFileInTopLevelType(ValueOrRefType t) { - hasAccessorAutoImplementation(this, result) and - t = getTopLevelDeclaringType(this) - } - - private File getAnImplementationFileInTopLevelType(int i, ValueOrRefType t) { - result = getAnImplementationInTopLevelType(i, _, t) - or - result = this.getAnAutoImplementationFileInTopLevelType(t) and - i = 0 - } - - /** - * Gets the file containing the "best" implementation of this element, that is, the - * file considered most likely to contain the actual run-time implementation. - * - * The heuristics we use is to choose the implementation belonging to the top-level type - * with the most control flow elements (excluding `throw` elements). In the case of a tie, - * we arbitrarily choose the implementation belonging to the last file (in lexicographic - * order). - * - * By counting elements for the top-level type, we ensure that all definitions belonging - * to the same top-level type will get implementations belonging to the same file. - */ - File getBestFile() { - exists(ValueOrRefType t | - result = - max(this.getAnImplementationFileInTopLevelType(_, t) as file - order by - getImplementationSize(t, file), file.toString() - ) - ) - } - - /** - * Gets the i`th child of this element. Only the "best" child among all the possible - * run-time implementations is returned, namely the child considered most likely to - * be the actual run-time implementation. - */ - ControlFlowElement getBestChild(int i) { - exists(File f, ValueOrRefType t | f = getBestFile() | - f = this.getAnImplementationInTopLevelType(i, result, t) - ) - } -} - -/** Gets the top-level type containing declaration `d`. */ -private ValueOrRefType getTopLevelDeclaringType(Declaration d) { - result = getDeclaringType+(d) and - not result instanceof NestedType -} - -/** Gets the declaring type of element `e`. */ -private ValueOrRefType getDeclaringType(Declaration d) { - methods(d, _, result, _, _) - or - constructors(d, _, result, _) - or - destructors(d, _, result, _) - or - operators(d, _, _, result, _, _) - or - properties(d, _, result, _, _) - or - indexers(d, _, result, _, _) - or - nested_types(d, result, _) - or - fields(d, _, _, result, _, _) - or - exists(DeclarationWithAccessors decl | d = decl.getAnAccessor() | result = getDeclaringType(decl)) - or - exists(Parameterizable p | params(d, _, _, _, _, p, _) | result = getDeclaringType(p)) -} - -private ControlFlowElement getAChild(ControlFlowElement cfe) { - expr_parent_adjusted(result, _, cfe) or - stmt_parent(result, _, cfe) -} - -private int getImplementationSize0(ValueOrRefType t, File f) { - result = - strictcount(ControlFlowElement cfe | - exists(MultiImplementationsParent p, ControlFlowElement child | - cfe = getAChild*(child) and - not cfe = getAChild*(any(ThrowElement te)) - | - f = p.getAnImplementationInTopLevelType(_, child, t) - or - // Merge stats for partial implementations belonging to the same folder - t.isPartial() and - f = p.getAnImplementationInTopLevelType(_, _, t) and - exists(File fOther, MultiImplementationsParent pOther | - f.getParentContainer() = fOther.getParentContainer() - | - fOther = pOther.getAnImplementationInTopLevelType(_, child, t) - ) - ) - ) -} - -private int getImplementationSize1(ValueOrRefType t, File f) { - result = - strictsum(MultiImplementationsParent p, int c | - // Count each auto-implemented accessor as size 4 (getter) or 5 (setter) - f = p.getAnAutoImplementationFileInTopLevelType(t) and - if p instanceof Getter then c = 4 else c = 5 - | - c - ) -} - -private int getImplementationSize(ValueOrRefType t, File f) { - if exists(getImplementationSize0(t, f)) - then - if exists(getImplementationSize1(t, f)) - then result = getImplementationSize0(t, f) + getImplementationSize1(t, f) - else result = getImplementationSize0(t, f) - else result = getImplementationSize1(t, f) -} - -/** - * Holds if declaration `d` should have a location in file `f`, because it is part of a - * type with multiple implementations, where the most likely run-time implementation is - * in `f`. - */ -private predicate mustHaveLocationInFile(Declaration d, File f) { - exists(MultiImplementationsParent p, ValueOrRefType t | - t = getTopLevelDeclaringType(p) and - f = p.getBestFile() - | - t = getTopLevelDeclaringType(d) or d = t or d = p - ) -} - private predicate hasNoSourceLocation(Element e) { not e.getALocation() instanceof SourceLocation } cached private module Cached { - cached - ControlFlowElement getTopLevelChild(ExprOrStmtParent p, int i) { - result = p.(MultiImplementationsParent).getBestChild(i) - or - not p instanceof MultiImplementationsParent and - (stmt_parent_top_level(result, i, p) or expr_parent_top_level_adjusted(result, i, p)) - } - cached Location bestLocation(Element e) { - result = e.getALocation().(SourceLocation) and - (mustHaveLocationInFile(e, _) implies mustHaveLocationInFile(e, result.getFile())) + result = e.getALocation().(SourceLocation) or hasNoSourceLocation(e) and result = min(Location l | l = e.getALocation() | l order by l.getFile().toString()) @@ -360,20 +69,71 @@ private module Cached { /** * INTERNAL: Do not use. * - * Holds if accessor `a` has an auto-implementation in file `f`. + * The `expr_parent_top_level()` relation extended to include a relation + * between getters and expression bodies in properties such as `int P => 0`. + */ + cached + predicate expr_parent_top_level_adjusted(Expr child, int i, @top_level_exprorstmt_parent parent) { + expr_parent_top_level(child, i, parent) + or + parent = any(Getter g | expr_parent_top_level(child, i, g.getDeclaration())) and + i = 0 + } + + /** + * The `expr_parent()` relation adjusted for expandable assignments. For example, + * the assignment `x += y` is extracted as + * + * ``` + * += + * | + * 2 + * | + * = + * / \ + * 1 0 + * / \ + * x + + * / \ + * 1 0 + * / \ + * x y + * ``` + * + * in order to be able to retrieve the expanded assignment `x = x + y` as the 2nd + * child. This predicate changes the diagram above into + * + * ``` + * += + * / \ + * 1 0 + * / \ + * x y + * ``` */ cached - predicate hasAccessorAutoImplementation(Accessor a, File f) { - exists(SourceLocation sl | sl = a.getALocation() | - f = sl.getFile() and - not exists(ControlFlowElement cfe, Location l | sl.getFile() = l.getFile() | - stmt_parent_top_level(cfe, _, a) and - stmt_location(cfe, l) - or - expr_parent_top_level_adjusted(cfe, 0, a) and - expr_location(cfe, l) - ) - ) + predicate expr_parent_adjusted(Expr child, int i, ControlFlowElement parent) { + if parent instanceof AssignOperation + then + parent = + any(AssignOperation ao | + exists(AssignExpr ae | ae = ao.getExpandedAssignment() | + i = 0 and + exists(Expr right | + // right = `x + y` + expr_parent(right, 0, ae) + | + expr_parent(child, 1, right) + ) + or + i = 1 and + expr_parent(child, 1, ae) + ) + or + not ao.hasExpandedAssignment() and + expr_parent(child, i, parent) + ) + else expr_parent(child, i, parent) } } diff --git a/csharp/ql/src/semmle/code/csharp/Generics.qll b/csharp/ql/src/semmle/code/csharp/Generics.qll index 5aec92ebb988..52fe9c7b6996 100644 --- a/csharp/ql/src/semmle/code/csharp/Generics.qll +++ b/csharp/ql/src/semmle/code/csharp/Generics.qll @@ -16,6 +16,7 @@ import Location import Namespace private import dotnet +private import TypeRef /** * A generic declaration. Either an unbound generic (`UnboundGeneric`) or a @@ -183,6 +184,8 @@ class TypeParameter extends DotNet::TypeParameter, Type, @type_parameter { /** Gets the generic that defines this type parameter. */ UnboundGeneric getGeneric() { type_parameters(this, _, result, _) } + + override string getAPrimaryQlClass() { result = "TypeParameter" } } /** @@ -190,7 +193,7 @@ class TypeParameter extends DotNet::TypeParameter, Type, @type_parameter { * * For example, `where` on line 2 in * - * ``` + * ```csharp * class Factory * where T : ICloneable { * } @@ -233,7 +236,7 @@ class TypeParameterConstraints extends Element, @type_parameter_constraints { * * For example, * - * ``` + * ```csharp * struct KeyValuePair { * ... * } @@ -256,7 +259,7 @@ class UnboundGenericStruct extends Struct, UnboundGenericType { /** * An unbound generic class, for example * - * ``` + * ```csharp * class List { * ... * } @@ -279,7 +282,7 @@ class UnboundGenericClass extends Class, UnboundGenericType { /** * An unbound generic interface, for example * - * ``` + * ```csharp * interface IEnumerable { * ... * } @@ -305,7 +308,7 @@ class UnboundGenericInterface extends Interface, UnboundGenericType { * * For example * - * ``` + * ```csharp * delegate void F(T t); * ``` */ @@ -375,7 +378,7 @@ class ConstructedType extends ValueOrRefType, ConstructedGeneric { * * For example, `KeyValuePair` on line 4 in * - * ``` + * ```csharp * struct KeyValuePair { ... } * * class C { @@ -398,7 +401,7 @@ class ConstructedStruct extends Struct, ConstructedType { * * For example, `List` on line 4 in * - * ``` + * ```csharp * class List { ... } * * class C { @@ -421,7 +424,7 @@ class ConstructedClass extends Class, ConstructedType { * * For example, `IEnumerable` on line 4 in * - * ``` + * ```csharp * interface IEnumerable { ... } * * class C { @@ -444,7 +447,7 @@ class ConstructedInterface extends Interface, ConstructedType { * * For example, `F` on line 4 in * - * ``` + * ```csharp * delegate void F(T t); * * class C { @@ -466,7 +469,7 @@ class ConstructedDelegateType extends DelegateType, ConstructedType { * An unbound generic method. This is a generic method whose signature involves formal type parameters, * For example `M` on line 2 in * - * ``` + * ```csharp * class C { * void M() { ... } * } @@ -492,7 +495,7 @@ class UnboundGenericMethod extends Method, UnboundGeneric { * A constructed (bound) method, for example the target `M` of the call on * line 5 in * - * ``` + * ```csharp * class C { * void M() { ... } * @@ -526,8 +529,8 @@ class ConstructedMethod extends Method, ConstructedGeneric { /** * An unbound generic local function, for example `f` on line 3 in * - * ``` - * class { + * ```csharp + * class C { * void M() { * void f(T t) { ... } * } @@ -544,8 +547,8 @@ class UnboundLocalFunction extends LocalFunction, UnboundGeneric { * A constructed generic local function, for example the target `f` * of the function call `f(5)` on line 4 in * - * ``` - * class { + * ```csharp + * class C { * void M() { * void f(T t) { ... } * f(5); @@ -580,7 +583,7 @@ class NonConstructedMethod extends Method { * * Example: * - * ``` + * ```csharp * class A { * void M1(T1 x1) { } * void M2(T1 x1, T2 x) { } diff --git a/csharp/ql/src/semmle/code/csharp/Implements.qll b/csharp/ql/src/semmle/code/csharp/Implements.qll index 1007ed2aaf97..7b5358170391 100644 --- a/csharp/ql/src/semmle/code/csharp/Implements.qll +++ b/csharp/ql/src/semmle/code/csharp/Implements.qll @@ -21,7 +21,7 @@ private import Conversion * * Example: * - * ``` + * ```csharp * interface I { void M(); } * * class A { public void M() { } } @@ -52,7 +52,7 @@ predicate implements(Virtualizable m1, Virtualizable m2, ValueOrRefType t) { * * Example: * - * ``` + * ```csharp * interface I { void M(); } * * class A { public void M() { } } @@ -143,10 +143,10 @@ private predicate getACompatibleInterfaceAccessorAux( * of the interface `i`. Note that the class or struct need not be a * sub type of the interface in the inheritance hierarchy: * - * ``` - * interface I { void M() } + * ```csharp + * interface I { void M(); } * - * class A { public void M() } + * class A { public void M() { } } * * class B { } * @@ -259,7 +259,7 @@ private module Gvn { private newtype TGvnType = TLeafGvnType(LeafType t) or TMethodTypeParameterGvnType(int i) { i = any(MethodTypeParameter p).getIndex() } or - TConstructedGvnType(ConstructedGvnTypeList l) + TConstructedGvnType(ConstructedGvnTypeList l) { l.isFullyConstructed() } private newtype TConstructedGvnTypeList = TConstructedGvnTypeNil(Unification::CompoundTypeKind k) or @@ -334,6 +334,10 @@ private module Gvn { ) } + predicate isFullyConstructed() { + this.getKind().getNumberOfTypeParameters() - 1 = this.length() + } + private GvnType getArg(int i) { exists(GvnType head, ConstructedGvnTypeList tail | this = TConstructedGvnTypeCons(head, tail) @@ -345,47 +349,71 @@ private module Gvn { ) } + private Unification::GenericType getConstructedGenericDeclaringTypeAt(int i) { + i = 0 and + result = this.getKind().getConstructedSourceDeclaration() + or + result = this.getConstructedGenericDeclaringTypeAt(i - 1).getGenericDeclaringType() + } + + private predicate isDeclaringTypeAt(int i) { + exists(this.getConstructedGenericDeclaringTypeAt(i - 1)) + } + /** - * Gets a textual representation of this constructed type, restricted - * to the prefix `t` of the underlying source declaration type. - * - * The `toString()` calculation needs to be split up into prefixes, in - * order to apply the type arguments correctly. For example, a source - * declaration type `A<>.B.C<,>` applied to types `int, string, bool` - * needs to be printed as `A.B.C`. + * Gets the `j`th `toString()` part of the `i`th nested component of this + * constructed type, if any. The nested components are sorted in reverse + * order, while the individual parts are sorted in normal order. */ language[monotonicAggregates] - private string toStringConstructed(Unification::GenericType t) { - t = this.getKind().getConstructedSourceDeclaration().getGenericDeclaringType*() and - exists(int offset, int children, string name, string nameArgs | - offset = t.getNumberOfDeclaringArguments() and - children = t.getNumberOfArgumentsSelf() and - name = Unification::getNameNested(t) and - if children = 0 - then nameArgs = name - else - exists(string offsetArgs | - offsetArgs = - concat(int i | - i in [offset .. offset + children - 1] - | - this.getArg(i).toString(), "," order by i - ) and - nameArgs = name.prefix(name.length() - children - 1) + "<" + offsetArgs + ">" + private string toStringConstructedPart(int i, int j) { + this.isFullyConstructed() and + exists(Unification::GenericType t | + t = this.getConstructedGenericDeclaringTypeAt(i) and + exists(int offset, int children, string name | + offset = t.getNumberOfDeclaringArguments() and + children = t.getNumberOfArgumentsSelf() and + name = Unification::getNameNested(t) and + if children = 0 + then + j = 0 and result = name + or + this.isDeclaringTypeAt(i) and j = 1 and result = "." + else ( + j = 0 and result = name.prefix(name.length() - children - 1) + "<" + or + j in [1 .. 2 * children - 1] and + if j % 2 = 0 + then result = "," + else result = this.getArg((j + 1) / 2 + offset - 1).toString() + or + j = 2 * children and + result = ">" + or + this.isDeclaringTypeAt(i) and + j = 2 * children + 1 and + result = "." ) - | - offset = 0 and result = nameArgs - or - result = this.toStringConstructed(t.getGenericDeclaringType()) + "." + nameArgs + ) ) } language[monotonicAggregates] string toString() { + this.isFullyConstructed() and exists(Unification::CompoundTypeKind k | k = this.getKind() | result = k.toStringBuiltin(this.getArg(0).toString()) or - result = this.toStringConstructed(k.getConstructedSourceDeclaration()) + result = + strictconcat(int i, int j | + exists(Unification::GenericType t, int children | + t = this.getConstructedGenericDeclaringTypeAt(i) and + children = t.getNumberOfArgumentsSelf() and + if children = 0 then j = 0 else j in [0 .. 2 * children] + ) + | + this.toStringConstructedPart(i, j) order by i desc, j + ) ) } diff --git a/csharp/ql/src/semmle/code/csharp/Location.qll b/csharp/ql/src/semmle/code/csharp/Location.qll index 178eddc1d4d7..99df294ae636 100644 --- a/csharp/ql/src/semmle/code/csharp/Location.qll +++ b/csharp/ql/src/semmle/code/csharp/Location.qll @@ -38,16 +38,16 @@ class Location extends @location { /** Gets a textual representation of this location. */ string toString() { none() } - /** Gets the start line of this location. */ + /** Gets the 1-based line number (inclusive) where this location starts. */ final int getStartLine() { this.hasLocationInfo(_, result, _, _, _) } - /** Gets the end line of this location. */ + /** Gets the 1-based line number (inclusive) where this location ends. */ final int getEndLine() { this.hasLocationInfo(_, _, _, result, _) } - /** Gets the start column of this location. */ + /** Gets the 1-based column number (inclusive) where this location starts. */ final int getStartColumn() { this.hasLocationInfo(_, _, result, _, _) } - /** Gets the end column of this location. */ + /** Gets the 1-based column number (inclusive) where this location ends. */ final int getEndColumn() { this.hasLocationInfo(_, _, _, _, result) } } diff --git a/csharp/ql/src/semmle/code/csharp/Member.qll b/csharp/ql/src/semmle/code/csharp/Member.qll index dd2a64c47ae9..6df943a51b9a 100644 --- a/csharp/ql/src/semmle/code/csharp/Member.qll +++ b/csharp/ql/src/semmle/code/csharp/Member.qll @@ -1,11 +1,12 @@ /** Provides classes relating to declarations and type members. */ -import Element -import Variable import Callable +import Element import Modifier -private import Implements +import Variable private import dotnet +private import Implements +private import TypeRef /** * A declaration. @@ -24,7 +25,7 @@ class Declaration extends DotNet::Declaration, Element, @declaration { * Gets the fully qualified name of this declaration, including types, for example * the fully qualified name with types of `M` on line 3 is `N.C.M(int, string)` in * - * ``` + * ```csharp * namespace N { * class C { * void M(int i, string s) { } @@ -195,7 +196,7 @@ class Virtualizable extends Member, @virtualizable { * * Example: * - * ``` + * ```csharp * interface I { void M(); } * * class A { public void M() { } } @@ -223,7 +224,7 @@ class Virtualizable extends Member, @virtualizable { * * Example: * - * ``` + * ```csharp * interface I { void M(); } * * class A { public void M() { } } @@ -251,7 +252,7 @@ class Virtualizable extends Member, @virtualizable { * Note that this is generally *not* equivalent with * `getOverridee*().getImplementee()`, as the example below illustrates: * - * ``` + * ```csharp * interface I { void M(); } * * class A { public virtual void M() { } } diff --git a/csharp/ql/src/semmle/code/csharp/Namespace.qll b/csharp/ql/src/semmle/code/csharp/Namespace.qll index 0c94d182bee8..ed1fece2ae64 100644 --- a/csharp/ql/src/semmle/code/csharp/Namespace.qll +++ b/csharp/ql/src/semmle/code/csharp/Namespace.qll @@ -12,7 +12,7 @@ class TypeContainer extends DotNet::NamedElement, Element, @type_container { } /** * A namespace, for example * - * ``` + * ```csharp * namespace System.IO { * ... * } @@ -37,7 +37,7 @@ class Namespace extends DotNet::Namespace, TypeContainer, Declaration, @namespac * Gets a type directly declared in this namespace, if any. * For example, the class `File` in * - * ``` + * ```csharp * namespace System.IO { * public class File { ... } * } @@ -49,7 +49,7 @@ class Namespace extends DotNet::Namespace, TypeContainer, Declaration, @namespac * Gets a class directly declared in this namespace, if any. * For example, the class `File` in * - * ``` + * ```csharp * namespace System.IO { * public class File { ... } * } @@ -61,7 +61,7 @@ class Namespace extends DotNet::Namespace, TypeContainer, Declaration, @namespac * Gets an interface directly declared in this namespace, if any. * For example, the interface `IEnumerable` in * - * ``` + * ```csharp * namespace System.Collections { * public interface IEnumerable { ... } * } @@ -73,7 +73,7 @@ class Namespace extends DotNet::Namespace, TypeContainer, Declaration, @namespac * Gets a struct directly declared in this namespace, if any. * For example, the struct `Timespan` in * - * ``` + * ```csharp * namespace System { * public struct Timespan { ... } * } @@ -85,7 +85,7 @@ class Namespace extends DotNet::Namespace, TypeContainer, Declaration, @namespac * Gets an enum directly declared in this namespace, if any. * For example, the enum `DayOfWeek` in * - * ``` + * ```csharp * namespace System { * public enum DayOfWeek { ... } * } @@ -97,7 +97,7 @@ class Namespace extends DotNet::Namespace, TypeContainer, Declaration, @namespac * Gets a delegate directly declared in this namespace, if any. * For example, the delegate `AsyncCallback` in * - * ``` + * ```csharp * namespace System { * public delegate void AsyncCallback(IAsyncResult ar); * } @@ -135,7 +135,7 @@ class GlobalNamespace extends Namespace { /** * An explicit namespace declaration in a source file. For example: * - * ``` + * ```csharp * namespace N1.N2 { * ... * } @@ -145,7 +145,7 @@ class NamespaceDeclaration extends Element, @namespace_declaration { /** * Gets the declared namespace, for example `N1.N2` in * - * ``` + * ```csharp * namespace N1.N2 { * ... * } @@ -159,7 +159,7 @@ class NamespaceDeclaration extends Element, @namespace_declaration { * declaration `namespace N1` on line 1, but `namespace N1` on line 1 and * `namespace N1.N2` on line 7 do not have parent namespace declarations. * - * ``` + * ```csharp * namespace N1 { * namespace N2 { * ... @@ -180,7 +180,7 @@ class NamespaceDeclaration extends Element, @namespace_declaration { * `namespace N2` on line 2 is a child namespace declaration of * `namespace N1` on line 1. * - * ``` + * ```csharp * namespace N1 { * namespace N2 { * ... @@ -196,7 +196,7 @@ class NamespaceDeclaration extends Element, @namespace_declaration { * Gets a type directly declared within this namespace declaration. * For example, class `C` in * - * ``` + * ```csharp * namespace N { * class C { ... } * } @@ -207,4 +207,6 @@ class NamespaceDeclaration extends Element, @namespace_declaration { override Location getALocation() { namespace_declaration_location(this, result) } override string toString() { result = "namespace ... { ... }" } + + override string getAPrimaryQlClass() { result = "NamespaceDeclaration" } } diff --git a/csharp/ql/src/semmle/code/csharp/PrintAst.ql b/csharp/ql/src/semmle/code/csharp/PrintAst.ql new file mode 100644 index 000000000000..3867fd2990fb --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/PrintAst.ql @@ -0,0 +1,20 @@ +/** + * @name Print AST + * @description Outputs a representation of the Abstract Syntax Tree. + * @id csharp/print-ast + * @kind graph + */ + +import csharp +import PrintAst + +/** + * Temporarily tweak this class or make a copy to control which functions are + * printed. + */ +class PrintAstConfigurationOverride extends PrintAstConfiguration { + /** + * TWEAK THIS PREDICATE AS NEEDED. + */ + override predicate shouldPrint(Element e, Location l) { super.shouldPrint(e, l) } +} diff --git a/csharp/ql/src/semmle/code/csharp/PrintAst.qll b/csharp/ql/src/semmle/code/csharp/PrintAst.qll new file mode 100644 index 000000000000..c8001f443aaa --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/PrintAst.qll @@ -0,0 +1,647 @@ +/** + * Provides queries to pretty-print a C# AST as a graph. + * + * By default, this will print the AST for all elements in the database. To change this behavior, + * extend `PrintAstConfiguration` and override `shouldPrint` to hold for only the elements + * you wish to view the AST for. + */ + +import csharp + +private newtype TPrintAstConfiguration = MkPrintAstConfiguration() + +/** + * The query can extend this class to control which elements are printed. + */ +class PrintAstConfiguration extends TPrintAstConfiguration { + /** + * Gets a textual representation of this `PrintAstConfiguration`. + */ + string toString() { result = "PrintAstConfiguration" } + + /** + * Controls whether the `Element` should be considered for AST printing. + * By default it checks whether the `Element` `e` belongs to `Location` `l`. + */ + predicate shouldPrint(Element e, Location l) { e.fromSource() and l = e.getLocation() } +} + +private predicate shouldPrint(Element e, Location l) { + exists(PrintAstConfiguration config | config.shouldPrint(e, l)) +} + +private predicate isImplicitExpression(ControlFlowElement element) { + element.(Expr).isImplicit() and not exists(element.getAChild()) +} + +private predicate isFilteredCompilerGenerated(Declaration d) { + d.isCompilerGenerated() and + not d instanceof Accessor +} + +private predicate isNotNeeded(Element e) { + isFilteredCompilerGenerated(e) + or + e instanceof ConstructedGeneric + or + e instanceof AnonymousClass + or + e instanceof TupleType + or + isNotNeeded(e.(Declaration).getDeclaringType()) + or + isNotNeeded(e.(Parameter).getDeclaringElement()) + or + isNotNeeded(e.(Attribute).getTarget()) +} + +/** + * Retrieves the canonical QL class(es) for entity `el` + */ +private string getQlClass(Element el) { + result = "[" + concat(el.getAPrimaryQlClass(), ",") + "] " + // Alternative implementation -- do not delete. It is useful for QL class discovery. + // result = "["+ concat(el.getAQlClass(), ",") + "] " +} + +/** + * An `Element`, such as a `namespace` and a `partial class`, might have multiple locations. + * The locations are ordered by line, column, and then the first one is selected. + */ +private Location getRepresentativeLocation(Element ast) { + result = + min(Location loc | + shouldPrint(ast, loc) + | + loc order by loc.getStartLine(), loc.getStartColumn(), loc.getEndLine(), loc.getEndColumn() + ) +} + +private predicate locationSortKeys(Element ast, string file, int line, int column) { + exists(Location loc | + loc = getRepresentativeLocation(ast) and + file = loc.getFile().toString() and + line = loc.getStartLine() and + column = loc.getStartColumn() + ) + or + not exists(getRepresentativeLocation(ast)) and + file = "" and + line = 0 and + column = 0 +} + +private predicate hasInterestingBaseTypes(ValueOrRefType type) { + exists(getAnInterestingBaseType(type)) +} + +private ValueOrRefType getAnInterestingBaseType(ValueOrRefType type) { + not type instanceof TupleType and + not type instanceof ArrayType and + not type instanceof NullableType and + result = type.getABaseType() and + isInterestingBaseType(result) +} + +private predicate isInterestingBaseType(ValueOrRefType base) { + not base instanceof ObjectType and + not base.getQualifiedName() = "System.ValueType" and + not base.getQualifiedName() = "System.Delegate" and + not base.getQualifiedName() = "System.MulticastDelegate" and + not base.getQualifiedName() = "System.Enum" +} + +/** + * Printed AST nodes are mostly `Element`s of the underlying AST. + * There are extra AST nodes generated for parameters of `Parameterizable`s, + * attributes of `Attributable`s, type parameters of `UnboundGeneric` and + * base types of `ValueOrRefType` declarations. These extra nodes are used + * as containers to organize the tree a bit better. + */ +private newtype TPrintAstNode = + TElementNode(Element element) { shouldPrint(element, _) } or + TParametersNode(Parameterizable parameterizable) { + shouldPrint(parameterizable, _) and + parameterizable.getNumberOfParameters() > 0 and + not isNotNeeded(parameterizable) + } or + TAttributesNode(Attributable attributable) { + shouldPrint(attributable, _) and + exists(attributable.getAnAttribute()) and + not isNotNeeded(attributable) + } or + TTypeParametersNode(UnboundGeneric unboundGeneric) { + shouldPrint(unboundGeneric, _) and + unboundGeneric.getNumberOfTypeParameters() > 0 and + not isNotNeeded(unboundGeneric) + } or + TBaseTypesNode(ValueOrRefType type) { + shouldPrint(type, _) and + hasInterestingBaseTypes(type) and + not isNotNeeded(type) + } or + TBaseTypeNode(ValueOrRefType derived, ValueOrRefType base) { + shouldPrint(derived, _) and + base = getAnInterestingBaseType(derived) and + not isNotNeeded(derived) + } + +/** + * A node in the output tree. + */ +class PrintAstNode extends TPrintAstNode { + /** + * Gets a textual representation of this node in the PrintAst output tree. + */ + string toString() { none() } + + /** + * Gets the child node at index `childIndex`. Child indices must be unique, + * but need not be contiguous. + */ + PrintAstNode getChild(int childIndex) { none() } + + /** + * Gets a child of this node. + */ + final PrintAstNode getAChild() { result = getChild(_) } + + /** + * Gets the parent of this node, if any. + */ + final PrintAstNode getParent() { result.getAChild() = this } + + /** + * Gets the location of this node in the source code. + */ + Location getLocation() { none() } + + /** + * Gets the value of the property of this node, where the name of the property + * is `key`. + */ + string getProperty(string key) { + key = "semmle.label" and + result = toString() + } + + /** + * Gets the label for the edge from this node to the specified child. By + * default, this is just the index of the child, but subclasses can override + * this. + */ + string getChildEdgeLabel(int childIndex) { + exists(getChild(childIndex)) and + result = childIndex.toString() + } +} + +/** A top-level AST node. */ +class TopLevelPrintAstNode extends PrintAstNode { + TopLevelPrintAstNode() { not exists(this.getParent()) } + + private int getOrder() { + this = + rank[result](TopLevelPrintAstNode n, Location l | + l = n.getLocation() + | + n + order by + l.getFile().getRelativePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(), + l.getEndColumn() + ) + } + + override string getProperty(string key) { + result = super.getProperty(key) + or + key = "semmle.order" and + result = this.getOrder().toString() + } +} + +/** + * A node representing an AST node with an underlying `Element`. + */ +abstract class ElementNode extends PrintAstNode, TElementNode { + Element element; + + ElementNode() { this = TElementNode(element) } + + override string toString() { result = getQlClass(element) + element.toString() } + + override Location getLocation() { result = getRepresentativeLocation(element) } + + /** + * Gets the `Element` represented by this node. + */ + final Element getElement() { result = element } +} + +/** + * A node representing a `ControlFlowElement` (`Expr` or `Stmt`). + */ +class ControlFlowElementNode extends ElementNode { + ControlFlowElement controlFlowElement; + + ControlFlowElementNode() { + controlFlowElement = element and + // Removing implicit expressions + not isImplicitExpression(element) and + // Removing extra nodes that are generated for an `AssignOperation` + not exists(AssignOperation ao | + ao.hasExpandedAssignment() and + ( + ao.getExpandedAssignment() = controlFlowElement or + ao.getExpandedAssignment().getRValue() = controlFlowElement or + ao.getExpandedAssignment().getRValue().(BinaryOperation).getLeftOperand() = + controlFlowElement.getParent*() or + ao.getExpandedAssignment().getRValue().(OperatorCall).getChild(0) = + controlFlowElement.getParent*() + ) + ) and + not isNotNeeded(element.getParent+()) + } + + override ElementNode getChild(int childIndex) { + result.getElement() = controlFlowElement.getChild(childIndex) + } +} + +/** + * A node representing a `LocalFunctionStmt`. + * Each `LocalFunction` is displayed below its corresponding `LocalFunctionStmt`. + */ +final class LocalFunctionStmtNode extends ControlFlowElementNode { + LocalFunctionStmt stmt; + + LocalFunctionStmtNode() { stmt = element } + + override CallableNode getChild(int childIndex) { + childIndex = 0 and + result.getElement() = stmt.getLocalFunction() + } +} + +/** + * A node representing a `Callable`, such as method declaration. + */ +final class CallableNode extends ElementNode { + Callable callable; + + CallableNode() { + callable = element and + not isNotNeeded(callable) + } + + override PrintAstNode getChild(int childIndex) { + childIndex = 0 and + result.(AttributesNode).getAttributable() = callable + or + childIndex = 1 and + result.(TypeParametersNode).getUnboundGeneric() = callable + or + childIndex = 2 and + result.(ParametersNode).getParameterizable() = callable + or + childIndex = 3 and + result.(ElementNode).getElement() = callable.(Constructor).getInitializer() + or + childIndex = 4 and + result.(ElementNode).getElement() = callable.getBody() + } +} + +/** + * A node representing a `DeclarationWithAccessors`, such as property declaration. + */ +final class DeclarationWithAccessorsNode extends ElementNode { + DeclarationWithAccessors declaration; + + DeclarationWithAccessorsNode() { + declaration = element and + not isNotNeeded(declaration.getDeclaringType()) + } + + override PrintAstNode getChild(int childIndex) { + childIndex = 0 and + result.(AttributesNode).getAttributable() = declaration + or + childIndex = 1 and + result.(ParametersNode).getParameterizable() = declaration + or + childIndex = 2 and + result.(ElementNode).getElement() = declaration.(Property).getInitializer().getParent() + or + result.(ElementNode).getElement() = + rank[childIndex - 2](Element a, string file, int line, int column, string name | + a = declaration.getAnAccessor() and + locationSortKeys(a, file, line, column) and + name = a.toString() + | + a order by file, line, column, name + ) + } +} + +/** + * A node representing a `Field` declaration. + */ +final class FieldNode extends ElementNode { + Field field; + + FieldNode() { + field = element and + not field.getDeclaringType() instanceof TupleType and + not isNotNeeded(field.getDeclaringType()) + } + + override PrintAstNode getChild(int childIndex) { + childIndex = 0 and + result.(AttributesNode).getAttributable() = field + or + childIndex = 1 and + field.hasInitializer() and + ( + if field.getDeclaringType() instanceof Enum + then result.(ElementNode).getElement() = field.getInitializer() + else result.(ElementNode).getElement() = field.getInitializer().getParent() + ) + } +} + +/** + * A node representing a `Parameter` declaration. + */ +final class ParameterNode extends ElementNode { + Parameter param; + + ParameterNode() { + param = element and + not isNotNeeded(param.getDeclaringElement()) + } + + override Location getLocation() { + not param.hasExtensionMethodModifier() and result = super.getLocation() + or + // for extension method first parameters, we're choosing the shorter location of the two + param.hasExtensionMethodModifier() and + result = + min(Location loc | + shouldPrint(param, loc) and + loc.getStartLine() = loc.getEndLine() + | + loc order by loc.getEndColumn() - loc.getStartColumn() + ) + } + + override PrintAstNode getChild(int childIndex) { + childIndex = 0 and + result.(AttributesNode).getAttributable() = param + or + childIndex = 1 and + result.(ElementNode).getElement() = param.getDefaultValue() + } +} + +/** + * A node representing an `Attribute`. + */ +final class AttributeNode extends ElementNode { + Attribute attr; + + AttributeNode() { + attr = element and + not isNotNeeded(attr.getTarget()) + } + + override ElementNode getChild(int childIndex) { result.getElement() = attr.getChild(childIndex) } +} + +/** + * A node representing a `TypeParameter`. + */ +final class TypeParameterNode extends ElementNode { + TypeParameter typeParameter; + + TypeParameterNode() { + typeParameter = element and + not isNotNeeded(typeParameter.getDeclaringGeneric()) + } + + override ElementNode getChild(int childIndex) { none() } +} + +/** + * A node representing a `ValueOrRefType`. + */ +final class TypeNode extends ElementNode { + ValueOrRefType type; + + TypeNode() { + type = element and + not type instanceof TupleType and + not type instanceof ArrayType and + not type instanceof NullableType and + not isNotNeeded(type) + } + + override PrintAstNode getChild(int childIndex) { + childIndex = 0 and + result.(AttributesNode).getAttributable() = type + or + childIndex = 1 and + result.(TypeParametersNode).getUnboundGeneric() = type + or + childIndex = 2 and + result.(ParametersNode).getParameterizable() = type + or + childIndex = 3 and + result.(BaseTypesNode).getValueOrRefType() = type + or + result.(ElementNode).getElement() = + rank[childIndex - 3](Member m, string file, int line, int column | + m = type.getAMember() and + locationSortKeys(m, file, line, column) + | + m order by file, line, column + ) + } +} + +/** + * A node representing a `NamespaceDeclaration`. + */ +final class NamespaceNode extends ElementNode { + NamespaceDeclaration namespace; + + NamespaceNode() { namespace = element } + + override PrintAstNode getChild(int childIndex) { + result.(ElementNode).getElement() = + rank[childIndex](Element a, string file, int line, int column | + (a = namespace.getAChildNamespaceDeclaration() or a = namespace.getATypeDeclaration()) and + locationSortKeys(a, file, line, column) + | + a order by file, line, column + ) + } +} + +/** + * A node representing the parameters of a `Parameterizable`. + * Only rendered if there's at least one parameter and if the + * `Parameterizable` is not compiler generated or is of type + * `Accessor`. + */ +final class ParametersNode extends PrintAstNode, TParametersNode { + Parameterizable parameterizable; + + ParametersNode() { this = TParametersNode(parameterizable) } + + override string toString() { result = "(Parameters)" } + + override Location getLocation() { none() } + + override ParameterNode getChild(int childIndex) { + result.getElement() = parameterizable.getParameter(childIndex) + } + + /** + * Gets the underlying `Parameterizable` + */ + Parameterizable getParameterizable() { result = parameterizable } +} + +/** + * A node representing the attributes of an `Attributable`. + * Only rendered if there's at least one attribute. + */ +final class AttributesNode extends PrintAstNode, TAttributesNode { + Attributable attributable; + + AttributesNode() { this = TAttributesNode(attributable) } + + override string toString() { result = "(Attributes)" } + + override Location getLocation() { none() } + + override AttributeNode getChild(int childIndex) { + result.getElement() = + rank[childIndex](Attribute a, string file, int line, int column | + a = attributable.getAnAttribute() and + locationSortKeys(a, file, line, column) + | + a order by file, line, column + ) + } + + /** + * Gets the underlying `Attributable` + */ + Attributable getAttributable() { result = attributable } +} + +/** + * A node representing the type parameters of an `UnboundGeneric`. + */ +final class TypeParametersNode extends PrintAstNode, TTypeParametersNode { + UnboundGeneric unboundGeneric; + + TypeParametersNode() { this = TTypeParametersNode(unboundGeneric) } + + override string toString() { result = "(Type parameters)" } + + override Location getLocation() { none() } + + override TypeParameterNode getChild(int childIndex) { + result.getElement() = unboundGeneric.getTypeParameter(childIndex) + } + + /** + * Gets the underlying `UnboundGeneric` + */ + UnboundGeneric getUnboundGeneric() { result = unboundGeneric } +} + +/** + * A node representing the base types of a `ValueOrRefType`. + */ +final class BaseTypesNode extends PrintAstNode, TBaseTypesNode { + ValueOrRefType valueOrRefType; + + BaseTypesNode() { this = TBaseTypesNode(valueOrRefType) } + + override string toString() { result = "(Base types)" } + + override Location getLocation() { none() } + + override BaseTypeNode getChild(int childIndex) { + childIndex = 0 and + result.getBaseType() = valueOrRefType.getBaseClass() and + result.getDerivedType() = valueOrRefType + or + result.getBaseType() = + rank[childIndex](ValueOrRefType base, string name | + base = valueOrRefType.getABaseInterface() and + name = base.toString() + | + base order by name + ) and + result.getDerivedType() = valueOrRefType + } + + /** + * Gets the underlying `ValueOrRefType` + */ + ValueOrRefType getValueOrRefType() { result = valueOrRefType } +} + +/** + * A node representing a base type reference of a `ValueOrRefType` declaration. + */ +final class BaseTypeNode extends PrintAstNode, TBaseTypeNode { + ValueOrRefType derived; + ValueOrRefType base; + + BaseTypeNode() { this = TBaseTypeNode(derived, base) } + + override string toString() { result = getQlClass(base) + base.toString() } + + override Location getLocation() { result = derived.getLocation() } + + override BaseTypeNode getChild(int childIndex) { none() } + + /** + * Gets the underlying derived `ValueOrRefType` + */ + ValueOrRefType getDerivedType() { result = derived } + + /** + * Gets the underlying base `ValueOrRefType` + */ + ValueOrRefType getBaseType() { result = base } +} + +/** Holds if `node` belongs to the output tree, and its property `key` has the given `value`. */ +query predicate nodes(PrintAstNode node, string key, string value) { value = node.getProperty(key) } + +/** + * Holds if `target` is a child of `source` in the AST, and property `key` of the edge has the + * given `value`. + */ +query predicate edges(PrintAstNode source, PrintAstNode target, string key, string value) { + exists(int childIndex | + target = source.getChild(childIndex) and + ( + key = "semmle.label" and value = source.getChildEdgeLabel(childIndex) + or + key = "semmle.order" and value = childIndex.toString() + ) + ) +} + +/** Holds if property `key` of the graph has the given `value`. */ +query predicate graphProperties(string key, string value) { + key = "semmle.graphKind" and value = "tree" +} diff --git a/csharp/ql/src/semmle/code/csharp/Property.qll b/csharp/ql/src/semmle/code/csharp/Property.qll index d7013927846d..f50daf58f901 100644 --- a/csharp/ql/src/semmle/code/csharp/Property.qll +++ b/csharp/ql/src/semmle/code/csharp/Property.qll @@ -2,12 +2,13 @@ * Provides classes for properties, indexers, and accessors. */ -import Type import Member import Stmt -private import semmle.code.csharp.ExprOrStmtParent -private import dotnet +import Type private import cil +private import dotnet +private import semmle.code.csharp.ExprOrStmtParent +private import TypeRef /** * A declaration that may have accessors. Either an event (`Event`), a property @@ -106,7 +107,7 @@ class DeclarationWithGetSetAccessors extends DeclarationWithAccessors, TopLevelE /** * A property, for example `P` on line 2 in * - * ``` + * ```csharp * class C { * public int P { get; set; } * } @@ -123,7 +124,7 @@ class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @proper * Holds if this property is automatically implemented. For example, `P1` * on line 2 is automatically implemented, while `P2` on line 5 is not in * - * ``` + * ```csharp * class C { * public int P1 { get; set; } * @@ -195,7 +196,7 @@ class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @proper * Gets the initial value of this property, if any. For example, the initial * value of `P` on line 2 is `20` in * - * ``` + * ```csharp * class C { * public int P { get; set; } = 20; * } @@ -207,7 +208,7 @@ class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @proper * Holds if this property has an initial value. For example, the initial * value of `P` on line 2 is `20` in * - * ``` + * ```csharp * class C { * public int P { get; set; } = 20; * } @@ -219,7 +220,7 @@ class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @proper * Gets the expression body of this property, if any. For example, the expression * body of `P` on line 2 is `20` in * - * ``` + * ```csharp * class C { * public int P => 20; * } @@ -232,12 +233,14 @@ class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @proper override Getter getGetter() { result = DeclarationWithGetSetAccessors.super.getGetter() } override Setter getSetter() { result = DeclarationWithGetSetAccessors.super.getSetter() } + + override string getAPrimaryQlClass() { result = "Property" } } /** * An indexer, for example `string this[int i]` on line 2 in * - * ``` + * ```csharp * class C { * public string this[int i] { * get { return i.ToString(); } @@ -261,7 +264,7 @@ class Indexer extends DeclarationWithGetSetAccessors, Parameterizable, @indexer * Gets the expression body of this indexer, if any. For example, the * expression body of the indexer on line 2 is `20` in * - * ``` + * ```csharp * class C { * public int this[int i] => 20; * } @@ -298,6 +301,8 @@ class Indexer extends DeclarationWithGetSetAccessors, Parameterizable, @indexer override Location getALocation() { indexer_location(this, result) } override string toStringWithTypes() { result = getName() + "[" + parameterTypesToString() + "]" } + + override string getAPrimaryQlClass() { result = "Indexer" } } /** @@ -314,7 +319,7 @@ class Accessor extends Callable, Modifiable, Attributable, @callable_accessor { * Gets the declaration that this accessor belongs to. For example, both * accessors on lines 3 and 4 belong to the property `P` on line 2 in * - * ``` + * ```csharp * class C { * public int P { * get; @@ -330,7 +335,7 @@ class Accessor extends Callable, Modifiable, Attributable, @callable_accessor { * the `get` accessor on line 3 has no access modifier and the `set` accessor * on line 4 has a `private` access modifier in * - * ``` + * ```csharp * class C { * public int P { * get; @@ -349,7 +354,7 @@ class Accessor extends Callable, Modifiable, Attributable, @callable_accessor { * has the modifiers `public` and `virtual`, and the `set` accessor on line 4 * has the modifiers `private` and `virtual` in * - * ``` + * ```csharp * class C { * public virtual int P { * get; @@ -375,7 +380,7 @@ class Accessor extends Callable, Modifiable, Attributable, @callable_accessor { /** * A `get` accessor, for example `get { return p; }` in * - * ``` + * ```csharp * public class C { * int p; * public int P { @@ -394,7 +399,7 @@ class Getter extends Accessor, @getter { * Gets the field used in the trival implementation of this getter, if any. * For example, the field `p` in * - * ``` + * ```csharp * public class C { * int p; * public int P { @@ -415,12 +420,14 @@ class Getter extends Accessor, @getter { override DeclarationWithGetSetAccessors getDeclaration() { result = Accessor.super.getDeclaration() } + + override string getAPrimaryQlClass() { result = "Getter" } } /** * A `set` accessor, for example `set { p = value; }` in * - * ``` + * ```csharp * public class C { * int p; * public int P { @@ -442,7 +449,7 @@ class Setter extends Accessor, @setter { * Gets the field used in the trival implementation of this setter, if any. * For example, the field `p` in * - * ``` + * ```csharp * public class C { * int p; * public int P { @@ -464,6 +471,8 @@ class Setter extends Accessor, @setter { override DeclarationWithGetSetAccessors getDeclaration() { result = Accessor.super.getDeclaration() } + + override string getAPrimaryQlClass() { result = "Setter" } } /** @@ -478,7 +487,7 @@ private ParameterAccess accessToValue() { * A property with a trivial getter and setter. For example, properties `P1` * and `P2` are trivial, while `P3` is not, in * - * ``` + * ```csharp * public class C { * int p1; * public int P1 { @@ -536,7 +545,7 @@ class IndexerProperty extends Property { // too many indexer calls, for example the call to the indexer // setter at `dict[0]` in // - // ``` + // ```csharp // class A // { // Dictionary dict; @@ -554,4 +563,6 @@ class IndexerProperty extends Property { // ``` result.getIndexer() = i } + + override string getAPrimaryQlClass() { result = "IndexerProperty" } } diff --git a/csharp/ql/src/semmle/code/csharp/Stmt.qll b/csharp/ql/src/semmle/code/csharp/Stmt.qll index 6b64abe88aac..8fadbc1267b4 100644 --- a/csharp/ql/src/semmle/code/csharp/Stmt.qll +++ b/csharp/ql/src/semmle/code/csharp/Stmt.qll @@ -4,12 +4,13 @@ * All statements have the common base class `Stmt`. */ -import Location import Element +import Location import Member import exprs.Expr private import semmle.code.csharp.Enclosing::Internal private import semmle.code.csharp.frameworks.System +private import TypeRef /** * A statement. @@ -44,7 +45,7 @@ class Stmt extends ControlFlowElement, @stmt { /** * A block statement, for example * - * ``` + * ```csharp * { * ... * } @@ -76,12 +77,14 @@ class BlockStmt extends Stmt, @block_stmt { } override string toString() { result = "{...}" } + + override string getAPrimaryQlClass() { result = "BlockStmt" } } /** * An expression statement, for example `M1()` on line 5 * - * ``` + * ```csharp * class C { * int M1() { ... } * @@ -96,6 +99,8 @@ class ExprStmt extends Stmt, @expr_stmt { Expr getExpr() { result.getParent() = this } override string toString() { result = "...;" } + + override string getAPrimaryQlClass() { result = "ExprStmt" } } /** @@ -111,7 +116,7 @@ class SelectionStmt extends Stmt, @cond_stmt { /** * An `if` statement, for example * - * ``` + * ```csharp * if (x==0) { * ... * } else { @@ -131,12 +136,14 @@ class IfStmt extends SelectionStmt, @if_stmt { Stmt getElse() { result = this.getChild(2) } override string toString() { result = "if (...) ..." } + + override string getAPrimaryQlClass() { result = "IfStmt" } } /** * A `switch` statement, for example * - * ``` + * ```csharp * switch (instruction) { * ... * } @@ -152,7 +159,7 @@ class SwitchStmt extends SelectionStmt, Switch, @switch_stmt { * * Example: * - * ``` + * ```csharp * switch (x) { * case "abc": // i = 0 * return 0; @@ -180,12 +187,14 @@ class SwitchStmt extends SelectionStmt, Switch, @switch_stmt { override string toString() { result = "switch (...) {...}" } + override string getAPrimaryQlClass() { result = "SwitchStmt" } + /** * Gets the `i`th statement in the body of this `switch` statement. * * Example: * - * ``` + * ```csharp * switch (x) { * case "abc": // i = 0 * return 0; @@ -268,7 +277,7 @@ class CaseStmt extends Case, @case_stmt { * Gets the condition on this case, if any. For example, the type case on line 3 * has no condition, and the type case on line 4 has condition `s.Length > 0`, in * - * ``` + * ```csharp * switch(p) * { * case int i: @@ -284,13 +293,15 @@ class CaseStmt extends Case, @case_stmt { SwitchStmt getSwitchStmt() { result.getACase() = this } override string toString() { result = "case ...:" } + + override string getAPrimaryQlClass() { result = "CaseStmt" } } /** * A constant case of a `switch` statement, for example `case OpCode.Nop:` * on line 2 in * - * ``` + * ```csharp * switch (instruction) { * case OpCode.Nop: ... * default: ... @@ -305,13 +316,15 @@ class ConstCase extends CaseStmt, LabeledStmt { override string getLabel() { result = p.getValue() } override string toString() { result = CaseStmt.super.toString() } + + override string getAPrimaryQlClass() { result = "ConstCase" } } /** * A default case of a `switch` statement, for example `default:` on * line 3 in * - * ``` + * ```csharp * switch (instruction) { * case OpCode.Nop: ... * default: ... @@ -324,6 +337,8 @@ class DefaultCase extends CaseStmt, LabeledStmt { override string getLabel() { result = "default" } override string toString() { result = "default:" } + + override string getAPrimaryQlClass() { result = "DefaultCase" } } /** @@ -344,7 +359,7 @@ class LoopStmt extends Stmt, @loop_stmt { /** * A `while` statement, for example * - * ``` + * ```csharp * while (remaining > 0) { * ... * } @@ -354,12 +369,14 @@ class WhileStmt extends LoopStmt, @while_stmt { override Expr getCondition() { result.getParent() = this } override string toString() { result = "while (...) ..." } + + override string getAPrimaryQlClass() { result = "WhileStmt" } } /** * A `do`-`while` statement, for example * - * ``` + * ```csharp * do { * ... * } @@ -370,12 +387,14 @@ class DoStmt extends LoopStmt, @do_stmt { override Expr getCondition() { result.getParent() = this } override string toString() { result = "do ... while (...);" } + + override string getAPrimaryQlClass() { result = "DoStmt" } } /** * A `for` loop, for example * - * ``` + * ```csharp * for (int i = 0; i < 10; i++) { * ... * } @@ -387,7 +406,7 @@ class ForStmt extends LoopStmt, @for_stmt { * * For example, `i = 0` in * - * ``` + * ```csharp * for (int i = 0; i < 10; i++) { * ... * } @@ -401,7 +420,7 @@ class ForStmt extends LoopStmt, @for_stmt { * * For example, the second (`n = 1`) initializer is `j = 10` in * - * ``` + * ```csharp * for (int i = 0, j = 10; i < j; i++) { * ... * } @@ -418,7 +437,7 @@ class ForStmt extends LoopStmt, @for_stmt { * * For example, `i++` in * - * ``` + * ```csharp * for (int i = 0; i < 10; i++) { * ... * } @@ -431,7 +450,7 @@ class ForStmt extends LoopStmt, @for_stmt { * * For example, the second (`n = 1`) update expression is `j--` in * - * ``` + * ```csharp * for (int i = 0, j = 10; i < j; i++, j--) { * ... * } @@ -440,12 +459,14 @@ class ForStmt extends LoopStmt, @for_stmt { Expr getUpdate(int n) { exists(int i | result = this.getChild(i) and n = i - 1 and i >= 1) } override string toString() { result = "for (...;...;...) ..." } + + override string getAPrimaryQlClass() { result = "ForStmt" } } /** * A `foreach` loop, for example * - * ``` + * ```csharp * foreach (var item in items) { * ... * } @@ -457,7 +478,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * * For example, `item` in * - * ``` + * ```csharp * foreach (var item in items) { * ... * } @@ -470,7 +491,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * * For example, `var item` in * - * ``` + * ```csharp * foreach (var item in items) { * ... * } @@ -483,7 +504,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * * For example, `int a` is the 0th local variable declaration in * - * ``` + * ```csharp * foreach ((int a, int b) in items) { * ... * } @@ -499,7 +520,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * Gets the local variable declaration tuple of this `foreach` loop, if any. * For example, `(int a, int b)` in * - * ``` + * ```csharp * foreach ((int a, int b) in items) { * ... * } @@ -512,7 +533,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * * For example, `a` is the 0th local variable in * - * ``` + * ```csharp * foreach ((int a, int b) in items) { * ... * } @@ -525,7 +546,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * * For example, `a` and `b` in * - * ``` + * ```csharp * foreach ((int a, int b) in items) { * ... * } @@ -538,7 +559,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * * For example, `int a` and `int b` in * - * ``` + * ```csharp * foreach ((int a, int b) in items) { * ... * } @@ -553,7 +574,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * * For example, `items` in * - * ``` + * ```csharp * foreach (var item in items) { * ... * } @@ -562,6 +583,8 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { Expr getIterableExpr() { result = this.getChild(1) } override string toString() { result = "foreach (... ... in ...) ..." } + + override string getAPrimaryQlClass() { result = "ForeachStmt" } } /** @@ -576,7 +599,7 @@ class JumpStmt extends Stmt, @jump_stmt { } /** * A `break` statement, for example line 4 in * - * ``` + * ```csharp * while (true) { * ... * if (done) @@ -586,12 +609,14 @@ class JumpStmt extends Stmt, @jump_stmt { } */ class BreakStmt extends JumpStmt, @break_stmt { override string toString() { result = "break;" } + + override string getAPrimaryQlClass() { result = "BreakStmt" } } /** * A `continue` statement, for example line 4 in * - * ``` + * ```csharp * while (true) { * ... * if (!done) @@ -602,6 +627,8 @@ class BreakStmt extends JumpStmt, @break_stmt { */ class ContinueStmt extends JumpStmt, @continue_stmt { override string toString() { result = "continue;" } + + override string getAPrimaryQlClass() { result = "ContinueStmt" } } /** @@ -618,7 +645,7 @@ class GotoStmt extends JumpStmt, @goto_any_stmt { /** * A `goto` statement that jumps to a labeled statement, for example line 4 in * - * ``` + * ```csharp * while (true) { * ... * if (done) @@ -637,6 +664,8 @@ class GotoLabelStmt extends GotoStmt, @goto_stmt { result.getEnclosingCallable() = getEnclosingCallable() and result.getLabel() = getLabel() } + + override string getAPrimaryQlClass() { result = "GotoLabelStmt" } } /** @@ -644,7 +673,7 @@ class GotoLabelStmt extends GotoStmt, @goto_stmt { * * For example, line 5 in * - * ``` + * ```csharp * switch (x) { * case 0 : * return 1; @@ -662,6 +691,8 @@ class GotoCaseStmt extends GotoStmt, @goto_case_stmt { override string getLabel() { result = getExpr().getValue() } override string toString() { result = "goto case ...;" } + + override string getAPrimaryQlClass() { result = "GotoCaseStmt" } } /** @@ -669,7 +700,7 @@ class GotoCaseStmt extends GotoStmt, @goto_case_stmt { * * For example, line 5 in * - * ``` + * ```csharp * switch (x) { * case 0 : * return 1; @@ -684,12 +715,14 @@ class GotoDefaultStmt extends GotoStmt, @goto_default_stmt { override string toString() { result = "goto default;" } override string getLabel() { result = "default" } + + override string getAPrimaryQlClass() { result = "GotoDefaultStmt" } } /** * A `throw` statement, for example line 3 in * - * ``` + * ```csharp * void M(string s) { * if (s == null) * throw new ArgumentNullException(nameof(s)); @@ -714,6 +747,8 @@ class ThrowStmt extends JumpStmt, ThrowElement, @throw_stmt { result = mid.getParent() ) } + + override string getAPrimaryQlClass() { result = "ThrowStmt" } } /** @@ -727,7 +762,7 @@ class ExceptionClass extends Class { /** * A `return` statement, for example line 2 in * - * ``` + * ```csharp * int M() { * return 0; * } @@ -738,6 +773,8 @@ class ReturnStmt extends JumpStmt, @return_stmt { Expr getExpr() { result.getParent() = this } override string toString() { result = "return ...;" } + + override string getAPrimaryQlClass() { result = "ReturnStmt" } } /** @@ -754,7 +791,7 @@ class YieldStmt extends JumpStmt, @yield_stmt { /** * A `yield break` statement, for example line 6 in * - * ``` + * ```csharp * IEnumerable DownFrom(int i) { * while (true) { * if (i > 0) @@ -769,12 +806,14 @@ class YieldBreakStmt extends YieldStmt { YieldBreakStmt() { not exists(this.getExpr()) } override string toString() { result = "yield break;" } + + override string getAPrimaryQlClass() { result = "YieldBreakStmt" } } /** * A `yield return` statement, for example line 4 in * - * ``` + * ```csharp * IEnumerable DownFrom(int i) { * while (true) { * if (i > 0) @@ -789,12 +828,14 @@ class YieldReturnStmt extends YieldStmt { YieldReturnStmt() { exists(this.getExpr()) } override string toString() { result = "yield return ...;" } + + override string getAPrimaryQlClass() { result = "YieldReturnStmt" } } /** * A `try` statement, for example * - * ``` + * ```csharp * try { * ... * } @@ -824,6 +865,8 @@ class TryStmt extends Stmt, @try_stmt { override string toString() { result = "try {...} ..." } + override string getAPrimaryQlClass() { result = "TryStmt" } + /** Gets the `catch` clause that handles an exception of type `ex`, if any. */ CatchClause getAnExceptionHandler(ExceptionClass ex) { result = clauseHandlesException(ex, 0) } @@ -900,7 +943,7 @@ class CatchClause extends Stmt, @catch { * Gets the type of the exception caught. For example, the type of the exception * caught on line 4 is `System.IO.IOException` in * - * ``` + * ```csharp * try { * ... * } @@ -915,7 +958,7 @@ class CatchClause extends Stmt, @catch { * Gets the `catch` filter clause, if any. For example, the filter expression * of the catch clause on line 4 is `ex.HResult == 1` in * - * ``` + * ```csharp * try { * ... * } @@ -944,7 +987,7 @@ class CatchClause extends Stmt, @catch { * * For example, the `catch` clause on line 4 in * - * ``` + * ```csharp * try { * ... * } @@ -965,6 +1008,8 @@ class SpecificCatchClause extends CatchClause { LocalVariableDeclExpr getVariableDeclExpr() { result.getParent() = this } override string toString() { result = "catch (...) {...}" } + + override string getAPrimaryQlClass() { result = "SpecificCatchClause" } } /** @@ -972,7 +1017,7 @@ class SpecificCatchClause extends CatchClause { * * For example, the `catch` clause on line 4 in * - * ``` + * ```csharp * try { * ... * } @@ -985,12 +1030,14 @@ class GeneralCatchClause extends CatchClause { GeneralCatchClause() { catch_type(this, _, 2) } override string toString() { result = "catch {...}" } + + override string getAPrimaryQlClass() { result = "GeneralCatchClause" } } /** * A `checked` statement, for example * - * ``` + * ```csharp * checked { * int i = 2147483647; * i++; @@ -1002,12 +1049,14 @@ class CheckedStmt extends Stmt, @checked_stmt { BlockStmt getBlock() { result.getParent() = this } override string toString() { result = "checked {...}" } + + override string getAPrimaryQlClass() { result = "CheckedStmt" } } /** * An `unchecked` statement, for example * - * ``` + * ```csharp * unchecked { * int i = 2147483647; * i++; @@ -1019,12 +1068,14 @@ class UncheckedStmt extends Stmt, @unchecked_stmt { BlockStmt getBlock() { result.getParent() = this } override string toString() { result = "unchecked {...}" } + + override string getAPrimaryQlClass() { result = "UncheckedStmt" } } /** * A `lock` statement, for example * - * ``` + * ```csharp * lock (mutex) { * ... * } @@ -1056,6 +1107,8 @@ class LockStmt extends Stmt, @lock_stmt { /** Gets the type `T` if this statement is of the form `lock(typeof(T)) { ... }`. */ Type getLockTypeObject() { result = getExpr().(TypeofExpr).getTypeAccess().getTarget() } + + override string getAPrimaryQlClass() { result = "LockStmt" } } /** @@ -1074,7 +1127,7 @@ class UsingStmt extends Stmt, @using_stmt { * expression assigned to a variable, for example `File.Open("settings.xml")` * in * - * ``` + * ```csharp * using (FileStream f = File.Open("settings.xml")) { * ... * } @@ -1083,7 +1136,7 @@ class UsingStmt extends Stmt, @using_stmt { * or an expression directly used, for example `File.Open("settings.xml")` * in * - * ``` + * ```csharp * using (File.Open("settings.xml")) { * ... * } @@ -1095,7 +1148,7 @@ class UsingStmt extends Stmt, @using_stmt { /** * A `using` block statement, for example * - * ``` + * ```csharp * using (FileStream f = File.Open("settings.xml")) { * ... * } @@ -1115,7 +1168,7 @@ class UsingBlockStmt extends UsingStmt, @using_block_stmt { * Gets the expression directly used by this `using` statement, if any. For * example, `f` on line 2 in * - * ``` + * ```csharp * var f = File.Open("settings.xml"); * using (f) { * ... @@ -1134,12 +1187,14 @@ class UsingBlockStmt extends UsingStmt, @using_block_stmt { Stmt getBody() { result.getParent() = this } override string toString() { result = "using (...) {...}" } + + override string getAPrimaryQlClass() { result = "UsingBlockStmt" } } /** * A local declaration statement, for example line 2 in * - * ``` + * ```csharp * void M() { * string x = null, y = ""; * } @@ -1150,7 +1205,7 @@ class LocalVariableDeclStmt extends Stmt, @decl_stmt { * Gets a local variable declaration, for example `x = null` and * `y = ""` in * - * ``` + * ```csharp * void M() { * string x = null, y = ""; * } @@ -1162,7 +1217,7 @@ class LocalVariableDeclStmt extends Stmt, @decl_stmt { * Gets the `n`th local variable declaration. For example, the second * (`n = 1`) declaration is `y = ""` in * - * ``` + * ```csharp * void M() { * string x = null, y = ""; * } @@ -1171,12 +1226,14 @@ class LocalVariableDeclStmt extends Stmt, @decl_stmt { LocalVariableDeclExpr getVariableDeclExpr(int n) { result = this.getChild(n) } override string toString() { result = "... ...;" } + + override string getAPrimaryQlClass() { result = "LocalVariableDeclStmt" } } /** * A local constant declaration statement, for example line 2 in * - * ``` + * ```csharp * void M() { * const int x = 1, y = 2; * } @@ -1186,7 +1243,7 @@ class LocalConstantDeclStmt extends LocalVariableDeclStmt, @const_decl_stmt { /** * Gets a local constant declaration, for example `x = 1` and `y = 2` in * - * ``` + * ```csharp * void M() { * const int x = 1, y = 2; * } @@ -1198,7 +1255,7 @@ class LocalConstantDeclStmt extends LocalVariableDeclStmt, @const_decl_stmt { * Gets the `n`th local constant declaration. For example, the second * (`n = 1`) declaration is `y = 2` in * - * ``` + * ```csharp * void M() { * const int x = 1, y = 2; * } @@ -1207,12 +1264,14 @@ class LocalConstantDeclStmt extends LocalVariableDeclStmt, @const_decl_stmt { override LocalConstantDeclExpr getVariableDeclExpr(int n) { result = this.getChild(n) } override string toString() { result = "const ... ...;" } + + override string getAPrimaryQlClass() { result = "LocalConstantDeclStmt" } } /** * A `using` declaration statement, for example * - * ``` + * ```csharp * using FileStream f = File.Open("settings.xml"); * ``` */ @@ -1228,12 +1287,14 @@ class UsingDeclStmt extends LocalVariableDeclStmt, UsingStmt, @using_decl_stmt { } override Expr getAnExpr() { result = this.getAVariableDeclExpr().getInitializer() } + + override string getAPrimaryQlClass() { result = "UsingDeclStmt" } } /** * An empty statement, for example line 2 in * - * ``` + * ```csharp * while (true) do { * ; * } @@ -1241,12 +1302,14 @@ class UsingDeclStmt extends LocalVariableDeclStmt, UsingStmt, @using_decl_stmt { */ class EmptyStmt extends Stmt, @empty_stmt { override string toString() { result = ";" } + + override string getAPrimaryQlClass() { result = "EmptyStmt" } } /** * An `unsafe` statement, for example * - * ``` + * ```csharp * unsafe { * var data = new int[10]; * fixed (int* p = data) { @@ -1260,12 +1323,14 @@ class UnsafeStmt extends Stmt, @unsafe_stmt { BlockStmt getBlock() { result.getParent() = this } override string toString() { result = "unsafe {...}" } + + override string getAPrimaryQlClass() { result = "UnsafeStmt" } } /** * A `fixed` statement, for example lines 3--5 in * - * ``` + * ```csharp * unsafe { * var data = new int[10]; * fixed (int* p = data) { @@ -1291,12 +1356,14 @@ class FixedStmt extends Stmt, @fixed_stmt { Stmt getBody() { result.getParent() = this } override string toString() { result = "fixed(...) { ... }" } + + override string getAPrimaryQlClass() { result = "FixedStmt" } } /** * A label statement, for example line 7 in * - * ``` + * ```csharp * while (true) { * if (done) * goto exit; @@ -1306,7 +1373,9 @@ class FixedStmt extends Stmt, @fixed_stmt { * exit: ... * ``` */ -class LabelStmt extends LabeledStmt, @label_stmt { } +class LabelStmt extends LabeledStmt, @label_stmt { + override string getAPrimaryQlClass() { result = "LabelStmt" } +} /** * A labeled statement. @@ -1319,7 +1388,7 @@ class LabeledStmt extends Stmt, @labeled_stmt { * * For example, the `return` statement in * - * ``` + * ```csharp * exit: * return MetadataToken.Zero; * ``` @@ -1341,7 +1410,7 @@ class LabeledStmt extends Stmt, @labeled_stmt { * A statement defining a local function. For example, * the statement on lines 2--4 in * - * ``` + * ```csharp * int Choose(int n, int m) { * int Fac(int x) { * return x > 1 ? x * Fac(x - 1) : 1; @@ -1356,4 +1425,6 @@ class LocalFunctionStmt extends Stmt, @local_function_stmt { LocalFunction getLocalFunction() { local_function_stmts(this, result) } override string toString() { result = getLocalFunction().getName() + "(...)" } + + override string getAPrimaryQlClass() { result = "LocalFunctionStmt" } } diff --git a/csharp/ql/src/semmle/code/csharp/Type.qll b/csharp/ql/src/semmle/code/csharp/Type.qll index fef53c086415..f3cadbd1237d 100644 --- a/csharp/ql/src/semmle/code/csharp/Type.qll +++ b/csharp/ql/src/semmle/code/csharp/Type.qll @@ -1,14 +1,15 @@ /** Provides classes for types. */ -import Location -import Namespace import Callable -import Property import Event import Generics +import Location +import Namespace +import Property private import Conversion -private import semmle.code.csharp.metrics.Coupling private import dotnet +private import semmle.code.csharp.metrics.Coupling +private import TypeRef /** * A type. @@ -45,6 +46,9 @@ class Type extends DotNet::Type, Member, TypeContainer, @type { predicate isValueType() { none() } } +pragma[nomagic] +private predicate isObjectClass(Class c) { c instanceof ObjectType } + /** * A value or reference type. * @@ -96,7 +100,7 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_ * In the following example, only the class `C2` has a parent namespace declaration * returned by `getParentNamespaceDeclaration`. * - * ``` + * ```csharp * class C1 { ... } * * namespace N { @@ -111,7 +115,15 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_ } /** Gets the immediate base class of this class, if any. */ - Class getBaseClass() { extend(this, getTypeRef(result)) } + final Class getBaseClass() { + extend(this, getTypeRef(result)) + or + not extend(this, _) and + not isObjectClass(this) and + not this instanceof DynamicType and + not this instanceof NullType and + isObjectClass(result) + } /** Gets an immediate base interface of this type, if any. */ Interface getABaseInterface() { implement(this, getTypeRef(result)) } @@ -140,7 +152,7 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_ * * For example, `C` has the methods `A.M1()`, `B.M3()`, and `C.M4()` in * - * ``` + * ```csharp * class A { * public void M1() { } * private void M2() { } @@ -165,7 +177,7 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_ * For example, `C` has the callables `A.get_P1`, `A.set_P1`, `A.M2()`, `B.get_P2`, * `B.set_P2`, and `C.M3()` in * - * ``` + * ```csharp * class A { * public int P1 { get; set; } * public virtual int P2 { get; set; } @@ -194,7 +206,7 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_ * * For example, `C` has the members `A.P1`, `A.M2()`, `B.P2`, and `C.M3()` in * - * ``` + * ```csharp * class A { * public int P1 { get; set; } * public virtual int P2 { get; set; } @@ -368,7 +380,7 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_ /** * A nested type, for example `class B` in * - * ``` + * ```csharp * class A { * class B { * ... @@ -608,7 +620,7 @@ class DecimalType extends SimpleType, @decimal_type { /** * An `enum`. For example * - * ``` + * ```csharp * enum Parity { * Even, * Odd @@ -622,7 +634,7 @@ class Enum extends ValueType, @enum_type { * * For example, the underlying type of `Parity` is `int` in * - * ``` + * ```csharp * enum Parity : int { * Even, * Odd @@ -635,11 +647,12 @@ class Enum extends ValueType, @enum_type { * Gets an `enum` constant declared in this `enum`, for example `Even` * and `Odd` in * - * ``` + * ```csharp * enum Parity : int { * Even, * Odd * } + * ``` */ EnumConstant getAnEnumConstant() { result.getDeclaringEnum() = this } @@ -647,12 +660,14 @@ class Enum extends ValueType, @enum_type { EnumConstant getEnumConstant(string value) { result = this.getAnEnumConstant() and result.getValue() = value } + + override string getAPrimaryQlClass() { result = "Enum" } } /** * A `struct`, for example * - * ``` + * ```csharp * struct S { * ... * } @@ -664,6 +679,8 @@ class Struct extends ValueType, @struct_type { /** Holds if this `struct` has a `readonly` modifier. */ predicate isReadonly() { hasModifier("readonly") } + + override string getAPrimaryQlClass() { result = "Struct" } } /** @@ -706,20 +723,22 @@ private predicate isNonOverridden(Member m) { not m.(Virtualizable).isOverridden /** * A `class`, for example * - * ``` + * ```csharp * class C { * ... * } * ``` */ -class Class extends RefType, @class_type { } +class Class extends RefType, @class_type { + override string getAPrimaryQlClass() { result = "Class" } +} /** * A class generated by the compiler from an anonymous object creation. * * For example, the class with fields `X` and `Y` in * - * ``` + * ```csharp * new { X = 0, Y = 0 }; * ``` */ @@ -748,18 +767,20 @@ class StringType extends Class { /** * An `interface`, for example * - * ``` + * ```csharp * interface I { * ... * } * ``` */ -class Interface extends RefType, @interface_type { } +class Interface extends RefType, @interface_type { + override string getAPrimaryQlClass() { result = "Interface" } +} /** * A `delegate` type, for example * - * ``` + * ```csharp * delegate int D(int p); * ``` */ @@ -769,6 +790,8 @@ class DelegateType extends RefType, Parameterizable, @delegate_type { /** Gets the annotated return type of this delegate. */ AnnotatedType getAnnotatedReturnType() { result.appliesTo(this) } + + override string getAPrimaryQlClass() { result = "DelegateType" } } /** @@ -793,6 +816,8 @@ class NullableType extends ValueType, DotNet::ConstructedGeneric, @nullable_type override Location getALocation() { result = getUnderlyingType().getALocation() } override Type getTypeArgument(int p) { p = 0 and result = getUnderlyingType() } + + override string getAPrimaryQlClass() { result = "NullableType" } } /** @@ -874,6 +899,8 @@ class PointerType extends DotNet::PointerType, Type, @pointer_type { override Location getALocation() { result = getReferentType().getALocation() } override string toString() { result = DotNet::PointerType.super.toString() } + + override string getAPrimaryQlClass() { result = "PointerType" } } /** @@ -881,6 +908,8 @@ class PointerType extends DotNet::PointerType, Type, @pointer_type { */ class DynamicType extends RefType, @dynamic_type { override string toStringWithTypes() { result = "dynamic" } + + override string getAPrimaryQlClass() { result = "DynamicType" } } /** @@ -888,6 +917,8 @@ class DynamicType extends RefType, @dynamic_type { */ class ArglistType extends Type, @arglist_type { override string toStringWithTypes() { result = "__arglist" } + + override string getAPrimaryQlClass() { result = "ArglistType" } } /** @@ -901,7 +932,7 @@ class UnknownType extends Type, @unknown_type { } */ class TupleType extends ValueType, @tuple_type { /** Gets the underlying type of this tuple, which is of type `System.ValueTuple`. */ - ConstructedStruct getUnderlyingType() { tuple_underlying_type(this, getTypeRef(result)) } + Struct getUnderlyingType() { tuple_underlying_type(this, getTypeRef(result)) } /** * Gets the `n`th element of this tuple, indexed from 0. @@ -959,7 +990,7 @@ class TypeMention extends @type_mention { * Gets the element to which this type mention belongs, if any. * For example, `IEnumerable` belongs to parameter `p` in * - * ``` + * ```csharp * void M(IEnumerable p) { } * ``` */ @@ -969,7 +1000,7 @@ class TypeMention extends @type_mention { * Gets the parent of this type mention, if any. * For example, the parent of `int` is `IEnumerable` in * - * ``` + * ```csharp * void M(IEnumerable p) { * ... * } @@ -983,15 +1014,3 @@ class TypeMention extends @type_mention { /** Gets the location of this type mention. */ Location getLocation() { type_mention_location(this, result) } } - -/** - * INTERNAL: Do not use. - * Gets a type reference for a given type `type`. - * This is used for extensionals that can be supplied - * as either type references or types. - */ -@type_or_ref getTypeRef(@type type) { - result = type - or - typeref_type(result, type) -} diff --git a/csharp/ql/src/semmle/code/csharp/TypeRef.qll b/csharp/ql/src/semmle/code/csharp/TypeRef.qll new file mode 100644 index 000000000000..1cdf74cf48ae --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/TypeRef.qll @@ -0,0 +1,29 @@ +/** + * INTERNAL: Do not use. + * + * Provides support for type-references. + */ + +import csharp + +/** A typeref is a reference to a type in some assembly. */ +private class TypeRef extends @typeref { + string getName() { typerefs(this, result) } + + string toString() { result = this.getName() } + + Type getReferencedType() { typeref_type(this, result) } +} + +/** + * INTERNAL: Do not use. + * + * Gets a type reference for a given type `type`. + * This is used for extensionals that can be supplied + * as either type references or types. + */ +@type_or_ref getTypeRef(Type type) { + result = type + or + result.(TypeRef).getReferencedType() = type +} diff --git a/csharp/ql/src/semmle/code/csharp/Unification.qll b/csharp/ql/src/semmle/code/csharp/Unification.qll index 48256a59a29c..4c057ad8c030 100644 --- a/csharp/ql/src/semmle/code/csharp/Unification.qll +++ b/csharp/ql/src/semmle/code/csharp/Unification.qll @@ -213,6 +213,10 @@ module Gvn { ) } + predicate isFullyConstructed() { + this.getKind().getNumberOfTypeParameters() - 1 = this.length() + } + GvnType getArg(int i) { exists(GvnType head, ConstructedGvnTypeList tail | this = TConstructedGvnTypeCons(head, tail) @@ -224,47 +228,72 @@ module Gvn { ) } + private GenericType getConstructedGenericDeclaringTypeAt(int i) { + i = 0 and + result = this.getKind().getConstructedSourceDeclaration() + or + result = this.getConstructedGenericDeclaringTypeAt(i - 1).getGenericDeclaringType() + } + + private predicate isDeclaringTypeAt(int i) { + exists(this.getConstructedGenericDeclaringTypeAt(i - 1)) + } + /** - * Gets a textual representation of this constructed type, restricted - * to the prefix `t` of the underlying source declaration type. - * - * The `toString()` calculation needs to be split up into prefixes, in - * order to apply the type arguments correctly. For example, a source - * declaration type `A<>.B.C<,>` applied to types `int, string, bool` - * needs to be printed as `A.B.C`. + * Gets the `j`th `toString()` part of the `i`th nested component of this + * constructed type, if any. The nested components are sorted in reverse + * order, while the individual parts are sorted in normal order. */ language[monotonicAggregates] - private string toStringConstructed(GenericType t) { - t = this.getKind().getConstructedSourceDeclaration().getGenericDeclaringType*() and - exists(int offset, int children, string name, string nameArgs | - offset = t.getNumberOfDeclaringArguments() and - children = t.getNumberOfArgumentsSelf() and - name = getNameNested(t) and - if children = 0 - then nameArgs = name - else - exists(string offsetArgs | - offsetArgs = - concat(int i | - i in [offset .. offset + children - 1] - | - this.getArg(i).toString(), "," order by i - ) and - nameArgs = name.prefix(name.length() - children - 1) + "<" + offsetArgs + ">" + private string toStringConstructedPart(int i, int j) { + this.isFullyConstructed() and + exists(GenericType t | + t = this.getConstructedGenericDeclaringTypeAt(i) and + exists(int offset, int children, string name | + offset = t.getNumberOfDeclaringArguments() and + children = t.getNumberOfArgumentsSelf() and + name = getNameNested(t) and + if children = 0 + then + j = 0 and result = name + or + this.isDeclaringTypeAt(i) and j = 1 and result = "." + else ( + j = 0 and result = name.prefix(name.length() - children - 1) + "<" + or + j in [1 .. 2 * children - 1] and + if j % 2 = 0 + then result = "," + else result = this.getArg((j + 1) / 2 + offset - 1).toString() + or + j = 2 * children and + result = ">" + or + this.isDeclaringTypeAt(i) and + j = 2 * children + 1 and + result = "." ) - | - offset = 0 and result = nameArgs - or - result = this.toStringConstructed(t.getGenericDeclaringType()) + "." + nameArgs + ) ) } language[monotonicAggregates] string toString() { + this.isFullyConstructed() and exists(CompoundTypeKind k | k = this.getKind() | result = k.toStringBuiltin(this.getArg(0).toString()) or - result = this.toStringConstructed(k.getConstructedSourceDeclaration()) + result = + strictconcat(int i, int j, int offset | + exists(GenericType t, int children | + t = this.getConstructedGenericDeclaringTypeAt(i) and + children = t.getNumberOfArgumentsSelf() and + (if this.isDeclaringTypeAt(i) then offset = 1 else offset = 0) and + if children = 0 then j in [0 .. offset] else j in [0 .. 2 * children + offset] + ) + | + this.toStringConstructedPart(i, j) order by i desc, j + ) ) } @@ -482,7 +511,7 @@ module Gvn { newtype TGvnType = TLeafGvnType(LeafType t) or TTypeParameterGvnType() or - TConstructedGvnType(ConstructedGvnTypeList l) + TConstructedGvnType(ConstructedGvnTypeList l) { l.isFullyConstructed() } cached newtype TConstructedGvnTypeList = @@ -685,7 +714,7 @@ module Unification { private import Cached /** - * Holds if types `t1` and `t2` are unifiable. That is, is it possible to replace + * Holds if types `t1` and `t2` are unifiable. That is, it is possible to replace * all type parameters in `t1` and `t2` with some (other) types to make the two * substituted terms equal. * @@ -722,7 +751,7 @@ module Unification { } /** - * Holds if type `t1` subsumes type `t2`. That is, is it possible to replace all + * Holds if type `t1` subsumes type `t2`. That is, it is possible to replace all * type parameters in `t1` with some (other) types to make the two types equal. * * The same limitations that apply to the predicate `unifiable()` apply to this diff --git a/csharp/ql/src/semmle/code/csharp/Using.qll b/csharp/ql/src/semmle/code/csharp/Using.qll index 9b1362cf9dc9..f26958a54585 100644 --- a/csharp/ql/src/semmle/code/csharp/Using.qll +++ b/csharp/ql/src/semmle/code/csharp/Using.qll @@ -5,6 +5,7 @@ */ import Element +private import TypeRef /** * A `using` directive. Either a namespace `using` directive @@ -17,7 +18,7 @@ class UsingDirective extends Element, @using_directive { * * Example: * - * ``` + * ```csharp * using System; * * namespace N { @@ -48,6 +49,8 @@ class UsingNamespaceDirective extends UsingDirective, @using_namespace_directive Namespace getImportedNamespace() { using_namespace_directives(this, result) } override string toString() { result = "using ...;" } + + override string getAPrimaryQlClass() { result = "UsingNamespaceDirective" } } /** @@ -61,4 +64,6 @@ class UsingStaticDirective extends UsingDirective, @using_static_directive { ValueOrRefType getTarget() { using_static_directives(this, getTypeRef(result)) } override string toString() { result = "using static ...;" } + + override string getAPrimaryQlClass() { result = "UsingStaticDirective" } } diff --git a/csharp/ql/src/semmle/code/csharp/Variable.qll b/csharp/ql/src/semmle/code/csharp/Variable.qll index 0d1d462f8888..522bcaf71c94 100644 --- a/csharp/ql/src/semmle/code/csharp/Variable.qll +++ b/csharp/ql/src/semmle/code/csharp/Variable.qll @@ -3,12 +3,13 @@ * constants. */ -import Element +import Assignable import Callable +import Element import Type -import Assignable private import dotnet private import semmle.code.csharp.ExprOrStmtParent +private import TypeRef /** * A variable. Either a variable with local scope (`LocalScopeVariable`) or a field (`Field`). @@ -36,7 +37,7 @@ class LocalScopeVariable extends Variable, @local_scope_variable { * Holds if this variable is captured by a nested callable. For example, * `v` is captured by the nested lambda expression in * - * ``` + * ```csharp * void M() { * var v = "captured"; * Action a = () => { @@ -51,7 +52,7 @@ class LocalScopeVariable extends Variable, @local_scope_variable { * Gets a callable that captures this variable, if any. For example, * `v` is captured by the nested lambda expression in * - * ``` + * ```csharp * void M() { * var v = "captured"; * Action a = () => { @@ -77,7 +78,7 @@ class LocalScopeVariable extends Variable, @local_scope_variable { * A parameter of a parameterizable declaration (callable, delegate, or indexer). * For example, `p` in * - * ``` + * ```csharp * void M(int p) { * ... * } @@ -89,7 +90,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * Gets the position of this parameter. For example, the position of `x` is * 0 and the position of `y` is 1 in * - * ``` + * ```csharp * void M(int x, int y) { * ... * } @@ -103,7 +104,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * Holds if this parameter is a normal value parameter. For example, `p` * is a value parameter in * - * ``` + * ```csharp * void M(int p) { * ... * } @@ -115,7 +116,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * Holds if this parameter is a reference parameter. For example, `p` * is a reference parameter in * - * ``` + * ```csharp * void M(ref int p) { * ... * } @@ -127,7 +128,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * Holds if this parameter is an output parameter. For example, `p` * is an output parameter in * - * ``` + * ```csharp * void M(out int p) { * ... * } @@ -139,7 +140,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * Holds if this parameter is a value type that is passed in by reference. * For example, `p` is an input parameter in * - * ``` + * ```csharp * void M(in int p) { * ... * } @@ -154,7 +155,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * Holds if this parameter is a parameter array. For example, `args` * is a parameter array in * - * ``` + * ```csharp * void M(params string[] args) { * ... * } @@ -167,7 +168,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * For example, `list` is the first parameter of the extension method * `Count` in * - * ``` + * ```csharp * static int Count(this IEnumerable list) { * ... * } @@ -194,11 +195,13 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top override string toString() { result = this.getName() } + override string getAPrimaryQlClass() { result = "Parameter" } + /** * Gets the default value of this parameter, if any. For example, the * default value of `numberOfTries` is `3` in * - * ``` + * ```csharp * void Connect(int numberOfTries = 3) { * ... * } @@ -220,7 +223,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * * Example: * - * ``` + * ```csharp * class C { * void M(int x, int y = 2, int z = 3) { } * @@ -249,7 +252,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * special `value` parameter. For example, the `value` parameter of * `set_ReadOnly` in * - * ``` + * ```csharp * public bool ReadOnly { * get { * return flags.HasValue(Attribute.ReadOnly); @@ -272,7 +275,7 @@ class ImplicitAccessorParameter extends Parameter { * A local variable, declared within the scope of a callable. For example, * the variables `total` and `s` in * - * ``` + * ```csharp * void M(string[] ss) { * int total = 0; * ... @@ -290,7 +293,7 @@ class LocalVariable extends LocalScopeVariable, @local_variable { * For example, the initializer of `total` is `0`, and `s` has no * initializer, in * - * ``` + * ```csharp * void M(string[] ss) { * int total = 0; * ... @@ -305,7 +308,7 @@ class LocalVariable extends LocalScopeVariable, @local_variable { * Holds if this variable is implicitly typed. For example, the variable * `s` is implicitly type, and the variable `total` is not, in * - * ``` + * ```csharp * void M(string[] ss) { * int total = 0; * ... @@ -338,7 +341,7 @@ class LocalVariable extends LocalScopeVariable, @local_variable { * A local constant, modeled as a special kind of local variable. For example, * the local constant `maxTries` in * - * ``` + * ```csharp * void M() { * const int maxTries = 10; * ... @@ -356,7 +359,7 @@ class LocalConstant extends LocalVariable, @local_constant { /** * A field. For example, the fields `x` and `y` in * - * ``` + * ```csharp * struct Coord { * public int x, y; * } @@ -368,7 +371,7 @@ class Field extends Variable, AssignableMember, Attributable, TopLevelExprParent * Gets the initial value of this field, if any. For example, the initial * value of `F` on line 2 is `20` in * - * ``` + * ```csharp * class C { * public int F = 20; * } @@ -380,7 +383,7 @@ class Field extends Variable, AssignableMember, Attributable, TopLevelExprParent * Holds if this field has an initial value. For example, the initial * value of `F` on line 2 is `20` in * - * ``` + * ```csharp * class C { * public int F = 20; * } @@ -407,13 +410,15 @@ class Field extends Variable, AssignableMember, Attributable, TopLevelExprParent override Location getALocation() { field_location(this, result) } override string toString() { result = Variable.super.toString() } + + override string getAPrimaryQlClass() { result = "Field" } } /** * A member constant, modeled a special kind of field. For example, * the constant `Separator` in * - * ``` + * ```csharp * class Path { * const char Separator = `\\`; * ... @@ -428,7 +433,7 @@ class MemberConstant extends Field, @constant { /** * An `enum` member constant. For example, `ReadOnly` and `Shared` in * - * ``` + * ```csharp * enum Attribute { * ReadOnly = 1, * Shared = 2 @@ -445,7 +450,7 @@ class EnumConstant extends MemberConstant { * Gets the underlying integral type of this `enum` constant. For example, * the underlying type of `Attribute` is `byte` in * - * ``` + * ```csharp * enum Attribute : byte { * ReadOnly = 1, * Shared = 2 @@ -460,7 +465,7 @@ class EnumConstant extends MemberConstant { * In this example, `ReadOnly` has an explicit value but * `Shared` does not have an explicit value. * - * ``` + * ```csharp * enum Attribute { * ReadOnly = 1, * Shared diff --git a/csharp/ql/src/semmle/code/csharp/commons/Assertions.qll b/csharp/ql/src/semmle/code/csharp/commons/Assertions.qll index a51ed63e49b0..bf29195547f2 100644 --- a/csharp/ql/src/semmle/code/csharp/commons/Assertions.qll +++ b/csharp/ql/src/semmle/code/csharp/commons/Assertions.qll @@ -52,7 +52,7 @@ class Assertion extends MethodCall { * Moreover, this assertion corresponds to multiple control flow nodes, * which is why * - * ``` + * ```ql * exists(BasicBlock bb | * bb.getANode() = this.getAControlFlowNode() | * bb.immediatelyDominates(succ) @@ -62,7 +62,7 @@ class Assertion extends MethodCall { * does not work. */ pragma[nomagic] - private predicate immediatelyDominatesBlockSplit(BasicBlock succ) { + deprecated private predicate immediatelyDominatesBlockSplit(BasicBlock succ) { // Only calculate dominance by explicit recursion for split nodes; // all other nodes can use regular CFG dominance this instanceof ControlFlow::Internal::SplitControlFlowElement and @@ -78,11 +78,11 @@ class Assertion extends MethodCall { } pragma[noinline] - private predicate strictlyDominatesJoinBlockPredecessor(JoinBlock jb, int i) { + deprecated private predicate strictlyDominatesJoinBlockPredecessor(JoinBlock jb, int i) { this.strictlyDominatesSplit(jb.getJoinBlockPredecessor(i)) } - private predicate strictlyDominatesJoinBlockSplit(JoinBlock jb, int i) { + deprecated private predicate strictlyDominatesJoinBlockSplit(JoinBlock jb, int i) { i = -1 and this.strictlyDominatesJoinBlockPredecessor(jb, _) or @@ -95,12 +95,12 @@ class Assertion extends MethodCall { } pragma[nomagic] - private predicate strictlyDominatesSplit(BasicBlock bb) { + deprecated private predicate strictlyDominatesSplit(BasicBlock bb) { this.immediatelyDominatesBlockSplit(bb) or // Equivalent with // - // ``` + // ```ql // exists(JoinBlockPredecessor pred | pred = bb.getAPredecessor() | // this.strictlyDominatesSplit(pred) // ) and @@ -121,6 +121,8 @@ class Assertion extends MethodCall { } /** + * DEPRECATED: Use `getExpr().controlsBlock()` instead. + * * Holds if this assertion strictly dominates basic block `bb`. That is, `bb` * can only be reached from the callable entry point by going via *some* basic * block containing this element. @@ -130,7 +132,7 @@ class Assertion extends MethodCall { * in that it takes control flow splitting into account. */ pragma[nomagic] - predicate strictlyDominates(BasicBlock bb) { + deprecated predicate strictlyDominates(BasicBlock bb) { this.strictlyDominatesSplit(bb) or this.getAControlFlowNode().getBasicBlock().strictlyDominates(bb) @@ -288,7 +290,7 @@ class ForwarderAssertMethod extends AssertMethod { ForwarderAssertMethod() { p = this.getAParameter() and strictcount(AssignableDefinition def | def.getTarget() = p) = 1 and - forex(ControlFlowElement body | body = this.getABody() | + forex(ControlFlowElement body | body = this.getBody() | bodyAsserts(this, body, a) and a.getExpr() = p.getAnAccess() ) @@ -306,7 +308,7 @@ class ForwarderAssertMethod extends AssertMethod { pragma[noinline] private predicate bodyAsserts(Callable c, ControlFlowElement body, Assertion a) { - c.getABody() = body and + c.getBody() = body and body = getAnAssertingElement(a) } diff --git a/csharp/ql/src/semmle/code/csharp/commons/Collections.qll b/csharp/ql/src/semmle/code/csharp/commons/Collections.qll index 412b33a703b0..df39b7fa96b6 100644 --- a/csharp/ql/src/semmle/code/csharp/commons/Collections.qll +++ b/csharp/ql/src/semmle/code/csharp/commons/Collections.qll @@ -143,8 +143,8 @@ private predicate readonlyAccess(Access a) { // A read-only method call exists(MethodCall mc | mc.getQualifier() = a | mc.getTarget().hasName(readonlyMethodName())) or - // Any property access - a = any(PropertyAccess pa).getQualifier() + // Any property read + a = any(PropertyRead pr).getQualifier() or // An element read a = any(ElementRead er).getQualifier() diff --git a/csharp/ql/src/semmle/code/csharp/commons/ComparisonTest.qll b/csharp/ql/src/semmle/code/csharp/commons/ComparisonTest.qll index 4a485ba767e7..ea7d250abb07 100644 --- a/csharp/ql/src/semmle/code/csharp/commons/ComparisonTest.qll +++ b/csharp/ql/src/semmle/code/csharp/commons/ComparisonTest.qll @@ -2,7 +2,7 @@ * Provides classes for capturing various ways of performing comparison tests. */ -import csharp +private import csharp private import semmle.code.csharp.frameworks.System private import semmle.code.csharp.frameworks.system.Collections private import semmle.code.csharp.frameworks.system.collections.Generic @@ -348,11 +348,12 @@ class CompareMethodCallComparisonTest extends ComparisonTest, TCompareCall { } * A comparison test using a user-defined comparison operator, for example * `this == other` on line 3 in * - * ``` + * ```csharp * public class C { * public static bool operator ==(C lhs, C rhs) => true; * public bool Is(C other) => this == other; * } + * ``` */ class OperatorCallComparisonTest extends ComparisonTest, TComparisonOperatorCall { } diff --git a/csharp/ql/src/semmle/code/csharp/commons/Constants.qll b/csharp/ql/src/semmle/code/csharp/commons/Constants.qll index 7815890b51a3..0e01f7f7ab76 100644 --- a/csharp/ql/src/semmle/code/csharp/commons/Constants.qll +++ b/csharp/ql/src/semmle/code/csharp/commons/Constants.qll @@ -23,7 +23,7 @@ predicate isConstantCondition(Expr e, boolean b) { * Holds if comparison operation `co` is constant with the Boolean value `b`. * For example, the comparison `x > x` is constantly `false` in * - * ``` + * ```csharp * int MaxWrong(int x, int y) => x > x ? x : y; * ``` */ diff --git a/csharp/ql/src/semmle/code/csharp/commons/Strings.qll b/csharp/ql/src/semmle/code/csharp/commons/Strings.qll index a222c74281b3..4e007d61737e 100644 --- a/csharp/ql/src/semmle/code/csharp/commons/Strings.qll +++ b/csharp/ql/src/semmle/code/csharp/commons/Strings.qll @@ -12,7 +12,7 @@ private import semmle.code.csharp.frameworks.system.Text * invocation will take place, unless the expression is already a string. * For example, `o` and `o.ToString()` on lines 2 and 3, respectively, in * - * ``` + * ```csharp * void Hello(object o) { * Console.WriteLine("Hello, " + o); * Console.WriteLine("Hello, " + o.ToString()); diff --git a/csharp/ql/src/semmle/code/csharp/commons/TargetFramework.qll b/csharp/ql/src/semmle/code/csharp/commons/TargetFramework.qll index c6532eebcb3e..83de1b9d2949 100644 --- a/csharp/ql/src/semmle/code/csharp/commons/TargetFramework.qll +++ b/csharp/ql/src/semmle/code/csharp/commons/TargetFramework.qll @@ -6,7 +6,7 @@ import csharp * An attribute of type `System.Runtime.Versioning.TargetFrameworkAttribute`, * specifying the target framework of an assembly. For example * - * ``` + * ```csharp * [assembly: TargetFramework(".NETFramework,Version=v4.6.1")] * ``` */ @@ -20,7 +20,7 @@ class TargetFrameworkAttribute extends Attribute { /** * Gets the framework name of this attribute. For example, the framework name of - * ``` + * ```csharp * [assembly: TargetFramework(".NETFramework,Version=v4.6.1")] * ``` * is `".NETFramework,Version=v4.6.1"`. @@ -33,7 +33,7 @@ class TargetFrameworkAttribute extends Attribute { /** * Gets the framework type of this attribute. For example, the framework type of - * ``` + * ```csharp * [assembly: TargetFramework(".NETFramework,Version=v4.6.1")] * ``` * is `".NETFramework"`. Other framework types include `".NETStandard"` and `".NETCoreApp"`. @@ -42,7 +42,7 @@ class TargetFrameworkAttribute extends Attribute { /** * Gets the framework version of this attribute. For example, the framework version of - * ``` + * ```csharp * [assembly: TargetFramework(".NETFramework,Version=v4.6.1")] * ``` * is `"4.6.1"`. Note that you can use the `Version` class to compare versions, for example diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/BasicBlocks.qll b/csharp/ql/src/semmle/code/csharp/controlflow/BasicBlocks.qll index 03f98b36d32d..9dc2c30eb8eb 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/BasicBlocks.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/BasicBlocks.qll @@ -34,7 +34,7 @@ class BasicBlock extends TBasicBlockStart { * * Example: * - * ``` + * ```csharp * if (x < 0) * x = -x; * ``` @@ -52,7 +52,7 @@ class BasicBlock extends TBasicBlockStart { * * Example: * - * ``` + * ```csharp * if (!(x >= 0)) * x = -x; * ``` @@ -89,7 +89,7 @@ class BasicBlock extends TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * if (s == null) * throw new ArgumentNullException(nameof(s)); @@ -112,7 +112,7 @@ class BasicBlock extends TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * if (s == null) * throw new ArgumentNullException(nameof(s)); @@ -134,7 +134,7 @@ class BasicBlock extends TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * if (s == null) * throw new ArgumentNullException(nameof(s)); @@ -161,7 +161,7 @@ class BasicBlock extends TBasicBlockStart { * * Example: * - * ``` + * ```csharp * if (x < 0) { * x = -x; * if (x > 10) @@ -195,7 +195,7 @@ class BasicBlock extends TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * if (s == null) * throw new ArgumentNullException(nameof(s)); @@ -219,7 +219,7 @@ class BasicBlock extends TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * try { * return s.Length; @@ -244,7 +244,7 @@ class BasicBlock extends TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * try { * return s.Length; @@ -447,7 +447,7 @@ class ConditionBlock extends BasicBlock { * all predecessors of `this.getATrueSuccessor()` are either `this` or dominated by `this.getATrueSuccessor()`. * * For example, in the following C# snippet: - * ``` + * ```csharp * if (x) * controlled; * false_successor; @@ -455,7 +455,7 @@ class ConditionBlock extends BasicBlock { * ``` * `false_successor` dominates `uncontrolled`, but not all of its predecessors are `this` (`if (x)`) * or dominated by itself. Whereas in the following code: - * ``` + * ```csharp * if (x) * while (controlled) * also_controlled; diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowElement.qll b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowElement.qll index a8ba5f858933..7f0a3666b298 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowElement.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowElement.qll @@ -118,7 +118,7 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element { * Moreover, this control flow element corresponds to multiple control flow nodes, * which is why * - * ``` + * ```ql * exists(ConditionBlock cb | * cb.getLastNode() = this.getAControlFlowNode() | * cb.immediatelyControls(succ, s) @@ -126,43 +126,51 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element { * ``` * * does not work. + * + * `cb` records all of the possible condition blocks for this control flow element + * that a path from the callable entry point to `succ` may go through. */ pragma[nomagic] - private predicate immediatelyControlsBlockSplit(BasicBlock succ, ConditionalSuccessor s) { - exists(ConditionBlock cb | this.immediatelyControlsBlockSplit0(cb, succ, s) | - forall(BasicBlock pred, SuccessorType t | - this.immediatelyControlsBlockSplit1(cb, succ, s, pred, t) - | - this.immediatelyControlsBlockSplit2(cb, succ, s, pred, t) - ) + private predicate immediatelyControlsBlockSplit( + BasicBlock succ, ConditionalSuccessor s, ConditionBlock cb + ) { + this.immediatelyControlsBlockSplit0(cb, succ, s) and + forall(BasicBlock pred, SuccessorType t | + this.immediatelyControlsBlockSplit1(cb, succ, s, pred, t) + | + this.immediatelyControlsBlockSplit2(cb, succ, s, pred, t) ) } pragma[noinline] - private predicate controlsJoinBlockPredecessor(JoinBlock controlled, ConditionalSuccessor s, int i) { - this.controlsBlockSplit(controlled.getJoinBlockPredecessor(i), s) + private predicate controlsJoinBlockPredecessor( + JoinBlock controlled, ConditionalSuccessor s, int i, ConditionBlock cb + ) { + this.controlsBlockSplit(controlled.getJoinBlockPredecessor(i), s, cb) } private predicate controlsJoinBlockSplit(JoinBlock controlled, ConditionalSuccessor s, int i) { i = -1 and - this.controlsJoinBlockPredecessor(controlled, s, _) + this.controlsJoinBlockPredecessor(controlled, s, _, _) or this.controlsJoinBlockSplit(controlled, s, i - 1) and ( - this.controlsJoinBlockPredecessor(controlled, s, i) + this.controlsJoinBlockPredecessor(controlled, s, i, _) or controlled.dominates(controlled.getJoinBlockPredecessor(i)) ) } cached - private predicate controlsBlockSplit(BasicBlock controlled, ConditionalSuccessor s) { + private predicate controlsBlockSplit( + BasicBlock controlled, ConditionalSuccessor s, ConditionBlock cb + ) { Stages::GuardsStage::forceCachingInSameStage() and - this.immediatelyControlsBlockSplit(controlled, s) + this.immediatelyControlsBlockSplit(controlled, s, cb) or // Equivalent with // - // ``` + // ```ql // exists(JoinBlockPredecessor pred | pred = controlled.getAPredecessor() | // this.controlsBlockSplit(pred, s) // ) and @@ -178,10 +186,11 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element { last = max(int i | exists(controlled.(JoinBlock).getJoinBlockPredecessor(i))) | this.controlsJoinBlockSplit(controlled, s, last) - ) + ) and + this.controlsJoinBlockPredecessor(controlled, s, _, cb) or not controlled instanceof JoinBlock and - this.controlsBlockSplit(controlled.getAPredecessor(), s) + this.controlsBlockSplit(controlled.getAPredecessor(), s, cb) } /** @@ -192,7 +201,7 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element { * * This predicate is different from * - * ``` + * ```ql * exists(ConditionBlock cb | * cb.getLastNode() = this.getAControlFlowNode() | * cb.controls(controlled, s) @@ -200,23 +209,32 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element { * ``` * * as control flow splitting is taken into account. + * + * `cb` records all of the possible condition blocks for this control flow element + * that a path from the callable entry point to `controlled` may go through. */ - predicate controlsBlock(BasicBlock controlled, ConditionalSuccessor s) { - this.controlsBlockSplit(controlled, s) + predicate controlsBlock(BasicBlock controlled, ConditionalSuccessor s, ConditionBlock cb) { + this.controlsBlockSplit(controlled, s, cb) or - exists(ConditionBlock cb | cb.getLastNode() = this.getAControlFlowNode() | - cb.controls(controlled, s) - ) + cb.getLastNode() = this.getAControlFlowNode() and + cb.controls(controlled, s) + } + + /** DEPRECATED: Use `controlsBlock/3` instead. */ + deprecated predicate controlsBlock(BasicBlock controlled, ConditionalSuccessor s) { + this.controlsBlock(controlled, s, _) } /** + * DEPRECATED. + * * Holds if control flow element `controlled` is controlled by this control flow * element with conditional value `s`. That is, `controlled` can only be reached * from the callable entry point by going via the `s` edge out of this element. * * This predicate is different from * - * ``` + * ```ql * exists(ConditionBlock cb | * cb.getLastNode() = this.getAControlFlowNode() | * cb.controls(controlled.getAControlFlowNode().getBasicBlock(), s) @@ -227,7 +245,7 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element { */ // potentially very large predicate, so must be inlined pragma[inline] - predicate controlsElement(ControlFlowElement controlled, ConditionalSuccessor s) { + deprecated predicate controlsElement(ControlFlowElement controlled, ConditionalSuccessor s) { forex(BasicBlock bb | bb = controlled.getAControlFlowNode().getBasicBlock() | this.controlsBlock(bb, s) ) diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll index fdf6f986554d..5ba6486fd7a1 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll @@ -48,7 +48,7 @@ module ControlFlow { * * Example: * - * ``` + * ```csharp * int M(string s) * { * if (s == null) @@ -80,7 +80,7 @@ module ControlFlow { * * Example: * - * ``` + * ```csharp * int M(string s) * { * if (s == null) @@ -113,7 +113,7 @@ module ControlFlow { * * Example: * - * ``` + * ```csharp * int M(string s) * { * try @@ -151,7 +151,7 @@ module ControlFlow { * * Example: * - * ``` + * ```csharp * int M(string s) * { * try @@ -201,7 +201,7 @@ module ControlFlow { * * Example: * - * ``` + * ```csharp * if (x < 0) * x = -x; * ``` @@ -221,7 +221,7 @@ module ControlFlow { * * Example: * - * ``` + * ```csharp * if (!(x >= 0)) * x = -x; * ``` @@ -318,7 +318,7 @@ module ControlFlow { class BooleanSplit = BooleanSplitting::BooleanSplitImpl; - class LoopUnrollingSplit = LoopUnrollingSplitting::LoopUnrollingSplitImpl; + class LoopSplit = LoopSplitting::LoopSplitImpl; } class BasicBlock = BBs::BasicBlock; @@ -517,7 +517,6 @@ module ControlFlow { e = any(QualifiableExpr qe | not qe instanceof ExtensionMethodCall and - not qe.isConditional() and result = qe.getChild(i) ) or @@ -557,7 +556,7 @@ module ControlFlow { this.hasQualifier() or // Member initializers like - // ``` + // ```csharp // new Dictionary() { [0] = "Zero", [1] = "One", [2] = "Two" } // ``` // need special treatment, because the the accesses `[0]`, `[1]`, and `[2]` @@ -582,7 +581,7 @@ module ControlFlow { * that the accessor is called *after* the assigned value has been evaluated. * In the example above, this means we want a CFG that looks like * - * ``` + * ```csharp * x -> 0 -> set_Prop -> x.Prop = 0 * ``` */ @@ -656,17 +655,16 @@ module ControlFlow { cfe = any(AssignOperationWithExpandedAssignment a | result = first(a.getExpandedAssignment())) or - cfe = any(ConditionallyQualifiedExpr cqe | result = first(cqe.getChildExpr(-1))) + cfe = any(ConditionallyQualifiedExpr cqe | result = first(getExprChildElement(cqe, 0))) or cfe = any(ArrayCreation ac | - if ac.isImplicitlySized() - then - // No length argument: element itself - result = ac - else - // First element of first length argument - result = first(ac.getLengthArgument(0)) + // First element of first length argument + result = first(ac.getLengthArgument(0)) + or + // No length argument: element itself + not exists(ac.getLengthArgument(0)) and + result = ac ) or cfe = @@ -882,7 +880,7 @@ module ControlFlow { c = getValidSelfCompletion(result) or // Qualifier exits with a `null` completion - result = cqe.getChildExpr(-1) and + result = getExprChildElement(cqe, 0) and c = TRec(TLastRecSpecificCompletion(any(NullnessCompletion nc | nc.isNull()))) ) or @@ -1454,16 +1452,16 @@ module ControlFlow { ) or exists(ConditionallyQualifiedExpr parent, int i | - cfe = last(parent.getChildExpr(i), c) and + cfe = last(getExprChildElement(parent, i), c) and c instanceof NormalCompletion and - not c.(NullnessCompletion).isNull() + if i = 0 then c.(NullnessCompletion).isNonNull() else any() | // Post-order: flow from last element of last child to element itself - i = max(int j | exists(parent.getChildExpr(j))) and + i = max(int j | exists(getExprChildElement(parent, j))) and result = parent or // Standard left-to-right evaluation - result = first(parent.getChildExpr(i + 1)) + result = first(getExprChildElement(parent, i + 1)) ) or // Post-order: flow from last element of thrown expression to expression itself diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll index 14438ff14185..3bd57b848e55 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll @@ -31,6 +31,25 @@ class Guard extends Expr { predicate controlsNode(ControlFlow::Nodes::ElementNode cfn, AccessOrCallExpr sub, AbstractValue v) { isGuardedByNode(cfn, this, sub, v) } + + /** + * Holds if basic block `bb` is guarded by this expression having value `v`. + */ + predicate controlsBasicBlock(BasicBlock bb, AbstractValue v) { + Internal::guardControls(this, _, bb, v) + } + + /** + * Holds if this guard is an equality test between `e1` and `e2`. If the test is + * negated, that is `!=`, then `polarity` is false, otherwise `polarity` is + * true. + */ + predicate isEquality(Expr e1, Expr e2, boolean polarity) { + exists(BooleanValue v | + this = Internal::getAnEqualityCheck(e1, v, e2) and + polarity = v.getValue() + ) + } } /** An abstract value. */ @@ -62,7 +81,7 @@ abstract class AbstractValue extends TAbstractValue { * * Such values only propagate through adjacent reads, for example, in * - * ``` + * ```csharp * int M() * { * var x = new string[]{ "a", "b", "c" }.ToList(); @@ -212,7 +231,12 @@ module AbstractValues { c.isValidFor(cfe) and foreachEmptiness(fs, cfe) and e = fs.getIterableExpr() - ) + ) and + // Only when taking the non-empty successor do we know that the original iterator + // expression was non-empty. When taking the empty successor, we may have already + // iterated through the `foreach` loop zero or more times, hence the iterator + // expression can be both empty and non-empty + this.isNonEmpty() } override EmptyCollectionValue getDualValue() { @@ -350,7 +374,7 @@ class DereferenceableExpr extends Expr { * * For example, if the case statement `case string s` matches in * - * ``` + * ```csharp * switch (o) * { * case string s: @@ -562,7 +586,7 @@ class AccessOrCallExpr extends Expr { * * Examples: * - * ``` + * ```csharp * x.Foo.Bar(); // SSA qualifier: SSA definition for `x.Foo` * x.Bar(); // SSA qualifier: SSA definition for `x` * x.Foo().Bar(); // SSA qualifier: SSA definition for `x` @@ -588,14 +612,11 @@ private Ssa::Definition getAnSsaQualifier(Expr e, ControlFlow::Node cfn) { } private AssignableAccess getATrackedAccess(Ssa::Definition def, ControlFlow::Node cfn) { - ( - result = def.getAReadAtNode(cfn) - or - result = def.(Ssa::ExplicitDefinition).getADefinition().getTargetAccess() and - result.getAControlFlowNode() = cfn and - cfn.getBasicBlock() = def.getBasicBlock() - ) and + result = def.getAReadAtNode(cfn) and not def instanceof Ssa::ImplicitUntrackedDefinition + or + result = def.(Ssa::ExplicitDefinition).getADefinition().getTargetAccess() and + cfn = def.getControlFlowNode() } /** @@ -607,7 +628,7 @@ private AssignableAccess getATrackedAccess(Ssa::Definition def, ControlFlow::Nod * * For example, the property call `x.Field.Property` on line 3 is guarded in * - * ``` + * ```csharp * string M(C x) { * if (x.Field.Property != null) * return x.Field.Property.ToString(); @@ -621,7 +642,7 @@ private AssignableAccess getATrackedAccess(Ssa::Definition def, ControlFlow::Nod * guard, whereas the null-guard on `stack.Pop()` on line 4 is not (invoking * `Pop()` twice on a stack does not yield the same result): * - * ``` + * ```csharp * string M(Stack stack) { * if (stack == null) * return ""; @@ -686,7 +707,7 @@ class GuardedExpr extends AccessOrCallExpr { * into account. That is, one control flow node belonging to an expression may * be guarded, while another split need not be guarded: * - * ``` + * ```csharp * if (b) * if (x == null) * return; @@ -736,7 +757,7 @@ class GuardedControlFlowNode extends ControlFlow::Nodes::ElementNode { * is, one data flow node belonging to an expression may be guarded, while another * split need not be guarded: * - * ``` + * ```csharp * if (b) * if (x == null) * return; @@ -876,6 +897,8 @@ module Internal { not e.(QualifiableExpr).isConditional() or e instanceof SuppressNullableWarningExpr + or + e.stripCasts().getType() = any(ValueType t | not t instanceof NullableType) } /** Holds if expression `e2` is a non-`null` value whenever `e1` is. */ @@ -936,44 +959,6 @@ module Internal { e = any(BinaryArithmeticOperation bao | result = bao.getAnOperand()) } - /** Holds if basic block `bb` only is reached when guard `g` has abstract value `v`. */ - private predicate guardControls(Guard g, BasicBlock bb, AbstractValue v) { - exists(ControlFlowElement cfe, ConditionalSuccessor s, AbstractValue v0, Guard g0 | - cfe.controlsBlock(bb, s) - | - v0.branch(cfe, s, g0) and - impliesSteps(g0, v0, g, v) - ) - } - - /** - * Holds if control flow node `cfn` only is reached when guard `g` evaluates to `v`, - * because of an assertion. - */ - private predicate guardAssertionControlsNode(Guard g, ControlFlow::Node cfn, AbstractValue v) { - exists(Assertion a, Guard g0, AbstractValue v0 | - asserts(a, g0, v0) and - impliesSteps(g0, v0, g, v) - | - a.strictlyDominates(cfn.getBasicBlock()) - or - exists(BasicBlock bb, int i, int j | bb.getNode(i) = a.getAControlFlowNode() | - bb.getNode(j) = cfn and - j > i - ) - ) - } - - /** - * Holds if control flow element `cfe` only is reached when guard `g` evaluates to `v`, - * because of an assertion. - */ - private predicate guardAssertionControlsElement(Guard g, ControlFlowElement cfe, AbstractValue v) { - forex(ControlFlow::Node cfn | cfn = cfe.getAControlFlowNode() | - guardAssertionControlsNode(g, cfn, v) - ) - } - /** Same as `this.getAChildExpr*()`, but avoids `fastTC`. */ private Expr getAChildExprStar(Guard g) { result = g @@ -981,26 +966,6 @@ module Internal { result = getAChildExprStar(g).getAChildExpr() } - /** - * Holds if assertion `a` directly asserts that expression `e` evaluates to value `v`. - */ - predicate asserts(Assertion a, Expr e, AbstractValue v) { - e = a.getExpr() and - ( - a.getAssertMethod() instanceof AssertTrueMethod and - v.(BooleanValue).getValue() = true - or - a.getAssertMethod() instanceof AssertFalseMethod and - v.(BooleanValue).getValue() = false - or - a.getAssertMethod() instanceof AssertNullMethod and - v.(NullValue).isNull() - or - a.getAssertMethod() instanceof AssertNonNullMethod and - v.(NullValue).isNonNull() - ) - } - private Expr stripConditionalExpr(Expr e) { e = any(ConditionalExpr ce | @@ -1262,7 +1227,7 @@ module Internal { * * For example, if the case statement `case ""` matches in * - * ``` + * ```csharp * switch (o) * { * case "": @@ -1284,24 +1249,6 @@ module Internal { ) } - /** - * Gets an expression that tests whether expression `e1` is equal to - * expression `e2`. - * - * If the returned expression has abstract value `v`, then expression `e1` is - * guaranteed to be equal to `e2`, and if the returned expression has abstract - * value `v.getDualValue()`, then this expression is guaranteed to be - * non-equal to `e`. - * - * For example, if the expression `x != ""` evaluates to `false` then the - * expression `x` is guaranteed to be equal to `""`. - */ - Expr getAnEqualityCheck(Expr e1, AbstractValue v, Expr e2) { - result = getABooleanEqualityCheck(e1, v, e2) - or - result = getAMatchingEqualityCheck(e1, v, e2) - } - private Expr getAnEqualityCheckVal(Expr e, AbstractValue v, AbstractValue vExpr) { result = getAnEqualityCheck(e, v, vExpr.getAnExpr()) } @@ -1448,8 +1395,6 @@ module Internal { or val.branch(_, _, e) or - asserts(_, e, val) - or e instanceof CollectionExpr and val = TEmptyCollectionValue(_) ) and @@ -1457,6 +1402,29 @@ module Internal { not e = any(LocalVariableDeclStmt s).getAVariableDeclExpr() } + /** + * Gets an expression that tests whether expression `e1` is equal to + * expression `e2`. + * + * If the returned expression has abstract value `v`, then expression `e1` is + * guaranteed to be equal to `e2`, and if the returned expression has abstract + * value `v.getDualValue()`, then this expression is guaranteed to be + * non-equal to `e`. + * + * For example, if the expression `x != ""` evaluates to `false` then the + * expression `x` is guaranteed to be equal to `""`. + */ + cached + Expr getAnEqualityCheck(Expr e1, AbstractValue v, Expr e2) { + result = getABooleanEqualityCheck(e1, v, e2) + or + result = getABooleanEqualityCheck(e2, v, e1) + or + result = getAMatchingEqualityCheck(e1, v, e2) + or + result = getAMatchingEqualityCheck(e2, v, e1) + } + cached predicate isCustomNullCheck(Call call, Expr arg, BooleanValue v, boolean isNull) { exists(Callable callable, Parameter p | @@ -1739,11 +1707,7 @@ module Internal { pragma[noinline] private predicate candidateAux(AccessOrCallExpr e, Declaration target, BasicBlock bb) { target = e.getTarget() and - exists(Guard g | e = getAChildExprStar(g) | - guardControls(g, bb, _) - or - guardAssertionControlsNode(g, bb.getANode(), _) - ) + exists(Guard g | e = getAChildExprStar(g) | guardControls(g, _, bb, _)) } } @@ -1751,27 +1715,52 @@ module Internal { private module Cached { private import semmle.code.csharp.Caching + /** + * Holds if basic block `bb` only is reached when guard `g` has abstract value `v`. + * + * `cb` records all of the possible condition blocks for `g` that a path from the + * callable entry point to `bb` may go through. + */ + cached + predicate guardControls(Guard g, ConditionBlock cb, BasicBlock bb, AbstractValue v) { + exists(AbstractValue v0, Guard g0 | + impliesSteps(g0, v0, g, v) and + exists(ControlFlowElement cfe, ConditionalSuccessor cs | + v0.branch(cfe, cs, g0) and cfe.controlsBlock(bb, cs, cb) + ) + ) + } + pragma[noinline] - private predicate isGuardedByNode0( - ControlFlow::Node cfn, AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, - AbstractValue v + private predicate nodeIsGuardedBySameSubExpr0( + ControlFlow::Node guardedCfn, AccessOrCallExpr guarded, Guard g, ConditionBlock cb, + AccessOrCallExpr sub, AbstractValue v ) { Stages::GuardsStage::forceCachingInSameStage() and - cfn = guarded.getAControlFlowNode() and - guardControls(g, cfn.getBasicBlock(), v) and + guardedCfn = guarded.getAControlFlowNode() and + guardControls(g, cb, guardedCfn.getBasicBlock(), v) and exists(ConditionOnExprComparisonConfig c | c.same(sub, guarded)) } pragma[noinline] - private predicate isGuardedByExpr1( - AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, AbstractValue v + private predicate nodeIsGuardedBySameSubExpr( + ControlFlow::Node guardedCfn, AccessOrCallExpr guarded, Guard g, ConditionBlock cb, + AccessOrCallExpr sub, AbstractValue v ) { - forex(ControlFlow::Node cfn | cfn = guarded.getAControlFlowNode() | - isGuardedByNode0(cfn, guarded, g, sub, v) + nodeIsGuardedBySameSubExpr0(guardedCfn, guarded, g, cb, sub, v) and + sub = getAChildExprStar(g) + } + + pragma[noinline] + private predicate nodeIsGuardedBySameSubExprSsaDef( + ControlFlow::Node cfn, AccessOrCallExpr guarded, Guard g, ControlFlow::Node subCfn, + AccessOrCallExpr sub, AbstractValue v, Ssa::Definition def + ) { + exists(ConditionBlock cb | + nodeIsGuardedBySameSubExpr(cfn, guarded, g, cb, sub, v) and + subCfn.getBasicBlock().dominates(cb) and + def = sub.getAnSsaQualifier(subCfn) ) - or - guardAssertionControlsElement(g, guarded, v) and - exists(ConditionOnExprComparisonConfig c | c.same(sub, guarded)) } private predicate adjacentReadPairSameVarUniquePredecessor( @@ -1785,47 +1774,45 @@ module Internal { ) } + pragma[noinline] + private predicate isGuardedByExpr0( + AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, AbstractValue v + ) { + forex(ControlFlow::Node cfn | cfn = guarded.getAControlFlowNode() | + nodeIsGuardedBySameSubExpr(cfn, guarded, g, _, sub, v) + ) + } + cached predicate isGuardedByExpr( AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, AbstractValue v ) { - isGuardedByExpr1(guarded, g, sub, v) and - sub = getAChildExprStar(g) and - forall(Ssa::Definition def, ControlFlow::Node subCfn | def = sub.getAnSsaQualifier(subCfn) | - exists(ControlFlow::Node defCfn | def = guarded.getAnSsaQualifier(defCfn) | + isGuardedByExpr0(guarded, g, sub, v) and + forall(ControlFlow::Node subCfn, Ssa::Definition def | + nodeIsGuardedBySameSubExprSsaDef(_, guarded, g, subCfn, sub, v, def) + | + exists(ControlFlow::Node guardedCfn | + def = guarded.getAnSsaQualifier(guardedCfn) and if v.isReferentialProperty() - then adjacentReadPairSameVarUniquePredecessor(def, subCfn, defCfn) + then adjacentReadPairSameVarUniquePredecessor(def, subCfn, guardedCfn) else any() ) ) } - pragma[noinline] - private predicate isGuardedByNode1( - ControlFlow::Nodes::ElementNode guarded, Guard g, AccessOrCallExpr sub, AbstractValue v - ) { - isGuardedByNode0(guarded, _, g, sub, v) - or - guardAssertionControlsNode(g, guarded, v) and - exists(ConditionOnExprComparisonConfig c | c.same(sub, guarded.getElement())) - } - - pragma[noinline] - private predicate isGuardedByNode2(ControlFlow::Nodes::ElementNode guarded, Ssa::Definition def) { - isGuardedByNode1(guarded, _, _, _) and - exists(BasicBlock bb | bb = guarded.getBasicBlock() | - def = guarded.getElement().(AccessOrCallExpr).getAnSsaQualifier(bb.getANode()) - ) - } - cached predicate isGuardedByNode( ControlFlow::Nodes::ElementNode guarded, Guard g, AccessOrCallExpr sub, AbstractValue v ) { - isGuardedByNode1(guarded, g, sub, v) and - sub = getAChildExprStar(g) and - forall(Ssa::Definition def, ControlFlow::Node subCfn | def = sub.getAnSsaQualifier(subCfn) | - isGuardedByNode2(guarded, def) and + nodeIsGuardedBySameSubExpr(guarded, _, g, _, sub, v) and + forall(ControlFlow::Node subCfn, Ssa::Definition def | + nodeIsGuardedBySameSubExprSsaDef(guarded, _, g, subCfn, sub, v, def) + | + def = + guarded + .getElement() + .(AccessOrCallExpr) + .getAnSsaQualifier(guarded.getBasicBlock().getANode()) and if v.isReferentialProperty() then adjacentReadPairSameVarUniquePredecessor(def, subCfn, guarded) else any() diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/internal/Completion.qll b/csharp/ql/src/semmle/code/csharp/controlflow/internal/Completion.qll index 36aa4e926e06..a1c77b78eeda 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/internal/Completion.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/internal/Completion.qll @@ -20,6 +20,7 @@ */ import csharp +private import semmle.code.csharp.commons.Assertions private import semmle.code.csharp.commons.Constants private import semmle.code.csharp.frameworks.System private import NonReturning @@ -98,6 +99,13 @@ class Completion extends TCompletion { cfe instanceof ThrowElement and this = TThrowCompletion(cfe.(ThrowElement).getThrownExceptionType()) or + exists(AssertMethod m | assertion(cfe, m, _) | + this = TThrowCompletion(m.getExceptionClass()) + or + not exists(m.getExceptionClass()) and + this = TExitCompletion() + ) + or completionIsValidForStmt(cfe, this) or mustHaveBooleanCompletion(cfe) and @@ -382,6 +390,11 @@ private predicate invalidCastCandidate(CastExpr ce) { ce.getType() = ce.getExpr().getType().(ValueOrRefType).getASubType+() } +private predicate assertion(Assertion a, AssertMethod am, Expr e) { + e = a.getExpr() and + am = a.getAssertMethod() +} + /** * Holds if a normal completion of `e` must be a Boolean completion. */ @@ -409,6 +422,9 @@ private predicate inBooleanContext(Expr e, boolean isBooleanCompletionForParent) or exists(SpecificCatchClause scc | scc.getFilterClause() = e | isBooleanCompletionForParent = false) or + assertion(_, [any(AssertTrueMethod m).(AssertMethod), any(AssertFalseMethod m)], e) and + isBooleanCompletionForParent = false + or exists(LogicalNotExpr lne | lne.getAnOperand() = e | inBooleanContext(lne, _) and isBooleanCompletionForParent = true @@ -479,6 +495,9 @@ private predicate inNullnessContext(Expr e, boolean isNullnessCompletionForParen isNullnessCompletionForParent = false ) or + assertion(_, [any(AssertNullMethod m).(AssertMethod), any(AssertNonNullMethod m)], e) and + isNullnessCompletionForParent = false + or exists(ConditionalExpr ce | inNullnessContext(ce, _) | (e = ce.getThen() or e = ce.getElse()) and isNullnessCompletionForParent = true @@ -635,7 +654,7 @@ class EmptinessCompletion extends ConditionalCompletion, TEmptinessCompletion { * * Example: * - * ``` + * ```csharp * while (...) { * ... * break; @@ -656,7 +675,7 @@ class BreakNormalCompletion extends NormalCompletion, TBreakNormalCompletion { /** * A nested completion. For example, in * - * ``` + * ```csharp * void M(bool b) * { * try diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/internal/NonReturning.qll b/csharp/ql/src/semmle/code/csharp/controlflow/internal/NonReturning.qll index 9cead96e1206..1fc91f2cc049 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/internal/NonReturning.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/internal/NonReturning.qll @@ -55,10 +55,13 @@ private class ThrowingCall extends NonReturningCall { override ThrowCompletion getACompletion() { result = c } } +/** Holds if accessor `a` has an auto-implementation. */ +private predicate hasAccessorAutoImplementation(Accessor a) { not a.hasBody() } + abstract private class NonReturningCallable extends Callable { NonReturningCallable() { not exists(ReturnStmt ret | ret.getEnclosingCallable() = this) and - not hasAccessorAutoImplementation(this, _) and + not hasAccessorAutoImplementation(this) and not exists(Virtualizable v | v.isOverridableOrImplementable() | v = this or v = this.(Accessor).getDeclaration() @@ -80,7 +83,7 @@ private class DirectlyExitingCallable extends ExitingCallable { private class IndirectlyExitingCallable extends ExitingCallable { IndirectlyExitingCallable() { - forex(ControlFlowElement body | body = this.getABody() | body = getAnExitingElement()) + forex(ControlFlowElement body | body = this.getBody() | body = getAnExitingElement()) } } @@ -104,11 +107,11 @@ private Stmt getAnExitingStmt() { private class ThrowingCallable extends NonReturningCallable { ThrowingCallable() { - forex(ControlFlowElement body | body = this.getABody() | body = getAThrowingElement(_)) + forex(ControlFlowElement body | body = this.getBody() | body = getAThrowingElement(_)) } /** Gets a valid completion for a call to this throwing callable. */ - ThrowCompletion getACallCompletion() { this.getABody() = getAThrowingElement(result) } + ThrowCompletion getACallCompletion() { this.getBody() = getAThrowingElement(result) } } private predicate directlyThrows(ThrowElement te, ThrowCompletion c) { diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/internal/PreBasicBlocks.qll b/csharp/ql/src/semmle/code/csharp/controlflow/internal/PreBasicBlocks.qll index b2c9398a9b1a..f71ea9dba362 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/internal/PreBasicBlocks.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/internal/PreBasicBlocks.qll @@ -89,10 +89,14 @@ class PreBasicBlock extends ControlFlowElement { private predicate dominatesPredecessor(PreBasicBlock df) { this.dominates(df.getAPredecessor()) } } +private Completion getConditionalCompletion(ConditionalCompletion cc) { + result.getInnerCompletion() = cc +} + class ConditionBlock extends PreBasicBlock { ConditionBlock() { strictcount(Completion c | - c.getInnerCompletion() instanceof ConditionalCompletion and + c = getConditionalCompletion(_) and ( exists(succ(this.getLastElement(), c)) or @@ -102,9 +106,20 @@ class ConditionBlock extends PreBasicBlock { } private predicate immediatelyControls(PreBasicBlock succ, ConditionalCompletion cc) { - succ = succ(this.getLastElement(), any(Completion c | c.getInnerCompletion() = cc)) and - forall(PreBasicBlock pred | pred = succ.getAPredecessor() and pred != this | - succ.dominates(pred) + exists(ControlFlowElement last, Completion c | + last = this.getLastElement() and + c = getConditionalCompletion(cc) and + succ = succ(last, c) and + // In the pre-CFG, we need to account for case where one predecessor node has + // two edges to the same successor node. Assertion expressions are examples of + // such nodes. + not exists(Completion other | + succ = succ(last, other) and + other != c + ) and + forall(PreBasicBlock pred | pred = succ.getAPredecessor() and pred != this | + succ.dominates(pred) + ) ) } diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/internal/Splitting.qll b/csharp/ql/src/semmle/code/csharp/controlflow/internal/Splitting.qll index 5a78344a3912..c56f3db362ab 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/internal/Splitting.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/internal/Splitting.qll @@ -27,14 +27,16 @@ private module Cached { cached newtype TSplitKind = TInitializerSplitKind() or + TAssertionSplitKind() or TFinallySplitKind(int nestLevel) { nestLevel = FinallySplitting::nestLevel(_) } or TExceptionHandlerSplitKind() or TBooleanSplitKind(BooleanSplitting::BooleanSplitSubKind kind) { kind.startsSplit(_) } or - TLoopUnrollingSplitKind(LoopUnrollingSplitting::UnrollableLoopStmt loop) + TLoopSplitKind(LoopSplitting::AnalyzableLoopStmt loop) cached newtype TSplit = TInitializerSplit(Constructor c) { InitializerSplitting::constructorInitializes(c, _) } or + TAssertionSplit(AssertionSplitting::Assertion a, boolean success) { success = [true, false] } or TFinallySplit(FinallySplitting::FinallySplitType type, int nestLevel) { nestLevel = FinallySplitting::nestLevel(_) } or @@ -43,7 +45,7 @@ private module Cached { kind.startsSplit(_) and (branch = true or branch = false) } or - TLoopUnrollingSplit(LoopUnrollingSplitting::UnrollableLoopStmt loop) + TLoopSplit(LoopSplitting::AnalyzableLoopStmt loop) cached newtype TSplits = @@ -278,7 +280,7 @@ module InitializerSplitting { * A split for non-static member initializers belonging to a given non-static * constructor. For example, in * - * ``` + * ```csharp * class C * { * int Field1 = 0; @@ -301,7 +303,7 @@ module InitializerSplitting { * on the two constructors. This is in order to generate CFGs for the two * constructors that mimic * - * ``` + * ```csharp * public C() * { * Field1 = 0; @@ -312,7 +314,7 @@ module InitializerSplitting { * * and * - * ``` + * ```csharp * public C() * { * Field1 = 0; @@ -385,6 +387,135 @@ module InitializerSplitting { } } +module AssertionSplitting { + import semmle.code.csharp.commons.Assertions + private import semmle.code.csharp.ExprOrStmtParent + + private ControlFlowElement getAnAssertionDescendant(Assertion a) { + result = a + or + result = getAnAssertionDescendant(a).getAChild() + } + + /** + * A split for assertions. For example, in + * + * ```csharp + * void M(int i) + * { + * Debug.Assert(i >= 0); + * System.Console.WriteLine("i is positive") + * } + * ``` + * + * we record whether `i >= 0` evaluates to `true` or `false`, and restrict the + * edges out of the assertion accordingly. + */ + class AssertionSplitImpl extends SplitImpl, TAssertionSplit { + Assertion a; + boolean success; + + AssertionSplitImpl() { this = TAssertionSplit(a, success) } + + /** Gets the assertion. */ + Assertion getAssertion() { result = a } + + /** Holds if this split represents a successful assertion. */ + predicate isSuccess() { success = true } + + override string toString() { + success = true and result = "assertion success" + or + success = false and result = "assertion failure" + } + } + + private class AssertionSplitKind extends SplitKind, TAssertionSplitKind { + override int getListOrder() { result = InitializerSplitting::getNextListOrder() } + + override predicate isEnabled(ControlFlowElement cfe) { this.appliesTo(cfe) } + + override string toString() { result = "Assertion" } + } + + int getNextListOrder() { result = InitializerSplitting::getNextListOrder() + 1 } + + private class AssertionSplitInternal extends SplitInternal, AssertionSplitImpl { + override AssertionSplitKind getKind() { any() } + + override predicate hasEntry(ControlFlowElement pred, ControlFlowElement succ, Completion c) { + exists(AssertMethod m | + pred = last(a.getExpr(), c) and + succ = succ(pred, c) and + this.getAssertion() = a and + m = a.getAssertMethod() + | + m instanceof AssertTrueMethod and + ( + c instanceof TrueCompletion and success = true + or + c instanceof FalseCompletion and success = false + ) + or + m instanceof AssertFalseMethod and + ( + c instanceof TrueCompletion and success = false + or + c instanceof FalseCompletion and success = true + ) + or + m instanceof AssertNullMethod and + ( + c.(NullnessCompletion).isNull() and success = true + or + c.(NullnessCompletion).isNonNull() and success = false + ) + or + m instanceof AssertNonNullMethod and + ( + c.(NullnessCompletion).isNull() and success = false + or + c.(NullnessCompletion).isNonNull() and success = true + ) + ) + } + + override predicate hasEntry(Callable c, ControlFlowElement succ) { none() } + + override predicate hasExit(ControlFlowElement pred, ControlFlowElement succ, Completion c) { + this.appliesTo(pred) and + pred = a and + succ = succ(pred, c) and + ( + success = true and + c instanceof NormalCompletion + or + success = false and + not c instanceof NormalCompletion + ) + } + + override Callable hasExit(ControlFlowElement pred, Completion c) { + this.appliesTo(pred) and + pred = a and + result = succExit(pred, c) and + ( + success = true and + c instanceof NormalCompletion + or + success = false and + not c instanceof NormalCompletion + ) + } + + override predicate hasSuccessor(ControlFlowElement pred, ControlFlowElement succ, Completion c) { + this.appliesTo(pred) and + succ = succ(pred, c) and + succ = getAnAssertionDescendant(a) + } + } +} + pragma[noinline] private ControlFlowElement getAChild(ControlFlowElement cfe, Callable c) { result = cfe.getAChild() and @@ -467,7 +598,7 @@ module FinallySplitting { * A split for elements belonging to a `finally` block, which determines how to * continue execution after leaving the `finally` block. For example, in * - * ``` + * ```csharp * try * { * if (!M()) @@ -509,11 +640,11 @@ module FinallySplitting { } private int getListOrder(FinallySplitKind kind) { - result = InitializerSplitting::getNextListOrder() + kind.getNestLevel() + result = AssertionSplitting::getNextListOrder() + kind.getNestLevel() } int getNextListOrder() { - result = max(int i | i = getListOrder(_) + 1 or i = InitializerSplitting::getNextListOrder()) + result = max(int i | i = getListOrder(_) + 1 or i = AssertionSplitting::getNextListOrder()) } private class FinallySplitKind extends SplitKind, TFinallySplitKind { @@ -599,7 +730,7 @@ module FinallySplitting { // If this split is normal, and an outer split can exit based on a inherited // completion, we need to exit this split as well. For example, in // - // ``` + // ```csharp // bool done; // try // { @@ -677,7 +808,7 @@ module ExceptionHandlerSplitting { * A split for elements belonging to a `catch` clause, which determines the type of * exception to handle. For example, in * - * ``` + * ```csharp * try * { * if (M() > 0) @@ -698,11 +829,11 @@ module ExceptionHandlerSplitting { * ``` * * all control flow nodes in - * ``` + * ```csharp * catch (ArgumentException e) * ``` * and - * ``` + * ```csharp * catch (ArithmeticException e) when (e.Message != null) * ``` * have two splits: one representing the `try` block throwing an `ArgumentException`, @@ -853,7 +984,7 @@ module BooleanSplitting { * * For example, in * - * ``` + * ```csharp * var b = GetB(); * if (b) * Console.WriteLine("b is true"); @@ -892,7 +1023,7 @@ module BooleanSplitting { * * For example, in * - * ``` + * ```csharp * var b = GetB(); * if (b) * Console.WriteLine("b is true"); @@ -969,7 +1100,7 @@ module BooleanSplitting { * A split for elements that can reach a condition where this split determines * the Boolean value that the condition evaluates to. For example, in * - * ``` + * ```csharp * if (b) * Console.WriteLine("b is true"); * if (!b) @@ -1109,7 +1240,7 @@ module BooleanSplitting { } } -module LoopUnrollingSplitting { +module LoopSplitting { private import semmle.code.csharp.controlflow.Guards as Guards private import PreBasicBlocks private import PreSsa @@ -1125,53 +1256,80 @@ module LoopUnrollingSplitting { } /** - * A loop where the body is guaranteed to be executed at least once, and - * can therefore be unrolled in the control flow graph. + * A loop where the body is guaranteed to be executed at least once, and hence + * can be unrolled in the control flow graph, or where the body is guaranteed + * to never be executed, and hence can be removed from the control flow graph. */ - abstract class UnrollableLoopStmt extends LoopStmt { - /** Holds if the step `pred --c--> succ` should start loop unrolling. */ - abstract predicate startUnroll(ControlFlowElement pred, ControlFlowElement succ, Completion c); + abstract class AnalyzableLoopStmt extends LoopStmt { + /** Holds if the step `pred --c--> succ` should start the split. */ + abstract predicate start(ControlFlowElement pred, ControlFlowElement succ, Completion c); - /** Holds if the step `pred --c--> succ` should stop loop unrolling. */ - abstract predicate stopUnroll(ControlFlowElement pred, ControlFlowElement succ, Completion c); + /** Holds if the step `pred --c--> succ` should stop the split. */ + abstract predicate stop(ControlFlowElement pred, ControlFlowElement succ, Completion c); /** - * Holds if any step `pred --c--> _` should be pruned from the unrolled loop - * (the loop condition evaluating to `false`). + * Holds if any step `pred --c--> _` should be pruned from the control flow graph. */ abstract predicate pruneLoopCondition(ControlFlowElement pred, ConditionalCompletion c); + + /** + * Holds if the body is guaranteed to be executed at least once. If not, the + * body is guaranteed to never be executed. + */ + abstract predicate isUnroll(); } - private class UnrollableForeachStmt extends UnrollableLoopStmt, ForeachStmt { - UnrollableForeachStmt() { - exists(Guards::AbstractValues::EmptyCollectionValue v | v.isNonEmpty() | - emptinessGuarded(_, this.getIterableExpr(), v) - or - this.getIterableExpr() = v.getAnExpr() - ) + private class AnalyzableForeachStmt extends AnalyzableLoopStmt, ForeachStmt { + Guards::AbstractValues::EmptyCollectionValue v; + + AnalyzableForeachStmt() { + /* + * We use `unique` to avoid degenerate cases like + * ```csharp + * if (xs.Length == 0) + * return; + * if (xs.Length > 0) + * return; + * foreach (var x in xs) + * .... + * ``` + * where the iterator expression `xs` is guarded by both an emptiness check + * and a non-emptiness check. + */ + + v = + unique(Guards::AbstractValues::EmptyCollectionValue v0 | + emptinessGuarded(_, this.getIterableExpr(), v0) + or + this.getIterableExpr() = v0.getAnExpr() + | + v0 + ) } - override predicate startUnroll(ControlFlowElement pred, ControlFlowElement succ, Completion c) { + override predicate start(ControlFlowElement pred, ControlFlowElement succ, Completion c) { pred = last(this.getIterableExpr(), c) and succ = this } - override predicate stopUnroll(ControlFlowElement pred, ControlFlowElement succ, Completion c) { + override predicate stop(ControlFlowElement pred, ControlFlowElement succ, Completion c) { pred = this and succ = succ(pred, c) } override predicate pruneLoopCondition(ControlFlowElement pred, ConditionalCompletion c) { pred = this and - c.(EmptinessCompletion).isEmpty() + c = any(EmptinessCompletion ec | if v.isEmpty() then not ec.isEmpty() else ec.isEmpty()) } + + override predicate isUnroll() { v.isNonEmpty() } } /** - * A split for loops where the body is guaranteed to be executed at least once, and - * can therefore be unrolled in the control flow graph. For example, in + * A split for loops where the body is guaranteed to be executed at least once, or + * guaranteed to never be executed. For example, in * - * ``` + * ```csharp * void M(string[] args) * { * if (args.Length == 0) @@ -1184,21 +1342,23 @@ module LoopUnrollingSplitting { * the `foreach` loop is guaranteed to be executed at least once, as a result of the * `args.Length == 0` check. */ - class LoopUnrollingSplitImpl extends SplitImpl, TLoopUnrollingSplit { - UnrollableLoopStmt loop; + class LoopSplitImpl extends SplitImpl, TLoopSplit { + AnalyzableLoopStmt loop; - LoopUnrollingSplitImpl() { this = TLoopUnrollingSplit(loop) } + LoopSplitImpl() { this = TLoopSplit(loop) } override string toString() { - result = "unroll (line " + loop.getLocation().getStartLine() + ")" + if loop.isUnroll() + then result = "unroll (line " + loop.getLocation().getStartLine() + ")" + else result = "skip (line " + loop.getLocation().getStartLine() + ")" } } - private int getListOrder(UnrollableLoopStmt loop) { + private int getListOrder(AnalyzableLoopStmt loop) { exists(Callable c, int r | c = loop.getEnclosingCallable() | result = r + BooleanSplitting::getNextListOrder() - 1 and loop = - rank[r](UnrollableLoopStmt loop0 | + rank[r](AnalyzableLoopStmt loop0 | loop0.getEnclosingCallable() = c | loop0 order by loop0.getLocation().getStartLine(), loop0.getLocation().getStartColumn() @@ -1210,21 +1370,21 @@ module LoopUnrollingSplitting { result = max(int i | i = getListOrder(_) + 1 or i = BooleanSplitting::getNextListOrder()) } - private class LoopUnrollingSplitKind extends SplitKind, TLoopUnrollingSplitKind { - private UnrollableLoopStmt loop; + private class LoopSplitKind extends SplitKind, TLoopSplitKind { + private AnalyzableLoopStmt loop; - LoopUnrollingSplitKind() { this = TLoopUnrollingSplitKind(loop) } + LoopSplitKind() { this = TLoopSplitKind(loop) } override int getListOrder() { result = getListOrder(loop) } override string toString() { result = "Unroll" } } - private class LoopUnrollingSplitInternal extends SplitInternal, LoopUnrollingSplitImpl { - override LoopUnrollingSplitKind getKind() { result = TLoopUnrollingSplitKind(loop) } + private class LoopUnrollingSplitInternal extends SplitInternal, LoopSplitImpl { + override LoopSplitKind getKind() { result = TLoopSplitKind(loop) } override predicate hasEntry(ControlFlowElement pred, ControlFlowElement succ, Completion c) { - loop.startUnroll(pred, succ, c) + loop.start(pred, succ, c) } override predicate hasEntry(Callable pred, ControlFlowElement succ) { none() } @@ -1241,7 +1401,7 @@ module LoopUnrollingSplitting { override predicate hasExit(ControlFlowElement pred, ControlFlowElement succ, Completion c) { this.appliesToPredecessor(pred, c) and - loop.stopUnroll(pred, succ, c) + loop.stop(pred, succ, c) } override Callable hasExit(ControlFlowElement pred, Completion c) { @@ -1252,7 +1412,7 @@ module LoopUnrollingSplitting { override predicate hasSuccessor(ControlFlowElement pred, ControlFlowElement succ, Completion c) { this.appliesToPredecessor(pred, c) and succ = succ(pred, c) and - not loop.stopUnroll(pred, succ, c) + not loop.stop(pred, succ, c) } } } @@ -1338,7 +1498,7 @@ predicate succExitSplits(ControlFlowElement pred, Splits predSplits, Callable su * * For the successor relation * - * ``` + * ```ql * succSplits(ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits, Completion c) * ``` * diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/internal/SuccessorType.qll b/csharp/ql/src/semmle/code/csharp/controlflow/internal/SuccessorType.qll index 3f265236fb41..8e34ac19a0d0 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/internal/SuccessorType.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/internal/SuccessorType.qll @@ -59,7 +59,7 @@ module SuccessorTypes { * * For example, this program fragment: * - * ``` + * ```csharp * if (x < 0) * return 0; * else @@ -95,7 +95,7 @@ module SuccessorTypes { * * For example, this program fragment: * - * ``` + * ```csharp * int? M(string s) => s?.Length; * ``` * @@ -134,7 +134,7 @@ module SuccessorTypes { * * For example, this program fragment: * - * ``` + * ```csharp * switch (x) { * case 0 : * return 0; @@ -181,7 +181,7 @@ module SuccessorTypes { * * For example, this program fragment: * - * ``` + * ```csharp * foreach (var arg in args) * { * yield return arg; @@ -228,7 +228,7 @@ module SuccessorTypes { * * Example: * - * ``` + * ```csharp * void M() * { * return; @@ -249,7 +249,7 @@ module SuccessorTypes { * * Example: * - * ``` + * ```csharp * int M(int x) * { * while (true) @@ -277,7 +277,7 @@ module SuccessorTypes { * * Example: * - * ``` + * ```csharp * int M(int x) * { * while (true) { @@ -302,7 +302,7 @@ module SuccessorTypes { * * Example: * - * ``` + * ```csharp * int M(int x) * { * while (true) @@ -333,7 +333,7 @@ module SuccessorTypes { * * Example: * - * ``` + * ```csharp * int M(string s) * { * if (s == null) @@ -361,7 +361,7 @@ module SuccessorTypes { * * Example: * - * ``` + * ```csharp * int M(string s) * { * if (s == null) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/Bound.qll b/csharp/ql/src/semmle/code/csharp/dataflow/Bound.qll new file mode 100644 index 000000000000..b129203db706 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/dataflow/Bound.qll @@ -0,0 +1,78 @@ +/** + * Provides classes for representing abstract bounds for use in, for example, range analysis. + */ + +private import internal.rangeanalysis.BoundSpecific + +private newtype TBound = + TBoundZero() or + TBoundSsa(SsaVariable v) { v.getSourceVariable().getType() instanceof IntegralType } or + TBoundExpr(Expr e) { + interestingExprBound(e) and + not exists(SsaVariable v | e = v.getAUse()) + } + +/** + * A bound that may be inferred for an expression plus/minus an integer delta. + */ +abstract class Bound extends TBound { + /** Gets a textual representation of this bound. */ + abstract string toString(); + + /** Gets an expression that equals this bound plus `delta`. */ + abstract Expr getExpr(int delta); + + /** Gets an expression that equals this bound. */ + Expr getExpr() { result = getExpr(0) } + + /** + * Holds if this element is at the specified location. + * The location spans column `sc` of line `sl` to + * column `ec` of line `el` in file `path`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ + predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { + path = "" and sl = 0 and sc = 0 and el = 0 and ec = 0 + } +} + +/** + * The bound that corresponds to the integer 0. This is used to represent all + * integer bounds as bounds are always accompanied by an added integer delta. + */ +class ZeroBound extends Bound, TBoundZero { + override string toString() { result = "0" } + + override Expr getExpr(int delta) { result.(ConstantIntegerExpr).getIntValue() = delta } +} + +/** + * A bound corresponding to the value of an SSA variable. + */ +class SsaBound extends Bound, TBoundSsa { + /** Gets the SSA variable that equals this bound. */ + SsaVariable getSsa() { this = TBoundSsa(result) } + + override string toString() { result = getSsa().toString() } + + override Expr getExpr(int delta) { result = getSsa().getAUse() and delta = 0 } + + override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { + getSsa().getLocation().hasLocationInfo(path, sl, sc, el, ec) + } +} + +/** + * A bound that corresponds to the value of a specific expression that might be + * interesting, but isn't otherwise represented by the value of an SSA variable. + */ +class ExprBound extends Bound, TBoundExpr { + override string toString() { result = getExpr().toString() } + + override Expr getExpr(int delta) { this = TBoundExpr(result) and delta = 0 } + + override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { + getExpr().getLocation().hasLocationInfo(path, sl, sc, el, ec) + } +} diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/CallContext.qll b/csharp/ql/src/semmle/code/csharp/dataflow/CallContext.qll index c36bcc0dc8a7..b0a6d9d98edc 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/CallContext.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/CallContext.qll @@ -11,10 +11,7 @@ cached private newtype TCallContext = TEmptyCallContext() or TArgNonDelegateCallContext(Expr arg) { exists(DispatchCall dc | arg = dc.getArgument(_)) } or - TArgDelegateCallContext(DelegateCall dc, int i) { exists(dc.getArgument(i)) } or - TDelegateToLibraryCallableArgCallContext(DelegateArgumentToLibraryCallable arg, int i) { - exists(arg.getDelegateType().getParameter(i)) - } + TArgDelegateCallContext(DelegateCall dc, int i) { exists(dc.getArgument(i)) } /** * A call context. @@ -79,31 +76,3 @@ class DelegateCallArgumentCallContext extends ArgumentCallContext, TArgDelegateC override Location getLocation() { result = dc.getArgument(arg).getLocation() } } - -/** - * An argument of a call to a delegate supplied to a library callable, - * identified by the delegate argument itself. - * - * For example, in `x.Select(y => y)` the call to the supplied delegate - * that happens inside the library callable `Select` is not available - * in the database, so the delegate argument `y => y` is used to - * represent the call. - */ -class DelegateArgumentToLibraryCallableArgumentContext extends ArgumentCallContext, - TDelegateToLibraryCallableArgCallContext { - Expr delegate; - int arg; - - DelegateArgumentToLibraryCallableArgumentContext() { - this = TDelegateToLibraryCallableArgCallContext(delegate, arg) - } - - override predicate isArgument(Expr call, int i) { - call = delegate and - i = arg - } - - override string toString() { result = "argument " + arg + " of " + delegate.toString() } - - override Location getLocation() { result = delegate.getLocation() } -} diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll b/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll index 1f08f81548a7..c1c10b9bf49d 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll @@ -3,7 +3,6 @@ */ import csharp -private import semmle.code.csharp.frameworks.WCF private import semmle.code.csharp.frameworks.System private import semmle.code.csharp.frameworks.system.Collections private import semmle.code.csharp.frameworks.system.collections.Generic @@ -12,28 +11,66 @@ private import semmle.code.csharp.frameworks.system.io.Compression private import semmle.code.csharp.frameworks.system.linq.Expressions private import semmle.code.csharp.frameworks.system.Net private import semmle.code.csharp.frameworks.system.Text +private import semmle.code.csharp.frameworks.system.runtime.CompilerServices private import semmle.code.csharp.frameworks.system.threading.Tasks private import semmle.code.csharp.frameworks.system.Web private import semmle.code.csharp.frameworks.system.web.ui.WebControls private import semmle.code.csharp.frameworks.system.Xml +private import semmle.code.csharp.dataflow.internal.DataFlowPrivate private import semmle.code.csharp.dataflow.internal.DataFlowPublic private import semmle.code.csharp.dataflow.internal.DelegateDataFlow +// import `LibraryTypeDataFlow` definitions from other files to avoid potential reevaluation +private import semmle.code.csharp.frameworks.EntityFramework +private import semmle.code.csharp.frameworks.JsonNET private newtype TAccessPath = TNilAccessPath() or - TAccessPathConsNil(Content c) + TConsAccessPath(Content head, AccessPath tail) { + tail = TNilAccessPath() + or + exists(LibraryTypeDataFlow ltdf | + ltdf.requiresAccessPath(head, tail) and + tail.length() < accessPathLimit() + ) + or + tail = AccessPath::singleton(_) and + head instanceof ElementContent + or + tail = AccessPath::element() + } -/** An access path of length 0 or 1. */ +/** An access path. */ class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ - Content getHead() { this = TAccessPathConsNil(result) } + Content getHead() { this = TConsAccessPath(result, _) } + + /** Gets the tail of this access path, if any. */ + AccessPath getTail() { this = TConsAccessPath(_, result) } + + /** Gets the length of this access path. */ + int length() { + this = TNilAccessPath() and result = 0 + or + result = 1 + this.getTail().length() + } + + /** Gets the access path obtained by dropping the first `i` elements, if any. */ + AccessPath drop(int i) { + i = 0 and result = this + or + result = this.getTail().drop(i - 1) + } /** Holds if this access path contains content `c`. */ - predicate contains(Content c) { this = TAccessPathConsNil(c) } + predicate contains(Content c) { c = this.drop(_).getHead() } /** Gets a textual representation of this access path. */ string toString() { - result = this.getHead().toString() + exists(Content head, AccessPath tail | + head = this.getHead() and + tail = this.getTail() and + if tail.length() = 0 then result = head.toString() else result = head + ", " + tail + ) or this = TNilAccessPath() and result = "" @@ -45,10 +82,27 @@ module AccessPath { /** Gets the empty access path. */ AccessPath empty() { result = TNilAccessPath() } + /** Gets a singleton access path containing `c`. */ + AccessPath singleton(Content c) { result = TConsAccessPath(c, TNilAccessPath()) } + + /** Gets the access path obtained by concatenating `head` onto `tail`. */ + AccessPath cons(Content head, AccessPath tail) { result = TConsAccessPath(head, tail) } + + /** Gets the singleton "element content" access path. */ + AccessPath element() { result = singleton(any(ElementContent c)) } + /** Gets a singleton property access path. */ AccessPath property(Property p) { - result = TAccessPathConsNil(any(PropertyContent c | c.getProperty() = p.getSourceDeclaration())) + result = singleton(any(PropertyContent c | c.getProperty() = p.getSourceDeclaration())) } + + /** Gets a singleton field access path. */ + AccessPath field(Field f) { + result = singleton(any(FieldContent c | c.getField() = f.getSourceDeclaration())) + } + + /** Gets an access path representing a property inside a collection. */ + AccessPath properties(Property p) { result = TConsAccessPath(any(ElementContent c), property(p)) } } /** An unbound callable. */ @@ -61,25 +115,9 @@ class SourceDeclarationMethod extends SourceDeclarationCallable, Method { } private newtype TCallableFlowSource = TCallableFlowSourceQualifier() or - TCallableFlowSourceArg(int i) { hasArgumentPosition(_, i) } or + TCallableFlowSourceArg(int i) { i = any(Parameter p).getPosition() } or TCallableFlowSourceDelegateArg(int i) { hasDelegateArgumentPosition(_, i) } -private predicate hasArgumentPosition(SourceDeclarationCallable callable, int position) { - exists(int arity | - if callable.getAParameter().isParams() - then - arity = - max(Call call | - call.getTarget().getSourceDeclaration() = callable - | - call.getNumberOfArguments() - ) - else arity = callable.getNumberOfParameters() - | - position in [0 .. arity - 1] - ) -} - private predicate hasDelegateArgumentPosition(SourceDeclarationCallable c, int i) { exists(DelegateType dt | dt = c.getParameter(i).getType().(SystemLinqExpressions::DelegateExtType).getDelegateType() @@ -161,12 +199,6 @@ class CallableFlowSink extends TCallableFlowSink { /** Gets the sink of flow for call `c`, if any. */ Expr getSink(Call c) { none() } - - /** - * Gets the type of the sink for call `c`. Unlike `getSink()`, this is defined - * for all flow sink specifications. - */ - Type getSinkType(Call c) { result = this.getSink(c).getType() } } /** A flow sink specification: (method call) qualifier. */ @@ -207,14 +239,22 @@ class CallableFlowSinkArg extends CallableFlowSink, TCallableFlowSinkArg { // The uses of the `i`th argument are the actual sinks none() } +} - override Type getSinkType(Call c) { result = this.getArgument(c).getType() } +private predicate isCollectionType(ValueOrRefType t) { + t.getABaseType*() instanceof SystemCollectionsIEnumerableInterface and + not t instanceof StringType } /** Gets the flow source for argument `i` of callable `callable`. */ -private CallableFlowSourceArg getFlowSourceArg(SourceDeclarationCallable callable, int i) { +private CallableFlowSourceArg getFlowSourceArg( + SourceDeclarationCallable callable, int i, AccessPath ap +) { i = result.getArgumentIndex() and - hasArgumentPosition(callable, i) + exists(Parameter p | + p = callable.getParameter(i) and + if isCollectionType(p.getType()) then ap = AccessPath::element() else ap = AccessPath::empty() + ) } /** Gets the flow source for argument `i` of delegate `callable`. */ @@ -256,16 +296,6 @@ class CallableFlowSinkDelegateArg extends CallableFlowSink, TCallableFlowSinkDel // The uses of the `j`th parameter are the actual sinks none() } - - override Type getSinkType(Call c) { - result = - c - .getArgument(delegateIndex) - .(DelegateArgumentToLibraryCallable) - .getDelegateType() - .getParameter(parameterIndex) - .getType() - } } /** A specification of data flow for a library (non-source code) type. */ @@ -291,13 +321,33 @@ abstract class LibraryTypeDataFlow extends Type { * Holds if data may flow from `source` to `sink` when calling callable `c`. * * `sourceAp` describes the contents of `source` that flows to `sink` - * (if any), and `sinkContent` describes the contents of `sink` that it + * (if any), and `sinkAp` describes the contents of `sink` that it * flows to (if any). */ pragma[nomagic] predicate callableFlow( CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, - SourceDeclarationCallable c + SourceDeclarationCallable c, boolean preservesValue + ) { + none() + } + + /** + * Holds if the access path obtained by concatenating `head` onto `tail` is + * needed for a summary specified by `callableFlow()`. + * + * This predicate is needed for QL technical reasons only (the IPA type used + * to represent access paths needs to be bounded). + */ + predicate requiresAccessPath(Content head, AccessPath tail) { none() } + + /** + * Holds if values stored inside `content` are cleared on objects passed as + * arguments of type `source` to calls that target `callable`. + */ + pragma[nomagic] + predicate clearsContent( + CallableFlowSource source, Content content, SourceDeclarationCallable callable ) { none() } @@ -392,8 +442,7 @@ class SystemUriFlow extends LibraryTypeDataFlow, SystemUriClass { private predicate methodFlow( CallableFlowSource source, CallableFlowSink sink, SourceDeclarationMethod m ) { - m.getDeclaringType() = getABaseType*() and - m = any(SystemObjectClass c).getToStringMethod().getAnOverrider*() and + m = this.getAMethod("ToString") and source = TCallableFlowSourceQualifier() and sink = TCallableFlowSinkReturn() } @@ -441,41 +490,48 @@ class SystemIOStringReaderFlow extends LibraryTypeDataFlow, SystemIOStringReader /** Data flow for `System.String`. */ class SystemStringFlow extends LibraryTypeDataFlow, SystemStringClass { override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue ) { - constructorFlow(source, sink, c) and preservesValue = false + constructorFlow(source, sourceAp, sink, sinkAp, c) and + preservesValue = false or - methodFlow(source, sink, c, preservesValue) + methodFlow(source, sourceAp, sink, sinkAp, c, preservesValue) } - private predicate constructorFlow(CallableFlowSource source, CallableFlowSink sink, Constructor c) { + private predicate constructorFlow( + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + Constructor c + ) { c = getAMember() and c.getParameter(0).getType().(ArrayType).getElementType() instanceof CharType and source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() } private predicate methodFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationMethod m, - boolean preservesValue + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationMethod m, boolean preservesValue ) { - m = getAMethod() and - ( - m = any(SystemObjectClass c).getToStringMethod().getAnOverrider*() and - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - preservesValue = true - ) + m = this.getAMethod("ToString") and + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + preservesValue = true or m = getSplitMethod() and - ( - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - preservesValue = false - ) + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() and + preservesValue = false or m = getReplaceMethod() and + sourceAp = AccessPath::empty() and + sinkAp = AccessPath::empty() and ( source = TCallableFlowSourceQualifier() and sink = TCallableFlowSinkReturn() and @@ -487,20 +543,22 @@ class SystemStringFlow extends LibraryTypeDataFlow, SystemStringClass { ) or m = getSubstringMethod() and - ( - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - preservesValue = false - ) + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + preservesValue = false or m = getCloneMethod() and - ( - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - preservesValue = true - ) + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + preservesValue = true or m = getInsertMethod() and + sourceAp = AccessPath::empty() and + sinkAp = AccessPath::empty() and ( source = TCallableFlowSourceQualifier() and sink = TCallableFlowSinkReturn() and @@ -512,55 +570,54 @@ class SystemStringFlow extends LibraryTypeDataFlow, SystemStringClass { ) or m = getNormalizeMethod() and - ( - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - preservesValue = false - ) + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + preservesValue = false or m = getRemoveMethod() and - ( - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - preservesValue = false - ) + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + preservesValue = false or m = getAMethod() and - ( - m - .getName() - .regexpMatch("((ToLower|ToUpper)(Invariant)?)|(Trim(Start|End)?)|(Pad(Left|Right))") and - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - preservesValue = false - ) + m.getName().regexpMatch("((ToLower|ToUpper)(Invariant)?)|(Trim(Start|End)?)|(Pad(Left|Right))") and + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + preservesValue = false or m = getConcatMethod() and - ( - source = getFlowSourceArg(m, _) and + exists(int i | + source = getFlowSourceArg(m, i, sourceAp) and sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and preservesValue = false ) or m = getCopyMethod() and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() and - preservesValue = true - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + preservesValue = true or m = getJoinMethod() and - ( - source = getFlowSourceArg(m, _) and - sink = TCallableFlowSinkReturn() and - preservesValue = false - ) + source = getFlowSourceArg(m, [0, 1], sourceAp) and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + preservesValue = false or m = getFormatMethod() and exists(int i | (m.getParameter(0).getType() instanceof SystemIFormatProviderInterface implies i != 0) and - source = getFlowSourceArg(m, i) and + source = getFlowSourceArg(m, i, sourceAp) and sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and preservesValue = false ) } @@ -569,53 +626,72 @@ class SystemStringFlow extends LibraryTypeDataFlow, SystemStringClass { /** Data flow for `System.Text.StringBuilder`. */ class SystemTextStringBuilderFlow extends LibraryTypeDataFlow, SystemTextStringBuilderClass { override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue ) { ( - constructorFlow(source, sink, c) + constructorFlow(source, sourceAp, sink, sinkAp, c) and + preservesValue = true or - methodFlow(source, sink, c) - ) and - preservesValue = false + methodFlow(source, sourceAp, sink, sinkAp, c, preservesValue) + ) } - private predicate constructorFlow(CallableFlowSource source, CallableFlowSink sink, Constructor c) { + private predicate constructorFlow( + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + Constructor c + ) { c = getAMember() and c.getParameter(0).getType() instanceof StringType and source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() } private predicate methodFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationMethod m + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationMethod m, boolean preservesValue ) { - m.getDeclaringType() = getABaseType*() and - ( - m = any(SystemObjectClass c).getToStringMethod().getAnOverrider*() and + exists(string name | m = this.getAMethod(name) | + name = "ToString" and source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() - ) - or - m = getAMethod() and - exists(int i, Type t | - m.getName().regexpMatch("Append(Format|Line)?") and - t = m.getParameter(i).getType() and - source = getFlowSourceArg(m, i) and - sink = TCallableFlowSinkQualifier() - | - t instanceof StringType or - t instanceof ObjectType + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + preservesValue = false + or + exists(int i, Type t | + name.regexpMatch("Append(Format|Line)?") and + t = m.getParameter(i).getType() and + source = TCallableFlowSourceArg(i) and + sourceAp = AccessPath::empty() and + sink = [TCallableFlowSinkQualifier().(TCallableFlowSink), TCallableFlowSinkReturn()] and + sinkAp = AccessPath::element() and + preservesValue = true + | + t instanceof StringType or + t instanceof ObjectType + ) ) } + + override predicate clearsContent( + CallableFlowSource source, Content content, SourceDeclarationCallable callable + ) { + source = TCallableFlowSourceQualifier() and + callable = this.getAMethod("Clear") and + content instanceof ElementContent + } } /** Data flow for `System.Lazy<>`. */ class SystemLazyFlow extends LibraryTypeDataFlow, SystemLazyClass { override predicate callableFlow( CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, - SourceDeclarationCallable c + SourceDeclarationCallable c, boolean preservesValue ) { + preservesValue = true and exists(SystemFuncDelegateType t, int i | t.getNumberOfTypeParameters() = 1 | c.(Constructor).getDeclaringType() = this and c.getParameter(i).getType().getSourceDeclaration() = t and @@ -624,53 +700,137 @@ class SystemLazyFlow extends LibraryTypeDataFlow, SystemLazyClass { sink = TCallableFlowSinkReturn() and sinkAp = AccessPath::property(this.getValueProperty()) ) + or + preservesValue = false and + c = this.getValueProperty().getGetter() and + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() } } -/** - * Data flow for `System.Collections.IEnumerable`, `System.Collections.Generic.IEnumerable<>`, - * and their sub types (for example `System.Collections.Generic.List<>`). - */ -class IEnumerableFlow extends LibraryTypeDataFlow { - IEnumerableFlow() { - exists(RefType t | t = this.(RefType).getABaseType*() | - t instanceof SystemCollectionsIEnumerableInterface - or - t instanceof SystemCollectionsGenericIEnumerableTInterface - or - t.(ConstructedInterface).getUnboundGeneric() instanceof - SystemCollectionsGenericIEnumerableTInterface - ) +/** Data flow for `System.Nullable<>`. */ +class SystemNullableFlow extends LibraryTypeDataFlow, SystemNullableStruct { + override predicate callableFlow( + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue + ) { + preservesValue = true and + c.(Constructor).getDeclaringType() = this and + source = getFlowSourceArg(c, 0, sourceAp) and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::property(this.getValueProperty()) + or + preservesValue = true and + c = this.getAGetValueOrDefaultMethod() and + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::property(this.getValueProperty()) and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() + or + preservesValue = false and + c = this.getHasValueProperty().getGetter() and + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::property(this.getValueProperty()) and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() + or + preservesValue = true and + c = this.getAGetValueOrDefaultMethod() and + source = getFlowSourceArg(c, 0, _) and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() + or + preservesValue = false and + c = this.getValueProperty().getGetter() and + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() } +} + +/** Data flow for `System.Collections.IEnumerable` (and sub types). */ +class IEnumerableFlow extends LibraryTypeDataFlow, RefType { + IEnumerableFlow() { this.getABaseType*() instanceof SystemCollectionsIEnumerableInterface } override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue ) { + preservesValue = true and ( - methodFlow(source, sink, c) + methodFlowLINQExtensions(source, sourceAp, sink, sinkAp, c) or - exists(Property p | - propertyFlow(p) and + c = this.getFind() and + sourceAp = AccessPath::element() and + sinkAp = AccessPath::empty() and + if c.(Method).isStatic() + then + source = TCallableFlowSourceArg(0) and + ( + sink = TCallableFlowSinkReturn() or + sink = getDelegateFlowSinkArg(c, 1, 0) + ) + else ( source = TCallableFlowSourceQualifier() and + ( + sink = TCallableFlowSinkReturn() or + sink = getDelegateFlowSinkArg(c, 0, 0) + ) + ) + or + exists(string name, int arity | + arity = c.getNumberOfParameters() and + c = this.getAMethod(name) + | + name = "Add" and + arity = 1 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::empty() and + sink instanceof CallableFlowSinkQualifier and + sinkAp = AccessPath::element() + or + name = "AddRange" and + arity = 1 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkQualifier() and + sinkAp = AccessPath::element() + or + exists(Property current | + name = "GetEnumerator" and + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::property(current) and + current = c.getReturnType().(ValueOrRefType).getProperty("Current") + ) + or + name = "Repeat" and + c.(Method).isStatic() and + arity = 2 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::empty() and sink = TCallableFlowSinkReturn() and - c = p.getGetter() + sinkAp = AccessPath::element() + or + name = "Reverse" and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) - ) and - preservesValue = false - } - - private predicate methodFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationMethod m - ) { - methodFlowLINQ(source, sink, m) - or - methodFlowSpecific(source, sink, m) + ) } - /** Flow for LINQ methods. */ - private predicate methodFlowLINQ( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationMethod m + /** Flow for LINQ extension methods. */ + private predicate methodFlowLINQExtensions( + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationMethod m ) { m.(ExtensionMethod).getExtendedType().getSourceDeclaration() = this and exists(string name, int arity | name = m.getName() and arity = m.getNumberOfParameters() | @@ -679,192 +839,239 @@ class IEnumerableFlow extends LibraryTypeDataFlow { arity = 2 and ( source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 1) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 1) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceDelegateArg(1) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() ) or arity = 3 and ( source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 2, 1) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 1) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceArg(1) and - sink = getDelegateFlowSinkArg(m, 2, 0) + sourceAp = AccessPath::empty() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceDelegateArg(2) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() ) or arity = 4 and ( source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 2, 1) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 1) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceArg(1) and - sink = getDelegateFlowSinkArg(m, 2, 0) + sourceAp = AccessPath::empty() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceDelegateArg(2) and - sink = getDelegateFlowSinkArg(m, 3, 0) + sourceAp = AccessPath::empty() and + sink = getDelegateFlowSinkArg(m, 3, 0) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceDelegateArg(3) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() ) ) or name = "All" and - ( - arity = 2 and - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - ) + arity = 2 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() or name = "Any" and - ( - arity = 2 and - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - ) + arity = 2 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() or name = "AsEnumerable" and - ( - arity = 1 and - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + arity = 1 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or name = "AsQueryable" and arity = 1 and source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or name = "Average" and - ( - arity = 2 and - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - ) + arity = 2 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() or name = "Cast" and - ( - arity = 1 and - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + arity = 1 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or name = "Concat" and + arity = 2 and ( - arity = 2 and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - or - source = TCallableFlowSourceArg(1) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() + or + source = TCallableFlowSourceArg(1) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) or name.regexpMatch("(Long)?Count") and - ( - arity = 2 and - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - ) + arity = 2 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() or name = "DefaultIfEmpty" and ( arity in [1 .. 2] and source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() or arity = 2 and source = TCallableFlowSourceArg(1) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() ) or name = "Distinct" and - ( - arity in [1 .. 2] and - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + arity in [1 .. 2] and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or name.regexpMatch("ElementAt(OrDefault)?") and - ( - arity = 2 and - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + arity = 2 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() or name = "Except" and - ( - arity in [2 .. 3] and - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + arity in [2 .. 3] and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() or name.regexpMatch("(First|Single)(OrDefault)?") and ( arity in [1 .. 2] and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() or arity = 2 and - ( - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() ) or name = "GroupBy" and ( + arity = 2 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() + or arity = 3 and ( source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() or m.getParameter(2).getType().(ConstructedDelegateType).getNumberOfTypeArguments() = 2 and source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 2, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() or m.getParameter(2).getType().(ConstructedDelegateType).getNumberOfTypeArguments() = 3 and source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 2, 1) + sourceAp = AccessPath::empty() and + sink = getDelegateFlowSinkArg(m, 2, 1) and + sinkAp = AccessPath::empty() or m.getParameter(2).getType().(ConstructedDelegateType).getNumberOfTypeArguments() = 3 and source = getDelegateFlowSourceArg(m, 1) and - sink = getDelegateFlowSinkArg(m, 2, 0) + sourceAp = AccessPath::empty() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() or not m.getParameter(2).getType().getSourceDeclaration() instanceof SystemCollectionsGenericIEqualityComparerTInterface and source = getDelegateFlowSourceArg(m, 2) and - sink = TCallableFlowSinkReturn() - or - m.getParameter(2).getType().getSourceDeclaration() instanceof - SystemCollectionsGenericIEqualityComparerTInterface and - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) or arity in [4 .. 5] and ( source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 2, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() or source = getDelegateFlowSourceArg(m, 1) and - sink = getDelegateFlowSinkArg(m, 3, 0) + sourceAp = AccessPath::empty() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() or source = getDelegateFlowSourceArg(m, 2) and - sink = getDelegateFlowSinkArg(m, 3, 1) + sourceAp = AccessPath::empty() and + sink = getDelegateFlowSinkArg(m, 3, 1) and + sinkAp = AccessPath::element() or source = getDelegateFlowSourceArg(m, 3) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) ) or @@ -873,19 +1080,29 @@ class IEnumerableFlow extends LibraryTypeDataFlow { arity in [5 .. 6] and ( source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 2, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 4, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 4, 0) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceArg(1) and - sink = getDelegateFlowSinkArg(m, 3, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 3, 0) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceArg(1) and - sink = getDelegateFlowSinkArg(m, 4, 1) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 4, 1) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceDelegateArg(4) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) ) or @@ -894,285 +1111,426 @@ class IEnumerableFlow extends LibraryTypeDataFlow { arity in [2 .. 3] and ( source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or source = TCallableFlowSourceArg(1) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) ) or name.regexpMatch("Last(OrDefault)?") and ( arity in [1 .. 2] and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() or arity = 2 and - ( - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() ) or name.regexpMatch("Max|Min|Sum") and ( arity = 2 and - ( - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() ) or name = "OfType" and - ( - arity = 1 and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) - ) + arity = 1 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or name.regexpMatch("OrderBy(Descending)?") and + arity in [2 .. 3] and ( - arity in [2 .. 3] and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - or - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - ) - ) - or - name = "Repeat" and - ( - arity = 2 and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() + or + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() ) or name = "Reverse" and - ( - arity = 1 and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) - ) + arity = 1 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or name.regexpMatch("Select(Many)?") and + arity = 2 and ( - arity = 2 and - ( - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - or - source = TCallableFlowSourceDelegateArg(1) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() + or + source = TCallableFlowSourceDelegateArg(1) and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) or name = "SelectMany" and + arity = 3 and ( - arity = 3 and - ( - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - or - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 2, 0) - or - source = TCallableFlowSourceDelegateArg(1) and - sink = getDelegateFlowSinkArg(m, 2, 1) - or - source = TCallableFlowSourceDelegateArg(2) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() + or + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() + or + source = TCallableFlowSourceDelegateArg(1) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 1) and + sinkAp = AccessPath::empty() + or + source = TCallableFlowSourceDelegateArg(2) and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) or name.regexpMatch("(Skip|Take)(While)?") and - ( - arity = 2 and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) - ) + arity = 2 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or name.regexpMatch("(Skip|Take)While") and - ( - arity = 2 and - ( - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - ) - ) + arity = 2 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() or name.regexpMatch("ThenBy(Descending)?") and + arity in [2 .. 3] and ( - arity in [2 .. 3] and - ( - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - or - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() + or + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) or name.regexpMatch("To(Array|List)") and - ( - arity = 1 and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) - ) + arity = 1 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or name.regexpMatch("To(Dictionary|Lookup)") and ( arity in [2 .. 3] and ( source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() and not m.getParameter(2).getType() instanceof DelegateType ) or arity in [3 .. 4] and ( source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 2, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() or source = getDelegateFlowSourceArg(m, 2) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) ) or name = "Union" and + arity in [2 .. 3] and ( - arity in [2 .. 3] and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - or - source = TCallableFlowSourceArg(1) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() + or + source = TCallableFlowSourceArg(1) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) or name = "Where" and + arity = 2 and ( - arity = 2 and - ( - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - or - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() + or + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) or name = "Zip" and + arity = 3 and ( - arity = 3 and - ( - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 2, 0) - or - source = TCallableFlowSourceArg(1) and - sink = getDelegateFlowSinkArg(m, 2, 1) - or - source = getDelegateFlowSourceArg(m, 2) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() + or + source = TCallableFlowSourceArg(1) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 1) and + sinkAp = AccessPath::empty() + or + source = getDelegateFlowSourceArg(m, 2) and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) ) } - /** Flow for specific enumerables (e.g., `List` and `Stack`). */ - private predicate methodFlowSpecific( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationMethod m + private SourceDeclarationMethod getFind() { + exists(string name | + name = result.getName() and + result.getDeclaringType() = this.getABaseType*() + | + name.regexpMatch("Find(All|Last)?") + ) + } + + override predicate clearsContent( + CallableFlowSource source, Content content, SourceDeclarationCallable callable ) { - m = getFind() and - if m.isStatic() - then - source = TCallableFlowSourceArg(0) and - ( - sink = TCallableFlowSinkReturn() or - sink = getDelegateFlowSinkArg(m, 1, 0) - ) - else ( - source = TCallableFlowSourceQualifier() and - ( - sink = TCallableFlowSinkReturn() or - sink = getDelegateFlowSinkArg(m, 0, 0) - ) + source = TCallableFlowSourceQualifier() and + callable = this.getAMethod("Clear") and + content instanceof ElementContent + } +} + +/** Data flow for `System.Collections.[Generic.]ICollection` (and sub types). */ +class ICollectionFlow extends LibraryTypeDataFlow, RefType { + ICollectionFlow() { + exists(Interface i | i = this.getABaseType*().getSourceDeclaration() | + i instanceof SystemCollectionsICollectionInterface + or + i instanceof SystemCollectionsGenericICollectionInterface ) - or + } + + override predicate callableFlow( + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue + ) { + preservesValue = true and exists(string name, int arity | - name = m.getName() and - arity = m.getNumberOfParameters() and - m.getDeclaringType() = this.(RefType).getABaseType*() + name = c.getName() and + arity = c.getNumberOfParameters() and + c = this.getAMethod() | - name = "FixedSize" and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + name = "CopyTo" and + arity = 2 and + source instanceof CallableFlowSourceQualifier and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkArg(0) and + sinkAp = AccessPath::element() or - name - .regexpMatch("GetByIndex|Peek|Pop|AsReadOnly|Clone|GetRange|MemberwiseClone|Reverse|GetEnumerator|GetValueList") and - ( - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() - ) + name.regexpMatch("AsReadOnly|Clone") and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or - name.regexpMatch("Add(Range)?") and - ( - arity = 1 and - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkQualifier() - ) + name.regexpMatch("Peek|Pop") and + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() or - name = "Add" and - ( - arity = 2 and - source = TCallableFlowSourceArg(1) and - sink = TCallableFlowSinkQualifier() - ) + name = "InsertRange" and + arity = 2 and + source = TCallableFlowSourceArg(1) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkQualifier() and + sinkAp = AccessPath::element() + ) + } +} + +/** Data flow for `System.Collections.[Generic.]IList` (and sub types). */ +class IListFlow extends LibraryTypeDataFlow, RefType { + IListFlow() { + exists(Interface i | i = this.getABaseType*().getSourceDeclaration() | + i instanceof SystemCollectionsIListInterface or - name.regexpMatch("Insert(Range)?") and - ( - not this instanceof StringType and + i instanceof SystemCollectionsGenericIListInterface + ) + } + + override predicate callableFlow( + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue + ) { + preservesValue = true and + ( + exists(string name, int arity | + name = c.getName() and + arity = c.getNumberOfParameters() and + c = this.getAMethod() + | + name = "Insert" and arity = 2 and source = TCallableFlowSourceArg(1) and - sink = TCallableFlowSinkQualifier() + sourceAp = AccessPath::empty() and + sink instanceof CallableFlowSinkQualifier and + sinkAp = AccessPath::element() + or + name.regexpMatch("FixedSize|GetRange") and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) + or + c = this.getAnIndexer().getSetter() and + source = TCallableFlowSourceArg(1) and + sourceAp = AccessPath::empty() and + sink instanceof CallableFlowSinkQualifier and + sinkAp = AccessPath::element() + or + c = this.getAnIndexer().getGetter() and + source instanceof CallableFlowSourceQualifier and + sourceAp = AccessPath::element() and + sink instanceof CallableFlowSinkReturn and + sinkAp = AccessPath::empty() ) } +} - private SourceDeclarationMethod getFind() { - exists(string name | - name = result.getName() and - result.getDeclaringType() = this.(RefType).getABaseType*() - | - name.regexpMatch("Find(All|Last)?") +/** Data flow for `System.Collections.[Generic.]IDictionary` (and sub types). */ +class IDictionaryFlow extends LibraryTypeDataFlow, RefType { + IDictionaryFlow() { + exists(Interface i | i = this.getABaseType*().getSourceDeclaration() | + i instanceof SystemCollectionsIDictionaryInterface + or + i instanceof SystemCollectionsGenericIDictionaryInterface ) } - private predicate propertyFlow(Property p) { - this.(RefType).getABaseType*() = p.getDeclaringType() and - p.hasName("Values") + override predicate callableFlow( + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue + ) { + preservesValue = true and + exists(SystemCollectionsGenericKeyValuePairStruct kvp | + exists(int i | + c = this.getAConstructor() and + source = TCallableFlowSourceArg(i) and + sourceAp = sinkAp and + c.getParameter(i).getType().(ValueOrRefType).getABaseType*() instanceof + SystemCollectionsIEnumerableInterface and + sink instanceof CallableFlowSinkReturn + | + sinkAp = AccessPath::properties(kvp.getKeyProperty()) + or + sinkAp = AccessPath::properties(kvp.getValueProperty()) + ) + or + c = this.getProperty("Keys").getGetter() and + source instanceof CallableFlowSourceQualifier and + sourceAp = AccessPath::properties(kvp.getKeyProperty()) and + sink instanceof CallableFlowSinkReturn and + sinkAp = AccessPath::element() + or + ( + c = this.getProperty("Values").getGetter() + or + c = this.getAMethod("GetValueList") + ) and + source instanceof CallableFlowSourceQualifier and + sourceAp = AccessPath::properties(kvp.getValueProperty()) and + sink instanceof CallableFlowSinkReturn and + sinkAp = AccessPath::element() + or + ( + c = this.getAMethod("Add") and + c.getNumberOfParameters() = 2 + or + c = this.getAnIndexer().getSetter() + ) and + ( + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::empty() and + sink instanceof CallableFlowSinkQualifier and + sinkAp = AccessPath::properties(kvp.getKeyProperty()) + or + source = TCallableFlowSourceArg(1) and + sourceAp = AccessPath::empty() and + sink instanceof CallableFlowSinkQualifier and + sinkAp = AccessPath::properties(kvp.getValueProperty()) + ) + or + exists(Property p | + c = this.getAMethod("Add") and + c.getNumberOfParameters() = 1 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::property(p) and + sink instanceof CallableFlowSinkQualifier and + sinkAp = AccessPath::properties(p) and + p = kvp.getAProperty() + ) + or + ( + c = this.getAnIndexer().getGetter() + or + c = this.getAMethod("GetByIndex") + ) and + source instanceof CallableFlowSourceQualifier and + sourceAp = AccessPath::properties(kvp.getValueProperty()) and + sink instanceof CallableFlowSinkReturn and + sinkAp = AccessPath::empty() + ) } } @@ -1195,33 +1553,6 @@ class SystemConvertFlow extends LibraryTypeDataFlow, SystemConvertClass { } } -/** - * Data flow for WCF data contracts. - * - * Flow is defined from a WCF data contract object to any of its data member - * properties. This flow model only makes sense from a taint-tracking perspective - * (a tainted data contract object implies tainted data members). - */ -class DataContractFlow extends LibraryTypeDataFlow, DataContractClass { - override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue - ) { - exists(Property p | - propertyFlow(p) and - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - c = p.getGetter() - ) and - preservesValue = false - } - - private predicate propertyFlow(Property p) { - p.getDeclaringType() = this and - p.getAnAttribute() instanceof DataMemberAttribute - } -} - /** Data flow for `System.Web.HttpCookie`. */ class SystemWebHttpCookieFlow extends LibraryTypeDataFlow, SystemWebHttpCookie { override predicate callableFlow( @@ -1301,97 +1632,39 @@ class SystemWebUIWebControlsTextBoxFlow extends LibraryTypeDataFlow, private predicate propertyFlow(Property p) { p = getTextProperty() } } -/** - * Data flow for `System.Collections.Generic.KeyValuePair`. - * - * Flow is only considered for the value (not the key). - */ -class SystemCollectionsGenericKeyValuePairStructFlow extends LibraryTypeDataFlow { - SystemCollectionsGenericKeyValuePairStructFlow() { - this instanceof SystemCollectionsGenericKeyValuePairStruct - } - +/** Data flow for `System.Collections.Generic.KeyValuePair`. */ +class SystemCollectionsGenericKeyValuePairStructFlow extends LibraryTypeDataFlow, + SystemCollectionsGenericKeyValuePairStruct { override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue ) { - ( - constructorFlow(source, sink, c) + preservesValue = true and + exists(int i | + c.(Constructor).getDeclaringType() = this and + source = TCallableFlowSourceArg(i) and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() + | + i = 0 and sinkAp = AccessPath::property(this.getKeyProperty()) or - exists(Property p | - propertyFlow(p) and - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - c = p.getGetter() - ) - ) and - preservesValue = true - } - - private predicate constructorFlow(CallableFlowSource source, CallableFlowSink sink, Constructor c) { - c.getDeclaringType() = this and - source = getFlowSourceArg(c, 1) and - sink = TCallableFlowSinkReturn() - } - - private predicate propertyFlow(Property p) { - p = this.(SystemCollectionsGenericKeyValuePairStruct).getValueProperty() - } -} - -/** Data flow for `System.Collections.Generic.IEnumerator`. */ -class SystemCollectionsGenericIEnumeratorInterfaceFlow extends LibraryTypeDataFlow { - SystemCollectionsGenericIEnumeratorInterfaceFlow() { - this instanceof SystemCollectionsGenericIEnumeratorInterface - } - - override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue - ) { - exists(Property p | - propertyFlow(p) and - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - c = p.getGetter() - ) and - preservesValue = true - } - - private predicate propertyFlow(Property p) { - p = this.(SystemCollectionsGenericIEnumeratorInterface).getCurrentProperty() - } -} - -/** Data flow for `System.Collections.IEnumerator`. */ -class SystemCollectionsIEnumeratorInterfaceFlow extends LibraryTypeDataFlow, - SystemCollectionsIEnumeratorInterface { - override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue - ) { - exists(Property p | - propertyFlow(p) and - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - c = p.getGetter() - ) and - preservesValue = true + i = 1 and sinkAp = AccessPath::property(this.getValueProperty()) + ) } - - private predicate propertyFlow(Property p) { p = getCurrentProperty() } } /** Data flow for `System.Threading.Tasks.Task`. */ class SystemThreadingTasksTaskFlow extends LibraryTypeDataFlow, SystemThreadingTasksTaskClass { override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue ) { ( - constructorFlow(source, sink, c) + constructorFlow(source, sink, c) and + sourceAp = AccessPath::empty() and + sinkAp = AccessPath::empty() or - methodFlow(source, sink, c) + methodFlow(source, sourceAp, sink, sinkAp, c) ) and preservesValue = true } @@ -1410,11 +1683,13 @@ class SystemThreadingTasksTaskFlow extends LibraryTypeDataFlow, SystemThreadingT } private predicate methodFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationMethod m + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationMethod m ) { m.getDeclaringType() = this and ( m.hasName("ContinueWith") and + sourceAp = AccessPath::empty() and ( // flow from supplied state to supplied delegate exists(ConstructedDelegateType delegate, int i, int j, int k | @@ -1426,7 +1701,8 @@ class SystemThreadingTasksTaskFlow extends LibraryTypeDataFlow, SystemThreadingT ) and delegate.getTypeArgument(k) instanceof ObjectType and source = TCallableFlowSourceArg(i) and - sink = getDelegateFlowSinkArg(m, j, k) + sink = getDelegateFlowSinkArg(m, j, k) and + sinkAp = AccessPath::empty() ) or // flow out of supplied function @@ -1434,66 +1710,74 @@ class SystemThreadingTasksTaskFlow extends LibraryTypeDataFlow, SystemThreadingT m.getParameter(i).getType() = func and func.getUnboundGeneric() instanceof SystemFuncDelegateType and source = getDelegateFlowSourceArg(m, i) and - sink = TCallableFlowSinkReturn() + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::property(any(SystemThreadingTasksTaskTClass c).getResultProperty()) ) ) or m.hasName("FromResult") and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::property(any(SystemThreadingTasksTaskTClass c).getResultProperty()) or m.hasName("Run") and - ( - m.getReturnType() = any(SystemThreadingTasksTaskTClass c).getAConstructedGeneric() and - m.(UnboundGenericMethod).getNumberOfTypeParameters() = 1 and - source = TCallableFlowSourceDelegateArg(0) and - sink = TCallableFlowSinkReturn() - ) + m.getReturnType() = any(SystemThreadingTasksTaskTClass c).getAConstructedGeneric() and + m.(UnboundGenericMethod).getNumberOfTypeParameters() = 1 and + source = TCallableFlowSourceDelegateArg(0) and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::property(any(SystemThreadingTasksTaskTClass c).getResultProperty()) or m.getName().regexpMatch("WhenAll|WhenAny") and - ( - m.getReturnType() = any(SystemThreadingTasksTaskTClass c).getAConstructedGeneric() and - m.(UnboundGenericMethod).getNumberOfTypeParameters() = 1 and - source = getFlowSourceArg(m, _) and - sink = TCallableFlowSinkReturn() - ) + m.getReturnType() = any(SystemThreadingTasksTaskTClass c).getAConstructedGeneric() and + m.(UnboundGenericMethod).getNumberOfTypeParameters() = 1 and + source = getFlowSourceArg(m, _, _) and + sourceAp = AccessPath::properties(any(SystemThreadingTasksTaskTClass c).getResultProperty()) and + sink = TCallableFlowSinkReturn() and + sinkAp = + AccessPath::cons(any(PropertyContent c | + c.getProperty() = any(SystemThreadingTasksTaskTClass tc).getResultProperty() + ), AccessPath::element()) ) } } /** Data flow for `System.Threading.Tasks.Task<>`. */ -class SystemThreadingTasksTaskTFlow extends LibraryTypeDataFlow { - SystemThreadingTasksTaskTFlow() { this instanceof SystemThreadingTasksTaskTClass } - +class SystemThreadingTasksTaskTFlow extends LibraryTypeDataFlow, SystemThreadingTasksTaskTClass { override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue ) { ( - constructorFlow(source, sink, c) - or - methodFlow(source, sink, c) + constructorFlow(source, sourceAp, sink, sinkAp, c) or - exists(Property p | - propertyFlow(p) and - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - c = p.getGetter() - ) + methodFlow(source, sourceAp, sink, sinkAp, c) ) and preservesValue = true + or + exists(Property p | + p = this.(SystemThreadingTasksTaskTClass).getResultProperty() and + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + c = p.getGetter() and + preservesValue = false + ) } - private predicate constructorFlow(CallableFlowSource source, CallableFlowSink sink, Constructor c) { + private predicate constructorFlow( + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + Constructor c + ) { // flow from supplied function into constructed Task c.getDeclaringType() = this and - ( - c.getParameter(0).getType() = any(SystemFuncDelegateType t).getAConstructedGeneric() and - source = TCallableFlowSourceDelegateArg(0) and - sink = TCallableFlowSinkReturn() - ) + c.getParameter(0).getType() = any(SystemFuncDelegateType t).getAConstructedGeneric() and + source = TCallableFlowSourceDelegateArg(0) and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::property(this.(SystemThreadingTasksTaskTClass).getResultProperty()) or // flow from supplied state to supplied delegate c.getDeclaringType() = this and @@ -1503,12 +1787,15 @@ class SystemThreadingTasksTaskTFlow extends LibraryTypeDataFlow { func.getUnboundGeneric().(SystemFuncDelegateType).getNumberOfTypeParameters() = 2 and func.getTypeArgument(0) instanceof ObjectType and source = TCallableFlowSourceArg(1) and - sink = getDelegateFlowSinkArg(c, 0, 0) + sourceAp = AccessPath::empty() and + sink = getDelegateFlowSinkArg(c, 0, 0) and + sinkAp = AccessPath::empty() ) } private predicate methodFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationMethod m + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationMethod m ) { m.getDeclaringType() = this and m.hasName("ContinueWith") and @@ -1525,13 +1812,17 @@ class SystemThreadingTasksTaskTFlow extends LibraryTypeDataFlow { delegate.getTypeArgument(j) instanceof ObjectType and m.getParameter(k).getType() instanceof ObjectType and source = TCallableFlowSourceArg(k) and - sink = getDelegateFlowSinkArg(m, i, j) + sourceAp = AccessPath::empty() and + sink = getDelegateFlowSinkArg(m, i, j) and + sinkAp = AccessPath::empty() ) or // flow from this task to supplied delegate delegate.getTypeArgument(j) = this and source = TCallableFlowSourceQualifier() and - sink = getDelegateFlowSinkArg(m, i, j) + sourceAp = AccessPath::empty() and + sink = getDelegateFlowSinkArg(m, i, j) and + sinkAp = AccessPath::empty() ) or // flow out of supplied function @@ -1539,13 +1830,19 @@ class SystemThreadingTasksTaskTFlow extends LibraryTypeDataFlow { m.getParameter(i).getType() = func and func.getUnboundGeneric() instanceof SystemFuncDelegateType and source = getDelegateFlowSourceArg(m, i) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::property(this.(SystemThreadingTasksTaskTClass).getResultProperty()) ) ) - } - - private predicate propertyFlow(Property p) { - p = this.(SystemThreadingTasksTaskTClass).getResultProperty() + or + m = this.getGetAwaiterMethod() and + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = + AccessPath::field(any(SystemRuntimeCompilerServicesTaskAwaiterStruct s) + .getUnderlyingTaskField()) } } @@ -1557,15 +1854,16 @@ class SystemThreadingTasksFactoryFlow extends LibraryTypeDataFlow { } override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue ) { - methodFlow(source, sink, c) and + methodFlow(source, sourceAp, sink, sinkAp, c) and preservesValue = true } private predicate methodFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationMethod m + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationMethod m ) { m.getDeclaringType() = this and ( @@ -1582,7 +1880,9 @@ class SystemThreadingTasksFactoryFlow extends LibraryTypeDataFlow { delegate.getUnboundGeneric() instanceof SystemFuncDelegateType ) and source = TCallableFlowSourceArg(i) and - sink = getDelegateFlowSinkArg(m, j, k) + sourceAp = AccessPath::empty() and + sink = getDelegateFlowSinkArg(m, j, k) and + sinkAp = AccessPath::empty() ) or // flow out of supplied function @@ -1590,7 +1890,9 @@ class SystemThreadingTasksFactoryFlow extends LibraryTypeDataFlow { m.getParameter(i).getType() = func and func.getUnboundGeneric() instanceof SystemFuncDelegateType and source = getDelegateFlowSourceArg(m, i) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::property(any(SystemThreadingTasksTaskTClass c).getResultProperty()) ) ) or @@ -1606,7 +1908,9 @@ class SystemThreadingTasksFactoryFlow extends LibraryTypeDataFlow { ) and delegate.getTypeArgument(k) instanceof ObjectType and source = TCallableFlowSourceArg(i) and - sink = getDelegateFlowSinkArg(m, j, k) + sourceAp = AccessPath::empty() and + sink = getDelegateFlowSinkArg(m, j, k) and + sinkAp = AccessPath::empty() ) or // flow out of supplied function @@ -1614,23 +1918,58 @@ class SystemThreadingTasksFactoryFlow extends LibraryTypeDataFlow { m.getParameter(i).getType() = func and func.getUnboundGeneric() instanceof SystemFuncDelegateType and source = getDelegateFlowSourceArg(m, i) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::property(any(SystemThreadingTasksTaskTClass c).getResultProperty()) ) ) ) } } +/** Data flow for `System.Runtime.CompilerServices.TaskAwaiter<>`. */ +class SystemRuntimeCompilerServicesTaskAwaiterFlow extends LibraryTypeDataFlow, + SystemRuntimeCompilerServicesTaskAwaiterStruct { + override predicate callableFlow( + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue + ) { + preservesValue = true and + c = this.getGetResultMethod() and + source = TCallableFlowSourceQualifier() and + sourceAp = + AccessPath::cons(any(FieldContent fc | fc.getField() = this.getUnderlyingTaskField()), + AccessPath::property(any(SystemThreadingTasksTaskTClass t).getResultProperty())) and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() + } + + override predicate requiresAccessPath(Content head, AccessPath tail) { + head.(FieldContent).getField() = this.getUnderlyingTaskField() and + tail = AccessPath::property(any(SystemThreadingTasksTaskTClass t).getResultProperty()) + } +} + /** Data flow for `System.Text.Encoding`. */ library class SystemTextEncodingFlow extends LibraryTypeDataFlow, SystemTextEncodingClass { override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue ) { - (c = getGetBytesMethod() or c = getGetStringMethod() or c = getGetCharsMethod()) and - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() and - preservesValue = false + preservesValue = false and + c = this.getAMethod() and + exists(Method m | m.getAnOverrider*().getSourceDeclaration() = c | + m = getGetBytesMethod() and + source = getFlowSourceArg(m, 0, sourceAp) and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() + or + m = [getGetStringMethod(), getGetCharsMethod()] and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() + ) } } @@ -1766,12 +2105,13 @@ class SystemXmlXmlNamedNodeMapFlow extends LibraryTypeDataFlow, SystemXmlXmlName /** Data flow for `System.IO.Path`. */ class SystemIOPathFlow extends LibraryTypeDataFlow, SystemIOPathClass { override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue ) { c = getAMethod("Combine") and - source = getFlowSourceArg(c, _) and + source = getFlowSourceArg(c, _, sourceAp) and sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and preservesValue = false or exists(Parameter p | @@ -1779,8 +2119,9 @@ class SystemIOPathFlow extends LibraryTypeDataFlow, SystemIOPathClass { c.getName().matches("Get%") and p = c.getAParameter() and p.hasName("path") and - source = getFlowSourceArg(c, p.getPosition()) and + source = getFlowSourceArg(c, p.getPosition(), sourceAp) and sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and preservesValue = false ) } @@ -1837,26 +2178,21 @@ class SystemNetWebUtilityFlow extends LibraryTypeDataFlow, SystemNetWebUtility { } /** - * The `StringValues` class used in many .NET Core libraries. Requires special `LibraryTypeDataFlow` flow. + * Custom flow through `StringValues` library class. */ -class StringValues extends Struct { - StringValues() { this.hasQualifiedName("Microsoft.Extensions.Primitives", "StringValues") } -} +class StringValuesFlow extends LibraryTypeDataFlow, Struct { + StringValuesFlow() { this.hasQualifiedName("Microsoft.Extensions.Primitives", "StringValues") } -/** - * Custom flow through StringValues.StringValues library class - */ -class StringValuesFlow extends LibraryTypeDataFlow, StringValues { override predicate callableFlow( CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, boolean preservesValue ) { - c = any(Callable ca | this = ca.getDeclaringType()) and + c.getDeclaringType() = this and ( - source = any(CallableFlowSourceArg a) or - source = any(CallableFlowSourceQualifier q) + source instanceof CallableFlowSourceArg or + source instanceof CallableFlowSourceQualifier ) and - sink = any(CallableFlowSinkReturn r) and + sink instanceof CallableFlowSinkReturn and preservesValue = false } } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/ModulusAnalysis.qll b/csharp/ql/src/semmle/code/csharp/dataflow/ModulusAnalysis.qll new file mode 100644 index 000000000000..2b3c3402415d --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/dataflow/ModulusAnalysis.qll @@ -0,0 +1,302 @@ +/** + * Provides inferences of the form: `e` equals `b + v` modulo `m` where `e` is + * an expression, `b` is a `Bound` (typically zero or the value of an SSA + * variable), and `v` is an integer in the range `[0 .. m-1]`. + */ + +private import internal.rangeanalysis.ModulusAnalysisSpecific::Private +private import Bound +private import internal.rangeanalysis.SsaReadPositionCommon + +/** + * Holds if `e + delta` equals `v` at `pos`. + */ +private predicate valueFlowStepSsa(SsaVariable v, SsaReadPosition pos, Expr e, int delta) { + ssaUpdateStep(v, e, delta) and pos.hasReadOfVar(v) + or + exists(Guard guard, boolean testIsTrue | + pos.hasReadOfVar(v) and + guard = eqFlowCond(v, e, delta, true, testIsTrue) and + guardDirectlyControlsSsaRead(guard, pos, testIsTrue) + ) +} + +/** + * Holds if `add` is the addition of `larg` and `rarg`, neither of which are + * `ConstantIntegerExpr`s. + */ +private predicate nonConstAddition(Expr add, Expr larg, Expr rarg) { + exists(AddExpr a | a = add | + larg = a.getLhs() and + rarg = a.getRhs() + ) and + not larg instanceof ConstantIntegerExpr and + not rarg instanceof ConstantIntegerExpr +} + +/** + * Holds if `sub` is the subtraction of `larg` and `rarg`, where `rarg` is not + * a `ConstantIntegerExpr`. + */ +private predicate nonConstSubtraction(Expr sub, Expr larg, Expr rarg) { + exists(SubExpr s | s = sub | + larg = s.getLhs() and + rarg = s.getRhs() + ) and + not rarg instanceof ConstantIntegerExpr +} + +/** Gets an expression that is the remainder modulo `mod` of `arg`. */ +private Expr modExpr(Expr arg, int mod) { + exists(RemExpr rem | + result = rem and + arg = rem.getLeftOperand() and + rem.getRightOperand().(ConstantIntegerExpr).getIntValue() = mod and + mod >= 2 + ) + or + exists(ConstantIntegerExpr c | + mod = 2.pow([1 .. 30]) and + c.getIntValue() = mod - 1 and + result.(BitwiseAndExpr).hasOperands(arg, c) + ) +} + +/** + * Gets a guard that tests whether `v` is congruent with `val` modulo `mod` on + * its `testIsTrue` branch. + */ +private Guard moduloCheck(SsaVariable v, int val, int mod, boolean testIsTrue) { + exists(Expr rem, ConstantIntegerExpr c, int r, boolean polarity | + result.isEquality(rem, c, polarity) and + c.getIntValue() = r and + rem = modExpr(v.getAUse(), mod) and + ( + testIsTrue = polarity and val = r + or + testIsTrue = polarity.booleanNot() and + mod = 2 and + val = 1 - r and + (r = 0 or r = 1) + ) + ) +} + +/** + * Holds if a guard ensures that `v` at `pos` is congruent with `val` modulo `mod`. + */ +private predicate moduloGuardedRead(SsaVariable v, SsaReadPosition pos, int val, int mod) { + exists(Guard guard, boolean testIsTrue | + pos.hasReadOfVar(v) and + guard = moduloCheck(v, val, mod, testIsTrue) and + guardControlsSsaRead(guard, pos, testIsTrue) + ) +} + +/** Holds if `factor` is a power of 2 that divides `mask`. */ +bindingset[mask] +private predicate andmaskFactor(int mask, int factor) { + mask % factor = 0 and + factor = 2.pow([1 .. 30]) +} + +/** Holds if `e` is evenly divisible by `factor`. */ +private predicate evenlyDivisibleExpr(Expr e, int factor) { + exists(ConstantIntegerExpr c, int k | k = c.getIntValue() | + e.(MulExpr).getAnOperand() = c and factor = k.abs() and factor >= 2 + or + e.(LShiftExpr).getRhs() = c and factor = 2.pow(k) and k > 0 + or + e.(BitwiseAndExpr).getAnOperand() = c and factor = max(int f | andmaskFactor(k, f)) + ) +} + +/** + * Holds if `inp` is an input to `phi` along `edge` and this input has index `r` + * in an arbitrary 1-based numbering of the input edges to `phi`. + */ +private predicate rankedPhiInput( + SsaPhiNode phi, SsaVariable inp, SsaReadPositionPhiInputEdge edge, int r +) { + edge.phiInput(phi, inp) and + edge = + rank[r](SsaReadPositionPhiInputEdge e | e.phiInput(phi, _) | e order by getId(e.getOrigBlock())) +} + +/** + * Holds if `rix` is the number of input edges to `phi`. + */ +private predicate maxPhiInputRank(SsaPhiNode phi, int rix) { + rix = max(int r | rankedPhiInput(phi, _, _, r)) +} + +/** + * Gets the remainder of `val` modulo `mod`. + * + * For `mod = 0` the result equals `val` and for `mod > 1` the result is within + * the range `[0 .. mod-1]`. + */ +bindingset[val, mod] +private int remainder(int val, int mod) { + mod = 0 and result = val + or + mod > 1 and result = ((val % mod) + mod) % mod +} + +/** + * Holds if `inp` is an input to `phi` and equals `phi` modulo `mod` along `edge`. + */ +private predicate phiSelfModulus( + SsaPhiNode phi, SsaVariable inp, SsaReadPositionPhiInputEdge edge, int mod +) { + exists(SsaBound phibound, int v, int m | + edge.phiInput(phi, inp) and + phibound.getSsa() = phi and + ssaModulus(inp, edge, phibound, v, m) and + mod = m.gcd(v) and + mod != 1 + ) +} + +/** + * Holds if `b + val` modulo `mod` is a candidate congruence class for `phi`. + */ +private predicate phiModulusInit(SsaPhiNode phi, Bound b, int val, int mod) { + exists(SsaVariable inp, SsaReadPositionPhiInputEdge edge | + edge.phiInput(phi, inp) and + ssaModulus(inp, edge, b, val, mod) + ) +} + +/** + * Holds if all inputs to `phi` numbered `1` to `rix` are equal to `b + val` modulo `mod`. + */ +private predicate phiModulusRankStep(SsaPhiNode phi, Bound b, int val, int mod, int rix) { + rix = 0 and + phiModulusInit(phi, b, val, mod) + or + exists(SsaVariable inp, SsaReadPositionPhiInputEdge edge, int v1, int m1 | + mod != 1 and + val = remainder(v1, mod) + | + exists(int v2, int m2 | + rankedPhiInput(phi, inp, edge, rix) and + phiModulusRankStep(phi, b, v1, m1, rix - 1) and + ssaModulus(inp, edge, b, v2, m2) and + mod = m1.gcd(m2).gcd(v1 - v2) + ) + or + exists(int m2 | + rankedPhiInput(phi, inp, edge, rix) and + phiModulusRankStep(phi, b, v1, m1, rix - 1) and + phiSelfModulus(phi, inp, edge, m2) and + mod = m1.gcd(m2) + ) + ) +} + +/** + * Holds if `phi` is equal to `b + val` modulo `mod`. + */ +private predicate phiModulus(SsaPhiNode phi, Bound b, int val, int mod) { + exists(int r | + maxPhiInputRank(phi, r) and + phiModulusRankStep(phi, b, val, mod, r) + ) +} + +/** + * Holds if `v` at `pos` is equal to `b + val` modulo `mod`. + */ +private predicate ssaModulus(SsaVariable v, SsaReadPosition pos, Bound b, int val, int mod) { + phiModulus(v, b, val, mod) and pos.hasReadOfVar(v) + or + b.(SsaBound).getSsa() = v and pos.hasReadOfVar(v) and val = 0 and mod = 0 + or + exists(Expr e, int val0, int delta | + exprModulus(e, b, val0, mod) and + valueFlowStepSsa(v, pos, e, delta) and + val = remainder(val0 + delta, mod) + ) + or + moduloGuardedRead(v, pos, val, mod) and b instanceof ZeroBound +} + +/** + * Holds if `e` is equal to `b + val` modulo `mod`. + * + * There are two cases for the modulus: + * - `mod = 0`: The equality `e = b + val` is an ordinary equality. + * - `mod > 1`: `val` lies within the range `[0 .. mod-1]`. + */ +cached +predicate exprModulus(Expr e, Bound b, int val, int mod) { + e = b.getExpr(val) and mod = 0 + or + evenlyDivisibleExpr(e, mod) and val = 0 and b instanceof ZeroBound + or + exists(SsaVariable v, SsaReadPositionBlock bb | + ssaModulus(v, bb, b, val, mod) and + e = v.getAUse() and + getABasicBlockExpr(bb.getBlock()) = e + ) + or + exists(Expr mid, int val0, int delta | + exprModulus(mid, b, val0, mod) and + valueFlowStep(e, mid, delta) and + val = remainder(val0 + delta, mod) + ) + or + exists(ConditionalExpr cond, int v1, int v2, int m1, int m2 | + cond = e and + condExprBranchModulus(cond, true, b, v1, m1) and + condExprBranchModulus(cond, false, b, v2, m2) and + mod = m1.gcd(m2).gcd(v1 - v2) and + mod != 1 and + val = remainder(v1, mod) + ) + or + exists(Bound b1, Bound b2, int v1, int v2, int m1, int m2 | + addModulus(e, true, b1, v1, m1) and + addModulus(e, false, b2, v2, m2) and + mod = m1.gcd(m2) and + mod != 1 and + val = remainder(v1 + v2, mod) + | + b = b1 and b2 instanceof ZeroBound + or + b = b2 and b1 instanceof ZeroBound + ) + or + exists(int v1, int v2, int m1, int m2 | + subModulus(e, true, b, v1, m1) and + subModulus(e, false, any(ZeroBound zb), v2, m2) and + mod = m1.gcd(m2) and + mod != 1 and + val = remainder(v1 - v2, mod) + ) +} + +private predicate condExprBranchModulus( + ConditionalExpr cond, boolean branch, Bound b, int val, int mod +) { + exprModulus(cond.getTrueExpr(), b, val, mod) and branch = true + or + exprModulus(cond.getFalseExpr(), b, val, mod) and branch = false +} + +private predicate addModulus(Expr add, boolean isLeft, Bound b, int val, int mod) { + exists(Expr larg, Expr rarg | nonConstAddition(add, larg, rarg) | + exprModulus(larg, b, val, mod) and isLeft = true + or + exprModulus(rarg, b, val, mod) and isLeft = false + ) +} + +private predicate subModulus(Expr sub, boolean isLeft, Bound b, int val, int mod) { + exists(Expr larg, Expr rarg | nonConstSubtraction(sub, larg, rarg) | + exprModulus(larg, b, val, mod) and isLeft = true + or + exprModulus(rarg, b, val, mod) and isLeft = false + ) +} diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll b/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll index 1750a297299b..f76b3414a867 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll @@ -5,7 +5,7 @@ * a `null` pointer exception (`NullReferenceException`) may be thrown. * Example: * - * ``` + * ```csharp * void M(string s) { * if (s != null) { * ... @@ -21,10 +21,8 @@ import csharp private import ControlFlow private import internal.CallableReturns private import semmle.code.csharp.commons.Assertions -private import semmle.code.csharp.commons.ComparisonTest private import semmle.code.csharp.controlflow.Guards as G private import semmle.code.csharp.controlflow.Guards::AbstractValues -private import semmle.code.csharp.dataflow.SSA private import semmle.code.csharp.frameworks.System private import semmle.code.csharp.frameworks.Test @@ -138,30 +136,6 @@ private predicate exprImpliesSsaDef( ) } -/** - * Holds if the `i`th node of basic block `bb` ensures that SSA definition - * `def` is not `null` in any subsequent uses. - */ -private predicate ensureNotNullAt(BasicBlock bb, int i, Ssa::Definition def) { - exists(Expr e, G::AbstractValue v, NullValue nv | - G::Internal::asserts(bb.getNode(i).getElement(), e, v) - | - exprImpliesSsaDef(e, v, def, nv) and - nv.isNonNull() - ) -} - -/** - * Holds if the `i`th node of basic block `bb` is a dereference `d` of SSA - * definition `def`, and `def` may potentially be `null`. - */ -private predicate potentialNullDereferenceAt( - BasicBlock bb, int i, Ssa::Definition def, Dereference d -) { - dereferenceAt(bb, i, def, d) and - not exists(int j | ensureNotNullAt(bb, j, def) | j < i) -} - /** * Gets an element that tests whether a given SSA definition, `def`, is * `null` or not. @@ -197,42 +171,44 @@ private predicate isNullDefaultArgument(Ssa::ExplicitDefinition def, AlwaysNullE /** Holds if `def` is an SSA definition that may be `null`. */ private predicate defMaybeNull(Ssa::Definition def, string msg, Element reason) { - // A variable compared to `null` might be `null` - exists(G::DereferenceableExpr de | de = def.getARead() | - reason = de.getANullCheck(_, true) and - msg = "as suggested by $@ null check" and - not de = any(Ssa::PseudoDefinition pdef).getARead() and - strictcount(Element e | e = any(Ssa::Definition def0 | de = def0.getARead()).getElement()) = 1 and - not nonNullDef(def) and - // Don't use a check as reason if there is a `null` assignment - // or argument - not def.(Ssa::ExplicitDefinition).getADefinition().getSource() instanceof MaybeNullExpr and - not isMaybeNullArgument(def, _) - ) - or - // A parameter might be `null` if there is a `null` argument somewhere - isMaybeNullArgument(def, reason) and + not nonNullDef(def) and ( - if reason instanceof AlwaysNullExpr - then msg = "because of $@ null argument" - else msg = "because of $@ potential null argument" - ) - or - isNullDefaultArgument(def, reason) and msg = "because the parameter has a null default value" - or - // If the source of a variable is `null` then the variable may be `null` - exists(AssignableDefinition adef | adef = def.(Ssa::ExplicitDefinition).getADefinition() | - adef.getSource() instanceof MaybeNullExpr and - reason = adef.getExpr() and - msg = "because of $@ assignment" - ) - or - // A variable of nullable type may be null - exists(Dereference d | dereferenceAt(_, _, def, d) | - d.hasNullableType() and - not def instanceof Ssa::PseudoDefinition and - reason = def.getSourceVariable().getAssignable() and - msg = "because it has a nullable type" + // A variable compared to `null` might be `null` + exists(G::DereferenceableExpr de | de = def.getARead() | + reason = de.getANullCheck(_, true) and + msg = "as suggested by $@ null check" and + not de = any(Ssa::PseudoDefinition pdef).getARead() and + strictcount(Element e | e = any(Ssa::Definition def0 | de = def0.getARead()).getElement()) = 1 and + // Don't use a check as reason if there is a `null` assignment + // or argument + not def.(Ssa::ExplicitDefinition).getADefinition().getSource() instanceof MaybeNullExpr and + not isMaybeNullArgument(def, _) + ) + or + // A parameter might be `null` if there is a `null` argument somewhere + isMaybeNullArgument(def, reason) and + ( + if reason instanceof AlwaysNullExpr + then msg = "because of $@ null argument" + else msg = "because of $@ potential null argument" + ) + or + isNullDefaultArgument(def, reason) and msg = "because the parameter has a null default value" + or + // If the source of a variable is `null` then the variable may be `null` + exists(AssignableDefinition adef | adef = def.(Ssa::ExplicitDefinition).getADefinition() | + adef.getSource() instanceof MaybeNullExpr and + reason = adef.getExpr() and + msg = "because of $@ assignment" + ) + or + // A variable of nullable type may be null + exists(Dereference d | dereferenceAt(_, _, def, d) | + d.hasNullableType() and + not def instanceof Ssa::PseudoDefinition and + reason = def.getSourceVariable().getAssignable() and + msg = "because it has a nullable type" + ) ) } @@ -269,7 +245,6 @@ private predicate defNullImpliesStep( bb2 = def.getBasicBlock() ) ) and - not ensureNotNullAt(bb1, _, def1) and not exists(SuccessorTypes::ConditionalSuccessor s, NullValue nv | bb1.getLastNode() = getANullCheck(def1, s, nv).getAControlFlowNode() | @@ -296,7 +271,7 @@ private predicate defMaybeNullInBlock(Ssa::Definition def, BasicBlock bb) { * dereference. */ private predicate nullDerefCandidateVariable(Ssa::SourceVariable v) { - exists(Ssa::Definition def, BasicBlock bb | potentialNullDereferenceAt(bb, _, def, _) | + exists(Ssa::Definition def, BasicBlock bb | dereferenceAt(bb, _, def, _) | defMaybeNullInBlock(def, bb) and v = def.getSourceVariable() ) @@ -328,7 +303,7 @@ private newtype TPathNode = succNullArgument(_, def, bb) } or TSinkPathNode(Ssa::Definition def, BasicBlock bb, int i, Dereference d) { - potentialNullDereferenceAt(bb, i, def, d) and + dereferenceAt(bb, i, def, d) and ( succStep(_, def, bb) or diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll b/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll index 7a6b58961477..928682a761ef 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll @@ -171,7 +171,7 @@ module Ssa { * callable. A pseudo read is inserted to make assignments to `out`/`ref` variables * live, for example line 1 in * - * ``` + * ```csharp * void M(out int i) { * i = 0; * } @@ -189,7 +189,7 @@ module Ssa { * A pseudo read is inserted to make assignments to the `ref` variable live, for example * line 2 in * - * ``` + * ```csharp * void M() { * ref int i = ref GetRef(); * i = 0; @@ -612,7 +612,7 @@ module Ssa { * For example, if `bb` is a basic block with a phi node for `v` (considered * to be at index -1), reads `v` at node 2, and defines it at node 5, we have: * - * ``` + * ```ql * ssaRefRank(bb, -1, v, SsaDef()) = 1 // phi node * ssaRefRank(bb, 2, v, Read()) = 2 // read at node 2 * ssaRefRank(bb, 5, v, SsaDef()) = 3 // definition at node 5 @@ -706,9 +706,9 @@ module Ssa { /** * Holds if `def` is accessed in basic block `bb1` (either a read or a write), - * `bb2` is a transitive successor of `bb1`, and `def` is *maybe* read in `bb2` - * or one of its transitive successors, but not in any block on the path between - * `bb1` and `bb2`. + * `bb2` is a transitive successor of `bb1`, `def` is live at the end of `bb1`, + * and the underlying variable for `def` is neither read nor written in any block + * on the path between `bb1` and `bb2`. */ private predicate varBlockReaches(TrackedDefinition def, BasicBlock bb1, BasicBlock bb2) { varOccursInBlock(def, bb1, _) and @@ -893,7 +893,7 @@ module Ssa { * of the field or property. For example, there is an implicit update of * `this.Field` on line 7 in * - * ``` + * ```csharp * int Field; * * void SetField(int i) { Field = i; } @@ -1018,7 +1018,7 @@ module Ssa { private predicate intraInstanceCallEdge(Callable c1, InstanceCallable c2) { exists(Call c | c.getEnclosingCallable() = c1 and - c2 = getARuntimeTarget(c) and + c2 = getARuntimeTarget(c, _) and c.(QualifiableExpr).targetIsLocalInstance() ) } @@ -1034,15 +1034,28 @@ module Ssa { * the SSA library and `Call.getARuntimeTarget()` mutually recursive), and * * (3) indirect calls to delegates via calls to library callables are included. + * + * The Boolean `libraryDelegateCall` indicates whether `c` is a call to a library + * method and the result is a delegate passed to `c`. For example, in + * + * ```csharp + * Lazy M1() + * { + * return new Lazy(M2); + * } + * ``` + * + * the constructor call `new Lazy(M2)` includes `M2` as a target. */ - Callable getARuntimeTarget(Call c) { + Callable getARuntimeTarget(Call c, boolean libraryDelegateCall) { // Non-delegate call: use dispatch library exists(DispatchCall dc | dc.getCall() = c | - result = dc.getADynamicTarget().getSourceDeclaration() + result = dc.getADynamicTarget().getSourceDeclaration() and + libraryDelegateCall = false ) or // Delegate call: use simple analysis - result = SimpleDelegateAnalysis::getARuntimeDelegateTarget(c) + result = SimpleDelegateAnalysis::getARuntimeDelegateTarget(c, libraryDelegateCall) } private module SimpleDelegateAnalysis { @@ -1055,12 +1068,14 @@ module Ssa { * Either `c` is a delegate call and `e` is the qualifier, or `c` is a call to * a library callable and `e` is a delegate argument. */ - private predicate delegateCall(Call c, Expr e) { - c = any(DelegateCall dc | e = dc.getDelegateExpr()) + private predicate delegateCall(Call c, Expr e, boolean libraryDelegateCall) { + c = any(DelegateCall dc | e = dc.getDelegateExpr()) and + libraryDelegateCall = false or c.getTarget().fromLibrary() and e = c.getAnArgument() and - e.getType() instanceof SystemLinqExpressions::DelegateExtType + e.getType() instanceof SystemLinqExpressions::DelegateExtType and + libraryDelegateCall = true } /** Holds if expression `e` is a delegate creation for callable `c` of type `t`. */ @@ -1090,7 +1105,7 @@ module Ssa { callable = call.getTarget() or callable = call.getTarget().(Method).getAnOverrider+() or callable = call.getTarget().(Method).getAnUltimateImplementor() or - callable = getARuntimeDelegateTarget(call) + callable = getARuntimeDelegateTarget(call, false) ) or pred = succ.(DelegateCreation).getArgument() @@ -1110,7 +1125,7 @@ module Ssa { } private predicate reachesDelegateCall(Expr e) { - delegateCall(_, e) + delegateCall(_, e, _) or exists(Expr mid | reachesDelegateCall(mid) | delegateFlowStep(e, mid)) } @@ -1128,12 +1143,14 @@ module Ssa { } /** Gets a run-time target for the delegate call `c`. */ - Callable getARuntimeDelegateTarget(Call c) { delegateCall(c, delegateCallSource(result)) } + Callable getARuntimeDelegateTarget(Call c, boolean libraryDelegateCall) { + delegateCall(c, delegateCallSource(result), libraryDelegateCall) + } } /** Holds if `(c1,c2)` is an edge in the call graph. */ predicate callEdge(Callable c1, Callable c2) { - exists(Call c | c.getEnclosingCallable() = c1 | getARuntimeTarget(c) = c2) + exists(Call c | c.getEnclosingCallable() = c1 and c2 = getARuntimeTarget(c, _)) } /** @@ -1179,7 +1196,7 @@ module Ssa { pragma[noinline] predicate callAt(BasicBlock bb, int i, Call call) { bb.getNode(i) = call.getAControlFlowNode() and - getARuntimeTarget(call).hasBody() + getARuntimeTarget(call, _).hasBody() } /** @@ -1201,7 +1218,7 @@ module Ssa { private predicate pruneFromLeft(Callable c) { exists(Call call, TrackedFieldOrProp f | updateCandidate(_, _, f, call) and - c = getARuntimeTarget(call) and + c = getARuntimeTarget(call, _) and generalSetter(_, f.getAssignable(), _) ) or @@ -1238,7 +1255,7 @@ module Ssa { updateCandidate(_, _, tfp, call) and fp = tfp.getAssignable() and generalSetter(_, fp, _) and - c1 = getARuntimeTarget(call) + c1 = getARuntimeTarget(call, _) } pragma[noinline] @@ -1279,7 +1296,7 @@ module Ssa { Call call, TrackedFieldOrProp tfp, Callable setter ) { updateCandidate(_, _, tfp, call) and - setsOwnFieldOrPropTransitive(getARuntimeTarget(call), tfp.getAssignable(), setter) + setsOwnFieldOrPropTransitive(getARuntimeTarget(call, _), tfp.getAssignable(), setter) } private predicate updatesNamedFieldOrPropPossiblyLive( @@ -1359,7 +1376,7 @@ module Ssa { * site that conceivably could reach an update of the captured variable. * For example, there is an implicit update of `v` on line 4 in * - * ``` + * ```csharp * int M() { * int i = 0; * Action a = () => { i = 1; }; @@ -1430,7 +1447,14 @@ module Ssa { ) { possiblyLiveAtAllNodes(bb, v) and callAt(bb, i, call) and - relevantDefinition(_, v.getAssignable(), _) + exists(Assignable a | + a = v.getAssignable() and + relevantDefinition(_, a, _) and + not exists(AssignableDefinitions::OutRefDefinition def | + def.getCall() = call and + def.getTarget() = a + ) + ) } /** @@ -1440,7 +1464,7 @@ module Ssa { private predicate pruneFromLeft(Callable c) { exists(Call call, CapturedWrittenLocalScopeSourceVariable v | updateCandidate(_, _, v, call) and - c = getARuntimeTarget(call) and + c = getARuntimeTarget(call, _) and relevantDefinition(_, v.getAssignable(), _) ) or @@ -1478,12 +1502,12 @@ module Ssa { pragma[noinline] private predicate updatesCapturedVariablePrefix( Call call, CapturedWrittenLocalScopeSourceVariable v, PrunedCallable c, - CapturedWrittenLocalScopeVariable captured + CapturedWrittenLocalScopeVariable captured, boolean libraryDelegateCall ) { updateCandidate(_, _, v, call) and captured = v.getAssignable() and relevantDefinitionProj(_, captured) and - c = getARuntimeTarget(call) + c = getARuntimeTarget(call, libraryDelegateCall) } /** @@ -1498,11 +1522,13 @@ module Ssa { Call call, CapturedWrittenLocalScopeSourceVariable v, PrunedCallable writer, boolean additionalCalls ) { - exists(PrunedCallable c, CapturedWrittenLocalScopeVariable captured | - updatesCapturedVariablePrefix(call, v, c, captured) and + exists( + PrunedCallable c, CapturedWrittenLocalScopeVariable captured, boolean libraryDelegateCall + | + updatesCapturedVariablePrefix(call, v, c, captured, libraryDelegateCall) and relevantDefinitionProj(writer, captured) and ( - c = writer and additionalCalls = false + c = writer and additionalCalls = libraryDelegateCall or callEdgePrunedPlus(c, writer) and additionalCalls = true ) @@ -1559,7 +1585,7 @@ module Ssa { * * Example: * - * ``` + * ```csharp * void M() { * int i = 0; * void M2() { @@ -1660,7 +1686,7 @@ module Ssa { private predicate pruneFromLeft(Callable c) { exists(Call call, CapturedReadLocalScopeSourceVariable v | implicitReadCandidate(_, _, call.getAControlFlowNode(), v) and - c = getARuntimeTarget(call) + c = getARuntimeTarget(call, _) ) or exists(Callable mid | pruneFromLeft(mid) | callEdge(mid, c)) @@ -1695,12 +1721,12 @@ module Ssa { pragma[noinline] private predicate readsCapturedVariablePrefix( ControlFlow::Node call, CapturedReadLocalScopeSourceVariable v, PrunedCallable c, - CapturedReadLocalScopeVariable captured + CapturedReadLocalScopeVariable captured, boolean libraryDelegateCall ) { implicitReadCandidate(_, _, call, v) and captured = v.getAssignable() and capturerReads(_, captured) and - c = getARuntimeTarget(call.getElement()) + c = getARuntimeTarget(call.getElement(), libraryDelegateCall) } /** @@ -1715,11 +1741,13 @@ module Ssa { ControlFlow::Nodes::ElementNode call, CapturedReadLocalScopeSourceVariable v, Callable reader, boolean additionalCalls ) { - exists(PrunedCallable c, CapturedReadLocalScopeVariable captured | - readsCapturedVariablePrefix(call, v, c, captured) and + exists( + PrunedCallable c, CapturedReadLocalScopeVariable captured, boolean libraryDelegateCall + | + readsCapturedVariablePrefix(call, v, c, captured, libraryDelegateCall) and capturerReads(reader, captured) and ( - c = reader and additionalCalls = false + c = reader and additionalCalls = libraryDelegateCall or callEdgePrunedPlus(c, reader) and additionalCalls = true ) @@ -1736,7 +1764,7 @@ module Ssa { * * Example: * - * ``` + * ```csharp * class C { * void M1() { * int i = 0; @@ -1758,7 +1786,6 @@ module Ssa { def.getSourceVariable().getAssignable() = lsv | lsv = v.getAssignable() and - adef = def.getAPossibleDefinition() and bb.getNode(i) = adef.getAControlFlowNode() and updatesCapturedVariable(def.getCall(), _, adef, additionalCalls) ) @@ -1775,7 +1802,7 @@ module Ssa { * * Example: * - * ``` + * ```csharp * class C { * void M1() { * int i = 0; @@ -1845,7 +1872,7 @@ module Ssa { ( exists(ReadKind rk | liveAfterWrite(bb, i, v, rk) | // A `ref` assignment such as - // ``` + // ```csharp // ref int i = ref GetRef(); // ``` // is dead when there are no reads of or writes to `i`. @@ -2005,7 +2032,7 @@ module Ssa { * can be reached from this SSA definition without passing through any * other SSA definitions. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -2034,7 +2061,7 @@ module Ssa { * control flow node `cfn` that can be reached from this SSA definition * without passing through any other SSA definitions. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -2066,7 +2093,7 @@ module Ssa { * can be reached from this SSA definition without passing through any * other SSA definition or read. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -2102,7 +2129,7 @@ module Ssa { * control flow node `cfn` that can be reached from this SSA definition * without passing through any other SSA definition or read. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -2142,7 +2169,7 @@ module Ssa { * another SSA definition for the source variable, without passing through * any other read. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -2172,7 +2199,7 @@ module Ssa { * enclosing callable, or another SSA definition for the source variable, * without passing through any other read. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -2203,7 +2230,7 @@ module Ssa { * Gets a definition that ultimately defines this SSA definition and is * not itself a pseudo node. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -2322,7 +2349,7 @@ module Ssa { * * Example: * - * ``` + * ```csharp * class C { * void M1() { * int i = 0; @@ -2349,7 +2376,7 @@ module Ssa { * * Example: * - * ``` + * ```csharp * class C { * void M1() { * int i = 0; @@ -2510,7 +2537,7 @@ module Ssa { /** * Gets an input of this phi node. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -2537,6 +2564,13 @@ module Ssa { ) } + /** Holds if `inp` is an input to the phi node along the edge originating in `bb`. */ + predicate hasInputFromBlock(Definition inp, BasicBlock bb) { + this.getAnInput() = inp and + this.getBasicBlock().getAPredecessor() = bb and + inp.isLiveAtEndOfBlock(bb) + } + override string toString() { result = getToStringPrefix(this) + "SSA phi(" + getSourceVariable() + ")" } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/SignAnalysis.qll b/csharp/ql/src/semmle/code/csharp/dataflow/SignAnalysis.qll new file mode 100644 index 000000000000..3742f87de251 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/dataflow/SignAnalysis.qll @@ -0,0 +1,9 @@ +/** + * Provides sign analysis to determine whether expression are always positive + * or negative. + * + * The analysis is implemented as an abstract interpretation over the + * three-valued domain `{negative, zero, positive}`. + */ + +import semmle.code.csharp.dataflow.internal.rangeanalysis.SignAnalysisCommon diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/flowsources/PublicCallableParameter.qll b/csharp/ql/src/semmle/code/csharp/dataflow/flowsources/PublicCallableParameter.qll index a9e27915fe3a..e24a793174ad 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/flowsources/PublicCallableParameter.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/flowsources/PublicCallableParameter.qll @@ -7,7 +7,7 @@ import csharp /** * A parameter of a public callable, for example `p` in * - * ``` + * ```csharp * public void M(int p) { * ... * } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll index 2b09436f27d1..9c2cbabcd618 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll @@ -44,7 +44,7 @@ private ControlFlow::BasicBlock getABasicBlockInScope(ControlFlowScope scope, bo * * For example, in * - * ``` + * ```csharp * if (b) * .... * var x = "foo"; diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll index fdf0480c8ef3..08d099961d00 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll @@ -3,18 +3,24 @@ private import cil private import dotnet private import DataFlowPrivate private import DelegateDataFlow +private import semmle.code.csharp.dataflow.LibraryTypeDataFlow private import semmle.code.csharp.dispatch.Dispatch private import semmle.code.csharp.frameworks.system.Collections private import semmle.code.csharp.frameworks.system.collections.Generic /** - * Gets a source declaration of callable `c` that has a body. + * Gets a source declaration of callable `c` that has a body or has + * a flow summary. + * * If the callable has both CIL and source code, return only the source * code version. */ DotNet::Callable getCallableForDataFlow(DotNet::Callable c) { - result.hasBody() and exists(DotNet::Callable sourceDecl | sourceDecl = c.getSourceDeclaration() | + result = sourceDecl and + Summaries::summary(result, _, _, _, _, _) + or + result.hasBody() and if sourceDecl.getFile().fromSource() then // C# callable with C# implementation in the database @@ -67,7 +73,6 @@ private predicate transitiveCapturedCallTarget(ControlFlow::Nodes::ElementNode c cached private module Cached { - private import CallContext private import semmle.code.csharp.Caching cached @@ -84,7 +89,8 @@ private module Cached { exists(Ssa::ExplicitDefinition def | def.isCapturedVariableDefinitionFlowOut(_, _) | v = def.getSourceVariable().getAssignable() ) - } + } or + TQualifierReturnKind() cached newtype TDataFlowCall = @@ -94,87 +100,79 @@ private module Cached { TExplicitDelegateCall(ControlFlow::Nodes::ElementNode cfn, DelegateCall dc) { cfn.getElement() = dc } or - TImplicitDelegateCall(ControlFlow::Nodes::ElementNode cfn, DelegateArgumentToLibraryCallable arg) { - cfn.getElement() = arg - } or TTransitiveCapturedCall(ControlFlow::Nodes::ElementNode cfn, Callable target) { transitiveCapturedCallTarget(cfn, target) } or TCilCall(CIL::Call call) { // No need to include calls that are compiled from source not call.getImplementation().getMethod().compiledFromSource() + } or + TSummaryDelegateCall(SourceDeclarationCallable c, int pos) { + exists(CallableFlowSourceDelegateArg source | + Summaries::summary(c, source, _, _, _, _) and + pos = source.getArgumentIndex() + ) + or + exists(CallableFlowSinkDelegateArg sink | + Summaries::summary(c, _, _, sink, _, _) and + pos = sink.getDelegateIndex() + ) } /** Gets a viable run-time target for the call `call`. */ cached - DataFlowCallable viableImpl(DataFlowCall call) { result = call.getARuntimeTarget() } + DataFlowCallable viableCallable(DataFlowCall call) { result = call.getARuntimeTarget() } +} + +import Cached + +private module DispatchImpl { + private import CallContext /** * Gets a viable run-time target for the delegate call `call`, requiring * call context `cc`. */ - private DotNet::Callable viableDelegateCallable(DataFlowCall call, CallContext cc) { + private DataFlowCallable viableDelegateCallable(DataFlowCall call, CallContext cc) { result = call.(DelegateDataFlowCall).getARuntimeTarget(cc) } /** - * Holds if the call context `ctx` reduces the set of viable run-time - * targets of call `call` in `c`. + * Holds if the set of viable implementations that can be called by `call` + * might be improved by knowing the call context. This is the case if the + * call is a delegate call, or if the qualifier accesses a parameter of + * the enclosing callable `c` (including the implicit `this` parameter). */ - cached - predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) { - c = viableImpl(ctx) and + predicate mayBenefitFromCallContext(DataFlowCall call, Callable c) { c = call.getEnclosingCallable() and - exists(CallContext cc | exists(viableDelegateCallable(call, cc)) | - not cc instanceof EmptyCallContext - ) - } - - private DotNet::Callable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { - exists(ArgumentCallContext cc | result = viableDelegateCallable(call, cc) | - cc.isArgument(ctx.getExpr(), _) + ( + exists(CallContext cc | exists(viableDelegateCallable(call, cc)) | + not cc instanceof EmptyCallContext + ) + or + call.(NonDelegateDataFlowCall).getDispatchCall().mayBenefitFromCallContext() ) } /** - * Gets a viable run-time target for the call `call` in the context - * `ctx`. This is restricted to those call nodes for which a context - * might make a difference. - */ - cached - DotNet::Callable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { - result = viableImplInCallContext(call, ctx) and - reducedViableImplInCallContext(call, _, ctx) - } - - /** - * Holds if flow returning from callable `c` to call `call` might return - * further and if this path restricts the set of call sites that can be - * returned to. + * Gets a viable dispatch target of `call` in the context `ctx`. This is + * restricted to those `call`s for which a context might make a difference. */ - cached - predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { - exists(int tgts, int ctxtgts | - c = viableImpl(call) and - ctxtgts = strictcount(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and - tgts = strictcount(DataFlowCall ctx | viableImpl(ctx) = call.getEnclosingCallable()) and - ctxtgts < tgts + DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { + exists(ArgumentCallContext cc | result = viableDelegateCallable(call, cc) | + cc.isArgument(ctx.getExpr(), _) ) - } - - /** - * Gets a viable run-time target for the call `call` in the context `ctx`. - * This is restricted to those call nodes and results for which the return - * flow from the result to `call` restricts the possible context `ctx`. - */ - cached - DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) { - result = viableImplInCallContext(call, ctx) and - reducedViableImplInReturn(result, call) + or + result = + call + .(NonDelegateDataFlowCall) + .getDispatchCall() + .getADynamicTargetInCallContext(ctx.(NonDelegateDataFlowCall).getDispatchCall()) + .getSourceDeclaration() } } -import Cached +import DispatchImpl /** * Gets a node that can read the value returned from `call` with return kind @@ -182,8 +180,6 @@ import Cached */ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { call = result.getCall(kind) } -predicate viableCallable = viableImpl/1; - /** * A return kind. A return kind describes how a value can be returned * from a callable. @@ -238,6 +234,11 @@ class ImplicitCapturedReturnKind extends ReturnKind, TImplicitCapturedReturnKind override string toString() { result = "captured " + v } } +/** A value returned through the qualifier of a call. */ +class QualifierReturnKind extends ReturnKind, TQualifierReturnKind { + override string toString() { result = "qualifier" } +} + class DataFlowCallable = DotNet::Callable; /** A call relevant for data flow. */ @@ -278,7 +279,10 @@ class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall { NonDelegateDataFlowCall() { this = TNonDelegateCall(cfn, dc) } - override DotNet::Callable getARuntimeTarget() { + /** Gets the underlying call. */ + DispatchCall getDispatchCall() { result = dc } + + override DataFlowCallable getARuntimeTarget() { result = getCallableForDataFlow(dc.getADynamicTarget()) } @@ -296,9 +300,9 @@ class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall { /** A delegate call relevant for data flow. */ abstract class DelegateDataFlowCall extends DataFlowCall { /** Gets a viable run-time target of this call requiring call context `cc`. */ - abstract DotNet::Callable getARuntimeTarget(CallContext::CallContext cc); + abstract DataFlowCallable getARuntimeTarget(CallContext::CallContext cc); - override DotNet::Callable getARuntimeTarget() { result = this.getARuntimeTarget(_) } + override DataFlowCallable getARuntimeTarget() { result = this.getARuntimeTarget(_) } } /** An explicit delegate call relevant for data flow. */ @@ -308,8 +312,8 @@ class ExplicitDelegateDataFlowCall extends DelegateDataFlowCall, TExplicitDelega ExplicitDelegateDataFlowCall() { this = TExplicitDelegateCall(cfn, dc) } - override DotNet::Callable getARuntimeTarget(CallContext::CallContext cc) { - result = dc.getARuntimeTarget(cc) + override DataFlowCallable getARuntimeTarget(CallContext::CallContext cc) { + result = getCallableForDataFlow(dc.getARuntimeTarget(cc)) } override ControlFlow::Nodes::ElementNode getControlFlowNode() { result = cfn } @@ -323,50 +327,6 @@ class ExplicitDelegateDataFlowCall extends DelegateDataFlowCall, TExplicitDelega override Location getLocation() { result = cfn.getLocation() } } -/** - * An implicit delegate call in a call to a library method. For example, we add - * an implicit call to `M` in `new Lazy(M)` (although, technically, the delegate - * would first be called when accessing the `Value` property). - */ -class ImplicitDelegateDataFlowCall extends DelegateDataFlowCall, TImplicitDelegateCall { - private ControlFlow::Nodes::ElementNode cfn; - private DelegateArgumentToLibraryCallable arg; - - ImplicitDelegateDataFlowCall() { this = TImplicitDelegateCall(cfn, arg) } - - /** - * Holds if the underlying delegate argument is the `i`th argument of the - * call `c` targeting a library callable. For example, `M` is the `0`th - * argument of `new Lazy(M)`. - */ - predicate isArgumentOf(NonDelegateDataFlowCall c, int i) { - exists(ImplicitDelegateOutNode out | out.getControlFlowNode() = cfn | out.isArgumentOf(c, i)) - } - - /** Gets the number of parameters of the supplied delegate. */ - int getNumberOfDelegateParameters() { result = arg.getDelegateType().getNumberOfParameters() } - - /** Gets the type of the `i`th parameter of the supplied delegate. */ - Type getDelegateParameterType(int i) { result = arg.getDelegateType().getParameter(i).getType() } - - /** Gets the return type of the supplied delegate. */ - Type getDelegateReturnType() { result = arg.getDelegateType().getReturnType() } - - override DotNet::Callable getARuntimeTarget(CallContext::CallContext cc) { - result = arg.getARuntimeTarget(cc) - } - - override ControlFlow::Nodes::ElementNode getControlFlowNode() { result = cfn } - - override ImplicitDelegateOutNode getNode() { result.getControlFlowNode() = cfn } - - override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() } - - override string toString() { result = "[implicit call] " + cfn.toString() } - - override Location getLocation() { result = cfn.getLocation() } -} - /** * A call that can reach a callable, using one or more additional calls, which * reads or updates a captured variable. We model such a chain of calls as just @@ -397,7 +357,7 @@ class CilDataFlowCall extends DataFlowCall, TCilCall { CilDataFlowCall() { this = TCilCall(call) } - override DotNet::Callable getARuntimeTarget() { + override DataFlowCallable getARuntimeTarget() { // There is no dispatch library for CIL, so do not consider overrides for now result = getCallableForDataFlow(call.getTarget()) } @@ -412,3 +372,34 @@ class CilDataFlowCall extends DataFlowCall, TCilCall { override Location getLocation() { result = call.getLocation() } } + +/** + * A delegate call inside a callable with a flow summary. + * + * For example, in `ints.Select(i => i + 1)` there is a call to the delegate at + * parameter position `1` (counting the qualifier as the `0`th argument) inside + * the method `Select`. + */ +class SummaryDelegateCall extends DelegateDataFlowCall, TSummaryDelegateCall { + private SourceDeclarationCallable c; + private int pos; + + SummaryDelegateCall() { this = TSummaryDelegateCall(c, pos) } + + override DataFlowCallable getARuntimeTarget(CallContext::CallContext cc) { + exists(SummaryDelegateParameterSink p | + p = TSummaryParameterNode(c, pos) and + result = p.getARuntimeTarget(cc) + ) + } + + override ControlFlow::Nodes::ElementNode getControlFlowNode() { none() } + + override DataFlow::Node getNode() { none() } + + override Callable getEnclosingCallable() { result = c } + + override string toString() { result = "[summary] delegate call, parameter " + pos + " of " + c } + + override Location getLocation() { result = c.getLocation() } +} diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index f876c04d6c66..8bc3d75ff86e 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -286,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -318,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -417,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -447,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -566,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -748,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -781,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -896,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -930,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1046,11 +1051,22 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1058,9 +1074,9 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1074,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1108,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1122,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1154,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1183,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1197,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1223,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1261,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } +pragma[nomagic] +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + pragma[nomagic] private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1385,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1417,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1497,24 +1523,24 @@ private predicate flowCandIsReturned( ) } -private newtype TAccessPath = +private newtype TAccessPathApprox = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two - * elements of the list and its length are tracked. If data flows from a source to - * a given node with a given `AccessPath`, this indicates the sequence 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. + * Conceptually a list of `TypedContent`s followed by a `DataFlowType`, but only + * the first two elements of the list and its length are tracked. If data flows + * from a source to a given node with a given `AccessPathApprox`, this indicates + * the sequence 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 { +abstract private class AccessPathApprox extends TAccessPathApprox { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1522,20 +1548,18 @@ abstract private class AccessPath extends TAccessPath { abstract AccessPathFront getFront(); - /** - * Holds if this access path has `head` at the front and may be followed by `tail`. - */ - abstract predicate pop(Content head, AccessPath tail); + /** Gets the access path obtained by popping `head` from this path, if any. */ + abstract AccessPathApprox pop(TypedContent head); } -private class AccessPathNil extends AccessPath, TNil { +private class AccessPathApproxNil extends AccessPathApprox, TNil { private DataFlowType t; - AccessPathNil() { this = TNil(t) } + AccessPathApproxNil() { this = TNil(t) } override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1543,258 +1567,285 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override AccessPathApprox pop(TypedContent head) { none() } } -abstract private class AccessPathCons extends AccessPath { } +abstract private class AccessPathApproxCons extends AccessPathApprox { } -private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; +private class AccessPathApproxConsNil extends AccessPathApproxCons, TConsNil { + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathApproxConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override AccessPathApprox pop(TypedContent head) { head = tc and result = TNil(t) } } -private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; +private class AccessPathApproxConsCons extends AccessPathApproxCons, TConsCons { + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathApproxConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override AccessPathApprox pop(TypedContent head) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + result = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + result = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPathApprox pop(TypedContent tc, AccessPathApprox apa) { result = apa.pop(tc) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPathApprox push(TypedContent tc, AccessPathApprox apa) { apa = pop(tc, result) } -private newtype TAccessPathOption = - TAccessPathNone() or - TAccessPathSome(AccessPath ap) +private newtype TAccessPathApproxOption = + TAccessPathApproxNone() or + TAccessPathApproxSome(AccessPathApprox apa) -private class AccessPathOption extends TAccessPathOption { +private class AccessPathApproxOption extends TAccessPathApproxOption { string toString() { - this = TAccessPathNone() and result = "" + this = TAccessPathApproxNone() and result = "" or - this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + this = TAccessPathApproxSome(any(AccessPathApprox apa | result = apa.toString())) } } /** - * Holds if `node` is reachable with access path `ap` from a source in - * the configuration `config`. + * Holds if `node` is reachable with approximate access path `apa` from a source + * in the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an - * argument in a call, and if so, `argAp` records the access path of that - * argument. + * The call context `cc` records whether the node is reached through an + * argument in a call, and if so, `argApa` records the approximate access path + * of that argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argApa, apf, apa, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, apf, apa, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and - apf = ap.(AccessPathNil).getFront() + exists(Node mid, AccessPathApproxNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and + apf = apa.(AccessPathApproxNil).getFront() ) or exists(Node mid | - flowFwd(mid, _, _, apf, ap, config) and + flowFwd(mid, _, _, apf, apa, config) and jumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | + exists(Node mid, AccessPathApproxNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, apa), apf, cc, argApa, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, apa), apf, cc, argApa, config) and + flowFwdConsCand(tc, apf, apa, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, _, cc, _, apf, apa, config) and if flowCand(node, true, _, apf, config) - then argAp = TAccessPathSome(ap) - else argAp = TAccessPathNone() + then argApa = TAccessPathApproxSome(apa) + else argApa = TAccessPathApproxNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argApa, apf, apa, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or - exists(AccessPath argAp0 | - flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + exists(AccessPathApprox argApa0 | + flowFwdOutFromArg(call, node, argApa0, apf, apa, config) and + flowFwdIsEntered(call, cc, argApa, argApa0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argApa, apf, apa, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - AccessPathOption argAp, Configuration config + Node node, TypedContent tc, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwd(mid, cc, argApa, apf0, apa0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPathApprox apa0, Node node2, + CallContext cc, AccessPathApproxOption argApa, Configuration config +) { + flowFwd(node1, cc, argApa, apf0, apa0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + pragma[nomagic] private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config + Node node, AccessPathFrontHead apf0, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, apa0, node, cc, argApa, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(Node n | - flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwd(n, _, _, apf, apa, config) and + flowFwdStore0(n, tc, _, apf, _, config) ) } pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argApa, apf, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argApa, apf, apa, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOutFromArg( - DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + DataFlowCall call, Node node, AccessPathApprox argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathApproxSome(argApa), apf, apa, + config) } /** @@ -1802,166 +1853,174 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathApproxOption argApa, AccessPathApprox apa, + Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argApa, apf, apa, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if `node` with access path `ap` is part of a path from a source to - * a sink in the configuration `config`. + * Holds if `node` with approximate access path `apa` is part of a path from a + * source to a sink in the configuration `config`. * * The Boolean `toReturn` records whether the node must be returned from - * the enclosing callable in order to reach a sink, and if so, `returnAp` - * records the access path of the returned value. + * the enclosing callable in order to reach a sink, and if so, `returnApa` + * records the approximate access path of the returned value. */ private predicate flow( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flow0(node, toReturn, returnAp, ap, config) and - flowFwd(node, _, _, _, ap, config) + flow0(node, toReturn, returnApa, apa, config) and + flowFwd(node, _, _, _, apa, config) } private predicate flow0( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flowFwd(node, _, _, _, ap, config) and + flowFwd(node, _, _, _, apa, config) and config.isSink(node) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil or exists(Node mid | localFlowBigStep(node, mid, true, _, config, _) and - flow(mid, toReturn, returnAp, ap, config) + flow(mid, toReturn, returnApa, apa, config) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and localFlowBigStep(node, mid, false, _, config, _) and - flow(mid, toReturn, returnAp, nil, config) and - ap instanceof AccessPathNil + flow(mid, toReturn, returnApa, nil, config) and + apa instanceof AccessPathApproxNil ) or exists(Node mid | jumpStep(node, mid, config) and - flow(mid, _, _, ap, config) and + flow(mid, _, _, apa, config) and toReturn = false and - returnAp = TAccessPathNone() + returnApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and additionalJumpStep(node, mid, config) and flow(mid, _, _, nil, config) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnApa, apa, config) and + flowConsCand(tc, apa, config) ) or // read - exists(Node mid, AccessPath ap0 | - readFlowFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + readFlowFwd(node, _, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) or // flow into a callable exists(DataFlowCall call | - flowIn(call, node, toReturn, returnAp, ap, config) and + flowIn(call, node, toReturn, returnApa, apa, config) and toReturn = false or - exists(AccessPath returnAp0 | - flowInToReturn(call, node, returnAp0, ap, config) and - flowIsReturned(call, toReturn, returnAp, returnAp0, config) + exists(AccessPathApprox returnApa0 | + flowInToReturn(call, node, returnApa0, apa, config) and + flowIsReturned(call, toReturn, returnApa, returnApa0, config) ) ) or // flow out of a callable - flowOut(_, node, _, _, ap, config) and + flowOut(_, node, _, _, apa, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) - then returnAp = TAccessPathSome(ap) - else returnAp = TAccessPathNone() + if flowFwd(node, any(CallContextCall ccc), TAccessPathApproxSome(_), _, apa, config) + then returnApa = TAccessPathApproxSome(apa) + else returnApa = TAccessPathApproxNone() } pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, apa, _, _, _, config) and + apa0 = push(tc, apa) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { - exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + storeFlowFwd(node, tc, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, apa, _, _, _, config) and + apa0 = pop(tc, apa) and + flowFwdConsCand(tc, _, apa0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPathApprox apa, Configuration config) { exists(Node n, Node mid | - flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + flow(mid, _, _, apa, config) and + readFlowFwd(n, tc, mid, _, apa, config) ) } pragma[nomagic] private predicate flowOut( - DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(Node out, boolean allowsFieldFlow | - flow(out, toReturn, returnAp, ap, config) and + flow(out, toReturn, returnApa, apa, config) and flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowIn( - DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(ParameterNode p, boolean allowsFieldFlow | - flow(p, toReturn, returnAp, ap, config) and + flow(p, toReturn, returnApa, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowInToReturn( - DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config + DataFlowCall call, ArgumentNode arg, AccessPathApprox returnApa, AccessPathApprox apa, + Configuration config ) { - flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) + flowIn(call, arg, true, TAccessPathApproxSome(returnApa), apa, config) } /** @@ -1969,12 +2028,13 @@ private predicate flowInToReturn( */ pragma[nomagic] private predicate flowIsReturned( - DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + DataFlowCall call, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, Configuration config ) { - exists(ReturnNodeExt ret | - flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + exists(ReturnNodeExt ret, CallContextCall ccc | + flowOut(call, ret, toReturn, returnApa, apa, config) and + flowFwd(ret, ccc, TAccessPathApproxSome(_), _, apa, config) and + ccc.matchesCall(call) ) } @@ -1985,21 +2045,23 @@ private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) pragma[noinline] private predicate parameterFlow( - ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config + ParameterNode p, AccessPathApprox apa, DataFlowCallable c, Configuration config ) { - flow(p, true, _, ap, config) and + flow(p, true, _, apa, config) and c = p.getEnclosingCallable() } +private predicate parameterMayFlowThrough(ParameterNode p, AccessPathApprox apa) { + exists(ReturnNodeExt ret, Configuration config, AccessPathApprox apa0 | + parameterFlow(p, apa, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathApproxSome(_), apa0, config) and + flowFwd(ret, any(CallContextCall ccc), TAccessPathApproxSome(apa), _, apa0, config) + ) +} + private newtype TSummaryCtx = TSummaryCtxNone() or - TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | - parameterFlow(p, ap, ret.getEnclosingCallable(), config) and - flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) - ) - } + TSummaryCtxSome(ParameterNode p, AccessPath ap) { parameterMayFlowThrough(p, ap.getApprox()) } /** * A context for generating flow summaries. This represents flow entry through @@ -2034,6 +2096,10 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { } } +private newtype TAccessPath = + TAccessPathNil(DataFlowType t) or + TAccessPathCons(TypedContent head, AccessPath tail) { flowConsCand(head, tail.getApprox(), _) } + private newtype TPathNode = TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) { // A PathNode is introduced by a source ... @@ -2041,13 +2107,13 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(node, _, _, ap, unbind(config)) + flow(node, _, _, ap.getApprox(), unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2059,12 +2125,99 @@ private newtype TPathNode = or // ... or a sink that can be reached from a source exists(PathNodeMid mid | - pathStep(mid, node, _, _, any(AccessPathNil nil)) and + pathStep(mid, node, _, _, TAccessPathNil(_)) and config = unbind(mid.getConfiguration()) ) ) } +/** + * A list of `TypedContent`s followed by a `DataFlowType`. If data flows from a + * source to a given node with a given `AccessPath`, this indicates the sequence + * 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 { + /** Gets the head of this access path, if any. */ + abstract TypedContent getHead(); + + /** Gets the tail of this access path, if any. */ + abstract AccessPath getTail(); + + /** Gets the front of this access path. */ + abstract AccessPathFront getFront(); + + /** Gets the approximation of this access path. */ + abstract AccessPathApprox getApprox(); + + /** Gets the length of this access path. */ + abstract int length(); + + /** Gets a textual representation of this access path. */ + abstract string toString(); + + /** Gets the access path obtained by popping `tc` from this access path, if any. */ + final AccessPath pop(TypedContent tc) { + result = this.getTail() and + tc = this.getHead() + } + + /** Gets the access path obtained by pushing `tc` onto this access path. */ + final AccessPath push(TypedContent tc) { this = result.pop(tc) } +} + +private class AccessPathNil extends AccessPath, TAccessPathNil { + private DataFlowType t; + + AccessPathNil() { this = TAccessPathNil(t) } + + DataFlowType getType() { result = t } + + override TypedContent getHead() { none() } + + override AccessPath getTail() { none() } + + override AccessPathFrontNil getFront() { result = TFrontNil(t) } + + override AccessPathApproxNil getApprox() { result = TNil(t) } + + override int length() { result = 0 } + + override string toString() { result = concat(": " + ppReprType(t)) } +} + +private class AccessPathCons extends AccessPath, TAccessPathCons { + private TypedContent head; + private AccessPath tail; + + AccessPathCons() { this = TAccessPathCons(head, tail) } + + override TypedContent getHead() { result = head } + + override AccessPath getTail() { result = tail } + + override AccessPathFrontHead getFront() { result = TFrontHead(head) } + + override AccessPathApproxCons getApprox() { + result = TConsNil(head, tail.(AccessPathNil).getType()) + or + result = TConsCons(head, tail.getHead(), this.length()) + } + + override int length() { result = 1 + tail.length() } + + private string toStringImpl() { + exists(DataFlowType t | + tail = TAccessPathNil(t) and + result = head.toString() + "]" + concat(" : " + ppReprType(t)) + ) + or + result = head + ", " + tail.(AccessPathCons).toStringImpl() + } + + override string toString() { result = "[" + this.toStringImpl() } +} + /** * A `Node` augmented with a call context (except for sinks), an access path, and a configuration. * Only those `PathNode`s that are reachable from a source are generated. @@ -2098,14 +2251,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2350,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2387,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2251,12 +2421,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2267,50 +2437,53 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } private predicate pathOutOfCallable0( - PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPath ap, Configuration config + PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa, + Configuration config ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and - ap = mid.getAp() and + innercc instanceof CallContextNoCall and + apa = mid.getAp().getApprox() and config = mid.getConfiguration() } pragma[nomagic] private predicate pathOutOfCallable1( - PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPath ap, + PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPathApprox apa, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | - pathOutOfCallable0(mid, pos, innercc, ap, config) and + pathOutOfCallable0(mid, pos, innercc, apa, config) and c = pos.getCallable() and kind = pos.getKind() and resolveReturn(innercc, c, call) @@ -2321,10 +2494,10 @@ private predicate pathOutOfCallable1( pragma[noinline] private Node getAnOutNodeFlow( - ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config + ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ) { result = kind.getAnOutNode(call) and - flow(result, _, _, ap, config) + flow(result, _, _, apa, config) } /** @@ -2333,10 +2506,9 @@ private Node getAnOutNodeFlow( */ pragma[noinline] private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { - exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | - pathOutOfCallable1(mid, call, kind, cc, ap, config) - | - out = getAnOutNodeFlow(kind, call, ap, config) + exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config | + pathOutOfCallable1(mid, call, kind, cc, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -2345,22 +2517,23 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa ) { exists(ArgumentNode arg | arg = mid.getNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and - ap = mid.getAp() + ap = mid.getAp() and + apa = ap.getApprox() ) } pragma[noinline] private predicate parameterCand( - DataFlowCallable callable, int i, AccessPath ap, Configuration config + DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { exists(ParameterNode p | - flow(p, _, _, ap, config) and + flow(p, _, _, apa, config) and p.isParameterOf(callable, i) ) } @@ -2370,9 +2543,11 @@ private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, AccessPath ap ) { - pathIntoArg(mid, i, outercc, call, ap) and - callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), ap, mid.getConfiguration()) + exists(AccessPathApprox apa | + pathIntoArg(mid, i, outercc, call, ap, apa) and + callable = resolveCall(call, outercc) and + parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + ) } /** @@ -2403,7 +2578,8 @@ private predicate pathIntoCallable( /** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */ pragma[nomagic] private predicate paramFlowsThrough( - ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config + ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(PathNodeMid mid, ReturnNodeExt ret, int pos | mid.getNode() = ret and @@ -2412,6 +2588,7 @@ private predicate paramFlowsThrough( sc = mid.getSummaryCtx() and config = mid.getConfiguration() and ap = mid.getAp() and + apa = ap.getApprox() and pos = sc.getParameterPos() and not kind.(ParamUpdateReturnKind).getPosition() = pos ) @@ -2419,11 +2596,12 @@ private predicate paramFlowsThrough( pragma[nomagic] private predicate pathThroughCallable0( - DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap + DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, + AccessPathApprox apa ) { exists(CallContext innercc, SummaryCtx sc | pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, unbind(mid.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration())) ) } @@ -2433,9 +2611,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind | - pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | + pathThroughCallable0(call, mid, kind, cc, ap, apa) and + out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration())) ) } @@ -2521,10 +2699,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2533,7 +2711,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2544,7 +2722,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2562,15 +2740,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2591,7 +2769,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2608,7 +2786,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2721,7 +2899,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2737,7 +2915,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2746,11 +2924,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2769,35 +2948,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( @@ -2806,7 +2992,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index f876c04d6c66..8bc3d75ff86e 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -286,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -318,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -417,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -447,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -566,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -748,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -781,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -896,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -930,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1046,11 +1051,22 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1058,9 +1074,9 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1074,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1108,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1122,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1154,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1183,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1197,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1223,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1261,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } +pragma[nomagic] +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + pragma[nomagic] private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1385,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1417,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1497,24 +1523,24 @@ private predicate flowCandIsReturned( ) } -private newtype TAccessPath = +private newtype TAccessPathApprox = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two - * elements of the list and its length are tracked. If data flows from a source to - * a given node with a given `AccessPath`, this indicates the sequence 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. + * Conceptually a list of `TypedContent`s followed by a `DataFlowType`, but only + * the first two elements of the list and its length are tracked. If data flows + * from a source to a given node with a given `AccessPathApprox`, this indicates + * the sequence 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 { +abstract private class AccessPathApprox extends TAccessPathApprox { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1522,20 +1548,18 @@ abstract private class AccessPath extends TAccessPath { abstract AccessPathFront getFront(); - /** - * Holds if this access path has `head` at the front and may be followed by `tail`. - */ - abstract predicate pop(Content head, AccessPath tail); + /** Gets the access path obtained by popping `head` from this path, if any. */ + abstract AccessPathApprox pop(TypedContent head); } -private class AccessPathNil extends AccessPath, TNil { +private class AccessPathApproxNil extends AccessPathApprox, TNil { private DataFlowType t; - AccessPathNil() { this = TNil(t) } + AccessPathApproxNil() { this = TNil(t) } override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1543,258 +1567,285 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override AccessPathApprox pop(TypedContent head) { none() } } -abstract private class AccessPathCons extends AccessPath { } +abstract private class AccessPathApproxCons extends AccessPathApprox { } -private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; +private class AccessPathApproxConsNil extends AccessPathApproxCons, TConsNil { + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathApproxConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override AccessPathApprox pop(TypedContent head) { head = tc and result = TNil(t) } } -private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; +private class AccessPathApproxConsCons extends AccessPathApproxCons, TConsCons { + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathApproxConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override AccessPathApprox pop(TypedContent head) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + result = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + result = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPathApprox pop(TypedContent tc, AccessPathApprox apa) { result = apa.pop(tc) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPathApprox push(TypedContent tc, AccessPathApprox apa) { apa = pop(tc, result) } -private newtype TAccessPathOption = - TAccessPathNone() or - TAccessPathSome(AccessPath ap) +private newtype TAccessPathApproxOption = + TAccessPathApproxNone() or + TAccessPathApproxSome(AccessPathApprox apa) -private class AccessPathOption extends TAccessPathOption { +private class AccessPathApproxOption extends TAccessPathApproxOption { string toString() { - this = TAccessPathNone() and result = "" + this = TAccessPathApproxNone() and result = "" or - this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + this = TAccessPathApproxSome(any(AccessPathApprox apa | result = apa.toString())) } } /** - * Holds if `node` is reachable with access path `ap` from a source in - * the configuration `config`. + * Holds if `node` is reachable with approximate access path `apa` from a source + * in the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an - * argument in a call, and if so, `argAp` records the access path of that - * argument. + * The call context `cc` records whether the node is reached through an + * argument in a call, and if so, `argApa` records the approximate access path + * of that argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argApa, apf, apa, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, apf, apa, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and - apf = ap.(AccessPathNil).getFront() + exists(Node mid, AccessPathApproxNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and + apf = apa.(AccessPathApproxNil).getFront() ) or exists(Node mid | - flowFwd(mid, _, _, apf, ap, config) and + flowFwd(mid, _, _, apf, apa, config) and jumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | + exists(Node mid, AccessPathApproxNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, apa), apf, cc, argApa, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, apa), apf, cc, argApa, config) and + flowFwdConsCand(tc, apf, apa, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, _, cc, _, apf, apa, config) and if flowCand(node, true, _, apf, config) - then argAp = TAccessPathSome(ap) - else argAp = TAccessPathNone() + then argApa = TAccessPathApproxSome(apa) + else argApa = TAccessPathApproxNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argApa, apf, apa, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or - exists(AccessPath argAp0 | - flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + exists(AccessPathApprox argApa0 | + flowFwdOutFromArg(call, node, argApa0, apf, apa, config) and + flowFwdIsEntered(call, cc, argApa, argApa0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argApa, apf, apa, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - AccessPathOption argAp, Configuration config + Node node, TypedContent tc, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwd(mid, cc, argApa, apf0, apa0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPathApprox apa0, Node node2, + CallContext cc, AccessPathApproxOption argApa, Configuration config +) { + flowFwd(node1, cc, argApa, apf0, apa0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + pragma[nomagic] private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config + Node node, AccessPathFrontHead apf0, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, apa0, node, cc, argApa, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(Node n | - flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwd(n, _, _, apf, apa, config) and + flowFwdStore0(n, tc, _, apf, _, config) ) } pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argApa, apf, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argApa, apf, apa, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOutFromArg( - DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + DataFlowCall call, Node node, AccessPathApprox argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathApproxSome(argApa), apf, apa, + config) } /** @@ -1802,166 +1853,174 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathApproxOption argApa, AccessPathApprox apa, + Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argApa, apf, apa, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if `node` with access path `ap` is part of a path from a source to - * a sink in the configuration `config`. + * Holds if `node` with approximate access path `apa` is part of a path from a + * source to a sink in the configuration `config`. * * The Boolean `toReturn` records whether the node must be returned from - * the enclosing callable in order to reach a sink, and if so, `returnAp` - * records the access path of the returned value. + * the enclosing callable in order to reach a sink, and if so, `returnApa` + * records the approximate access path of the returned value. */ private predicate flow( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flow0(node, toReturn, returnAp, ap, config) and - flowFwd(node, _, _, _, ap, config) + flow0(node, toReturn, returnApa, apa, config) and + flowFwd(node, _, _, _, apa, config) } private predicate flow0( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flowFwd(node, _, _, _, ap, config) and + flowFwd(node, _, _, _, apa, config) and config.isSink(node) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil or exists(Node mid | localFlowBigStep(node, mid, true, _, config, _) and - flow(mid, toReturn, returnAp, ap, config) + flow(mid, toReturn, returnApa, apa, config) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and localFlowBigStep(node, mid, false, _, config, _) and - flow(mid, toReturn, returnAp, nil, config) and - ap instanceof AccessPathNil + flow(mid, toReturn, returnApa, nil, config) and + apa instanceof AccessPathApproxNil ) or exists(Node mid | jumpStep(node, mid, config) and - flow(mid, _, _, ap, config) and + flow(mid, _, _, apa, config) and toReturn = false and - returnAp = TAccessPathNone() + returnApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and additionalJumpStep(node, mid, config) and flow(mid, _, _, nil, config) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnApa, apa, config) and + flowConsCand(tc, apa, config) ) or // read - exists(Node mid, AccessPath ap0 | - readFlowFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + readFlowFwd(node, _, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) or // flow into a callable exists(DataFlowCall call | - flowIn(call, node, toReturn, returnAp, ap, config) and + flowIn(call, node, toReturn, returnApa, apa, config) and toReturn = false or - exists(AccessPath returnAp0 | - flowInToReturn(call, node, returnAp0, ap, config) and - flowIsReturned(call, toReturn, returnAp, returnAp0, config) + exists(AccessPathApprox returnApa0 | + flowInToReturn(call, node, returnApa0, apa, config) and + flowIsReturned(call, toReturn, returnApa, returnApa0, config) ) ) or // flow out of a callable - flowOut(_, node, _, _, ap, config) and + flowOut(_, node, _, _, apa, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) - then returnAp = TAccessPathSome(ap) - else returnAp = TAccessPathNone() + if flowFwd(node, any(CallContextCall ccc), TAccessPathApproxSome(_), _, apa, config) + then returnApa = TAccessPathApproxSome(apa) + else returnApa = TAccessPathApproxNone() } pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, apa, _, _, _, config) and + apa0 = push(tc, apa) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { - exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + storeFlowFwd(node, tc, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, apa, _, _, _, config) and + apa0 = pop(tc, apa) and + flowFwdConsCand(tc, _, apa0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPathApprox apa, Configuration config) { exists(Node n, Node mid | - flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + flow(mid, _, _, apa, config) and + readFlowFwd(n, tc, mid, _, apa, config) ) } pragma[nomagic] private predicate flowOut( - DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(Node out, boolean allowsFieldFlow | - flow(out, toReturn, returnAp, ap, config) and + flow(out, toReturn, returnApa, apa, config) and flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowIn( - DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(ParameterNode p, boolean allowsFieldFlow | - flow(p, toReturn, returnAp, ap, config) and + flow(p, toReturn, returnApa, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowInToReturn( - DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config + DataFlowCall call, ArgumentNode arg, AccessPathApprox returnApa, AccessPathApprox apa, + Configuration config ) { - flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) + flowIn(call, arg, true, TAccessPathApproxSome(returnApa), apa, config) } /** @@ -1969,12 +2028,13 @@ private predicate flowInToReturn( */ pragma[nomagic] private predicate flowIsReturned( - DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + DataFlowCall call, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, Configuration config ) { - exists(ReturnNodeExt ret | - flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + exists(ReturnNodeExt ret, CallContextCall ccc | + flowOut(call, ret, toReturn, returnApa, apa, config) and + flowFwd(ret, ccc, TAccessPathApproxSome(_), _, apa, config) and + ccc.matchesCall(call) ) } @@ -1985,21 +2045,23 @@ private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) pragma[noinline] private predicate parameterFlow( - ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config + ParameterNode p, AccessPathApprox apa, DataFlowCallable c, Configuration config ) { - flow(p, true, _, ap, config) and + flow(p, true, _, apa, config) and c = p.getEnclosingCallable() } +private predicate parameterMayFlowThrough(ParameterNode p, AccessPathApprox apa) { + exists(ReturnNodeExt ret, Configuration config, AccessPathApprox apa0 | + parameterFlow(p, apa, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathApproxSome(_), apa0, config) and + flowFwd(ret, any(CallContextCall ccc), TAccessPathApproxSome(apa), _, apa0, config) + ) +} + private newtype TSummaryCtx = TSummaryCtxNone() or - TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | - parameterFlow(p, ap, ret.getEnclosingCallable(), config) and - flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) - ) - } + TSummaryCtxSome(ParameterNode p, AccessPath ap) { parameterMayFlowThrough(p, ap.getApprox()) } /** * A context for generating flow summaries. This represents flow entry through @@ -2034,6 +2096,10 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { } } +private newtype TAccessPath = + TAccessPathNil(DataFlowType t) or + TAccessPathCons(TypedContent head, AccessPath tail) { flowConsCand(head, tail.getApprox(), _) } + private newtype TPathNode = TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) { // A PathNode is introduced by a source ... @@ -2041,13 +2107,13 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(node, _, _, ap, unbind(config)) + flow(node, _, _, ap.getApprox(), unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2059,12 +2125,99 @@ private newtype TPathNode = or // ... or a sink that can be reached from a source exists(PathNodeMid mid | - pathStep(mid, node, _, _, any(AccessPathNil nil)) and + pathStep(mid, node, _, _, TAccessPathNil(_)) and config = unbind(mid.getConfiguration()) ) ) } +/** + * A list of `TypedContent`s followed by a `DataFlowType`. If data flows from a + * source to a given node with a given `AccessPath`, this indicates the sequence + * 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 { + /** Gets the head of this access path, if any. */ + abstract TypedContent getHead(); + + /** Gets the tail of this access path, if any. */ + abstract AccessPath getTail(); + + /** Gets the front of this access path. */ + abstract AccessPathFront getFront(); + + /** Gets the approximation of this access path. */ + abstract AccessPathApprox getApprox(); + + /** Gets the length of this access path. */ + abstract int length(); + + /** Gets a textual representation of this access path. */ + abstract string toString(); + + /** Gets the access path obtained by popping `tc` from this access path, if any. */ + final AccessPath pop(TypedContent tc) { + result = this.getTail() and + tc = this.getHead() + } + + /** Gets the access path obtained by pushing `tc` onto this access path. */ + final AccessPath push(TypedContent tc) { this = result.pop(tc) } +} + +private class AccessPathNil extends AccessPath, TAccessPathNil { + private DataFlowType t; + + AccessPathNil() { this = TAccessPathNil(t) } + + DataFlowType getType() { result = t } + + override TypedContent getHead() { none() } + + override AccessPath getTail() { none() } + + override AccessPathFrontNil getFront() { result = TFrontNil(t) } + + override AccessPathApproxNil getApprox() { result = TNil(t) } + + override int length() { result = 0 } + + override string toString() { result = concat(": " + ppReprType(t)) } +} + +private class AccessPathCons extends AccessPath, TAccessPathCons { + private TypedContent head; + private AccessPath tail; + + AccessPathCons() { this = TAccessPathCons(head, tail) } + + override TypedContent getHead() { result = head } + + override AccessPath getTail() { result = tail } + + override AccessPathFrontHead getFront() { result = TFrontHead(head) } + + override AccessPathApproxCons getApprox() { + result = TConsNil(head, tail.(AccessPathNil).getType()) + or + result = TConsCons(head, tail.getHead(), this.length()) + } + + override int length() { result = 1 + tail.length() } + + private string toStringImpl() { + exists(DataFlowType t | + tail = TAccessPathNil(t) and + result = head.toString() + "]" + concat(" : " + ppReprType(t)) + ) + or + result = head + ", " + tail.(AccessPathCons).toStringImpl() + } + + override string toString() { result = "[" + this.toStringImpl() } +} + /** * A `Node` augmented with a call context (except for sinks), an access path, and a configuration. * Only those `PathNode`s that are reachable from a source are generated. @@ -2098,14 +2251,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2350,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2387,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2251,12 +2421,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2267,50 +2437,53 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } private predicate pathOutOfCallable0( - PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPath ap, Configuration config + PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa, + Configuration config ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and - ap = mid.getAp() and + innercc instanceof CallContextNoCall and + apa = mid.getAp().getApprox() and config = mid.getConfiguration() } pragma[nomagic] private predicate pathOutOfCallable1( - PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPath ap, + PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPathApprox apa, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | - pathOutOfCallable0(mid, pos, innercc, ap, config) and + pathOutOfCallable0(mid, pos, innercc, apa, config) and c = pos.getCallable() and kind = pos.getKind() and resolveReturn(innercc, c, call) @@ -2321,10 +2494,10 @@ private predicate pathOutOfCallable1( pragma[noinline] private Node getAnOutNodeFlow( - ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config + ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ) { result = kind.getAnOutNode(call) and - flow(result, _, _, ap, config) + flow(result, _, _, apa, config) } /** @@ -2333,10 +2506,9 @@ private Node getAnOutNodeFlow( */ pragma[noinline] private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { - exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | - pathOutOfCallable1(mid, call, kind, cc, ap, config) - | - out = getAnOutNodeFlow(kind, call, ap, config) + exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config | + pathOutOfCallable1(mid, call, kind, cc, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -2345,22 +2517,23 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa ) { exists(ArgumentNode arg | arg = mid.getNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and - ap = mid.getAp() + ap = mid.getAp() and + apa = ap.getApprox() ) } pragma[noinline] private predicate parameterCand( - DataFlowCallable callable, int i, AccessPath ap, Configuration config + DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { exists(ParameterNode p | - flow(p, _, _, ap, config) and + flow(p, _, _, apa, config) and p.isParameterOf(callable, i) ) } @@ -2370,9 +2543,11 @@ private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, AccessPath ap ) { - pathIntoArg(mid, i, outercc, call, ap) and - callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), ap, mid.getConfiguration()) + exists(AccessPathApprox apa | + pathIntoArg(mid, i, outercc, call, ap, apa) and + callable = resolveCall(call, outercc) and + parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + ) } /** @@ -2403,7 +2578,8 @@ private predicate pathIntoCallable( /** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */ pragma[nomagic] private predicate paramFlowsThrough( - ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config + ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(PathNodeMid mid, ReturnNodeExt ret, int pos | mid.getNode() = ret and @@ -2412,6 +2588,7 @@ private predicate paramFlowsThrough( sc = mid.getSummaryCtx() and config = mid.getConfiguration() and ap = mid.getAp() and + apa = ap.getApprox() and pos = sc.getParameterPos() and not kind.(ParamUpdateReturnKind).getPosition() = pos ) @@ -2419,11 +2596,12 @@ private predicate paramFlowsThrough( pragma[nomagic] private predicate pathThroughCallable0( - DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap + DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, + AccessPathApprox apa ) { exists(CallContext innercc, SummaryCtx sc | pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, unbind(mid.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration())) ) } @@ -2433,9 +2611,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind | - pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | + pathThroughCallable0(call, mid, kind, cc, ap, apa) and + out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration())) ) } @@ -2521,10 +2699,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2533,7 +2711,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2544,7 +2722,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2562,15 +2740,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2591,7 +2769,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2608,7 +2786,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2721,7 +2899,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2737,7 +2915,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2746,11 +2924,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2769,35 +2948,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( @@ -2806,7 +2992,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index f876c04d6c66..8bc3d75ff86e 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -286,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -318,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -417,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -447,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -566,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -748,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -781,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -896,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -930,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1046,11 +1051,22 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1058,9 +1074,9 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1074,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1108,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1122,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1154,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1183,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1197,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1223,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1261,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } +pragma[nomagic] +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + pragma[nomagic] private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1385,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1417,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1497,24 +1523,24 @@ private predicate flowCandIsReturned( ) } -private newtype TAccessPath = +private newtype TAccessPathApprox = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two - * elements of the list and its length are tracked. If data flows from a source to - * a given node with a given `AccessPath`, this indicates the sequence 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. + * Conceptually a list of `TypedContent`s followed by a `DataFlowType`, but only + * the first two elements of the list and its length are tracked. If data flows + * from a source to a given node with a given `AccessPathApprox`, this indicates + * the sequence 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 { +abstract private class AccessPathApprox extends TAccessPathApprox { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1522,20 +1548,18 @@ abstract private class AccessPath extends TAccessPath { abstract AccessPathFront getFront(); - /** - * Holds if this access path has `head` at the front and may be followed by `tail`. - */ - abstract predicate pop(Content head, AccessPath tail); + /** Gets the access path obtained by popping `head` from this path, if any. */ + abstract AccessPathApprox pop(TypedContent head); } -private class AccessPathNil extends AccessPath, TNil { +private class AccessPathApproxNil extends AccessPathApprox, TNil { private DataFlowType t; - AccessPathNil() { this = TNil(t) } + AccessPathApproxNil() { this = TNil(t) } override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1543,258 +1567,285 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override AccessPathApprox pop(TypedContent head) { none() } } -abstract private class AccessPathCons extends AccessPath { } +abstract private class AccessPathApproxCons extends AccessPathApprox { } -private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; +private class AccessPathApproxConsNil extends AccessPathApproxCons, TConsNil { + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathApproxConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override AccessPathApprox pop(TypedContent head) { head = tc and result = TNil(t) } } -private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; +private class AccessPathApproxConsCons extends AccessPathApproxCons, TConsCons { + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathApproxConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override AccessPathApprox pop(TypedContent head) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + result = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + result = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPathApprox pop(TypedContent tc, AccessPathApprox apa) { result = apa.pop(tc) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPathApprox push(TypedContent tc, AccessPathApprox apa) { apa = pop(tc, result) } -private newtype TAccessPathOption = - TAccessPathNone() or - TAccessPathSome(AccessPath ap) +private newtype TAccessPathApproxOption = + TAccessPathApproxNone() or + TAccessPathApproxSome(AccessPathApprox apa) -private class AccessPathOption extends TAccessPathOption { +private class AccessPathApproxOption extends TAccessPathApproxOption { string toString() { - this = TAccessPathNone() and result = "" + this = TAccessPathApproxNone() and result = "" or - this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + this = TAccessPathApproxSome(any(AccessPathApprox apa | result = apa.toString())) } } /** - * Holds if `node` is reachable with access path `ap` from a source in - * the configuration `config`. + * Holds if `node` is reachable with approximate access path `apa` from a source + * in the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an - * argument in a call, and if so, `argAp` records the access path of that - * argument. + * The call context `cc` records whether the node is reached through an + * argument in a call, and if so, `argApa` records the approximate access path + * of that argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argApa, apf, apa, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, apf, apa, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and - apf = ap.(AccessPathNil).getFront() + exists(Node mid, AccessPathApproxNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and + apf = apa.(AccessPathApproxNil).getFront() ) or exists(Node mid | - flowFwd(mid, _, _, apf, ap, config) and + flowFwd(mid, _, _, apf, apa, config) and jumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | + exists(Node mid, AccessPathApproxNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, apa), apf, cc, argApa, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, apa), apf, cc, argApa, config) and + flowFwdConsCand(tc, apf, apa, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, _, cc, _, apf, apa, config) and if flowCand(node, true, _, apf, config) - then argAp = TAccessPathSome(ap) - else argAp = TAccessPathNone() + then argApa = TAccessPathApproxSome(apa) + else argApa = TAccessPathApproxNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argApa, apf, apa, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or - exists(AccessPath argAp0 | - flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + exists(AccessPathApprox argApa0 | + flowFwdOutFromArg(call, node, argApa0, apf, apa, config) and + flowFwdIsEntered(call, cc, argApa, argApa0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argApa, apf, apa, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - AccessPathOption argAp, Configuration config + Node node, TypedContent tc, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwd(mid, cc, argApa, apf0, apa0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPathApprox apa0, Node node2, + CallContext cc, AccessPathApproxOption argApa, Configuration config +) { + flowFwd(node1, cc, argApa, apf0, apa0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + pragma[nomagic] private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config + Node node, AccessPathFrontHead apf0, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, apa0, node, cc, argApa, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(Node n | - flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwd(n, _, _, apf, apa, config) and + flowFwdStore0(n, tc, _, apf, _, config) ) } pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argApa, apf, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argApa, apf, apa, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOutFromArg( - DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + DataFlowCall call, Node node, AccessPathApprox argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathApproxSome(argApa), apf, apa, + config) } /** @@ -1802,166 +1853,174 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathApproxOption argApa, AccessPathApprox apa, + Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argApa, apf, apa, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if `node` with access path `ap` is part of a path from a source to - * a sink in the configuration `config`. + * Holds if `node` with approximate access path `apa` is part of a path from a + * source to a sink in the configuration `config`. * * The Boolean `toReturn` records whether the node must be returned from - * the enclosing callable in order to reach a sink, and if so, `returnAp` - * records the access path of the returned value. + * the enclosing callable in order to reach a sink, and if so, `returnApa` + * records the approximate access path of the returned value. */ private predicate flow( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flow0(node, toReturn, returnAp, ap, config) and - flowFwd(node, _, _, _, ap, config) + flow0(node, toReturn, returnApa, apa, config) and + flowFwd(node, _, _, _, apa, config) } private predicate flow0( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flowFwd(node, _, _, _, ap, config) and + flowFwd(node, _, _, _, apa, config) and config.isSink(node) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil or exists(Node mid | localFlowBigStep(node, mid, true, _, config, _) and - flow(mid, toReturn, returnAp, ap, config) + flow(mid, toReturn, returnApa, apa, config) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and localFlowBigStep(node, mid, false, _, config, _) and - flow(mid, toReturn, returnAp, nil, config) and - ap instanceof AccessPathNil + flow(mid, toReturn, returnApa, nil, config) and + apa instanceof AccessPathApproxNil ) or exists(Node mid | jumpStep(node, mid, config) and - flow(mid, _, _, ap, config) and + flow(mid, _, _, apa, config) and toReturn = false and - returnAp = TAccessPathNone() + returnApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and additionalJumpStep(node, mid, config) and flow(mid, _, _, nil, config) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnApa, apa, config) and + flowConsCand(tc, apa, config) ) or // read - exists(Node mid, AccessPath ap0 | - readFlowFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + readFlowFwd(node, _, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) or // flow into a callable exists(DataFlowCall call | - flowIn(call, node, toReturn, returnAp, ap, config) and + flowIn(call, node, toReturn, returnApa, apa, config) and toReturn = false or - exists(AccessPath returnAp0 | - flowInToReturn(call, node, returnAp0, ap, config) and - flowIsReturned(call, toReturn, returnAp, returnAp0, config) + exists(AccessPathApprox returnApa0 | + flowInToReturn(call, node, returnApa0, apa, config) and + flowIsReturned(call, toReturn, returnApa, returnApa0, config) ) ) or // flow out of a callable - flowOut(_, node, _, _, ap, config) and + flowOut(_, node, _, _, apa, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) - then returnAp = TAccessPathSome(ap) - else returnAp = TAccessPathNone() + if flowFwd(node, any(CallContextCall ccc), TAccessPathApproxSome(_), _, apa, config) + then returnApa = TAccessPathApproxSome(apa) + else returnApa = TAccessPathApproxNone() } pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, apa, _, _, _, config) and + apa0 = push(tc, apa) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { - exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + storeFlowFwd(node, tc, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, apa, _, _, _, config) and + apa0 = pop(tc, apa) and + flowFwdConsCand(tc, _, apa0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPathApprox apa, Configuration config) { exists(Node n, Node mid | - flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + flow(mid, _, _, apa, config) and + readFlowFwd(n, tc, mid, _, apa, config) ) } pragma[nomagic] private predicate flowOut( - DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(Node out, boolean allowsFieldFlow | - flow(out, toReturn, returnAp, ap, config) and + flow(out, toReturn, returnApa, apa, config) and flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowIn( - DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(ParameterNode p, boolean allowsFieldFlow | - flow(p, toReturn, returnAp, ap, config) and + flow(p, toReturn, returnApa, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowInToReturn( - DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config + DataFlowCall call, ArgumentNode arg, AccessPathApprox returnApa, AccessPathApprox apa, + Configuration config ) { - flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) + flowIn(call, arg, true, TAccessPathApproxSome(returnApa), apa, config) } /** @@ -1969,12 +2028,13 @@ private predicate flowInToReturn( */ pragma[nomagic] private predicate flowIsReturned( - DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + DataFlowCall call, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, Configuration config ) { - exists(ReturnNodeExt ret | - flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + exists(ReturnNodeExt ret, CallContextCall ccc | + flowOut(call, ret, toReturn, returnApa, apa, config) and + flowFwd(ret, ccc, TAccessPathApproxSome(_), _, apa, config) and + ccc.matchesCall(call) ) } @@ -1985,21 +2045,23 @@ private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) pragma[noinline] private predicate parameterFlow( - ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config + ParameterNode p, AccessPathApprox apa, DataFlowCallable c, Configuration config ) { - flow(p, true, _, ap, config) and + flow(p, true, _, apa, config) and c = p.getEnclosingCallable() } +private predicate parameterMayFlowThrough(ParameterNode p, AccessPathApprox apa) { + exists(ReturnNodeExt ret, Configuration config, AccessPathApprox apa0 | + parameterFlow(p, apa, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathApproxSome(_), apa0, config) and + flowFwd(ret, any(CallContextCall ccc), TAccessPathApproxSome(apa), _, apa0, config) + ) +} + private newtype TSummaryCtx = TSummaryCtxNone() or - TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | - parameterFlow(p, ap, ret.getEnclosingCallable(), config) and - flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) - ) - } + TSummaryCtxSome(ParameterNode p, AccessPath ap) { parameterMayFlowThrough(p, ap.getApprox()) } /** * A context for generating flow summaries. This represents flow entry through @@ -2034,6 +2096,10 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { } } +private newtype TAccessPath = + TAccessPathNil(DataFlowType t) or + TAccessPathCons(TypedContent head, AccessPath tail) { flowConsCand(head, tail.getApprox(), _) } + private newtype TPathNode = TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) { // A PathNode is introduced by a source ... @@ -2041,13 +2107,13 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(node, _, _, ap, unbind(config)) + flow(node, _, _, ap.getApprox(), unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2059,12 +2125,99 @@ private newtype TPathNode = or // ... or a sink that can be reached from a source exists(PathNodeMid mid | - pathStep(mid, node, _, _, any(AccessPathNil nil)) and + pathStep(mid, node, _, _, TAccessPathNil(_)) and config = unbind(mid.getConfiguration()) ) ) } +/** + * A list of `TypedContent`s followed by a `DataFlowType`. If data flows from a + * source to a given node with a given `AccessPath`, this indicates the sequence + * 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 { + /** Gets the head of this access path, if any. */ + abstract TypedContent getHead(); + + /** Gets the tail of this access path, if any. */ + abstract AccessPath getTail(); + + /** Gets the front of this access path. */ + abstract AccessPathFront getFront(); + + /** Gets the approximation of this access path. */ + abstract AccessPathApprox getApprox(); + + /** Gets the length of this access path. */ + abstract int length(); + + /** Gets a textual representation of this access path. */ + abstract string toString(); + + /** Gets the access path obtained by popping `tc` from this access path, if any. */ + final AccessPath pop(TypedContent tc) { + result = this.getTail() and + tc = this.getHead() + } + + /** Gets the access path obtained by pushing `tc` onto this access path. */ + final AccessPath push(TypedContent tc) { this = result.pop(tc) } +} + +private class AccessPathNil extends AccessPath, TAccessPathNil { + private DataFlowType t; + + AccessPathNil() { this = TAccessPathNil(t) } + + DataFlowType getType() { result = t } + + override TypedContent getHead() { none() } + + override AccessPath getTail() { none() } + + override AccessPathFrontNil getFront() { result = TFrontNil(t) } + + override AccessPathApproxNil getApprox() { result = TNil(t) } + + override int length() { result = 0 } + + override string toString() { result = concat(": " + ppReprType(t)) } +} + +private class AccessPathCons extends AccessPath, TAccessPathCons { + private TypedContent head; + private AccessPath tail; + + AccessPathCons() { this = TAccessPathCons(head, tail) } + + override TypedContent getHead() { result = head } + + override AccessPath getTail() { result = tail } + + override AccessPathFrontHead getFront() { result = TFrontHead(head) } + + override AccessPathApproxCons getApprox() { + result = TConsNil(head, tail.(AccessPathNil).getType()) + or + result = TConsCons(head, tail.getHead(), this.length()) + } + + override int length() { result = 1 + tail.length() } + + private string toStringImpl() { + exists(DataFlowType t | + tail = TAccessPathNil(t) and + result = head.toString() + "]" + concat(" : " + ppReprType(t)) + ) + or + result = head + ", " + tail.(AccessPathCons).toStringImpl() + } + + override string toString() { result = "[" + this.toStringImpl() } +} + /** * A `Node` augmented with a call context (except for sinks), an access path, and a configuration. * Only those `PathNode`s that are reachable from a source are generated. @@ -2098,14 +2251,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2350,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2387,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2251,12 +2421,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2267,50 +2437,53 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } private predicate pathOutOfCallable0( - PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPath ap, Configuration config + PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa, + Configuration config ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and - ap = mid.getAp() and + innercc instanceof CallContextNoCall and + apa = mid.getAp().getApprox() and config = mid.getConfiguration() } pragma[nomagic] private predicate pathOutOfCallable1( - PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPath ap, + PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPathApprox apa, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | - pathOutOfCallable0(mid, pos, innercc, ap, config) and + pathOutOfCallable0(mid, pos, innercc, apa, config) and c = pos.getCallable() and kind = pos.getKind() and resolveReturn(innercc, c, call) @@ -2321,10 +2494,10 @@ private predicate pathOutOfCallable1( pragma[noinline] private Node getAnOutNodeFlow( - ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config + ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ) { result = kind.getAnOutNode(call) and - flow(result, _, _, ap, config) + flow(result, _, _, apa, config) } /** @@ -2333,10 +2506,9 @@ private Node getAnOutNodeFlow( */ pragma[noinline] private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { - exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | - pathOutOfCallable1(mid, call, kind, cc, ap, config) - | - out = getAnOutNodeFlow(kind, call, ap, config) + exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config | + pathOutOfCallable1(mid, call, kind, cc, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -2345,22 +2517,23 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa ) { exists(ArgumentNode arg | arg = mid.getNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and - ap = mid.getAp() + ap = mid.getAp() and + apa = ap.getApprox() ) } pragma[noinline] private predicate parameterCand( - DataFlowCallable callable, int i, AccessPath ap, Configuration config + DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { exists(ParameterNode p | - flow(p, _, _, ap, config) and + flow(p, _, _, apa, config) and p.isParameterOf(callable, i) ) } @@ -2370,9 +2543,11 @@ private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, AccessPath ap ) { - pathIntoArg(mid, i, outercc, call, ap) and - callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), ap, mid.getConfiguration()) + exists(AccessPathApprox apa | + pathIntoArg(mid, i, outercc, call, ap, apa) and + callable = resolveCall(call, outercc) and + parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + ) } /** @@ -2403,7 +2578,8 @@ private predicate pathIntoCallable( /** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */ pragma[nomagic] private predicate paramFlowsThrough( - ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config + ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(PathNodeMid mid, ReturnNodeExt ret, int pos | mid.getNode() = ret and @@ -2412,6 +2588,7 @@ private predicate paramFlowsThrough( sc = mid.getSummaryCtx() and config = mid.getConfiguration() and ap = mid.getAp() and + apa = ap.getApprox() and pos = sc.getParameterPos() and not kind.(ParamUpdateReturnKind).getPosition() = pos ) @@ -2419,11 +2596,12 @@ private predicate paramFlowsThrough( pragma[nomagic] private predicate pathThroughCallable0( - DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap + DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, + AccessPathApprox apa ) { exists(CallContext innercc, SummaryCtx sc | pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, unbind(mid.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration())) ) } @@ -2433,9 +2611,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind | - pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | + pathThroughCallable0(call, mid, kind, cc, ap, apa) and + out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration())) ) } @@ -2521,10 +2699,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2533,7 +2711,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2544,7 +2722,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2562,15 +2740,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2591,7 +2769,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2608,7 +2786,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2721,7 +2899,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2737,7 +2915,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2746,11 +2924,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2769,35 +2948,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( @@ -2806,7 +2992,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index f876c04d6c66..8bc3d75ff86e 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -286,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -318,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -417,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -447,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -566,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -748,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -781,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -896,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -930,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1046,11 +1051,22 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1058,9 +1074,9 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1074,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1108,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1122,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1154,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1183,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1197,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1223,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1261,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } +pragma[nomagic] +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + pragma[nomagic] private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1385,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1417,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1497,24 +1523,24 @@ private predicate flowCandIsReturned( ) } -private newtype TAccessPath = +private newtype TAccessPathApprox = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two - * elements of the list and its length are tracked. If data flows from a source to - * a given node with a given `AccessPath`, this indicates the sequence 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. + * Conceptually a list of `TypedContent`s followed by a `DataFlowType`, but only + * the first two elements of the list and its length are tracked. If data flows + * from a source to a given node with a given `AccessPathApprox`, this indicates + * the sequence 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 { +abstract private class AccessPathApprox extends TAccessPathApprox { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1522,20 +1548,18 @@ abstract private class AccessPath extends TAccessPath { abstract AccessPathFront getFront(); - /** - * Holds if this access path has `head` at the front and may be followed by `tail`. - */ - abstract predicate pop(Content head, AccessPath tail); + /** Gets the access path obtained by popping `head` from this path, if any. */ + abstract AccessPathApprox pop(TypedContent head); } -private class AccessPathNil extends AccessPath, TNil { +private class AccessPathApproxNil extends AccessPathApprox, TNil { private DataFlowType t; - AccessPathNil() { this = TNil(t) } + AccessPathApproxNil() { this = TNil(t) } override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1543,258 +1567,285 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override AccessPathApprox pop(TypedContent head) { none() } } -abstract private class AccessPathCons extends AccessPath { } +abstract private class AccessPathApproxCons extends AccessPathApprox { } -private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; +private class AccessPathApproxConsNil extends AccessPathApproxCons, TConsNil { + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathApproxConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override AccessPathApprox pop(TypedContent head) { head = tc and result = TNil(t) } } -private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; +private class AccessPathApproxConsCons extends AccessPathApproxCons, TConsCons { + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathApproxConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override AccessPathApprox pop(TypedContent head) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + result = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + result = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPathApprox pop(TypedContent tc, AccessPathApprox apa) { result = apa.pop(tc) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPathApprox push(TypedContent tc, AccessPathApprox apa) { apa = pop(tc, result) } -private newtype TAccessPathOption = - TAccessPathNone() or - TAccessPathSome(AccessPath ap) +private newtype TAccessPathApproxOption = + TAccessPathApproxNone() or + TAccessPathApproxSome(AccessPathApprox apa) -private class AccessPathOption extends TAccessPathOption { +private class AccessPathApproxOption extends TAccessPathApproxOption { string toString() { - this = TAccessPathNone() and result = "" + this = TAccessPathApproxNone() and result = "" or - this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + this = TAccessPathApproxSome(any(AccessPathApprox apa | result = apa.toString())) } } /** - * Holds if `node` is reachable with access path `ap` from a source in - * the configuration `config`. + * Holds if `node` is reachable with approximate access path `apa` from a source + * in the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an - * argument in a call, and if so, `argAp` records the access path of that - * argument. + * The call context `cc` records whether the node is reached through an + * argument in a call, and if so, `argApa` records the approximate access path + * of that argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argApa, apf, apa, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, apf, apa, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and - apf = ap.(AccessPathNil).getFront() + exists(Node mid, AccessPathApproxNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and + apf = apa.(AccessPathApproxNil).getFront() ) or exists(Node mid | - flowFwd(mid, _, _, apf, ap, config) and + flowFwd(mid, _, _, apf, apa, config) and jumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | + exists(Node mid, AccessPathApproxNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, apa), apf, cc, argApa, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, apa), apf, cc, argApa, config) and + flowFwdConsCand(tc, apf, apa, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, _, cc, _, apf, apa, config) and if flowCand(node, true, _, apf, config) - then argAp = TAccessPathSome(ap) - else argAp = TAccessPathNone() + then argApa = TAccessPathApproxSome(apa) + else argApa = TAccessPathApproxNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argApa, apf, apa, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or - exists(AccessPath argAp0 | - flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + exists(AccessPathApprox argApa0 | + flowFwdOutFromArg(call, node, argApa0, apf, apa, config) and + flowFwdIsEntered(call, cc, argApa, argApa0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argApa, apf, apa, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - AccessPathOption argAp, Configuration config + Node node, TypedContent tc, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwd(mid, cc, argApa, apf0, apa0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPathApprox apa0, Node node2, + CallContext cc, AccessPathApproxOption argApa, Configuration config +) { + flowFwd(node1, cc, argApa, apf0, apa0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + pragma[nomagic] private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config + Node node, AccessPathFrontHead apf0, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, apa0, node, cc, argApa, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(Node n | - flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwd(n, _, _, apf, apa, config) and + flowFwdStore0(n, tc, _, apf, _, config) ) } pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argApa, apf, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argApa, apf, apa, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOutFromArg( - DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + DataFlowCall call, Node node, AccessPathApprox argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathApproxSome(argApa), apf, apa, + config) } /** @@ -1802,166 +1853,174 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathApproxOption argApa, AccessPathApprox apa, + Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argApa, apf, apa, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if `node` with access path `ap` is part of a path from a source to - * a sink in the configuration `config`. + * Holds if `node` with approximate access path `apa` is part of a path from a + * source to a sink in the configuration `config`. * * The Boolean `toReturn` records whether the node must be returned from - * the enclosing callable in order to reach a sink, and if so, `returnAp` - * records the access path of the returned value. + * the enclosing callable in order to reach a sink, and if so, `returnApa` + * records the approximate access path of the returned value. */ private predicate flow( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flow0(node, toReturn, returnAp, ap, config) and - flowFwd(node, _, _, _, ap, config) + flow0(node, toReturn, returnApa, apa, config) and + flowFwd(node, _, _, _, apa, config) } private predicate flow0( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flowFwd(node, _, _, _, ap, config) and + flowFwd(node, _, _, _, apa, config) and config.isSink(node) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil or exists(Node mid | localFlowBigStep(node, mid, true, _, config, _) and - flow(mid, toReturn, returnAp, ap, config) + flow(mid, toReturn, returnApa, apa, config) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and localFlowBigStep(node, mid, false, _, config, _) and - flow(mid, toReturn, returnAp, nil, config) and - ap instanceof AccessPathNil + flow(mid, toReturn, returnApa, nil, config) and + apa instanceof AccessPathApproxNil ) or exists(Node mid | jumpStep(node, mid, config) and - flow(mid, _, _, ap, config) and + flow(mid, _, _, apa, config) and toReturn = false and - returnAp = TAccessPathNone() + returnApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and additionalJumpStep(node, mid, config) and flow(mid, _, _, nil, config) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnApa, apa, config) and + flowConsCand(tc, apa, config) ) or // read - exists(Node mid, AccessPath ap0 | - readFlowFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + readFlowFwd(node, _, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) or // flow into a callable exists(DataFlowCall call | - flowIn(call, node, toReturn, returnAp, ap, config) and + flowIn(call, node, toReturn, returnApa, apa, config) and toReturn = false or - exists(AccessPath returnAp0 | - flowInToReturn(call, node, returnAp0, ap, config) and - flowIsReturned(call, toReturn, returnAp, returnAp0, config) + exists(AccessPathApprox returnApa0 | + flowInToReturn(call, node, returnApa0, apa, config) and + flowIsReturned(call, toReturn, returnApa, returnApa0, config) ) ) or // flow out of a callable - flowOut(_, node, _, _, ap, config) and + flowOut(_, node, _, _, apa, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) - then returnAp = TAccessPathSome(ap) - else returnAp = TAccessPathNone() + if flowFwd(node, any(CallContextCall ccc), TAccessPathApproxSome(_), _, apa, config) + then returnApa = TAccessPathApproxSome(apa) + else returnApa = TAccessPathApproxNone() } pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, apa, _, _, _, config) and + apa0 = push(tc, apa) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { - exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + storeFlowFwd(node, tc, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, apa, _, _, _, config) and + apa0 = pop(tc, apa) and + flowFwdConsCand(tc, _, apa0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPathApprox apa, Configuration config) { exists(Node n, Node mid | - flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + flow(mid, _, _, apa, config) and + readFlowFwd(n, tc, mid, _, apa, config) ) } pragma[nomagic] private predicate flowOut( - DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(Node out, boolean allowsFieldFlow | - flow(out, toReturn, returnAp, ap, config) and + flow(out, toReturn, returnApa, apa, config) and flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowIn( - DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(ParameterNode p, boolean allowsFieldFlow | - flow(p, toReturn, returnAp, ap, config) and + flow(p, toReturn, returnApa, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowInToReturn( - DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config + DataFlowCall call, ArgumentNode arg, AccessPathApprox returnApa, AccessPathApprox apa, + Configuration config ) { - flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) + flowIn(call, arg, true, TAccessPathApproxSome(returnApa), apa, config) } /** @@ -1969,12 +2028,13 @@ private predicate flowInToReturn( */ pragma[nomagic] private predicate flowIsReturned( - DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + DataFlowCall call, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, Configuration config ) { - exists(ReturnNodeExt ret | - flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + exists(ReturnNodeExt ret, CallContextCall ccc | + flowOut(call, ret, toReturn, returnApa, apa, config) and + flowFwd(ret, ccc, TAccessPathApproxSome(_), _, apa, config) and + ccc.matchesCall(call) ) } @@ -1985,21 +2045,23 @@ private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) pragma[noinline] private predicate parameterFlow( - ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config + ParameterNode p, AccessPathApprox apa, DataFlowCallable c, Configuration config ) { - flow(p, true, _, ap, config) and + flow(p, true, _, apa, config) and c = p.getEnclosingCallable() } +private predicate parameterMayFlowThrough(ParameterNode p, AccessPathApprox apa) { + exists(ReturnNodeExt ret, Configuration config, AccessPathApprox apa0 | + parameterFlow(p, apa, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathApproxSome(_), apa0, config) and + flowFwd(ret, any(CallContextCall ccc), TAccessPathApproxSome(apa), _, apa0, config) + ) +} + private newtype TSummaryCtx = TSummaryCtxNone() or - TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | - parameterFlow(p, ap, ret.getEnclosingCallable(), config) and - flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) - ) - } + TSummaryCtxSome(ParameterNode p, AccessPath ap) { parameterMayFlowThrough(p, ap.getApprox()) } /** * A context for generating flow summaries. This represents flow entry through @@ -2034,6 +2096,10 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { } } +private newtype TAccessPath = + TAccessPathNil(DataFlowType t) or + TAccessPathCons(TypedContent head, AccessPath tail) { flowConsCand(head, tail.getApprox(), _) } + private newtype TPathNode = TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) { // A PathNode is introduced by a source ... @@ -2041,13 +2107,13 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(node, _, _, ap, unbind(config)) + flow(node, _, _, ap.getApprox(), unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2059,12 +2125,99 @@ private newtype TPathNode = or // ... or a sink that can be reached from a source exists(PathNodeMid mid | - pathStep(mid, node, _, _, any(AccessPathNil nil)) and + pathStep(mid, node, _, _, TAccessPathNil(_)) and config = unbind(mid.getConfiguration()) ) ) } +/** + * A list of `TypedContent`s followed by a `DataFlowType`. If data flows from a + * source to a given node with a given `AccessPath`, this indicates the sequence + * 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 { + /** Gets the head of this access path, if any. */ + abstract TypedContent getHead(); + + /** Gets the tail of this access path, if any. */ + abstract AccessPath getTail(); + + /** Gets the front of this access path. */ + abstract AccessPathFront getFront(); + + /** Gets the approximation of this access path. */ + abstract AccessPathApprox getApprox(); + + /** Gets the length of this access path. */ + abstract int length(); + + /** Gets a textual representation of this access path. */ + abstract string toString(); + + /** Gets the access path obtained by popping `tc` from this access path, if any. */ + final AccessPath pop(TypedContent tc) { + result = this.getTail() and + tc = this.getHead() + } + + /** Gets the access path obtained by pushing `tc` onto this access path. */ + final AccessPath push(TypedContent tc) { this = result.pop(tc) } +} + +private class AccessPathNil extends AccessPath, TAccessPathNil { + private DataFlowType t; + + AccessPathNil() { this = TAccessPathNil(t) } + + DataFlowType getType() { result = t } + + override TypedContent getHead() { none() } + + override AccessPath getTail() { none() } + + override AccessPathFrontNil getFront() { result = TFrontNil(t) } + + override AccessPathApproxNil getApprox() { result = TNil(t) } + + override int length() { result = 0 } + + override string toString() { result = concat(": " + ppReprType(t)) } +} + +private class AccessPathCons extends AccessPath, TAccessPathCons { + private TypedContent head; + private AccessPath tail; + + AccessPathCons() { this = TAccessPathCons(head, tail) } + + override TypedContent getHead() { result = head } + + override AccessPath getTail() { result = tail } + + override AccessPathFrontHead getFront() { result = TFrontHead(head) } + + override AccessPathApproxCons getApprox() { + result = TConsNil(head, tail.(AccessPathNil).getType()) + or + result = TConsCons(head, tail.getHead(), this.length()) + } + + override int length() { result = 1 + tail.length() } + + private string toStringImpl() { + exists(DataFlowType t | + tail = TAccessPathNil(t) and + result = head.toString() + "]" + concat(" : " + ppReprType(t)) + ) + or + result = head + ", " + tail.(AccessPathCons).toStringImpl() + } + + override string toString() { result = "[" + this.toStringImpl() } +} + /** * A `Node` augmented with a call context (except for sinks), an access path, and a configuration. * Only those `PathNode`s that are reachable from a source are generated. @@ -2098,14 +2251,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2350,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2387,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2251,12 +2421,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2267,50 +2437,53 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } private predicate pathOutOfCallable0( - PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPath ap, Configuration config + PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa, + Configuration config ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and - ap = mid.getAp() and + innercc instanceof CallContextNoCall and + apa = mid.getAp().getApprox() and config = mid.getConfiguration() } pragma[nomagic] private predicate pathOutOfCallable1( - PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPath ap, + PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPathApprox apa, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | - pathOutOfCallable0(mid, pos, innercc, ap, config) and + pathOutOfCallable0(mid, pos, innercc, apa, config) and c = pos.getCallable() and kind = pos.getKind() and resolveReturn(innercc, c, call) @@ -2321,10 +2494,10 @@ private predicate pathOutOfCallable1( pragma[noinline] private Node getAnOutNodeFlow( - ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config + ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ) { result = kind.getAnOutNode(call) and - flow(result, _, _, ap, config) + flow(result, _, _, apa, config) } /** @@ -2333,10 +2506,9 @@ private Node getAnOutNodeFlow( */ pragma[noinline] private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { - exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | - pathOutOfCallable1(mid, call, kind, cc, ap, config) - | - out = getAnOutNodeFlow(kind, call, ap, config) + exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config | + pathOutOfCallable1(mid, call, kind, cc, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -2345,22 +2517,23 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa ) { exists(ArgumentNode arg | arg = mid.getNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and - ap = mid.getAp() + ap = mid.getAp() and + apa = ap.getApprox() ) } pragma[noinline] private predicate parameterCand( - DataFlowCallable callable, int i, AccessPath ap, Configuration config + DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { exists(ParameterNode p | - flow(p, _, _, ap, config) and + flow(p, _, _, apa, config) and p.isParameterOf(callable, i) ) } @@ -2370,9 +2543,11 @@ private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, AccessPath ap ) { - pathIntoArg(mid, i, outercc, call, ap) and - callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), ap, mid.getConfiguration()) + exists(AccessPathApprox apa | + pathIntoArg(mid, i, outercc, call, ap, apa) and + callable = resolveCall(call, outercc) and + parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + ) } /** @@ -2403,7 +2578,8 @@ private predicate pathIntoCallable( /** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */ pragma[nomagic] private predicate paramFlowsThrough( - ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config + ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(PathNodeMid mid, ReturnNodeExt ret, int pos | mid.getNode() = ret and @@ -2412,6 +2588,7 @@ private predicate paramFlowsThrough( sc = mid.getSummaryCtx() and config = mid.getConfiguration() and ap = mid.getAp() and + apa = ap.getApprox() and pos = sc.getParameterPos() and not kind.(ParamUpdateReturnKind).getPosition() = pos ) @@ -2419,11 +2596,12 @@ private predicate paramFlowsThrough( pragma[nomagic] private predicate pathThroughCallable0( - DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap + DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, + AccessPathApprox apa ) { exists(CallContext innercc, SummaryCtx sc | pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, unbind(mid.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration())) ) } @@ -2433,9 +2611,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind | - pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | + pathThroughCallable0(call, mid, kind, cc, ap, apa) and + out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration())) ) } @@ -2521,10 +2699,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2533,7 +2711,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2544,7 +2722,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2562,15 +2740,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2591,7 +2769,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2608,7 +2786,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2721,7 +2899,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2737,7 +2915,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2746,11 +2924,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2769,35 +2948,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( @@ -2806,7 +2992,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index f876c04d6c66..8bc3d75ff86e 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -286,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -318,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -417,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -447,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -566,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -748,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -781,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -896,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -930,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1046,11 +1051,22 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1058,9 +1074,9 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1074,11 +1090,11 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1108,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1122,16 +1138,16 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1154,19 +1170,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1183,9 +1201,8 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + not apf.isClearedAt(node) and + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1197,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1223,21 +1240,22 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1261,24 +1279,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } +pragma[nomagic] +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + pragma[nomagic] private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1385,17 +1409,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1417,36 +1439,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1497,24 +1523,24 @@ private predicate flowCandIsReturned( ) } -private newtype TAccessPath = +private newtype TAccessPathApprox = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two - * elements of the list and its length are tracked. If data flows from a source to - * a given node with a given `AccessPath`, this indicates the sequence 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. + * Conceptually a list of `TypedContent`s followed by a `DataFlowType`, but only + * the first two elements of the list and its length are tracked. If data flows + * from a source to a given node with a given `AccessPathApprox`, this indicates + * the sequence 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 { +abstract private class AccessPathApprox extends TAccessPathApprox { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1522,20 +1548,18 @@ abstract private class AccessPath extends TAccessPath { abstract AccessPathFront getFront(); - /** - * Holds if this access path has `head` at the front and may be followed by `tail`. - */ - abstract predicate pop(Content head, AccessPath tail); + /** Gets the access path obtained by popping `head` from this path, if any. */ + abstract AccessPathApprox pop(TypedContent head); } -private class AccessPathNil extends AccessPath, TNil { +private class AccessPathApproxNil extends AccessPathApprox, TNil { private DataFlowType t; - AccessPathNil() { this = TNil(t) } + AccessPathApproxNil() { this = TNil(t) } override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1543,258 +1567,285 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override AccessPathApprox pop(TypedContent head) { none() } } -abstract private class AccessPathCons extends AccessPath { } +abstract private class AccessPathApproxCons extends AccessPathApprox { } -private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; +private class AccessPathApproxConsNil extends AccessPathApproxCons, TConsNil { + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathApproxConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override AccessPathApprox pop(TypedContent head) { head = tc and result = TNil(t) } } -private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; +private class AccessPathApproxConsCons extends AccessPathApproxCons, TConsCons { + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathApproxConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override AccessPathApprox pop(TypedContent head) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + result = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + result = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPathApprox pop(TypedContent tc, AccessPathApprox apa) { result = apa.pop(tc) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPathApprox push(TypedContent tc, AccessPathApprox apa) { apa = pop(tc, result) } -private newtype TAccessPathOption = - TAccessPathNone() or - TAccessPathSome(AccessPath ap) +private newtype TAccessPathApproxOption = + TAccessPathApproxNone() or + TAccessPathApproxSome(AccessPathApprox apa) -private class AccessPathOption extends TAccessPathOption { +private class AccessPathApproxOption extends TAccessPathApproxOption { string toString() { - this = TAccessPathNone() and result = "" + this = TAccessPathApproxNone() and result = "" or - this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + this = TAccessPathApproxSome(any(AccessPathApprox apa | result = apa.toString())) } } /** - * Holds if `node` is reachable with access path `ap` from a source in - * the configuration `config`. + * Holds if `node` is reachable with approximate access path `apa` from a source + * in the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an - * argument in a call, and if so, `argAp` records the access path of that - * argument. + * The call context `cc` records whether the node is reached through an + * argument in a call, and if so, `argApa` records the approximate access path + * of that argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argApa, apf, apa, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, - Configuration config + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, apf, apa, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and - apf = ap.(AccessPathNil).getFront() + exists(Node mid, AccessPathApproxNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argApa, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and + apf = apa.(AccessPathApproxNil).getFront() ) or exists(Node mid | - flowFwd(mid, _, _, apf, ap, config) and + flowFwd(mid, _, _, apf, apa, config) and jumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | + exists(Node mid, AccessPathApproxNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and - argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and - apf = ap.(AccessPathNil).getFront() + cc instanceof CallContextAny and + argApa = TAccessPathApproxNone() and + apa = TNil(getNodeType(node)) and + apf = apa.(AccessPathApproxNil).getFront() ) ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, apa), apf, cc, argApa, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, apa), apf, cc, argApa, config) and + flowFwdConsCand(tc, apf, apa, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, _, cc, _, apf, apa, config) and if flowCand(node, true, _, apf, config) - then argAp = TAccessPathSome(ap) - else argAp = TAccessPathNone() + then argApa = TAccessPathApproxSome(apa) + else argApa = TAccessPathApproxNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argApa, apf, apa, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or - exists(AccessPath argAp0 | - flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + exists(AccessPathApprox argApa0 | + flowFwdOutFromArg(call, node, argApa0, apf, apa, config) and + flowFwdIsEntered(call, cc, argApa, argApa0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathApproxOption argApa, AccessPathFront apf, + AccessPathApprox apa, LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argApa, apf, apa, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - AccessPathOption argAp, Configuration config + Node node, TypedContent tc, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwd(mid, cc, argApa, apf0, apa0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPathApprox apa0, Node node2, + CallContext cc, AccessPathApproxOption argApa, Configuration config +) { + flowFwd(node1, cc, argApa, apf0, apa0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + pragma[nomagic] private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config + Node node, AccessPathFrontHead apf0, AccessPathApprox apa0, AccessPathFront apf, CallContext cc, + AccessPathApproxOption argApa, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, apa0, node, cc, argApa, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(Node n | - flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwd(n, _, _, apf, apa, config) and + flowFwdStore0(n, tc, _, apf, _, config) ) } pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argApa, apf, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathApproxOption argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argApa, apf, apa, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowFwdOutFromArg( - DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + DataFlowCall call, Node node, AccessPathApprox argApa, AccessPathFront apf, AccessPathApprox apa, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathApproxSome(argApa), apf, apa, + config) } /** @@ -1802,166 +1853,174 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathApproxOption argApa, AccessPathApprox apa, + Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argApa, apf, apa, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if `node` with access path `ap` is part of a path from a source to - * a sink in the configuration `config`. + * Holds if `node` with approximate access path `apa` is part of a path from a + * source to a sink in the configuration `config`. * * The Boolean `toReturn` records whether the node must be returned from - * the enclosing callable in order to reach a sink, and if so, `returnAp` - * records the access path of the returned value. + * the enclosing callable in order to reach a sink, and if so, `returnApa` + * records the approximate access path of the returned value. */ private predicate flow( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flow0(node, toReturn, returnAp, ap, config) and - flowFwd(node, _, _, _, ap, config) + flow0(node, toReturn, returnApa, apa, config) and + flowFwd(node, _, _, _, apa, config) } private predicate flow0( - Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config + Node node, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, + Configuration config ) { - flowFwd(node, _, _, _, ap, config) and + flowFwd(node, _, _, _, apa, config) and config.isSink(node) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil or exists(Node mid | localFlowBigStep(node, mid, true, _, config, _) and - flow(mid, toReturn, returnAp, ap, config) + flow(mid, toReturn, returnApa, apa, config) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and localFlowBigStep(node, mid, false, _, config, _) and - flow(mid, toReturn, returnAp, nil, config) and - ap instanceof AccessPathNil + flow(mid, toReturn, returnApa, nil, config) and + apa instanceof AccessPathApproxNil ) or exists(Node mid | jumpStep(node, mid, config) and - flow(mid, _, _, ap, config) and + flow(mid, _, _, apa, config) and toReturn = false and - returnAp = TAccessPathNone() + returnApa = TAccessPathApproxNone() ) or - exists(Node mid, AccessPathNil nil | - flowFwd(node, _, _, _, ap, config) and + exists(Node mid, AccessPathApproxNil nil | + flowFwd(node, _, _, _, apa, config) and additionalJumpStep(node, mid, config) and flow(mid, _, _, nil, config) and toReturn = false and - returnAp = TAccessPathNone() and - ap instanceof AccessPathNil + returnApa = TAccessPathApproxNone() and + apa instanceof AccessPathApproxNil ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnApa, apa, config) and + flowConsCand(tc, apa, config) ) or // read - exists(Node mid, AccessPath ap0 | - readFlowFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + readFlowFwd(node, _, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) or // flow into a callable exists(DataFlowCall call | - flowIn(call, node, toReturn, returnAp, ap, config) and + flowIn(call, node, toReturn, returnApa, apa, config) and toReturn = false or - exists(AccessPath returnAp0 | - flowInToReturn(call, node, returnAp0, ap, config) and - flowIsReturned(call, toReturn, returnAp, returnAp0, config) + exists(AccessPathApprox returnApa0 | + flowInToReturn(call, node, returnApa0, apa, config) and + flowIsReturned(call, toReturn, returnApa, returnApa0, config) ) ) or // flow out of a callable - flowOut(_, node, _, _, ap, config) and + flowOut(_, node, _, _, apa, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) - then returnAp = TAccessPathSome(ap) - else returnAp = TAccessPathNone() + if flowFwd(node, any(CallContextCall ccc), TAccessPathApproxSome(_), _, apa, config) + then returnApa = TAccessPathApproxSome(apa) + else returnApa = TAccessPathApproxNone() } pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, apa, _, _, _, config) and + apa0 = push(tc, apa) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { - exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, returnAp, ap0, config) + exists(Node mid, AccessPathApprox apa0 | + storeFlowFwd(node, tc, mid, apa, apa0, config) and + flow(mid, toReturn, returnApa, apa0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPathApprox apa, AccessPathApprox apa0, + Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, apa, _, _, _, config) and + apa0 = pop(tc, apa) and + flowFwdConsCand(tc, _, apa0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPathApprox apa, Configuration config) { exists(Node n, Node mid | - flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + flow(mid, _, _, apa, config) and + readFlowFwd(n, tc, mid, _, apa, config) ) } pragma[nomagic] private predicate flowOut( - DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(Node out, boolean allowsFieldFlow | - flow(out, toReturn, returnAp, ap, config) and + flow(out, toReturn, returnApa, apa, config) and flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowIn( - DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, - Configuration config + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathApproxOption returnApa, + AccessPathApprox apa, Configuration config ) { exists(ParameterNode p, boolean allowsFieldFlow | - flow(p, toReturn, returnAp, ap, config) and + flow(p, toReturn, returnApa, apa, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | - ap instanceof AccessPathNil or allowsFieldFlow = true + apa instanceof AccessPathApproxNil or allowsFieldFlow = true ) } pragma[nomagic] private predicate flowInToReturn( - DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config + DataFlowCall call, ArgumentNode arg, AccessPathApprox returnApa, AccessPathApprox apa, + Configuration config ) { - flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) + flowIn(call, arg, true, TAccessPathApproxSome(returnApa), apa, config) } /** @@ -1969,12 +2028,13 @@ private predicate flowInToReturn( */ pragma[nomagic] private predicate flowIsReturned( - DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + DataFlowCall call, boolean toReturn, AccessPathApproxOption returnApa, AccessPathApprox apa, Configuration config ) { - exists(ReturnNodeExt ret | - flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + exists(ReturnNodeExt ret, CallContextCall ccc | + flowOut(call, ret, toReturn, returnApa, apa, config) and + flowFwd(ret, ccc, TAccessPathApproxSome(_), _, apa, config) and + ccc.matchesCall(call) ) } @@ -1985,21 +2045,23 @@ private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) pragma[noinline] private predicate parameterFlow( - ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config + ParameterNode p, AccessPathApprox apa, DataFlowCallable c, Configuration config ) { - flow(p, true, _, ap, config) and + flow(p, true, _, apa, config) and c = p.getEnclosingCallable() } +private predicate parameterMayFlowThrough(ParameterNode p, AccessPathApprox apa) { + exists(ReturnNodeExt ret, Configuration config, AccessPathApprox apa0 | + parameterFlow(p, apa, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathApproxSome(_), apa0, config) and + flowFwd(ret, any(CallContextCall ccc), TAccessPathApproxSome(apa), _, apa0, config) + ) +} + private newtype TSummaryCtx = TSummaryCtxNone() or - TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | - parameterFlow(p, ap, ret.getEnclosingCallable(), config) and - flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) - ) - } + TSummaryCtxSome(ParameterNode p, AccessPath ap) { parameterMayFlowThrough(p, ap.getApprox()) } /** * A context for generating flow summaries. This represents flow entry through @@ -2034,6 +2096,10 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { } } +private newtype TAccessPath = + TAccessPathNil(DataFlowType t) or + TAccessPathCons(TypedContent head, AccessPath tail) { flowConsCand(head, tail.getApprox(), _) } + private newtype TPathNode = TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) { // A PathNode is introduced by a source ... @@ -2041,13 +2107,13 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(node, _, _, ap, unbind(config)) + flow(node, _, _, ap.getApprox(), unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2059,12 +2125,99 @@ private newtype TPathNode = or // ... or a sink that can be reached from a source exists(PathNodeMid mid | - pathStep(mid, node, _, _, any(AccessPathNil nil)) and + pathStep(mid, node, _, _, TAccessPathNil(_)) and config = unbind(mid.getConfiguration()) ) ) } +/** + * A list of `TypedContent`s followed by a `DataFlowType`. If data flows from a + * source to a given node with a given `AccessPath`, this indicates the sequence + * 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 { + /** Gets the head of this access path, if any. */ + abstract TypedContent getHead(); + + /** Gets the tail of this access path, if any. */ + abstract AccessPath getTail(); + + /** Gets the front of this access path. */ + abstract AccessPathFront getFront(); + + /** Gets the approximation of this access path. */ + abstract AccessPathApprox getApprox(); + + /** Gets the length of this access path. */ + abstract int length(); + + /** Gets a textual representation of this access path. */ + abstract string toString(); + + /** Gets the access path obtained by popping `tc` from this access path, if any. */ + final AccessPath pop(TypedContent tc) { + result = this.getTail() and + tc = this.getHead() + } + + /** Gets the access path obtained by pushing `tc` onto this access path. */ + final AccessPath push(TypedContent tc) { this = result.pop(tc) } +} + +private class AccessPathNil extends AccessPath, TAccessPathNil { + private DataFlowType t; + + AccessPathNil() { this = TAccessPathNil(t) } + + DataFlowType getType() { result = t } + + override TypedContent getHead() { none() } + + override AccessPath getTail() { none() } + + override AccessPathFrontNil getFront() { result = TFrontNil(t) } + + override AccessPathApproxNil getApprox() { result = TNil(t) } + + override int length() { result = 0 } + + override string toString() { result = concat(": " + ppReprType(t)) } +} + +private class AccessPathCons extends AccessPath, TAccessPathCons { + private TypedContent head; + private AccessPath tail; + + AccessPathCons() { this = TAccessPathCons(head, tail) } + + override TypedContent getHead() { result = head } + + override AccessPath getTail() { result = tail } + + override AccessPathFrontHead getFront() { result = TFrontHead(head) } + + override AccessPathApproxCons getApprox() { + result = TConsNil(head, tail.(AccessPathNil).getType()) + or + result = TConsCons(head, tail.getHead(), this.length()) + } + + override int length() { result = 1 + tail.length() } + + private string toStringImpl() { + exists(DataFlowType t | + tail = TAccessPathNil(t) and + result = head.toString() + "]" + concat(" : " + ppReprType(t)) + ) + or + result = head + ", " + tail.(AccessPathCons).toStringImpl() + } + + override string toString() { result = "[" + this.toStringImpl() } +} + /** * A `Node` augmented with a call context (except for sinks), an access path, and a configuration. * Only those `PathNode`s that are reachable from a source are generated. @@ -2098,14 +2251,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2350,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2387,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } @@ -2251,12 +2421,12 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TAccessPathNil(getNodeType(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2267,50 +2437,53 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } private predicate pathOutOfCallable0( - PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPath ap, Configuration config + PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa, + Configuration config ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and - ap = mid.getAp() and + innercc instanceof CallContextNoCall and + apa = mid.getAp().getApprox() and config = mid.getConfiguration() } pragma[nomagic] private predicate pathOutOfCallable1( - PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPath ap, + PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPathApprox apa, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | - pathOutOfCallable0(mid, pos, innercc, ap, config) and + pathOutOfCallable0(mid, pos, innercc, apa, config) and c = pos.getCallable() and kind = pos.getKind() and resolveReturn(innercc, c, call) @@ -2321,10 +2494,10 @@ private predicate pathOutOfCallable1( pragma[noinline] private Node getAnOutNodeFlow( - ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config + ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ) { result = kind.getAnOutNode(call) and - flow(result, _, _, ap, config) + flow(result, _, _, apa, config) } /** @@ -2333,10 +2506,9 @@ private Node getAnOutNodeFlow( */ pragma[noinline] private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { - exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | - pathOutOfCallable1(mid, call, kind, cc, ap, config) - | - out = getAnOutNodeFlow(kind, call, ap, config) + exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config | + pathOutOfCallable1(mid, call, kind, cc, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -2345,22 +2517,23 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa ) { exists(ArgumentNode arg | arg = mid.getNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and - ap = mid.getAp() + ap = mid.getAp() and + apa = ap.getApprox() ) } pragma[noinline] private predicate parameterCand( - DataFlowCallable callable, int i, AccessPath ap, Configuration config + DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { exists(ParameterNode p | - flow(p, _, _, ap, config) and + flow(p, _, _, apa, config) and p.isParameterOf(callable, i) ) } @@ -2370,9 +2543,11 @@ private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, AccessPath ap ) { - pathIntoArg(mid, i, outercc, call, ap) and - callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), ap, mid.getConfiguration()) + exists(AccessPathApprox apa | + pathIntoArg(mid, i, outercc, call, ap, apa) and + callable = resolveCall(call, outercc) and + parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + ) } /** @@ -2403,7 +2578,8 @@ private predicate pathIntoCallable( /** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */ pragma[nomagic] private predicate paramFlowsThrough( - ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config + ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(PathNodeMid mid, ReturnNodeExt ret, int pos | mid.getNode() = ret and @@ -2412,6 +2588,7 @@ private predicate paramFlowsThrough( sc = mid.getSummaryCtx() and config = mid.getConfiguration() and ap = mid.getAp() and + apa = ap.getApprox() and pos = sc.getParameterPos() and not kind.(ParamUpdateReturnKind).getPosition() = pos ) @@ -2419,11 +2596,12 @@ private predicate paramFlowsThrough( pragma[nomagic] private predicate pathThroughCallable0( - DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap + DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, + AccessPathApprox apa ) { exists(CallContext innercc, SummaryCtx sc | pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, unbind(mid.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration())) ) } @@ -2433,9 +2611,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind | - pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | + pathThroughCallable0(call, mid, kind, cc, ap, apa) and + out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration())) ) } @@ -2521,10 +2699,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2533,7 +2711,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2544,7 +2722,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2562,15 +2740,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2591,7 +2769,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2608,7 +2786,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2721,7 +2899,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2737,7 +2915,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2746,11 +2924,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2769,35 +2948,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( @@ -2806,7 +2992,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll index 852f54974e24..892250f44bb8 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -22,7 +22,7 @@ private module Cached { exists(int i | viableParam(call, i, p) and arg.argumentOf(call, i) and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(p)) + compatibleTypes(getNodeType(arg), getNodeType(p)) ) } @@ -147,174 +147,140 @@ private module Cached { } } - private module LocalFlowBigStep { - private predicate localFlowEntry(Node n) { - Cand::cand(_, n) and - ( - n instanceof ParameterNode or - n instanceof OutNode or - readStep(_, _, n) or - n instanceof CastNode - ) - } - - private predicate localFlowExit(Node n) { - Cand::cand(_, n) and - ( - n instanceof ArgumentNode - or - n instanceof ReturnNode - or - readStep(n, _, _) - or - n instanceof CastNode - or - n = - any(PostUpdateNode pun | Cand::parameterValueFlowsToPreUpdateCand(_, pun)) - .getPreUpdateNode() - ) - } - - pragma[nomagic] - private predicate localFlowStepPlus(Node node1, Node node2) { - localFlowEntry(node1) and - simpleLocalFlowStep(node1, node2) and - node1 != node2 - or - exists(Node mid | - localFlowStepPlus(node1, mid) and - simpleLocalFlowStep(mid, node2) and - not mid instanceof CastNode - ) - } - - pragma[nomagic] - predicate localFlowBigStep(Node node1, Node node2) { - localFlowStepPlus(node1, node2) and - localFlowExit(node2) - } - } - /** * The final flow-through calculation: * - * - Input access paths are abstracted with a `ContentOption` parameter - * that represents the head of the access path. `TContentNone()` means that - * the access path is unrestricted. + * - Calculated flow is either value-preserving (`read = TReadStepTypesNone()`) + * or summarized as a single read step with before and after types recorded + * in the `ReadStepTypesOption` parameter. * - Types are checked using the `compatibleTypes()` relation. */ private module Final { /** * Holds if `p` can flow to `node` in the same callable using only - * value-preserving steps, not taking call contexts into account. + * value-preserving steps and possibly a single read step, not taking + * call contexts into account. * - * `contentIn` describes the content of `p` that can flow to `node` - * (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ - predicate parameterValueFlow(ParameterNode p, Node node, ContentOption contentIn) { - parameterValueFlow0(p, node, contentIn) and + predicate parameterValueFlow(ParameterNode p, Node node, ReadStepTypesOption read) { + parameterValueFlow0(p, node, read) and if node instanceof CastingNode then // normal flow through - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) + read = TReadStepTypesNone() and + compatibleTypes(getNodeType(p), getNodeType(node)) or // getter - exists(Content fIn | - contentIn.getContent() = fIn and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(node)) - ) + compatibleTypes(read.getContentType(), getNodeType(node)) else any() } pragma[nomagic] - private predicate parameterValueFlow0(ParameterNode p, Node node, ContentOption contentIn) { + private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() + read = TReadStepTypesNone() or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn) and - LocalFlowBigStep::localFlowBigStep(mid, node) + parameterValueFlow(p, mid, read) and + simpleLocalFlowStep(mid, node) ) or // read - exists(Node mid, Content f | - parameterValueFlow(p, mid, TContentNone()) and - readStep(mid, f, node) and - contentIn.getContent() = f and + exists(Node mid | + parameterValueFlow(p, mid, TReadStepTypesNone()) and + readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, + read.getContentType()) and Cand::parameterValueFlowReturnCand(p, _, true) and - compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) + compatibleTypes(getNodeType(p), read.getContainerType()) ) or + parameterValueFlow0_0(TReadStepTypesNone(), p, node, read) + } + + pragma[nomagic] + private predicate parameterValueFlow0_0( + ReadStepTypesOption mustBeNone, ParameterNode p, Node node, ReadStepTypesOption read + ) { // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, TContentNone()) and - argumentValueFlowsThrough(arg, contentIn, node) + parameterValueFlowArg(p, arg, mustBeNone) and + argumentValueFlowsThrough(arg, read, node) ) or // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, contentIn) and - argumentValueFlowsThrough(arg, TContentNone(), node) + parameterValueFlowArg(p, arg, read) and + argumentValueFlowsThrough(arg, mustBeNone, node) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn + ParameterNode p, ArgumentNode arg, ReadStepTypesOption read ) { - parameterValueFlow(p, arg, contentIn) and + parameterValueFlow(p, arg, read) and Cand::argumentValueFlowsThroughCand(arg, _, _) } pragma[nomagic] private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn + DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, kind, contentIn) + parameterValueFlowReturn(param, kind, read) ) } /** - * Holds if `arg` flows to `out` through a call using only value-preserving steps, - * not taking call contexts into account. + * Holds if `arg` flows to `out` through a call using only + * value-preserving steps and possibly a single read step, not taking + * call contexts into account. * - * `contentIn` describes the content of `arg` that can flow to `out` (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ pragma[nomagic] - predicate argumentValueFlowsThrough(ArgumentNode arg, ContentOption contentIn, Node out) { + predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) { exists(DataFlowCall call, ReturnKind kind | - argumentValueFlowsThrough0(call, arg, kind, contentIn) and + argumentValueFlowsThrough0(call, arg, kind, read) and out = getAnOutNode(call, kind) | // normal flow through - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) + read = TReadStepTypesNone() and + compatibleTypes(getNodeType(arg), getNodeType(out)) or // getter - exists(Content fIn | - contentIn.getContent() = fIn and - compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(out)) - ) + compatibleTypes(getNodeType(arg), read.getContainerType()) and + compatibleTypes(read.getContentType(), getNodeType(out)) ) } + /** + * Holds if `arg` flows to `out` through a call using only + * value-preserving steps and a single read step, not taking call + * contexts into account, thus representing a getter-step. + */ + predicate getterStep(ArgumentNode arg, Content c, Node out) { + argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out) + } + /** * Holds if `p` can flow to a return node of kind `kind` in the same - * callable using only value-preserving steps. + * callable using only value-preserving steps and possibly a single read + * step. * - * `contentIn` describes the content of `p` that can flow to the return - * node (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ private predicate parameterValueFlowReturn( - ParameterNode p, ReturnKind kind, ContentOption contentIn + ParameterNode p, ReturnKind kind, ReadStepTypesOption read ) { exists(ReturnNode ret | - parameterValueFlow(p, ret, contentIn) and + parameterValueFlow(p, ret, read) and kind = ret.getKind() ) } @@ -323,37 +289,107 @@ private module Cached { import Final } + import FlowThrough + + cached + private module DispatchWithCallContext { + /** + * Holds if the call context `ctx` reduces the set of viable run-time + * dispatch targets of call `call` in `c`. + */ + cached + predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) { + exists(int tgts, int ctxtgts | + mayBenefitFromCallContext(call, c) and + c = viableCallable(ctx) and + ctxtgts = count(viableImplInCallContext(call, ctx)) and + tgts = strictcount(viableCallable(call)) and + ctxtgts < tgts + ) + } + + /** + * Gets a viable run-time dispatch target for the call `call` in the + * context `ctx`. This is restricted to those calls for which a context + * makes a difference. + */ + cached + DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) and + reducedViableImplInCallContext(call, _, ctx) + } + + /** + * Holds if flow returning from callable `c` to call `call` might return + * further and if this path restricts the set of call sites that can be + * returned to. + */ + cached + predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { + exists(int tgts, int ctxtgts | + mayBenefitFromCallContext(call, _) and + c = viableCallable(call) and + ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and + tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and + ctxtgts < tgts + ) + } + + /** + * Gets a viable run-time dispatch target for the call `call` in the + * context `ctx`. This is restricted to those calls and results for which + * the return flow from the result to `call` restricts the possible context + * `ctx`. + */ + cached + DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) and + reducedViableImplInReturn(result, call) + } + } + + import DispatchWithCallContext + /** * Holds if `p` can flow to the pre-update node associated with post-update * node `n`, in the same callable, using only value-preserving steps. */ cached predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone()) + parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone()) } - /** - * Holds if data can flow from `node1` to `node2` via a direct assignment to - * `f`. - * - * This includes reverse steps through reads when the result of the read has - * been stored into, in order to handle cases like `x.f1.f2 = y`. - */ - cached - predicate store(Node node1, Content f, Node node2) { - storeStep(node1, f, node2) and readStep(_, f, _) + private predicate store( + Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType + ) { + storeStep(node1, c, node2) and + readStep(_, c, _) and + contentType = getNodeType(node1) and + containerType = getNodeType(node2) or exists(Node n1, Node n2 | n1 = node1.(PostUpdateNode).getPreUpdateNode() and n2 = node2.(PostUpdateNode).getPreUpdateNode() | - argumentValueFlowsThrough(n2, TContentSome(f), n1) + argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1) or - readStep(n2, f, n1) + readStep(n2, c, n1) and + contentType = getNodeType(n1) and + containerType = getNodeType(n2) ) } - import FlowThrough + /** + * Holds if data can flow from `node1` to `node2` via a direct assignment to + * `f`. + * + * This includes reverse steps through reads when the result of the read has + * been stored into, in order to handle cases like `x.f1.f2 = y`. + */ + cached + predicate store(Node node1, TypedContent tc, Node node2, DataFlowType contentType) { + store(node1, tc.getContent(), node2, contentType, tc.getContainerType()) + } /** * Holds if the call context `call` either improves virtual dispatch in @@ -397,10 +433,13 @@ private module Cached { TBooleanNone() or TBooleanSome(boolean b) { b = true or b = false } + cached + newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } + cached newtype TAccessPathFront = TFrontNil(DataFlowType t) or - TFrontHead(Content f) + TFrontHead(TypedContent tc) cached newtype TAccessPathFrontOption = @@ -415,25 +454,38 @@ class CastingNode extends Node { CastingNode() { this instanceof ParameterNode or this instanceof CastNode or - this instanceof OutNodeExt + this instanceof OutNodeExt or + // For reads, `x.f`, we want to check that the tracked type after the read (which + // is obtained by popping the head of the access path stack) is compatible with + // the type of `x.f`. + readStep(_, _, this) } } -newtype TContentOption = - TContentNone() or - TContentSome(Content f) +private predicate readStepWithTypes( + Node n1, DataFlowType container, Content c, Node n2, DataFlowType content +) { + readStep(n1, c, n2) and + container = getNodeType(n1) and + content = getNodeType(n2) +} -private class ContentOption extends TContentOption { - Content getContent() { this = TContentSome(result) } +private newtype TReadStepTypesOption = + TReadStepTypesNone() or + TReadStepTypesSome(DataFlowType container, Content c, DataFlowType content) { + readStepWithTypes(_, container, c, _, content) + } - predicate hasContent() { exists(this.getContent()) } +private class ReadStepTypesOption extends TReadStepTypesOption { + predicate isSome() { this instanceof TReadStepTypesSome } - string toString() { - result = this.getContent().toString() - or - not this.hasContent() and - result = "" - } + DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) } + + Content getContent() { this = TReadStepTypesSome(_, result, _) } + + DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) } + + string toString() { if this.isSome() then result = "Some(..)" else result = "None()" } } /** @@ -460,13 +512,19 @@ abstract class CallContext extends TCallContext { abstract predicate relevantFor(DataFlowCallable callable); } -class CallContextAny extends CallContext, TAnyCallContext { +abstract class CallContextNoCall extends CallContext { } + +class CallContextAny extends CallContextNoCall, TAnyCallContext { override string toString() { result = "CcAny" } override predicate relevantFor(DataFlowCallable callable) { any() } } -abstract class CallContextCall extends CallContext { } +abstract class CallContextCall extends CallContext { + /** Holds if this call context may be `call`. */ + bindingset[call] + abstract predicate matchesCall(DataFlowCall call); +} class CallContextSpecificCall extends CallContextCall, TSpecificCall { override string toString() { @@ -477,6 +535,8 @@ class CallContextSpecificCall extends CallContextCall, TSpecificCall { recordDataFlowCallSite(getCall(), callable) } + override predicate matchesCall(DataFlowCall call) { call = this.getCall() } + DataFlowCall getCall() { this = TSpecificCall(result) } } @@ -486,9 +546,11 @@ class CallContextSomeCall extends CallContextCall, TSomeCall { override predicate relevantFor(DataFlowCallable callable) { exists(ParameterNode p | p.getEnclosingCallable() = callable) } + + override predicate matchesCall(DataFlowCall call) { any() } } -class CallContextReturn extends CallContext, TReturn { +class CallContextReturn extends CallContextNoCall, TReturn { override string toString() { exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")") } @@ -678,9 +740,6 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { result = viableCallable(call) and cc instanceof CallContextReturn } -pragma[noinline] -DataFlowType getErasedNodeTypeBound(Node n) { result = getErasedRepr(n.getTypeBound()) } - predicate read = readStep/3; /** An optional Boolean value. */ @@ -692,6 +751,23 @@ class BooleanOption extends TBooleanOption { } } +/** Content tagged with the type of a containing object. */ +class TypedContent extends MkTypedContent { + private Content c; + private DataFlowType t; + + TypedContent() { this = MkTypedContent(c, t) } + + /** Gets the content. */ + Content getContent() { result = c } + + /** Gets the container type. */ + DataFlowType getContainerType() { result = t } + + /** Gets a textual representation of this content. */ + string toString() { result = c.toString() } +} + /** * The front of an access path. This is either a head or a nil. */ @@ -702,25 +778,36 @@ abstract class AccessPathFront extends TAccessPathFront { abstract boolean toBoolNonEmpty(); - predicate headUsesContent(Content f) { this = TFrontHead(f) } + predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) } + + predicate isClearedAt(Node n) { + exists(TypedContent tc | + this.headUsesContent(tc) and + clearsContent(n, tc.getContent()) + ) + } } class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } + private DataFlowType t; + + AccessPathFrontNil() { this = TFrontNil(t) } + + override string toString() { result = ppReprType(t) } - override DataFlowType getType() { this = TFrontNil(result) } + override DataFlowType getType() { result = t } override boolean toBoolNonEmpty() { result = false } } class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } + private TypedContent tc; - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } + AccessPathFrontHead() { this = TFrontHead(tc) } + + override string toString() { result = tc.toString() } + + override DataFlowType getType() { result = tc.getContainerType() } override boolean toBoolNonEmpty() { result = true } } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll index 0dc3b8eff450..4e1cd281488f 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll @@ -37,21 +37,12 @@ module Consistency { ) } - query predicate uniqueTypeBound(Node n, string msg) { + query predicate uniqueType(Node n, string msg) { exists(int c | n instanceof RelevantNode and - c = count(n.getTypeBound()) and + c = count(getNodeType(n)) and c != 1 and - msg = "Node should have one type bound but has " + c + "." - ) - } - - query predicate uniqueTypeRepr(Node n, string msg) { - exists(int c | - n instanceof RelevantNode and - c = count(getErasedRepr(n.getTypeBound())) and - c != 1 and - msg = "Node should have one type representation but has " + c + "." + msg = "Node should have one type but has " + c + "." ) } @@ -104,7 +95,7 @@ module Consistency { msg = "Local flow step does not preserve enclosing callable." } - private DataFlowType typeRepr() { result = getErasedRepr(any(Node n).getTypeBound()) } + private DataFlowType typeRepr() { result = getNodeType(_) } query predicate compatibleTypesReflexive(DataFlowType t, string msg) { t = typeRepr() and @@ -132,8 +123,18 @@ module Consistency { n.getEnclosingCallable() != call.getEnclosingCallable() } + // This predicate helps the compiler forget that in some languages + // it is impossible for a result of `getPreUpdateNode` to be an + // instance of `PostUpdateNode`. + private Node getPre(PostUpdateNode n) { + result = n.getPreUpdateNode() + or + none() + } + query predicate postIsNotPre(PostUpdateNode n, string msg) { - n.getPreUpdateNode() = n and msg = "PostUpdateNode should not equal its pre-update node." + getPre(n) = n and + msg = "PostUpdateNode should not equal its pre-update node." } query predicate postHasUniquePre(PostUpdateNode n, string msg) { @@ -161,15 +162,14 @@ module Consistency { msg = "Origin of readStep is missing a PostUpdateNode." } - query predicate storeIsPostUpdate(Node n, string msg) { - storeStep(_, _, n) and - not n instanceof PostUpdateNode and - msg = "Store targets should be PostUpdateNodes." - } - query predicate argHasPostUpdate(ArgumentNode n, string msg) { not hasPost(n) and not isImmutableOrUnobservable(n) and msg = "ArgumentNode is missing PostUpdateNode." } + + query predicate postWithInFlow(PostUpdateNode n, string msg) { + simpleLocalFlowStep(_, n) and + msg = "PostUpdateNode should not be the target of local flow." + } } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index f9bac316d706..bae73a6609d9 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -15,6 +15,57 @@ private import semmle.code.csharp.dataflow.LibraryTypeDataFlow private import semmle.code.csharp.dispatch.Dispatch private import semmle.code.csharp.frameworks.EntityFramework private import semmle.code.csharp.frameworks.NHibernate +private import semmle.code.csharp.frameworks.system.Collections +private import semmle.code.csharp.frameworks.system.threading.Tasks +private import semmle.code.csharp.frameworks.system.linq.Expressions + +abstract class NodeImpl extends Node { + /** Do not call: use `getEnclosingCallable()` instead. */ + abstract DataFlowCallable getEnclosingCallableImpl(); + + /** Do not call: use `getType()` instead. */ + abstract DotNet::Type getTypeImpl(); + + /** Gets the type of this node used for type pruning. */ + cached + Gvn::GvnType getDataFlowType() { + Stages::DataFlowStage::forceCachingInSameStage() and + exists(Type t0 | result = Gvn::getGlobalValueNumber(t0) | + t0 = getCSharpType(this.getType()) + or + not exists(getCSharpType(this.getType())) and + t0 instanceof ObjectType + ) + } + + /** Do not call: use `getControlFlowNode()` instead. */ + abstract ControlFlow::Node getControlFlowNodeImpl(); + + /** Do not call: use `getLocation()` instead. */ + abstract Location getLocationImpl(); + + /** Do not call: use `toString()` instead. */ + abstract string toStringImpl(); +} + +private class ExprNodeImpl extends ExprNode, NodeImpl { + override DataFlowCallable getEnclosingCallableImpl() { + result = this.getExpr().getEnclosingCallable() + } + + override DotNet::Type getTypeImpl() { result = this.getExpr().getType() } + + override ControlFlow::Nodes::ElementNode getControlFlowNodeImpl() { this = TExprNode(result) } + + override Location getLocationImpl() { result = this.getExpr().getLocation() } + + override string toStringImpl() { + result = this.getControlFlowNode().toString() + or + this = TCilExprNode(_) and + result = "CIL expression" + } +} /** Calculation of the relative order in which `this` references are read. */ private module ThisFlow { @@ -73,7 +124,7 @@ private module ThisFlow { /** Provides predicates related to local data flow. */ module LocalFlow { - class LocalExprStepConfiguration extends ControlFlowReachabilityConfiguration { + private class LocalExprStepConfiguration extends ControlFlowReachabilityConfiguration { LocalExprStepConfiguration() { this = "LocalExprStepConfiguration" } override predicate candidate( @@ -105,10 +156,6 @@ module LocalFlow { scope = e2 and isSuccessor = true or - e1 = e2.(AwaitExpr).getExpr() and - scope = e2 and - isSuccessor = true - or // An `=` expression, where the result of the expression is used e2 = any(AssignExpr ae | @@ -117,6 +164,18 @@ module LocalFlow { ) and scope = e2 and isSuccessor = true + or + e1 = e2.(ObjectCreation).getInitializer() and + scope = e2 and + isSuccessor = false + or + e1 = e2.(ArrayCreation).getInitializer() and + scope = e2 and + isSuccessor = false + or + e1 = e2.(SwitchExpr).getACase().getBody() and + scope = e2 and + isSuccessor = false ) } @@ -151,7 +210,7 @@ module LocalFlow { result = node.asExpr() } - predicate localFlowStepCil(Node nodeFrom, Node nodeTo) { + private predicate localFlowStepCil(Node nodeFrom, Node nodeTo) { asCilDataFlowNode(nodeFrom).getALocalFlowSucc(asCilDataFlowNode(nodeTo), any(CIL::Untainted t)) } @@ -241,6 +300,62 @@ module LocalFlow { nodeTo = TImplicitCapturedArgumentNode(call, def.getSourceVariable().getAssignable()) ) } + + predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) { + exists(Ssa::Definition def | + localSsaFlowStep(def, nodeFrom, nodeTo) and + not usesInstanceField(def) + ) + or + any(LocalExprStepConfiguration x).hasNodePath(nodeFrom, nodeTo) + or + ThisFlow::adjacentThisRefs(nodeFrom, nodeTo) + or + ThisFlow::adjacentThisRefs(nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo) + or + localFlowStepCil(nodeFrom, nodeTo) + } + + /** + * Holds if node `n` should not be included in the exposed local data/taint + * flow relations. This is the case for nodes that are only relevant for + * inter-procedurality or field-sensitivity. + */ + predicate excludeFromExposedRelations(Node n) { + n instanceof Summaries::SummaryNodeImpl or + n instanceof ImplicitCapturedArgumentNode + } +} + +pragma[noinline] +private Expr getImplicitArgument(Call c, int pos) { + result = c.getArgument(pos) and + not exists(result.getExplicitArgumentName()) +} + +pragma[nomagic] +private Expr getExplicitArgument(Call c, string name) { + result = c.getAnArgument() and + result.getExplicitArgumentName() = name +} + +/** + * Holds if `arg` is a `params` argument of `c`, for parameter `p`, and `arg` will + * be wrapped in an array by the C# compiler. + */ +private predicate isParamsArg(Call c, Expr arg, Parameter p) { + exists(Callable target, int numArgs | + target = c.getTarget() and + p = target.getAParameter() and + p.isParams() and + numArgs = c.getNumberOfArguments() and + arg = + [getImplicitArgument(c, [p.getPosition() .. numArgs - 1]), getExplicitArgument(c, p.getName())] + | + numArgs > target.getNumberOfParameters() + or + not arg.getType().isImplicitlyConvertibleTo(p.getType()) + ) } /** An argument of a C# call (including qualifier arguments). */ @@ -251,7 +366,8 @@ private class Argument extends Expr { Argument() { call = any(DispatchCall dc | - this = dc.getArgument(arg) + this = dc.getArgument(arg) and + not isParamsArg(_, this, _) or this = dc.getQualifier() and arg = -1 and not dc.getAStaticTarget().(Modifiable).isStatic() ).getCall() @@ -269,43 +385,39 @@ private class Argument extends Expr { /** * Holds if `e` is an assignment of `src` to field or property `c` of `q`. + * + * `postUpdate` indicates whether the store targets a post-update node. */ -private predicate fieldOrPropertyAssign(Expr e, Content c, Expr src, Expr q) { - exists(FieldOrPropertyAccess fa, FieldOrProperty f, AssignableDefinition def | - def.getTargetAccess() = fa and - f = fa.getTarget() and +private predicate fieldOrPropertyStore(Expr e, Content c, Expr src, Expr q, boolean postUpdate) { + exists(FieldOrProperty f | c = f.getContent() and - src = def.getSource() and - q = fa.getQualifier() and - e = def.getExpr() - | - f.isFieldLike() and - f instanceof InstanceFieldOrProperty - or - exists(AccessPath ap | - LibraryFlow::libraryFlow(_, _, ap, _, _, _) and - ap.contains(f.getContent()) + ( + f.isFieldLike() and + f instanceof InstanceFieldOrProperty + or + exists(AccessPath ap | + Summaries::summary(_, _, ap, _, _, _) and + ap.contains(f.getContent()) + ) ) - ) -} - -/** - * Holds if `oc` has an object initializer that assigns `src` to field or - * property `c`. - */ -private predicate fieldOrPropertyInit(ObjectCreation oc, Content c, Expr src) { - exists(MemberInitializer mi, FieldOrProperty f | - mi = oc.getInitializer().(ObjectInitializer).getAMemberInitializer() and - f = mi.getInitializedMember() and - c = f.getContent() and - src = mi.getRValue() | - f.isFieldLike() and - f instanceof InstanceFieldOrProperty + // Direct assignment, `q.f = src` + exists(FieldOrPropertyAccess fa, AssignableDefinition def | + def.getTargetAccess() = fa and + f = fa.getTarget() and + src = def.getSource() and + q = fa.getQualifier() and + e = def.getExpr() and + postUpdate = true + ) or - exists(AccessPath ap | - LibraryFlow::libraryFlow(_, _, ap, _, _, _) and - ap.contains(f.getContent()) + // Object initializer, `new C() { f = src }` + exists(MemberInitializer mi | + e = q and + mi = q.(ObjectInitializer).getAMemberInitializer() and + f = mi.getInitializedMember() and + src = mi.getRValue() and + postUpdate = false ) ) } @@ -329,7 +441,7 @@ private predicate fieldOrPropertyRead(Expr e1, Content c, FieldOrPropertyRead e2 ret = e2.getTarget() or exists(AccessPath ap, Property target | - LibraryFlow::libraryFlow(_, _, _, _, ap, _) and + Summaries::summary(_, _, _, _, ap, _) and ap.contains(ret.getContent()) and target.getGetter() = e2.(PropertyCall).getARuntimeTarget() and overridesOrImplementsSourceDecl(target, ret) @@ -337,20 +449,64 @@ private predicate fieldOrPropertyRead(Expr e1, Content c, FieldOrPropertyRead e2 ) } -Type getCSharpType(DotNet::Type t) { +/** + * Holds if `e` is an expression that adds `src` to array `a`. + * + * `postUpdate` indicates whether the store targets a post-update node. + */ +private predicate arrayStore(Expr e, Expr src, Expr a, boolean postUpdate) { + // Direct assignment, `a[i] = src` + exists(AssignableDefinition def | + a = def.getTargetAccess().(ArrayWrite).getQualifier() and + src = def.getSource() and + e = def.getExpr() and + postUpdate = true + ) + or + // Array initializer, `new [] { src }` + src = a.(ArrayInitializer).getAnElement() and + e = a and + postUpdate = false + or + // Member initalizer, `new C { Array = { [i] = src } }` + exists(MemberInitializer mi | + mi = a.(ObjectInitializer).getAMemberInitializer() and + mi.getLValue() instanceof ArrayAccess and + mi.getRValue() = src and + e = a and + postUpdate = false + ) +} + +/** + * Holds if `e2` is an expression that reads an array element from + * from expresion `e1`. + */ +private predicate arrayRead(Expr e1, ArrayRead e2) { e1 = e2.getQualifier() } + +private Type getCSharpType(DotNet::Type t) { result = t or result.matchesHandle(t) } +/** A GVN type that is either a `DataFlowType` or unifiable with a `DataFlowType`. */ +private class DataFlowTypeOrUnifiable extends Gvn::GvnType { + pragma[nomagic] + DataFlowTypeOrUnifiable() { + this instanceof DataFlowType or + Gvn::unifiable(any(DataFlowType t), this) + } +} + pragma[noinline] -private TypeParameter getATypeParameterSubType(DataFlowType t) { +private TypeParameter getATypeParameterSubType(DataFlowTypeOrUnifiable t) { not t instanceof Gvn::TypeParameterGvnType and exists(Type t0 | t = Gvn::getGlobalValueNumber(t0) | implicitConversionRestricted(result, t0)) } pragma[noinline] -private DataFlowType getANonTypeParameterSubType(DataFlowType t) { +private Gvn::GvnType getANonTypeParameterSubType(DataFlowTypeOrUnifiable t) { not t instanceof Gvn::TypeParameterGvnType and not result instanceof Gvn::TypeParameterGvnType and exists(Type t1, Type t2 | @@ -363,6 +519,8 @@ private DataFlowType getANonTypeParameterSubType(DataFlowType t) { /** A collection of cached types and predicates to be evaluated in the same stage. */ cached private module Cached { + private import Summaries + cached newtype TNode = TExprNode(ControlFlow::Nodes::ElementNode cfn) { @@ -380,21 +538,10 @@ private module Cached { v = def.getSourceVariable().getAssignable() ) } or - TImplicitDelegateOutNode( - ControlFlow::Nodes::ElementNode cfn, ControlFlow::Nodes::ElementNode call - ) { - cfn.getElement() instanceof DelegateArgumentToLibraryCallable and - any(DelegateArgumentConfiguration x).hasExprPath(_, cfn, _, call) - } or - TImplicitDelegateArgumentNode(ControlFlow::Nodes::ElementNode cfn, int i, int j) { - exists(Call call, CallableFlowSinkDelegateArg sink | - LibraryFlow::libraryFlow(call, _, _, sink, _, _) and - i = sink.getDelegateIndex() and - j = sink.getDelegateParameterIndex() and - call.getArgument(i).getAControlFlowNode() = cfn - ) - } or TMallocNode(ControlFlow::Nodes::ElementNode cfn) { cfn.getElement() instanceof ObjectCreation } or + TObjectInitializerNode(ControlFlow::Nodes::ElementNode cfn) { + cfn.getElement().(ObjectCreation).hasInitializer() + } or TExprPostUpdateNode(ControlFlow::Nodes::ElementNode cfn) { exists(Argument a, Type t | a = cfn.getElement() and @@ -406,7 +553,9 @@ private module Cached { t = any(TypeParameter tp | not tp.isValueType()) ) or - fieldOrPropertyAssign(_, _, _, cfn.getElement()) + fieldOrPropertyStore(_, _, _, cfn.getElement(), true) + or + arrayStore(_, _, cfn.getElement(), true) or exists(TExprPostUpdateNode upd, FieldOrPropertyAccess fla | upd = TExprPostUpdateNode(fla.getAControlFlowNode()) @@ -414,54 +563,87 @@ private module Cached { cfn.getElement() = fla.getQualifier() ) } or - TLibraryCodeNode( - ControlFlow::Node callCfn, CallableFlowSource source, AccessPath sourceAp, - CallableFlowSink sink, AccessPath sinkAp, boolean preservesValue + TSummaryParameterNode(SourceDeclarationCallable c, int i) { + exists(CallableFlowSource source | Summaries::summary(c, source, _, _, _, _) | + source instanceof CallableFlowSourceQualifier and i = -1 + or + i = source.(CallableFlowSourceArg).getArgumentIndex() + or + i = source.(CallableFlowSourceDelegateArg).getArgumentIndex() + ) + or + exists(CallableFlowSink sink | Summaries::summary(c, _, _, sink, _, _) | + i = sink.(CallableFlowSinkDelegateArg).getDelegateIndex() + ) + } or + TSummaryInternalNode( + SourceDeclarationCallable c, CallableFlowSource source, AccessPath sourceAp, + CallableFlowSink sink, AccessPath sinkAp, boolean preservesValue, + SummaryInternalNodeState state ) { - LibraryFlow::libraryFlow(callCfn.getElement(), source, sourceAp, sink, sinkAp, preservesValue) + Summaries::summary(c, source, sourceAp, sink, sinkAp, preservesValue) and + ( + state = TSummaryInternalNodeAfterReadState(sourceAp.drop(_)) + or + state = TSummaryInternalNodeBeforeStoreState(sinkAp.drop(_)) + ) + } or + TSummaryReturnNode(SourceDeclarationCallable c, ReturnKind rk) { + exists(CallableFlowSink sink | + Summaries::summary(c, _, _, sink, _, _) and + rk = Summaries::toReturnKind(sink) + ) + } or + TSummaryDelegateOutNode(SourceDeclarationCallable c, int pos) { + exists(CallableFlowSourceDelegateArg source | + Summaries::summary(c, source, _, _, _, _) and + pos = source.getArgumentIndex() + ) + } or + TSummaryDelegateArgumentNode(SourceDeclarationCallable c, int delegateIndex, int parameterIndex) { + exists(CallableFlowSinkDelegateArg sink | + Summaries::summary(c, _, _, sink, _, _) and + delegateIndex = sink.getDelegateIndex() and + parameterIndex = sink.getDelegateParameterIndex() + ) + } or + TParamsArgumentNode(ControlFlow::Node callCfn) { + callCfn = any(Call c | isParamsArg(c, _, _)).getAControlFlowNode() } /** * This is the local flow predicate that is used as a building block in global - * data flow. It is a strict subset of the `localFlowStep` predicate, as it - * excludes SSA flow through instance fields. + * data flow. It excludes SSA flow through instance fields, as flow through fields + * is handled by the global data-flow library, but includes various other steps + * that are only relevant for global flow. */ cached predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { - exists(Ssa::Definition def | - LocalFlow::localSsaFlowStep(def, nodeFrom, nodeTo) and - not LocalFlow::usesInstanceField(def) - ) - or - any(LocalFlow::LocalExprStepConfiguration x).hasNodePath(nodeFrom, nodeTo) - or - ThisFlow::adjacentThisRefs(nodeFrom, nodeTo) - or - ThisFlow::adjacentThisRefs(nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo) + LocalFlow::localFlowStepCommon(nodeFrom, nodeTo) or LocalFlow::localFlowCapturedVarStep(nodeFrom, nodeTo) or - LocalFlow::localFlowStepCil(nodeFrom, nodeTo) + Summaries::summaryLocalStep(nodeFrom, nodeTo, true) or - exists(LibraryCodeNode n | n.preservesValue() | - n = nodeTo and - nodeFrom = n.getPredecessor(AccessPath::empty()) - or - n = nodeFrom and - nodeTo = n.getSuccessor(AccessPath::empty()) - ) + nodeTo.(ObjectCreationNode).getPreUpdateNode() = nodeFrom.(ObjectInitializerNode) } /** - * This is the extension of the predicate `simpleLocalFlowStep` that is exposed - * as the `localFlowStep` predicate. It includes SSA flow through instance fields. + * Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local + * (intra-procedural) step. */ cached - predicate extendedLocalFlowStep(Node nodeFrom, Node nodeTo) { + predicate localFlowStepImpl(Node nodeFrom, Node nodeTo) { + LocalFlow::localFlowStepCommon(nodeFrom, nodeTo) + or exists(Ssa::Definition def | LocalFlow::localSsaFlowStep(def, nodeFrom, nodeTo) and LocalFlow::usesInstanceField(def) ) + or + // Simple flow through library code is included in the exposed local + // step relation, even though flow is technically inter-procedural + Summaries::summaryThroughStep(nodeFrom, nodeTo, true) } /** @@ -477,7 +659,8 @@ private module Cached { cached newtype TContent = TFieldContent(Field f) { f = f.getSourceDeclaration() } or - TPropertyContent(Property p) { p = p.getSourceDeclaration() } + TPropertyContent(Property p) { p = p.getSourceDeclaration() } or + TElementContent() /** * Holds if data can flow from `node1` to `node2` via an assignment to @@ -485,17 +668,34 @@ private module Cached { */ cached predicate storeStepImpl(Node node1, Content c, Node node2) { - exists(StoreStepConfiguration x, ExprNode preNode2 | - preNode2 = node2.(PostUpdateNode).getPreUpdateNode() and - x.hasNodePath(node1, preNode2) and - fieldOrPropertyAssign(_, c, node1.asExpr(), preNode2.getExpr()) + exists(StoreStepConfiguration x, ExprNode node, boolean postUpdate | + x.hasNodePath(node1, node) and + if postUpdate = true then node = node2.(PostUpdateNode).getPreUpdateNode() else node = node2 + | + fieldOrPropertyStore(_, c, node1.asExpr(), node.getExpr(), postUpdate) + or + arrayStore(_, node1.asExpr(), node.getExpr(), postUpdate) and c instanceof ElementContent ) or - exists(StoreStepConfiguration x | x.hasNodePath(node1, node2) | - fieldOrPropertyInit(node2.(ObjectCreationNode).getExpr(), c, node1.asExpr()) + exists(StoreStepConfiguration x, Expr arg, ControlFlow::Node callCfn | + x.hasExprPath(arg, node1.(ExprNode).getControlFlowNode(), _, callCfn) and + node2 = TParamsArgumentNode(callCfn) and + isParamsArg(_, arg, _) and + c instanceof ElementContent ) or - node2 = node1.(LibraryCodeNode).getSuccessor(any(AccessPath ap | ap.getHead() = c)) + exists(Expr e | + e = node1.asExpr() and + node2.(YieldReturnNode).getYieldReturnStmt().getExpr() = e and + c instanceof ElementContent + ) + or + summaryStoreStep(node1, c, node2) + } + + pragma[nomagic] + private PropertyContent getResultContent() { + result.getProperty() = any(SystemThreadingTasksTaskTClass c_).getResultProperty() } /** @@ -506,9 +706,42 @@ private module Cached { exists(ReadStepConfiguration x | x.hasNodePath(node1, node2) and fieldOrPropertyRead(node1.asExpr(), c, node2.asExpr()) + or + x.hasNodePath(node1, node2) and + arrayRead(node1.asExpr(), node2.asExpr()) and + c instanceof ElementContent + or + exists(ForeachStmt fs, Ssa::ExplicitDefinition def | + x + .hasDefPath(fs.getIterableExpr(), node1.getControlFlowNode(), def.getADefinition(), + def.getControlFlowNode()) and + node2.(SsaDefinitionNode).getDefinition() = def and + c instanceof ElementContent + ) + or + x.hasNodePath(node1, node2) and + node2.asExpr().(AwaitExpr).getExpr() = node1.asExpr() and + c = getResultContent() ) or - node1 = node2.(LibraryCodeNode).getPredecessor(any(AccessPath ap | ap.getHead() = c)) + summaryReadStep(node1, c, node2) + } + + /** + * Holds if values stored inside content `c` are cleared at node `n`. For example, + * any value stored inside `f` is cleared at the pre-update node associated with `x` + * in `x.f = newValue`. + */ + cached + predicate clearsContent(Node n, Content c) { + fieldOrPropertyStore(_, c, _, n.asExpr(), true) + or + fieldOrPropertyStore(_, c, _, n.(ObjectInitializerNode).getInitializer(), false) + or + summaryStoreStep(n, c, _) and + not c instanceof ElementContent + or + summaryClearsContent(n, c) } /** @@ -523,16 +756,12 @@ private module Cached { viableConstantBooleanParamArg(paramNode, bs.getValue().booleanNot(), call) and paramNode.getDefinition() = param and param.getARead() = guard and - guard.controlsBlock(n.getControlFlowNode().getBasicBlock(), bs) + guard.controlsBlock(n.getControlFlowNode().getBasicBlock(), bs, _) ) } - /** - * Holds if GVNs `t1` and `t2` may have a common sub type. Neither `t1` nor - * `t2` are allowed to be type parameters. - */ - cached - predicate commonSubType(DataFlowType t1, DataFlowType t2) { + pragma[nomagic] + private predicate commonSubTypeGeneral(DataFlowTypeOrUnifiable t1, DataFlowType t2) { not t1 instanceof Gvn::TypeParameterGvnType and t1 = t2 or @@ -541,19 +770,75 @@ private module Cached { getANonTypeParameterSubType(t1) = getANonTypeParameterSubType(t2) } + /** + * Holds if GVNs `t1` and `t2` may have a common sub type. Neither `t1` nor + * `t2` are allowed to be type parameters. + */ + cached + predicate commonSubType(DataFlowType t1, DataFlowType t2) { commonSubTypeGeneral(t1, t2) } + cached predicate commonSubTypeUnifiableLeft(DataFlowType t1, DataFlowType t2) { - exists(DataFlowType t | + exists(Gvn::GvnType t | Gvn::unifiable(t1, t) and - commonSubType(t, t2) + commonSubTypeGeneral(t, t2) + ) + } + + cached + predicate outRefReturnNode(Ssa::ExplicitDefinition def, OutRefReturnKind kind) { + exists(Parameter p | + def.isLiveOutRefParameterDefinition(p) and + kind.getPosition() = p.getPosition() + | + p.isOut() and kind instanceof OutReturnKind + or + p.isRef() and kind instanceof RefReturnKind + ) + } + + cached + predicate qualifierOutNode(DataFlowCall call, Node n) { + n.(ExprPostUpdateNode).getPreUpdateNode().(ExplicitArgumentNode).argumentOf(call, -1) + or + any(ObjectOrCollectionInitializerConfiguration x) + .hasExprPath(_, n.(ExprNode).getControlFlowNode(), _, call.getControlFlowNode()) + } + + cached + predicate castNode(Node n) { + n.asExpr() instanceof Cast + or + n.(AssignableDefinitionNode).getDefinition() instanceof AssignableDefinitions::PatternDefinition + } + + /** Holds if `n` should be hidden from path explanations. */ + cached + predicate nodeIsHidden(Node n) { + exists(Ssa::Definition def | def = n.(SsaDefinitionNode).getDefinition() | + def instanceof Ssa::PseudoDefinition + or + def instanceof Ssa::ImplicitEntryDefinition + or + def instanceof Ssa::ImplicitCallDefinition ) + or + n instanceof YieldReturnNode + or + n instanceof ImplicitCapturedArgumentNode + or + n instanceof MallocNode + or + n instanceof Summaries::SummaryNodeImpl + or + n instanceof ParamsArgumentNode } } import Cached /** An SSA definition, viewed as a node in a data flow graph. */ -class SsaDefinitionNode extends Node, TSsaDefinitionNode { +class SsaDefinitionNode extends NodeImpl, TSsaDefinitionNode { Ssa::Definition def; SsaDefinitionNode() { this = TSsaDefinitionNode(def) } @@ -561,19 +846,23 @@ class SsaDefinitionNode extends Node, TSsaDefinitionNode { /** Gets the underlying SSA definition. */ Ssa::Definition getDefinition() { result = def } - override Callable getEnclosingCallable() { result = def.getEnclosingCallable() } + override Callable getEnclosingCallableImpl() { result = def.getEnclosingCallable() } + + override Type getTypeImpl() { result = def.getSourceVariable().getType() } - override Type getType() { result = def.getSourceVariable().getType() } + override ControlFlow::Node getControlFlowNodeImpl() { result = def.getControlFlowNode() } - override Location getLocation() { result = def.getLocation() } + override Location getLocationImpl() { result = def.getLocation() } - override string toString() { + override string toStringImpl() { not explicitParameterNode(this, _) and result = def.toString() } } private module ParameterNodes { + abstract private class ParameterNodeImpl extends ParameterNode, NodeImpl { } + /** * Holds if definition node `node` is an entry definition for parameter `p`. */ @@ -585,11 +874,12 @@ private module ParameterNodes { * The value of an explicit parameter at function entry, viewed as a node in a data * flow graph. */ - class ExplicitParameterNode extends ParameterNode { + class ExplicitParameterNode extends ParameterNodeImpl { private DotNet::Parameter parameter; ExplicitParameterNode() { - explicitParameterNode(this, parameter) or + explicitParameterNode(this, parameter) + or this = TCilParameterNode(parameter) } @@ -597,17 +887,19 @@ private module ParameterNodes { override predicate isParameterOf(DataFlowCallable c, int i) { c.getParameter(i) = parameter } - override DotNet::Callable getEnclosingCallable() { result = parameter.getCallable() } + override DataFlowCallable getEnclosingCallableImpl() { result = parameter.getCallable() } - override DotNet::Type getType() { result = parameter.getType() } + override DotNet::Type getTypeImpl() { result = parameter.getType() } - override Location getLocation() { result = parameter.getLocation() } + override ControlFlow::Node getControlFlowNodeImpl() { none() } - override string toString() { result = parameter.toString() } + override Location getLocationImpl() { result = parameter.getLocation() } + + override string toStringImpl() { result = parameter.toString() } } /** An implicit instance (`this`) parameter. */ - class InstanceParameterNode extends ParameterNode, TInstanceParameterNode { + class InstanceParameterNode extends ParameterNodeImpl, TInstanceParameterNode { private Callable callable; InstanceParameterNode() { this = TInstanceParameterNode(callable) } @@ -617,13 +909,15 @@ private module ParameterNodes { override predicate isParameterOf(DataFlowCallable c, int pos) { callable = c and pos = -1 } - override Callable getEnclosingCallable() { result = callable } + override Callable getEnclosingCallableImpl() { result = callable } + + override Type getTypeImpl() { result = callable.getDeclaringType() } - override Type getType() { result = callable.getDeclaringType() } + override ControlFlow::Node getControlFlowNodeImpl() { none() } - override Location getLocation() { result = callable.getLocation() } + override Location getLocationImpl() { result = callable.getLocation() } - override string toString() { result = "this" } + override string toStringImpl() { result = "this" } } module ImplicitCapturedParameterNodeImpl { @@ -692,11 +986,52 @@ private module ParameterNodes { c = this.getEnclosingCallable() } } + + /** A parameter node for a callable with a flow summary. */ + class SummaryParameterNode extends ParameterNodeImpl, Summaries::SummaryNodeImpl, + TSummaryParameterNode { + private SourceDeclarationCallable sdc; + private int i; + + SummaryParameterNode() { this = TSummaryParameterNode(sdc, i) } + + override Parameter getParameter() { result = sdc.getParameter(i) } + + override predicate isParameterOf(DataFlowCallable c, int pos) { + c = sdc and + pos = i + } + + override Callable getEnclosingCallableImpl() { result = sdc } + + override Type getTypeImpl() { + result = sdc.getParameter(i).getType() + or + i = -1 and + result = sdc.getDeclaringType() + } + + override ControlFlow::Node getControlFlowNodeImpl() { none() } + + override Location getLocationImpl() { + result = sdc.getParameter(i).getLocation() + or + i = -1 and + result = sdc.getLocation() + } + + override string toStringImpl() { + result = "[summary] " + sdc.getParameter(i) + or + i = -1 and + result = "[summary] this" + } + } } import ParameterNodes -/** A data flow node that represents a call argument. */ +/** A data-flow node that represents a call argument. */ abstract class ArgumentNode extends Node { /** Holds if this argument occurs at the given position in the given call. */ cached @@ -707,21 +1042,6 @@ abstract class ArgumentNode extends Node { } private module ArgumentNodes { - class DelegateArgumentConfiguration extends ControlFlowReachabilityConfiguration { - DelegateArgumentConfiguration() { this = "DelegateArgumentConfiguration" } - - override predicate candidate( - Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor - ) { - exists(DelegateArgumentToLibraryCallable arg | e1 = arg.getCall().getAnArgument() | - e2 = arg.getCall() and - scope = e2 and - exactScope = false and - isSuccessor = true - ) - } - } - private class ArgumentConfiguration extends ControlFlowReachabilityConfiguration { ArgumentConfiguration() { this = "ArgumentConfiguration" } @@ -735,8 +1055,8 @@ private module ArgumentNodes { } } - /** A data flow node that represents an explicit call argument. */ - private class ExplicitArgumentNode extends ArgumentNode { + /** A data-flow node that represents an explicit call argument. */ + class ExplicitArgumentNode extends ArgumentNode { ExplicitArgumentNode() { this.asExpr() instanceof Argument or @@ -776,7 +1096,7 @@ private module ArgumentNodes { * } } * ``` */ - class ImplicitCapturedArgumentNode extends ArgumentNode, TImplicitCapturedArgumentNode { + class ImplicitCapturedArgumentNode extends ArgumentNode, NodeImpl, TImplicitCapturedArgumentNode { private LocalScopeVariable v; private ControlFlow::Nodes::ElementNode cfn; @@ -795,39 +1115,30 @@ private module ArgumentNodes { override predicate argumentOf(DataFlowCall call, int pos) { exists(ImplicitCapturedParameterNode p, boolean additionalCalls | this.flowsInto(p, additionalCalls) and - p.isParameterOf(call.getARuntimeTarget(), pos) - | + p.isParameterOf(call.getARuntimeTarget(), pos) and + call.getControlFlowNode() = cfn and if call instanceof TransitiveCapturedDataFlowCall - then additionalCalls = true and call.getControlFlowNode() = cfn - else ( - additionalCalls = false and - ( - call.getControlFlowNode() = cfn - or - exists(DataFlowCall parent | - call.(ImplicitDelegateDataFlowCall).isArgumentOf(parent, _) - | - parent.getControlFlowNode() = cfn - ) - ) - ) + then additionalCalls = true + else additionalCalls = false ) } - override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() } + override Callable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } + + override Type getTypeImpl() { result = v.getType() } - override Type getType() { result = v.getType() } + override ControlFlow::Node getControlFlowNodeImpl() { none() } - override Location getLocation() { result = cfn.getLocation() } + override Location getLocationImpl() { result = cfn.getLocation() } - override string toString() { result = "[implicit argument] " + v } + override string toStringImpl() { result = "[implicit argument] " + v } } /** * A node that corresponds to the value of an object creation (`new C()`) before * the constructor has run. */ - class MallocNode extends ArgumentNode, TMallocNode { + class MallocNode extends ArgumentNode, NodeImpl, TMallocNode { private ControlFlow::Nodes::ElementNode cfn; MallocNode() { this = TMallocNode(cfn) } @@ -837,58 +1148,104 @@ private module ArgumentNodes { pos = -1 } - override ControlFlow::Node getControlFlowNode() { result = cfn } + override ControlFlow::Node getControlFlowNodeImpl() { result = cfn } - override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() } + override Callable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } - override Type getType() { result = cfn.getElement().(Expr).getType() } + override Type getTypeImpl() { result = cfn.getElement().(Expr).getType() } - override Location getLocation() { result = cfn.getLocation() } + override Location getLocationImpl() { result = cfn.getLocation() } - override string toString() { result = "malloc" } + override string toStringImpl() { result = "malloc" } } /** - * A data flow node that represents an implicit argument of an implicit delegate - * call in library code. For example, in + * A data-flow node that represents the implicit array creation in a call to a + * callable with a `params` parameter. For example, there is an implicit array + * creation `new [] { "a", "b", "c" }` in * * ```csharp - * x.Select(Foo); + * void Foo(params string[] args) { ... } + * Foo("a", "b", "c"); * ``` * - * `x` is an implicit argument of the implicit call to `Foo`. + * Note that array creations are not inserted when there is only one argument, + * and that argument is itself a compatible array, for example + * `Foo(new[] { "a", "b", "c" })`. */ - class ImplicitDelegateArgumentNode extends ArgumentNode, TImplicitDelegateArgumentNode { - private ControlFlow::Node cfn; - private int delegateIndex; - private int parameterIndex; + class ParamsArgumentNode extends ArgumentNode, NodeImpl, TParamsArgumentNode { + private ControlFlow::Node callCfn; - ImplicitDelegateArgumentNode() { - this = TImplicitDelegateArgumentNode(cfn, delegateIndex, parameterIndex) - } + ParamsArgumentNode() { this = TParamsArgumentNode(callCfn) } - private ImplicitDelegateDataFlowCall getDelegateCall() { result.getControlFlowNode() = cfn } + private Parameter getParameter() { + callCfn = any(Call c | isParamsArg(c, _, result)).getAControlFlowNode() + } override predicate argumentOf(DataFlowCall call, int pos) { - call = this.getDelegateCall() and - pos = parameterIndex + callCfn = call.getControlFlowNode() and + pos = this.getParameter().getPosition() } - override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() } + override Callable getEnclosingCallableImpl() { result = callCfn.getEnclosingCallable() } + + override Type getTypeImpl() { result = this.getParameter().getType() } + + override ControlFlow::Node getControlFlowNodeImpl() { none() } + + override Location getLocationImpl() { result = callCfn.getLocation() } + + override string toStringImpl() { result = "[implicit array creation] " + callCfn } + } + + /** + * An argument node inside a callable with a flow summary, where the argument is + * passed to a supplied delegate. For example, in `ints.Select(Foo)` there is a + * node that represents the argument of the call to `Foo` inside `Select`. + */ + class SummaryDelegateArgumentNode extends ArgumentNode, Summaries::SummaryNodeImpl, + TSummaryDelegateArgumentNode { + private SourceDeclarationCallable c; + private int delegateIndex; + private int parameterIndex; + + SummaryDelegateArgumentNode() { + this = TSummaryDelegateArgumentNode(c, delegateIndex, parameterIndex) + } - override Type getType() { - result = this.getDelegateCall().getDelegateParameterType(parameterIndex) + override DataFlowCallable getEnclosingCallableImpl() { result = c } + + override DotNet::Type getTypeImpl() { + result = + c + .getParameter(delegateIndex) + .getType() + .(SystemLinqExpressions::DelegateExtType) + .getDelegateType() + .getParameter(parameterIndex) + .getType() } - override Location getLocation() { result = cfn.getLocation() } + override ControlFlow::Node getControlFlowNodeImpl() { none() } + + override Location getLocationImpl() { result = c.getLocation() } - override string toString() { result = "[implicit argument " + parameterIndex + "] " + cfn } + override string toStringImpl() { + result = + "[summary] argument " + parameterIndex + " of delegate call, parameter " + parameterIndex + + " of " + c + } + + override predicate argumentOf(DataFlowCall call, int pos) { + call = TSummaryDelegateCall(c, delegateIndex) and + pos = parameterIndex + } } } import ArgumentNodes -/** A data flow node that represents a value returned by a callable. */ +/** A data-flow node that represents a value returned by a callable. */ abstract class ReturnNode extends Node { /** Gets the kind of this return node. */ abstract ReturnKind getKind(); @@ -896,7 +1253,7 @@ abstract class ReturnNode extends Node { private module ReturnNodes { /** - * A data flow node that represents an expression returned by a callable, + * A data-flow node that represents an expression returned by a callable, * either using a (`yield`) `return` statement or an expression body (`=>`). */ class ExprReturnNode extends ReturnNode, ExprNode { @@ -914,22 +1271,13 @@ private module ReturnNodes { } /** - * A data flow node that represents an assignment to an `out` or a `ref` + * A data-flow node that represents an assignment to an `out` or a `ref` * parameter. */ class OutRefReturnNode extends ReturnNode, SsaDefinitionNode { OutRefReturnKind kind; - OutRefReturnNode() { - exists(Parameter p | - this.getDefinition().(Ssa::ExplicitDefinition).isLiveOutRefParameterDefinition(p) and - kind.getPosition() = p.getPosition() - | - p.isOut() and kind instanceof OutReturnKind - or - p.isRef() and kind instanceof RefReturnKind - ) - } + OutRefReturnNode() { outRefReturnNode(this.getDefinition(), kind) } override ReturnKind getKind() { result = kind } } @@ -939,7 +1287,7 @@ private module ReturnNodes { * `yield return`s as stores into collections, i.e., there is flow from `e` * to `yield return e [e]`. */ - class YieldReturnNode extends ReturnNode, PostUpdateNode, TYieldReturnNode { + class YieldReturnNode extends ReturnNode, NodeImpl, TYieldReturnNode { private ControlFlow::Nodes::ElementNode cfn; private YieldReturnStmt yrs; @@ -949,15 +1297,15 @@ private module ReturnNodes { override YieldReturnKind getKind() { any() } - override ExprNode getPreUpdateNode() { result.getControlFlowNode() = cfn } + override Callable getEnclosingCallableImpl() { result = yrs.getEnclosingCallable() } - override Callable getEnclosingCallable() { result = yrs.getEnclosingCallable() } + override Type getTypeImpl() { result = yrs.getEnclosingCallable().getReturnType() } - override Type getType() { result = yrs.getEnclosingCallable().getReturnType() } + override ControlFlow::Node getControlFlowNodeImpl() { result = cfn } - override Location getLocation() { result = yrs.getLocation() } + override Location getLocationImpl() { result = yrs.getLocation() } - override string toString() { result = yrs.toString() } + override string toStringImpl() { result = yrs.toString() } } /** @@ -998,11 +1346,39 @@ private module ReturnNodes { result.getVariable() = edef.getSourceVariable().getAssignable() } } + + /** A return node for a callable with a flow summary. */ + class SummaryReturnNode extends ReturnNode, Summaries::SummaryNodeImpl, TSummaryReturnNode { + private SourceDeclarationCallable sdc; + private ReturnKind rk; + + SummaryReturnNode() { this = TSummaryReturnNode(sdc, rk) } + + override Callable getEnclosingCallableImpl() { result = sdc } + + override DotNet::Type getTypeImpl() { + rk instanceof NormalReturnKind and + result in [sdc.getReturnType(), sdc.(Constructor).getDeclaringType()] + or + rk instanceof QualifierReturnKind and + result = sdc.getDeclaringType() + or + result = sdc.getParameter(rk.(OutRefReturnKind).getPosition()).getType() + } + + override ControlFlow::Node getControlFlowNodeImpl() { none() } + + override Location getLocationImpl() { result = sdc.getLocation() } + + override string toStringImpl() { result = "[summary] return of kind " + rk + " inside " + sdc } + + override ReturnKind getKind() { result = rk } + } } import ReturnNodes -/** A data flow node that represents the output of a call. */ +/** A data-flow node that represents the output of a call. */ abstract class OutNode extends Node { /** Gets the underlying call, where this node is a corresponding output of kind `kind`. */ cached @@ -1034,7 +1410,7 @@ private module OutNodes { } /** - * A data flow node that reads a value returned directly by a callable, + * A data-flow node that reads a value returned directly by a callable, * either via a C# call or a CIL call. */ class ExprOutNode extends OutNode, ExprNode { @@ -1060,8 +1436,44 @@ private module OutNodes { } } + class ObjectOrCollectionInitializerConfiguration extends ControlFlowReachabilityConfiguration { + ObjectOrCollectionInitializerConfiguration() { + this = "ObjectOrCollectionInitializerConfiguration" + } + + override predicate candidate( + Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor + ) { + exactScope = false and + scope = e1 and + isSuccessor = false and + ( + // E.g. `new Dictionary{ {0, "a"}, {1, "b"} }` + e1.(CollectionInitializer).getAnElementInitializer() = e2 + or + // E.g. `new Dictionary() { [0] = "a", [1] = "b" }` + e1.(ObjectInitializer).getAMemberInitializer().getLValue() = e2 + ) + } + } + + /** + * A data-flow node that contains a value returned by a callable, by writing + * to the qualifier of the call. + */ + private class QualifierOutNode extends OutNode, Node { + private DataFlowCall call; + + QualifierOutNode() { qualifierOutNode(call, this) } + + override DataFlowCall getCall(ReturnKind kind) { + result = call and + kind instanceof QualifierReturnKind + } + } + /** - * A data flow node that reads a value returned implicitly by a callable + * A data-flow node that reads a value returned implicitly by a callable * using a captured variable. */ class CapturedOutNode extends OutNode, SsaDefinitionNode { @@ -1074,10 +1486,8 @@ private module OutNodes { | additionalCalls = false and call = csharpCall(_, cfn) or - additionalCalls = false and - call.(ImplicitDelegateDataFlowCall).isArgumentOf(csharpCall(_, cfn), _) - or - additionalCalls = true and call = TTransitiveCapturedCall(cfn, n.getEnclosingCallable()) + additionalCalls = true and + call = TTransitiveCapturedCall(cfn, n.getEnclosingCallable()) ) } @@ -1089,7 +1499,7 @@ private module OutNodes { } /** - * A data flow node that reads a value returned by a callable using an + * A data-flow node that reads a value returned by a callable using an * `out` or `ref` parameter. */ class ParamOutNode extends OutNode, AssignableDefinitionNode { @@ -1108,331 +1518,357 @@ private module OutNodes { } /** - * A data flow node that represents the output of an implicit delegate call, - * in a call to a library method. For example, the output from the implicit - * call to `M` in `new Lazy(M)`. + * An output node inside a callable with a flow summary, where the output is the + * result of calling a supplied delegate. For example, in `ints.Select(Foo)` there + * is a node that represents the output of calling `Foo` inside `Select`. */ - class ImplicitDelegateOutNode extends OutNode, TImplicitDelegateOutNode { - private ControlFlow::Nodes::ElementNode cfn; - private ControlFlow::Nodes::ElementNode call; - - ImplicitDelegateOutNode() { this = TImplicitDelegateOutNode(cfn, call) } - - /** - * Holds if the underlying delegate argument is the `i`th argument of the - * call `c` targeting a library callable. For example, `M` is the `0`th - * argument of `new Lazy(M)`. - */ - predicate isArgumentOf(DataFlowCall c, int i) { - c.getControlFlowNode() = call and - call.getElement().(Call).getArgument(i) = cfn.getElement() + private class SummaryDelegateOutNode extends OutNode, Summaries::SummaryNodeImpl, + TSummaryDelegateOutNode { + private SourceDeclarationCallable c; + private int pos; + + SummaryDelegateOutNode() { this = TSummaryDelegateOutNode(c, pos) } + + override Callable getEnclosingCallableImpl() { result = c } + + override DotNet::Type getTypeImpl() { + result = + c + .getParameter(pos) + .getType() + .(SystemLinqExpressions::DelegateExtType) + .getDelegateType() + .getReturnType() } - override ControlFlow::Nodes::ElementNode getControlFlowNode() { result = cfn } + override ControlFlow::Node getControlFlowNodeImpl() { none() } - override ImplicitDelegateDataFlowCall getCall(ReturnKind kind) { - result.getNode() = this and - ( - kind instanceof NormalReturnKind and - not result.getDelegateReturnType() instanceof VoidType - or - kind instanceof YieldReturnKind and - result.getDelegateReturnType() instanceof YieldReturnType - ) - } + override Location getLocationImpl() { result = c.getLocation() } - override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() } - - override Type getType() { - exists(ImplicitDelegateDataFlowCall c | c.getNode() = this | - result = c.getDelegateReturnType() - ) + override string toStringImpl() { + result = "[summary] output from delegate call, parameter " + pos + " of " + c + "]" } - override Location getLocation() { result = cfn.getLocation() } - - override string toString() { result = "[output] " + cfn } + override SummaryDelegateCall getCall(ReturnKind kind) { + result = TSummaryDelegateCall(c, pos) and + kind instanceof NormalReturnKind + } } } import OutNodes /** - * Provides predicates related to flow through library code, based on - * the flow summaries in `LibraryTypeDataFlow.qll`. + * Provides predicates for interpreting flow summaries defined in + * `LibraryTypeDataFlow.qll`. */ -module LibraryFlow { - pragma[nomagic] - private ValueOrRefType getPreciseSourceProperty0( - Call call, CallableFlowSource source, AccessPath sourceAp, Property p - ) { - exists(LibraryTypeDataFlow ltdf, Property p0 | - ltdf.callableFlow(source, sourceAp, _, _, call.getTarget().getSourceDeclaration()) and - sourceAp = AccessPath::property(p0) and - overridesOrImplementsSourceDecl(p, p0) and - result = source.getSourceType(call) - ) - } +module Summaries { + /** A data-flow node used to interpret a flow summary. */ + abstract class SummaryNodeImpl extends NodeImpl { } /** - * Gets a precise source property for source `source` and access path `sourceAp`, - * in the context of `call`. For example, in - * - * ```csharp - * var list = new List(); - * var count = list.Count(); - * ``` + * Holds if data can flow from a node of kind `source` to a node of kind `sink`, + * using a call to a callable with a flow summary. * - * the step from `list` to `list.Count()`, which may be modeled as a read of - * the `Count` property from `ICollection`, can be strengthened to be a - * read of the `Count` property from `List`. + * `sourceAp` describes the contents of the source node that flows to the sink + * (if any), and `sinkAp` describes the contents of the sink that it flows to + * (if any). */ pragma[nomagic] - private Property getPreciseSourceProperty( - Call call, CallableFlowSource source, AccessPath sourceAp + predicate summary( + SourceDeclarationCallable c, CallableFlowSource source, AccessPath sourceAp, + CallableFlowSink sink, AccessPath sinkAp, boolean preservesValue ) { - getPreciseSourceProperty0(call, source, sourceAp, result).hasMember(result) + any(LibraryTypeDataFlow ltdf).callableFlow(source, sink, c, preservesValue) and + sourceAp = AccessPath::empty() and + sinkAp = AccessPath::empty() + or + any(LibraryTypeDataFlow ltdf).callableFlow(source, sourceAp, sink, sinkAp, c, preservesValue) } - pragma[nomagic] - private ValueOrRefType getPreciseSinkProperty0( - Call call, CallableFlowSink sink, AccessPath sinkAp, Property p - ) { - exists(LibraryTypeDataFlow ltdf, Property p0 | - ltdf.callableFlow(_, _, sink, sinkAp, call.getTarget().getSourceDeclaration()) and - sinkAp = AccessPath::property(p0) and - overridesOrImplementsSourceDecl(p, p0) and - result = sink.getSinkType(call) - ) + /** Gets the return kind that matches `sink`, if any. */ + ReturnKind toReturnKind(CallableFlowSink sink) { + sink instanceof CallableFlowSinkQualifier and result instanceof QualifierReturnKind + or + sink instanceof CallableFlowSinkReturn and result instanceof NormalReturnKind + or + sink.(CallableFlowSinkArg).getArgumentIndex() = result.(OutRefReturnKind).getPosition() } + newtype TSummaryInternalNodeState = + TSummaryInternalNodeAfterReadState(AccessPath ap) { ap.length() > 0 } or + TSummaryInternalNodeBeforeStoreState(AccessPath ap) { ap.length() > 0 } + /** - * Gets a precise sink property for sink `sink` and access path `sinkAp`, - * in the context of `call`. For example, in + * A state used to break up (complex) flow summaries for library code into atomic + * flow steps. For a flow summary with source access path `sourceAp` and sink + * access path `sinkAp`, the following states are used: * - * ```csharp - * var list = new List(); - * list.Add("taint"); - * var enumerator = list.getEnumerator(); - * ``` + * - `TSummaryInternalNodeAfterReadState(AccessPath ap)`: this state represents + * that the head of `ap` has been read from, where `ap` is a suffix of + * `sourceAp`. + * - `TSummaryInternalNodeBeforeStoreState(AccessPath ap)`: this state represents + * that the head of `ap` is to be stored into next, where `ap` is a suffix of + * `sinkAp`. * - * the step from `list` to `list.getEnumerator()`, which may be modeled as a - * read of a collection element followed by a store into the `Current` - * property, can be strengthened to be a store into the `Current` property - * from `List.Enumerator`, rather than the generic `Current` property - * from `IEnumerator`. + * The state machine for flow summaries has no branching, hence from the entry + * state there is a unique path to the exit state. */ - pragma[nomagic] - private Property getPreciseSinkProperty(Call call, CallableFlowSink sink, AccessPath sinkAp) { - getPreciseSinkProperty0(call, sink, sinkAp, result).hasMember(result) + class SummaryInternalNodeState extends TSummaryInternalNodeState { + string toString() { + exists(AccessPath ap | + this = TSummaryInternalNodeAfterReadState(ap) and + result = "after read: " + ap + ) + or + exists(AccessPath ap | + this = TSummaryInternalNodeBeforeStoreState(ap) and + result = "before store: " + ap + ) + } + + /** Holds if this state represents the state after the last read. */ + predicate isLastReadState() { + this = TSummaryInternalNodeAfterReadState(AccessPath::singleton(_)) + } + + /** Holds if this state represents the state before the first store. */ + predicate isFirstStoreState() { + this = TSummaryInternalNodeBeforeStoreState(AccessPath::singleton(_)) + } + } + + private NodeImpl getSourceNode(SourceDeclarationCallable c, CallableFlowSource source) { + exists(int i | result = TSummaryParameterNode(c, i) | + source instanceof CallableFlowSourceQualifier and i = -1 + or + i = source.(CallableFlowSourceArg).getArgumentIndex() + ) + or + result = TSummaryDelegateOutNode(c, source.(CallableFlowSourceDelegateArg).getArgumentIndex()) + } + + private NodeImpl getSinkNode(SourceDeclarationCallable c, CallableFlowSink sink) { + result = TSummaryReturnNode(c, toReturnKind(sink)) + or + sink = + any(CallableFlowSinkDelegateArg s | + result = + TSummaryDelegateArgumentNode(c, s.getDelegateIndex(), s.getDelegateParameterIndex()) + ) } /** - * Holds if data can flow from a node of kind `source` to a node of kind `sink`, - * using a call to a library callable. - * - * `sourceAp` describes the contents of the source node that flows to the sink - * (if any), and `sinkAp` describes the contents of the sink that it flows to - * (if any). - * - * `preservesValue = false` implies that both `sourceAp` and `sinkAp` are empty. + * Holds if there is a local step from `pred` to `succ`, which is synthesized + * from a flow summary. */ - pragma[nomagic] - predicate libraryFlow( - Call call, CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, - AccessPath sinkAp, boolean preservesValue - ) { - exists(LibraryTypeDataFlow ltdf, SourceDeclarationCallable c | - c = call.getTarget().getSourceDeclaration() + predicate summaryLocalStep(Node pred, Node succ, boolean preservesValue) { + exists( + SourceDeclarationCallable c, CallableFlowSource source, AccessPath sourceAp, + CallableFlowSink sink, AccessPath sinkAp + | + pred = getSourceNode(c, source) | - ltdf.callableFlow(source, sink, c, preservesValue) and + // Simple flow summary without reads or stores sourceAp = AccessPath::empty() and - sinkAp = AccessPath::empty() + sinkAp = AccessPath::empty() and + summary(c, source, sourceAp, sink, sinkAp, preservesValue) and + succ = getSinkNode(c, sink) or - preservesValue = true and - exists(AccessPath sourceAp0, AccessPath sinkAp0 | - ltdf.callableFlow(source, sourceAp0, sink, sinkAp0, c) and - ( - not sourceAp0 = AccessPath::property(_) and - sourceAp = sourceAp0 - or - exists(Property p | - overridesOrImplementsSourceDecl(p, - getPreciseSourceProperty(call, source, sourceAp0).getSourceDeclaration()) and - sourceAp = AccessPath::property(p) - ) - ) and - ( - not sinkAp0 = AccessPath::property(_) and - sinkAp = sinkAp0 - or - sinkAp = AccessPath::property(getPreciseSinkProperty(call, sink, sinkAp0)) - ) + // Flow summary with stores but no reads + exists(SummaryInternalNodeState succState | + sourceAp = AccessPath::empty() and + succState.isFirstStoreState() and + succ = TSummaryInternalNode(c, source, sourceAp, sink, sinkAp, preservesValue, succState) ) ) + or + // Exit step after last read (no stores) + exists( + SourceDeclarationCallable c, SummaryInternalNodeState predState, CallableFlowSink sink, + AccessPath sinkAp + | + sinkAp = AccessPath::empty() and + predState.isLastReadState() and + pred = TSummaryInternalNode(c, _, _, sink, sinkAp, preservesValue, predState) and + succ = getSinkNode(c, sink) + ) + or + // Internal step for complex flow summaries with both reads and writes + exists( + SourceDeclarationCallable c, CallableFlowSource source, AccessPath sourceAp, + CallableFlowSink sink, AccessPath sinkAp, SummaryInternalNodeState predState, + SummaryInternalNodeState succState + | + predState.isLastReadState() and + pred = TSummaryInternalNode(c, source, sourceAp, sink, sinkAp, preservesValue, predState) and + succState.isFirstStoreState() and + succ = TSummaryInternalNode(c, source, sourceAp, sink, sinkAp, preservesValue, succState) + ) } - class LibrarySourceConfiguration extends ControlFlowReachabilityConfiguration { - LibrarySourceConfiguration() { this = "LibrarySourceConfiguration" } - - override predicate candidate( - Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor - ) { - exists(CallableFlowSource source | - libraryFlow(e2, source, _, _, _, _) and - e1 = source.getSource(e2) and - scope = e2 and - exactScope = false and - isSuccessor = true + /** + * Holds if data can flow from `pred` to `succ` via an assignment to + * content `c`, using a flow summary. + */ + predicate summaryStoreStep(Node pred, Content c, Node succ) { + exists( + SourceDeclarationCallable sdc, CallableFlowSource source, AccessPath sourceAp, + CallableFlowSink sink, AccessPath sinkAp, boolean preservesValue, + SummaryInternalNodeState predState, AccessPath predAp + | + predState = TSummaryInternalNodeBeforeStoreState(predAp) and + pred = TSummaryInternalNode(sdc, source, sourceAp, sink, sinkAp, preservesValue, predState) and + c = predAp.getHead() + | + // More stores needed + exists(SummaryInternalNodeState succState | + succState = + TSummaryInternalNodeBeforeStoreState(any(AccessPath succAp | succAp.getTail() = predAp)) and + succ = TSummaryInternalNode(sdc, source, sourceAp, sink, sinkAp, preservesValue, succState) ) - } + or + // Last store + predAp = sinkAp and + succ = getSinkNode(sdc, sink) + ) } - class LibrarySinkConfiguration extends ControlFlowReachabilityConfiguration { - LibrarySinkConfiguration() { this = "LibrarySinkConfiguration" } - - override predicate candidate( - Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor - ) { - exists(CallableFlowSink sink | - libraryFlow(e1, _, _, sink, _, _) and - e2 = sink.getSink(e1) and - scope = e1 and - exactScope = false and - isSuccessor = false - ) - } - - override predicate candidateDef( - Expr e, AssignableDefinition def, ControlFlowElement scope, boolean exactScope, - boolean isSuccessor - ) { - exists(CallableFlowSinkArg sink | - libraryFlow(e, _, _, sink, _, _) and - scope = e and - exactScope = false and - isSuccessor = true and - def.getTargetAccess() = sink.getArgument(e) and - def instanceof AssignableDefinitions::OutRefDefinition + /** + * Holds if data can flow from `pred` to `succ` via a read of content `c`, + * using library code. + */ + predicate summaryReadStep(Node pred, Content c, Node succ) { + exists( + SourceDeclarationCallable sdc, CallableFlowSource source, AccessPath sourceAp, + CallableFlowSink sink, AccessPath sinkAp, boolean preservesValue, + SummaryInternalNodeState succState, AccessPath succAp + | + succState = TSummaryInternalNodeAfterReadState(succAp) and + succ = TSummaryInternalNode(sdc, source, sourceAp, sink, sinkAp, preservesValue, succState) and + c = succAp.getHead() + | + // First read + succAp = sourceAp and + pred = getSourceNode(sdc, source) + or + // Subsequent reads + exists(SummaryInternalNodeState predState, AccessPath predAp | + predState = TSummaryInternalNodeAfterReadState(predAp) and + predAp.getTail() = succAp and + pred = TSummaryInternalNode(sdc, source, sourceAp, sink, sinkAp, preservesValue, predState) ) - } + ) } -} -/** A data-flow node used to model flow through library code. */ -class LibraryCodeNode extends Node, TLibraryCodeNode { - private ControlFlow::Node callCfn; - private CallableFlowSource source; - private AccessPath sourceAp; - private CallableFlowSink sink; - private AccessPath sinkAp; - private boolean preservesValue; + pragma[nomagic] + private SummaryParameterNode summaryArgParam(ArgumentNode arg, ReturnKind rk, OutNode out) { + exists(DataFlowCall call, int pos, SourceDeclarationCallable sdc | + arg.argumentOf(call, pos) and + call.getARuntimeTarget() = sdc and + result = TSummaryParameterNode(sdc, pos) and + call = out.getCall(rk) + ) + } - LibraryCodeNode() { - this = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue) + /** + * Holds if `arg` flows to `out` using a simple flow summary, that is, a flow + * summary without delegates, reads, and stores. + */ + predicate summaryThroughStep(ArgumentNode arg, OutNode out, boolean preservesValue) { + exists(ReturnKind rk | + summaryLocalStep(summaryArgParam(arg, rk, out), TSummaryReturnNode(_, rk), preservesValue) + ) } - /** Holds if this node is part of a value-preserving library step. */ - predicate preservesValue() { preservesValue = true } + /** + * Holds if there is a (taint+)store of `arg` into content `c` of `out` using a + * flow summary. + */ + predicate summarySetterStep(ArgumentNode arg, Content c, OutNode out) { + exists(ReturnKind rk, Node mid | + summaryLocalStep(summaryArgParam(arg, rk, out), mid, _) and + summaryStoreStep(mid, c, TSummaryReturnNode(_, rk)) + ) + } /** - * Gets the predecessor of this library-code node. The head of `ap` describes - * the content that is read from when entering this node (if any). + * Holds if there is a read(+taint) of `c` from `arg` to `out` using a + * flow summary. */ - Node getPredecessor(AccessPath ap) { - ap = sourceAp and - ( - // The source is either an argument or a qualifier, for example - // `s` in `int.Parse(s)` - exists(LibraryFlow::LibrarySourceConfiguration x, Call call | - callCfn = call.getAControlFlowNode() and - x.hasExprPath(source.getSource(call), result.(ExprNode).getControlFlowNode(), _, callCfn) - ) - or - // The source is the output of a supplied delegate argument, for - // example the output of `Foo` in `new Lazy(Foo)` - exists(DataFlowCall call, int pos | - pos = source.(CallableFlowSourceDelegateArg).getArgumentIndex() and - result.(ImplicitDelegateOutNode).isArgumentOf(call, pos) and - callCfn = call.getControlFlowNode() - ) + predicate summaryGetterStep(ArgumentNode arg, Content c, OutNode out) { + exists(ReturnKind rk, Node mid | + summaryReadStep(summaryArgParam(arg, rk, out), c, mid) and + summaryLocalStep(mid, TSummaryReturnNode(_, rk), _) ) } /** - * Gets the successor of this library-code node. The head of `ap` describes - * the content that is stored into when leaving this node (if any). + * Holds if values stored inside content `c` are cleared at node `n`, as a result + * of calling a library method. */ - Node getSuccessor(AccessPath ap) { - ap = sinkAp and - ( - exists(LibraryFlow::LibrarySinkConfiguration x, Call call, ExprNode e | - callCfn = call.getAControlFlowNode() and - x.hasExprPath(_, callCfn, sink.getSink(call), e.getControlFlowNode()) - | - // The sink is an ordinary return value, for example `int.Parse(s)` - sink instanceof CallableFlowSinkReturn and - result = e - or - // The sink is a qualifier, for example `list` in `list.Add(x)` - sink instanceof CallableFlowSinkQualifier and - if sinkAp = AccessPath::empty() - then result = e - else result.(ExprPostUpdateNode).getPreUpdateNode() = e - ) + predicate summaryClearsContent(Node n, Content c) { + exists(LibraryTypeDataFlow ltdf, CallableFlowSource source, Call call | + ltdf.clearsContent(source, c, call.getTarget().getSourceDeclaration()) and + n.asExpr() = source.getSource(call) + ) + } + + /** Gets the type of content `c`. */ + pragma[noinline] + private Gvn::GvnType getContentType(Content c) { + exists(Type t | result = Gvn::getGlobalValueNumber(t) | + t = c.(FieldContent).getField().getType() or - // The sink is an `out`/`ref` argument, for example `out i` in - // `int.TryParse(s, out i)` - exists(LibraryFlow::LibrarySinkConfiguration x, OutRefReturnKind k | - result = - any(ParamOutNode out | - out.getCall(k).getControlFlowNode() = callCfn and - sink.(CallableFlowSinkArg).getArgumentIndex() = k.getPosition() and - x.hasDefPath(_, callCfn, out.getDefinition(), _) - ) - ) + t = c.(PropertyContent).getProperty().getType() or - // The sink is a parameter of a supplied delegate argument, for example - // the parameter of `Foo` in `list.Select(Foo)`. - // - // This is implemented using a node that represents the implicit argument - // (`ImplicitDelegateArgumentNode`) of the implicit call - // (`ImplicitDelegateDataFlowCall`) to `Foo`. - exists( - DataFlowCall call, ImplicitDelegateDataFlowCall dcall, int delegateIndex, int parameterIndex - | - sink = - any(CallableFlowSinkDelegateArg s | - delegateIndex = s.getDelegateIndex() and - parameterIndex = s.getDelegateParameterIndex() - ) and - result = TImplicitDelegateArgumentNode(dcall.getControlFlowNode(), _, parameterIndex) and - dcall.isArgumentOf(call, delegateIndex) and - callCfn = call.getControlFlowNode() - ) + c instanceof ElementContent and + t instanceof ObjectType // we don't know what the actual element type is ) } - override Callable getEnclosingCallable() { result = callCfn.getEnclosingCallable() } + /** A data-flow node used to model flow summaries. */ + private class SummaryInternalNode extends SummaryNodeImpl, TSummaryInternalNode { + private SourceDeclarationCallable c; + private CallableFlowSource source; + private AccessPath sourceAp; + private CallableFlowSink sink; + private AccessPath sinkAp; + private boolean preservesValue; + private SummaryInternalNodeState state; - override DataFlowType getTypeBound() { - preservesValue = true and - sourceAp = AccessPath::empty() and - result = this.getPredecessor(_).getTypeBound() - or - result = sourceAp.getHead().getType() - or - preservesValue = false and - result = this.getSuccessor(_).getTypeBound() - } + SummaryInternalNode() { + this = TSummaryInternalNode(c, source, sourceAp, sink, sinkAp, preservesValue, state) + } + + override DataFlowCallable getEnclosingCallableImpl() { result = c } + + override Gvn::GvnType getDataFlowType() { + exists(AccessPath ap | + state = TSummaryInternalNodeAfterReadState(ap) and + if sinkAp.length() = 0 and state.isLastReadState() and preservesValue = true + then result = getSinkNode(c, sink).getDataFlowType() + else result = getContentType(ap.getHead()) + or + state = TSummaryInternalNodeBeforeStoreState(ap) and + if sourceAp.length() = 0 and state.isFirstStoreState() and preservesValue = true + then result = getSourceNode(c, source).getDataFlowType() + else result = getContentType(ap.getHead()) + ) + } + + override DotNet::Type getTypeImpl() { none() } - override Location getLocation() { result = callCfn.getLocation() } + override ControlFlow::Node getControlFlowNodeImpl() { none() } - override string toString() { result = "[library code] " + callCfn } + override Location getLocationImpl() { result = c.getLocation() } + + override string toStringImpl() { result = "[summary] " + state + " in " + c } + } } /** A field or a property. */ -private class FieldOrProperty extends Assignable, Modifiable { +class FieldOrProperty extends Assignable, Modifiable { FieldOrProperty() { this instanceof Field or @@ -1516,12 +1952,14 @@ private class StoreStepConfiguration extends ControlFlowReachabilityConfiguratio Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor ) { exactScope = false and - isSuccessor = false and - fieldOrPropertyAssign(scope, _, e1, e2) + fieldOrPropertyStore(scope, _, e1, e2, isSuccessor.booleanNot()) + or + exactScope = false and + arrayStore(scope, e1, e2, isSuccessor.booleanNot()) or exactScope = false and - isSuccessor = false and - fieldOrPropertyInit(e2, _, e1) and + isSuccessor = true and + isParamsArg(e2, e1, _) and scope = e2 } } @@ -1538,12 +1976,60 @@ private class ReadStepConfiguration extends ControlFlowReachabilityConfiguration isSuccessor = true and fieldOrPropertyRead(e1, _, e2) and scope = e2 + or + exactScope = false and + isSuccessor = true and + arrayRead(e1, e2) and + scope = e2 + or + exactScope = false and + e1 = e2.(AwaitExpr).getExpr() and + scope = e2 and + isSuccessor = true + } + + override predicate candidateDef( + Expr e, AssignableDefinition defTo, ControlFlowElement scope, boolean exactScope, + boolean isSuccessor + ) { + exists(ForeachStmt fs | + e = fs.getIterableExpr() and + defTo.(AssignableDefinitions::LocalVariableDefinition).getDeclaration() = + fs.getVariableDeclExpr() and + isSuccessor = true + | + scope = fs and + exactScope = true + or + scope = fs.getIterableExpr() and + exactScope = false + or + scope = fs.getVariableDeclExpr() and + exactScope = false + ) } } predicate readStep = readStepImpl/3; -/** Gets a string representation of a type returned by `getErasedRepr`. */ +/** + * An entity used to represent the type of data-flow node. Two nodes will have + * the same `DataFlowType` when the underlying `Type`s are structurally equal + * modulo type parameters and identity conversions. + * + * For example, `Func` and `Func` are mapped to the same + * `DataFlowType`, while `Func` and `Func` are not, because + * `string` is not a type parameter. + */ +class DataFlowType extends Gvn::GvnType { + pragma[nomagic] + DataFlowType() { this = any(NodeImpl n).getDataFlowType() } +} + +/** Gets the type of `n` used for type pruning. */ +DataFlowType getNodeType(NodeImpl n) { result = n.getDataFlowType() } + +/** Gets a string representation of a `DataFlowType`. */ string ppReprType(DataFlowType t) { result = t.toString() } private class DataFlowNullType extends DataFlowType { @@ -1595,25 +2081,68 @@ abstract class PostUpdateNode extends Node { private module PostUpdateNodes { class ObjectCreationNode extends PostUpdateNode, ExprNode, TExprNode { - ObjectCreationNode() { exists(ObjectCreation oc | this = TExprNode(oc.getAControlFlowNode())) } + private ObjectCreation oc; + + ObjectCreationNode() { this = TExprNode(oc.getAControlFlowNode()) } + + override Node getPreUpdateNode() { + exists(ControlFlow::Nodes::ElementNode cfn | this = TExprNode(cfn) | + result.(ObjectInitializerNode).getControlFlowNode() = cfn + or + not oc.hasInitializer() and + result.(MallocNode).getControlFlowNode() = cfn + ) + } + } + + /** + * A node that represents the value of a newly created object after the object + * has been created, but before the object initializer has been executed. + * + * Such a node acts as both a post-update node for the `MallocNode`, as well as + * a pre-update node for the `ObjectCreationNode`. + */ + class ObjectInitializerNode extends PostUpdateNode, NodeImpl, TObjectInitializerNode { + private ObjectCreation oc; + private ControlFlow::Nodes::ElementNode cfn; + + ObjectInitializerNode() { + this = TObjectInitializerNode(cfn) and + cfn = oc.getAControlFlowNode() + } + + /** Gets the initializer to which this initializer node belongs. */ + ObjectOrCollectionInitializer getInitializer() { result = oc.getInitializer() } + + override MallocNode getPreUpdateNode() { result.getControlFlowNode() = cfn } + + override Callable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } - override MallocNode getPreUpdateNode() { this = TExprNode(result.getControlFlowNode()) } + override DotNet::Type getTypeImpl() { result = oc.getType() } + + override ControlFlow::Nodes::ElementNode getControlFlowNodeImpl() { result = cfn } + + override Location getLocationImpl() { result = cfn.getLocation() } + + override string toStringImpl() { result = "[pre-initializer] " + cfn } } - class ExprPostUpdateNode extends PostUpdateNode, TExprPostUpdateNode { + class ExprPostUpdateNode extends PostUpdateNode, NodeImpl, TExprPostUpdateNode { private ControlFlow::Nodes::ElementNode cfn; ExprPostUpdateNode() { this = TExprPostUpdateNode(cfn) } override ExprNode getPreUpdateNode() { cfn = result.getControlFlowNode() } - override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() } + override Callable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } + + override Type getTypeImpl() { result = cfn.getElement().(Expr).getType() } - override Type getType() { result = cfn.getElement().(Expr).getType() } + override ControlFlow::Node getControlFlowNodeImpl() { none() } - override Location getLocation() { result = cfn.getLocation() } + override Location getLocationImpl() { result = cfn.getLocation() } - override string toString() { result = "[post] " + cfn.toString() } + override string toStringImpl() { result = "[post] " + cfn.toString() } } } @@ -1621,22 +2150,11 @@ private import PostUpdateNodes /** A node that performs a type cast. */ class CastNode extends Node { - CastNode() { - this.asExpr() instanceof Cast - or - this.(AssignableDefinitionNode).getDefinition() instanceof - AssignableDefinitions::PatternDefinition - or - readStep(_, _, this) - or - storeStep(this, _, _) - } + CastNode() { castNode(this) } } class DataFlowExpr = DotNet::Expr; -class DataFlowType = Gvn::GvnType; - /** Holds if `e` is an expression that always has the same Boolean value `val`. */ private predicate constantBooleanExpr(Expr e, boolean val) { e = any(AbstractValues::BooleanValue bv | val = bv.getValue()).getAnExpr() @@ -1666,7 +2184,7 @@ private predicate viableConstantBooleanParamArg( ) } -int accessPathLimit() { result = 3 } +int accessPathLimit() { result = 5 } /** * Holds if `n` does not require a `PostUpdateNode` as it either cannot be @@ -1676,6 +2194,3 @@ int accessPathLimit() { result = 3 } * This predicate is only used for consistency checks. */ predicate isImmutableOrUnobservable(Node n) { none() } - -pragma[inline] -DataFlowType getErasedRepr(DataFlowType t) { result = t } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll index 328db073d6e9..bf012e53283f 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll @@ -39,35 +39,37 @@ class Node extends TNode { /** Gets the type of this node. */ cached - DotNet::Type getType() { none() } - - /** INTERNAL: Do not use. Gets an upper bound on the type of this node. */ - cached - DataFlowType getTypeBound() { - Stages::DataFlowStage::forceCachingInSameStage() and - exists(Type t0 | result = Gvn::getGlobalValueNumber(t0) | - t0 = getCSharpType(this.getType()) - or - not exists(getCSharpType(this.getType())) and - t0 instanceof ObjectType - ) + final DotNet::Type getType() { + Stages::DataFlowStage::forceCachingInSameStage() and result = this.(NodeImpl).getTypeImpl() } /** Gets the enclosing callable of this node. */ cached - DataFlowCallable getEnclosingCallable() { none() } + final DataFlowCallable getEnclosingCallable() { + Stages::DataFlowStage::forceCachingInSameStage() and + result = unique(DataFlowCallable c | c = this.(NodeImpl).getEnclosingCallableImpl() | c) + } /** Gets the control flow node corresponding to this node, if any. */ cached - ControlFlow::Node getControlFlowNode() { none() } + final ControlFlow::Node getControlFlowNode() { + Stages::DataFlowStage::forceCachingInSameStage() and + result = unique(ControlFlow::Node n | n = this.(NodeImpl).getControlFlowNodeImpl() | n) + } /** Gets a textual representation of this node. */ cached - string toString() { none() } + final string toString() { + Stages::DataFlowStage::forceCachingInSameStage() and + result = this.(NodeImpl).toStringImpl() + } /** Gets the location of this node. */ cached - Location getLocation() { none() } + final Location getLocation() { + Stages::DataFlowStage::forceCachingInSameStage() and + result = this.(NodeImpl).getLocationImpl() + } /** * Holds if this element is at the specified location. @@ -108,31 +110,6 @@ class ExprNode extends Node { this = TExprNode(cfn) and result = cfn.getElement() } - - override DataFlowCallable getEnclosingCallable() { - Stages::DataFlowStage::forceCachingInSameStage() and - result = this.getExpr().getEnclosingCallable() - } - - override ControlFlow::Nodes::ElementNode getControlFlowNode() { - Stages::DataFlowStage::forceCachingInSameStage() and this = TExprNode(result) - } - - override DotNet::Type getType() { - Stages::DataFlowStage::forceCachingInSameStage() and result = this.getExpr().getType() - } - - override Location getLocation() { - Stages::DataFlowStage::forceCachingInSameStage() and result = this.getExpr().getLocation() - } - - override string toString() { - Stages::DataFlowStage::forceCachingInSameStage() and - result = this.getControlFlowNode().toString() - or - this = TCilExprNode(_) and - result = "CIL expression" - } } /** @@ -146,7 +123,8 @@ class ParameterNode extends Node { this.(SsaDefinitionNode).getDefinition() instanceof ImplicitCapturedParameterNodeImpl::SsaCapturedEntryDefinition or this = TInstanceParameterNode(_) or - this = TCilParameterNode(_) + this = TCilParameterNode(_) or + this = TSummaryParameterNode(_, _) } /** Gets the parameter corresponding to this node, if any. */ @@ -188,15 +166,7 @@ AssignableDefinitionNode assignableDefinitionNode(AssignableDefinition def) { result.getDefinition() = def } -/** - * Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local - * (intra-procedural) step. - */ -predicate localFlowStep(Node nodeFrom, Node nodeTo) { - simpleLocalFlowStep(nodeFrom, nodeTo) - or - extendedLocalFlowStep(nodeFrom, nodeTo) -} +predicate localFlowStep = localFlowStepImpl/2; /** * Holds if data flows from `source` to `sink` in zero or more local @@ -242,7 +212,8 @@ class BarrierGuard extends Guard { } /** - * A reference contained in an object. This is either a field or a property. + * A reference contained in an object. This is either a field, a property, + * or an element in a collection. */ class Content extends TContent { /** Gets a textual representation of this content. */ @@ -252,10 +223,10 @@ class Content extends TContent { Location getLocation() { none() } /** Gets the type of the object containing this content. */ - DataFlowType getContainerType() { none() } + deprecated Gvn::GvnType getContainerType() { none() } /** Gets the type of this content. */ - DataFlowType getType() { none() } + deprecated Gvn::GvnType getType() { none() } } /** A reference to a field. */ @@ -271,11 +242,11 @@ class FieldContent extends Content, TFieldContent { override Location getLocation() { result = f.getLocation() } - override DataFlowType getContainerType() { + deprecated override Gvn::GvnType getContainerType() { result = Gvn::getGlobalValueNumber(f.getDeclaringType()) } - override DataFlowType getType() { result = Gvn::getGlobalValueNumber(f.getType()) } + deprecated override Gvn::GvnType getType() { result = Gvn::getGlobalValueNumber(f.getType()) } } /** A reference to a property. */ @@ -291,9 +262,16 @@ class PropertyContent extends Content, TPropertyContent { override Location getLocation() { result = p.getLocation() } - override DataFlowType getContainerType() { + deprecated override Gvn::GvnType getContainerType() { result = Gvn::getGlobalValueNumber(p.getDeclaringType()) } - override DataFlowType getType() { result = Gvn::getGlobalValueNumber(p.getType()) } + deprecated override Gvn::GvnType getType() { result = Gvn::getGlobalValueNumber(p.getType()) } +} + +/** A reference to an element in a collection. */ +class ElementContent extends Content, TElementContent { + override string toString() { result = "[]" } + + override Location getLocation() { result instanceof EmptyLocation } } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll index 56b2cdbccf56..243c6b83ef50 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll @@ -30,13 +30,13 @@ private class DelegateFlowSource extends DataFlow::ExprNode { } /** A sink of flow for a delegate expression. */ -abstract private class DelegateFlowSink extends DataFlow::ExprNode { +abstract private class DelegateFlowSink extends DataFlow::Node { /** * Gets an actual run-time target of this delegate call in the given call * context, if any. The call context records the *last* call required to * resolve the target, if any. Example: * - * ``` + * ```csharp * public int M(Func f, string x) { * return f(x); * } @@ -60,7 +60,7 @@ abstract private class DelegateFlowSink extends DataFlow::ExprNode { * Note that only the *last* call required is taken into account, hence if * `M` above is redefined as follows: * - * ``` + * ```csharp * public int M(Func f, string x) { * return M2(f, x); * } @@ -92,7 +92,7 @@ abstract private class DelegateFlowSink extends DataFlow::ExprNode { } /** A delegate call expression. */ -library class DelegateCallExpr extends DelegateFlowSink { +class DelegateCallExpr extends DelegateFlowSink, DataFlow::ExprNode { DelegateCall dc; DelegateCallExpr() { this.getExpr() = dc.getDelegateExpr() } @@ -101,50 +101,15 @@ library class DelegateCallExpr extends DelegateFlowSink { DelegateCall getDelegateCall() { result = dc } } -/** A delegate expression that is passed as the argument to a library callable. */ -library class DelegateArgumentToLibraryCallable extends Expr { - DelegateType dt; - Call call; - - DelegateArgumentToLibraryCallable() { - exists(Callable callable, Parameter p | - this = call.getArgumentForParameter(p) and - callable = call.getTarget() and - callable.fromLibrary() and - dt = p.getType().(SystemLinqExpressions::DelegateExtType).getDelegateType() - ) - } - - /** Gets the call that this argument belongs to. */ - Call getCall() { result = call } - - /** Gets the index of this delegate argument in the call. */ - int getArgumentIndex() { this = this.getCall().getArgument(result) } - - /** Gets the delegate type of this argument. */ - DelegateType getDelegateType() { result = dt } - - /** - * Gets an actual run-time target of this delegate call in the given call - * context, if any. The call context records the *last* call required to - * resolve the target, if any. Example: - */ - Callable getARuntimeTarget(CallContext context) { - exists(DelegateArgumentToLibraryCallableSink sink | sink.getExpr() = this | - result = sink.getARuntimeTarget(context) - ) - } -} - -/** A delegate expression that is passed as the argument to a library callable. */ -private class DelegateArgumentToLibraryCallableSink extends DelegateFlowSink { - DelegateArgumentToLibraryCallableSink() { - this.getExpr() instanceof DelegateArgumentToLibraryCallable +/** A parameter of delegate type belonging to a callable with a flow summary. */ +class SummaryDelegateParameterSink extends DelegateFlowSink, SummaryParameterNode { + SummaryDelegateParameterSink() { + this.getType() instanceof SystemLinqExpressions::DelegateExtType } } /** A delegate expression that is added to an event. */ -library class AddEventSource extends DelegateFlowSink { +class AddEventSource extends DelegateFlowSink, DataFlow::ExprNode { AddEventExpr ae; AddEventSource() { this.getExpr() = ae.getRValue() } @@ -192,7 +157,13 @@ private predicate flowsFrom( or // Local flow exists(DataFlow::Node mid | flowsFrom(sink, mid, isReturned, lastCall) | - DataFlow::localFlowStep(node, mid) or + LocalFlow::localFlowStepCommon(node, mid) + or + exists(Ssa::Definition def | + LocalFlow::localSsaFlowStep(def, node, mid) and + LocalFlow::usesInstanceField(def) + ) + or node.asExpr() = mid.asExpr().(DelegateCreation).getArgument() ) or @@ -205,7 +176,7 @@ private predicate flowsFrom( ) or // Flow into a callable (non-delegate call) - exists(ExplicitParameterNode mid, CallContext prevLastCall, NonDelegateCall call, Parameter p | + exists(ParameterNode mid, CallContext prevLastCall, NonDelegateCall call, Parameter p | flowsFrom(sink, mid, isReturned, prevLastCall) and isReturned = false and p = mid.getParameter() and @@ -215,8 +186,7 @@ private predicate flowsFrom( or // Flow into a callable (delegate call) exists( - ExplicitParameterNode mid, CallContext prevLastCall, DelegateCall call, Callable c, Parameter p, - int i + ParameterNode mid, CallContext prevLastCall, DelegateCall call, Callable c, Parameter p, int i | flowsFrom(sink, mid, isReturned, prevLastCall) and isReturned = false and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/Steps.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/Steps.qll index f80a2036aeaa..9eb296b67873 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/Steps.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/Steps.qll @@ -78,7 +78,7 @@ module Steps { * assumption. For example, there is flow from `0` on line 3 to `i` on line * 8 and from `1` on line 4 to `i` on line 12 in * - * ``` + * ```csharp * public class C { * public void A() { * B(0); @@ -106,7 +106,7 @@ module Steps { * 8 (but not from `1` on line 4 to `i` on line 12 because `C` is virtual) * in * - * ``` + * ```csharp * public class C { * public void A() { * B(0); diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll index 93fe29c4619f..68284e965fa0 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll @@ -1,29 +1,25 @@ private import csharp private import TaintTrackingPublic +private import DataFlowImplCommon +private import semmle.code.csharp.Caching private import semmle.code.csharp.dataflow.internal.DataFlowPrivate private import semmle.code.csharp.dataflow.internal.ControlFlowReachability private import semmle.code.csharp.dataflow.LibraryTypeDataFlow private import semmle.code.csharp.dispatch.Dispatch private import semmle.code.csharp.commons.ComparisonTest -private import semmle.code.csharp.frameworks.JsonNET private import cil private import dotnet +// import `TaintedMember` definitions from other files to avoid potential reevaluation +private import semmle.code.csharp.frameworks.JsonNET +private import semmle.code.csharp.frameworks.WCF /** - * Holds if `node` should be a barrier in all global taint flow configurations + * Holds if `node` should be a sanitizer in all global taint flow configurations * but not in local taint. */ -predicate defaultTaintBarrier(DataFlow::Node node) { none() } +predicate defaultTaintSanitizer(DataFlow::Node node) { none() } -/** - * Holds if the additional step from `src` to `sink` should be included in all - * global taint flow configurations. - */ -predicate defaultAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { - localAdditionalTaintStep(pred, succ) - or - succ = pred.(DataFlow::NonLocalJumpNode).getAJumpSuccessor(false) -} +deprecated predicate localAdditionalTaintStep = defaultAdditionalTaintStep/2; private CIL::DataFlowNode asCilDataFlowNode(DataFlow::Node node) { result = node.asParameter() or @@ -34,9 +30,6 @@ private predicate localTaintStepCil(DataFlow::Node nodeFrom, DataFlow::Node node asCilDataFlowNode(nodeFrom).getALocalFlowSucc(asCilDataFlowNode(nodeTo), any(CIL::Tainted t)) } -/** Gets the qualifier of element access `ea`. */ -private Expr getElementAccessQualifier(ElementAccess ea) { result = ea.getQualifier() } - private class LocalTaintExprStepConfiguration extends ControlFlowReachabilityConfiguration { LocalTaintExprStepConfiguration() { this = "LocalTaintExprStepConfiguration" } @@ -45,28 +38,6 @@ private class LocalTaintExprStepConfiguration extends ControlFlowReachabilityCon ) { exactScope = false and ( - // Taint from assigned value to element qualifier (`x[i] = 0`) - exists(AssignExpr ae | - e1 = ae.getRValue() and - e2.(AssignableRead) = getElementAccessQualifier+(ae.getLValue()) and - scope = ae and - isSuccessor = false - ) - or - // Taint from array initializer - e1 = e2.(ArrayCreation).getInitializer().getAnElement() and - scope = e2 and - isSuccessor = false - or - // Taint from object initializer - exists(ElementInitializer ei | - ei = e2.(ObjectCreation).getInitializer().(CollectionInitializer).getAnElementInitializer() and - e1 = ei.getArgument(ei.getNumberOfArguments() - 1) and // assume the last argument is the value (i.e., not a key) - scope = e2 and - isSuccessor = false - ) - or - // Taint from element qualifier e1 = e2.(ElementAccess).getQualifier() and scope = e2 and isSuccessor = true @@ -124,63 +95,84 @@ private class LocalTaintExprStepConfiguration extends ControlFlowReachabilityCon scope = e2 and isSuccessor = true ) - ) - } - - override predicate candidateDef( - Expr e, AssignableDefinition defTo, ControlFlowElement scope, boolean exactScope, - boolean isSuccessor - ) { - // Taint from `foreach` expression - exists(ForeachStmt fs | - e = fs.getIterableExpr() and - defTo.(AssignableDefinitions::LocalVariableDefinition).getDeclaration() = - fs.getVariableDeclExpr() and - isSuccessor = true - | - scope = fs and - exactScope = true - or - scope = fs.getIterableExpr() and - exactScope = false or - scope = fs.getVariableDeclExpr() and - exactScope = false + e1 = e2.(AwaitExpr).getExpr() and + scope = e2 and + isSuccessor = true ) } } +private predicate localTaintStepCommon(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + Stages::DataFlowStage::forceCachingInSameStage() and + any(LocalTaintExprStepConfiguration x).hasNodePath(nodeFrom, nodeTo) + or + localTaintStepCil(nodeFrom, nodeTo) +} + cached -module Cached { - private import semmle.code.csharp.Caching +private module Cached { + private import Summaries + /** + * Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local + * (intra-procedural) step. + */ cached - predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - Stages::DataFlowStage::forceCachingInSameStage() and - any(LocalTaintExprStepConfiguration x).hasNodePath(nodeFrom, nodeTo) + predicate localTaintStepImpl(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + // Ordinary data flow + DataFlow::localFlowStep(nodeFrom, nodeTo) or - nodeFrom = nodeTo.(YieldReturnNode).getPreUpdateNode() + localTaintStepCommon(nodeFrom, nodeTo) or - localTaintStepCil(nodeFrom, nodeTo) - or - // Taint members - exists(Access access | - access = nodeTo.asExpr() and - access.getTarget() instanceof TaintedMember - | - access.(FieldRead).getQualifier() = nodeFrom.asExpr() + not LocalFlow::excludeFromExposedRelations(nodeFrom) and + not LocalFlow::excludeFromExposedRelations(nodeTo) and + ( + // Simple flow through library code is included in the exposed local + // step relation, even though flow is technically inter-procedural + summaryThroughStep(nodeFrom, nodeTo, false) or - access.(PropertyRead).getQualifier() = nodeFrom.asExpr() - ) - or - exists(LibraryCodeNode n | not n.preservesValue() | - n = nodeTo and - nodeFrom = n.getPredecessor(AccessPath::empty()) + // Taint collection by adding a tainted element + exists(DataFlow::ElementContent c | + storeStep(nodeFrom, c, nodeTo) + or + summarySetterStep(nodeFrom, c, nodeTo) + ) or - n = nodeFrom and - nodeTo = n.getSuccessor(AccessPath::empty()) + exists(DataFlow::Content c | + readStep(nodeFrom, c, nodeTo) + or + summaryGetterStep(nodeFrom, c, nodeTo) + | + // Taint members + c = any(TaintedMember m).(FieldOrProperty).getContent() + or + // Read from a tainted collection + c = TElementContent() + ) ) } + + /** + * Holds if the additional step from `nodeFrom` to `nodeTo` should be included + * in all global taint flow configurations. + */ + cached + predicate defaultAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + localTaintStepCommon(nodeFrom, nodeTo) + or + // Taint members + readStep(nodeFrom, any(TaintedMember m).(FieldOrProperty).getContent(), nodeTo) + or + // Although flow through collections is modelled precisely using stores/reads, we still + // allow flow out of a _tainted_ collection. This is needed in order to support taint- + // tracking configurations where the source is a collection + readStep(nodeFrom, TElementContent(), nodeTo) + or + summaryLocalStep(nodeFrom, nodeTo, false) + or + nodeTo = nodeFrom.(DataFlow::NonLocalJumpNode).getAJumpSuccessor(false) + } } import Cached diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPublic.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPublic.qll index eda33f2fcd90..6e4ba538a402 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPublic.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPublic.qll @@ -18,13 +18,4 @@ predicate localExprTaint(Expr e1, Expr e2) { /** A member (property or field) that is tainted if its containing object is tainted. */ abstract class TaintedMember extends AssignableMember { } -/** - * Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local - * (intra-procedural) step. - */ -predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - // Ordinary data flow - DataFlow::localFlowStep(nodeFrom, nodeTo) - or - localAdditionalTaintStep(nodeFrom, nodeTo) -} +predicate localTaintStep = localTaintStepImpl/2; diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/BoundSpecific.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/BoundSpecific.qll new file mode 100644 index 000000000000..edf437e919c4 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/BoundSpecific.qll @@ -0,0 +1,21 @@ +/** + * Provides C#-specific definitions for bounds. + */ + +private import csharp as CS +private import semmle.code.csharp.dataflow.SSA::Ssa as Ssa +private import semmle.code.csharp.dataflow.internal.rangeanalysis.ConstantUtils as CU + +class SsaVariable extends Ssa::Definition { + /** Gets a read of the source variable underlying this SSA definition. */ + Expr getAUse() { result = getARead() } +} + +class Expr = CS::Expr; + +class IntegralType = CS::IntegralType; + +class ConstantIntegerExpr = CU::ConstantIntegerExpr; + +/** Holds if `e` is a bound expression and it is not an SSA variable read. */ +predicate interestingExprBound(Expr e) { CU::systemArrayLengthAccess(e.(CS::PropertyRead)) } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/ConstantUtils.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/ConstantUtils.qll new file mode 100644 index 000000000000..08b64321a38a --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/ConstantUtils.qll @@ -0,0 +1,71 @@ +/** + * Provides classes and predicates to represent constant integer expressions. + */ + +private import csharp +private import Ssa + +/** + * Holds if property `p` matches `property` in `baseClass` or any overrides. + */ +predicate propertyOverrides(Property p, string baseClass, string property) { + exists(Property p2 | + p2.getSourceDeclaration().getDeclaringType().hasQualifiedName(baseClass) and + p2.hasName(property) + | + p.overridesOrImplementsOrEquals(p2) + ) +} + +/** + * Holds if `pa` is an access to the `Length` property of an array. + */ +predicate systemArrayLengthAccess(PropertyAccess pa) { + propertyOverrides(pa.getTarget(), "System.Array", "Length") +} + +/** + * Holds if expression `e` is either + * - a compile time constant with integer value `val`, or + * - a read of a compile time constant with integer value `val`, or + * - a read of the `Length` of an array with `val` lengths. + */ +private predicate constantIntegerExpr(Expr e, int val) { + e.getValue().toInt() = val + or + exists(ExplicitDefinition v, Expr src | + e = v.getARead() and + src = v.getADefinition().getSource() and + constantIntegerExpr(src, val) + ) + or + isArrayLengthAccess(e, val) +} + +private int getArrayLength(ArrayCreation arrCreation, int index) { + constantIntegerExpr(arrCreation.getLengthArgument(index), result) +} + +private int getArrayLengthRec(ArrayCreation arrCreation, int index) { + index = 0 and result = getArrayLength(arrCreation, 0) + or + index > 0 and + result = getArrayLength(arrCreation, index) * getArrayLengthRec(arrCreation, index - 1) +} + +private predicate isArrayLengthAccess(PropertyAccess pa, int length) { + systemArrayLengthAccess(pa) and + exists(ExplicitDefinition arr, ArrayCreation arrCreation | + getArrayLengthRec(arrCreation, arrCreation.getNumberOfLengthArguments() - 1) = length and + arrCreation = arr.getADefinition().getSource() and + pa.getQualifier() = arr.getARead() + ) +} + +/** An expression that always has the same integer value. */ +class ConstantIntegerExpr extends Expr { + ConstantIntegerExpr() { constantIntegerExpr(this, _) } + + /** Gets the integer value of this expression. */ + int getIntValue() { constantIntegerExpr(this, result) } +} diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/ModulusAnalysisSpecific.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/ModulusAnalysisSpecific.qll new file mode 100644 index 000000000000..2cdbfbf65f4e --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/ModulusAnalysisSpecific.qll @@ -0,0 +1,110 @@ +module Private { + private import csharp as CS + private import ConstantUtils as CU + private import semmle.code.csharp.controlflow.Guards as G + private import semmle.code.csharp.dataflow.internal.rangeanalysis.RangeUtils as RU + private import SsaUtils as SU + private import SignAnalysisSpecific::Private as SA + + class BasicBlock = CS::Ssa::BasicBlock; + + class SsaVariable extends CS::Ssa::Definition { + CS::AssignableRead getAUse() { result = this.getARead() } + } + + class SsaPhiNode = CS::Ssa::PhiNode; + + class Expr = CS::Expr; + + class Guard = G::Guard; + + class ConstantIntegerExpr = CU::ConstantIntegerExpr; + + class ConditionalExpr extends CS::ConditionalExpr { + /** Gets the "then" expression of this conditional expression. */ + Expr getTrueExpr() { result = this.getThen() } + + /** Gets the "else" expression of this conditional expression. */ + Expr getFalseExpr() { result = this.getElse() } + } + + /** Represent an addition expression. */ + class AddExpr extends CS::AddExpr { + /** Gets the LHS operand of this add expression. */ + Expr getLhs() { result = this.getLeftOperand() } + + /** Gets the RHS operand of this add expression. */ + Expr getRhs() { result = this.getRightOperand() } + } + + /** Represent a subtraction expression. */ + class SubExpr extends CS::SubExpr { + /** Gets the LHS operand of this subtraction expression. */ + Expr getLhs() { result = this.getLeftOperand() } + + /** Gets the RHS operand of this subtraction expression. */ + Expr getRhs() { result = this.getRightOperand() } + } + + class RemExpr = CS::RemExpr; + + /** Represent a bitwise and or an assign-and expression. */ + class BitwiseAndExpr extends CS::Expr { + BitwiseAndExpr() { this instanceof CS::BitwiseAndExpr or this instanceof CS::AssignAndExpr } + + /** Gets an operand of this bitwise and operation. */ + Expr getAnOperand() { + result = this.(CS::BitwiseAndExpr).getAnOperand() or + result = this.(CS::AssignAndExpr).getRValue() or + result = this.(CS::AssignAndExpr).getLValue() + } + + /** Holds if this expression has operands `e1` and `e2`. */ + predicate hasOperands(Expr e1, Expr e2) { + this.getAnOperand() = e1 and + this.getAnOperand() = e2 and + e1 != e2 + } + } + + /** Represent a multiplication or an assign-mul expression. */ + class MulExpr extends CS::Expr { + MulExpr() { this instanceof CS::MulExpr or this instanceof CS::AssignMulExpr } + + /** Gets an operand of this multiplication. */ + Expr getAnOperand() { + result = this.(CS::MulExpr).getAnOperand() or + result = this.(CS::AssignMulExpr).getRValue() or + result = this.(CS::AssignMulExpr).getLValue() + } + } + + /** Represent a left shift or an assign-lshift expression. */ + class LShiftExpr extends CS::Expr { + LShiftExpr() { this instanceof CS::LShiftExpr or this instanceof CS::AssignLShiftExpr } + + /** Gets the RHS operand of this shift. */ + Expr getRhs() { + result = this.(CS::LShiftExpr).getRightOperand() or + result = this.(CS::AssignLShiftExpr).getRValue() + } + } + + predicate guardDirectlyControlsSsaRead = SA::guardControlsSsaRead/3; + + predicate guardControlsSsaRead = SA::guardControlsSsaRead/3; + + predicate valueFlowStep = RU::valueFlowStep/3; + + predicate eqFlowCond = RU::eqFlowCond/5; + + predicate ssaUpdateStep = RU::ssaUpdateStep/3; + + Expr getABasicBlockExpr(BasicBlock bb) { result = bb.getANode().getElement() } + + private predicate id(CS::ControlFlowElement x, CS::ControlFlowElement y) { x = y } + + private predicate idOf(CS::ControlFlowElement x, int y) = equivalenceRelation(id/2)(x, y) + + int getId(BasicBlock bb) { idOf(bb.getFirstNode().getElement(), result) } +} diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll new file mode 100644 index 000000000000..4abfb2d17793 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll @@ -0,0 +1,98 @@ +/** + * Provides predicates for range and modulus analysis. + */ + +private import csharp +private import Ssa +private import SsaUtils +private import ConstantUtils +private import SsaReadPositionCommon +private import semmle.code.csharp.controlflow.Guards as G + +private class BooleanValue = G::AbstractValues::BooleanValue; + +/** + * Holds if `v` is an `ExplicitDefinition` that equals `e + delta`. + */ +predicate ssaUpdateStep(ExplicitDefinition v, Expr e, int delta) { + v.getADefinition().getExpr().(Assignment).getRValue() = e and delta = 0 + or + v.getADefinition().getExpr().(PostIncrExpr).getOperand() = e and delta = 1 + or + v.getADefinition().getExpr().(PreIncrExpr).getOperand() = e and delta = 1 + or + v.getADefinition().getExpr().(PostDecrExpr).getOperand() = e and delta = -1 + or + v.getADefinition().getExpr().(PreDecrExpr).getOperand() = e and delta = -1 +} + +private G::Guard eqFlowCondAbs(Definition def, Expr e, int delta, boolean isEq, G::AbstractValue v) { + exists(boolean eqpolarity | + result.isEquality(ssaRead(def, delta), e, eqpolarity) and + eqpolarity.booleanXor(v.(BooleanValue).getValue()).booleanNot() = isEq + ) + or + exists(G::AbstractValue v0 | + G::Internal::impliesSteps(result, v, eqFlowCondAbs(def, e, delta, isEq, v0), v0) + ) +} + +/** + * Gets a condition that tests whether `def` equals `e + delta`. + * + * If the condition evaluates to `testIsTrue`: + * - `isEq = true` : `def == e + delta` + * - `isEq = false` : `def != e + delta` + */ +G::Guard eqFlowCond(Definition def, Expr e, int delta, boolean isEq, boolean testIsTrue) { + exists(BooleanValue v | + result = eqFlowCondAbs(def, e, delta, isEq, v) and + testIsTrue = v.getValue() + ) +} + +/** + * Holds if `e1 + delta` equals `e2`. + */ +predicate valueFlowStep(Expr e2, Expr e1, int delta) { + valueFlowStep(e2.(AssignOperation).getExpandedAssignment(), e1, delta) + or + e2.(AssignExpr).getRValue() = e1 and delta = 0 + or + e2.(UnaryPlusExpr).getOperand() = e1 and delta = 0 + or + e2.(PostIncrExpr).getOperand() = e1 and delta = 0 + or + e2.(PostDecrExpr).getOperand() = e1 and delta = 0 + or + e2.(PreIncrExpr).getOperand() = e1 and delta = 1 + or + e2.(PreDecrExpr).getOperand() = e1 and delta = -1 + or + exists(ConstantIntegerExpr x | + e2.(AddExpr).getAnOperand() = e1 and + e2.(AddExpr).getAnOperand() = x and + not e1 = x + | + x.getIntValue() = delta + ) + or + exists(ConstantIntegerExpr x | + exists(SubExpr sub | + e2 = sub and + sub.getLeftOperand() = e1 and + sub.getRightOperand() = x + ) + | + x.getIntValue() = -delta + ) +} + +/** + * Holds if `guard` controls the position `controlled` with the value `testIsTrue`. + */ +predicate guardControlsSsaRead(G::Guard guard, SsaReadPosition controlled, boolean testIsTrue) { + exists(BooleanValue b | b.getValue() = testIsTrue | + guard.controlsBasicBlock(controlled.(SsaReadPositionBlock).getBlock(), b) + ) +} diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/Sign.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/Sign.qll new file mode 100644 index 000000000000..b2058a271148 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/Sign.qll @@ -0,0 +1,280 @@ +newtype TSign = + TNeg() or + TZero() or + TPos() + +newtype TUnarySignOperation = + TNegOp() or + TIncOp() or + TDecOp() or + TBitNotOp() + +newtype TBinarySignOperation = + TAddOp() or + TSubOp() or + TMulOp() or + TDivOp() or + TRemOp() or + TBitAndOp() or + TBitOrOp() or + TBitXorOp() or + TLShiftOp() or + TRShiftOp() or + TURShiftOp() + +/** Class representing expression signs (+, -, 0). */ +class Sign extends TSign { + /** Gets the string representation of this sign. */ + string toString() { + result = "-" and this = TNeg() + or + result = "0" and this = TZero() + or + result = "+" and this = TPos() + } + + /** Gets a possible sign after incrementing an expression that has this sign. */ + Sign inc() { + this = TNeg() and result = TNeg() + or + this = TNeg() and result = TZero() + or + this = TZero() and result = TPos() + or + this = TPos() and result = TPos() + } + + /** Gets a possible sign after decrementing an expression that has this sign. */ + Sign dec() { result.inc() = this } + + /** Gets a possible sign after negating an expression that has this sign. */ + Sign neg() { + this = TNeg() and result = TPos() + or + this = TZero() and result = TZero() + or + this = TPos() and result = TNeg() + } + + /** + * Gets a possible sign after bitwise complementing an expression that has this + * sign. + */ + Sign bitnot() { + this = TNeg() and result = TPos() + or + this = TNeg() and result = TZero() + or + this = TZero() and result = TNeg() + or + this = TPos() and result = TNeg() + } + + /** + * Gets a possible sign after adding an expression with sign `s` to an expression + * that has this sign. + */ + Sign add(Sign s) { + this = TZero() and result = s + or + s = TZero() and result = this + or + this = s and this = result + or + this = TPos() and s = TNeg() + or + this = TNeg() and s = TPos() + } + + /** + * Gets a possible sign after subtracting an expression with sign `s` from an expression + * that has this sign. + */ + Sign sub(Sign s) { result = add(s.neg()) } + + /** + * Gets a possible sign after multiplying an expression with sign `s` to an expression + * that has this sign. + */ + Sign mul(Sign s) { + result = TZero() and this = TZero() + or + result = TZero() and s = TZero() + or + result = TNeg() and this = TPos() and s = TNeg() + or + result = TNeg() and this = TNeg() and s = TPos() + or + result = TPos() and this = TPos() and s = TPos() + or + result = TPos() and this = TNeg() and s = TNeg() + } + + /** + * Gets a possible sign after integer dividing an expression that has this sign + * by an expression with sign `s`. + */ + Sign div(Sign s) { + result = TZero() and s = TNeg() // ex: 3 / -5 = 0 + or + result = TZero() and s = TPos() // ex: 3 / 5 = 0 + or + result = TNeg() and this = TPos() and s = TNeg() + or + result = TNeg() and this = TNeg() and s = TPos() + or + result = TPos() and this = TPos() and s = TPos() + or + result = TPos() and this = TNeg() and s = TNeg() + } + + /** + * Gets a possible sign after modulo dividing an expression that has this sign + * by an expression with sign `s`. + */ + Sign rem(Sign s) { + result = TZero() and s = TNeg() + or + result = TZero() and s = TPos() + or + result = this and s = TNeg() + or + result = this and s = TPos() + } + + /** + * Gets a possible sign after bitwise `and` of an expression that has this sign + * and an expression with sign `s`. + */ + Sign bitand(Sign s) { + result = TZero() and this = TZero() + or + result = TZero() and s = TZero() + or + result = TZero() and this = TPos() + or + result = TZero() and s = TPos() + or + result = TNeg() and this = TNeg() and s = TNeg() + or + result = TPos() and this = TNeg() and s = TPos() + or + result = TPos() and this = TPos() and s = TNeg() + or + result = TPos() and this = TPos() and s = TPos() + } + + /** + * Gets a possible sign after bitwise `or` of an expression that has this sign + * and an expression with sign `s`. + */ + Sign bitor(Sign s) { + result = TZero() and this = TZero() and s = TZero() + or + result = TNeg() and this = TNeg() + or + result = TNeg() and s = TNeg() + or + result = TPos() and this = TPos() and s = TZero() + or + result = TPos() and this = TZero() and s = TPos() + or + result = TPos() and this = TPos() and s = TPos() + } + + /** + * Gets a possible sign after bitwise `xor` of an expression that has this sign + * and an expression with sign `s`. + */ + Sign bitxor(Sign s) { + result = TZero() and this = s + or + result = this and s = TZero() + or + result = s and this = TZero() + or + result = TPos() and this = TPos() and s = TPos() + or + result = TNeg() and this = TNeg() and s = TPos() + or + result = TNeg() and this = TPos() and s = TNeg() + or + result = TPos() and this = TNeg() and s = TNeg() + } + + /** + * Gets a possible sign after left shift of an expression that has this sign + * by an expression with sign `s`. + */ + Sign lshift(Sign s) { + result = TZero() and this = TZero() + or + result = this and s = TZero() + or + this != TZero() and s != TZero() + } + + /** + * Gets a possible sign after right shift of an expression that has this sign + * by an expression with sign `s`. + */ + Sign rshift(Sign s) { + result = TZero() and this = TZero() + or + result = this and s = TZero() + or + result = TNeg() and this = TNeg() + or + result != TNeg() and this = TPos() and s != TZero() + } + + /** + * Gets a possible sign after unsigned right shift of an expression that has + * this sign by an expression with sign `s`. + */ + Sign urshift(Sign s) { + result = TZero() and this = TZero() + or + result = this and s = TZero() + or + result != TZero() and this = TNeg() and s != TZero() + or + result != TNeg() and this = TPos() and s != TZero() + } + + /** Perform `op` on this sign. */ + Sign applyUnaryOp(TUnarySignOperation op) { + op = TIncOp() and result = inc() + or + op = TDecOp() and result = dec() + or + op = TNegOp() and result = neg() + or + op = TBitNotOp() and result = bitnot() + } + + /** Perform `op` on this sign and sign `s`. */ + Sign applyBinaryOp(Sign s, TBinarySignOperation op) { + op = TAddOp() and result = add(s) + or + op = TSubOp() and result = sub(s) + or + op = TMulOp() and result = mul(s) + or + op = TDivOp() and result = div(s) + or + op = TRemOp() and result = rem(s) + or + op = TBitAndOp() and result = bitand(s) + or + op = TBitOrOp() and result = bitor(s) + or + op = TBitXorOp() and result = bitxor(s) + or + op = TLShiftOp() and result = lshift(s) + or + op = TRShiftOp() and result = rshift(s) + or + op = TURShiftOp() and result = urshift(s) + } +} diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll new file mode 100644 index 000000000000..d00a38bac737 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll @@ -0,0 +1,376 @@ +/** + * Provides sign analysis to determine whether expression are always positive + * or negative. + * + * The analysis is implemented as an abstract interpretation over the + * three-valued domain `{negative, zero, positive}`. + */ + +private import SignAnalysisSpecific::Private +private import SsaReadPositionCommon +private import Sign + +/** Gets the sign of `e` if this can be directly determined. */ +private Sign certainExprSign(Expr e) { + exists(int i | e.(ConstantIntegerExpr).getIntValue() = i | + i < 0 and result = TNeg() + or + i = 0 and result = TZero() + or + i > 0 and result = TPos() + ) + or + not exists(e.(ConstantIntegerExpr).getIntValue()) and + ( + exists(float f | f = getNonIntegerValue(e) | + f < 0 and result = TNeg() + or + f = 0 and result = TZero() + or + f > 0 and result = TPos() + ) + or + exists(string charlit | charlit = getCharValue(e) | + if charlit.regexpMatch("\\u0000") then result = TZero() else result = TPos() + ) + or + containerSizeAccess(e) and + (result = TPos() or result = TZero()) + or + positiveExpression(e) and result = TPos() + ) +} + +/** Holds if the sign of `e` is too complicated to determine. */ +private predicate unknownSign(Expr e) { + not exists(certainExprSign(e)) and + ( + exists(IntegerLiteral lit | lit = e and not exists(lit.getValue().toInt())) + or + exists(LongLiteral lit | lit = e and not exists(lit.getValue().toFloat())) + or + exists(CastExpr cast, Type fromtyp | + cast = e and + fromtyp = cast.getExpr().getType() and + not fromtyp instanceof NumericOrCharType + ) + or + numericExprWithUnknownSign(e) + ) +} + +/** + * Holds if `lowerbound` is a lower bound for `v` at `pos`. This is restricted + * to only include bounds for which we might determine a sign. + */ +private predicate lowerBound(Expr lowerbound, SsaVariable v, SsaReadPosition pos, boolean isStrict) { + exists(boolean testIsTrue, ComparisonExpr comp | + pos.hasReadOfVar(v) and + guardControlsSsaRead(getComparisonGuard(comp), pos, testIsTrue) and + not unknownSign(lowerbound) + | + testIsTrue = true and + comp.getLesserOperand() = lowerbound and + comp.getGreaterOperand() = ssaRead(v, 0) and + (if comp.isStrict() then isStrict = true else isStrict = false) + or + testIsTrue = false and + comp.getGreaterOperand() = lowerbound and + comp.getLesserOperand() = ssaRead(v, 0) and + (if comp.isStrict() then isStrict = false else isStrict = true) + ) +} + +/** + * Holds if `upperbound` is an upper bound for `v` at `pos`. This is restricted + * to only include bounds for which we might determine a sign. + */ +private predicate upperBound(Expr upperbound, SsaVariable v, SsaReadPosition pos, boolean isStrict) { + exists(boolean testIsTrue, ComparisonExpr comp | + pos.hasReadOfVar(v) and + guardControlsSsaRead(getComparisonGuard(comp), pos, testIsTrue) and + not unknownSign(upperbound) + | + testIsTrue = true and + comp.getGreaterOperand() = upperbound and + comp.getLesserOperand() = ssaRead(v, 0) and + (if comp.isStrict() then isStrict = true else isStrict = false) + or + testIsTrue = false and + comp.getLesserOperand() = upperbound and + comp.getGreaterOperand() = ssaRead(v, 0) and + (if comp.isStrict() then isStrict = false else isStrict = true) + ) +} + +/** + * Holds if `eqbound` is an equality/inequality for `v` at `pos`. This is + * restricted to only include bounds for which we might determine a sign. The + * boolean `isEq` gives the polarity: + * - `isEq = true` : `v = eqbound` + * - `isEq = false` : `v != eqbound` + */ +private predicate eqBound(Expr eqbound, SsaVariable v, SsaReadPosition pos, boolean isEq) { + exists(Guard guard, boolean testIsTrue, boolean polarity | + pos.hasReadOfVar(v) and + guardControlsSsaRead(guard, pos, testIsTrue) and + guard.isEquality(eqbound, ssaRead(v, 0), polarity) and + isEq = polarity.booleanXor(testIsTrue).booleanNot() and + not unknownSign(eqbound) + ) +} + +/** + * Holds if `bound` is a bound for `v` at `pos` that needs to be positive in + * order for `v` to be positive. + */ +private predicate posBound(Expr bound, SsaVariable v, SsaReadPosition pos) { + upperBound(bound, v, pos, _) or + eqBound(bound, v, pos, true) +} + +/** + * Holds if `bound` is a bound for `v` at `pos` that needs to be negative in + * order for `v` to be negative. + */ +private predicate negBound(Expr bound, SsaVariable v, SsaReadPosition pos) { + lowerBound(bound, v, pos, _) or + eqBound(bound, v, pos, true) +} + +/** + * Holds if `bound` is a bound for `v` at `pos` that can restrict whether `v` + * can be zero. + */ +private predicate zeroBound(Expr bound, SsaVariable v, SsaReadPosition pos) { + lowerBound(bound, v, pos, _) or + upperBound(bound, v, pos, _) or + eqBound(bound, v, pos, _) +} + +/** Holds if `bound` allows `v` to be positive at `pos`. */ +private predicate posBoundOk(Expr bound, SsaVariable v, SsaReadPosition pos) { + posBound(bound, v, pos) and TPos() = exprSign(bound) +} + +/** Holds if `bound` allows `v` to be negative at `pos`. */ +private predicate negBoundOk(Expr bound, SsaVariable v, SsaReadPosition pos) { + negBound(bound, v, pos) and TNeg() = exprSign(bound) +} + +/** Holds if `bound` allows `v` to be zero at `pos`. */ +private predicate zeroBoundOk(Expr bound, SsaVariable v, SsaReadPosition pos) { + lowerBound(bound, v, pos, _) and TNeg() = exprSign(bound) + or + lowerBound(bound, v, pos, false) and TZero() = exprSign(bound) + or + upperBound(bound, v, pos, _) and TPos() = exprSign(bound) + or + upperBound(bound, v, pos, false) and TZero() = exprSign(bound) + or + eqBound(bound, v, pos, true) and TZero() = exprSign(bound) + or + eqBound(bound, v, pos, false) and TZero() != exprSign(bound) +} + +/** + * Holds if there is a bound that might restrict whether `v` has the sign `s` + * at `pos`. + */ +private predicate hasGuard(SsaVariable v, SsaReadPosition pos, Sign s) { + s = TPos() and posBound(_, v, pos) + or + s = TNeg() and negBound(_, v, pos) + or + s = TZero() and zeroBound(_, v, pos) +} + +/** + * Gets a possible sign of `v` at `pos` based on its definition, where the sign + * might be ruled out by a guard. + */ +pragma[noinline] +private Sign guardedSsaSign(SsaVariable v, SsaReadPosition pos) { + result = ssaDefSign(v) and + pos.hasReadOfVar(v) and + hasGuard(v, pos, result) +} + +/** + * Gets a possible sign of `v` at `pos` based on its definition, where no guard + * can rule it out. + */ +pragma[noinline] +private Sign unguardedSsaSign(SsaVariable v, SsaReadPosition pos) { + result = ssaDefSign(v) and + pos.hasReadOfVar(v) and + not hasGuard(v, pos, result) +} + +/** + * Gets a possible sign of `v` at read position `pos`, where a guard could have + * ruled out the sign but does not. + * This does not check that the definition of `v` also allows the sign. + */ +private Sign guardedSsaSignOk(SsaVariable v, SsaReadPosition pos) { + result = TPos() and + forex(Expr bound | posBound(bound, v, pos) | posBoundOk(bound, v, pos)) + or + result = TNeg() and + forex(Expr bound | negBound(bound, v, pos) | negBoundOk(bound, v, pos)) + or + result = TZero() and + forex(Expr bound | zeroBound(bound, v, pos) | zeroBoundOk(bound, v, pos)) +} + +/** Gets a possible sign for `v` at `pos`. */ +private Sign ssaSign(SsaVariable v, SsaReadPosition pos) { + result = unguardedSsaSign(v, pos) + or + result = guardedSsaSign(v, pos) and + result = guardedSsaSignOk(v, pos) +} + +/** Gets a possible sign for `v`. */ +pragma[nomagic] +private Sign ssaDefSign(SsaVariable v) { + result = explicitSsaDefSign(v) + or + result = implicitSsaDefSign(v) + or + exists(SsaPhiNode phi, SsaVariable inp, SsaReadPositionPhiInputEdge edge | + v = phi and + edge.phiInput(phi, inp) and + result = ssaSign(inp, edge) + ) +} + +/** Returns the sign of explicit SSA definition `v`. */ +private Sign explicitSsaDefSign(SsaVariable v) { + exists(VariableUpdate def | def = getExplicitSsaAssignment(v) | + result = exprSign(getExprFromSsaAssignment(def)) + or + anySign(result) and explicitSsaDefWithAnySign(def) + or + result = exprSign(getIncrementOperand(def)).inc() + or + result = exprSign(getDecrementOperand(def)).dec() + ) +} + +/** Returns the sign of implicit SSA definition `v`. */ +private Sign implicitSsaDefSign(SsaVariable v) { + result = fieldSign(getImplicitSsaDeclaration(v)) + or + anySign(result) and nonFieldImplicitSsaDefinition(v) +} + +/** Gets a possible sign for `f`. */ +private Sign fieldSign(Field f) { + if not fieldWithUnknownSign(f) + then + result = exprSign(getAssignedValueToField(f)) + or + fieldIncrementOperationOperand(f) and result = fieldSign(f).inc() + or + fieldDecrementOperationOperand(f) and result = fieldSign(f).dec() + or + result = specificFieldSign(f) + else anySign(result) +} + +/** Gets a possible sign for `e`. */ +cached +Sign exprSign(Expr e) { + exists(Sign s | + s = certainExprSign(e) + or + not exists(certainExprSign(e)) and + ( + anySign(s) and unknownSign(e) + or + exists(SsaVariable v | getARead(v) = e | + s = ssaSign(v, any(SsaReadPositionBlock bb | getAnExpression(bb) = e)) + or + not exists(SsaReadPositionBlock bb | getAnExpression(bb) = e) and + s = ssaDefSign(v) + ) + or + exists(VarAccess access | access = e | + not exists(SsaVariable v | getARead(v) = access) and + ( + s = fieldSign(getField(access.(FieldAccess))) + or + anySign(s) and not access instanceof FieldAccess + ) + ) + or + s = specificSubExprSign(e) + ) + | + if e.getType() instanceof UnsignedNumericType and s = TNeg() + then result = TPos() + else result = s + ) +} + +/** Gets a possible sign for `e` from the signs of its child nodes. */ +private Sign specificSubExprSign(Expr e) { + result = exprSign(getASubExprWithSameSign(e)) + or + exists(DivExpr div | div = e | + result = exprSign(div.getLeftOperand()) and + result != TZero() and + div.getRightOperand().(RealLiteral).getValue().toFloat() = 0 + ) + or + exists(UnaryOperation unary | unary = e | + result = exprSign(unary.getOperand()).applyUnaryOp(unary.getOp()) + ) + or + exists(Sign s1, Sign s2 | binaryOpSigns(e, s1, s2) | + result = s1.applyBinaryOp(s2, e.(BinaryOperation).getOp()) + ) +} + +pragma[noinline] +private predicate binaryOpSigns(Expr e, Sign lhs, Sign rhs) { + lhs = binaryOpLhsSign(e) and + rhs = binaryOpRhsSign(e) +} + +private Sign binaryOpLhsSign(BinaryOperation e) { result = exprSign(e.getLeftOperand()) } + +private Sign binaryOpRhsSign(BinaryOperation e) { result = exprSign(e.getRightOperand()) } + +/** + * Dummy predicate that holds for any sign. This is added to improve readability + * of cases where the sign is unrestricted. + */ +predicate anySign(Sign s) { any() } + +/** Holds if `e` can be positive and cannot be negative. */ +predicate positive(Expr e) { + exprSign(e) = TPos() and + not exprSign(e) = TNeg() +} + +/** Holds if `e` can be negative and cannot be positive. */ +predicate negative(Expr e) { + exprSign(e) = TNeg() and + not exprSign(e) = TPos() +} + +/** Holds if `e` is strictly positive. */ +predicate strictlyPositive(Expr e) { + exprSign(e) = TPos() and + not exprSign(e) = TNeg() and + not exprSign(e) = TZero() +} + +/** Holds if `e` is strictly negative. */ +predicate strictlyNegative(Expr e) { + exprSign(e) = TNeg() and + not exprSign(e) = TPos() and + not exprSign(e) = TZero() +} diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll new file mode 100644 index 000000000000..782c01d15b7a --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll @@ -0,0 +1,339 @@ +/** + * Provides C#-specific definitions for use in sign analysis. + */ +module Private { + private import csharp as CS + private import SsaUtils as SU + private import ConstantUtils as CU + private import RangeUtils as RU + private import semmle.code.csharp.controlflow.Guards as G + private import Sign + import Impl + + class Guard = G::Guard; + + class ConstantIntegerExpr = CU::ConstantIntegerExpr; + + class SsaVariable = CS::Ssa::Definition; + + class SsaPhiNode = CS::Ssa::PhiNode; + + class VarAccess = CS::AssignableAccess; + + class FieldAccess = CS::FieldAccess; + + class CharacterLiteral = CS::CharLiteral; + + class IntegerLiteral = CS::IntegerLiteral; + + class LongLiteral = CS::LongLiteral; + + class CastExpr = CS::CastExpr; + + class Type = CS::Type; + + class Expr = CS::Expr; + + class VariableUpdate = CS::AssignableDefinition; + + class Field = CS::Field; + + class RealLiteral = CS::RealLiteral; + + class DivExpr = CS::DivExpr; + + /** Class to represent unary operation. */ + class UnaryOperation extends Expr { + UnaryOperation() { + this instanceof CS::PreIncrExpr or + this instanceof CS::PreDecrExpr or + this instanceof CS::UnaryMinusExpr or + this instanceof CS::ComplementExpr + } + + /** Returns the operand of this expression. */ + Expr getOperand() { + result = this.(CS::PreIncrExpr).getOperand() or + result = this.(CS::PreDecrExpr).getOperand() or + result = this.(CS::UnaryMinusExpr).getOperand() or + result = this.(CS::ComplementExpr).getOperand() + } + + /** Returns the operation representing this expression. */ + TUnarySignOperation getOp() { + this instanceof CS::PreIncrExpr and result = TIncOp() + or + this instanceof CS::PreDecrExpr and result = TDecOp() + or + this instanceof CS::UnaryMinusExpr and result = TNegOp() + or + this instanceof CS::ComplementExpr and result = TBitNotOp() + } + } + + /** Class to represent binary operation. */ + class BinaryOperation extends CS::BinaryOperation { + BinaryOperation() { + this instanceof CS::AddExpr or + this instanceof CS::SubExpr or + this instanceof CS::MulExpr or + this instanceof CS::DivExpr or + this instanceof CS::RemExpr or + this instanceof CS::BitwiseAndExpr or + this instanceof CS::BitwiseOrExpr or + this instanceof CS::BitwiseXorExpr or + this instanceof CS::LShiftExpr or + this instanceof CS::RShiftExpr + } + + /** Returns the operation representing this expression. */ + TBinarySignOperation getOp() { + this instanceof CS::AddExpr and result = TAddOp() + or + this instanceof CS::SubExpr and result = TSubOp() + or + this instanceof CS::MulExpr and result = TMulOp() + or + this instanceof CS::DivExpr and result = TDivOp() + or + this instanceof CS::RemExpr and result = TRemOp() + or + this instanceof CS::BitwiseAndExpr and result = TBitAndOp() + or + this instanceof CS::BitwiseOrExpr and result = TBitOrOp() + or + this instanceof CS::BitwiseXorExpr and result = TBitXorOp() + or + this instanceof CS::LShiftExpr and result = TLShiftOp() + or + this instanceof CS::RShiftExpr and result = TRShiftOp() + } + } + + predicate ssaRead = SU::ssaRead/2; + + predicate guardControlsSsaRead = RU::guardControlsSsaRead/3; +} + +private module Impl { + private import csharp + private import SsaUtils + private import ConstantUtils + private import semmle.code.csharp.controlflow.Guards + private import Linq.Helpers + private import Sign + private import SignAnalysisCommon + private import SsaReadPositionCommon + private import semmle.code.csharp.commons.ComparisonTest + + private class BooleanValue = AbstractValues::BooleanValue; + + /** Gets the character value of expression `e`. */ + string getCharValue(Expr e) { result = e.getValue() and e.getType() instanceof CharType } + + /** Gets the constant `float` value of non-`ConstantIntegerExpr` expressions. */ + float getNonIntegerValue(Expr e) { + exists(string s | + s = e.getValue() and + result = s.toFloat() and + not exists(s.toInt()) + ) + } + + /** + * Holds if `e` is an access to the size of a container (`string`, `Array`, + * `IEnumerable`, or `ICollection`). + */ + predicate containerSizeAccess(Expr e) { + exists(Property p | p = e.(PropertyAccess).getTarget() | + propertyOverrides(p, "System.Collections.Generic.IEnumerable<>", "Count") or + propertyOverrides(p, "System.Collections.ICollection", "Count") or + propertyOverrides(p, "System.String", "Length") or + propertyOverrides(p, "System.Array", "Length") + ) + or + e instanceof CountCall + } + + /** Holds if `e` is by definition strictly positive. */ + predicate positiveExpression(Expr e) { e instanceof SizeofExpr } + + abstract class NumericOrCharType extends Type { } + + class UnsignedNumericType extends NumericOrCharType { + UnsignedNumericType() { + this instanceof CharType + or + this instanceof UnsignedIntegralType + or + this instanceof PointerType + or + this instanceof Enum and this.(Enum).getUnderlyingType() instanceof UnsignedIntegralType + } + } + + class SignedNumericType extends NumericOrCharType { + SignedNumericType() { + this instanceof SignedIntegralType + or + this instanceof FloatingPointType + or + this instanceof DecimalType + or + this instanceof Enum and this.(Enum).getUnderlyingType() instanceof SignedIntegralType + } + } + + /** Returns the underlying variable update of the explicit SSA variable `v`. */ + AssignableDefinition getExplicitSsaAssignment(Ssa::ExplicitDefinition v) { + result = v.getADefinition() + } + + /** Returns the assignment of the variable update `def`. */ + Expr getExprFromSsaAssignment(AssignableDefinition def) { result = def.getSource() } + + /** Holds if `def` can have any sign. */ + predicate explicitSsaDefWithAnySign(AssignableDefinition def) { + not exists(def.getSource()) and + not def.getElement() instanceof MutatorOperation + } + + /** Returns the operand of the operation if `def` is a decrement. */ + Expr getDecrementOperand(AssignableDefinition def) { + result = def.getElement().(DecrementOperation).getOperand() + } + + /** Returns the operand of the operation if `def` is an increment. */ + Expr getIncrementOperand(AssignableDefinition def) { + result = def.getElement().(IncrementOperation).getOperand() + } + + /** Gets the variable underlying the implicit SSA variable `v`. */ + Declaration getImplicitSsaDeclaration(Ssa::ImplicitDefinition v) { + result = v.getSourceVariable().getAssignable() + } + + /** Holds if the variable underlying the implicit SSA variable `v` is not a field. */ + predicate nonFieldImplicitSsaDefinition(Ssa::ImplicitDefinition v) { + not getImplicitSsaDeclaration(v) instanceof Field + } + + /** Returned an expression that is assigned to `f`. */ + Expr getAssignedValueToField(Field f) { + result = f.getAnAssignedValue() or + result = any(AssignOperation a | a.getLValue() = f.getAnAccess()) + } + + /** Holds if `f` can have any sign. */ + predicate fieldWithUnknownSign(Field f) { not f.fromSource() or not f.isEffectivelyPrivate() } + + /** Holds if `f` is accessed in an increment operation. */ + predicate fieldIncrementOperationOperand(Field f) { + any(IncrementOperation inc).getOperand() = f.getAnAccess() + } + + /** Holds if `f` is accessed in a decrement operation. */ + predicate fieldDecrementOperationOperand(Field f) { + any(DecrementOperation dec).getOperand() = f.getAnAccess() + } + + /** Returns possible signs of `f` based on the declaration. */ + pragma[inline] + Sign specificFieldSign(Field f) { not exists(f.getInitializer()) and result = TZero() } + + /** + * Holds if `e` has type `NumericOrCharType`, but the sign of `e` is unknown. + */ + predicate numericExprWithUnknownSign(Expr e) { + e.getType() instanceof NumericOrCharType and + not e = getARead(_) and + not e instanceof FieldAccess and + not e instanceof TypeAccess and + // The expression types that are listed here are the ones handled in `specificSubExprSign`. + // Keep them in sync. + not e instanceof AssignExpr and + not e instanceof AssignOperation and + not e instanceof UnaryPlusExpr and + not e instanceof PostIncrExpr and + not e instanceof PostDecrExpr and + not e instanceof PreIncrExpr and + not e instanceof PreDecrExpr and + not e instanceof UnaryMinusExpr and + not e instanceof ComplementExpr and + not e instanceof AddExpr and + not e instanceof SubExpr and + not e instanceof MulExpr and + not e instanceof DivExpr and + not e instanceof RemExpr and + not e instanceof BitwiseAndExpr and + not e instanceof BitwiseOrExpr and + not e instanceof BitwiseXorExpr and + not e instanceof LShiftExpr and + not e instanceof RShiftExpr and + not e instanceof ConditionalExpr and + not e instanceof RefExpr and + not e instanceof LocalVariableDeclAndInitExpr and + not e instanceof SwitchCaseExpr and + not e instanceof CastExpr and + not e instanceof SwitchExpr and + not e instanceof NullCoalescingExpr + } + + /** Returns a sub expression of `e` for expression types where the sign depends on the child. */ + Expr getASubExprWithSameSign(Expr e) { + result = e.(AssignExpr).getRValue() or + result = e.(AssignOperation).getExpandedAssignment() or + result = e.(UnaryPlusExpr).getOperand() or + result = e.(PostIncrExpr).getOperand() or + result = e.(PostDecrExpr).getOperand() or + result = e.(ConditionalExpr).getAChild() or + result = e.(NullCoalescingExpr).getAChild() or + result = e.(SwitchExpr).getACase().getBody() or + result = e.(SwitchCaseExpr).getBody() or + result = e.(LocalVariableDeclAndInitExpr).getInitializer() or + result = e.(RefExpr).getExpr() or + result = e.(CastExpr).getExpr() + } + + Expr getARead(Ssa::Definition v) { result = v.getARead() } + + Field getField(FieldAccess fa) { result = fa.getTarget() } + + Expr getAnExpression(SsaReadPositionBlock bb) { result = bb.getBlock().getANode().getElement() } + + Guard getComparisonGuard(ComparisonExpr ce) { result = ce.getExpr() } + + /** A relational comparison */ + class ComparisonExpr extends ComparisonTest { + private boolean strict; + + ComparisonExpr() { + this.getComparisonKind() = + any(ComparisonKind ck | + ck.isLessThan() and strict = true + or + ck.isLessThanEquals() and + strict = false + ) + } + + /** + * Gets the operand on the "greater" (or "greater-or-equal") side + * of this relational expression, that is, the side that is larger + * if the overall expression evaluates to `true`; for example on + * `x <= 20` this is the `20`, and on `y > 0` it is `y`. + */ + Expr getGreaterOperand() { result = this.getSecondArgument() } + + /** + * Gets the operand on the "lesser" (or "lesser-or-equal") side + * of this relational expression, that is, the side that is smaller + * if the overall expression evaluates to `true`; for example on + * `x <= 20` this is `x`, and on `y > 0` it is the `0`. + */ + Expr getLesserOperand() { result = this.getFirstArgument() } + + /** Holds if this comparison is strict, i.e. `<` or `>`. */ + predicate isStrict() { strict = true } + } +} diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll new file mode 100644 index 000000000000..558ecd1b88b3 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll @@ -0,0 +1,57 @@ +/** + * Provides classes for representing a position at which an SSA variable is read. + */ + +private import SsaReadPositionSpecific + +private newtype TSsaReadPosition = + TSsaReadPositionBlock(BasicBlock bb) { bb = getAReadBasicBlock(_) } or + TSsaReadPositionPhiInputEdge(BasicBlock bbOrig, BasicBlock bbPhi) { + exists(SsaPhiNode phi | phi.hasInputFromBlock(_, bbOrig) and bbPhi = phi.getBasicBlock()) + } + +/** + * A position at which an SSA variable is read. This includes both ordinary + * reads occurring in basic blocks and input to phi nodes occurring along an + * edge between two basic blocks. + */ +class SsaReadPosition extends TSsaReadPosition { + /** Holds if `v` is read at this position. */ + abstract predicate hasReadOfVar(SsaVariable v); + + /** Gets a textual representation of this SSA read position. */ + abstract string toString(); +} + +/** A basic block in which an SSA variable is read. */ +class SsaReadPositionBlock extends SsaReadPosition, TSsaReadPositionBlock { + /** Gets the basic block corresponding to this position. */ + BasicBlock getBlock() { this = TSsaReadPositionBlock(result) } + + override predicate hasReadOfVar(SsaVariable v) { getBlock() = getAReadBasicBlock(v) } + + override string toString() { result = "block" } +} + +/** + * An edge between two basic blocks where the latter block has an SSA phi + * definition. The edge therefore has a read of an SSA variable serving as the + * input to the phi node. + */ +class SsaReadPositionPhiInputEdge extends SsaReadPosition, TSsaReadPositionPhiInputEdge { + /** Gets the source of the edge. */ + BasicBlock getOrigBlock() { this = TSsaReadPositionPhiInputEdge(result, _) } + + /** Gets the target of the edge. */ + BasicBlock getPhiBlock() { this = TSsaReadPositionPhiInputEdge(_, result) } + + override predicate hasReadOfVar(SsaVariable v) { this.phiInput(_, v) } + + /** Holds if `inp` is an input to `phi` along this edge. */ + predicate phiInput(SsaPhiNode phi, SsaVariable inp) { + phi.hasInputFromBlock(inp, getOrigBlock()) and + getPhiBlock() = phi.getBasicBlock() + } + + override string toString() { result = "edge" } +} diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionSpecific.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionSpecific.qll new file mode 100644 index 000000000000..d7df9781b2ae --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionSpecific.qll @@ -0,0 +1,16 @@ +/** + * Provides C#-specific definitions for use in the `SsaReadPosition`. + */ + +private import csharp + +class SsaVariable = Ssa::Definition; + +class SsaPhiNode = Ssa::PhiNode; + +class BasicBlock = Ssa::BasicBlock; + +/** Gets a basic block in which SSA variable `v` is read. */ +BasicBlock getAReadBasicBlock(SsaVariable v) { + result = v.getARead().getAControlFlowNode().getBasicBlock() +} diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaUtils.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaUtils.qll new file mode 100644 index 000000000000..7f1811c1f371 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaUtils.qll @@ -0,0 +1,42 @@ +/** + * Provides utility predicates to extend the core SSA functionality. + */ + +private import csharp +private import Ssa +private import ConstantUtils + +/** + * Gets an expression that equals `v - delta`. + */ +Expr ssaRead(Definition v, int delta) { + result = v.getARead() and delta = 0 + or + exists(AddExpr add, int d1, ConstantIntegerExpr c | + result = add and + delta = d1 - c.getIntValue() + | + add.getLeftOperand() = ssaRead(v, d1) and add.getRightOperand() = c + or + add.getRightOperand() = ssaRead(v, d1) and add.getLeftOperand() = c + ) + or + exists(SubExpr sub, int d1, ConstantIntegerExpr c | + result = sub and + sub.getLeftOperand() = ssaRead(v, d1) and + sub.getRightOperand() = c and + delta = d1 + c.getIntValue() + ) + or + v.(ExplicitDefinition).getADefinition().getExpr().(PreIncrExpr) = result and delta = 0 + or + v.(ExplicitDefinition).getADefinition().getExpr().(PreDecrExpr) = result and delta = 0 + or + v.(ExplicitDefinition).getADefinition().getExpr().(PostIncrExpr) = result and delta = 1 // x++ === ++x - 1 + or + v.(ExplicitDefinition).getADefinition().getExpr().(PostDecrExpr) = result and delta = -1 // x-- === --x + 1 + or + v.(ExplicitDefinition).getADefinition().getExpr().(Assignment) = result and delta = 0 + or + result.(AssignExpr).getRValue() = ssaRead(v, delta) +} diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll index 0f0607662e90..b509fad9cd20 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * To create a configuration, extend this class with a subclass whose * characteristic predicate is a unique singleton string. For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends TaintTracking::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -76,20 +76,20 @@ abstract class Configuration extends DataFlow::Configuration { final override predicate isBarrier(DataFlow::Node node) { isSanitizer(node) or - defaultTaintBarrier(node) + defaultTaintSanitizer(node) } - /** Holds if data flow into `node` is prohibited. */ + /** Holds if taint propagation into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) } - /** Holds if data flow out of `node` is prohibited. */ + /** Holds if taint propagation out of `node` is prohibited. */ predicate isSanitizerOut(DataFlow::Node node) { none() } final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) } - /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + /** Holds if taint propagation through nodes guarded by `guard` is prohibited. */ predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() } final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll index 0f0607662e90..b509fad9cd20 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * To create a configuration, extend this class with a subclass whose * characteristic predicate is a unique singleton string. For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends TaintTracking::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -76,20 +76,20 @@ abstract class Configuration extends DataFlow::Configuration { final override predicate isBarrier(DataFlow::Node node) { isSanitizer(node) or - defaultTaintBarrier(node) + defaultTaintSanitizer(node) } - /** Holds if data flow into `node` is prohibited. */ + /** Holds if taint propagation into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) } - /** Holds if data flow out of `node` is prohibited. */ + /** Holds if taint propagation out of `node` is prohibited. */ predicate isSanitizerOut(DataFlow::Node node) { none() } final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) } - /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + /** Holds if taint propagation through nodes guarded by `guard` is prohibited. */ predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() } final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll index 0f0607662e90..b509fad9cd20 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * To create a configuration, extend this class with a subclass whose * characteristic predicate is a unique singleton string. For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends TaintTracking::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -76,20 +76,20 @@ abstract class Configuration extends DataFlow::Configuration { final override predicate isBarrier(DataFlow::Node node) { isSanitizer(node) or - defaultTaintBarrier(node) + defaultTaintSanitizer(node) } - /** Holds if data flow into `node` is prohibited. */ + /** Holds if taint propagation into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) } - /** Holds if data flow out of `node` is prohibited. */ + /** Holds if taint propagation out of `node` is prohibited. */ predicate isSanitizerOut(DataFlow::Node node) { none() } final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) } - /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + /** Holds if taint propagation through nodes guarded by `guard` is prohibited. */ predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() } final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll index 0f0607662e90..b509fad9cd20 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * To create a configuration, extend this class with a subclass whose * characteristic predicate is a unique singleton string. For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends TaintTracking::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -76,20 +76,20 @@ abstract class Configuration extends DataFlow::Configuration { final override predicate isBarrier(DataFlow::Node node) { isSanitizer(node) or - defaultTaintBarrier(node) + defaultTaintSanitizer(node) } - /** Holds if data flow into `node` is prohibited. */ + /** Holds if taint propagation into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) } - /** Holds if data flow out of `node` is prohibited. */ + /** Holds if taint propagation out of `node` is prohibited. */ predicate isSanitizerOut(DataFlow::Node node) { none() } final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) } - /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + /** Holds if taint propagation through nodes guarded by `guard` is prohibited. */ predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() } final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll index 0f0607662e90..b509fad9cd20 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * To create a configuration, extend this class with a subclass whose * characteristic predicate is a unique singleton string. For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends TaintTracking::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -76,20 +76,20 @@ abstract class Configuration extends DataFlow::Configuration { final override predicate isBarrier(DataFlow::Node node) { isSanitizer(node) or - defaultTaintBarrier(node) + defaultTaintSanitizer(node) } - /** Holds if data flow into `node` is prohibited. */ + /** Holds if taint propagation into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) } - /** Holds if data flow out of `node` is prohibited. */ + /** Holds if taint propagation out of `node` is prohibited. */ predicate isSanitizerOut(DataFlow::Node node) { none() } final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) } - /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + /** Holds if taint propagation through nodes guarded by `guard` is prohibited. */ predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() } final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) } diff --git a/csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll b/csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll index 3e74eb4ff45a..925ee3e97445 100644 --- a/csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll +++ b/csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll @@ -30,6 +30,26 @@ class DispatchCall extends Internal::TDispatchCall { /** Gets a dynamic (run-time) target of this call, if any. */ RuntimeCallable getADynamicTarget() { result = Internal::getADynamicTarget(this) } + + /** + * Holds if a call context may limit the set of viable source declaration + * run-time targets of this call. + * + * This is the case if the qualifier is either a `this` access or a parameter + * access, as the corresponding qualifier/argument in the call context may + * have a more precise type. + */ + predicate mayBenefitFromCallContext() { Internal::mayBenefitFromCallContext(this) } + + /** + * Gets a dynamic (run-time) target of this call in call context `ctx`, if any. + * + * This predicate is restricted to calls for which `mayBenefitFromCallContext()` + * holds. + */ + RuntimeCallable getADynamicTargetInCallContext(DispatchCall ctx) { + result = Internal::getADynamicTargetInCallContext(this, ctx) + } } /** Internal implementation details. */ @@ -40,6 +60,7 @@ private module Internal { private import semmle.code.csharp.dataflow.internal.Steps private import semmle.code.csharp.frameworks.System private import semmle.code.csharp.frameworks.system.Reflection + private import semmle.code.csharp.dataflow.internal.BaseSSA cached private module Cached { @@ -90,6 +111,16 @@ private module Internal { RuntimeCallable getADynamicTarget(DispatchCall dc) { result = dc.(DispatchCallImpl).getADynamicTarget() } + + cached + predicate mayBenefitFromCallContext(DispatchMethodOrAccessorCall dc) { + dc.mayBenefitFromCallContext(_, _) + } + + cached + RuntimeCallable getADynamicTargetInCallContext(DispatchMethodOrAccessorCall dc, DispatchCall ctx) { + result = dc.getADynamicTargetInCallContext(ctx) + } } import Cached @@ -190,6 +221,17 @@ private module Internal { abstract RuntimeCallable getADynamicTarget(); } + /** A non-constructed overridable callable. */ + private class NonConstructedOverridableCallable extends OverridableCallable { + NonConstructedOverridableCallable() { not this instanceof ConstructedMethod } + + OverridableCallable getAConstructingCallableOrSelf() { + result = this + or + result = this.(UnboundGenericMethod).getAConstructedGeneric() + } + } + pragma[noinline] private predicate hasOverrider(OverridableCallable oc, ValueOrRefType t) { exists(oc.getAnOverrider(t)) @@ -223,12 +265,13 @@ private module Internal { private predicate hasQualifierTypeOverridden0(ValueOrRefType t, DispatchMethodOrAccessorCall call) { hasOverrider(_, t) and ( - exists(Type t0 | t0 = getAPossibleType(call.getQualifier(), false) | - t = t0 - or - Unification::subsumes(t0, t) + exists(Type t0, Type t1 | + t0 = getAPossibleType(call.getQualifier(), false) and + t1 = [t0, t0.(Unification::UnconstrainedTypeParameter).getAnUltimatelySuppliedType()] + | + t = t1 or - t = t0.(Unification::UnconstrainedTypeParameter).getAnUltimatelySuppliedType() + Unification::subsumes(t1, t) ) or constrainedTypeParameterQualifierTypeSubsumes(t, @@ -249,15 +292,257 @@ private module Internal { abstract private class DispatchMethodOrAccessorCall extends DispatchCallImpl { pragma[nomagic] - predicate hasQualifierTypeInherited(SourceDeclarationType t) { - t = getAPossibleType(this.getQualifier(), _).getSourceDeclaration() - } + predicate hasQualifierTypeInherited(Type t) { t = getAPossibleType(this.getQualifier(), _) } pragma[nomagic] predicate hasQualifierTypeOverridden(ValueOrRefType t, OverridableCallable c) { hasQualifierTypeOverridden0(t, this) and hasCallable(any(OverridableCallable oc | hasQualifierTypeOverridden1(oc, this)), t, c) } + + /** + * Holds if a call context may limit the set of viable source declaration + * run-time targets of this call. + * + * This is the case if the qualifier is either a `this` access or a parameter + * access, as the corresponding qualifier/argument in the call context may + * have a more precise type. + */ + predicate mayBenefitFromCallContext(Callable c, int i) { + 1 < strictcount(this.getADynamicTarget().getSourceDeclaration()) and + c = this.getCall().getEnclosingCallable().getSourceDeclaration() and + ( + exists(AssignableDefinitions::ImplicitParameterDefinition pdef, Parameter p | + this.getQualifier() = BaseSsa::getARead(pdef, p) and + p.getPosition() = i and + c.getAParameter() = p and + not p.isParams() + ) + or + i = -1 and + this.getQualifier() instanceof ThisAccess + ) + } + + /** + * Holds if the call `ctx` might act as a context that improves the set of + * dispatch targets of this call, depending on the type of the `i`th argument + * of `ctx`. + */ + pragma[nomagic] + private predicate relevantContext(DispatchCall ctx, int i) { + this.mayBenefitFromCallContext(ctx.getADynamicTarget().getSourceDeclaration(), i) + } + + /** + * Holds if the argument of `ctx`, which is passed for the parameter that is + * accessed in the qualifier of this call, has type `t` and `ctx` is a relevant + * call context. + */ + private predicate contextArgHasType(DispatchCall ctx, Type t, boolean isExact) { + exists(Expr arg, int i | + this.relevantContext(ctx, i) and + t = getAPossibleType(arg, isExact) + | + ctx.getArgument(i) = arg + or + ctx.getQualifier() = arg and + i = -1 + ) + } + + pragma[nomagic] + private Callable getASubsumedStaticTarget0(Type t) { + exists(Callable staticTarget, Type declType | + staticTarget = this.getAStaticTarget() and + declType = staticTarget.getDeclaringType() and + result = staticTarget.getSourceDeclaration() and + Unification::subsumes(declType, t) + ) + } + + /** + * Gets a callable whose source declaration matches the source declaration of + * some static target `target`, and whose declaring type is subsumed by the + * declaring type of `target`. + */ + pragma[nomagic] + private Callable getASubsumedStaticTarget() { + result = this.getAStaticTarget() + or + result.getSourceDeclaration() = this.getASubsumedStaticTarget0(result.getDeclaringType()) + } + + /** + * Gets a callable inherited by (or defined in) the qualifier type of this + * call that overrides (or equals) a static target of this call. + * + * Example: + * + * ```csharp + * class A + * { + * public virtual void M() { } + * } + * + * class B : A + * { + * public override void M() { } + * } + * + * class C : B { } + * + * class D + * { + * void CallM() + * { + * A x = new A(); + * x.M(); + * x = new B(); + * x.M(); + * x = new C(); + * x.M(); + * } + * } + * ``` + * + * The static target is `A.M` in all three calls on lines 14, 16, and 18, + * but the methods inherited by the actual qualifier types are `A.M`, + * `B.M`, and `B.M`, respectively. + */ + private RuntimeCallable getAViableInherited() { + exists(NonConstructedOverridableCallable c, Type t | this.hasQualifierTypeInherited(t) | + this.getASubsumedStaticTarget() = c.getAConstructingCallableOrSelf() and + result = c.getInherited(t) + or + t instanceof TypeParameter and + this.getAStaticTarget() = c.getAConstructingCallableOrSelf() and + result = c + ) + } + + /** + * Gets a callable that is defined in a subtype of the qualifier type of this + * call, and which overrides a static target of this call. + * + * Example: + * + * ```csharp + * class A + * { + * public virtual void M() { } + * } + * + * class B : A + * { + * public override void M() { } + * } + * + * class C : B + * { + * public override void M() { } + * } + * + * class D + * { + * void CallM() + * { + * A x = new A(); + * x.M(); + * x = new B(); + * x.M(); + * x = new C(); + * x.M(); + * } + * } + * ``` + * + * The static target is `A.M` in all three calls on lines 16, 18, and 20, + * but the methods overriding the static targets in subtypes of the actual + * qualifier types are `B.M` and `C.M`, `C.M`, and none, respectively. + */ + private RuntimeCallable getAViableOverrider() { + exists(ValueOrRefType t, NonConstructedOverridableCallable c | + this.hasQualifierTypeOverridden(t, c.getAConstructingCallableOrSelf()) and + result = c.getAnOverrider(t) + ) + } + + override RuntimeCallable getADynamicTarget() { + result = getAViableInherited() + or + result = getAViableOverrider() + or + // Simple case: target method cannot be overridden + result = getAStaticTarget() and + not result instanceof OverridableCallable + } + + pragma[nomagic] + private RuntimeCallable getAViableInheritedInCallContext0(ValueOrRefType t) { + this.contextArgHasType(_, t, _) and + result = this.getADynamicTarget() + } + + pragma[nomagic] + private RuntimeCallable getAViableInheritedInCallContext1( + NonConstructedOverridableCallable c, ValueOrRefType t + ) { + result = this.getAViableInheritedInCallContext0(t) and + result = c.getInherited(t) + } + + pragma[nomagic] + private RuntimeCallable getAViableInheritedInCallContext(DispatchCall ctx) { + exists(Type t, NonConstructedOverridableCallable c | this.contextArgHasType(ctx, t, _) | + this.getASubsumedStaticTarget() = c.getAConstructingCallableOrSelf() and + result = this.getAViableInheritedInCallContext1(c, t) + or + t instanceof TypeParameter and + this.getAStaticTarget() = c.getAConstructingCallableOrSelf() and + result = c + ) + } + + pragma[nomagic] + private RuntimeCallable getAViableOverriderInCallContext0( + NonConstructedOverridableCallable c, ValueOrRefType t + ) { + result = this.getAViableOverrider() and + this.contextArgHasType(_, _, false) and + result = c.getAnOverrider(t) + } + + pragma[nomagic] + private RuntimeCallable getAViableOverriderInCallContext1( + NonConstructedOverridableCallable c, DispatchCall ctx + ) { + exists(ValueOrRefType t | + result = this.getAViableOverriderInCallContext0(c, t) and + exists(Type t0, Type t1 | + this.contextArgHasType(ctx, t0, false) and + t1 = [t0, t0.(Unification::UnconstrainedTypeParameter).getAnUltimatelySuppliedType()] + | + t = t1 + or + Unification::subsumes(t1, t) + ) + ) + } + + pragma[nomagic] + private RuntimeCallable getAViableOverriderInCallContext(DispatchCall ctx) { + exists(NonConstructedOverridableCallable c | + result = this.getAViableOverriderInCallContext1(c, ctx) and + this.getAStaticTarget() = c.getAConstructingCallableOrSelf() + ) + } + + RuntimeCallable getADynamicTargetInCallContext(DispatchCall ctx) { + result = this.getAViableInheritedInCallContext(ctx) + or + result = this.getAViableOverriderInCallContext(ctx) + } } private class DynamicFieldOrProperty extends Assignable { @@ -386,6 +671,8 @@ private module Internal { .getQualifier() or this = any(DispatchCallImpl c).getQualifier() + or + this = any(DispatchCallImpl c).getArgument(_) } Source getASource() { stepTC(this, result) } @@ -430,109 +717,8 @@ private module Internal { override Expr getQualifier() { result = getCall().getQualifier() } override Method getAStaticTarget() { result = getCall().getTarget() } - - override RuntimeMethod getADynamicTarget() { - result = getViableInherited() - or - result = getAViableOverrider() - or - // Simple case: target method cannot be overridden - result = getAStaticTarget() and - not result instanceof OverridableMethod - } - - /** - * Gets the (unique) instance method inherited by (or defined in) the - * qualifier type of this call that overrides (or equals) the static - * target of this call. - * - * Example: - * - * ``` - * class A { - * public virtual void M() { } - * } - * - * class B : A { - * public override void M() { } - * } - * - * class C : B { } - * - * class D { - * void CallM() { - * A x = new A(); - * x.M(); - * x = new B(); - * x.M(); - * x = new C(); - * x.M(); - * } - * } - * ``` - * - * The static target is `A.M` in all three calls on lines 14, 16, and 18, - * but the methods inherited by the actual qualifier types are `A.M`, - * `B.M`, and `B.M`, respectively. - */ - private RuntimeInstanceMethod getViableInherited() { - exists(NonConstructedOverridableMethod m, SourceDeclarationType t | - this.getAStaticTarget() = m.getAConstructingMethodOrSelf() and - this.hasQualifierTypeInherited(t) - | - result = m.getInherited(t) - or - t instanceof TypeParameter and - result = m - ) - } - - /** - * Gets an instance method that is defined in a subtype of the qualifier - * type of this call, and which overrides the static target of this call. - * - * Example: - * - * ``` - * class A { - * public virtual void M() { } - * } - * - * class B : A { - * public override void M() { } - * } - * - * class C : B { - * public override void M() { } - * } - * - * class D { - * void CallM() { - * A x = new A(); - * x.M(); - * x = new B(); - * x.M(); - * x = new C(); - * x.M(); - * } - * } - * ``` - * - * The static target is `A.M` in all three calls on lines 16, 18, and 20, - * but the methods overriding the static targets in subtypes of the actual - * qualifier types are `B.M` and `C.M`, `C.M`, and none, respectively. - */ - private RuntimeInstanceMethod getAViableOverrider() { - exists(ValueOrRefType t, NonConstructedOverridableMethod m | - this.hasQualifierTypeOverridden(t, m.getAConstructingMethodOrSelf()) and - result = m.getAnOverrider(t) - ) - } } - /** A non-constructed overridable method. */ - private class NonConstructedOverridableMethod extends OverridableMethod, NonConstructedMethod { } - /** * A call to an accessor. * @@ -549,7 +735,7 @@ private module Internal { override Accessor getAStaticTarget() { result = getCall().getTarget() } override RuntimeAccessor getADynamicTarget() { - result = getADynamicTargetCandidate() and + result = DispatchMethodOrAccessorCall.super.getADynamicTarget() and // Calls to accessors may have `dynamic` expression arguments, // so we need to check that the types match forall(Type argumentType, int i | hasDynamicArg(i, argumentType) | @@ -557,16 +743,6 @@ private module Internal { ) } - private RuntimeAccessor getADynamicTargetCandidate() { - result = getViableInherited() - or - result = getAViableOverrider() - or - // Simple case: target accessor cannot be overridden - result = getAStaticTarget() and - not result instanceof OverridableAccessor - } - private predicate hasDynamicArg(int i, Type argumentType) { exists(Expr argument | argument = getArgument(i) and @@ -574,91 +750,6 @@ private module Internal { argumentType = getAPossibleType(argument, _) ) } - - /** - * Gets the (unique) accessor inherited by (or defined in) the qualifier - * type of this call that overrides (or equals) the static target of this - * call. - * - * Example: - * - * ``` - * class A { - * public virtual int P { get => 0; } - * } - * - * class B : A { - * public override int P { get => 1; } - * } - * - * class C : B { } - * - * class D { - * void CallM() { - * A x = new A(); - * x.P; - * x = new B(); - * x.P; - * x = new C(); - * x.P; - * } - * } - * ``` - * - * The static target is `A.get_P` in all three calls on lines 14, 16, and 18, - * but the accessors inherited by the actual qualifier types are `A.get_P`, - * `B.get_P`, and `B.get_P`, respectively. - */ - private RuntimeAccessor getViableInherited() { - exists(OverridableAccessor a, SourceDeclarationType t | - this.getAStaticTarget() = a and - this.hasQualifierTypeInherited(t) and - result = a.getInherited(t) - ) - } - - /** - * Gets an accessor that is defined in a subtype of the qualifier type of - * this call, and which overrides the static target of this call. - * - * Example: - * - * ``` - * class A { - * public virtual int P { get => 0; } - * } - * - * class B : A { - * public override int P { get => 1; } - * } - * - * class C : B { - * public override int P { get => 2; } - * } - * - * class D { - * void CallM() { - * A x = new A(); - * x.P; - * x = new B(); - * x.P; - * x = new C(); - * x.P; - * } - * } - * ``` - * - * The static target is `A.get_P` in all three calls on lines 16, 18, and 20, - * but the accessors overriding the static targets in subtypes of the actual - * qualifier types are `B.get_P` and `C.get_P`, `C.get_P`, and none, - * respectively. - */ - private RuntimeAccessor getAViableOverrider() { - exists(ValueOrRefType t, OverridableAccessor a | - this.hasQualifierTypeOverridden(t, a) and - result = a.getAnOverrider(t) - ) - } } /** A reflection-based call or a call using dynamic types. */ @@ -686,22 +777,25 @@ private module Internal { * For reflection/dynamic calls, unless the type of the qualifier is exact, * all subtypes of the qualifier type must be considered relevant. Example: * - * ``` - * class A { - * public void M() { Console.WriteLine("A"); } + * ```csharp + * class A + * { + * public void M() { Console.WriteLine("A"); } * } * - * class B : A { - * new public void M() { Console.WriteLine("B"); } + * class B : A + * { + * new public void M() { Console.WriteLine("B"); } * } * - * class C { - * void InvokeMDyn(A x) { ((dynamic) x).M(); } + * class C + * { + * void InvokeMDyn(A x) { ((dynamic) x).M(); } * - * void CallM() { - * InvokeMDyn(new A()); // prints "A" - * InvokeMDyn(new B()); // prints "B" - * } + * void CallM() { + * InvokeMDyn(new A()); // prints "A" + * InvokeMDyn(new B()); // prints "B" + * } * } * ``` * diff --git a/csharp/ql/src/semmle/code/csharp/dispatch/OverridableCallable.qll b/csharp/ql/src/semmle/code/csharp/dispatch/OverridableCallable.qll index e8c717b8e097..cfb8c89f7bbf 100644 --- a/csharp/ql/src/semmle/code/csharp/dispatch/OverridableCallable.qll +++ b/csharp/ql/src/semmle/code/csharp/dispatch/OverridableCallable.qll @@ -38,7 +38,7 @@ class OverridableCallable extends Callable { * * Example: * - * ``` + * ```csharp * interface I { void M(); } * * class A { public void M() { } } @@ -76,7 +76,7 @@ class OverridableCallable extends Callable { * * Note that this is generally *not* equivalent with * - * ``` + * ```ql * result = getAnImplementor() * or * result = getAnImplementor().(OverridableCallable).getAnOverrider+()` @@ -84,7 +84,7 @@ class OverridableCallable extends Callable { * * as the example below illustrates: * - * ``` + * ```csharp * interface I { void M(); } * * class A { public virtual void M() { } } @@ -118,7 +118,7 @@ class OverridableCallable extends Callable { * * Example: * - * ``` + * ```csharp * class C1 { public virtual void M() { } } * * class C2 : C1 { public override void M() { } } @@ -134,10 +134,9 @@ class OverridableCallable extends Callable { * - `C2.M = C2.M.getInherited(C2)`, and * - `C2.M = C2.M.getInherited(C3)`. */ - Callable getInherited(SourceDeclarationType t) { - exists(Callable sourceDecl | result = this.getInherited2(t, sourceDecl) | - hasSourceDeclarationCallable(t, sourceDecl) - ) + Callable getInherited(ValueOrRefType t) { + result = this.getInherited1(t) and + t.hasCallable(result) } private Callable getInherited0(ValueOrRefType t) { @@ -150,19 +149,11 @@ class OverridableCallable extends Callable { exists(ValueOrRefType mid | result = this.getInherited0(mid) | t = mid.getASubType()) } - private Callable getInherited1(SourceDeclarationType t) { - exists(ValueOrRefType t0 | result = getInherited0(t0) | t = t0.getSourceDeclaration()) + private Callable getInherited1(ValueOrRefType t) { + result = getInherited0(t) or // An interface implementation - exists(ValueOrRefType s | - result = getAnImplementorSubType(s) and - t = s.getSourceDeclaration() - ) - } - - private Callable getInherited2(SourceDeclarationType t, Callable sourceDecl) { - result = this.getInherited1(t) and - sourceDecl = result.getSourceDeclaration() + result = getAnImplementorSubType(t) } pragma[noinline] @@ -218,11 +209,6 @@ class OverridableCallable extends Callable { } } -pragma[noinline] -private predicate hasSourceDeclarationCallable(ValueOrRefType t, Callable sourceDecl) { - exists(Callable c | t.hasCallable(c) | sourceDecl = c.getSourceDeclaration()) -} - /** An overridable method. */ class OverridableMethod extends Method, OverridableCallable { override Method getAnOverrider() { result = Method.super.getAnOverrider() } @@ -231,7 +217,7 @@ class OverridableMethod extends Method, OverridableCallable { override Method getAnUltimateImplementor() { result = Method.super.getAnUltimateImplementor() } - override Method getInherited(SourceDeclarationType t) { + override Method getInherited(ValueOrRefType t) { result = OverridableCallable.super.getInherited(t) } @@ -278,7 +264,7 @@ class OverridableAccessor extends Accessor, OverridableCallable { ) } - override Accessor getInherited(SourceDeclarationType t) { + override Accessor getInherited(ValueOrRefType t) { result = OverridableCallable.super.getInherited(t) } diff --git a/csharp/ql/src/semmle/code/csharp/dispatch/RuntimeCallable.qll b/csharp/ql/src/semmle/code/csharp/dispatch/RuntimeCallable.qll index a6d8a0ac9fac..22758fce4abd 100644 --- a/csharp/ql/src/semmle/code/csharp/dispatch/RuntimeCallable.qll +++ b/csharp/ql/src/semmle/code/csharp/dispatch/RuntimeCallable.qll @@ -26,6 +26,7 @@ class RuntimeMethod extends RuntimeCallable { this instanceof CIL::Method } + /** Holds if the method is `static`. */ predicate isStatic() { this.(Method).isStatic() or this.(CIL::Method).isStatic() } } diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Access.qll b/csharp/ql/src/semmle/code/csharp/exprs/Access.qll index 842c374ecd1a..ab3ea1820562 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Access.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Access.qll @@ -51,7 +51,7 @@ private module AccessImpl { /** * A `this` access, for example `this` on line 5 in * - * ``` + * ```csharp * class C { * int Count; * @@ -64,7 +64,7 @@ private module AccessImpl { * Note that a `this` access may be implicit, for example the implicit `this` * qualifier on line 5 in * - * ``` + * ```csharp * class C { * int Count; * @@ -78,12 +78,14 @@ class ThisAccess extends Access, @this_access_expr { override Class getTarget() { result = this.getEnclosingCallable().getDeclaringType() } override string toString() { result = "this access" } + + override string getAPrimaryQlClass() { result = "ThisAccess" } } /** * A `base` access, for example `base` on line 2 in * - * ``` + * ```csharp * public override void Dispose() { * base.Dispose(); * ... @@ -96,6 +98,8 @@ class BaseAccess extends Access, @base_access_expr { } override string toString() { result = "base access" } + + override string getAPrimaryQlClass() { result = "BaseAccess" } } /** @@ -211,7 +215,7 @@ class LocalScopeVariableWrite extends LocalScopeVariableAccess, VariableWrite { /** * An access to a parameter, for example the access to `p` on line 2 in * - * ``` + * ```csharp * int M(int p) { * return -p; * } @@ -221,13 +225,15 @@ class ParameterAccess extends LocalScopeVariableAccess, @parameter_access_expr { override Parameter getTarget() { expr_access(this, result) } override string toString() { result = "access to parameter " + this.getTarget().getName() } + + override string getAPrimaryQlClass() { result = "ParameterAccess" } } /** * An access to a parameter that reads the underlying value, for example * the access to `p` on line 2 in * - * ``` + * ```csharp * int M(int p) { * return -p; * } @@ -245,7 +251,7 @@ class ParameterRead extends ParameterAccess, LocalScopeVariableRead { * An access to a parameter that updates the underlying value, for example * the access to `p` on line 2 in * - * ``` + * ```csharp * int M(int p) { * p = 1; * return p; @@ -257,7 +263,7 @@ class ParameterWrite extends ParameterAccess, VariableWrite { } /** * An access to a local variable, for example the access to `x` on line 3 in * - * ``` + * ```csharp * int M(int p) { * var x = -p; * return x; @@ -273,13 +279,15 @@ class LocalVariableAccess extends LocalScopeVariableAccess, @local_variable_acce not this instanceof LocalVariableDeclExpr and result = "access to local variable " + this.getTarget().getName() } + + override string getAPrimaryQlClass() { result = "LocalVariableAccess" } } /** * An access to a local variable that reads the underlying value, for example * the access to `x` on line 3 in * - * ``` + * ```csharp * int M(int p) { * var x = -p; * return x; @@ -298,7 +306,7 @@ class LocalVariableRead extends LocalVariableAccess, LocalScopeVariableRead { * An access to a local variable that updates the underlying value, for example * the access to `x` on line 3 in * - * ``` + * ```csharp * int M(int p) { * int x; * x = -p; @@ -311,7 +319,7 @@ class LocalVariableWrite extends LocalVariableAccess, VariableWrite { } /** * An access to a field, for example the access to `F` on line 5 in * - * ``` + * ```csharp * class C { * int F = 0; * @@ -325,13 +333,15 @@ class FieldAccess extends AssignableMemberAccess, VariableAccess, @field_access_ override Field getTarget() { expr_access(this, result) } override string toString() { result = "access to field " + this.getTarget().getName() } + + override string getAPrimaryQlClass() { result = "FieldAccess" } } /** * An access to a field that reads the underlying value, for example the * access to `F` on line 5 in * - * ``` + * ```csharp * class C { * int F = 0; * @@ -347,7 +357,7 @@ class FieldRead extends FieldAccess, VariableRead { } * An access to a field that updates the underlying value, for example the * access to `F` on line 5 in * - * ``` + * ```csharp * class C { * int F = 0; * @@ -362,7 +372,7 @@ class FieldWrite extends FieldAccess, VariableWrite { } /** * An access to a member (field), for example the access to `F` on line 5 in * - * ``` + * ```csharp * class C { * const int F = 0; * @@ -378,6 +388,8 @@ class MemberConstantAccess extends FieldAccess { override MemberConstant getTarget() { expr_access(this, result) } override string toString() { result = "access to constant " + this.getTarget().getName() } + + override string getAPrimaryQlClass() { result = "MemberConstantAccess" } } /** @@ -399,7 +411,7 @@ library class PropertyAccessExpr extends Expr, @property_access_expr { /** * An access to a property, for example the access to `P` on line 5 in * - * ``` + * ```csharp * class C { * int P { get; private set; } * @@ -417,7 +429,7 @@ class PropertyAccess extends AssignableMemberAccess, PropertyAccessExpr { * An access to a property that reads the underlying value, for example * the access to `P` on line 5 in * - * ``` + * ```csharp * class C { * int P { get; private set; } * @@ -437,7 +449,7 @@ class PropertyRead extends PropertyAccess, AssignableRead { * An access to a property that updates the underlying value, for example the * access to `P` on line 5 in * - * ``` + * ```csharp * class C { * int P { get; private set; } * @@ -453,7 +465,7 @@ class PropertyWrite extends PropertyAccess, AssignableWrite { } * An access to a trivial property - a property with a default getter and * setter. For example, the access to `P` on line 5 in * - * ``` + * ```csharp * class C { * int P { get; private set; } * @@ -471,7 +483,7 @@ class TrivialPropertyAccess extends PropertyAccess { * An access to a virtual property - a property that is virtual or defined in * an interface. For example, the access to `P` on line 5 in * - * ``` + * ```csharp * class C { * virtual int P { get; private set; } * @@ -534,7 +546,7 @@ library class IndexerAccessExpr extends Expr, @indexer_access_expr { /** * An access to an indexer, for example the access to `c` on line 5 in * - * ``` + * ```csharp * class C { * public string this[int i] { ... } * @@ -556,7 +568,7 @@ class IndexerAccess extends AssignableMemberAccess, ElementAccess, IndexerAccess * An access to an indexer that reads the underlying value, for example the * access to `c` on line 5 in * - * ``` + * ```csharp * class C { * public string this[int i] { ... } * @@ -576,7 +588,7 @@ class IndexerRead extends IndexerAccess, ElementRead { * An access to an indexer that updates the underlying value, for example the * access to `c` on line 5 in * - * ``` + * ```csharp * class C { * public string this[int i] { ... } * @@ -592,7 +604,7 @@ class IndexerWrite extends IndexerAccess, ElementWrite { } * An access to a virtual indexer - an indexer that is virtual or defined in * an interface. For example, the access to `c` on line 5 in * - * ``` + * ```csharp * class C { * public virtual string this[int i] { ... } * @@ -600,6 +612,7 @@ class IndexerWrite extends IndexerAccess, ElementWrite { } * return c[0]; * } * } + * ``` */ class VirtualIndexerAccess extends IndexerAccess { VirtualIndexerAccess() { targetIsOverridableOrImplementable() } @@ -620,7 +633,7 @@ library class EventAccessExpr extends Expr, @event_access_expr { * An access to an event, for example the accesses to `Click` on lines * 7 and 8 in * - * ``` + * ```csharp * class C { * public delegate void EventHandler(object sender, object e); * @@ -635,13 +648,15 @@ library class EventAccessExpr extends Expr, @event_access_expr { */ class EventAccess extends AssignableMemberAccess, EventAccessExpr { override Event getTarget() { result = getEvent() } + + override string getAPrimaryQlClass() { result = "EventAccess" } } /** * An access to an event that reads the underlying value, for example the * accesses to `Click` on lines 7 and 8 in * - * ``` + * ```csharp * class C { * public delegate void EventHandler(object sender, object e); * @@ -660,7 +675,7 @@ class EventRead extends EventAccess, AssignableRead { } * An access to an event that updates the underlying value, for example the * access to `Click` on line 7 in * - * ``` + * ```csharp * class C { * public delegate void EventHandler(object sender, object e); * @@ -678,7 +693,7 @@ class EventWrite extends EventAccess, AssignableWrite { } * An access to a virtual event - an event that is virtual or defined in * an interface. For example, the accesses to `Click` on lines 7 and 8 in * - * ``` + * ```csharp * class C { * public delegate void EventHandler(object sender, object e); * @@ -708,7 +723,7 @@ class CallableAccess extends Access, @method_access_expr { /** * An access to a method, for example the access to `Filter` on line 5 in * - * ``` + * ```csharp * class C { * bool Filter(string s) { ... } * @@ -726,12 +741,14 @@ class MethodAccess extends MemberAccess, CallableAccess { override Method getTarget() { expr_access(this, result) } override string toString() { result = "access to method " + this.getTarget().getName() } + + override string getAPrimaryQlClass() { result = "MethodAccess" } } /** * An access to a local function, for example the access to `Filter` on line 4 in * - * ``` + * ```csharp * class C { * public IEnumerable DoFilter(IEnumerable list) { * bool Filter(string s) { ... }; @@ -749,13 +766,15 @@ class LocalFunctionAccess extends CallableAccess { override LocalFunction getTarget() { expr_access(this, result) } override string toString() { result = "access to local function " + this.getTarget().getName() } + + override string getAPrimaryQlClass() { result = "LocalFunctionAccess" } } /** * An access to a virtual method - a method that is virtual or defined in * an interface. For example, the access to `Filter` on line 5 in * - * ``` + * ```csharp * class C { * public virtual bool Filter(string s) { ... } * @@ -774,7 +793,7 @@ class VirtualMethodAccess extends MethodAccess { /** * An access to a type, for example the access to `C` on line 3 in * - * ``` + * ```csharp * class C { * public Type GetCType() { * return typeof(C); @@ -786,12 +805,14 @@ class TypeAccess extends MemberAccess, @type_access_expr { override Type getTarget() { result = this.getType() } override string toString() { result = "access to type " + this.getTarget().getName() } + + override string getAPrimaryQlClass() { result = "TypeAccess" } } /** * An access to an array, for example the access to `args` on line 3 in * - * ``` + * ```csharp * public int FirstOrNegative(params int[] args) { * return args.Length > 0 * ? args[0] @@ -806,13 +827,15 @@ class ArrayAccess extends ElementAccess, @array_access_expr { // Although an array (element) can be assigned a value, there is no // corresponding assignable (`ArrayAccess` does not extend `MemberAccess`) override Assignable getTarget() { none() } + + override string getAPrimaryQlClass() { result = "ArrayAccess" } } /** * An access to an array that reads the underlying value, for example * the access to `a` on line 2 in * - * ``` + * ```csharp * public string Get(string[] a, int i) { * return a[i]; * } @@ -824,7 +847,7 @@ class ArrayRead extends ArrayAccess, ElementRead { } * An access to an array that updates the underlying value, for example * the access to `a` on line 2 in * - * ``` + * ```csharp * public void Set(string[] a, int i, string s) { * a[i] = s; * } @@ -839,4 +862,6 @@ class NamespaceAccess extends Access, @namespace_access_expr { override Namespace getTarget() { expr_access(this, result) } override string toString() { result = "access to namespace " + this.getTarget().getName() } + + override string getAPrimaryQlClass() { result = "NamespaceAccess" } } diff --git a/csharp/ql/src/semmle/code/csharp/exprs/ArithmeticOperation.qll b/csharp/ql/src/semmle/code/csharp/exprs/ArithmeticOperation.qll index 38033b9a9555..ac98c0eafcf8 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/ArithmeticOperation.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/ArithmeticOperation.qll @@ -27,6 +27,8 @@ class UnaryArithmeticOperation extends ArithmeticOperation, UnaryOperation, @un_ */ class UnaryMinusExpr extends UnaryArithmeticOperation, @minus_expr { override string getOperator() { result = "-" } + + override string getAPrimaryQlClass() { result = "UnaryMinusExpr" } } /** @@ -34,6 +36,8 @@ class UnaryMinusExpr extends UnaryArithmeticOperation, @minus_expr { */ class UnaryPlusExpr extends UnaryArithmeticOperation, @plus_expr { override string getOperator() { result = "+" } + + override string getAPrimaryQlClass() { result = "UnaryPlusExpr" } } /** @@ -61,18 +65,24 @@ class DecrementOperation extends MutatorOperation, @decr_op_expr { /** * A prefix increment operation, for example `++x`. */ -class PreIncrExpr extends IncrementOperation, @pre_incr_expr { } +class PreIncrExpr extends IncrementOperation, @pre_incr_expr { + override string getAPrimaryQlClass() { result = "PreIncrExpr" } +} /** * A prefix decrement operation, for example `--x`. */ -class PreDecrExpr extends DecrementOperation, @pre_decr_expr { } +class PreDecrExpr extends DecrementOperation, @pre_decr_expr { + override string getAPrimaryQlClass() { result = "PreDecrExpr" } +} /** * A postfix increment operation, for example `x++`. */ class PostIncrExpr extends IncrementOperation, @post_incr_expr { override string toString() { result = "..." + this.getOperator() } + + override string getAPrimaryQlClass() { result = "PostIncrExpr" } } /** @@ -80,6 +90,8 @@ class PostIncrExpr extends IncrementOperation, @post_incr_expr { */ class PostDecrExpr extends DecrementOperation, @post_decr_expr { override string toString() { result = "..." + this.getOperator() } + + override string getAPrimaryQlClass() { result = "PostDecrExpr" } } /** @@ -97,6 +109,8 @@ class BinaryArithmeticOperation extends ArithmeticOperation, BinaryOperation, @b */ class AddExpr extends BinaryArithmeticOperation, @add_expr { override string getOperator() { result = "+" } + + override string getAPrimaryQlClass() { result = "AddExpr" } } /** @@ -104,6 +118,8 @@ class AddExpr extends BinaryArithmeticOperation, @add_expr { */ class SubExpr extends BinaryArithmeticOperation, @sub_expr { override string getOperator() { result = "-" } + + override string getAPrimaryQlClass() { result = "SubExpr" } } /** @@ -111,6 +127,8 @@ class SubExpr extends BinaryArithmeticOperation, @sub_expr { */ class MulExpr extends BinaryArithmeticOperation, @mul_expr { override string getOperator() { result = "*" } + + override string getAPrimaryQlClass() { result = "MulExpr" } } /** @@ -124,6 +142,8 @@ class DivExpr extends BinaryArithmeticOperation, @div_expr { /** Gets the denominator of this division operation. */ Expr getDenominator() { result = getRightOperand() } + + override string getAPrimaryQlClass() { result = "DivExpr" } } /** @@ -131,4 +151,6 @@ class DivExpr extends BinaryArithmeticOperation, @div_expr { */ class RemExpr extends BinaryArithmeticOperation, @rem_expr { override string getOperator() { result = "%" } + + override string getAPrimaryQlClass() { result = "RemExpr" } } diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Assignment.qll b/csharp/ql/src/semmle/code/csharp/exprs/Assignment.qll index fe1a131e46c9..88ef770160a0 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Assignment.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Assignment.qll @@ -43,6 +43,8 @@ class LocalVariableDeclAndInitExpr extends LocalVariableDeclExpr, Assignment { override LocalVariableAccess getLValue() { result = Assignment.super.getLValue() } override string toString() { result = LocalVariableDeclExpr.super.toString() + " = ..." } + + override string getAPrimaryQlClass() { result = "LocalVariableDeclAndInitExpr" } } /** @@ -52,6 +54,8 @@ class AssignExpr extends Assignment, @simple_assign_expr { override string getOperator() { result = "=" } override string toString() { result = "... = ..." } + + override string getAPrimaryQlClass() { result = "AssignExpr" } } /** @@ -101,6 +105,8 @@ class AssignArithmeticOperation extends AssignOperation, @assign_arith_expr { } */ class AssignAddExpr extends AssignArithmeticOperation, @assign_add_expr { override string getOperator() { result = "+=" } + + override string getAPrimaryQlClass() { result = "AssignAddExpr" } } /** @@ -108,6 +114,8 @@ class AssignAddExpr extends AssignArithmeticOperation, @assign_add_expr { */ class AssignSubExpr extends AssignArithmeticOperation, @assign_sub_expr { override string getOperator() { result = "-=" } + + override string getAPrimaryQlClass() { result = "AssignSubExpr" } } /** @@ -115,6 +123,8 @@ class AssignSubExpr extends AssignArithmeticOperation, @assign_sub_expr { */ class AssignMulExpr extends AssignArithmeticOperation, @assign_mul_expr { override string getOperator() { result = "*=" } + + override string getAPrimaryQlClass() { result = "AssignMulExpr" } } /** @@ -122,6 +132,8 @@ class AssignMulExpr extends AssignArithmeticOperation, @assign_mul_expr { */ class AssignDivExpr extends AssignArithmeticOperation, @assign_div_expr { override string getOperator() { result = "/=" } + + override string getAPrimaryQlClass() { result = "AssignDivExpr" } } /** @@ -129,6 +141,8 @@ class AssignDivExpr extends AssignArithmeticOperation, @assign_div_expr { */ class AssignRemExpr extends AssignArithmeticOperation, @assign_rem_expr { override string getOperator() { result = "%=" } + + override string getAPrimaryQlClass() { result = "AssignRemExpr" } } /** @@ -146,6 +160,8 @@ class AssignBitwiseOperation extends AssignOperation, @assign_bitwise_expr { } */ class AssignAndExpr extends AssignBitwiseOperation, @assign_and_expr { override string getOperator() { result = "&=" } + + override string getAPrimaryQlClass() { result = "AssignAndExpr" } } /** @@ -153,6 +169,8 @@ class AssignAndExpr extends AssignBitwiseOperation, @assign_and_expr { */ class AssignOrExpr extends AssignBitwiseOperation, @assign_or_expr { override string getOperator() { result = "|=" } + + override string getAPrimaryQlClass() { result = "AssignOrExpr" } } /** @@ -160,6 +178,8 @@ class AssignOrExpr extends AssignBitwiseOperation, @assign_or_expr { */ class AssignXorExpr extends AssignBitwiseOperation, @assign_xor_expr { override string getOperator() { result = "^=" } + + override string getAPrimaryQlClass() { result = "AssignXorExpr" } } /** @@ -167,6 +187,8 @@ class AssignXorExpr extends AssignBitwiseOperation, @assign_xor_expr { */ class AssignLShiftExpr extends AssignBitwiseOperation, @assign_lshift_expr { override string getOperator() { result = "<<=" } + + override string getAPrimaryQlClass() { result = "AssignLShiftExpr" } } /** @@ -174,6 +196,8 @@ class AssignLShiftExpr extends AssignBitwiseOperation, @assign_lshift_expr { */ class AssignRShiftExpr extends AssignBitwiseOperation, @assign_rshift_expr { override string getOperator() { result = ">>=" } + + override string getAPrimaryQlClass() { result = "AssignRShiftExpr" } } /** @@ -192,7 +216,7 @@ class AddOrRemoveEventExpr extends AssignOperation, @assign_event_expr { /** * An event addition, for example line 9 in * - * ``` + * ```csharp * class A { * public delegate void EventHandler(object sender, object e); * @@ -208,12 +232,14 @@ class AddOrRemoveEventExpr extends AssignOperation, @assign_event_expr { */ class AddEventExpr extends AddOrRemoveEventExpr, @add_event_expr { override string toString() { result = "... += ..." } + + override string getAPrimaryQlClass() { result = "AddEventExpr" } } /** * An event removal, for example line 9 in * - * ``` + * ```csharp * class A { * public delegate void EventHandler(object sender, object e); * @@ -229,6 +255,8 @@ class AddEventExpr extends AddOrRemoveEventExpr, @add_event_expr { */ class RemoveEventExpr extends AddOrRemoveEventExpr, @remove_event_expr { override string toString() { result = "... -= ..." } + + override string getAPrimaryQlClass() { result = "RemoveEventExpr" } } /** @@ -236,4 +264,6 @@ class RemoveEventExpr extends AddOrRemoveEventExpr, @remove_event_expr { */ class AssignCoalesceExpr extends AssignOperation, @assign_coalesce_expr { override string toString() { result = "... ??= ..." } + + override string getAPrimaryQlClass() { result = "AssignCoalesceExpr" } } diff --git a/csharp/ql/src/semmle/code/csharp/exprs/BitwiseOperation.qll b/csharp/ql/src/semmle/code/csharp/exprs/BitwiseOperation.qll index c96738b6961f..0ae16bb50656 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/BitwiseOperation.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/BitwiseOperation.qll @@ -23,6 +23,8 @@ class UnaryBitwiseOperation extends BitwiseOperation, UnaryOperation, @un_bit_op */ class ComplementExpr extends UnaryBitwiseOperation, @bit_not_expr { override string getOperator() { result = "~" } + + override string getAPrimaryQlClass() { result = "ComplementExpr" } } /** @@ -40,6 +42,8 @@ class BinaryBitwiseOperation extends BitwiseOperation, BinaryOperation, @bin_bit */ class LShiftExpr extends BinaryBitwiseOperation, @lshift_expr { override string getOperator() { result = "<<" } + + override string getAPrimaryQlClass() { result = "LShiftExpr" } } /** @@ -47,6 +51,8 @@ class LShiftExpr extends BinaryBitwiseOperation, @lshift_expr { */ class RShiftExpr extends BinaryBitwiseOperation, @rshift_expr { override string getOperator() { result = ">>" } + + override string getAPrimaryQlClass() { result = "RShiftExpr" } } /** @@ -54,6 +60,8 @@ class RShiftExpr extends BinaryBitwiseOperation, @rshift_expr { */ class BitwiseAndExpr extends BinaryBitwiseOperation, @bit_and_expr { override string getOperator() { result = "&" } + + override string getAPrimaryQlClass() { result = "BitwiseAndExpr" } } /** @@ -61,6 +69,8 @@ class BitwiseAndExpr extends BinaryBitwiseOperation, @bit_and_expr { */ class BitwiseOrExpr extends BinaryBitwiseOperation, @bit_or_expr { override string getOperator() { result = "|" } + + override string getAPrimaryQlClass() { result = "BitwiseOrExpr" } } /** @@ -68,4 +78,6 @@ class BitwiseOrExpr extends BinaryBitwiseOperation, @bit_or_expr { */ class BitwiseXorExpr extends BinaryBitwiseOperation, @bit_xor_expr { override string getOperator() { result = "^" } + + override string getAPrimaryQlClass() { result = "BitwiseXorExpr" } } diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Call.qll b/csharp/ql/src/semmle/code/csharp/exprs/Call.qll index 9e451781c540..90225a9aec3c 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Call.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Call.qll @@ -22,7 +22,7 @@ class Call extends DotNet::Call, Expr, @call { * Gets the static (compile-time) target of this call. For example, the * static target of `x.M()` on line 9 is `A.M` in * - * ``` + * ```csharp * class A { * virtual void M() { } * } @@ -65,7 +65,7 @@ class Call extends DotNet::Call, Expr, @call { * on line 5, `o` is not an argument for `M1`'s `args` parameter, while * `new object[] { o }` on line 6 is, in * - * ``` + * ```csharp * class C { * void M1(params object[] args) { } * @@ -143,7 +143,7 @@ class Call extends DotNet::Call, Expr, @call { * Unlike `getTarget()`, this predicate takes reflection/dynamic based calls, * virtual dispatch, and delegate calls into account. Example: * - * ``` + * ```csharp * class A { * virtual void M() { } * } @@ -188,7 +188,7 @@ class Call extends DotNet::Call, Expr, @call { * Unlike `getArgument()`, this predicate takes reflection based calls and named * arguments into account. Example: * - * ``` + * ```csharp * class A { * virtual void M(int first, int second) { } * @@ -261,7 +261,7 @@ class Call extends DotNet::Call, Expr, @call { * of the arguments on lines 4 and 5, respectively, are valid for the parameter * `args` on line 1 in * - * ``` + * ```csharp * void M(params object[] args) { ... } * * void CallM(object[] os, string[] ss, string s) { @@ -280,7 +280,7 @@ private predicate isValidExplicitParamsType(Parameter p, Type t) { /** * A method call, for example `a.M()` on line 5 in * - * ``` + * ```csharp * class A { * void M() { } * @@ -297,6 +297,8 @@ class MethodCall extends Call, QualifiableExpr, LateBindableExpr, @method_invoca override string toString() { result = "call to method " + concat(this.getTarget().getName()) } + override string getAPrimaryQlClass() { result = "MethodCall" } + override Expr getRawArgument(int i) { if exists(getQualifier()) then @@ -310,7 +312,7 @@ class MethodCall extends Call, QualifiableExpr, LateBindableExpr, @method_invoca /** * A call to an extension method, for example lines 5 and 6 in * - * ``` + * ```csharp * static class A { * static void M(this int i) { } * @@ -341,7 +343,7 @@ class ExtensionMethodCall extends MethodCall { * happens to be an extension method, for example the calls on lines 6 and * 7 (but not line 5) in * - * ``` + * ```csharp * static class Extensions { * public static void Ext(int i) { } * @@ -363,7 +365,7 @@ class ExtensionMethodCall extends MethodCall { /** * A virtual method call, for example `a.M()` on line 5 in * - * ``` + * ```csharp * class A { * public virtual void M() { } * @@ -384,7 +386,7 @@ class VirtualMethodCall extends MethodCall { * A constructor initializer call, for example `base()` (line 6) and * `this(0)` (line 8) in * - * ``` + * ```csharp * class A * { * public A() { } @@ -405,6 +407,8 @@ class ConstructorInitializer extends Call, @constructor_init_expr { override string toString() { result = "call to constructor " + this.getTarget().getName() } + override string getAPrimaryQlClass() { result = "ConstructorInitializer" } + private ValueOrRefType getTargetType() { result = this.getTarget().getDeclaringType().getSourceDeclaration() } @@ -417,7 +421,7 @@ class ConstructorInitializer extends Call, @constructor_init_expr { * Holds if this initialier is a `this` initializer, for example `this(0)` * in * - * ``` + * ```csharp * class A * { * A(int i) { } @@ -431,7 +435,7 @@ class ConstructorInitializer extends Call, @constructor_init_expr { * Holds if this initialier is a `base` initializer, for example `base(0)` * in * - * ``` + * ```csharp * class A * { * A(int i) { } @@ -450,7 +454,7 @@ class ConstructorInitializer extends Call, @constructor_init_expr { * the initializer call `base()` on line 7 belongs to the constructor `B` * on line 6 in * - * ``` + * ```csharp * class A * { * public A() { } @@ -475,7 +479,7 @@ class ConstructorInitializer extends Call, @constructor_init_expr { * A call to a user-defined operator, for example `this + other` * on line 7 in * - * ``` + * ```csharp * class A { * public static A operator+(A left, A right) { * return left; @@ -493,13 +497,15 @@ class OperatorCall extends Call, LateBindableExpr, @operator_invocation_expr { override Operator getARuntimeTarget() { result = Call.super.getARuntimeTarget() } override string toString() { result = "call to operator " + this.getTarget().getName() } + + override string getAPrimaryQlClass() { result = "OperatorCall" } } /** * A call to a user-defined mutator operator, for example `a++` on * line 7 in * - * ``` + * ```csharp * class A { * public static A operator++(A a) { * return a; @@ -524,7 +530,7 @@ class MutatorOperatorCall extends OperatorCall { /** * A delegate call, for example `x()` on line 5 in * - * ``` + * ```csharp * class A { * Action X = () => { }; * @@ -581,7 +587,7 @@ class DelegateCall extends Call, @delegate_invocation_expr { * Gets the delegate expression of this delegate call. For example, the * delegate expression of `X()` on line 5 is the access to the field `X` in * - * ``` + * ```csharp * class A { * Action X = () => { }; * @@ -594,6 +600,8 @@ class DelegateCall extends Call, @delegate_invocation_expr { Expr getDelegateExpr() { result = this.getChild(-1) } override string toString() { result = "delegate call" } + + override string getAPrimaryQlClass() { result = "DelegateCall" } } /** @@ -613,7 +621,7 @@ class AccessorCall extends Call, QualifiableExpr, @call_access_expr { * A call to a property accessor, for example the call to `get_P` on * line 5 in * - * ``` + * ```csharp * class A { * int P { get { return 0; } } * @@ -638,13 +646,15 @@ class PropertyCall extends AccessorCall, PropertyAccessExpr { } override string toString() { result = PropertyAccessExpr.super.toString() } + + override string getAPrimaryQlClass() { result = "PropertyCall" } } /** * A call to an indexer accessor, for example the call to `get_Item` * (defined on line 3) on line 7 in * - * ``` + * ```csharp * class A { * string this[int i] { * get { return i.ToString(); } @@ -673,13 +683,15 @@ class IndexerCall extends AccessorCall, IndexerAccessExpr { } override string toString() { result = IndexerAccessExpr.super.toString() } + + override string getAPrimaryQlClass() { result = "IndexerCall" } } /** * A call to an event accessor, for example the call to `add_Click` * (defined on line 5) on line 12 in * - * ``` + * ```csharp * class A { * public delegate void EventHandler(object sender, object e); * @@ -717,12 +729,14 @@ class EventCall extends AccessorCall, EventAccessExpr { } override string toString() { result = EventAccessExpr.super.toString() } + + override string getAPrimaryQlClass() { result = "EventCall" } } /** * A call to a local function, for example the call `Fac(n)` on line 6 in * - * ``` + * ```csharp * int Choose(int n, int m) { * int Fac(int x) { * return x > 1 ? x * Fac(x - 1) : 1; @@ -736,4 +750,6 @@ class LocalFunctionCall extends Call, @local_function_invocation_expr { override LocalFunction getTarget() { expr_call(this, result) } override string toString() { result = "call to local function " + getTarget().getName() } + + override string getAPrimaryQlClass() { result = "LocalFunctionCall" } } diff --git a/csharp/ql/src/semmle/code/csharp/exprs/ComparisonOperation.qll b/csharp/ql/src/semmle/code/csharp/exprs/ComparisonOperation.qll index 6ebb8e40ade9..8b94ef5b4d79 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/ComparisonOperation.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/ComparisonOperation.qll @@ -23,6 +23,8 @@ class EqualityOperation extends ComparisonOperation, @equality_op_expr { } */ class EQExpr extends EqualityOperation, @eq_expr { override string getOperator() { result = "==" } + + override string getAPrimaryQlClass() { result = "EQExpr" } } /** @@ -30,6 +32,8 @@ class EQExpr extends EqualityOperation, @eq_expr { */ class NEExpr extends EqualityOperation, @ne_expr { override string getOperator() { result = "!=" } + + override string getAPrimaryQlClass() { result = "NEExpr" } } /** @@ -53,6 +57,9 @@ class RelationalOperation extends ComparisonOperation, @rel_op_expr { * `x <= 20` this is `x`, and on `y > 0` it is the `0`. */ Expr getLesserOperand() { none() } + + /** Holds if this comparison is strict, i.e. `<` or `>`. */ + predicate isStrict() { this instanceof LTExpr or this instanceof GTExpr } } /** @@ -64,6 +71,8 @@ class GTExpr extends RelationalOperation, @gt_expr { override Expr getGreaterOperand() { result = getLeftOperand() } override Expr getLesserOperand() { result = getRightOperand() } + + override string getAPrimaryQlClass() { result = "GTExpr" } } /** @@ -75,6 +84,8 @@ class LTExpr extends RelationalOperation, @lt_expr { override Expr getGreaterOperand() { result = getRightOperand() } override Expr getLesserOperand() { result = getLeftOperand() } + + override string getAPrimaryQlClass() { result = "LTExpr" } } /** @@ -86,6 +97,8 @@ class GEExpr extends RelationalOperation, @ge_expr { override Expr getGreaterOperand() { result = getLeftOperand() } override Expr getLesserOperand() { result = getRightOperand() } + + override string getAPrimaryQlClass() { result = "GEExpr" } } /** @@ -97,4 +110,6 @@ class LEExpr extends RelationalOperation, @le_expr { override Expr getGreaterOperand() { result = getRightOperand() } override Expr getLesserOperand() { result = getLeftOperand() } + + override string getAPrimaryQlClass() { result = "LEExpr" } } diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Creation.qll b/csharp/ql/src/semmle/code/csharp/exprs/Creation.qll index f0aebc389d09..42bdcdf1a0d2 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Creation.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Creation.qll @@ -17,7 +17,7 @@ class ObjectOrCollectionInitializer extends Expr, @objectorcollection_init_expr /** * An object initializer, for example `{ X = 0, Y = 1 }` on line 6 in * - * ``` + * ```csharp * class A { * int X; * int Y; @@ -34,7 +34,7 @@ class ObjectInitializer extends ObjectOrCollectionInitializer, @object_init_expr * is a member initializer of the object initializer `{ X = 0, Y = 1 }` on * line 6 in * - * ``` + * ```csharp * class A { * int X; * int Y; @@ -52,7 +52,7 @@ class ObjectInitializer extends ObjectOrCollectionInitializer, @object_init_expr * `Y = 1` is the second (`i = 1`) member initializer of the object initializer * `{ X = 0, Y = 1 }` on line 6 in * - * ``` + * ```csharp * class A { * int X; * int Y; @@ -73,12 +73,14 @@ class ObjectInitializer extends ObjectOrCollectionInitializer, @object_init_expr /** Holds if this object initializer has no member initializers. */ predicate hasNoMemberInitializers() { not exists(this.getAMemberInitializer()) } + + override string getAPrimaryQlClass() { result = "ObjectInitializer" } } /** * A member initializer, for example `X = 0` on line 6 in * - * ``` + * ```csharp * class A { * int X; * int Y; @@ -94,12 +96,14 @@ class MemberInitializer extends AssignExpr { /** Gets the initialized member. */ Member getInitializedMember() { result.getAnAccess() = this.getLValue() } + + override string getAPrimaryQlClass() { result = "MemberInitializer" } } /** * A collection initializer, for example `{ {0, "a"}, {1, "b"} }` in * - * ``` + * ```csharp * var dict = new Dictionary{ * {0, "a"}, * {1, "b"} @@ -111,7 +115,7 @@ class CollectionInitializer extends ObjectOrCollectionInitializer, @collection_i * Gets an element initializer of this collection initializer, for example the * implicit call to `Add(0, "a")` on line 2 in * - * ``` + * ```csharp * var dict = new Dictionary{ * {0, "a"}, * {1, "b"} @@ -125,7 +129,7 @@ class CollectionInitializer extends ObjectOrCollectionInitializer, @collection_i * example the second (`i = 1`) element initializer is the implicit call to * `Add(1, "b")` in * - * ``` + * ```csharp * var dict = new Dictionary{ * {0, "a"}, * {1, "b"} @@ -142,13 +146,15 @@ class CollectionInitializer extends ObjectOrCollectionInitializer, @collection_i /** Holds if this collection initializer has no element initializers. */ predicate hasNoElementInitializers() { not exists(this.getAnElementInitializer()) } + + override string getAPrimaryQlClass() { result = "CollectionInitializer" } } /** * An element initializer, for example the implicit call to `Add(0, "a")` * on line 2 in * - * ``` + * ```csharp * var dict = new Dictionary{ * {0, "a"}, * {1, "b"} @@ -157,12 +163,14 @@ class CollectionInitializer extends ObjectOrCollectionInitializer, @collection_i */ class ElementInitializer extends MethodCall { ElementInitializer() { this.getParent() instanceof CollectionInitializer } + + override string getAPrimaryQlClass() { result = "ElementInitializer" } } /** * A constructor call, for example `new A()` on line 3 in * - * ``` + * ```csharp * class A { * public static A Create() { * return new A(); @@ -188,7 +196,7 @@ class ObjectCreation extends Call, LateBindableExpr, @object_creation_expr { * Gets the object initializer or collection initializer of this constructor * call, if any. For example `{ {0, "a"}, {1, "b"} }` in * - * ``` + * ```csharp * var dict = new Dictionary{ * {0, "a"}, * {1, "b"} @@ -204,13 +212,17 @@ class ObjectCreation extends Call, LateBindableExpr, @object_creation_expr { then result = this.getArgument(i) else result = this.getArgument(i - 1) } + + override string getAPrimaryQlClass() { + result = "ObjectCreation" and not this instanceof AnonymousObjectCreation + } } /** * An anonymous constructor call, for example * `new { First = x[0], Last = x[x.Length - 1] }` on line 2 in * - * ``` + * ```csharp * public IEnumerable FirstLast(IEnumerable list) { * return list.Select(x => new { First = x[0], Last = x[x.Length - 1] }). * Select(y => y.First + y.Last); @@ -221,6 +233,8 @@ class AnonymousObjectCreation extends ObjectCreation { AnonymousObjectCreation() { this.getObjectType() instanceof AnonymousClass } override ObjectInitializer getInitializer() { result = this.getChild(-1) } + + override string getAPrimaryQlClass() { result = "AnonymousObjectCreation" } } /** @@ -245,7 +259,7 @@ class DelegateCreation extends Expr, @delegate_creation_expr { /** * An explicit delegate creation, for example `new D(M)` on line 6 in * - * ``` + * ```csharp * class A { * delegate void D(int x); * @@ -255,12 +269,14 @@ class DelegateCreation extends Expr, @delegate_creation_expr { * } * ``` */ -class ExplicitDelegateCreation extends DelegateCreation, @explicit_delegate_creation_expr { } +class ExplicitDelegateCreation extends DelegateCreation, @explicit_delegate_creation_expr { + override string getAPrimaryQlClass() { result = "ExplicitDelegateCreation" } +} /** * An implicit delegate creation, for example the access to `M` on line 6 in * - * ``` + * ```csharp * class A { * delegate void D(int x); * @@ -270,12 +286,14 @@ class ExplicitDelegateCreation extends DelegateCreation, @explicit_delegate_crea * } * ``` */ -class ImplicitDelegateCreation extends DelegateCreation, @implicit_delegate_creation_expr { } +class ImplicitDelegateCreation extends DelegateCreation, @implicit_delegate_creation_expr { + override string getAPrimaryQlClass() { result = "ImplicitDelegateCreation" } +} /** * An array initializer, for example `{ {0, 1}, {2, 3}, {4, 5} }` in * - * ``` + * ```csharp * var ints = new int[,] { * {0, 1}, * {2, 3}, @@ -288,7 +306,7 @@ class ArrayInitializer extends Expr, @array_init_expr { * Gets an element of this array initializer, for example `{0, 1}` on line * 2 (itself an array initializer) in * - * ``` + * ```csharp * var ints = new int[,] { * {0, 1}, * {2, 3}, @@ -302,7 +320,7 @@ class ArrayInitializer extends Expr, @array_init_expr { * Gets the `i`th element of this array initializer, for example the second * (`i = 1`) element is `{2, 3}` on line 3 (itself an array initializer) in * - * ``` + * ```csharp * var ints = new int[,] { * {0, 1}, * {2, 3}, @@ -322,6 +340,8 @@ class ArrayInitializer extends Expr, @array_init_expr { predicate hasNoElements() { not exists(this.getAnElement()) } override string toString() { result = "{ ..., ... }" } + + override string getAPrimaryQlClass() { result = "ArrayInitializer" } } /** @@ -335,7 +355,7 @@ class ArrayCreation extends Expr, @array_creation_expr { * Gets a dimension's length argument of this array creation, for * example `5` in * - * ``` + * ```csharp * new int[5, 10] * ``` */ @@ -345,7 +365,7 @@ class ArrayCreation extends Expr, @array_creation_expr { * Gets the `i`th dimension's length argument of this array creation, for * example the second (`i = 1`) dimension's length is `10` in * - * ``` + * ```csharp * new int[5, 10] * ``` */ @@ -370,6 +390,8 @@ class ArrayCreation extends Expr, @array_creation_expr { predicate isImplicitlyTyped() { implicitly_typed_array_creation(this) } override string toString() { result = "array creation of type " + this.getType().getName() } + + override string getAPrimaryQlClass() { result = "ArrayCreation" } } /** @@ -377,6 +399,8 @@ class ArrayCreation extends Expr, @array_creation_expr { */ class Stackalloc extends ArrayCreation { Stackalloc() { stackalloc_array_creation(this) } + + override string getAPrimaryQlClass() { result = "Stackalloc" } } /** @@ -405,6 +429,8 @@ class AnonymousFunctionExpr extends Expr, Callable, @anonymous_function_expr { */ class LambdaExpr extends AnonymousFunctionExpr, @lambda_expr { override string toString() { result = "(...) => ..." } + + override string getAPrimaryQlClass() { result = "LambdaExpr" } } /** @@ -413,4 +439,6 @@ class LambdaExpr extends AnonymousFunctionExpr, @lambda_expr { */ class AnonymousMethodExpr extends AnonymousFunctionExpr, @anonymous_method_expr { override string toString() { result = "delegate(...) { ... }" } + + override string getAPrimaryQlClass() { result = "AnonymousMethodExpr" } } diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Dynamic.qll b/csharp/ql/src/semmle/code/csharp/exprs/Dynamic.qll index 6493bd0dabfb..ea6012ca3e15 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Dynamic.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Dynamic.qll @@ -22,7 +22,7 @@ class DynamicExpr extends LateBindableExpr { * A constructor call where one of the arguments is a `dynamic` expression, for * example `new A(d)` on line 8 in * - * ``` + * ```csharp * class A { * A(int i) { } * @@ -42,13 +42,15 @@ class DynamicObjectCreation extends DynamicExpr, ObjectCreation { override string toString() { result = "dynamic object creation of type " + this.getType().getName() } + + override string getAPrimaryQlClass() { result = "DynamicObjectCreation" } } /** * A method call where the qualifier or one of the arguments is a `dynamic` * expression, for example `M(d)` on line 8 in * - * ``` + * ```csharp * class A { * void M(int i) { } * @@ -66,13 +68,15 @@ class DynamicObjectCreation extends DynamicExpr, ObjectCreation { */ class DynamicMethodCall extends DynamicExpr, MethodCall { override string toString() { result = "dynamic call to method " + getLateBoundTargetName() } + + override string getAPrimaryQlClass() { result = "DynamicMethodCall" } } /** * A call to a user-defined operator where one of the operands is a `dynamic` * expression, for example `this + d` on line 12 in * - * ``` + * ```csharp * class A { * public static A operator+(A left, int right) { * return left; @@ -94,13 +98,15 @@ class DynamicMethodCall extends DynamicExpr, MethodCall { */ class DynamicOperatorCall extends DynamicExpr, OperatorCall { override string toString() { result = "dynamic call to operator " + getLateBoundTargetName() } + + override string getAPrimaryQlClass() { result = "DynamicOperatorCall" } } /** * A call to a user-defined mutator operator where the operand is a `dynamic` * expression, for example `d++` on line 20 in * - * ``` + * ```csharp * class A { * public A() { } * @@ -147,7 +153,7 @@ class DynamicAccess extends DynamicExpr { * A member access where the qualifier is a `dynamic` expression, for example * `d.X` on line 24 in * - * ``` + * ```csharp * class A { * public A() { } * @@ -185,6 +191,8 @@ class DynamicMemberAccess extends DynamicAccess, MemberAccess, AssignableAccess, @dynamic_member_access_expr { override string toString() { result = "dynamic access to member " + getLateBoundTargetName() } + override string getAPrimaryQlClass() { result = "DynamicMemberAccess" } + // The target is unknown when the qualifier is a `dynamic` expression override DynamicMember getTarget() { none() } } @@ -193,7 +201,7 @@ class DynamicMemberAccess extends DynamicAccess, MemberAccess, AssignableAccess, * An access to a dynamic member that reads the underlying value, for example * `d.X` on line 16 in * - * ``` + * ```csharp * class A { * public A() { } * @@ -220,7 +228,7 @@ class DynamicMemberRead extends DynamicMemberAccess, AssignableRead { } * An access to a dynamic member that updates the underlying value, for * example `d.X` on line 16 in * - * ``` + * ```csharp * class A { * public A() { } * @@ -259,7 +267,7 @@ class DynamicMember extends AssignableMember { * A call to an accessor where the qualifier is a `dynamic` expression, for * example `d.X` on line 20 and `d[0]` on line 25 in * - * ``` + * ```csharp * class A { * public A() { } * @@ -315,7 +323,7 @@ class DynamicAccessorCall extends DynamicAccess { * An element access where the qualifier is a `dynamic` expression, for example * `d[0]` on line 12 in * - * ``` + * ```csharp * class A { * public A() { } * @@ -338,13 +346,15 @@ class DynamicAccessorCall extends DynamicAccess { */ class DynamicElementAccess extends DynamicAccess, ElementAccess, @dynamic_element_access_expr { override string toString() { result = "dynamic access to element" } + + override string getAPrimaryQlClass() { result = "DynamicElementAccess" } } /** * An access to a dynamic element that reads the underlying value, for example * `d[0]` on line 12 in * - * ``` + * ```csharp * class A { * public A() { } * @@ -367,7 +377,7 @@ class DynamicElementRead extends DynamicElementAccess, ElementRead { } * An access to a dynamic element that updates the underlying value, for example * `d[0]` on line 12 in * - * ``` + * ```csharp * class A { * public A() { } * diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll b/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll index c06591768416..b133b628732e 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll @@ -4,10 +4,6 @@ * All expressions have the common base class `Expr`. */ -import semmle.code.csharp.Location -import semmle.code.csharp.Stmt -import semmle.code.csharp.Callable -import semmle.code.csharp.Type import Access import ArithmeticOperation import Assignment @@ -19,9 +15,14 @@ import Dynamic import Literal import LogicalOperation import semmle.code.csharp.controlflow.ControlFlowElement +import semmle.code.csharp.Callable +import semmle.code.csharp.Location +import semmle.code.csharp.Stmt +import semmle.code.csharp.Type +private import dotnet private import semmle.code.csharp.Enclosing::Internal private import semmle.code.csharp.frameworks.System -private import dotnet +private import semmle.code.csharp.TypeRef /** * An expression. Either an access (`Access`), a call (`Call`), an object or @@ -125,7 +126,7 @@ class LocalVariableDeclExpr extends Expr, @local_var_decl_expr { /** * Gets the local variable being declared, if any. The only case where * no variable is declared is when a discard symbol is used, for example - * ``` + * ```csharp * if (int.TryParse(s, out var _)) * ... * ``` @@ -165,6 +166,11 @@ class LocalVariableDeclExpr extends Expr, @local_var_decl_expr { * for example `M(out int x)`. */ predicate isOutArgument() { expr_argument(this, 2) } + + override string getAPrimaryQlClass() { + result = "LocalVariableDeclExpr" and + not this instanceof LocalVariableDeclAndInitExpr + } } /** @@ -237,7 +243,7 @@ class TernaryOperation extends Operation, @ternary_op { } /** * A parenthesized expression, for example `(2 + 3)` in * - * ``` + * ```csharp * 4 * (2 + 3) * ``` */ @@ -246,6 +252,8 @@ class ParenthesizedExpr extends Expr, @par_expr { Expr getExpr() { result = this.getChild(0) } override string toString() { result = "(...)" } + + override string getAPrimaryQlClass() { result = "ParenthesizedExpr" } } /** @@ -256,6 +264,8 @@ class CheckedExpr extends Expr, @checked_expr { Expr getExpr() { result = this.getChild(0) } override string toString() { result = "checked (...)" } + + override string getAPrimaryQlClass() { result = "CheckedExpr" } } /** @@ -266,6 +276,8 @@ class UncheckedExpr extends Expr, @unchecked_expr { Expr getExpr() { result = this.getChild(0) } override string toString() { result = "unchecked (...)" } + + override string getAPrimaryQlClass() { result = "UncheckedExpr" } } cached @@ -291,7 +303,7 @@ private predicate hasChildPattern(ControlFlowElement pm, Expr child) { /** * A pattern expression, for example `(_, false)` in * - * ``` + * ```csharp * (a,b) switch { * (_, false) => true, * _ => false @@ -308,7 +320,7 @@ class PatternExpr extends Expr { * (transitively). For example, `_`, `false`, and `(_, false)` belong to the * pattern match `(_, false) => true` in * - * ``` + * ```csharp * (a,b) switch { * (_, false) => true, * _ => false @@ -319,11 +331,15 @@ class PatternExpr extends Expr { } /** A discard pattern, for example `_` in `x is (_, false)` */ -class DiscardPatternExpr extends DiscardExpr, PatternExpr { } +class DiscardPatternExpr extends DiscardExpr, PatternExpr { + override string getAPrimaryQlClass() { result = "DiscardPatternExpr" } +} /** A constant pattern, for example `false` in `x is (_, false)`. */ class ConstantPatternExpr extends PatternExpr { ConstantPatternExpr() { this.hasValue() } + + override string getAPrimaryQlClass() { result = "ConstantPatternExpr" } } /** @@ -343,7 +359,9 @@ class TypePatternExpr extends PatternExpr { } /** A type access pattern, for example `string` in `x is string`. */ -class TypeAccessPatternExpr extends TypePatternExpr, TypeAccess { } +class TypeAccessPatternExpr extends TypePatternExpr, TypeAccess { + override string getAPrimaryQlClass() { result = "TypeAccessPatternExpr" } +} /** A pattern that may bind a variable, for example `string s` in `x is string s`. */ class BindingPatternExpr extends PatternExpr { @@ -362,6 +380,8 @@ class BindingPatternExpr extends PatternExpr { /** A variable declaration pattern, for example `string s` in `x is string s`. */ class VariablePatternExpr extends BindingPatternExpr, LocalVariableDeclExpr { override LocalVariableDeclExpr getVariableDeclExpr() { result = this } + + override string getAPrimaryQlClass() { result = "VariablePatternExpr" } } /** @@ -371,6 +391,8 @@ class VariablePatternExpr extends BindingPatternExpr, LocalVariableDeclExpr { class RecursivePatternExpr extends BindingPatternExpr, @recursive_pattern_expr { override string toString() { result = "{ ... }" } + override string getAPrimaryQlClass() { result = "RecursivePatternExpr" } + /** * Gets the position patterns of this recursive pattern, if any. * For example, `(1, _)`. @@ -398,6 +420,8 @@ class PropertyPatternExpr extends Expr, @property_pattern_expr { /** Gets the `n`th pattern. */ PatternExpr getPattern(int n) { result = this.getChild(n) } + + override string getAPrimaryQlClass() { result = "PropertyPatternExpr" } } /** @@ -409,6 +433,8 @@ class LabeledPatternExpr extends PatternExpr { /** Gets the label of this pattern. */ string getLabel() { exprorstmt_name(this, result) } + + override string getAPrimaryQlClass() { result = "LabeledPatternExpr" } } /** A positional pattern. For example, `(int x, int y)`. */ @@ -417,6 +443,8 @@ class PositionalPatternExpr extends Expr, @positional_pattern_expr { /** Gets the `n`th pattern. */ PatternExpr getPattern(int n) { result = this.getChild(n) } + + override string getAPrimaryQlClass() { result = "PositionalPatternExpr" } } /** @@ -439,6 +467,8 @@ class IsExpr extends Expr, PatternMatch, @is_expr { override PatternExpr getPattern() { result = this.getChild(1) } override string toString() { result = "... is ..." } + + override string getAPrimaryQlClass() { result = "IsExpr" } } /** A `switch` expression or statement. */ @@ -458,7 +488,7 @@ class Switch extends ControlFlowElement, @switch { /** * A `switch` expression, for example - * ``` + * ```csharp * (a,b) switch { * (false, false) => true, * _ => false @@ -473,6 +503,8 @@ class SwitchExpr extends Expr, Switch, @switch_expr { override SwitchCaseExpr getCase(int n) { result = this.getChild(n) } override SwitchCaseExpr getACase() { result = this.getCase(_) } + + override string getAPrimaryQlClass() { result = "SwitchExpr" } } /** A `case` expression or statement. */ @@ -510,6 +542,8 @@ class SwitchCaseExpr extends Expr, Case, @switch_case_expr { // should match all cases due to the type of the expression. this.getPattern() instanceof DiscardPatternExpr } + + override string getAPrimaryQlClass() { result = "SwitchCaseExpr" } } /** @@ -544,7 +578,7 @@ class Cast extends Expr { * An implicit cast. For example, the implicit cast from `string` to `object` * on line 3 in * - * ``` + * ```csharp * class C { * void M1(object o) { } * void M2(string s) => M1(s); @@ -559,7 +593,7 @@ class ImplicitCast extends Cast { * An explicit cast. For example, the explicit cast from `object` to `string` * on line 2 in * - * ``` + * ```csharp * class C { * string M1(object o) => (string) o; * } @@ -574,6 +608,8 @@ class ExplicitCast extends Cast { */ class AsExpr extends Cast, @as_expr { override string toString() { result = "... as ..." } + + override string getAPrimaryQlClass() { result = "AsExpr" } } /** @@ -581,6 +617,8 @@ class AsExpr extends Cast, @as_expr { */ class CastExpr extends Cast, @cast_expr { override string toString() { result = "(...) ..." } + + override string getAPrimaryQlClass() { result = "CastExpr" } } /** @@ -594,6 +632,8 @@ class TypeofExpr extends Expr, @typeof_expr { TypeAccess getTypeAccess() { result = this.getChild(0) } override string toString() { result = "typeof(...)" } + + override string getAPrimaryQlClass() { result = "TypeofExpr" } } /** @@ -609,6 +649,8 @@ class DefaultValueExpr extends Expr, @default_expr { override string toString() { if exists(getTypeAccess()) then result = "default(...)" else result = "default" } + + override string getAPrimaryQlClass() { result = "DefaultValueExpr" } } /** @@ -624,13 +666,15 @@ class SizeofExpr extends UnaryOperation, @sizeof_expr { override string getOperator() { result = "sizeof(..)" } override string toString() { result = "sizeof(..)" } + + override string getAPrimaryQlClass() { result = "SizeofExpr" } } /** * A pointer indirection operation, for example `*pn` on line 7, * `pa->M()` on line 13, and `cp[1]` on line 18 in * - * ``` + * ```csharp * struct A { * public void M() { } * @@ -662,12 +706,14 @@ class SizeofExpr extends UnaryOperation, @sizeof_expr { */ class PointerIndirectionExpr extends UnaryOperation, @pointer_indirection_expr { override string getOperator() { result = "*" } + + override string getAPrimaryQlClass() { result = "PointerIndirectionExpr" } } /** * An address-of expression, for example `&n` on line 4 in * - * ``` + * ```csharp * class A { * unsafe int DirectDerefence() { * int n = 10; @@ -679,6 +725,8 @@ class PointerIndirectionExpr extends UnaryOperation, @pointer_indirection_expr { */ class AddressOfExpr extends UnaryOperation, @address_of_expr { override string getOperator() { result = "&" } + + override string getAPrimaryQlClass() { result = "AddressOfExpr" } } /** @@ -689,12 +737,14 @@ class AwaitExpr extends Expr, @await_expr { Expr getExpr() { result = getChild(0) } override string toString() { result = "await ..." } + + override string getAPrimaryQlClass() { result = "AwaitExpr" } } /** * A `nameof` expression, for example `nameof(s)` on line 3 in * - * ``` + * ```csharp * void M(string s) { * if (s == null) * throw new ArgumentNullException(nameof(s)); @@ -710,12 +760,14 @@ class NameOfExpr extends Expr, @nameof_expr { * `nameof(x.F)`. */ Access getAccess() { result = this.getChild(0) } + + override string getAPrimaryQlClass() { result = "NameOfExpr" } } /** * An interpolated string, for example `$"Hello, {name}!"` on line 2 in * - * ``` + * ```csharp * void Hello(string name) { * Console.WriteLine($"Hello, {name}!"); * } @@ -724,6 +776,8 @@ class NameOfExpr extends Expr, @nameof_expr { class InterpolatedStringExpr extends Expr, @interpolated_string_expr { override string toString() { result = "$\"...\"" } + override string getAPrimaryQlClass() { result = "InterpolatedStringExpr" } + /** * Gets the insert at index `i` in this interpolated string, if any. For * example, the insert at index `i = 1` is `name` in `$"Hello, {name}!"`. @@ -787,6 +841,8 @@ class ThrowExpr extends Expr, ThrowElement, @throw_expr { */ // overriden for more precise qldoc override Expr getExpr() { result = ThrowElement.super.getExpr() } + + override string getAPrimaryQlClass() { result = "ThrowExpr" } } /** @@ -863,8 +919,8 @@ private Expr getAnAssignOrForeachChild() { * An expression representing a tuple, for example * `(1, 2)` on line 2 or `(var x, var y)` on line 5 in * - * ``` - * class { + * ```csharp + * class C { * (int, int) F() => (1, 2); * * void M() { @@ -884,12 +940,14 @@ class TupleExpr extends Expr, @tuple_expr { /** Holds if this tuple is a read access. */ predicate isReadAccess() { not this = getAnAssignOrForeachChild() } + + override string getAPrimaryQlClass() { result = "TupleExpr" } } /** * A reference expression, for example `ref a[i]` on line 2 in * - * ``` + * ```csharp * ref int GetElement(int[] a, int i) { * return ref a[i]; * } @@ -902,17 +960,21 @@ class RefExpr extends Expr, @ref_expr { override string toString() { result = "ref ..." } override Type getType() { result = getExpr().getType() } + + override string getAPrimaryQlClass() { result = "RefExpr" } } /** * A discard expression, for example `_` in * - * ``` + * ```csharp * (var name, _, _) = GetDetails(); * ``` */ class DiscardExpr extends Expr, @discard_expr { override string toString() { result = "_" } + + override string getAPrimaryQlClass() { result = "DiscardExpr" } } private class UnknownExpr extends Expr, @unknown_expr { @@ -921,7 +983,7 @@ private class UnknownExpr extends Expr, @unknown_expr { /** * A range expression, used to create a `System.Range`. For example - * ``` + * ```csharp * 1..3 * 1..^1 * 3.. @@ -944,18 +1006,23 @@ class RangeExpr extends Expr, @range_expr { /** Holds if this range expression has a right hand operand. */ predicate hasEnd() { exists(this.getEnd()) } + + override string getAPrimaryQlClass() { result = "RangeExpr" } } /** An index expression, for example `^1` meaning "1 from the end". */ class IndexExpr extends Expr, @index_expr { + /** Gets the sub expression of this index expression. */ Expr getExpr() { result.getParent() = this } override string toString() { result = "^..." } + + override string getAPrimaryQlClass() { result = "IndexExpr" } } /** * A nullable warning suppression expression, for example `x!` in - * ``` + * ```csharp * string GetName() * { * string? x = ...; @@ -968,4 +1035,6 @@ class SuppressNullableWarningExpr extends Expr, @suppress_nullable_warning_expr Expr getExpr() { result.getParent() = this } override string toString() { result = "...!" } + + override string getAPrimaryQlClass() { result = "SuppressNullableWarningExpr" } } diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Literal.qll b/csharp/ql/src/semmle/code/csharp/exprs/Literal.qll index 1a8231e7c18c..0ca9f6d0db03 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Literal.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Literal.qll @@ -27,12 +27,16 @@ class BoolLiteral extends Literal, @bool_literal_expr { or getValue() = "false" and result = false } + + override string getAPrimaryQlClass() { result = "BoolLiteral" } } /** * A Unicode character literal, for example `'a'`. */ -class CharLiteral extends Literal, @char_literal_expr { } +class CharLiteral extends Literal, @char_literal_expr { + override string getAPrimaryQlClass() { result = "CharLiteral" } +} /** * An integer literal. Either an `int` literal (`IntLiteral`), a `long` @@ -44,22 +48,30 @@ class IntegerLiteral extends DotNet::IntLiteral, Literal, @integer_literal_expr /** * An `int` literal, for example `0`. */ -class IntLiteral extends IntegerLiteral, @int_literal_expr { } +class IntLiteral extends IntegerLiteral, @int_literal_expr { + override string getAPrimaryQlClass() { result = "IntLiteral" } +} /** * A `long` literal, for example `-5L`. */ -class LongLiteral extends IntegerLiteral, @long_literal_expr { } +class LongLiteral extends IntegerLiteral, @long_literal_expr { + override string getAPrimaryQlClass() { result = "LongLiteral" } +} /** * A `uint` literal, for example `5U`. */ -class UIntLiteral extends IntegerLiteral, @uint_literal_expr { } +class UIntLiteral extends IntegerLiteral, @uint_literal_expr { + override string getAPrimaryQlClass() { result = "UIntLiteral" } +} /** * A `ulong` literal, for example `5UL`. */ -class ULongLiteral extends IntegerLiteral, @ulong_literal_expr { } +class ULongLiteral extends IntegerLiteral, @ulong_literal_expr { + override string getAPrimaryQlClass() { result = "ULongLiteral" } +} /** * A floating point literal. Either a `float` literal (`FloatLiteral`), a @@ -71,26 +83,36 @@ class RealLiteral extends Literal, @real_literal_expr { } /** * A `float` literal, for example `5F`. */ -class FloatLiteral extends RealLiteral, @float_literal_expr { } +class FloatLiteral extends RealLiteral, @float_literal_expr { + override string getAPrimaryQlClass() { result = "FloatLiteral" } +} /** * A `double` literal, for example `5D`. */ -class DoubleLiteral extends RealLiteral, @double_literal_expr { } +class DoubleLiteral extends RealLiteral, @double_literal_expr { + override string getAPrimaryQlClass() { result = "DoubleLiteral" } +} /** * A `decimal` literal, for example `5m`. */ -class DecimalLiteral extends RealLiteral, @decimal_literal_expr { } +class DecimalLiteral extends RealLiteral, @decimal_literal_expr { + override string getAPrimaryQlClass() { result = "DecimalLiteral" } +} /** * A `string` literal, for example `"Hello, World!"`. */ class StringLiteral extends DotNet::StringLiteral, Literal, @string_literal_expr { override string toString() { result = "\"" + getValue().replaceAll("\"", "\\\"") + "\"" } + + override string getAPrimaryQlClass() { result = "StringLiteral" } } /** * A `null` literal. */ -class NullLiteral extends DotNet::NullLiteral, Literal, @null_literal_expr { } +class NullLiteral extends DotNet::NullLiteral, Literal, @null_literal_expr { + override string getAPrimaryQlClass() { result = "NullLiteral" } +} diff --git a/csharp/ql/src/semmle/code/csharp/exprs/LogicalOperation.qll b/csharp/ql/src/semmle/code/csharp/exprs/LogicalOperation.qll index 95f039383dfe..e94d8ff93e7a 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/LogicalOperation.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/LogicalOperation.qll @@ -25,6 +25,8 @@ class UnaryLogicalOperation extends LogicalOperation, UnaryOperation, @un_log_op */ class LogicalNotExpr extends UnaryLogicalOperation, @log_not_expr { override string getOperator() { result = "!" } + + override string getAPrimaryQlClass() { result = "LogicalNotExpr" } } /** @@ -41,6 +43,8 @@ class BinaryLogicalOperation extends LogicalOperation, BinaryOperation, @bin_log */ class LogicalAndExpr extends BinaryLogicalOperation, @log_and_expr { override string getOperator() { result = "&&" } + + override string getAPrimaryQlClass() { result = "LogicalAndExpr" } } /** @@ -48,12 +52,14 @@ class LogicalAndExpr extends BinaryLogicalOperation, @log_and_expr { */ class LogicalOrExpr extends BinaryLogicalOperation, @log_or_expr { override string getOperator() { result = "||" } + + override string getAPrimaryQlClass() { result = "LogicalOrExpr" } } /** * A null-coalescing operation, for example `s ?? ""` on line 2 in * - * ``` + * ```csharp * string NonNullOrEmpty(string s) { * return s ?? ""; * } @@ -61,6 +67,8 @@ class LogicalOrExpr extends BinaryLogicalOperation, @log_or_expr { */ class NullCoalescingExpr extends BinaryLogicalOperation, @null_coalescing_expr { override string getOperator() { result = "??" } + + override string getAPrimaryQlClass() { result = "NullCoalescingExpr" } } /** @@ -73,7 +81,7 @@ class TernaryLogicalOperation extends LogicalOperation, TernaryOperation, @terna * A conditional expression, for example `s != null ? s.Length : -1` * on line 2 in * - * ``` + * ```csharp * int LengthOrNegative(string s) { * return s != null ? s.Length : -1; * } @@ -92,4 +100,6 @@ class ConditionalExpr extends TernaryLogicalOperation, @conditional_expr { override string getOperator() { result = "?" } override string toString() { result = "... ? ... : ..." } + + override string getAPrimaryQlClass() { result = "ConditionalExpr" } } diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/EntityFramework.qll b/csharp/ql/src/semmle/code/csharp/frameworks/EntityFramework.qll index b3c1ca9f9d37..517499ef76cd 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/EntityFramework.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/EntityFramework.qll @@ -8,7 +8,12 @@ private import semmle.code.csharp.frameworks.system.collections.Generic private import semmle.code.csharp.frameworks.Sql private import semmle.code.csharp.dataflow.LibraryTypeDataFlow +/** + * Definitions relating to the `System.ComponentModel.DataAnnotations` + * namespace. + */ module DataAnnotations { + /** Class for `NotMappedAttribute`. */ class NotMappedAttribute extends Attribute { NotMappedAttribute() { this @@ -18,6 +23,10 @@ module DataAnnotations { } } +/** + * Definitions relating to the `Microsoft.EntityFrameworkCore` or + * `System.Data.Entity` namespaces. + */ module EntityFramework { /** An EF6 or EFCore namespace. */ class EFNamespace extends Namespace { @@ -43,12 +52,14 @@ module EntityFramework { class DbContext extends EFClass { DbContext() { this.getName() = "DbContext" } + /** Gets a `Find` or `FindAsync` method in the `DbContext`. */ Method getAFindMethod() { result = this.getAMethod("Find") or result = this.getAMethod("FindAsync") } + /** Gets an `Update` method in the `DbContext`. */ Method getAnUpdateMethod() { result = this.getAMethod("Update") } } @@ -111,14 +122,15 @@ module EntityFramework { c = this.getAConstructor() and source.(CallableFlowSourceArg).getArgumentIndex() = 0 and sink instanceof CallableFlowSinkReturn and - preservesValue = true + preservesValue = false or c = this.getAConversionTo() and source.(CallableFlowSourceArg).getArgumentIndex() = 0 and sink instanceof CallableFlowSinkReturn and - preservesValue = true + preservesValue = false } + /** Gets a conversion operator from `string` to `RawSqlString`. */ ConversionOperator getAConversionTo() { result = this.getAMember() and result.getTargetType() instanceof RawSqlStringStruct and diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll b/csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll index b439f958a018..54019d13216d 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll @@ -106,7 +106,7 @@ module JsonNET { private class SerializedMember extends TaintTracking::TaintedMember { SerializedMember() { // This member has a Json attribute - exists(Class attribute | attribute = this.(Attributable).getAnAttribute().getType() | + exists(Class attribute | attribute = this.getAnAttribute().getType() | attribute.hasName("JsonPropertyAttribute") or attribute.hasName("JsonDictionaryAttribute") @@ -135,8 +135,10 @@ module JsonNET { class JsonSerializerClass extends JsonClass, LibraryTypeDataFlow { JsonSerializerClass() { this.hasName("JsonSerializer") } + /** Gets the method for `JsonSerializer.Serialize`. */ Method getSerializeMethod() { result = this.getAMethod("Serialize") } + /** Gets the method for `JsonSerializer.Deserialize`. */ Method getDeserializeMethod() { result = this.getAMethod("Deserialize") } override predicate callableFlow( @@ -214,7 +216,7 @@ module JsonNET { any(Operator op | op.getDeclaringType() = this.getABaseType*() and op.getReturnType() instanceof StringType ) and - source = any(CallableFlowSourceArg arg | arg.getArgumentIndex() = 0) and + source.(CallableFlowSourceArg).getArgumentIndex() = 0 and sink instanceof CallableFlowSinkReturn and preservesValue = false or diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/NHibernate.qll b/csharp/ql/src/semmle/code/csharp/frameworks/NHibernate.qll index a75b7b0b3492..3e46bd130476 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/NHibernate.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/NHibernate.qll @@ -1,8 +1,13 @@ +/** + * Classes for modelling NHibernate. + */ + import csharp private import semmle.code.csharp.frameworks.System private import semmle.code.csharp.frameworks.system.Collections private import semmle.code.csharp.frameworks.Sql +/** Definitions relating to the `NHibernate` package. */ module NHibernate { /** A class that is mapped to the database. */ abstract class MappedClass extends Class { } diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/System.qll b/csharp/ql/src/semmle/code/csharp/frameworks/System.qll index 093c8da9318a..9812fe08c6ba 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/System.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/System.qll @@ -21,6 +21,11 @@ class SystemUnboundGenericClass extends UnboundGenericClass { SystemUnboundGenericClass() { this.getNamespace() instanceof SystemNamespace } } +/** An unbound generic struct in the `System` namespace. */ +class SystemUnboundGenericStruct extends UnboundGenericStruct { + SystemUnboundGenericStruct() { this.getNamespace() instanceof SystemNamespace } +} + /** An interface in the `System` namespace. */ class SystemInterface extends Interface { SystemInterface() { this.getNamespace() instanceof SystemNamespace } @@ -215,6 +220,35 @@ class SystemLazyClass extends SystemUnboundGenericClass { } } +/** The `System.Nullable` struct. */ +class SystemNullableStruct extends SystemUnboundGenericStruct { + SystemNullableStruct() { + this.hasName("Nullable<>") and + this.getNumberOfTypeParameters() = 1 + } + + /** Gets the `Value` property. */ + Property getValueProperty() { + result.getDeclaringType() = this and + result.hasName("Value") and + result.getType() = getTypeParameter(0) + } + + /** Gets the `HasValue` property. */ + Property getHasValueProperty() { + result.getDeclaringType() = this and + result.hasName("HasValue") and + result.getType() instanceof BoolType + } + + /** Gets a `GetValueOrDefault()` method. */ + Method getAGetValueOrDefaultMethod() { + result.getDeclaringType() = this and + result.hasName("GetValueOrDefault") and + result.getReturnType() = getTypeParameter(0) + } +} + /** The `System.NullReferenceException` class. */ class SystemNullReferenceExceptionClass extends SystemClass { SystemNullReferenceExceptionClass() { this.hasName("NullReferenceException") } @@ -360,12 +394,11 @@ class SystemStringClass extends StringType { result.getReturnType() instanceof StringType } - /** Gets a `Join(string, ...)` method. */ + /** Gets a `Join(...)` method. */ Method getJoinMethod() { result.getDeclaringType() = this and result.hasName("Join") and result.getNumberOfParameters() > 1 and - result.getParameter(0).getType() instanceof StringType and result.getReturnType() instanceof StringType } @@ -564,7 +597,7 @@ private EqualsMethod getInheritedEqualsMethod(ValueOrRefType t) { t.hasMethod(re * * Example: * - * ``` + * ```csharp * abstract class A : IEquatable { * public abstract bool Equals(T other); * public override bool Equals(object other) { return other != null && GetType() == other.GetType() && Equals((T)other); } @@ -653,7 +686,7 @@ private DisposeMethod getInheritedDisposeMethod(ValueOrRefType t) { t.hasMethod( * * Example: * - * ``` + * ```csharp * class A : IDisposable { * public void Dispose() { Dispose(true); } * public virtual void Dispose(bool disposing) { ... } diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/WCF.qll b/csharp/ql/src/semmle/code/csharp/frameworks/WCF.qll index a9505388a921..655648d88c90 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/WCF.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/WCF.qll @@ -53,3 +53,17 @@ class OperationMethod extends Method { ) } } + +/** + * Data flow for WCF data contracts. + * + * Flow is defined from a WCF data contract object to any of its data member + * properties. This flow model only makes sense from a taint-tracking perspective + * (a tainted data contract object implies tainted data members). + */ +private class DataContractMember extends TaintTracking::TaintedMember { + DataContractMember() { + this.getAnAttribute() instanceof DataMemberAttribute and + this.getDeclaringType() instanceof DataContractClass + } +} diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/microsoft/AspNetCore.qll b/csharp/ql/src/semmle/code/csharp/frameworks/microsoft/AspNetCore.qll index cdcc9c2a37c8..3ebd70285040 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/microsoft/AspNetCore.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/microsoft/AspNetCore.qll @@ -27,6 +27,14 @@ class MicrosoftAspNetCoreMvcViewFeatures extends Namespace { } } +/** The 'Microsoft.AspNetCore.Mvc.Rendering' namespace. */ +class MicrosoftAspNetCoreMvcRendering extends Namespace { + MicrosoftAspNetCoreMvcRendering() { + getParentNamespace() instanceof MicrosoftAspNetCoreMvcNamespace and + hasName("Rendering") + } +} + /** An attribute whose type is in the `Microsoft.AspNetCore.Mvc` namespace. */ class MicrosoftAspNetCoreMvcAttribute extends Attribute { MicrosoftAspNetCoreMvcAttribute() { @@ -191,11 +199,11 @@ class MicrosoftAspNetCoreMvcController extends Class { } } -/** The `Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelper` class. */ -class MicrosoftAspNetCoreMvcHtmlHelperClass extends Class { - MicrosoftAspNetCoreMvcHtmlHelperClass() { - getNamespace() instanceof MicrosoftAspNetCoreMvcViewFeatures and - hasName("HtmlHelper") +/** The `Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper` interface. */ +class MicrosoftAspNetCoreMvcRenderingIHtmlHelperInterface extends Interface { + MicrosoftAspNetCoreMvcRenderingIHtmlHelperInterface() { + getNamespace() instanceof MicrosoftAspNetCoreMvcRendering and + hasName("IHtmlHelper") } /** Gets the `Raw` method. */ diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/Collections.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/Collections.qll index e932740cc022..aee0a1c8f7cc 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/system/Collections.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/Collections.qll @@ -52,3 +52,13 @@ class SystemCollectionsIEnumeratorInterface extends SystemCollectionsInterface { class SystemCollectionsICollectionInterface extends SystemCollectionsInterface { SystemCollectionsICollectionInterface() { this.hasName("ICollection") } } + +/** The `System.Collections.IList` interface. */ +class SystemCollectionsIListInterface extends SystemCollectionsInterface { + SystemCollectionsIListInterface() { this.hasName("IList") } +} + +/** The `System.Collections.IDictionary` interface. */ +class SystemCollectionsIDictionaryInterface extends SystemCollectionsInterface { + SystemCollectionsIDictionaryInterface() { this.hasName("IDictionary") } +} diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/Linq.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/Linq.qll index d5b7d4cff4ee..a6602899eaf4 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/system/Linq.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/Linq.qll @@ -5,6 +5,7 @@ private import csharp as csharp private import semmle.code.csharp.frameworks.System as System +/** Definitions relating to the `System.Linq` namespace. */ module SystemLinq { /** The `System.Linq` namespace. */ class Namespace extends csharp::Namespace { diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/Xml.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/Xml.qll index 21ca14310126..c84fa47a1035 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/system/Xml.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/Xml.qll @@ -2,7 +2,7 @@ import csharp private import semmle.code.csharp.frameworks.System -private import semmle.code.csharp.dataflow.DataFlow2 +private import semmle.code.csharp.dataflow.DataFlow3 /** The `System.Xml` namespace. */ class SystemXmlNamespace extends Namespace { @@ -163,7 +163,7 @@ class XmlReaderSettingsCreation extends ObjectCreation { } } -private class SettingsDataFlowConfig extends DataFlow2::Configuration { +private class SettingsDataFlowConfig extends DataFlow3::Configuration { SettingsDataFlowConfig() { this = "SettingsDataFlowConfig" } override predicate isSource(DataFlow::Node source) { diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/collections/Generic.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/collections/Generic.qll index 3160f82f2d49..a3616e57522d 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/system/collections/Generic.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/collections/Generic.qll @@ -136,3 +136,16 @@ class SystemCollectionsGenericICollectionInterface extends SystemCollectionsGene /** Gets the `Add` method. */ Method getAddMethod() { result = this.getAMethod("Add") } } + +/** The `System.Collections.Generic.IList<>` interface. */ +class SystemCollectionsGenericIListInterface extends SystemCollectionsGenericUnboundGenericInterface { + SystemCollectionsGenericIListInterface() { this.hasName("IList<>") } +} + +/** The `System.Collections.Generic.IDictionary` interface. */ +class SystemCollectionsGenericIDictionaryInterface extends SystemCollectionsGenericUnboundGenericInterface { + SystemCollectionsGenericIDictionaryInterface() { + this.hasName("IDictionary<,>") and + this.getNumberOfTypeParameters() = 2 + } +} diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/data/Common.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/data/Common.qll index 1ccbd5e1e7ed..a4aaa25611d3 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/system/data/Common.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/data/Common.qll @@ -5,6 +5,7 @@ private import csharp as csharp private import semmle.code.csharp.frameworks.system.Data as Data +/** Definitions relating to the `System.Data.Common` namespace. */ module SystemDataCommon { /** The `System.Data.Common` namespace. */ class Namespace extends csharp::Namespace { diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/data/Entity.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/data/Entity.qll index 45dcda1b776b..2aaa9a5889a1 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/system/data/Entity.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/data/Entity.qll @@ -5,6 +5,7 @@ private import csharp as csharp private import semmle.code.csharp.frameworks.system.Data as Data +/** Definitions relating to the `System.Data.Entity` namespace. */ module SystemDataEntity { /** The `System.Data.Entity` namespace. */ class Namespace extends csharp::Namespace { @@ -78,6 +79,7 @@ module SystemDataEntity { } } +/** Definitions relating to the `System.Data.Entity.Infrastructure` namespace. */ module SystemDataEntityInfrastructure { /** The `System.Data.Entity.Infrastructure` namespace. */ class Namespace extends csharp::Namespace { diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/linq/Expressions.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/linq/Expressions.qll index 1254b8552532..c4126834d20d 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/system/linq/Expressions.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/linq/Expressions.qll @@ -5,6 +5,7 @@ private import csharp as csharp private import semmle.code.csharp.frameworks.system.Linq +/** Definitions relating to the `System.Linq.Expressions` namespace. */ module SystemLinqExpressions { /** The `System.Linq.Expressions` namespace. */ class Namespace extends csharp::Namespace { diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/runtime/CompilerServices.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/runtime/CompilerServices.qll new file mode 100644 index 000000000000..a5dd6e4c20f7 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/runtime/CompilerServices.qll @@ -0,0 +1,30 @@ +/** Provides definitions related to the namespace `System.Runtime.CompilerServices`. */ + +import csharp +private import semmle.code.csharp.frameworks.system.Runtime + +/** The `System.Runtime.CompilerServices` namespace. */ +class SystemRuntimeCompilerServicesNamespace extends Namespace { + SystemRuntimeCompilerServicesNamespace() { + this.getParentNamespace() instanceof SystemRuntimeNamespace and + this.hasName("CompilerServices") + } +} + +/** An unbound generic struct in the `System.Runtime.CompilerServices` namespace. */ +class SystemRuntimeCompilerServicesNamespaceUnboundGenericStruct extends UnboundGenericStruct { + SystemRuntimeCompilerServicesNamespaceUnboundGenericStruct() { + this = any(SystemRuntimeCompilerServicesNamespace n).getATypeDeclaration() + } +} + +/** The `System.Runtime.CompilerServices.TaskAwaiter<>` struct. */ +class SystemRuntimeCompilerServicesTaskAwaiterStruct extends SystemRuntimeCompilerServicesNamespaceUnboundGenericStruct { + SystemRuntimeCompilerServicesTaskAwaiterStruct() { this.hasName("TaskAwaiter<>") } + + /** Gets the `GetResult` method. */ + Method getGetResultMethod() { result = this.getAMethod("GetResult") } + + /** Gets the field that stores the underlying task. */ + Field getUnderlyingTaskField() { result = this.getAField() and result.hasName("m_task") } +} diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/text/RegularExpressions.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/text/RegularExpressions.qll index ce03f5275d9d..1820192da11e 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/system/text/RegularExpressions.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/text/RegularExpressions.qll @@ -1,3 +1,7 @@ +/** + * Provides classes related to the namespace `System.Text.RegularExpressions`. + */ + import default import semmle.code.csharp.frameworks.system.Text diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/threading/Tasks.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/threading/Tasks.qll index 808ce188aac1..bf1898baf00e 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/system/threading/Tasks.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/threading/Tasks.qll @@ -38,4 +38,7 @@ class SystemThreadingTasksTaskTClass extends SystemThreadingTasksUnboundGenericC result.hasName("Result") and result.getType() = this.getTypeParameter(0) } + + /** Gets the `GetAwaiter` method. */ + Method getGetAwaiterMethod() { result = this.getAMethod("GetAwaiter") } } diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/xml/XPath.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/xml/XPath.qll index dd0b7a4f5e95..9374d7c282fa 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/system/xml/XPath.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/xml/XPath.qll @@ -3,6 +3,7 @@ import csharp as csharp private import semmle.code.csharp.frameworks.system.Xml as xml +/** Definitions relating to the `System.Xml.XPath` namespace. */ module SystemXmlXPath { /** The `System.Xml.XPath` namespace. */ class Namespace extends csharp::Namespace { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/EdgeKindInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/EdgeKindInternal.qll deleted file mode 100644 index 0ee01a30ac37..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/EdgeKindInternal.qll +++ /dev/null @@ -1 +0,0 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRConfigurationInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRConfigurationInternal.qll deleted file mode 100644 index 0ee01a30ac37..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRConfigurationInternal.qll +++ /dev/null @@ -1 +0,0 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRTypeInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRTypeInternal.qll deleted file mode 100644 index 0ee01a30ac37..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRTypeInternal.qll +++ /dev/null @@ -1 +0,0 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OpcodeImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OpcodeImports.qll deleted file mode 100644 index 4fbc0f301693..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OpcodeImports.qll +++ /dev/null @@ -1 +0,0 @@ -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTagInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTagInternal.qll deleted file mode 100644 index 0ee01a30ac37..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTagInternal.qll +++ /dev/null @@ -1 +0,0 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariableInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariableInternal.qll deleted file mode 100644 index 4dee687dabd3..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariableInternal.qll +++ /dev/null @@ -1,7 +0,0 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import semmle.code.csharp.ir.implementation.raw.internal.IRConstruction as Construction -private import semmle.code.csharp.ir.implementation.TempVariableTag as TempVariableTag_ - -module Imports { - module TempVariableTag = TempVariableTag_; -} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TempVariableTagInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TempVariableTagInternal.qll deleted file mode 100644 index 354a09f0f58e..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TempVariableTagInternal.qll +++ /dev/null @@ -1,6 +0,0 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -private import semmle.code.csharp.ir.internal.TempVariableTag as TempVariableTag_ - -module Imports { - module TempVariableTag = TempVariableTag_; -} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IR.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IR.qll deleted file mode 100644 index badd48552a5f..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IR.qll +++ /dev/null @@ -1,30 +0,0 @@ -import IRFunction -import Instruction -import IRBlock -import IRVariable -import Operand -private import internal.IRImports as Imports -import Imports::EdgeKind -import Imports::IRType -import Imports::MemoryAccessKind - -private newtype TIRPropertyProvider = MkIRPropertyProvider() - -/** - * Class that provides additional properties to be dumped for IR instructions and blocks when using - * the PrintIR module. Libraries that compute additional facts about IR elements can extend the - * single instance of this class to specify the additional properties computed by the library. - */ -class IRPropertyProvider extends TIRPropertyProvider { - string toString() { result = "IRPropertyProvider" } - - /** - * Gets the value of the property named `key` for the specified instruction. - */ - string getInstructionProperty(Instruction instruction, string key) { none() } - - /** - * Gets the value of the property named `key` for the specified block. - */ - string getBlockProperty(IRBlock block, string key) { none() } -} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll deleted file mode 100644 index 65af34942b6b..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll +++ /dev/null @@ -1,331 +0,0 @@ -private import IR -import InstructionConsistency // module is below -import IRTypeConsistency // module is in IRType.qll - -module InstructionConsistency { - private import internal.InstructionImports as Imports - private import Imports::OperandTag - private import Imports::Overlap - private import internal.IRInternal - - /** - * Holds if instruction `instr` is missing an expected operand with tag `tag`. - */ - query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) { - exists(OperandTag tag | - instr.getOpcode().hasOperand(tag) and - not exists(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and - message = - "Instruction '" + instr.getOpcode().toString() + - "' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - ) - } - - /** - * Holds if instruction `instr` has an unexpected operand with tag `tag`. - */ - query predicate unexpectedOperand(Instruction instr, OperandTag tag) { - exists(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and - not instr.getOpcode().hasOperand(tag) and - not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and - not ( - instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag - ) and - not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag) - } - - /** - * Holds if instruction `instr` has multiple operands with tag `tag`. - */ - query predicate duplicateOperand( - Instruction instr, string message, IRFunction func, string funcText - ) { - exists(OperandTag tag, int operandCount | - operandCount = - strictcount(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and - operandCount > 1 and - message = - "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + - " in function '$@'." and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - ) - } - - /** - * Holds if `Phi` instruction `instr` is missing an operand corresponding to - * the predecessor block `pred`. - */ - query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) { - pred = instr.getBlock().getAPredecessor() and - not exists(PhiInputOperand operand | - operand = instr.getAnOperand() and - operand.getPredecessorBlock() = pred - ) - } - - query predicate missingOperandType(Operand operand, string message) { - exists(Language::Function func, Instruction use | - not exists(operand.getType()) and - use = operand.getUse() and - func = use.getEnclosingFunction() and - message = - "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() + - "' missing type in function '" + Language::getIdentityString(func) + "'." - ) - } - - query predicate duplicateChiOperand( - ChiInstruction chi, string message, IRFunction func, string funcText - ) { - chi.getTotal() = chi.getPartial() and - message = - "Chi instruction for " + chi.getPartial().toString() + - " has duplicate operands in function $@" and - func = chi.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - } - - query predicate sideEffectWithoutPrimary( - SideEffectInstruction instr, string message, IRFunction func, string funcText - ) { - not exists(instr.getPrimaryInstruction()) and - message = "Side effect instruction missing primary instruction in function $@" and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - } - - /** - * Holds if an instruction, other than `ExitFunction`, has no successors. - */ - query predicate instructionWithoutSuccessor(Instruction instr) { - not exists(instr.getASuccessor()) and - not instr instanceof ExitFunctionInstruction and - // Phi instructions aren't linked into the instruction-level flow graph. - not instr instanceof PhiInstruction and - not instr instanceof UnreachedInstruction - } - - /** - * Holds if there are multiple (`n`) edges of kind `kind` from `source`, - * where `target` is among the targets of those edges. - */ - query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) { - n = strictcount(Instruction t | source.getSuccessor(kind) = t) and - n > 1 and - source.getSuccessor(kind) = target - } - - /** - * Holds if `instr` in `f` is part of a loop even though the AST of `f` - * contains no element that can cause loops. - */ - query predicate unexplainedLoop(Language::Function f, Instruction instr) { - exists(IRBlock block | - instr.getBlock() = block and - block.getEnclosingFunction() = f and - block.getASuccessor+() = block - ) and - not Language::hasPotentialLoop(f) - } - - /** - * Holds if a `Phi` instruction is present in a block with fewer than two - * predecessors. - */ - query predicate unnecessaryPhiInstruction(PhiInstruction instr) { - count(instr.getBlock().getAPredecessor()) < 2 - } - - /** - * Holds if a memory operand is connected to a definition with an unmodeled result. - */ - query predicate memoryOperandDefinitionIsUnmodeled( - Instruction instr, string message, IRFunction func, string funcText - ) { - exists(MemoryOperand operand, Instruction def | - operand = instr.getAnOperand() and - def = operand.getAnyDef() and - not def.isResultModeled() and - message = "Memory operand definition has unmodeled result in function '$@'" and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - ) - } - - /** - * Holds if operand `operand` consumes a value that was defined in - * a different function. - */ - query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) { - operand.getUse() = instr and - operand.getAnyDef() = defInstr and - instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction() - } - - /** - * Holds if instruction `instr` is not in exactly one block. - */ - query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) { - blockCount = count(instr.getBlock()) and - blockCount != 1 - } - - private predicate forwardEdge(IRBlock b1, IRBlock b2) { - b1.getASuccessor() = b2 and - not b1.getBackEdgeSuccessor(_) = b2 - } - - /** - * Holds if `f` contains a loop in which no edge is a back edge. - * - * This check ensures we don't have too _few_ back edges. - */ - query predicate containsLoopOfForwardEdges(IRFunction f) { - exists(IRBlock block | - forwardEdge+(block, block) and - block.getEnclosingIRFunction() = f - ) - } - - /** - * Holds if `block` is reachable from its function entry point but would not - * be reachable by traversing only forward edges. This check is skipped for - * functions containing `goto` statements as the property does not generally - * hold there. - * - * This check ensures we don't have too _many_ back edges. - */ - query predicate lostReachability(IRBlock block) { - exists(IRFunction f, IRBlock entry | - entry = f.getEntryBlock() and - entry.getASuccessor+() = block and - not forwardEdge+(entry, block) and - not Language::hasGoto(f.getFunction()) - ) - } - - /** - * Holds if the number of back edges differs between the `Instruction` graph - * and the `IRBlock` graph. - */ - query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) { - fromInstr = - count(Instruction i1, Instruction i2 | - i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2 - ) and - fromBlock = - count(IRBlock b1, IRBlock b2 | - b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2 - ) and - fromInstr != fromBlock - } - - /** - * Gets the point in the function at which the specified operand is evaluated. For most operands, - * this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point - * of evaluation is at the end of the corresponding predecessor block. - */ - private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) { - block = operand.(PhiInputOperand).getPredecessorBlock() and - index = block.getInstructionCount() - or - exists(Instruction use | - use = operand.(NonPhiOperand).getUse() and - block.getInstruction(index) = use - ) - } - - /** - * Holds if `useOperand` has a definition that does not dominate the use. - */ - query predicate useNotDominatedByDefinition( - Operand useOperand, string message, IRFunction func, string funcText - ) { - exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | - pointOfEvaluation(useOperand, useBlock, useIndex) and - defInstr = useOperand.getAnyDef() and - ( - defInstr instanceof PhiInstruction and - defBlock = defInstr.getBlock() and - defIndex = -1 - or - defBlock.getInstruction(defIndex) = defInstr - ) and - not ( - defBlock.strictlyDominates(useBlock) - or - defBlock = useBlock and - defIndex < useIndex - ) and - message = - "Operand '" + useOperand.toString() + - "' is not dominated by its definition in function '$@'." and - func = useOperand.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - ) - } - - query predicate switchInstructionWithoutDefaultEdge( - SwitchInstruction switchInstr, string message, IRFunction func, string funcText - ) { - not exists(switchInstr.getDefaultSuccessor()) and - message = - "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and - func = switchInstr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - } - - /** - * Holds if `instr` is on the chain of chi/phi instructions for all aliased - * memory. - */ - private predicate isOnAliasedDefinitionChain(Instruction instr) { - instr instanceof AliasedDefinitionInstruction - or - isOnAliasedDefinitionChain(instr.(ChiInstruction).getTotal()) - or - isOnAliasedDefinitionChain(instr.(PhiInstruction).getAnInputOperand().getAnyDef()) - } - - private predicate shouldBeConflated(Instruction instr) { - isOnAliasedDefinitionChain(instr) - or - instr.getOpcode() instanceof Opcode::InitializeNonLocal - } - - query predicate notMarkedAsConflated(Instruction instr) { - shouldBeConflated(instr) and - not instr.isResultConflated() - } - - query predicate wronglyMarkedAsConflated(Instruction instr) { - instr.isResultConflated() and - not shouldBeConflated(instr) - } - - query predicate invalidOverlap( - MemoryOperand useOperand, string message, IRFunction func, string funcText - ) { - exists(Overlap overlap | - overlap = useOperand.getDefinitionOverlap() and - overlap instanceof MayPartiallyOverlap and - message = - "MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" + - overlap.toString() + "'." and - func = useOperand.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - ) - } -} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll deleted file mode 100644 index b49dacc701bf..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll +++ /dev/null @@ -1 +0,0 @@ -import semmle.code.csharp.ir.implementation.raw.IR as IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll deleted file mode 100644 index 3d200900445b..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll +++ /dev/null @@ -1,3 +0,0 @@ -import semmle.code.csharp.ir.internal.Overlap -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import semmle.code.csharp.ir.implementation.unaliased_ssa.IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRBlockImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRBlockImports.qll deleted file mode 100644 index 9aa0d93de1f3..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRBlockImports.qll +++ /dev/null @@ -1 +0,0 @@ -import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll deleted file mode 100644 index 3b716c201ac3..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll +++ /dev/null @@ -1,3 +0,0 @@ -import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRInternal.qll deleted file mode 100644 index 421091e00d3f..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRInternal.qll +++ /dev/null @@ -1,3 +0,0 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import IRConstruction as Construction -import semmle.code.csharp.ir.implementation.IRConfiguration as IRConfiguration diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll deleted file mode 100644 index 9ab8de412594..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll +++ /dev/null @@ -1,5 +0,0 @@ -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.implementation.TempVariableTag as TempVariableTag -import semmle.code.csharp.ir.internal.IRUtilities as IRUtilities -import semmle.code.csharp.ir.internal.TempVariableTag as TTempVariableTag -import semmle.code.csharp.ir.implementation.internal.TIRVariable as TIRVariable diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll deleted file mode 100644 index 05b119f6c5b9..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll +++ /dev/null @@ -1,6 +0,0 @@ -import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind -import semmle.code.csharp.ir.implementation.Opcode as Opcode -import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag -import semmle.code.csharp.ir.internal.Overlap as Overlap diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll deleted file mode 100644 index 997185fb9f70..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll +++ /dev/null @@ -1,4 +0,0 @@ -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.internal.Overlap as Overlap -import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/PrintIRImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/PrintIRImports.qll deleted file mode 100644 index a74b4bffbc4d..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/PrintIRImports.qll +++ /dev/null @@ -1 +0,0 @@ -import semmle.code.csharp.ir.IRConfiguration as IRConfiguration diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll deleted file mode 100644 index 8464941e0a74..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll +++ /dev/null @@ -1,2 +0,0 @@ -import semmle.code.csharp.ir.implementation.raw.IR as IR -import semmle.code.csharp.ir.implementation.raw.constant.ConstantAnalysis as ConstantAnalysis diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IR.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IR.qll deleted file mode 100644 index badd48552a5f..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IR.qll +++ /dev/null @@ -1,30 +0,0 @@ -import IRFunction -import Instruction -import IRBlock -import IRVariable -import Operand -private import internal.IRImports as Imports -import Imports::EdgeKind -import Imports::IRType -import Imports::MemoryAccessKind - -private newtype TIRPropertyProvider = MkIRPropertyProvider() - -/** - * Class that provides additional properties to be dumped for IR instructions and blocks when using - * the PrintIR module. Libraries that compute additional facts about IR elements can extend the - * single instance of this class to specify the additional properties computed by the library. - */ -class IRPropertyProvider extends TIRPropertyProvider { - string toString() { result = "IRPropertyProvider" } - - /** - * Gets the value of the property named `key` for the specified instruction. - */ - string getInstructionProperty(Instruction instruction, string key) { none() } - - /** - * Gets the value of the property named `key` for the specified block. - */ - string getBlockProperty(IRBlock block, string key) { none() } -} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll deleted file mode 100644 index 65af34942b6b..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll +++ /dev/null @@ -1,331 +0,0 @@ -private import IR -import InstructionConsistency // module is below -import IRTypeConsistency // module is in IRType.qll - -module InstructionConsistency { - private import internal.InstructionImports as Imports - private import Imports::OperandTag - private import Imports::Overlap - private import internal.IRInternal - - /** - * Holds if instruction `instr` is missing an expected operand with tag `tag`. - */ - query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) { - exists(OperandTag tag | - instr.getOpcode().hasOperand(tag) and - not exists(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and - message = - "Instruction '" + instr.getOpcode().toString() + - "' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - ) - } - - /** - * Holds if instruction `instr` has an unexpected operand with tag `tag`. - */ - query predicate unexpectedOperand(Instruction instr, OperandTag tag) { - exists(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and - not instr.getOpcode().hasOperand(tag) and - not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and - not ( - instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag - ) and - not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag) - } - - /** - * Holds if instruction `instr` has multiple operands with tag `tag`. - */ - query predicate duplicateOperand( - Instruction instr, string message, IRFunction func, string funcText - ) { - exists(OperandTag tag, int operandCount | - operandCount = - strictcount(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and - operandCount > 1 and - message = - "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + - " in function '$@'." and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - ) - } - - /** - * Holds if `Phi` instruction `instr` is missing an operand corresponding to - * the predecessor block `pred`. - */ - query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) { - pred = instr.getBlock().getAPredecessor() and - not exists(PhiInputOperand operand | - operand = instr.getAnOperand() and - operand.getPredecessorBlock() = pred - ) - } - - query predicate missingOperandType(Operand operand, string message) { - exists(Language::Function func, Instruction use | - not exists(operand.getType()) and - use = operand.getUse() and - func = use.getEnclosingFunction() and - message = - "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() + - "' missing type in function '" + Language::getIdentityString(func) + "'." - ) - } - - query predicate duplicateChiOperand( - ChiInstruction chi, string message, IRFunction func, string funcText - ) { - chi.getTotal() = chi.getPartial() and - message = - "Chi instruction for " + chi.getPartial().toString() + - " has duplicate operands in function $@" and - func = chi.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - } - - query predicate sideEffectWithoutPrimary( - SideEffectInstruction instr, string message, IRFunction func, string funcText - ) { - not exists(instr.getPrimaryInstruction()) and - message = "Side effect instruction missing primary instruction in function $@" and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - } - - /** - * Holds if an instruction, other than `ExitFunction`, has no successors. - */ - query predicate instructionWithoutSuccessor(Instruction instr) { - not exists(instr.getASuccessor()) and - not instr instanceof ExitFunctionInstruction and - // Phi instructions aren't linked into the instruction-level flow graph. - not instr instanceof PhiInstruction and - not instr instanceof UnreachedInstruction - } - - /** - * Holds if there are multiple (`n`) edges of kind `kind` from `source`, - * where `target` is among the targets of those edges. - */ - query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) { - n = strictcount(Instruction t | source.getSuccessor(kind) = t) and - n > 1 and - source.getSuccessor(kind) = target - } - - /** - * Holds if `instr` in `f` is part of a loop even though the AST of `f` - * contains no element that can cause loops. - */ - query predicate unexplainedLoop(Language::Function f, Instruction instr) { - exists(IRBlock block | - instr.getBlock() = block and - block.getEnclosingFunction() = f and - block.getASuccessor+() = block - ) and - not Language::hasPotentialLoop(f) - } - - /** - * Holds if a `Phi` instruction is present in a block with fewer than two - * predecessors. - */ - query predicate unnecessaryPhiInstruction(PhiInstruction instr) { - count(instr.getBlock().getAPredecessor()) < 2 - } - - /** - * Holds if a memory operand is connected to a definition with an unmodeled result. - */ - query predicate memoryOperandDefinitionIsUnmodeled( - Instruction instr, string message, IRFunction func, string funcText - ) { - exists(MemoryOperand operand, Instruction def | - operand = instr.getAnOperand() and - def = operand.getAnyDef() and - not def.isResultModeled() and - message = "Memory operand definition has unmodeled result in function '$@'" and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - ) - } - - /** - * Holds if operand `operand` consumes a value that was defined in - * a different function. - */ - query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) { - operand.getUse() = instr and - operand.getAnyDef() = defInstr and - instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction() - } - - /** - * Holds if instruction `instr` is not in exactly one block. - */ - query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) { - blockCount = count(instr.getBlock()) and - blockCount != 1 - } - - private predicate forwardEdge(IRBlock b1, IRBlock b2) { - b1.getASuccessor() = b2 and - not b1.getBackEdgeSuccessor(_) = b2 - } - - /** - * Holds if `f` contains a loop in which no edge is a back edge. - * - * This check ensures we don't have too _few_ back edges. - */ - query predicate containsLoopOfForwardEdges(IRFunction f) { - exists(IRBlock block | - forwardEdge+(block, block) and - block.getEnclosingIRFunction() = f - ) - } - - /** - * Holds if `block` is reachable from its function entry point but would not - * be reachable by traversing only forward edges. This check is skipped for - * functions containing `goto` statements as the property does not generally - * hold there. - * - * This check ensures we don't have too _many_ back edges. - */ - query predicate lostReachability(IRBlock block) { - exists(IRFunction f, IRBlock entry | - entry = f.getEntryBlock() and - entry.getASuccessor+() = block and - not forwardEdge+(entry, block) and - not Language::hasGoto(f.getFunction()) - ) - } - - /** - * Holds if the number of back edges differs between the `Instruction` graph - * and the `IRBlock` graph. - */ - query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) { - fromInstr = - count(Instruction i1, Instruction i2 | - i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2 - ) and - fromBlock = - count(IRBlock b1, IRBlock b2 | - b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2 - ) and - fromInstr != fromBlock - } - - /** - * Gets the point in the function at which the specified operand is evaluated. For most operands, - * this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point - * of evaluation is at the end of the corresponding predecessor block. - */ - private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) { - block = operand.(PhiInputOperand).getPredecessorBlock() and - index = block.getInstructionCount() - or - exists(Instruction use | - use = operand.(NonPhiOperand).getUse() and - block.getInstruction(index) = use - ) - } - - /** - * Holds if `useOperand` has a definition that does not dominate the use. - */ - query predicate useNotDominatedByDefinition( - Operand useOperand, string message, IRFunction func, string funcText - ) { - exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | - pointOfEvaluation(useOperand, useBlock, useIndex) and - defInstr = useOperand.getAnyDef() and - ( - defInstr instanceof PhiInstruction and - defBlock = defInstr.getBlock() and - defIndex = -1 - or - defBlock.getInstruction(defIndex) = defInstr - ) and - not ( - defBlock.strictlyDominates(useBlock) - or - defBlock = useBlock and - defIndex < useIndex - ) and - message = - "Operand '" + useOperand.toString() + - "' is not dominated by its definition in function '$@'." and - func = useOperand.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - ) - } - - query predicate switchInstructionWithoutDefaultEdge( - SwitchInstruction switchInstr, string message, IRFunction func, string funcText - ) { - not exists(switchInstr.getDefaultSuccessor()) and - message = - "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and - func = switchInstr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - } - - /** - * Holds if `instr` is on the chain of chi/phi instructions for all aliased - * memory. - */ - private predicate isOnAliasedDefinitionChain(Instruction instr) { - instr instanceof AliasedDefinitionInstruction - or - isOnAliasedDefinitionChain(instr.(ChiInstruction).getTotal()) - or - isOnAliasedDefinitionChain(instr.(PhiInstruction).getAnInputOperand().getAnyDef()) - } - - private predicate shouldBeConflated(Instruction instr) { - isOnAliasedDefinitionChain(instr) - or - instr.getOpcode() instanceof Opcode::InitializeNonLocal - } - - query predicate notMarkedAsConflated(Instruction instr) { - shouldBeConflated(instr) and - not instr.isResultConflated() - } - - query predicate wronglyMarkedAsConflated(Instruction instr) { - instr.isResultConflated() and - not shouldBeConflated(instr) - } - - query predicate invalidOverlap( - MemoryOperand useOperand, string message, IRFunction func, string funcText - ) { - exists(Overlap overlap | - overlap = useOperand.getDefinitionOverlap() and - overlap instanceof MayPartiallyOverlap and - message = - "MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" + - overlap.toString() + "'." and - func = useOperand.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - ) - } -} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll deleted file mode 100644 index 188c68483ad9..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll +++ /dev/null @@ -1 +0,0 @@ -import semmle.code.csharp.ir.implementation.unaliased_ssa.IR as IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll deleted file mode 100644 index 3d200900445b..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll +++ /dev/null @@ -1,3 +0,0 @@ -import semmle.code.csharp.ir.internal.Overlap -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import semmle.code.csharp.ir.implementation.unaliased_ssa.IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll deleted file mode 100644 index e7884ce20b6f..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll +++ /dev/null @@ -1,3 +0,0 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import semmle.code.csharp.ir.implementation.raw.IR as InputIR -import AliasConfiguration as Configuration diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll deleted file mode 100644 index 0db2b9566107..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll +++ /dev/null @@ -1 +0,0 @@ -import semmle.code.csharp.ir.implementation.raw.IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll deleted file mode 100644 index 9aa0d93de1f3..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll +++ /dev/null @@ -1 +0,0 @@ -import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll deleted file mode 100644 index 3b716c201ac3..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll +++ /dev/null @@ -1,3 +0,0 @@ -import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRInternal.qll deleted file mode 100644 index 7d27b9aa92fe..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRInternal.qll +++ /dev/null @@ -1,3 +0,0 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import SSAConstruction as Construction -import semmle.code.csharp.ir.implementation.IRConfiguration as IRConfiguration diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll deleted file mode 100644 index 9ab8de412594..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll +++ /dev/null @@ -1,5 +0,0 @@ -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.implementation.TempVariableTag as TempVariableTag -import semmle.code.csharp.ir.internal.IRUtilities as IRUtilities -import semmle.code.csharp.ir.internal.TempVariableTag as TTempVariableTag -import semmle.code.csharp.ir.implementation.internal.TIRVariable as TIRVariable diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll deleted file mode 100644 index 05b119f6c5b9..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll +++ /dev/null @@ -1,6 +0,0 @@ -import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind -import semmle.code.csharp.ir.implementation.Opcode as Opcode -import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag -import semmle.code.csharp.ir.internal.Overlap as Overlap diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll deleted file mode 100644 index 997185fb9f70..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll +++ /dev/null @@ -1,4 +0,0 @@ -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.internal.Overlap as Overlap -import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll deleted file mode 100644 index a74b4bffbc4d..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll +++ /dev/null @@ -1 +0,0 @@ -import semmle.code.csharp.ir.IRConfiguration as IRConfiguration diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll deleted file mode 100644 index 6ee403226bc0..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll +++ /dev/null @@ -1,3 +0,0 @@ -import semmle.code.csharp.ir.implementation.Opcode -import semmle.code.csharp.ir.implementation.internal.OperandTag -import semmle.code.csharp.ir.internal.Overlap diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll deleted file mode 100644 index 44ff1f110c1f..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll +++ /dev/null @@ -1,6 +0,0 @@ -import semmle.code.csharp.ir.implementation.raw.IR as OldIR -import semmle.code.csharp.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability -import semmle.code.csharp.ir.implementation.raw.internal.reachability.Dominance as Dominance -import semmle.code.csharp.ir.implementation.unaliased_ssa.IR as NewIR -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import SimpleSSA as Alias diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll deleted file mode 100644 index 91d4124f558a..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll +++ /dev/null @@ -1,4 +0,0 @@ -import semmle.code.csharp.ir.implementation.raw.IR -import semmle.code.csharp.ir.internal.IntegerConstant as Ints -import semmle.code.csharp.ir.implementation.internal.OperandTag -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll deleted file mode 100644 index 555cb581d375..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll +++ /dev/null @@ -1 +0,0 @@ -import semmle.code.csharp.ir.internal.Overlap diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll deleted file mode 100644 index 1f9f8c40003a..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll +++ /dev/null @@ -1,2 +0,0 @@ -import semmle.code.csharp.ir.implementation.unaliased_ssa.IR as IR -import semmle.code.csharp.ir.implementation.unaliased_ssa.constant.ConstantAnalysis as ConstantAnalysis diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/TIRVariable.qll b/csharp/ql/src/semmle/code/csharp/ir/internal/TIRVariable.qll deleted file mode 100644 index ac65c1f32bdd..000000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/TIRVariable.qll +++ /dev/null @@ -1,16 +0,0 @@ -private import csharp -private import semmle.code.csharp.ir.implementation.TempVariableTag -private import semmle.code.csharp.ir.implementation.raw.internal.IRConstruction as Construction -private import semmle.code.csharp.ir.Util -private import IRCSharpLanguage as Language - -newtype TIRVariable = - TIRAutomaticUserVariable(LocalScopeVariable var, Callable callable) { - Construction::functionHasIR(callable) and - var.getCallable() = callable - } or - TIRTempVariable( - Callable callable, Language::AST ast, TempVariableTag tag, Language::LanguageType type - ) { - Construction::hasTempVariable(callable, ast, tag, type) - } diff --git a/csharp/ql/src/semmle/code/csharp/metrics/Coupling.qll b/csharp/ql/src/semmle/code/csharp/metrics/Coupling.qll index f2262f2c4b58..b5330ce770e3 100644 --- a/csharp/ql/src/semmle/code/csharp/metrics/Coupling.qll +++ b/csharp/ql/src/semmle/code/csharp/metrics/Coupling.qll @@ -222,6 +222,10 @@ predicate shareFieldOrProperty(ValueOrRefType t, Method m1, Method m2) { ) } +/** + * Holds if the declaring type of method `m` is `t` and `m` accesses declaration + * `d`, which is either a field or a property. + */ predicate methodUsesFieldOrProperty(ValueOrRefType t, Method m, Declaration d) { m.getDeclaringType() = t and ( diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/ConditionalBypass.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/ConditionalBypass.qll index 0694b27f9851..21399d502372 100644 --- a/csharp/ql/src/semmle/code/csharp/security/dataflow/ConditionalBypass.qll +++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/ConditionalBypass.qll @@ -61,7 +61,9 @@ module UserControlledBypassOfSensitiveMethod { private predicate conditionControlsCall0( SensitiveExecutionMethodCall call, Expr e, ControlFlow::SuccessorTypes::BooleanSuccessor s ) { - forex(BasicBlock bb | bb = call.getAControlFlowNode().getBasicBlock() | e.controlsBlock(bb, s)) + forex(BasicBlock bb | bb = call.getAControlFlowNode().getBasicBlock() | + e.controlsBlock(bb, s, _) + ) } private predicate conditionControlsCall( diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsinks/Html.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsinks/Html.qll index 2363e24ffeb3..97b81b6561ed 100644 --- a/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsinks/Html.qll +++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsinks/Html.qll @@ -176,13 +176,18 @@ class WebPageWriteLiteralToSink extends HtmlSink { abstract class AspNetCoreHtmlSink extends HtmlSink { } /** - * An expression that is used as an argument to `HtmlHelper.Raw`, typically in + * An expression that is used as an argument to `IHtmlHelper.Raw`, typically in * a `.cshtml` file. */ class MicrosoftAspNetCoreMvcHtmlHelperRawSink extends AspNetCoreHtmlSink { MicrosoftAspNetCoreMvcHtmlHelperRawSink() { - this.getExpr() = - any(MicrosoftAspNetCoreMvcHtmlHelperClass h).getRawMethod().getACall().getAnArgument() + exists(Call c, Callable target | + c.getTarget() = target and + target.hasName("Raw") and + target.getDeclaringType().getABaseType*() instanceof + MicrosoftAspNetCoreMvcRenderingIHtmlHelperInterface and + this.getExpr() = c.getAnArgument() + ) } } diff --git a/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll b/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll index 685a48b7079b..ece42b188c00 100644 --- a/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll +++ b/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll @@ -8,6 +8,7 @@ import csharp /** An unsafe deserializer. */ abstract class UnsafeDeserializer extends Callable { } +/** An unsafe deserializer method in the `System.*` namespace. */ class SystemDeserializer extends UnsafeDeserializer { SystemDeserializer() { this @@ -48,12 +49,17 @@ class SystemDeserializer extends UnsafeDeserializer { } } +/** An unsafe deserializer method in the `Microsoft.*` namespace. */ class MicrosoftDeserializer extends UnsafeDeserializer { MicrosoftDeserializer() { this.hasQualifiedName("Microsoft.Web.Design.Remote.ProxyObject", "DecodeValue") } } +/** + * An unsafe deserializer method that calls any unsafe deserializer on any of + * the parameters. + */ class WrapperDeserializer extends UnsafeDeserializer { WrapperDeserializer() { exists(Call call | diff --git a/csharp/ql/src/semmle/code/csharp/serialization/Serialization.qll b/csharp/ql/src/semmle/code/csharp/serialization/Serialization.qll index bf7dff102ec4..047d1c411c7f 100644 --- a/csharp/ql/src/semmle/code/csharp/serialization/Serialization.qll +++ b/csharp/ql/src/semmle/code/csharp/serialization/Serialization.qll @@ -1,5 +1,14 @@ +/** + * Provides classes to identify any .Net serializable type such as types + * attributed with `SerializableAttribute` and types implementing the + * `ISerializable` interface. + */ + import csharp +/** + * A constructor with `SerializationInfo` and `StreamingContext` parameters. + */ class SerializationConstructor extends Constructor { SerializationConstructor() { this.getNumberOfParameters() = 2 and @@ -91,16 +100,3 @@ class CustomBinarySerializableType extends BinarySerializableType { result.(SerializationConstructor).getDeclaringType() = this } } - -class DangerousCallable extends Callable { - DangerousCallable() { - //files - this.(Method).getQualifiedName().matches("System.IO.File.Write%") or - this.(Method).getQualifiedName().matches("System.IO.File.%Copy%") or - this.(Method).getQualifiedName().matches("System.IO.File.%Move%") or - this.(Method).getQualifiedName().matches("System.IO.File.%Append%") or - this.(Method).getQualifiedName().matches("System.IO.%.%Delete%") or - //assembly - this.(Method).getQualifiedName().matches("System.Reflection.Assembly.%Load%") - } -} diff --git a/csharp/ql/src/semmle/code/dotnet/Callable.qll b/csharp/ql/src/semmle/code/dotnet/Callable.qll index 443c0040a584..8e8de83f8811 100644 --- a/csharp/ql/src/semmle/code/dotnet/Callable.qll +++ b/csharp/ql/src/semmle/code/dotnet/Callable.qll @@ -1,3 +1,8 @@ +/** + * Provides `Callable` classes, which are things that can be called + * such as methods and constructors. + */ + import Declaration import Variable import Expr diff --git a/csharp/ql/src/semmle/code/dotnet/Element.qll b/csharp/ql/src/semmle/code/dotnet/Element.qll index 9d8b35023aad..10a688d8ddd0 100644 --- a/csharp/ql/src/semmle/code/dotnet/Element.qll +++ b/csharp/ql/src/semmle/code/dotnet/Element.qll @@ -50,7 +50,7 @@ class NamedElement extends Element, @dotnet_named_element { * Gets the fully qualified name of this element, for example the * fully qualified name of `M` on line 3 is `N.C.M` in * - * ``` + * ```csharp * namespace N { * class C { * void M(int i, string s) { } diff --git a/csharp/ql/src/semmle/code/dotnet/Variable.qll b/csharp/ql/src/semmle/code/dotnet/Variable.qll index 0ae3706b7115..c004b9ab6b38 100644 --- a/csharp/ql/src/semmle/code/dotnet/Variable.qll +++ b/csharp/ql/src/semmle/code/dotnet/Variable.qll @@ -1,3 +1,5 @@ +/** Provides classes for .Net variables, such as fields and parameters. */ + import Declaration import Callable diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index f2aa2d4ac313..ddd39829bb71 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -692,7 +692,7 @@ overrides( int base_id: @callable ref); explicitly_implements( - unique int id: @member ref, + int id: @member ref, int interface_id: @interface_or_ref ref); local_functions( diff --git a/csharp/ql/test/experimental/Security Features/Serialization/DefiningDatasetRelatedType.expected b/csharp/ql/test/experimental/Security Features/Serialization/DefiningDatasetRelatedType.expected new file mode 100644 index 000000000000..8d01c5e62b4a --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/Serialization/DefiningDatasetRelatedType.expected @@ -0,0 +1,2 @@ +| test0.cs:13:18:13:43 | DerivesFromDeprecatedType1 | Defining a class that inherits or has a property derived from the obsolete DataSet or DataTable types. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. | +| test0.cs:59:18:59:38 | AttributeSerializer01 | Defining a class that inherits or has a property derived from the obsolete DataSet or DataTable types. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. | diff --git a/csharp/ql/test/experimental/Security Features/Serialization/DefiningDatasetRelatedType.qlref b/csharp/ql/test/experimental/Security Features/Serialization/DefiningDatasetRelatedType.qlref new file mode 100644 index 000000000000..7283db95daf5 --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/Serialization/DefiningDatasetRelatedType.qlref @@ -0,0 +1 @@ +experimental/Security Features/Serialization/DefiningDatasetRelatedType.ql \ No newline at end of file diff --git a/csharp/ql/test/experimental/Security Features/Serialization/DefiningPotentiallyUnsafeXmlSerializer.expected b/csharp/ql/test/experimental/Security Features/Serialization/DefiningPotentiallyUnsafeXmlSerializer.expected new file mode 100644 index 000000000000..5b90d0c0a642 --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/Serialization/DefiningPotentiallyUnsafeXmlSerializer.expected @@ -0,0 +1,2 @@ +| test0.cs:15:24:15:32 | MyDataSet | Defining an serializable class $@ that has member $@ of a type that is derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. | test0.cs:13:18:13:43 | DerivesFromDeprecatedType1 | DerivesFromDeprecatedType1 | test0.cs:15:24:15:32 | MyDataSet | MyDataSet | +| test0.cs:61:25:61:33 | MyDataSet | Defining an serializable class $@ that has member $@ of a type that is derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. | test0.cs:59:18:59:38 | AttributeSerializer01 | AttributeSerializer01 | test0.cs:61:25:61:33 | MyDataSet | MyDataSet | diff --git a/csharp/ql/test/experimental/Security Features/Serialization/DefiningPotentiallyUnsafeXmlSerializer.qlref b/csharp/ql/test/experimental/Security Features/Serialization/DefiningPotentiallyUnsafeXmlSerializer.qlref new file mode 100644 index 000000000000..8a8632c6ee3b --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/Serialization/DefiningPotentiallyUnsafeXmlSerializer.qlref @@ -0,0 +1 @@ +experimental/Security Features/Serialization/DefiningPotentiallyUnsafeXmlSerializer.ql \ No newline at end of file diff --git a/csharp/ql/test/experimental/Security Features/Serialization/UnsafeTypeUsedDataContractSerializer.expected b/csharp/ql/test/experimental/Security Features/Serialization/UnsafeTypeUsedDataContractSerializer.expected new file mode 100644 index 000000000000..0c9ce7297e97 --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/Serialization/UnsafeTypeUsedDataContractSerializer.expected @@ -0,0 +1,2 @@ +| test0.cs:95:49:95:63 | typeof(...) | Unsafe type is used in data contract serializer. Make sure $@ comes from the trusted source. | test0.cs:95:49:95:63 | typeof(...) | typeof(...) | +| test0.cs:96:49:96:77 | typeof(...) | Unsafe type is used in data contract serializer. Make sure $@ comes from the trusted source. | test0.cs:96:49:96:77 | typeof(...) | typeof(...) | diff --git a/csharp/ql/test/experimental/Security Features/Serialization/UnsafeTypeUsedDataContractSerializer.qlref b/csharp/ql/test/experimental/Security Features/Serialization/UnsafeTypeUsedDataContractSerializer.qlref new file mode 100644 index 000000000000..1593497c7932 --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/Serialization/UnsafeTypeUsedDataContractSerializer.qlref @@ -0,0 +1 @@ +experimental/Security Features/Serialization/UnsafeTypeUsedDataContractSerializer.ql \ No newline at end of file diff --git a/csharp/ql/test/experimental/Security Features/Serialization/XmlDeserializationWithDataSet.expected b/csharp/ql/test/experimental/Security Features/Serialization/XmlDeserializationWithDataSet.expected new file mode 100644 index 000000000000..4f451559aaf0 --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/Serialization/XmlDeserializationWithDataSet.expected @@ -0,0 +1 @@ +| test0.cs:88:17:88:46 | call to method ReadXmlSchema | Making an XML deserialization call with a type derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. | diff --git a/csharp/ql/test/experimental/Security Features/Serialization/XmlDeserializationWithDataSet.qlref b/csharp/ql/test/experimental/Security Features/Serialization/XmlDeserializationWithDataSet.qlref new file mode 100644 index 000000000000..8054e46f929b --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/Serialization/XmlDeserializationWithDataSet.qlref @@ -0,0 +1 @@ +experimental/Security Features/Serialization/XmlDeserializationWithDataSet.ql \ No newline at end of file diff --git a/csharp/ql/test/experimental/Security Features/Serialization/test0.cs b/csharp/ql/test/experimental/Security Features/Serialization/test0.cs new file mode 100644 index 000000000000..30d266203fac --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/Serialization/test0.cs @@ -0,0 +1,101 @@ +// semmle-extractor-options: /r:System.Data.Common.dll /r:System.Runtime.WindowsRuntime.dll /r:System.Xml.XmlSerializer.dll /r:System.Runtime.Serialization.Xml.dll /r:System.Runtime.Serialization.Xml.dll /r:System.Collections.dll /r:System.Private.Xml.dll /r:System.Private.DataContractSerialization.dll /r:System.Runtime.Extensions.dll /r:System.ComponentModel.TypeConverter.dll /r:System.Xml.ReaderWriter.dll /r:System.IO.FileSystem.dll + +using System; +using System.Data; +using System.IO; +using System.Xml.Serialization; +using System.Runtime.Serialization; +using System.Xml; +using System.Collections.Generic; + +namespace DataSetSerializationTest +{ + public class DerivesFromDeprecatedType1 : XmlSerializer // warning:DefiningDatasetRelatedType.ql + { + public DataSet MyDataSet { get; set; } // bug:DefiningPotentiallyUnsafeXmlSerializer.ql + + public DerivesFromDeprecatedType1() + { + } + } + + /* + * TODO: I cannot use DataContract on a QL unit test + * + [DataContract(Name = "Customer", Namespace = "http://www.contoso.com")] + public class PatternDataContractSerializer : XmlObjectSerializer + { + [DataMember()] + public DataSet MyDataSet { get; set; } + [DataMember()] + public DataTable MyDataTable { get; set; } + + PatternDataContractSerializer() { } + private ExtensionDataObject extensionData_Value; + public ExtensionDataObject ExtensionData + { + get + { + return extensionData_Value; + } + set + { + extensionData_Value = value; + } + } + + public override void WriteObject(System.IO.Stream stream, object graph) { } + public override void WriteObjectContent(System.Xml.XmlDictionaryWriter writer, object graph) { } + public override bool IsStartObject(System.Xml.XmlDictionaryReader reader) { return false; } + public override void WriteStartObject(System.Xml.XmlDictionaryWriter writer, object graph) { } + public override void WriteEndObject(System.Xml.XmlWriter writer) { } + public override void WriteEndObject(XmlDictionaryWriter writer) { } + public override object ReadObject(System.IO.Stream stream) { return null; } + public override object ReadObject(XmlDictionaryReader reader, bool b) { return null; } + } + */ + + [Serializable()] + public class AttributeSerializer01 // warning:DefiningDatasetRelatedType.ql + { + private DataSet MyDataSet; // bug:DefiningPotentiallyUnsafeXmlSerializer.ql + + AttributeSerializer01() + { + } + } + + class Program + { + static string GetSerializedDataSet(DataSet dataSet) + { + DataTable dataTable = new DataTable("MyTable"); + dataTable.Columns.Add("FirstName", typeof(string)); + dataTable.Columns.Add("LastName", typeof(string)); + dataTable.Columns.Add("Age", typeof(int)); + + StringWriter writer = new StringWriter(); + dataSet.WriteXml(writer, XmlWriteMode.DiffGram); + return writer.ToString(); + } + + static void datatable_readxmlschema_01(string fileName) + { + using (FileStream fs = File.OpenRead(fileName)) + { + DataTable newTable = new DataTable(); + System.Xml.XmlTextReader reader = new System.Xml.XmlTextReader(fs); + newTable.ReadXmlSchema(reader); //bug:XmlDeserializationWithDataSet.ql + } + } + + static void Main(string[] args) + { + + XmlSerializer x = new XmlSerializer(typeof(DataSet)); // bug:UnsafeTypeUsedDataContractSerializer.ql + XmlSerializer y = new XmlSerializer(typeof(AttributeSerializer01)); //bug:UnsafeTypeUsedDataContractSerializer.ql + + Console.WriteLine("Hello World!"); + } + } +} \ No newline at end of file diff --git a/csharp/ql/test/experimental/ir/ir/PrintAst.expected b/csharp/ql/test/experimental/ir/ir/PrintAst.expected new file mode 100644 index 000000000000..25ea10bc4766 --- /dev/null +++ b/csharp/ql/test/experimental/ir/ir/PrintAst.expected @@ -0,0 +1,1151 @@ +array.cs: +# 1| [Class] ArrayTest +# 2| 5: [Method] one_dim_init_acc +# 3| 4: [BlockStmt] {...} +# 4| 0: [LocalVariableDeclStmt] ... ...; +# 4| 0: [LocalVariableDeclAndInitExpr] Int32[] one_dim = ... +# 4| 0: [ArrayCreation] array creation of type Int32[] +# 4| -1: [ArrayInitializer] { ..., ... } +# 4| 0: [IntLiteral] 100 +# 4| 1: [IntLiteral] 101 +# 4| 2: [IntLiteral] 102 +# 4| 1: [LocalVariableAccess] access to local variable one_dim +# 5| 1: [ExprStmt] ...; +# 5| 0: [AssignExpr] ... = ... +# 5| 0: [IntLiteral] 1000 +# 5| 1: [ArrayAccess] access to array element +# 5| -1: [LocalVariableAccess] access to local variable one_dim +# 5| 0: [IntLiteral] 0 +# 6| 2: [ExprStmt] ...; +# 6| 0: [AssignExpr] ... = ... +# 6| 0: [ArrayAccess] access to array element +# 6| -1: [LocalVariableAccess] access to local variable one_dim +# 6| 0: [IntLiteral] 0 +# 6| 1: [ArrayAccess] access to array element +# 6| -1: [LocalVariableAccess] access to local variable one_dim +# 6| 0: [IntLiteral] 1 +# 7| 3: [ExprStmt] ...; +# 7| 0: [AssignExpr] ... = ... +# 7| 0: [IntLiteral] 1003 +# 7| 1: [ArrayAccess] access to array element +# 7| -1: [LocalVariableAccess] access to local variable one_dim +# 7| 0: [IntLiteral] 1 +# 9| 4: [LocalVariableDeclStmt] ... ...; +# 9| 0: [LocalVariableDeclAndInitExpr] Int32 i = ... +# 9| 0: [IntLiteral] 0 +# 9| 1: [LocalVariableAccess] access to local variable i +# 10| 5: [ExprStmt] ...; +# 10| 0: [AssignExpr] ... = ... +# 10| 0: [IntLiteral] 0 +# 10| 1: [ArrayAccess] access to array element +# 10| -1: [LocalVariableAccess] access to local variable one_dim +# 10| 0: [LocalVariableAccess] access to local variable i +# 13| 6: [Method] twod_and_init_acc +# 14| 4: [BlockStmt] {...} +# 15| 0: [LocalVariableDeclStmt] ... ...; +# 15| 0: [LocalVariableDeclAndInitExpr] Int32[,] a = ... +# 15| 0: [ArrayCreation] array creation of type Int32[,] +# 15| -1: [ArrayInitializer] { ..., ... } +# 15| 0: [ArrayInitializer] { ..., ... } +# 15| 0: [IntLiteral] 100 +# 15| 1: [IntLiteral] 101 +# 15| 1: [ArrayInitializer] { ..., ... } +# 15| 0: [IntLiteral] 102 +# 15| 1: [IntLiteral] 103 +# 15| 1: [LocalVariableAccess] access to local variable a +# 16| 1: [LocalVariableDeclStmt] ... ...; +# 16| 0: [LocalVariableDeclAndInitExpr] Int32[,] b = ... +# 16| 0: [ArrayCreation] array creation of type Int32[,] +# 16| 0: [IntLiteral] 5 +# 16| 1: [IntLiteral] 5 +# 16| 1: [LocalVariableAccess] access to local variable b +# 17| 2: [LocalVariableDeclStmt] ... ...; +# 17| 0: [LocalVariableDeclAndInitExpr] Int32[,] c = ... +# 17| 0: [ArrayCreation] array creation of type Int32[,] +# 17| -1: [ArrayInitializer] { ..., ... } +# 17| 0: [ArrayInitializer] { ..., ... } +# 17| 0: [IntLiteral] 100 +# 17| 1: [IntLiteral] 101 +# 17| 1: [ArrayInitializer] { ..., ... } +# 17| 0: [IntLiteral] 102 +# 17| 1: [IntLiteral] 103 +# 17| 0: [IntLiteral] 2 +# 17| 1: [IntLiteral] 2 +# 17| 1: [LocalVariableAccess] access to local variable c +# 18| 3: [LocalVariableDeclStmt] ... ...; +# 18| 0: [LocalVariableDeclAndInitExpr] Int32[,] d = ... +# 18| 0: [ArrayCreation] array creation of type Int32[,] +# 18| -1: [ArrayInitializer] { ..., ... } +# 18| 0: [ArrayInitializer] { ..., ... } +# 18| 0: [IntLiteral] 100 +# 18| 1: [IntLiteral] 101 +# 18| 1: [ArrayInitializer] { ..., ... } +# 18| 0: [IntLiteral] 102 +# 18| 1: [IntLiteral] 103 +# 18| 1: [LocalVariableAccess] access to local variable d +# 19| 4: [LocalVariableDeclStmt] ... ...; +# 19| 0: [LocalVariableDeclAndInitExpr] Int32[,] e = ... +# 19| 0: [LocalVariableAccess] access to local variable a +# 19| 1: [LocalVariableAccess] access to local variable e +# 20| 5: [ExprStmt] ...; +# 20| 0: [AssignExpr] ... = ... +# 20| 0: [UnaryMinusExpr] -... +# 20| 0: [IntLiteral] 1 +# 20| 1: [ArrayAccess] access to array element +# 20| -1: [LocalVariableAccess] access to local variable e +# 20| 0: [IntLiteral] 1 +# 20| 1: [IntLiteral] 1 +assignop.cs: +# 3| [Class] AssignOp +# 4| 5: [Method] Main +# 4| 4: [BlockStmt] {...} +# 5| 0: [LocalVariableDeclStmt] ... ...; +# 5| 0: [LocalVariableDeclAndInitExpr] Int32 a = ... +# 5| 0: [IntLiteral] 1 +# 5| 1: [LocalVariableAccess] access to local variable a +# 6| 1: [LocalVariableDeclStmt] ... ...; +# 6| 0: [LocalVariableDeclAndInitExpr] Int32 c = ... +# 6| 0: [IntLiteral] 1 +# 6| 1: [LocalVariableAccess] access to local variable c +# 8| 2: [ExprStmt] ...; +# 8| 0: [AssignAddExpr] ... += ... +# 8| 0: [LocalVariableAccess] access to local variable a +# 8| 1: [LocalVariableAccess] access to local variable c +# 9| 3: [ExprStmt] ...; +# 9| 0: [AssignSubExpr] ... -= ... +# 9| 0: [LocalVariableAccess] access to local variable a +# 9| 1: [LocalVariableAccess] access to local variable c +# 10| 4: [ExprStmt] ...; +# 10| 0: [AssignMulExpr] ... *= ... +# 10| 0: [LocalVariableAccess] access to local variable a +# 10| 1: [LocalVariableAccess] access to local variable c +# 11| 5: [ExprStmt] ...; +# 11| 0: [AssignDivExpr] ... /= ... +# 11| 0: [LocalVariableAccess] access to local variable a +# 11| 1: [LocalVariableAccess] access to local variable c +# 12| 6: [ExprStmt] ...; +# 12| 0: [AssignRemExpr] ... %= ... +# 12| 0: [LocalVariableAccess] access to local variable a +# 12| 1: [LocalVariableAccess] access to local variable c +# 13| 7: [ExprStmt] ...; +# 13| 0: [AssignLShiftExpr] ... <<= ... +# 13| 0: [IntLiteral] 2 +# 13| 1: [LocalVariableAccess] access to local variable c +# 14| 8: [ExprStmt] ...; +# 14| 0: [AssignRShiftExpr] ... >>= ... +# 14| 0: [IntLiteral] 2 +# 14| 1: [LocalVariableAccess] access to local variable c +# 15| 9: [ExprStmt] ...; +# 15| 0: [AssignAndExpr] ... &= ... +# 15| 0: [IntLiteral] 2 +# 15| 1: [LocalVariableAccess] access to local variable c +# 16| 10: [ExprStmt] ...; +# 16| 0: [AssignXorExpr] ... ^= ... +# 16| 0: [IntLiteral] 2 +# 16| 1: [LocalVariableAccess] access to local variable c +# 17| 11: [ExprStmt] ...; +# 17| 0: [AssignOrExpr] ... |= ... +# 17| 0: [IntLiteral] 2 +# 17| 1: [LocalVariableAccess] access to local variable c +casts.cs: +# 1| [Class] Casts_A +# 5| [Class] Casts_B +#-----| 3: (Base types) +# 5| 0: [Class] Casts_A +# 9| [Class] Casts +# 11| 5: [Method] Main +# 12| 4: [BlockStmt] {...} +# 13| 0: [LocalVariableDeclStmt] ... ...; +# 13| 0: [LocalVariableDeclAndInitExpr] Casts_A Aobj = ... +# 13| 0: [ObjectCreation] object creation of type Casts_A +# 13| 1: [LocalVariableAccess] access to local variable Aobj +# 14| 1: [LocalVariableDeclStmt] ... ...; +# 14| 0: [LocalVariableDeclAndInitExpr] Casts_B bobjCE = ... +# 14| 0: [CastExpr] (...) ... +# 14| 0: [LocalVariableAccess] access to local variable Aobj +# 14| 1: [TypeAccess] access to type Casts_B +# 14| 1: [LocalVariableAccess] access to local variable bobjCE +# 15| 2: [LocalVariableDeclStmt] ... ...; +# 15| 0: [LocalVariableDeclAndInitExpr] Casts_B bobjAS = ... +# 15| 0: [AsExpr] ... as ... +# 15| 0: [LocalVariableAccess] access to local variable Aobj +# 15| 1: [TypeAccess] access to type Casts_B +# 15| 1: [LocalVariableAccess] access to local variable bobjAS +collections.cs: +# 3| [Class] Collections +# 5| 5: [Class] MyClass +# 7| 5: [Field] a +# 8| 6: [Field] b +# 11| 6: [Method] Main +# 12| 4: [BlockStmt] {...} +# 13| 0: [LocalVariableDeclStmt] ... ...; +# 13| 0: [LocalVariableDeclAndInitExpr] Dictionary dict = ... +# 13| 0: [ObjectCreation] object creation of type Dictionary +# 14| -1: [CollectionInitializer] { ..., ... } +# 15| 0: [ElementInitializer] call to method Add +# 15| 0: [IntLiteral] 0 +# 15| 1: [ObjectCreation] object creation of type MyClass +# 15| -1: [ObjectInitializer] { ..., ... } +# 15| 0: [MemberInitializer] ... = ... +# 15| 0: [StringLiteral] "Hello" +# 15| 1: [FieldAccess] access to field a +# 15| 1: [MemberInitializer] ... = ... +# 15| 0: [StringLiteral] "World" +# 15| 1: [FieldAccess] access to field b +# 16| 1: [ElementInitializer] call to method Add +# 16| 0: [IntLiteral] 1 +# 16| 1: [ObjectCreation] object creation of type MyClass +# 16| -1: [ObjectInitializer] { ..., ... } +# 16| 0: [MemberInitializer] ... = ... +# 16| 0: [StringLiteral] "Foo" +# 16| 1: [FieldAccess] access to field a +# 16| 1: [MemberInitializer] ... = ... +# 16| 0: [StringLiteral] "Bar" +# 16| 1: [FieldAccess] access to field b +# 13| 1: [LocalVariableAccess] access to local variable dict +constructor_init.cs: +# 1| [Class] BaseClass +# 3| 4: [Field] num +# 5| 5: [InstanceConstructor] BaseClass +# 6| 4: [BlockStmt] {...} +# 9| 6: [InstanceConstructor] BaseClass +#-----| 2: (Parameters) +# 9| 0: [Parameter] i +# 10| 4: [BlockStmt] {...} +# 11| 0: [ExprStmt] ...; +# 11| 0: [AssignExpr] ... = ... +# 11| 0: [ParameterAccess] access to parameter i +# 11| 1: [FieldAccess] access to field num +# 15| [Class] DerivedClass +#-----| 3: (Base types) +# 15| 0: [Class] BaseClass +# 17| 4: [InstanceConstructor] DerivedClass +# 17| 3: [ConstructorInitializer] call to constructor BaseClass +# 18| 4: [BlockStmt] {...} +# 21| 5: [InstanceConstructor] DerivedClass +#-----| 2: (Parameters) +# 21| 0: [Parameter] i +# 21| 3: [ConstructorInitializer] call to constructor BaseClass +# 21| 0: [ParameterAccess] access to parameter i +# 22| 4: [BlockStmt] {...} +# 25| 6: [InstanceConstructor] DerivedClass +#-----| 2: (Parameters) +# 25| 0: [Parameter] i +# 25| 1: [Parameter] j +# 25| 3: [ConstructorInitializer] call to constructor DerivedClass +# 25| 0: [ParameterAccess] access to parameter i +# 26| 4: [BlockStmt] {...} +# 29| 7: [Method] Main +# 30| 4: [BlockStmt] {...} +# 31| 0: [LocalVariableDeclStmt] ... ...; +# 31| 0: [LocalVariableDeclAndInitExpr] DerivedClass obj1 = ... +# 31| 0: [ObjectCreation] object creation of type DerivedClass +# 31| 1: [LocalVariableAccess] access to local variable obj1 +# 32| 1: [LocalVariableDeclStmt] ... ...; +# 32| 0: [LocalVariableDeclAndInitExpr] DerivedClass obj2 = ... +# 32| 0: [ObjectCreation] object creation of type DerivedClass +# 32| 0: [IntLiteral] 1 +# 32| 1: [LocalVariableAccess] access to local variable obj2 +# 33| 2: [LocalVariableDeclStmt] ... ...; +# 33| 0: [LocalVariableDeclAndInitExpr] DerivedClass obj3 = ... +# 33| 0: [ObjectCreation] object creation of type DerivedClass +# 33| 0: [IntLiteral] 1 +# 33| 1: [IntLiteral] 2 +# 33| 1: [LocalVariableAccess] access to local variable obj3 +crement.cs: +# 1| [Class] CrementOpsTest +# 3| 5: [Method] Main +# 4| 4: [BlockStmt] {...} +# 5| 0: [LocalVariableDeclStmt] ... ...; +# 5| 0: [LocalVariableDeclAndInitExpr] Int32 x = ... +# 5| 0: [IntLiteral] 10 +# 5| 1: [LocalVariableAccess] access to local variable x +# 6| 1: [LocalVariableDeclStmt] ... ...; +# 6| 0: [LocalVariableDeclAndInitExpr] Int32 a = ... +# 6| 0: [PostIncrExpr] ...++ +# 6| 0: [LocalVariableAccess] access to local variable x +# 6| 1: [LocalVariableAccess] access to local variable a +# 7| 2: [LocalVariableDeclStmt] ... ...; +# 7| 0: [LocalVariableDeclAndInitExpr] Int32 b = ... +# 7| 0: [PreDecrExpr] --... +# 7| 0: [LocalVariableAccess] access to local variable x +# 7| 1: [LocalVariableAccess] access to local variable b +# 8| 3: [LocalVariableDeclStmt] ... ...; +# 8| 0: [LocalVariableDeclAndInitExpr] Int32 c = ... +# 8| 0: [PreIncrExpr] ++... +# 8| 0: [LocalVariableAccess] access to local variable x +# 8| 1: [LocalVariableAccess] access to local variable c +# 9| 4: [ExprStmt] ...; +# 9| 0: [AssignExpr] ... = ... +# 9| 0: [PostDecrExpr] ...-- +# 9| 0: [LocalVariableAccess] access to local variable x +# 9| 1: [LocalVariableAccess] access to local variable x +delegates.cs: +# 3| [Class] Delegates +# 4| 5: [DelegateType] Del +#-----| 2: (Parameters) +# 4| 0: [Parameter] num +# 6| 6: [Method] returns +#-----| 2: (Parameters) +# 6| 0: [Parameter] ret +# 7| 4: [BlockStmt] {...} +# 8| 0: [ReturnStmt] return ...; +# 8| 0: [ParameterAccess] access to parameter ret +# 11| 7: [Method] Main +# 11| 4: [BlockStmt] {...} +# 12| 0: [LocalVariableDeclStmt] ... ...; +# 12| 0: [LocalVariableDeclAndInitExpr] Del del1 = ... +# 12| 0: [ExplicitDelegateCreation] delegate creation of type Del +# 12| 0: [MethodAccess] access to method returns +# 12| 1: [LocalVariableAccess] access to local variable del1 +# 13| 1: [ExprStmt] ...; +# 13| 0: [DelegateCall] delegate call +# 13| -1: [LocalVariableAccess] access to local variable del1 +# 13| 0: [IntLiteral] 5 +events.cs: +# 1| [Class] Events +# 3| 4: [DelegateType] MyDel +#-----| 2: (Parameters) +# 3| 0: [Parameter] str +# 4| 5: [Field] Inst +# 6| 6: [Event] MyEvent +# 6| 3: [AddEventAccessor] add_MyEvent +#-----| 2: (Parameters) +# 6| 0: [Parameter] value +# 6| 4: [RemoveEventAccessor] remove_MyEvent +#-----| 2: (Parameters) +# 6| 0: [Parameter] value +# 8| 7: [InstanceConstructor] Events +# 9| 4: [BlockStmt] {...} +# 10| 0: [ExprStmt] ...; +# 10| 0: [AssignExpr] ... = ... +# 10| 0: [ExplicitDelegateCreation] delegate creation of type MyDel +# 10| 0: [MethodAccess] access to method Fun +# 10| -1: [ThisAccess] this access +# 10| 1: [FieldAccess] access to field Inst +# 10| -1: [ThisAccess] this access +# 13| 8: [Method] AddEvent +# 14| 4: [BlockStmt] {...} +# 15| 0: [ExprStmt] ...; +# 15| 0: [AddEventExpr] ... += ... +# 15| 0: [FieldAccess] access to field Inst +# 15| -1: [ThisAccess] this access +# 15| 1: [EventAccess,EventCall] access to event MyEvent +# 15| -1: [ThisAccess] this access +# 18| 9: [Method] RemoveEvent +# 19| 4: [BlockStmt] {...} +# 20| 0: [ExprStmt] ...; +# 20| 0: [RemoveEventExpr] ... -= ... +# 20| 0: [FieldAccess] access to field Inst +# 20| -1: [ThisAccess] this access +# 20| 1: [EventAccess,EventCall] access to event MyEvent +# 20| -1: [ThisAccess] this access +# 23| 10: [Method] Fun +#-----| 2: (Parameters) +# 23| 0: [Parameter] str +# 24| 4: [BlockStmt] {...} +# 25| 0: [ReturnStmt] return ...; +# 25| 0: [ParameterAccess] access to parameter str +# 28| 11: [Method] Main +#-----| 2: (Parameters) +# 28| 0: [Parameter] args +# 29| 4: [BlockStmt] {...} +# 30| 0: [LocalVariableDeclStmt] ... ...; +# 30| 0: [LocalVariableDeclAndInitExpr] Events obj = ... +# 30| 0: [ObjectCreation] object creation of type Events +# 30| 1: [LocalVariableAccess] access to local variable obj +# 31| 1: [ExprStmt] ...; +# 31| 0: [MethodCall] call to method AddEvent +# 31| -1: [LocalVariableAccess] access to local variable obj +# 32| 2: [LocalVariableDeclStmt] ... ...; +# 32| 0: [LocalVariableDeclAndInitExpr] String result = ... +# 32| 0: [DelegateCall] delegate call +# 32| -1: [LocalVariableAccess] access to local variable obj +# 32| 0: [StringLiteral] "string" +# 32| 1: [LocalVariableAccess] access to local variable result +# 33| 3: [ExprStmt] ...; +# 33| 0: [MethodCall] call to method RemoveEvent +# 33| -1: [LocalVariableAccess] access to local variable obj +foreach.cs: +# 3| [Class] ForEach +# 4| 5: [Method] Main +# 4| 4: [BlockStmt] {...} +# 5| 0: [LocalVariableDeclStmt] ... ...; +# 5| 0: [LocalVariableDeclAndInitExpr] Int32[] a_array = ... +# 5| 0: [ArrayCreation] array creation of type Int32[] +# 5| -1: [ArrayInitializer] { ..., ... } +# 5| 0: [IntLiteral] 1 +# 5| 1: [IntLiteral] 2 +# 5| 2: [IntLiteral] 3 +# 5| 3: [IntLiteral] 4 +# 5| 4: [IntLiteral] 5 +# 5| 5: [IntLiteral] 6 +# 5| 6: [IntLiteral] 7 +# 5| 1: [LocalVariableAccess] access to local variable a_array +# 7| 1: [ForeachStmt] foreach (... ... in ...) ... +# 7| 0: [LocalVariableDeclExpr] Int32 items +# 7| 1: [LocalVariableAccess] access to local variable a_array +# 8| 2: [BlockStmt] {...} +# 9| 0: [LocalVariableDeclStmt] ... ...; +# 9| 0: [LocalVariableDeclAndInitExpr] Int32 x = ... +# 9| 0: [LocalVariableAccess] access to local variable items +# 9| 1: [LocalVariableAccess] access to local variable x +func_with_param_call.cs: +# 3| [Class] test_call_with_param +# 5| 5: [Method] f +#-----| 2: (Parameters) +# 5| 0: [Parameter] x +# 5| 1: [Parameter] y +# 6| 4: [BlockStmt] {...} +# 7| 0: [ReturnStmt] return ...; +# 7| 0: [AddExpr] ... + ... +# 7| 0: [ParameterAccess] access to parameter x +# 7| 1: [ParameterAccess] access to parameter y +# 10| 6: [Method] g +# 11| 4: [BlockStmt] {...} +# 12| 0: [ReturnStmt] return ...; +# 12| 0: [MethodCall] call to method f +# 12| 0: [IntLiteral] 2 +# 12| 1: [IntLiteral] 3 +indexers.cs: +# 1| [Class] Indexers +# 3| 5: [Class] MyClass +# 5| 5: [Field] address +# 5| 1: [AssignExpr] ... = ... +# 5| 0: [ArrayCreation] array creation of type String[] +# 5| 0: [IntLiteral] 2 +# 5| 1: [FieldAccess] access to field address +# 6| 6: [Indexer] Item +#-----| 1: (Parameters) +# 6| 0: [Parameter] index +# 8| 3: [Getter] get_Item +#-----| 2: (Parameters) +# 6| 0: [Parameter] index +# 9| 4: [BlockStmt] {...} +# 10| 0: [ReturnStmt] return ...; +# 10| 0: [ArrayAccess] access to array element +# 10| -1: [FieldAccess] access to field address +# 10| 0: [ParameterAccess] access to parameter index +# 12| 4: [Setter] set_Item +#-----| 2: (Parameters) +# 6| 0: [Parameter] index +# 12| 1: [Parameter] value +# 13| 4: [BlockStmt] {...} +# 14| 0: [ExprStmt] ...; +# 14| 0: [AssignExpr] ... = ... +# 14| 0: [ParameterAccess] access to parameter value +# 14| 1: [ArrayAccess] access to array element +# 14| -1: [FieldAccess] access to field address +# 14| 0: [ParameterAccess] access to parameter index +# 19| 6: [Method] Main +# 20| 4: [BlockStmt] {...} +# 21| 0: [LocalVariableDeclStmt] ... ...; +# 21| 0: [LocalVariableDeclAndInitExpr] MyClass inst = ... +# 21| 0: [ObjectCreation] object creation of type MyClass +# 21| 1: [LocalVariableAccess] access to local variable inst +# 22| 1: [ExprStmt] ...; +# 22| 0: [AssignExpr] ... = ... +# 22| 0: [StringLiteral] "str1" +# 22| 1: [IndexerCall] access to indexer +# 22| -1: [LocalVariableAccess] access to local variable inst +# 22| 0: [IntLiteral] 0 +# 23| 2: [ExprStmt] ...; +# 23| 0: [AssignExpr] ... = ... +# 23| 0: [StringLiteral] "str1" +# 23| 1: [IndexerCall] access to indexer +# 23| -1: [LocalVariableAccess] access to local variable inst +# 23| 0: [IntLiteral] 1 +# 24| 3: [ExprStmt] ...; +# 24| 0: [AssignExpr] ... = ... +# 24| 0: [IndexerCall] access to indexer +# 24| -1: [LocalVariableAccess] access to local variable inst +# 24| 0: [IntLiteral] 0 +# 24| 1: [IndexerCall] access to indexer +# 24| -1: [LocalVariableAccess] access to local variable inst +# 24| 0: [IntLiteral] 1 +inheritance_polymorphism.cs: +# 1| [Class] A +# 3| 5: [Method] function +# 4| 4: [BlockStmt] {...} +# 5| 0: [ReturnStmt] return ...; +# 5| 0: [IntLiteral] 0 +# 9| [Class] B +#-----| 3: (Base types) +# 9| 0: [Class] A +# 13| [Class] C +#-----| 3: (Base types) +# 13| 0: [Class] B +# 15| 5: [Method] function +# 16| 4: [BlockStmt] {...} +# 17| 0: [ReturnStmt] return ...; +# 17| 0: [IntLiteral] 1 +# 21| [Class] Program +# 23| 5: [Method] Main +# 24| 4: [BlockStmt] {...} +# 25| 0: [LocalVariableDeclStmt] ... ...; +# 25| 0: [LocalVariableDeclAndInitExpr] B objB = ... +# 25| 0: [ObjectCreation] object creation of type B +# 25| 1: [LocalVariableAccess] access to local variable objB +# 26| 1: [ExprStmt] ...; +# 26| 0: [MethodCall] call to method function +# 26| -1: [LocalVariableAccess] access to local variable objB +# 29| 2: [LocalVariableDeclStmt] ... ...; +# 29| 0: [LocalVariableDeclExpr] A objA +# 30| 3: [ExprStmt] ...; +# 30| 0: [AssignExpr] ... = ... +# 30| 0: [LocalVariableAccess] access to local variable objB +# 30| 1: [LocalVariableAccess] access to local variable objA +# 31| 4: [ExprStmt] ...; +# 31| 0: [MethodCall] call to method function +# 31| -1: [LocalVariableAccess] access to local variable objA +# 33| 5: [LocalVariableDeclStmt] ... ...; +# 33| 0: [LocalVariableDeclAndInitExpr] A objC = ... +# 33| 0: [ObjectCreation] object creation of type C +# 33| 1: [LocalVariableAccess] access to local variable objC +# 34| 6: [ExprStmt] ...; +# 34| 0: [MethodCall] call to method function +# 34| -1: [LocalVariableAccess] access to local variable objC +inoutref.cs: +# 1| [Class] MyClass +# 2| 5: [Field] fld +# 5| [Struct] MyStruct +# 6| 5: [Field] fld +# 9| [Class] InOutRef +# 11| 5: [Method] set +#-----| 2: (Parameters) +# 11| 0: [Parameter] o1 +# 11| 1: [Parameter] o2 +# 12| 4: [BlockStmt] {...} +# 13| 0: [ExprStmt] ...; +# 13| 0: [AssignExpr] ... = ... +# 13| 0: [ParameterAccess] access to parameter o2 +# 13| 1: [ParameterAccess] access to parameter o1 +# 16| 6: [Method] F +#-----| 2: (Parameters) +# 16| 0: [Parameter] a +# 16| 1: [Parameter] b +# 16| 2: [Parameter] b1 +# 16| 3: [Parameter] c +# 16| 4: [Parameter] c1 +# 17| 4: [BlockStmt] {...} +# 18| 0: [ExprStmt] ...; +# 18| 0: [AssignExpr] ... = ... +# 18| 0: [IntLiteral] 0 +# 18| 1: [FieldAccess] access to field fld +# 18| -1: [ParameterAccess] access to parameter b +# 19| 1: [ExprStmt] ...; +# 19| 0: [AssignExpr] ... = ... +# 19| 0: [FieldAccess] access to field fld +# 19| -1: [ParameterAccess] access to parameter b +# 19| 1: [ParameterAccess] access to parameter a +# 21| 2: [ExprStmt] ...; +# 21| 0: [AssignExpr] ... = ... +# 21| 0: [IntLiteral] 10 +# 21| 1: [FieldAccess] access to field fld +# 21| -1: [ParameterAccess] access to parameter c +# 22| 3: [ExprStmt] ...; +# 22| 0: [AssignExpr] ... = ... +# 22| 0: [FieldAccess] access to field fld +# 22| -1: [ParameterAccess] access to parameter c +# 22| 1: [ParameterAccess] access to parameter a +# 24| 4: [ExprStmt] ...; +# 24| 0: [AssignExpr] ... = ... +# 24| 0: [ParameterAccess] access to parameter b1 +# 24| 1: [ParameterAccess] access to parameter b +# 26| 5: [ExprStmt] ...; +# 26| 0: [MethodCall] call to method set +# 26| 0: [ParameterAccess] access to parameter c +# 26| 1: [ParameterAccess] access to parameter c1 +# 29| 7: [Method] Main +# 30| 4: [BlockStmt] {...} +# 31| 0: [LocalVariableDeclStmt] ... ...; +# 31| 0: [LocalVariableDeclAndInitExpr] Int32 a = ... +# 31| 0: [IntLiteral] 0 +# 31| 1: [LocalVariableAccess] access to local variable a +# 32| 1: [LocalVariableDeclStmt] ... ...; +# 32| 0: [LocalVariableDeclAndInitExpr] MyStruct b = ... +# 32| 0: [ObjectCreation] object creation of type MyStruct +# 32| 1: [LocalVariableAccess] access to local variable b +# 33| 2: [LocalVariableDeclStmt] ... ...; +# 33| 0: [LocalVariableDeclAndInitExpr] MyClass c = ... +# 33| 0: [ObjectCreation] object creation of type MyClass +# 33| 1: [LocalVariableAccess] access to local variable c +# 34| 3: [ExprStmt] ...; +# 34| 0: [MethodCall] call to method F +# 34| 0: [LocalVariableAccess] access to local variable a +# 34| 1: [LocalVariableAccess] access to local variable b +# 34| 2: [LocalVariableAccess] access to local variable b +# 34| 3: [LocalVariableAccess] access to local variable c +# 34| 4: [LocalVariableAccess] access to local variable c +# 36| 4: [LocalVariableDeclStmt] ... ...; +# 36| 0: [LocalVariableDeclAndInitExpr] Int32 x = ... +# 36| 0: [FieldAccess] access to field fld +# 36| -1: [LocalVariableAccess] access to local variable b +# 36| 1: [LocalVariableAccess] access to local variable x +isexpr.cs: +# 1| [Class] Is_A +# 3| 5: [Field] x +# 6| [Class] IsExpr +# 8| 5: [Method] Main +# 9| 4: [BlockStmt] {...} +# 10| 0: [LocalVariableDeclStmt] ... ...; +# 10| 0: [LocalVariableDeclAndInitExpr] Is_A obj = ... +# 10| 0: [NullLiteral] null +# 10| 1: [LocalVariableAccess] access to local variable obj +# 12| 1: [LocalVariableDeclStmt] ... ...; +# 12| 0: [LocalVariableDeclAndInitExpr] Object o = ... +# 12| 0: [LocalVariableAccess] access to local variable obj +# 12| 1: [LocalVariableAccess] access to local variable o +# 13| 2: [IfStmt] if (...) ... +# 13| 0: [IsExpr] ... is ... +# 13| 0: [LocalVariableAccess] access to local variable o +# 13| 1: [VariablePatternExpr] Is_A tmp +# 14| 1: [BlockStmt] {...} +# 15| 0: [LocalVariableDeclStmt] ... ...; +# 15| 0: [LocalVariableDeclAndInitExpr] Int32 res = ... +# 15| 0: [FieldAccess] access to field x +# 15| -1: [LocalVariableAccess] access to local variable tmp +# 15| 1: [LocalVariableAccess] access to local variable res +# 17| 3: [IfStmt] if (...) ... +# 17| 0: [IsExpr] ... is ... +# 17| 0: [LocalVariableAccess] access to local variable o +# 17| 1: [TypeAccessPatternExpr] access to type Is_A +# 18| 1: [BlockStmt] {...} +jumps.cs: +# 3| [Class] Jumps +# 5| 5: [Method] Main +# 6| 4: [BlockStmt] {...} +# 7| 0: [ForStmt] for (...;...;...) ... +# 7| -1: [LocalVariableDeclAndInitExpr] Int32 i = ... +# 7| 0: [IntLiteral] 1 +# 7| 1: [LocalVariableAccess] access to local variable i +# 7| 0: [LEExpr] ... <= ... +# 7| 0: [LocalVariableAccess] access to local variable i +# 7| 1: [IntLiteral] 10 +# 7| 1: [PostIncrExpr] ...++ +# 7| 0: [LocalVariableAccess] access to local variable i +# 8| 2: [BlockStmt] {...} +# 9| 0: [IfStmt] if (...) ... +# 9| 0: [EQExpr] ... == ... +# 9| 0: [LocalVariableAccess] access to local variable i +# 9| 1: [IntLiteral] 3 +# 10| 1: [ContinueStmt] continue; +# 11| 2: [IfStmt] if (...) ... +# 11| 0: [EQExpr] ... == ... +# 11| 0: [LocalVariableAccess] access to local variable i +# 11| 1: [IntLiteral] 5 +# 12| 1: [BreakStmt] break; +# 13| 1: [ExprStmt] ...; +# 13| 0: [MethodCall] call to method WriteLine +# 13| -1: [TypeAccess] access to type Console +# 13| 0: [StringLiteral] "BreakAndContinue" +# 16| 1: [ForStmt] for (...;...;...) ... +# 16| -1: [LocalVariableDeclAndInitExpr] Int32 i = ... +# 16| 0: [IntLiteral] 0 +# 16| 1: [LocalVariableAccess] access to local variable i +# 16| 0: [LTExpr] ... < ... +# 16| 0: [LocalVariableAccess] access to local variable i +# 16| 1: [IntLiteral] 10 +# 17| 1: [BlockStmt] {...} +# 18| 0: [ExprStmt] ...; +# 18| 0: [PostIncrExpr] ...++ +# 18| 0: [LocalVariableAccess] access to local variable i +# 19| 1: [ContinueStmt] continue; +# 22| 2: [LocalVariableDeclStmt] ... ...; +# 22| 0: [LocalVariableDeclAndInitExpr] Int32 a = ... +# 22| 0: [IntLiteral] 0 +# 22| 1: [LocalVariableAccess] access to local variable a +# 23| 3: [WhileStmt] while (...) ... +# 23| 0: [BoolLiteral] true +# 24| 1: [BlockStmt] {...} +# 25| 0: [ExprStmt] ...; +# 25| 0: [PostIncrExpr] ...++ +# 25| 0: [LocalVariableAccess] access to local variable a +# 26| 1: [IfStmt] if (...) ... +# 26| 0: [EQExpr] ... == ... +# 26| 0: [LocalVariableAccess] access to local variable a +# 26| 1: [IntLiteral] 5 +# 27| 1: [ContinueStmt] continue; +# 28| 2: [IfStmt] if (...) ... +# 28| 0: [EQExpr] ... == ... +# 28| 0: [LocalVariableAccess] access to local variable a +# 28| 1: [IntLiteral] 10 +# 29| 1: [BreakStmt] break; +# 32| 4: [ForStmt] for (...;...;...) ... +# 32| -1: [LocalVariableDeclAndInitExpr] Int32 i = ... +# 32| 0: [IntLiteral] 1 +# 32| 1: [LocalVariableAccess] access to local variable i +# 32| 0: [LEExpr] ... <= ... +# 32| 0: [LocalVariableAccess] access to local variable i +# 32| 1: [IntLiteral] 10 +# 32| 1: [PostIncrExpr] ...++ +# 32| 0: [LocalVariableAccess] access to local variable i +# 33| 2: [BlockStmt] {...} +# 34| 0: [IfStmt] if (...) ... +# 34| 0: [EQExpr] ... == ... +# 34| 0: [LocalVariableAccess] access to local variable i +# 34| 1: [IntLiteral] 5 +# 35| 1: [GotoLabelStmt] goto ...; +# 37| 5: [LabelStmt] done: +# 38| 6: [ExprStmt] ...; +# 38| 0: [MethodCall] call to method WriteLine +# 38| -1: [TypeAccess] access to type Console +# 38| 0: [StringLiteral] "Done" +lock.cs: +# 3| [Class] LockTest +# 5| 5: [Method] A +# 6| 4: [BlockStmt] {...} +# 7| 0: [LocalVariableDeclStmt] ... ...; +# 7| 0: [LocalVariableDeclAndInitExpr] Object object = ... +# 7| 0: [ObjectCreation] object creation of type Object +# 7| 1: [LocalVariableAccess] access to local variable object +# 8| 1: [LockStmt] lock (...) {...} +# 8| 0: [LocalVariableAccess] access to local variable object +# 9| 1: [BlockStmt] {...} +# 10| 0: [ExprStmt] ...; +# 10| 0: [MethodCall] call to method WriteLine +# 10| -1: [TypeAccess] access to type Console +# 10| 0: [MethodCall] call to method ToString +# 10| -1: [LocalVariableAccess] access to local variable object +obj_creation.cs: +# 1| [Class] ObjCreation +# 3| 5: [Class] MyClass +# 5| 4: [Field] x +# 7| 5: [InstanceConstructor] MyClass +# 8| 4: [BlockStmt] {...} +# 11| 6: [InstanceConstructor] MyClass +#-----| 2: (Parameters) +# 11| 0: [Parameter] _x +# 12| 4: [BlockStmt] {...} +# 13| 0: [ExprStmt] ...; +# 13| 0: [AssignExpr] ... = ... +# 13| 0: [ParameterAccess] access to parameter _x +# 13| 1: [FieldAccess] access to field x +# 17| 6: [Method] SomeFun +#-----| 2: (Parameters) +# 17| 0: [Parameter] x +# 18| 4: [BlockStmt] {...} +# 21| 7: [Method] Main +# 22| 4: [BlockStmt] {...} +# 23| 0: [LocalVariableDeclStmt] ... ...; +# 23| 0: [LocalVariableDeclAndInitExpr] MyClass obj = ... +# 23| 0: [ObjectCreation] object creation of type MyClass +# 23| 0: [IntLiteral] 100 +# 23| 1: [LocalVariableAccess] access to local variable obj +# 24| 1: [LocalVariableDeclStmt] ... ...; +# 24| 0: [LocalVariableDeclAndInitExpr] MyClass obj_initlist = ... +# 24| 0: [ObjectCreation] object creation of type MyClass +# 24| -1: [ObjectInitializer] { ..., ... } +# 24| 0: [MemberInitializer] ... = ... +# 24| 0: [IntLiteral] 101 +# 24| 1: [FieldAccess] access to field x +# 24| 1: [LocalVariableAccess] access to local variable obj_initlist +# 25| 2: [LocalVariableDeclStmt] ... ...; +# 25| 0: [LocalVariableDeclAndInitExpr] Int32 a = ... +# 25| 0: [FieldAccess] access to field x +# 25| -1: [LocalVariableAccess] access to local variable obj +# 25| 1: [LocalVariableAccess] access to local variable a +# 27| 3: [ExprStmt] ...; +# 27| 0: [MethodCall] call to method SomeFun +# 27| 0: [ObjectCreation] object creation of type MyClass +# 27| 0: [IntLiteral] 100 +pointers.cs: +# 1| [Class] Pointers +# 3| 5: [Method] addone +#-----| 2: (Parameters) +# 3| 0: [Parameter] arr +# 4| 4: [BlockStmt] {...} +# 5| 0: [LocalVariableDeclStmt] ... ...; +# 5| 0: [LocalVariableDeclAndInitExpr] Int32 length = ... +# 5| 0: [PropertyCall] access to property Length +# 5| -1: [ParameterAccess] access to parameter arr +# 5| 1: [LocalVariableAccess] access to local variable length +# 6| 1: [FixedStmt] fixed(...) { ... } +# 6| -1: [LocalVariableDeclAndInitExpr] Int32* b = ... +# 6| 0: [CastExpr] (...) ... +# 6| 0: [ParameterAccess] access to parameter arr +# 6| 1: [LocalVariableAccess] access to local variable b +# 7| 0: [BlockStmt] {...} +# 8| 0: [LocalVariableDeclStmt] ... ...; +# 8| 0: [LocalVariableDeclAndInitExpr] Int32* p = ... +# 8| 0: [LocalVariableAccess] access to local variable b +# 8| 1: [LocalVariableAccess] access to local variable p +# 9| 1: [ForStmt] for (...;...;...) ... +# 9| -1: [LocalVariableDeclAndInitExpr] Int32 i = ... +# 9| 0: [IntLiteral] 0 +# 9| 1: [LocalVariableAccess] access to local variable i +# 9| 0: [LTExpr] ... < ... +# 9| 0: [LocalVariableAccess] access to local variable i +# 9| 1: [LocalVariableAccess] access to local variable length +# 9| 1: [PostIncrExpr] ...++ +# 9| 0: [LocalVariableAccess] access to local variable i +# 10| 2: [ExprStmt] ...; +# 10| 0: [AssignAddExpr] ... += ... +# 10| 0: [IntLiteral] 1 +# 10| 1: [PointerIndirectionExpr] *... +# 10| 0: [PostIncrExpr] ...++ +# 10| 0: [LocalVariableAccess] access to local variable p +# 14| 6: [Class] MyClass +# 16| 5: [Field] fld1 +# 17| 6: [Field] fld2 +# 20| 7: [Struct] MyStruct +# 22| 5: [Field] fld +# 25| 8: [Method] Main +# 25| 4: [BlockStmt] {...} +# 26| 0: [LocalVariableDeclStmt] ... ...; +# 26| 0: [LocalVariableDeclAndInitExpr] MyClass o = ... +# 26| 0: [ObjectCreation] object creation of type MyClass +# 26| 1: [LocalVariableAccess] access to local variable o +# 27| 1: [LocalVariableDeclStmt] ... ...; +# 27| 0: [LocalVariableDeclAndInitExpr] MyStruct s = ... +# 27| 0: [ObjectCreation] object creation of type MyStruct +# 27| 1: [LocalVariableAccess] access to local variable s +# 28| 2: [UnsafeStmt] unsafe {...} +# 29| 0: [BlockStmt] {...} +# 30| 0: [FixedStmt] fixed(...) { ... } +# 30| -2: [LocalVariableDeclAndInitExpr] Int32* q = ... +# 30| 0: [AddressOfExpr] &... +# 30| 0: [FieldAccess] access to field fld2 +# 30| -1: [LocalVariableAccess] access to local variable o +# 30| 1: [LocalVariableAccess] access to local variable q +# 30| -1: [LocalVariableDeclAndInitExpr] Int32* p = ... +# 30| 0: [AddressOfExpr] &... +# 30| 0: [FieldAccess] access to field fld1 +# 30| -1: [LocalVariableAccess] access to local variable o +# 30| 1: [LocalVariableAccess] access to local variable p +# 31| 0: [BlockStmt] {...} +# 32| 0: [ExprStmt] ...; +# 32| 0: [AssignExpr] ... = ... +# 32| 0: [IntLiteral] 0 +# 32| 1: [PointerIndirectionExpr] *... +# 32| 0: [LocalVariableAccess] access to local variable p +# 33| 1: [ExprStmt] ...; +# 33| 0: [AssignExpr] ... = ... +# 33| 0: [IntLiteral] 0 +# 33| 1: [PointerIndirectionExpr] *... +# 33| 0: [LocalVariableAccess] access to local variable q +# 34| 2: [LocalVariableDeclStmt] ... ...; +# 34| 0: [LocalVariableDeclAndInitExpr] MyStruct* r = ... +# 34| 0: [AddressOfExpr] &... +# 34| 0: [LocalVariableAccess] access to local variable s +# 34| 1: [LocalVariableAccess] access to local variable r +# 35| 3: [ExprStmt] ...; +# 35| 0: [AssignExpr] ... = ... +# 35| 0: [IntLiteral] 0 +# 35| 1: [FieldAccess] access to field fld +# 35| -1: [PointerIndirectionExpr] *... +# 35| 0: [LocalVariableAccess] access to local variable r +# 39| 3: [LocalVariableDeclStmt] ... ...; +# 39| 0: [LocalVariableDeclAndInitExpr] Int32[] arr = ... +# 39| 0: [ArrayCreation] array creation of type Int32[] +# 39| -1: [ArrayInitializer] { ..., ... } +# 39| 0: [IntLiteral] 1 +# 39| 1: [IntLiteral] 2 +# 39| 2: [IntLiteral] 3 +# 39| 1: [LocalVariableAccess] access to local variable arr +# 40| 4: [ExprStmt] ...; +# 40| 0: [MethodCall] call to method addone +# 40| 0: [LocalVariableAccess] access to local variable arr +prop.cs: +# 1| [Class] PropClass +# 3| 5: [Field] prop +# 5| 6: [Property] Prop +# 7| 3: [Getter] get_Prop +# 8| 4: [BlockStmt] {...} +# 9| 0: [ReturnStmt] return ...; +# 9| 0: [MethodCall] call to method func +# 12| 4: [Setter] set_Prop +#-----| 2: (Parameters) +# 12| 0: [Parameter] value +# 13| 4: [BlockStmt] {...} +# 14| 0: [ExprStmt] ...; +# 14| 0: [AssignExpr] ... = ... +# 14| 0: [ParameterAccess] access to parameter value +# 14| 1: [FieldAccess] access to field prop +# 18| 7: [Method] func +# 19| 4: [BlockStmt] {...} +# 20| 0: [ReturnStmt] return ...; +# 20| 0: [IntLiteral] 0 +# 24| [Class] Prog +# 26| 5: [Method] Main +# 27| 4: [BlockStmt] {...} +# 28| 0: [LocalVariableDeclStmt] ... ...; +# 28| 0: [LocalVariableDeclAndInitExpr] PropClass obj = ... +# 28| 0: [ObjectCreation] object creation of type PropClass +# 28| 1: [LocalVariableAccess] access to local variable obj +# 29| 1: [ExprStmt] ...; +# 29| 0: [AssignExpr] ... = ... +# 29| 0: [IntLiteral] 5 +# 29| 1: [PropertyCall] access to property Prop +# 29| -1: [LocalVariableAccess] access to local variable obj +# 30| 2: [LocalVariableDeclStmt] ... ...; +# 30| 0: [LocalVariableDeclAndInitExpr] Int32 x = ... +# 30| 0: [PropertyCall] access to property Prop +# 30| -1: [LocalVariableAccess] access to local variable obj +# 30| 1: [LocalVariableAccess] access to local variable x +simple_call.cs: +# 3| [Class] test_simple_call +# 5| 5: [Method] f +# 6| 4: [BlockStmt] {...} +# 7| 0: [ReturnStmt] return ...; +# 7| 0: [IntLiteral] 0 +# 10| 6: [Method] g +# 11| 4: [BlockStmt] {...} +# 12| 0: [ReturnStmt] return ...; +# 12| 0: [MethodCall] call to method f +simple_function.cs: +# 3| [Class] test_simple_function +# 5| 5: [Method] f +# 6| 4: [BlockStmt] {...} +# 7| 0: [ReturnStmt] return ...; +# 7| 0: [IntLiteral] 0 +stmts.cs: +# 3| [Class] test_stmts +# 5| 5: [Method] ifStmt +#-----| 2: (Parameters) +# 5| 0: [Parameter] x +# 6| 4: [BlockStmt] {...} +# 7| 0: [IfStmt] if (...) ... +# 7| 0: [EQExpr] ... == ... +# 7| 0: [ParameterAccess] access to parameter x +# 7| 1: [IntLiteral] 5 +# 8| 1: [ReturnStmt] return ...; +# 8| 0: [IntLiteral] 0 +# 10| 2: [ReturnStmt] return ...; +# 10| 0: [IntLiteral] 1 +# 13| 6: [Method] whileStmt +#-----| 2: (Parameters) +# 13| 0: [Parameter] x +# 14| 4: [BlockStmt] {...} +# 15| 0: [LocalVariableDeclStmt] ... ...; +# 15| 0: [LocalVariableDeclAndInitExpr] Int32 i = ... +# 15| 0: [IntLiteral] 0 +# 15| 1: [LocalVariableAccess] access to local variable i +# 16| 1: [WhileStmt] while (...) ... +# 16| 0: [LTExpr] ... < ... +# 16| 0: [LocalVariableAccess] access to local variable i +# 16| 1: [IntLiteral] 10 +# 17| 1: [BlockStmt] {...} +# 18| 0: [ExprStmt] ...; +# 18| 0: [AssignExpr] ... = ... +# 18| 0: [AddExpr] ... + ... +# 18| 0: [ParameterAccess] access to parameter x +# 18| 1: [IntLiteral] 1 +# 18| 1: [ParameterAccess] access to parameter x +# 22| 7: [Method] switchStmt +# 23| 4: [BlockStmt] {...} +# 24| 0: [LocalVariableDeclStmt] ... ...; +# 24| 0: [LocalVariableDeclAndInitExpr] Object caseSwitch = ... +# 24| 0: [ObjectCreation] object creation of type Object +# 24| 1: [LocalVariableAccess] access to local variable caseSwitch +# 25| 1: [LocalVariableDeclStmt] ... ...; +# 25| 0: [LocalVariableDeclAndInitExpr] Int32 select = ... +# 25| 0: [IntLiteral] 0 +# 25| 1: [LocalVariableAccess] access to local variable select +# 27| 2: [SwitchStmt] switch (...) {...} +# 27| 0: [LocalVariableAccess] access to local variable caseSwitch +# 29| 0: [ConstCase] case ...: +# 29| 0: [ConstantPatternExpr,UnaryMinusExpr] -... +# 29| 0: [IntLiteral] 1 +# 30| 1: [GotoCaseStmt] goto case ...; +# 30| 0: [BoolLiteral] true +# 31| 2: [ConstCase] case ...: +# 31| 0: [ConstantPatternExpr,IntLiteral] 0 +# 32| 3: [GotoCaseStmt] goto case ...; +# 32| 0: [StringLiteral] "123" +# 33| 4: [ConstCase] case ...: +# 33| 0: [ConstantPatternExpr,StringLiteral] "123" +# 34| 5: [ExprStmt] ...; +# 34| 0: [AssignExpr] ... = ... +# 34| 0: [IntLiteral] 100 +# 34| 1: [LocalVariableAccess] access to local variable select +# 35| 6: [BreakStmt] break; +# 36| 7: [ConstCase] case ...: +# 36| 0: [BoolLiteral,ConstantPatternExpr] true +# 37| 8: [ExprStmt] ...; +# 37| 0: [AssignExpr] ... = ... +# 37| 0: [IntLiteral] 101 +# 37| 1: [LocalVariableAccess] access to local variable select +# 38| 9: [GotoDefaultStmt] goto default; +# 39| 10: [DefaultCase] default: +# 40| 11: [ReturnStmt] return ...; +# 40| 0: [LocalVariableAccess] access to local variable select +# 42| 3: [ReturnStmt] return ...; +# 42| 0: [IntLiteral] 0 +# 46| 8: [Method] tryCatchFinally +# 47| 4: [BlockStmt] {...} +# 48| 0: [LocalVariableDeclStmt] ... ...; +# 48| 0: [LocalVariableDeclAndInitExpr] Int32 x = ... +# 48| 0: [IntLiteral] 5 +# 48| 1: [LocalVariableAccess] access to local variable x +# 49| 1: [TryStmt] try {...} ... +# 64| -1: [BlockStmt] {...} +# 65| 0: [ExprStmt] ...; +# 65| 0: [AssignExpr] ... = ... +# 65| 0: [IntLiteral] 2 +# 65| 1: [LocalVariableAccess] access to local variable x +# 50| 0: [BlockStmt] {...} +# 51| 0: [IfStmt] if (...) ... +# 51| 0: [NEExpr] ... != ... +# 51| 0: [LocalVariableAccess] access to local variable x +# 51| 1: [IntLiteral] 0 +# 52| 1: [ThrowStmt] throw ...; +# 52| 0: [ObjectCreation] object creation of type Exception +# 53| 1: [ExprStmt] ...; +# 53| 0: [AssignExpr] ... = ... +# 53| 0: [IntLiteral] 0 +# 53| 1: [LocalVariableAccess] access to local variable x +# 55| 1: [SpecificCatchClause] catch (...) {...} +# 55| 0: [LocalVariableDeclExpr] Exception ex +# 56| 1: [BlockStmt] {...} +# 57| 0: [ExprStmt] ...; +# 57| 0: [AssignExpr] ... = ... +# 57| 0: [IntLiteral] 1 +# 57| 1: [LocalVariableAccess] access to local variable x +# 59| 2: [GeneralCatchClause] catch {...} +# 60| 1: [BlockStmt] {...} +# 61| 0: [ThrowStmt] throw ...; +# 69| 9: [Method] forStmt +# 70| 4: [BlockStmt] {...} +# 71| 0: [LocalVariableDeclStmt] ... ...; +# 71| 0: [LocalVariableDeclAndInitExpr] Int32 x = ... +# 71| 0: [IntLiteral] 0 +# 71| 1: [LocalVariableAccess] access to local variable x +# 72| 1: [ForStmt] for (...;...;...) ... +# 72| -2: [LocalVariableDeclAndInitExpr] Int32 j = ... +# 72| 0: [IntLiteral] 10 +# 72| 1: [LocalVariableAccess] access to local variable j +# 72| -1: [LocalVariableDeclAndInitExpr] Int32 i = ... +# 72| 0: [IntLiteral] 0 +# 72| 1: [LocalVariableAccess] access to local variable i +# 72| 0: [LTExpr] ... < ... +# 72| 0: [LocalVariableAccess] access to local variable i +# 72| 1: [LocalVariableAccess] access to local variable j +# 72| 1: [PostIncrExpr] ...++ +# 72| 0: [LocalVariableAccess] access to local variable i +# 72| 2: [PostDecrExpr] ...-- +# 72| 0: [LocalVariableAccess] access to local variable j +# 73| 3: [BlockStmt] {...} +# 74| 0: [ExprStmt] ...; +# 74| 0: [AssignExpr] ... = ... +# 74| 0: [SubExpr] ... - ... +# 74| 0: [LocalVariableAccess] access to local variable x +# 74| 1: [IntLiteral] 1 +# 74| 1: [LocalVariableAccess] access to local variable x +# 77| 2: [LocalVariableDeclStmt] ... ...; +# 77| 0: [LocalVariableDeclExpr] Int32 a +# 77| 1: [LocalVariableDeclAndInitExpr] Int32 b = ... +# 77| 0: [IntLiteral] 10 +# 77| 1: [LocalVariableAccess] access to local variable b +# 78| 3: [ForStmt] for (...;...;...) ... +# 78| -1: [AssignExpr] ... = ... +# 78| 0: [IntLiteral] 0 +# 78| 1: [LocalVariableAccess] access to local variable a +# 78| 0: [LTExpr] ... < ... +# 78| 0: [LocalVariableAccess] access to local variable a +# 78| 1: [LocalVariableAccess] access to local variable b +# 79| 1: [BlockStmt] {...} +# 80| 0: [ExprStmt] ...; +# 80| 0: [PostIncrExpr] ...++ +# 80| 0: [LocalVariableAccess] access to local variable a +# 83| 4: [ForStmt] for (...;...;...) ... +# 84| 1: [BlockStmt] {...} +# 89| 10: [Method] doWhile +# 90| 4: [BlockStmt] {...} +# 91| 0: [LocalVariableDeclStmt] ... ...; +# 91| 0: [LocalVariableDeclAndInitExpr] Int32 x = ... +# 91| 0: [IntLiteral] 0 +# 91| 1: [LocalVariableAccess] access to local variable x +# 92| 1: [DoStmt] do ... while (...); +# 96| 0: [LTExpr] ... < ... +# 96| 0: [LocalVariableAccess] access to local variable x +# 96| 1: [IntLiteral] 10 +# 93| 1: [BlockStmt] {...} +# 94| 0: [ExprStmt] ...; +# 94| 0: [AssignExpr] ... = ... +# 94| 0: [AddExpr] ... + ... +# 94| 0: [LocalVariableAccess] access to local variable x +# 94| 1: [IntLiteral] 1 +# 94| 1: [LocalVariableAccess] access to local variable x +# 99| 11: [Method] checkedUnchecked +# 100| 4: [BlockStmt] {...} +# 101| 0: [LocalVariableDeclStmt] ... ...; +# 101| 0: [LocalVariableDeclAndInitExpr] Int32 num = ... +# 101| 0: [MemberConstantAccess] access to constant MaxValue +# 101| -1: [TypeAccess] access to type Int32 +# 101| 1: [LocalVariableAccess] access to local variable num +# 102| 1: [UncheckedStmt] unchecked {...} +# 103| 0: [BlockStmt] {...} +# 104| 0: [ExprStmt] ...; +# 104| 0: [AssignExpr] ... = ... +# 104| 0: [AddExpr] ... + ... +# 104| 0: [LocalVariableAccess] access to local variable num +# 104| 1: [IntLiteral] 1 +# 104| 1: [LocalVariableAccess] access to local variable num +# 106| 2: [CheckedStmt] checked {...} +# 107| 0: [BlockStmt] {...} +# 108| 0: [ExprStmt] ...; +# 108| 0: [AssignExpr] ... = ... +# 108| 0: [AddExpr] ... + ... +# 108| 0: [LocalVariableAccess] access to local variable num +# 108| 1: [IntLiteral] 1 +# 108| 1: [LocalVariableAccess] access to local variable num +using.cs: +# 3| [Class] UsingStmt +# 5| 5: [Class] MyDisposable +#-----| 3: (Base types) +# 5| 1: [Interface] IDisposable +# 7| 4: [InstanceConstructor] MyDisposable +# 7| 4: [BlockStmt] {...} +# 8| 5: [Method] DoSomething +# 8| 4: [BlockStmt] {...} +# 9| 6: [Method] Dispose +# 9| 4: [BlockStmt] {...} +# 12| 6: [Method] Main +# 13| 4: [BlockStmt] {...} +# 14| 0: [UsingBlockStmt] using (...) {...} +# 14| -1: [LocalVariableDeclAndInitExpr] MyDisposable o1 = ... +# 14| 0: [ObjectCreation] object creation of type MyDisposable +# 14| 1: [LocalVariableAccess] access to local variable o1 +# 15| 1: [BlockStmt] {...} +# 16| 0: [ExprStmt] ...; +# 16| 0: [MethodCall] call to method DoSomething +# 16| -1: [LocalVariableAccess] access to local variable o1 +# 19| 1: [LocalVariableDeclStmt] ... ...; +# 19| 0: [LocalVariableDeclAndInitExpr] MyDisposable o2 = ... +# 19| 0: [ObjectCreation] object creation of type MyDisposable +# 19| 1: [LocalVariableAccess] access to local variable o2 +# 20| 2: [UsingBlockStmt] using (...) {...} +# 20| 0: [LocalVariableAccess] access to local variable o2 +# 21| 1: [BlockStmt] {...} +# 22| 0: [ExprStmt] ...; +# 22| 0: [MethodCall] call to method DoSomething +# 22| -1: [LocalVariableAccess] access to local variable o2 +# 25| 3: [UsingDeclStmt] using ... ...; +# 25| 0: [LocalVariableDeclAndInitExpr] MyDisposable o3 = ... +# 25| 0: [ObjectCreation] object creation of type MyDisposable +# 25| 1: [LocalVariableAccess] access to local variable o3 +# 26| 4: [ExprStmt] ...; +# 26| 0: [MethodCall] call to method DoSomething +# 26| -1: [LocalVariableAccess] access to local variable o3 +variables.cs: +# 3| [Class] test_variables +# 5| 5: [Method] f +# 6| 4: [BlockStmt] {...} +# 7| 0: [LocalVariableDeclStmt] ... ...; +# 7| 0: [LocalVariableDeclExpr] Int32 x +# 7| 1: [LocalVariableDeclAndInitExpr] Int32 y = ... +# 7| 0: [IntLiteral] 5 +# 7| 1: [LocalVariableAccess] access to local variable y +# 8| 1: [ExprStmt] ...; +# 8| 0: [AssignExpr] ... = ... +# 8| 0: [IntLiteral] 4 +# 8| 1: [LocalVariableAccess] access to local variable x +# 9| 2: [ExprStmt] ...; +# 9| 0: [AssignExpr] ... = ... +# 9| 0: [LocalVariableAccess] access to local variable y +# 9| 1: [LocalVariableAccess] access to local variable x +# 10| 3: [LocalVariableDeclStmt] ... ...; +# 10| 0: [LocalVariableDeclAndInitExpr] Int32 z = ... +# 10| 0: [LocalVariableAccess] access to local variable y +# 10| 1: [LocalVariableAccess] access to local variable z diff --git a/csharp/ql/test/experimental/ir/ir/PrintAst.qlref b/csharp/ql/test/experimental/ir/ir/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/experimental/ir/ir/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/ir/ir/array.cs b/csharp/ql/test/experimental/ir/ir/array.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/array.cs rename to csharp/ql/test/experimental/ir/ir/array.cs diff --git a/csharp/ql/test/library-tests/ir/ir/assignop.cs b/csharp/ql/test/experimental/ir/ir/assignop.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/assignop.cs rename to csharp/ql/test/experimental/ir/ir/assignop.cs diff --git a/csharp/ql/test/library-tests/ir/ir/casts.cs b/csharp/ql/test/experimental/ir/ir/casts.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/casts.cs rename to csharp/ql/test/experimental/ir/ir/casts.cs diff --git a/csharp/ql/test/library-tests/ir/ir/collections.cs b/csharp/ql/test/experimental/ir/ir/collections.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/collections.cs rename to csharp/ql/test/experimental/ir/ir/collections.cs diff --git a/csharp/ql/test/library-tests/ir/ir/constructor_init.cs b/csharp/ql/test/experimental/ir/ir/constructor_init.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/constructor_init.cs rename to csharp/ql/test/experimental/ir/ir/constructor_init.cs diff --git a/csharp/ql/test/library-tests/ir/ir/crement.cs b/csharp/ql/test/experimental/ir/ir/crement.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/crement.cs rename to csharp/ql/test/experimental/ir/ir/crement.cs diff --git a/csharp/ql/test/library-tests/ir/ir/delegates.cs b/csharp/ql/test/experimental/ir/ir/delegates.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/delegates.cs rename to csharp/ql/test/experimental/ir/ir/delegates.cs diff --git a/csharp/ql/test/library-tests/ir/ir/events.cs b/csharp/ql/test/experimental/ir/ir/events.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/events.cs rename to csharp/ql/test/experimental/ir/ir/events.cs diff --git a/csharp/ql/test/library-tests/ir/ir/foreach.cs b/csharp/ql/test/experimental/ir/ir/foreach.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/foreach.cs rename to csharp/ql/test/experimental/ir/ir/foreach.cs diff --git a/csharp/ql/test/library-tests/ir/ir/func_with_param_call.cs b/csharp/ql/test/experimental/ir/ir/func_with_param_call.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/func_with_param_call.cs rename to csharp/ql/test/experimental/ir/ir/func_with_param_call.cs diff --git a/csharp/ql/test/library-tests/ir/ir/indexers.cs b/csharp/ql/test/experimental/ir/ir/indexers.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/indexers.cs rename to csharp/ql/test/experimental/ir/ir/indexers.cs diff --git a/csharp/ql/test/library-tests/ir/ir/inheritance_polymorphism.cs b/csharp/ql/test/experimental/ir/ir/inheritance_polymorphism.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/inheritance_polymorphism.cs rename to csharp/ql/test/experimental/ir/ir/inheritance_polymorphism.cs diff --git a/csharp/ql/test/library-tests/ir/ir/inoutref.cs b/csharp/ql/test/experimental/ir/ir/inoutref.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/inoutref.cs rename to csharp/ql/test/experimental/ir/ir/inoutref.cs diff --git a/csharp/ql/test/library-tests/ir/ir/isexpr.cs b/csharp/ql/test/experimental/ir/ir/isexpr.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/isexpr.cs rename to csharp/ql/test/experimental/ir/ir/isexpr.cs diff --git a/csharp/ql/test/library-tests/ir/ir/jumps.cs b/csharp/ql/test/experimental/ir/ir/jumps.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/jumps.cs rename to csharp/ql/test/experimental/ir/ir/jumps.cs diff --git a/csharp/ql/test/library-tests/ir/ir/lock.cs b/csharp/ql/test/experimental/ir/ir/lock.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/lock.cs rename to csharp/ql/test/experimental/ir/ir/lock.cs diff --git a/csharp/ql/test/library-tests/ir/ir/obj_creation.cs b/csharp/ql/test/experimental/ir/ir/obj_creation.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/obj_creation.cs rename to csharp/ql/test/experimental/ir/ir/obj_creation.cs diff --git a/csharp/ql/test/library-tests/ir/ir/pointers.cs b/csharp/ql/test/experimental/ir/ir/pointers.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/pointers.cs rename to csharp/ql/test/experimental/ir/ir/pointers.cs diff --git a/csharp/ql/test/library-tests/ir/ir/prop.cs b/csharp/ql/test/experimental/ir/ir/prop.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/prop.cs rename to csharp/ql/test/experimental/ir/ir/prop.cs diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected b/csharp/ql/test/experimental/ir/ir/raw_ir.expected similarity index 99% rename from csharp/ql/test/library-tests/ir/ir/raw_ir.expected rename to csharp/ql/test/experimental/ir/ir/raw_ir.expected index 785f38727876..e426955f9da3 100644 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/csharp/ql/test/experimental/ir/ir/raw_ir.expected @@ -1327,8 +1327,8 @@ pointers.cs: # 6| r6_1(glval) = VariableAddress[b] : # 6| r6_2(glval) = VariableAddress[arr] : # 6| r6_3(Int32[]) = Load : &:r6_2, ~m? -# 6| r6_4(Int32*) = Convert : r6_3 -# 6| mu6_5(Int32*) = Store : &:r6_1, r6_3 +# 6| r6_4(Int32*) = CheckedConvertOrThrow : r6_3 +# 6| mu6_5(Int32*) = Store : &:r6_1, r6_4 # 8| r8_1(glval) = VariableAddress[p] : # 8| r8_2(glval) = VariableAddress[b] : # 8| r8_3(Int32*) = Load : &:r8_2, ~m? diff --git a/csharp/ql/test/experimental/ir/ir/raw_ir.qlref b/csharp/ql/test/experimental/ir/ir/raw_ir.qlref new file mode 100644 index 000000000000..336afc397f56 --- /dev/null +++ b/csharp/ql/test/experimental/ir/ir/raw_ir.qlref @@ -0,0 +1 @@ +experimental/ir/implementation/raw/PrintIR.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir_consistency.expected b/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.expected similarity index 95% rename from csharp/ql/test/library-tests/ir/ir/raw_ir_consistency.expected rename to csharp/ql/test/experimental/ir/ir/raw_ir_consistency.expected index 61bc9b2261c1..5d16b01eaca5 100644 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir_consistency.expected +++ b/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.expected @@ -20,6 +20,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.qlref b/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.qlref new file mode 100644 index 000000000000..3059c9b7b77b --- /dev/null +++ b/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.qlref @@ -0,0 +1 @@ +experimental/ir/implementation/raw/IRConsistency.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/ir/ir/simple_call.cs b/csharp/ql/test/experimental/ir/ir/simple_call.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/simple_call.cs rename to csharp/ql/test/experimental/ir/ir/simple_call.cs diff --git a/csharp/ql/test/library-tests/ir/ir/simple_function.cs b/csharp/ql/test/experimental/ir/ir/simple_function.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/simple_function.cs rename to csharp/ql/test/experimental/ir/ir/simple_function.cs diff --git a/csharp/ql/test/library-tests/ir/ir/stmts.cs b/csharp/ql/test/experimental/ir/ir/stmts.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/stmts.cs rename to csharp/ql/test/experimental/ir/ir/stmts.cs diff --git a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.expected similarity index 95% rename from csharp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected rename to csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.expected index 61bc9b2261c1..5d16b01eaca5 100644 --- a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected +++ b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.expected @@ -20,6 +20,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.qlref b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.qlref new file mode 100644 index 000000000000..65c394825298 --- /dev/null +++ b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.qlref @@ -0,0 +1 @@ +experimental/ir/implementation/unaliased_ssa/IRConsistency.ql diff --git a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.expected b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.expected similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.expected rename to csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.expected diff --git a/csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.qlref b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.qlref new file mode 100644 index 000000000000..8d24936eceab --- /dev/null +++ b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.qlref @@ -0,0 +1 @@ +experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/ir/ir/using.cs b/csharp/ql/test/experimental/ir/ir/using.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/using.cs rename to csharp/ql/test/experimental/ir/ir/using.cs diff --git a/csharp/ql/test/library-tests/ir/ir/variables.cs b/csharp/ql/test/experimental/ir/ir/variables.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/variables.cs rename to csharp/ql/test/experimental/ir/ir/variables.cs diff --git a/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.expected b/csharp/ql/test/experimental/ir/offbyone/OffByOneRA.expected similarity index 100% rename from csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.expected rename to csharp/ql/test/experimental/ir/offbyone/OffByOneRA.expected diff --git a/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.ql b/csharp/ql/test/experimental/ir/offbyone/OffByOneRA.ql similarity index 91% rename from csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.ql rename to csharp/ql/test/experimental/ir/offbyone/OffByOneRA.ql index 16ba1c861a19..7518386e6d21 100644 --- a/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.ql +++ b/csharp/ql/test/experimental/ir/offbyone/OffByOneRA.ql @@ -1,7 +1,7 @@ import csharp -import semmle.code.csharp.ir.IR -import semmle.code.csharp.ir.rangeanalysis.RangeAnalysis -import semmle.code.csharp.ir.rangeanalysis.RangeUtils +import experimental.ir.IR +import experimental.ir.rangeanalysis.RangeAnalysis +import experimental.ir.rangeanalysis.RangeUtils /** * Holds if the index expression of `aa` is less than or equal to the array length plus `k`. diff --git a/csharp/ql/test/library-tests/ir/offbyone/null.cs b/csharp/ql/test/experimental/ir/offbyone/null.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/offbyone/null.cs rename to csharp/ql/test/experimental/ir/offbyone/null.cs diff --git a/csharp/ql/test/library-tests/ir/offbyone/test.cs b/csharp/ql/test/experimental/ir/offbyone/test.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/offbyone/test.cs rename to csharp/ql/test/experimental/ir/offbyone/test.cs diff --git a/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.expected b/csharp/ql/test/experimental/ir/rangeanalysis/RangeAnalysis.expected similarity index 100% rename from csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.expected rename to csharp/ql/test/experimental/ir/rangeanalysis/RangeAnalysis.expected diff --git a/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.ql b/csharp/ql/test/experimental/ir/rangeanalysis/RangeAnalysis.ql similarity index 79% rename from csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.ql rename to csharp/ql/test/experimental/ir/rangeanalysis/RangeAnalysis.ql index 0eed018495ad..ab62db5e5ffc 100644 --- a/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.ql +++ b/csharp/ql/test/experimental/ir/rangeanalysis/RangeAnalysis.ql @@ -1,7 +1,7 @@ -import semmle.code.csharp.ir.rangeanalysis.RangeAnalysis -import semmle.code.csharp.ir.IR -import semmle.code.csharp.ir.internal.IRGuards -import semmle.code.csharp.ir.ValueNumbering +import experimental.ir.rangeanalysis.RangeAnalysis +import experimental.ir.IR +import experimental.ir.internal.IRGuards +import experimental.ir.ValueNumbering query predicate instructionBounds( Instruction i, Bound b, int delta, boolean upper, Reason reason, Location reasonLoc diff --git a/csharp/ql/test/library-tests/ir/rangeanalysis/null.cs b/csharp/ql/test/experimental/ir/rangeanalysis/null.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/rangeanalysis/null.cs rename to csharp/ql/test/experimental/ir/rangeanalysis/null.cs diff --git a/csharp/ql/test/library-tests/ir/rangeanalysis/test.cs b/csharp/ql/test/experimental/ir/rangeanalysis/test.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/rangeanalysis/test.cs rename to csharp/ql/test/experimental/ir/rangeanalysis/test.cs diff --git a/csharp/ql/test/library-tests/aliases/aliases1.expected b/csharp/ql/test/library-tests/aliases/aliases1.expected index f6289f38f51c..9417df43012e 100644 --- a/csharp/ql/test/library-tests/aliases/aliases1.expected +++ b/csharp/ql/test/library-tests/aliases/aliases1.expected @@ -1,3 +1 @@ -| Assembly1.dll:0:0:0:0 | Class | -| Assembly2.dll:0:0:0:0 | Class | | Program.cs:10:7:10:11 | Class | diff --git a/csharp/ql/test/library-tests/aliases/aliases2.expected b/csharp/ql/test/library-tests/aliases/aliases2.expected index 45870c5dda24..50cfbf37f1ed 100644 --- a/csharp/ql/test/library-tests/aliases/aliases2.expected +++ b/csharp/ql/test/library-tests/aliases/aliases2.expected @@ -1,3 +1,3 @@ -| Program.cs:18:21:18:22 | c1 | Assembly1.dll:0:0:0:0 | Class | -| Program.cs:19:21:19:22 | c2 | Assembly2.dll:0:0:0:0 | Class | +| Program.cs:18:21:18:22 | c1 | Program.cs:10:7:10:11 | Class | +| Program.cs:19:21:19:22 | c2 | Program.cs:10:7:10:11 | Class | | Program.cs:20:15:20:16 | c3 | Program.cs:10:7:10:11 | Class | diff --git a/csharp/ql/test/library-tests/arguments/PrintAst.expected b/csharp/ql/test/library-tests/arguments/PrintAst.expected new file mode 100644 index 000000000000..528cfa5ca3e9 --- /dev/null +++ b/csharp/ql/test/library-tests/arguments/PrintAst.expected @@ -0,0 +1,211 @@ +arguments.cs: +# 3| [Class] ArgumentsTest +# 5| 4: [InstanceConstructor] ArgumentsTest +#-----| 2: (Parameters) +# 5| 0: [Parameter] x +# 5| 1: [IntLiteral] 0 +# 5| 1: [Parameter] y +# 5| 1: [IntLiteral] 0 +# 6| 4: [BlockStmt] {...} +# 9| 5: [InstanceConstructor] ArgumentsTest +#-----| 2: (Parameters) +# 9| 0: [Parameter] x +# 9| 1: [Parameter] y +# 9| 2: [Parameter] z +# 10| 4: [BlockStmt] {...} +# 11| 0: [ExprStmt] ...; +# 11| 0: [AssignExpr] ... = ... +# 11| 0: [ParameterAccess] access to parameter x +# 11| 1: [ParameterAccess] access to parameter y +# 14| 6: [Method] f1 +#-----| 2: (Parameters) +# 14| 0: [Parameter] x +# 14| 1: [IntLiteral] 1 +# 14| 1: [Parameter] y +# 14| 1: [IntLiteral] 2 +# 15| 4: [BlockStmt] {...} +# 18| 7: [Method] f2 +#-----| 2: (Parameters) +# 18| 0: [Parameter] x +# 18| 1: [Parameter] y +# 18| 2: [Parameter] z +# 19| 4: [BlockStmt] {...} +# 20| 0: [ExprStmt] ...; +# 20| 0: [AssignExpr] ... = ... +# 20| 0: [ParameterAccess] access to parameter x +# 20| 1: [ParameterAccess] access to parameter y +# 23| 8: [Method] f +# 24| 4: [BlockStmt] {...} +# 25| 0: [LocalVariableDeclStmt] ... ...; +# 25| 0: [LocalVariableDeclAndInitExpr] Int32 x = ... +# 25| 0: [IntLiteral] 1 +# 25| 1: [LocalVariableAccess] access to local variable x +# 27| 1: [ExprStmt] ...; +# 27| 0: [MethodCall] call to method f1 +# 27| 0: [IntLiteral] 2 +# 28| 2: [ExprStmt] ...; +# 28| 0: [MethodCall] call to method f2 +# 28| 0: [LocalVariableAccess] access to local variable x +# 28| 1: [LocalVariableAccess] access to local variable x +# 28| 2: [LocalVariableAccess] access to local variable x +# 29| 3: [ExprStmt] ...; +# 29| 0: [ObjectCreation] object creation of type ArgumentsTest +# 29| 0: [LocalVariableAccess] access to local variable x +# 29| 1: [LocalVariableAccess] access to local variable x +# 29| 2: [LocalVariableAccess] access to local variable x +# 30| 4: [ExprStmt] ...; +# 30| 0: [ObjectCreation] object creation of type ArgumentsTest +# 30| 0: [IntLiteral] 10 +# 30| 1: [IntLiteral] 5 +# 33| 9: [Method] f3 +#-----| 2: (Parameters) +# 33| 0: [Parameter] o +# 33| 1: [Parameter] args +# 34| 4: [BlockStmt] {...} +# 35| 0: [ExprStmt] ...; +# 35| 0: [MethodCall] call to method f3 +# 35| 0: [IntLiteral] 0 +# 35| 1: [IntLiteral] 1 +# 35| 2: [IntLiteral] 2 +# 36| 1: [ExprStmt] ...; +# 36| 0: [MethodCall] call to method f3 +# 36| 0: [IntLiteral] 0 +# 36| 1: [ArrayCreation] array creation of type Int32[] +# 36| -1: [ArrayInitializer] { ..., ... } +# 36| 0: [IntLiteral] 1 +# 36| 1: [IntLiteral] 2 +# 37| 2: [ExprStmt] ...; +# 37| 0: [MethodCall] call to method f3 +# 37| 0: [IntLiteral] 1 +# 37| 1: [IntLiteral] 0 +# 38| 3: [ExprStmt] ...; +# 38| 0: [MethodCall] call to method f3 +# 38| 0: [IntLiteral] 0 +# 38| 1: [ParameterAccess] access to parameter args +# 39| 4: [ExprStmt] ...; +# 39| 0: [MethodCall] call to method f3 +# 39| 0: [ParameterAccess] access to parameter args +# 39| 1: [IntLiteral] 0 +# 40| 5: [ExprStmt] ...; +# 40| 0: [MethodCall] call to method f3 +# 40| 0: [ArrayCreation] array creation of type Int32[] +# 40| -1: [ArrayInitializer] { ..., ... } +# 40| 0: [IntLiteral] 1 +# 40| 1: [IntLiteral] 2 +# 40| 1: [IntLiteral] 0 +# 43| 10: [Method] f4 +#-----| 2: (Parameters) +# 43| 0: [Parameter] args +# 44| 4: [BlockStmt] {...} +# 45| 0: [ExprStmt] ...; +# 45| 0: [MethodCall] call to method f4 +# 45| 0: [ArrayCreation] array creation of type Object[] +# 45| -1: [ArrayInitializer] { ..., ... } +# 45| 0: [NullLiteral] null +# 45| 1: [NullLiteral] null +# 48| 11: [Property] Prop +# 48| 3: [Getter] get_Prop +# 48| 4: [Setter] set_Prop +#-----| 2: (Parameters) +# 48| 0: [Parameter] value +# 50| 12: [Indexer] Item +#-----| 1: (Parameters) +# 50| 0: [Parameter] a +# 50| 1: [Parameter] b +# 50| 3: [Getter] get_Item +#-----| 2: (Parameters) +# 50| 0: [Parameter] a +# 50| 1: [Parameter] b +# 50| 4: [AddExpr] ... + ... +# 50| 0: [ParameterAccess] access to parameter a +# 50| 1: [ParameterAccess] access to parameter b +# 50| 4: [Setter] set_Item +#-----| 2: (Parameters) +# 50| 0: [Parameter] a +# 50| 1: [Parameter] b +# 50| 2: [Parameter] value +# 50| 4: [BlockStmt] {...} +# 52| 13: [Method] f5 +# 53| 4: [BlockStmt] {...} +# 54| 0: [ExprStmt] ...; +# 54| 0: [AssignExpr] ... = ... +# 54| 0: [IntLiteral] 0 +# 54| 1: [PropertyCall] access to property Prop +# 55| 1: [ExprStmt] ...; +# 55| 0: [AssignExpr] ... = ... +# 55| 0: [IndexerCall] access to indexer +# 55| -1: [ThisAccess] this access +# 55| 0: [IntLiteral] 1 +# 55| 1: [IntLiteral] 2 +# 55| 1: [PropertyCall] access to property Prop +# 56| 2: [ExprStmt] ...; +# 56| 0: [AssignExpr] ... = ... +# 56| 0: [TupleExpr] (..., ...) +# 56| 0: [IntLiteral] 5 +# 56| 1: [IntLiteral] 6 +# 56| 1: [TupleExpr] (..., ...) +# 56| 0: [PropertyCall] access to property Prop +# 56| 1: [IndexerCall] access to indexer +# 56| -1: [ThisAccess] this access +# 56| 0: [IntLiteral] 3 +# 56| 1: [IntLiteral] 4 +# 57| 3: [ExprStmt] ...; +# 57| 0: [PostIncrExpr] ...++ +# 57| 0: [PropertyCall] access to property Prop +# 58| 4: [ExprStmt] ...; +# 58| 0: [AssignAddExpr] ... += ... +# 58| 0: [IntLiteral] 7 +# 58| 1: [PropertyCall] access to property Prop +# 59| 5: [ExprStmt] ...; +# 59| 0: [PostIncrExpr] ...++ +# 59| 0: [IndexerCall] access to indexer +# 59| -1: [ThisAccess] this access +# 59| 0: [IntLiteral] 8 +# 59| 1: [IntLiteral] 9 +# 60| 6: [ExprStmt] ...; +# 60| 0: [AssignAddExpr] ... += ... +# 60| 0: [IntLiteral] 12 +# 60| 1: [IndexerCall] access to indexer +# 60| -1: [ThisAccess] this access +# 60| 0: [IntLiteral] 10 +# 60| 1: [IntLiteral] 11 +# 61| 7: [LocalVariableDeclStmt] ... ...; +# 61| 0: [LocalVariableDeclAndInitExpr] (Int32,Int32) tuple = ... +# 61| 0: [TupleExpr] (..., ...) +# 61| 0: [IntLiteral] 13 +# 61| 1: [IntLiteral] 14 +# 61| 1: [LocalVariableAccess] access to local variable tuple +# 62| 8: [ExprStmt] ...; +# 62| 0: [AssignExpr] ... = ... +# 62| 0: [LocalVariableAccess] access to local variable tuple +# 62| 1: [TupleExpr] (..., ...) +# 62| 0: [PropertyCall] access to property Prop +# 62| 1: [IndexerCall] access to indexer +# 62| -1: [ThisAccess] this access +# 62| 0: [IntLiteral] 15 +# 62| 1: [IntLiteral] 16 +# 66| 14: [Method] f6 +#-----| 0: (Attributes) +# 65| 1: [Attribute] [My(...)] +# 65| 0: [BoolLiteral] false +# 66| 4: [BlockStmt] {...} +# 69| 15: [Method] f7 +#-----| 0: (Attributes) +# 68| 1: [Attribute] [My(...)] +# 68| 0: [BoolLiteral] true +# 68| 1: [StringLiteral] "" +# 68| 2: [IntLiteral] 0 +# 69| 4: [BlockStmt] {...} +# 72| [Class] MyAttribute +#-----| 3: (Base types) +# 72| 0: [Class] Attribute +# 74| 4: [Field] x +# 75| 5: [IndexerProperty] y +# 75| 3: [Getter] get_y +# 75| 4: [Setter] set_y +#-----| 2: (Parameters) +# 75| 0: [Parameter] value +# 76| 6: [InstanceConstructor] MyAttribute +#-----| 2: (Parameters) +# 76| 0: [Parameter] b +# 76| 4: [BlockStmt] {...} diff --git a/csharp/ql/test/library-tests/arguments/PrintAst.qlref b/csharp/ql/test/library-tests/arguments/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/arguments/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/assignments/PrintAst.expected b/csharp/ql/test/library-tests/assignments/PrintAst.expected new file mode 100644 index 000000000000..d3353805cdb3 --- /dev/null +++ b/csharp/ql/test/library-tests/assignments/PrintAst.expected @@ -0,0 +1,55 @@ +Assignments.cs: +# 1| [Class] Assignments +# 3| 5: [Method] M +# 4| 4: [BlockStmt] {...} +# 5| 0: [LocalVariableDeclStmt] ... ...; +# 5| 0: [LocalVariableDeclAndInitExpr] Int32 x = ... +# 5| 0: [IntLiteral] 0 +# 5| 1: [LocalVariableAccess] access to local variable x +# 6| 1: [ExprStmt] ...; +# 6| 0: [AssignAddExpr] ... += ... +# 6| 0: [IntLiteral] 1 +# 6| 1: [LocalVariableAccess] access to local variable x +# 8| 2: [LocalVariableDeclStmt] ... ...; +# 8| 0: [LocalVariableDeclAndInitExpr] dynamic d = ... +# 8| 0: [CastExpr] (...) ... +# 8| 0: [IntLiteral] 0 +# 8| 1: [LocalVariableAccess] access to local variable d +# 9| 3: [ExprStmt] ...; +# 9| 0: [AssignSubExpr] ... -= ... +# 9| 0: [IntLiteral] 2 +# 9| 1: [LocalVariableAccess] access to local variable d +# 11| 4: [LocalVariableDeclStmt] ... ...; +# 11| 0: [LocalVariableDeclAndInitExpr] Assignments a = ... +# 11| 0: [ObjectCreation] object creation of type Assignments +# 11| 1: [LocalVariableAccess] access to local variable a +# 12| 5: [ExprStmt] ...; +# 12| 0: [AssignAddExpr] ... += ... +# 12| 0: [ThisAccess] this access +# 12| 1: [LocalVariableAccess] access to local variable a +# 14| 6: [ExprStmt] ...; +# 14| 0: [AddEventExpr] ... += ... +# 14| 0: [LambdaExpr] (...) => ... +#-----| 2: (Parameters) +# 14| 0: [Parameter] sender +# 14| 1: [Parameter] e +# 14| 4: [BlockStmt] {...} +# 14| 1: [EventAccess,EventCall] access to event Event +# 17| 6: [AddOperator] + +#-----| 2: (Parameters) +# 17| 0: [Parameter] x +# 17| 1: [Parameter] y +# 18| 4: [BlockStmt] {...} +# 19| 0: [ReturnStmt] return ...; +# 19| 0: [ParameterAccess] access to parameter x +# 22| 7: [DelegateType] EventHandler +#-----| 2: (Parameters) +# 22| 0: [Parameter] sender +# 22| 1: [Parameter] e +# 23| 8: [Event] Event +# 23| 3: [AddEventAccessor] add_Event +#-----| 2: (Parameters) +# 23| 0: [Parameter] value +# 23| 4: [RemoveEventAccessor] remove_Event +#-----| 2: (Parameters) +# 23| 0: [Parameter] value diff --git a/csharp/ql/test/library-tests/assignments/PrintAst.qlref b/csharp/ql/test/library-tests/assignments/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/assignments/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/attributes/PrintAst.expected b/csharp/ql/test/library-tests/attributes/PrintAst.expected new file mode 100644 index 000000000000..87114afe0cb0 --- /dev/null +++ b/csharp/ql/test/library-tests/attributes/PrintAst.expected @@ -0,0 +1,73 @@ +attributes.cs: +# 10| [Attribute] [AssemblyTitle(...)] +# 10| 0: [StringLiteral] "C# attributes test" +# 11| [Attribute] [AssemblyDescription(...)] +# 11| 0: [StringLiteral] "A test of C# attributes" +# 12| [Attribute] [AssemblyConfiguration(...)] +# 12| 0: [StringLiteral] "" +# 13| [Attribute] [AssemblyCompany(...)] +# 13| 0: [StringLiteral] "Semmle Plc" +# 14| [Attribute] [AssemblyProduct(...)] +# 14| 0: [StringLiteral] "Odasa" +# 15| [Attribute] [AssemblyCopyright(...)] +# 15| 0: [StringLiteral] "Copyright � Semmle 2018" +# 16| [Attribute] [AssemblyTrademark(...)] +# 16| 0: [StringLiteral] "" +# 17| [Attribute] [AssemblyCulture(...)] +# 17| 0: [StringLiteral] "" +# 22| [Attribute] [ComVisible(...)] +# 22| 0: [BoolLiteral] false +# 25| [Attribute] [Guid(...)] +# 25| 0: [StringLiteral] "2f70fdd6-14aa-4850-b053-d547adb1f476" +# 37| [Attribute] [AssemblyVersion(...)] +# 37| 0: [StringLiteral] "1.0.0.0" +# 38| [Attribute] [AssemblyFileVersion(...)] +# 38| 0: [StringLiteral] "1.0.0.0" +# 41| [Class] Foo +#-----| 0: (Attributes) +# 40| 1: [Attribute] [AttributeUsage(...)] +# 40| 0: [MemberConstantAccess] access to constant All +# 40| -1: [TypeAccess] access to type AttributeTargets +#-----| 3: (Base types) +# 41| 0: [Class] Attribute +# 44| 5: [Method] foo +#-----| 0: (Attributes) +# 43| 1: [Attribute] [Conditional(...)] +# 43| 0: [StringLiteral] "DEBUG2" +# 44| 4: [BlockStmt] {...} +# 47| [Class] Bar +# 49| 5: [Method] inc +#-----| 2: (Parameters) +# 49| 0: [Parameter] x +#-----| 0: (Attributes) +# 49| 1: [Attribute] [Foo(...)] +# 49| 4: [BlockStmt] {...} +# 49| 0: [ReturnStmt] return ...; +# 49| 0: [AddExpr] ... + ... +# 49| 0: [ParameterAccess] access to parameter x +# 49| 1: [IntLiteral] 1 +# 52| 6: [Method] M1 +#-----| 0: (Attributes) +# 51| 1: [Attribute] [My(...)] +# 51| 0: [BoolLiteral] false +# 52| 4: [BlockStmt] {...} +# 55| 7: [Method] M2 +#-----| 0: (Attributes) +# 54| 1: [Attribute] [My(...)] +# 54| 0: [BoolLiteral] true +# 54| 1: [StringLiteral] "" +# 54| 2: [IntLiteral] 0 +# 55| 4: [BlockStmt] {...} +# 58| [Class] MyAttribute +#-----| 3: (Base types) +# 58| 0: [Class] Attribute +# 60| 4: [Field] x +# 61| 5: [IndexerProperty] y +# 61| 3: [Getter] get_y +# 61| 4: [Setter] set_y +#-----| 2: (Parameters) +# 61| 0: [Parameter] value +# 62| 6: [InstanceConstructor] MyAttribute +#-----| 2: (Parameters) +# 62| 0: [Parameter] b +# 62| 4: [BlockStmt] {...} diff --git a/csharp/ql/test/library-tests/attributes/PrintAst.qlref b/csharp/ql/test/library-tests/attributes/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/attributes/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/cil/consistency/Handles.expected b/csharp/ql/test/library-tests/cil/consistency/Handles.expected index dfc2c225ff9a..d48a89c24a34 100644 --- a/csharp/ql/test/library-tests/cil/consistency/Handles.expected +++ b/csharp/ql/test/library-tests/cil/consistency/Handles.expected @@ -1,3 +1,4 @@ +tooManyHandles tooManyMatchingHandles missingCil csharpLocationViolation diff --git a/csharp/ql/test/library-tests/cil/consistency/Handles.ql b/csharp/ql/test/library-tests/cil/consistency/Handles.ql index 4ceeea6eeab8..a64ea94eb98f 100644 --- a/csharp/ql/test/library-tests/cil/consistency/Handles.ql +++ b/csharp/ql/test/library-tests/cil/consistency/Handles.ql @@ -10,8 +10,27 @@ class MetadataEntity extends DotNet::NamedElement, @metadata_entity { Assembly getAssembly() { metadata_handle(this, result, _) } } -query predicate tooManyMatchingHandles(MetadataEntity e) { - strictcount(MetadataEntity e2 | e.matchesHandle(e2)) > 2 +query predicate tooManyHandles(string s) { + exists(MetadataEntity e, Assembly a | + strictcount(int handle | metadata_handle(e, a, handle)) > 1 and + s = e.getQualifiedName() + ) +} + +private class UniqueMetadataEntity extends MetadataEntity { + UniqueMetadataEntity() { + // Tuple types such as `(,)` and `ValueTuple`2` share the same handle + not this instanceof TupleType and + not this.getQualifiedName().matches("System.ValueTuple%") + } +} + +query predicate tooManyMatchingHandles(string s) { + exists(UniqueMetadataEntity e, Assembly a, int handle | + metadata_handle(e, a, handle) and + strictcount(UniqueMetadataEntity e2 | metadata_handle(e2, a, handle)) > 2 and + s = e.getQualifiedName() + ) } query predicate missingCil(Element e) { diff --git a/csharp/ql/test/library-tests/cil/dataflow/Nullness.expected b/csharp/ql/test/library-tests/cil/dataflow/Nullness.expected index adb291634d96..f9f0d31b5cb8 100644 --- a/csharp/ql/test/library-tests/cil/dataflow/Nullness.expected +++ b/csharp/ql/test/library-tests/cil/dataflow/Nullness.expected @@ -8,7 +8,10 @@ alwaysNull | dataflow.cs:80:21:80:44 | access to property NullProperty | | dataflow.cs:89:31:89:44 | call to method NullFunction | alwaysNotNull +| dataflow.cs:71:13:71:20 | access to local variable nonNull1 | +| dataflow.cs:71:13:71:35 | Int32 nonNull1 = ... | | dataflow.cs:71:24:71:35 | default(...) | +| dataflow.cs:71:32:71:34 | access to type Int32 | | dataflow.cs:72:27:72:30 | this access | | dataflow.cs:72:27:72:40 | call to method GetType | | dataflow.cs:73:30:73:33 | true | @@ -25,6 +28,7 @@ alwaysNotNull | dataflow.cs:85:24:85:30 | access to local variable nonNull | | dataflow.cs:85:24:85:55 | call to method ReturnsNonNullIndirect | | dataflow.cs:86:24:86:30 | access to local variable nonNull | +| dataflow.cs:89:24:89:27 | access to field cond | | dataflow.cs:89:24:89:27 | this access | | dataflow.cs:89:31:89:44 | this access | | dataflow.cs:89:48:89:51 | this access | diff --git a/csharp/ql/test/library-tests/constructors/PrintAst.expected b/csharp/ql/test/library-tests/constructors/PrintAst.expected new file mode 100644 index 000000000000..84a08a3522eb --- /dev/null +++ b/csharp/ql/test/library-tests/constructors/PrintAst.expected @@ -0,0 +1,17 @@ +constructors.cs: +# 1| [NamespaceDeclaration] namespace ... { ... } +# 3| 1: [Class] Class +# 5| 4: [InstanceConstructor] Class +# 6| 4: [BlockStmt] {...} +# 8| 5: [InstanceConstructor] Class +#-----| 2: (Parameters) +# 8| 0: [Parameter] i +# 9| 4: [BlockStmt] {...} +# 11| 6: [StaticConstructor] Class +# 12| 4: [BlockStmt] {...} +# 14| 7: [Destructor] ~Class +# 15| 4: [BlockStmt] {...} +# 16| 0: [LocalVariableDeclStmt] ... ...; +# 16| 0: [LocalVariableDeclAndInitExpr] Int32 i = ... +# 16| 0: [IntLiteral] 0 +# 16| 1: [LocalVariableAccess] access to local variable i diff --git a/csharp/ql/test/library-tests/constructors/PrintAst.qlref b/csharp/ql/test/library-tests/constructors/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/constructors/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/controlflow/graph/Assert.cs b/csharp/ql/test/library-tests/controlflow/graph/Assert.cs new file mode 100644 index 000000000000..3c7ebb08ff1d --- /dev/null +++ b/csharp/ql/test/library-tests/controlflow/graph/Assert.cs @@ -0,0 +1,130 @@ +using System; +using System.Diagnostics; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +class AssertTests +{ + void M1(bool b) + { + string s = b ? null : ""; + Debug.Assert(s != null); + Console.WriteLine(s.Length); + } + + void M2(bool b) + { + string s = b ? null : ""; + Assert.IsNull(s); + Console.WriteLine(s.Length); + } + + void M3(bool b) + { + string s = b ? null : ""; + Assert.IsNotNull(s); + Console.WriteLine(s.Length); + } + + void M4(bool b) + { + string s = b ? null : ""; + Assert.IsTrue(s == null); + Console.WriteLine(s.Length); + } + + void M5(bool b) + { + string s = b ? null : ""; + Assert.IsTrue(s != null); + Console.WriteLine(s.Length); + } + + void M6(bool b) + { + string s = b ? null : ""; + Assert.IsFalse(s != null); + Console.WriteLine(s.Length); + } + + void M7(bool b) + { + string s = b ? null : ""; + Assert.IsFalse(s == null); + Console.WriteLine(s.Length); + } + + void M8(bool b) + { + string s = b ? null : ""; + Assert.IsTrue(s != null && b); + Console.WriteLine(s.Length); + } + + void M9(bool b) + { + string s = b ? null : ""; + Assert.IsFalse(s == null || b); + Console.WriteLine(s.Length); + } + + void M10(bool b) + { + string s = b ? null : ""; + Assert.IsTrue(s == null && b); + Console.WriteLine(s.Length); + } + + void M11(bool b) + { + string s = b ? null : ""; + Assert.IsFalse(s != null || b); + Console.WriteLine(s.Length); + } + + void M12(bool b) + { + string s = b ? null : ""; + Debug.Assert(s != null); + Console.WriteLine(s.Length); + + s = b ? null : ""; + Assert.IsNull(s); + Console.WriteLine(s.Length); + + s = b ? null : ""; + Assert.IsNotNull(s); + Console.WriteLine(s.Length); + + s = b ? null : ""; + Assert.IsTrue(s == null); + Console.WriteLine(s.Length); + + s = b ? null : ""; + Assert.IsTrue(s != null); + Console.WriteLine(s.Length); + + s = b ? null : ""; + Assert.IsFalse(s != null); + Console.WriteLine(s.Length); + + s = b ? null : ""; + Assert.IsFalse(s == null); + Console.WriteLine(s.Length); + + s = b ? null : ""; + Assert.IsTrue(s != null && b); + Console.WriteLine(s.Length); + + s = b ? null : ""; + Assert.IsFalse(s == null || !b); + Console.WriteLine(s.Length); + + s = b ? null : ""; + Assert.IsTrue(s == null && b); + Console.WriteLine(s.Length); + + s = b ? null : ""; + Assert.IsFalse(s != null || !b); + Console.WriteLine(s.Length); + } +} diff --git a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected index 6409269ce5b9..2ac6070c1ddb 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected @@ -13,8 +13,127 @@ | AccessorCalls.cs:66:10:66:11 | enter M9 | AccessorCalls.cs:66:10:66:11 | exit M9 | 57 | | ArrayCreation.cs:3:11:3:12 | enter M1 | ArrayCreation.cs:3:11:3:12 | exit M1 | 4 | | ArrayCreation.cs:5:12:5:13 | enter M2 | ArrayCreation.cs:5:12:5:13 | exit M2 | 5 | -| ArrayCreation.cs:7:11:7:12 | enter M3 | ArrayCreation.cs:7:11:7:12 | exit M3 | 6 | -| ArrayCreation.cs:9:12:9:13 | enter M4 | ArrayCreation.cs:9:12:9:13 | exit M4 | 10 | +| ArrayCreation.cs:7:11:7:12 | enter M3 | ArrayCreation.cs:7:11:7:12 | exit M3 | 7 | +| ArrayCreation.cs:9:12:9:13 | enter M4 | ArrayCreation.cs:9:12:9:13 | exit M4 | 12 | +| Assert.cs:7:10:7:11 | enter M1 | Assert.cs:9:20:9:20 | access to parameter b | 5 | +| Assert.cs:7:10:7:11 | exit M1 | Assert.cs:7:10:7:11 | exit M1 | 1 | +| Assert.cs:9:16:9:32 | String s = ... | Assert.cs:10:22:10:30 | ... != ... | 5 | +| Assert.cs:9:24:9:27 | null | Assert.cs:9:24:9:27 | null | 1 | +| Assert.cs:9:31:9:32 | "" | Assert.cs:9:31:9:32 | "" | 1 | +| Assert.cs:10:9:10:31 | [assertion failure] call to method Assert | Assert.cs:10:9:10:31 | [assertion failure] call to method Assert | 1 | +| Assert.cs:10:9:10:31 | [assertion success] call to method Assert | Assert.cs:11:9:11:35 | call to method WriteLine | 5 | +| Assert.cs:14:10:14:11 | enter M2 | Assert.cs:16:20:16:20 | access to parameter b | 5 | +| Assert.cs:14:10:14:11 | exit M2 | Assert.cs:14:10:14:11 | exit M2 | 1 | +| Assert.cs:16:16:16:32 | String s = ... | Assert.cs:17:23:17:23 | access to local variable s | 3 | +| Assert.cs:16:24:16:27 | null | Assert.cs:16:24:16:27 | null | 1 | +| Assert.cs:16:31:16:32 | "" | Assert.cs:16:31:16:32 | "" | 1 | +| Assert.cs:17:9:17:24 | [assertion failure] call to method IsNull | Assert.cs:17:9:17:24 | [assertion failure] call to method IsNull | 1 | +| Assert.cs:17:9:17:24 | [assertion success] call to method IsNull | Assert.cs:18:9:18:35 | call to method WriteLine | 5 | +| Assert.cs:21:10:21:11 | enter M3 | Assert.cs:23:20:23:20 | access to parameter b | 5 | +| Assert.cs:21:10:21:11 | exit M3 | Assert.cs:21:10:21:11 | exit M3 | 1 | +| Assert.cs:23:16:23:32 | String s = ... | Assert.cs:24:26:24:26 | access to local variable s | 3 | +| Assert.cs:23:24:23:27 | null | Assert.cs:23:24:23:27 | null | 1 | +| Assert.cs:23:31:23:32 | "" | Assert.cs:23:31:23:32 | "" | 1 | +| Assert.cs:24:9:24:27 | [assertion failure] call to method IsNotNull | Assert.cs:24:9:24:27 | [assertion failure] call to method IsNotNull | 1 | +| Assert.cs:24:9:24:27 | [assertion success] call to method IsNotNull | Assert.cs:25:9:25:35 | call to method WriteLine | 5 | +| Assert.cs:28:10:28:11 | enter M4 | Assert.cs:30:20:30:20 | access to parameter b | 5 | +| Assert.cs:28:10:28:11 | exit M4 | Assert.cs:28:10:28:11 | exit M4 | 1 | +| Assert.cs:30:16:30:32 | String s = ... | Assert.cs:31:23:31:31 | ... == ... | 5 | +| Assert.cs:30:24:30:27 | null | Assert.cs:30:24:30:27 | null | 1 | +| Assert.cs:30:31:30:32 | "" | Assert.cs:30:31:30:32 | "" | 1 | +| Assert.cs:31:9:31:32 | [assertion failure] call to method IsTrue | Assert.cs:31:9:31:32 | [assertion failure] call to method IsTrue | 1 | +| Assert.cs:31:9:31:32 | [assertion success] call to method IsTrue | Assert.cs:32:9:32:35 | call to method WriteLine | 5 | +| Assert.cs:35:10:35:11 | enter M5 | Assert.cs:37:20:37:20 | access to parameter b | 5 | +| Assert.cs:35:10:35:11 | exit M5 | Assert.cs:35:10:35:11 | exit M5 | 1 | +| Assert.cs:37:16:37:32 | String s = ... | Assert.cs:38:23:38:31 | ... != ... | 5 | +| Assert.cs:37:24:37:27 | null | Assert.cs:37:24:37:27 | null | 1 | +| Assert.cs:37:31:37:32 | "" | Assert.cs:37:31:37:32 | "" | 1 | +| Assert.cs:38:9:38:32 | [assertion failure] call to method IsTrue | Assert.cs:38:9:38:32 | [assertion failure] call to method IsTrue | 1 | +| Assert.cs:38:9:38:32 | [assertion success] call to method IsTrue | Assert.cs:39:9:39:35 | call to method WriteLine | 5 | +| Assert.cs:42:10:42:11 | enter M6 | Assert.cs:44:20:44:20 | access to parameter b | 5 | +| Assert.cs:42:10:42:11 | exit M6 | Assert.cs:42:10:42:11 | exit M6 | 1 | +| Assert.cs:44:16:44:32 | String s = ... | Assert.cs:45:24:45:32 | ... != ... | 5 | +| Assert.cs:44:24:44:27 | null | Assert.cs:44:24:44:27 | null | 1 | +| Assert.cs:44:31:44:32 | "" | Assert.cs:44:31:44:32 | "" | 1 | +| Assert.cs:45:9:45:33 | [assertion failure] call to method IsFalse | Assert.cs:45:9:45:33 | [assertion failure] call to method IsFalse | 1 | +| Assert.cs:45:9:45:33 | [assertion success] call to method IsFalse | Assert.cs:46:9:46:35 | call to method WriteLine | 5 | +| Assert.cs:49:10:49:11 | enter M7 | Assert.cs:51:20:51:20 | access to parameter b | 5 | +| Assert.cs:49:10:49:11 | exit M7 | Assert.cs:49:10:49:11 | exit M7 | 1 | +| Assert.cs:51:16:51:32 | String s = ... | Assert.cs:52:24:52:32 | ... == ... | 5 | +| Assert.cs:51:24:51:27 | null | Assert.cs:51:24:51:27 | null | 1 | +| Assert.cs:51:31:51:32 | "" | Assert.cs:51:31:51:32 | "" | 1 | +| Assert.cs:52:9:52:33 | [assertion failure] call to method IsFalse | Assert.cs:52:9:52:33 | [assertion failure] call to method IsFalse | 1 | +| Assert.cs:52:9:52:33 | [assertion success] call to method IsFalse | Assert.cs:53:9:53:35 | call to method WriteLine | 5 | +| Assert.cs:56:10:56:11 | enter M8 | Assert.cs:58:20:58:20 | access to parameter b | 5 | +| Assert.cs:56:10:56:11 | exit M8 | Assert.cs:56:10:56:11 | exit M8 | 1 | +| Assert.cs:58:24:58:27 | [b (line 56): true] null | Assert.cs:59:23:59:31 | [b (line 56): true] ... != ... | 7 | +| Assert.cs:58:31:58:32 | [b (line 56): false] "" | Assert.cs:59:23:59:31 | [b (line 56): false] ... != ... | 7 | +| Assert.cs:59:9:59:37 | [assertion failure] call to method IsTrue | Assert.cs:59:9:59:37 | [assertion failure] call to method IsTrue | 1 | +| Assert.cs:59:36:59:36 | [b (line 56): false] access to parameter b | Assert.cs:59:36:59:36 | [b (line 56): false] access to parameter b | 1 | +| Assert.cs:59:36:59:36 | [b (line 56): true] access to parameter b | Assert.cs:60:9:60:35 | call to method WriteLine | 6 | +| Assert.cs:63:10:63:11 | enter M9 | Assert.cs:65:20:65:20 | access to parameter b | 5 | +| Assert.cs:63:10:63:11 | exit M9 | Assert.cs:63:10:63:11 | exit M9 | 1 | +| Assert.cs:65:24:65:27 | [b (line 63): true] null | Assert.cs:66:24:66:32 | [b (line 63): true] ... == ... | 7 | +| Assert.cs:65:31:65:32 | [b (line 63): false] "" | Assert.cs:66:24:66:32 | [b (line 63): false] ... == ... | 7 | +| Assert.cs:66:9:66:38 | [assertion failure] call to method IsFalse | Assert.cs:66:9:66:38 | [assertion failure] call to method IsFalse | 1 | +| Assert.cs:66:37:66:37 | [b (line 63): false] access to parameter b | Assert.cs:67:9:67:35 | call to method WriteLine | 6 | +| Assert.cs:66:37:66:37 | [b (line 63): true] access to parameter b | Assert.cs:66:37:66:37 | [b (line 63): true] access to parameter b | 1 | +| Assert.cs:70:10:70:12 | enter M10 | Assert.cs:72:20:72:20 | access to parameter b | 5 | +| Assert.cs:70:10:70:12 | exit M10 | Assert.cs:70:10:70:12 | exit M10 | 1 | +| Assert.cs:72:24:72:27 | [b (line 70): true] null | Assert.cs:73:23:73:31 | [b (line 70): true] ... == ... | 7 | +| Assert.cs:72:31:72:32 | [b (line 70): false] "" | Assert.cs:73:23:73:31 | [b (line 70): false] ... == ... | 7 | +| Assert.cs:73:9:73:37 | [assertion failure] call to method IsTrue | Assert.cs:73:9:73:37 | [assertion failure] call to method IsTrue | 1 | +| Assert.cs:73:36:73:36 | [b (line 70): false] access to parameter b | Assert.cs:73:36:73:36 | [b (line 70): false] access to parameter b | 1 | +| Assert.cs:73:36:73:36 | [b (line 70): true] access to parameter b | Assert.cs:74:9:74:35 | call to method WriteLine | 6 | +| Assert.cs:77:10:77:12 | enter M11 | Assert.cs:79:20:79:20 | access to parameter b | 5 | +| Assert.cs:77:10:77:12 | exit M11 | Assert.cs:77:10:77:12 | exit M11 | 1 | +| Assert.cs:79:24:79:27 | [b (line 77): true] null | Assert.cs:80:24:80:32 | [b (line 77): true] ... != ... | 7 | +| Assert.cs:79:31:79:32 | [b (line 77): false] "" | Assert.cs:80:24:80:32 | [b (line 77): false] ... != ... | 7 | +| Assert.cs:80:9:80:38 | [assertion failure] call to method IsFalse | Assert.cs:80:9:80:38 | [assertion failure] call to method IsFalse | 1 | +| Assert.cs:80:37:80:37 | [b (line 77): false] access to parameter b | Assert.cs:81:9:81:35 | call to method WriteLine | 6 | +| Assert.cs:80:37:80:37 | [b (line 77): true] access to parameter b | Assert.cs:80:37:80:37 | [b (line 77): true] access to parameter b | 1 | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:86:20:86:20 | access to parameter b | 5 | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:84:10:84:12 | exit M12 | 1 | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:87:22:87:30 | [b (line 84): true] ... != ... | 6 | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:87:22:87:30 | [b (line 84): false] ... != ... | 6 | +| Assert.cs:87:9:87:31 | [assertion failure, b (line 84): false] call to method Assert | Assert.cs:87:9:87:31 | [assertion failure, b (line 84): false] call to method Assert | 1 | +| Assert.cs:87:9:87:31 | [assertion failure, b (line 84): true] call to method Assert | Assert.cs:87:9:87:31 | [assertion failure, b (line 84): true] call to method Assert | 1 | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:91:23:91:23 | [b (line 84): false] access to local variable s | 12 | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:91:23:91:23 | [b (line 84): true] access to local variable s | 12 | +| Assert.cs:91:9:91:24 | [assertion failure, b (line 84): false] call to method IsNull | Assert.cs:91:9:91:24 | [assertion failure, b (line 84): false] call to method IsNull | 1 | +| Assert.cs:91:9:91:24 | [assertion failure, b (line 84): true] call to method IsNull | Assert.cs:91:9:91:24 | [assertion failure, b (line 84): true] call to method IsNull | 1 | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:95:26:95:26 | [b (line 84): false] access to local variable s | 12 | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:95:26:95:26 | [b (line 84): true] access to local variable s | 12 | +| Assert.cs:95:9:95:27 | [assertion failure, b (line 84): false] call to method IsNotNull | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): false] call to method IsNotNull | 1 | +| Assert.cs:95:9:95:27 | [assertion failure, b (line 84): true] call to method IsNotNull | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): true] call to method IsNotNull | 1 | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | Assert.cs:99:23:99:31 | [b (line 84): false] ... == ... | 14 | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:99:23:99:31 | [b (line 84): true] ... == ... | 14 | +| Assert.cs:99:9:99:32 | [assertion failure, b (line 84): false] call to method IsTrue | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): false] call to method IsTrue | 1 | +| Assert.cs:99:9:99:32 | [assertion failure, b (line 84): true] call to method IsTrue | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): true] call to method IsTrue | 1 | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:103:23:103:31 | [b (line 84): false] ... != ... | 14 | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:103:23:103:31 | [b (line 84): true] ... != ... | 14 | +| Assert.cs:103:9:103:32 | [assertion failure, b (line 84): false] call to method IsTrue | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): false] call to method IsTrue | 1 | +| Assert.cs:103:9:103:32 | [assertion failure, b (line 84): true] call to method IsTrue | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): true] call to method IsTrue | 1 | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:107:24:107:32 | [b (line 84): false] ... != ... | 14 | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:107:24:107:32 | [b (line 84): true] ... != ... | 14 | +| Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | 1 | +| Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | 1 | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | Assert.cs:111:24:111:32 | [b (line 84): false] ... == ... | 14 | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:111:24:111:32 | [b (line 84): true] ... == ... | 14 | +| Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | 1 | +| Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | 1 | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | Assert.cs:115:23:115:31 | [b (line 84): false] ... != ... | 15 | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:115:23:115:31 | [b (line 84): true] ... != ... | 15 | +| Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | 1 | +| Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | 1 | +| Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | 1 | +| Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | Assert.cs:119:24:119:32 | [b (line 84): true] ... == ... | 16 | +| Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | 1 | +| Assert.cs:119:37:119:38 | [b (line 84): true] !... | Assert.cs:123:23:123:31 | [b (line 84): true] ... == ... | 17 | +| Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | 1 | +| Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | Assert.cs:127:24:127:32 | [b (line 84): true] ... != ... | 16 | +| Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | 1 | +| Assert.cs:127:37:127:38 | [b (line 84): true] !... | Assert.cs:128:9:128:35 | call to method WriteLine | 7 | | Assignments.cs:3:10:3:10 | enter M | Assignments.cs:3:10:3:10 | exit M | 33 | | Assignments.cs:14:18:14:35 | enter (...) => ... | Assignments.cs:14:18:14:35 | exit (...) => ... | 3 | | Assignments.cs:17:40:17:40 | enter + | Assignments.cs:17:40:17:40 | exit + | 5 | @@ -59,6 +178,8 @@ | CompileTimeOperators.cs:15:10:15:15 | enter Typeof | CompileTimeOperators.cs:15:10:15:15 | exit Typeof | 5 | | CompileTimeOperators.cs:20:12:20:17 | enter Nameof | CompileTimeOperators.cs:20:12:20:17 | exit Nameof | 5 | | CompileTimeOperators.cs:28:10:28:10 | enter M | CompileTimeOperators.cs:28:10:28:10 | exit M | 14 | +| ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | ConditionalAccess.cs:30:28:30:32 | ... = ... | 3 | +| ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | 1 | | ConditionalAccess.cs:3:12:3:13 | enter M1 | ConditionalAccess.cs:3:26:3:26 | access to parameter i | 2 | | ConditionalAccess.cs:3:12:3:13 | exit M1 | ConditionalAccess.cs:3:12:3:13 | exit M1 | 1 | | ConditionalAccess.cs:3:28:3:38 | call to method ToString | ConditionalAccess.cs:3:28:3:38 | call to method ToString | 1 | @@ -84,7 +205,12 @@ | ConditionalAccess.cs:19:12:19:13 | exit M6 | ConditionalAccess.cs:19:12:19:13 | exit M6 | 1 | | ConditionalAccess.cs:19:58:19:59 | access to parameter s2 | ConditionalAccess.cs:19:43:19:60 | call to method CommaJoinWith | 2 | | ConditionalAccess.cs:21:10:21:11 | enter M7 | ConditionalAccess.cs:21:10:21:11 | exit M7 | 17 | -| ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | ConditionalAccess.cs:31:26:31:38 | exit CommaJoinWith | 7 | +| ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:30:28:30:32 | ... = ... | 3 | +| ConditionalAccess.cs:30:10:30:12 | exit Out | ConditionalAccess.cs:30:10:30:12 | exit Out | 1 | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:35:9:35:12 | access to property Prop | 8 | +| ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:32:10:32:11 | exit M8 | 1 | +| ConditionalAccess.cs:35:14:35:24 | call to method Out | ConditionalAccess.cs:35:14:35:24 | call to method Out | 1 | +| ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:26:41:38 | exit CommaJoinWith | 7 | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:5:13:5:15 | access to parameter inc | 4 | | Conditions.cs:3:10:3:19 | exit IncrOrDecr | Conditions.cs:3:10:3:19 | exit IncrOrDecr | 1 | | Conditions.cs:6:13:6:16 | [inc (line 3): true] ...; | Conditions.cs:7:14:7:16 | [inc (line 3): true] access to parameter inc | 6 | @@ -132,7 +258,7 @@ | Conditions.cs:77:17:77:20 | ...; | Conditions.cs:77:17:77:19 | ...++ | 3 | | Conditions.cs:78:13:79:26 | if (...) ... | Conditions.cs:78:17:78:21 | ... > ... | 4 | | Conditions.cs:79:17:79:26 | ...; | Conditions.cs:79:17:79:25 | ... = ... | 3 | -| Conditions.cs:81:9:82:16 | if (...) ... | Conditions.cs:81:12:81:12 | access to local variable b | 2 | +| Conditions.cs:81:9:82:16 | if (...) ... | Conditions.cs:81:13:81:13 | access to local variable b | 2 | | Conditions.cs:82:13:82:16 | ...; | Conditions.cs:82:13:82:15 | ...++ | 3 | | Conditions.cs:83:16:83:16 | access to local variable x | Conditions.cs:70:9:70:10 | exit M6 | 3 | | Conditions.cs:86:9:86:10 | enter M7 | Conditions.cs:90:27:90:28 | access to parameter ss | 12 | @@ -150,10 +276,10 @@ | Conditions.cs:108:13:109:24 | [b (line 102): false] if (...) ... | Conditions.cs:109:17:109:23 | ... = ... | 8 | | Conditions.cs:108:13:109:24 | [b (line 102): true] if (...) ... | Conditions.cs:108:18:108:18 | [b (line 102): true] access to parameter b | 3 | | Conditions.cs:110:16:110:16 | access to local variable x | Conditions.cs:102:12:102:13 | exit M8 | 3 | -| Conditions.cs:113:10:113:11 | enter M9 | Conditions.cs:116:17:116:21 | Int32 i = ... | 8 | +| Conditions.cs:113:10:113:11 | enter M9 | Conditions.cs:116:18:116:22 | Int32 i = ... | 8 | | Conditions.cs:113:10:113:11 | exit M9 | Conditions.cs:113:10:113:11 | exit M9 | 1 | -| Conditions.cs:116:24:116:24 | access to local variable i | Conditions.cs:116:24:116:38 | ... < ... | 4 | -| Conditions.cs:116:41:116:41 | access to local variable i | Conditions.cs:116:41:116:43 | ...++ | 2 | +| Conditions.cs:116:25:116:25 | access to local variable i | Conditions.cs:116:25:116:39 | ... < ... | 4 | +| Conditions.cs:116:42:116:42 | access to local variable i | Conditions.cs:116:42:116:44 | ...++ | 2 | | Conditions.cs:117:9:123:9 | {...} | Conditions.cs:119:18:119:21 | access to local variable last | 12 | | Conditions.cs:120:17:120:23 | [last (line 118): false] ...; | Conditions.cs:121:17:121:20 | [last (line 118): false] access to local variable last | 5 | | Conditions.cs:121:13:122:25 | [last (line 118): true] if (...) ... | Conditions.cs:122:17:122:24 | ... = ... | 5 | @@ -162,6 +288,10 @@ | Conditions.cs:131:16:131:19 | [Field1 (line 129): true, Field2 (line 129): false] true | Conditions.cs:135:21:135:26 | [Field1 (line 129): true, Field2 (line 129): false] access to field Field2 | 9 | | Conditions.cs:134:13:139:13 | [Field1 (line 129): true] {...} | Conditions.cs:135:21:135:26 | [Field1 (line 129): true] access to field Field2 | 4 | | Conditions.cs:136:17:138:17 | [Field1 (line 129): true, Field2 (line 129): true] {...} | Conditions.cs:135:21:135:26 | [Field1 (line 129): true, Field2 (line 129): true] access to field Field2 | 14 | +| Conditions.cs:143:10:143:12 | enter M11 | Conditions.cs:145:17:145:17 | access to parameter b | 5 | +| Conditions.cs:143:10:143:12 | exit M11 | Conditions.cs:143:10:143:12 | exit M11 | 1 | +| Conditions.cs:145:21:145:23 | [b (line 143): true] "a" | Conditions.cs:147:13:147:48 | call to method WriteLine | 9 | +| Conditions.cs:145:27:145:29 | [b (line 143): false] "b" | Conditions.cs:149:13:149:48 | call to method WriteLine | 9 | | ExitMethods.cs:7:10:7:11 | enter M1 | ExitMethods.cs:7:10:7:11 | exit M1 | 7 | | ExitMethods.cs:13:10:13:11 | enter M2 | ExitMethods.cs:13:10:13:11 | exit M2 | 7 | | ExitMethods.cs:19:10:19:11 | enter M3 | ExitMethods.cs:19:10:19:11 | exit M3 | 6 | @@ -197,7 +327,10 @@ | ExitMethods.cs:116:38:116:38 | 1 | ExitMethods.cs:116:38:116:38 | 1 | 1 | | ExitMethods.cs:119:17:119:32 | enter FailingAssertion | ExitMethods.cs:119:17:119:32 | exit FailingAssertion | 6 | | ExitMethods.cs:125:17:125:33 | enter FailingAssertion2 | ExitMethods.cs:125:17:125:33 | exit FailingAssertion2 | 6 | -| ExitMethods.cs:131:10:131:20 | enter AssertFalse | ExitMethods.cs:131:10:131:20 | exit AssertFalse | 4 | +| ExitMethods.cs:131:10:131:20 | enter AssertFalse | ExitMethods.cs:131:48:131:48 | access to parameter b | 2 | +| ExitMethods.cs:131:10:131:20 | exit AssertFalse | ExitMethods.cs:131:10:131:20 | exit AssertFalse | 1 | +| ExitMethods.cs:131:33:131:49 | [assertion failure] call to method IsFalse | ExitMethods.cs:131:33:131:49 | [assertion failure] call to method IsFalse | 1 | +| ExitMethods.cs:131:33:131:49 | [assertion success] call to method IsFalse | ExitMethods.cs:131:33:131:49 | [assertion success] call to method IsFalse | 1 | | ExitMethods.cs:133:17:133:33 | enter FailingAssertion3 | ExitMethods.cs:133:17:133:33 | exit FailingAssertion3 | 7 | | Extensions.cs:5:23:5:29 | enter ToInt32 | Extensions.cs:5:23:5:29 | exit ToInt32 | 6 | | Extensions.cs:10:24:10:29 | enter ToBool | Extensions.cs:10:24:10:29 | exit ToBool | 7 | @@ -402,7 +535,7 @@ | Foreach.cs:38:26:38:26 | String x | Foreach.cs:39:11:39:11 | ; | 4 | | Initializers.cs:8:5:8:16 | enter Initializers | Initializers.cs:8:5:8:16 | exit Initializers | 14 | | Initializers.cs:10:5:10:16 | enter Initializers | Initializers.cs:10:5:10:16 | exit Initializers | 14 | -| Initializers.cs:12:10:12:10 | enter M | Initializers.cs:12:10:12:10 | exit M | 20 | +| Initializers.cs:12:10:12:10 | enter M | Initializers.cs:12:10:12:10 | exit M | 21 | | Initializers.cs:18:20:18:20 | 1 | Initializers.cs:18:16:18:20 | ... = ... | 2 | | Initializers.cs:20:11:20:23 | enter NoConstructor | Initializers.cs:20:11:20:23 | exit NoConstructor | 8 | | Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:9:31:11 | exit Sub | 11 | @@ -412,39 +545,182 @@ | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:9:13:9:28 | ... == ... | 7 | | LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:7:10:7:11 | exit M1 | 1 | | LoopUnrolling.cs:10:13:10:19 | return ...; | LoopUnrolling.cs:10:13:10:19 | return ...; | 1 | -| LoopUnrolling.cs:11:21:11:23 | String arg | LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | 5 | -| LoopUnrolling.cs:11:28:11:31 | access to parameter args | LoopUnrolling.cs:11:9:12:35 | [unroll (line 11)] foreach (... ... in ...) ... | 2 | -| LoopUnrolling.cs:15:10:15:11 | enter M2 | LoopUnrolling.cs:18:9:19:33 | [unroll (line 18)] foreach (... ... in ...) ... | 11 | +| LoopUnrolling.cs:11:22:11:24 | String arg | LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | 5 | +| LoopUnrolling.cs:11:29:11:32 | access to parameter args | LoopUnrolling.cs:11:9:12:35 | [unroll (line 11)] foreach (... ... in ...) ... | 2 | +| LoopUnrolling.cs:15:10:15:11 | enter M2 | LoopUnrolling.cs:18:9:19:33 | [unroll (line 18)] foreach (... ... in ...) ... | 12 | | LoopUnrolling.cs:15:10:15:11 | exit M2 | LoopUnrolling.cs:15:10:15:11 | exit M2 | 1 | -| LoopUnrolling.cs:18:21:18:21 | String x | LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... | 5 | +| LoopUnrolling.cs:18:22:18:22 | String x | LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... | 5 | | LoopUnrolling.cs:22:10:22:11 | enter M3 | LoopUnrolling.cs:24:29:24:32 | access to parameter args | 3 | | LoopUnrolling.cs:22:10:22:11 | exit M3 | LoopUnrolling.cs:22:10:22:11 | exit M3 | 1 | | LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | 1 | | LoopUnrolling.cs:24:22:24:24 | Char arg | LoopUnrolling.cs:25:13:26:40 | [unroll (line 25)] foreach (... ... in ...) ... | 3 | | LoopUnrolling.cs:25:26:25:29 | Char arg0 | LoopUnrolling.cs:25:13:26:40 | foreach (... ... in ...) ... | 5 | -| LoopUnrolling.cs:29:10:29:11 | enter M4 | LoopUnrolling.cs:32:26:32:27 | access to local variable xs | 7 | -| LoopUnrolling.cs:29:10:29:11 | exit M4 | LoopUnrolling.cs:29:10:29:11 | exit M4 | 1 | -| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | 1 | -| LoopUnrolling.cs:32:21:32:21 | String x | LoopUnrolling.cs:33:13:33:32 | call to method WriteLine | 4 | -| LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:40:9:42:41 | [unroll (line 40)] foreach (... ... in ...) ... | 18 | +| LoopUnrolling.cs:29:10:29:11 | enter M4 | LoopUnrolling.cs:29:10:29:11 | exit M4 | 9 | +| LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:40:9:42:41 | [unroll (line 40)] foreach (... ... in ...) ... | 20 | | LoopUnrolling.cs:36:10:36:11 | exit M5 | LoopUnrolling.cs:36:10:36:11 | exit M5 | 1 | | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | 1 | -| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:41:13:42:41 | [unroll (line 41)] foreach (... ... in ...) ... | 3 | -| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:41:13:42:41 | foreach (... ... in ...) ... | 7 | -| LoopUnrolling.cs:45:10:45:11 | enter M6 | LoopUnrolling.cs:49:9:52:9 | {...} | 13 | -| LoopUnrolling.cs:50:13:50:17 | Label: | LoopUnrolling.cs:51:13:51:23 | goto ...; | 5 | -| LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:60:17:60:17 | access to parameter b | 15 | +| LoopUnrolling.cs:40:22:40:22 | String x | LoopUnrolling.cs:41:13:42:41 | [unroll (line 41)] foreach (... ... in ...) ... | 3 | +| LoopUnrolling.cs:41:26:41:26 | String y | LoopUnrolling.cs:41:13:42:41 | foreach (... ... in ...) ... | 7 | +| LoopUnrolling.cs:45:10:45:11 | enter M6 | LoopUnrolling.cs:49:9:52:9 | {...} | 14 | +| LoopUnrolling.cs:50:9:50:13 | Label: | LoopUnrolling.cs:51:13:51:23 | goto ...; | 5 | +| LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:60:17:60:17 | access to parameter b | 16 | | LoopUnrolling.cs:55:10:55:11 | exit M7 | LoopUnrolling.cs:55:10:55:11 | exit M7 | 1 | -| LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | LoopUnrolling.cs:60:17:60:17 | [b (line 55): false] access to parameter b | 4 | -| LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | LoopUnrolling.cs:60:17:60:17 | [b (line 55): true] access to parameter b | 4 | +| LoopUnrolling.cs:58:22:58:22 | [b (line 55): false] String x | LoopUnrolling.cs:60:17:60:17 | [b (line 55): false] access to parameter b | 4 | +| LoopUnrolling.cs:58:22:58:22 | [b (line 55): true] String x | LoopUnrolling.cs:60:17:60:17 | [b (line 55): true] access to parameter b | 4 | | LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | LoopUnrolling.cs:58:9:64:9 | [b (line 55): true] foreach (... ... in ...) ... | 9 | | LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | LoopUnrolling.cs:58:9:64:9 | [b (line 55): false] foreach (... ... in ...) ... | 3 | | LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:69:14:69:23 | call to method Any | 6 | | LoopUnrolling.cs:67:10:67:11 | exit M8 | LoopUnrolling.cs:67:10:67:11 | exit M8 | 1 | | LoopUnrolling.cs:70:13:70:19 | return ...; | LoopUnrolling.cs:70:13:70:19 | return ...; | 1 | -| LoopUnrolling.cs:71:9:71:21 | ...; | LoopUnrolling.cs:72:28:72:31 | access to parameter args | 4 | -| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | 1 | -| LoopUnrolling.cs:72:21:72:23 | String arg | LoopUnrolling.cs:73:13:73:34 | call to method WriteLine | 4 | +| LoopUnrolling.cs:71:9:71:21 | ...; | LoopUnrolling.cs:72:9:73:35 | [skip (line 72)] foreach (... ... in ...) ... | 5 | +| LoopUnrolling.cs:76:10:76:11 | enter M9 | LoopUnrolling.cs:76:10:76:11 | exit M9 | 10 | +| LoopUnrolling.cs:85:10:85:12 | enter M10 | LoopUnrolling.cs:85:10:85:12 | exit M10 | 10 | +| LoopUnrolling.cs:94:10:94:12 | enter M11 | LoopUnrolling.cs:97:9:100:9 | [unroll (line 97)] foreach (... ... in ...) ... | 9 | +| LoopUnrolling.cs:94:10:94:12 | exit M11 | LoopUnrolling.cs:94:10:94:12 | exit M11 | 1 | +| LoopUnrolling.cs:97:22:97:22 | String x | LoopUnrolling.cs:97:9:100:9 | foreach (... ... in ...) ... | 6 | +| MultiImplementationA.cs:6:22:6:31 | enter get_P1 | MultiImplementationA.cs:6:22:6:31 | enter get_P1 | 1 | +| MultiImplementationA.cs:6:22:6:31 | enter get_P1 | MultiImplementationB.cs:3:22:3:22 | enter get_P1 | 1 | +| MultiImplementationA.cs:6:22:6:31 | exit get_P1 | MultiImplementationA.cs:6:22:6:31 | exit get_P1 | 1 | +| MultiImplementationA.cs:6:22:6:31 | exit get_P1 | MultiImplementationB.cs:3:22:3:22 | exit get_P1 | 1 | +| MultiImplementationA.cs:6:28:6:31 | null | MultiImplementationA.cs:6:22:6:31 | throw ... | 2 | +| MultiImplementationA.cs:7:21:7:23 | enter get_P2 | MultiImplementationA.cs:7:21:7:23 | enter get_P2 | 1 | +| MultiImplementationA.cs:7:21:7:23 | enter get_P2 | MultiImplementationB.cs:4:21:4:23 | enter get_P2 | 1 | +| MultiImplementationA.cs:7:21:7:23 | exit get_P2 | MultiImplementationA.cs:7:21:7:23 | exit get_P2 | 1 | +| MultiImplementationA.cs:7:21:7:23 | exit get_P2 | MultiImplementationB.cs:4:21:4:23 | exit get_P2 | 1 | +| MultiImplementationA.cs:7:25:7:39 | {...} | MultiImplementationA.cs:7:27:7:37 | throw ...; | 3 | +| MultiImplementationA.cs:7:41:7:43 | enter set_P2 | MultiImplementationA.cs:7:41:7:43 | enter set_P2 | 1 | +| MultiImplementationA.cs:7:41:7:43 | enter set_P2 | MultiImplementationB.cs:4:39:4:41 | enter set_P2 | 1 | +| MultiImplementationA.cs:7:41:7:43 | exit set_P2 | MultiImplementationA.cs:7:41:7:43 | exit set_P2 | 1 | +| MultiImplementationA.cs:7:41:7:43 | exit set_P2 | MultiImplementationB.cs:4:39:4:41 | exit set_P2 | 1 | +| MultiImplementationA.cs:7:45:7:59 | {...} | MultiImplementationA.cs:7:47:7:57 | throw ...; | 3 | +| MultiImplementationA.cs:8:16:8:16 | enter M | MultiImplementationA.cs:8:16:8:16 | enter M | 1 | +| MultiImplementationA.cs:8:16:8:16 | enter M | MultiImplementationB.cs:5:16:5:16 | enter M | 1 | +| MultiImplementationA.cs:8:16:8:16 | exit M | MultiImplementationA.cs:8:16:8:16 | exit M | 1 | +| MultiImplementationA.cs:8:16:8:16 | exit M | MultiImplementationB.cs:5:16:5:16 | exit M | 1 | +| MultiImplementationA.cs:8:29:8:32 | null | MultiImplementationA.cs:8:23:8:32 | throw ... | 2 | +| MultiImplementationA.cs:13:16:13:16 | this access | MultiImplementationA.cs:13:16:13:20 | ... = ... | 3 | +| MultiImplementationA.cs:14:31:14:31 | access to parameter i | MultiImplementationA.cs:14:31:14:31 | access to parameter i | 1 | +| MultiImplementationA.cs:14:31:14:31 | enter get_Item | MultiImplementationA.cs:14:31:14:31 | enter get_Item | 1 | +| MultiImplementationA.cs:14:31:14:31 | enter get_Item | MultiImplementationB.cs:12:31:12:40 | enter get_Item | 1 | +| MultiImplementationA.cs:14:31:14:31 | exit get_Item | MultiImplementationA.cs:14:31:14:31 | exit get_Item | 1 | +| MultiImplementationA.cs:14:31:14:31 | exit get_Item | MultiImplementationB.cs:12:31:12:40 | exit get_Item | 1 | +| MultiImplementationA.cs:15:36:15:38 | enter get_Item | MultiImplementationA.cs:15:36:15:38 | enter get_Item | 1 | +| MultiImplementationA.cs:15:36:15:38 | enter get_Item | MultiImplementationB.cs:13:36:13:38 | enter get_Item | 1 | +| MultiImplementationA.cs:15:36:15:38 | exit get_Item | MultiImplementationA.cs:15:36:15:38 | exit get_Item | 1 | +| MultiImplementationA.cs:15:36:15:38 | exit get_Item | MultiImplementationB.cs:13:36:13:38 | exit get_Item | 1 | +| MultiImplementationA.cs:15:40:15:52 | {...} | MultiImplementationA.cs:15:42:15:50 | return ...; | 3 | +| MultiImplementationA.cs:15:54:15:56 | enter set_Item | MultiImplementationA.cs:15:54:15:56 | enter set_Item | 1 | +| MultiImplementationA.cs:15:54:15:56 | enter set_Item | MultiImplementationB.cs:13:56:13:58 | enter set_Item | 1 | +| MultiImplementationA.cs:15:54:15:56 | exit set_Item | MultiImplementationA.cs:15:54:15:56 | exit set_Item | 1 | +| MultiImplementationA.cs:15:54:15:56 | exit set_Item | MultiImplementationB.cs:13:56:13:58 | exit set_Item | 1 | +| MultiImplementationA.cs:15:58:15:60 | {...} | MultiImplementationA.cs:15:58:15:60 | {...} | 1 | +| MultiImplementationA.cs:16:17:16:18 | enter M1 | MultiImplementationA.cs:16:17:16:18 | enter M1 | 1 | +| MultiImplementationA.cs:16:17:16:18 | enter M1 | MultiImplementationB.cs:14:17:14:18 | enter M1 | 1 | +| MultiImplementationA.cs:16:17:16:18 | exit M1 | MultiImplementationA.cs:16:17:16:18 | exit M1 | 1 | +| MultiImplementationA.cs:16:17:16:18 | exit M1 | MultiImplementationB.cs:14:17:14:18 | exit M1 | 1 | +| MultiImplementationA.cs:17:5:19:5 | {...} | MultiImplementationA.cs:18:9:18:22 | M2(...) | 2 | +| MultiImplementationA.cs:18:9:18:22 | enter M2 | MultiImplementationA.cs:18:9:18:22 | exit M2 | 3 | +| MultiImplementationA.cs:20:12:20:13 | enter C2 | MultiImplementationA.cs:20:12:20:13 | enter C2 | 1 | +| MultiImplementationA.cs:20:12:20:13 | enter C2 | MultiImplementationB.cs:18:12:18:13 | enter C2 | 1 | +| MultiImplementationA.cs:20:12:20:13 | exit C2 | MultiImplementationA.cs:20:12:20:13 | exit C2 | 1 | +| MultiImplementationA.cs:20:12:20:13 | exit C2 | MultiImplementationB.cs:18:12:18:13 | exit C2 | 1 | +| MultiImplementationA.cs:20:22:20:31 | {...} | MultiImplementationA.cs:20:24:20:28 | ... = ... | 5 | +| MultiImplementationA.cs:21:12:21:13 | enter C2 | MultiImplementationA.cs:21:12:21:13 | enter C2 | 1 | +| MultiImplementationA.cs:21:12:21:13 | enter C2 | MultiImplementationB.cs:19:12:19:13 | enter C2 | 1 | +| MultiImplementationA.cs:21:12:21:13 | exit C2 | MultiImplementationA.cs:21:12:21:13 | exit C2 | 1 | +| MultiImplementationA.cs:21:12:21:13 | exit C2 | MultiImplementationB.cs:19:12:19:13 | exit C2 | 1 | +| MultiImplementationA.cs:21:24:21:24 | 0 | MultiImplementationA.cs:21:19:21:22 | call to constructor C2 | 2 | +| MultiImplementationA.cs:21:27:21:29 | {...} | MultiImplementationA.cs:21:27:21:29 | {...} | 1 | +| MultiImplementationA.cs:22:6:22:7 | enter ~C2 | MultiImplementationA.cs:22:6:22:7 | enter ~C2 | 1 | +| MultiImplementationA.cs:22:6:22:7 | enter ~C2 | MultiImplementationB.cs:20:6:20:7 | enter ~C2 | 1 | +| MultiImplementationA.cs:22:6:22:7 | exit ~C2 | MultiImplementationA.cs:22:6:22:7 | exit ~C2 | 1 | +| MultiImplementationA.cs:22:6:22:7 | exit ~C2 | MultiImplementationB.cs:20:6:20:7 | exit ~C2 | 1 | +| MultiImplementationA.cs:22:11:22:13 | {...} | MultiImplementationA.cs:22:11:22:13 | {...} | 1 | +| MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | 1 | +| MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | 1 | +| MultiImplementationA.cs:23:28:23:35 | exit implicit conversion | MultiImplementationA.cs:23:28:23:35 | exit implicit conversion | 1 | +| MultiImplementationA.cs:23:28:23:35 | exit implicit conversion | MultiImplementationB.cs:21:28:21:35 | exit implicit conversion | 1 | +| MultiImplementationA.cs:23:50:23:53 | null | MultiImplementationA.cs:23:50:23:53 | null | 1 | +| MultiImplementationA.cs:24:16:24:16 | this access | MultiImplementationA.cs:24:32:24:34 | ... = ... | 4 | +| MultiImplementationA.cs:30:21:30:23 | enter get_P3 | MultiImplementationA.cs:30:21:30:23 | exit get_P3 | 4 | +| MultiImplementationA.cs:30:21:30:23 | enter get_P3 | MultiImplementationB.cs:27:21:27:23 | exit get_P3 | 4 | +| MultiImplementationA.cs:36:9:36:10 | enter M1 | MultiImplementationA.cs:36:9:36:10 | enter M1 | 1 | +| MultiImplementationA.cs:36:9:36:10 | enter M1 | MultiImplementationB.cs:32:9:32:10 | enter M1 | 1 | +| MultiImplementationA.cs:36:9:36:10 | exit M1 | MultiImplementationA.cs:36:9:36:10 | exit M1 | 1 | +| MultiImplementationA.cs:36:9:36:10 | exit M1 | MultiImplementationB.cs:32:9:32:10 | exit M1 | 1 | +| MultiImplementationA.cs:36:14:36:28 | {...} | MultiImplementationA.cs:36:16:36:26 | throw ...; | 3 | +| MultiImplementationA.cs:37:9:37:10 | enter M2 | MultiImplementationA.cs:37:9:37:10 | exit M2 | 5 | +| MultiImplementationB.cs:3:22:3:22 | 0 | MultiImplementationB.cs:3:22:3:22 | 0 | 1 | +| MultiImplementationB.cs:3:22:3:22 | enter get_P1 | MultiImplementationA.cs:6:22:6:31 | enter get_P1 | 1 | +| MultiImplementationB.cs:3:22:3:22 | enter get_P1 | MultiImplementationB.cs:3:22:3:22 | enter get_P1 | 1 | +| MultiImplementationB.cs:3:22:3:22 | exit get_P1 | MultiImplementationA.cs:6:22:6:31 | exit get_P1 | 1 | +| MultiImplementationB.cs:3:22:3:22 | exit get_P1 | MultiImplementationB.cs:3:22:3:22 | exit get_P1 | 1 | +| MultiImplementationB.cs:4:21:4:23 | enter get_P2 | MultiImplementationA.cs:7:21:7:23 | enter get_P2 | 1 | +| MultiImplementationB.cs:4:21:4:23 | enter get_P2 | MultiImplementationB.cs:4:21:4:23 | enter get_P2 | 1 | +| MultiImplementationB.cs:4:21:4:23 | exit get_P2 | MultiImplementationA.cs:7:21:7:23 | exit get_P2 | 1 | +| MultiImplementationB.cs:4:21:4:23 | exit get_P2 | MultiImplementationB.cs:4:21:4:23 | exit get_P2 | 1 | +| MultiImplementationB.cs:4:25:4:37 | {...} | MultiImplementationB.cs:4:27:4:35 | return ...; | 3 | +| MultiImplementationB.cs:4:39:4:41 | enter set_P2 | MultiImplementationA.cs:7:41:7:43 | enter set_P2 | 1 | +| MultiImplementationB.cs:4:39:4:41 | enter set_P2 | MultiImplementationB.cs:4:39:4:41 | enter set_P2 | 1 | +| MultiImplementationB.cs:4:39:4:41 | exit set_P2 | MultiImplementationA.cs:7:41:7:43 | exit set_P2 | 1 | +| MultiImplementationB.cs:4:39:4:41 | exit set_P2 | MultiImplementationB.cs:4:39:4:41 | exit set_P2 | 1 | +| MultiImplementationB.cs:4:43:4:45 | {...} | MultiImplementationB.cs:4:43:4:45 | {...} | 1 | +| MultiImplementationB.cs:5:16:5:16 | enter M | MultiImplementationA.cs:8:16:8:16 | enter M | 1 | +| MultiImplementationB.cs:5:16:5:16 | enter M | MultiImplementationB.cs:5:16:5:16 | enter M | 1 | +| MultiImplementationB.cs:5:16:5:16 | exit M | MultiImplementationA.cs:8:16:8:16 | exit M | 1 | +| MultiImplementationB.cs:5:16:5:16 | exit M | MultiImplementationB.cs:5:16:5:16 | exit M | 1 | +| MultiImplementationB.cs:5:23:5:23 | 2 | MultiImplementationB.cs:5:23:5:23 | 2 | 1 | +| MultiImplementationB.cs:11:16:11:16 | this access | MultiImplementationB.cs:11:16:11:20 | ... = ... | 3 | +| MultiImplementationB.cs:12:31:12:40 | enter get_Item | MultiImplementationA.cs:14:31:14:31 | enter get_Item | 1 | +| MultiImplementationB.cs:12:31:12:40 | enter get_Item | MultiImplementationB.cs:12:31:12:40 | enter get_Item | 1 | +| MultiImplementationB.cs:12:31:12:40 | exit get_Item | MultiImplementationA.cs:14:31:14:31 | exit get_Item | 1 | +| MultiImplementationB.cs:12:31:12:40 | exit get_Item | MultiImplementationB.cs:12:31:12:40 | exit get_Item | 1 | +| MultiImplementationB.cs:12:37:12:40 | null | MultiImplementationB.cs:12:31:12:40 | throw ... | 2 | +| MultiImplementationB.cs:13:36:13:38 | enter get_Item | MultiImplementationA.cs:15:36:15:38 | enter get_Item | 1 | +| MultiImplementationB.cs:13:36:13:38 | enter get_Item | MultiImplementationB.cs:13:36:13:38 | enter get_Item | 1 | +| MultiImplementationB.cs:13:36:13:38 | exit get_Item | MultiImplementationA.cs:15:36:15:38 | exit get_Item | 1 | +| MultiImplementationB.cs:13:36:13:38 | exit get_Item | MultiImplementationB.cs:13:36:13:38 | exit get_Item | 1 | +| MultiImplementationB.cs:13:40:13:54 | {...} | MultiImplementationB.cs:13:42:13:52 | throw ...; | 3 | +| MultiImplementationB.cs:13:56:13:58 | enter set_Item | MultiImplementationA.cs:15:54:15:56 | enter set_Item | 1 | +| MultiImplementationB.cs:13:56:13:58 | enter set_Item | MultiImplementationB.cs:13:56:13:58 | enter set_Item | 1 | +| MultiImplementationB.cs:13:56:13:58 | exit set_Item | MultiImplementationA.cs:15:54:15:56 | exit set_Item | 1 | +| MultiImplementationB.cs:13:56:13:58 | exit set_Item | MultiImplementationB.cs:13:56:13:58 | exit set_Item | 1 | +| MultiImplementationB.cs:13:60:13:62 | {...} | MultiImplementationB.cs:13:60:13:62 | {...} | 1 | +| MultiImplementationB.cs:14:17:14:18 | enter M1 | MultiImplementationA.cs:16:17:16:18 | enter M1 | 1 | +| MultiImplementationB.cs:14:17:14:18 | enter M1 | MultiImplementationB.cs:14:17:14:18 | enter M1 | 1 | +| MultiImplementationB.cs:14:17:14:18 | exit M1 | MultiImplementationA.cs:16:17:16:18 | exit M1 | 1 | +| MultiImplementationB.cs:14:17:14:18 | exit M1 | MultiImplementationB.cs:14:17:14:18 | exit M1 | 1 | +| MultiImplementationB.cs:15:5:17:5 | {...} | MultiImplementationB.cs:16:9:16:31 | M2(...) | 2 | +| MultiImplementationB.cs:16:9:16:31 | enter M2 | MultiImplementationB.cs:16:9:16:31 | exit M2 | 4 | +| MultiImplementationB.cs:18:12:18:13 | enter C2 | MultiImplementationA.cs:20:12:20:13 | enter C2 | 1 | +| MultiImplementationB.cs:18:12:18:13 | enter C2 | MultiImplementationB.cs:18:12:18:13 | enter C2 | 1 | +| MultiImplementationB.cs:18:12:18:13 | exit C2 | MultiImplementationA.cs:20:12:20:13 | exit C2 | 1 | +| MultiImplementationB.cs:18:12:18:13 | exit C2 | MultiImplementationB.cs:18:12:18:13 | exit C2 | 1 | +| MultiImplementationB.cs:18:22:18:36 | {...} | MultiImplementationB.cs:18:24:18:34 | throw ...; | 3 | +| MultiImplementationB.cs:19:12:19:13 | enter C2 | MultiImplementationA.cs:21:12:21:13 | enter C2 | 1 | +| MultiImplementationB.cs:19:12:19:13 | enter C2 | MultiImplementationB.cs:19:12:19:13 | enter C2 | 1 | +| MultiImplementationB.cs:19:12:19:13 | exit C2 | MultiImplementationA.cs:21:12:21:13 | exit C2 | 1 | +| MultiImplementationB.cs:19:12:19:13 | exit C2 | MultiImplementationB.cs:19:12:19:13 | exit C2 | 1 | +| MultiImplementationB.cs:19:24:19:24 | 1 | MultiImplementationB.cs:19:19:19:22 | call to constructor C2 | 2 | +| MultiImplementationB.cs:19:27:19:29 | {...} | MultiImplementationB.cs:19:27:19:29 | {...} | 1 | +| MultiImplementationB.cs:20:6:20:7 | enter ~C2 | MultiImplementationA.cs:22:6:22:7 | enter ~C2 | 1 | +| MultiImplementationB.cs:20:6:20:7 | enter ~C2 | MultiImplementationB.cs:20:6:20:7 | enter ~C2 | 1 | +| MultiImplementationB.cs:20:6:20:7 | exit ~C2 | MultiImplementationA.cs:22:6:22:7 | exit ~C2 | 1 | +| MultiImplementationB.cs:20:6:20:7 | exit ~C2 | MultiImplementationB.cs:20:6:20:7 | exit ~C2 | 1 | +| MultiImplementationB.cs:20:11:20:25 | {...} | MultiImplementationB.cs:20:13:20:23 | throw ...; | 3 | +| MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | 1 | +| MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | 1 | +| MultiImplementationB.cs:21:28:21:35 | exit implicit conversion | MultiImplementationA.cs:23:28:23:35 | exit implicit conversion | 1 | +| MultiImplementationB.cs:21:28:21:35 | exit implicit conversion | MultiImplementationB.cs:21:28:21:35 | exit implicit conversion | 1 | +| MultiImplementationB.cs:21:56:21:59 | null | MultiImplementationB.cs:21:50:21:59 | throw ... | 2 | +| MultiImplementationB.cs:22:16:22:16 | this access | MultiImplementationB.cs:22:32:22:34 | ... = ... | 4 | +| MultiImplementationB.cs:27:21:27:23 | enter get_P3 | MultiImplementationA.cs:30:21:30:23 | exit get_P3 | 4 | +| MultiImplementationB.cs:27:21:27:23 | enter get_P3 | MultiImplementationB.cs:27:21:27:23 | exit get_P3 | 4 | +| MultiImplementationB.cs:32:9:32:10 | enter M1 | MultiImplementationA.cs:36:9:36:10 | enter M1 | 1 | +| MultiImplementationB.cs:32:9:32:10 | enter M1 | MultiImplementationB.cs:32:9:32:10 | enter M1 | 1 | +| MultiImplementationB.cs:32:9:32:10 | exit M1 | MultiImplementationA.cs:36:9:36:10 | exit M1 | 1 | +| MultiImplementationB.cs:32:9:32:10 | exit M1 | MultiImplementationB.cs:32:9:32:10 | exit M1 | 1 | +| MultiImplementationB.cs:32:17:32:17 | 0 | MultiImplementationB.cs:32:17:32:17 | 0 | 1 | | NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:23:3:23 | access to parameter i | 3 | | NullCoalescing.cs:3:9:3:10 | exit M1 | NullCoalescing.cs:3:9:3:10 | exit M1 | 1 | | NullCoalescing.cs:3:28:3:28 | 0 | NullCoalescing.cs:3:28:3:28 | 0 | 1 | @@ -520,35 +796,35 @@ | Switch.cs:55:10:55:11 | enter M5 | Switch.cs:55:10:55:11 | exit M5 | 12 | | Switch.cs:66:10:66:11 | enter M6 | Switch.cs:72:18:72:19 | "" | 9 | | Switch.cs:66:10:66:11 | exit M6 | Switch.cs:66:10:66:11 | exit M6 | 1 | -| Switch.cs:73:15:73:20 | break; | Switch.cs:73:15:73:20 | break; | 1 | +| Switch.cs:73:17:73:22 | break; | Switch.cs:73:17:73:22 | break; | 1 | | Switch.cs:77:10:77:11 | enter M7 | Switch.cs:81:18:81:18 | 1 | 6 | | Switch.cs:77:10:77:11 | exit M7 | Switch.cs:77:10:77:11 | exit M7 | 1 | -| Switch.cs:82:22:82:25 | true | Switch.cs:82:15:82:26 | return ...; | 2 | -| Switch.cs:83:13:83:20 | case ...: | Switch.cs:83:18:83:18 | 2 | 2 | -| Switch.cs:84:15:85:22 | if (...) ... | Switch.cs:84:19:84:23 | ... > ... | 4 | -| Switch.cs:85:17:85:22 | break; | Switch.cs:85:17:85:22 | break; | 1 | -| Switch.cs:86:22:86:25 | true | Switch.cs:86:15:86:26 | return ...; | 2 | +| Switch.cs:82:24:82:27 | true | Switch.cs:82:17:82:28 | return ...; | 2 | +| Switch.cs:83:13:83:19 | case ...: | Switch.cs:83:18:83:18 | 2 | 2 | +| Switch.cs:84:17:85:26 | if (...) ... | Switch.cs:84:21:84:25 | ... > ... | 4 | +| Switch.cs:85:21:85:26 | break; | Switch.cs:85:21:85:26 | break; | 1 | +| Switch.cs:86:24:86:27 | true | Switch.cs:86:17:86:28 | return ...; | 2 | | Switch.cs:88:16:88:20 | false | Switch.cs:88:9:88:21 | return ...; | 2 | | Switch.cs:91:10:91:11 | enter M8 | Switch.cs:95:18:95:20 | access to type Int32 | 6 | | Switch.cs:91:10:91:11 | exit M8 | Switch.cs:91:10:91:11 | exit M8 | 1 | -| Switch.cs:96:22:96:25 | true | Switch.cs:96:15:96:26 | return ...; | 2 | +| Switch.cs:96:24:96:27 | true | Switch.cs:96:17:96:28 | return ...; | 2 | | Switch.cs:98:16:98:20 | false | Switch.cs:98:9:98:21 | return ...; | 2 | | Switch.cs:101:9:101:10 | enter M9 | Switch.cs:103:17:103:17 | access to parameter s | 4 | | Switch.cs:101:9:101:10 | exit M9 | Switch.cs:101:9:101:10 | exit M9 | 1 | | Switch.cs:103:19:103:25 | access to property Length | Switch.cs:103:19:103:25 | access to property Length | 1 | -| Switch.cs:105:13:105:20 | case ...: | Switch.cs:105:18:105:18 | 0 | 2 | -| Switch.cs:105:29:105:29 | 0 | Switch.cs:105:22:105:30 | return ...; | 2 | -| Switch.cs:106:13:106:20 | case ...: | Switch.cs:106:18:106:18 | 1 | 2 | -| Switch.cs:106:29:106:29 | 1 | Switch.cs:106:22:106:30 | return ...; | 2 | +| Switch.cs:105:13:105:19 | case ...: | Switch.cs:105:18:105:18 | 0 | 2 | +| Switch.cs:105:28:105:28 | 0 | Switch.cs:105:21:105:29 | return ...; | 2 | +| Switch.cs:106:13:106:19 | case ...: | Switch.cs:106:18:106:18 | 1 | 2 | +| Switch.cs:106:28:106:28 | 1 | Switch.cs:106:21:106:29 | return ...; | 2 | | Switch.cs:108:17:108:17 | 1 | Switch.cs:108:9:108:18 | return ...; | 3 | | Switch.cs:111:17:111:21 | enter Throw | Switch.cs:111:17:111:21 | exit Throw | 4 | | Switch.cs:113:9:113:11 | enter M10 | Switch.cs:117:18:117:18 | 3 | 7 | | Switch.cs:113:9:113:11 | exit M10 | Switch.cs:113:9:113:11 | exit M10 | 1 | -| Switch.cs:117:25:117:25 | access to parameter s | Switch.cs:117:25:117:32 | ... == ... | 3 | -| Switch.cs:117:43:117:43 | 1 | Switch.cs:117:36:117:44 | return ...; | 2 | -| Switch.cs:118:13:118:33 | case ...: | Switch.cs:118:18:118:18 | 2 | 2 | -| Switch.cs:118:25:118:25 | access to parameter s | Switch.cs:118:25:118:31 | ... == ... | 3 | -| Switch.cs:118:42:118:42 | 2 | Switch.cs:118:35:118:43 | return ...; | 2 | +| Switch.cs:117:25:117:25 | access to parameter s | Switch.cs:117:25:117:34 | ... == ... | 3 | +| Switch.cs:117:44:117:44 | 1 | Switch.cs:117:37:117:45 | return ...; | 2 | +| Switch.cs:118:13:118:34 | case ...: | Switch.cs:118:18:118:18 | 2 | 2 | +| Switch.cs:118:25:118:25 | access to parameter s | Switch.cs:118:25:118:33 | ... == ... | 3 | +| Switch.cs:118:43:118:43 | 2 | Switch.cs:118:36:118:44 | return ...; | 2 | | Switch.cs:120:17:120:17 | 1 | Switch.cs:120:9:120:18 | return ...; | 3 | | Switch.cs:123:10:123:12 | enter M11 | Switch.cs:125:24:125:29 | Boolean b | 7 | | Switch.cs:123:10:123:12 | exit M11 | Switch.cs:123:10:123:12 | exit M11 | 1 | @@ -572,10 +848,18 @@ | Switch.cs:149:13:149:20 | default: | Switch.cs:149:22:149:31 | return ...; | 4 | | Switch.cs:150:13:150:19 | case ...: | Switch.cs:150:18:150:18 | 2 | 2 | | Switch.cs:150:28:150:28 | 2 | Switch.cs:150:21:150:29 | return ...; | 2 | +| Switch.cs:154:10:154:12 | enter M15 | Switch.cs:156:28:156:31 | true | 7 | +| Switch.cs:154:10:154:12 | exit M15 | Switch.cs:154:10:154:12 | exit M15 | 1 | +| Switch.cs:156:13:156:54 | String s = ... | Switch.cs:157:13:157:13 | access to parameter b | 3 | +| Switch.cs:156:36:156:38 | "a" | Switch.cs:156:36:156:38 | "a" | 1 | +| Switch.cs:156:41:156:52 | ... => ... | Switch.cs:156:41:156:45 | false | 2 | +| Switch.cs:156:50:156:52 | "b" | Switch.cs:156:50:156:52 | "b" | 1 | +| Switch.cs:158:13:158:49 | ...; | Switch.cs:158:13:158:48 | call to method WriteLine | 5 | +| Switch.cs:160:13:160:49 | ...; | Switch.cs:160:13:160:48 | call to method WriteLine | 5 | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:7:13:7:22 | ... is ... | 14 | | TypeAccesses.cs:7:25:7:25 | ; | TypeAccesses.cs:7:25:7:25 | ; | 1 | | TypeAccesses.cs:8:9:8:28 | ... ...; | TypeAccesses.cs:3:10:3:10 | exit M | 4 | -| VarDecls.cs:5:18:5:19 | enter M1 | VarDecls.cs:5:18:5:19 | exit M1 | 16 | +| VarDecls.cs:5:18:5:19 | enter M1 | VarDecls.cs:5:18:5:19 | exit M1 | 18 | | VarDecls.cs:13:12:13:13 | enter M2 | VarDecls.cs:13:12:13:13 | exit M2 | 12 | | VarDecls.cs:19:7:19:8 | enter M3 | VarDecls.cs:25:20:25:20 | access to parameter b | 12 | | VarDecls.cs:25:13:25:29 | return ...; | VarDecls.cs:19:7:19:8 | exit M3 | 2 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Condition.expected b/csharp/ql/test/library-tests/controlflow/graph/Condition.expected index 4937b513ac9f..df9d8425b5f2 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Condition.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Condition.expected @@ -1,4 +1,299 @@ conditionBlock +| Assert.cs:7:10:7:11 | enter M1 | Assert.cs:9:24:9:27 | null | true | +| Assert.cs:7:10:7:11 | enter M1 | Assert.cs:9:31:9:32 | "" | false | +| Assert.cs:9:16:9:32 | String s = ... | Assert.cs:10:9:10:31 | [assertion failure] call to method Assert | false | +| Assert.cs:9:16:9:32 | String s = ... | Assert.cs:10:9:10:31 | [assertion success] call to method Assert | true | +| Assert.cs:14:10:14:11 | enter M2 | Assert.cs:16:24:16:27 | null | true | +| Assert.cs:14:10:14:11 | enter M2 | Assert.cs:16:31:16:32 | "" | false | +| Assert.cs:16:16:16:32 | String s = ... | Assert.cs:17:9:17:24 | [assertion failure] call to method IsNull | false | +| Assert.cs:16:16:16:32 | String s = ... | Assert.cs:17:9:17:24 | [assertion success] call to method IsNull | true | +| Assert.cs:21:10:21:11 | enter M3 | Assert.cs:23:24:23:27 | null | true | +| Assert.cs:21:10:21:11 | enter M3 | Assert.cs:23:31:23:32 | "" | false | +| Assert.cs:23:16:23:32 | String s = ... | Assert.cs:24:9:24:27 | [assertion failure] call to method IsNotNull | true | +| Assert.cs:23:16:23:32 | String s = ... | Assert.cs:24:9:24:27 | [assertion success] call to method IsNotNull | false | +| Assert.cs:28:10:28:11 | enter M4 | Assert.cs:30:24:30:27 | null | true | +| Assert.cs:28:10:28:11 | enter M4 | Assert.cs:30:31:30:32 | "" | false | +| Assert.cs:30:16:30:32 | String s = ... | Assert.cs:31:9:31:32 | [assertion failure] call to method IsTrue | false | +| Assert.cs:30:16:30:32 | String s = ... | Assert.cs:31:9:31:32 | [assertion success] call to method IsTrue | true | +| Assert.cs:35:10:35:11 | enter M5 | Assert.cs:37:24:37:27 | null | true | +| Assert.cs:35:10:35:11 | enter M5 | Assert.cs:37:31:37:32 | "" | false | +| Assert.cs:37:16:37:32 | String s = ... | Assert.cs:38:9:38:32 | [assertion failure] call to method IsTrue | false | +| Assert.cs:37:16:37:32 | String s = ... | Assert.cs:38:9:38:32 | [assertion success] call to method IsTrue | true | +| Assert.cs:42:10:42:11 | enter M6 | Assert.cs:44:24:44:27 | null | true | +| Assert.cs:42:10:42:11 | enter M6 | Assert.cs:44:31:44:32 | "" | false | +| Assert.cs:44:16:44:32 | String s = ... | Assert.cs:45:9:45:33 | [assertion failure] call to method IsFalse | true | +| Assert.cs:44:16:44:32 | String s = ... | Assert.cs:45:9:45:33 | [assertion success] call to method IsFalse | false | +| Assert.cs:49:10:49:11 | enter M7 | Assert.cs:51:24:51:27 | null | true | +| Assert.cs:49:10:49:11 | enter M7 | Assert.cs:51:31:51:32 | "" | false | +| Assert.cs:51:16:51:32 | String s = ... | Assert.cs:52:9:52:33 | [assertion failure] call to method IsFalse | true | +| Assert.cs:51:16:51:32 | String s = ... | Assert.cs:52:9:52:33 | [assertion success] call to method IsFalse | false | +| Assert.cs:56:10:56:11 | enter M8 | Assert.cs:58:24:58:27 | [b (line 56): true] null | true | +| Assert.cs:56:10:56:11 | enter M8 | Assert.cs:58:31:58:32 | [b (line 56): false] "" | false | +| Assert.cs:56:10:56:11 | enter M8 | Assert.cs:59:36:59:36 | [b (line 56): false] access to parameter b | false | +| Assert.cs:56:10:56:11 | enter M8 | Assert.cs:59:36:59:36 | [b (line 56): true] access to parameter b | true | +| Assert.cs:58:24:58:27 | [b (line 56): true] null | Assert.cs:59:36:59:36 | [b (line 56): true] access to parameter b | true | +| Assert.cs:58:31:58:32 | [b (line 56): false] "" | Assert.cs:59:36:59:36 | [b (line 56): false] access to parameter b | true | +| Assert.cs:63:10:63:11 | enter M9 | Assert.cs:65:24:65:27 | [b (line 63): true] null | true | +| Assert.cs:63:10:63:11 | enter M9 | Assert.cs:65:31:65:32 | [b (line 63): false] "" | false | +| Assert.cs:63:10:63:11 | enter M9 | Assert.cs:66:37:66:37 | [b (line 63): false] access to parameter b | false | +| Assert.cs:63:10:63:11 | enter M9 | Assert.cs:66:37:66:37 | [b (line 63): true] access to parameter b | true | +| Assert.cs:65:24:65:27 | [b (line 63): true] null | Assert.cs:66:37:66:37 | [b (line 63): true] access to parameter b | false | +| Assert.cs:65:31:65:32 | [b (line 63): false] "" | Assert.cs:66:37:66:37 | [b (line 63): false] access to parameter b | false | +| Assert.cs:70:10:70:12 | enter M10 | Assert.cs:72:24:72:27 | [b (line 70): true] null | true | +| Assert.cs:70:10:70:12 | enter M10 | Assert.cs:72:31:72:32 | [b (line 70): false] "" | false | +| Assert.cs:70:10:70:12 | enter M10 | Assert.cs:73:36:73:36 | [b (line 70): false] access to parameter b | false | +| Assert.cs:70:10:70:12 | enter M10 | Assert.cs:73:36:73:36 | [b (line 70): true] access to parameter b | true | +| Assert.cs:72:24:72:27 | [b (line 70): true] null | Assert.cs:73:36:73:36 | [b (line 70): true] access to parameter b | true | +| Assert.cs:72:31:72:32 | [b (line 70): false] "" | Assert.cs:73:36:73:36 | [b (line 70): false] access to parameter b | true | +| Assert.cs:77:10:77:12 | enter M11 | Assert.cs:79:24:79:27 | [b (line 77): true] null | true | +| Assert.cs:77:10:77:12 | enter M11 | Assert.cs:79:31:79:32 | [b (line 77): false] "" | false | +| Assert.cs:77:10:77:12 | enter M11 | Assert.cs:80:37:80:37 | [b (line 77): false] access to parameter b | false | +| Assert.cs:77:10:77:12 | enter M11 | Assert.cs:80:37:80:37 | [b (line 77): true] access to parameter b | true | +| Assert.cs:79:24:79:27 | [b (line 77): true] null | Assert.cs:80:37:80:37 | [b (line 77): true] access to parameter b | false | +| Assert.cs:79:31:79:32 | [b (line 77): false] "" | Assert.cs:80:37:80:37 | [b (line 77): false] access to parameter b | false | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:86:24:86:27 | [b (line 84): true] null | true | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:86:31:86:32 | [b (line 84): false] "" | false | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:87:9:87:31 | [assertion failure, b (line 84): false] call to method Assert | false | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:87:9:87:31 | [assertion failure, b (line 84): true] call to method Assert | true | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | false | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | true | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:91:9:91:24 | [assertion failure, b (line 84): false] call to method IsNull | false | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:91:9:91:24 | [assertion failure, b (line 84): true] call to method IsNull | true | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | false | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | true | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): false] call to method IsNotNull | false | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): true] call to method IsNotNull | true | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | false | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | true | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): false] call to method IsTrue | false | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): true] call to method IsTrue | true | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | false | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | true | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): false] call to method IsTrue | false | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): true] call to method IsTrue | true | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | false | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | true | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | false | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | true | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | false | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | true | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | false | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | true | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | false | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | true | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | false | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | true | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | false | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | true | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | true | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:119:37:119:38 | [b (line 84): true] !... | true | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | true | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | true | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | true | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:127:37:127:38 | [b (line 84): true] !... | true | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:87:9:87:31 | [assertion failure, b (line 84): true] call to method Assert | false | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | true | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:91:9:91:24 | [assertion failure, b (line 84): true] call to method IsNull | true | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | true | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): true] call to method IsNotNull | true | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | true | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): true] call to method IsTrue | true | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | true | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): true] call to method IsTrue | true | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | true | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | true | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | true | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | true | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | true | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | true | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | true | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | true | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:119:37:119:38 | [b (line 84): true] !... | true | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | true | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | true | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | true | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:127:37:127:38 | [b (line 84): true] !... | true | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:87:9:87:31 | [assertion failure, b (line 84): false] call to method Assert | false | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | true | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:91:9:91:24 | [assertion failure, b (line 84): false] call to method IsNull | true | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | true | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): false] call to method IsNotNull | true | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | true | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): false] call to method IsTrue | true | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | true | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): false] call to method IsTrue | true | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | true | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | true | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | true | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | true | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | true | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | true | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:91:9:91:24 | [assertion failure, b (line 84): false] call to method IsNull | false | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): false] call to method IsNotNull | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): false] call to method IsTrue | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): false] call to method IsTrue | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:91:9:91:24 | [assertion failure, b (line 84): true] call to method IsNull | false | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): true] call to method IsNotNull | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): true] call to method IsTrue | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): true] call to method IsTrue | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:119:37:119:38 | [b (line 84): true] !... | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:127:37:127:38 | [b (line 84): true] !... | true | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): false] call to method IsNotNull | true | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): false] call to method IsTrue | false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): false] call to method IsTrue | false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): true] call to method IsNotNull | true | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): true] call to method IsTrue | false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): true] call to method IsTrue | false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:119:37:119:38 | [b (line 84): true] !... | false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:127:37:127:38 | [b (line 84): true] !... | false | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): false] call to method IsTrue | false | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | true | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): false] call to method IsTrue | true | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | true | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | true | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | true | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | true | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | true | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | true | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | true | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): true] call to method IsTrue | false | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | true | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): true] call to method IsTrue | true | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | true | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | true | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | true | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | true | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | true | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | true | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | true | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | true | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:119:37:119:38 | [b (line 84): true] !... | true | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | true | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | true | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | true | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:127:37:127:38 | [b (line 84): true] !... | true | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): false] call to method IsTrue | false | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | true | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | true | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | true | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | true | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | true | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | true | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | true | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): true] call to method IsTrue | false | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | true | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | true | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | true | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | true | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | true | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | true | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | true | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | true | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:119:37:119:38 | [b (line 84): true] !... | true | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | true | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | true | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | true | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:127:37:127:38 | [b (line 84): true] !... | true | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | true | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | false | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | false | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | false | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | false | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | false | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | true | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | false | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | false | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | false | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | false | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | false | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | false | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:119:37:119:38 | [b (line 84): true] !... | false | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | false | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | false | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | false | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:127:37:127:38 | [b (line 84): true] !... | false | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | true | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | false | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | false | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | false | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | true | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | false | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | false | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | false | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | false | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:119:37:119:38 | [b (line 84): true] !... | false | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | false | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | false | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | false | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:127:37:127:38 | [b (line 84): true] !... | false | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | true | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | false | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | true | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | true | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:119:37:119:38 | [b (line 84): true] !... | true | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | true | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | true | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | true | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:127:37:127:38 | [b (line 84): true] !... | true | +| Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | true | +| Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | Assert.cs:119:37:119:38 | [b (line 84): true] !... | false | +| Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | false | +| Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | false | +| Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | false | +| Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | Assert.cs:127:37:127:38 | [b (line 84): true] !... | false | +| Assert.cs:119:37:119:38 | [b (line 84): true] !... | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | false | +| Assert.cs:119:37:119:38 | [b (line 84): true] !... | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | true | +| Assert.cs:119:37:119:38 | [b (line 84): true] !... | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | true | +| Assert.cs:119:37:119:38 | [b (line 84): true] !... | Assert.cs:127:37:127:38 | [b (line 84): true] !... | true | +| Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | true | +| Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | Assert.cs:127:37:127:38 | [b (line 84): true] !... | false | | BreakInTry.cs:7:13:11:13 | foreach (... ... in ...) ... | BreakInTry.cs:7:26:7:28 | String arg | false | | BreakInTry.cs:7:13:11:13 | foreach (... ... in ...) ... | BreakInTry.cs:10:21:10:26 | break; | false | | BreakInTry.cs:7:26:7:28 | String arg | BreakInTry.cs:10:21:10:26 | break; | true | @@ -53,6 +348,7 @@ conditionBlock | ConditionalAccess.cs:13:25:13:25 | 0 | ConditionalAccess.cs:14:20:14:20 | 0 | true | | ConditionalAccess.cs:13:25:13:25 | 0 | ConditionalAccess.cs:16:20:16:20 | 1 | false | | ConditionalAccess.cs:19:12:19:13 | enter M6 | ConditionalAccess.cs:19:58:19:59 | access to parameter s2 | false | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:35:14:35:24 | call to method Out | false | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:6:13:6:16 | [inc (line 3): true] ...; | true | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:7:9:8:16 | [inc (line 3): false] if (...) ... | false | | Conditions.cs:11:9:11:10 | enter M1 | Conditions.cs:15:13:15:16 | [b (line 11): true] ...; | true | @@ -125,11 +421,11 @@ conditionBlock | Conditions.cs:102:12:102:13 | enter M8 | Conditions.cs:108:13:109:24 | [b (line 102): true] if (...) ... | true | | Conditions.cs:106:13:106:20 | [b (line 102): true] ...; | Conditions.cs:108:13:109:24 | [b (line 102): true] if (...) ... | true | | Conditions.cs:107:9:109:24 | [b (line 102): false] if (...) ... | Conditions.cs:108:13:109:24 | [b (line 102): false] if (...) ... | true | -| Conditions.cs:116:24:116:24 | access to local variable i | Conditions.cs:113:10:113:11 | exit M9 | false | -| Conditions.cs:116:24:116:24 | access to local variable i | Conditions.cs:116:41:116:41 | access to local variable i | true | -| Conditions.cs:116:24:116:24 | access to local variable i | Conditions.cs:117:9:123:9 | {...} | true | -| Conditions.cs:116:24:116:24 | access to local variable i | Conditions.cs:120:17:120:23 | [last (line 118): false] ...; | true | -| Conditions.cs:116:24:116:24 | access to local variable i | Conditions.cs:121:13:122:25 | [last (line 118): true] if (...) ... | true | +| Conditions.cs:116:25:116:25 | access to local variable i | Conditions.cs:113:10:113:11 | exit M9 | false | +| Conditions.cs:116:25:116:25 | access to local variable i | Conditions.cs:116:42:116:42 | access to local variable i | true | +| Conditions.cs:116:25:116:25 | access to local variable i | Conditions.cs:117:9:123:9 | {...} | true | +| Conditions.cs:116:25:116:25 | access to local variable i | Conditions.cs:120:17:120:23 | [last (line 118): false] ...; | true | +| Conditions.cs:116:25:116:25 | access to local variable i | Conditions.cs:121:13:122:25 | [last (line 118): true] if (...) ... | true | | Conditions.cs:117:9:123:9 | {...} | Conditions.cs:120:17:120:23 | [last (line 118): false] ...; | false | | Conditions.cs:117:9:123:9 | {...} | Conditions.cs:121:13:122:25 | [last (line 118): true] if (...) ... | true | | Conditions.cs:129:10:129:12 | enter M10 | Conditions.cs:131:16:131:19 | [Field1 (line 129): false] true | false | @@ -138,6 +434,8 @@ conditionBlock | Conditions.cs:129:10:129:12 | enter M10 | Conditions.cs:136:17:138:17 | [Field1 (line 129): true, Field2 (line 129): true] {...} | true | | Conditions.cs:134:13:139:13 | [Field1 (line 129): true] {...} | Conditions.cs:131:16:131:19 | [Field1 (line 129): true, Field2 (line 129): false] true | false | | Conditions.cs:134:13:139:13 | [Field1 (line 129): true] {...} | Conditions.cs:136:17:138:17 | [Field1 (line 129): true, Field2 (line 129): true] {...} | true | +| Conditions.cs:143:10:143:12 | enter M11 | Conditions.cs:145:21:145:23 | [b (line 143): true] "a" | true | +| Conditions.cs:143:10:143:12 | enter M11 | Conditions.cs:145:27:145:29 | [b (line 143): false] "b" | false | | ExitMethods.cs:43:9:46:9 | [exception: Exception] catch (...) {...} | ExitMethods.cs:47:9:50:9 | [exception: Exception] catch (...) {...} | false | | ExitMethods.cs:65:17:65:26 | enter ErrorMaybe | ExitMethods.cs:68:19:68:33 | object creation of type Exception | true | | ExitMethods.cs:71:17:71:27 | enter ErrorAlways | ExitMethods.cs:74:19:74:33 | object creation of type Exception | true | @@ -146,6 +444,8 @@ conditionBlock | ExitMethods.cs:109:13:109:21 | enter ThrowExpr | ExitMethods.cs:111:69:111:75 | "input" | false | | ExitMethods.cs:114:16:114:34 | enter ExtensionMethodCall | ExitMethods.cs:116:34:116:34 | 0 | true | | ExitMethods.cs:114:16:114:34 | enter ExtensionMethodCall | ExitMethods.cs:116:38:116:38 | 1 | false | +| ExitMethods.cs:131:10:131:20 | enter AssertFalse | ExitMethods.cs:131:33:131:49 | [assertion failure] call to method IsFalse | true | +| ExitMethods.cs:131:10:131:20 | enter AssertFalse | ExitMethods.cs:131:33:131:49 | [assertion success] call to method IsFalse | false | | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | Finally.cs:26:38:26:39 | [exception: Exception] IOException ex | true | | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | false | | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | Finally.cs:30:41:30:42 | [exception: Exception] ArgumentException ex | false | @@ -423,39 +723,37 @@ conditionBlock | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:36:10:36:11 | exit M6 | true | | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:26:38:26 | String x | false | | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:10:13:10:19 | return ...; | true | -| LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:11:21:11:23 | String arg | false | -| LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:11:28:11:31 | access to parameter args | false | -| LoopUnrolling.cs:11:28:11:31 | access to parameter args | LoopUnrolling.cs:11:21:11:23 | String arg | false | +| LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:11:22:11:24 | String arg | false | +| LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:11:29:11:32 | access to parameter args | false | +| LoopUnrolling.cs:11:29:11:32 | access to parameter args | LoopUnrolling.cs:11:22:11:24 | String arg | false | | LoopUnrolling.cs:15:10:15:11 | enter M2 | LoopUnrolling.cs:15:10:15:11 | exit M2 | false | -| LoopUnrolling.cs:15:10:15:11 | enter M2 | LoopUnrolling.cs:18:21:18:21 | String x | false | -| LoopUnrolling.cs:18:21:18:21 | String x | LoopUnrolling.cs:15:10:15:11 | exit M2 | true | +| LoopUnrolling.cs:15:10:15:11 | enter M2 | LoopUnrolling.cs:18:22:18:22 | String x | false | +| LoopUnrolling.cs:18:22:18:22 | String x | LoopUnrolling.cs:15:10:15:11 | exit M2 | true | | LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:22:10:22:11 | exit M3 | true | | LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:24:22:24:24 | Char arg | false | | LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:25:26:25:29 | Char arg0 | false | | LoopUnrolling.cs:24:22:24:24 | Char arg | LoopUnrolling.cs:25:26:25:29 | Char arg0 | false | -| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:29:10:29:11 | exit M4 | true | -| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:32:21:32:21 | String x | false | | LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:36:10:36:11 | exit M5 | false | | LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | false | -| LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:40:21:40:21 | String x | false | -| LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:41:25:41:25 | String y | false | +| LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:40:22:40:22 | String x | false | +| LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:41:26:41:26 | String y | false | | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:36:10:36:11 | exit M5 | true | -| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:36:10:36:11 | exit M5 | false | -| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | false | -| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:41:25:41:25 | String y | false | -| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:36:10:36:11 | exit M5 | true | -| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | true | -| LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | false | -| LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | true | +| LoopUnrolling.cs:40:22:40:22 | String x | LoopUnrolling.cs:36:10:36:11 | exit M5 | false | +| LoopUnrolling.cs:40:22:40:22 | String x | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | false | +| LoopUnrolling.cs:40:22:40:22 | String x | LoopUnrolling.cs:41:26:41:26 | String y | false | +| LoopUnrolling.cs:41:26:41:26 | String y | LoopUnrolling.cs:36:10:36:11 | exit M5 | true | +| LoopUnrolling.cs:41:26:41:26 | String y | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | true | +| LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:58:22:58:22 | [b (line 55): false] String x | false | +| LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:58:22:58:22 | [b (line 55): true] String x | true | | LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | true | | LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | false | -| LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | false | -| LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | false | +| LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | LoopUnrolling.cs:58:22:58:22 | [b (line 55): true] String x | false | +| LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | LoopUnrolling.cs:58:22:58:22 | [b (line 55): false] String x | false | | LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:70:13:70:19 | return ...; | false | | LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:71:9:71:21 | ...; | true | -| LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | true | -| LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:72:21:72:23 | String arg | true | -| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:72:21:72:23 | String arg | false | +| LoopUnrolling.cs:94:10:94:12 | enter M11 | LoopUnrolling.cs:94:10:94:12 | exit M11 | false | +| LoopUnrolling.cs:94:10:94:12 | enter M11 | LoopUnrolling.cs:97:22:97:22 | String x | false | +| LoopUnrolling.cs:97:22:97:22 | String x | LoopUnrolling.cs:94:10:94:12 | exit M11 | true | | NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:28:3:28 | 0 | true | | NullCoalescing.cs:5:9:5:10 | enter M2 | NullCoalescing.cs:5:30:5:34 | false | true | | NullCoalescing.cs:5:9:5:10 | enter M2 | NullCoalescing.cs:5:39:5:39 | 0 | true | @@ -568,33 +866,33 @@ conditionBlock | Switch.cs:50:13:50:39 | case ...: | Switch.cs:50:30:50:30 | access to parameter o | true | | Switch.cs:50:13:50:39 | case ...: | Switch.cs:51:17:51:22 | break; | true | | Switch.cs:50:30:50:30 | access to parameter o | Switch.cs:51:17:51:22 | break; | true | -| Switch.cs:66:10:66:11 | enter M6 | Switch.cs:73:15:73:20 | break; | true | -| Switch.cs:77:10:77:11 | enter M7 | Switch.cs:82:22:82:25 | true | true | -| Switch.cs:77:10:77:11 | enter M7 | Switch.cs:83:13:83:20 | case ...: | false | -| Switch.cs:77:10:77:11 | enter M7 | Switch.cs:84:15:85:22 | if (...) ... | false | -| Switch.cs:77:10:77:11 | enter M7 | Switch.cs:85:17:85:22 | break; | false | -| Switch.cs:77:10:77:11 | enter M7 | Switch.cs:86:22:86:25 | true | false | +| Switch.cs:66:10:66:11 | enter M6 | Switch.cs:73:17:73:22 | break; | true | +| Switch.cs:77:10:77:11 | enter M7 | Switch.cs:82:24:82:27 | true | true | +| Switch.cs:77:10:77:11 | enter M7 | Switch.cs:83:13:83:19 | case ...: | false | +| Switch.cs:77:10:77:11 | enter M7 | Switch.cs:84:17:85:26 | if (...) ... | false | +| Switch.cs:77:10:77:11 | enter M7 | Switch.cs:85:21:85:26 | break; | false | +| Switch.cs:77:10:77:11 | enter M7 | Switch.cs:86:24:86:27 | true | false | | Switch.cs:77:10:77:11 | enter M7 | Switch.cs:88:16:88:20 | false | false | -| Switch.cs:83:13:83:20 | case ...: | Switch.cs:84:15:85:22 | if (...) ... | true | -| Switch.cs:83:13:83:20 | case ...: | Switch.cs:85:17:85:22 | break; | true | -| Switch.cs:83:13:83:20 | case ...: | Switch.cs:86:22:86:25 | true | true | -| Switch.cs:84:15:85:22 | if (...) ... | Switch.cs:85:17:85:22 | break; | true | -| Switch.cs:84:15:85:22 | if (...) ... | Switch.cs:86:22:86:25 | true | false | -| Switch.cs:91:10:91:11 | enter M8 | Switch.cs:96:22:96:25 | true | true | +| Switch.cs:83:13:83:19 | case ...: | Switch.cs:84:17:85:26 | if (...) ... | true | +| Switch.cs:83:13:83:19 | case ...: | Switch.cs:85:21:85:26 | break; | true | +| Switch.cs:83:13:83:19 | case ...: | Switch.cs:86:24:86:27 | true | true | +| Switch.cs:84:17:85:26 | if (...) ... | Switch.cs:85:21:85:26 | break; | true | +| Switch.cs:84:17:85:26 | if (...) ... | Switch.cs:86:24:86:27 | true | false | +| Switch.cs:91:10:91:11 | enter M8 | Switch.cs:96:24:96:27 | true | true | | Switch.cs:91:10:91:11 | enter M8 | Switch.cs:98:16:98:20 | false | false | | Switch.cs:101:9:101:10 | enter M9 | Switch.cs:103:19:103:25 | access to property Length | false | -| Switch.cs:105:13:105:20 | case ...: | Switch.cs:105:29:105:29 | 0 | true | -| Switch.cs:105:13:105:20 | case ...: | Switch.cs:106:13:106:20 | case ...: | false | -| Switch.cs:105:13:105:20 | case ...: | Switch.cs:106:29:106:29 | 1 | false | -| Switch.cs:105:13:105:20 | case ...: | Switch.cs:108:17:108:17 | 1 | false | -| Switch.cs:106:13:106:20 | case ...: | Switch.cs:106:29:106:29 | 1 | true | -| Switch.cs:106:13:106:20 | case ...: | Switch.cs:108:17:108:17 | 1 | false | +| Switch.cs:105:13:105:19 | case ...: | Switch.cs:105:28:105:28 | 0 | true | +| Switch.cs:105:13:105:19 | case ...: | Switch.cs:106:13:106:19 | case ...: | false | +| Switch.cs:105:13:105:19 | case ...: | Switch.cs:106:28:106:28 | 1 | false | +| Switch.cs:105:13:105:19 | case ...: | Switch.cs:108:17:108:17 | 1 | false | +| Switch.cs:106:13:106:19 | case ...: | Switch.cs:106:28:106:28 | 1 | true | +| Switch.cs:106:13:106:19 | case ...: | Switch.cs:108:17:108:17 | 1 | false | | Switch.cs:113:9:113:11 | enter M10 | Switch.cs:117:25:117:25 | access to parameter s | true | -| Switch.cs:113:9:113:11 | enter M10 | Switch.cs:117:43:117:43 | 1 | true | -| Switch.cs:117:25:117:25 | access to parameter s | Switch.cs:117:43:117:43 | 1 | true | -| Switch.cs:118:13:118:33 | case ...: | Switch.cs:118:25:118:25 | access to parameter s | true | -| Switch.cs:118:13:118:33 | case ...: | Switch.cs:118:42:118:42 | 2 | true | -| Switch.cs:118:25:118:25 | access to parameter s | Switch.cs:118:42:118:42 | 2 | true | +| Switch.cs:113:9:113:11 | enter M10 | Switch.cs:117:44:117:44 | 1 | true | +| Switch.cs:117:25:117:25 | access to parameter s | Switch.cs:117:44:117:44 | 1 | true | +| Switch.cs:118:13:118:34 | case ...: | Switch.cs:118:25:118:25 | access to parameter s | true | +| Switch.cs:118:13:118:34 | case ...: | Switch.cs:118:43:118:43 | 2 | true | +| Switch.cs:118:25:118:25 | access to parameter s | Switch.cs:118:43:118:43 | 2 | true | | Switch.cs:123:10:123:12 | enter M11 | Switch.cs:125:34:125:34 | access to local variable b | true | | Switch.cs:123:10:123:12 | enter M11 | Switch.cs:125:37:125:46 | ... => ... | false | | Switch.cs:123:10:123:12 | enter M11 | Switch.cs:126:13:126:19 | return ...; | true | @@ -615,6 +913,12 @@ conditionBlock | Switch.cs:144:9:144:11 | enter M14 | Switch.cs:150:28:150:28 | 2 | false | | Switch.cs:150:13:150:19 | case ...: | Switch.cs:149:13:149:20 | default: | false | | Switch.cs:150:13:150:19 | case ...: | Switch.cs:150:28:150:28 | 2 | true | +| Switch.cs:154:10:154:12 | enter M15 | Switch.cs:156:36:156:38 | "a" | true | +| Switch.cs:154:10:154:12 | enter M15 | Switch.cs:156:41:156:52 | ... => ... | false | +| Switch.cs:154:10:154:12 | enter M15 | Switch.cs:156:50:156:52 | "b" | false | +| Switch.cs:156:13:156:54 | String s = ... | Switch.cs:158:13:158:49 | ...; | true | +| Switch.cs:156:13:156:54 | String s = ... | Switch.cs:160:13:160:49 | ...; | false | +| Switch.cs:156:41:156:52 | ... => ... | Switch.cs:156:50:156:52 | "b" | true | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:7:25:7:25 | ; | true | | VarDecls.cs:19:7:19:8 | enter M3 | VarDecls.cs:25:24:25:24 | access to local variable x | true | | VarDecls.cs:19:7:19:8 | enter M3 | VarDecls.cs:25:28:25:28 | access to local variable y | false | @@ -793,6 +1097,116 @@ conditionBlock | cflow.cs:264:25:264:25 | access to local variable i | cflow.cs:268:9:276:9 | try {...} ... | false | | cflow.cs:298:10:298:10 | enter M | cflow.cs:300:56:300:56 | access to parameter s | false | conditionFlow +| Assert.cs:9:20:9:20 | access to parameter b | Assert.cs:9:24:9:27 | null | true | +| Assert.cs:9:20:9:20 | access to parameter b | Assert.cs:9:31:9:32 | "" | false | +| Assert.cs:10:22:10:30 | ... != ... | Assert.cs:10:9:10:31 | [assertion failure] call to method Assert | false | +| Assert.cs:10:22:10:30 | ... != ... | Assert.cs:10:9:10:31 | [assertion success] call to method Assert | true | +| Assert.cs:16:20:16:20 | access to parameter b | Assert.cs:16:24:16:27 | null | true | +| Assert.cs:16:20:16:20 | access to parameter b | Assert.cs:16:31:16:32 | "" | false | +| Assert.cs:23:20:23:20 | access to parameter b | Assert.cs:23:24:23:27 | null | true | +| Assert.cs:23:20:23:20 | access to parameter b | Assert.cs:23:31:23:32 | "" | false | +| Assert.cs:30:20:30:20 | access to parameter b | Assert.cs:30:24:30:27 | null | true | +| Assert.cs:30:20:30:20 | access to parameter b | Assert.cs:30:31:30:32 | "" | false | +| Assert.cs:31:23:31:31 | ... == ... | Assert.cs:31:9:31:32 | [assertion failure] call to method IsTrue | false | +| Assert.cs:31:23:31:31 | ... == ... | Assert.cs:31:9:31:32 | [assertion success] call to method IsTrue | true | +| Assert.cs:37:20:37:20 | access to parameter b | Assert.cs:37:24:37:27 | null | true | +| Assert.cs:37:20:37:20 | access to parameter b | Assert.cs:37:31:37:32 | "" | false | +| Assert.cs:38:23:38:31 | ... != ... | Assert.cs:38:9:38:32 | [assertion failure] call to method IsTrue | false | +| Assert.cs:38:23:38:31 | ... != ... | Assert.cs:38:9:38:32 | [assertion success] call to method IsTrue | true | +| Assert.cs:44:20:44:20 | access to parameter b | Assert.cs:44:24:44:27 | null | true | +| Assert.cs:44:20:44:20 | access to parameter b | Assert.cs:44:31:44:32 | "" | false | +| Assert.cs:45:24:45:32 | ... != ... | Assert.cs:45:9:45:33 | [assertion failure] call to method IsFalse | true | +| Assert.cs:45:24:45:32 | ... != ... | Assert.cs:45:9:45:33 | [assertion success] call to method IsFalse | false | +| Assert.cs:51:20:51:20 | access to parameter b | Assert.cs:51:24:51:27 | null | true | +| Assert.cs:51:20:51:20 | access to parameter b | Assert.cs:51:31:51:32 | "" | false | +| Assert.cs:52:24:52:32 | ... == ... | Assert.cs:52:9:52:33 | [assertion failure] call to method IsFalse | true | +| Assert.cs:52:24:52:32 | ... == ... | Assert.cs:52:9:52:33 | [assertion success] call to method IsFalse | false | +| Assert.cs:58:20:58:20 | access to parameter b | Assert.cs:58:24:58:27 | [b (line 56): true] null | true | +| Assert.cs:58:20:58:20 | access to parameter b | Assert.cs:58:31:58:32 | [b (line 56): false] "" | false | +| Assert.cs:59:23:59:31 | [b (line 56): false] ... != ... | Assert.cs:59:9:59:37 | [assertion failure] call to method IsTrue | false | +| Assert.cs:59:23:59:31 | [b (line 56): false] ... != ... | Assert.cs:59:36:59:36 | [b (line 56): false] access to parameter b | true | +| Assert.cs:59:23:59:31 | [b (line 56): true] ... != ... | Assert.cs:59:9:59:37 | [assertion failure] call to method IsTrue | false | +| Assert.cs:59:23:59:31 | [b (line 56): true] ... != ... | Assert.cs:59:36:59:36 | [b (line 56): true] access to parameter b | true | +| Assert.cs:59:36:59:36 | [b (line 56): false] access to parameter b | Assert.cs:59:9:59:37 | [assertion failure] call to method IsTrue | false | +| Assert.cs:59:36:59:36 | [b (line 56): true] access to parameter b | Assert.cs:59:9:59:37 | [assertion success] call to method IsTrue | true | +| Assert.cs:65:20:65:20 | access to parameter b | Assert.cs:65:24:65:27 | [b (line 63): true] null | true | +| Assert.cs:65:20:65:20 | access to parameter b | Assert.cs:65:31:65:32 | [b (line 63): false] "" | false | +| Assert.cs:66:24:66:32 | [b (line 63): false] ... == ... | Assert.cs:66:9:66:38 | [assertion failure] call to method IsFalse | true | +| Assert.cs:66:24:66:32 | [b (line 63): false] ... == ... | Assert.cs:66:37:66:37 | [b (line 63): false] access to parameter b | false | +| Assert.cs:66:24:66:32 | [b (line 63): true] ... == ... | Assert.cs:66:9:66:38 | [assertion failure] call to method IsFalse | true | +| Assert.cs:66:24:66:32 | [b (line 63): true] ... == ... | Assert.cs:66:37:66:37 | [b (line 63): true] access to parameter b | false | +| Assert.cs:66:37:66:37 | [b (line 63): false] access to parameter b | Assert.cs:66:9:66:38 | [assertion success] call to method IsFalse | false | +| Assert.cs:66:37:66:37 | [b (line 63): true] access to parameter b | Assert.cs:66:9:66:38 | [assertion failure] call to method IsFalse | true | +| Assert.cs:72:20:72:20 | access to parameter b | Assert.cs:72:24:72:27 | [b (line 70): true] null | true | +| Assert.cs:72:20:72:20 | access to parameter b | Assert.cs:72:31:72:32 | [b (line 70): false] "" | false | +| Assert.cs:73:23:73:31 | [b (line 70): false] ... == ... | Assert.cs:73:9:73:37 | [assertion failure] call to method IsTrue | false | +| Assert.cs:73:23:73:31 | [b (line 70): false] ... == ... | Assert.cs:73:36:73:36 | [b (line 70): false] access to parameter b | true | +| Assert.cs:73:23:73:31 | [b (line 70): true] ... == ... | Assert.cs:73:9:73:37 | [assertion failure] call to method IsTrue | false | +| Assert.cs:73:23:73:31 | [b (line 70): true] ... == ... | Assert.cs:73:36:73:36 | [b (line 70): true] access to parameter b | true | +| Assert.cs:73:36:73:36 | [b (line 70): false] access to parameter b | Assert.cs:73:9:73:37 | [assertion failure] call to method IsTrue | false | +| Assert.cs:73:36:73:36 | [b (line 70): true] access to parameter b | Assert.cs:73:9:73:37 | [assertion success] call to method IsTrue | true | +| Assert.cs:79:20:79:20 | access to parameter b | Assert.cs:79:24:79:27 | [b (line 77): true] null | true | +| Assert.cs:79:20:79:20 | access to parameter b | Assert.cs:79:31:79:32 | [b (line 77): false] "" | false | +| Assert.cs:80:24:80:32 | [b (line 77): false] ... != ... | Assert.cs:80:9:80:38 | [assertion failure] call to method IsFalse | true | +| Assert.cs:80:24:80:32 | [b (line 77): false] ... != ... | Assert.cs:80:37:80:37 | [b (line 77): false] access to parameter b | false | +| Assert.cs:80:24:80:32 | [b (line 77): true] ... != ... | Assert.cs:80:9:80:38 | [assertion failure] call to method IsFalse | true | +| Assert.cs:80:24:80:32 | [b (line 77): true] ... != ... | Assert.cs:80:37:80:37 | [b (line 77): true] access to parameter b | false | +| Assert.cs:80:37:80:37 | [b (line 77): false] access to parameter b | Assert.cs:80:9:80:38 | [assertion success] call to method IsFalse | false | +| Assert.cs:80:37:80:37 | [b (line 77): true] access to parameter b | Assert.cs:80:9:80:38 | [assertion failure] call to method IsFalse | true | +| Assert.cs:86:20:86:20 | access to parameter b | Assert.cs:86:24:86:27 | [b (line 84): true] null | true | +| Assert.cs:86:20:86:20 | access to parameter b | Assert.cs:86:31:86:32 | [b (line 84): false] "" | false | +| Assert.cs:87:22:87:30 | [b (line 84): false] ... != ... | Assert.cs:87:9:87:31 | [assertion failure, b (line 84): false] call to method Assert | false | +| Assert.cs:87:22:87:30 | [b (line 84): false] ... != ... | Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | true | +| Assert.cs:87:22:87:30 | [b (line 84): true] ... != ... | Assert.cs:87:9:87:31 | [assertion failure, b (line 84): true] call to method Assert | false | +| Assert.cs:87:22:87:30 | [b (line 84): true] ... != ... | Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | true | +| Assert.cs:90:13:90:13 | [b (line 84): false] access to parameter b | Assert.cs:90:24:90:25 | [b (line 84): false] "" | false | +| Assert.cs:90:13:90:13 | [b (line 84): true] access to parameter b | Assert.cs:90:17:90:20 | [b (line 84): true] null | true | +| Assert.cs:94:13:94:13 | [b (line 84): false] access to parameter b | Assert.cs:94:24:94:25 | [b (line 84): false] "" | false | +| Assert.cs:94:13:94:13 | [b (line 84): true] access to parameter b | Assert.cs:94:17:94:20 | [b (line 84): true] null | true | +| Assert.cs:98:13:98:13 | [b (line 84): false] access to parameter b | Assert.cs:98:24:98:25 | [b (line 84): false] "" | false | +| Assert.cs:98:13:98:13 | [b (line 84): true] access to parameter b | Assert.cs:98:17:98:20 | [b (line 84): true] null | true | +| Assert.cs:99:23:99:31 | [b (line 84): false] ... == ... | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): false] call to method IsTrue | false | +| Assert.cs:99:23:99:31 | [b (line 84): false] ... == ... | Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | true | +| Assert.cs:99:23:99:31 | [b (line 84): true] ... == ... | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): true] call to method IsTrue | false | +| Assert.cs:99:23:99:31 | [b (line 84): true] ... == ... | Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | true | +| Assert.cs:102:13:102:13 | [b (line 84): false] access to parameter b | Assert.cs:102:24:102:25 | [b (line 84): false] "" | false | +| Assert.cs:102:13:102:13 | [b (line 84): true] access to parameter b | Assert.cs:102:17:102:20 | [b (line 84): true] null | true | +| Assert.cs:103:23:103:31 | [b (line 84): false] ... != ... | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): false] call to method IsTrue | false | +| Assert.cs:103:23:103:31 | [b (line 84): false] ... != ... | Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | true | +| Assert.cs:103:23:103:31 | [b (line 84): true] ... != ... | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): true] call to method IsTrue | false | +| Assert.cs:103:23:103:31 | [b (line 84): true] ... != ... | Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | true | +| Assert.cs:106:13:106:13 | [b (line 84): false] access to parameter b | Assert.cs:106:24:106:25 | [b (line 84): false] "" | false | +| Assert.cs:106:13:106:13 | [b (line 84): true] access to parameter b | Assert.cs:106:17:106:20 | [b (line 84): true] null | true | +| Assert.cs:107:24:107:32 | [b (line 84): false] ... != ... | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | true | +| Assert.cs:107:24:107:32 | [b (line 84): false] ... != ... | Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | false | +| Assert.cs:107:24:107:32 | [b (line 84): true] ... != ... | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | true | +| Assert.cs:107:24:107:32 | [b (line 84): true] ... != ... | Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | false | +| Assert.cs:110:13:110:13 | [b (line 84): false] access to parameter b | Assert.cs:110:24:110:25 | [b (line 84): false] "" | false | +| Assert.cs:110:13:110:13 | [b (line 84): true] access to parameter b | Assert.cs:110:17:110:20 | [b (line 84): true] null | true | +| Assert.cs:111:24:111:32 | [b (line 84): false] ... == ... | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | true | +| Assert.cs:111:24:111:32 | [b (line 84): false] ... == ... | Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | false | +| Assert.cs:111:24:111:32 | [b (line 84): true] ... == ... | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | true | +| Assert.cs:111:24:111:32 | [b (line 84): true] ... == ... | Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | false | +| Assert.cs:114:13:114:13 | [b (line 84): false] access to parameter b | Assert.cs:114:24:114:25 | [b (line 84): false] "" | false | +| Assert.cs:114:13:114:13 | [b (line 84): true] access to parameter b | Assert.cs:114:17:114:20 | [b (line 84): true] null | true | +| Assert.cs:115:23:115:31 | [b (line 84): false] ... != ... | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | false | +| Assert.cs:115:23:115:31 | [b (line 84): false] ... != ... | Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | true | +| Assert.cs:115:23:115:31 | [b (line 84): true] ... != ... | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | false | +| Assert.cs:115:23:115:31 | [b (line 84): true] ... != ... | Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | true | +| Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | false | +| Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | Assert.cs:115:9:115:37 | [assertion success, b (line 84): true] call to method IsTrue | true | +| Assert.cs:118:13:118:13 | [b (line 84): true] access to parameter b | Assert.cs:118:17:118:20 | [b (line 84): true] null | true | +| Assert.cs:119:24:119:32 | [b (line 84): true] ... == ... | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | true | +| Assert.cs:119:24:119:32 | [b (line 84): true] ... == ... | Assert.cs:119:37:119:38 | [b (line 84): true] !... | false | +| Assert.cs:119:38:119:38 | [b (line 84): true] access to parameter b | Assert.cs:119:9:119:39 | [assertion success, b (line 84): true] call to method IsFalse | true | +| Assert.cs:122:13:122:13 | [b (line 84): true] access to parameter b | Assert.cs:122:17:122:20 | [b (line 84): true] null | true | +| Assert.cs:123:23:123:31 | [b (line 84): true] ... == ... | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | false | +| Assert.cs:123:23:123:31 | [b (line 84): true] ... == ... | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | true | +| Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | Assert.cs:123:9:123:37 | [assertion success, b (line 84): true] call to method IsTrue | true | +| Assert.cs:126:13:126:13 | [b (line 84): true] access to parameter b | Assert.cs:126:17:126:20 | [b (line 84): true] null | true | +| Assert.cs:127:24:127:32 | [b (line 84): true] ... != ... | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | true | +| Assert.cs:127:24:127:32 | [b (line 84): true] ... != ... | Assert.cs:127:37:127:38 | [b (line 84): true] !... | false | +| Assert.cs:127:38:127:38 | [b (line 84): true] access to parameter b | Assert.cs:127:9:127:39 | [assertion success] call to method IsFalse | true | | BreakInTry.cs:9:21:9:31 | ... == ... | BreakInTry.cs:7:13:11:13 | foreach (... ... in ...) ... | false | | BreakInTry.cs:9:21:9:31 | ... == ... | BreakInTry.cs:10:21:10:26 | break; | true | | BreakInTry.cs:15:17:15:28 | ... == ... | BreakInTry.cs:3:10:3:11 | exit M1 | false | @@ -870,8 +1284,8 @@ conditionFlow | Conditions.cs:76:17:76:17 | access to local variable b | Conditions.cs:78:13:79:26 | if (...) ... | false | | Conditions.cs:78:17:78:21 | ... > ... | Conditions.cs:74:9:80:9 | foreach (... ... in ...) ... | false | | Conditions.cs:78:17:78:21 | ... > ... | Conditions.cs:79:17:79:26 | ...; | true | -| Conditions.cs:81:12:81:12 | access to local variable b | Conditions.cs:82:13:82:16 | ...; | true | -| Conditions.cs:81:12:81:12 | access to local variable b | Conditions.cs:83:16:83:16 | access to local variable x | false | +| Conditions.cs:81:13:81:13 | access to local variable b | Conditions.cs:82:13:82:16 | ...; | true | +| Conditions.cs:81:13:81:13 | access to local variable b | Conditions.cs:83:16:83:16 | access to local variable x | false | | Conditions.cs:92:17:92:17 | access to local variable b | Conditions.cs:93:17:93:20 | ...; | true | | Conditions.cs:92:17:92:17 | access to local variable b | Conditions.cs:94:13:95:26 | if (...) ... | false | | Conditions.cs:94:17:94:21 | ... > ... | Conditions.cs:95:17:95:26 | ...; | true | @@ -886,11 +1300,11 @@ conditionFlow | Conditions.cs:107:13:107:24 | [b (line 102): true] ... > ... | Conditions.cs:110:16:110:16 | access to local variable x | false | | Conditions.cs:108:18:108:18 | [b (line 102): false] access to parameter b | Conditions.cs:109:17:109:24 | ...; | false | | Conditions.cs:108:18:108:18 | [b (line 102): true] access to parameter b | Conditions.cs:110:16:110:16 | access to local variable x | true | -| Conditions.cs:116:24:116:38 | ... < ... | Conditions.cs:113:10:113:11 | exit M9 | false | -| Conditions.cs:116:24:116:38 | ... < ... | Conditions.cs:117:9:123:9 | {...} | true | +| Conditions.cs:116:25:116:39 | ... < ... | Conditions.cs:113:10:113:11 | exit M9 | false | +| Conditions.cs:116:25:116:39 | ... < ... | Conditions.cs:117:9:123:9 | {...} | true | | Conditions.cs:119:18:119:21 | access to local variable last | Conditions.cs:120:17:120:23 | [last (line 118): false] ...; | false | | Conditions.cs:119:18:119:21 | access to local variable last | Conditions.cs:121:13:122:25 | [last (line 118): true] if (...) ... | true | -| Conditions.cs:121:17:121:20 | [last (line 118): false] access to local variable last | Conditions.cs:116:41:116:41 | access to local variable i | false | +| Conditions.cs:121:17:121:20 | [last (line 118): false] access to local variable last | Conditions.cs:116:42:116:42 | access to local variable i | false | | Conditions.cs:121:17:121:20 | [last (line 118): true] access to local variable last | Conditions.cs:122:17:122:25 | ...; | true | | Conditions.cs:131:16:131:19 | [Field1 (line 129): false] true | Conditions.cs:132:9:140:9 | [Field1 (line 129): false] {...} | true | | Conditions.cs:131:16:131:19 | [Field1 (line 129): true, Field2 (line 129): false] true | Conditions.cs:132:9:140:9 | [Field1 (line 129): true, Field2 (line 129): false] {...} | true | @@ -905,6 +1319,10 @@ conditionFlow | Conditions.cs:135:21:135:26 | [Field1 (line 129): true, Field2 (line 129): true] access to field Field2 | Conditions.cs:136:17:138:17 | [Field1 (line 129): true, Field2 (line 129): true] {...} | true | | Conditions.cs:135:21:135:26 | [Field1 (line 129): true] access to field Field2 | Conditions.cs:131:16:131:19 | [Field1 (line 129): true, Field2 (line 129): false] true | false | | Conditions.cs:135:21:135:26 | [Field1 (line 129): true] access to field Field2 | Conditions.cs:136:17:138:17 | [Field1 (line 129): true, Field2 (line 129): true] {...} | true | +| Conditions.cs:145:17:145:17 | access to parameter b | Conditions.cs:145:21:145:23 | [b (line 143): true] "a" | true | +| Conditions.cs:145:17:145:17 | access to parameter b | Conditions.cs:145:27:145:29 | [b (line 143): false] "b" | false | +| Conditions.cs:146:13:146:13 | [b (line 143): false] access to parameter b | Conditions.cs:149:13:149:49 | ...; | false | +| Conditions.cs:146:13:146:13 | [b (line 143): true] access to parameter b | Conditions.cs:147:13:147:49 | ...; | true | | ExitMethods.cs:67:13:67:13 | access to parameter b | ExitMethods.cs:65:17:65:26 | exit ErrorMaybe | false | | ExitMethods.cs:67:13:67:13 | access to parameter b | ExitMethods.cs:68:19:68:33 | object creation of type Exception | true | | ExitMethods.cs:73:13:73:13 | access to parameter b | ExitMethods.cs:74:19:74:33 | object creation of type Exception | true | @@ -913,6 +1331,10 @@ conditionFlow | ExitMethods.cs:111:16:111:25 | ... != ... | ExitMethods.cs:111:69:111:75 | "input" | false | | ExitMethods.cs:116:16:116:30 | call to method Contains | ExitMethods.cs:116:34:116:34 | 0 | true | | ExitMethods.cs:116:16:116:30 | call to method Contains | ExitMethods.cs:116:38:116:38 | 1 | false | +| ExitMethods.cs:121:23:121:27 | false | ExitMethods.cs:121:9:121:28 | [assertion failure] call to method IsTrue | false | +| ExitMethods.cs:131:48:131:48 | access to parameter b | ExitMethods.cs:131:33:131:49 | [assertion failure] call to method IsFalse | true | +| ExitMethods.cs:131:48:131:48 | access to parameter b | ExitMethods.cs:131:33:131:49 | [assertion success] call to method IsFalse | false | +| ExitMethods.cs:135:21:135:24 | true | ExitMethods.cs:135:9:135:25 | [assertion failure] call to method AssertFalse | true | | Finally.cs:26:48:26:51 | [exception: Exception] true | Finally.cs:27:9:29:9 | {...} | true | | Finally.cs:34:21:34:24 | true | Finally.cs:34:27:34:32 | throw ...; | true | | Finally.cs:61:48:61:51 | [exception: Exception] true | Finally.cs:62:9:64:9 | {...} | true | @@ -1008,7 +1430,7 @@ conditionFlow | Finally.cs:209:21:209:22 | access to parameter b3 | Finally.cs:209:31:209:46 | object creation of type ExceptionC | true | | Finally.cs:209:21:209:22 | access to parameter b3 | Finally.cs:211:13:211:29 | ...; | false | | LoopUnrolling.cs:9:13:9:28 | ... == ... | LoopUnrolling.cs:10:13:10:19 | return ...; | true | -| LoopUnrolling.cs:9:13:9:28 | ... == ... | LoopUnrolling.cs:11:28:11:31 | access to parameter args | false | +| LoopUnrolling.cs:9:13:9:28 | ... == ... | LoopUnrolling.cs:11:29:11:32 | access to parameter args | false | | LoopUnrolling.cs:60:17:60:17 | [b (line 55): false] access to parameter b | LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | false | | LoopUnrolling.cs:60:17:60:17 | [b (line 55): true] access to parameter b | LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | true | | LoopUnrolling.cs:60:17:60:17 | access to parameter b | LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | true | @@ -1044,15 +1466,17 @@ conditionFlow | Switch.cs:24:48:24:55 | ... != ... | Switch.cs:27:13:27:39 | case ...: | false | | Switch.cs:50:30:50:38 | ... != ... | Switch.cs:44:10:44:11 | exit M4 | false | | Switch.cs:50:30:50:38 | ... != ... | Switch.cs:51:17:51:22 | break; | true | -| Switch.cs:84:19:84:23 | ... > ... | Switch.cs:85:17:85:22 | break; | true | -| Switch.cs:84:19:84:23 | ... > ... | Switch.cs:86:22:86:25 | true | false | -| Switch.cs:117:25:117:32 | ... == ... | Switch.cs:117:43:117:43 | 1 | true | -| Switch.cs:117:25:117:32 | ... == ... | Switch.cs:118:13:118:33 | case ...: | false | -| Switch.cs:118:25:118:31 | ... == ... | Switch.cs:118:42:118:42 | 2 | true | -| Switch.cs:118:25:118:31 | ... == ... | Switch.cs:120:17:120:17 | 1 | false | +| Switch.cs:84:21:84:25 | ... > ... | Switch.cs:85:21:85:26 | break; | true | +| Switch.cs:84:21:84:25 | ... > ... | Switch.cs:86:24:86:27 | true | false | +| Switch.cs:117:25:117:34 | ... == ... | Switch.cs:117:44:117:44 | 1 | true | +| Switch.cs:117:25:117:34 | ... == ... | Switch.cs:118:13:118:34 | case ...: | false | +| Switch.cs:118:25:118:33 | ... == ... | Switch.cs:118:43:118:43 | 2 | true | +| Switch.cs:118:25:118:33 | ... == ... | Switch.cs:120:17:120:17 | 1 | false | | Switch.cs:125:34:125:34 | access to local variable b | Switch.cs:123:10:123:12 | exit M11 | false | | Switch.cs:125:34:125:34 | access to local variable b | Switch.cs:126:13:126:19 | return ...; | true | | Switch.cs:125:42:125:46 | false | Switch.cs:123:10:123:12 | exit M11 | false | +| Switch.cs:157:13:157:13 | access to parameter b | Switch.cs:158:13:158:49 | ...; | true | +| Switch.cs:157:13:157:13 | access to parameter b | Switch.cs:160:13:160:49 | ...; | false | | TypeAccesses.cs:7:13:7:22 | ... is ... | TypeAccesses.cs:7:25:7:25 | ; | true | | TypeAccesses.cs:7:13:7:22 | ... is ... | TypeAccesses.cs:8:9:8:28 | ... ...; | false | | VarDecls.cs:25:20:25:20 | access to parameter b | VarDecls.cs:25:24:25:24 | access to local variable x | true | diff --git a/csharp/ql/test/library-tests/controlflow/graph/ConditionalAccess.cs b/csharp/ql/test/library-tests/controlflow/graph/ConditionalAccess.cs index 00743aba1694..a03564b529f5 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/ConditionalAccess.cs +++ b/csharp/ql/test/library-tests/controlflow/graph/ConditionalAccess.cs @@ -24,6 +24,16 @@ void M7(int i) var s = ((int?)i)?.ToString(); s = ""?.CommaJoinWith(s); } + + ConditionalAccess Prop { get; set; } + + void Out(out int i) => i = 0; + + void M8(bool b, out int i) + { + i = 0; + Prop?.Out(out i); + } } static class Ext diff --git a/csharp/ql/test/library-tests/controlflow/graph/Conditions.cs b/csharp/ql/test/library-tests/controlflow/graph/Conditions.cs index bedcba97884d..761718082ab4 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Conditions.cs +++ b/csharp/ql/test/library-tests/controlflow/graph/Conditions.cs @@ -78,7 +78,7 @@ int M6(string[] ss) if (x > 0) b = false; } - if(b) + if (b) x++; return x; } @@ -113,7 +113,7 @@ string M8(bool b) void M9(string[] args) { string s = null; - for(var i = 0; i < args.Length; i++) + for (var i = 0; i < args.Length; i++) { var last = i == args.Length - 1; if (!last) @@ -139,4 +139,13 @@ void M10() } } } + + void M11(bool b) + { + var s = b ? "a" : "b"; + if (b) + System.Console.WriteLine($"a = {s}"); + else + System.Console.WriteLine($"b = {s}"); + } } diff --git a/csharp/ql/test/library-tests/controlflow/graph/Consistency.expected b/csharp/ql/test/library-tests/controlflow/graph/Consistency.expected index bccab8e85a45..abcb76bffec5 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Consistency.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Consistency.expected @@ -5,3 +5,77 @@ breakInvariant3 breakInvariant4 breakInvariant5 multipleSuccessors +| ConditionalAccess.cs:30:28:30:32 | ... = ... | successor | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | successor | ConditionalAccess.cs:30:10:30:12 | exit Out | +| MultiImplementationA.cs:6:22:6:31 | enter get_P1 | successor | MultiImplementationA.cs:6:28:6:31 | null | +| MultiImplementationA.cs:6:22:6:31 | enter get_P1 | successor | MultiImplementationB.cs:3:22:3:22 | 0 | +| MultiImplementationA.cs:7:21:7:23 | enter get_P2 | successor | MultiImplementationA.cs:7:25:7:39 | {...} | +| MultiImplementationA.cs:7:21:7:23 | enter get_P2 | successor | MultiImplementationB.cs:4:25:4:37 | {...} | +| MultiImplementationA.cs:7:41:7:43 | enter set_P2 | successor | MultiImplementationA.cs:7:45:7:59 | {...} | +| MultiImplementationA.cs:7:41:7:43 | enter set_P2 | successor | MultiImplementationB.cs:4:43:4:45 | {...} | +| MultiImplementationA.cs:8:16:8:16 | enter M | successor | MultiImplementationA.cs:8:29:8:32 | null | +| MultiImplementationA.cs:8:16:8:16 | enter M | successor | MultiImplementationB.cs:5:23:5:23 | 2 | +| MultiImplementationA.cs:13:16:13:20 | ... = ... | successor | MultiImplementationA.cs:13:16:13:16 | this access | +| MultiImplementationA.cs:13:16:13:20 | ... = ... | successor | MultiImplementationA.cs:24:16:24:16 | this access | +| MultiImplementationA.cs:13:16:13:20 | ... = ... | successor | MultiImplementationB.cs:11:16:11:16 | this access | +| MultiImplementationA.cs:13:16:13:20 | ... = ... | successor | MultiImplementationB.cs:22:16:22:16 | this access | +| MultiImplementationA.cs:14:31:14:31 | enter get_Item | successor | MultiImplementationA.cs:14:31:14:31 | access to parameter i | +| MultiImplementationA.cs:14:31:14:31 | enter get_Item | successor | MultiImplementationB.cs:12:37:12:40 | null | +| MultiImplementationA.cs:15:36:15:38 | enter get_Item | successor | MultiImplementationA.cs:15:40:15:52 | {...} | +| MultiImplementationA.cs:15:36:15:38 | enter get_Item | successor | MultiImplementationB.cs:13:40:13:54 | {...} | +| MultiImplementationA.cs:15:54:15:56 | enter set_Item | successor | MultiImplementationA.cs:15:58:15:60 | {...} | +| MultiImplementationA.cs:15:54:15:56 | enter set_Item | successor | MultiImplementationB.cs:13:60:13:62 | {...} | +| MultiImplementationA.cs:16:17:16:18 | enter M1 | successor | MultiImplementationA.cs:17:5:19:5 | {...} | +| MultiImplementationA.cs:16:17:16:18 | enter M1 | successor | MultiImplementationB.cs:15:5:17:5 | {...} | +| MultiImplementationA.cs:20:12:20:13 | enter C2 | successor | MultiImplementationA.cs:13:16:13:16 | this access | +| MultiImplementationA.cs:20:12:20:13 | enter C2 | successor | MultiImplementationB.cs:11:16:11:16 | this access | +| MultiImplementationA.cs:21:12:21:13 | enter C2 | successor | MultiImplementationA.cs:21:24:21:24 | 0 | +| MultiImplementationA.cs:21:12:21:13 | enter C2 | successor | MultiImplementationB.cs:19:24:19:24 | 1 | +| MultiImplementationA.cs:21:19:21:22 | call to constructor C2 | successor | MultiImplementationA.cs:21:27:21:29 | {...} | +| MultiImplementationA.cs:21:19:21:22 | call to constructor C2 | successor | MultiImplementationB.cs:19:27:19:29 | {...} | +| MultiImplementationA.cs:22:6:22:7 | enter ~C2 | successor | MultiImplementationA.cs:22:11:22:13 | {...} | +| MultiImplementationA.cs:22:6:22:7 | enter ~C2 | successor | MultiImplementationB.cs:20:11:20:25 | {...} | +| MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | successor | MultiImplementationA.cs:23:50:23:53 | null | +| MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | successor | MultiImplementationB.cs:21:56:21:59 | null | +| MultiImplementationA.cs:24:32:24:34 | ... = ... | successor | MultiImplementationA.cs:20:22:20:31 | {...} | +| MultiImplementationA.cs:24:32:24:34 | ... = ... | successor | MultiImplementationA.cs:24:16:24:16 | this access | +| MultiImplementationA.cs:24:32:24:34 | ... = ... | successor | MultiImplementationB.cs:18:22:18:36 | {...} | +| MultiImplementationA.cs:24:32:24:34 | ... = ... | successor | MultiImplementationB.cs:22:16:22:16 | this access | +| MultiImplementationA.cs:36:9:36:10 | enter M1 | successor | MultiImplementationA.cs:36:14:36:28 | {...} | +| MultiImplementationA.cs:36:9:36:10 | enter M1 | successor | MultiImplementationB.cs:32:17:32:17 | 0 | +| MultiImplementationB.cs:3:22:3:22 | enter get_P1 | successor | MultiImplementationA.cs:6:28:6:31 | null | +| MultiImplementationB.cs:3:22:3:22 | enter get_P1 | successor | MultiImplementationB.cs:3:22:3:22 | 0 | +| MultiImplementationB.cs:4:21:4:23 | enter get_P2 | successor | MultiImplementationA.cs:7:25:7:39 | {...} | +| MultiImplementationB.cs:4:21:4:23 | enter get_P2 | successor | MultiImplementationB.cs:4:25:4:37 | {...} | +| MultiImplementationB.cs:4:39:4:41 | enter set_P2 | successor | MultiImplementationA.cs:7:45:7:59 | {...} | +| MultiImplementationB.cs:4:39:4:41 | enter set_P2 | successor | MultiImplementationB.cs:4:43:4:45 | {...} | +| MultiImplementationB.cs:5:16:5:16 | enter M | successor | MultiImplementationA.cs:8:29:8:32 | null | +| MultiImplementationB.cs:5:16:5:16 | enter M | successor | MultiImplementationB.cs:5:23:5:23 | 2 | +| MultiImplementationB.cs:11:16:11:20 | ... = ... | successor | MultiImplementationA.cs:13:16:13:16 | this access | +| MultiImplementationB.cs:11:16:11:20 | ... = ... | successor | MultiImplementationA.cs:24:16:24:16 | this access | +| MultiImplementationB.cs:11:16:11:20 | ... = ... | successor | MultiImplementationB.cs:11:16:11:16 | this access | +| MultiImplementationB.cs:11:16:11:20 | ... = ... | successor | MultiImplementationB.cs:22:16:22:16 | this access | +| MultiImplementationB.cs:12:31:12:40 | enter get_Item | successor | MultiImplementationA.cs:14:31:14:31 | access to parameter i | +| MultiImplementationB.cs:12:31:12:40 | enter get_Item | successor | MultiImplementationB.cs:12:37:12:40 | null | +| MultiImplementationB.cs:13:36:13:38 | enter get_Item | successor | MultiImplementationA.cs:15:40:15:52 | {...} | +| MultiImplementationB.cs:13:36:13:38 | enter get_Item | successor | MultiImplementationB.cs:13:40:13:54 | {...} | +| MultiImplementationB.cs:13:56:13:58 | enter set_Item | successor | MultiImplementationA.cs:15:58:15:60 | {...} | +| MultiImplementationB.cs:13:56:13:58 | enter set_Item | successor | MultiImplementationB.cs:13:60:13:62 | {...} | +| MultiImplementationB.cs:14:17:14:18 | enter M1 | successor | MultiImplementationA.cs:17:5:19:5 | {...} | +| MultiImplementationB.cs:14:17:14:18 | enter M1 | successor | MultiImplementationB.cs:15:5:17:5 | {...} | +| MultiImplementationB.cs:18:12:18:13 | enter C2 | successor | MultiImplementationA.cs:13:16:13:16 | this access | +| MultiImplementationB.cs:18:12:18:13 | enter C2 | successor | MultiImplementationB.cs:11:16:11:16 | this access | +| MultiImplementationB.cs:19:12:19:13 | enter C2 | successor | MultiImplementationA.cs:21:24:21:24 | 0 | +| MultiImplementationB.cs:19:12:19:13 | enter C2 | successor | MultiImplementationB.cs:19:24:19:24 | 1 | +| MultiImplementationB.cs:19:19:19:22 | call to constructor C2 | successor | MultiImplementationA.cs:21:27:21:29 | {...} | +| MultiImplementationB.cs:19:19:19:22 | call to constructor C2 | successor | MultiImplementationB.cs:19:27:19:29 | {...} | +| MultiImplementationB.cs:20:6:20:7 | enter ~C2 | successor | MultiImplementationA.cs:22:11:22:13 | {...} | +| MultiImplementationB.cs:20:6:20:7 | enter ~C2 | successor | MultiImplementationB.cs:20:11:20:25 | {...} | +| MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | successor | MultiImplementationA.cs:23:50:23:53 | null | +| MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | successor | MultiImplementationB.cs:21:56:21:59 | null | +| MultiImplementationB.cs:22:32:22:34 | ... = ... | successor | MultiImplementationA.cs:20:22:20:31 | {...} | +| MultiImplementationB.cs:22:32:22:34 | ... = ... | successor | MultiImplementationA.cs:24:16:24:16 | this access | +| MultiImplementationB.cs:22:32:22:34 | ... = ... | successor | MultiImplementationB.cs:18:22:18:36 | {...} | +| MultiImplementationB.cs:22:32:22:34 | ... = ... | successor | MultiImplementationB.cs:22:16:22:16 | this access | +| MultiImplementationB.cs:32:9:32:10 | enter M1 | successor | MultiImplementationA.cs:36:14:36:28 | {...} | +| MultiImplementationB.cs:32:9:32:10 | enter M1 | successor | MultiImplementationB.cs:32:17:32:17 | 0 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected index 577f2f6ccbea..d087f17f601e 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected @@ -294,12 +294,15 @@ dominance | ArrayCreation.cs:5:20:5:32 | array creation of type Int32[,] | ArrayCreation.cs:5:12:5:13 | exit M2 | | ArrayCreation.cs:5:28:5:28 | 0 | ArrayCreation.cs:5:31:5:31 | 1 | | ArrayCreation.cs:5:31:5:31 | 1 | ArrayCreation.cs:5:20:5:32 | array creation of type Int32[,] | -| ArrayCreation.cs:7:11:7:12 | enter M3 | ArrayCreation.cs:7:19:7:36 | array creation of type Int32[] | +| ArrayCreation.cs:7:11:7:12 | enter M3 | ArrayCreation.cs:7:19:7:36 | 2 | +| ArrayCreation.cs:7:19:7:36 | 2 | ArrayCreation.cs:7:19:7:36 | array creation of type Int32[] | | ArrayCreation.cs:7:19:7:36 | array creation of type Int32[] | ArrayCreation.cs:7:31:7:31 | 0 | | ArrayCreation.cs:7:29:7:36 | { ..., ... } | ArrayCreation.cs:7:11:7:12 | exit M3 | | ArrayCreation.cs:7:31:7:31 | 0 | ArrayCreation.cs:7:34:7:34 | 1 | | ArrayCreation.cs:7:34:7:34 | 1 | ArrayCreation.cs:7:29:7:36 | { ..., ... } | -| ArrayCreation.cs:9:12:9:13 | enter M4 | ArrayCreation.cs:9:20:9:52 | array creation of type Int32[,] | +| ArrayCreation.cs:9:12:9:13 | enter M4 | ArrayCreation.cs:9:20:9:52 | 2 | +| ArrayCreation.cs:9:20:9:52 | 2 | ArrayCreation.cs:9:20:9:52 | 2 | +| ArrayCreation.cs:9:20:9:52 | 2 | ArrayCreation.cs:9:20:9:52 | array creation of type Int32[,] | | ArrayCreation.cs:9:20:9:52 | array creation of type Int32[,] | ArrayCreation.cs:9:35:9:35 | 0 | | ArrayCreation.cs:9:31:9:52 | { ..., ... } | ArrayCreation.cs:9:12:9:13 | exit M4 | | ArrayCreation.cs:9:33:9:40 | { ..., ... } | ArrayCreation.cs:9:45:9:45 | 2 | @@ -308,6 +311,496 @@ dominance | ArrayCreation.cs:9:43:9:50 | { ..., ... } | ArrayCreation.cs:9:31:9:52 | { ..., ... } | | ArrayCreation.cs:9:45:9:45 | 2 | ArrayCreation.cs:9:48:9:48 | 3 | | ArrayCreation.cs:9:48:9:48 | 3 | ArrayCreation.cs:9:43:9:50 | { ..., ... } | +| Assert.cs:7:10:7:11 | enter M1 | Assert.cs:8:5:12:5 | {...} | +| Assert.cs:8:5:12:5 | {...} | Assert.cs:9:9:9:33 | ... ...; | +| Assert.cs:9:9:9:33 | ... ...; | Assert.cs:9:20:9:32 | ... ? ... : ... | +| Assert.cs:9:16:9:32 | String s = ... | Assert.cs:10:9:10:32 | ...; | +| Assert.cs:9:20:9:20 | access to parameter b | Assert.cs:9:24:9:27 | null | +| Assert.cs:9:20:9:20 | access to parameter b | Assert.cs:9:31:9:32 | "" | +| Assert.cs:9:20:9:32 | ... ? ... : ... | Assert.cs:9:20:9:20 | access to parameter b | +| Assert.cs:10:9:10:31 | [assertion success] call to method Assert | Assert.cs:11:9:11:36 | ...; | +| Assert.cs:10:9:10:32 | ...; | Assert.cs:10:22:10:22 | access to local variable s | +| Assert.cs:10:22:10:22 | access to local variable s | Assert.cs:10:27:10:30 | null | +| Assert.cs:10:22:10:30 | ... != ... | Assert.cs:10:9:10:31 | [assertion failure] call to method Assert | +| Assert.cs:10:22:10:30 | ... != ... | Assert.cs:10:9:10:31 | [assertion success] call to method Assert | +| Assert.cs:10:27:10:30 | null | Assert.cs:10:22:10:30 | ... != ... | +| Assert.cs:11:9:11:36 | ...; | Assert.cs:11:27:11:27 | access to local variable s | +| Assert.cs:11:27:11:27 | access to local variable s | Assert.cs:11:27:11:34 | access to property Length | +| Assert.cs:11:27:11:34 | access to property Length | Assert.cs:11:9:11:35 | call to method WriteLine | +| Assert.cs:14:10:14:11 | enter M2 | Assert.cs:15:5:19:5 | {...} | +| Assert.cs:15:5:19:5 | {...} | Assert.cs:16:9:16:33 | ... ...; | +| Assert.cs:16:9:16:33 | ... ...; | Assert.cs:16:20:16:32 | ... ? ... : ... | +| Assert.cs:16:16:16:32 | String s = ... | Assert.cs:17:9:17:25 | ...; | +| Assert.cs:16:20:16:20 | access to parameter b | Assert.cs:16:24:16:27 | null | +| Assert.cs:16:20:16:20 | access to parameter b | Assert.cs:16:31:16:32 | "" | +| Assert.cs:16:20:16:32 | ... ? ... : ... | Assert.cs:16:20:16:20 | access to parameter b | +| Assert.cs:17:9:17:24 | [assertion success] call to method IsNull | Assert.cs:18:9:18:36 | ...; | +| Assert.cs:17:9:17:25 | ...; | Assert.cs:17:23:17:23 | access to local variable s | +| Assert.cs:17:23:17:23 | access to local variable s | Assert.cs:17:9:17:24 | [assertion failure] call to method IsNull | +| Assert.cs:17:23:17:23 | access to local variable s | Assert.cs:17:9:17:24 | [assertion success] call to method IsNull | +| Assert.cs:18:9:18:36 | ...; | Assert.cs:18:27:18:27 | access to local variable s | +| Assert.cs:18:27:18:27 | access to local variable s | Assert.cs:18:27:18:34 | access to property Length | +| Assert.cs:18:27:18:34 | access to property Length | Assert.cs:18:9:18:35 | call to method WriteLine | +| Assert.cs:21:10:21:11 | enter M3 | Assert.cs:22:5:26:5 | {...} | +| Assert.cs:22:5:26:5 | {...} | Assert.cs:23:9:23:33 | ... ...; | +| Assert.cs:23:9:23:33 | ... ...; | Assert.cs:23:20:23:32 | ... ? ... : ... | +| Assert.cs:23:16:23:32 | String s = ... | Assert.cs:24:9:24:28 | ...; | +| Assert.cs:23:20:23:20 | access to parameter b | Assert.cs:23:24:23:27 | null | +| Assert.cs:23:20:23:20 | access to parameter b | Assert.cs:23:31:23:32 | "" | +| Assert.cs:23:20:23:32 | ... ? ... : ... | Assert.cs:23:20:23:20 | access to parameter b | +| Assert.cs:24:9:24:27 | [assertion success] call to method IsNotNull | Assert.cs:25:9:25:36 | ...; | +| Assert.cs:24:9:24:28 | ...; | Assert.cs:24:26:24:26 | access to local variable s | +| Assert.cs:24:26:24:26 | access to local variable s | Assert.cs:24:9:24:27 | [assertion failure] call to method IsNotNull | +| Assert.cs:24:26:24:26 | access to local variable s | Assert.cs:24:9:24:27 | [assertion success] call to method IsNotNull | +| Assert.cs:25:9:25:36 | ...; | Assert.cs:25:27:25:27 | access to local variable s | +| Assert.cs:25:27:25:27 | access to local variable s | Assert.cs:25:27:25:34 | access to property Length | +| Assert.cs:25:27:25:34 | access to property Length | Assert.cs:25:9:25:35 | call to method WriteLine | +| Assert.cs:28:10:28:11 | enter M4 | Assert.cs:29:5:33:5 | {...} | +| Assert.cs:29:5:33:5 | {...} | Assert.cs:30:9:30:33 | ... ...; | +| Assert.cs:30:9:30:33 | ... ...; | Assert.cs:30:20:30:32 | ... ? ... : ... | +| Assert.cs:30:16:30:32 | String s = ... | Assert.cs:31:9:31:33 | ...; | +| Assert.cs:30:20:30:20 | access to parameter b | Assert.cs:30:24:30:27 | null | +| Assert.cs:30:20:30:20 | access to parameter b | Assert.cs:30:31:30:32 | "" | +| Assert.cs:30:20:30:32 | ... ? ... : ... | Assert.cs:30:20:30:20 | access to parameter b | +| Assert.cs:31:9:31:32 | [assertion success] call to method IsTrue | Assert.cs:32:9:32:36 | ...; | +| Assert.cs:31:9:31:33 | ...; | Assert.cs:31:23:31:23 | access to local variable s | +| Assert.cs:31:23:31:23 | access to local variable s | Assert.cs:31:28:31:31 | null | +| Assert.cs:31:23:31:31 | ... == ... | Assert.cs:31:9:31:32 | [assertion failure] call to method IsTrue | +| Assert.cs:31:23:31:31 | ... == ... | Assert.cs:31:9:31:32 | [assertion success] call to method IsTrue | +| Assert.cs:31:28:31:31 | null | Assert.cs:31:23:31:31 | ... == ... | +| Assert.cs:32:9:32:36 | ...; | Assert.cs:32:27:32:27 | access to local variable s | +| Assert.cs:32:27:32:27 | access to local variable s | Assert.cs:32:27:32:34 | access to property Length | +| Assert.cs:32:27:32:34 | access to property Length | Assert.cs:32:9:32:35 | call to method WriteLine | +| Assert.cs:35:10:35:11 | enter M5 | Assert.cs:36:5:40:5 | {...} | +| Assert.cs:36:5:40:5 | {...} | Assert.cs:37:9:37:33 | ... ...; | +| Assert.cs:37:9:37:33 | ... ...; | Assert.cs:37:20:37:32 | ... ? ... : ... | +| Assert.cs:37:16:37:32 | String s = ... | Assert.cs:38:9:38:33 | ...; | +| Assert.cs:37:20:37:20 | access to parameter b | Assert.cs:37:24:37:27 | null | +| Assert.cs:37:20:37:20 | access to parameter b | Assert.cs:37:31:37:32 | "" | +| Assert.cs:37:20:37:32 | ... ? ... : ... | Assert.cs:37:20:37:20 | access to parameter b | +| Assert.cs:38:9:38:32 | [assertion success] call to method IsTrue | Assert.cs:39:9:39:36 | ...; | +| Assert.cs:38:9:38:33 | ...; | Assert.cs:38:23:38:23 | access to local variable s | +| Assert.cs:38:23:38:23 | access to local variable s | Assert.cs:38:28:38:31 | null | +| Assert.cs:38:23:38:31 | ... != ... | Assert.cs:38:9:38:32 | [assertion failure] call to method IsTrue | +| Assert.cs:38:23:38:31 | ... != ... | Assert.cs:38:9:38:32 | [assertion success] call to method IsTrue | +| Assert.cs:38:28:38:31 | null | Assert.cs:38:23:38:31 | ... != ... | +| Assert.cs:39:9:39:36 | ...; | Assert.cs:39:27:39:27 | access to local variable s | +| Assert.cs:39:27:39:27 | access to local variable s | Assert.cs:39:27:39:34 | access to property Length | +| Assert.cs:39:27:39:34 | access to property Length | Assert.cs:39:9:39:35 | call to method WriteLine | +| Assert.cs:42:10:42:11 | enter M6 | Assert.cs:43:5:47:5 | {...} | +| Assert.cs:43:5:47:5 | {...} | Assert.cs:44:9:44:33 | ... ...; | +| Assert.cs:44:9:44:33 | ... ...; | Assert.cs:44:20:44:32 | ... ? ... : ... | +| Assert.cs:44:16:44:32 | String s = ... | Assert.cs:45:9:45:34 | ...; | +| Assert.cs:44:20:44:20 | access to parameter b | Assert.cs:44:24:44:27 | null | +| Assert.cs:44:20:44:20 | access to parameter b | Assert.cs:44:31:44:32 | "" | +| Assert.cs:44:20:44:32 | ... ? ... : ... | Assert.cs:44:20:44:20 | access to parameter b | +| Assert.cs:45:9:45:33 | [assertion success] call to method IsFalse | Assert.cs:46:9:46:36 | ...; | +| Assert.cs:45:9:45:34 | ...; | Assert.cs:45:24:45:24 | access to local variable s | +| Assert.cs:45:24:45:24 | access to local variable s | Assert.cs:45:29:45:32 | null | +| Assert.cs:45:24:45:32 | ... != ... | Assert.cs:45:9:45:33 | [assertion failure] call to method IsFalse | +| Assert.cs:45:24:45:32 | ... != ... | Assert.cs:45:9:45:33 | [assertion success] call to method IsFalse | +| Assert.cs:45:29:45:32 | null | Assert.cs:45:24:45:32 | ... != ... | +| Assert.cs:46:9:46:36 | ...; | Assert.cs:46:27:46:27 | access to local variable s | +| Assert.cs:46:27:46:27 | access to local variable s | Assert.cs:46:27:46:34 | access to property Length | +| Assert.cs:46:27:46:34 | access to property Length | Assert.cs:46:9:46:35 | call to method WriteLine | +| Assert.cs:49:10:49:11 | enter M7 | Assert.cs:50:5:54:5 | {...} | +| Assert.cs:50:5:54:5 | {...} | Assert.cs:51:9:51:33 | ... ...; | +| Assert.cs:51:9:51:33 | ... ...; | Assert.cs:51:20:51:32 | ... ? ... : ... | +| Assert.cs:51:16:51:32 | String s = ... | Assert.cs:52:9:52:34 | ...; | +| Assert.cs:51:20:51:20 | access to parameter b | Assert.cs:51:24:51:27 | null | +| Assert.cs:51:20:51:20 | access to parameter b | Assert.cs:51:31:51:32 | "" | +| Assert.cs:51:20:51:32 | ... ? ... : ... | Assert.cs:51:20:51:20 | access to parameter b | +| Assert.cs:52:9:52:33 | [assertion success] call to method IsFalse | Assert.cs:53:9:53:36 | ...; | +| Assert.cs:52:9:52:34 | ...; | Assert.cs:52:24:52:24 | access to local variable s | +| Assert.cs:52:24:52:24 | access to local variable s | Assert.cs:52:29:52:32 | null | +| Assert.cs:52:24:52:32 | ... == ... | Assert.cs:52:9:52:33 | [assertion failure] call to method IsFalse | +| Assert.cs:52:24:52:32 | ... == ... | Assert.cs:52:9:52:33 | [assertion success] call to method IsFalse | +| Assert.cs:52:29:52:32 | null | Assert.cs:52:24:52:32 | ... == ... | +| Assert.cs:53:9:53:36 | ...; | Assert.cs:53:27:53:27 | access to local variable s | +| Assert.cs:53:27:53:27 | access to local variable s | Assert.cs:53:27:53:34 | access to property Length | +| Assert.cs:53:27:53:34 | access to property Length | Assert.cs:53:9:53:35 | call to method WriteLine | +| Assert.cs:56:10:56:11 | enter M8 | Assert.cs:57:5:61:5 | {...} | +| Assert.cs:57:5:61:5 | {...} | Assert.cs:58:9:58:33 | ... ...; | +| Assert.cs:58:9:58:33 | ... ...; | Assert.cs:58:20:58:32 | ... ? ... : ... | +| Assert.cs:58:16:58:32 | [b (line 56): false] String s = ... | Assert.cs:59:9:59:38 | [b (line 56): false] ...; | +| Assert.cs:58:16:58:32 | [b (line 56): true] String s = ... | Assert.cs:59:9:59:38 | [b (line 56): true] ...; | +| Assert.cs:58:20:58:20 | access to parameter b | Assert.cs:58:24:58:27 | [b (line 56): true] null | +| Assert.cs:58:20:58:20 | access to parameter b | Assert.cs:58:31:58:32 | [b (line 56): false] "" | +| Assert.cs:58:20:58:32 | ... ? ... : ... | Assert.cs:58:20:58:20 | access to parameter b | +| Assert.cs:58:24:58:27 | [b (line 56): true] null | Assert.cs:58:16:58:32 | [b (line 56): true] String s = ... | +| Assert.cs:58:31:58:32 | [b (line 56): false] "" | Assert.cs:58:16:58:32 | [b (line 56): false] String s = ... | +| Assert.cs:59:9:59:37 | [assertion success] call to method IsTrue | Assert.cs:60:9:60:36 | ...; | +| Assert.cs:59:9:59:38 | [b (line 56): false] ...; | Assert.cs:59:23:59:36 | [b (line 56): false] ... && ... | +| Assert.cs:59:9:59:38 | [b (line 56): true] ...; | Assert.cs:59:23:59:36 | [b (line 56): true] ... && ... | +| Assert.cs:59:23:59:23 | [b (line 56): false] access to local variable s | Assert.cs:59:28:59:31 | [b (line 56): false] null | +| Assert.cs:59:23:59:23 | [b (line 56): true] access to local variable s | Assert.cs:59:28:59:31 | [b (line 56): true] null | +| Assert.cs:59:23:59:31 | [b (line 56): false] ... != ... | Assert.cs:59:36:59:36 | [b (line 56): false] access to parameter b | +| Assert.cs:59:23:59:31 | [b (line 56): true] ... != ... | Assert.cs:59:36:59:36 | [b (line 56): true] access to parameter b | +| Assert.cs:59:23:59:36 | [b (line 56): false] ... && ... | Assert.cs:59:23:59:23 | [b (line 56): false] access to local variable s | +| Assert.cs:59:23:59:36 | [b (line 56): true] ... && ... | Assert.cs:59:23:59:23 | [b (line 56): true] access to local variable s | +| Assert.cs:59:28:59:31 | [b (line 56): false] null | Assert.cs:59:23:59:31 | [b (line 56): false] ... != ... | +| Assert.cs:59:28:59:31 | [b (line 56): true] null | Assert.cs:59:23:59:31 | [b (line 56): true] ... != ... | +| Assert.cs:59:36:59:36 | [b (line 56): true] access to parameter b | Assert.cs:59:9:59:37 | [assertion success] call to method IsTrue | +| Assert.cs:60:9:60:36 | ...; | Assert.cs:60:27:60:27 | access to local variable s | +| Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:60:27:60:34 | access to property Length | +| Assert.cs:60:27:60:34 | access to property Length | Assert.cs:60:9:60:35 | call to method WriteLine | +| Assert.cs:63:10:63:11 | enter M9 | Assert.cs:64:5:68:5 | {...} | +| Assert.cs:64:5:68:5 | {...} | Assert.cs:65:9:65:33 | ... ...; | +| Assert.cs:65:9:65:33 | ... ...; | Assert.cs:65:20:65:32 | ... ? ... : ... | +| Assert.cs:65:16:65:32 | [b (line 63): false] String s = ... | Assert.cs:66:9:66:39 | [b (line 63): false] ...; | +| Assert.cs:65:16:65:32 | [b (line 63): true] String s = ... | Assert.cs:66:9:66:39 | [b (line 63): true] ...; | +| Assert.cs:65:20:65:20 | access to parameter b | Assert.cs:65:24:65:27 | [b (line 63): true] null | +| Assert.cs:65:20:65:20 | access to parameter b | Assert.cs:65:31:65:32 | [b (line 63): false] "" | +| Assert.cs:65:20:65:32 | ... ? ... : ... | Assert.cs:65:20:65:20 | access to parameter b | +| Assert.cs:65:24:65:27 | [b (line 63): true] null | Assert.cs:65:16:65:32 | [b (line 63): true] String s = ... | +| Assert.cs:65:31:65:32 | [b (line 63): false] "" | Assert.cs:65:16:65:32 | [b (line 63): false] String s = ... | +| Assert.cs:66:9:66:38 | [assertion success] call to method IsFalse | Assert.cs:67:9:67:36 | ...; | +| Assert.cs:66:9:66:39 | [b (line 63): false] ...; | Assert.cs:66:24:66:37 | [b (line 63): false] ... \|\| ... | +| Assert.cs:66:9:66:39 | [b (line 63): true] ...; | Assert.cs:66:24:66:37 | [b (line 63): true] ... \|\| ... | +| Assert.cs:66:24:66:24 | [b (line 63): false] access to local variable s | Assert.cs:66:29:66:32 | [b (line 63): false] null | +| Assert.cs:66:24:66:24 | [b (line 63): true] access to local variable s | Assert.cs:66:29:66:32 | [b (line 63): true] null | +| Assert.cs:66:24:66:32 | [b (line 63): false] ... == ... | Assert.cs:66:37:66:37 | [b (line 63): false] access to parameter b | +| Assert.cs:66:24:66:32 | [b (line 63): true] ... == ... | Assert.cs:66:37:66:37 | [b (line 63): true] access to parameter b | +| Assert.cs:66:24:66:37 | [b (line 63): false] ... \|\| ... | Assert.cs:66:24:66:24 | [b (line 63): false] access to local variable s | +| Assert.cs:66:24:66:37 | [b (line 63): true] ... \|\| ... | Assert.cs:66:24:66:24 | [b (line 63): true] access to local variable s | +| Assert.cs:66:29:66:32 | [b (line 63): false] null | Assert.cs:66:24:66:32 | [b (line 63): false] ... == ... | +| Assert.cs:66:29:66:32 | [b (line 63): true] null | Assert.cs:66:24:66:32 | [b (line 63): true] ... == ... | +| Assert.cs:66:37:66:37 | [b (line 63): false] access to parameter b | Assert.cs:66:9:66:38 | [assertion success] call to method IsFalse | +| Assert.cs:67:9:67:36 | ...; | Assert.cs:67:27:67:27 | access to local variable s | +| Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:67:27:67:34 | access to property Length | +| Assert.cs:67:27:67:34 | access to property Length | Assert.cs:67:9:67:35 | call to method WriteLine | +| Assert.cs:70:10:70:12 | enter M10 | Assert.cs:71:5:75:5 | {...} | +| Assert.cs:71:5:75:5 | {...} | Assert.cs:72:9:72:33 | ... ...; | +| Assert.cs:72:9:72:33 | ... ...; | Assert.cs:72:20:72:32 | ... ? ... : ... | +| Assert.cs:72:16:72:32 | [b (line 70): false] String s = ... | Assert.cs:73:9:73:38 | [b (line 70): false] ...; | +| Assert.cs:72:16:72:32 | [b (line 70): true] String s = ... | Assert.cs:73:9:73:38 | [b (line 70): true] ...; | +| Assert.cs:72:20:72:20 | access to parameter b | Assert.cs:72:24:72:27 | [b (line 70): true] null | +| Assert.cs:72:20:72:20 | access to parameter b | Assert.cs:72:31:72:32 | [b (line 70): false] "" | +| Assert.cs:72:20:72:32 | ... ? ... : ... | Assert.cs:72:20:72:20 | access to parameter b | +| Assert.cs:72:24:72:27 | [b (line 70): true] null | Assert.cs:72:16:72:32 | [b (line 70): true] String s = ... | +| Assert.cs:72:31:72:32 | [b (line 70): false] "" | Assert.cs:72:16:72:32 | [b (line 70): false] String s = ... | +| Assert.cs:73:9:73:37 | [assertion success] call to method IsTrue | Assert.cs:74:9:74:36 | ...; | +| Assert.cs:73:9:73:38 | [b (line 70): false] ...; | Assert.cs:73:23:73:36 | [b (line 70): false] ... && ... | +| Assert.cs:73:9:73:38 | [b (line 70): true] ...; | Assert.cs:73:23:73:36 | [b (line 70): true] ... && ... | +| Assert.cs:73:23:73:23 | [b (line 70): false] access to local variable s | Assert.cs:73:28:73:31 | [b (line 70): false] null | +| Assert.cs:73:23:73:23 | [b (line 70): true] access to local variable s | Assert.cs:73:28:73:31 | [b (line 70): true] null | +| Assert.cs:73:23:73:31 | [b (line 70): false] ... == ... | Assert.cs:73:36:73:36 | [b (line 70): false] access to parameter b | +| Assert.cs:73:23:73:31 | [b (line 70): true] ... == ... | Assert.cs:73:36:73:36 | [b (line 70): true] access to parameter b | +| Assert.cs:73:23:73:36 | [b (line 70): false] ... && ... | Assert.cs:73:23:73:23 | [b (line 70): false] access to local variable s | +| Assert.cs:73:23:73:36 | [b (line 70): true] ... && ... | Assert.cs:73:23:73:23 | [b (line 70): true] access to local variable s | +| Assert.cs:73:28:73:31 | [b (line 70): false] null | Assert.cs:73:23:73:31 | [b (line 70): false] ... == ... | +| Assert.cs:73:28:73:31 | [b (line 70): true] null | Assert.cs:73:23:73:31 | [b (line 70): true] ... == ... | +| Assert.cs:73:36:73:36 | [b (line 70): true] access to parameter b | Assert.cs:73:9:73:37 | [assertion success] call to method IsTrue | +| Assert.cs:74:9:74:36 | ...; | Assert.cs:74:27:74:27 | access to local variable s | +| Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:74:27:74:34 | access to property Length | +| Assert.cs:74:27:74:34 | access to property Length | Assert.cs:74:9:74:35 | call to method WriteLine | +| Assert.cs:77:10:77:12 | enter M11 | Assert.cs:78:5:82:5 | {...} | +| Assert.cs:78:5:82:5 | {...} | Assert.cs:79:9:79:33 | ... ...; | +| Assert.cs:79:9:79:33 | ... ...; | Assert.cs:79:20:79:32 | ... ? ... : ... | +| Assert.cs:79:16:79:32 | [b (line 77): false] String s = ... | Assert.cs:80:9:80:39 | [b (line 77): false] ...; | +| Assert.cs:79:16:79:32 | [b (line 77): true] String s = ... | Assert.cs:80:9:80:39 | [b (line 77): true] ...; | +| Assert.cs:79:20:79:20 | access to parameter b | Assert.cs:79:24:79:27 | [b (line 77): true] null | +| Assert.cs:79:20:79:20 | access to parameter b | Assert.cs:79:31:79:32 | [b (line 77): false] "" | +| Assert.cs:79:20:79:32 | ... ? ... : ... | Assert.cs:79:20:79:20 | access to parameter b | +| Assert.cs:79:24:79:27 | [b (line 77): true] null | Assert.cs:79:16:79:32 | [b (line 77): true] String s = ... | +| Assert.cs:79:31:79:32 | [b (line 77): false] "" | Assert.cs:79:16:79:32 | [b (line 77): false] String s = ... | +| Assert.cs:80:9:80:38 | [assertion success] call to method IsFalse | Assert.cs:81:9:81:36 | ...; | +| Assert.cs:80:9:80:39 | [b (line 77): false] ...; | Assert.cs:80:24:80:37 | [b (line 77): false] ... \|\| ... | +| Assert.cs:80:9:80:39 | [b (line 77): true] ...; | Assert.cs:80:24:80:37 | [b (line 77): true] ... \|\| ... | +| Assert.cs:80:24:80:24 | [b (line 77): false] access to local variable s | Assert.cs:80:29:80:32 | [b (line 77): false] null | +| Assert.cs:80:24:80:24 | [b (line 77): true] access to local variable s | Assert.cs:80:29:80:32 | [b (line 77): true] null | +| Assert.cs:80:24:80:32 | [b (line 77): false] ... != ... | Assert.cs:80:37:80:37 | [b (line 77): false] access to parameter b | +| Assert.cs:80:24:80:32 | [b (line 77): true] ... != ... | Assert.cs:80:37:80:37 | [b (line 77): true] access to parameter b | +| Assert.cs:80:24:80:37 | [b (line 77): false] ... \|\| ... | Assert.cs:80:24:80:24 | [b (line 77): false] access to local variable s | +| Assert.cs:80:24:80:37 | [b (line 77): true] ... \|\| ... | Assert.cs:80:24:80:24 | [b (line 77): true] access to local variable s | +| Assert.cs:80:29:80:32 | [b (line 77): false] null | Assert.cs:80:24:80:32 | [b (line 77): false] ... != ... | +| Assert.cs:80:29:80:32 | [b (line 77): true] null | Assert.cs:80:24:80:32 | [b (line 77): true] ... != ... | +| Assert.cs:80:37:80:37 | [b (line 77): false] access to parameter b | Assert.cs:80:9:80:38 | [assertion success] call to method IsFalse | +| Assert.cs:81:9:81:36 | ...; | Assert.cs:81:27:81:27 | access to local variable s | +| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:81:27:81:34 | access to property Length | +| Assert.cs:81:27:81:34 | access to property Length | Assert.cs:81:9:81:35 | call to method WriteLine | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:85:5:129:5 | {...} | +| Assert.cs:85:5:129:5 | {...} | Assert.cs:86:9:86:33 | ... ...; | +| Assert.cs:86:9:86:33 | ... ...; | Assert.cs:86:20:86:32 | ... ? ... : ... | +| Assert.cs:86:16:86:32 | [b (line 84): false] String s = ... | Assert.cs:87:9:87:32 | [b (line 84): false] ...; | +| Assert.cs:86:16:86:32 | [b (line 84): true] String s = ... | Assert.cs:87:9:87:32 | [b (line 84): true] ...; | +| Assert.cs:86:20:86:20 | access to parameter b | Assert.cs:86:24:86:27 | [b (line 84): true] null | +| Assert.cs:86:20:86:20 | access to parameter b | Assert.cs:86:31:86:32 | [b (line 84): false] "" | +| Assert.cs:86:20:86:32 | ... ? ... : ... | Assert.cs:86:20:86:20 | access to parameter b | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:86:16:86:32 | [b (line 84): true] String s = ... | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:86:16:86:32 | [b (line 84): false] String s = ... | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:88:9:88:36 | [b (line 84): false] ...; | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:88:9:88:36 | [b (line 84): true] ...; | +| Assert.cs:87:9:87:32 | [b (line 84): false] ...; | Assert.cs:87:22:87:22 | [b (line 84): false] access to local variable s | +| Assert.cs:87:9:87:32 | [b (line 84): true] ...; | Assert.cs:87:22:87:22 | [b (line 84): true] access to local variable s | +| Assert.cs:87:22:87:22 | [b (line 84): false] access to local variable s | Assert.cs:87:27:87:30 | [b (line 84): false] null | +| Assert.cs:87:22:87:22 | [b (line 84): true] access to local variable s | Assert.cs:87:27:87:30 | [b (line 84): true] null | +| Assert.cs:87:22:87:30 | [b (line 84): false] ... != ... | Assert.cs:87:9:87:31 | [assertion failure, b (line 84): false] call to method Assert | +| Assert.cs:87:22:87:30 | [b (line 84): false] ... != ... | Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | +| Assert.cs:87:22:87:30 | [b (line 84): true] ... != ... | Assert.cs:87:9:87:31 | [assertion failure, b (line 84): true] call to method Assert | +| Assert.cs:87:22:87:30 | [b (line 84): true] ... != ... | Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | +| Assert.cs:87:27:87:30 | [b (line 84): false] null | Assert.cs:87:22:87:30 | [b (line 84): false] ... != ... | +| Assert.cs:87:27:87:30 | [b (line 84): true] null | Assert.cs:87:22:87:30 | [b (line 84): true] ... != ... | +| Assert.cs:88:9:88:35 | [b (line 84): false] call to method WriteLine | Assert.cs:90:9:90:26 | [b (line 84): false] ...; | +| Assert.cs:88:9:88:35 | [b (line 84): true] call to method WriteLine | Assert.cs:90:9:90:26 | [b (line 84): true] ...; | +| Assert.cs:88:9:88:36 | [b (line 84): false] ...; | Assert.cs:88:27:88:27 | [b (line 84): false] access to local variable s | +| Assert.cs:88:9:88:36 | [b (line 84): true] ...; | Assert.cs:88:27:88:27 | [b (line 84): true] access to local variable s | +| Assert.cs:88:27:88:27 | [b (line 84): false] access to local variable s | Assert.cs:88:27:88:34 | [b (line 84): false] access to property Length | +| Assert.cs:88:27:88:27 | [b (line 84): true] access to local variable s | Assert.cs:88:27:88:34 | [b (line 84): true] access to property Length | +| Assert.cs:88:27:88:34 | [b (line 84): false] access to property Length | Assert.cs:88:9:88:35 | [b (line 84): false] call to method WriteLine | +| Assert.cs:88:27:88:34 | [b (line 84): true] access to property Length | Assert.cs:88:9:88:35 | [b (line 84): true] call to method WriteLine | +| Assert.cs:90:9:90:25 | [b (line 84): false] ... = ... | Assert.cs:91:9:91:25 | [b (line 84): false] ...; | +| Assert.cs:90:9:90:25 | [b (line 84): true] ... = ... | Assert.cs:91:9:91:25 | [b (line 84): true] ...; | +| Assert.cs:90:9:90:26 | [b (line 84): false] ...; | Assert.cs:90:13:90:25 | [b (line 84): false] ... ? ... : ... | +| Assert.cs:90:9:90:26 | [b (line 84): true] ...; | Assert.cs:90:13:90:25 | [b (line 84): true] ... ? ... : ... | +| Assert.cs:90:13:90:13 | [b (line 84): false] access to parameter b | Assert.cs:90:24:90:25 | [b (line 84): false] "" | +| Assert.cs:90:13:90:13 | [b (line 84): true] access to parameter b | Assert.cs:90:17:90:20 | [b (line 84): true] null | +| Assert.cs:90:13:90:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:90:13:90:13 | [b (line 84): false] access to parameter b | +| Assert.cs:90:13:90:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:90:13:90:13 | [b (line 84): true] access to parameter b | +| Assert.cs:90:17:90:20 | [b (line 84): true] null | Assert.cs:90:9:90:25 | [b (line 84): true] ... = ... | +| Assert.cs:90:24:90:25 | [b (line 84): false] "" | Assert.cs:90:9:90:25 | [b (line 84): false] ... = ... | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:92:9:92:36 | [b (line 84): false] ...; | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:92:9:92:36 | [b (line 84): true] ...; | +| Assert.cs:91:9:91:25 | [b (line 84): false] ...; | Assert.cs:91:23:91:23 | [b (line 84): false] access to local variable s | +| Assert.cs:91:9:91:25 | [b (line 84): true] ...; | Assert.cs:91:23:91:23 | [b (line 84): true] access to local variable s | +| Assert.cs:91:23:91:23 | [b (line 84): false] access to local variable s | Assert.cs:91:9:91:24 | [assertion failure, b (line 84): false] call to method IsNull | +| Assert.cs:91:23:91:23 | [b (line 84): false] access to local variable s | Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | +| Assert.cs:91:23:91:23 | [b (line 84): true] access to local variable s | Assert.cs:91:9:91:24 | [assertion failure, b (line 84): true] call to method IsNull | +| Assert.cs:91:23:91:23 | [b (line 84): true] access to local variable s | Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | +| Assert.cs:92:9:92:35 | [b (line 84): false] call to method WriteLine | Assert.cs:94:9:94:26 | [b (line 84): false] ...; | +| Assert.cs:92:9:92:35 | [b (line 84): true] call to method WriteLine | Assert.cs:94:9:94:26 | [b (line 84): true] ...; | +| Assert.cs:92:9:92:36 | [b (line 84): false] ...; | Assert.cs:92:27:92:27 | [b (line 84): false] access to local variable s | +| Assert.cs:92:9:92:36 | [b (line 84): true] ...; | Assert.cs:92:27:92:27 | [b (line 84): true] access to local variable s | +| Assert.cs:92:27:92:27 | [b (line 84): false] access to local variable s | Assert.cs:92:27:92:34 | [b (line 84): false] access to property Length | +| Assert.cs:92:27:92:27 | [b (line 84): true] access to local variable s | Assert.cs:92:27:92:34 | [b (line 84): true] access to property Length | +| Assert.cs:92:27:92:34 | [b (line 84): false] access to property Length | Assert.cs:92:9:92:35 | [b (line 84): false] call to method WriteLine | +| Assert.cs:92:27:92:34 | [b (line 84): true] access to property Length | Assert.cs:92:9:92:35 | [b (line 84): true] call to method WriteLine | +| Assert.cs:94:9:94:25 | [b (line 84): false] ... = ... | Assert.cs:95:9:95:28 | [b (line 84): false] ...; | +| Assert.cs:94:9:94:25 | [b (line 84): true] ... = ... | Assert.cs:95:9:95:28 | [b (line 84): true] ...; | +| Assert.cs:94:9:94:26 | [b (line 84): false] ...; | Assert.cs:94:13:94:25 | [b (line 84): false] ... ? ... : ... | +| Assert.cs:94:9:94:26 | [b (line 84): true] ...; | Assert.cs:94:13:94:25 | [b (line 84): true] ... ? ... : ... | +| Assert.cs:94:13:94:13 | [b (line 84): false] access to parameter b | Assert.cs:94:24:94:25 | [b (line 84): false] "" | +| Assert.cs:94:13:94:13 | [b (line 84): true] access to parameter b | Assert.cs:94:17:94:20 | [b (line 84): true] null | +| Assert.cs:94:13:94:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:94:13:94:13 | [b (line 84): false] access to parameter b | +| Assert.cs:94:13:94:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:94:13:94:13 | [b (line 84): true] access to parameter b | +| Assert.cs:94:17:94:20 | [b (line 84): true] null | Assert.cs:94:9:94:25 | [b (line 84): true] ... = ... | +| Assert.cs:94:24:94:25 | [b (line 84): false] "" | Assert.cs:94:9:94:25 | [b (line 84): false] ... = ... | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | Assert.cs:96:9:96:36 | [b (line 84): false] ...; | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:96:9:96:36 | [b (line 84): true] ...; | +| Assert.cs:95:9:95:28 | [b (line 84): false] ...; | Assert.cs:95:26:95:26 | [b (line 84): false] access to local variable s | +| Assert.cs:95:9:95:28 | [b (line 84): true] ...; | Assert.cs:95:26:95:26 | [b (line 84): true] access to local variable s | +| Assert.cs:95:26:95:26 | [b (line 84): false] access to local variable s | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): false] call to method IsNotNull | +| Assert.cs:95:26:95:26 | [b (line 84): false] access to local variable s | Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | +| Assert.cs:95:26:95:26 | [b (line 84): true] access to local variable s | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): true] call to method IsNotNull | +| Assert.cs:95:26:95:26 | [b (line 84): true] access to local variable s | Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | +| Assert.cs:96:9:96:35 | [b (line 84): false] call to method WriteLine | Assert.cs:98:9:98:26 | [b (line 84): false] ...; | +| Assert.cs:96:9:96:35 | [b (line 84): true] call to method WriteLine | Assert.cs:98:9:98:26 | [b (line 84): true] ...; | +| Assert.cs:96:9:96:36 | [b (line 84): false] ...; | Assert.cs:96:27:96:27 | [b (line 84): false] access to local variable s | +| Assert.cs:96:9:96:36 | [b (line 84): true] ...; | Assert.cs:96:27:96:27 | [b (line 84): true] access to local variable s | +| Assert.cs:96:27:96:27 | [b (line 84): false] access to local variable s | Assert.cs:96:27:96:34 | [b (line 84): false] access to property Length | +| Assert.cs:96:27:96:27 | [b (line 84): true] access to local variable s | Assert.cs:96:27:96:34 | [b (line 84): true] access to property Length | +| Assert.cs:96:27:96:34 | [b (line 84): false] access to property Length | Assert.cs:96:9:96:35 | [b (line 84): false] call to method WriteLine | +| Assert.cs:96:27:96:34 | [b (line 84): true] access to property Length | Assert.cs:96:9:96:35 | [b (line 84): true] call to method WriteLine | +| Assert.cs:98:9:98:25 | [b (line 84): false] ... = ... | Assert.cs:99:9:99:33 | [b (line 84): false] ...; | +| Assert.cs:98:9:98:25 | [b (line 84): true] ... = ... | Assert.cs:99:9:99:33 | [b (line 84): true] ...; | +| Assert.cs:98:9:98:26 | [b (line 84): false] ...; | Assert.cs:98:13:98:25 | [b (line 84): false] ... ? ... : ... | +| Assert.cs:98:9:98:26 | [b (line 84): true] ...; | Assert.cs:98:13:98:25 | [b (line 84): true] ... ? ... : ... | +| Assert.cs:98:13:98:13 | [b (line 84): false] access to parameter b | Assert.cs:98:24:98:25 | [b (line 84): false] "" | +| Assert.cs:98:13:98:13 | [b (line 84): true] access to parameter b | Assert.cs:98:17:98:20 | [b (line 84): true] null | +| Assert.cs:98:13:98:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:98:13:98:13 | [b (line 84): false] access to parameter b | +| Assert.cs:98:13:98:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:98:13:98:13 | [b (line 84): true] access to parameter b | +| Assert.cs:98:17:98:20 | [b (line 84): true] null | Assert.cs:98:9:98:25 | [b (line 84): true] ... = ... | +| Assert.cs:98:24:98:25 | [b (line 84): false] "" | Assert.cs:98:9:98:25 | [b (line 84): false] ... = ... | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:100:9:100:36 | [b (line 84): false] ...; | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:100:9:100:36 | [b (line 84): true] ...; | +| Assert.cs:99:9:99:33 | [b (line 84): false] ...; | Assert.cs:99:23:99:23 | [b (line 84): false] access to local variable s | +| Assert.cs:99:9:99:33 | [b (line 84): true] ...; | Assert.cs:99:23:99:23 | [b (line 84): true] access to local variable s | +| Assert.cs:99:23:99:23 | [b (line 84): false] access to local variable s | Assert.cs:99:28:99:31 | [b (line 84): false] null | +| Assert.cs:99:23:99:23 | [b (line 84): true] access to local variable s | Assert.cs:99:28:99:31 | [b (line 84): true] null | +| Assert.cs:99:23:99:31 | [b (line 84): false] ... == ... | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:99:23:99:31 | [b (line 84): false] ... == ... | Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | +| Assert.cs:99:23:99:31 | [b (line 84): true] ... == ... | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:99:23:99:31 | [b (line 84): true] ... == ... | Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | +| Assert.cs:99:28:99:31 | [b (line 84): false] null | Assert.cs:99:23:99:31 | [b (line 84): false] ... == ... | +| Assert.cs:99:28:99:31 | [b (line 84): true] null | Assert.cs:99:23:99:31 | [b (line 84): true] ... == ... | +| Assert.cs:100:9:100:35 | [b (line 84): false] call to method WriteLine | Assert.cs:102:9:102:26 | [b (line 84): false] ...; | +| Assert.cs:100:9:100:35 | [b (line 84): true] call to method WriteLine | Assert.cs:102:9:102:26 | [b (line 84): true] ...; | +| Assert.cs:100:9:100:36 | [b (line 84): false] ...; | Assert.cs:100:27:100:27 | [b (line 84): false] access to local variable s | +| Assert.cs:100:9:100:36 | [b (line 84): true] ...; | Assert.cs:100:27:100:27 | [b (line 84): true] access to local variable s | +| Assert.cs:100:27:100:27 | [b (line 84): false] access to local variable s | Assert.cs:100:27:100:34 | [b (line 84): false] access to property Length | +| Assert.cs:100:27:100:27 | [b (line 84): true] access to local variable s | Assert.cs:100:27:100:34 | [b (line 84): true] access to property Length | +| Assert.cs:100:27:100:34 | [b (line 84): false] access to property Length | Assert.cs:100:9:100:35 | [b (line 84): false] call to method WriteLine | +| Assert.cs:100:27:100:34 | [b (line 84): true] access to property Length | Assert.cs:100:9:100:35 | [b (line 84): true] call to method WriteLine | +| Assert.cs:102:9:102:25 | [b (line 84): false] ... = ... | Assert.cs:103:9:103:33 | [b (line 84): false] ...; | +| Assert.cs:102:9:102:25 | [b (line 84): true] ... = ... | Assert.cs:103:9:103:33 | [b (line 84): true] ...; | +| Assert.cs:102:9:102:26 | [b (line 84): false] ...; | Assert.cs:102:13:102:25 | [b (line 84): false] ... ? ... : ... | +| Assert.cs:102:9:102:26 | [b (line 84): true] ...; | Assert.cs:102:13:102:25 | [b (line 84): true] ... ? ... : ... | +| Assert.cs:102:13:102:13 | [b (line 84): false] access to parameter b | Assert.cs:102:24:102:25 | [b (line 84): false] "" | +| Assert.cs:102:13:102:13 | [b (line 84): true] access to parameter b | Assert.cs:102:17:102:20 | [b (line 84): true] null | +| Assert.cs:102:13:102:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:102:13:102:13 | [b (line 84): false] access to parameter b | +| Assert.cs:102:13:102:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:102:13:102:13 | [b (line 84): true] access to parameter b | +| Assert.cs:102:17:102:20 | [b (line 84): true] null | Assert.cs:102:9:102:25 | [b (line 84): true] ... = ... | +| Assert.cs:102:24:102:25 | [b (line 84): false] "" | Assert.cs:102:9:102:25 | [b (line 84): false] ... = ... | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:104:9:104:36 | [b (line 84): false] ...; | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:104:9:104:36 | [b (line 84): true] ...; | +| Assert.cs:103:9:103:33 | [b (line 84): false] ...; | Assert.cs:103:23:103:23 | [b (line 84): false] access to local variable s | +| Assert.cs:103:9:103:33 | [b (line 84): true] ...; | Assert.cs:103:23:103:23 | [b (line 84): true] access to local variable s | +| Assert.cs:103:23:103:23 | [b (line 84): false] access to local variable s | Assert.cs:103:28:103:31 | [b (line 84): false] null | +| Assert.cs:103:23:103:23 | [b (line 84): true] access to local variable s | Assert.cs:103:28:103:31 | [b (line 84): true] null | +| Assert.cs:103:23:103:31 | [b (line 84): false] ... != ... | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:103:23:103:31 | [b (line 84): false] ... != ... | Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | +| Assert.cs:103:23:103:31 | [b (line 84): true] ... != ... | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:103:23:103:31 | [b (line 84): true] ... != ... | Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | +| Assert.cs:103:28:103:31 | [b (line 84): false] null | Assert.cs:103:23:103:31 | [b (line 84): false] ... != ... | +| Assert.cs:103:28:103:31 | [b (line 84): true] null | Assert.cs:103:23:103:31 | [b (line 84): true] ... != ... | +| Assert.cs:104:9:104:35 | [b (line 84): false] call to method WriteLine | Assert.cs:106:9:106:26 | [b (line 84): false] ...; | +| Assert.cs:104:9:104:35 | [b (line 84): true] call to method WriteLine | Assert.cs:106:9:106:26 | [b (line 84): true] ...; | +| Assert.cs:104:9:104:36 | [b (line 84): false] ...; | Assert.cs:104:27:104:27 | [b (line 84): false] access to local variable s | +| Assert.cs:104:9:104:36 | [b (line 84): true] ...; | Assert.cs:104:27:104:27 | [b (line 84): true] access to local variable s | +| Assert.cs:104:27:104:27 | [b (line 84): false] access to local variable s | Assert.cs:104:27:104:34 | [b (line 84): false] access to property Length | +| Assert.cs:104:27:104:27 | [b (line 84): true] access to local variable s | Assert.cs:104:27:104:34 | [b (line 84): true] access to property Length | +| Assert.cs:104:27:104:34 | [b (line 84): false] access to property Length | Assert.cs:104:9:104:35 | [b (line 84): false] call to method WriteLine | +| Assert.cs:104:27:104:34 | [b (line 84): true] access to property Length | Assert.cs:104:9:104:35 | [b (line 84): true] call to method WriteLine | +| Assert.cs:106:9:106:25 | [b (line 84): false] ... = ... | Assert.cs:107:9:107:34 | [b (line 84): false] ...; | +| Assert.cs:106:9:106:25 | [b (line 84): true] ... = ... | Assert.cs:107:9:107:34 | [b (line 84): true] ...; | +| Assert.cs:106:9:106:26 | [b (line 84): false] ...; | Assert.cs:106:13:106:25 | [b (line 84): false] ... ? ... : ... | +| Assert.cs:106:9:106:26 | [b (line 84): true] ...; | Assert.cs:106:13:106:25 | [b (line 84): true] ... ? ... : ... | +| Assert.cs:106:13:106:13 | [b (line 84): false] access to parameter b | Assert.cs:106:24:106:25 | [b (line 84): false] "" | +| Assert.cs:106:13:106:13 | [b (line 84): true] access to parameter b | Assert.cs:106:17:106:20 | [b (line 84): true] null | +| Assert.cs:106:13:106:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:106:13:106:13 | [b (line 84): false] access to parameter b | +| Assert.cs:106:13:106:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:106:13:106:13 | [b (line 84): true] access to parameter b | +| Assert.cs:106:17:106:20 | [b (line 84): true] null | Assert.cs:106:9:106:25 | [b (line 84): true] ... = ... | +| Assert.cs:106:24:106:25 | [b (line 84): false] "" | Assert.cs:106:9:106:25 | [b (line 84): false] ... = ... | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | Assert.cs:108:9:108:36 | [b (line 84): false] ...; | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:108:9:108:36 | [b (line 84): true] ...; | +| Assert.cs:107:9:107:34 | [b (line 84): false] ...; | Assert.cs:107:24:107:24 | [b (line 84): false] access to local variable s | +| Assert.cs:107:9:107:34 | [b (line 84): true] ...; | Assert.cs:107:24:107:24 | [b (line 84): true] access to local variable s | +| Assert.cs:107:24:107:24 | [b (line 84): false] access to local variable s | Assert.cs:107:29:107:32 | [b (line 84): false] null | +| Assert.cs:107:24:107:24 | [b (line 84): true] access to local variable s | Assert.cs:107:29:107:32 | [b (line 84): true] null | +| Assert.cs:107:24:107:32 | [b (line 84): false] ... != ... | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | +| Assert.cs:107:24:107:32 | [b (line 84): false] ... != ... | Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | +| Assert.cs:107:24:107:32 | [b (line 84): true] ... != ... | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:107:24:107:32 | [b (line 84): true] ... != ... | Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | +| Assert.cs:107:29:107:32 | [b (line 84): false] null | Assert.cs:107:24:107:32 | [b (line 84): false] ... != ... | +| Assert.cs:107:29:107:32 | [b (line 84): true] null | Assert.cs:107:24:107:32 | [b (line 84): true] ... != ... | +| Assert.cs:108:9:108:35 | [b (line 84): false] call to method WriteLine | Assert.cs:110:9:110:26 | [b (line 84): false] ...; | +| Assert.cs:108:9:108:35 | [b (line 84): true] call to method WriteLine | Assert.cs:110:9:110:26 | [b (line 84): true] ...; | +| Assert.cs:108:9:108:36 | [b (line 84): false] ...; | Assert.cs:108:27:108:27 | [b (line 84): false] access to local variable s | +| Assert.cs:108:9:108:36 | [b (line 84): true] ...; | Assert.cs:108:27:108:27 | [b (line 84): true] access to local variable s | +| Assert.cs:108:27:108:27 | [b (line 84): false] access to local variable s | Assert.cs:108:27:108:34 | [b (line 84): false] access to property Length | +| Assert.cs:108:27:108:27 | [b (line 84): true] access to local variable s | Assert.cs:108:27:108:34 | [b (line 84): true] access to property Length | +| Assert.cs:108:27:108:34 | [b (line 84): false] access to property Length | Assert.cs:108:9:108:35 | [b (line 84): false] call to method WriteLine | +| Assert.cs:108:27:108:34 | [b (line 84): true] access to property Length | Assert.cs:108:9:108:35 | [b (line 84): true] call to method WriteLine | +| Assert.cs:110:9:110:25 | [b (line 84): false] ... = ... | Assert.cs:111:9:111:34 | [b (line 84): false] ...; | +| Assert.cs:110:9:110:25 | [b (line 84): true] ... = ... | Assert.cs:111:9:111:34 | [b (line 84): true] ...; | +| Assert.cs:110:9:110:26 | [b (line 84): false] ...; | Assert.cs:110:13:110:25 | [b (line 84): false] ... ? ... : ... | +| Assert.cs:110:9:110:26 | [b (line 84): true] ...; | Assert.cs:110:13:110:25 | [b (line 84): true] ... ? ... : ... | +| Assert.cs:110:13:110:13 | [b (line 84): false] access to parameter b | Assert.cs:110:24:110:25 | [b (line 84): false] "" | +| Assert.cs:110:13:110:13 | [b (line 84): true] access to parameter b | Assert.cs:110:17:110:20 | [b (line 84): true] null | +| Assert.cs:110:13:110:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:110:13:110:13 | [b (line 84): false] access to parameter b | +| Assert.cs:110:13:110:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:110:13:110:13 | [b (line 84): true] access to parameter b | +| Assert.cs:110:17:110:20 | [b (line 84): true] null | Assert.cs:110:9:110:25 | [b (line 84): true] ... = ... | +| Assert.cs:110:24:110:25 | [b (line 84): false] "" | Assert.cs:110:9:110:25 | [b (line 84): false] ... = ... | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | Assert.cs:112:9:112:36 | [b (line 84): false] ...; | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:112:9:112:36 | [b (line 84): true] ...; | +| Assert.cs:111:9:111:34 | [b (line 84): false] ...; | Assert.cs:111:24:111:24 | [b (line 84): false] access to local variable s | +| Assert.cs:111:9:111:34 | [b (line 84): true] ...; | Assert.cs:111:24:111:24 | [b (line 84): true] access to local variable s | +| Assert.cs:111:24:111:24 | [b (line 84): false] access to local variable s | Assert.cs:111:29:111:32 | [b (line 84): false] null | +| Assert.cs:111:24:111:24 | [b (line 84): true] access to local variable s | Assert.cs:111:29:111:32 | [b (line 84): true] null | +| Assert.cs:111:24:111:32 | [b (line 84): false] ... == ... | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | +| Assert.cs:111:24:111:32 | [b (line 84): false] ... == ... | Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | +| Assert.cs:111:24:111:32 | [b (line 84): true] ... == ... | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:111:24:111:32 | [b (line 84): true] ... == ... | Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | +| Assert.cs:111:29:111:32 | [b (line 84): false] null | Assert.cs:111:24:111:32 | [b (line 84): false] ... == ... | +| Assert.cs:111:29:111:32 | [b (line 84): true] null | Assert.cs:111:24:111:32 | [b (line 84): true] ... == ... | +| Assert.cs:112:9:112:35 | [b (line 84): false] call to method WriteLine | Assert.cs:114:9:114:26 | [b (line 84): false] ...; | +| Assert.cs:112:9:112:35 | [b (line 84): true] call to method WriteLine | Assert.cs:114:9:114:26 | [b (line 84): true] ...; | +| Assert.cs:112:9:112:36 | [b (line 84): false] ...; | Assert.cs:112:27:112:27 | [b (line 84): false] access to local variable s | +| Assert.cs:112:9:112:36 | [b (line 84): true] ...; | Assert.cs:112:27:112:27 | [b (line 84): true] access to local variable s | +| Assert.cs:112:27:112:27 | [b (line 84): false] access to local variable s | Assert.cs:112:27:112:34 | [b (line 84): false] access to property Length | +| Assert.cs:112:27:112:27 | [b (line 84): true] access to local variable s | Assert.cs:112:27:112:34 | [b (line 84): true] access to property Length | +| Assert.cs:112:27:112:34 | [b (line 84): false] access to property Length | Assert.cs:112:9:112:35 | [b (line 84): false] call to method WriteLine | +| Assert.cs:112:27:112:34 | [b (line 84): true] access to property Length | Assert.cs:112:9:112:35 | [b (line 84): true] call to method WriteLine | +| Assert.cs:114:9:114:25 | [b (line 84): false] ... = ... | Assert.cs:115:9:115:38 | [b (line 84): false] ...; | +| Assert.cs:114:9:114:25 | [b (line 84): true] ... = ... | Assert.cs:115:9:115:38 | [b (line 84): true] ...; | +| Assert.cs:114:9:114:26 | [b (line 84): false] ...; | Assert.cs:114:13:114:25 | [b (line 84): false] ... ? ... : ... | +| Assert.cs:114:9:114:26 | [b (line 84): true] ...; | Assert.cs:114:13:114:25 | [b (line 84): true] ... ? ... : ... | +| Assert.cs:114:13:114:13 | [b (line 84): false] access to parameter b | Assert.cs:114:24:114:25 | [b (line 84): false] "" | +| Assert.cs:114:13:114:13 | [b (line 84): true] access to parameter b | Assert.cs:114:17:114:20 | [b (line 84): true] null | +| Assert.cs:114:13:114:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:114:13:114:13 | [b (line 84): false] access to parameter b | +| Assert.cs:114:13:114:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:114:13:114:13 | [b (line 84): true] access to parameter b | +| Assert.cs:114:17:114:20 | [b (line 84): true] null | Assert.cs:114:9:114:25 | [b (line 84): true] ... = ... | +| Assert.cs:114:24:114:25 | [b (line 84): false] "" | Assert.cs:114:9:114:25 | [b (line 84): false] ... = ... | +| Assert.cs:115:9:115:37 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:116:9:116:36 | [b (line 84): true] ...; | +| Assert.cs:115:9:115:38 | [b (line 84): false] ...; | Assert.cs:115:23:115:36 | [b (line 84): false] ... && ... | +| Assert.cs:115:9:115:38 | [b (line 84): true] ...; | Assert.cs:115:23:115:36 | [b (line 84): true] ... && ... | +| Assert.cs:115:23:115:23 | [b (line 84): false] access to local variable s | Assert.cs:115:28:115:31 | [b (line 84): false] null | +| Assert.cs:115:23:115:23 | [b (line 84): true] access to local variable s | Assert.cs:115:28:115:31 | [b (line 84): true] null | +| Assert.cs:115:23:115:31 | [b (line 84): false] ... != ... | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:115:23:115:31 | [b (line 84): false] ... != ... | Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | +| Assert.cs:115:23:115:31 | [b (line 84): true] ... != ... | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:115:23:115:31 | [b (line 84): true] ... != ... | Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | +| Assert.cs:115:23:115:36 | [b (line 84): false] ... && ... | Assert.cs:115:23:115:23 | [b (line 84): false] access to local variable s | +| Assert.cs:115:23:115:36 | [b (line 84): true] ... && ... | Assert.cs:115:23:115:23 | [b (line 84): true] access to local variable s | +| Assert.cs:115:28:115:31 | [b (line 84): false] null | Assert.cs:115:23:115:31 | [b (line 84): false] ... != ... | +| Assert.cs:115:28:115:31 | [b (line 84): true] null | Assert.cs:115:23:115:31 | [b (line 84): true] ... != ... | +| Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | Assert.cs:115:9:115:37 | [assertion success, b (line 84): true] call to method IsTrue | +| Assert.cs:116:9:116:35 | [b (line 84): true] call to method WriteLine | Assert.cs:118:9:118:26 | [b (line 84): true] ...; | +| Assert.cs:116:9:116:36 | [b (line 84): true] ...; | Assert.cs:116:27:116:27 | [b (line 84): true] access to local variable s | +| Assert.cs:116:27:116:27 | [b (line 84): true] access to local variable s | Assert.cs:116:27:116:34 | [b (line 84): true] access to property Length | +| Assert.cs:116:27:116:34 | [b (line 84): true] access to property Length | Assert.cs:116:9:116:35 | [b (line 84): true] call to method WriteLine | +| Assert.cs:118:9:118:25 | [b (line 84): true] ... = ... | Assert.cs:119:9:119:40 | [b (line 84): true] ...; | +| Assert.cs:118:9:118:26 | [b (line 84): true] ...; | Assert.cs:118:13:118:25 | [b (line 84): true] ... ? ... : ... | +| Assert.cs:118:13:118:13 | [b (line 84): true] access to parameter b | Assert.cs:118:17:118:20 | [b (line 84): true] null | +| Assert.cs:118:13:118:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:118:13:118:13 | [b (line 84): true] access to parameter b | +| Assert.cs:118:17:118:20 | [b (line 84): true] null | Assert.cs:118:9:118:25 | [b (line 84): true] ... = ... | +| Assert.cs:119:9:119:39 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:120:9:120:36 | [b (line 84): true] ...; | +| Assert.cs:119:9:119:40 | [b (line 84): true] ...; | Assert.cs:119:24:119:38 | [b (line 84): true] ... \|\| ... | +| Assert.cs:119:24:119:24 | [b (line 84): true] access to local variable s | Assert.cs:119:29:119:32 | [b (line 84): true] null | +| Assert.cs:119:24:119:32 | [b (line 84): true] ... == ... | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:119:24:119:32 | [b (line 84): true] ... == ... | Assert.cs:119:37:119:38 | [b (line 84): true] !... | +| Assert.cs:119:24:119:38 | [b (line 84): true] ... \|\| ... | Assert.cs:119:24:119:24 | [b (line 84): true] access to local variable s | +| Assert.cs:119:29:119:32 | [b (line 84): true] null | Assert.cs:119:24:119:32 | [b (line 84): true] ... == ... | +| Assert.cs:119:37:119:38 | [b (line 84): true] !... | Assert.cs:119:38:119:38 | [b (line 84): true] access to parameter b | +| Assert.cs:119:38:119:38 | [b (line 84): true] access to parameter b | Assert.cs:119:9:119:39 | [assertion success, b (line 84): true] call to method IsFalse | +| Assert.cs:120:9:120:35 | [b (line 84): true] call to method WriteLine | Assert.cs:122:9:122:26 | [b (line 84): true] ...; | +| Assert.cs:120:9:120:36 | [b (line 84): true] ...; | Assert.cs:120:27:120:27 | [b (line 84): true] access to local variable s | +| Assert.cs:120:27:120:27 | [b (line 84): true] access to local variable s | Assert.cs:120:27:120:34 | [b (line 84): true] access to property Length | +| Assert.cs:120:27:120:34 | [b (line 84): true] access to property Length | Assert.cs:120:9:120:35 | [b (line 84): true] call to method WriteLine | +| Assert.cs:122:9:122:25 | [b (line 84): true] ... = ... | Assert.cs:123:9:123:38 | [b (line 84): true] ...; | +| Assert.cs:122:9:122:26 | [b (line 84): true] ...; | Assert.cs:122:13:122:25 | [b (line 84): true] ... ? ... : ... | +| Assert.cs:122:13:122:13 | [b (line 84): true] access to parameter b | Assert.cs:122:17:122:20 | [b (line 84): true] null | +| Assert.cs:122:13:122:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:122:13:122:13 | [b (line 84): true] access to parameter b | +| Assert.cs:122:17:122:20 | [b (line 84): true] null | Assert.cs:122:9:122:25 | [b (line 84): true] ... = ... | +| Assert.cs:123:9:123:37 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:124:9:124:36 | [b (line 84): true] ...; | +| Assert.cs:123:9:123:38 | [b (line 84): true] ...; | Assert.cs:123:23:123:36 | [b (line 84): true] ... && ... | +| Assert.cs:123:23:123:23 | [b (line 84): true] access to local variable s | Assert.cs:123:28:123:31 | [b (line 84): true] null | +| Assert.cs:123:23:123:31 | [b (line 84): true] ... == ... | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:123:23:123:31 | [b (line 84): true] ... == ... | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | +| Assert.cs:123:23:123:36 | [b (line 84): true] ... && ... | Assert.cs:123:23:123:23 | [b (line 84): true] access to local variable s | +| Assert.cs:123:28:123:31 | [b (line 84): true] null | Assert.cs:123:23:123:31 | [b (line 84): true] ... == ... | +| Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | Assert.cs:123:9:123:37 | [assertion success, b (line 84): true] call to method IsTrue | +| Assert.cs:124:9:124:35 | [b (line 84): true] call to method WriteLine | Assert.cs:126:9:126:26 | [b (line 84): true] ...; | +| Assert.cs:124:9:124:36 | [b (line 84): true] ...; | Assert.cs:124:27:124:27 | [b (line 84): true] access to local variable s | +| Assert.cs:124:27:124:27 | [b (line 84): true] access to local variable s | Assert.cs:124:27:124:34 | [b (line 84): true] access to property Length | +| Assert.cs:124:27:124:34 | [b (line 84): true] access to property Length | Assert.cs:124:9:124:35 | [b (line 84): true] call to method WriteLine | +| Assert.cs:126:9:126:25 | [b (line 84): true] ... = ... | Assert.cs:127:9:127:40 | [b (line 84): true] ...; | +| Assert.cs:126:9:126:26 | [b (line 84): true] ...; | Assert.cs:126:13:126:25 | [b (line 84): true] ... ? ... : ... | +| Assert.cs:126:13:126:13 | [b (line 84): true] access to parameter b | Assert.cs:126:17:126:20 | [b (line 84): true] null | +| Assert.cs:126:13:126:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:126:13:126:13 | [b (line 84): true] access to parameter b | +| Assert.cs:126:17:126:20 | [b (line 84): true] null | Assert.cs:126:9:126:25 | [b (line 84): true] ... = ... | +| Assert.cs:127:9:127:39 | [assertion success] call to method IsFalse | Assert.cs:128:9:128:36 | ...; | +| Assert.cs:127:9:127:40 | [b (line 84): true] ...; | Assert.cs:127:24:127:38 | [b (line 84): true] ... \|\| ... | +| Assert.cs:127:24:127:24 | [b (line 84): true] access to local variable s | Assert.cs:127:29:127:32 | [b (line 84): true] null | +| Assert.cs:127:24:127:32 | [b (line 84): true] ... != ... | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | +| Assert.cs:127:24:127:32 | [b (line 84): true] ... != ... | Assert.cs:127:37:127:38 | [b (line 84): true] !... | +| Assert.cs:127:24:127:38 | [b (line 84): true] ... \|\| ... | Assert.cs:127:24:127:24 | [b (line 84): true] access to local variable s | +| Assert.cs:127:29:127:32 | [b (line 84): true] null | Assert.cs:127:24:127:32 | [b (line 84): true] ... != ... | +| Assert.cs:127:37:127:38 | [b (line 84): true] !... | Assert.cs:127:38:127:38 | [b (line 84): true] access to parameter b | +| Assert.cs:127:38:127:38 | [b (line 84): true] access to parameter b | Assert.cs:127:9:127:39 | [assertion success] call to method IsFalse | +| Assert.cs:128:9:128:36 | ...; | Assert.cs:128:27:128:27 | access to local variable s | +| Assert.cs:128:27:128:27 | access to local variable s | Assert.cs:128:27:128:34 | access to property Length | +| Assert.cs:128:27:128:34 | access to property Length | Assert.cs:128:9:128:35 | call to method WriteLine | | Assignments.cs:3:10:3:10 | enter M | Assignments.cs:4:5:15:5 | {...} | | Assignments.cs:4:5:15:5 | {...} | Assignments.cs:5:9:5:18 | ... ...; | | Assignments.cs:5:9:5:18 | ... ...; | Assignments.cs:5:17:5:17 | 0 | @@ -477,6 +970,7 @@ dominance | CompileTimeOperators.cs:40:14:40:37 | call to method WriteLine | CompileTimeOperators.cs:28:10:28:10 | exit M | | CompileTimeOperators.cs:40:14:40:38 | ...; | CompileTimeOperators.cs:40:32:40:36 | "End" | | CompileTimeOperators.cs:40:32:40:36 | "End" | CompileTimeOperators.cs:40:14:40:37 | call to method WriteLine | +| ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | ConditionalAccess.cs:30:32:30:32 | 0 | | ConditionalAccess.cs:3:12:3:13 | enter M1 | ConditionalAccess.cs:3:26:3:26 | access to parameter i | | ConditionalAccess.cs:3:26:3:26 | access to parameter i | ConditionalAccess.cs:3:12:3:13 | exit M1 | | ConditionalAccess.cs:3:26:3:26 | access to parameter i | ConditionalAccess.cs:3:28:3:38 | call to method ToString | @@ -523,12 +1017,27 @@ dominance | ConditionalAccess.cs:25:13:25:14 | "" | ConditionalAccess.cs:25:31:25:31 | access to local variable s | | ConditionalAccess.cs:25:16:25:32 | call to method CommaJoinWith | ConditionalAccess.cs:25:9:25:32 | ... = ... | | ConditionalAccess.cs:25:31:25:31 | access to local variable s | ConditionalAccess.cs:25:16:25:32 | call to method CommaJoinWith | -| ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | -| ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | ConditionalAccess.cs:31:75:31:78 | ", " | -| ConditionalAccess.cs:31:70:31:78 | ... + ... | ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | -| ConditionalAccess.cs:31:70:31:83 | ... + ... | ConditionalAccess.cs:31:26:31:38 | exit CommaJoinWith | -| ConditionalAccess.cs:31:75:31:78 | ", " | ConditionalAccess.cs:31:70:31:78 | ... + ... | -| ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | ConditionalAccess.cs:31:70:31:83 | ... + ... | +| ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:30:32:30:32 | 0 | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:30:10:30:12 | exit Out | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:28:30:32 | ... = ... | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:28:30:32 | ... = ... | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:33:5:36:5 | {...} | +| ConditionalAccess.cs:33:5:36:5 | {...} | ConditionalAccess.cs:34:9:34:14 | ...; | +| ConditionalAccess.cs:34:9:34:13 | ... = ... | ConditionalAccess.cs:35:9:35:25 | ...; | +| ConditionalAccess.cs:34:9:34:14 | ...; | ConditionalAccess.cs:34:13:34:13 | 0 | +| ConditionalAccess.cs:34:13:34:13 | 0 | ConditionalAccess.cs:34:9:34:13 | ... = ... | +| ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:32:10:32:11 | exit M8 | +| ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:35:14:35:24 | call to method Out | +| ConditionalAccess.cs:35:9:35:12 | this access | ConditionalAccess.cs:35:9:35:12 | access to property Prop | +| ConditionalAccess.cs:35:9:35:25 | ...; | ConditionalAccess.cs:35:9:35:12 | this access | +| ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | +| ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | ConditionalAccess.cs:41:75:41:78 | ", " | +| ConditionalAccess.cs:41:70:41:78 | ... + ... | ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | +| ConditionalAccess.cs:41:70:41:83 | ... + ... | ConditionalAccess.cs:41:26:41:38 | exit CommaJoinWith | +| ConditionalAccess.cs:41:75:41:78 | ", " | ConditionalAccess.cs:41:70:41:78 | ... + ... | +| ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | ConditionalAccess.cs:41:70:41:83 | ... + ... | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:4:5:9:5 | {...} | | Conditions.cs:4:5:9:5 | {...} | Conditions.cs:5:9:6:16 | if (...) ... | | Conditions.cs:5:9:6:16 | if (...) ... | Conditions.cs:5:13:5:15 | access to parameter inc | @@ -717,9 +1226,9 @@ dominance | Conditions.cs:78:21:78:21 | 0 | Conditions.cs:78:17:78:21 | ... > ... | | Conditions.cs:79:17:79:26 | ...; | Conditions.cs:79:21:79:25 | false | | Conditions.cs:79:21:79:25 | false | Conditions.cs:79:17:79:25 | ... = ... | -| Conditions.cs:81:9:82:16 | if (...) ... | Conditions.cs:81:12:81:12 | access to local variable b | -| Conditions.cs:81:12:81:12 | access to local variable b | Conditions.cs:82:13:82:16 | ...; | -| Conditions.cs:81:12:81:12 | access to local variable b | Conditions.cs:83:16:83:16 | access to local variable x | +| Conditions.cs:81:9:82:16 | if (...) ... | Conditions.cs:81:13:81:13 | access to local variable b | +| Conditions.cs:81:13:81:13 | access to local variable b | Conditions.cs:82:13:82:16 | ...; | +| Conditions.cs:81:13:81:13 | access to local variable b | Conditions.cs:83:16:83:16 | access to local variable x | | Conditions.cs:82:13:82:13 | access to local variable x | Conditions.cs:82:13:82:15 | ...++ | | Conditions.cs:82:13:82:16 | ...; | Conditions.cs:82:13:82:13 | access to local variable x | | Conditions.cs:83:9:83:17 | return ...; | Conditions.cs:70:9:70:10 | exit M6 | @@ -798,15 +1307,15 @@ dominance | Conditions.cs:115:9:115:24 | ... ...; | Conditions.cs:115:20:115:23 | null | | Conditions.cs:115:16:115:23 | String s = ... | Conditions.cs:116:9:123:9 | for (...;...;...) ... | | Conditions.cs:115:20:115:23 | null | Conditions.cs:115:16:115:23 | String s = ... | -| Conditions.cs:116:9:123:9 | for (...;...;...) ... | Conditions.cs:116:21:116:21 | 0 | -| Conditions.cs:116:17:116:21 | Int32 i = ... | Conditions.cs:116:24:116:24 | access to local variable i | -| Conditions.cs:116:21:116:21 | 0 | Conditions.cs:116:17:116:21 | Int32 i = ... | -| Conditions.cs:116:24:116:24 | access to local variable i | Conditions.cs:116:28:116:31 | access to parameter args | -| Conditions.cs:116:24:116:38 | ... < ... | Conditions.cs:113:10:113:11 | exit M9 | -| Conditions.cs:116:24:116:38 | ... < ... | Conditions.cs:117:9:123:9 | {...} | -| Conditions.cs:116:28:116:31 | access to parameter args | Conditions.cs:116:28:116:38 | access to property Length | -| Conditions.cs:116:28:116:38 | access to property Length | Conditions.cs:116:24:116:38 | ... < ... | -| Conditions.cs:116:41:116:41 | access to local variable i | Conditions.cs:116:41:116:43 | ...++ | +| Conditions.cs:116:9:123:9 | for (...;...;...) ... | Conditions.cs:116:22:116:22 | 0 | +| Conditions.cs:116:18:116:22 | Int32 i = ... | Conditions.cs:116:25:116:25 | access to local variable i | +| Conditions.cs:116:22:116:22 | 0 | Conditions.cs:116:18:116:22 | Int32 i = ... | +| Conditions.cs:116:25:116:25 | access to local variable i | Conditions.cs:116:29:116:32 | access to parameter args | +| Conditions.cs:116:25:116:39 | ... < ... | Conditions.cs:113:10:113:11 | exit M9 | +| Conditions.cs:116:25:116:39 | ... < ... | Conditions.cs:117:9:123:9 | {...} | +| Conditions.cs:116:29:116:32 | access to parameter args | Conditions.cs:116:29:116:39 | access to property Length | +| Conditions.cs:116:29:116:39 | access to property Length | Conditions.cs:116:25:116:39 | ... < ... | +| Conditions.cs:116:42:116:42 | access to local variable i | Conditions.cs:116:42:116:44 | ...++ | | Conditions.cs:117:9:123:9 | {...} | Conditions.cs:118:13:118:44 | ... ...; | | Conditions.cs:118:13:118:44 | ... ...; | Conditions.cs:118:24:118:24 | access to local variable i | | Conditions.cs:118:17:118:43 | Boolean last = ... | Conditions.cs:119:13:120:23 | if (...) ... | @@ -867,6 +1376,28 @@ dominance | Conditions.cs:137:21:137:26 | [Field1 (line 129): true, Field2 (line 129): true] this access | Conditions.cs:137:21:137:26 | [Field1 (line 129): true, Field2 (line 129): true] access to field Field1 | | Conditions.cs:137:21:137:37 | [Field1 (line 129): true, Field2 (line 129): true] call to method ToString | Conditions.cs:131:16:131:19 | [Field1 (line 129): true, Field2 (line 129): true] true | | Conditions.cs:137:21:137:38 | [Field1 (line 129): true, Field2 (line 129): true] ...; | Conditions.cs:137:21:137:26 | [Field1 (line 129): true, Field2 (line 129): true] this access | +| Conditions.cs:143:10:143:12 | enter M11 | Conditions.cs:144:5:150:5 | {...} | +| Conditions.cs:144:5:150:5 | {...} | Conditions.cs:145:9:145:30 | ... ...; | +| Conditions.cs:145:9:145:30 | ... ...; | Conditions.cs:145:17:145:29 | ... ? ... : ... | +| Conditions.cs:145:13:145:29 | [b (line 143): false] String s = ... | Conditions.cs:146:9:149:49 | [b (line 143): false] if (...) ... | +| Conditions.cs:145:13:145:29 | [b (line 143): true] String s = ... | Conditions.cs:146:9:149:49 | [b (line 143): true] if (...) ... | +| Conditions.cs:145:17:145:17 | access to parameter b | Conditions.cs:145:21:145:23 | [b (line 143): true] "a" | +| Conditions.cs:145:17:145:17 | access to parameter b | Conditions.cs:145:27:145:29 | [b (line 143): false] "b" | +| Conditions.cs:145:17:145:29 | ... ? ... : ... | Conditions.cs:145:17:145:17 | access to parameter b | +| Conditions.cs:145:21:145:23 | [b (line 143): true] "a" | Conditions.cs:145:13:145:29 | [b (line 143): true] String s = ... | +| Conditions.cs:145:27:145:29 | [b (line 143): false] "b" | Conditions.cs:145:13:145:29 | [b (line 143): false] String s = ... | +| Conditions.cs:146:9:149:49 | [b (line 143): false] if (...) ... | Conditions.cs:146:13:146:13 | [b (line 143): false] access to parameter b | +| Conditions.cs:146:9:149:49 | [b (line 143): true] if (...) ... | Conditions.cs:146:13:146:13 | [b (line 143): true] access to parameter b | +| Conditions.cs:146:13:146:13 | [b (line 143): false] access to parameter b | Conditions.cs:149:13:149:49 | ...; | +| Conditions.cs:146:13:146:13 | [b (line 143): true] access to parameter b | Conditions.cs:147:13:147:49 | ...; | +| Conditions.cs:147:13:147:49 | ...; | Conditions.cs:147:40:147:43 | "a = " | +| Conditions.cs:147:38:147:47 | $"..." | Conditions.cs:147:13:147:48 | call to method WriteLine | +| Conditions.cs:147:40:147:43 | "a = " | Conditions.cs:147:45:147:45 | access to local variable s | +| Conditions.cs:147:45:147:45 | access to local variable s | Conditions.cs:147:38:147:47 | $"..." | +| Conditions.cs:149:13:149:49 | ...; | Conditions.cs:149:40:149:43 | "b = " | +| Conditions.cs:149:38:149:47 | $"..." | Conditions.cs:149:13:149:48 | call to method WriteLine | +| Conditions.cs:149:40:149:43 | "b = " | Conditions.cs:149:45:149:45 | access to local variable s | +| Conditions.cs:149:45:149:45 | access to local variable s | Conditions.cs:149:38:149:47 | $"..." | | ExitMethods.cs:7:10:7:11 | enter M1 | ExitMethods.cs:8:5:11:5 | {...} | | ExitMethods.cs:8:5:11:5 | {...} | ExitMethods.cs:9:9:9:25 | ...; | | ExitMethods.cs:9:9:9:24 | call to method ErrorMaybe | ExitMethods.cs:10:9:10:15 | return ...; | @@ -975,23 +1506,23 @@ dominance | ExitMethods.cs:116:27:116:29 | - | ExitMethods.cs:116:16:116:30 | call to method Contains | | ExitMethods.cs:119:17:119:32 | enter FailingAssertion | ExitMethods.cs:120:5:123:5 | {...} | | ExitMethods.cs:120:5:123:5 | {...} | ExitMethods.cs:121:9:121:29 | ...; | -| ExitMethods.cs:121:9:121:28 | call to method IsTrue | ExitMethods.cs:119:17:119:32 | exit FailingAssertion | +| ExitMethods.cs:121:9:121:28 | [assertion failure] call to method IsTrue | ExitMethods.cs:119:17:119:32 | exit FailingAssertion | | ExitMethods.cs:121:9:121:29 | ...; | ExitMethods.cs:121:23:121:27 | false | -| ExitMethods.cs:121:23:121:27 | false | ExitMethods.cs:121:9:121:28 | call to method IsTrue | +| ExitMethods.cs:121:23:121:27 | false | ExitMethods.cs:121:9:121:28 | [assertion failure] call to method IsTrue | | ExitMethods.cs:125:17:125:33 | enter FailingAssertion2 | ExitMethods.cs:126:5:129:5 | {...} | | ExitMethods.cs:126:5:129:5 | {...} | ExitMethods.cs:127:9:127:27 | ...; | | ExitMethods.cs:127:9:127:26 | call to method FailingAssertion | ExitMethods.cs:125:17:125:33 | exit FailingAssertion2 | | ExitMethods.cs:127:9:127:26 | this access | ExitMethods.cs:127:9:127:26 | call to method FailingAssertion | | ExitMethods.cs:127:9:127:27 | ...; | ExitMethods.cs:127:9:127:26 | this access | | ExitMethods.cs:131:10:131:20 | enter AssertFalse | ExitMethods.cs:131:48:131:48 | access to parameter b | -| ExitMethods.cs:131:33:131:49 | call to method IsFalse | ExitMethods.cs:131:10:131:20 | exit AssertFalse | -| ExitMethods.cs:131:48:131:48 | access to parameter b | ExitMethods.cs:131:33:131:49 | call to method IsFalse | +| ExitMethods.cs:131:48:131:48 | access to parameter b | ExitMethods.cs:131:33:131:49 | [assertion failure] call to method IsFalse | +| ExitMethods.cs:131:48:131:48 | access to parameter b | ExitMethods.cs:131:33:131:49 | [assertion success] call to method IsFalse | | ExitMethods.cs:133:17:133:33 | enter FailingAssertion3 | ExitMethods.cs:134:5:137:5 | {...} | | ExitMethods.cs:134:5:137:5 | {...} | ExitMethods.cs:135:9:135:26 | ...; | -| ExitMethods.cs:135:9:135:25 | call to method AssertFalse | ExitMethods.cs:133:17:133:33 | exit FailingAssertion3 | +| ExitMethods.cs:135:9:135:25 | [assertion failure] call to method AssertFalse | ExitMethods.cs:133:17:133:33 | exit FailingAssertion3 | | ExitMethods.cs:135:9:135:25 | this access | ExitMethods.cs:135:21:135:24 | true | | ExitMethods.cs:135:9:135:26 | ...; | ExitMethods.cs:135:9:135:25 | this access | -| ExitMethods.cs:135:21:135:24 | true | ExitMethods.cs:135:9:135:25 | call to method AssertFalse | +| ExitMethods.cs:135:21:135:24 | true | ExitMethods.cs:135:9:135:25 | [assertion failure] call to method AssertFalse | | Extensions.cs:5:23:5:29 | enter ToInt32 | Extensions.cs:6:5:8:5 | {...} | | Extensions.cs:6:5:8:5 | {...} | Extensions.cs:7:28:7:28 | access to parameter s | | Extensions.cs:7:9:7:30 | return ...; | Extensions.cs:5:23:5:29 | exit ToInt32 | @@ -1721,8 +2252,9 @@ dominance | Initializers.cs:14:47:14:47 | access to property G | Initializers.cs:14:47:14:51 | ... = ... | | Initializers.cs:14:47:14:51 | ... = ... | Initializers.cs:14:38:14:53 | { ..., ... } | | Initializers.cs:14:51:14:51 | 1 | Initializers.cs:14:47:14:47 | access to property G | -| Initializers.cs:15:9:15:64 | ... ...; | Initializers.cs:15:18:15:63 | array creation of type Initializers[] | +| Initializers.cs:15:9:15:64 | ... ...; | Initializers.cs:15:18:15:63 | 2 | | Initializers.cs:15:13:15:63 | Initializers[] iz = ... | Initializers.cs:12:10:12:10 | exit M | +| Initializers.cs:15:18:15:63 | 2 | Initializers.cs:15:18:15:63 | array creation of type Initializers[] | | Initializers.cs:15:18:15:63 | array creation of type Initializers[] | Initializers.cs:15:39:15:39 | access to local variable i | | Initializers.cs:15:37:15:63 | { ..., ... } | Initializers.cs:15:13:15:63 | Initializers[] iz = ... | | Initializers.cs:15:39:15:39 | access to local variable i | Initializers.cs:15:59:15:60 | "" | @@ -1879,27 +2411,28 @@ dominance | LoopUnrolling.cs:9:13:9:16 | access to parameter args | LoopUnrolling.cs:9:13:9:23 | access to property Length | | LoopUnrolling.cs:9:13:9:23 | access to property Length | LoopUnrolling.cs:9:28:9:28 | 0 | | LoopUnrolling.cs:9:13:9:28 | ... == ... | LoopUnrolling.cs:10:13:10:19 | return ...; | -| LoopUnrolling.cs:9:13:9:28 | ... == ... | LoopUnrolling.cs:11:28:11:31 | access to parameter args | +| LoopUnrolling.cs:9:13:9:28 | ... == ... | LoopUnrolling.cs:11:29:11:32 | access to parameter args | | LoopUnrolling.cs:9:28:9:28 | 0 | LoopUnrolling.cs:9:13:9:28 | ... == ... | -| LoopUnrolling.cs:11:9:12:35 | [unroll (line 11)] foreach (... ... in ...) ... | LoopUnrolling.cs:11:21:11:23 | String arg | -| LoopUnrolling.cs:11:21:11:23 | String arg | LoopUnrolling.cs:12:13:12:35 | ...; | -| LoopUnrolling.cs:11:28:11:31 | access to parameter args | LoopUnrolling.cs:11:9:12:35 | [unroll (line 11)] foreach (... ... in ...) ... | +| LoopUnrolling.cs:11:9:12:35 | [unroll (line 11)] foreach (... ... in ...) ... | LoopUnrolling.cs:11:22:11:24 | String arg | +| LoopUnrolling.cs:11:22:11:24 | String arg | LoopUnrolling.cs:12:13:12:35 | ...; | +| LoopUnrolling.cs:11:29:11:32 | access to parameter args | LoopUnrolling.cs:11:9:12:35 | [unroll (line 11)] foreach (... ... in ...) ... | | LoopUnrolling.cs:12:13:12:34 | call to method WriteLine | LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | | LoopUnrolling.cs:12:13:12:35 | ...; | LoopUnrolling.cs:12:31:12:33 | access to local variable arg | | LoopUnrolling.cs:12:31:12:33 | access to local variable arg | LoopUnrolling.cs:12:13:12:34 | call to method WriteLine | | LoopUnrolling.cs:15:10:15:11 | enter M2 | LoopUnrolling.cs:16:5:20:5 | {...} | -| LoopUnrolling.cs:16:5:20:5 | {...} | LoopUnrolling.cs:17:9:17:47 | ... ...; | -| LoopUnrolling.cs:17:9:17:47 | ... ...; | LoopUnrolling.cs:17:18:17:46 | array creation of type String[] | -| LoopUnrolling.cs:17:13:17:46 | String[] xs = ... | LoopUnrolling.cs:18:26:18:27 | access to local variable xs | -| LoopUnrolling.cs:17:18:17:46 | array creation of type String[] | LoopUnrolling.cs:17:32:17:34 | "a" | -| LoopUnrolling.cs:17:30:17:46 | { ..., ... } | LoopUnrolling.cs:17:13:17:46 | String[] xs = ... | -| LoopUnrolling.cs:17:32:17:34 | "a" | LoopUnrolling.cs:17:37:17:39 | "b" | -| LoopUnrolling.cs:17:37:17:39 | "b" | LoopUnrolling.cs:17:42:17:44 | "c" | -| LoopUnrolling.cs:17:42:17:44 | "c" | LoopUnrolling.cs:17:30:17:46 | { ..., ... } | -| LoopUnrolling.cs:18:9:19:33 | [unroll (line 18)] foreach (... ... in ...) ... | LoopUnrolling.cs:18:21:18:21 | String x | +| LoopUnrolling.cs:16:5:20:5 | {...} | LoopUnrolling.cs:17:9:17:48 | ... ...; | +| LoopUnrolling.cs:17:9:17:48 | ... ...; | LoopUnrolling.cs:17:18:17:47 | 3 | +| LoopUnrolling.cs:17:13:17:47 | String[] xs = ... | LoopUnrolling.cs:18:27:18:28 | access to local variable xs | +| LoopUnrolling.cs:17:18:17:47 | 3 | LoopUnrolling.cs:17:18:17:47 | array creation of type String[] | +| LoopUnrolling.cs:17:18:17:47 | array creation of type String[] | LoopUnrolling.cs:17:33:17:35 | "a" | +| LoopUnrolling.cs:17:31:17:47 | { ..., ... } | LoopUnrolling.cs:17:13:17:47 | String[] xs = ... | +| LoopUnrolling.cs:17:33:17:35 | "a" | LoopUnrolling.cs:17:38:17:40 | "b" | +| LoopUnrolling.cs:17:38:17:40 | "b" | LoopUnrolling.cs:17:43:17:45 | "c" | +| LoopUnrolling.cs:17:43:17:45 | "c" | LoopUnrolling.cs:17:31:17:47 | { ..., ... } | +| LoopUnrolling.cs:18:9:19:33 | [unroll (line 18)] foreach (... ... in ...) ... | LoopUnrolling.cs:18:22:18:22 | String x | | LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:15:10:15:11 | exit M2 | -| LoopUnrolling.cs:18:21:18:21 | String x | LoopUnrolling.cs:19:13:19:33 | ...; | -| LoopUnrolling.cs:18:26:18:27 | access to local variable xs | LoopUnrolling.cs:18:9:19:33 | [unroll (line 18)] foreach (... ... in ...) ... | +| LoopUnrolling.cs:18:22:18:22 | String x | LoopUnrolling.cs:19:13:19:33 | ...; | +| LoopUnrolling.cs:18:27:18:28 | access to local variable xs | LoopUnrolling.cs:18:9:19:33 | [unroll (line 18)] foreach (... ... in ...) ... | | LoopUnrolling.cs:19:13:19:32 | call to method WriteLine | LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... | | LoopUnrolling.cs:19:13:19:33 | ...; | LoopUnrolling.cs:19:31:19:31 | access to local variable x | | LoopUnrolling.cs:19:31:19:31 | access to local variable x | LoopUnrolling.cs:19:13:19:32 | call to method WriteLine | @@ -1918,77 +2451,77 @@ dominance | LoopUnrolling.cs:29:10:29:11 | enter M4 | LoopUnrolling.cs:30:5:34:5 | {...} | | LoopUnrolling.cs:30:5:34:5 | {...} | LoopUnrolling.cs:31:9:31:31 | ... ...; | | LoopUnrolling.cs:31:9:31:31 | ... ...; | LoopUnrolling.cs:31:29:31:29 | 0 | -| LoopUnrolling.cs:31:13:31:30 | String[] xs = ... | LoopUnrolling.cs:32:26:32:27 | access to local variable xs | +| LoopUnrolling.cs:31:13:31:30 | String[] xs = ... | LoopUnrolling.cs:32:27:32:28 | access to local variable xs | | LoopUnrolling.cs:31:18:31:30 | array creation of type String[] | LoopUnrolling.cs:31:13:31:30 | String[] xs = ... | | LoopUnrolling.cs:31:29:31:29 | 0 | LoopUnrolling.cs:31:18:31:30 | array creation of type String[] | -| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:29:10:29:11 | exit M4 | -| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:32:21:32:21 | String x | -| LoopUnrolling.cs:32:21:32:21 | String x | LoopUnrolling.cs:33:13:33:33 | ...; | -| LoopUnrolling.cs:32:26:32:27 | access to local variable xs | LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | -| LoopUnrolling.cs:33:13:33:33 | ...; | LoopUnrolling.cs:33:31:33:31 | access to local variable x | -| LoopUnrolling.cs:33:31:33:31 | access to local variable x | LoopUnrolling.cs:33:13:33:32 | call to method WriteLine | +| LoopUnrolling.cs:32:9:33:33 | [skip (line 32)] foreach (... ... in ...) ... | LoopUnrolling.cs:29:10:29:11 | exit M4 | +| LoopUnrolling.cs:32:27:32:28 | access to local variable xs | LoopUnrolling.cs:32:9:33:33 | [skip (line 32)] foreach (... ... in ...) ... | | LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:37:5:43:5 | {...} | -| LoopUnrolling.cs:37:5:43:5 | {...} | LoopUnrolling.cs:38:9:38:47 | ... ...; | -| LoopUnrolling.cs:38:9:38:47 | ... ...; | LoopUnrolling.cs:38:18:38:46 | array creation of type String[] | -| LoopUnrolling.cs:38:13:38:46 | String[] xs = ... | LoopUnrolling.cs:39:9:39:47 | ... ...; | -| LoopUnrolling.cs:38:18:38:46 | array creation of type String[] | LoopUnrolling.cs:38:32:38:34 | "a" | -| LoopUnrolling.cs:38:30:38:46 | { ..., ... } | LoopUnrolling.cs:38:13:38:46 | String[] xs = ... | -| LoopUnrolling.cs:38:32:38:34 | "a" | LoopUnrolling.cs:38:37:38:39 | "b" | -| LoopUnrolling.cs:38:37:38:39 | "b" | LoopUnrolling.cs:38:42:38:44 | "c" | -| LoopUnrolling.cs:38:42:38:44 | "c" | LoopUnrolling.cs:38:30:38:46 | { ..., ... } | -| LoopUnrolling.cs:39:9:39:47 | ... ...; | LoopUnrolling.cs:39:18:39:46 | array creation of type String[] | -| LoopUnrolling.cs:39:13:39:46 | String[] ys = ... | LoopUnrolling.cs:40:26:40:27 | access to local variable xs | -| LoopUnrolling.cs:39:18:39:46 | array creation of type String[] | LoopUnrolling.cs:39:32:39:34 | "0" | -| LoopUnrolling.cs:39:30:39:46 | { ..., ... } | LoopUnrolling.cs:39:13:39:46 | String[] ys = ... | -| LoopUnrolling.cs:39:32:39:34 | "0" | LoopUnrolling.cs:39:37:39:39 | "1" | -| LoopUnrolling.cs:39:37:39:39 | "1" | LoopUnrolling.cs:39:42:39:44 | "2" | -| LoopUnrolling.cs:39:42:39:44 | "2" | LoopUnrolling.cs:39:30:39:46 | { ..., ... } | -| LoopUnrolling.cs:40:9:42:41 | [unroll (line 40)] foreach (... ... in ...) ... | LoopUnrolling.cs:40:21:40:21 | String x | +| LoopUnrolling.cs:37:5:43:5 | {...} | LoopUnrolling.cs:38:9:38:48 | ... ...; | +| LoopUnrolling.cs:38:9:38:48 | ... ...; | LoopUnrolling.cs:38:18:38:47 | 3 | +| LoopUnrolling.cs:38:13:38:47 | String[] xs = ... | LoopUnrolling.cs:39:9:39:48 | ... ...; | +| LoopUnrolling.cs:38:18:38:47 | 3 | LoopUnrolling.cs:38:18:38:47 | array creation of type String[] | +| LoopUnrolling.cs:38:18:38:47 | array creation of type String[] | LoopUnrolling.cs:38:33:38:35 | "a" | +| LoopUnrolling.cs:38:31:38:47 | { ..., ... } | LoopUnrolling.cs:38:13:38:47 | String[] xs = ... | +| LoopUnrolling.cs:38:33:38:35 | "a" | LoopUnrolling.cs:38:38:38:40 | "b" | +| LoopUnrolling.cs:38:38:38:40 | "b" | LoopUnrolling.cs:38:43:38:45 | "c" | +| LoopUnrolling.cs:38:43:38:45 | "c" | LoopUnrolling.cs:38:31:38:47 | { ..., ... } | +| LoopUnrolling.cs:39:9:39:48 | ... ...; | LoopUnrolling.cs:39:18:39:47 | 3 | +| LoopUnrolling.cs:39:13:39:47 | String[] ys = ... | LoopUnrolling.cs:40:27:40:28 | access to local variable xs | +| LoopUnrolling.cs:39:18:39:47 | 3 | LoopUnrolling.cs:39:18:39:47 | array creation of type String[] | +| LoopUnrolling.cs:39:18:39:47 | array creation of type String[] | LoopUnrolling.cs:39:33:39:35 | "0" | +| LoopUnrolling.cs:39:31:39:47 | { ..., ... } | LoopUnrolling.cs:39:13:39:47 | String[] ys = ... | +| LoopUnrolling.cs:39:33:39:35 | "0" | LoopUnrolling.cs:39:38:39:40 | "1" | +| LoopUnrolling.cs:39:38:39:40 | "1" | LoopUnrolling.cs:39:43:39:45 | "2" | +| LoopUnrolling.cs:39:43:39:45 | "2" | LoopUnrolling.cs:39:31:39:47 | { ..., ... } | +| LoopUnrolling.cs:40:9:42:41 | [unroll (line 40)] foreach (... ... in ...) ... | LoopUnrolling.cs:40:22:40:22 | String x | | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:36:10:36:11 | exit M5 | -| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:41:30:41:31 | access to local variable ys | -| LoopUnrolling.cs:40:26:40:27 | access to local variable xs | LoopUnrolling.cs:40:9:42:41 | [unroll (line 40)] foreach (... ... in ...) ... | -| LoopUnrolling.cs:41:13:42:41 | [unroll (line 41)] foreach (... ... in ...) ... | LoopUnrolling.cs:41:25:41:25 | String y | +| LoopUnrolling.cs:40:22:40:22 | String x | LoopUnrolling.cs:41:31:41:32 | access to local variable ys | +| LoopUnrolling.cs:40:27:40:28 | access to local variable xs | LoopUnrolling.cs:40:9:42:41 | [unroll (line 40)] foreach (... ... in ...) ... | +| LoopUnrolling.cs:41:13:42:41 | [unroll (line 41)] foreach (... ... in ...) ... | LoopUnrolling.cs:41:26:41:26 | String y | | LoopUnrolling.cs:41:13:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | -| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:42:17:42:41 | ...; | -| LoopUnrolling.cs:41:30:41:31 | access to local variable ys | LoopUnrolling.cs:41:13:42:41 | [unroll (line 41)] foreach (... ... in ...) ... | +| LoopUnrolling.cs:41:26:41:26 | String y | LoopUnrolling.cs:42:17:42:41 | ...; | +| LoopUnrolling.cs:41:31:41:32 | access to local variable ys | LoopUnrolling.cs:41:13:42:41 | [unroll (line 41)] foreach (... ... in ...) ... | | LoopUnrolling.cs:42:17:42:40 | call to method WriteLine | LoopUnrolling.cs:41:13:42:41 | foreach (... ... in ...) ... | | LoopUnrolling.cs:42:17:42:41 | ...; | LoopUnrolling.cs:42:35:42:35 | access to local variable x | | LoopUnrolling.cs:42:35:42:35 | access to local variable x | LoopUnrolling.cs:42:39:42:39 | access to local variable y | | LoopUnrolling.cs:42:35:42:39 | ... + ... | LoopUnrolling.cs:42:17:42:40 | call to method WriteLine | | LoopUnrolling.cs:42:39:42:39 | access to local variable y | LoopUnrolling.cs:42:35:42:39 | ... + ... | | LoopUnrolling.cs:45:10:45:11 | enter M6 | LoopUnrolling.cs:46:5:53:5 | {...} | -| LoopUnrolling.cs:46:5:53:5 | {...} | LoopUnrolling.cs:47:9:47:47 | ... ...; | -| LoopUnrolling.cs:47:9:47:47 | ... ...; | LoopUnrolling.cs:47:18:47:46 | array creation of type String[] | -| LoopUnrolling.cs:47:13:47:46 | String[] xs = ... | LoopUnrolling.cs:48:26:48:27 | access to local variable xs | -| LoopUnrolling.cs:47:18:47:46 | array creation of type String[] | LoopUnrolling.cs:47:32:47:34 | "a" | -| LoopUnrolling.cs:47:30:47:46 | { ..., ... } | LoopUnrolling.cs:47:13:47:46 | String[] xs = ... | -| LoopUnrolling.cs:47:32:47:34 | "a" | LoopUnrolling.cs:47:37:47:39 | "b" | -| LoopUnrolling.cs:47:37:47:39 | "b" | LoopUnrolling.cs:47:42:47:44 | "c" | -| LoopUnrolling.cs:47:42:47:44 | "c" | LoopUnrolling.cs:47:30:47:46 | { ..., ... } | -| LoopUnrolling.cs:48:9:52:9 | [unroll (line 48)] foreach (... ... in ...) ... | LoopUnrolling.cs:48:21:48:21 | String x | -| LoopUnrolling.cs:48:21:48:21 | String x | LoopUnrolling.cs:49:9:52:9 | {...} | -| LoopUnrolling.cs:48:26:48:27 | access to local variable xs | LoopUnrolling.cs:48:9:52:9 | [unroll (line 48)] foreach (... ... in ...) ... | -| LoopUnrolling.cs:49:9:52:9 | {...} | LoopUnrolling.cs:50:13:50:17 | Label: | -| LoopUnrolling.cs:50:13:50:17 | Label: | LoopUnrolling.cs:50:20:50:40 | ...; | -| LoopUnrolling.cs:50:20:50:39 | call to method WriteLine | LoopUnrolling.cs:51:13:51:23 | goto ...; | -| LoopUnrolling.cs:50:20:50:40 | ...; | LoopUnrolling.cs:50:38:50:38 | access to local variable x | -| LoopUnrolling.cs:50:38:50:38 | access to local variable x | LoopUnrolling.cs:50:20:50:39 | call to method WriteLine | +| LoopUnrolling.cs:46:5:53:5 | {...} | LoopUnrolling.cs:47:9:47:48 | ... ...; | +| LoopUnrolling.cs:47:9:47:48 | ... ...; | LoopUnrolling.cs:47:18:47:47 | 3 | +| LoopUnrolling.cs:47:13:47:47 | String[] xs = ... | LoopUnrolling.cs:48:27:48:28 | access to local variable xs | +| LoopUnrolling.cs:47:18:47:47 | 3 | LoopUnrolling.cs:47:18:47:47 | array creation of type String[] | +| LoopUnrolling.cs:47:18:47:47 | array creation of type String[] | LoopUnrolling.cs:47:33:47:35 | "a" | +| LoopUnrolling.cs:47:31:47:47 | { ..., ... } | LoopUnrolling.cs:47:13:47:47 | String[] xs = ... | +| LoopUnrolling.cs:47:33:47:35 | "a" | LoopUnrolling.cs:47:38:47:40 | "b" | +| LoopUnrolling.cs:47:38:47:40 | "b" | LoopUnrolling.cs:47:43:47:45 | "c" | +| LoopUnrolling.cs:47:43:47:45 | "c" | LoopUnrolling.cs:47:31:47:47 | { ..., ... } | +| LoopUnrolling.cs:48:9:52:9 | [unroll (line 48)] foreach (... ... in ...) ... | LoopUnrolling.cs:48:22:48:22 | String x | +| LoopUnrolling.cs:48:22:48:22 | String x | LoopUnrolling.cs:49:9:52:9 | {...} | +| LoopUnrolling.cs:48:27:48:28 | access to local variable xs | LoopUnrolling.cs:48:9:52:9 | [unroll (line 48)] foreach (... ... in ...) ... | +| LoopUnrolling.cs:49:9:52:9 | {...} | LoopUnrolling.cs:50:9:50:13 | Label: | +| LoopUnrolling.cs:50:9:50:13 | Label: | LoopUnrolling.cs:50:16:50:36 | ...; | +| LoopUnrolling.cs:50:16:50:35 | call to method WriteLine | LoopUnrolling.cs:51:13:51:23 | goto ...; | +| LoopUnrolling.cs:50:16:50:36 | ...; | LoopUnrolling.cs:50:34:50:34 | access to local variable x | +| LoopUnrolling.cs:50:34:50:34 | access to local variable x | LoopUnrolling.cs:50:16:50:35 | call to method WriteLine | | LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:56:5:65:5 | {...} | -| LoopUnrolling.cs:56:5:65:5 | {...} | LoopUnrolling.cs:57:9:57:47 | ... ...; | -| LoopUnrolling.cs:57:9:57:47 | ... ...; | LoopUnrolling.cs:57:18:57:46 | array creation of type String[] | -| LoopUnrolling.cs:57:13:57:46 | String[] xs = ... | LoopUnrolling.cs:58:26:58:27 | access to local variable xs | -| LoopUnrolling.cs:57:18:57:46 | array creation of type String[] | LoopUnrolling.cs:57:32:57:34 | "a" | -| LoopUnrolling.cs:57:30:57:46 | { ..., ... } | LoopUnrolling.cs:57:13:57:46 | String[] xs = ... | -| LoopUnrolling.cs:57:32:57:34 | "a" | LoopUnrolling.cs:57:37:57:39 | "b" | -| LoopUnrolling.cs:57:37:57:39 | "b" | LoopUnrolling.cs:57:42:57:44 | "c" | -| LoopUnrolling.cs:57:42:57:44 | "c" | LoopUnrolling.cs:57:30:57:46 | { ..., ... } | -| LoopUnrolling.cs:58:9:64:9 | [b (line 55): false] foreach (... ... in ...) ... | LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | -| LoopUnrolling.cs:58:9:64:9 | [b (line 55): true] foreach (... ... in ...) ... | LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | -| LoopUnrolling.cs:58:9:64:9 | [unroll (line 58)] foreach (... ... in ...) ... | LoopUnrolling.cs:58:21:58:21 | String x | -| LoopUnrolling.cs:58:21:58:21 | String x | LoopUnrolling.cs:59:9:64:9 | {...} | -| LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | LoopUnrolling.cs:59:9:64:9 | [b (line 55): false] {...} | -| LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | LoopUnrolling.cs:59:9:64:9 | [b (line 55): true] {...} | -| LoopUnrolling.cs:58:26:58:27 | access to local variable xs | LoopUnrolling.cs:58:9:64:9 | [unroll (line 58)] foreach (... ... in ...) ... | +| LoopUnrolling.cs:56:5:65:5 | {...} | LoopUnrolling.cs:57:9:57:48 | ... ...; | +| LoopUnrolling.cs:57:9:57:48 | ... ...; | LoopUnrolling.cs:57:18:57:47 | 3 | +| LoopUnrolling.cs:57:13:57:47 | String[] xs = ... | LoopUnrolling.cs:58:27:58:28 | access to local variable xs | +| LoopUnrolling.cs:57:18:57:47 | 3 | LoopUnrolling.cs:57:18:57:47 | array creation of type String[] | +| LoopUnrolling.cs:57:18:57:47 | array creation of type String[] | LoopUnrolling.cs:57:33:57:35 | "a" | +| LoopUnrolling.cs:57:31:57:47 | { ..., ... } | LoopUnrolling.cs:57:13:57:47 | String[] xs = ... | +| LoopUnrolling.cs:57:33:57:35 | "a" | LoopUnrolling.cs:57:38:57:40 | "b" | +| LoopUnrolling.cs:57:38:57:40 | "b" | LoopUnrolling.cs:57:43:57:45 | "c" | +| LoopUnrolling.cs:57:43:57:45 | "c" | LoopUnrolling.cs:57:31:57:47 | { ..., ... } | +| LoopUnrolling.cs:58:9:64:9 | [b (line 55): false] foreach (... ... in ...) ... | LoopUnrolling.cs:58:22:58:22 | [b (line 55): false] String x | +| LoopUnrolling.cs:58:9:64:9 | [b (line 55): true] foreach (... ... in ...) ... | LoopUnrolling.cs:58:22:58:22 | [b (line 55): true] String x | +| LoopUnrolling.cs:58:9:64:9 | [unroll (line 58)] foreach (... ... in ...) ... | LoopUnrolling.cs:58:22:58:22 | String x | +| LoopUnrolling.cs:58:22:58:22 | String x | LoopUnrolling.cs:59:9:64:9 | {...} | +| LoopUnrolling.cs:58:22:58:22 | [b (line 55): false] String x | LoopUnrolling.cs:59:9:64:9 | [b (line 55): false] {...} | +| LoopUnrolling.cs:58:22:58:22 | [b (line 55): true] String x | LoopUnrolling.cs:59:9:64:9 | [b (line 55): true] {...} | +| LoopUnrolling.cs:58:27:58:28 | access to local variable xs | LoopUnrolling.cs:58:9:64:9 | [unroll (line 58)] foreach (... ... in ...) ... | | LoopUnrolling.cs:59:9:64:9 | [b (line 55): false] {...} | LoopUnrolling.cs:60:13:61:37 | [b (line 55): false] if (...) ... | | LoopUnrolling.cs:59:9:64:9 | [b (line 55): true] {...} | LoopUnrolling.cs:60:13:61:37 | [b (line 55): true] if (...) ... | | LoopUnrolling.cs:59:9:64:9 | {...} | LoopUnrolling.cs:60:13:61:37 | if (...) ... | @@ -2015,13 +2548,146 @@ dominance | LoopUnrolling.cs:69:14:69:23 | call to method Any | LoopUnrolling.cs:70:13:70:19 | return ...; | | LoopUnrolling.cs:69:14:69:23 | call to method Any | LoopUnrolling.cs:71:9:71:21 | ...; | | LoopUnrolling.cs:71:9:71:12 | access to parameter args | LoopUnrolling.cs:71:9:71:20 | call to method Clear | -| LoopUnrolling.cs:71:9:71:20 | call to method Clear | LoopUnrolling.cs:72:28:72:31 | access to parameter args | +| LoopUnrolling.cs:71:9:71:20 | call to method Clear | LoopUnrolling.cs:72:29:72:32 | access to parameter args | | LoopUnrolling.cs:71:9:71:21 | ...; | LoopUnrolling.cs:71:9:71:12 | access to parameter args | -| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:72:21:72:23 | String arg | -| LoopUnrolling.cs:72:21:72:23 | String arg | LoopUnrolling.cs:73:13:73:35 | ...; | -| LoopUnrolling.cs:72:28:72:31 | access to parameter args | LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | -| LoopUnrolling.cs:73:13:73:35 | ...; | LoopUnrolling.cs:73:31:73:33 | access to local variable arg | -| LoopUnrolling.cs:73:31:73:33 | access to local variable arg | LoopUnrolling.cs:73:13:73:34 | call to method WriteLine | +| LoopUnrolling.cs:72:29:72:32 | access to parameter args | LoopUnrolling.cs:72:9:73:35 | [skip (line 72)] foreach (... ... in ...) ... | +| LoopUnrolling.cs:76:10:76:11 | enter M9 | LoopUnrolling.cs:77:5:83:5 | {...} | +| LoopUnrolling.cs:77:5:83:5 | {...} | LoopUnrolling.cs:78:9:78:34 | ... ...; | +| LoopUnrolling.cs:78:9:78:34 | ... ...; | LoopUnrolling.cs:78:29:78:29 | 2 | +| LoopUnrolling.cs:78:13:78:33 | String[,] xs = ... | LoopUnrolling.cs:79:27:79:28 | access to local variable xs | +| LoopUnrolling.cs:78:18:78:33 | array creation of type String[,] | LoopUnrolling.cs:78:13:78:33 | String[,] xs = ... | +| LoopUnrolling.cs:78:29:78:29 | 2 | LoopUnrolling.cs:78:32:78:32 | 0 | +| LoopUnrolling.cs:78:32:78:32 | 0 | LoopUnrolling.cs:78:18:78:33 | array creation of type String[,] | +| LoopUnrolling.cs:79:9:82:9 | [skip (line 79)] foreach (... ... in ...) ... | LoopUnrolling.cs:76:10:76:11 | exit M9 | +| LoopUnrolling.cs:79:27:79:28 | access to local variable xs | LoopUnrolling.cs:79:9:82:9 | [skip (line 79)] foreach (... ... in ...) ... | +| LoopUnrolling.cs:85:10:85:12 | enter M10 | LoopUnrolling.cs:86:5:92:5 | {...} | +| LoopUnrolling.cs:86:5:92:5 | {...} | LoopUnrolling.cs:87:9:87:34 | ... ...; | +| LoopUnrolling.cs:87:9:87:34 | ... ...; | LoopUnrolling.cs:87:29:87:29 | 0 | +| LoopUnrolling.cs:87:13:87:33 | String[,] xs = ... | LoopUnrolling.cs:88:27:88:28 | access to local variable xs | +| LoopUnrolling.cs:87:18:87:33 | array creation of type String[,] | LoopUnrolling.cs:87:13:87:33 | String[,] xs = ... | +| LoopUnrolling.cs:87:29:87:29 | 0 | LoopUnrolling.cs:87:32:87:32 | 2 | +| LoopUnrolling.cs:87:32:87:32 | 2 | LoopUnrolling.cs:87:18:87:33 | array creation of type String[,] | +| LoopUnrolling.cs:88:9:91:9 | [skip (line 88)] foreach (... ... in ...) ... | LoopUnrolling.cs:85:10:85:12 | exit M10 | +| LoopUnrolling.cs:88:27:88:28 | access to local variable xs | LoopUnrolling.cs:88:9:91:9 | [skip (line 88)] foreach (... ... in ...) ... | +| LoopUnrolling.cs:94:10:94:12 | enter M11 | LoopUnrolling.cs:95:5:101:5 | {...} | +| LoopUnrolling.cs:95:5:101:5 | {...} | LoopUnrolling.cs:96:9:96:34 | ... ...; | +| LoopUnrolling.cs:96:9:96:34 | ... ...; | LoopUnrolling.cs:96:29:96:29 | 2 | +| LoopUnrolling.cs:96:13:96:33 | String[,] xs = ... | LoopUnrolling.cs:97:27:97:28 | access to local variable xs | +| LoopUnrolling.cs:96:18:96:33 | array creation of type String[,] | LoopUnrolling.cs:96:13:96:33 | String[,] xs = ... | +| LoopUnrolling.cs:96:29:96:29 | 2 | LoopUnrolling.cs:96:32:96:32 | 2 | +| LoopUnrolling.cs:96:32:96:32 | 2 | LoopUnrolling.cs:96:18:96:33 | array creation of type String[,] | +| LoopUnrolling.cs:97:9:100:9 | [unroll (line 97)] foreach (... ... in ...) ... | LoopUnrolling.cs:97:22:97:22 | String x | +| LoopUnrolling.cs:97:9:100:9 | foreach (... ... in ...) ... | LoopUnrolling.cs:94:10:94:12 | exit M11 | +| LoopUnrolling.cs:97:22:97:22 | String x | LoopUnrolling.cs:98:9:100:9 | {...} | +| LoopUnrolling.cs:97:27:97:28 | access to local variable xs | LoopUnrolling.cs:97:9:100:9 | [unroll (line 97)] foreach (... ... in ...) ... | +| LoopUnrolling.cs:98:9:100:9 | {...} | LoopUnrolling.cs:99:13:99:33 | ...; | +| LoopUnrolling.cs:99:13:99:32 | call to method WriteLine | LoopUnrolling.cs:97:9:100:9 | foreach (... ... in ...) ... | +| LoopUnrolling.cs:99:13:99:33 | ...; | LoopUnrolling.cs:99:31:99:31 | access to local variable x | +| LoopUnrolling.cs:99:31:99:31 | access to local variable x | LoopUnrolling.cs:99:13:99:32 | call to method WriteLine | +| MultiImplementationA.cs:6:22:6:31 | enter get_P1 | MultiImplementationA.cs:6:28:6:31 | null | +| MultiImplementationA.cs:6:22:6:31 | enter get_P1 | MultiImplementationB.cs:3:22:3:22 | 0 | +| MultiImplementationA.cs:6:28:6:31 | null | MultiImplementationA.cs:6:22:6:31 | throw ... | +| MultiImplementationA.cs:7:21:7:23 | enter get_P2 | MultiImplementationA.cs:7:25:7:39 | {...} | +| MultiImplementationA.cs:7:21:7:23 | enter get_P2 | MultiImplementationB.cs:4:25:4:37 | {...} | +| MultiImplementationA.cs:7:25:7:39 | {...} | MultiImplementationA.cs:7:33:7:36 | null | +| MultiImplementationA.cs:7:33:7:36 | null | MultiImplementationA.cs:7:27:7:37 | throw ...; | +| MultiImplementationA.cs:7:41:7:43 | enter set_P2 | MultiImplementationA.cs:7:45:7:59 | {...} | +| MultiImplementationA.cs:7:41:7:43 | enter set_P2 | MultiImplementationB.cs:4:43:4:45 | {...} | +| MultiImplementationA.cs:7:45:7:59 | {...} | MultiImplementationA.cs:7:53:7:56 | null | +| MultiImplementationA.cs:7:53:7:56 | null | MultiImplementationA.cs:7:47:7:57 | throw ...; | +| MultiImplementationA.cs:8:16:8:16 | enter M | MultiImplementationA.cs:8:29:8:32 | null | +| MultiImplementationA.cs:8:16:8:16 | enter M | MultiImplementationB.cs:5:23:5:23 | 2 | +| MultiImplementationA.cs:8:29:8:32 | null | MultiImplementationA.cs:8:23:8:32 | throw ... | +| MultiImplementationA.cs:13:16:13:16 | this access | MultiImplementationA.cs:13:20:13:20 | 0 | +| MultiImplementationA.cs:13:20:13:20 | 0 | MultiImplementationA.cs:13:16:13:20 | ... = ... | +| MultiImplementationA.cs:14:31:14:31 | enter get_Item | MultiImplementationA.cs:14:31:14:31 | access to parameter i | +| MultiImplementationA.cs:14:31:14:31 | enter get_Item | MultiImplementationB.cs:12:37:12:40 | null | +| MultiImplementationA.cs:15:36:15:38 | enter get_Item | MultiImplementationA.cs:15:40:15:52 | {...} | +| MultiImplementationA.cs:15:36:15:38 | enter get_Item | MultiImplementationB.cs:13:40:13:54 | {...} | +| MultiImplementationA.cs:15:40:15:52 | {...} | MultiImplementationA.cs:15:49:15:49 | access to parameter s | +| MultiImplementationA.cs:15:49:15:49 | access to parameter s | MultiImplementationA.cs:15:42:15:50 | return ...; | +| MultiImplementationA.cs:15:54:15:56 | enter set_Item | MultiImplementationA.cs:15:58:15:60 | {...} | +| MultiImplementationA.cs:15:54:15:56 | enter set_Item | MultiImplementationB.cs:13:60:13:62 | {...} | +| MultiImplementationA.cs:16:17:16:18 | enter M1 | MultiImplementationA.cs:17:5:19:5 | {...} | +| MultiImplementationA.cs:16:17:16:18 | enter M1 | MultiImplementationB.cs:15:5:17:5 | {...} | +| MultiImplementationA.cs:17:5:19:5 | {...} | MultiImplementationA.cs:18:9:18:22 | M2(...) | +| MultiImplementationA.cs:18:9:18:22 | enter M2 | MultiImplementationA.cs:18:21:18:21 | 0 | +| MultiImplementationA.cs:18:21:18:21 | 0 | MultiImplementationA.cs:18:9:18:22 | exit M2 | +| MultiImplementationA.cs:20:12:20:13 | enter C2 | MultiImplementationA.cs:13:16:13:16 | this access | +| MultiImplementationA.cs:20:12:20:13 | enter C2 | MultiImplementationB.cs:11:16:11:16 | this access | +| MultiImplementationA.cs:20:22:20:31 | {...} | MultiImplementationA.cs:20:24:20:29 | ...; | +| MultiImplementationA.cs:20:24:20:24 | this access | MultiImplementationA.cs:20:28:20:28 | access to parameter i | +| MultiImplementationA.cs:20:24:20:29 | ...; | MultiImplementationA.cs:20:24:20:24 | this access | +| MultiImplementationA.cs:20:28:20:28 | access to parameter i | MultiImplementationA.cs:20:24:20:28 | ... = ... | +| MultiImplementationA.cs:21:12:21:13 | enter C2 | MultiImplementationA.cs:21:24:21:24 | 0 | +| MultiImplementationA.cs:21:12:21:13 | enter C2 | MultiImplementationB.cs:19:24:19:24 | 1 | +| MultiImplementationA.cs:21:24:21:24 | 0 | MultiImplementationA.cs:21:19:21:22 | call to constructor C2 | +| MultiImplementationA.cs:22:6:22:7 | enter ~C2 | MultiImplementationA.cs:22:11:22:13 | {...} | +| MultiImplementationA.cs:22:6:22:7 | enter ~C2 | MultiImplementationB.cs:20:11:20:25 | {...} | +| MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | MultiImplementationA.cs:23:50:23:53 | null | +| MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | MultiImplementationB.cs:21:56:21:59 | null | +| MultiImplementationA.cs:24:16:24:16 | access to property P | MultiImplementationA.cs:24:32:24:34 | ... = ... | +| MultiImplementationA.cs:24:16:24:16 | this access | MultiImplementationA.cs:24:34:24:34 | 0 | +| MultiImplementationA.cs:24:34:24:34 | 0 | MultiImplementationA.cs:24:16:24:16 | access to property P | +| MultiImplementationA.cs:30:21:30:23 | enter get_P3 | MultiImplementationA.cs:30:34:30:37 | null | +| MultiImplementationA.cs:30:28:30:37 | throw ... | MultiImplementationA.cs:30:21:30:23 | exit get_P3 | +| MultiImplementationA.cs:30:28:30:37 | throw ... | MultiImplementationB.cs:27:21:27:23 | exit get_P3 | +| MultiImplementationA.cs:30:34:30:37 | null | MultiImplementationA.cs:30:28:30:37 | throw ... | +| MultiImplementationA.cs:36:9:36:10 | enter M1 | MultiImplementationA.cs:36:14:36:28 | {...} | +| MultiImplementationA.cs:36:9:36:10 | enter M1 | MultiImplementationB.cs:32:17:32:17 | 0 | +| MultiImplementationA.cs:36:14:36:28 | {...} | MultiImplementationA.cs:36:22:36:25 | null | +| MultiImplementationA.cs:36:22:36:25 | null | MultiImplementationA.cs:36:16:36:26 | throw ...; | +| MultiImplementationA.cs:37:9:37:10 | enter M2 | MultiImplementationA.cs:37:14:37:28 | {...} | +| MultiImplementationA.cs:37:14:37:28 | {...} | MultiImplementationA.cs:37:22:37:25 | null | +| MultiImplementationA.cs:37:16:37:26 | throw ...; | MultiImplementationA.cs:37:9:37:10 | exit M2 | +| MultiImplementationA.cs:37:22:37:25 | null | MultiImplementationA.cs:37:16:37:26 | throw ...; | +| MultiImplementationB.cs:3:22:3:22 | enter get_P1 | MultiImplementationA.cs:6:28:6:31 | null | +| MultiImplementationB.cs:3:22:3:22 | enter get_P1 | MultiImplementationB.cs:3:22:3:22 | 0 | +| MultiImplementationB.cs:4:21:4:23 | enter get_P2 | MultiImplementationA.cs:7:25:7:39 | {...} | +| MultiImplementationB.cs:4:21:4:23 | enter get_P2 | MultiImplementationB.cs:4:25:4:37 | {...} | +| MultiImplementationB.cs:4:25:4:37 | {...} | MultiImplementationB.cs:4:34:4:34 | 1 | +| MultiImplementationB.cs:4:34:4:34 | 1 | MultiImplementationB.cs:4:27:4:35 | return ...; | +| MultiImplementationB.cs:4:39:4:41 | enter set_P2 | MultiImplementationA.cs:7:45:7:59 | {...} | +| MultiImplementationB.cs:4:39:4:41 | enter set_P2 | MultiImplementationB.cs:4:43:4:45 | {...} | +| MultiImplementationB.cs:5:16:5:16 | enter M | MultiImplementationA.cs:8:29:8:32 | null | +| MultiImplementationB.cs:5:16:5:16 | enter M | MultiImplementationB.cs:5:23:5:23 | 2 | +| MultiImplementationB.cs:11:16:11:16 | this access | MultiImplementationB.cs:11:20:11:20 | 1 | +| MultiImplementationB.cs:11:20:11:20 | 1 | MultiImplementationB.cs:11:16:11:20 | ... = ... | +| MultiImplementationB.cs:12:31:12:40 | enter get_Item | MultiImplementationA.cs:14:31:14:31 | access to parameter i | +| MultiImplementationB.cs:12:31:12:40 | enter get_Item | MultiImplementationB.cs:12:37:12:40 | null | +| MultiImplementationB.cs:12:37:12:40 | null | MultiImplementationB.cs:12:31:12:40 | throw ... | +| MultiImplementationB.cs:13:36:13:38 | enter get_Item | MultiImplementationA.cs:15:40:15:52 | {...} | +| MultiImplementationB.cs:13:36:13:38 | enter get_Item | MultiImplementationB.cs:13:40:13:54 | {...} | +| MultiImplementationB.cs:13:40:13:54 | {...} | MultiImplementationB.cs:13:48:13:51 | null | +| MultiImplementationB.cs:13:48:13:51 | null | MultiImplementationB.cs:13:42:13:52 | throw ...; | +| MultiImplementationB.cs:13:56:13:58 | enter set_Item | MultiImplementationA.cs:15:58:15:60 | {...} | +| MultiImplementationB.cs:13:56:13:58 | enter set_Item | MultiImplementationB.cs:13:60:13:62 | {...} | +| MultiImplementationB.cs:14:17:14:18 | enter M1 | MultiImplementationA.cs:17:5:19:5 | {...} | +| MultiImplementationB.cs:14:17:14:18 | enter M1 | MultiImplementationB.cs:15:5:17:5 | {...} | +| MultiImplementationB.cs:15:5:17:5 | {...} | MultiImplementationB.cs:16:9:16:31 | M2(...) | +| MultiImplementationB.cs:16:9:16:31 | enter M2 | MultiImplementationB.cs:16:27:16:30 | null | +| MultiImplementationB.cs:16:21:16:30 | throw ... | MultiImplementationB.cs:16:9:16:31 | exit M2 | +| MultiImplementationB.cs:16:27:16:30 | null | MultiImplementationB.cs:16:21:16:30 | throw ... | +| MultiImplementationB.cs:18:12:18:13 | enter C2 | MultiImplementationA.cs:13:16:13:16 | this access | +| MultiImplementationB.cs:18:12:18:13 | enter C2 | MultiImplementationB.cs:11:16:11:16 | this access | +| MultiImplementationB.cs:18:22:18:36 | {...} | MultiImplementationB.cs:18:30:18:33 | null | +| MultiImplementationB.cs:18:30:18:33 | null | MultiImplementationB.cs:18:24:18:34 | throw ...; | +| MultiImplementationB.cs:19:12:19:13 | enter C2 | MultiImplementationA.cs:21:24:21:24 | 0 | +| MultiImplementationB.cs:19:12:19:13 | enter C2 | MultiImplementationB.cs:19:24:19:24 | 1 | +| MultiImplementationB.cs:19:24:19:24 | 1 | MultiImplementationB.cs:19:19:19:22 | call to constructor C2 | +| MultiImplementationB.cs:20:6:20:7 | enter ~C2 | MultiImplementationA.cs:22:11:22:13 | {...} | +| MultiImplementationB.cs:20:6:20:7 | enter ~C2 | MultiImplementationB.cs:20:11:20:25 | {...} | +| MultiImplementationB.cs:20:11:20:25 | {...} | MultiImplementationB.cs:20:19:20:22 | null | +| MultiImplementationB.cs:20:19:20:22 | null | MultiImplementationB.cs:20:13:20:23 | throw ...; | +| MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | MultiImplementationA.cs:23:50:23:53 | null | +| MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | MultiImplementationB.cs:21:56:21:59 | null | +| MultiImplementationB.cs:21:56:21:59 | null | MultiImplementationB.cs:21:50:21:59 | throw ... | +| MultiImplementationB.cs:22:16:22:16 | access to property P | MultiImplementationB.cs:22:32:22:34 | ... = ... | +| MultiImplementationB.cs:22:16:22:16 | this access | MultiImplementationB.cs:22:34:22:34 | 1 | +| MultiImplementationB.cs:22:34:22:34 | 1 | MultiImplementationB.cs:22:16:22:16 | access to property P | +| MultiImplementationB.cs:27:21:27:23 | enter get_P3 | MultiImplementationA.cs:30:34:30:37 | null | +| MultiImplementationB.cs:32:9:32:10 | enter M1 | MultiImplementationA.cs:36:14:36:28 | {...} | +| MultiImplementationB.cs:32:9:32:10 | enter M1 | MultiImplementationB.cs:32:17:32:17 | 0 | | NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:23:3:28 | ... ?? ... | | NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:9:3:10 | exit M1 | | NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:28:3:28 | 0 | @@ -2242,9 +2908,9 @@ dominance | Switch.cs:25:35:25:35 | access to local variable s | Switch.cs:25:17:25:36 | call to method WriteLine | | Switch.cs:27:13:27:39 | case ...: | Switch.cs:27:18:27:25 | Double d | | Switch.cs:27:18:27:25 | Double d | Switch.cs:27:32:27:38 | call to method Throw | -| Switch.cs:28:17:28:21 | Label: | Switch.cs:29:17:29:23 | return ...; | +| Switch.cs:28:13:28:17 | Label: | Switch.cs:29:17:29:23 | return ...; | | Switch.cs:30:13:30:20 | default: | Switch.cs:31:17:31:27 | goto ...; | -| Switch.cs:31:17:31:27 | goto ...; | Switch.cs:28:17:28:21 | Label: | +| Switch.cs:31:17:31:27 | goto ...; | Switch.cs:28:13:28:17 | Label: | | Switch.cs:35:10:35:11 | enter M3 | Switch.cs:36:5:42:5 | {...} | | Switch.cs:36:5:42:5 | {...} | Switch.cs:37:9:41:9 | switch (...) {...} | | Switch.cs:37:9:41:9 | switch (...) {...} | Switch.cs:37:17:37:23 | call to method Throw | @@ -2265,63 +2931,63 @@ dominance | Switch.cs:56:5:64:5 | {...} | Switch.cs:57:9:63:9 | switch (...) {...} | | Switch.cs:57:9:63:9 | switch (...) {...} | Switch.cs:57:17:57:17 | 1 | | Switch.cs:57:17:57:17 | 1 | Switch.cs:57:21:57:21 | 2 | -| Switch.cs:57:17:57:21 | ... + ... | Switch.cs:59:13:59:20 | case ...: | +| Switch.cs:57:17:57:21 | ... + ... | Switch.cs:59:13:59:19 | case ...: | | Switch.cs:57:21:57:21 | 2 | Switch.cs:57:17:57:21 | ... + ... | -| Switch.cs:59:13:59:20 | case ...: | Switch.cs:59:18:59:18 | 2 | -| Switch.cs:59:18:59:18 | 2 | Switch.cs:61:13:61:20 | case ...: | -| Switch.cs:61:13:61:20 | case ...: | Switch.cs:61:18:61:18 | 3 | -| Switch.cs:61:18:61:18 | 3 | Switch.cs:62:15:62:20 | break; | -| Switch.cs:62:15:62:20 | break; | Switch.cs:55:10:55:11 | exit M5 | +| Switch.cs:59:13:59:19 | case ...: | Switch.cs:59:18:59:18 | 2 | +| Switch.cs:59:18:59:18 | 2 | Switch.cs:61:13:61:19 | case ...: | +| Switch.cs:61:13:61:19 | case ...: | Switch.cs:61:18:61:18 | 3 | +| Switch.cs:61:18:61:18 | 3 | Switch.cs:62:17:62:22 | break; | +| Switch.cs:62:17:62:22 | break; | Switch.cs:55:10:55:11 | exit M5 | | Switch.cs:66:10:66:11 | enter M6 | Switch.cs:67:5:75:5 | {...} | | Switch.cs:67:5:75:5 | {...} | Switch.cs:68:9:74:9 | switch (...) {...} | | Switch.cs:68:9:74:9 | switch (...) {...} | Switch.cs:68:25:68:25 | access to parameter s | -| Switch.cs:68:17:68:25 | (...) ... | Switch.cs:70:13:70:24 | case ...: | +| Switch.cs:68:17:68:25 | (...) ... | Switch.cs:70:13:70:23 | case ...: | | Switch.cs:68:25:68:25 | access to parameter s | Switch.cs:68:17:68:25 | (...) ... | -| Switch.cs:70:13:70:24 | case ...: | Switch.cs:70:18:70:20 | access to type Int32 | -| Switch.cs:70:18:70:20 | access to type Int32 | Switch.cs:72:13:72:21 | case ...: | -| Switch.cs:72:13:72:21 | case ...: | Switch.cs:72:18:72:19 | "" | +| Switch.cs:70:13:70:23 | case ...: | Switch.cs:70:18:70:20 | access to type Int32 | +| Switch.cs:70:18:70:20 | access to type Int32 | Switch.cs:72:13:72:20 | case ...: | +| Switch.cs:72:13:72:20 | case ...: | Switch.cs:72:18:72:19 | "" | | Switch.cs:72:18:72:19 | "" | Switch.cs:66:10:66:11 | exit M6 | -| Switch.cs:72:18:72:19 | "" | Switch.cs:73:15:73:20 | break; | +| Switch.cs:72:18:72:19 | "" | Switch.cs:73:17:73:22 | break; | | Switch.cs:77:10:77:11 | enter M7 | Switch.cs:78:5:89:5 | {...} | | Switch.cs:78:5:89:5 | {...} | Switch.cs:79:9:87:9 | switch (...) {...} | | Switch.cs:79:9:87:9 | switch (...) {...} | Switch.cs:79:17:79:17 | access to parameter i | -| Switch.cs:79:17:79:17 | access to parameter i | Switch.cs:81:13:81:20 | case ...: | -| Switch.cs:81:13:81:20 | case ...: | Switch.cs:81:18:81:18 | 1 | -| Switch.cs:81:18:81:18 | 1 | Switch.cs:82:22:82:25 | true | -| Switch.cs:81:18:81:18 | 1 | Switch.cs:83:13:83:20 | case ...: | -| Switch.cs:82:22:82:25 | true | Switch.cs:82:15:82:26 | return ...; | -| Switch.cs:83:13:83:20 | case ...: | Switch.cs:83:18:83:18 | 2 | -| Switch.cs:83:18:83:18 | 2 | Switch.cs:84:15:85:22 | if (...) ... | +| Switch.cs:79:17:79:17 | access to parameter i | Switch.cs:81:13:81:19 | case ...: | +| Switch.cs:81:13:81:19 | case ...: | Switch.cs:81:18:81:18 | 1 | +| Switch.cs:81:18:81:18 | 1 | Switch.cs:82:24:82:27 | true | +| Switch.cs:81:18:81:18 | 1 | Switch.cs:83:13:83:19 | case ...: | +| Switch.cs:82:24:82:27 | true | Switch.cs:82:17:82:28 | return ...; | +| Switch.cs:83:13:83:19 | case ...: | Switch.cs:83:18:83:18 | 2 | +| Switch.cs:83:18:83:18 | 2 | Switch.cs:84:17:85:26 | if (...) ... | | Switch.cs:83:18:83:18 | 2 | Switch.cs:88:16:88:20 | false | -| Switch.cs:84:15:85:22 | if (...) ... | Switch.cs:84:19:84:19 | access to parameter j | -| Switch.cs:84:19:84:19 | access to parameter j | Switch.cs:84:23:84:23 | 2 | -| Switch.cs:84:19:84:23 | ... > ... | Switch.cs:85:17:85:22 | break; | -| Switch.cs:84:19:84:23 | ... > ... | Switch.cs:86:22:86:25 | true | -| Switch.cs:84:23:84:23 | 2 | Switch.cs:84:19:84:23 | ... > ... | -| Switch.cs:86:22:86:25 | true | Switch.cs:86:15:86:26 | return ...; | +| Switch.cs:84:17:85:26 | if (...) ... | Switch.cs:84:21:84:21 | access to parameter j | +| Switch.cs:84:21:84:21 | access to parameter j | Switch.cs:84:25:84:25 | 2 | +| Switch.cs:84:21:84:25 | ... > ... | Switch.cs:85:21:85:26 | break; | +| Switch.cs:84:21:84:25 | ... > ... | Switch.cs:86:24:86:27 | true | +| Switch.cs:84:25:84:25 | 2 | Switch.cs:84:21:84:25 | ... > ... | +| Switch.cs:86:24:86:27 | true | Switch.cs:86:17:86:28 | return ...; | | Switch.cs:88:16:88:20 | false | Switch.cs:88:9:88:21 | return ...; | | Switch.cs:91:10:91:11 | enter M8 | Switch.cs:92:5:99:5 | {...} | | Switch.cs:92:5:99:5 | {...} | Switch.cs:93:9:97:9 | switch (...) {...} | | Switch.cs:93:9:97:9 | switch (...) {...} | Switch.cs:93:17:93:17 | access to parameter o | -| Switch.cs:93:17:93:17 | access to parameter o | Switch.cs:95:13:95:24 | case ...: | -| Switch.cs:95:13:95:24 | case ...: | Switch.cs:95:18:95:20 | access to type Int32 | -| Switch.cs:95:18:95:20 | access to type Int32 | Switch.cs:96:22:96:25 | true | +| Switch.cs:93:17:93:17 | access to parameter o | Switch.cs:95:13:95:23 | case ...: | +| Switch.cs:95:13:95:23 | case ...: | Switch.cs:95:18:95:20 | access to type Int32 | +| Switch.cs:95:18:95:20 | access to type Int32 | Switch.cs:96:24:96:27 | true | | Switch.cs:95:18:95:20 | access to type Int32 | Switch.cs:98:16:98:20 | false | -| Switch.cs:96:22:96:25 | true | Switch.cs:96:15:96:26 | return ...; | +| Switch.cs:96:24:96:27 | true | Switch.cs:96:17:96:28 | return ...; | | Switch.cs:98:16:98:20 | false | Switch.cs:98:9:98:21 | return ...; | | Switch.cs:101:9:101:10 | enter M9 | Switch.cs:102:5:109:5 | {...} | | Switch.cs:102:5:109:5 | {...} | Switch.cs:103:9:107:9 | switch (...) {...} | | Switch.cs:103:9:107:9 | switch (...) {...} | Switch.cs:103:17:103:17 | access to parameter s | | Switch.cs:103:17:103:17 | access to parameter s | Switch.cs:103:19:103:25 | access to property Length | -| Switch.cs:103:17:103:17 | access to parameter s | Switch.cs:105:13:105:20 | case ...: | -| Switch.cs:105:13:105:20 | case ...: | Switch.cs:105:18:105:18 | 0 | -| Switch.cs:105:18:105:18 | 0 | Switch.cs:105:29:105:29 | 0 | -| Switch.cs:105:18:105:18 | 0 | Switch.cs:106:13:106:20 | case ...: | -| Switch.cs:105:29:105:29 | 0 | Switch.cs:105:22:105:30 | return ...; | -| Switch.cs:106:13:106:20 | case ...: | Switch.cs:106:18:106:18 | 1 | -| Switch.cs:106:18:106:18 | 1 | Switch.cs:106:29:106:29 | 1 | +| Switch.cs:103:17:103:17 | access to parameter s | Switch.cs:105:13:105:19 | case ...: | +| Switch.cs:105:13:105:19 | case ...: | Switch.cs:105:18:105:18 | 0 | +| Switch.cs:105:18:105:18 | 0 | Switch.cs:105:28:105:28 | 0 | +| Switch.cs:105:18:105:18 | 0 | Switch.cs:106:13:106:19 | case ...: | +| Switch.cs:105:28:105:28 | 0 | Switch.cs:105:21:105:29 | return ...; | +| Switch.cs:106:13:106:19 | case ...: | Switch.cs:106:18:106:18 | 1 | +| Switch.cs:106:18:106:18 | 1 | Switch.cs:106:28:106:28 | 1 | | Switch.cs:106:18:106:18 | 1 | Switch.cs:108:17:108:17 | 1 | -| Switch.cs:106:29:106:29 | 1 | Switch.cs:106:22:106:30 | return ...; | +| Switch.cs:106:28:106:28 | 1 | Switch.cs:106:21:106:29 | return ...; | | Switch.cs:108:16:108:17 | -... | Switch.cs:108:9:108:18 | return ...; | | Switch.cs:108:17:108:17 | 1 | Switch.cs:108:16:108:17 | -... | | Switch.cs:111:17:111:21 | enter Throw | Switch.cs:111:34:111:48 | object creation of type Exception | @@ -2331,21 +2997,21 @@ dominance | Switch.cs:114:5:121:5 | {...} | Switch.cs:115:9:119:9 | switch (...) {...} | | Switch.cs:115:9:119:9 | switch (...) {...} | Switch.cs:115:17:115:17 | access to parameter s | | Switch.cs:115:17:115:17 | access to parameter s | Switch.cs:115:17:115:24 | access to property Length | -| Switch.cs:115:17:115:24 | access to property Length | Switch.cs:117:13:117:34 | case ...: | -| Switch.cs:117:13:117:34 | case ...: | Switch.cs:117:18:117:18 | 3 | +| Switch.cs:115:17:115:24 | access to property Length | Switch.cs:117:13:117:35 | case ...: | +| Switch.cs:117:13:117:35 | case ...: | Switch.cs:117:18:117:18 | 3 | | Switch.cs:117:18:117:18 | 3 | Switch.cs:117:25:117:25 | access to parameter s | -| Switch.cs:117:18:117:18 | 3 | Switch.cs:118:13:118:33 | case ...: | -| Switch.cs:117:25:117:25 | access to parameter s | Switch.cs:117:28:117:32 | "foo" | -| Switch.cs:117:25:117:32 | ... == ... | Switch.cs:117:43:117:43 | 1 | -| Switch.cs:117:28:117:32 | "foo" | Switch.cs:117:25:117:32 | ... == ... | -| Switch.cs:117:43:117:43 | 1 | Switch.cs:117:36:117:44 | return ...; | -| Switch.cs:118:13:118:33 | case ...: | Switch.cs:118:18:118:18 | 2 | +| Switch.cs:117:18:117:18 | 3 | Switch.cs:118:13:118:34 | case ...: | +| Switch.cs:117:25:117:25 | access to parameter s | Switch.cs:117:30:117:34 | "foo" | +| Switch.cs:117:25:117:34 | ... == ... | Switch.cs:117:44:117:44 | 1 | +| Switch.cs:117:30:117:34 | "foo" | Switch.cs:117:25:117:34 | ... == ... | +| Switch.cs:117:44:117:44 | 1 | Switch.cs:117:37:117:45 | return ...; | +| Switch.cs:118:13:118:34 | case ...: | Switch.cs:118:18:118:18 | 2 | | Switch.cs:118:18:118:18 | 2 | Switch.cs:118:25:118:25 | access to parameter s | | Switch.cs:118:18:118:18 | 2 | Switch.cs:120:17:120:17 | 1 | -| Switch.cs:118:25:118:25 | access to parameter s | Switch.cs:118:28:118:31 | "fu" | -| Switch.cs:118:25:118:31 | ... == ... | Switch.cs:118:42:118:42 | 2 | -| Switch.cs:118:28:118:31 | "fu" | Switch.cs:118:25:118:31 | ... == ... | -| Switch.cs:118:42:118:42 | 2 | Switch.cs:118:35:118:43 | return ...; | +| Switch.cs:118:25:118:25 | access to parameter s | Switch.cs:118:30:118:33 | "fu" | +| Switch.cs:118:25:118:33 | ... == ... | Switch.cs:118:43:118:43 | 2 | +| Switch.cs:118:30:118:33 | "fu" | Switch.cs:118:25:118:33 | ... == ... | +| Switch.cs:118:43:118:43 | 2 | Switch.cs:118:36:118:44 | return ...; | | Switch.cs:120:16:120:17 | -... | Switch.cs:120:9:120:18 | return ...; | | Switch.cs:120:17:120:17 | 1 | Switch.cs:120:16:120:17 | -... | | Switch.cs:123:10:123:12 | enter M11 | Switch.cs:124:5:127:5 | {...} | @@ -2400,6 +3066,28 @@ dominance | Switch.cs:150:18:150:18 | 2 | Switch.cs:149:13:149:20 | default: | | Switch.cs:150:18:150:18 | 2 | Switch.cs:150:28:150:28 | 2 | | Switch.cs:150:28:150:28 | 2 | Switch.cs:150:21:150:29 | return ...; | +| Switch.cs:154:10:154:12 | enter M15 | Switch.cs:155:5:161:5 | {...} | +| Switch.cs:155:5:161:5 | {...} | Switch.cs:156:9:156:55 | ... ...; | +| Switch.cs:156:9:156:55 | ... ...; | Switch.cs:156:17:156:54 | ... switch { ... } | +| Switch.cs:156:13:156:54 | String s = ... | Switch.cs:157:9:160:49 | if (...) ... | +| Switch.cs:156:17:156:17 | access to parameter b | Switch.cs:156:28:156:38 | ... => ... | +| Switch.cs:156:17:156:54 | ... switch { ... } | Switch.cs:156:17:156:17 | access to parameter b | +| Switch.cs:156:28:156:31 | true | Switch.cs:156:36:156:38 | "a" | +| Switch.cs:156:28:156:31 | true | Switch.cs:156:41:156:52 | ... => ... | +| Switch.cs:156:28:156:38 | ... => ... | Switch.cs:156:28:156:31 | true | +| Switch.cs:156:41:156:45 | false | Switch.cs:156:50:156:52 | "b" | +| Switch.cs:156:41:156:52 | ... => ... | Switch.cs:156:41:156:45 | false | +| Switch.cs:157:9:160:49 | if (...) ... | Switch.cs:157:13:157:13 | access to parameter b | +| Switch.cs:157:13:157:13 | access to parameter b | Switch.cs:158:13:158:49 | ...; | +| Switch.cs:157:13:157:13 | access to parameter b | Switch.cs:160:13:160:49 | ...; | +| Switch.cs:158:13:158:49 | ...; | Switch.cs:158:40:158:43 | "a = " | +| Switch.cs:158:38:158:47 | $"..." | Switch.cs:158:13:158:48 | call to method WriteLine | +| Switch.cs:158:40:158:43 | "a = " | Switch.cs:158:45:158:45 | access to local variable s | +| Switch.cs:158:45:158:45 | access to local variable s | Switch.cs:158:38:158:47 | $"..." | +| Switch.cs:160:13:160:49 | ...; | Switch.cs:160:40:160:43 | "b = " | +| Switch.cs:160:38:160:47 | $"..." | Switch.cs:160:13:160:48 | call to method WriteLine | +| Switch.cs:160:40:160:43 | "b = " | Switch.cs:160:45:160:45 | access to local variable s | +| Switch.cs:160:45:160:45 | access to local variable s | Switch.cs:160:38:160:47 | $"..." | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:4:5:9:5 | {...} | | TypeAccesses.cs:4:5:9:5 | {...} | TypeAccesses.cs:5:9:5:26 | ... ...; | | TypeAccesses.cs:5:9:5:26 | ... ...; | TypeAccesses.cs:5:25:5:25 | access to parameter o | @@ -2423,11 +3111,13 @@ dominance | VarDecls.cs:7:9:10:9 | fixed(...) { ... } | VarDecls.cs:7:27:7:33 | access to parameter strings | | VarDecls.cs:7:22:7:36 | Char* c1 = ... | VarDecls.cs:7:44:7:50 | access to parameter strings | | VarDecls.cs:7:27:7:33 | access to parameter strings | VarDecls.cs:7:35:7:35 | 0 | -| VarDecls.cs:7:27:7:36 | access to array element | VarDecls.cs:7:22:7:36 | Char* c1 = ... | +| VarDecls.cs:7:27:7:36 | (...) ... | VarDecls.cs:7:22:7:36 | Char* c1 = ... | +| VarDecls.cs:7:27:7:36 | access to array element | VarDecls.cs:7:27:7:36 | (...) ... | | VarDecls.cs:7:35:7:35 | 0 | VarDecls.cs:7:27:7:36 | access to array element | | VarDecls.cs:7:39:7:53 | Char* c2 = ... | VarDecls.cs:8:9:10:9 | {...} | | VarDecls.cs:7:44:7:50 | access to parameter strings | VarDecls.cs:7:52:7:52 | 1 | -| VarDecls.cs:7:44:7:53 | access to array element | VarDecls.cs:7:39:7:53 | Char* c2 = ... | +| VarDecls.cs:7:44:7:53 | (...) ... | VarDecls.cs:7:39:7:53 | Char* c2 = ... | +| VarDecls.cs:7:44:7:53 | access to array element | VarDecls.cs:7:44:7:53 | (...) ... | | VarDecls.cs:7:52:7:52 | 1 | VarDecls.cs:7:44:7:53 | access to array element | | VarDecls.cs:8:9:10:9 | {...} | VarDecls.cs:9:27:9:28 | access to local variable c1 | | VarDecls.cs:9:13:9:29 | return ...; | VarDecls.cs:5:18:5:19 | exit M1 | @@ -3356,12 +4046,15 @@ postDominance | ArrayCreation.cs:5:28:5:28 | 0 | ArrayCreation.cs:5:12:5:13 | enter M2 | | ArrayCreation.cs:5:31:5:31 | 1 | ArrayCreation.cs:5:28:5:28 | 0 | | ArrayCreation.cs:7:11:7:12 | exit M3 | ArrayCreation.cs:7:29:7:36 | { ..., ... } | -| ArrayCreation.cs:7:19:7:36 | array creation of type Int32[] | ArrayCreation.cs:7:11:7:12 | enter M3 | +| ArrayCreation.cs:7:19:7:36 | 2 | ArrayCreation.cs:7:11:7:12 | enter M3 | +| ArrayCreation.cs:7:19:7:36 | array creation of type Int32[] | ArrayCreation.cs:7:19:7:36 | 2 | | ArrayCreation.cs:7:29:7:36 | { ..., ... } | ArrayCreation.cs:7:34:7:34 | 1 | | ArrayCreation.cs:7:31:7:31 | 0 | ArrayCreation.cs:7:19:7:36 | array creation of type Int32[] | | ArrayCreation.cs:7:34:7:34 | 1 | ArrayCreation.cs:7:31:7:31 | 0 | | ArrayCreation.cs:9:12:9:13 | exit M4 | ArrayCreation.cs:9:31:9:52 | { ..., ... } | -| ArrayCreation.cs:9:20:9:52 | array creation of type Int32[,] | ArrayCreation.cs:9:12:9:13 | enter M4 | +| ArrayCreation.cs:9:20:9:52 | 2 | ArrayCreation.cs:9:12:9:13 | enter M4 | +| ArrayCreation.cs:9:20:9:52 | 2 | ArrayCreation.cs:9:20:9:52 | 2 | +| ArrayCreation.cs:9:20:9:52 | array creation of type Int32[,] | ArrayCreation.cs:9:20:9:52 | 2 | | ArrayCreation.cs:9:31:9:52 | { ..., ... } | ArrayCreation.cs:9:43:9:50 | { ..., ... } | | ArrayCreation.cs:9:33:9:40 | { ..., ... } | ArrayCreation.cs:9:38:9:38 | 1 | | ArrayCreation.cs:9:35:9:35 | 0 | ArrayCreation.cs:9:20:9:52 | array creation of type Int32[,] | @@ -3369,6 +4062,478 @@ postDominance | ArrayCreation.cs:9:43:9:50 | { ..., ... } | ArrayCreation.cs:9:48:9:48 | 3 | | ArrayCreation.cs:9:45:9:45 | 2 | ArrayCreation.cs:9:33:9:40 | { ..., ... } | | ArrayCreation.cs:9:48:9:48 | 3 | ArrayCreation.cs:9:45:9:45 | 2 | +| Assert.cs:7:10:7:11 | exit M1 | Assert.cs:10:9:10:31 | [assertion failure] call to method Assert | +| Assert.cs:7:10:7:11 | exit M1 | Assert.cs:11:9:11:35 | call to method WriteLine | +| Assert.cs:8:5:12:5 | {...} | Assert.cs:7:10:7:11 | enter M1 | +| Assert.cs:9:9:9:33 | ... ...; | Assert.cs:8:5:12:5 | {...} | +| Assert.cs:9:16:9:32 | String s = ... | Assert.cs:9:24:9:27 | null | +| Assert.cs:9:16:9:32 | String s = ... | Assert.cs:9:31:9:32 | "" | +| Assert.cs:9:20:9:20 | access to parameter b | Assert.cs:9:20:9:32 | ... ? ... : ... | +| Assert.cs:9:20:9:32 | ... ? ... : ... | Assert.cs:9:9:9:33 | ... ...; | +| Assert.cs:10:9:10:32 | ...; | Assert.cs:9:16:9:32 | String s = ... | +| Assert.cs:10:22:10:22 | access to local variable s | Assert.cs:10:9:10:32 | ...; | +| Assert.cs:10:22:10:30 | ... != ... | Assert.cs:10:27:10:30 | null | +| Assert.cs:10:27:10:30 | null | Assert.cs:10:22:10:22 | access to local variable s | +| Assert.cs:11:9:11:35 | call to method WriteLine | Assert.cs:11:27:11:34 | access to property Length | +| Assert.cs:11:9:11:36 | ...; | Assert.cs:10:9:10:31 | [assertion success] call to method Assert | +| Assert.cs:11:27:11:27 | access to local variable s | Assert.cs:11:9:11:36 | ...; | +| Assert.cs:11:27:11:34 | access to property Length | Assert.cs:11:27:11:27 | access to local variable s | +| Assert.cs:14:10:14:11 | exit M2 | Assert.cs:17:9:17:24 | [assertion failure] call to method IsNull | +| Assert.cs:14:10:14:11 | exit M2 | Assert.cs:18:9:18:35 | call to method WriteLine | +| Assert.cs:15:5:19:5 | {...} | Assert.cs:14:10:14:11 | enter M2 | +| Assert.cs:16:9:16:33 | ... ...; | Assert.cs:15:5:19:5 | {...} | +| Assert.cs:16:16:16:32 | String s = ... | Assert.cs:16:24:16:27 | null | +| Assert.cs:16:16:16:32 | String s = ... | Assert.cs:16:31:16:32 | "" | +| Assert.cs:16:20:16:20 | access to parameter b | Assert.cs:16:20:16:32 | ... ? ... : ... | +| Assert.cs:16:20:16:32 | ... ? ... : ... | Assert.cs:16:9:16:33 | ... ...; | +| Assert.cs:17:9:17:25 | ...; | Assert.cs:16:16:16:32 | String s = ... | +| Assert.cs:17:23:17:23 | access to local variable s | Assert.cs:17:9:17:25 | ...; | +| Assert.cs:18:9:18:35 | call to method WriteLine | Assert.cs:18:27:18:34 | access to property Length | +| Assert.cs:18:9:18:36 | ...; | Assert.cs:17:9:17:24 | [assertion success] call to method IsNull | +| Assert.cs:18:27:18:27 | access to local variable s | Assert.cs:18:9:18:36 | ...; | +| Assert.cs:18:27:18:34 | access to property Length | Assert.cs:18:27:18:27 | access to local variable s | +| Assert.cs:21:10:21:11 | exit M3 | Assert.cs:24:9:24:27 | [assertion failure] call to method IsNotNull | +| Assert.cs:21:10:21:11 | exit M3 | Assert.cs:25:9:25:35 | call to method WriteLine | +| Assert.cs:22:5:26:5 | {...} | Assert.cs:21:10:21:11 | enter M3 | +| Assert.cs:23:9:23:33 | ... ...; | Assert.cs:22:5:26:5 | {...} | +| Assert.cs:23:16:23:32 | String s = ... | Assert.cs:23:24:23:27 | null | +| Assert.cs:23:16:23:32 | String s = ... | Assert.cs:23:31:23:32 | "" | +| Assert.cs:23:20:23:20 | access to parameter b | Assert.cs:23:20:23:32 | ... ? ... : ... | +| Assert.cs:23:20:23:32 | ... ? ... : ... | Assert.cs:23:9:23:33 | ... ...; | +| Assert.cs:24:9:24:28 | ...; | Assert.cs:23:16:23:32 | String s = ... | +| Assert.cs:24:26:24:26 | access to local variable s | Assert.cs:24:9:24:28 | ...; | +| Assert.cs:25:9:25:35 | call to method WriteLine | Assert.cs:25:27:25:34 | access to property Length | +| Assert.cs:25:9:25:36 | ...; | Assert.cs:24:9:24:27 | [assertion success] call to method IsNotNull | +| Assert.cs:25:27:25:27 | access to local variable s | Assert.cs:25:9:25:36 | ...; | +| Assert.cs:25:27:25:34 | access to property Length | Assert.cs:25:27:25:27 | access to local variable s | +| Assert.cs:28:10:28:11 | exit M4 | Assert.cs:31:9:31:32 | [assertion failure] call to method IsTrue | +| Assert.cs:28:10:28:11 | exit M4 | Assert.cs:32:9:32:35 | call to method WriteLine | +| Assert.cs:29:5:33:5 | {...} | Assert.cs:28:10:28:11 | enter M4 | +| Assert.cs:30:9:30:33 | ... ...; | Assert.cs:29:5:33:5 | {...} | +| Assert.cs:30:16:30:32 | String s = ... | Assert.cs:30:24:30:27 | null | +| Assert.cs:30:16:30:32 | String s = ... | Assert.cs:30:31:30:32 | "" | +| Assert.cs:30:20:30:20 | access to parameter b | Assert.cs:30:20:30:32 | ... ? ... : ... | +| Assert.cs:30:20:30:32 | ... ? ... : ... | Assert.cs:30:9:30:33 | ... ...; | +| Assert.cs:31:9:31:33 | ...; | Assert.cs:30:16:30:32 | String s = ... | +| Assert.cs:31:23:31:23 | access to local variable s | Assert.cs:31:9:31:33 | ...; | +| Assert.cs:31:23:31:31 | ... == ... | Assert.cs:31:28:31:31 | null | +| Assert.cs:31:28:31:31 | null | Assert.cs:31:23:31:23 | access to local variable s | +| Assert.cs:32:9:32:35 | call to method WriteLine | Assert.cs:32:27:32:34 | access to property Length | +| Assert.cs:32:9:32:36 | ...; | Assert.cs:31:9:31:32 | [assertion success] call to method IsTrue | +| Assert.cs:32:27:32:27 | access to local variable s | Assert.cs:32:9:32:36 | ...; | +| Assert.cs:32:27:32:34 | access to property Length | Assert.cs:32:27:32:27 | access to local variable s | +| Assert.cs:35:10:35:11 | exit M5 | Assert.cs:38:9:38:32 | [assertion failure] call to method IsTrue | +| Assert.cs:35:10:35:11 | exit M5 | Assert.cs:39:9:39:35 | call to method WriteLine | +| Assert.cs:36:5:40:5 | {...} | Assert.cs:35:10:35:11 | enter M5 | +| Assert.cs:37:9:37:33 | ... ...; | Assert.cs:36:5:40:5 | {...} | +| Assert.cs:37:16:37:32 | String s = ... | Assert.cs:37:24:37:27 | null | +| Assert.cs:37:16:37:32 | String s = ... | Assert.cs:37:31:37:32 | "" | +| Assert.cs:37:20:37:20 | access to parameter b | Assert.cs:37:20:37:32 | ... ? ... : ... | +| Assert.cs:37:20:37:32 | ... ? ... : ... | Assert.cs:37:9:37:33 | ... ...; | +| Assert.cs:38:9:38:33 | ...; | Assert.cs:37:16:37:32 | String s = ... | +| Assert.cs:38:23:38:23 | access to local variable s | Assert.cs:38:9:38:33 | ...; | +| Assert.cs:38:23:38:31 | ... != ... | Assert.cs:38:28:38:31 | null | +| Assert.cs:38:28:38:31 | null | Assert.cs:38:23:38:23 | access to local variable s | +| Assert.cs:39:9:39:35 | call to method WriteLine | Assert.cs:39:27:39:34 | access to property Length | +| Assert.cs:39:9:39:36 | ...; | Assert.cs:38:9:38:32 | [assertion success] call to method IsTrue | +| Assert.cs:39:27:39:27 | access to local variable s | Assert.cs:39:9:39:36 | ...; | +| Assert.cs:39:27:39:34 | access to property Length | Assert.cs:39:27:39:27 | access to local variable s | +| Assert.cs:42:10:42:11 | exit M6 | Assert.cs:45:9:45:33 | [assertion failure] call to method IsFalse | +| Assert.cs:42:10:42:11 | exit M6 | Assert.cs:46:9:46:35 | call to method WriteLine | +| Assert.cs:43:5:47:5 | {...} | Assert.cs:42:10:42:11 | enter M6 | +| Assert.cs:44:9:44:33 | ... ...; | Assert.cs:43:5:47:5 | {...} | +| Assert.cs:44:16:44:32 | String s = ... | Assert.cs:44:24:44:27 | null | +| Assert.cs:44:16:44:32 | String s = ... | Assert.cs:44:31:44:32 | "" | +| Assert.cs:44:20:44:20 | access to parameter b | Assert.cs:44:20:44:32 | ... ? ... : ... | +| Assert.cs:44:20:44:32 | ... ? ... : ... | Assert.cs:44:9:44:33 | ... ...; | +| Assert.cs:45:9:45:34 | ...; | Assert.cs:44:16:44:32 | String s = ... | +| Assert.cs:45:24:45:24 | access to local variable s | Assert.cs:45:9:45:34 | ...; | +| Assert.cs:45:24:45:32 | ... != ... | Assert.cs:45:29:45:32 | null | +| Assert.cs:45:29:45:32 | null | Assert.cs:45:24:45:24 | access to local variable s | +| Assert.cs:46:9:46:35 | call to method WriteLine | Assert.cs:46:27:46:34 | access to property Length | +| Assert.cs:46:9:46:36 | ...; | Assert.cs:45:9:45:33 | [assertion success] call to method IsFalse | +| Assert.cs:46:27:46:27 | access to local variable s | Assert.cs:46:9:46:36 | ...; | +| Assert.cs:46:27:46:34 | access to property Length | Assert.cs:46:27:46:27 | access to local variable s | +| Assert.cs:49:10:49:11 | exit M7 | Assert.cs:52:9:52:33 | [assertion failure] call to method IsFalse | +| Assert.cs:49:10:49:11 | exit M7 | Assert.cs:53:9:53:35 | call to method WriteLine | +| Assert.cs:50:5:54:5 | {...} | Assert.cs:49:10:49:11 | enter M7 | +| Assert.cs:51:9:51:33 | ... ...; | Assert.cs:50:5:54:5 | {...} | +| Assert.cs:51:16:51:32 | String s = ... | Assert.cs:51:24:51:27 | null | +| Assert.cs:51:16:51:32 | String s = ... | Assert.cs:51:31:51:32 | "" | +| Assert.cs:51:20:51:20 | access to parameter b | Assert.cs:51:20:51:32 | ... ? ... : ... | +| Assert.cs:51:20:51:32 | ... ? ... : ... | Assert.cs:51:9:51:33 | ... ...; | +| Assert.cs:52:9:52:34 | ...; | Assert.cs:51:16:51:32 | String s = ... | +| Assert.cs:52:24:52:24 | access to local variable s | Assert.cs:52:9:52:34 | ...; | +| Assert.cs:52:24:52:32 | ... == ... | Assert.cs:52:29:52:32 | null | +| Assert.cs:52:29:52:32 | null | Assert.cs:52:24:52:24 | access to local variable s | +| Assert.cs:53:9:53:35 | call to method WriteLine | Assert.cs:53:27:53:34 | access to property Length | +| Assert.cs:53:9:53:36 | ...; | Assert.cs:52:9:52:33 | [assertion success] call to method IsFalse | +| Assert.cs:53:27:53:27 | access to local variable s | Assert.cs:53:9:53:36 | ...; | +| Assert.cs:53:27:53:34 | access to property Length | Assert.cs:53:27:53:27 | access to local variable s | +| Assert.cs:56:10:56:11 | exit M8 | Assert.cs:59:9:59:37 | [assertion failure] call to method IsTrue | +| Assert.cs:56:10:56:11 | exit M8 | Assert.cs:60:9:60:35 | call to method WriteLine | +| Assert.cs:57:5:61:5 | {...} | Assert.cs:56:10:56:11 | enter M8 | +| Assert.cs:58:9:58:33 | ... ...; | Assert.cs:57:5:61:5 | {...} | +| Assert.cs:58:16:58:32 | [b (line 56): false] String s = ... | Assert.cs:58:31:58:32 | [b (line 56): false] "" | +| Assert.cs:58:16:58:32 | [b (line 56): true] String s = ... | Assert.cs:58:24:58:27 | [b (line 56): true] null | +| Assert.cs:58:20:58:20 | access to parameter b | Assert.cs:58:20:58:32 | ... ? ... : ... | +| Assert.cs:58:20:58:32 | ... ? ... : ... | Assert.cs:58:9:58:33 | ... ...; | +| Assert.cs:59:9:59:37 | [assertion failure] call to method IsTrue | Assert.cs:59:23:59:31 | [b (line 56): false] ... != ... | +| Assert.cs:59:9:59:37 | [assertion failure] call to method IsTrue | Assert.cs:59:36:59:36 | [b (line 56): false] access to parameter b | +| Assert.cs:59:9:59:37 | [assertion success] call to method IsTrue | Assert.cs:59:36:59:36 | [b (line 56): true] access to parameter b | +| Assert.cs:59:9:59:38 | [b (line 56): false] ...; | Assert.cs:58:16:58:32 | [b (line 56): false] String s = ... | +| Assert.cs:59:9:59:38 | [b (line 56): true] ...; | Assert.cs:58:16:58:32 | [b (line 56): true] String s = ... | +| Assert.cs:59:23:59:23 | [b (line 56): false] access to local variable s | Assert.cs:59:23:59:36 | [b (line 56): false] ... && ... | +| Assert.cs:59:23:59:23 | [b (line 56): true] access to local variable s | Assert.cs:59:23:59:36 | [b (line 56): true] ... && ... | +| Assert.cs:59:23:59:31 | [b (line 56): false] ... != ... | Assert.cs:59:28:59:31 | [b (line 56): false] null | +| Assert.cs:59:23:59:31 | [b (line 56): true] ... != ... | Assert.cs:59:28:59:31 | [b (line 56): true] null | +| Assert.cs:59:23:59:36 | [b (line 56): false] ... && ... | Assert.cs:59:9:59:38 | [b (line 56): false] ...; | +| Assert.cs:59:23:59:36 | [b (line 56): true] ... && ... | Assert.cs:59:9:59:38 | [b (line 56): true] ...; | +| Assert.cs:59:28:59:31 | [b (line 56): false] null | Assert.cs:59:23:59:23 | [b (line 56): false] access to local variable s | +| Assert.cs:59:28:59:31 | [b (line 56): true] null | Assert.cs:59:23:59:23 | [b (line 56): true] access to local variable s | +| Assert.cs:60:9:60:35 | call to method WriteLine | Assert.cs:60:27:60:34 | access to property Length | +| Assert.cs:60:9:60:36 | ...; | Assert.cs:59:9:59:37 | [assertion success] call to method IsTrue | +| Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:60:9:60:36 | ...; | +| Assert.cs:60:27:60:34 | access to property Length | Assert.cs:60:27:60:27 | access to local variable s | +| Assert.cs:63:10:63:11 | exit M9 | Assert.cs:66:9:66:38 | [assertion failure] call to method IsFalse | +| Assert.cs:63:10:63:11 | exit M9 | Assert.cs:67:9:67:35 | call to method WriteLine | +| Assert.cs:64:5:68:5 | {...} | Assert.cs:63:10:63:11 | enter M9 | +| Assert.cs:65:9:65:33 | ... ...; | Assert.cs:64:5:68:5 | {...} | +| Assert.cs:65:16:65:32 | [b (line 63): false] String s = ... | Assert.cs:65:31:65:32 | [b (line 63): false] "" | +| Assert.cs:65:16:65:32 | [b (line 63): true] String s = ... | Assert.cs:65:24:65:27 | [b (line 63): true] null | +| Assert.cs:65:20:65:20 | access to parameter b | Assert.cs:65:20:65:32 | ... ? ... : ... | +| Assert.cs:65:20:65:32 | ... ? ... : ... | Assert.cs:65:9:65:33 | ... ...; | +| Assert.cs:66:9:66:38 | [assertion failure] call to method IsFalse | Assert.cs:66:24:66:32 | [b (line 63): true] ... == ... | +| Assert.cs:66:9:66:38 | [assertion failure] call to method IsFalse | Assert.cs:66:37:66:37 | [b (line 63): true] access to parameter b | +| Assert.cs:66:9:66:38 | [assertion success] call to method IsFalse | Assert.cs:66:37:66:37 | [b (line 63): false] access to parameter b | +| Assert.cs:66:9:66:39 | [b (line 63): false] ...; | Assert.cs:65:16:65:32 | [b (line 63): false] String s = ... | +| Assert.cs:66:9:66:39 | [b (line 63): true] ...; | Assert.cs:65:16:65:32 | [b (line 63): true] String s = ... | +| Assert.cs:66:24:66:24 | [b (line 63): false] access to local variable s | Assert.cs:66:24:66:37 | [b (line 63): false] ... \|\| ... | +| Assert.cs:66:24:66:24 | [b (line 63): true] access to local variable s | Assert.cs:66:24:66:37 | [b (line 63): true] ... \|\| ... | +| Assert.cs:66:24:66:32 | [b (line 63): false] ... == ... | Assert.cs:66:29:66:32 | [b (line 63): false] null | +| Assert.cs:66:24:66:32 | [b (line 63): true] ... == ... | Assert.cs:66:29:66:32 | [b (line 63): true] null | +| Assert.cs:66:24:66:37 | [b (line 63): false] ... \|\| ... | Assert.cs:66:9:66:39 | [b (line 63): false] ...; | +| Assert.cs:66:24:66:37 | [b (line 63): true] ... \|\| ... | Assert.cs:66:9:66:39 | [b (line 63): true] ...; | +| Assert.cs:66:29:66:32 | [b (line 63): false] null | Assert.cs:66:24:66:24 | [b (line 63): false] access to local variable s | +| Assert.cs:66:29:66:32 | [b (line 63): true] null | Assert.cs:66:24:66:24 | [b (line 63): true] access to local variable s | +| Assert.cs:67:9:67:35 | call to method WriteLine | Assert.cs:67:27:67:34 | access to property Length | +| Assert.cs:67:9:67:36 | ...; | Assert.cs:66:9:66:38 | [assertion success] call to method IsFalse | +| Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:67:9:67:36 | ...; | +| Assert.cs:67:27:67:34 | access to property Length | Assert.cs:67:27:67:27 | access to local variable s | +| Assert.cs:70:10:70:12 | exit M10 | Assert.cs:73:9:73:37 | [assertion failure] call to method IsTrue | +| Assert.cs:70:10:70:12 | exit M10 | Assert.cs:74:9:74:35 | call to method WriteLine | +| Assert.cs:71:5:75:5 | {...} | Assert.cs:70:10:70:12 | enter M10 | +| Assert.cs:72:9:72:33 | ... ...; | Assert.cs:71:5:75:5 | {...} | +| Assert.cs:72:16:72:32 | [b (line 70): false] String s = ... | Assert.cs:72:31:72:32 | [b (line 70): false] "" | +| Assert.cs:72:16:72:32 | [b (line 70): true] String s = ... | Assert.cs:72:24:72:27 | [b (line 70): true] null | +| Assert.cs:72:20:72:20 | access to parameter b | Assert.cs:72:20:72:32 | ... ? ... : ... | +| Assert.cs:72:20:72:32 | ... ? ... : ... | Assert.cs:72:9:72:33 | ... ...; | +| Assert.cs:73:9:73:37 | [assertion failure] call to method IsTrue | Assert.cs:73:23:73:31 | [b (line 70): false] ... == ... | +| Assert.cs:73:9:73:37 | [assertion failure] call to method IsTrue | Assert.cs:73:36:73:36 | [b (line 70): false] access to parameter b | +| Assert.cs:73:9:73:37 | [assertion success] call to method IsTrue | Assert.cs:73:36:73:36 | [b (line 70): true] access to parameter b | +| Assert.cs:73:9:73:38 | [b (line 70): false] ...; | Assert.cs:72:16:72:32 | [b (line 70): false] String s = ... | +| Assert.cs:73:9:73:38 | [b (line 70): true] ...; | Assert.cs:72:16:72:32 | [b (line 70): true] String s = ... | +| Assert.cs:73:23:73:23 | [b (line 70): false] access to local variable s | Assert.cs:73:23:73:36 | [b (line 70): false] ... && ... | +| Assert.cs:73:23:73:23 | [b (line 70): true] access to local variable s | Assert.cs:73:23:73:36 | [b (line 70): true] ... && ... | +| Assert.cs:73:23:73:31 | [b (line 70): false] ... == ... | Assert.cs:73:28:73:31 | [b (line 70): false] null | +| Assert.cs:73:23:73:31 | [b (line 70): true] ... == ... | Assert.cs:73:28:73:31 | [b (line 70): true] null | +| Assert.cs:73:23:73:36 | [b (line 70): false] ... && ... | Assert.cs:73:9:73:38 | [b (line 70): false] ...; | +| Assert.cs:73:23:73:36 | [b (line 70): true] ... && ... | Assert.cs:73:9:73:38 | [b (line 70): true] ...; | +| Assert.cs:73:28:73:31 | [b (line 70): false] null | Assert.cs:73:23:73:23 | [b (line 70): false] access to local variable s | +| Assert.cs:73:28:73:31 | [b (line 70): true] null | Assert.cs:73:23:73:23 | [b (line 70): true] access to local variable s | +| Assert.cs:74:9:74:35 | call to method WriteLine | Assert.cs:74:27:74:34 | access to property Length | +| Assert.cs:74:9:74:36 | ...; | Assert.cs:73:9:73:37 | [assertion success] call to method IsTrue | +| Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:74:9:74:36 | ...; | +| Assert.cs:74:27:74:34 | access to property Length | Assert.cs:74:27:74:27 | access to local variable s | +| Assert.cs:77:10:77:12 | exit M11 | Assert.cs:80:9:80:38 | [assertion failure] call to method IsFalse | +| Assert.cs:77:10:77:12 | exit M11 | Assert.cs:81:9:81:35 | call to method WriteLine | +| Assert.cs:78:5:82:5 | {...} | Assert.cs:77:10:77:12 | enter M11 | +| Assert.cs:79:9:79:33 | ... ...; | Assert.cs:78:5:82:5 | {...} | +| Assert.cs:79:16:79:32 | [b (line 77): false] String s = ... | Assert.cs:79:31:79:32 | [b (line 77): false] "" | +| Assert.cs:79:16:79:32 | [b (line 77): true] String s = ... | Assert.cs:79:24:79:27 | [b (line 77): true] null | +| Assert.cs:79:20:79:20 | access to parameter b | Assert.cs:79:20:79:32 | ... ? ... : ... | +| Assert.cs:79:20:79:32 | ... ? ... : ... | Assert.cs:79:9:79:33 | ... ...; | +| Assert.cs:80:9:80:38 | [assertion failure] call to method IsFalse | Assert.cs:80:24:80:32 | [b (line 77): true] ... != ... | +| Assert.cs:80:9:80:38 | [assertion failure] call to method IsFalse | Assert.cs:80:37:80:37 | [b (line 77): true] access to parameter b | +| Assert.cs:80:9:80:38 | [assertion success] call to method IsFalse | Assert.cs:80:37:80:37 | [b (line 77): false] access to parameter b | +| Assert.cs:80:9:80:39 | [b (line 77): false] ...; | Assert.cs:79:16:79:32 | [b (line 77): false] String s = ... | +| Assert.cs:80:9:80:39 | [b (line 77): true] ...; | Assert.cs:79:16:79:32 | [b (line 77): true] String s = ... | +| Assert.cs:80:24:80:24 | [b (line 77): false] access to local variable s | Assert.cs:80:24:80:37 | [b (line 77): false] ... \|\| ... | +| Assert.cs:80:24:80:24 | [b (line 77): true] access to local variable s | Assert.cs:80:24:80:37 | [b (line 77): true] ... \|\| ... | +| Assert.cs:80:24:80:32 | [b (line 77): false] ... != ... | Assert.cs:80:29:80:32 | [b (line 77): false] null | +| Assert.cs:80:24:80:32 | [b (line 77): true] ... != ... | Assert.cs:80:29:80:32 | [b (line 77): true] null | +| Assert.cs:80:24:80:37 | [b (line 77): false] ... \|\| ... | Assert.cs:80:9:80:39 | [b (line 77): false] ...; | +| Assert.cs:80:24:80:37 | [b (line 77): true] ... \|\| ... | Assert.cs:80:9:80:39 | [b (line 77): true] ...; | +| Assert.cs:80:29:80:32 | [b (line 77): false] null | Assert.cs:80:24:80:24 | [b (line 77): false] access to local variable s | +| Assert.cs:80:29:80:32 | [b (line 77): true] null | Assert.cs:80:24:80:24 | [b (line 77): true] access to local variable s | +| Assert.cs:81:9:81:35 | call to method WriteLine | Assert.cs:81:27:81:34 | access to property Length | +| Assert.cs:81:9:81:36 | ...; | Assert.cs:80:9:80:38 | [assertion success] call to method IsFalse | +| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:81:9:81:36 | ...; | +| Assert.cs:81:27:81:34 | access to property Length | Assert.cs:81:27:81:27 | access to local variable s | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:87:9:87:31 | [assertion failure, b (line 84): false] call to method Assert | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:87:9:87:31 | [assertion failure, b (line 84): true] call to method Assert | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:91:9:91:24 | [assertion failure, b (line 84): false] call to method IsNull | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:91:9:91:24 | [assertion failure, b (line 84): true] call to method IsNull | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): false] call to method IsNotNull | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): true] call to method IsNotNull | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:128:9:128:35 | call to method WriteLine | +| Assert.cs:85:5:129:5 | {...} | Assert.cs:84:10:84:12 | enter M12 | +| Assert.cs:86:9:86:33 | ... ...; | Assert.cs:85:5:129:5 | {...} | +| Assert.cs:86:16:86:32 | [b (line 84): false] String s = ... | Assert.cs:86:31:86:32 | [b (line 84): false] "" | +| Assert.cs:86:16:86:32 | [b (line 84): true] String s = ... | Assert.cs:86:24:86:27 | [b (line 84): true] null | +| Assert.cs:86:20:86:20 | access to parameter b | Assert.cs:86:20:86:32 | ... ? ... : ... | +| Assert.cs:86:20:86:32 | ... ? ... : ... | Assert.cs:86:9:86:33 | ... ...; | +| Assert.cs:87:9:87:32 | [b (line 84): false] ...; | Assert.cs:86:16:86:32 | [b (line 84): false] String s = ... | +| Assert.cs:87:9:87:32 | [b (line 84): true] ...; | Assert.cs:86:16:86:32 | [b (line 84): true] String s = ... | +| Assert.cs:87:22:87:22 | [b (line 84): false] access to local variable s | Assert.cs:87:9:87:32 | [b (line 84): false] ...; | +| Assert.cs:87:22:87:22 | [b (line 84): true] access to local variable s | Assert.cs:87:9:87:32 | [b (line 84): true] ...; | +| Assert.cs:87:22:87:30 | [b (line 84): false] ... != ... | Assert.cs:87:27:87:30 | [b (line 84): false] null | +| Assert.cs:87:22:87:30 | [b (line 84): true] ... != ... | Assert.cs:87:27:87:30 | [b (line 84): true] null | +| Assert.cs:87:27:87:30 | [b (line 84): false] null | Assert.cs:87:22:87:22 | [b (line 84): false] access to local variable s | +| Assert.cs:87:27:87:30 | [b (line 84): true] null | Assert.cs:87:22:87:22 | [b (line 84): true] access to local variable s | +| Assert.cs:88:9:88:35 | [b (line 84): false] call to method WriteLine | Assert.cs:88:27:88:34 | [b (line 84): false] access to property Length | +| Assert.cs:88:9:88:35 | [b (line 84): true] call to method WriteLine | Assert.cs:88:27:88:34 | [b (line 84): true] access to property Length | +| Assert.cs:88:9:88:36 | [b (line 84): false] ...; | Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | +| Assert.cs:88:9:88:36 | [b (line 84): true] ...; | Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | +| Assert.cs:88:27:88:27 | [b (line 84): false] access to local variable s | Assert.cs:88:9:88:36 | [b (line 84): false] ...; | +| Assert.cs:88:27:88:27 | [b (line 84): true] access to local variable s | Assert.cs:88:9:88:36 | [b (line 84): true] ...; | +| Assert.cs:88:27:88:34 | [b (line 84): false] access to property Length | Assert.cs:88:27:88:27 | [b (line 84): false] access to local variable s | +| Assert.cs:88:27:88:34 | [b (line 84): true] access to property Length | Assert.cs:88:27:88:27 | [b (line 84): true] access to local variable s | +| Assert.cs:90:9:90:25 | [b (line 84): false] ... = ... | Assert.cs:90:24:90:25 | [b (line 84): false] "" | +| Assert.cs:90:9:90:25 | [b (line 84): true] ... = ... | Assert.cs:90:17:90:20 | [b (line 84): true] null | +| Assert.cs:90:9:90:26 | [b (line 84): false] ...; | Assert.cs:88:9:88:35 | [b (line 84): false] call to method WriteLine | +| Assert.cs:90:9:90:26 | [b (line 84): true] ...; | Assert.cs:88:9:88:35 | [b (line 84): true] call to method WriteLine | +| Assert.cs:90:13:90:13 | [b (line 84): false] access to parameter b | Assert.cs:90:13:90:25 | [b (line 84): false] ... ? ... : ... | +| Assert.cs:90:13:90:13 | [b (line 84): true] access to parameter b | Assert.cs:90:13:90:25 | [b (line 84): true] ... ? ... : ... | +| Assert.cs:90:13:90:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:90:9:90:26 | [b (line 84): false] ...; | +| Assert.cs:90:13:90:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:90:9:90:26 | [b (line 84): true] ...; | +| Assert.cs:90:17:90:20 | [b (line 84): true] null | Assert.cs:90:13:90:13 | [b (line 84): true] access to parameter b | +| Assert.cs:90:24:90:25 | [b (line 84): false] "" | Assert.cs:90:13:90:13 | [b (line 84): false] access to parameter b | +| Assert.cs:91:9:91:25 | [b (line 84): false] ...; | Assert.cs:90:9:90:25 | [b (line 84): false] ... = ... | +| Assert.cs:91:9:91:25 | [b (line 84): true] ...; | Assert.cs:90:9:90:25 | [b (line 84): true] ... = ... | +| Assert.cs:91:23:91:23 | [b (line 84): false] access to local variable s | Assert.cs:91:9:91:25 | [b (line 84): false] ...; | +| Assert.cs:91:23:91:23 | [b (line 84): true] access to local variable s | Assert.cs:91:9:91:25 | [b (line 84): true] ...; | +| Assert.cs:92:9:92:35 | [b (line 84): false] call to method WriteLine | Assert.cs:92:27:92:34 | [b (line 84): false] access to property Length | +| Assert.cs:92:9:92:35 | [b (line 84): true] call to method WriteLine | Assert.cs:92:27:92:34 | [b (line 84): true] access to property Length | +| Assert.cs:92:9:92:36 | [b (line 84): false] ...; | Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | +| Assert.cs:92:9:92:36 | [b (line 84): true] ...; | Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | +| Assert.cs:92:27:92:27 | [b (line 84): false] access to local variable s | Assert.cs:92:9:92:36 | [b (line 84): false] ...; | +| Assert.cs:92:27:92:27 | [b (line 84): true] access to local variable s | Assert.cs:92:9:92:36 | [b (line 84): true] ...; | +| Assert.cs:92:27:92:34 | [b (line 84): false] access to property Length | Assert.cs:92:27:92:27 | [b (line 84): false] access to local variable s | +| Assert.cs:92:27:92:34 | [b (line 84): true] access to property Length | Assert.cs:92:27:92:27 | [b (line 84): true] access to local variable s | +| Assert.cs:94:9:94:25 | [b (line 84): false] ... = ... | Assert.cs:94:24:94:25 | [b (line 84): false] "" | +| Assert.cs:94:9:94:25 | [b (line 84): true] ... = ... | Assert.cs:94:17:94:20 | [b (line 84): true] null | +| Assert.cs:94:9:94:26 | [b (line 84): false] ...; | Assert.cs:92:9:92:35 | [b (line 84): false] call to method WriteLine | +| Assert.cs:94:9:94:26 | [b (line 84): true] ...; | Assert.cs:92:9:92:35 | [b (line 84): true] call to method WriteLine | +| Assert.cs:94:13:94:13 | [b (line 84): false] access to parameter b | Assert.cs:94:13:94:25 | [b (line 84): false] ... ? ... : ... | +| Assert.cs:94:13:94:13 | [b (line 84): true] access to parameter b | Assert.cs:94:13:94:25 | [b (line 84): true] ... ? ... : ... | +| Assert.cs:94:13:94:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:94:9:94:26 | [b (line 84): false] ...; | +| Assert.cs:94:13:94:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:94:9:94:26 | [b (line 84): true] ...; | +| Assert.cs:94:17:94:20 | [b (line 84): true] null | Assert.cs:94:13:94:13 | [b (line 84): true] access to parameter b | +| Assert.cs:94:24:94:25 | [b (line 84): false] "" | Assert.cs:94:13:94:13 | [b (line 84): false] access to parameter b | +| Assert.cs:95:9:95:28 | [b (line 84): false] ...; | Assert.cs:94:9:94:25 | [b (line 84): false] ... = ... | +| Assert.cs:95:9:95:28 | [b (line 84): true] ...; | Assert.cs:94:9:94:25 | [b (line 84): true] ... = ... | +| Assert.cs:95:26:95:26 | [b (line 84): false] access to local variable s | Assert.cs:95:9:95:28 | [b (line 84): false] ...; | +| Assert.cs:95:26:95:26 | [b (line 84): true] access to local variable s | Assert.cs:95:9:95:28 | [b (line 84): true] ...; | +| Assert.cs:96:9:96:35 | [b (line 84): false] call to method WriteLine | Assert.cs:96:27:96:34 | [b (line 84): false] access to property Length | +| Assert.cs:96:9:96:35 | [b (line 84): true] call to method WriteLine | Assert.cs:96:27:96:34 | [b (line 84): true] access to property Length | +| Assert.cs:96:9:96:36 | [b (line 84): false] ...; | Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | +| Assert.cs:96:9:96:36 | [b (line 84): true] ...; | Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | +| Assert.cs:96:27:96:27 | [b (line 84): false] access to local variable s | Assert.cs:96:9:96:36 | [b (line 84): false] ...; | +| Assert.cs:96:27:96:27 | [b (line 84): true] access to local variable s | Assert.cs:96:9:96:36 | [b (line 84): true] ...; | +| Assert.cs:96:27:96:34 | [b (line 84): false] access to property Length | Assert.cs:96:27:96:27 | [b (line 84): false] access to local variable s | +| Assert.cs:96:27:96:34 | [b (line 84): true] access to property Length | Assert.cs:96:27:96:27 | [b (line 84): true] access to local variable s | +| Assert.cs:98:9:98:25 | [b (line 84): false] ... = ... | Assert.cs:98:24:98:25 | [b (line 84): false] "" | +| Assert.cs:98:9:98:25 | [b (line 84): true] ... = ... | Assert.cs:98:17:98:20 | [b (line 84): true] null | +| Assert.cs:98:9:98:26 | [b (line 84): false] ...; | Assert.cs:96:9:96:35 | [b (line 84): false] call to method WriteLine | +| Assert.cs:98:9:98:26 | [b (line 84): true] ...; | Assert.cs:96:9:96:35 | [b (line 84): true] call to method WriteLine | +| Assert.cs:98:13:98:13 | [b (line 84): false] access to parameter b | Assert.cs:98:13:98:25 | [b (line 84): false] ... ? ... : ... | +| Assert.cs:98:13:98:13 | [b (line 84): true] access to parameter b | Assert.cs:98:13:98:25 | [b (line 84): true] ... ? ... : ... | +| Assert.cs:98:13:98:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:98:9:98:26 | [b (line 84): false] ...; | +| Assert.cs:98:13:98:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:98:9:98:26 | [b (line 84): true] ...; | +| Assert.cs:98:17:98:20 | [b (line 84): true] null | Assert.cs:98:13:98:13 | [b (line 84): true] access to parameter b | +| Assert.cs:98:24:98:25 | [b (line 84): false] "" | Assert.cs:98:13:98:13 | [b (line 84): false] access to parameter b | +| Assert.cs:99:9:99:33 | [b (line 84): false] ...; | Assert.cs:98:9:98:25 | [b (line 84): false] ... = ... | +| Assert.cs:99:9:99:33 | [b (line 84): true] ...; | Assert.cs:98:9:98:25 | [b (line 84): true] ... = ... | +| Assert.cs:99:23:99:23 | [b (line 84): false] access to local variable s | Assert.cs:99:9:99:33 | [b (line 84): false] ...; | +| Assert.cs:99:23:99:23 | [b (line 84): true] access to local variable s | Assert.cs:99:9:99:33 | [b (line 84): true] ...; | +| Assert.cs:99:23:99:31 | [b (line 84): false] ... == ... | Assert.cs:99:28:99:31 | [b (line 84): false] null | +| Assert.cs:99:23:99:31 | [b (line 84): true] ... == ... | Assert.cs:99:28:99:31 | [b (line 84): true] null | +| Assert.cs:99:28:99:31 | [b (line 84): false] null | Assert.cs:99:23:99:23 | [b (line 84): false] access to local variable s | +| Assert.cs:99:28:99:31 | [b (line 84): true] null | Assert.cs:99:23:99:23 | [b (line 84): true] access to local variable s | +| Assert.cs:100:9:100:35 | [b (line 84): false] call to method WriteLine | Assert.cs:100:27:100:34 | [b (line 84): false] access to property Length | +| Assert.cs:100:9:100:35 | [b (line 84): true] call to method WriteLine | Assert.cs:100:27:100:34 | [b (line 84): true] access to property Length | +| Assert.cs:100:9:100:36 | [b (line 84): false] ...; | Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | +| Assert.cs:100:9:100:36 | [b (line 84): true] ...; | Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | +| Assert.cs:100:27:100:27 | [b (line 84): false] access to local variable s | Assert.cs:100:9:100:36 | [b (line 84): false] ...; | +| Assert.cs:100:27:100:27 | [b (line 84): true] access to local variable s | Assert.cs:100:9:100:36 | [b (line 84): true] ...; | +| Assert.cs:100:27:100:34 | [b (line 84): false] access to property Length | Assert.cs:100:27:100:27 | [b (line 84): false] access to local variable s | +| Assert.cs:100:27:100:34 | [b (line 84): true] access to property Length | Assert.cs:100:27:100:27 | [b (line 84): true] access to local variable s | +| Assert.cs:102:9:102:25 | [b (line 84): false] ... = ... | Assert.cs:102:24:102:25 | [b (line 84): false] "" | +| Assert.cs:102:9:102:25 | [b (line 84): true] ... = ... | Assert.cs:102:17:102:20 | [b (line 84): true] null | +| Assert.cs:102:9:102:26 | [b (line 84): false] ...; | Assert.cs:100:9:100:35 | [b (line 84): false] call to method WriteLine | +| Assert.cs:102:9:102:26 | [b (line 84): true] ...; | Assert.cs:100:9:100:35 | [b (line 84): true] call to method WriteLine | +| Assert.cs:102:13:102:13 | [b (line 84): false] access to parameter b | Assert.cs:102:13:102:25 | [b (line 84): false] ... ? ... : ... | +| Assert.cs:102:13:102:13 | [b (line 84): true] access to parameter b | Assert.cs:102:13:102:25 | [b (line 84): true] ... ? ... : ... | +| Assert.cs:102:13:102:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:102:9:102:26 | [b (line 84): false] ...; | +| Assert.cs:102:13:102:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:102:9:102:26 | [b (line 84): true] ...; | +| Assert.cs:102:17:102:20 | [b (line 84): true] null | Assert.cs:102:13:102:13 | [b (line 84): true] access to parameter b | +| Assert.cs:102:24:102:25 | [b (line 84): false] "" | Assert.cs:102:13:102:13 | [b (line 84): false] access to parameter b | +| Assert.cs:103:9:103:33 | [b (line 84): false] ...; | Assert.cs:102:9:102:25 | [b (line 84): false] ... = ... | +| Assert.cs:103:9:103:33 | [b (line 84): true] ...; | Assert.cs:102:9:102:25 | [b (line 84): true] ... = ... | +| Assert.cs:103:23:103:23 | [b (line 84): false] access to local variable s | Assert.cs:103:9:103:33 | [b (line 84): false] ...; | +| Assert.cs:103:23:103:23 | [b (line 84): true] access to local variable s | Assert.cs:103:9:103:33 | [b (line 84): true] ...; | +| Assert.cs:103:23:103:31 | [b (line 84): false] ... != ... | Assert.cs:103:28:103:31 | [b (line 84): false] null | +| Assert.cs:103:23:103:31 | [b (line 84): true] ... != ... | Assert.cs:103:28:103:31 | [b (line 84): true] null | +| Assert.cs:103:28:103:31 | [b (line 84): false] null | Assert.cs:103:23:103:23 | [b (line 84): false] access to local variable s | +| Assert.cs:103:28:103:31 | [b (line 84): true] null | Assert.cs:103:23:103:23 | [b (line 84): true] access to local variable s | +| Assert.cs:104:9:104:35 | [b (line 84): false] call to method WriteLine | Assert.cs:104:27:104:34 | [b (line 84): false] access to property Length | +| Assert.cs:104:9:104:35 | [b (line 84): true] call to method WriteLine | Assert.cs:104:27:104:34 | [b (line 84): true] access to property Length | +| Assert.cs:104:9:104:36 | [b (line 84): false] ...; | Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | +| Assert.cs:104:9:104:36 | [b (line 84): true] ...; | Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | +| Assert.cs:104:27:104:27 | [b (line 84): false] access to local variable s | Assert.cs:104:9:104:36 | [b (line 84): false] ...; | +| Assert.cs:104:27:104:27 | [b (line 84): true] access to local variable s | Assert.cs:104:9:104:36 | [b (line 84): true] ...; | +| Assert.cs:104:27:104:34 | [b (line 84): false] access to property Length | Assert.cs:104:27:104:27 | [b (line 84): false] access to local variable s | +| Assert.cs:104:27:104:34 | [b (line 84): true] access to property Length | Assert.cs:104:27:104:27 | [b (line 84): true] access to local variable s | +| Assert.cs:106:9:106:25 | [b (line 84): false] ... = ... | Assert.cs:106:24:106:25 | [b (line 84): false] "" | +| Assert.cs:106:9:106:25 | [b (line 84): true] ... = ... | Assert.cs:106:17:106:20 | [b (line 84): true] null | +| Assert.cs:106:9:106:26 | [b (line 84): false] ...; | Assert.cs:104:9:104:35 | [b (line 84): false] call to method WriteLine | +| Assert.cs:106:9:106:26 | [b (line 84): true] ...; | Assert.cs:104:9:104:35 | [b (line 84): true] call to method WriteLine | +| Assert.cs:106:13:106:13 | [b (line 84): false] access to parameter b | Assert.cs:106:13:106:25 | [b (line 84): false] ... ? ... : ... | +| Assert.cs:106:13:106:13 | [b (line 84): true] access to parameter b | Assert.cs:106:13:106:25 | [b (line 84): true] ... ? ... : ... | +| Assert.cs:106:13:106:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:106:9:106:26 | [b (line 84): false] ...; | +| Assert.cs:106:13:106:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:106:9:106:26 | [b (line 84): true] ...; | +| Assert.cs:106:17:106:20 | [b (line 84): true] null | Assert.cs:106:13:106:13 | [b (line 84): true] access to parameter b | +| Assert.cs:106:24:106:25 | [b (line 84): false] "" | Assert.cs:106:13:106:13 | [b (line 84): false] access to parameter b | +| Assert.cs:107:9:107:34 | [b (line 84): false] ...; | Assert.cs:106:9:106:25 | [b (line 84): false] ... = ... | +| Assert.cs:107:9:107:34 | [b (line 84): true] ...; | Assert.cs:106:9:106:25 | [b (line 84): true] ... = ... | +| Assert.cs:107:24:107:24 | [b (line 84): false] access to local variable s | Assert.cs:107:9:107:34 | [b (line 84): false] ...; | +| Assert.cs:107:24:107:24 | [b (line 84): true] access to local variable s | Assert.cs:107:9:107:34 | [b (line 84): true] ...; | +| Assert.cs:107:24:107:32 | [b (line 84): false] ... != ... | Assert.cs:107:29:107:32 | [b (line 84): false] null | +| Assert.cs:107:24:107:32 | [b (line 84): true] ... != ... | Assert.cs:107:29:107:32 | [b (line 84): true] null | +| Assert.cs:107:29:107:32 | [b (line 84): false] null | Assert.cs:107:24:107:24 | [b (line 84): false] access to local variable s | +| Assert.cs:107:29:107:32 | [b (line 84): true] null | Assert.cs:107:24:107:24 | [b (line 84): true] access to local variable s | +| Assert.cs:108:9:108:35 | [b (line 84): false] call to method WriteLine | Assert.cs:108:27:108:34 | [b (line 84): false] access to property Length | +| Assert.cs:108:9:108:35 | [b (line 84): true] call to method WriteLine | Assert.cs:108:27:108:34 | [b (line 84): true] access to property Length | +| Assert.cs:108:9:108:36 | [b (line 84): false] ...; | Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | +| Assert.cs:108:9:108:36 | [b (line 84): true] ...; | Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | +| Assert.cs:108:27:108:27 | [b (line 84): false] access to local variable s | Assert.cs:108:9:108:36 | [b (line 84): false] ...; | +| Assert.cs:108:27:108:27 | [b (line 84): true] access to local variable s | Assert.cs:108:9:108:36 | [b (line 84): true] ...; | +| Assert.cs:108:27:108:34 | [b (line 84): false] access to property Length | Assert.cs:108:27:108:27 | [b (line 84): false] access to local variable s | +| Assert.cs:108:27:108:34 | [b (line 84): true] access to property Length | Assert.cs:108:27:108:27 | [b (line 84): true] access to local variable s | +| Assert.cs:110:9:110:25 | [b (line 84): false] ... = ... | Assert.cs:110:24:110:25 | [b (line 84): false] "" | +| Assert.cs:110:9:110:25 | [b (line 84): true] ... = ... | Assert.cs:110:17:110:20 | [b (line 84): true] null | +| Assert.cs:110:9:110:26 | [b (line 84): false] ...; | Assert.cs:108:9:108:35 | [b (line 84): false] call to method WriteLine | +| Assert.cs:110:9:110:26 | [b (line 84): true] ...; | Assert.cs:108:9:108:35 | [b (line 84): true] call to method WriteLine | +| Assert.cs:110:13:110:13 | [b (line 84): false] access to parameter b | Assert.cs:110:13:110:25 | [b (line 84): false] ... ? ... : ... | +| Assert.cs:110:13:110:13 | [b (line 84): true] access to parameter b | Assert.cs:110:13:110:25 | [b (line 84): true] ... ? ... : ... | +| Assert.cs:110:13:110:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:110:9:110:26 | [b (line 84): false] ...; | +| Assert.cs:110:13:110:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:110:9:110:26 | [b (line 84): true] ...; | +| Assert.cs:110:17:110:20 | [b (line 84): true] null | Assert.cs:110:13:110:13 | [b (line 84): true] access to parameter b | +| Assert.cs:110:24:110:25 | [b (line 84): false] "" | Assert.cs:110:13:110:13 | [b (line 84): false] access to parameter b | +| Assert.cs:111:9:111:34 | [b (line 84): false] ...; | Assert.cs:110:9:110:25 | [b (line 84): false] ... = ... | +| Assert.cs:111:9:111:34 | [b (line 84): true] ...; | Assert.cs:110:9:110:25 | [b (line 84): true] ... = ... | +| Assert.cs:111:24:111:24 | [b (line 84): false] access to local variable s | Assert.cs:111:9:111:34 | [b (line 84): false] ...; | +| Assert.cs:111:24:111:24 | [b (line 84): true] access to local variable s | Assert.cs:111:9:111:34 | [b (line 84): true] ...; | +| Assert.cs:111:24:111:32 | [b (line 84): false] ... == ... | Assert.cs:111:29:111:32 | [b (line 84): false] null | +| Assert.cs:111:24:111:32 | [b (line 84): true] ... == ... | Assert.cs:111:29:111:32 | [b (line 84): true] null | +| Assert.cs:111:29:111:32 | [b (line 84): false] null | Assert.cs:111:24:111:24 | [b (line 84): false] access to local variable s | +| Assert.cs:111:29:111:32 | [b (line 84): true] null | Assert.cs:111:24:111:24 | [b (line 84): true] access to local variable s | +| Assert.cs:112:9:112:35 | [b (line 84): false] call to method WriteLine | Assert.cs:112:27:112:34 | [b (line 84): false] access to property Length | +| Assert.cs:112:9:112:35 | [b (line 84): true] call to method WriteLine | Assert.cs:112:27:112:34 | [b (line 84): true] access to property Length | +| Assert.cs:112:9:112:36 | [b (line 84): false] ...; | Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | +| Assert.cs:112:9:112:36 | [b (line 84): true] ...; | Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | +| Assert.cs:112:27:112:27 | [b (line 84): false] access to local variable s | Assert.cs:112:9:112:36 | [b (line 84): false] ...; | +| Assert.cs:112:27:112:27 | [b (line 84): true] access to local variable s | Assert.cs:112:9:112:36 | [b (line 84): true] ...; | +| Assert.cs:112:27:112:34 | [b (line 84): false] access to property Length | Assert.cs:112:27:112:27 | [b (line 84): false] access to local variable s | +| Assert.cs:112:27:112:34 | [b (line 84): true] access to property Length | Assert.cs:112:27:112:27 | [b (line 84): true] access to local variable s | +| Assert.cs:114:9:114:25 | [b (line 84): false] ... = ... | Assert.cs:114:24:114:25 | [b (line 84): false] "" | +| Assert.cs:114:9:114:25 | [b (line 84): true] ... = ... | Assert.cs:114:17:114:20 | [b (line 84): true] null | +| Assert.cs:114:9:114:26 | [b (line 84): false] ...; | Assert.cs:112:9:112:35 | [b (line 84): false] call to method WriteLine | +| Assert.cs:114:9:114:26 | [b (line 84): true] ...; | Assert.cs:112:9:112:35 | [b (line 84): true] call to method WriteLine | +| Assert.cs:114:13:114:13 | [b (line 84): false] access to parameter b | Assert.cs:114:13:114:25 | [b (line 84): false] ... ? ... : ... | +| Assert.cs:114:13:114:13 | [b (line 84): true] access to parameter b | Assert.cs:114:13:114:25 | [b (line 84): true] ... ? ... : ... | +| Assert.cs:114:13:114:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:114:9:114:26 | [b (line 84): false] ...; | +| Assert.cs:114:13:114:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:114:9:114:26 | [b (line 84): true] ...; | +| Assert.cs:114:17:114:20 | [b (line 84): true] null | Assert.cs:114:13:114:13 | [b (line 84): true] access to parameter b | +| Assert.cs:114:24:114:25 | [b (line 84): false] "" | Assert.cs:114:13:114:13 | [b (line 84): false] access to parameter b | +| Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | Assert.cs:115:23:115:31 | [b (line 84): false] ... != ... | +| Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | +| Assert.cs:115:9:115:37 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | +| Assert.cs:115:9:115:38 | [b (line 84): false] ...; | Assert.cs:114:9:114:25 | [b (line 84): false] ... = ... | +| Assert.cs:115:9:115:38 | [b (line 84): true] ...; | Assert.cs:114:9:114:25 | [b (line 84): true] ... = ... | +| Assert.cs:115:23:115:23 | [b (line 84): false] access to local variable s | Assert.cs:115:23:115:36 | [b (line 84): false] ... && ... | +| Assert.cs:115:23:115:23 | [b (line 84): true] access to local variable s | Assert.cs:115:23:115:36 | [b (line 84): true] ... && ... | +| Assert.cs:115:23:115:31 | [b (line 84): false] ... != ... | Assert.cs:115:28:115:31 | [b (line 84): false] null | +| Assert.cs:115:23:115:31 | [b (line 84): true] ... != ... | Assert.cs:115:28:115:31 | [b (line 84): true] null | +| Assert.cs:115:23:115:36 | [b (line 84): false] ... && ... | Assert.cs:115:9:115:38 | [b (line 84): false] ...; | +| Assert.cs:115:23:115:36 | [b (line 84): true] ... && ... | Assert.cs:115:9:115:38 | [b (line 84): true] ...; | +| Assert.cs:115:28:115:31 | [b (line 84): false] null | Assert.cs:115:23:115:23 | [b (line 84): false] access to local variable s | +| Assert.cs:115:28:115:31 | [b (line 84): true] null | Assert.cs:115:23:115:23 | [b (line 84): true] access to local variable s | +| Assert.cs:116:9:116:35 | [b (line 84): true] call to method WriteLine | Assert.cs:116:27:116:34 | [b (line 84): true] access to property Length | +| Assert.cs:116:9:116:36 | [b (line 84): true] ...; | Assert.cs:115:9:115:37 | [assertion success, b (line 84): true] call to method IsTrue | +| Assert.cs:116:27:116:27 | [b (line 84): true] access to local variable s | Assert.cs:116:9:116:36 | [b (line 84): true] ...; | +| Assert.cs:116:27:116:34 | [b (line 84): true] access to property Length | Assert.cs:116:27:116:27 | [b (line 84): true] access to local variable s | +| Assert.cs:118:9:118:25 | [b (line 84): true] ... = ... | Assert.cs:118:17:118:20 | [b (line 84): true] null | +| Assert.cs:118:9:118:26 | [b (line 84): true] ...; | Assert.cs:116:9:116:35 | [b (line 84): true] call to method WriteLine | +| Assert.cs:118:13:118:13 | [b (line 84): true] access to parameter b | Assert.cs:118:13:118:25 | [b (line 84): true] ... ? ... : ... | +| Assert.cs:118:13:118:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:118:9:118:26 | [b (line 84): true] ...; | +| Assert.cs:118:17:118:20 | [b (line 84): true] null | Assert.cs:118:13:118:13 | [b (line 84): true] access to parameter b | +| Assert.cs:119:9:119:39 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:119:38:119:38 | [b (line 84): true] access to parameter b | +| Assert.cs:119:9:119:40 | [b (line 84): true] ...; | Assert.cs:118:9:118:25 | [b (line 84): true] ... = ... | +| Assert.cs:119:24:119:24 | [b (line 84): true] access to local variable s | Assert.cs:119:24:119:38 | [b (line 84): true] ... \|\| ... | +| Assert.cs:119:24:119:32 | [b (line 84): true] ... == ... | Assert.cs:119:29:119:32 | [b (line 84): true] null | +| Assert.cs:119:24:119:38 | [b (line 84): true] ... \|\| ... | Assert.cs:119:9:119:40 | [b (line 84): true] ...; | +| Assert.cs:119:29:119:32 | [b (line 84): true] null | Assert.cs:119:24:119:24 | [b (line 84): true] access to local variable s | +| Assert.cs:119:38:119:38 | [b (line 84): true] access to parameter b | Assert.cs:119:37:119:38 | [b (line 84): true] !... | +| Assert.cs:120:9:120:35 | [b (line 84): true] call to method WriteLine | Assert.cs:120:27:120:34 | [b (line 84): true] access to property Length | +| Assert.cs:120:9:120:36 | [b (line 84): true] ...; | Assert.cs:119:9:119:39 | [assertion success, b (line 84): true] call to method IsFalse | +| Assert.cs:120:27:120:27 | [b (line 84): true] access to local variable s | Assert.cs:120:9:120:36 | [b (line 84): true] ...; | +| Assert.cs:120:27:120:34 | [b (line 84): true] access to property Length | Assert.cs:120:27:120:27 | [b (line 84): true] access to local variable s | +| Assert.cs:122:9:122:25 | [b (line 84): true] ... = ... | Assert.cs:122:17:122:20 | [b (line 84): true] null | +| Assert.cs:122:9:122:26 | [b (line 84): true] ...; | Assert.cs:120:9:120:35 | [b (line 84): true] call to method WriteLine | +| Assert.cs:122:13:122:13 | [b (line 84): true] access to parameter b | Assert.cs:122:13:122:25 | [b (line 84): true] ... ? ... : ... | +| Assert.cs:122:13:122:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:122:9:122:26 | [b (line 84): true] ...; | +| Assert.cs:122:17:122:20 | [b (line 84): true] null | Assert.cs:122:13:122:13 | [b (line 84): true] access to parameter b | +| Assert.cs:123:9:123:37 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | +| Assert.cs:123:9:123:38 | [b (line 84): true] ...; | Assert.cs:122:9:122:25 | [b (line 84): true] ... = ... | +| Assert.cs:123:23:123:23 | [b (line 84): true] access to local variable s | Assert.cs:123:23:123:36 | [b (line 84): true] ... && ... | +| Assert.cs:123:23:123:31 | [b (line 84): true] ... == ... | Assert.cs:123:28:123:31 | [b (line 84): true] null | +| Assert.cs:123:23:123:36 | [b (line 84): true] ... && ... | Assert.cs:123:9:123:38 | [b (line 84): true] ...; | +| Assert.cs:123:28:123:31 | [b (line 84): true] null | Assert.cs:123:23:123:23 | [b (line 84): true] access to local variable s | +| Assert.cs:124:9:124:35 | [b (line 84): true] call to method WriteLine | Assert.cs:124:27:124:34 | [b (line 84): true] access to property Length | +| Assert.cs:124:9:124:36 | [b (line 84): true] ...; | Assert.cs:123:9:123:37 | [assertion success, b (line 84): true] call to method IsTrue | +| Assert.cs:124:27:124:27 | [b (line 84): true] access to local variable s | Assert.cs:124:9:124:36 | [b (line 84): true] ...; | +| Assert.cs:124:27:124:34 | [b (line 84): true] access to property Length | Assert.cs:124:27:124:27 | [b (line 84): true] access to local variable s | +| Assert.cs:126:9:126:25 | [b (line 84): true] ... = ... | Assert.cs:126:17:126:20 | [b (line 84): true] null | +| Assert.cs:126:9:126:26 | [b (line 84): true] ...; | Assert.cs:124:9:124:35 | [b (line 84): true] call to method WriteLine | +| Assert.cs:126:13:126:13 | [b (line 84): true] access to parameter b | Assert.cs:126:13:126:25 | [b (line 84): true] ... ? ... : ... | +| Assert.cs:126:13:126:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:126:9:126:26 | [b (line 84): true] ...; | +| Assert.cs:126:17:126:20 | [b (line 84): true] null | Assert.cs:126:13:126:13 | [b (line 84): true] access to parameter b | +| Assert.cs:127:9:127:39 | [assertion success] call to method IsFalse | Assert.cs:127:38:127:38 | [b (line 84): true] access to parameter b | +| Assert.cs:127:9:127:40 | [b (line 84): true] ...; | Assert.cs:126:9:126:25 | [b (line 84): true] ... = ... | +| Assert.cs:127:24:127:24 | [b (line 84): true] access to local variable s | Assert.cs:127:24:127:38 | [b (line 84): true] ... \|\| ... | +| Assert.cs:127:24:127:32 | [b (line 84): true] ... != ... | Assert.cs:127:29:127:32 | [b (line 84): true] null | +| Assert.cs:127:24:127:38 | [b (line 84): true] ... \|\| ... | Assert.cs:127:9:127:40 | [b (line 84): true] ...; | +| Assert.cs:127:29:127:32 | [b (line 84): true] null | Assert.cs:127:24:127:24 | [b (line 84): true] access to local variable s | +| Assert.cs:127:38:127:38 | [b (line 84): true] access to parameter b | Assert.cs:127:37:127:38 | [b (line 84): true] !... | +| Assert.cs:128:9:128:35 | call to method WriteLine | Assert.cs:128:27:128:34 | access to property Length | +| Assert.cs:128:9:128:36 | ...; | Assert.cs:127:9:127:39 | [assertion success] call to method IsFalse | +| Assert.cs:128:27:128:27 | access to local variable s | Assert.cs:128:9:128:36 | ...; | +| Assert.cs:128:27:128:34 | access to property Length | Assert.cs:128:27:128:27 | access to local variable s | | Assignments.cs:3:10:3:10 | exit M | Assignments.cs:14:9:14:35 | ... += ... | | Assignments.cs:4:5:15:5 | {...} | Assignments.cs:3:10:3:10 | enter M | | Assignments.cs:5:9:5:18 | ... ...; | Assignments.cs:4:5:15:5 | {...} | @@ -3532,6 +4697,8 @@ postDominance | CompileTimeOperators.cs:40:14:40:37 | call to method WriteLine | CompileTimeOperators.cs:40:32:40:36 | "End" | | CompileTimeOperators.cs:40:14:40:38 | ...; | CompileTimeOperators.cs:40:9:40:11 | End: | | CompileTimeOperators.cs:40:32:40:36 | "End" | CompileTimeOperators.cs:40:14:40:38 | ...; | +| ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | ConditionalAccess.cs:30:28:30:32 | ... = ... | +| ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | ConditionalAccess.cs:30:28:30:32 | ... = ... | | ConditionalAccess.cs:3:12:3:13 | exit M1 | ConditionalAccess.cs:3:26:3:26 | access to parameter i | | ConditionalAccess.cs:3:12:3:13 | exit M1 | ConditionalAccess.cs:3:28:3:38 | call to method ToString | | ConditionalAccess.cs:3:12:3:13 | exit M1 | ConditionalAccess.cs:3:40:3:49 | call to method ToLower | @@ -3578,12 +4745,26 @@ postDominance | ConditionalAccess.cs:25:13:25:14 | "" | ConditionalAccess.cs:25:9:25:33 | ...; | | ConditionalAccess.cs:25:16:25:32 | call to method CommaJoinWith | ConditionalAccess.cs:25:31:25:31 | access to local variable s | | ConditionalAccess.cs:25:31:25:31 | access to local variable s | ConditionalAccess.cs:25:13:25:14 | "" | -| ConditionalAccess.cs:31:26:31:38 | exit CommaJoinWith | ConditionalAccess.cs:31:70:31:83 | ... + ... | -| ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | -| ConditionalAccess.cs:31:70:31:78 | ... + ... | ConditionalAccess.cs:31:75:31:78 | ", " | -| ConditionalAccess.cs:31:70:31:83 | ... + ... | ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | -| ConditionalAccess.cs:31:75:31:78 | ", " | ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | -| ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | ConditionalAccess.cs:31:70:31:78 | ... + ... | +| ConditionalAccess.cs:30:10:30:12 | exit Out | ConditionalAccess.cs:30:28:30:32 | ... = ... | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:30:32:30:32 | 0 | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:30:32:30:32 | 0 | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:10:30:12 | enter Out | +| ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:35:9:35:12 | access to property Prop | +| ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:35:14:35:24 | call to method Out | +| ConditionalAccess.cs:33:5:36:5 | {...} | ConditionalAccess.cs:32:10:32:11 | enter M8 | +| ConditionalAccess.cs:34:9:34:13 | ... = ... | ConditionalAccess.cs:34:13:34:13 | 0 | +| ConditionalAccess.cs:34:9:34:14 | ...; | ConditionalAccess.cs:33:5:36:5 | {...} | +| ConditionalAccess.cs:34:13:34:13 | 0 | ConditionalAccess.cs:34:9:34:14 | ...; | +| ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:35:9:35:12 | this access | +| ConditionalAccess.cs:35:9:35:12 | this access | ConditionalAccess.cs:35:9:35:25 | ...; | +| ConditionalAccess.cs:35:9:35:25 | ...; | ConditionalAccess.cs:34:9:34:13 | ... = ... | +| ConditionalAccess.cs:41:26:41:38 | exit CommaJoinWith | ConditionalAccess.cs:41:70:41:83 | ... + ... | +| ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | +| ConditionalAccess.cs:41:70:41:78 | ... + ... | ConditionalAccess.cs:41:75:41:78 | ", " | +| ConditionalAccess.cs:41:70:41:83 | ... + ... | ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | +| ConditionalAccess.cs:41:75:41:78 | ", " | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | +| ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | ConditionalAccess.cs:41:70:41:78 | ... + ... | | Conditions.cs:3:10:3:19 | exit IncrOrDecr | Conditions.cs:7:14:7:16 | [inc (line 3): true] access to parameter inc | | Conditions.cs:3:10:3:19 | exit IncrOrDecr | Conditions.cs:8:13:8:15 | ...-- | | Conditions.cs:4:5:9:5 | {...} | Conditions.cs:3:10:3:19 | enter IncrOrDecr | @@ -3772,11 +4953,11 @@ postDominance | Conditions.cs:79:17:79:25 | ... = ... | Conditions.cs:79:21:79:25 | false | | Conditions.cs:79:21:79:25 | false | Conditions.cs:79:17:79:26 | ...; | | Conditions.cs:81:9:82:16 | if (...) ... | Conditions.cs:74:9:80:9 | foreach (... ... in ...) ... | -| Conditions.cs:81:12:81:12 | access to local variable b | Conditions.cs:81:9:82:16 | if (...) ... | +| Conditions.cs:81:13:81:13 | access to local variable b | Conditions.cs:81:9:82:16 | if (...) ... | | Conditions.cs:82:13:82:13 | access to local variable x | Conditions.cs:82:13:82:16 | ...; | | Conditions.cs:82:13:82:15 | ...++ | Conditions.cs:82:13:82:13 | access to local variable x | | Conditions.cs:83:9:83:17 | return ...; | Conditions.cs:83:16:83:16 | access to local variable x | -| Conditions.cs:83:16:83:16 | access to local variable x | Conditions.cs:81:12:81:12 | access to local variable b | +| Conditions.cs:83:16:83:16 | access to local variable x | Conditions.cs:81:13:81:13 | access to local variable b | | Conditions.cs:83:16:83:16 | access to local variable x | Conditions.cs:82:13:82:15 | ...++ | | Conditions.cs:86:9:86:10 | exit M7 | Conditions.cs:99:9:99:17 | return ...; | | Conditions.cs:87:5:100:5 | {...} | Conditions.cs:86:9:86:10 | enter M7 | @@ -3847,22 +5028,22 @@ postDominance | Conditions.cs:110:16:110:16 | access to local variable x | Conditions.cs:107:13:107:24 | [b (line 102): true] ... > ... | | Conditions.cs:110:16:110:16 | access to local variable x | Conditions.cs:108:18:108:18 | [b (line 102): true] access to parameter b | | Conditions.cs:110:16:110:16 | access to local variable x | Conditions.cs:109:17:109:23 | ... = ... | -| Conditions.cs:113:10:113:11 | exit M9 | Conditions.cs:116:24:116:38 | ... < ... | +| Conditions.cs:113:10:113:11 | exit M9 | Conditions.cs:116:25:116:39 | ... < ... | | Conditions.cs:114:5:124:5 | {...} | Conditions.cs:113:10:113:11 | enter M9 | | Conditions.cs:115:9:115:24 | ... ...; | Conditions.cs:114:5:124:5 | {...} | | Conditions.cs:115:16:115:23 | String s = ... | Conditions.cs:115:20:115:23 | null | | Conditions.cs:115:20:115:23 | null | Conditions.cs:115:9:115:24 | ... ...; | | Conditions.cs:116:9:123:9 | for (...;...;...) ... | Conditions.cs:115:16:115:23 | String s = ... | -| Conditions.cs:116:17:116:21 | Int32 i = ... | Conditions.cs:116:21:116:21 | 0 | -| Conditions.cs:116:21:116:21 | 0 | Conditions.cs:116:9:123:9 | for (...;...;...) ... | -| Conditions.cs:116:24:116:24 | access to local variable i | Conditions.cs:116:17:116:21 | Int32 i = ... | -| Conditions.cs:116:24:116:24 | access to local variable i | Conditions.cs:116:41:116:43 | ...++ | -| Conditions.cs:116:24:116:38 | ... < ... | Conditions.cs:116:28:116:38 | access to property Length | -| Conditions.cs:116:28:116:31 | access to parameter args | Conditions.cs:116:24:116:24 | access to local variable i | -| Conditions.cs:116:28:116:38 | access to property Length | Conditions.cs:116:28:116:31 | access to parameter args | -| Conditions.cs:116:41:116:41 | access to local variable i | Conditions.cs:121:17:121:20 | [last (line 118): false] access to local variable last | -| Conditions.cs:116:41:116:41 | access to local variable i | Conditions.cs:122:17:122:24 | ... = ... | -| Conditions.cs:116:41:116:43 | ...++ | Conditions.cs:116:41:116:41 | access to local variable i | +| Conditions.cs:116:18:116:22 | Int32 i = ... | Conditions.cs:116:22:116:22 | 0 | +| Conditions.cs:116:22:116:22 | 0 | Conditions.cs:116:9:123:9 | for (...;...;...) ... | +| Conditions.cs:116:25:116:25 | access to local variable i | Conditions.cs:116:18:116:22 | Int32 i = ... | +| Conditions.cs:116:25:116:25 | access to local variable i | Conditions.cs:116:42:116:44 | ...++ | +| Conditions.cs:116:25:116:39 | ... < ... | Conditions.cs:116:29:116:39 | access to property Length | +| Conditions.cs:116:29:116:32 | access to parameter args | Conditions.cs:116:25:116:25 | access to local variable i | +| Conditions.cs:116:29:116:39 | access to property Length | Conditions.cs:116:29:116:32 | access to parameter args | +| Conditions.cs:116:42:116:42 | access to local variable i | Conditions.cs:121:17:121:20 | [last (line 118): false] access to local variable last | +| Conditions.cs:116:42:116:42 | access to local variable i | Conditions.cs:122:17:122:24 | ... = ... | +| Conditions.cs:116:42:116:44 | ...++ | Conditions.cs:116:42:116:42 | access to local variable i | | Conditions.cs:118:13:118:44 | ... ...; | Conditions.cs:117:9:123:9 | {...} | | Conditions.cs:118:17:118:43 | Boolean last = ... | Conditions.cs:118:24:118:43 | ... == ... | | Conditions.cs:118:24:118:24 | access to local variable i | Conditions.cs:118:13:118:44 | ... ...; | @@ -3917,6 +5098,28 @@ postDominance | Conditions.cs:137:21:137:26 | [Field1 (line 129): true, Field2 (line 129): true] this access | Conditions.cs:137:21:137:38 | [Field1 (line 129): true, Field2 (line 129): true] ...; | | Conditions.cs:137:21:137:37 | [Field1 (line 129): true, Field2 (line 129): true] call to method ToString | Conditions.cs:137:21:137:26 | [Field1 (line 129): true, Field2 (line 129): true] access to field Field1 | | Conditions.cs:137:21:137:38 | [Field1 (line 129): true, Field2 (line 129): true] ...; | Conditions.cs:136:17:138:17 | [Field1 (line 129): true, Field2 (line 129): true] {...} | +| Conditions.cs:143:10:143:12 | exit M11 | Conditions.cs:147:13:147:48 | call to method WriteLine | +| Conditions.cs:143:10:143:12 | exit M11 | Conditions.cs:149:13:149:48 | call to method WriteLine | +| Conditions.cs:144:5:150:5 | {...} | Conditions.cs:143:10:143:12 | enter M11 | +| Conditions.cs:145:9:145:30 | ... ...; | Conditions.cs:144:5:150:5 | {...} | +| Conditions.cs:145:13:145:29 | [b (line 143): false] String s = ... | Conditions.cs:145:27:145:29 | [b (line 143): false] "b" | +| Conditions.cs:145:13:145:29 | [b (line 143): true] String s = ... | Conditions.cs:145:21:145:23 | [b (line 143): true] "a" | +| Conditions.cs:145:17:145:17 | access to parameter b | Conditions.cs:145:17:145:29 | ... ? ... : ... | +| Conditions.cs:145:17:145:29 | ... ? ... : ... | Conditions.cs:145:9:145:30 | ... ...; | +| Conditions.cs:146:9:149:49 | [b (line 143): false] if (...) ... | Conditions.cs:145:13:145:29 | [b (line 143): false] String s = ... | +| Conditions.cs:146:9:149:49 | [b (line 143): true] if (...) ... | Conditions.cs:145:13:145:29 | [b (line 143): true] String s = ... | +| Conditions.cs:146:13:146:13 | [b (line 143): false] access to parameter b | Conditions.cs:146:9:149:49 | [b (line 143): false] if (...) ... | +| Conditions.cs:146:13:146:13 | [b (line 143): true] access to parameter b | Conditions.cs:146:9:149:49 | [b (line 143): true] if (...) ... | +| Conditions.cs:147:13:147:48 | call to method WriteLine | Conditions.cs:147:38:147:47 | $"..." | +| Conditions.cs:147:13:147:49 | ...; | Conditions.cs:146:13:146:13 | [b (line 143): true] access to parameter b | +| Conditions.cs:147:38:147:47 | $"..." | Conditions.cs:147:45:147:45 | access to local variable s | +| Conditions.cs:147:40:147:43 | "a = " | Conditions.cs:147:13:147:49 | ...; | +| Conditions.cs:147:45:147:45 | access to local variable s | Conditions.cs:147:40:147:43 | "a = " | +| Conditions.cs:149:13:149:48 | call to method WriteLine | Conditions.cs:149:38:149:47 | $"..." | +| Conditions.cs:149:13:149:49 | ...; | Conditions.cs:146:13:146:13 | [b (line 143): false] access to parameter b | +| Conditions.cs:149:38:149:47 | $"..." | Conditions.cs:149:45:149:45 | access to local variable s | +| Conditions.cs:149:40:149:43 | "b = " | Conditions.cs:149:13:149:49 | ...; | +| Conditions.cs:149:45:149:45 | access to local variable s | Conditions.cs:149:40:149:43 | "b = " | | ExitMethods.cs:7:10:7:11 | exit M1 | ExitMethods.cs:10:9:10:15 | return ...; | | ExitMethods.cs:8:5:11:5 | {...} | ExitMethods.cs:7:10:7:11 | enter M1 | | ExitMethods.cs:9:9:9:24 | call to method ErrorMaybe | ExitMethods.cs:9:20:9:23 | true | @@ -4023,9 +5226,9 @@ postDominance | ExitMethods.cs:116:16:116:30 | call to method Contains | ExitMethods.cs:116:27:116:29 | - | | ExitMethods.cs:116:16:116:38 | ... ? ... : ... | ExitMethods.cs:115:5:117:5 | {...} | | ExitMethods.cs:116:27:116:29 | - | ExitMethods.cs:116:16:116:16 | access to parameter s | -| ExitMethods.cs:119:17:119:32 | exit FailingAssertion | ExitMethods.cs:121:9:121:28 | call to method IsTrue | +| ExitMethods.cs:119:17:119:32 | exit FailingAssertion | ExitMethods.cs:121:9:121:28 | [assertion failure] call to method IsTrue | | ExitMethods.cs:120:5:123:5 | {...} | ExitMethods.cs:119:17:119:32 | enter FailingAssertion | -| ExitMethods.cs:121:9:121:28 | call to method IsTrue | ExitMethods.cs:121:23:121:27 | false | +| ExitMethods.cs:121:9:121:28 | [assertion failure] call to method IsTrue | ExitMethods.cs:121:23:121:27 | false | | ExitMethods.cs:121:9:121:29 | ...; | ExitMethods.cs:120:5:123:5 | {...} | | ExitMethods.cs:121:23:121:27 | false | ExitMethods.cs:121:9:121:29 | ...; | | ExitMethods.cs:125:17:125:33 | exit FailingAssertion2 | ExitMethods.cs:127:9:127:26 | call to method FailingAssertion | @@ -4033,12 +5236,12 @@ postDominance | ExitMethods.cs:127:9:127:26 | call to method FailingAssertion | ExitMethods.cs:127:9:127:26 | this access | | ExitMethods.cs:127:9:127:26 | this access | ExitMethods.cs:127:9:127:27 | ...; | | ExitMethods.cs:127:9:127:27 | ...; | ExitMethods.cs:126:5:129:5 | {...} | -| ExitMethods.cs:131:10:131:20 | exit AssertFalse | ExitMethods.cs:131:33:131:49 | call to method IsFalse | -| ExitMethods.cs:131:33:131:49 | call to method IsFalse | ExitMethods.cs:131:48:131:48 | access to parameter b | +| ExitMethods.cs:131:10:131:20 | exit AssertFalse | ExitMethods.cs:131:33:131:49 | [assertion failure] call to method IsFalse | +| ExitMethods.cs:131:10:131:20 | exit AssertFalse | ExitMethods.cs:131:33:131:49 | [assertion success] call to method IsFalse | | ExitMethods.cs:131:48:131:48 | access to parameter b | ExitMethods.cs:131:10:131:20 | enter AssertFalse | -| ExitMethods.cs:133:17:133:33 | exit FailingAssertion3 | ExitMethods.cs:135:9:135:25 | call to method AssertFalse | +| ExitMethods.cs:133:17:133:33 | exit FailingAssertion3 | ExitMethods.cs:135:9:135:25 | [assertion failure] call to method AssertFalse | | ExitMethods.cs:134:5:137:5 | {...} | ExitMethods.cs:133:17:133:33 | enter FailingAssertion3 | -| ExitMethods.cs:135:9:135:25 | call to method AssertFalse | ExitMethods.cs:135:21:135:24 | true | +| ExitMethods.cs:135:9:135:25 | [assertion failure] call to method AssertFalse | ExitMethods.cs:135:21:135:24 | true | | ExitMethods.cs:135:9:135:25 | this access | ExitMethods.cs:135:9:135:26 | ...; | | ExitMethods.cs:135:9:135:26 | ...; | ExitMethods.cs:134:5:137:5 | {...} | | ExitMethods.cs:135:21:135:24 | true | ExitMethods.cs:135:9:135:25 | this access | @@ -4738,7 +5941,8 @@ postDominance | Initializers.cs:14:51:14:51 | 1 | Initializers.cs:14:40:14:44 | ... = ... | | Initializers.cs:15:9:15:64 | ... ...; | Initializers.cs:14:13:14:53 | Initializers i = ... | | Initializers.cs:15:13:15:63 | Initializers[] iz = ... | Initializers.cs:15:37:15:63 | { ..., ... } | -| Initializers.cs:15:18:15:63 | array creation of type Initializers[] | Initializers.cs:15:9:15:64 | ... ...; | +| Initializers.cs:15:18:15:63 | 2 | Initializers.cs:15:9:15:64 | ... ...; | +| Initializers.cs:15:18:15:63 | array creation of type Initializers[] | Initializers.cs:15:18:15:63 | 2 | | Initializers.cs:15:37:15:63 | { ..., ... } | Initializers.cs:15:42:15:61 | object creation of type Initializers | | Initializers.cs:15:39:15:39 | access to local variable i | Initializers.cs:15:18:15:63 | array creation of type Initializers[] | | Initializers.cs:15:42:15:61 | object creation of type Initializers | Initializers.cs:15:59:15:60 | "" | @@ -4896,27 +6100,28 @@ postDominance | LoopUnrolling.cs:9:13:9:23 | access to property Length | LoopUnrolling.cs:9:13:9:16 | access to parameter args | | LoopUnrolling.cs:9:13:9:28 | ... == ... | LoopUnrolling.cs:9:28:9:28 | 0 | | LoopUnrolling.cs:9:28:9:28 | 0 | LoopUnrolling.cs:9:13:9:23 | access to property Length | -| LoopUnrolling.cs:11:9:12:35 | [unroll (line 11)] foreach (... ... in ...) ... | LoopUnrolling.cs:11:28:11:31 | access to parameter args | +| LoopUnrolling.cs:11:9:12:35 | [unroll (line 11)] foreach (... ... in ...) ... | LoopUnrolling.cs:11:29:11:32 | access to parameter args | | LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:12:13:12:34 | call to method WriteLine | -| LoopUnrolling.cs:11:21:11:23 | String arg | LoopUnrolling.cs:11:9:12:35 | [unroll (line 11)] foreach (... ... in ...) ... | +| LoopUnrolling.cs:11:22:11:24 | String arg | LoopUnrolling.cs:11:9:12:35 | [unroll (line 11)] foreach (... ... in ...) ... | | LoopUnrolling.cs:12:13:12:34 | call to method WriteLine | LoopUnrolling.cs:12:31:12:33 | access to local variable arg | -| LoopUnrolling.cs:12:13:12:35 | ...; | LoopUnrolling.cs:11:21:11:23 | String arg | +| LoopUnrolling.cs:12:13:12:35 | ...; | LoopUnrolling.cs:11:22:11:24 | String arg | | LoopUnrolling.cs:12:31:12:33 | access to local variable arg | LoopUnrolling.cs:12:13:12:35 | ...; | | LoopUnrolling.cs:15:10:15:11 | exit M2 | LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... | | LoopUnrolling.cs:16:5:20:5 | {...} | LoopUnrolling.cs:15:10:15:11 | enter M2 | -| LoopUnrolling.cs:17:9:17:47 | ... ...; | LoopUnrolling.cs:16:5:20:5 | {...} | -| LoopUnrolling.cs:17:13:17:46 | String[] xs = ... | LoopUnrolling.cs:17:30:17:46 | { ..., ... } | -| LoopUnrolling.cs:17:18:17:46 | array creation of type String[] | LoopUnrolling.cs:17:9:17:47 | ... ...; | -| LoopUnrolling.cs:17:30:17:46 | { ..., ... } | LoopUnrolling.cs:17:42:17:44 | "c" | -| LoopUnrolling.cs:17:32:17:34 | "a" | LoopUnrolling.cs:17:18:17:46 | array creation of type String[] | -| LoopUnrolling.cs:17:37:17:39 | "b" | LoopUnrolling.cs:17:32:17:34 | "a" | -| LoopUnrolling.cs:17:42:17:44 | "c" | LoopUnrolling.cs:17:37:17:39 | "b" | -| LoopUnrolling.cs:18:9:19:33 | [unroll (line 18)] foreach (... ... in ...) ... | LoopUnrolling.cs:18:26:18:27 | access to local variable xs | +| LoopUnrolling.cs:17:9:17:48 | ... ...; | LoopUnrolling.cs:16:5:20:5 | {...} | +| LoopUnrolling.cs:17:13:17:47 | String[] xs = ... | LoopUnrolling.cs:17:31:17:47 | { ..., ... } | +| LoopUnrolling.cs:17:18:17:47 | 3 | LoopUnrolling.cs:17:9:17:48 | ... ...; | +| LoopUnrolling.cs:17:18:17:47 | array creation of type String[] | LoopUnrolling.cs:17:18:17:47 | 3 | +| LoopUnrolling.cs:17:31:17:47 | { ..., ... } | LoopUnrolling.cs:17:43:17:45 | "c" | +| LoopUnrolling.cs:17:33:17:35 | "a" | LoopUnrolling.cs:17:18:17:47 | array creation of type String[] | +| LoopUnrolling.cs:17:38:17:40 | "b" | LoopUnrolling.cs:17:33:17:35 | "a" | +| LoopUnrolling.cs:17:43:17:45 | "c" | LoopUnrolling.cs:17:38:17:40 | "b" | +| LoopUnrolling.cs:18:9:19:33 | [unroll (line 18)] foreach (... ... in ...) ... | LoopUnrolling.cs:18:27:18:28 | access to local variable xs | | LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:19:13:19:32 | call to method WriteLine | -| LoopUnrolling.cs:18:21:18:21 | String x | LoopUnrolling.cs:18:9:19:33 | [unroll (line 18)] foreach (... ... in ...) ... | -| LoopUnrolling.cs:18:26:18:27 | access to local variable xs | LoopUnrolling.cs:17:13:17:46 | String[] xs = ... | +| LoopUnrolling.cs:18:22:18:22 | String x | LoopUnrolling.cs:18:9:19:33 | [unroll (line 18)] foreach (... ... in ...) ... | +| LoopUnrolling.cs:18:27:18:28 | access to local variable xs | LoopUnrolling.cs:17:13:17:47 | String[] xs = ... | | LoopUnrolling.cs:19:13:19:32 | call to method WriteLine | LoopUnrolling.cs:19:31:19:31 | access to local variable x | -| LoopUnrolling.cs:19:13:19:33 | ...; | LoopUnrolling.cs:18:21:18:21 | String x | +| LoopUnrolling.cs:19:13:19:33 | ...; | LoopUnrolling.cs:18:22:18:22 | String x | | LoopUnrolling.cs:19:31:19:31 | access to local variable x | LoopUnrolling.cs:19:13:19:33 | ...; | | LoopUnrolling.cs:22:10:22:11 | exit M3 | LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | | LoopUnrolling.cs:23:5:27:5 | {...} | LoopUnrolling.cs:22:10:22:11 | enter M3 | @@ -4930,81 +6135,81 @@ postDominance | LoopUnrolling.cs:26:17:26:39 | call to method WriteLine | LoopUnrolling.cs:26:35:26:38 | access to local variable arg0 | | LoopUnrolling.cs:26:17:26:40 | ...; | LoopUnrolling.cs:25:26:25:29 | Char arg0 | | LoopUnrolling.cs:26:35:26:38 | access to local variable arg0 | LoopUnrolling.cs:26:17:26:40 | ...; | -| LoopUnrolling.cs:29:10:29:11 | exit M4 | LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | +| LoopUnrolling.cs:29:10:29:11 | exit M4 | LoopUnrolling.cs:32:9:33:33 | [skip (line 32)] foreach (... ... in ...) ... | | LoopUnrolling.cs:30:5:34:5 | {...} | LoopUnrolling.cs:29:10:29:11 | enter M4 | | LoopUnrolling.cs:31:9:31:31 | ... ...; | LoopUnrolling.cs:30:5:34:5 | {...} | | LoopUnrolling.cs:31:13:31:30 | String[] xs = ... | LoopUnrolling.cs:31:18:31:30 | array creation of type String[] | | LoopUnrolling.cs:31:18:31:30 | array creation of type String[] | LoopUnrolling.cs:31:29:31:29 | 0 | | LoopUnrolling.cs:31:29:31:29 | 0 | LoopUnrolling.cs:31:9:31:31 | ... ...; | -| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:32:26:32:27 | access to local variable xs | -| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:33:13:33:32 | call to method WriteLine | -| LoopUnrolling.cs:32:26:32:27 | access to local variable xs | LoopUnrolling.cs:31:13:31:30 | String[] xs = ... | -| LoopUnrolling.cs:33:13:33:32 | call to method WriteLine | LoopUnrolling.cs:33:31:33:31 | access to local variable x | -| LoopUnrolling.cs:33:13:33:33 | ...; | LoopUnrolling.cs:32:21:32:21 | String x | -| LoopUnrolling.cs:33:31:33:31 | access to local variable x | LoopUnrolling.cs:33:13:33:33 | ...; | +| LoopUnrolling.cs:32:9:33:33 | [skip (line 32)] foreach (... ... in ...) ... | LoopUnrolling.cs:32:27:32:28 | access to local variable xs | +| LoopUnrolling.cs:32:27:32:28 | access to local variable xs | LoopUnrolling.cs:31:13:31:30 | String[] xs = ... | | LoopUnrolling.cs:36:10:36:11 | exit M5 | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | | LoopUnrolling.cs:37:5:43:5 | {...} | LoopUnrolling.cs:36:10:36:11 | enter M5 | -| LoopUnrolling.cs:38:9:38:47 | ... ...; | LoopUnrolling.cs:37:5:43:5 | {...} | -| LoopUnrolling.cs:38:13:38:46 | String[] xs = ... | LoopUnrolling.cs:38:30:38:46 | { ..., ... } | -| LoopUnrolling.cs:38:18:38:46 | array creation of type String[] | LoopUnrolling.cs:38:9:38:47 | ... ...; | -| LoopUnrolling.cs:38:30:38:46 | { ..., ... } | LoopUnrolling.cs:38:42:38:44 | "c" | -| LoopUnrolling.cs:38:32:38:34 | "a" | LoopUnrolling.cs:38:18:38:46 | array creation of type String[] | -| LoopUnrolling.cs:38:37:38:39 | "b" | LoopUnrolling.cs:38:32:38:34 | "a" | -| LoopUnrolling.cs:38:42:38:44 | "c" | LoopUnrolling.cs:38:37:38:39 | "b" | -| LoopUnrolling.cs:39:9:39:47 | ... ...; | LoopUnrolling.cs:38:13:38:46 | String[] xs = ... | -| LoopUnrolling.cs:39:13:39:46 | String[] ys = ... | LoopUnrolling.cs:39:30:39:46 | { ..., ... } | -| LoopUnrolling.cs:39:18:39:46 | array creation of type String[] | LoopUnrolling.cs:39:9:39:47 | ... ...; | -| LoopUnrolling.cs:39:30:39:46 | { ..., ... } | LoopUnrolling.cs:39:42:39:44 | "2" | -| LoopUnrolling.cs:39:32:39:34 | "0" | LoopUnrolling.cs:39:18:39:46 | array creation of type String[] | -| LoopUnrolling.cs:39:37:39:39 | "1" | LoopUnrolling.cs:39:32:39:34 | "0" | -| LoopUnrolling.cs:39:42:39:44 | "2" | LoopUnrolling.cs:39:37:39:39 | "1" | -| LoopUnrolling.cs:40:9:42:41 | [unroll (line 40)] foreach (... ... in ...) ... | LoopUnrolling.cs:40:26:40:27 | access to local variable xs | +| LoopUnrolling.cs:38:9:38:48 | ... ...; | LoopUnrolling.cs:37:5:43:5 | {...} | +| LoopUnrolling.cs:38:13:38:47 | String[] xs = ... | LoopUnrolling.cs:38:31:38:47 | { ..., ... } | +| LoopUnrolling.cs:38:18:38:47 | 3 | LoopUnrolling.cs:38:9:38:48 | ... ...; | +| LoopUnrolling.cs:38:18:38:47 | array creation of type String[] | LoopUnrolling.cs:38:18:38:47 | 3 | +| LoopUnrolling.cs:38:31:38:47 | { ..., ... } | LoopUnrolling.cs:38:43:38:45 | "c" | +| LoopUnrolling.cs:38:33:38:35 | "a" | LoopUnrolling.cs:38:18:38:47 | array creation of type String[] | +| LoopUnrolling.cs:38:38:38:40 | "b" | LoopUnrolling.cs:38:33:38:35 | "a" | +| LoopUnrolling.cs:38:43:38:45 | "c" | LoopUnrolling.cs:38:38:38:40 | "b" | +| LoopUnrolling.cs:39:9:39:48 | ... ...; | LoopUnrolling.cs:38:13:38:47 | String[] xs = ... | +| LoopUnrolling.cs:39:13:39:47 | String[] ys = ... | LoopUnrolling.cs:39:31:39:47 | { ..., ... } | +| LoopUnrolling.cs:39:18:39:47 | 3 | LoopUnrolling.cs:39:9:39:48 | ... ...; | +| LoopUnrolling.cs:39:18:39:47 | array creation of type String[] | LoopUnrolling.cs:39:18:39:47 | 3 | +| LoopUnrolling.cs:39:31:39:47 | { ..., ... } | LoopUnrolling.cs:39:43:39:45 | "2" | +| LoopUnrolling.cs:39:33:39:35 | "0" | LoopUnrolling.cs:39:18:39:47 | array creation of type String[] | +| LoopUnrolling.cs:39:38:39:40 | "1" | LoopUnrolling.cs:39:33:39:35 | "0" | +| LoopUnrolling.cs:39:43:39:45 | "2" | LoopUnrolling.cs:39:38:39:40 | "1" | +| LoopUnrolling.cs:40:9:42:41 | [unroll (line 40)] foreach (... ... in ...) ... | LoopUnrolling.cs:40:27:40:28 | access to local variable xs | | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:41:13:42:41 | foreach (... ... in ...) ... | -| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:40:9:42:41 | [unroll (line 40)] foreach (... ... in ...) ... | -| LoopUnrolling.cs:40:26:40:27 | access to local variable xs | LoopUnrolling.cs:39:13:39:46 | String[] ys = ... | -| LoopUnrolling.cs:41:13:42:41 | [unroll (line 41)] foreach (... ... in ...) ... | LoopUnrolling.cs:41:30:41:31 | access to local variable ys | +| LoopUnrolling.cs:40:22:40:22 | String x | LoopUnrolling.cs:40:9:42:41 | [unroll (line 40)] foreach (... ... in ...) ... | +| LoopUnrolling.cs:40:27:40:28 | access to local variable xs | LoopUnrolling.cs:39:13:39:47 | String[] ys = ... | +| LoopUnrolling.cs:41:13:42:41 | [unroll (line 41)] foreach (... ... in ...) ... | LoopUnrolling.cs:41:31:41:32 | access to local variable ys | | LoopUnrolling.cs:41:13:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:42:17:42:40 | call to method WriteLine | -| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:41:13:42:41 | [unroll (line 41)] foreach (... ... in ...) ... | -| LoopUnrolling.cs:41:30:41:31 | access to local variable ys | LoopUnrolling.cs:40:21:40:21 | String x | +| LoopUnrolling.cs:41:26:41:26 | String y | LoopUnrolling.cs:41:13:42:41 | [unroll (line 41)] foreach (... ... in ...) ... | +| LoopUnrolling.cs:41:31:41:32 | access to local variable ys | LoopUnrolling.cs:40:22:40:22 | String x | | LoopUnrolling.cs:42:17:42:40 | call to method WriteLine | LoopUnrolling.cs:42:35:42:39 | ... + ... | -| LoopUnrolling.cs:42:17:42:41 | ...; | LoopUnrolling.cs:41:25:41:25 | String y | +| LoopUnrolling.cs:42:17:42:41 | ...; | LoopUnrolling.cs:41:26:41:26 | String y | | LoopUnrolling.cs:42:35:42:35 | access to local variable x | LoopUnrolling.cs:42:17:42:41 | ...; | | LoopUnrolling.cs:42:35:42:39 | ... + ... | LoopUnrolling.cs:42:39:42:39 | access to local variable y | | LoopUnrolling.cs:42:39:42:39 | access to local variable y | LoopUnrolling.cs:42:35:42:35 | access to local variable x | | LoopUnrolling.cs:46:5:53:5 | {...} | LoopUnrolling.cs:45:10:45:11 | enter M6 | -| LoopUnrolling.cs:47:9:47:47 | ... ...; | LoopUnrolling.cs:46:5:53:5 | {...} | -| LoopUnrolling.cs:47:13:47:46 | String[] xs = ... | LoopUnrolling.cs:47:30:47:46 | { ..., ... } | -| LoopUnrolling.cs:47:18:47:46 | array creation of type String[] | LoopUnrolling.cs:47:9:47:47 | ... ...; | -| LoopUnrolling.cs:47:30:47:46 | { ..., ... } | LoopUnrolling.cs:47:42:47:44 | "c" | -| LoopUnrolling.cs:47:32:47:34 | "a" | LoopUnrolling.cs:47:18:47:46 | array creation of type String[] | -| LoopUnrolling.cs:47:37:47:39 | "b" | LoopUnrolling.cs:47:32:47:34 | "a" | -| LoopUnrolling.cs:47:42:47:44 | "c" | LoopUnrolling.cs:47:37:47:39 | "b" | -| LoopUnrolling.cs:48:9:52:9 | [unroll (line 48)] foreach (... ... in ...) ... | LoopUnrolling.cs:48:26:48:27 | access to local variable xs | -| LoopUnrolling.cs:48:21:48:21 | String x | LoopUnrolling.cs:48:9:52:9 | [unroll (line 48)] foreach (... ... in ...) ... | -| LoopUnrolling.cs:48:26:48:27 | access to local variable xs | LoopUnrolling.cs:47:13:47:46 | String[] xs = ... | -| LoopUnrolling.cs:49:9:52:9 | {...} | LoopUnrolling.cs:48:21:48:21 | String x | -| LoopUnrolling.cs:50:20:50:39 | call to method WriteLine | LoopUnrolling.cs:50:38:50:38 | access to local variable x | -| LoopUnrolling.cs:50:20:50:40 | ...; | LoopUnrolling.cs:50:13:50:17 | Label: | -| LoopUnrolling.cs:50:38:50:38 | access to local variable x | LoopUnrolling.cs:50:20:50:40 | ...; | -| LoopUnrolling.cs:51:13:51:23 | goto ...; | LoopUnrolling.cs:50:20:50:39 | call to method WriteLine | +| LoopUnrolling.cs:47:9:47:48 | ... ...; | LoopUnrolling.cs:46:5:53:5 | {...} | +| LoopUnrolling.cs:47:13:47:47 | String[] xs = ... | LoopUnrolling.cs:47:31:47:47 | { ..., ... } | +| LoopUnrolling.cs:47:18:47:47 | 3 | LoopUnrolling.cs:47:9:47:48 | ... ...; | +| LoopUnrolling.cs:47:18:47:47 | array creation of type String[] | LoopUnrolling.cs:47:18:47:47 | 3 | +| LoopUnrolling.cs:47:31:47:47 | { ..., ... } | LoopUnrolling.cs:47:43:47:45 | "c" | +| LoopUnrolling.cs:47:33:47:35 | "a" | LoopUnrolling.cs:47:18:47:47 | array creation of type String[] | +| LoopUnrolling.cs:47:38:47:40 | "b" | LoopUnrolling.cs:47:33:47:35 | "a" | +| LoopUnrolling.cs:47:43:47:45 | "c" | LoopUnrolling.cs:47:38:47:40 | "b" | +| LoopUnrolling.cs:48:9:52:9 | [unroll (line 48)] foreach (... ... in ...) ... | LoopUnrolling.cs:48:27:48:28 | access to local variable xs | +| LoopUnrolling.cs:48:22:48:22 | String x | LoopUnrolling.cs:48:9:52:9 | [unroll (line 48)] foreach (... ... in ...) ... | +| LoopUnrolling.cs:48:27:48:28 | access to local variable xs | LoopUnrolling.cs:47:13:47:47 | String[] xs = ... | +| LoopUnrolling.cs:49:9:52:9 | {...} | LoopUnrolling.cs:48:22:48:22 | String x | +| LoopUnrolling.cs:50:16:50:35 | call to method WriteLine | LoopUnrolling.cs:50:34:50:34 | access to local variable x | +| LoopUnrolling.cs:50:16:50:36 | ...; | LoopUnrolling.cs:50:9:50:13 | Label: | +| LoopUnrolling.cs:50:34:50:34 | access to local variable x | LoopUnrolling.cs:50:16:50:36 | ...; | +| LoopUnrolling.cs:51:13:51:23 | goto ...; | LoopUnrolling.cs:50:16:50:35 | call to method WriteLine | | LoopUnrolling.cs:55:10:55:11 | exit M7 | LoopUnrolling.cs:58:9:64:9 | [b (line 55): false] foreach (... ... in ...) ... | | LoopUnrolling.cs:55:10:55:11 | exit M7 | LoopUnrolling.cs:58:9:64:9 | [b (line 55): true] foreach (... ... in ...) ... | | LoopUnrolling.cs:56:5:65:5 | {...} | LoopUnrolling.cs:55:10:55:11 | enter M7 | -| LoopUnrolling.cs:57:9:57:47 | ... ...; | LoopUnrolling.cs:56:5:65:5 | {...} | -| LoopUnrolling.cs:57:13:57:46 | String[] xs = ... | LoopUnrolling.cs:57:30:57:46 | { ..., ... } | -| LoopUnrolling.cs:57:18:57:46 | array creation of type String[] | LoopUnrolling.cs:57:9:57:47 | ... ...; | -| LoopUnrolling.cs:57:30:57:46 | { ..., ... } | LoopUnrolling.cs:57:42:57:44 | "c" | -| LoopUnrolling.cs:57:32:57:34 | "a" | LoopUnrolling.cs:57:18:57:46 | array creation of type String[] | -| LoopUnrolling.cs:57:37:57:39 | "b" | LoopUnrolling.cs:57:32:57:34 | "a" | -| LoopUnrolling.cs:57:42:57:44 | "c" | LoopUnrolling.cs:57:37:57:39 | "b" | +| LoopUnrolling.cs:57:9:57:48 | ... ...; | LoopUnrolling.cs:56:5:65:5 | {...} | +| LoopUnrolling.cs:57:13:57:47 | String[] xs = ... | LoopUnrolling.cs:57:31:57:47 | { ..., ... } | +| LoopUnrolling.cs:57:18:57:47 | 3 | LoopUnrolling.cs:57:9:57:48 | ... ...; | +| LoopUnrolling.cs:57:18:57:47 | array creation of type String[] | LoopUnrolling.cs:57:18:57:47 | 3 | +| LoopUnrolling.cs:57:31:57:47 | { ..., ... } | LoopUnrolling.cs:57:43:57:45 | "c" | +| LoopUnrolling.cs:57:33:57:35 | "a" | LoopUnrolling.cs:57:18:57:47 | array creation of type String[] | +| LoopUnrolling.cs:57:38:57:40 | "b" | LoopUnrolling.cs:57:33:57:35 | "a" | +| LoopUnrolling.cs:57:43:57:45 | "c" | LoopUnrolling.cs:57:38:57:40 | "b" | | LoopUnrolling.cs:58:9:64:9 | [b (line 55): false] foreach (... ... in ...) ... | LoopUnrolling.cs:62:17:62:17 | [b (line 55): false] access to parameter b | | LoopUnrolling.cs:58:9:64:9 | [b (line 55): true] foreach (... ... in ...) ... | LoopUnrolling.cs:63:17:63:36 | [b (line 55): true] call to method WriteLine | -| LoopUnrolling.cs:58:9:64:9 | [unroll (line 58)] foreach (... ... in ...) ... | LoopUnrolling.cs:58:26:58:27 | access to local variable xs | -| LoopUnrolling.cs:58:21:58:21 | String x | LoopUnrolling.cs:58:9:64:9 | [unroll (line 58)] foreach (... ... in ...) ... | -| LoopUnrolling.cs:58:26:58:27 | access to local variable xs | LoopUnrolling.cs:57:13:57:46 | String[] xs = ... | -| LoopUnrolling.cs:59:9:64:9 | [b (line 55): false] {...} | LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | -| LoopUnrolling.cs:59:9:64:9 | [b (line 55): true] {...} | LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | -| LoopUnrolling.cs:59:9:64:9 | {...} | LoopUnrolling.cs:58:21:58:21 | String x | +| LoopUnrolling.cs:58:9:64:9 | [unroll (line 58)] foreach (... ... in ...) ... | LoopUnrolling.cs:58:27:58:28 | access to local variable xs | +| LoopUnrolling.cs:58:22:58:22 | String x | LoopUnrolling.cs:58:9:64:9 | [unroll (line 58)] foreach (... ... in ...) ... | +| LoopUnrolling.cs:58:27:58:28 | access to local variable xs | LoopUnrolling.cs:57:13:57:47 | String[] xs = ... | +| LoopUnrolling.cs:59:9:64:9 | [b (line 55): false] {...} | LoopUnrolling.cs:58:22:58:22 | [b (line 55): false] String x | +| LoopUnrolling.cs:59:9:64:9 | [b (line 55): true] {...} | LoopUnrolling.cs:58:22:58:22 | [b (line 55): true] String x | +| LoopUnrolling.cs:59:9:64:9 | {...} | LoopUnrolling.cs:58:22:58:22 | String x | | LoopUnrolling.cs:60:13:61:37 | [b (line 55): false] if (...) ... | LoopUnrolling.cs:59:9:64:9 | [b (line 55): false] {...} | | LoopUnrolling.cs:60:13:61:37 | [b (line 55): true] if (...) ... | LoopUnrolling.cs:59:9:64:9 | [b (line 55): true] {...} | | LoopUnrolling.cs:60:13:61:37 | if (...) ... | LoopUnrolling.cs:59:9:64:9 | {...} | @@ -5022,7 +6227,7 @@ postDominance | LoopUnrolling.cs:63:17:63:37 | [b (line 55): true] ...; | LoopUnrolling.cs:62:17:62:17 | [b (line 55): true] access to parameter b | | LoopUnrolling.cs:63:35:63:35 | [b (line 55): true] access to local variable x | LoopUnrolling.cs:63:17:63:37 | [b (line 55): true] ...; | | LoopUnrolling.cs:67:10:67:11 | exit M8 | LoopUnrolling.cs:70:13:70:19 | return ...; | -| LoopUnrolling.cs:67:10:67:11 | exit M8 | LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | +| LoopUnrolling.cs:67:10:67:11 | exit M8 | LoopUnrolling.cs:72:9:73:35 | [skip (line 72)] foreach (... ... in ...) ... | | LoopUnrolling.cs:68:5:74:5 | {...} | LoopUnrolling.cs:67:10:67:11 | enter M8 | | LoopUnrolling.cs:69:9:70:19 | if (...) ... | LoopUnrolling.cs:68:5:74:5 | {...} | | LoopUnrolling.cs:69:13:69:23 | !... | LoopUnrolling.cs:69:9:70:19 | if (...) ... | @@ -5030,12 +6235,145 @@ postDominance | LoopUnrolling.cs:69:14:69:23 | call to method Any | LoopUnrolling.cs:69:14:69:17 | access to parameter args | | LoopUnrolling.cs:71:9:71:12 | access to parameter args | LoopUnrolling.cs:71:9:71:21 | ...; | | LoopUnrolling.cs:71:9:71:20 | call to method Clear | LoopUnrolling.cs:71:9:71:12 | access to parameter args | -| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:72:28:72:31 | access to parameter args | -| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:73:13:73:34 | call to method WriteLine | -| LoopUnrolling.cs:72:28:72:31 | access to parameter args | LoopUnrolling.cs:71:9:71:20 | call to method Clear | -| LoopUnrolling.cs:73:13:73:34 | call to method WriteLine | LoopUnrolling.cs:73:31:73:33 | access to local variable arg | -| LoopUnrolling.cs:73:13:73:35 | ...; | LoopUnrolling.cs:72:21:72:23 | String arg | -| LoopUnrolling.cs:73:31:73:33 | access to local variable arg | LoopUnrolling.cs:73:13:73:35 | ...; | +| LoopUnrolling.cs:72:9:73:35 | [skip (line 72)] foreach (... ... in ...) ... | LoopUnrolling.cs:72:29:72:32 | access to parameter args | +| LoopUnrolling.cs:72:29:72:32 | access to parameter args | LoopUnrolling.cs:71:9:71:20 | call to method Clear | +| LoopUnrolling.cs:76:10:76:11 | exit M9 | LoopUnrolling.cs:79:9:82:9 | [skip (line 79)] foreach (... ... in ...) ... | +| LoopUnrolling.cs:77:5:83:5 | {...} | LoopUnrolling.cs:76:10:76:11 | enter M9 | +| LoopUnrolling.cs:78:9:78:34 | ... ...; | LoopUnrolling.cs:77:5:83:5 | {...} | +| LoopUnrolling.cs:78:13:78:33 | String[,] xs = ... | LoopUnrolling.cs:78:18:78:33 | array creation of type String[,] | +| LoopUnrolling.cs:78:18:78:33 | array creation of type String[,] | LoopUnrolling.cs:78:32:78:32 | 0 | +| LoopUnrolling.cs:78:29:78:29 | 2 | LoopUnrolling.cs:78:9:78:34 | ... ...; | +| LoopUnrolling.cs:78:32:78:32 | 0 | LoopUnrolling.cs:78:29:78:29 | 2 | +| LoopUnrolling.cs:79:9:82:9 | [skip (line 79)] foreach (... ... in ...) ... | LoopUnrolling.cs:79:27:79:28 | access to local variable xs | +| LoopUnrolling.cs:79:27:79:28 | access to local variable xs | LoopUnrolling.cs:78:13:78:33 | String[,] xs = ... | +| LoopUnrolling.cs:85:10:85:12 | exit M10 | LoopUnrolling.cs:88:9:91:9 | [skip (line 88)] foreach (... ... in ...) ... | +| LoopUnrolling.cs:86:5:92:5 | {...} | LoopUnrolling.cs:85:10:85:12 | enter M10 | +| LoopUnrolling.cs:87:9:87:34 | ... ...; | LoopUnrolling.cs:86:5:92:5 | {...} | +| LoopUnrolling.cs:87:13:87:33 | String[,] xs = ... | LoopUnrolling.cs:87:18:87:33 | array creation of type String[,] | +| LoopUnrolling.cs:87:18:87:33 | array creation of type String[,] | LoopUnrolling.cs:87:32:87:32 | 2 | +| LoopUnrolling.cs:87:29:87:29 | 0 | LoopUnrolling.cs:87:9:87:34 | ... ...; | +| LoopUnrolling.cs:87:32:87:32 | 2 | LoopUnrolling.cs:87:29:87:29 | 0 | +| LoopUnrolling.cs:88:9:91:9 | [skip (line 88)] foreach (... ... in ...) ... | LoopUnrolling.cs:88:27:88:28 | access to local variable xs | +| LoopUnrolling.cs:88:27:88:28 | access to local variable xs | LoopUnrolling.cs:87:13:87:33 | String[,] xs = ... | +| LoopUnrolling.cs:94:10:94:12 | exit M11 | LoopUnrolling.cs:97:9:100:9 | foreach (... ... in ...) ... | +| LoopUnrolling.cs:95:5:101:5 | {...} | LoopUnrolling.cs:94:10:94:12 | enter M11 | +| LoopUnrolling.cs:96:9:96:34 | ... ...; | LoopUnrolling.cs:95:5:101:5 | {...} | +| LoopUnrolling.cs:96:13:96:33 | String[,] xs = ... | LoopUnrolling.cs:96:18:96:33 | array creation of type String[,] | +| LoopUnrolling.cs:96:18:96:33 | array creation of type String[,] | LoopUnrolling.cs:96:32:96:32 | 2 | +| LoopUnrolling.cs:96:29:96:29 | 2 | LoopUnrolling.cs:96:9:96:34 | ... ...; | +| LoopUnrolling.cs:96:32:96:32 | 2 | LoopUnrolling.cs:96:29:96:29 | 2 | +| LoopUnrolling.cs:97:9:100:9 | [unroll (line 97)] foreach (... ... in ...) ... | LoopUnrolling.cs:97:27:97:28 | access to local variable xs | +| LoopUnrolling.cs:97:9:100:9 | foreach (... ... in ...) ... | LoopUnrolling.cs:99:13:99:32 | call to method WriteLine | +| LoopUnrolling.cs:97:22:97:22 | String x | LoopUnrolling.cs:97:9:100:9 | [unroll (line 97)] foreach (... ... in ...) ... | +| LoopUnrolling.cs:97:27:97:28 | access to local variable xs | LoopUnrolling.cs:96:13:96:33 | String[,] xs = ... | +| LoopUnrolling.cs:98:9:100:9 | {...} | LoopUnrolling.cs:97:22:97:22 | String x | +| LoopUnrolling.cs:99:13:99:32 | call to method WriteLine | LoopUnrolling.cs:99:31:99:31 | access to local variable x | +| LoopUnrolling.cs:99:13:99:33 | ...; | LoopUnrolling.cs:98:9:100:9 | {...} | +| LoopUnrolling.cs:99:31:99:31 | access to local variable x | LoopUnrolling.cs:99:13:99:33 | ...; | +| MultiImplementationA.cs:6:22:6:31 | exit get_P1 | MultiImplementationA.cs:6:22:6:31 | throw ... | +| MultiImplementationA.cs:6:22:6:31 | exit get_P1 | MultiImplementationB.cs:3:22:3:22 | 0 | +| MultiImplementationA.cs:6:22:6:31 | throw ... | MultiImplementationA.cs:6:28:6:31 | null | +| MultiImplementationA.cs:7:21:7:23 | exit get_P2 | MultiImplementationA.cs:7:27:7:37 | throw ...; | +| MultiImplementationA.cs:7:21:7:23 | exit get_P2 | MultiImplementationB.cs:4:27:4:35 | return ...; | +| MultiImplementationA.cs:7:27:7:37 | throw ...; | MultiImplementationA.cs:7:33:7:36 | null | +| MultiImplementationA.cs:7:33:7:36 | null | MultiImplementationA.cs:7:25:7:39 | {...} | +| MultiImplementationA.cs:7:41:7:43 | exit set_P2 | MultiImplementationA.cs:7:47:7:57 | throw ...; | +| MultiImplementationA.cs:7:41:7:43 | exit set_P2 | MultiImplementationB.cs:4:43:4:45 | {...} | +| MultiImplementationA.cs:7:47:7:57 | throw ...; | MultiImplementationA.cs:7:53:7:56 | null | +| MultiImplementationA.cs:7:53:7:56 | null | MultiImplementationA.cs:7:45:7:59 | {...} | +| MultiImplementationA.cs:8:16:8:16 | exit M | MultiImplementationA.cs:8:23:8:32 | throw ... | +| MultiImplementationA.cs:8:16:8:16 | exit M | MultiImplementationB.cs:5:23:5:23 | 2 | +| MultiImplementationA.cs:8:23:8:32 | throw ... | MultiImplementationA.cs:8:29:8:32 | null | +| MultiImplementationA.cs:13:16:13:20 | ... = ... | MultiImplementationA.cs:13:20:13:20 | 0 | +| MultiImplementationA.cs:13:20:13:20 | 0 | MultiImplementationA.cs:13:16:13:16 | this access | +| MultiImplementationA.cs:14:31:14:31 | exit get_Item | MultiImplementationA.cs:14:31:14:31 | access to parameter i | +| MultiImplementationA.cs:14:31:14:31 | exit get_Item | MultiImplementationB.cs:12:31:12:40 | throw ... | +| MultiImplementationA.cs:15:36:15:38 | exit get_Item | MultiImplementationA.cs:15:42:15:50 | return ...; | +| MultiImplementationA.cs:15:36:15:38 | exit get_Item | MultiImplementationB.cs:13:42:13:52 | throw ...; | +| MultiImplementationA.cs:15:42:15:50 | return ...; | MultiImplementationA.cs:15:49:15:49 | access to parameter s | +| MultiImplementationA.cs:15:49:15:49 | access to parameter s | MultiImplementationA.cs:15:40:15:52 | {...} | +| MultiImplementationA.cs:15:54:15:56 | exit set_Item | MultiImplementationA.cs:15:58:15:60 | {...} | +| MultiImplementationA.cs:15:54:15:56 | exit set_Item | MultiImplementationB.cs:13:60:13:62 | {...} | +| MultiImplementationA.cs:16:17:16:18 | exit M1 | MultiImplementationA.cs:18:9:18:22 | M2(...) | +| MultiImplementationA.cs:16:17:16:18 | exit M1 | MultiImplementationB.cs:16:9:16:31 | M2(...) | +| MultiImplementationA.cs:18:9:18:22 | M2(...) | MultiImplementationA.cs:17:5:19:5 | {...} | +| MultiImplementationA.cs:18:9:18:22 | exit M2 | MultiImplementationA.cs:18:21:18:21 | 0 | +| MultiImplementationA.cs:18:21:18:21 | 0 | MultiImplementationA.cs:18:9:18:22 | enter M2 | +| MultiImplementationA.cs:20:12:20:13 | exit C2 | MultiImplementationA.cs:20:24:20:28 | ... = ... | +| MultiImplementationA.cs:20:12:20:13 | exit C2 | MultiImplementationB.cs:18:24:18:34 | throw ...; | +| MultiImplementationA.cs:20:24:20:24 | this access | MultiImplementationA.cs:20:24:20:29 | ...; | +| MultiImplementationA.cs:20:24:20:28 | ... = ... | MultiImplementationA.cs:20:28:20:28 | access to parameter i | +| MultiImplementationA.cs:20:24:20:29 | ...; | MultiImplementationA.cs:20:22:20:31 | {...} | +| MultiImplementationA.cs:20:28:20:28 | access to parameter i | MultiImplementationA.cs:20:24:20:24 | this access | +| MultiImplementationA.cs:21:12:21:13 | exit C2 | MultiImplementationA.cs:21:27:21:29 | {...} | +| MultiImplementationA.cs:21:12:21:13 | exit C2 | MultiImplementationB.cs:19:27:19:29 | {...} | +| MultiImplementationA.cs:21:19:21:22 | call to constructor C2 | MultiImplementationA.cs:21:24:21:24 | 0 | +| MultiImplementationA.cs:22:6:22:7 | exit ~C2 | MultiImplementationA.cs:22:11:22:13 | {...} | +| MultiImplementationA.cs:22:6:22:7 | exit ~C2 | MultiImplementationB.cs:20:13:20:23 | throw ...; | +| MultiImplementationA.cs:23:28:23:35 | exit implicit conversion | MultiImplementationA.cs:23:50:23:53 | null | +| MultiImplementationA.cs:23:28:23:35 | exit implicit conversion | MultiImplementationB.cs:21:50:21:59 | throw ... | +| MultiImplementationA.cs:24:16:24:16 | access to property P | MultiImplementationA.cs:24:34:24:34 | 0 | +| MultiImplementationA.cs:24:32:24:34 | ... = ... | MultiImplementationA.cs:24:16:24:16 | access to property P | +| MultiImplementationA.cs:24:34:24:34 | 0 | MultiImplementationA.cs:24:16:24:16 | this access | +| MultiImplementationA.cs:30:21:30:23 | exit get_P3 | MultiImplementationA.cs:30:28:30:37 | throw ... | +| MultiImplementationA.cs:30:28:30:37 | throw ... | MultiImplementationA.cs:30:34:30:37 | null | +| MultiImplementationA.cs:30:34:30:37 | null | MultiImplementationA.cs:30:21:30:23 | enter get_P3 | +| MultiImplementationA.cs:30:34:30:37 | null | MultiImplementationB.cs:27:21:27:23 | enter get_P3 | +| MultiImplementationA.cs:36:9:36:10 | exit M1 | MultiImplementationA.cs:36:16:36:26 | throw ...; | +| MultiImplementationA.cs:36:9:36:10 | exit M1 | MultiImplementationB.cs:32:17:32:17 | 0 | +| MultiImplementationA.cs:36:16:36:26 | throw ...; | MultiImplementationA.cs:36:22:36:25 | null | +| MultiImplementationA.cs:36:22:36:25 | null | MultiImplementationA.cs:36:14:36:28 | {...} | +| MultiImplementationA.cs:37:9:37:10 | exit M2 | MultiImplementationA.cs:37:16:37:26 | throw ...; | +| MultiImplementationA.cs:37:14:37:28 | {...} | MultiImplementationA.cs:37:9:37:10 | enter M2 | +| MultiImplementationA.cs:37:16:37:26 | throw ...; | MultiImplementationA.cs:37:22:37:25 | null | +| MultiImplementationA.cs:37:22:37:25 | null | MultiImplementationA.cs:37:14:37:28 | {...} | +| MultiImplementationB.cs:3:22:3:22 | exit get_P1 | MultiImplementationA.cs:6:22:6:31 | throw ... | +| MultiImplementationB.cs:3:22:3:22 | exit get_P1 | MultiImplementationB.cs:3:22:3:22 | 0 | +| MultiImplementationB.cs:4:21:4:23 | exit get_P2 | MultiImplementationA.cs:7:27:7:37 | throw ...; | +| MultiImplementationB.cs:4:21:4:23 | exit get_P2 | MultiImplementationB.cs:4:27:4:35 | return ...; | +| MultiImplementationB.cs:4:27:4:35 | return ...; | MultiImplementationB.cs:4:34:4:34 | 1 | +| MultiImplementationB.cs:4:34:4:34 | 1 | MultiImplementationB.cs:4:25:4:37 | {...} | +| MultiImplementationB.cs:4:39:4:41 | exit set_P2 | MultiImplementationA.cs:7:47:7:57 | throw ...; | +| MultiImplementationB.cs:4:39:4:41 | exit set_P2 | MultiImplementationB.cs:4:43:4:45 | {...} | +| MultiImplementationB.cs:5:16:5:16 | exit M | MultiImplementationA.cs:8:23:8:32 | throw ... | +| MultiImplementationB.cs:5:16:5:16 | exit M | MultiImplementationB.cs:5:23:5:23 | 2 | +| MultiImplementationB.cs:11:16:11:20 | ... = ... | MultiImplementationB.cs:11:20:11:20 | 1 | +| MultiImplementationB.cs:11:20:11:20 | 1 | MultiImplementationB.cs:11:16:11:16 | this access | +| MultiImplementationB.cs:12:31:12:40 | exit get_Item | MultiImplementationA.cs:14:31:14:31 | access to parameter i | +| MultiImplementationB.cs:12:31:12:40 | exit get_Item | MultiImplementationB.cs:12:31:12:40 | throw ... | +| MultiImplementationB.cs:12:31:12:40 | throw ... | MultiImplementationB.cs:12:37:12:40 | null | +| MultiImplementationB.cs:13:36:13:38 | exit get_Item | MultiImplementationA.cs:15:42:15:50 | return ...; | +| MultiImplementationB.cs:13:36:13:38 | exit get_Item | MultiImplementationB.cs:13:42:13:52 | throw ...; | +| MultiImplementationB.cs:13:42:13:52 | throw ...; | MultiImplementationB.cs:13:48:13:51 | null | +| MultiImplementationB.cs:13:48:13:51 | null | MultiImplementationB.cs:13:40:13:54 | {...} | +| MultiImplementationB.cs:13:56:13:58 | exit set_Item | MultiImplementationA.cs:15:58:15:60 | {...} | +| MultiImplementationB.cs:13:56:13:58 | exit set_Item | MultiImplementationB.cs:13:60:13:62 | {...} | +| MultiImplementationB.cs:14:17:14:18 | exit M1 | MultiImplementationA.cs:18:9:18:22 | M2(...) | +| MultiImplementationB.cs:14:17:14:18 | exit M1 | MultiImplementationB.cs:16:9:16:31 | M2(...) | +| MultiImplementationB.cs:16:9:16:31 | M2(...) | MultiImplementationB.cs:15:5:17:5 | {...} | +| MultiImplementationB.cs:16:9:16:31 | exit M2 | MultiImplementationB.cs:16:21:16:30 | throw ... | +| MultiImplementationB.cs:16:21:16:30 | throw ... | MultiImplementationB.cs:16:27:16:30 | null | +| MultiImplementationB.cs:16:27:16:30 | null | MultiImplementationB.cs:16:9:16:31 | enter M2 | +| MultiImplementationB.cs:18:12:18:13 | exit C2 | MultiImplementationA.cs:20:24:20:28 | ... = ... | +| MultiImplementationB.cs:18:12:18:13 | exit C2 | MultiImplementationB.cs:18:24:18:34 | throw ...; | +| MultiImplementationB.cs:18:24:18:34 | throw ...; | MultiImplementationB.cs:18:30:18:33 | null | +| MultiImplementationB.cs:18:30:18:33 | null | MultiImplementationB.cs:18:22:18:36 | {...} | +| MultiImplementationB.cs:19:12:19:13 | exit C2 | MultiImplementationA.cs:21:27:21:29 | {...} | +| MultiImplementationB.cs:19:12:19:13 | exit C2 | MultiImplementationB.cs:19:27:19:29 | {...} | +| MultiImplementationB.cs:19:19:19:22 | call to constructor C2 | MultiImplementationB.cs:19:24:19:24 | 1 | +| MultiImplementationB.cs:20:6:20:7 | exit ~C2 | MultiImplementationA.cs:22:11:22:13 | {...} | +| MultiImplementationB.cs:20:6:20:7 | exit ~C2 | MultiImplementationB.cs:20:13:20:23 | throw ...; | +| MultiImplementationB.cs:20:13:20:23 | throw ...; | MultiImplementationB.cs:20:19:20:22 | null | +| MultiImplementationB.cs:20:19:20:22 | null | MultiImplementationB.cs:20:11:20:25 | {...} | +| MultiImplementationB.cs:21:28:21:35 | exit implicit conversion | MultiImplementationA.cs:23:50:23:53 | null | +| MultiImplementationB.cs:21:28:21:35 | exit implicit conversion | MultiImplementationB.cs:21:50:21:59 | throw ... | +| MultiImplementationB.cs:21:50:21:59 | throw ... | MultiImplementationB.cs:21:56:21:59 | null | +| MultiImplementationB.cs:22:16:22:16 | access to property P | MultiImplementationB.cs:22:34:22:34 | 1 | +| MultiImplementationB.cs:22:32:22:34 | ... = ... | MultiImplementationB.cs:22:16:22:16 | access to property P | +| MultiImplementationB.cs:22:34:22:34 | 1 | MultiImplementationB.cs:22:16:22:16 | this access | +| MultiImplementationB.cs:27:21:27:23 | exit get_P3 | MultiImplementationA.cs:30:28:30:37 | throw ... | +| MultiImplementationB.cs:32:9:32:10 | exit M1 | MultiImplementationA.cs:36:16:36:26 | throw ...; | +| MultiImplementationB.cs:32:9:32:10 | exit M1 | MultiImplementationB.cs:32:17:32:17 | 0 | | NullCoalescing.cs:3:9:3:10 | exit M1 | NullCoalescing.cs:3:23:3:23 | access to parameter i | | NullCoalescing.cs:3:9:3:10 | exit M1 | NullCoalescing.cs:3:28:3:28 | 0 | | NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:23:3:28 | ... ?? ... | @@ -5241,8 +6579,8 @@ postDominance | Switch.cs:25:35:25:35 | access to local variable s | Switch.cs:25:17:25:37 | ...; | | Switch.cs:26:17:26:23 | return ...; | Switch.cs:25:17:25:36 | call to method WriteLine | | Switch.cs:27:18:27:25 | Double d | Switch.cs:27:13:27:39 | case ...: | -| Switch.cs:28:17:28:21 | Label: | Switch.cs:31:17:31:27 | goto ...; | -| Switch.cs:29:17:29:23 | return ...; | Switch.cs:28:17:28:21 | Label: | +| Switch.cs:28:13:28:17 | Label: | Switch.cs:31:17:31:27 | goto ...; | +| Switch.cs:29:17:29:23 | return ...; | Switch.cs:28:13:28:17 | Label: | | Switch.cs:30:13:30:20 | default: | Switch.cs:19:17:19:29 | goto default; | | Switch.cs:31:17:31:27 | goto ...; | Switch.cs:30:13:30:20 | default: | | Switch.cs:35:10:35:11 | exit M3 | Switch.cs:37:17:37:23 | call to method Throw | @@ -5261,85 +6599,85 @@ postDominance | Switch.cs:50:18:50:21 | access to type Boolean | Switch.cs:50:13:50:39 | case ...: | | Switch.cs:50:30:50:38 | ... != ... | Switch.cs:50:35:50:38 | null | | Switch.cs:50:35:50:38 | null | Switch.cs:50:30:50:30 | access to parameter o | -| Switch.cs:55:10:55:11 | exit M5 | Switch.cs:62:15:62:20 | break; | +| Switch.cs:55:10:55:11 | exit M5 | Switch.cs:62:17:62:22 | break; | | Switch.cs:56:5:64:5 | {...} | Switch.cs:55:10:55:11 | enter M5 | | Switch.cs:57:9:63:9 | switch (...) {...} | Switch.cs:56:5:64:5 | {...} | | Switch.cs:57:17:57:17 | 1 | Switch.cs:57:9:63:9 | switch (...) {...} | | Switch.cs:57:17:57:21 | ... + ... | Switch.cs:57:21:57:21 | 2 | | Switch.cs:57:21:57:21 | 2 | Switch.cs:57:17:57:17 | 1 | -| Switch.cs:59:13:59:20 | case ...: | Switch.cs:57:17:57:21 | ... + ... | -| Switch.cs:59:18:59:18 | 2 | Switch.cs:59:13:59:20 | case ...: | -| Switch.cs:61:13:61:20 | case ...: | Switch.cs:59:18:59:18 | 2 | -| Switch.cs:61:18:61:18 | 3 | Switch.cs:61:13:61:20 | case ...: | -| Switch.cs:62:15:62:20 | break; | Switch.cs:61:18:61:18 | 3 | +| Switch.cs:59:13:59:19 | case ...: | Switch.cs:57:17:57:21 | ... + ... | +| Switch.cs:59:18:59:18 | 2 | Switch.cs:59:13:59:19 | case ...: | +| Switch.cs:61:13:61:19 | case ...: | Switch.cs:59:18:59:18 | 2 | +| Switch.cs:61:18:61:18 | 3 | Switch.cs:61:13:61:19 | case ...: | +| Switch.cs:62:17:62:22 | break; | Switch.cs:61:18:61:18 | 3 | | Switch.cs:66:10:66:11 | exit M6 | Switch.cs:72:18:72:19 | "" | -| Switch.cs:66:10:66:11 | exit M6 | Switch.cs:73:15:73:20 | break; | +| Switch.cs:66:10:66:11 | exit M6 | Switch.cs:73:17:73:22 | break; | | Switch.cs:67:5:75:5 | {...} | Switch.cs:66:10:66:11 | enter M6 | | Switch.cs:68:9:74:9 | switch (...) {...} | Switch.cs:67:5:75:5 | {...} | | Switch.cs:68:17:68:25 | (...) ... | Switch.cs:68:25:68:25 | access to parameter s | | Switch.cs:68:25:68:25 | access to parameter s | Switch.cs:68:9:74:9 | switch (...) {...} | -| Switch.cs:70:13:70:24 | case ...: | Switch.cs:68:17:68:25 | (...) ... | -| Switch.cs:70:18:70:20 | access to type Int32 | Switch.cs:70:13:70:24 | case ...: | -| Switch.cs:72:13:72:21 | case ...: | Switch.cs:70:18:70:20 | access to type Int32 | -| Switch.cs:72:18:72:19 | "" | Switch.cs:72:13:72:21 | case ...: | -| Switch.cs:77:10:77:11 | exit M7 | Switch.cs:82:15:82:26 | return ...; | -| Switch.cs:77:10:77:11 | exit M7 | Switch.cs:86:15:86:26 | return ...; | +| Switch.cs:70:13:70:23 | case ...: | Switch.cs:68:17:68:25 | (...) ... | +| Switch.cs:70:18:70:20 | access to type Int32 | Switch.cs:70:13:70:23 | case ...: | +| Switch.cs:72:13:72:20 | case ...: | Switch.cs:70:18:70:20 | access to type Int32 | +| Switch.cs:72:18:72:19 | "" | Switch.cs:72:13:72:20 | case ...: | +| Switch.cs:77:10:77:11 | exit M7 | Switch.cs:82:17:82:28 | return ...; | +| Switch.cs:77:10:77:11 | exit M7 | Switch.cs:86:17:86:28 | return ...; | | Switch.cs:77:10:77:11 | exit M7 | Switch.cs:88:9:88:21 | return ...; | | Switch.cs:78:5:89:5 | {...} | Switch.cs:77:10:77:11 | enter M7 | | Switch.cs:79:9:87:9 | switch (...) {...} | Switch.cs:78:5:89:5 | {...} | | Switch.cs:79:17:79:17 | access to parameter i | Switch.cs:79:9:87:9 | switch (...) {...} | -| Switch.cs:81:13:81:20 | case ...: | Switch.cs:79:17:79:17 | access to parameter i | -| Switch.cs:81:18:81:18 | 1 | Switch.cs:81:13:81:20 | case ...: | -| Switch.cs:82:15:82:26 | return ...; | Switch.cs:82:22:82:25 | true | -| Switch.cs:83:18:83:18 | 2 | Switch.cs:83:13:83:20 | case ...: | -| Switch.cs:84:19:84:19 | access to parameter j | Switch.cs:84:15:85:22 | if (...) ... | -| Switch.cs:84:19:84:23 | ... > ... | Switch.cs:84:23:84:23 | 2 | -| Switch.cs:84:23:84:23 | 2 | Switch.cs:84:19:84:19 | access to parameter j | -| Switch.cs:86:15:86:26 | return ...; | Switch.cs:86:22:86:25 | true | +| Switch.cs:81:13:81:19 | case ...: | Switch.cs:79:17:79:17 | access to parameter i | +| Switch.cs:81:18:81:18 | 1 | Switch.cs:81:13:81:19 | case ...: | +| Switch.cs:82:17:82:28 | return ...; | Switch.cs:82:24:82:27 | true | +| Switch.cs:83:18:83:18 | 2 | Switch.cs:83:13:83:19 | case ...: | +| Switch.cs:84:21:84:21 | access to parameter j | Switch.cs:84:17:85:26 | if (...) ... | +| Switch.cs:84:21:84:25 | ... > ... | Switch.cs:84:25:84:25 | 2 | +| Switch.cs:84:25:84:25 | 2 | Switch.cs:84:21:84:21 | access to parameter j | +| Switch.cs:86:17:86:28 | return ...; | Switch.cs:86:24:86:27 | true | | Switch.cs:88:9:88:21 | return ...; | Switch.cs:88:16:88:20 | false | -| Switch.cs:88:16:88:20 | false | Switch.cs:85:17:85:22 | break; | -| Switch.cs:91:10:91:11 | exit M8 | Switch.cs:96:15:96:26 | return ...; | +| Switch.cs:88:16:88:20 | false | Switch.cs:85:21:85:26 | break; | +| Switch.cs:91:10:91:11 | exit M8 | Switch.cs:96:17:96:28 | return ...; | | Switch.cs:91:10:91:11 | exit M8 | Switch.cs:98:9:98:21 | return ...; | | Switch.cs:92:5:99:5 | {...} | Switch.cs:91:10:91:11 | enter M8 | | Switch.cs:93:9:97:9 | switch (...) {...} | Switch.cs:92:5:99:5 | {...} | | Switch.cs:93:17:93:17 | access to parameter o | Switch.cs:93:9:97:9 | switch (...) {...} | -| Switch.cs:95:13:95:24 | case ...: | Switch.cs:93:17:93:17 | access to parameter o | -| Switch.cs:95:18:95:20 | access to type Int32 | Switch.cs:95:13:95:24 | case ...: | -| Switch.cs:96:15:96:26 | return ...; | Switch.cs:96:22:96:25 | true | +| Switch.cs:95:13:95:23 | case ...: | Switch.cs:93:17:93:17 | access to parameter o | +| Switch.cs:95:18:95:20 | access to type Int32 | Switch.cs:95:13:95:23 | case ...: | +| Switch.cs:96:17:96:28 | return ...; | Switch.cs:96:24:96:27 | true | | Switch.cs:98:9:98:21 | return ...; | Switch.cs:98:16:98:20 | false | -| Switch.cs:101:9:101:10 | exit M9 | Switch.cs:105:22:105:30 | return ...; | -| Switch.cs:101:9:101:10 | exit M9 | Switch.cs:106:22:106:30 | return ...; | +| Switch.cs:101:9:101:10 | exit M9 | Switch.cs:105:21:105:29 | return ...; | +| Switch.cs:101:9:101:10 | exit M9 | Switch.cs:106:21:106:29 | return ...; | | Switch.cs:101:9:101:10 | exit M9 | Switch.cs:108:9:108:18 | return ...; | | Switch.cs:102:5:109:5 | {...} | Switch.cs:101:9:101:10 | enter M9 | | Switch.cs:103:9:107:9 | switch (...) {...} | Switch.cs:102:5:109:5 | {...} | | Switch.cs:103:17:103:17 | access to parameter s | Switch.cs:103:9:107:9 | switch (...) {...} | -| Switch.cs:105:13:105:20 | case ...: | Switch.cs:103:17:103:17 | access to parameter s | -| Switch.cs:105:13:105:20 | case ...: | Switch.cs:103:19:103:25 | access to property Length | -| Switch.cs:105:18:105:18 | 0 | Switch.cs:105:13:105:20 | case ...: | -| Switch.cs:105:22:105:30 | return ...; | Switch.cs:105:29:105:29 | 0 | -| Switch.cs:106:18:106:18 | 1 | Switch.cs:106:13:106:20 | case ...: | -| Switch.cs:106:22:106:30 | return ...; | Switch.cs:106:29:106:29 | 1 | +| Switch.cs:105:13:105:19 | case ...: | Switch.cs:103:17:103:17 | access to parameter s | +| Switch.cs:105:13:105:19 | case ...: | Switch.cs:103:19:103:25 | access to property Length | +| Switch.cs:105:18:105:18 | 0 | Switch.cs:105:13:105:19 | case ...: | +| Switch.cs:105:21:105:29 | return ...; | Switch.cs:105:28:105:28 | 0 | +| Switch.cs:106:18:106:18 | 1 | Switch.cs:106:13:106:19 | case ...: | +| Switch.cs:106:21:106:29 | return ...; | Switch.cs:106:28:106:28 | 1 | | Switch.cs:108:9:108:18 | return ...; | Switch.cs:108:16:108:17 | -... | | Switch.cs:108:16:108:17 | -... | Switch.cs:108:17:108:17 | 1 | | Switch.cs:111:17:111:21 | exit Throw | Switch.cs:111:28:111:48 | throw ... | | Switch.cs:111:28:111:48 | throw ... | Switch.cs:111:34:111:48 | object creation of type Exception | | Switch.cs:111:34:111:48 | object creation of type Exception | Switch.cs:111:17:111:21 | enter Throw | -| Switch.cs:113:9:113:11 | exit M10 | Switch.cs:117:36:117:44 | return ...; | -| Switch.cs:113:9:113:11 | exit M10 | Switch.cs:118:35:118:43 | return ...; | +| Switch.cs:113:9:113:11 | exit M10 | Switch.cs:117:37:117:45 | return ...; | +| Switch.cs:113:9:113:11 | exit M10 | Switch.cs:118:36:118:44 | return ...; | | Switch.cs:113:9:113:11 | exit M10 | Switch.cs:120:9:120:18 | return ...; | | Switch.cs:114:5:121:5 | {...} | Switch.cs:113:9:113:11 | enter M10 | | Switch.cs:115:9:119:9 | switch (...) {...} | Switch.cs:114:5:121:5 | {...} | | Switch.cs:115:17:115:17 | access to parameter s | Switch.cs:115:9:119:9 | switch (...) {...} | | Switch.cs:115:17:115:24 | access to property Length | Switch.cs:115:17:115:17 | access to parameter s | -| Switch.cs:117:13:117:34 | case ...: | Switch.cs:115:17:115:24 | access to property Length | -| Switch.cs:117:18:117:18 | 3 | Switch.cs:117:13:117:34 | case ...: | -| Switch.cs:117:25:117:32 | ... == ... | Switch.cs:117:28:117:32 | "foo" | -| Switch.cs:117:28:117:32 | "foo" | Switch.cs:117:25:117:25 | access to parameter s | -| Switch.cs:117:36:117:44 | return ...; | Switch.cs:117:43:117:43 | 1 | -| Switch.cs:118:18:118:18 | 2 | Switch.cs:118:13:118:33 | case ...: | -| Switch.cs:118:25:118:31 | ... == ... | Switch.cs:118:28:118:31 | "fu" | -| Switch.cs:118:28:118:31 | "fu" | Switch.cs:118:25:118:25 | access to parameter s | -| Switch.cs:118:35:118:43 | return ...; | Switch.cs:118:42:118:42 | 2 | +| Switch.cs:117:13:117:35 | case ...: | Switch.cs:115:17:115:24 | access to property Length | +| Switch.cs:117:18:117:18 | 3 | Switch.cs:117:13:117:35 | case ...: | +| Switch.cs:117:25:117:34 | ... == ... | Switch.cs:117:30:117:34 | "foo" | +| Switch.cs:117:30:117:34 | "foo" | Switch.cs:117:25:117:25 | access to parameter s | +| Switch.cs:117:37:117:45 | return ...; | Switch.cs:117:44:117:44 | 1 | +| Switch.cs:118:18:118:18 | 2 | Switch.cs:118:13:118:34 | case ...: | +| Switch.cs:118:25:118:33 | ... == ... | Switch.cs:118:30:118:33 | "fu" | +| Switch.cs:118:30:118:33 | "fu" | Switch.cs:118:25:118:25 | access to parameter s | +| Switch.cs:118:36:118:44 | return ...; | Switch.cs:118:43:118:43 | 2 | | Switch.cs:120:9:120:18 | return ...; | Switch.cs:120:16:120:17 | -... | | Switch.cs:120:16:120:17 | -... | Switch.cs:120:17:120:17 | 1 | | Switch.cs:123:10:123:12 | exit M11 | Switch.cs:125:34:125:34 | access to local variable b | @@ -5392,6 +6730,28 @@ postDominance | Switch.cs:149:30:149:30 | 1 | Switch.cs:149:13:149:20 | default: | | Switch.cs:150:18:150:18 | 2 | Switch.cs:150:13:150:19 | case ...: | | Switch.cs:150:21:150:29 | return ...; | Switch.cs:150:28:150:28 | 2 | +| Switch.cs:154:10:154:12 | exit M15 | Switch.cs:156:41:156:45 | false | +| Switch.cs:154:10:154:12 | exit M15 | Switch.cs:158:13:158:48 | call to method WriteLine | +| Switch.cs:154:10:154:12 | exit M15 | Switch.cs:160:13:160:48 | call to method WriteLine | +| Switch.cs:155:5:161:5 | {...} | Switch.cs:154:10:154:12 | enter M15 | +| Switch.cs:156:9:156:55 | ... ...; | Switch.cs:155:5:161:5 | {...} | +| Switch.cs:156:13:156:54 | String s = ... | Switch.cs:156:36:156:38 | "a" | +| Switch.cs:156:13:156:54 | String s = ... | Switch.cs:156:50:156:52 | "b" | +| Switch.cs:156:17:156:17 | access to parameter b | Switch.cs:156:17:156:54 | ... switch { ... } | +| Switch.cs:156:17:156:54 | ... switch { ... } | Switch.cs:156:9:156:55 | ... ...; | +| Switch.cs:156:28:156:31 | true | Switch.cs:156:28:156:38 | ... => ... | +| Switch.cs:156:28:156:38 | ... => ... | Switch.cs:156:17:156:17 | access to parameter b | +| Switch.cs:156:41:156:45 | false | Switch.cs:156:41:156:52 | ... => ... | +| Switch.cs:157:9:160:49 | if (...) ... | Switch.cs:156:13:156:54 | String s = ... | +| Switch.cs:157:13:157:13 | access to parameter b | Switch.cs:157:9:160:49 | if (...) ... | +| Switch.cs:158:13:158:48 | call to method WriteLine | Switch.cs:158:38:158:47 | $"..." | +| Switch.cs:158:38:158:47 | $"..." | Switch.cs:158:45:158:45 | access to local variable s | +| Switch.cs:158:40:158:43 | "a = " | Switch.cs:158:13:158:49 | ...; | +| Switch.cs:158:45:158:45 | access to local variable s | Switch.cs:158:40:158:43 | "a = " | +| Switch.cs:160:13:160:48 | call to method WriteLine | Switch.cs:160:38:160:47 | $"..." | +| Switch.cs:160:38:160:47 | $"..." | Switch.cs:160:45:160:45 | access to local variable s | +| Switch.cs:160:40:160:43 | "b = " | Switch.cs:160:13:160:49 | ...; | +| Switch.cs:160:45:160:45 | access to local variable s | Switch.cs:160:40:160:43 | "b = " | | TypeAccesses.cs:3:10:3:10 | exit M | TypeAccesses.cs:8:13:8:27 | Type t = ... | | TypeAccesses.cs:4:5:9:5 | {...} | TypeAccesses.cs:3:10:3:10 | enter M | | TypeAccesses.cs:5:9:5:26 | ... ...; | TypeAccesses.cs:4:5:9:5 | {...} | @@ -5413,12 +6773,14 @@ postDominance | VarDecls.cs:5:18:5:19 | exit M1 | VarDecls.cs:9:13:9:29 | return ...; | | VarDecls.cs:6:5:11:5 | {...} | VarDecls.cs:5:18:5:19 | enter M1 | | VarDecls.cs:7:9:10:9 | fixed(...) { ... } | VarDecls.cs:6:5:11:5 | {...} | -| VarDecls.cs:7:22:7:36 | Char* c1 = ... | VarDecls.cs:7:27:7:36 | access to array element | +| VarDecls.cs:7:22:7:36 | Char* c1 = ... | VarDecls.cs:7:27:7:36 | (...) ... | | VarDecls.cs:7:27:7:33 | access to parameter strings | VarDecls.cs:7:9:10:9 | fixed(...) { ... } | +| VarDecls.cs:7:27:7:36 | (...) ... | VarDecls.cs:7:27:7:36 | access to array element | | VarDecls.cs:7:27:7:36 | access to array element | VarDecls.cs:7:35:7:35 | 0 | | VarDecls.cs:7:35:7:35 | 0 | VarDecls.cs:7:27:7:33 | access to parameter strings | -| VarDecls.cs:7:39:7:53 | Char* c2 = ... | VarDecls.cs:7:44:7:53 | access to array element | +| VarDecls.cs:7:39:7:53 | Char* c2 = ... | VarDecls.cs:7:44:7:53 | (...) ... | | VarDecls.cs:7:44:7:50 | access to parameter strings | VarDecls.cs:7:22:7:36 | Char* c1 = ... | +| VarDecls.cs:7:44:7:53 | (...) ... | VarDecls.cs:7:44:7:53 | access to array element | | VarDecls.cs:7:44:7:53 | access to array element | VarDecls.cs:7:52:7:52 | 1 | | VarDecls.cs:7:52:7:52 | 1 | VarDecls.cs:7:44:7:50 | access to parameter strings | | VarDecls.cs:8:9:10:9 | {...} | VarDecls.cs:7:39:7:53 | Char* c2 = ... | @@ -6059,6 +7421,465 @@ blockDominance | ArrayCreation.cs:5:12:5:13 | enter M2 | ArrayCreation.cs:5:12:5:13 | enter M2 | | ArrayCreation.cs:7:11:7:12 | enter M3 | ArrayCreation.cs:7:11:7:12 | enter M3 | | ArrayCreation.cs:9:12:9:13 | enter M4 | ArrayCreation.cs:9:12:9:13 | enter M4 | +| Assert.cs:7:10:7:11 | enter M1 | Assert.cs:7:10:7:11 | enter M1 | +| Assert.cs:7:10:7:11 | enter M1 | Assert.cs:7:10:7:11 | exit M1 | +| Assert.cs:7:10:7:11 | enter M1 | Assert.cs:9:16:9:32 | String s = ... | +| Assert.cs:7:10:7:11 | enter M1 | Assert.cs:9:24:9:27 | null | +| Assert.cs:7:10:7:11 | enter M1 | Assert.cs:9:31:9:32 | "" | +| Assert.cs:7:10:7:11 | enter M1 | Assert.cs:10:9:10:31 | [assertion failure] call to method Assert | +| Assert.cs:7:10:7:11 | enter M1 | Assert.cs:10:9:10:31 | [assertion success] call to method Assert | +| Assert.cs:7:10:7:11 | exit M1 | Assert.cs:7:10:7:11 | exit M1 | +| Assert.cs:9:16:9:32 | String s = ... | Assert.cs:7:10:7:11 | exit M1 | +| Assert.cs:9:16:9:32 | String s = ... | Assert.cs:9:16:9:32 | String s = ... | +| Assert.cs:9:16:9:32 | String s = ... | Assert.cs:10:9:10:31 | [assertion failure] call to method Assert | +| Assert.cs:9:16:9:32 | String s = ... | Assert.cs:10:9:10:31 | [assertion success] call to method Assert | +| Assert.cs:9:24:9:27 | null | Assert.cs:9:24:9:27 | null | +| Assert.cs:9:31:9:32 | "" | Assert.cs:9:31:9:32 | "" | +| Assert.cs:10:9:10:31 | [assertion failure] call to method Assert | Assert.cs:10:9:10:31 | [assertion failure] call to method Assert | +| Assert.cs:10:9:10:31 | [assertion success] call to method Assert | Assert.cs:10:9:10:31 | [assertion success] call to method Assert | +| Assert.cs:14:10:14:11 | enter M2 | Assert.cs:14:10:14:11 | enter M2 | +| Assert.cs:14:10:14:11 | enter M2 | Assert.cs:14:10:14:11 | exit M2 | +| Assert.cs:14:10:14:11 | enter M2 | Assert.cs:16:16:16:32 | String s = ... | +| Assert.cs:14:10:14:11 | enter M2 | Assert.cs:16:24:16:27 | null | +| Assert.cs:14:10:14:11 | enter M2 | Assert.cs:16:31:16:32 | "" | +| Assert.cs:14:10:14:11 | enter M2 | Assert.cs:17:9:17:24 | [assertion failure] call to method IsNull | +| Assert.cs:14:10:14:11 | enter M2 | Assert.cs:17:9:17:24 | [assertion success] call to method IsNull | +| Assert.cs:14:10:14:11 | exit M2 | Assert.cs:14:10:14:11 | exit M2 | +| Assert.cs:16:16:16:32 | String s = ... | Assert.cs:14:10:14:11 | exit M2 | +| Assert.cs:16:16:16:32 | String s = ... | Assert.cs:16:16:16:32 | String s = ... | +| Assert.cs:16:16:16:32 | String s = ... | Assert.cs:17:9:17:24 | [assertion failure] call to method IsNull | +| Assert.cs:16:16:16:32 | String s = ... | Assert.cs:17:9:17:24 | [assertion success] call to method IsNull | +| Assert.cs:16:24:16:27 | null | Assert.cs:16:24:16:27 | null | +| Assert.cs:16:31:16:32 | "" | Assert.cs:16:31:16:32 | "" | +| Assert.cs:17:9:17:24 | [assertion failure] call to method IsNull | Assert.cs:17:9:17:24 | [assertion failure] call to method IsNull | +| Assert.cs:17:9:17:24 | [assertion success] call to method IsNull | Assert.cs:17:9:17:24 | [assertion success] call to method IsNull | +| Assert.cs:21:10:21:11 | enter M3 | Assert.cs:21:10:21:11 | enter M3 | +| Assert.cs:21:10:21:11 | enter M3 | Assert.cs:21:10:21:11 | exit M3 | +| Assert.cs:21:10:21:11 | enter M3 | Assert.cs:23:16:23:32 | String s = ... | +| Assert.cs:21:10:21:11 | enter M3 | Assert.cs:23:24:23:27 | null | +| Assert.cs:21:10:21:11 | enter M3 | Assert.cs:23:31:23:32 | "" | +| Assert.cs:21:10:21:11 | enter M3 | Assert.cs:24:9:24:27 | [assertion failure] call to method IsNotNull | +| Assert.cs:21:10:21:11 | enter M3 | Assert.cs:24:9:24:27 | [assertion success] call to method IsNotNull | +| Assert.cs:21:10:21:11 | exit M3 | Assert.cs:21:10:21:11 | exit M3 | +| Assert.cs:23:16:23:32 | String s = ... | Assert.cs:21:10:21:11 | exit M3 | +| Assert.cs:23:16:23:32 | String s = ... | Assert.cs:23:16:23:32 | String s = ... | +| Assert.cs:23:16:23:32 | String s = ... | Assert.cs:24:9:24:27 | [assertion failure] call to method IsNotNull | +| Assert.cs:23:16:23:32 | String s = ... | Assert.cs:24:9:24:27 | [assertion success] call to method IsNotNull | +| Assert.cs:23:24:23:27 | null | Assert.cs:23:24:23:27 | null | +| Assert.cs:23:31:23:32 | "" | Assert.cs:23:31:23:32 | "" | +| Assert.cs:24:9:24:27 | [assertion failure] call to method IsNotNull | Assert.cs:24:9:24:27 | [assertion failure] call to method IsNotNull | +| Assert.cs:24:9:24:27 | [assertion success] call to method IsNotNull | Assert.cs:24:9:24:27 | [assertion success] call to method IsNotNull | +| Assert.cs:28:10:28:11 | enter M4 | Assert.cs:28:10:28:11 | enter M4 | +| Assert.cs:28:10:28:11 | enter M4 | Assert.cs:28:10:28:11 | exit M4 | +| Assert.cs:28:10:28:11 | enter M4 | Assert.cs:30:16:30:32 | String s = ... | +| Assert.cs:28:10:28:11 | enter M4 | Assert.cs:30:24:30:27 | null | +| Assert.cs:28:10:28:11 | enter M4 | Assert.cs:30:31:30:32 | "" | +| Assert.cs:28:10:28:11 | enter M4 | Assert.cs:31:9:31:32 | [assertion failure] call to method IsTrue | +| Assert.cs:28:10:28:11 | enter M4 | Assert.cs:31:9:31:32 | [assertion success] call to method IsTrue | +| Assert.cs:28:10:28:11 | exit M4 | Assert.cs:28:10:28:11 | exit M4 | +| Assert.cs:30:16:30:32 | String s = ... | Assert.cs:28:10:28:11 | exit M4 | +| Assert.cs:30:16:30:32 | String s = ... | Assert.cs:30:16:30:32 | String s = ... | +| Assert.cs:30:16:30:32 | String s = ... | Assert.cs:31:9:31:32 | [assertion failure] call to method IsTrue | +| Assert.cs:30:16:30:32 | String s = ... | Assert.cs:31:9:31:32 | [assertion success] call to method IsTrue | +| Assert.cs:30:24:30:27 | null | Assert.cs:30:24:30:27 | null | +| Assert.cs:30:31:30:32 | "" | Assert.cs:30:31:30:32 | "" | +| Assert.cs:31:9:31:32 | [assertion failure] call to method IsTrue | Assert.cs:31:9:31:32 | [assertion failure] call to method IsTrue | +| Assert.cs:31:9:31:32 | [assertion success] call to method IsTrue | Assert.cs:31:9:31:32 | [assertion success] call to method IsTrue | +| Assert.cs:35:10:35:11 | enter M5 | Assert.cs:35:10:35:11 | enter M5 | +| Assert.cs:35:10:35:11 | enter M5 | Assert.cs:35:10:35:11 | exit M5 | +| Assert.cs:35:10:35:11 | enter M5 | Assert.cs:37:16:37:32 | String s = ... | +| Assert.cs:35:10:35:11 | enter M5 | Assert.cs:37:24:37:27 | null | +| Assert.cs:35:10:35:11 | enter M5 | Assert.cs:37:31:37:32 | "" | +| Assert.cs:35:10:35:11 | enter M5 | Assert.cs:38:9:38:32 | [assertion failure] call to method IsTrue | +| Assert.cs:35:10:35:11 | enter M5 | Assert.cs:38:9:38:32 | [assertion success] call to method IsTrue | +| Assert.cs:35:10:35:11 | exit M5 | Assert.cs:35:10:35:11 | exit M5 | +| Assert.cs:37:16:37:32 | String s = ... | Assert.cs:35:10:35:11 | exit M5 | +| Assert.cs:37:16:37:32 | String s = ... | Assert.cs:37:16:37:32 | String s = ... | +| Assert.cs:37:16:37:32 | String s = ... | Assert.cs:38:9:38:32 | [assertion failure] call to method IsTrue | +| Assert.cs:37:16:37:32 | String s = ... | Assert.cs:38:9:38:32 | [assertion success] call to method IsTrue | +| Assert.cs:37:24:37:27 | null | Assert.cs:37:24:37:27 | null | +| Assert.cs:37:31:37:32 | "" | Assert.cs:37:31:37:32 | "" | +| Assert.cs:38:9:38:32 | [assertion failure] call to method IsTrue | Assert.cs:38:9:38:32 | [assertion failure] call to method IsTrue | +| Assert.cs:38:9:38:32 | [assertion success] call to method IsTrue | Assert.cs:38:9:38:32 | [assertion success] call to method IsTrue | +| Assert.cs:42:10:42:11 | enter M6 | Assert.cs:42:10:42:11 | enter M6 | +| Assert.cs:42:10:42:11 | enter M6 | Assert.cs:42:10:42:11 | exit M6 | +| Assert.cs:42:10:42:11 | enter M6 | Assert.cs:44:16:44:32 | String s = ... | +| Assert.cs:42:10:42:11 | enter M6 | Assert.cs:44:24:44:27 | null | +| Assert.cs:42:10:42:11 | enter M6 | Assert.cs:44:31:44:32 | "" | +| Assert.cs:42:10:42:11 | enter M6 | Assert.cs:45:9:45:33 | [assertion failure] call to method IsFalse | +| Assert.cs:42:10:42:11 | enter M6 | Assert.cs:45:9:45:33 | [assertion success] call to method IsFalse | +| Assert.cs:42:10:42:11 | exit M6 | Assert.cs:42:10:42:11 | exit M6 | +| Assert.cs:44:16:44:32 | String s = ... | Assert.cs:42:10:42:11 | exit M6 | +| Assert.cs:44:16:44:32 | String s = ... | Assert.cs:44:16:44:32 | String s = ... | +| Assert.cs:44:16:44:32 | String s = ... | Assert.cs:45:9:45:33 | [assertion failure] call to method IsFalse | +| Assert.cs:44:16:44:32 | String s = ... | Assert.cs:45:9:45:33 | [assertion success] call to method IsFalse | +| Assert.cs:44:24:44:27 | null | Assert.cs:44:24:44:27 | null | +| Assert.cs:44:31:44:32 | "" | Assert.cs:44:31:44:32 | "" | +| Assert.cs:45:9:45:33 | [assertion failure] call to method IsFalse | Assert.cs:45:9:45:33 | [assertion failure] call to method IsFalse | +| Assert.cs:45:9:45:33 | [assertion success] call to method IsFalse | Assert.cs:45:9:45:33 | [assertion success] call to method IsFalse | +| Assert.cs:49:10:49:11 | enter M7 | Assert.cs:49:10:49:11 | enter M7 | +| Assert.cs:49:10:49:11 | enter M7 | Assert.cs:49:10:49:11 | exit M7 | +| Assert.cs:49:10:49:11 | enter M7 | Assert.cs:51:16:51:32 | String s = ... | +| Assert.cs:49:10:49:11 | enter M7 | Assert.cs:51:24:51:27 | null | +| Assert.cs:49:10:49:11 | enter M7 | Assert.cs:51:31:51:32 | "" | +| Assert.cs:49:10:49:11 | enter M7 | Assert.cs:52:9:52:33 | [assertion failure] call to method IsFalse | +| Assert.cs:49:10:49:11 | enter M7 | Assert.cs:52:9:52:33 | [assertion success] call to method IsFalse | +| Assert.cs:49:10:49:11 | exit M7 | Assert.cs:49:10:49:11 | exit M7 | +| Assert.cs:51:16:51:32 | String s = ... | Assert.cs:49:10:49:11 | exit M7 | +| Assert.cs:51:16:51:32 | String s = ... | Assert.cs:51:16:51:32 | String s = ... | +| Assert.cs:51:16:51:32 | String s = ... | Assert.cs:52:9:52:33 | [assertion failure] call to method IsFalse | +| Assert.cs:51:16:51:32 | String s = ... | Assert.cs:52:9:52:33 | [assertion success] call to method IsFalse | +| Assert.cs:51:24:51:27 | null | Assert.cs:51:24:51:27 | null | +| Assert.cs:51:31:51:32 | "" | Assert.cs:51:31:51:32 | "" | +| Assert.cs:52:9:52:33 | [assertion failure] call to method IsFalse | Assert.cs:52:9:52:33 | [assertion failure] call to method IsFalse | +| Assert.cs:52:9:52:33 | [assertion success] call to method IsFalse | Assert.cs:52:9:52:33 | [assertion success] call to method IsFalse | +| Assert.cs:56:10:56:11 | enter M8 | Assert.cs:56:10:56:11 | enter M8 | +| Assert.cs:56:10:56:11 | enter M8 | Assert.cs:56:10:56:11 | exit M8 | +| Assert.cs:56:10:56:11 | enter M8 | Assert.cs:58:24:58:27 | [b (line 56): true] null | +| Assert.cs:56:10:56:11 | enter M8 | Assert.cs:58:31:58:32 | [b (line 56): false] "" | +| Assert.cs:56:10:56:11 | enter M8 | Assert.cs:59:9:59:37 | [assertion failure] call to method IsTrue | +| Assert.cs:56:10:56:11 | enter M8 | Assert.cs:59:36:59:36 | [b (line 56): false] access to parameter b | +| Assert.cs:56:10:56:11 | enter M8 | Assert.cs:59:36:59:36 | [b (line 56): true] access to parameter b | +| Assert.cs:56:10:56:11 | exit M8 | Assert.cs:56:10:56:11 | exit M8 | +| Assert.cs:58:24:58:27 | [b (line 56): true] null | Assert.cs:58:24:58:27 | [b (line 56): true] null | +| Assert.cs:58:24:58:27 | [b (line 56): true] null | Assert.cs:59:36:59:36 | [b (line 56): true] access to parameter b | +| Assert.cs:58:31:58:32 | [b (line 56): false] "" | Assert.cs:58:31:58:32 | [b (line 56): false] "" | +| Assert.cs:58:31:58:32 | [b (line 56): false] "" | Assert.cs:59:36:59:36 | [b (line 56): false] access to parameter b | +| Assert.cs:59:9:59:37 | [assertion failure] call to method IsTrue | Assert.cs:59:9:59:37 | [assertion failure] call to method IsTrue | +| Assert.cs:59:36:59:36 | [b (line 56): false] access to parameter b | Assert.cs:59:36:59:36 | [b (line 56): false] access to parameter b | +| Assert.cs:59:36:59:36 | [b (line 56): true] access to parameter b | Assert.cs:59:36:59:36 | [b (line 56): true] access to parameter b | +| Assert.cs:63:10:63:11 | enter M9 | Assert.cs:63:10:63:11 | enter M9 | +| Assert.cs:63:10:63:11 | enter M9 | Assert.cs:63:10:63:11 | exit M9 | +| Assert.cs:63:10:63:11 | enter M9 | Assert.cs:65:24:65:27 | [b (line 63): true] null | +| Assert.cs:63:10:63:11 | enter M9 | Assert.cs:65:31:65:32 | [b (line 63): false] "" | +| Assert.cs:63:10:63:11 | enter M9 | Assert.cs:66:9:66:38 | [assertion failure] call to method IsFalse | +| Assert.cs:63:10:63:11 | enter M9 | Assert.cs:66:37:66:37 | [b (line 63): false] access to parameter b | +| Assert.cs:63:10:63:11 | enter M9 | Assert.cs:66:37:66:37 | [b (line 63): true] access to parameter b | +| Assert.cs:63:10:63:11 | exit M9 | Assert.cs:63:10:63:11 | exit M9 | +| Assert.cs:65:24:65:27 | [b (line 63): true] null | Assert.cs:65:24:65:27 | [b (line 63): true] null | +| Assert.cs:65:24:65:27 | [b (line 63): true] null | Assert.cs:66:37:66:37 | [b (line 63): true] access to parameter b | +| Assert.cs:65:31:65:32 | [b (line 63): false] "" | Assert.cs:65:31:65:32 | [b (line 63): false] "" | +| Assert.cs:65:31:65:32 | [b (line 63): false] "" | Assert.cs:66:37:66:37 | [b (line 63): false] access to parameter b | +| Assert.cs:66:9:66:38 | [assertion failure] call to method IsFalse | Assert.cs:66:9:66:38 | [assertion failure] call to method IsFalse | +| Assert.cs:66:37:66:37 | [b (line 63): false] access to parameter b | Assert.cs:66:37:66:37 | [b (line 63): false] access to parameter b | +| Assert.cs:66:37:66:37 | [b (line 63): true] access to parameter b | Assert.cs:66:37:66:37 | [b (line 63): true] access to parameter b | +| Assert.cs:70:10:70:12 | enter M10 | Assert.cs:70:10:70:12 | enter M10 | +| Assert.cs:70:10:70:12 | enter M10 | Assert.cs:70:10:70:12 | exit M10 | +| Assert.cs:70:10:70:12 | enter M10 | Assert.cs:72:24:72:27 | [b (line 70): true] null | +| Assert.cs:70:10:70:12 | enter M10 | Assert.cs:72:31:72:32 | [b (line 70): false] "" | +| Assert.cs:70:10:70:12 | enter M10 | Assert.cs:73:9:73:37 | [assertion failure] call to method IsTrue | +| Assert.cs:70:10:70:12 | enter M10 | Assert.cs:73:36:73:36 | [b (line 70): false] access to parameter b | +| Assert.cs:70:10:70:12 | enter M10 | Assert.cs:73:36:73:36 | [b (line 70): true] access to parameter b | +| Assert.cs:70:10:70:12 | exit M10 | Assert.cs:70:10:70:12 | exit M10 | +| Assert.cs:72:24:72:27 | [b (line 70): true] null | Assert.cs:72:24:72:27 | [b (line 70): true] null | +| Assert.cs:72:24:72:27 | [b (line 70): true] null | Assert.cs:73:36:73:36 | [b (line 70): true] access to parameter b | +| Assert.cs:72:31:72:32 | [b (line 70): false] "" | Assert.cs:72:31:72:32 | [b (line 70): false] "" | +| Assert.cs:72:31:72:32 | [b (line 70): false] "" | Assert.cs:73:36:73:36 | [b (line 70): false] access to parameter b | +| Assert.cs:73:9:73:37 | [assertion failure] call to method IsTrue | Assert.cs:73:9:73:37 | [assertion failure] call to method IsTrue | +| Assert.cs:73:36:73:36 | [b (line 70): false] access to parameter b | Assert.cs:73:36:73:36 | [b (line 70): false] access to parameter b | +| Assert.cs:73:36:73:36 | [b (line 70): true] access to parameter b | Assert.cs:73:36:73:36 | [b (line 70): true] access to parameter b | +| Assert.cs:77:10:77:12 | enter M11 | Assert.cs:77:10:77:12 | enter M11 | +| Assert.cs:77:10:77:12 | enter M11 | Assert.cs:77:10:77:12 | exit M11 | +| Assert.cs:77:10:77:12 | enter M11 | Assert.cs:79:24:79:27 | [b (line 77): true] null | +| Assert.cs:77:10:77:12 | enter M11 | Assert.cs:79:31:79:32 | [b (line 77): false] "" | +| Assert.cs:77:10:77:12 | enter M11 | Assert.cs:80:9:80:38 | [assertion failure] call to method IsFalse | +| Assert.cs:77:10:77:12 | enter M11 | Assert.cs:80:37:80:37 | [b (line 77): false] access to parameter b | +| Assert.cs:77:10:77:12 | enter M11 | Assert.cs:80:37:80:37 | [b (line 77): true] access to parameter b | +| Assert.cs:77:10:77:12 | exit M11 | Assert.cs:77:10:77:12 | exit M11 | +| Assert.cs:79:24:79:27 | [b (line 77): true] null | Assert.cs:79:24:79:27 | [b (line 77): true] null | +| Assert.cs:79:24:79:27 | [b (line 77): true] null | Assert.cs:80:37:80:37 | [b (line 77): true] access to parameter b | +| Assert.cs:79:31:79:32 | [b (line 77): false] "" | Assert.cs:79:31:79:32 | [b (line 77): false] "" | +| Assert.cs:79:31:79:32 | [b (line 77): false] "" | Assert.cs:80:37:80:37 | [b (line 77): false] access to parameter b | +| Assert.cs:80:9:80:38 | [assertion failure] call to method IsFalse | Assert.cs:80:9:80:38 | [assertion failure] call to method IsFalse | +| Assert.cs:80:37:80:37 | [b (line 77): false] access to parameter b | Assert.cs:80:37:80:37 | [b (line 77): false] access to parameter b | +| Assert.cs:80:37:80:37 | [b (line 77): true] access to parameter b | Assert.cs:80:37:80:37 | [b (line 77): true] access to parameter b | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:84:10:84:12 | enter M12 | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:84:10:84:12 | exit M12 | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:86:24:86:27 | [b (line 84): true] null | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:86:31:86:32 | [b (line 84): false] "" | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:87:9:87:31 | [assertion failure, b (line 84): false] call to method Assert | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:87:9:87:31 | [assertion failure, b (line 84): true] call to method Assert | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:91:9:91:24 | [assertion failure, b (line 84): false] call to method IsNull | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:91:9:91:24 | [assertion failure, b (line 84): true] call to method IsNull | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): false] call to method IsNotNull | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): true] call to method IsNotNull | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:119:37:119:38 | [b (line 84): true] !... | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:127:37:127:38 | [b (line 84): true] !... | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:84:10:84:12 | exit M12 | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:86:24:86:27 | [b (line 84): true] null | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:87:9:87:31 | [assertion failure, b (line 84): true] call to method Assert | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:91:9:91:24 | [assertion failure, b (line 84): true] call to method IsNull | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): true] call to method IsNotNull | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:119:37:119:38 | [b (line 84): true] !... | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:127:37:127:38 | [b (line 84): true] !... | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:86:31:86:32 | [b (line 84): false] "" | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:87:9:87:31 | [assertion failure, b (line 84): false] call to method Assert | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:91:9:91:24 | [assertion failure, b (line 84): false] call to method IsNull | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): false] call to method IsNotNull | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | +| Assert.cs:87:9:87:31 | [assertion failure, b (line 84): false] call to method Assert | Assert.cs:87:9:87:31 | [assertion failure, b (line 84): false] call to method Assert | +| Assert.cs:87:9:87:31 | [assertion failure, b (line 84): true] call to method Assert | Assert.cs:87:9:87:31 | [assertion failure, b (line 84): true] call to method Assert | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:91:9:91:24 | [assertion failure, b (line 84): false] call to method IsNull | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): false] call to method IsNotNull | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:91:9:91:24 | [assertion failure, b (line 84): true] call to method IsNull | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): true] call to method IsNotNull | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:119:37:119:38 | [b (line 84): true] !... | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:127:37:127:38 | [b (line 84): true] !... | +| Assert.cs:91:9:91:24 | [assertion failure, b (line 84): false] call to method IsNull | Assert.cs:91:9:91:24 | [assertion failure, b (line 84): false] call to method IsNull | +| Assert.cs:91:9:91:24 | [assertion failure, b (line 84): true] call to method IsNull | Assert.cs:91:9:91:24 | [assertion failure, b (line 84): true] call to method IsNull | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): false] call to method IsNotNull | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): true] call to method IsNotNull | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:119:37:119:38 | [b (line 84): true] !... | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:127:37:127:38 | [b (line 84): true] !... | +| Assert.cs:95:9:95:27 | [assertion failure, b (line 84): false] call to method IsNotNull | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): false] call to method IsNotNull | +| Assert.cs:95:9:95:27 | [assertion failure, b (line 84): true] call to method IsNotNull | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): true] call to method IsNotNull | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:119:37:119:38 | [b (line 84): true] !... | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:127:37:127:38 | [b (line 84): true] !... | +| Assert.cs:99:9:99:32 | [assertion failure, b (line 84): false] call to method IsTrue | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:99:9:99:32 | [assertion failure, b (line 84): true] call to method IsTrue | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:119:37:119:38 | [b (line 84): true] !... | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:127:37:127:38 | [b (line 84): true] !... | +| Assert.cs:103:9:103:32 | [assertion failure, b (line 84): false] call to method IsTrue | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:103:9:103:32 | [assertion failure, b (line 84): true] call to method IsTrue | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:119:37:119:38 | [b (line 84): true] !... | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:127:37:127:38 | [b (line 84): true] !... | +| Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | +| Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:119:37:119:38 | [b (line 84): true] !... | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:127:37:127:38 | [b (line 84): true] !... | +| Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | +| Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:119:37:119:38 | [b (line 84): true] !... | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:127:37:127:38 | [b (line 84): true] !... | +| Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | +| Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | +| Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | Assert.cs:119:37:119:38 | [b (line 84): true] !... | +| Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | +| Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | +| Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | Assert.cs:127:37:127:38 | [b (line 84): true] !... | +| Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:119:37:119:38 | [b (line 84): true] !... | Assert.cs:119:37:119:38 | [b (line 84): true] !... | +| Assert.cs:119:37:119:38 | [b (line 84): true] !... | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:119:37:119:38 | [b (line 84): true] !... | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | +| Assert.cs:119:37:119:38 | [b (line 84): true] !... | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | +| Assert.cs:119:37:119:38 | [b (line 84): true] !... | Assert.cs:127:37:127:38 | [b (line 84): true] !... | +| Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | +| Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | +| Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | Assert.cs:127:37:127:38 | [b (line 84): true] !... | +| Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | +| Assert.cs:127:37:127:38 | [b (line 84): true] !... | Assert.cs:127:37:127:38 | [b (line 84): true] !... | | Assignments.cs:3:10:3:10 | enter M | Assignments.cs:3:10:3:10 | enter M | | Assignments.cs:14:18:14:35 | enter (...) => ... | Assignments.cs:14:18:14:35 | enter (...) => ... | | Assignments.cs:17:40:17:40 | enter + | Assignments.cs:17:40:17:40 | enter + | @@ -6181,6 +8002,9 @@ blockDominance | CompileTimeOperators.cs:15:10:15:15 | enter Typeof | CompileTimeOperators.cs:15:10:15:15 | enter Typeof | | CompileTimeOperators.cs:20:12:20:17 | enter Nameof | CompileTimeOperators.cs:20:12:20:17 | enter Nameof | | CompileTimeOperators.cs:28:10:28:10 | enter M | CompileTimeOperators.cs:28:10:28:10 | enter M | +| ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | +| ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | +| ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | | ConditionalAccess.cs:3:12:3:13 | enter M1 | ConditionalAccess.cs:3:12:3:13 | enter M1 | | ConditionalAccess.cs:3:12:3:13 | enter M1 | ConditionalAccess.cs:3:12:3:13 | exit M1 | | ConditionalAccess.cs:3:12:3:13 | enter M1 | ConditionalAccess.cs:3:28:3:38 | call to method ToString | @@ -6228,7 +8052,16 @@ blockDominance | ConditionalAccess.cs:19:12:19:13 | exit M6 | ConditionalAccess.cs:19:12:19:13 | exit M6 | | ConditionalAccess.cs:19:58:19:59 | access to parameter s2 | ConditionalAccess.cs:19:58:19:59 | access to parameter s2 | | ConditionalAccess.cs:21:10:21:11 | enter M7 | ConditionalAccess.cs:21:10:21:11 | enter M7 | -| ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | +| ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | +| ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:30:10:30:12 | enter Out | +| ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:30:10:30:12 | exit Out | +| ConditionalAccess.cs:30:10:30:12 | exit Out | ConditionalAccess.cs:30:10:30:12 | exit Out | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:32:10:32:11 | enter M8 | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:32:10:32:11 | exit M8 | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:35:14:35:24 | call to method Out | +| ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:32:10:32:11 | exit M8 | +| ConditionalAccess.cs:35:14:35:24 | call to method Out | ConditionalAccess.cs:35:14:35:24 | call to method Out | +| ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:3:10:3:19 | enter IncrOrDecr | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:3:10:3:19 | exit IncrOrDecr | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:6:13:6:16 | [inc (line 3): true] ...; | @@ -6406,20 +8239,20 @@ blockDominance | Conditions.cs:110:16:110:16 | access to local variable x | Conditions.cs:110:16:110:16 | access to local variable x | | Conditions.cs:113:10:113:11 | enter M9 | Conditions.cs:113:10:113:11 | enter M9 | | Conditions.cs:113:10:113:11 | enter M9 | Conditions.cs:113:10:113:11 | exit M9 | -| Conditions.cs:113:10:113:11 | enter M9 | Conditions.cs:116:24:116:24 | access to local variable i | -| Conditions.cs:113:10:113:11 | enter M9 | Conditions.cs:116:41:116:41 | access to local variable i | +| Conditions.cs:113:10:113:11 | enter M9 | Conditions.cs:116:25:116:25 | access to local variable i | +| Conditions.cs:113:10:113:11 | enter M9 | Conditions.cs:116:42:116:42 | access to local variable i | | Conditions.cs:113:10:113:11 | enter M9 | Conditions.cs:117:9:123:9 | {...} | | Conditions.cs:113:10:113:11 | enter M9 | Conditions.cs:120:17:120:23 | [last (line 118): false] ...; | | Conditions.cs:113:10:113:11 | enter M9 | Conditions.cs:121:13:122:25 | [last (line 118): true] if (...) ... | | Conditions.cs:113:10:113:11 | exit M9 | Conditions.cs:113:10:113:11 | exit M9 | -| Conditions.cs:116:24:116:24 | access to local variable i | Conditions.cs:113:10:113:11 | exit M9 | -| Conditions.cs:116:24:116:24 | access to local variable i | Conditions.cs:116:24:116:24 | access to local variable i | -| Conditions.cs:116:24:116:24 | access to local variable i | Conditions.cs:116:41:116:41 | access to local variable i | -| Conditions.cs:116:24:116:24 | access to local variable i | Conditions.cs:117:9:123:9 | {...} | -| Conditions.cs:116:24:116:24 | access to local variable i | Conditions.cs:120:17:120:23 | [last (line 118): false] ...; | -| Conditions.cs:116:24:116:24 | access to local variable i | Conditions.cs:121:13:122:25 | [last (line 118): true] if (...) ... | -| Conditions.cs:116:41:116:41 | access to local variable i | Conditions.cs:116:41:116:41 | access to local variable i | -| Conditions.cs:117:9:123:9 | {...} | Conditions.cs:116:41:116:41 | access to local variable i | +| Conditions.cs:116:25:116:25 | access to local variable i | Conditions.cs:113:10:113:11 | exit M9 | +| Conditions.cs:116:25:116:25 | access to local variable i | Conditions.cs:116:25:116:25 | access to local variable i | +| Conditions.cs:116:25:116:25 | access to local variable i | Conditions.cs:116:42:116:42 | access to local variable i | +| Conditions.cs:116:25:116:25 | access to local variable i | Conditions.cs:117:9:123:9 | {...} | +| Conditions.cs:116:25:116:25 | access to local variable i | Conditions.cs:120:17:120:23 | [last (line 118): false] ...; | +| Conditions.cs:116:25:116:25 | access to local variable i | Conditions.cs:121:13:122:25 | [last (line 118): true] if (...) ... | +| Conditions.cs:116:42:116:42 | access to local variable i | Conditions.cs:116:42:116:42 | access to local variable i | +| Conditions.cs:117:9:123:9 | {...} | Conditions.cs:116:42:116:42 | access to local variable i | | Conditions.cs:117:9:123:9 | {...} | Conditions.cs:117:9:123:9 | {...} | | Conditions.cs:117:9:123:9 | {...} | Conditions.cs:120:17:120:23 | [last (line 118): false] ...; | | Conditions.cs:117:9:123:9 | {...} | Conditions.cs:121:13:122:25 | [last (line 118): true] if (...) ... | @@ -6436,6 +8269,13 @@ blockDominance | Conditions.cs:134:13:139:13 | [Field1 (line 129): true] {...} | Conditions.cs:134:13:139:13 | [Field1 (line 129): true] {...} | | Conditions.cs:134:13:139:13 | [Field1 (line 129): true] {...} | Conditions.cs:136:17:138:17 | [Field1 (line 129): true, Field2 (line 129): true] {...} | | Conditions.cs:136:17:138:17 | [Field1 (line 129): true, Field2 (line 129): true] {...} | Conditions.cs:136:17:138:17 | [Field1 (line 129): true, Field2 (line 129): true] {...} | +| Conditions.cs:143:10:143:12 | enter M11 | Conditions.cs:143:10:143:12 | enter M11 | +| Conditions.cs:143:10:143:12 | enter M11 | Conditions.cs:143:10:143:12 | exit M11 | +| Conditions.cs:143:10:143:12 | enter M11 | Conditions.cs:145:21:145:23 | [b (line 143): true] "a" | +| Conditions.cs:143:10:143:12 | enter M11 | Conditions.cs:145:27:145:29 | [b (line 143): false] "b" | +| Conditions.cs:143:10:143:12 | exit M11 | Conditions.cs:143:10:143:12 | exit M11 | +| Conditions.cs:145:21:145:23 | [b (line 143): true] "a" | Conditions.cs:145:21:145:23 | [b (line 143): true] "a" | +| Conditions.cs:145:27:145:29 | [b (line 143): false] "b" | Conditions.cs:145:27:145:29 | [b (line 143): false] "b" | | ExitMethods.cs:7:10:7:11 | enter M1 | ExitMethods.cs:7:10:7:11 | enter M1 | | ExitMethods.cs:13:10:13:11 | enter M2 | ExitMethods.cs:13:10:13:11 | enter M2 | | ExitMethods.cs:19:10:19:11 | enter M3 | ExitMethods.cs:19:10:19:11 | enter M3 | @@ -6489,6 +8329,12 @@ blockDominance | ExitMethods.cs:119:17:119:32 | enter FailingAssertion | ExitMethods.cs:119:17:119:32 | enter FailingAssertion | | ExitMethods.cs:125:17:125:33 | enter FailingAssertion2 | ExitMethods.cs:125:17:125:33 | enter FailingAssertion2 | | ExitMethods.cs:131:10:131:20 | enter AssertFalse | ExitMethods.cs:131:10:131:20 | enter AssertFalse | +| ExitMethods.cs:131:10:131:20 | enter AssertFalse | ExitMethods.cs:131:10:131:20 | exit AssertFalse | +| ExitMethods.cs:131:10:131:20 | enter AssertFalse | ExitMethods.cs:131:33:131:49 | [assertion failure] call to method IsFalse | +| ExitMethods.cs:131:10:131:20 | enter AssertFalse | ExitMethods.cs:131:33:131:49 | [assertion success] call to method IsFalse | +| ExitMethods.cs:131:10:131:20 | exit AssertFalse | ExitMethods.cs:131:10:131:20 | exit AssertFalse | +| ExitMethods.cs:131:33:131:49 | [assertion failure] call to method IsFalse | ExitMethods.cs:131:33:131:49 | [assertion failure] call to method IsFalse | +| ExitMethods.cs:131:33:131:49 | [assertion success] call to method IsFalse | ExitMethods.cs:131:33:131:49 | [assertion success] call to method IsFalse | | ExitMethods.cs:133:17:133:33 | enter FailingAssertion3 | ExitMethods.cs:133:17:133:33 | enter FailingAssertion3 | | Extensions.cs:5:23:5:29 | enter ToInt32 | Extensions.cs:5:23:5:29 | enter ToInt32 | | Extensions.cs:10:24:10:29 | enter ToBool | Extensions.cs:10:24:10:29 | enter ToBool | @@ -7262,19 +9108,19 @@ blockDominance | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:7:10:7:11 | enter M1 | | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:7:10:7:11 | exit M1 | | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:10:13:10:19 | return ...; | -| LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:11:21:11:23 | String arg | -| LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:11:28:11:31 | access to parameter args | +| LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:11:22:11:24 | String arg | +| LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:11:29:11:32 | access to parameter args | | LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:7:10:7:11 | exit M1 | | LoopUnrolling.cs:10:13:10:19 | return ...; | LoopUnrolling.cs:10:13:10:19 | return ...; | -| LoopUnrolling.cs:11:21:11:23 | String arg | LoopUnrolling.cs:11:21:11:23 | String arg | -| LoopUnrolling.cs:11:28:11:31 | access to parameter args | LoopUnrolling.cs:11:21:11:23 | String arg | -| LoopUnrolling.cs:11:28:11:31 | access to parameter args | LoopUnrolling.cs:11:28:11:31 | access to parameter args | +| LoopUnrolling.cs:11:22:11:24 | String arg | LoopUnrolling.cs:11:22:11:24 | String arg | +| LoopUnrolling.cs:11:29:11:32 | access to parameter args | LoopUnrolling.cs:11:22:11:24 | String arg | +| LoopUnrolling.cs:11:29:11:32 | access to parameter args | LoopUnrolling.cs:11:29:11:32 | access to parameter args | | LoopUnrolling.cs:15:10:15:11 | enter M2 | LoopUnrolling.cs:15:10:15:11 | enter M2 | | LoopUnrolling.cs:15:10:15:11 | enter M2 | LoopUnrolling.cs:15:10:15:11 | exit M2 | -| LoopUnrolling.cs:15:10:15:11 | enter M2 | LoopUnrolling.cs:18:21:18:21 | String x | +| LoopUnrolling.cs:15:10:15:11 | enter M2 | LoopUnrolling.cs:18:22:18:22 | String x | | LoopUnrolling.cs:15:10:15:11 | exit M2 | LoopUnrolling.cs:15:10:15:11 | exit M2 | -| LoopUnrolling.cs:18:21:18:21 | String x | LoopUnrolling.cs:15:10:15:11 | exit M2 | -| LoopUnrolling.cs:18:21:18:21 | String x | LoopUnrolling.cs:18:21:18:21 | String x | +| LoopUnrolling.cs:18:22:18:22 | String x | LoopUnrolling.cs:15:10:15:11 | exit M2 | +| LoopUnrolling.cs:18:22:18:22 | String x | LoopUnrolling.cs:18:22:18:22 | String x | | LoopUnrolling.cs:22:10:22:11 | enter M3 | LoopUnrolling.cs:22:10:22:11 | enter M3 | | LoopUnrolling.cs:22:10:22:11 | enter M3 | LoopUnrolling.cs:22:10:22:11 | exit M3 | | LoopUnrolling.cs:22:10:22:11 | enter M3 | LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | @@ -7289,59 +9135,311 @@ blockDominance | LoopUnrolling.cs:24:22:24:24 | Char arg | LoopUnrolling.cs:25:26:25:29 | Char arg0 | | LoopUnrolling.cs:25:26:25:29 | Char arg0 | LoopUnrolling.cs:25:26:25:29 | Char arg0 | | LoopUnrolling.cs:29:10:29:11 | enter M4 | LoopUnrolling.cs:29:10:29:11 | enter M4 | -| LoopUnrolling.cs:29:10:29:11 | enter M4 | LoopUnrolling.cs:29:10:29:11 | exit M4 | -| LoopUnrolling.cs:29:10:29:11 | enter M4 | LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | -| LoopUnrolling.cs:29:10:29:11 | enter M4 | LoopUnrolling.cs:32:21:32:21 | String x | -| LoopUnrolling.cs:29:10:29:11 | exit M4 | LoopUnrolling.cs:29:10:29:11 | exit M4 | -| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:29:10:29:11 | exit M4 | -| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | -| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:32:21:32:21 | String x | -| LoopUnrolling.cs:32:21:32:21 | String x | LoopUnrolling.cs:32:21:32:21 | String x | | LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:36:10:36:11 | enter M5 | | LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:36:10:36:11 | exit M5 | | LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | -| LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:40:21:40:21 | String x | -| LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:41:25:41:25 | String y | +| LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:40:22:40:22 | String x | +| LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:41:26:41:26 | String y | | LoopUnrolling.cs:36:10:36:11 | exit M5 | LoopUnrolling.cs:36:10:36:11 | exit M5 | | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:36:10:36:11 | exit M5 | | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | -| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:36:10:36:11 | exit M5 | -| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | -| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:40:21:40:21 | String x | -| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:41:25:41:25 | String y | -| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:36:10:36:11 | exit M5 | -| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | -| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:41:25:41:25 | String y | +| LoopUnrolling.cs:40:22:40:22 | String x | LoopUnrolling.cs:36:10:36:11 | exit M5 | +| LoopUnrolling.cs:40:22:40:22 | String x | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | +| LoopUnrolling.cs:40:22:40:22 | String x | LoopUnrolling.cs:40:22:40:22 | String x | +| LoopUnrolling.cs:40:22:40:22 | String x | LoopUnrolling.cs:41:26:41:26 | String y | +| LoopUnrolling.cs:41:26:41:26 | String y | LoopUnrolling.cs:36:10:36:11 | exit M5 | +| LoopUnrolling.cs:41:26:41:26 | String y | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | +| LoopUnrolling.cs:41:26:41:26 | String y | LoopUnrolling.cs:41:26:41:26 | String y | | LoopUnrolling.cs:45:10:45:11 | enter M6 | LoopUnrolling.cs:45:10:45:11 | enter M6 | -| LoopUnrolling.cs:45:10:45:11 | enter M6 | LoopUnrolling.cs:50:13:50:17 | Label: | -| LoopUnrolling.cs:50:13:50:17 | Label: | LoopUnrolling.cs:50:13:50:17 | Label: | +| LoopUnrolling.cs:45:10:45:11 | enter M6 | LoopUnrolling.cs:50:9:50:13 | Label: | +| LoopUnrolling.cs:50:9:50:13 | Label: | LoopUnrolling.cs:50:9:50:13 | Label: | | LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:55:10:55:11 | enter M7 | | LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:55:10:55:11 | exit M7 | -| LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | -| LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | +| LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:58:22:58:22 | [b (line 55): false] String x | +| LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:58:22:58:22 | [b (line 55): true] String x | | LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | | LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | | LoopUnrolling.cs:55:10:55:11 | exit M7 | LoopUnrolling.cs:55:10:55:11 | exit M7 | -| LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | -| LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | -| LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | +| LoopUnrolling.cs:58:22:58:22 | [b (line 55): false] String x | LoopUnrolling.cs:58:22:58:22 | [b (line 55): false] String x | +| LoopUnrolling.cs:58:22:58:22 | [b (line 55): true] String x | LoopUnrolling.cs:58:22:58:22 | [b (line 55): true] String x | +| LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | LoopUnrolling.cs:58:22:58:22 | [b (line 55): true] String x | | LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | -| LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | +| LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | LoopUnrolling.cs:58:22:58:22 | [b (line 55): false] String x | | LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | | LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:67:10:67:11 | enter M8 | | LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:67:10:67:11 | exit M8 | | LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:70:13:70:19 | return ...; | | LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:71:9:71:21 | ...; | -| LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | -| LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:72:21:72:23 | String arg | | LoopUnrolling.cs:67:10:67:11 | exit M8 | LoopUnrolling.cs:67:10:67:11 | exit M8 | | LoopUnrolling.cs:70:13:70:19 | return ...; | LoopUnrolling.cs:70:13:70:19 | return ...; | | LoopUnrolling.cs:71:9:71:21 | ...; | LoopUnrolling.cs:71:9:71:21 | ...; | -| LoopUnrolling.cs:71:9:71:21 | ...; | LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | -| LoopUnrolling.cs:71:9:71:21 | ...; | LoopUnrolling.cs:72:21:72:23 | String arg | -| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | -| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:72:21:72:23 | String arg | -| LoopUnrolling.cs:72:21:72:23 | String arg | LoopUnrolling.cs:72:21:72:23 | String arg | +| LoopUnrolling.cs:76:10:76:11 | enter M9 | LoopUnrolling.cs:76:10:76:11 | enter M9 | +| LoopUnrolling.cs:85:10:85:12 | enter M10 | LoopUnrolling.cs:85:10:85:12 | enter M10 | +| LoopUnrolling.cs:94:10:94:12 | enter M11 | LoopUnrolling.cs:94:10:94:12 | enter M11 | +| LoopUnrolling.cs:94:10:94:12 | enter M11 | LoopUnrolling.cs:94:10:94:12 | exit M11 | +| LoopUnrolling.cs:94:10:94:12 | enter M11 | LoopUnrolling.cs:97:22:97:22 | String x | +| LoopUnrolling.cs:94:10:94:12 | exit M11 | LoopUnrolling.cs:94:10:94:12 | exit M11 | +| LoopUnrolling.cs:97:22:97:22 | String x | LoopUnrolling.cs:94:10:94:12 | exit M11 | +| LoopUnrolling.cs:97:22:97:22 | String x | LoopUnrolling.cs:97:22:97:22 | String x | +| MultiImplementationA.cs:6:22:6:31 | enter get_P1 | MultiImplementationA.cs:6:22:6:31 | enter get_P1 | +| MultiImplementationA.cs:6:22:6:31 | enter get_P1 | MultiImplementationA.cs:6:22:6:31 | exit get_P1 | +| MultiImplementationA.cs:6:22:6:31 | enter get_P1 | MultiImplementationA.cs:6:28:6:31 | null | +| MultiImplementationA.cs:6:22:6:31 | enter get_P1 | MultiImplementationB.cs:3:22:3:22 | 0 | +| MultiImplementationA.cs:6:22:6:31 | enter get_P1 | MultiImplementationB.cs:3:22:3:22 | enter get_P1 | +| MultiImplementationA.cs:6:22:6:31 | enter get_P1 | MultiImplementationB.cs:3:22:3:22 | exit get_P1 | +| MultiImplementationA.cs:6:22:6:31 | exit get_P1 | MultiImplementationA.cs:6:22:6:31 | exit get_P1 | +| MultiImplementationA.cs:6:22:6:31 | exit get_P1 | MultiImplementationB.cs:3:22:3:22 | exit get_P1 | +| MultiImplementationA.cs:6:28:6:31 | null | MultiImplementationA.cs:6:28:6:31 | null | +| MultiImplementationA.cs:7:21:7:23 | enter get_P2 | MultiImplementationA.cs:7:21:7:23 | enter get_P2 | +| MultiImplementationA.cs:7:21:7:23 | enter get_P2 | MultiImplementationA.cs:7:21:7:23 | exit get_P2 | +| MultiImplementationA.cs:7:21:7:23 | enter get_P2 | MultiImplementationA.cs:7:25:7:39 | {...} | +| MultiImplementationA.cs:7:21:7:23 | enter get_P2 | MultiImplementationB.cs:4:21:4:23 | enter get_P2 | +| MultiImplementationA.cs:7:21:7:23 | enter get_P2 | MultiImplementationB.cs:4:21:4:23 | exit get_P2 | +| MultiImplementationA.cs:7:21:7:23 | enter get_P2 | MultiImplementationB.cs:4:25:4:37 | {...} | +| MultiImplementationA.cs:7:21:7:23 | exit get_P2 | MultiImplementationA.cs:7:21:7:23 | exit get_P2 | +| MultiImplementationA.cs:7:21:7:23 | exit get_P2 | MultiImplementationB.cs:4:21:4:23 | exit get_P2 | +| MultiImplementationA.cs:7:25:7:39 | {...} | MultiImplementationA.cs:7:25:7:39 | {...} | +| MultiImplementationA.cs:7:41:7:43 | enter set_P2 | MultiImplementationA.cs:7:41:7:43 | enter set_P2 | +| MultiImplementationA.cs:7:41:7:43 | enter set_P2 | MultiImplementationA.cs:7:41:7:43 | exit set_P2 | +| MultiImplementationA.cs:7:41:7:43 | enter set_P2 | MultiImplementationA.cs:7:45:7:59 | {...} | +| MultiImplementationA.cs:7:41:7:43 | enter set_P2 | MultiImplementationB.cs:4:39:4:41 | enter set_P2 | +| MultiImplementationA.cs:7:41:7:43 | enter set_P2 | MultiImplementationB.cs:4:39:4:41 | exit set_P2 | +| MultiImplementationA.cs:7:41:7:43 | enter set_P2 | MultiImplementationB.cs:4:43:4:45 | {...} | +| MultiImplementationA.cs:7:41:7:43 | exit set_P2 | MultiImplementationA.cs:7:41:7:43 | exit set_P2 | +| MultiImplementationA.cs:7:41:7:43 | exit set_P2 | MultiImplementationB.cs:4:39:4:41 | exit set_P2 | +| MultiImplementationA.cs:7:45:7:59 | {...} | MultiImplementationA.cs:7:45:7:59 | {...} | +| MultiImplementationA.cs:8:16:8:16 | enter M | MultiImplementationA.cs:8:16:8:16 | enter M | +| MultiImplementationA.cs:8:16:8:16 | enter M | MultiImplementationA.cs:8:16:8:16 | exit M | +| MultiImplementationA.cs:8:16:8:16 | enter M | MultiImplementationA.cs:8:29:8:32 | null | +| MultiImplementationA.cs:8:16:8:16 | enter M | MultiImplementationB.cs:5:16:5:16 | enter M | +| MultiImplementationA.cs:8:16:8:16 | enter M | MultiImplementationB.cs:5:16:5:16 | exit M | +| MultiImplementationA.cs:8:16:8:16 | enter M | MultiImplementationB.cs:5:23:5:23 | 2 | +| MultiImplementationA.cs:8:16:8:16 | exit M | MultiImplementationA.cs:8:16:8:16 | exit M | +| MultiImplementationA.cs:8:16:8:16 | exit M | MultiImplementationB.cs:5:16:5:16 | exit M | +| MultiImplementationA.cs:8:29:8:32 | null | MultiImplementationA.cs:8:29:8:32 | null | +| MultiImplementationA.cs:13:16:13:16 | this access | MultiImplementationA.cs:13:16:13:16 | this access | +| MultiImplementationA.cs:14:31:14:31 | access to parameter i | MultiImplementationA.cs:14:31:14:31 | access to parameter i | +| MultiImplementationA.cs:14:31:14:31 | enter get_Item | MultiImplementationA.cs:14:31:14:31 | access to parameter i | +| MultiImplementationA.cs:14:31:14:31 | enter get_Item | MultiImplementationA.cs:14:31:14:31 | enter get_Item | +| MultiImplementationA.cs:14:31:14:31 | enter get_Item | MultiImplementationA.cs:14:31:14:31 | exit get_Item | +| MultiImplementationA.cs:14:31:14:31 | enter get_Item | MultiImplementationB.cs:12:31:12:40 | enter get_Item | +| MultiImplementationA.cs:14:31:14:31 | enter get_Item | MultiImplementationB.cs:12:31:12:40 | exit get_Item | +| MultiImplementationA.cs:14:31:14:31 | enter get_Item | MultiImplementationB.cs:12:37:12:40 | null | +| MultiImplementationA.cs:14:31:14:31 | exit get_Item | MultiImplementationA.cs:14:31:14:31 | exit get_Item | +| MultiImplementationA.cs:14:31:14:31 | exit get_Item | MultiImplementationB.cs:12:31:12:40 | exit get_Item | +| MultiImplementationA.cs:15:36:15:38 | enter get_Item | MultiImplementationA.cs:15:36:15:38 | enter get_Item | +| MultiImplementationA.cs:15:36:15:38 | enter get_Item | MultiImplementationA.cs:15:36:15:38 | exit get_Item | +| MultiImplementationA.cs:15:36:15:38 | enter get_Item | MultiImplementationA.cs:15:40:15:52 | {...} | +| MultiImplementationA.cs:15:36:15:38 | enter get_Item | MultiImplementationB.cs:13:36:13:38 | enter get_Item | +| MultiImplementationA.cs:15:36:15:38 | enter get_Item | MultiImplementationB.cs:13:36:13:38 | exit get_Item | +| MultiImplementationA.cs:15:36:15:38 | enter get_Item | MultiImplementationB.cs:13:40:13:54 | {...} | +| MultiImplementationA.cs:15:36:15:38 | exit get_Item | MultiImplementationA.cs:15:36:15:38 | exit get_Item | +| MultiImplementationA.cs:15:36:15:38 | exit get_Item | MultiImplementationB.cs:13:36:13:38 | exit get_Item | +| MultiImplementationA.cs:15:40:15:52 | {...} | MultiImplementationA.cs:15:40:15:52 | {...} | +| MultiImplementationA.cs:15:54:15:56 | enter set_Item | MultiImplementationA.cs:15:54:15:56 | enter set_Item | +| MultiImplementationA.cs:15:54:15:56 | enter set_Item | MultiImplementationA.cs:15:54:15:56 | exit set_Item | +| MultiImplementationA.cs:15:54:15:56 | enter set_Item | MultiImplementationA.cs:15:58:15:60 | {...} | +| MultiImplementationA.cs:15:54:15:56 | enter set_Item | MultiImplementationB.cs:13:56:13:58 | enter set_Item | +| MultiImplementationA.cs:15:54:15:56 | enter set_Item | MultiImplementationB.cs:13:56:13:58 | exit set_Item | +| MultiImplementationA.cs:15:54:15:56 | enter set_Item | MultiImplementationB.cs:13:60:13:62 | {...} | +| MultiImplementationA.cs:15:54:15:56 | exit set_Item | MultiImplementationA.cs:15:54:15:56 | exit set_Item | +| MultiImplementationA.cs:15:54:15:56 | exit set_Item | MultiImplementationB.cs:13:56:13:58 | exit set_Item | +| MultiImplementationA.cs:15:58:15:60 | {...} | MultiImplementationA.cs:15:58:15:60 | {...} | +| MultiImplementationA.cs:16:17:16:18 | enter M1 | MultiImplementationA.cs:16:17:16:18 | enter M1 | +| MultiImplementationA.cs:16:17:16:18 | enter M1 | MultiImplementationA.cs:16:17:16:18 | exit M1 | +| MultiImplementationA.cs:16:17:16:18 | enter M1 | MultiImplementationA.cs:17:5:19:5 | {...} | +| MultiImplementationA.cs:16:17:16:18 | enter M1 | MultiImplementationB.cs:14:17:14:18 | enter M1 | +| MultiImplementationA.cs:16:17:16:18 | enter M1 | MultiImplementationB.cs:14:17:14:18 | exit M1 | +| MultiImplementationA.cs:16:17:16:18 | enter M1 | MultiImplementationB.cs:15:5:17:5 | {...} | +| MultiImplementationA.cs:16:17:16:18 | exit M1 | MultiImplementationA.cs:16:17:16:18 | exit M1 | +| MultiImplementationA.cs:16:17:16:18 | exit M1 | MultiImplementationB.cs:14:17:14:18 | exit M1 | +| MultiImplementationA.cs:17:5:19:5 | {...} | MultiImplementationA.cs:17:5:19:5 | {...} | +| MultiImplementationA.cs:18:9:18:22 | enter M2 | MultiImplementationA.cs:18:9:18:22 | enter M2 | +| MultiImplementationA.cs:20:12:20:13 | enter C2 | MultiImplementationA.cs:13:16:13:16 | this access | +| MultiImplementationA.cs:20:12:20:13 | enter C2 | MultiImplementationA.cs:20:12:20:13 | enter C2 | +| MultiImplementationA.cs:20:12:20:13 | enter C2 | MultiImplementationA.cs:20:12:20:13 | exit C2 | +| MultiImplementationA.cs:20:12:20:13 | enter C2 | MultiImplementationA.cs:20:22:20:31 | {...} | +| MultiImplementationA.cs:20:12:20:13 | enter C2 | MultiImplementationA.cs:24:16:24:16 | this access | +| MultiImplementationA.cs:20:12:20:13 | enter C2 | MultiImplementationB.cs:11:16:11:16 | this access | +| MultiImplementationA.cs:20:12:20:13 | enter C2 | MultiImplementationB.cs:18:12:18:13 | enter C2 | +| MultiImplementationA.cs:20:12:20:13 | enter C2 | MultiImplementationB.cs:18:12:18:13 | exit C2 | +| MultiImplementationA.cs:20:12:20:13 | enter C2 | MultiImplementationB.cs:18:22:18:36 | {...} | +| MultiImplementationA.cs:20:12:20:13 | enter C2 | MultiImplementationB.cs:22:16:22:16 | this access | +| MultiImplementationA.cs:20:12:20:13 | exit C2 | MultiImplementationA.cs:20:12:20:13 | exit C2 | +| MultiImplementationA.cs:20:12:20:13 | exit C2 | MultiImplementationB.cs:18:12:18:13 | exit C2 | +| MultiImplementationA.cs:20:22:20:31 | {...} | MultiImplementationA.cs:20:22:20:31 | {...} | +| MultiImplementationA.cs:21:12:21:13 | enter C2 | MultiImplementationA.cs:21:12:21:13 | enter C2 | +| MultiImplementationA.cs:21:12:21:13 | enter C2 | MultiImplementationA.cs:21:12:21:13 | exit C2 | +| MultiImplementationA.cs:21:12:21:13 | enter C2 | MultiImplementationA.cs:21:24:21:24 | 0 | +| MultiImplementationA.cs:21:12:21:13 | enter C2 | MultiImplementationA.cs:21:27:21:29 | {...} | +| MultiImplementationA.cs:21:12:21:13 | enter C2 | MultiImplementationB.cs:19:12:19:13 | enter C2 | +| MultiImplementationA.cs:21:12:21:13 | enter C2 | MultiImplementationB.cs:19:12:19:13 | exit C2 | +| MultiImplementationA.cs:21:12:21:13 | enter C2 | MultiImplementationB.cs:19:24:19:24 | 1 | +| MultiImplementationA.cs:21:12:21:13 | enter C2 | MultiImplementationB.cs:19:27:19:29 | {...} | +| MultiImplementationA.cs:21:12:21:13 | exit C2 | MultiImplementationA.cs:21:12:21:13 | exit C2 | +| MultiImplementationA.cs:21:12:21:13 | exit C2 | MultiImplementationB.cs:19:12:19:13 | exit C2 | +| MultiImplementationA.cs:21:24:21:24 | 0 | MultiImplementationA.cs:21:24:21:24 | 0 | +| MultiImplementationA.cs:21:27:21:29 | {...} | MultiImplementationA.cs:21:27:21:29 | {...} | +| MultiImplementationA.cs:22:6:22:7 | enter ~C2 | MultiImplementationA.cs:22:6:22:7 | enter ~C2 | +| MultiImplementationA.cs:22:6:22:7 | enter ~C2 | MultiImplementationA.cs:22:6:22:7 | exit ~C2 | +| MultiImplementationA.cs:22:6:22:7 | enter ~C2 | MultiImplementationA.cs:22:11:22:13 | {...} | +| MultiImplementationA.cs:22:6:22:7 | enter ~C2 | MultiImplementationB.cs:20:6:20:7 | enter ~C2 | +| MultiImplementationA.cs:22:6:22:7 | enter ~C2 | MultiImplementationB.cs:20:6:20:7 | exit ~C2 | +| MultiImplementationA.cs:22:6:22:7 | enter ~C2 | MultiImplementationB.cs:20:11:20:25 | {...} | +| MultiImplementationA.cs:22:6:22:7 | exit ~C2 | MultiImplementationA.cs:22:6:22:7 | exit ~C2 | +| MultiImplementationA.cs:22:6:22:7 | exit ~C2 | MultiImplementationB.cs:20:6:20:7 | exit ~C2 | +| MultiImplementationA.cs:22:11:22:13 | {...} | MultiImplementationA.cs:22:11:22:13 | {...} | +| MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | +| MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | MultiImplementationA.cs:23:28:23:35 | exit implicit conversion | +| MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | MultiImplementationA.cs:23:50:23:53 | null | +| MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | +| MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | MultiImplementationB.cs:21:28:21:35 | exit implicit conversion | +| MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | MultiImplementationB.cs:21:56:21:59 | null | +| MultiImplementationA.cs:23:28:23:35 | exit implicit conversion | MultiImplementationA.cs:23:28:23:35 | exit implicit conversion | +| MultiImplementationA.cs:23:28:23:35 | exit implicit conversion | MultiImplementationB.cs:21:28:21:35 | exit implicit conversion | +| MultiImplementationA.cs:23:50:23:53 | null | MultiImplementationA.cs:23:50:23:53 | null | +| MultiImplementationA.cs:24:16:24:16 | this access | MultiImplementationA.cs:24:16:24:16 | this access | +| MultiImplementationA.cs:30:21:30:23 | enter get_P3 | MultiImplementationA.cs:30:21:30:23 | enter get_P3 | +| MultiImplementationA.cs:30:21:30:23 | enter get_P3 | MultiImplementationB.cs:27:21:27:23 | enter get_P3 | +| MultiImplementationA.cs:36:9:36:10 | enter M1 | MultiImplementationA.cs:36:9:36:10 | enter M1 | +| MultiImplementationA.cs:36:9:36:10 | enter M1 | MultiImplementationA.cs:36:9:36:10 | exit M1 | +| MultiImplementationA.cs:36:9:36:10 | enter M1 | MultiImplementationA.cs:36:14:36:28 | {...} | +| MultiImplementationA.cs:36:9:36:10 | enter M1 | MultiImplementationB.cs:32:9:32:10 | enter M1 | +| MultiImplementationA.cs:36:9:36:10 | enter M1 | MultiImplementationB.cs:32:9:32:10 | exit M1 | +| MultiImplementationA.cs:36:9:36:10 | enter M1 | MultiImplementationB.cs:32:17:32:17 | 0 | +| MultiImplementationA.cs:36:9:36:10 | exit M1 | MultiImplementationA.cs:36:9:36:10 | exit M1 | +| MultiImplementationA.cs:36:9:36:10 | exit M1 | MultiImplementationB.cs:32:9:32:10 | exit M1 | +| MultiImplementationA.cs:36:14:36:28 | {...} | MultiImplementationA.cs:36:14:36:28 | {...} | +| MultiImplementationA.cs:37:9:37:10 | enter M2 | MultiImplementationA.cs:37:9:37:10 | enter M2 | +| MultiImplementationB.cs:3:22:3:22 | 0 | MultiImplementationB.cs:3:22:3:22 | 0 | +| MultiImplementationB.cs:3:22:3:22 | enter get_P1 | MultiImplementationA.cs:6:22:6:31 | enter get_P1 | +| MultiImplementationB.cs:3:22:3:22 | enter get_P1 | MultiImplementationA.cs:6:22:6:31 | exit get_P1 | +| MultiImplementationB.cs:3:22:3:22 | enter get_P1 | MultiImplementationA.cs:6:28:6:31 | null | +| MultiImplementationB.cs:3:22:3:22 | enter get_P1 | MultiImplementationB.cs:3:22:3:22 | 0 | +| MultiImplementationB.cs:3:22:3:22 | enter get_P1 | MultiImplementationB.cs:3:22:3:22 | enter get_P1 | +| MultiImplementationB.cs:3:22:3:22 | enter get_P1 | MultiImplementationB.cs:3:22:3:22 | exit get_P1 | +| MultiImplementationB.cs:3:22:3:22 | exit get_P1 | MultiImplementationA.cs:6:22:6:31 | exit get_P1 | +| MultiImplementationB.cs:3:22:3:22 | exit get_P1 | MultiImplementationB.cs:3:22:3:22 | exit get_P1 | +| MultiImplementationB.cs:4:21:4:23 | enter get_P2 | MultiImplementationA.cs:7:21:7:23 | enter get_P2 | +| MultiImplementationB.cs:4:21:4:23 | enter get_P2 | MultiImplementationA.cs:7:21:7:23 | exit get_P2 | +| MultiImplementationB.cs:4:21:4:23 | enter get_P2 | MultiImplementationA.cs:7:25:7:39 | {...} | +| MultiImplementationB.cs:4:21:4:23 | enter get_P2 | MultiImplementationB.cs:4:21:4:23 | enter get_P2 | +| MultiImplementationB.cs:4:21:4:23 | enter get_P2 | MultiImplementationB.cs:4:21:4:23 | exit get_P2 | +| MultiImplementationB.cs:4:21:4:23 | enter get_P2 | MultiImplementationB.cs:4:25:4:37 | {...} | +| MultiImplementationB.cs:4:21:4:23 | exit get_P2 | MultiImplementationA.cs:7:21:7:23 | exit get_P2 | +| MultiImplementationB.cs:4:21:4:23 | exit get_P2 | MultiImplementationB.cs:4:21:4:23 | exit get_P2 | +| MultiImplementationB.cs:4:25:4:37 | {...} | MultiImplementationB.cs:4:25:4:37 | {...} | +| MultiImplementationB.cs:4:39:4:41 | enter set_P2 | MultiImplementationA.cs:7:41:7:43 | enter set_P2 | +| MultiImplementationB.cs:4:39:4:41 | enter set_P2 | MultiImplementationA.cs:7:41:7:43 | exit set_P2 | +| MultiImplementationB.cs:4:39:4:41 | enter set_P2 | MultiImplementationA.cs:7:45:7:59 | {...} | +| MultiImplementationB.cs:4:39:4:41 | enter set_P2 | MultiImplementationB.cs:4:39:4:41 | enter set_P2 | +| MultiImplementationB.cs:4:39:4:41 | enter set_P2 | MultiImplementationB.cs:4:39:4:41 | exit set_P2 | +| MultiImplementationB.cs:4:39:4:41 | enter set_P2 | MultiImplementationB.cs:4:43:4:45 | {...} | +| MultiImplementationB.cs:4:39:4:41 | exit set_P2 | MultiImplementationA.cs:7:41:7:43 | exit set_P2 | +| MultiImplementationB.cs:4:39:4:41 | exit set_P2 | MultiImplementationB.cs:4:39:4:41 | exit set_P2 | +| MultiImplementationB.cs:4:43:4:45 | {...} | MultiImplementationB.cs:4:43:4:45 | {...} | +| MultiImplementationB.cs:5:16:5:16 | enter M | MultiImplementationA.cs:8:16:8:16 | enter M | +| MultiImplementationB.cs:5:16:5:16 | enter M | MultiImplementationA.cs:8:16:8:16 | exit M | +| MultiImplementationB.cs:5:16:5:16 | enter M | MultiImplementationA.cs:8:29:8:32 | null | +| MultiImplementationB.cs:5:16:5:16 | enter M | MultiImplementationB.cs:5:16:5:16 | enter M | +| MultiImplementationB.cs:5:16:5:16 | enter M | MultiImplementationB.cs:5:16:5:16 | exit M | +| MultiImplementationB.cs:5:16:5:16 | enter M | MultiImplementationB.cs:5:23:5:23 | 2 | +| MultiImplementationB.cs:5:16:5:16 | exit M | MultiImplementationA.cs:8:16:8:16 | exit M | +| MultiImplementationB.cs:5:16:5:16 | exit M | MultiImplementationB.cs:5:16:5:16 | exit M | +| MultiImplementationB.cs:5:23:5:23 | 2 | MultiImplementationB.cs:5:23:5:23 | 2 | +| MultiImplementationB.cs:11:16:11:16 | this access | MultiImplementationB.cs:11:16:11:16 | this access | +| MultiImplementationB.cs:12:31:12:40 | enter get_Item | MultiImplementationA.cs:14:31:14:31 | access to parameter i | +| MultiImplementationB.cs:12:31:12:40 | enter get_Item | MultiImplementationA.cs:14:31:14:31 | enter get_Item | +| MultiImplementationB.cs:12:31:12:40 | enter get_Item | MultiImplementationA.cs:14:31:14:31 | exit get_Item | +| MultiImplementationB.cs:12:31:12:40 | enter get_Item | MultiImplementationB.cs:12:31:12:40 | enter get_Item | +| MultiImplementationB.cs:12:31:12:40 | enter get_Item | MultiImplementationB.cs:12:31:12:40 | exit get_Item | +| MultiImplementationB.cs:12:31:12:40 | enter get_Item | MultiImplementationB.cs:12:37:12:40 | null | +| MultiImplementationB.cs:12:31:12:40 | exit get_Item | MultiImplementationA.cs:14:31:14:31 | exit get_Item | +| MultiImplementationB.cs:12:31:12:40 | exit get_Item | MultiImplementationB.cs:12:31:12:40 | exit get_Item | +| MultiImplementationB.cs:12:37:12:40 | null | MultiImplementationB.cs:12:37:12:40 | null | +| MultiImplementationB.cs:13:36:13:38 | enter get_Item | MultiImplementationA.cs:15:36:15:38 | enter get_Item | +| MultiImplementationB.cs:13:36:13:38 | enter get_Item | MultiImplementationA.cs:15:36:15:38 | exit get_Item | +| MultiImplementationB.cs:13:36:13:38 | enter get_Item | MultiImplementationA.cs:15:40:15:52 | {...} | +| MultiImplementationB.cs:13:36:13:38 | enter get_Item | MultiImplementationB.cs:13:36:13:38 | enter get_Item | +| MultiImplementationB.cs:13:36:13:38 | enter get_Item | MultiImplementationB.cs:13:36:13:38 | exit get_Item | +| MultiImplementationB.cs:13:36:13:38 | enter get_Item | MultiImplementationB.cs:13:40:13:54 | {...} | +| MultiImplementationB.cs:13:36:13:38 | exit get_Item | MultiImplementationA.cs:15:36:15:38 | exit get_Item | +| MultiImplementationB.cs:13:36:13:38 | exit get_Item | MultiImplementationB.cs:13:36:13:38 | exit get_Item | +| MultiImplementationB.cs:13:40:13:54 | {...} | MultiImplementationB.cs:13:40:13:54 | {...} | +| MultiImplementationB.cs:13:56:13:58 | enter set_Item | MultiImplementationA.cs:15:54:15:56 | enter set_Item | +| MultiImplementationB.cs:13:56:13:58 | enter set_Item | MultiImplementationA.cs:15:54:15:56 | exit set_Item | +| MultiImplementationB.cs:13:56:13:58 | enter set_Item | MultiImplementationA.cs:15:58:15:60 | {...} | +| MultiImplementationB.cs:13:56:13:58 | enter set_Item | MultiImplementationB.cs:13:56:13:58 | enter set_Item | +| MultiImplementationB.cs:13:56:13:58 | enter set_Item | MultiImplementationB.cs:13:56:13:58 | exit set_Item | +| MultiImplementationB.cs:13:56:13:58 | enter set_Item | MultiImplementationB.cs:13:60:13:62 | {...} | +| MultiImplementationB.cs:13:56:13:58 | exit set_Item | MultiImplementationA.cs:15:54:15:56 | exit set_Item | +| MultiImplementationB.cs:13:56:13:58 | exit set_Item | MultiImplementationB.cs:13:56:13:58 | exit set_Item | +| MultiImplementationB.cs:13:60:13:62 | {...} | MultiImplementationB.cs:13:60:13:62 | {...} | +| MultiImplementationB.cs:14:17:14:18 | enter M1 | MultiImplementationA.cs:16:17:16:18 | enter M1 | +| MultiImplementationB.cs:14:17:14:18 | enter M1 | MultiImplementationA.cs:16:17:16:18 | exit M1 | +| MultiImplementationB.cs:14:17:14:18 | enter M1 | MultiImplementationA.cs:17:5:19:5 | {...} | +| MultiImplementationB.cs:14:17:14:18 | enter M1 | MultiImplementationB.cs:14:17:14:18 | enter M1 | +| MultiImplementationB.cs:14:17:14:18 | enter M1 | MultiImplementationB.cs:14:17:14:18 | exit M1 | +| MultiImplementationB.cs:14:17:14:18 | enter M1 | MultiImplementationB.cs:15:5:17:5 | {...} | +| MultiImplementationB.cs:14:17:14:18 | exit M1 | MultiImplementationA.cs:16:17:16:18 | exit M1 | +| MultiImplementationB.cs:14:17:14:18 | exit M1 | MultiImplementationB.cs:14:17:14:18 | exit M1 | +| MultiImplementationB.cs:15:5:17:5 | {...} | MultiImplementationB.cs:15:5:17:5 | {...} | +| MultiImplementationB.cs:16:9:16:31 | enter M2 | MultiImplementationB.cs:16:9:16:31 | enter M2 | +| MultiImplementationB.cs:18:12:18:13 | enter C2 | MultiImplementationA.cs:13:16:13:16 | this access | +| MultiImplementationB.cs:18:12:18:13 | enter C2 | MultiImplementationA.cs:20:12:20:13 | enter C2 | +| MultiImplementationB.cs:18:12:18:13 | enter C2 | MultiImplementationA.cs:20:12:20:13 | exit C2 | +| MultiImplementationB.cs:18:12:18:13 | enter C2 | MultiImplementationA.cs:20:22:20:31 | {...} | +| MultiImplementationB.cs:18:12:18:13 | enter C2 | MultiImplementationA.cs:24:16:24:16 | this access | +| MultiImplementationB.cs:18:12:18:13 | enter C2 | MultiImplementationB.cs:11:16:11:16 | this access | +| MultiImplementationB.cs:18:12:18:13 | enter C2 | MultiImplementationB.cs:18:12:18:13 | enter C2 | +| MultiImplementationB.cs:18:12:18:13 | enter C2 | MultiImplementationB.cs:18:12:18:13 | exit C2 | +| MultiImplementationB.cs:18:12:18:13 | enter C2 | MultiImplementationB.cs:18:22:18:36 | {...} | +| MultiImplementationB.cs:18:12:18:13 | enter C2 | MultiImplementationB.cs:22:16:22:16 | this access | +| MultiImplementationB.cs:18:12:18:13 | exit C2 | MultiImplementationA.cs:20:12:20:13 | exit C2 | +| MultiImplementationB.cs:18:12:18:13 | exit C2 | MultiImplementationB.cs:18:12:18:13 | exit C2 | +| MultiImplementationB.cs:18:22:18:36 | {...} | MultiImplementationB.cs:18:22:18:36 | {...} | +| MultiImplementationB.cs:19:12:19:13 | enter C2 | MultiImplementationA.cs:21:12:21:13 | enter C2 | +| MultiImplementationB.cs:19:12:19:13 | enter C2 | MultiImplementationA.cs:21:12:21:13 | exit C2 | +| MultiImplementationB.cs:19:12:19:13 | enter C2 | MultiImplementationA.cs:21:24:21:24 | 0 | +| MultiImplementationB.cs:19:12:19:13 | enter C2 | MultiImplementationA.cs:21:27:21:29 | {...} | +| MultiImplementationB.cs:19:12:19:13 | enter C2 | MultiImplementationB.cs:19:12:19:13 | enter C2 | +| MultiImplementationB.cs:19:12:19:13 | enter C2 | MultiImplementationB.cs:19:12:19:13 | exit C2 | +| MultiImplementationB.cs:19:12:19:13 | enter C2 | MultiImplementationB.cs:19:24:19:24 | 1 | +| MultiImplementationB.cs:19:12:19:13 | enter C2 | MultiImplementationB.cs:19:27:19:29 | {...} | +| MultiImplementationB.cs:19:12:19:13 | exit C2 | MultiImplementationA.cs:21:12:21:13 | exit C2 | +| MultiImplementationB.cs:19:12:19:13 | exit C2 | MultiImplementationB.cs:19:12:19:13 | exit C2 | +| MultiImplementationB.cs:19:24:19:24 | 1 | MultiImplementationB.cs:19:24:19:24 | 1 | +| MultiImplementationB.cs:19:27:19:29 | {...} | MultiImplementationB.cs:19:27:19:29 | {...} | +| MultiImplementationB.cs:20:6:20:7 | enter ~C2 | MultiImplementationA.cs:22:6:22:7 | enter ~C2 | +| MultiImplementationB.cs:20:6:20:7 | enter ~C2 | MultiImplementationA.cs:22:6:22:7 | exit ~C2 | +| MultiImplementationB.cs:20:6:20:7 | enter ~C2 | MultiImplementationA.cs:22:11:22:13 | {...} | +| MultiImplementationB.cs:20:6:20:7 | enter ~C2 | MultiImplementationB.cs:20:6:20:7 | enter ~C2 | +| MultiImplementationB.cs:20:6:20:7 | enter ~C2 | MultiImplementationB.cs:20:6:20:7 | exit ~C2 | +| MultiImplementationB.cs:20:6:20:7 | enter ~C2 | MultiImplementationB.cs:20:11:20:25 | {...} | +| MultiImplementationB.cs:20:6:20:7 | exit ~C2 | MultiImplementationA.cs:22:6:22:7 | exit ~C2 | +| MultiImplementationB.cs:20:6:20:7 | exit ~C2 | MultiImplementationB.cs:20:6:20:7 | exit ~C2 | +| MultiImplementationB.cs:20:11:20:25 | {...} | MultiImplementationB.cs:20:11:20:25 | {...} | +| MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | +| MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | MultiImplementationA.cs:23:28:23:35 | exit implicit conversion | +| MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | MultiImplementationA.cs:23:50:23:53 | null | +| MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | +| MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | MultiImplementationB.cs:21:28:21:35 | exit implicit conversion | +| MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | MultiImplementationB.cs:21:56:21:59 | null | +| MultiImplementationB.cs:21:28:21:35 | exit implicit conversion | MultiImplementationA.cs:23:28:23:35 | exit implicit conversion | +| MultiImplementationB.cs:21:28:21:35 | exit implicit conversion | MultiImplementationB.cs:21:28:21:35 | exit implicit conversion | +| MultiImplementationB.cs:21:56:21:59 | null | MultiImplementationB.cs:21:56:21:59 | null | +| MultiImplementationB.cs:22:16:22:16 | this access | MultiImplementationB.cs:22:16:22:16 | this access | +| MultiImplementationB.cs:27:21:27:23 | enter get_P3 | MultiImplementationA.cs:30:21:30:23 | enter get_P3 | +| MultiImplementationB.cs:27:21:27:23 | enter get_P3 | MultiImplementationB.cs:27:21:27:23 | enter get_P3 | +| MultiImplementationB.cs:32:9:32:10 | enter M1 | MultiImplementationA.cs:36:9:36:10 | enter M1 | +| MultiImplementationB.cs:32:9:32:10 | enter M1 | MultiImplementationA.cs:36:9:36:10 | exit M1 | +| MultiImplementationB.cs:32:9:32:10 | enter M1 | MultiImplementationA.cs:36:14:36:28 | {...} | +| MultiImplementationB.cs:32:9:32:10 | enter M1 | MultiImplementationB.cs:32:9:32:10 | enter M1 | +| MultiImplementationB.cs:32:9:32:10 | enter M1 | MultiImplementationB.cs:32:9:32:10 | exit M1 | +| MultiImplementationB.cs:32:9:32:10 | enter M1 | MultiImplementationB.cs:32:17:32:17 | 0 | +| MultiImplementationB.cs:32:9:32:10 | exit M1 | MultiImplementationA.cs:36:9:36:10 | exit M1 | +| MultiImplementationB.cs:32:9:32:10 | exit M1 | MultiImplementationB.cs:32:9:32:10 | exit M1 | +| MultiImplementationB.cs:32:17:32:17 | 0 | MultiImplementationB.cs:32:17:32:17 | 0 | | NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:9:3:10 | enter M1 | | NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:9:3:10 | exit M1 | | NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:28:3:28 | 0 | @@ -7564,79 +9662,79 @@ blockDominance | Switch.cs:55:10:55:11 | enter M5 | Switch.cs:55:10:55:11 | enter M5 | | Switch.cs:66:10:66:11 | enter M6 | Switch.cs:66:10:66:11 | enter M6 | | Switch.cs:66:10:66:11 | enter M6 | Switch.cs:66:10:66:11 | exit M6 | -| Switch.cs:66:10:66:11 | enter M6 | Switch.cs:73:15:73:20 | break; | +| Switch.cs:66:10:66:11 | enter M6 | Switch.cs:73:17:73:22 | break; | | Switch.cs:66:10:66:11 | exit M6 | Switch.cs:66:10:66:11 | exit M6 | -| Switch.cs:73:15:73:20 | break; | Switch.cs:73:15:73:20 | break; | +| Switch.cs:73:17:73:22 | break; | Switch.cs:73:17:73:22 | break; | | Switch.cs:77:10:77:11 | enter M7 | Switch.cs:77:10:77:11 | enter M7 | | Switch.cs:77:10:77:11 | enter M7 | Switch.cs:77:10:77:11 | exit M7 | -| Switch.cs:77:10:77:11 | enter M7 | Switch.cs:82:22:82:25 | true | -| Switch.cs:77:10:77:11 | enter M7 | Switch.cs:83:13:83:20 | case ...: | -| Switch.cs:77:10:77:11 | enter M7 | Switch.cs:84:15:85:22 | if (...) ... | -| Switch.cs:77:10:77:11 | enter M7 | Switch.cs:85:17:85:22 | break; | -| Switch.cs:77:10:77:11 | enter M7 | Switch.cs:86:22:86:25 | true | +| Switch.cs:77:10:77:11 | enter M7 | Switch.cs:82:24:82:27 | true | +| Switch.cs:77:10:77:11 | enter M7 | Switch.cs:83:13:83:19 | case ...: | +| Switch.cs:77:10:77:11 | enter M7 | Switch.cs:84:17:85:26 | if (...) ... | +| Switch.cs:77:10:77:11 | enter M7 | Switch.cs:85:21:85:26 | break; | +| Switch.cs:77:10:77:11 | enter M7 | Switch.cs:86:24:86:27 | true | | Switch.cs:77:10:77:11 | enter M7 | Switch.cs:88:16:88:20 | false | | Switch.cs:77:10:77:11 | exit M7 | Switch.cs:77:10:77:11 | exit M7 | -| Switch.cs:82:22:82:25 | true | Switch.cs:82:22:82:25 | true | -| Switch.cs:83:13:83:20 | case ...: | Switch.cs:83:13:83:20 | case ...: | -| Switch.cs:83:13:83:20 | case ...: | Switch.cs:84:15:85:22 | if (...) ... | -| Switch.cs:83:13:83:20 | case ...: | Switch.cs:85:17:85:22 | break; | -| Switch.cs:83:13:83:20 | case ...: | Switch.cs:86:22:86:25 | true | -| Switch.cs:83:13:83:20 | case ...: | Switch.cs:88:16:88:20 | false | -| Switch.cs:84:15:85:22 | if (...) ... | Switch.cs:84:15:85:22 | if (...) ... | -| Switch.cs:84:15:85:22 | if (...) ... | Switch.cs:85:17:85:22 | break; | -| Switch.cs:84:15:85:22 | if (...) ... | Switch.cs:86:22:86:25 | true | -| Switch.cs:85:17:85:22 | break; | Switch.cs:85:17:85:22 | break; | -| Switch.cs:86:22:86:25 | true | Switch.cs:86:22:86:25 | true | +| Switch.cs:82:24:82:27 | true | Switch.cs:82:24:82:27 | true | +| Switch.cs:83:13:83:19 | case ...: | Switch.cs:83:13:83:19 | case ...: | +| Switch.cs:83:13:83:19 | case ...: | Switch.cs:84:17:85:26 | if (...) ... | +| Switch.cs:83:13:83:19 | case ...: | Switch.cs:85:21:85:26 | break; | +| Switch.cs:83:13:83:19 | case ...: | Switch.cs:86:24:86:27 | true | +| Switch.cs:83:13:83:19 | case ...: | Switch.cs:88:16:88:20 | false | +| Switch.cs:84:17:85:26 | if (...) ... | Switch.cs:84:17:85:26 | if (...) ... | +| Switch.cs:84:17:85:26 | if (...) ... | Switch.cs:85:21:85:26 | break; | +| Switch.cs:84:17:85:26 | if (...) ... | Switch.cs:86:24:86:27 | true | +| Switch.cs:85:21:85:26 | break; | Switch.cs:85:21:85:26 | break; | +| Switch.cs:86:24:86:27 | true | Switch.cs:86:24:86:27 | true | | Switch.cs:88:16:88:20 | false | Switch.cs:88:16:88:20 | false | | Switch.cs:91:10:91:11 | enter M8 | Switch.cs:91:10:91:11 | enter M8 | | Switch.cs:91:10:91:11 | enter M8 | Switch.cs:91:10:91:11 | exit M8 | -| Switch.cs:91:10:91:11 | enter M8 | Switch.cs:96:22:96:25 | true | +| Switch.cs:91:10:91:11 | enter M8 | Switch.cs:96:24:96:27 | true | | Switch.cs:91:10:91:11 | enter M8 | Switch.cs:98:16:98:20 | false | | Switch.cs:91:10:91:11 | exit M8 | Switch.cs:91:10:91:11 | exit M8 | -| Switch.cs:96:22:96:25 | true | Switch.cs:96:22:96:25 | true | +| Switch.cs:96:24:96:27 | true | Switch.cs:96:24:96:27 | true | | Switch.cs:98:16:98:20 | false | Switch.cs:98:16:98:20 | false | | Switch.cs:101:9:101:10 | enter M9 | Switch.cs:101:9:101:10 | enter M9 | | Switch.cs:101:9:101:10 | enter M9 | Switch.cs:101:9:101:10 | exit M9 | | Switch.cs:101:9:101:10 | enter M9 | Switch.cs:103:19:103:25 | access to property Length | -| Switch.cs:101:9:101:10 | enter M9 | Switch.cs:105:13:105:20 | case ...: | -| Switch.cs:101:9:101:10 | enter M9 | Switch.cs:105:29:105:29 | 0 | -| Switch.cs:101:9:101:10 | enter M9 | Switch.cs:106:13:106:20 | case ...: | -| Switch.cs:101:9:101:10 | enter M9 | Switch.cs:106:29:106:29 | 1 | +| Switch.cs:101:9:101:10 | enter M9 | Switch.cs:105:13:105:19 | case ...: | +| Switch.cs:101:9:101:10 | enter M9 | Switch.cs:105:28:105:28 | 0 | +| Switch.cs:101:9:101:10 | enter M9 | Switch.cs:106:13:106:19 | case ...: | +| Switch.cs:101:9:101:10 | enter M9 | Switch.cs:106:28:106:28 | 1 | | Switch.cs:101:9:101:10 | enter M9 | Switch.cs:108:17:108:17 | 1 | | Switch.cs:101:9:101:10 | exit M9 | Switch.cs:101:9:101:10 | exit M9 | | Switch.cs:103:19:103:25 | access to property Length | Switch.cs:103:19:103:25 | access to property Length | -| Switch.cs:105:13:105:20 | case ...: | Switch.cs:101:9:101:10 | exit M9 | -| Switch.cs:105:13:105:20 | case ...: | Switch.cs:105:13:105:20 | case ...: | -| Switch.cs:105:13:105:20 | case ...: | Switch.cs:105:29:105:29 | 0 | -| Switch.cs:105:13:105:20 | case ...: | Switch.cs:106:13:106:20 | case ...: | -| Switch.cs:105:13:105:20 | case ...: | Switch.cs:106:29:106:29 | 1 | -| Switch.cs:105:13:105:20 | case ...: | Switch.cs:108:17:108:17 | 1 | -| Switch.cs:105:29:105:29 | 0 | Switch.cs:105:29:105:29 | 0 | -| Switch.cs:106:13:106:20 | case ...: | Switch.cs:106:13:106:20 | case ...: | -| Switch.cs:106:13:106:20 | case ...: | Switch.cs:106:29:106:29 | 1 | -| Switch.cs:106:13:106:20 | case ...: | Switch.cs:108:17:108:17 | 1 | -| Switch.cs:106:29:106:29 | 1 | Switch.cs:106:29:106:29 | 1 | +| Switch.cs:105:13:105:19 | case ...: | Switch.cs:101:9:101:10 | exit M9 | +| Switch.cs:105:13:105:19 | case ...: | Switch.cs:105:13:105:19 | case ...: | +| Switch.cs:105:13:105:19 | case ...: | Switch.cs:105:28:105:28 | 0 | +| Switch.cs:105:13:105:19 | case ...: | Switch.cs:106:13:106:19 | case ...: | +| Switch.cs:105:13:105:19 | case ...: | Switch.cs:106:28:106:28 | 1 | +| Switch.cs:105:13:105:19 | case ...: | Switch.cs:108:17:108:17 | 1 | +| Switch.cs:105:28:105:28 | 0 | Switch.cs:105:28:105:28 | 0 | +| Switch.cs:106:13:106:19 | case ...: | Switch.cs:106:13:106:19 | case ...: | +| Switch.cs:106:13:106:19 | case ...: | Switch.cs:106:28:106:28 | 1 | +| Switch.cs:106:13:106:19 | case ...: | Switch.cs:108:17:108:17 | 1 | +| Switch.cs:106:28:106:28 | 1 | Switch.cs:106:28:106:28 | 1 | | Switch.cs:108:17:108:17 | 1 | Switch.cs:108:17:108:17 | 1 | | Switch.cs:111:17:111:21 | enter Throw | Switch.cs:111:17:111:21 | enter Throw | | Switch.cs:113:9:113:11 | enter M10 | Switch.cs:113:9:113:11 | enter M10 | | Switch.cs:113:9:113:11 | enter M10 | Switch.cs:113:9:113:11 | exit M10 | | Switch.cs:113:9:113:11 | enter M10 | Switch.cs:117:25:117:25 | access to parameter s | -| Switch.cs:113:9:113:11 | enter M10 | Switch.cs:117:43:117:43 | 1 | -| Switch.cs:113:9:113:11 | enter M10 | Switch.cs:118:13:118:33 | case ...: | +| Switch.cs:113:9:113:11 | enter M10 | Switch.cs:117:44:117:44 | 1 | +| Switch.cs:113:9:113:11 | enter M10 | Switch.cs:118:13:118:34 | case ...: | | Switch.cs:113:9:113:11 | enter M10 | Switch.cs:118:25:118:25 | access to parameter s | -| Switch.cs:113:9:113:11 | enter M10 | Switch.cs:118:42:118:42 | 2 | +| Switch.cs:113:9:113:11 | enter M10 | Switch.cs:118:43:118:43 | 2 | | Switch.cs:113:9:113:11 | enter M10 | Switch.cs:120:17:120:17 | 1 | | Switch.cs:113:9:113:11 | exit M10 | Switch.cs:113:9:113:11 | exit M10 | | Switch.cs:117:25:117:25 | access to parameter s | Switch.cs:117:25:117:25 | access to parameter s | -| Switch.cs:117:25:117:25 | access to parameter s | Switch.cs:117:43:117:43 | 1 | -| Switch.cs:117:43:117:43 | 1 | Switch.cs:117:43:117:43 | 1 | -| Switch.cs:118:13:118:33 | case ...: | Switch.cs:118:13:118:33 | case ...: | -| Switch.cs:118:13:118:33 | case ...: | Switch.cs:118:25:118:25 | access to parameter s | -| Switch.cs:118:13:118:33 | case ...: | Switch.cs:118:42:118:42 | 2 | -| Switch.cs:118:13:118:33 | case ...: | Switch.cs:120:17:120:17 | 1 | +| Switch.cs:117:25:117:25 | access to parameter s | Switch.cs:117:44:117:44 | 1 | +| Switch.cs:117:44:117:44 | 1 | Switch.cs:117:44:117:44 | 1 | +| Switch.cs:118:13:118:34 | case ...: | Switch.cs:118:13:118:34 | case ...: | +| Switch.cs:118:13:118:34 | case ...: | Switch.cs:118:25:118:25 | access to parameter s | +| Switch.cs:118:13:118:34 | case ...: | Switch.cs:118:43:118:43 | 2 | +| Switch.cs:118:13:118:34 | case ...: | Switch.cs:120:17:120:17 | 1 | | Switch.cs:118:25:118:25 | access to parameter s | Switch.cs:118:25:118:25 | access to parameter s | -| Switch.cs:118:25:118:25 | access to parameter s | Switch.cs:118:42:118:42 | 2 | -| Switch.cs:118:42:118:42 | 2 | Switch.cs:118:42:118:42 | 2 | +| Switch.cs:118:25:118:25 | access to parameter s | Switch.cs:118:43:118:43 | 2 | +| Switch.cs:118:43:118:43 | 2 | Switch.cs:118:43:118:43 | 2 | | Switch.cs:120:17:120:17 | 1 | Switch.cs:120:17:120:17 | 1 | | Switch.cs:123:10:123:12 | enter M11 | Switch.cs:123:10:123:12 | enter M11 | | Switch.cs:123:10:123:12 | enter M11 | Switch.cs:123:10:123:12 | exit M11 | @@ -7684,6 +9782,24 @@ blockDominance | Switch.cs:150:13:150:19 | case ...: | Switch.cs:150:13:150:19 | case ...: | | Switch.cs:150:13:150:19 | case ...: | Switch.cs:150:28:150:28 | 2 | | Switch.cs:150:28:150:28 | 2 | Switch.cs:150:28:150:28 | 2 | +| Switch.cs:154:10:154:12 | enter M15 | Switch.cs:154:10:154:12 | enter M15 | +| Switch.cs:154:10:154:12 | enter M15 | Switch.cs:154:10:154:12 | exit M15 | +| Switch.cs:154:10:154:12 | enter M15 | Switch.cs:156:13:156:54 | String s = ... | +| Switch.cs:154:10:154:12 | enter M15 | Switch.cs:156:36:156:38 | "a" | +| Switch.cs:154:10:154:12 | enter M15 | Switch.cs:156:41:156:52 | ... => ... | +| Switch.cs:154:10:154:12 | enter M15 | Switch.cs:156:50:156:52 | "b" | +| Switch.cs:154:10:154:12 | enter M15 | Switch.cs:158:13:158:49 | ...; | +| Switch.cs:154:10:154:12 | enter M15 | Switch.cs:160:13:160:49 | ...; | +| Switch.cs:154:10:154:12 | exit M15 | Switch.cs:154:10:154:12 | exit M15 | +| Switch.cs:156:13:156:54 | String s = ... | Switch.cs:156:13:156:54 | String s = ... | +| Switch.cs:156:13:156:54 | String s = ... | Switch.cs:158:13:158:49 | ...; | +| Switch.cs:156:13:156:54 | String s = ... | Switch.cs:160:13:160:49 | ...; | +| Switch.cs:156:36:156:38 | "a" | Switch.cs:156:36:156:38 | "a" | +| Switch.cs:156:41:156:52 | ... => ... | Switch.cs:156:41:156:52 | ... => ... | +| Switch.cs:156:41:156:52 | ... => ... | Switch.cs:156:50:156:52 | "b" | +| Switch.cs:156:50:156:52 | "b" | Switch.cs:156:50:156:52 | "b" | +| Switch.cs:158:13:158:49 | ...; | Switch.cs:158:13:158:49 | ...; | +| Switch.cs:160:13:160:49 | ...; | Switch.cs:160:13:160:49 | ...; | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:3:10:3:10 | enter M | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:7:25:7:25 | ; | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:8:9:8:28 | ... ...; | @@ -8255,6 +10371,263 @@ postBlockDominance | ArrayCreation.cs:5:12:5:13 | enter M2 | ArrayCreation.cs:5:12:5:13 | enter M2 | | ArrayCreation.cs:7:11:7:12 | enter M3 | ArrayCreation.cs:7:11:7:12 | enter M3 | | ArrayCreation.cs:9:12:9:13 | enter M4 | ArrayCreation.cs:9:12:9:13 | enter M4 | +| Assert.cs:7:10:7:11 | enter M1 | Assert.cs:7:10:7:11 | enter M1 | +| Assert.cs:7:10:7:11 | exit M1 | Assert.cs:7:10:7:11 | enter M1 | +| Assert.cs:7:10:7:11 | exit M1 | Assert.cs:7:10:7:11 | exit M1 | +| Assert.cs:7:10:7:11 | exit M1 | Assert.cs:9:16:9:32 | String s = ... | +| Assert.cs:7:10:7:11 | exit M1 | Assert.cs:9:24:9:27 | null | +| Assert.cs:7:10:7:11 | exit M1 | Assert.cs:9:31:9:32 | "" | +| Assert.cs:7:10:7:11 | exit M1 | Assert.cs:10:9:10:31 | [assertion failure] call to method Assert | +| Assert.cs:7:10:7:11 | exit M1 | Assert.cs:10:9:10:31 | [assertion success] call to method Assert | +| Assert.cs:9:16:9:32 | String s = ... | Assert.cs:7:10:7:11 | enter M1 | +| Assert.cs:9:16:9:32 | String s = ... | Assert.cs:9:16:9:32 | String s = ... | +| Assert.cs:9:16:9:32 | String s = ... | Assert.cs:9:24:9:27 | null | +| Assert.cs:9:16:9:32 | String s = ... | Assert.cs:9:31:9:32 | "" | +| Assert.cs:9:24:9:27 | null | Assert.cs:9:24:9:27 | null | +| Assert.cs:9:31:9:32 | "" | Assert.cs:9:31:9:32 | "" | +| Assert.cs:10:9:10:31 | [assertion failure] call to method Assert | Assert.cs:10:9:10:31 | [assertion failure] call to method Assert | +| Assert.cs:10:9:10:31 | [assertion success] call to method Assert | Assert.cs:10:9:10:31 | [assertion success] call to method Assert | +| Assert.cs:14:10:14:11 | enter M2 | Assert.cs:14:10:14:11 | enter M2 | +| Assert.cs:14:10:14:11 | exit M2 | Assert.cs:14:10:14:11 | enter M2 | +| Assert.cs:14:10:14:11 | exit M2 | Assert.cs:14:10:14:11 | exit M2 | +| Assert.cs:14:10:14:11 | exit M2 | Assert.cs:16:16:16:32 | String s = ... | +| Assert.cs:14:10:14:11 | exit M2 | Assert.cs:16:24:16:27 | null | +| Assert.cs:14:10:14:11 | exit M2 | Assert.cs:16:31:16:32 | "" | +| Assert.cs:14:10:14:11 | exit M2 | Assert.cs:17:9:17:24 | [assertion failure] call to method IsNull | +| Assert.cs:14:10:14:11 | exit M2 | Assert.cs:17:9:17:24 | [assertion success] call to method IsNull | +| Assert.cs:16:16:16:32 | String s = ... | Assert.cs:14:10:14:11 | enter M2 | +| Assert.cs:16:16:16:32 | String s = ... | Assert.cs:16:16:16:32 | String s = ... | +| Assert.cs:16:16:16:32 | String s = ... | Assert.cs:16:24:16:27 | null | +| Assert.cs:16:16:16:32 | String s = ... | Assert.cs:16:31:16:32 | "" | +| Assert.cs:16:24:16:27 | null | Assert.cs:16:24:16:27 | null | +| Assert.cs:16:31:16:32 | "" | Assert.cs:16:31:16:32 | "" | +| Assert.cs:17:9:17:24 | [assertion failure] call to method IsNull | Assert.cs:17:9:17:24 | [assertion failure] call to method IsNull | +| Assert.cs:17:9:17:24 | [assertion success] call to method IsNull | Assert.cs:17:9:17:24 | [assertion success] call to method IsNull | +| Assert.cs:21:10:21:11 | enter M3 | Assert.cs:21:10:21:11 | enter M3 | +| Assert.cs:21:10:21:11 | exit M3 | Assert.cs:21:10:21:11 | enter M3 | +| Assert.cs:21:10:21:11 | exit M3 | Assert.cs:21:10:21:11 | exit M3 | +| Assert.cs:21:10:21:11 | exit M3 | Assert.cs:23:16:23:32 | String s = ... | +| Assert.cs:21:10:21:11 | exit M3 | Assert.cs:23:24:23:27 | null | +| Assert.cs:21:10:21:11 | exit M3 | Assert.cs:23:31:23:32 | "" | +| Assert.cs:21:10:21:11 | exit M3 | Assert.cs:24:9:24:27 | [assertion failure] call to method IsNotNull | +| Assert.cs:21:10:21:11 | exit M3 | Assert.cs:24:9:24:27 | [assertion success] call to method IsNotNull | +| Assert.cs:23:16:23:32 | String s = ... | Assert.cs:21:10:21:11 | enter M3 | +| Assert.cs:23:16:23:32 | String s = ... | Assert.cs:23:16:23:32 | String s = ... | +| Assert.cs:23:16:23:32 | String s = ... | Assert.cs:23:24:23:27 | null | +| Assert.cs:23:16:23:32 | String s = ... | Assert.cs:23:31:23:32 | "" | +| Assert.cs:23:24:23:27 | null | Assert.cs:23:24:23:27 | null | +| Assert.cs:23:31:23:32 | "" | Assert.cs:23:31:23:32 | "" | +| Assert.cs:24:9:24:27 | [assertion failure] call to method IsNotNull | Assert.cs:24:9:24:27 | [assertion failure] call to method IsNotNull | +| Assert.cs:24:9:24:27 | [assertion success] call to method IsNotNull | Assert.cs:24:9:24:27 | [assertion success] call to method IsNotNull | +| Assert.cs:28:10:28:11 | enter M4 | Assert.cs:28:10:28:11 | enter M4 | +| Assert.cs:28:10:28:11 | exit M4 | Assert.cs:28:10:28:11 | enter M4 | +| Assert.cs:28:10:28:11 | exit M4 | Assert.cs:28:10:28:11 | exit M4 | +| Assert.cs:28:10:28:11 | exit M4 | Assert.cs:30:16:30:32 | String s = ... | +| Assert.cs:28:10:28:11 | exit M4 | Assert.cs:30:24:30:27 | null | +| Assert.cs:28:10:28:11 | exit M4 | Assert.cs:30:31:30:32 | "" | +| Assert.cs:28:10:28:11 | exit M4 | Assert.cs:31:9:31:32 | [assertion failure] call to method IsTrue | +| Assert.cs:28:10:28:11 | exit M4 | Assert.cs:31:9:31:32 | [assertion success] call to method IsTrue | +| Assert.cs:30:16:30:32 | String s = ... | Assert.cs:28:10:28:11 | enter M4 | +| Assert.cs:30:16:30:32 | String s = ... | Assert.cs:30:16:30:32 | String s = ... | +| Assert.cs:30:16:30:32 | String s = ... | Assert.cs:30:24:30:27 | null | +| Assert.cs:30:16:30:32 | String s = ... | Assert.cs:30:31:30:32 | "" | +| Assert.cs:30:24:30:27 | null | Assert.cs:30:24:30:27 | null | +| Assert.cs:30:31:30:32 | "" | Assert.cs:30:31:30:32 | "" | +| Assert.cs:31:9:31:32 | [assertion failure] call to method IsTrue | Assert.cs:31:9:31:32 | [assertion failure] call to method IsTrue | +| Assert.cs:31:9:31:32 | [assertion success] call to method IsTrue | Assert.cs:31:9:31:32 | [assertion success] call to method IsTrue | +| Assert.cs:35:10:35:11 | enter M5 | Assert.cs:35:10:35:11 | enter M5 | +| Assert.cs:35:10:35:11 | exit M5 | Assert.cs:35:10:35:11 | enter M5 | +| Assert.cs:35:10:35:11 | exit M5 | Assert.cs:35:10:35:11 | exit M5 | +| Assert.cs:35:10:35:11 | exit M5 | Assert.cs:37:16:37:32 | String s = ... | +| Assert.cs:35:10:35:11 | exit M5 | Assert.cs:37:24:37:27 | null | +| Assert.cs:35:10:35:11 | exit M5 | Assert.cs:37:31:37:32 | "" | +| Assert.cs:35:10:35:11 | exit M5 | Assert.cs:38:9:38:32 | [assertion failure] call to method IsTrue | +| Assert.cs:35:10:35:11 | exit M5 | Assert.cs:38:9:38:32 | [assertion success] call to method IsTrue | +| Assert.cs:37:16:37:32 | String s = ... | Assert.cs:35:10:35:11 | enter M5 | +| Assert.cs:37:16:37:32 | String s = ... | Assert.cs:37:16:37:32 | String s = ... | +| Assert.cs:37:16:37:32 | String s = ... | Assert.cs:37:24:37:27 | null | +| Assert.cs:37:16:37:32 | String s = ... | Assert.cs:37:31:37:32 | "" | +| Assert.cs:37:24:37:27 | null | Assert.cs:37:24:37:27 | null | +| Assert.cs:37:31:37:32 | "" | Assert.cs:37:31:37:32 | "" | +| Assert.cs:38:9:38:32 | [assertion failure] call to method IsTrue | Assert.cs:38:9:38:32 | [assertion failure] call to method IsTrue | +| Assert.cs:38:9:38:32 | [assertion success] call to method IsTrue | Assert.cs:38:9:38:32 | [assertion success] call to method IsTrue | +| Assert.cs:42:10:42:11 | enter M6 | Assert.cs:42:10:42:11 | enter M6 | +| Assert.cs:42:10:42:11 | exit M6 | Assert.cs:42:10:42:11 | enter M6 | +| Assert.cs:42:10:42:11 | exit M6 | Assert.cs:42:10:42:11 | exit M6 | +| Assert.cs:42:10:42:11 | exit M6 | Assert.cs:44:16:44:32 | String s = ... | +| Assert.cs:42:10:42:11 | exit M6 | Assert.cs:44:24:44:27 | null | +| Assert.cs:42:10:42:11 | exit M6 | Assert.cs:44:31:44:32 | "" | +| Assert.cs:42:10:42:11 | exit M6 | Assert.cs:45:9:45:33 | [assertion failure] call to method IsFalse | +| Assert.cs:42:10:42:11 | exit M6 | Assert.cs:45:9:45:33 | [assertion success] call to method IsFalse | +| Assert.cs:44:16:44:32 | String s = ... | Assert.cs:42:10:42:11 | enter M6 | +| Assert.cs:44:16:44:32 | String s = ... | Assert.cs:44:16:44:32 | String s = ... | +| Assert.cs:44:16:44:32 | String s = ... | Assert.cs:44:24:44:27 | null | +| Assert.cs:44:16:44:32 | String s = ... | Assert.cs:44:31:44:32 | "" | +| Assert.cs:44:24:44:27 | null | Assert.cs:44:24:44:27 | null | +| Assert.cs:44:31:44:32 | "" | Assert.cs:44:31:44:32 | "" | +| Assert.cs:45:9:45:33 | [assertion failure] call to method IsFalse | Assert.cs:45:9:45:33 | [assertion failure] call to method IsFalse | +| Assert.cs:45:9:45:33 | [assertion success] call to method IsFalse | Assert.cs:45:9:45:33 | [assertion success] call to method IsFalse | +| Assert.cs:49:10:49:11 | enter M7 | Assert.cs:49:10:49:11 | enter M7 | +| Assert.cs:49:10:49:11 | exit M7 | Assert.cs:49:10:49:11 | enter M7 | +| Assert.cs:49:10:49:11 | exit M7 | Assert.cs:49:10:49:11 | exit M7 | +| Assert.cs:49:10:49:11 | exit M7 | Assert.cs:51:16:51:32 | String s = ... | +| Assert.cs:49:10:49:11 | exit M7 | Assert.cs:51:24:51:27 | null | +| Assert.cs:49:10:49:11 | exit M7 | Assert.cs:51:31:51:32 | "" | +| Assert.cs:49:10:49:11 | exit M7 | Assert.cs:52:9:52:33 | [assertion failure] call to method IsFalse | +| Assert.cs:49:10:49:11 | exit M7 | Assert.cs:52:9:52:33 | [assertion success] call to method IsFalse | +| Assert.cs:51:16:51:32 | String s = ... | Assert.cs:49:10:49:11 | enter M7 | +| Assert.cs:51:16:51:32 | String s = ... | Assert.cs:51:16:51:32 | String s = ... | +| Assert.cs:51:16:51:32 | String s = ... | Assert.cs:51:24:51:27 | null | +| Assert.cs:51:16:51:32 | String s = ... | Assert.cs:51:31:51:32 | "" | +| Assert.cs:51:24:51:27 | null | Assert.cs:51:24:51:27 | null | +| Assert.cs:51:31:51:32 | "" | Assert.cs:51:31:51:32 | "" | +| Assert.cs:52:9:52:33 | [assertion failure] call to method IsFalse | Assert.cs:52:9:52:33 | [assertion failure] call to method IsFalse | +| Assert.cs:52:9:52:33 | [assertion success] call to method IsFalse | Assert.cs:52:9:52:33 | [assertion success] call to method IsFalse | +| Assert.cs:56:10:56:11 | enter M8 | Assert.cs:56:10:56:11 | enter M8 | +| Assert.cs:56:10:56:11 | exit M8 | Assert.cs:56:10:56:11 | enter M8 | +| Assert.cs:56:10:56:11 | exit M8 | Assert.cs:56:10:56:11 | exit M8 | +| Assert.cs:56:10:56:11 | exit M8 | Assert.cs:58:24:58:27 | [b (line 56): true] null | +| Assert.cs:56:10:56:11 | exit M8 | Assert.cs:58:31:58:32 | [b (line 56): false] "" | +| Assert.cs:56:10:56:11 | exit M8 | Assert.cs:59:9:59:37 | [assertion failure] call to method IsTrue | +| Assert.cs:56:10:56:11 | exit M8 | Assert.cs:59:36:59:36 | [b (line 56): false] access to parameter b | +| Assert.cs:56:10:56:11 | exit M8 | Assert.cs:59:36:59:36 | [b (line 56): true] access to parameter b | +| Assert.cs:58:24:58:27 | [b (line 56): true] null | Assert.cs:58:24:58:27 | [b (line 56): true] null | +| Assert.cs:58:31:58:32 | [b (line 56): false] "" | Assert.cs:58:31:58:32 | [b (line 56): false] "" | +| Assert.cs:59:9:59:37 | [assertion failure] call to method IsTrue | Assert.cs:58:31:58:32 | [b (line 56): false] "" | +| Assert.cs:59:9:59:37 | [assertion failure] call to method IsTrue | Assert.cs:59:9:59:37 | [assertion failure] call to method IsTrue | +| Assert.cs:59:9:59:37 | [assertion failure] call to method IsTrue | Assert.cs:59:36:59:36 | [b (line 56): false] access to parameter b | +| Assert.cs:59:36:59:36 | [b (line 56): false] access to parameter b | Assert.cs:59:36:59:36 | [b (line 56): false] access to parameter b | +| Assert.cs:59:36:59:36 | [b (line 56): true] access to parameter b | Assert.cs:59:36:59:36 | [b (line 56): true] access to parameter b | +| Assert.cs:63:10:63:11 | enter M9 | Assert.cs:63:10:63:11 | enter M9 | +| Assert.cs:63:10:63:11 | exit M9 | Assert.cs:63:10:63:11 | enter M9 | +| Assert.cs:63:10:63:11 | exit M9 | Assert.cs:63:10:63:11 | exit M9 | +| Assert.cs:63:10:63:11 | exit M9 | Assert.cs:65:24:65:27 | [b (line 63): true] null | +| Assert.cs:63:10:63:11 | exit M9 | Assert.cs:65:31:65:32 | [b (line 63): false] "" | +| Assert.cs:63:10:63:11 | exit M9 | Assert.cs:66:9:66:38 | [assertion failure] call to method IsFalse | +| Assert.cs:63:10:63:11 | exit M9 | Assert.cs:66:37:66:37 | [b (line 63): false] access to parameter b | +| Assert.cs:63:10:63:11 | exit M9 | Assert.cs:66:37:66:37 | [b (line 63): true] access to parameter b | +| Assert.cs:65:24:65:27 | [b (line 63): true] null | Assert.cs:65:24:65:27 | [b (line 63): true] null | +| Assert.cs:65:31:65:32 | [b (line 63): false] "" | Assert.cs:65:31:65:32 | [b (line 63): false] "" | +| Assert.cs:66:9:66:38 | [assertion failure] call to method IsFalse | Assert.cs:65:24:65:27 | [b (line 63): true] null | +| Assert.cs:66:9:66:38 | [assertion failure] call to method IsFalse | Assert.cs:66:9:66:38 | [assertion failure] call to method IsFalse | +| Assert.cs:66:9:66:38 | [assertion failure] call to method IsFalse | Assert.cs:66:37:66:37 | [b (line 63): true] access to parameter b | +| Assert.cs:66:37:66:37 | [b (line 63): false] access to parameter b | Assert.cs:66:37:66:37 | [b (line 63): false] access to parameter b | +| Assert.cs:66:37:66:37 | [b (line 63): true] access to parameter b | Assert.cs:66:37:66:37 | [b (line 63): true] access to parameter b | +| Assert.cs:70:10:70:12 | enter M10 | Assert.cs:70:10:70:12 | enter M10 | +| Assert.cs:70:10:70:12 | exit M10 | Assert.cs:70:10:70:12 | enter M10 | +| Assert.cs:70:10:70:12 | exit M10 | Assert.cs:70:10:70:12 | exit M10 | +| Assert.cs:70:10:70:12 | exit M10 | Assert.cs:72:24:72:27 | [b (line 70): true] null | +| Assert.cs:70:10:70:12 | exit M10 | Assert.cs:72:31:72:32 | [b (line 70): false] "" | +| Assert.cs:70:10:70:12 | exit M10 | Assert.cs:73:9:73:37 | [assertion failure] call to method IsTrue | +| Assert.cs:70:10:70:12 | exit M10 | Assert.cs:73:36:73:36 | [b (line 70): false] access to parameter b | +| Assert.cs:70:10:70:12 | exit M10 | Assert.cs:73:36:73:36 | [b (line 70): true] access to parameter b | +| Assert.cs:72:24:72:27 | [b (line 70): true] null | Assert.cs:72:24:72:27 | [b (line 70): true] null | +| Assert.cs:72:31:72:32 | [b (line 70): false] "" | Assert.cs:72:31:72:32 | [b (line 70): false] "" | +| Assert.cs:73:9:73:37 | [assertion failure] call to method IsTrue | Assert.cs:72:31:72:32 | [b (line 70): false] "" | +| Assert.cs:73:9:73:37 | [assertion failure] call to method IsTrue | Assert.cs:73:9:73:37 | [assertion failure] call to method IsTrue | +| Assert.cs:73:9:73:37 | [assertion failure] call to method IsTrue | Assert.cs:73:36:73:36 | [b (line 70): false] access to parameter b | +| Assert.cs:73:36:73:36 | [b (line 70): false] access to parameter b | Assert.cs:73:36:73:36 | [b (line 70): false] access to parameter b | +| Assert.cs:73:36:73:36 | [b (line 70): true] access to parameter b | Assert.cs:73:36:73:36 | [b (line 70): true] access to parameter b | +| Assert.cs:77:10:77:12 | enter M11 | Assert.cs:77:10:77:12 | enter M11 | +| Assert.cs:77:10:77:12 | exit M11 | Assert.cs:77:10:77:12 | enter M11 | +| Assert.cs:77:10:77:12 | exit M11 | Assert.cs:77:10:77:12 | exit M11 | +| Assert.cs:77:10:77:12 | exit M11 | Assert.cs:79:24:79:27 | [b (line 77): true] null | +| Assert.cs:77:10:77:12 | exit M11 | Assert.cs:79:31:79:32 | [b (line 77): false] "" | +| Assert.cs:77:10:77:12 | exit M11 | Assert.cs:80:9:80:38 | [assertion failure] call to method IsFalse | +| Assert.cs:77:10:77:12 | exit M11 | Assert.cs:80:37:80:37 | [b (line 77): false] access to parameter b | +| Assert.cs:77:10:77:12 | exit M11 | Assert.cs:80:37:80:37 | [b (line 77): true] access to parameter b | +| Assert.cs:79:24:79:27 | [b (line 77): true] null | Assert.cs:79:24:79:27 | [b (line 77): true] null | +| Assert.cs:79:31:79:32 | [b (line 77): false] "" | Assert.cs:79:31:79:32 | [b (line 77): false] "" | +| Assert.cs:80:9:80:38 | [assertion failure] call to method IsFalse | Assert.cs:79:24:79:27 | [b (line 77): true] null | +| Assert.cs:80:9:80:38 | [assertion failure] call to method IsFalse | Assert.cs:80:9:80:38 | [assertion failure] call to method IsFalse | +| Assert.cs:80:9:80:38 | [assertion failure] call to method IsFalse | Assert.cs:80:37:80:37 | [b (line 77): true] access to parameter b | +| Assert.cs:80:37:80:37 | [b (line 77): false] access to parameter b | Assert.cs:80:37:80:37 | [b (line 77): false] access to parameter b | +| Assert.cs:80:37:80:37 | [b (line 77): true] access to parameter b | Assert.cs:80:37:80:37 | [b (line 77): true] access to parameter b | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:84:10:84:12 | enter M12 | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:84:10:84:12 | enter M12 | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:84:10:84:12 | exit M12 | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:86:24:86:27 | [b (line 84): true] null | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:86:31:86:32 | [b (line 84): false] "" | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:87:9:87:31 | [assertion failure, b (line 84): false] call to method Assert | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:87:9:87:31 | [assertion failure, b (line 84): true] call to method Assert | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:91:9:91:24 | [assertion failure, b (line 84): false] call to method IsNull | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:91:9:91:24 | [assertion failure, b (line 84): true] call to method IsNull | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): false] call to method IsNotNull | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): true] call to method IsNotNull | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:119:37:119:38 | [b (line 84): true] !... | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:127:37:127:38 | [b (line 84): true] !... | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:86:24:86:27 | [b (line 84): true] null | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:86:31:86:32 | [b (line 84): false] "" | +| Assert.cs:87:9:87:31 | [assertion failure, b (line 84): false] call to method Assert | Assert.cs:87:9:87:31 | [assertion failure, b (line 84): false] call to method Assert | +| Assert.cs:87:9:87:31 | [assertion failure, b (line 84): true] call to method Assert | Assert.cs:87:9:87:31 | [assertion failure, b (line 84): true] call to method Assert | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | +| Assert.cs:91:9:91:24 | [assertion failure, b (line 84): false] call to method IsNull | Assert.cs:91:9:91:24 | [assertion failure, b (line 84): false] call to method IsNull | +| Assert.cs:91:9:91:24 | [assertion failure, b (line 84): true] call to method IsNull | Assert.cs:91:9:91:24 | [assertion failure, b (line 84): true] call to method IsNull | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | +| Assert.cs:95:9:95:27 | [assertion failure, b (line 84): false] call to method IsNotNull | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): false] call to method IsNotNull | +| Assert.cs:95:9:95:27 | [assertion failure, b (line 84): true] call to method IsNotNull | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): true] call to method IsNotNull | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | +| Assert.cs:99:9:99:32 | [assertion failure, b (line 84): false] call to method IsTrue | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:99:9:99:32 | [assertion failure, b (line 84): true] call to method IsTrue | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | +| Assert.cs:103:9:103:32 | [assertion failure, b (line 84): false] call to method IsTrue | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:103:9:103:32 | [assertion failure, b (line 84): true] call to method IsTrue | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | +| Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | +| Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | +| Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | +| Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | +| Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | +| Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | +| Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | +| Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | +| Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | +| Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | +| Assert.cs:119:37:119:38 | [b (line 84): true] !... | Assert.cs:119:37:119:38 | [b (line 84): true] !... | +| Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | +| Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | +| Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | +| Assert.cs:127:37:127:38 | [b (line 84): true] !... | Assert.cs:127:37:127:38 | [b (line 84): true] !... | | Assignments.cs:3:10:3:10 | enter M | Assignments.cs:3:10:3:10 | enter M | | Assignments.cs:14:18:14:35 | enter (...) => ... | Assignments.cs:14:18:14:35 | enter (...) => ... | | Assignments.cs:17:40:17:40 | enter + | Assignments.cs:17:40:17:40 | enter + | @@ -8347,6 +10720,10 @@ postBlockDominance | CompileTimeOperators.cs:15:10:15:15 | enter Typeof | CompileTimeOperators.cs:15:10:15:15 | enter Typeof | | CompileTimeOperators.cs:20:12:20:17 | enter Nameof | CompileTimeOperators.cs:20:12:20:17 | enter Nameof | | CompileTimeOperators.cs:28:10:28:10 | enter M | CompileTimeOperators.cs:28:10:28:10 | enter M | +| ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | +| ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | +| ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | +| ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | ConditionalAccess.cs:30:10:30:12 | enter Out | | ConditionalAccess.cs:3:12:3:13 | enter M1 | ConditionalAccess.cs:3:12:3:13 | enter M1 | | ConditionalAccess.cs:3:12:3:13 | exit M1 | ConditionalAccess.cs:3:12:3:13 | enter M1 | | ConditionalAccess.cs:3:12:3:13 | exit M1 | ConditionalAccess.cs:3:12:3:13 | exit M1 | @@ -8392,7 +10769,15 @@ postBlockDominance | ConditionalAccess.cs:19:12:19:13 | exit M6 | ConditionalAccess.cs:19:58:19:59 | access to parameter s2 | | ConditionalAccess.cs:19:58:19:59 | access to parameter s2 | ConditionalAccess.cs:19:58:19:59 | access to parameter s2 | | ConditionalAccess.cs:21:10:21:11 | enter M7 | ConditionalAccess.cs:21:10:21:11 | enter M7 | -| ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | +| ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:30:10:30:12 | enter Out | +| ConditionalAccess.cs:30:10:30:12 | exit Out | ConditionalAccess.cs:30:10:30:12 | enter Out | +| ConditionalAccess.cs:30:10:30:12 | exit Out | ConditionalAccess.cs:30:10:30:12 | exit Out | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:32:10:32:11 | enter M8 | +| ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:32:10:32:11 | enter M8 | +| ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:32:10:32:11 | exit M8 | +| ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:35:14:35:24 | call to method Out | +| ConditionalAccess.cs:35:14:35:24 | call to method Out | ConditionalAccess.cs:35:14:35:24 | call to method Out | +| ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:3:10:3:19 | enter IncrOrDecr | | Conditions.cs:3:10:3:19 | exit IncrOrDecr | Conditions.cs:3:10:3:19 | enter IncrOrDecr | | Conditions.cs:3:10:3:19 | exit IncrOrDecr | Conditions.cs:3:10:3:19 | exit IncrOrDecr | @@ -8557,21 +10942,21 @@ postBlockDominance | Conditions.cs:113:10:113:11 | enter M9 | Conditions.cs:113:10:113:11 | enter M9 | | Conditions.cs:113:10:113:11 | exit M9 | Conditions.cs:113:10:113:11 | enter M9 | | Conditions.cs:113:10:113:11 | exit M9 | Conditions.cs:113:10:113:11 | exit M9 | -| Conditions.cs:113:10:113:11 | exit M9 | Conditions.cs:116:24:116:24 | access to local variable i | -| Conditions.cs:113:10:113:11 | exit M9 | Conditions.cs:116:41:116:41 | access to local variable i | +| Conditions.cs:113:10:113:11 | exit M9 | Conditions.cs:116:25:116:25 | access to local variable i | +| Conditions.cs:113:10:113:11 | exit M9 | Conditions.cs:116:42:116:42 | access to local variable i | | Conditions.cs:113:10:113:11 | exit M9 | Conditions.cs:117:9:123:9 | {...} | | Conditions.cs:113:10:113:11 | exit M9 | Conditions.cs:120:17:120:23 | [last (line 118): false] ...; | | Conditions.cs:113:10:113:11 | exit M9 | Conditions.cs:121:13:122:25 | [last (line 118): true] if (...) ... | -| Conditions.cs:116:24:116:24 | access to local variable i | Conditions.cs:113:10:113:11 | enter M9 | -| Conditions.cs:116:24:116:24 | access to local variable i | Conditions.cs:116:24:116:24 | access to local variable i | -| Conditions.cs:116:24:116:24 | access to local variable i | Conditions.cs:116:41:116:41 | access to local variable i | -| Conditions.cs:116:24:116:24 | access to local variable i | Conditions.cs:117:9:123:9 | {...} | -| Conditions.cs:116:24:116:24 | access to local variable i | Conditions.cs:120:17:120:23 | [last (line 118): false] ...; | -| Conditions.cs:116:24:116:24 | access to local variable i | Conditions.cs:121:13:122:25 | [last (line 118): true] if (...) ... | -| Conditions.cs:116:41:116:41 | access to local variable i | Conditions.cs:116:41:116:41 | access to local variable i | -| Conditions.cs:116:41:116:41 | access to local variable i | Conditions.cs:117:9:123:9 | {...} | -| Conditions.cs:116:41:116:41 | access to local variable i | Conditions.cs:120:17:120:23 | [last (line 118): false] ...; | -| Conditions.cs:116:41:116:41 | access to local variable i | Conditions.cs:121:13:122:25 | [last (line 118): true] if (...) ... | +| Conditions.cs:116:25:116:25 | access to local variable i | Conditions.cs:113:10:113:11 | enter M9 | +| Conditions.cs:116:25:116:25 | access to local variable i | Conditions.cs:116:25:116:25 | access to local variable i | +| Conditions.cs:116:25:116:25 | access to local variable i | Conditions.cs:116:42:116:42 | access to local variable i | +| Conditions.cs:116:25:116:25 | access to local variable i | Conditions.cs:117:9:123:9 | {...} | +| Conditions.cs:116:25:116:25 | access to local variable i | Conditions.cs:120:17:120:23 | [last (line 118): false] ...; | +| Conditions.cs:116:25:116:25 | access to local variable i | Conditions.cs:121:13:122:25 | [last (line 118): true] if (...) ... | +| Conditions.cs:116:42:116:42 | access to local variable i | Conditions.cs:116:42:116:42 | access to local variable i | +| Conditions.cs:116:42:116:42 | access to local variable i | Conditions.cs:117:9:123:9 | {...} | +| Conditions.cs:116:42:116:42 | access to local variable i | Conditions.cs:120:17:120:23 | [last (line 118): false] ...; | +| Conditions.cs:116:42:116:42 | access to local variable i | Conditions.cs:121:13:122:25 | [last (line 118): true] if (...) ... | | Conditions.cs:117:9:123:9 | {...} | Conditions.cs:117:9:123:9 | {...} | | Conditions.cs:120:17:120:23 | [last (line 118): false] ...; | Conditions.cs:120:17:120:23 | [last (line 118): false] ...; | | Conditions.cs:121:13:122:25 | [last (line 118): true] if (...) ... | Conditions.cs:121:13:122:25 | [last (line 118): true] if (...) ... | @@ -8580,6 +10965,13 @@ postBlockDominance | Conditions.cs:131:16:131:19 | [Field1 (line 129): true, Field2 (line 129): false] true | Conditions.cs:131:16:131:19 | [Field1 (line 129): true, Field2 (line 129): false] true | | Conditions.cs:134:13:139:13 | [Field1 (line 129): true] {...} | Conditions.cs:134:13:139:13 | [Field1 (line 129): true] {...} | | Conditions.cs:136:17:138:17 | [Field1 (line 129): true, Field2 (line 129): true] {...} | Conditions.cs:136:17:138:17 | [Field1 (line 129): true, Field2 (line 129): true] {...} | +| Conditions.cs:143:10:143:12 | enter M11 | Conditions.cs:143:10:143:12 | enter M11 | +| Conditions.cs:143:10:143:12 | exit M11 | Conditions.cs:143:10:143:12 | enter M11 | +| Conditions.cs:143:10:143:12 | exit M11 | Conditions.cs:143:10:143:12 | exit M11 | +| Conditions.cs:143:10:143:12 | exit M11 | Conditions.cs:145:21:145:23 | [b (line 143): true] "a" | +| Conditions.cs:143:10:143:12 | exit M11 | Conditions.cs:145:27:145:29 | [b (line 143): false] "b" | +| Conditions.cs:145:21:145:23 | [b (line 143): true] "a" | Conditions.cs:145:21:145:23 | [b (line 143): true] "a" | +| Conditions.cs:145:27:145:29 | [b (line 143): false] "b" | Conditions.cs:145:27:145:29 | [b (line 143): false] "b" | | ExitMethods.cs:7:10:7:11 | enter M1 | ExitMethods.cs:7:10:7:11 | enter M1 | | ExitMethods.cs:13:10:13:11 | enter M2 | ExitMethods.cs:13:10:13:11 | enter M2 | | ExitMethods.cs:19:10:19:11 | enter M3 | ExitMethods.cs:19:10:19:11 | enter M3 | @@ -8633,6 +11025,12 @@ postBlockDominance | ExitMethods.cs:119:17:119:32 | enter FailingAssertion | ExitMethods.cs:119:17:119:32 | enter FailingAssertion | | ExitMethods.cs:125:17:125:33 | enter FailingAssertion2 | ExitMethods.cs:125:17:125:33 | enter FailingAssertion2 | | ExitMethods.cs:131:10:131:20 | enter AssertFalse | ExitMethods.cs:131:10:131:20 | enter AssertFalse | +| ExitMethods.cs:131:10:131:20 | exit AssertFalse | ExitMethods.cs:131:10:131:20 | enter AssertFalse | +| ExitMethods.cs:131:10:131:20 | exit AssertFalse | ExitMethods.cs:131:10:131:20 | exit AssertFalse | +| ExitMethods.cs:131:10:131:20 | exit AssertFalse | ExitMethods.cs:131:33:131:49 | [assertion failure] call to method IsFalse | +| ExitMethods.cs:131:10:131:20 | exit AssertFalse | ExitMethods.cs:131:33:131:49 | [assertion success] call to method IsFalse | +| ExitMethods.cs:131:33:131:49 | [assertion failure] call to method IsFalse | ExitMethods.cs:131:33:131:49 | [assertion failure] call to method IsFalse | +| ExitMethods.cs:131:33:131:49 | [assertion success] call to method IsFalse | ExitMethods.cs:131:33:131:49 | [assertion success] call to method IsFalse | | ExitMethods.cs:133:17:133:33 | enter FailingAssertion3 | ExitMethods.cs:133:17:133:33 | enter FailingAssertion3 | | Extensions.cs:5:23:5:29 | enter ToInt32 | Extensions.cs:5:23:5:29 | enter ToInt32 | | Extensions.cs:10:24:10:29 | enter ToBool | Extensions.cs:10:24:10:29 | enter ToBool | @@ -9077,18 +11475,18 @@ postBlockDominance | LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:7:10:7:11 | enter M1 | | LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:7:10:7:11 | exit M1 | | LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:10:13:10:19 | return ...; | -| LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:11:21:11:23 | String arg | -| LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:11:28:11:31 | access to parameter args | +| LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:11:22:11:24 | String arg | +| LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:11:29:11:32 | access to parameter args | | LoopUnrolling.cs:10:13:10:19 | return ...; | LoopUnrolling.cs:10:13:10:19 | return ...; | -| LoopUnrolling.cs:11:21:11:23 | String arg | LoopUnrolling.cs:11:21:11:23 | String arg | -| LoopUnrolling.cs:11:21:11:23 | String arg | LoopUnrolling.cs:11:28:11:31 | access to parameter args | -| LoopUnrolling.cs:11:28:11:31 | access to parameter args | LoopUnrolling.cs:11:28:11:31 | access to parameter args | +| LoopUnrolling.cs:11:22:11:24 | String arg | LoopUnrolling.cs:11:22:11:24 | String arg | +| LoopUnrolling.cs:11:22:11:24 | String arg | LoopUnrolling.cs:11:29:11:32 | access to parameter args | +| LoopUnrolling.cs:11:29:11:32 | access to parameter args | LoopUnrolling.cs:11:29:11:32 | access to parameter args | | LoopUnrolling.cs:15:10:15:11 | enter M2 | LoopUnrolling.cs:15:10:15:11 | enter M2 | | LoopUnrolling.cs:15:10:15:11 | exit M2 | LoopUnrolling.cs:15:10:15:11 | enter M2 | | LoopUnrolling.cs:15:10:15:11 | exit M2 | LoopUnrolling.cs:15:10:15:11 | exit M2 | -| LoopUnrolling.cs:15:10:15:11 | exit M2 | LoopUnrolling.cs:18:21:18:21 | String x | -| LoopUnrolling.cs:18:21:18:21 | String x | LoopUnrolling.cs:15:10:15:11 | enter M2 | -| LoopUnrolling.cs:18:21:18:21 | String x | LoopUnrolling.cs:18:21:18:21 | String x | +| LoopUnrolling.cs:15:10:15:11 | exit M2 | LoopUnrolling.cs:18:22:18:22 | String x | +| LoopUnrolling.cs:18:22:18:22 | String x | LoopUnrolling.cs:15:10:15:11 | enter M2 | +| LoopUnrolling.cs:18:22:18:22 | String x | LoopUnrolling.cs:18:22:18:22 | String x | | LoopUnrolling.cs:22:10:22:11 | enter M3 | LoopUnrolling.cs:22:10:22:11 | enter M3 | | LoopUnrolling.cs:22:10:22:11 | exit M3 | LoopUnrolling.cs:22:10:22:11 | enter M3 | | LoopUnrolling.cs:22:10:22:11 | exit M3 | LoopUnrolling.cs:22:10:22:11 | exit M3 | @@ -9103,57 +11501,310 @@ postBlockDominance | LoopUnrolling.cs:25:26:25:29 | Char arg0 | LoopUnrolling.cs:24:22:24:24 | Char arg | | LoopUnrolling.cs:25:26:25:29 | Char arg0 | LoopUnrolling.cs:25:26:25:29 | Char arg0 | | LoopUnrolling.cs:29:10:29:11 | enter M4 | LoopUnrolling.cs:29:10:29:11 | enter M4 | -| LoopUnrolling.cs:29:10:29:11 | exit M4 | LoopUnrolling.cs:29:10:29:11 | enter M4 | -| LoopUnrolling.cs:29:10:29:11 | exit M4 | LoopUnrolling.cs:29:10:29:11 | exit M4 | -| LoopUnrolling.cs:29:10:29:11 | exit M4 | LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | -| LoopUnrolling.cs:29:10:29:11 | exit M4 | LoopUnrolling.cs:32:21:32:21 | String x | -| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:29:10:29:11 | enter M4 | -| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | -| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:32:21:32:21 | String x | -| LoopUnrolling.cs:32:21:32:21 | String x | LoopUnrolling.cs:32:21:32:21 | String x | | LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:36:10:36:11 | enter M5 | | LoopUnrolling.cs:36:10:36:11 | exit M5 | LoopUnrolling.cs:36:10:36:11 | enter M5 | | LoopUnrolling.cs:36:10:36:11 | exit M5 | LoopUnrolling.cs:36:10:36:11 | exit M5 | | LoopUnrolling.cs:36:10:36:11 | exit M5 | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | -| LoopUnrolling.cs:36:10:36:11 | exit M5 | LoopUnrolling.cs:40:21:40:21 | String x | -| LoopUnrolling.cs:36:10:36:11 | exit M5 | LoopUnrolling.cs:41:25:41:25 | String y | +| LoopUnrolling.cs:36:10:36:11 | exit M5 | LoopUnrolling.cs:40:22:40:22 | String x | +| LoopUnrolling.cs:36:10:36:11 | exit M5 | LoopUnrolling.cs:41:26:41:26 | String y | | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:36:10:36:11 | enter M5 | | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | -| LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:40:21:40:21 | String x | -| LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:41:25:41:25 | String y | -| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:36:10:36:11 | enter M5 | -| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:40:21:40:21 | String x | -| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:36:10:36:11 | enter M5 | -| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:40:21:40:21 | String x | -| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:41:25:41:25 | String y | +| LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:40:22:40:22 | String x | +| LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:41:26:41:26 | String y | +| LoopUnrolling.cs:40:22:40:22 | String x | LoopUnrolling.cs:36:10:36:11 | enter M5 | +| LoopUnrolling.cs:40:22:40:22 | String x | LoopUnrolling.cs:40:22:40:22 | String x | +| LoopUnrolling.cs:41:26:41:26 | String y | LoopUnrolling.cs:36:10:36:11 | enter M5 | +| LoopUnrolling.cs:41:26:41:26 | String y | LoopUnrolling.cs:40:22:40:22 | String x | +| LoopUnrolling.cs:41:26:41:26 | String y | LoopUnrolling.cs:41:26:41:26 | String y | | LoopUnrolling.cs:45:10:45:11 | enter M6 | LoopUnrolling.cs:45:10:45:11 | enter M6 | -| LoopUnrolling.cs:50:13:50:17 | Label: | LoopUnrolling.cs:50:13:50:17 | Label: | +| LoopUnrolling.cs:50:9:50:13 | Label: | LoopUnrolling.cs:50:9:50:13 | Label: | | LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:55:10:55:11 | enter M7 | | LoopUnrolling.cs:55:10:55:11 | exit M7 | LoopUnrolling.cs:55:10:55:11 | enter M7 | | LoopUnrolling.cs:55:10:55:11 | exit M7 | LoopUnrolling.cs:55:10:55:11 | exit M7 | -| LoopUnrolling.cs:55:10:55:11 | exit M7 | LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | -| LoopUnrolling.cs:55:10:55:11 | exit M7 | LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | +| LoopUnrolling.cs:55:10:55:11 | exit M7 | LoopUnrolling.cs:58:22:58:22 | [b (line 55): false] String x | +| LoopUnrolling.cs:55:10:55:11 | exit M7 | LoopUnrolling.cs:58:22:58:22 | [b (line 55): true] String x | | LoopUnrolling.cs:55:10:55:11 | exit M7 | LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | | LoopUnrolling.cs:55:10:55:11 | exit M7 | LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | -| LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | -| LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | -| LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | +| LoopUnrolling.cs:58:22:58:22 | [b (line 55): false] String x | LoopUnrolling.cs:58:22:58:22 | [b (line 55): false] String x | +| LoopUnrolling.cs:58:22:58:22 | [b (line 55): true] String x | LoopUnrolling.cs:58:22:58:22 | [b (line 55): true] String x | +| LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | LoopUnrolling.cs:58:22:58:22 | [b (line 55): true] String x | | LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | -| LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | +| LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | LoopUnrolling.cs:58:22:58:22 | [b (line 55): false] String x | | LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | | LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:67:10:67:11 | enter M8 | | LoopUnrolling.cs:67:10:67:11 | exit M8 | LoopUnrolling.cs:67:10:67:11 | enter M8 | | LoopUnrolling.cs:67:10:67:11 | exit M8 | LoopUnrolling.cs:67:10:67:11 | exit M8 | | LoopUnrolling.cs:67:10:67:11 | exit M8 | LoopUnrolling.cs:70:13:70:19 | return ...; | | LoopUnrolling.cs:67:10:67:11 | exit M8 | LoopUnrolling.cs:71:9:71:21 | ...; | -| LoopUnrolling.cs:67:10:67:11 | exit M8 | LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | -| LoopUnrolling.cs:67:10:67:11 | exit M8 | LoopUnrolling.cs:72:21:72:23 | String arg | | LoopUnrolling.cs:70:13:70:19 | return ...; | LoopUnrolling.cs:70:13:70:19 | return ...; | | LoopUnrolling.cs:71:9:71:21 | ...; | LoopUnrolling.cs:71:9:71:21 | ...; | -| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:71:9:71:21 | ...; | -| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | -| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:72:21:72:23 | String arg | -| LoopUnrolling.cs:72:21:72:23 | String arg | LoopUnrolling.cs:72:21:72:23 | String arg | +| LoopUnrolling.cs:76:10:76:11 | enter M9 | LoopUnrolling.cs:76:10:76:11 | enter M9 | +| LoopUnrolling.cs:85:10:85:12 | enter M10 | LoopUnrolling.cs:85:10:85:12 | enter M10 | +| LoopUnrolling.cs:94:10:94:12 | enter M11 | LoopUnrolling.cs:94:10:94:12 | enter M11 | +| LoopUnrolling.cs:94:10:94:12 | exit M11 | LoopUnrolling.cs:94:10:94:12 | enter M11 | +| LoopUnrolling.cs:94:10:94:12 | exit M11 | LoopUnrolling.cs:94:10:94:12 | exit M11 | +| LoopUnrolling.cs:94:10:94:12 | exit M11 | LoopUnrolling.cs:97:22:97:22 | String x | +| LoopUnrolling.cs:97:22:97:22 | String x | LoopUnrolling.cs:94:10:94:12 | enter M11 | +| LoopUnrolling.cs:97:22:97:22 | String x | LoopUnrolling.cs:97:22:97:22 | String x | +| MultiImplementationA.cs:6:22:6:31 | enter get_P1 | MultiImplementationA.cs:6:22:6:31 | enter get_P1 | +| MultiImplementationA.cs:6:22:6:31 | enter get_P1 | MultiImplementationB.cs:3:22:3:22 | enter get_P1 | +| MultiImplementationA.cs:6:22:6:31 | exit get_P1 | MultiImplementationA.cs:6:22:6:31 | enter get_P1 | +| MultiImplementationA.cs:6:22:6:31 | exit get_P1 | MultiImplementationA.cs:6:22:6:31 | exit get_P1 | +| MultiImplementationA.cs:6:22:6:31 | exit get_P1 | MultiImplementationA.cs:6:28:6:31 | null | +| MultiImplementationA.cs:6:22:6:31 | exit get_P1 | MultiImplementationB.cs:3:22:3:22 | 0 | +| MultiImplementationA.cs:6:22:6:31 | exit get_P1 | MultiImplementationB.cs:3:22:3:22 | enter get_P1 | +| MultiImplementationA.cs:6:22:6:31 | exit get_P1 | MultiImplementationB.cs:3:22:3:22 | exit get_P1 | +| MultiImplementationA.cs:6:28:6:31 | null | MultiImplementationA.cs:6:28:6:31 | null | +| MultiImplementationA.cs:7:21:7:23 | enter get_P2 | MultiImplementationA.cs:7:21:7:23 | enter get_P2 | +| MultiImplementationA.cs:7:21:7:23 | enter get_P2 | MultiImplementationB.cs:4:21:4:23 | enter get_P2 | +| MultiImplementationA.cs:7:21:7:23 | exit get_P2 | MultiImplementationA.cs:7:21:7:23 | enter get_P2 | +| MultiImplementationA.cs:7:21:7:23 | exit get_P2 | MultiImplementationA.cs:7:21:7:23 | exit get_P2 | +| MultiImplementationA.cs:7:21:7:23 | exit get_P2 | MultiImplementationA.cs:7:25:7:39 | {...} | +| MultiImplementationA.cs:7:21:7:23 | exit get_P2 | MultiImplementationB.cs:4:21:4:23 | enter get_P2 | +| MultiImplementationA.cs:7:21:7:23 | exit get_P2 | MultiImplementationB.cs:4:21:4:23 | exit get_P2 | +| MultiImplementationA.cs:7:21:7:23 | exit get_P2 | MultiImplementationB.cs:4:25:4:37 | {...} | +| MultiImplementationA.cs:7:25:7:39 | {...} | MultiImplementationA.cs:7:25:7:39 | {...} | +| MultiImplementationA.cs:7:41:7:43 | enter set_P2 | MultiImplementationA.cs:7:41:7:43 | enter set_P2 | +| MultiImplementationA.cs:7:41:7:43 | enter set_P2 | MultiImplementationB.cs:4:39:4:41 | enter set_P2 | +| MultiImplementationA.cs:7:41:7:43 | exit set_P2 | MultiImplementationA.cs:7:41:7:43 | enter set_P2 | +| MultiImplementationA.cs:7:41:7:43 | exit set_P2 | MultiImplementationA.cs:7:41:7:43 | exit set_P2 | +| MultiImplementationA.cs:7:41:7:43 | exit set_P2 | MultiImplementationA.cs:7:45:7:59 | {...} | +| MultiImplementationA.cs:7:41:7:43 | exit set_P2 | MultiImplementationB.cs:4:39:4:41 | enter set_P2 | +| MultiImplementationA.cs:7:41:7:43 | exit set_P2 | MultiImplementationB.cs:4:39:4:41 | exit set_P2 | +| MultiImplementationA.cs:7:41:7:43 | exit set_P2 | MultiImplementationB.cs:4:43:4:45 | {...} | +| MultiImplementationA.cs:7:45:7:59 | {...} | MultiImplementationA.cs:7:45:7:59 | {...} | +| MultiImplementationA.cs:8:16:8:16 | enter M | MultiImplementationA.cs:8:16:8:16 | enter M | +| MultiImplementationA.cs:8:16:8:16 | enter M | MultiImplementationB.cs:5:16:5:16 | enter M | +| MultiImplementationA.cs:8:16:8:16 | exit M | MultiImplementationA.cs:8:16:8:16 | enter M | +| MultiImplementationA.cs:8:16:8:16 | exit M | MultiImplementationA.cs:8:16:8:16 | exit M | +| MultiImplementationA.cs:8:16:8:16 | exit M | MultiImplementationA.cs:8:29:8:32 | null | +| MultiImplementationA.cs:8:16:8:16 | exit M | MultiImplementationB.cs:5:16:5:16 | enter M | +| MultiImplementationA.cs:8:16:8:16 | exit M | MultiImplementationB.cs:5:16:5:16 | exit M | +| MultiImplementationA.cs:8:16:8:16 | exit M | MultiImplementationB.cs:5:23:5:23 | 2 | +| MultiImplementationA.cs:8:29:8:32 | null | MultiImplementationA.cs:8:29:8:32 | null | +| MultiImplementationA.cs:13:16:13:16 | this access | MultiImplementationA.cs:13:16:13:16 | this access | +| MultiImplementationA.cs:14:31:14:31 | access to parameter i | MultiImplementationA.cs:14:31:14:31 | access to parameter i | +| MultiImplementationA.cs:14:31:14:31 | enter get_Item | MultiImplementationA.cs:14:31:14:31 | enter get_Item | +| MultiImplementationA.cs:14:31:14:31 | enter get_Item | MultiImplementationB.cs:12:31:12:40 | enter get_Item | +| MultiImplementationA.cs:14:31:14:31 | exit get_Item | MultiImplementationA.cs:14:31:14:31 | access to parameter i | +| MultiImplementationA.cs:14:31:14:31 | exit get_Item | MultiImplementationA.cs:14:31:14:31 | enter get_Item | +| MultiImplementationA.cs:14:31:14:31 | exit get_Item | MultiImplementationA.cs:14:31:14:31 | exit get_Item | +| MultiImplementationA.cs:14:31:14:31 | exit get_Item | MultiImplementationB.cs:12:31:12:40 | enter get_Item | +| MultiImplementationA.cs:14:31:14:31 | exit get_Item | MultiImplementationB.cs:12:31:12:40 | exit get_Item | +| MultiImplementationA.cs:14:31:14:31 | exit get_Item | MultiImplementationB.cs:12:37:12:40 | null | +| MultiImplementationA.cs:15:36:15:38 | enter get_Item | MultiImplementationA.cs:15:36:15:38 | enter get_Item | +| MultiImplementationA.cs:15:36:15:38 | enter get_Item | MultiImplementationB.cs:13:36:13:38 | enter get_Item | +| MultiImplementationA.cs:15:36:15:38 | exit get_Item | MultiImplementationA.cs:15:36:15:38 | enter get_Item | +| MultiImplementationA.cs:15:36:15:38 | exit get_Item | MultiImplementationA.cs:15:36:15:38 | exit get_Item | +| MultiImplementationA.cs:15:36:15:38 | exit get_Item | MultiImplementationA.cs:15:40:15:52 | {...} | +| MultiImplementationA.cs:15:36:15:38 | exit get_Item | MultiImplementationB.cs:13:36:13:38 | enter get_Item | +| MultiImplementationA.cs:15:36:15:38 | exit get_Item | MultiImplementationB.cs:13:36:13:38 | exit get_Item | +| MultiImplementationA.cs:15:36:15:38 | exit get_Item | MultiImplementationB.cs:13:40:13:54 | {...} | +| MultiImplementationA.cs:15:40:15:52 | {...} | MultiImplementationA.cs:15:40:15:52 | {...} | +| MultiImplementationA.cs:15:54:15:56 | enter set_Item | MultiImplementationA.cs:15:54:15:56 | enter set_Item | +| MultiImplementationA.cs:15:54:15:56 | enter set_Item | MultiImplementationB.cs:13:56:13:58 | enter set_Item | +| MultiImplementationA.cs:15:54:15:56 | exit set_Item | MultiImplementationA.cs:15:54:15:56 | enter set_Item | +| MultiImplementationA.cs:15:54:15:56 | exit set_Item | MultiImplementationA.cs:15:54:15:56 | exit set_Item | +| MultiImplementationA.cs:15:54:15:56 | exit set_Item | MultiImplementationA.cs:15:58:15:60 | {...} | +| MultiImplementationA.cs:15:54:15:56 | exit set_Item | MultiImplementationB.cs:13:56:13:58 | enter set_Item | +| MultiImplementationA.cs:15:54:15:56 | exit set_Item | MultiImplementationB.cs:13:56:13:58 | exit set_Item | +| MultiImplementationA.cs:15:54:15:56 | exit set_Item | MultiImplementationB.cs:13:60:13:62 | {...} | +| MultiImplementationA.cs:15:58:15:60 | {...} | MultiImplementationA.cs:15:58:15:60 | {...} | +| MultiImplementationA.cs:16:17:16:18 | enter M1 | MultiImplementationA.cs:16:17:16:18 | enter M1 | +| MultiImplementationA.cs:16:17:16:18 | enter M1 | MultiImplementationB.cs:14:17:14:18 | enter M1 | +| MultiImplementationA.cs:16:17:16:18 | exit M1 | MultiImplementationA.cs:16:17:16:18 | enter M1 | +| MultiImplementationA.cs:16:17:16:18 | exit M1 | MultiImplementationA.cs:16:17:16:18 | exit M1 | +| MultiImplementationA.cs:16:17:16:18 | exit M1 | MultiImplementationA.cs:17:5:19:5 | {...} | +| MultiImplementationA.cs:16:17:16:18 | exit M1 | MultiImplementationB.cs:14:17:14:18 | enter M1 | +| MultiImplementationA.cs:16:17:16:18 | exit M1 | MultiImplementationB.cs:14:17:14:18 | exit M1 | +| MultiImplementationA.cs:16:17:16:18 | exit M1 | MultiImplementationB.cs:15:5:17:5 | {...} | +| MultiImplementationA.cs:17:5:19:5 | {...} | MultiImplementationA.cs:17:5:19:5 | {...} | +| MultiImplementationA.cs:18:9:18:22 | enter M2 | MultiImplementationA.cs:18:9:18:22 | enter M2 | +| MultiImplementationA.cs:20:12:20:13 | enter C2 | MultiImplementationA.cs:20:12:20:13 | enter C2 | +| MultiImplementationA.cs:20:12:20:13 | enter C2 | MultiImplementationB.cs:18:12:18:13 | enter C2 | +| MultiImplementationA.cs:20:12:20:13 | exit C2 | MultiImplementationA.cs:13:16:13:16 | this access | +| MultiImplementationA.cs:20:12:20:13 | exit C2 | MultiImplementationA.cs:20:12:20:13 | enter C2 | +| MultiImplementationA.cs:20:12:20:13 | exit C2 | MultiImplementationA.cs:20:12:20:13 | exit C2 | +| MultiImplementationA.cs:20:12:20:13 | exit C2 | MultiImplementationA.cs:20:22:20:31 | {...} | +| MultiImplementationA.cs:20:12:20:13 | exit C2 | MultiImplementationA.cs:24:16:24:16 | this access | +| MultiImplementationA.cs:20:12:20:13 | exit C2 | MultiImplementationB.cs:11:16:11:16 | this access | +| MultiImplementationA.cs:20:12:20:13 | exit C2 | MultiImplementationB.cs:18:12:18:13 | enter C2 | +| MultiImplementationA.cs:20:12:20:13 | exit C2 | MultiImplementationB.cs:18:12:18:13 | exit C2 | +| MultiImplementationA.cs:20:12:20:13 | exit C2 | MultiImplementationB.cs:18:22:18:36 | {...} | +| MultiImplementationA.cs:20:12:20:13 | exit C2 | MultiImplementationB.cs:22:16:22:16 | this access | +| MultiImplementationA.cs:20:22:20:31 | {...} | MultiImplementationA.cs:20:22:20:31 | {...} | +| MultiImplementationA.cs:21:12:21:13 | enter C2 | MultiImplementationA.cs:21:12:21:13 | enter C2 | +| MultiImplementationA.cs:21:12:21:13 | enter C2 | MultiImplementationB.cs:19:12:19:13 | enter C2 | +| MultiImplementationA.cs:21:12:21:13 | exit C2 | MultiImplementationA.cs:21:12:21:13 | enter C2 | +| MultiImplementationA.cs:21:12:21:13 | exit C2 | MultiImplementationA.cs:21:12:21:13 | exit C2 | +| MultiImplementationA.cs:21:12:21:13 | exit C2 | MultiImplementationA.cs:21:24:21:24 | 0 | +| MultiImplementationA.cs:21:12:21:13 | exit C2 | MultiImplementationA.cs:21:27:21:29 | {...} | +| MultiImplementationA.cs:21:12:21:13 | exit C2 | MultiImplementationB.cs:19:12:19:13 | enter C2 | +| MultiImplementationA.cs:21:12:21:13 | exit C2 | MultiImplementationB.cs:19:12:19:13 | exit C2 | +| MultiImplementationA.cs:21:12:21:13 | exit C2 | MultiImplementationB.cs:19:24:19:24 | 1 | +| MultiImplementationA.cs:21:12:21:13 | exit C2 | MultiImplementationB.cs:19:27:19:29 | {...} | +| MultiImplementationA.cs:21:24:21:24 | 0 | MultiImplementationA.cs:21:24:21:24 | 0 | +| MultiImplementationA.cs:21:27:21:29 | {...} | MultiImplementationA.cs:21:27:21:29 | {...} | +| MultiImplementationA.cs:22:6:22:7 | enter ~C2 | MultiImplementationA.cs:22:6:22:7 | enter ~C2 | +| MultiImplementationA.cs:22:6:22:7 | enter ~C2 | MultiImplementationB.cs:20:6:20:7 | enter ~C2 | +| MultiImplementationA.cs:22:6:22:7 | exit ~C2 | MultiImplementationA.cs:22:6:22:7 | enter ~C2 | +| MultiImplementationA.cs:22:6:22:7 | exit ~C2 | MultiImplementationA.cs:22:6:22:7 | exit ~C2 | +| MultiImplementationA.cs:22:6:22:7 | exit ~C2 | MultiImplementationA.cs:22:11:22:13 | {...} | +| MultiImplementationA.cs:22:6:22:7 | exit ~C2 | MultiImplementationB.cs:20:6:20:7 | enter ~C2 | +| MultiImplementationA.cs:22:6:22:7 | exit ~C2 | MultiImplementationB.cs:20:6:20:7 | exit ~C2 | +| MultiImplementationA.cs:22:6:22:7 | exit ~C2 | MultiImplementationB.cs:20:11:20:25 | {...} | +| MultiImplementationA.cs:22:11:22:13 | {...} | MultiImplementationA.cs:22:11:22:13 | {...} | +| MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | +| MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | +| MultiImplementationA.cs:23:28:23:35 | exit implicit conversion | MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | +| MultiImplementationA.cs:23:28:23:35 | exit implicit conversion | MultiImplementationA.cs:23:28:23:35 | exit implicit conversion | +| MultiImplementationA.cs:23:28:23:35 | exit implicit conversion | MultiImplementationA.cs:23:50:23:53 | null | +| MultiImplementationA.cs:23:28:23:35 | exit implicit conversion | MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | +| MultiImplementationA.cs:23:28:23:35 | exit implicit conversion | MultiImplementationB.cs:21:28:21:35 | exit implicit conversion | +| MultiImplementationA.cs:23:28:23:35 | exit implicit conversion | MultiImplementationB.cs:21:56:21:59 | null | +| MultiImplementationA.cs:23:50:23:53 | null | MultiImplementationA.cs:23:50:23:53 | null | +| MultiImplementationA.cs:24:16:24:16 | this access | MultiImplementationA.cs:24:16:24:16 | this access | +| MultiImplementationA.cs:30:21:30:23 | enter get_P3 | MultiImplementationA.cs:30:21:30:23 | enter get_P3 | +| MultiImplementationA.cs:30:21:30:23 | enter get_P3 | MultiImplementationB.cs:27:21:27:23 | enter get_P3 | +| MultiImplementationA.cs:36:9:36:10 | enter M1 | MultiImplementationA.cs:36:9:36:10 | enter M1 | +| MultiImplementationA.cs:36:9:36:10 | enter M1 | MultiImplementationB.cs:32:9:32:10 | enter M1 | +| MultiImplementationA.cs:36:9:36:10 | exit M1 | MultiImplementationA.cs:36:9:36:10 | enter M1 | +| MultiImplementationA.cs:36:9:36:10 | exit M1 | MultiImplementationA.cs:36:9:36:10 | exit M1 | +| MultiImplementationA.cs:36:9:36:10 | exit M1 | MultiImplementationA.cs:36:14:36:28 | {...} | +| MultiImplementationA.cs:36:9:36:10 | exit M1 | MultiImplementationB.cs:32:9:32:10 | enter M1 | +| MultiImplementationA.cs:36:9:36:10 | exit M1 | MultiImplementationB.cs:32:9:32:10 | exit M1 | +| MultiImplementationA.cs:36:9:36:10 | exit M1 | MultiImplementationB.cs:32:17:32:17 | 0 | +| MultiImplementationA.cs:36:14:36:28 | {...} | MultiImplementationA.cs:36:14:36:28 | {...} | +| MultiImplementationA.cs:37:9:37:10 | enter M2 | MultiImplementationA.cs:37:9:37:10 | enter M2 | +| MultiImplementationB.cs:3:22:3:22 | 0 | MultiImplementationB.cs:3:22:3:22 | 0 | +| MultiImplementationB.cs:3:22:3:22 | enter get_P1 | MultiImplementationA.cs:6:22:6:31 | enter get_P1 | +| MultiImplementationB.cs:3:22:3:22 | enter get_P1 | MultiImplementationB.cs:3:22:3:22 | enter get_P1 | +| MultiImplementationB.cs:3:22:3:22 | exit get_P1 | MultiImplementationA.cs:6:22:6:31 | enter get_P1 | +| MultiImplementationB.cs:3:22:3:22 | exit get_P1 | MultiImplementationA.cs:6:22:6:31 | exit get_P1 | +| MultiImplementationB.cs:3:22:3:22 | exit get_P1 | MultiImplementationA.cs:6:28:6:31 | null | +| MultiImplementationB.cs:3:22:3:22 | exit get_P1 | MultiImplementationB.cs:3:22:3:22 | 0 | +| MultiImplementationB.cs:3:22:3:22 | exit get_P1 | MultiImplementationB.cs:3:22:3:22 | enter get_P1 | +| MultiImplementationB.cs:3:22:3:22 | exit get_P1 | MultiImplementationB.cs:3:22:3:22 | exit get_P1 | +| MultiImplementationB.cs:4:21:4:23 | enter get_P2 | MultiImplementationA.cs:7:21:7:23 | enter get_P2 | +| MultiImplementationB.cs:4:21:4:23 | enter get_P2 | MultiImplementationB.cs:4:21:4:23 | enter get_P2 | +| MultiImplementationB.cs:4:21:4:23 | exit get_P2 | MultiImplementationA.cs:7:21:7:23 | enter get_P2 | +| MultiImplementationB.cs:4:21:4:23 | exit get_P2 | MultiImplementationA.cs:7:21:7:23 | exit get_P2 | +| MultiImplementationB.cs:4:21:4:23 | exit get_P2 | MultiImplementationA.cs:7:25:7:39 | {...} | +| MultiImplementationB.cs:4:21:4:23 | exit get_P2 | MultiImplementationB.cs:4:21:4:23 | enter get_P2 | +| MultiImplementationB.cs:4:21:4:23 | exit get_P2 | MultiImplementationB.cs:4:21:4:23 | exit get_P2 | +| MultiImplementationB.cs:4:21:4:23 | exit get_P2 | MultiImplementationB.cs:4:25:4:37 | {...} | +| MultiImplementationB.cs:4:25:4:37 | {...} | MultiImplementationB.cs:4:25:4:37 | {...} | +| MultiImplementationB.cs:4:39:4:41 | enter set_P2 | MultiImplementationA.cs:7:41:7:43 | enter set_P2 | +| MultiImplementationB.cs:4:39:4:41 | enter set_P2 | MultiImplementationB.cs:4:39:4:41 | enter set_P2 | +| MultiImplementationB.cs:4:39:4:41 | exit set_P2 | MultiImplementationA.cs:7:41:7:43 | enter set_P2 | +| MultiImplementationB.cs:4:39:4:41 | exit set_P2 | MultiImplementationA.cs:7:41:7:43 | exit set_P2 | +| MultiImplementationB.cs:4:39:4:41 | exit set_P2 | MultiImplementationA.cs:7:45:7:59 | {...} | +| MultiImplementationB.cs:4:39:4:41 | exit set_P2 | MultiImplementationB.cs:4:39:4:41 | enter set_P2 | +| MultiImplementationB.cs:4:39:4:41 | exit set_P2 | MultiImplementationB.cs:4:39:4:41 | exit set_P2 | +| MultiImplementationB.cs:4:39:4:41 | exit set_P2 | MultiImplementationB.cs:4:43:4:45 | {...} | +| MultiImplementationB.cs:4:43:4:45 | {...} | MultiImplementationB.cs:4:43:4:45 | {...} | +| MultiImplementationB.cs:5:16:5:16 | enter M | MultiImplementationA.cs:8:16:8:16 | enter M | +| MultiImplementationB.cs:5:16:5:16 | enter M | MultiImplementationB.cs:5:16:5:16 | enter M | +| MultiImplementationB.cs:5:16:5:16 | exit M | MultiImplementationA.cs:8:16:8:16 | enter M | +| MultiImplementationB.cs:5:16:5:16 | exit M | MultiImplementationA.cs:8:16:8:16 | exit M | +| MultiImplementationB.cs:5:16:5:16 | exit M | MultiImplementationA.cs:8:29:8:32 | null | +| MultiImplementationB.cs:5:16:5:16 | exit M | MultiImplementationB.cs:5:16:5:16 | enter M | +| MultiImplementationB.cs:5:16:5:16 | exit M | MultiImplementationB.cs:5:16:5:16 | exit M | +| MultiImplementationB.cs:5:16:5:16 | exit M | MultiImplementationB.cs:5:23:5:23 | 2 | +| MultiImplementationB.cs:5:23:5:23 | 2 | MultiImplementationB.cs:5:23:5:23 | 2 | +| MultiImplementationB.cs:11:16:11:16 | this access | MultiImplementationB.cs:11:16:11:16 | this access | +| MultiImplementationB.cs:12:31:12:40 | enter get_Item | MultiImplementationA.cs:14:31:14:31 | enter get_Item | +| MultiImplementationB.cs:12:31:12:40 | enter get_Item | MultiImplementationB.cs:12:31:12:40 | enter get_Item | +| MultiImplementationB.cs:12:31:12:40 | exit get_Item | MultiImplementationA.cs:14:31:14:31 | access to parameter i | +| MultiImplementationB.cs:12:31:12:40 | exit get_Item | MultiImplementationA.cs:14:31:14:31 | enter get_Item | +| MultiImplementationB.cs:12:31:12:40 | exit get_Item | MultiImplementationA.cs:14:31:14:31 | exit get_Item | +| MultiImplementationB.cs:12:31:12:40 | exit get_Item | MultiImplementationB.cs:12:31:12:40 | enter get_Item | +| MultiImplementationB.cs:12:31:12:40 | exit get_Item | MultiImplementationB.cs:12:31:12:40 | exit get_Item | +| MultiImplementationB.cs:12:31:12:40 | exit get_Item | MultiImplementationB.cs:12:37:12:40 | null | +| MultiImplementationB.cs:12:37:12:40 | null | MultiImplementationB.cs:12:37:12:40 | null | +| MultiImplementationB.cs:13:36:13:38 | enter get_Item | MultiImplementationA.cs:15:36:15:38 | enter get_Item | +| MultiImplementationB.cs:13:36:13:38 | enter get_Item | MultiImplementationB.cs:13:36:13:38 | enter get_Item | +| MultiImplementationB.cs:13:36:13:38 | exit get_Item | MultiImplementationA.cs:15:36:15:38 | enter get_Item | +| MultiImplementationB.cs:13:36:13:38 | exit get_Item | MultiImplementationA.cs:15:36:15:38 | exit get_Item | +| MultiImplementationB.cs:13:36:13:38 | exit get_Item | MultiImplementationA.cs:15:40:15:52 | {...} | +| MultiImplementationB.cs:13:36:13:38 | exit get_Item | MultiImplementationB.cs:13:36:13:38 | enter get_Item | +| MultiImplementationB.cs:13:36:13:38 | exit get_Item | MultiImplementationB.cs:13:36:13:38 | exit get_Item | +| MultiImplementationB.cs:13:36:13:38 | exit get_Item | MultiImplementationB.cs:13:40:13:54 | {...} | +| MultiImplementationB.cs:13:40:13:54 | {...} | MultiImplementationB.cs:13:40:13:54 | {...} | +| MultiImplementationB.cs:13:56:13:58 | enter set_Item | MultiImplementationA.cs:15:54:15:56 | enter set_Item | +| MultiImplementationB.cs:13:56:13:58 | enter set_Item | MultiImplementationB.cs:13:56:13:58 | enter set_Item | +| MultiImplementationB.cs:13:56:13:58 | exit set_Item | MultiImplementationA.cs:15:54:15:56 | enter set_Item | +| MultiImplementationB.cs:13:56:13:58 | exit set_Item | MultiImplementationA.cs:15:54:15:56 | exit set_Item | +| MultiImplementationB.cs:13:56:13:58 | exit set_Item | MultiImplementationA.cs:15:58:15:60 | {...} | +| MultiImplementationB.cs:13:56:13:58 | exit set_Item | MultiImplementationB.cs:13:56:13:58 | enter set_Item | +| MultiImplementationB.cs:13:56:13:58 | exit set_Item | MultiImplementationB.cs:13:56:13:58 | exit set_Item | +| MultiImplementationB.cs:13:56:13:58 | exit set_Item | MultiImplementationB.cs:13:60:13:62 | {...} | +| MultiImplementationB.cs:13:60:13:62 | {...} | MultiImplementationB.cs:13:60:13:62 | {...} | +| MultiImplementationB.cs:14:17:14:18 | enter M1 | MultiImplementationA.cs:16:17:16:18 | enter M1 | +| MultiImplementationB.cs:14:17:14:18 | enter M1 | MultiImplementationB.cs:14:17:14:18 | enter M1 | +| MultiImplementationB.cs:14:17:14:18 | exit M1 | MultiImplementationA.cs:16:17:16:18 | enter M1 | +| MultiImplementationB.cs:14:17:14:18 | exit M1 | MultiImplementationA.cs:16:17:16:18 | exit M1 | +| MultiImplementationB.cs:14:17:14:18 | exit M1 | MultiImplementationA.cs:17:5:19:5 | {...} | +| MultiImplementationB.cs:14:17:14:18 | exit M1 | MultiImplementationB.cs:14:17:14:18 | enter M1 | +| MultiImplementationB.cs:14:17:14:18 | exit M1 | MultiImplementationB.cs:14:17:14:18 | exit M1 | +| MultiImplementationB.cs:14:17:14:18 | exit M1 | MultiImplementationB.cs:15:5:17:5 | {...} | +| MultiImplementationB.cs:15:5:17:5 | {...} | MultiImplementationB.cs:15:5:17:5 | {...} | +| MultiImplementationB.cs:16:9:16:31 | enter M2 | MultiImplementationB.cs:16:9:16:31 | enter M2 | +| MultiImplementationB.cs:18:12:18:13 | enter C2 | MultiImplementationA.cs:20:12:20:13 | enter C2 | +| MultiImplementationB.cs:18:12:18:13 | enter C2 | MultiImplementationB.cs:18:12:18:13 | enter C2 | +| MultiImplementationB.cs:18:12:18:13 | exit C2 | MultiImplementationA.cs:13:16:13:16 | this access | +| MultiImplementationB.cs:18:12:18:13 | exit C2 | MultiImplementationA.cs:20:12:20:13 | enter C2 | +| MultiImplementationB.cs:18:12:18:13 | exit C2 | MultiImplementationA.cs:20:12:20:13 | exit C2 | +| MultiImplementationB.cs:18:12:18:13 | exit C2 | MultiImplementationA.cs:20:22:20:31 | {...} | +| MultiImplementationB.cs:18:12:18:13 | exit C2 | MultiImplementationA.cs:24:16:24:16 | this access | +| MultiImplementationB.cs:18:12:18:13 | exit C2 | MultiImplementationB.cs:11:16:11:16 | this access | +| MultiImplementationB.cs:18:12:18:13 | exit C2 | MultiImplementationB.cs:18:12:18:13 | enter C2 | +| MultiImplementationB.cs:18:12:18:13 | exit C2 | MultiImplementationB.cs:18:12:18:13 | exit C2 | +| MultiImplementationB.cs:18:12:18:13 | exit C2 | MultiImplementationB.cs:18:22:18:36 | {...} | +| MultiImplementationB.cs:18:12:18:13 | exit C2 | MultiImplementationB.cs:22:16:22:16 | this access | +| MultiImplementationB.cs:18:22:18:36 | {...} | MultiImplementationB.cs:18:22:18:36 | {...} | +| MultiImplementationB.cs:19:12:19:13 | enter C2 | MultiImplementationA.cs:21:12:21:13 | enter C2 | +| MultiImplementationB.cs:19:12:19:13 | enter C2 | MultiImplementationB.cs:19:12:19:13 | enter C2 | +| MultiImplementationB.cs:19:12:19:13 | exit C2 | MultiImplementationA.cs:21:12:21:13 | enter C2 | +| MultiImplementationB.cs:19:12:19:13 | exit C2 | MultiImplementationA.cs:21:12:21:13 | exit C2 | +| MultiImplementationB.cs:19:12:19:13 | exit C2 | MultiImplementationA.cs:21:24:21:24 | 0 | +| MultiImplementationB.cs:19:12:19:13 | exit C2 | MultiImplementationA.cs:21:27:21:29 | {...} | +| MultiImplementationB.cs:19:12:19:13 | exit C2 | MultiImplementationB.cs:19:12:19:13 | enter C2 | +| MultiImplementationB.cs:19:12:19:13 | exit C2 | MultiImplementationB.cs:19:12:19:13 | exit C2 | +| MultiImplementationB.cs:19:12:19:13 | exit C2 | MultiImplementationB.cs:19:24:19:24 | 1 | +| MultiImplementationB.cs:19:12:19:13 | exit C2 | MultiImplementationB.cs:19:27:19:29 | {...} | +| MultiImplementationB.cs:19:24:19:24 | 1 | MultiImplementationB.cs:19:24:19:24 | 1 | +| MultiImplementationB.cs:19:27:19:29 | {...} | MultiImplementationB.cs:19:27:19:29 | {...} | +| MultiImplementationB.cs:20:6:20:7 | enter ~C2 | MultiImplementationA.cs:22:6:22:7 | enter ~C2 | +| MultiImplementationB.cs:20:6:20:7 | enter ~C2 | MultiImplementationB.cs:20:6:20:7 | enter ~C2 | +| MultiImplementationB.cs:20:6:20:7 | exit ~C2 | MultiImplementationA.cs:22:6:22:7 | enter ~C2 | +| MultiImplementationB.cs:20:6:20:7 | exit ~C2 | MultiImplementationA.cs:22:6:22:7 | exit ~C2 | +| MultiImplementationB.cs:20:6:20:7 | exit ~C2 | MultiImplementationA.cs:22:11:22:13 | {...} | +| MultiImplementationB.cs:20:6:20:7 | exit ~C2 | MultiImplementationB.cs:20:6:20:7 | enter ~C2 | +| MultiImplementationB.cs:20:6:20:7 | exit ~C2 | MultiImplementationB.cs:20:6:20:7 | exit ~C2 | +| MultiImplementationB.cs:20:6:20:7 | exit ~C2 | MultiImplementationB.cs:20:11:20:25 | {...} | +| MultiImplementationB.cs:20:11:20:25 | {...} | MultiImplementationB.cs:20:11:20:25 | {...} | +| MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | +| MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | +| MultiImplementationB.cs:21:28:21:35 | exit implicit conversion | MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | +| MultiImplementationB.cs:21:28:21:35 | exit implicit conversion | MultiImplementationA.cs:23:28:23:35 | exit implicit conversion | +| MultiImplementationB.cs:21:28:21:35 | exit implicit conversion | MultiImplementationA.cs:23:50:23:53 | null | +| MultiImplementationB.cs:21:28:21:35 | exit implicit conversion | MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | +| MultiImplementationB.cs:21:28:21:35 | exit implicit conversion | MultiImplementationB.cs:21:28:21:35 | exit implicit conversion | +| MultiImplementationB.cs:21:28:21:35 | exit implicit conversion | MultiImplementationB.cs:21:56:21:59 | null | +| MultiImplementationB.cs:21:56:21:59 | null | MultiImplementationB.cs:21:56:21:59 | null | +| MultiImplementationB.cs:22:16:22:16 | this access | MultiImplementationB.cs:22:16:22:16 | this access | +| MultiImplementationB.cs:27:21:27:23 | enter get_P3 | MultiImplementationA.cs:30:21:30:23 | enter get_P3 | +| MultiImplementationB.cs:27:21:27:23 | enter get_P3 | MultiImplementationB.cs:27:21:27:23 | enter get_P3 | +| MultiImplementationB.cs:32:9:32:10 | enter M1 | MultiImplementationA.cs:36:9:36:10 | enter M1 | +| MultiImplementationB.cs:32:9:32:10 | enter M1 | MultiImplementationB.cs:32:9:32:10 | enter M1 | +| MultiImplementationB.cs:32:9:32:10 | exit M1 | MultiImplementationA.cs:36:9:36:10 | enter M1 | +| MultiImplementationB.cs:32:9:32:10 | exit M1 | MultiImplementationA.cs:36:9:36:10 | exit M1 | +| MultiImplementationB.cs:32:9:32:10 | exit M1 | MultiImplementationA.cs:36:14:36:28 | {...} | +| MultiImplementationB.cs:32:9:32:10 | exit M1 | MultiImplementationB.cs:32:9:32:10 | enter M1 | +| MultiImplementationB.cs:32:9:32:10 | exit M1 | MultiImplementationB.cs:32:9:32:10 | exit M1 | +| MultiImplementationB.cs:32:9:32:10 | exit M1 | MultiImplementationB.cs:32:17:32:17 | 0 | +| MultiImplementationB.cs:32:17:32:17 | 0 | MultiImplementationB.cs:32:17:32:17 | 0 | | NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:9:3:10 | enter M1 | | NullCoalescing.cs:3:9:3:10 | exit M1 | NullCoalescing.cs:3:9:3:10 | enter M1 | | NullCoalescing.cs:3:9:3:10 | exit M1 | NullCoalescing.cs:3:9:3:10 | exit M1 | @@ -9297,63 +11948,63 @@ postBlockDominance | Switch.cs:66:10:66:11 | enter M6 | Switch.cs:66:10:66:11 | enter M6 | | Switch.cs:66:10:66:11 | exit M6 | Switch.cs:66:10:66:11 | enter M6 | | Switch.cs:66:10:66:11 | exit M6 | Switch.cs:66:10:66:11 | exit M6 | -| Switch.cs:66:10:66:11 | exit M6 | Switch.cs:73:15:73:20 | break; | -| Switch.cs:73:15:73:20 | break; | Switch.cs:73:15:73:20 | break; | +| Switch.cs:66:10:66:11 | exit M6 | Switch.cs:73:17:73:22 | break; | +| Switch.cs:73:17:73:22 | break; | Switch.cs:73:17:73:22 | break; | | Switch.cs:77:10:77:11 | enter M7 | Switch.cs:77:10:77:11 | enter M7 | | Switch.cs:77:10:77:11 | exit M7 | Switch.cs:77:10:77:11 | enter M7 | | Switch.cs:77:10:77:11 | exit M7 | Switch.cs:77:10:77:11 | exit M7 | -| Switch.cs:77:10:77:11 | exit M7 | Switch.cs:82:22:82:25 | true | -| Switch.cs:77:10:77:11 | exit M7 | Switch.cs:83:13:83:20 | case ...: | -| Switch.cs:77:10:77:11 | exit M7 | Switch.cs:84:15:85:22 | if (...) ... | -| Switch.cs:77:10:77:11 | exit M7 | Switch.cs:85:17:85:22 | break; | -| Switch.cs:77:10:77:11 | exit M7 | Switch.cs:86:22:86:25 | true | +| Switch.cs:77:10:77:11 | exit M7 | Switch.cs:82:24:82:27 | true | +| Switch.cs:77:10:77:11 | exit M7 | Switch.cs:83:13:83:19 | case ...: | +| Switch.cs:77:10:77:11 | exit M7 | Switch.cs:84:17:85:26 | if (...) ... | +| Switch.cs:77:10:77:11 | exit M7 | Switch.cs:85:21:85:26 | break; | +| Switch.cs:77:10:77:11 | exit M7 | Switch.cs:86:24:86:27 | true | | Switch.cs:77:10:77:11 | exit M7 | Switch.cs:88:16:88:20 | false | -| Switch.cs:82:22:82:25 | true | Switch.cs:82:22:82:25 | true | -| Switch.cs:83:13:83:20 | case ...: | Switch.cs:83:13:83:20 | case ...: | -| Switch.cs:84:15:85:22 | if (...) ... | Switch.cs:84:15:85:22 | if (...) ... | -| Switch.cs:85:17:85:22 | break; | Switch.cs:85:17:85:22 | break; | -| Switch.cs:86:22:86:25 | true | Switch.cs:86:22:86:25 | true | -| Switch.cs:88:16:88:20 | false | Switch.cs:85:17:85:22 | break; | +| Switch.cs:82:24:82:27 | true | Switch.cs:82:24:82:27 | true | +| Switch.cs:83:13:83:19 | case ...: | Switch.cs:83:13:83:19 | case ...: | +| Switch.cs:84:17:85:26 | if (...) ... | Switch.cs:84:17:85:26 | if (...) ... | +| Switch.cs:85:21:85:26 | break; | Switch.cs:85:21:85:26 | break; | +| Switch.cs:86:24:86:27 | true | Switch.cs:86:24:86:27 | true | +| Switch.cs:88:16:88:20 | false | Switch.cs:85:21:85:26 | break; | | Switch.cs:88:16:88:20 | false | Switch.cs:88:16:88:20 | false | | Switch.cs:91:10:91:11 | enter M8 | Switch.cs:91:10:91:11 | enter M8 | | Switch.cs:91:10:91:11 | exit M8 | Switch.cs:91:10:91:11 | enter M8 | | Switch.cs:91:10:91:11 | exit M8 | Switch.cs:91:10:91:11 | exit M8 | -| Switch.cs:91:10:91:11 | exit M8 | Switch.cs:96:22:96:25 | true | +| Switch.cs:91:10:91:11 | exit M8 | Switch.cs:96:24:96:27 | true | | Switch.cs:91:10:91:11 | exit M8 | Switch.cs:98:16:98:20 | false | -| Switch.cs:96:22:96:25 | true | Switch.cs:96:22:96:25 | true | +| Switch.cs:96:24:96:27 | true | Switch.cs:96:24:96:27 | true | | Switch.cs:98:16:98:20 | false | Switch.cs:98:16:98:20 | false | | Switch.cs:101:9:101:10 | enter M9 | Switch.cs:101:9:101:10 | enter M9 | | Switch.cs:101:9:101:10 | exit M9 | Switch.cs:101:9:101:10 | enter M9 | | Switch.cs:101:9:101:10 | exit M9 | Switch.cs:101:9:101:10 | exit M9 | | Switch.cs:101:9:101:10 | exit M9 | Switch.cs:103:19:103:25 | access to property Length | -| Switch.cs:101:9:101:10 | exit M9 | Switch.cs:105:13:105:20 | case ...: | -| Switch.cs:101:9:101:10 | exit M9 | Switch.cs:105:29:105:29 | 0 | -| Switch.cs:101:9:101:10 | exit M9 | Switch.cs:106:13:106:20 | case ...: | -| Switch.cs:101:9:101:10 | exit M9 | Switch.cs:106:29:106:29 | 1 | +| Switch.cs:101:9:101:10 | exit M9 | Switch.cs:105:13:105:19 | case ...: | +| Switch.cs:101:9:101:10 | exit M9 | Switch.cs:105:28:105:28 | 0 | +| Switch.cs:101:9:101:10 | exit M9 | Switch.cs:106:13:106:19 | case ...: | +| Switch.cs:101:9:101:10 | exit M9 | Switch.cs:106:28:106:28 | 1 | | Switch.cs:101:9:101:10 | exit M9 | Switch.cs:108:17:108:17 | 1 | | Switch.cs:103:19:103:25 | access to property Length | Switch.cs:103:19:103:25 | access to property Length | -| Switch.cs:105:13:105:20 | case ...: | Switch.cs:101:9:101:10 | enter M9 | -| Switch.cs:105:13:105:20 | case ...: | Switch.cs:103:19:103:25 | access to property Length | -| Switch.cs:105:13:105:20 | case ...: | Switch.cs:105:13:105:20 | case ...: | -| Switch.cs:105:29:105:29 | 0 | Switch.cs:105:29:105:29 | 0 | -| Switch.cs:106:13:106:20 | case ...: | Switch.cs:106:13:106:20 | case ...: | -| Switch.cs:106:29:106:29 | 1 | Switch.cs:106:29:106:29 | 1 | +| Switch.cs:105:13:105:19 | case ...: | Switch.cs:101:9:101:10 | enter M9 | +| Switch.cs:105:13:105:19 | case ...: | Switch.cs:103:19:103:25 | access to property Length | +| Switch.cs:105:13:105:19 | case ...: | Switch.cs:105:13:105:19 | case ...: | +| Switch.cs:105:28:105:28 | 0 | Switch.cs:105:28:105:28 | 0 | +| Switch.cs:106:13:106:19 | case ...: | Switch.cs:106:13:106:19 | case ...: | +| Switch.cs:106:28:106:28 | 1 | Switch.cs:106:28:106:28 | 1 | | Switch.cs:108:17:108:17 | 1 | Switch.cs:108:17:108:17 | 1 | | Switch.cs:111:17:111:21 | enter Throw | Switch.cs:111:17:111:21 | enter Throw | | Switch.cs:113:9:113:11 | enter M10 | Switch.cs:113:9:113:11 | enter M10 | | Switch.cs:113:9:113:11 | exit M10 | Switch.cs:113:9:113:11 | enter M10 | | Switch.cs:113:9:113:11 | exit M10 | Switch.cs:113:9:113:11 | exit M10 | | Switch.cs:113:9:113:11 | exit M10 | Switch.cs:117:25:117:25 | access to parameter s | -| Switch.cs:113:9:113:11 | exit M10 | Switch.cs:117:43:117:43 | 1 | -| Switch.cs:113:9:113:11 | exit M10 | Switch.cs:118:13:118:33 | case ...: | +| Switch.cs:113:9:113:11 | exit M10 | Switch.cs:117:44:117:44 | 1 | +| Switch.cs:113:9:113:11 | exit M10 | Switch.cs:118:13:118:34 | case ...: | | Switch.cs:113:9:113:11 | exit M10 | Switch.cs:118:25:118:25 | access to parameter s | -| Switch.cs:113:9:113:11 | exit M10 | Switch.cs:118:42:118:42 | 2 | +| Switch.cs:113:9:113:11 | exit M10 | Switch.cs:118:43:118:43 | 2 | | Switch.cs:113:9:113:11 | exit M10 | Switch.cs:120:17:120:17 | 1 | | Switch.cs:117:25:117:25 | access to parameter s | Switch.cs:117:25:117:25 | access to parameter s | -| Switch.cs:117:43:117:43 | 1 | Switch.cs:117:43:117:43 | 1 | -| Switch.cs:118:13:118:33 | case ...: | Switch.cs:118:13:118:33 | case ...: | +| Switch.cs:117:44:117:44 | 1 | Switch.cs:117:44:117:44 | 1 | +| Switch.cs:118:13:118:34 | case ...: | Switch.cs:118:13:118:34 | case ...: | | Switch.cs:118:25:118:25 | access to parameter s | Switch.cs:118:25:118:25 | access to parameter s | -| Switch.cs:118:42:118:42 | 2 | Switch.cs:118:42:118:42 | 2 | +| Switch.cs:118:43:118:43 | 2 | Switch.cs:118:43:118:43 | 2 | | Switch.cs:120:17:120:17 | 1 | Switch.cs:120:17:120:17 | 1 | | Switch.cs:123:10:123:12 | enter M11 | Switch.cs:123:10:123:12 | enter M11 | | Switch.cs:123:10:123:12 | exit M11 | Switch.cs:123:10:123:12 | enter M11 | @@ -9395,6 +12046,23 @@ postBlockDominance | Switch.cs:149:13:149:20 | default: | Switch.cs:149:13:149:20 | default: | | Switch.cs:150:13:150:19 | case ...: | Switch.cs:150:13:150:19 | case ...: | | Switch.cs:150:28:150:28 | 2 | Switch.cs:150:28:150:28 | 2 | +| Switch.cs:154:10:154:12 | enter M15 | Switch.cs:154:10:154:12 | enter M15 | +| Switch.cs:154:10:154:12 | exit M15 | Switch.cs:154:10:154:12 | enter M15 | +| Switch.cs:154:10:154:12 | exit M15 | Switch.cs:154:10:154:12 | exit M15 | +| Switch.cs:154:10:154:12 | exit M15 | Switch.cs:156:13:156:54 | String s = ... | +| Switch.cs:154:10:154:12 | exit M15 | Switch.cs:156:36:156:38 | "a" | +| Switch.cs:154:10:154:12 | exit M15 | Switch.cs:156:41:156:52 | ... => ... | +| Switch.cs:154:10:154:12 | exit M15 | Switch.cs:156:50:156:52 | "b" | +| Switch.cs:154:10:154:12 | exit M15 | Switch.cs:158:13:158:49 | ...; | +| Switch.cs:154:10:154:12 | exit M15 | Switch.cs:160:13:160:49 | ...; | +| Switch.cs:156:13:156:54 | String s = ... | Switch.cs:156:13:156:54 | String s = ... | +| Switch.cs:156:13:156:54 | String s = ... | Switch.cs:156:36:156:38 | "a" | +| Switch.cs:156:13:156:54 | String s = ... | Switch.cs:156:50:156:52 | "b" | +| Switch.cs:156:36:156:38 | "a" | Switch.cs:156:36:156:38 | "a" | +| Switch.cs:156:41:156:52 | ... => ... | Switch.cs:156:41:156:52 | ... => ... | +| Switch.cs:156:50:156:52 | "b" | Switch.cs:156:50:156:52 | "b" | +| Switch.cs:158:13:158:49 | ...; | Switch.cs:158:13:158:49 | ...; | +| Switch.cs:160:13:160:49 | ...; | Switch.cs:160:13:160:49 | ...; | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:3:10:3:10 | enter M | | TypeAccesses.cs:7:25:7:25 | ; | TypeAccesses.cs:7:25:7:25 | ; | | TypeAccesses.cs:8:9:8:28 | ... ...; | TypeAccesses.cs:3:10:3:10 | enter M | diff --git a/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected b/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected index bb34142d5506..e73626a3c95b 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected @@ -311,12 +311,15 @@ nodeEnclosing | ArrayCreation.cs:5:31:5:31 | 1 | ArrayCreation.cs:5:12:5:13 | M2 | | ArrayCreation.cs:7:11:7:12 | enter M3 | ArrayCreation.cs:7:11:7:12 | M3 | | ArrayCreation.cs:7:11:7:12 | exit M3 | ArrayCreation.cs:7:11:7:12 | M3 | +| ArrayCreation.cs:7:19:7:36 | 2 | ArrayCreation.cs:7:11:7:12 | M3 | | ArrayCreation.cs:7:19:7:36 | array creation of type Int32[] | ArrayCreation.cs:7:11:7:12 | M3 | | ArrayCreation.cs:7:29:7:36 | { ..., ... } | ArrayCreation.cs:7:11:7:12 | M3 | | ArrayCreation.cs:7:31:7:31 | 0 | ArrayCreation.cs:7:11:7:12 | M3 | | ArrayCreation.cs:7:34:7:34 | 1 | ArrayCreation.cs:7:11:7:12 | M3 | | ArrayCreation.cs:9:12:9:13 | enter M4 | ArrayCreation.cs:9:12:9:13 | M4 | | ArrayCreation.cs:9:12:9:13 | exit M4 | ArrayCreation.cs:9:12:9:13 | M4 | +| ArrayCreation.cs:9:20:9:52 | 2 | ArrayCreation.cs:9:12:9:13 | M4 | +| ArrayCreation.cs:9:20:9:52 | 2 | ArrayCreation.cs:9:12:9:13 | M4 | | ArrayCreation.cs:9:20:9:52 | array creation of type Int32[,] | ArrayCreation.cs:9:12:9:13 | M4 | | ArrayCreation.cs:9:31:9:52 | { ..., ... } | ArrayCreation.cs:9:12:9:13 | M4 | | ArrayCreation.cs:9:33:9:40 | { ..., ... } | ArrayCreation.cs:9:12:9:13 | M4 | @@ -325,6 +328,531 @@ nodeEnclosing | ArrayCreation.cs:9:43:9:50 | { ..., ... } | ArrayCreation.cs:9:12:9:13 | M4 | | ArrayCreation.cs:9:45:9:45 | 2 | ArrayCreation.cs:9:12:9:13 | M4 | | ArrayCreation.cs:9:48:9:48 | 3 | ArrayCreation.cs:9:12:9:13 | M4 | +| Assert.cs:7:10:7:11 | enter M1 | Assert.cs:7:10:7:11 | M1 | +| Assert.cs:7:10:7:11 | exit M1 | Assert.cs:7:10:7:11 | M1 | +| Assert.cs:8:5:12:5 | {...} | Assert.cs:7:10:7:11 | M1 | +| Assert.cs:9:9:9:33 | ... ...; | Assert.cs:7:10:7:11 | M1 | +| Assert.cs:9:16:9:32 | String s = ... | Assert.cs:7:10:7:11 | M1 | +| Assert.cs:9:20:9:20 | access to parameter b | Assert.cs:7:10:7:11 | M1 | +| Assert.cs:9:20:9:32 | ... ? ... : ... | Assert.cs:7:10:7:11 | M1 | +| Assert.cs:9:24:9:27 | null | Assert.cs:7:10:7:11 | M1 | +| Assert.cs:9:31:9:32 | "" | Assert.cs:7:10:7:11 | M1 | +| Assert.cs:10:9:10:31 | [assertion failure] call to method Assert | Assert.cs:7:10:7:11 | M1 | +| Assert.cs:10:9:10:31 | [assertion success] call to method Assert | Assert.cs:7:10:7:11 | M1 | +| Assert.cs:10:9:10:32 | ...; | Assert.cs:7:10:7:11 | M1 | +| Assert.cs:10:22:10:22 | access to local variable s | Assert.cs:7:10:7:11 | M1 | +| Assert.cs:10:22:10:30 | ... != ... | Assert.cs:7:10:7:11 | M1 | +| Assert.cs:10:27:10:30 | null | Assert.cs:7:10:7:11 | M1 | +| Assert.cs:11:9:11:35 | call to method WriteLine | Assert.cs:7:10:7:11 | M1 | +| Assert.cs:11:9:11:36 | ...; | Assert.cs:7:10:7:11 | M1 | +| Assert.cs:11:27:11:27 | access to local variable s | Assert.cs:7:10:7:11 | M1 | +| Assert.cs:11:27:11:34 | access to property Length | Assert.cs:7:10:7:11 | M1 | +| Assert.cs:14:10:14:11 | enter M2 | Assert.cs:14:10:14:11 | M2 | +| Assert.cs:14:10:14:11 | exit M2 | Assert.cs:14:10:14:11 | M2 | +| Assert.cs:15:5:19:5 | {...} | Assert.cs:14:10:14:11 | M2 | +| Assert.cs:16:9:16:33 | ... ...; | Assert.cs:14:10:14:11 | M2 | +| Assert.cs:16:16:16:32 | String s = ... | Assert.cs:14:10:14:11 | M2 | +| Assert.cs:16:20:16:20 | access to parameter b | Assert.cs:14:10:14:11 | M2 | +| Assert.cs:16:20:16:32 | ... ? ... : ... | Assert.cs:14:10:14:11 | M2 | +| Assert.cs:16:24:16:27 | null | Assert.cs:14:10:14:11 | M2 | +| Assert.cs:16:31:16:32 | "" | Assert.cs:14:10:14:11 | M2 | +| Assert.cs:17:9:17:24 | [assertion failure] call to method IsNull | Assert.cs:14:10:14:11 | M2 | +| Assert.cs:17:9:17:24 | [assertion success] call to method IsNull | Assert.cs:14:10:14:11 | M2 | +| Assert.cs:17:9:17:25 | ...; | Assert.cs:14:10:14:11 | M2 | +| Assert.cs:17:23:17:23 | access to local variable s | Assert.cs:14:10:14:11 | M2 | +| Assert.cs:18:9:18:35 | call to method WriteLine | Assert.cs:14:10:14:11 | M2 | +| Assert.cs:18:9:18:36 | ...; | Assert.cs:14:10:14:11 | M2 | +| Assert.cs:18:27:18:27 | access to local variable s | Assert.cs:14:10:14:11 | M2 | +| Assert.cs:18:27:18:34 | access to property Length | Assert.cs:14:10:14:11 | M2 | +| Assert.cs:21:10:21:11 | enter M3 | Assert.cs:21:10:21:11 | M3 | +| Assert.cs:21:10:21:11 | exit M3 | Assert.cs:21:10:21:11 | M3 | +| Assert.cs:22:5:26:5 | {...} | Assert.cs:21:10:21:11 | M3 | +| Assert.cs:23:9:23:33 | ... ...; | Assert.cs:21:10:21:11 | M3 | +| Assert.cs:23:16:23:32 | String s = ... | Assert.cs:21:10:21:11 | M3 | +| Assert.cs:23:20:23:20 | access to parameter b | Assert.cs:21:10:21:11 | M3 | +| Assert.cs:23:20:23:32 | ... ? ... : ... | Assert.cs:21:10:21:11 | M3 | +| Assert.cs:23:24:23:27 | null | Assert.cs:21:10:21:11 | M3 | +| Assert.cs:23:31:23:32 | "" | Assert.cs:21:10:21:11 | M3 | +| Assert.cs:24:9:24:27 | [assertion failure] call to method IsNotNull | Assert.cs:21:10:21:11 | M3 | +| Assert.cs:24:9:24:27 | [assertion success] call to method IsNotNull | Assert.cs:21:10:21:11 | M3 | +| Assert.cs:24:9:24:28 | ...; | Assert.cs:21:10:21:11 | M3 | +| Assert.cs:24:26:24:26 | access to local variable s | Assert.cs:21:10:21:11 | M3 | +| Assert.cs:25:9:25:35 | call to method WriteLine | Assert.cs:21:10:21:11 | M3 | +| Assert.cs:25:9:25:36 | ...; | Assert.cs:21:10:21:11 | M3 | +| Assert.cs:25:27:25:27 | access to local variable s | Assert.cs:21:10:21:11 | M3 | +| Assert.cs:25:27:25:34 | access to property Length | Assert.cs:21:10:21:11 | M3 | +| Assert.cs:28:10:28:11 | enter M4 | Assert.cs:28:10:28:11 | M4 | +| Assert.cs:28:10:28:11 | exit M4 | Assert.cs:28:10:28:11 | M4 | +| Assert.cs:29:5:33:5 | {...} | Assert.cs:28:10:28:11 | M4 | +| Assert.cs:30:9:30:33 | ... ...; | Assert.cs:28:10:28:11 | M4 | +| Assert.cs:30:16:30:32 | String s = ... | Assert.cs:28:10:28:11 | M4 | +| Assert.cs:30:20:30:20 | access to parameter b | Assert.cs:28:10:28:11 | M4 | +| Assert.cs:30:20:30:32 | ... ? ... : ... | Assert.cs:28:10:28:11 | M4 | +| Assert.cs:30:24:30:27 | null | Assert.cs:28:10:28:11 | M4 | +| Assert.cs:30:31:30:32 | "" | Assert.cs:28:10:28:11 | M4 | +| Assert.cs:31:9:31:32 | [assertion failure] call to method IsTrue | Assert.cs:28:10:28:11 | M4 | +| Assert.cs:31:9:31:32 | [assertion success] call to method IsTrue | Assert.cs:28:10:28:11 | M4 | +| Assert.cs:31:9:31:33 | ...; | Assert.cs:28:10:28:11 | M4 | +| Assert.cs:31:23:31:23 | access to local variable s | Assert.cs:28:10:28:11 | M4 | +| Assert.cs:31:23:31:31 | ... == ... | Assert.cs:28:10:28:11 | M4 | +| Assert.cs:31:28:31:31 | null | Assert.cs:28:10:28:11 | M4 | +| Assert.cs:32:9:32:35 | call to method WriteLine | Assert.cs:28:10:28:11 | M4 | +| Assert.cs:32:9:32:36 | ...; | Assert.cs:28:10:28:11 | M4 | +| Assert.cs:32:27:32:27 | access to local variable s | Assert.cs:28:10:28:11 | M4 | +| Assert.cs:32:27:32:34 | access to property Length | Assert.cs:28:10:28:11 | M4 | +| Assert.cs:35:10:35:11 | enter M5 | Assert.cs:35:10:35:11 | M5 | +| Assert.cs:35:10:35:11 | exit M5 | Assert.cs:35:10:35:11 | M5 | +| Assert.cs:36:5:40:5 | {...} | Assert.cs:35:10:35:11 | M5 | +| Assert.cs:37:9:37:33 | ... ...; | Assert.cs:35:10:35:11 | M5 | +| Assert.cs:37:16:37:32 | String s = ... | Assert.cs:35:10:35:11 | M5 | +| Assert.cs:37:20:37:20 | access to parameter b | Assert.cs:35:10:35:11 | M5 | +| Assert.cs:37:20:37:32 | ... ? ... : ... | Assert.cs:35:10:35:11 | M5 | +| Assert.cs:37:24:37:27 | null | Assert.cs:35:10:35:11 | M5 | +| Assert.cs:37:31:37:32 | "" | Assert.cs:35:10:35:11 | M5 | +| Assert.cs:38:9:38:32 | [assertion failure] call to method IsTrue | Assert.cs:35:10:35:11 | M5 | +| Assert.cs:38:9:38:32 | [assertion success] call to method IsTrue | Assert.cs:35:10:35:11 | M5 | +| Assert.cs:38:9:38:33 | ...; | Assert.cs:35:10:35:11 | M5 | +| Assert.cs:38:23:38:23 | access to local variable s | Assert.cs:35:10:35:11 | M5 | +| Assert.cs:38:23:38:31 | ... != ... | Assert.cs:35:10:35:11 | M5 | +| Assert.cs:38:28:38:31 | null | Assert.cs:35:10:35:11 | M5 | +| Assert.cs:39:9:39:35 | call to method WriteLine | Assert.cs:35:10:35:11 | M5 | +| Assert.cs:39:9:39:36 | ...; | Assert.cs:35:10:35:11 | M5 | +| Assert.cs:39:27:39:27 | access to local variable s | Assert.cs:35:10:35:11 | M5 | +| Assert.cs:39:27:39:34 | access to property Length | Assert.cs:35:10:35:11 | M5 | +| Assert.cs:42:10:42:11 | enter M6 | Assert.cs:42:10:42:11 | M6 | +| Assert.cs:42:10:42:11 | exit M6 | Assert.cs:42:10:42:11 | M6 | +| Assert.cs:43:5:47:5 | {...} | Assert.cs:42:10:42:11 | M6 | +| Assert.cs:44:9:44:33 | ... ...; | Assert.cs:42:10:42:11 | M6 | +| Assert.cs:44:16:44:32 | String s = ... | Assert.cs:42:10:42:11 | M6 | +| Assert.cs:44:20:44:20 | access to parameter b | Assert.cs:42:10:42:11 | M6 | +| Assert.cs:44:20:44:32 | ... ? ... : ... | Assert.cs:42:10:42:11 | M6 | +| Assert.cs:44:24:44:27 | null | Assert.cs:42:10:42:11 | M6 | +| Assert.cs:44:31:44:32 | "" | Assert.cs:42:10:42:11 | M6 | +| Assert.cs:45:9:45:33 | [assertion failure] call to method IsFalse | Assert.cs:42:10:42:11 | M6 | +| Assert.cs:45:9:45:33 | [assertion success] call to method IsFalse | Assert.cs:42:10:42:11 | M6 | +| Assert.cs:45:9:45:34 | ...; | Assert.cs:42:10:42:11 | M6 | +| Assert.cs:45:24:45:24 | access to local variable s | Assert.cs:42:10:42:11 | M6 | +| Assert.cs:45:24:45:32 | ... != ... | Assert.cs:42:10:42:11 | M6 | +| Assert.cs:45:29:45:32 | null | Assert.cs:42:10:42:11 | M6 | +| Assert.cs:46:9:46:35 | call to method WriteLine | Assert.cs:42:10:42:11 | M6 | +| Assert.cs:46:9:46:36 | ...; | Assert.cs:42:10:42:11 | M6 | +| Assert.cs:46:27:46:27 | access to local variable s | Assert.cs:42:10:42:11 | M6 | +| Assert.cs:46:27:46:34 | access to property Length | Assert.cs:42:10:42:11 | M6 | +| Assert.cs:49:10:49:11 | enter M7 | Assert.cs:49:10:49:11 | M7 | +| Assert.cs:49:10:49:11 | exit M7 | Assert.cs:49:10:49:11 | M7 | +| Assert.cs:50:5:54:5 | {...} | Assert.cs:49:10:49:11 | M7 | +| Assert.cs:51:9:51:33 | ... ...; | Assert.cs:49:10:49:11 | M7 | +| Assert.cs:51:16:51:32 | String s = ... | Assert.cs:49:10:49:11 | M7 | +| Assert.cs:51:20:51:20 | access to parameter b | Assert.cs:49:10:49:11 | M7 | +| Assert.cs:51:20:51:32 | ... ? ... : ... | Assert.cs:49:10:49:11 | M7 | +| Assert.cs:51:24:51:27 | null | Assert.cs:49:10:49:11 | M7 | +| Assert.cs:51:31:51:32 | "" | Assert.cs:49:10:49:11 | M7 | +| Assert.cs:52:9:52:33 | [assertion failure] call to method IsFalse | Assert.cs:49:10:49:11 | M7 | +| Assert.cs:52:9:52:33 | [assertion success] call to method IsFalse | Assert.cs:49:10:49:11 | M7 | +| Assert.cs:52:9:52:34 | ...; | Assert.cs:49:10:49:11 | M7 | +| Assert.cs:52:24:52:24 | access to local variable s | Assert.cs:49:10:49:11 | M7 | +| Assert.cs:52:24:52:32 | ... == ... | Assert.cs:49:10:49:11 | M7 | +| Assert.cs:52:29:52:32 | null | Assert.cs:49:10:49:11 | M7 | +| Assert.cs:53:9:53:35 | call to method WriteLine | Assert.cs:49:10:49:11 | M7 | +| Assert.cs:53:9:53:36 | ...; | Assert.cs:49:10:49:11 | M7 | +| Assert.cs:53:27:53:27 | access to local variable s | Assert.cs:49:10:49:11 | M7 | +| Assert.cs:53:27:53:34 | access to property Length | Assert.cs:49:10:49:11 | M7 | +| Assert.cs:56:10:56:11 | enter M8 | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:56:10:56:11 | exit M8 | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:57:5:61:5 | {...} | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:58:9:58:33 | ... ...; | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:58:16:58:32 | [b (line 56): false] String s = ... | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:58:16:58:32 | [b (line 56): true] String s = ... | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:58:20:58:20 | access to parameter b | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:58:20:58:32 | ... ? ... : ... | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:58:24:58:27 | [b (line 56): true] null | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:58:31:58:32 | [b (line 56): false] "" | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:59:9:59:37 | [assertion failure] call to method IsTrue | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:59:9:59:37 | [assertion success] call to method IsTrue | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:59:9:59:38 | [b (line 56): false] ...; | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:59:9:59:38 | [b (line 56): true] ...; | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:59:23:59:23 | [b (line 56): false] access to local variable s | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:59:23:59:23 | [b (line 56): true] access to local variable s | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:59:23:59:31 | [b (line 56): false] ... != ... | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:59:23:59:31 | [b (line 56): true] ... != ... | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:59:23:59:36 | [b (line 56): false] ... && ... | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:59:23:59:36 | [b (line 56): true] ... && ... | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:59:28:59:31 | [b (line 56): false] null | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:59:28:59:31 | [b (line 56): true] null | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:59:36:59:36 | [b (line 56): false] access to parameter b | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:59:36:59:36 | [b (line 56): true] access to parameter b | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:60:9:60:35 | call to method WriteLine | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:60:9:60:36 | ...; | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:60:27:60:34 | access to property Length | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:63:10:63:11 | enter M9 | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:63:10:63:11 | exit M9 | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:64:5:68:5 | {...} | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:65:9:65:33 | ... ...; | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:65:16:65:32 | [b (line 63): false] String s = ... | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:65:16:65:32 | [b (line 63): true] String s = ... | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:65:20:65:20 | access to parameter b | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:65:20:65:32 | ... ? ... : ... | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:65:24:65:27 | [b (line 63): true] null | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:65:31:65:32 | [b (line 63): false] "" | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:66:9:66:38 | [assertion failure] call to method IsFalse | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:66:9:66:38 | [assertion success] call to method IsFalse | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:66:9:66:39 | [b (line 63): false] ...; | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:66:9:66:39 | [b (line 63): true] ...; | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:66:24:66:24 | [b (line 63): false] access to local variable s | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:66:24:66:24 | [b (line 63): true] access to local variable s | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:66:24:66:32 | [b (line 63): false] ... == ... | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:66:24:66:32 | [b (line 63): true] ... == ... | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:66:24:66:37 | [b (line 63): false] ... \|\| ... | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:66:24:66:37 | [b (line 63): true] ... \|\| ... | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:66:29:66:32 | [b (line 63): false] null | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:66:29:66:32 | [b (line 63): true] null | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:66:37:66:37 | [b (line 63): false] access to parameter b | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:66:37:66:37 | [b (line 63): true] access to parameter b | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:67:9:67:35 | call to method WriteLine | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:67:9:67:36 | ...; | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:67:27:67:34 | access to property Length | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:70:10:70:12 | enter M10 | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:70:10:70:12 | exit M10 | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:71:5:75:5 | {...} | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:72:9:72:33 | ... ...; | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:72:16:72:32 | [b (line 70): false] String s = ... | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:72:16:72:32 | [b (line 70): true] String s = ... | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:72:20:72:20 | access to parameter b | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:72:20:72:32 | ... ? ... : ... | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:72:24:72:27 | [b (line 70): true] null | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:72:31:72:32 | [b (line 70): false] "" | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:73:9:73:37 | [assertion failure] call to method IsTrue | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:73:9:73:37 | [assertion success] call to method IsTrue | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:73:9:73:38 | [b (line 70): false] ...; | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:73:9:73:38 | [b (line 70): true] ...; | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:73:23:73:23 | [b (line 70): false] access to local variable s | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:73:23:73:23 | [b (line 70): true] access to local variable s | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:73:23:73:31 | [b (line 70): false] ... == ... | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:73:23:73:31 | [b (line 70): true] ... == ... | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:73:23:73:36 | [b (line 70): false] ... && ... | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:73:23:73:36 | [b (line 70): true] ... && ... | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:73:28:73:31 | [b (line 70): false] null | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:73:28:73:31 | [b (line 70): true] null | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:73:36:73:36 | [b (line 70): false] access to parameter b | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:73:36:73:36 | [b (line 70): true] access to parameter b | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:74:9:74:35 | call to method WriteLine | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:74:9:74:36 | ...; | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:74:27:74:34 | access to property Length | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:77:10:77:12 | enter M11 | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:77:10:77:12 | exit M11 | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:78:5:82:5 | {...} | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:79:9:79:33 | ... ...; | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:79:16:79:32 | [b (line 77): false] String s = ... | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:79:16:79:32 | [b (line 77): true] String s = ... | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:79:20:79:20 | access to parameter b | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:79:20:79:32 | ... ? ... : ... | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:79:24:79:27 | [b (line 77): true] null | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:79:31:79:32 | [b (line 77): false] "" | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:80:9:80:38 | [assertion failure] call to method IsFalse | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:80:9:80:38 | [assertion success] call to method IsFalse | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:80:9:80:39 | [b (line 77): false] ...; | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:80:9:80:39 | [b (line 77): true] ...; | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:80:24:80:24 | [b (line 77): false] access to local variable s | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:80:24:80:24 | [b (line 77): true] access to local variable s | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:80:24:80:32 | [b (line 77): false] ... != ... | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:80:24:80:32 | [b (line 77): true] ... != ... | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:80:24:80:37 | [b (line 77): false] ... \|\| ... | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:80:24:80:37 | [b (line 77): true] ... \|\| ... | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:80:29:80:32 | [b (line 77): false] null | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:80:29:80:32 | [b (line 77): true] null | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:80:37:80:37 | [b (line 77): false] access to parameter b | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:80:37:80:37 | [b (line 77): true] access to parameter b | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:81:9:81:35 | call to method WriteLine | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:81:9:81:36 | ...; | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:81:27:81:34 | access to property Length | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:85:5:129:5 | {...} | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:86:9:86:33 | ... ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:86:16:86:32 | [b (line 84): false] String s = ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:86:16:86:32 | [b (line 84): true] String s = ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:86:20:86:20 | access to parameter b | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:86:20:86:32 | ... ? ... : ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:87:9:87:31 | [assertion failure, b (line 84): false] call to method Assert | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:87:9:87:31 | [assertion failure, b (line 84): true] call to method Assert | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:87:9:87:32 | [b (line 84): false] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:87:9:87:32 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:87:22:87:22 | [b (line 84): false] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:87:22:87:22 | [b (line 84): true] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:87:22:87:30 | [b (line 84): false] ... != ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:87:22:87:30 | [b (line 84): true] ... != ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:87:27:87:30 | [b (line 84): false] null | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:87:27:87:30 | [b (line 84): true] null | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:88:9:88:35 | [b (line 84): false] call to method WriteLine | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:88:9:88:35 | [b (line 84): true] call to method WriteLine | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:88:9:88:36 | [b (line 84): false] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:88:9:88:36 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:88:27:88:27 | [b (line 84): false] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:88:27:88:27 | [b (line 84): true] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:88:27:88:34 | [b (line 84): false] access to property Length | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:88:27:88:34 | [b (line 84): true] access to property Length | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:90:9:90:25 | [b (line 84): false] ... = ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:90:9:90:25 | [b (line 84): true] ... = ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:90:9:90:26 | [b (line 84): false] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:90:9:90:26 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:90:13:90:13 | [b (line 84): false] access to parameter b | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:90:13:90:13 | [b (line 84): true] access to parameter b | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:90:13:90:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:90:13:90:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:90:17:90:20 | [b (line 84): true] null | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:90:24:90:25 | [b (line 84): false] "" | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:91:9:91:24 | [assertion failure, b (line 84): false] call to method IsNull | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:91:9:91:24 | [assertion failure, b (line 84): true] call to method IsNull | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:91:9:91:25 | [b (line 84): false] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:91:9:91:25 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:91:23:91:23 | [b (line 84): false] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:91:23:91:23 | [b (line 84): true] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:92:9:92:35 | [b (line 84): false] call to method WriteLine | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:92:9:92:35 | [b (line 84): true] call to method WriteLine | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:92:9:92:36 | [b (line 84): false] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:92:9:92:36 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:92:27:92:27 | [b (line 84): false] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:92:27:92:27 | [b (line 84): true] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:92:27:92:34 | [b (line 84): false] access to property Length | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:92:27:92:34 | [b (line 84): true] access to property Length | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:94:9:94:25 | [b (line 84): false] ... = ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:94:9:94:25 | [b (line 84): true] ... = ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:94:9:94:26 | [b (line 84): false] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:94:9:94:26 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:94:13:94:13 | [b (line 84): false] access to parameter b | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:94:13:94:13 | [b (line 84): true] access to parameter b | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:94:13:94:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:94:13:94:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:94:17:94:20 | [b (line 84): true] null | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:94:24:94:25 | [b (line 84): false] "" | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:95:9:95:27 | [assertion failure, b (line 84): false] call to method IsNotNull | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:95:9:95:27 | [assertion failure, b (line 84): true] call to method IsNotNull | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:95:9:95:28 | [b (line 84): false] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:95:9:95:28 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:95:26:95:26 | [b (line 84): false] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:95:26:95:26 | [b (line 84): true] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:96:9:96:35 | [b (line 84): false] call to method WriteLine | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:96:9:96:35 | [b (line 84): true] call to method WriteLine | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:96:9:96:36 | [b (line 84): false] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:96:9:96:36 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:96:27:96:27 | [b (line 84): false] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:96:27:96:27 | [b (line 84): true] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:96:27:96:34 | [b (line 84): false] access to property Length | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:96:27:96:34 | [b (line 84): true] access to property Length | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:98:9:98:25 | [b (line 84): false] ... = ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:98:9:98:25 | [b (line 84): true] ... = ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:98:9:98:26 | [b (line 84): false] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:98:9:98:26 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:98:13:98:13 | [b (line 84): false] access to parameter b | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:98:13:98:13 | [b (line 84): true] access to parameter b | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:98:13:98:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:98:13:98:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:98:17:98:20 | [b (line 84): true] null | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:98:24:98:25 | [b (line 84): false] "" | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:99:9:99:32 | [assertion failure, b (line 84): false] call to method IsTrue | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:99:9:99:32 | [assertion failure, b (line 84): true] call to method IsTrue | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:99:9:99:33 | [b (line 84): false] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:99:9:99:33 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:99:23:99:23 | [b (line 84): false] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:99:23:99:23 | [b (line 84): true] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:99:23:99:31 | [b (line 84): false] ... == ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:99:23:99:31 | [b (line 84): true] ... == ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:99:28:99:31 | [b (line 84): false] null | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:99:28:99:31 | [b (line 84): true] null | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:100:9:100:35 | [b (line 84): false] call to method WriteLine | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:100:9:100:35 | [b (line 84): true] call to method WriteLine | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:100:9:100:36 | [b (line 84): false] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:100:9:100:36 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:100:27:100:27 | [b (line 84): false] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:100:27:100:27 | [b (line 84): true] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:100:27:100:34 | [b (line 84): false] access to property Length | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:100:27:100:34 | [b (line 84): true] access to property Length | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:102:9:102:25 | [b (line 84): false] ... = ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:102:9:102:25 | [b (line 84): true] ... = ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:102:9:102:26 | [b (line 84): false] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:102:9:102:26 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:102:13:102:13 | [b (line 84): false] access to parameter b | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:102:13:102:13 | [b (line 84): true] access to parameter b | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:102:13:102:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:102:13:102:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:102:17:102:20 | [b (line 84): true] null | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:102:24:102:25 | [b (line 84): false] "" | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:103:9:103:32 | [assertion failure, b (line 84): false] call to method IsTrue | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:103:9:103:32 | [assertion failure, b (line 84): true] call to method IsTrue | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:103:9:103:33 | [b (line 84): false] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:103:9:103:33 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:103:23:103:23 | [b (line 84): false] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:103:23:103:23 | [b (line 84): true] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:103:23:103:31 | [b (line 84): false] ... != ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:103:23:103:31 | [b (line 84): true] ... != ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:103:28:103:31 | [b (line 84): false] null | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:103:28:103:31 | [b (line 84): true] null | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:104:9:104:35 | [b (line 84): false] call to method WriteLine | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:104:9:104:35 | [b (line 84): true] call to method WriteLine | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:104:9:104:36 | [b (line 84): false] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:104:9:104:36 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:104:27:104:27 | [b (line 84): false] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:104:27:104:27 | [b (line 84): true] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:104:27:104:34 | [b (line 84): false] access to property Length | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:104:27:104:34 | [b (line 84): true] access to property Length | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:106:9:106:25 | [b (line 84): false] ... = ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:106:9:106:25 | [b (line 84): true] ... = ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:106:9:106:26 | [b (line 84): false] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:106:9:106:26 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:106:13:106:13 | [b (line 84): false] access to parameter b | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:106:13:106:13 | [b (line 84): true] access to parameter b | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:106:13:106:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:106:13:106:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:106:17:106:20 | [b (line 84): true] null | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:106:24:106:25 | [b (line 84): false] "" | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:107:9:107:34 | [b (line 84): false] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:107:9:107:34 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:107:24:107:24 | [b (line 84): false] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:107:24:107:24 | [b (line 84): true] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:107:24:107:32 | [b (line 84): false] ... != ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:107:24:107:32 | [b (line 84): true] ... != ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:107:29:107:32 | [b (line 84): false] null | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:107:29:107:32 | [b (line 84): true] null | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:108:9:108:35 | [b (line 84): false] call to method WriteLine | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:108:9:108:35 | [b (line 84): true] call to method WriteLine | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:108:9:108:36 | [b (line 84): false] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:108:9:108:36 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:108:27:108:27 | [b (line 84): false] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:108:27:108:27 | [b (line 84): true] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:108:27:108:34 | [b (line 84): false] access to property Length | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:108:27:108:34 | [b (line 84): true] access to property Length | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:110:9:110:25 | [b (line 84): false] ... = ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:110:9:110:25 | [b (line 84): true] ... = ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:110:9:110:26 | [b (line 84): false] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:110:9:110:26 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:110:13:110:13 | [b (line 84): false] access to parameter b | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:110:13:110:13 | [b (line 84): true] access to parameter b | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:110:13:110:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:110:13:110:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:110:17:110:20 | [b (line 84): true] null | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:110:24:110:25 | [b (line 84): false] "" | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:111:9:111:34 | [b (line 84): false] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:111:9:111:34 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:111:24:111:24 | [b (line 84): false] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:111:24:111:24 | [b (line 84): true] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:111:24:111:32 | [b (line 84): false] ... == ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:111:24:111:32 | [b (line 84): true] ... == ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:111:29:111:32 | [b (line 84): false] null | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:111:29:111:32 | [b (line 84): true] null | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:112:9:112:35 | [b (line 84): false] call to method WriteLine | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:112:9:112:35 | [b (line 84): true] call to method WriteLine | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:112:9:112:36 | [b (line 84): false] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:112:9:112:36 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:112:27:112:27 | [b (line 84): false] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:112:27:112:27 | [b (line 84): true] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:112:27:112:34 | [b (line 84): false] access to property Length | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:112:27:112:34 | [b (line 84): true] access to property Length | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:114:9:114:25 | [b (line 84): false] ... = ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:114:9:114:25 | [b (line 84): true] ... = ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:114:9:114:26 | [b (line 84): false] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:114:9:114:26 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:114:13:114:13 | [b (line 84): false] access to parameter b | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:114:13:114:13 | [b (line 84): true] access to parameter b | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:114:13:114:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:114:13:114:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:114:17:114:20 | [b (line 84): true] null | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:114:24:114:25 | [b (line 84): false] "" | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:115:9:115:37 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:115:9:115:38 | [b (line 84): false] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:115:9:115:38 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:115:23:115:23 | [b (line 84): false] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:115:23:115:23 | [b (line 84): true] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:115:23:115:31 | [b (line 84): false] ... != ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:115:23:115:31 | [b (line 84): true] ... != ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:115:23:115:36 | [b (line 84): false] ... && ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:115:23:115:36 | [b (line 84): true] ... && ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:115:28:115:31 | [b (line 84): false] null | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:115:28:115:31 | [b (line 84): true] null | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:116:9:116:35 | [b (line 84): true] call to method WriteLine | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:116:9:116:36 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:116:27:116:27 | [b (line 84): true] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:116:27:116:34 | [b (line 84): true] access to property Length | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:118:9:118:25 | [b (line 84): true] ... = ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:118:9:118:26 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:118:13:118:13 | [b (line 84): true] access to parameter b | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:118:13:118:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:118:17:118:20 | [b (line 84): true] null | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:119:9:119:39 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:119:9:119:40 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:119:24:119:24 | [b (line 84): true] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:119:24:119:32 | [b (line 84): true] ... == ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:119:24:119:38 | [b (line 84): true] ... \|\| ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:119:29:119:32 | [b (line 84): true] null | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:119:37:119:38 | [b (line 84): true] !... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:119:38:119:38 | [b (line 84): true] access to parameter b | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:120:9:120:35 | [b (line 84): true] call to method WriteLine | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:120:9:120:36 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:120:27:120:27 | [b (line 84): true] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:120:27:120:34 | [b (line 84): true] access to property Length | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:122:9:122:25 | [b (line 84): true] ... = ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:122:9:122:26 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:122:13:122:13 | [b (line 84): true] access to parameter b | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:122:13:122:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:122:17:122:20 | [b (line 84): true] null | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:123:9:123:37 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:123:9:123:38 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:123:23:123:23 | [b (line 84): true] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:123:23:123:31 | [b (line 84): true] ... == ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:123:23:123:36 | [b (line 84): true] ... && ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:123:28:123:31 | [b (line 84): true] null | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:124:9:124:35 | [b (line 84): true] call to method WriteLine | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:124:9:124:36 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:124:27:124:27 | [b (line 84): true] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:124:27:124:34 | [b (line 84): true] access to property Length | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:126:9:126:25 | [b (line 84): true] ... = ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:126:9:126:26 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:126:13:126:13 | [b (line 84): true] access to parameter b | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:126:13:126:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:126:17:126:20 | [b (line 84): true] null | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:127:9:127:39 | [assertion success] call to method IsFalse | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:127:9:127:40 | [b (line 84): true] ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:127:24:127:24 | [b (line 84): true] access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:127:24:127:32 | [b (line 84): true] ... != ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:127:24:127:38 | [b (line 84): true] ... \|\| ... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:127:29:127:32 | [b (line 84): true] null | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:127:37:127:38 | [b (line 84): true] !... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:127:38:127:38 | [b (line 84): true] access to parameter b | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:128:9:128:35 | call to method WriteLine | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:128:9:128:36 | ...; | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:128:27:128:27 | access to local variable s | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:128:27:128:34 | access to property Length | Assert.cs:84:10:84:12 | M12 | | Assignments.cs:3:10:3:10 | enter M | Assignments.cs:3:10:3:10 | M | | Assignments.cs:3:10:3:10 | exit M | Assignments.cs:3:10:3:10 | M | | Assignments.cs:4:5:15:5 | {...} | Assignments.cs:3:10:3:10 | M | @@ -508,6 +1036,8 @@ nodeEnclosing | CompileTimeOperators.cs:40:14:40:37 | call to method WriteLine | CompileTimeOperators.cs:28:10:28:10 | M | | CompileTimeOperators.cs:40:14:40:38 | ...; | CompileTimeOperators.cs:28:10:28:10 | M | | CompileTimeOperators.cs:40:32:40:36 | "End" | CompileTimeOperators.cs:28:10:28:10 | M | +| ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | ConditionalAccess | +| ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | ConditionalAccess | | ConditionalAccess.cs:3:12:3:13 | enter M1 | ConditionalAccess.cs:3:12:3:13 | M1 | | ConditionalAccess.cs:3:12:3:13 | exit M1 | ConditionalAccess.cs:3:12:3:13 | M1 | | ConditionalAccess.cs:3:26:3:26 | access to parameter i | ConditionalAccess.cs:3:12:3:13 | M1 | @@ -564,13 +1094,31 @@ nodeEnclosing | ConditionalAccess.cs:25:13:25:14 | "" | ConditionalAccess.cs:21:10:21:11 | M7 | | ConditionalAccess.cs:25:16:25:32 | call to method CommaJoinWith | ConditionalAccess.cs:21:10:21:11 | M7 | | ConditionalAccess.cs:25:31:25:31 | access to local variable s | ConditionalAccess.cs:21:10:21:11 | M7 | -| ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | ConditionalAccess.cs:31:26:31:38 | CommaJoinWith | -| ConditionalAccess.cs:31:26:31:38 | exit CommaJoinWith | ConditionalAccess.cs:31:26:31:38 | CommaJoinWith | -| ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | ConditionalAccess.cs:31:26:31:38 | CommaJoinWith | -| ConditionalAccess.cs:31:70:31:78 | ... + ... | ConditionalAccess.cs:31:26:31:38 | CommaJoinWith | -| ConditionalAccess.cs:31:70:31:83 | ... + ... | ConditionalAccess.cs:31:26:31:38 | CommaJoinWith | -| ConditionalAccess.cs:31:75:31:78 | ", " | ConditionalAccess.cs:31:26:31:38 | CommaJoinWith | -| ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | ConditionalAccess.cs:31:26:31:38 | CommaJoinWith | +| ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:30:10:30:12 | Out | +| ConditionalAccess.cs:30:10:30:12 | exit Out | ConditionalAccess.cs:30:10:30:12 | Out | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:1:7:1:23 | ConditionalAccess | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:30:10:30:12 | Out | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:30:10:30:12 | Out | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:1:7:1:23 | ConditionalAccess | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:10:30:12 | Out | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:10:30:12 | Out | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:33:5:36:5 | {...} | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:34:9:34:13 | ... = ... | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:34:9:34:14 | ...; | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:34:13:34:13 | 0 | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:35:9:35:12 | this access | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:35:9:35:25 | ...; | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:35:14:35:24 | call to method Out | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | +| ConditionalAccess.cs:41:26:41:38 | exit CommaJoinWith | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | +| ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | +| ConditionalAccess.cs:41:70:41:78 | ... + ... | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | +| ConditionalAccess.cs:41:70:41:83 | ... + ... | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | +| ConditionalAccess.cs:41:75:41:78 | ", " | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | +| ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:3:10:3:19 | IncrOrDecr | | Conditions.cs:3:10:3:19 | exit IncrOrDecr | Conditions.cs:3:10:3:19 | IncrOrDecr | | Conditions.cs:4:5:9:5 | {...} | Conditions.cs:3:10:3:19 | IncrOrDecr | @@ -774,7 +1322,7 @@ nodeEnclosing | Conditions.cs:79:17:79:26 | ...; | Conditions.cs:70:9:70:10 | M6 | | Conditions.cs:79:21:79:25 | false | Conditions.cs:70:9:70:10 | M6 | | Conditions.cs:81:9:82:16 | if (...) ... | Conditions.cs:70:9:70:10 | M6 | -| Conditions.cs:81:12:81:12 | access to local variable b | Conditions.cs:70:9:70:10 | M6 | +| Conditions.cs:81:13:81:13 | access to local variable b | Conditions.cs:70:9:70:10 | M6 | | Conditions.cs:82:13:82:13 | access to local variable x | Conditions.cs:70:9:70:10 | M6 | | Conditions.cs:82:13:82:15 | ...++ | Conditions.cs:70:9:70:10 | M6 | | Conditions.cs:82:13:82:16 | ...; | Conditions.cs:70:9:70:10 | M6 | @@ -859,14 +1407,14 @@ nodeEnclosing | Conditions.cs:115:16:115:23 | String s = ... | Conditions.cs:113:10:113:11 | M9 | | Conditions.cs:115:20:115:23 | null | Conditions.cs:113:10:113:11 | M9 | | Conditions.cs:116:9:123:9 | for (...;...;...) ... | Conditions.cs:113:10:113:11 | M9 | -| Conditions.cs:116:17:116:21 | Int32 i = ... | Conditions.cs:113:10:113:11 | M9 | -| Conditions.cs:116:21:116:21 | 0 | Conditions.cs:113:10:113:11 | M9 | -| Conditions.cs:116:24:116:24 | access to local variable i | Conditions.cs:113:10:113:11 | M9 | -| Conditions.cs:116:24:116:38 | ... < ... | Conditions.cs:113:10:113:11 | M9 | -| Conditions.cs:116:28:116:31 | access to parameter args | Conditions.cs:113:10:113:11 | M9 | -| Conditions.cs:116:28:116:38 | access to property Length | Conditions.cs:113:10:113:11 | M9 | -| Conditions.cs:116:41:116:41 | access to local variable i | Conditions.cs:113:10:113:11 | M9 | -| Conditions.cs:116:41:116:43 | ...++ | Conditions.cs:113:10:113:11 | M9 | +| Conditions.cs:116:18:116:22 | Int32 i = ... | Conditions.cs:113:10:113:11 | M9 | +| Conditions.cs:116:22:116:22 | 0 | Conditions.cs:113:10:113:11 | M9 | +| Conditions.cs:116:25:116:25 | access to local variable i | Conditions.cs:113:10:113:11 | M9 | +| Conditions.cs:116:25:116:39 | ... < ... | Conditions.cs:113:10:113:11 | M9 | +| Conditions.cs:116:29:116:32 | access to parameter args | Conditions.cs:113:10:113:11 | M9 | +| Conditions.cs:116:29:116:39 | access to property Length | Conditions.cs:113:10:113:11 | M9 | +| Conditions.cs:116:42:116:42 | access to local variable i | Conditions.cs:113:10:113:11 | M9 | +| Conditions.cs:116:42:116:44 | ...++ | Conditions.cs:113:10:113:11 | M9 | | Conditions.cs:117:9:123:9 | {...} | Conditions.cs:113:10:113:11 | M9 | | Conditions.cs:118:13:118:44 | ... ...; | Conditions.cs:113:10:113:11 | M9 | | Conditions.cs:118:17:118:43 | Boolean last = ... | Conditions.cs:113:10:113:11 | M9 | @@ -929,6 +1477,30 @@ nodeEnclosing | Conditions.cs:137:21:137:26 | [Field1 (line 129): true, Field2 (line 129): true] this access | Conditions.cs:129:10:129:12 | M10 | | Conditions.cs:137:21:137:37 | [Field1 (line 129): true, Field2 (line 129): true] call to method ToString | Conditions.cs:129:10:129:12 | M10 | | Conditions.cs:137:21:137:38 | [Field1 (line 129): true, Field2 (line 129): true] ...; | Conditions.cs:129:10:129:12 | M10 | +| Conditions.cs:143:10:143:12 | enter M11 | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:143:10:143:12 | exit M11 | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:144:5:150:5 | {...} | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:145:9:145:30 | ... ...; | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:145:13:145:29 | [b (line 143): false] String s = ... | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:145:13:145:29 | [b (line 143): true] String s = ... | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:145:17:145:17 | access to parameter b | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:145:17:145:29 | ... ? ... : ... | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:145:21:145:23 | [b (line 143): true] "a" | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:145:27:145:29 | [b (line 143): false] "b" | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:146:9:149:49 | [b (line 143): false] if (...) ... | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:146:9:149:49 | [b (line 143): true] if (...) ... | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:146:13:146:13 | [b (line 143): false] access to parameter b | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:146:13:146:13 | [b (line 143): true] access to parameter b | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:147:13:147:48 | call to method WriteLine | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:147:13:147:49 | ...; | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:147:38:147:47 | $"..." | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:147:40:147:43 | "a = " | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:147:45:147:45 | access to local variable s | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:149:13:149:48 | call to method WriteLine | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:149:13:149:49 | ...; | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:149:38:149:47 | $"..." | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:149:40:149:43 | "b = " | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:149:45:149:45 | access to local variable s | Conditions.cs:143:10:143:12 | M11 | | ExitMethods.cs:7:10:7:11 | enter M1 | ExitMethods.cs:7:10:7:11 | M1 | | ExitMethods.cs:7:10:7:11 | exit M1 | ExitMethods.cs:7:10:7:11 | M1 | | ExitMethods.cs:8:5:11:5 | {...} | ExitMethods.cs:7:10:7:11 | M1 | @@ -1060,7 +1632,7 @@ nodeEnclosing | ExitMethods.cs:119:17:119:32 | enter FailingAssertion | ExitMethods.cs:119:17:119:32 | FailingAssertion | | ExitMethods.cs:119:17:119:32 | exit FailingAssertion | ExitMethods.cs:119:17:119:32 | FailingAssertion | | ExitMethods.cs:120:5:123:5 | {...} | ExitMethods.cs:119:17:119:32 | FailingAssertion | -| ExitMethods.cs:121:9:121:28 | call to method IsTrue | ExitMethods.cs:119:17:119:32 | FailingAssertion | +| ExitMethods.cs:121:9:121:28 | [assertion failure] call to method IsTrue | ExitMethods.cs:119:17:119:32 | FailingAssertion | | ExitMethods.cs:121:9:121:29 | ...; | ExitMethods.cs:119:17:119:32 | FailingAssertion | | ExitMethods.cs:121:23:121:27 | false | ExitMethods.cs:119:17:119:32 | FailingAssertion | | ExitMethods.cs:125:17:125:33 | enter FailingAssertion2 | ExitMethods.cs:125:17:125:33 | FailingAssertion2 | @@ -1071,12 +1643,13 @@ nodeEnclosing | ExitMethods.cs:127:9:127:27 | ...; | ExitMethods.cs:125:17:125:33 | FailingAssertion2 | | ExitMethods.cs:131:10:131:20 | enter AssertFalse | ExitMethods.cs:131:10:131:20 | AssertFalse | | ExitMethods.cs:131:10:131:20 | exit AssertFalse | ExitMethods.cs:131:10:131:20 | AssertFalse | -| ExitMethods.cs:131:33:131:49 | call to method IsFalse | ExitMethods.cs:131:10:131:20 | AssertFalse | +| ExitMethods.cs:131:33:131:49 | [assertion failure] call to method IsFalse | ExitMethods.cs:131:10:131:20 | AssertFalse | +| ExitMethods.cs:131:33:131:49 | [assertion success] call to method IsFalse | ExitMethods.cs:131:10:131:20 | AssertFalse | | ExitMethods.cs:131:48:131:48 | access to parameter b | ExitMethods.cs:131:10:131:20 | AssertFalse | | ExitMethods.cs:133:17:133:33 | enter FailingAssertion3 | ExitMethods.cs:133:17:133:33 | FailingAssertion3 | | ExitMethods.cs:133:17:133:33 | exit FailingAssertion3 | ExitMethods.cs:133:17:133:33 | FailingAssertion3 | | ExitMethods.cs:134:5:137:5 | {...} | ExitMethods.cs:133:17:133:33 | FailingAssertion3 | -| ExitMethods.cs:135:9:135:25 | call to method AssertFalse | ExitMethods.cs:133:17:133:33 | FailingAssertion3 | +| ExitMethods.cs:135:9:135:25 | [assertion failure] call to method AssertFalse | ExitMethods.cs:133:17:133:33 | FailingAssertion3 | | ExitMethods.cs:135:9:135:25 | this access | ExitMethods.cs:133:17:133:33 | FailingAssertion3 | | ExitMethods.cs:135:9:135:26 | ...; | ExitMethods.cs:133:17:133:33 | FailingAssertion3 | | ExitMethods.cs:135:21:135:24 | true | ExitMethods.cs:133:17:133:33 | FailingAssertion3 | @@ -1856,6 +2429,7 @@ nodeEnclosing | Initializers.cs:14:51:14:51 | 1 | Initializers.cs:12:10:12:10 | M | | Initializers.cs:15:9:15:64 | ... ...; | Initializers.cs:12:10:12:10 | M | | Initializers.cs:15:13:15:63 | Initializers[] iz = ... | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:15:18:15:63 | 2 | Initializers.cs:12:10:12:10 | M | | Initializers.cs:15:18:15:63 | array creation of type Initializers[] | Initializers.cs:12:10:12:10 | M | | Initializers.cs:15:37:15:63 | { ..., ... } | Initializers.cs:12:10:12:10 | M | | Initializers.cs:15:39:15:39 | access to local variable i | Initializers.cs:12:10:12:10 | M | @@ -2021,25 +2595,26 @@ nodeEnclosing | LoopUnrolling.cs:10:13:10:19 | return ...; | LoopUnrolling.cs:7:10:7:11 | M1 | | LoopUnrolling.cs:11:9:12:35 | [unroll (line 11)] foreach (... ... in ...) ... | LoopUnrolling.cs:7:10:7:11 | M1 | | LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:7:10:7:11 | M1 | -| LoopUnrolling.cs:11:21:11:23 | String arg | LoopUnrolling.cs:7:10:7:11 | M1 | -| LoopUnrolling.cs:11:28:11:31 | access to parameter args | LoopUnrolling.cs:7:10:7:11 | M1 | +| LoopUnrolling.cs:11:22:11:24 | String arg | LoopUnrolling.cs:7:10:7:11 | M1 | +| LoopUnrolling.cs:11:29:11:32 | access to parameter args | LoopUnrolling.cs:7:10:7:11 | M1 | | LoopUnrolling.cs:12:13:12:34 | call to method WriteLine | LoopUnrolling.cs:7:10:7:11 | M1 | | LoopUnrolling.cs:12:13:12:35 | ...; | LoopUnrolling.cs:7:10:7:11 | M1 | | LoopUnrolling.cs:12:31:12:33 | access to local variable arg | LoopUnrolling.cs:7:10:7:11 | M1 | | LoopUnrolling.cs:15:10:15:11 | enter M2 | LoopUnrolling.cs:15:10:15:11 | M2 | | LoopUnrolling.cs:15:10:15:11 | exit M2 | LoopUnrolling.cs:15:10:15:11 | M2 | | LoopUnrolling.cs:16:5:20:5 | {...} | LoopUnrolling.cs:15:10:15:11 | M2 | -| LoopUnrolling.cs:17:9:17:47 | ... ...; | LoopUnrolling.cs:15:10:15:11 | M2 | -| LoopUnrolling.cs:17:13:17:46 | String[] xs = ... | LoopUnrolling.cs:15:10:15:11 | M2 | -| LoopUnrolling.cs:17:18:17:46 | array creation of type String[] | LoopUnrolling.cs:15:10:15:11 | M2 | -| LoopUnrolling.cs:17:30:17:46 | { ..., ... } | LoopUnrolling.cs:15:10:15:11 | M2 | -| LoopUnrolling.cs:17:32:17:34 | "a" | LoopUnrolling.cs:15:10:15:11 | M2 | -| LoopUnrolling.cs:17:37:17:39 | "b" | LoopUnrolling.cs:15:10:15:11 | M2 | -| LoopUnrolling.cs:17:42:17:44 | "c" | LoopUnrolling.cs:15:10:15:11 | M2 | +| LoopUnrolling.cs:17:9:17:48 | ... ...; | LoopUnrolling.cs:15:10:15:11 | M2 | +| LoopUnrolling.cs:17:13:17:47 | String[] xs = ... | LoopUnrolling.cs:15:10:15:11 | M2 | +| LoopUnrolling.cs:17:18:17:47 | 3 | LoopUnrolling.cs:15:10:15:11 | M2 | +| LoopUnrolling.cs:17:18:17:47 | array creation of type String[] | LoopUnrolling.cs:15:10:15:11 | M2 | +| LoopUnrolling.cs:17:31:17:47 | { ..., ... } | LoopUnrolling.cs:15:10:15:11 | M2 | +| LoopUnrolling.cs:17:33:17:35 | "a" | LoopUnrolling.cs:15:10:15:11 | M2 | +| LoopUnrolling.cs:17:38:17:40 | "b" | LoopUnrolling.cs:15:10:15:11 | M2 | +| LoopUnrolling.cs:17:43:17:45 | "c" | LoopUnrolling.cs:15:10:15:11 | M2 | | LoopUnrolling.cs:18:9:19:33 | [unroll (line 18)] foreach (... ... in ...) ... | LoopUnrolling.cs:15:10:15:11 | M2 | | LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:15:10:15:11 | M2 | -| LoopUnrolling.cs:18:21:18:21 | String x | LoopUnrolling.cs:15:10:15:11 | M2 | -| LoopUnrolling.cs:18:26:18:27 | access to local variable xs | LoopUnrolling.cs:15:10:15:11 | M2 | +| LoopUnrolling.cs:18:22:18:22 | String x | LoopUnrolling.cs:15:10:15:11 | M2 | +| LoopUnrolling.cs:18:27:18:28 | access to local variable xs | LoopUnrolling.cs:15:10:15:11 | M2 | | LoopUnrolling.cs:19:13:19:32 | call to method WriteLine | LoopUnrolling.cs:15:10:15:11 | M2 | | LoopUnrolling.cs:19:13:19:33 | ...; | LoopUnrolling.cs:15:10:15:11 | M2 | | LoopUnrolling.cs:19:31:19:31 | access to local variable x | LoopUnrolling.cs:15:10:15:11 | M2 | @@ -2063,37 +2638,35 @@ nodeEnclosing | LoopUnrolling.cs:31:13:31:30 | String[] xs = ... | LoopUnrolling.cs:29:10:29:11 | M4 | | LoopUnrolling.cs:31:18:31:30 | array creation of type String[] | LoopUnrolling.cs:29:10:29:11 | M4 | | LoopUnrolling.cs:31:29:31:29 | 0 | LoopUnrolling.cs:29:10:29:11 | M4 | -| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:29:10:29:11 | M4 | -| LoopUnrolling.cs:32:21:32:21 | String x | LoopUnrolling.cs:29:10:29:11 | M4 | -| LoopUnrolling.cs:32:26:32:27 | access to local variable xs | LoopUnrolling.cs:29:10:29:11 | M4 | -| LoopUnrolling.cs:33:13:33:32 | call to method WriteLine | LoopUnrolling.cs:29:10:29:11 | M4 | -| LoopUnrolling.cs:33:13:33:33 | ...; | LoopUnrolling.cs:29:10:29:11 | M4 | -| LoopUnrolling.cs:33:31:33:31 | access to local variable x | LoopUnrolling.cs:29:10:29:11 | M4 | +| LoopUnrolling.cs:32:9:33:33 | [skip (line 32)] foreach (... ... in ...) ... | LoopUnrolling.cs:29:10:29:11 | M4 | +| LoopUnrolling.cs:32:27:32:28 | access to local variable xs | LoopUnrolling.cs:29:10:29:11 | M4 | | LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:36:10:36:11 | M5 | | LoopUnrolling.cs:36:10:36:11 | exit M5 | LoopUnrolling.cs:36:10:36:11 | M5 | | LoopUnrolling.cs:37:5:43:5 | {...} | LoopUnrolling.cs:36:10:36:11 | M5 | -| LoopUnrolling.cs:38:9:38:47 | ... ...; | LoopUnrolling.cs:36:10:36:11 | M5 | -| LoopUnrolling.cs:38:13:38:46 | String[] xs = ... | LoopUnrolling.cs:36:10:36:11 | M5 | -| LoopUnrolling.cs:38:18:38:46 | array creation of type String[] | LoopUnrolling.cs:36:10:36:11 | M5 | -| LoopUnrolling.cs:38:30:38:46 | { ..., ... } | LoopUnrolling.cs:36:10:36:11 | M5 | -| LoopUnrolling.cs:38:32:38:34 | "a" | LoopUnrolling.cs:36:10:36:11 | M5 | -| LoopUnrolling.cs:38:37:38:39 | "b" | LoopUnrolling.cs:36:10:36:11 | M5 | -| LoopUnrolling.cs:38:42:38:44 | "c" | LoopUnrolling.cs:36:10:36:11 | M5 | -| LoopUnrolling.cs:39:9:39:47 | ... ...; | LoopUnrolling.cs:36:10:36:11 | M5 | -| LoopUnrolling.cs:39:13:39:46 | String[] ys = ... | LoopUnrolling.cs:36:10:36:11 | M5 | -| LoopUnrolling.cs:39:18:39:46 | array creation of type String[] | LoopUnrolling.cs:36:10:36:11 | M5 | -| LoopUnrolling.cs:39:30:39:46 | { ..., ... } | LoopUnrolling.cs:36:10:36:11 | M5 | -| LoopUnrolling.cs:39:32:39:34 | "0" | LoopUnrolling.cs:36:10:36:11 | M5 | -| LoopUnrolling.cs:39:37:39:39 | "1" | LoopUnrolling.cs:36:10:36:11 | M5 | -| LoopUnrolling.cs:39:42:39:44 | "2" | LoopUnrolling.cs:36:10:36:11 | M5 | +| LoopUnrolling.cs:38:9:38:48 | ... ...; | LoopUnrolling.cs:36:10:36:11 | M5 | +| LoopUnrolling.cs:38:13:38:47 | String[] xs = ... | LoopUnrolling.cs:36:10:36:11 | M5 | +| LoopUnrolling.cs:38:18:38:47 | 3 | LoopUnrolling.cs:36:10:36:11 | M5 | +| LoopUnrolling.cs:38:18:38:47 | array creation of type String[] | LoopUnrolling.cs:36:10:36:11 | M5 | +| LoopUnrolling.cs:38:31:38:47 | { ..., ... } | LoopUnrolling.cs:36:10:36:11 | M5 | +| LoopUnrolling.cs:38:33:38:35 | "a" | LoopUnrolling.cs:36:10:36:11 | M5 | +| LoopUnrolling.cs:38:38:38:40 | "b" | LoopUnrolling.cs:36:10:36:11 | M5 | +| LoopUnrolling.cs:38:43:38:45 | "c" | LoopUnrolling.cs:36:10:36:11 | M5 | +| LoopUnrolling.cs:39:9:39:48 | ... ...; | LoopUnrolling.cs:36:10:36:11 | M5 | +| LoopUnrolling.cs:39:13:39:47 | String[] ys = ... | LoopUnrolling.cs:36:10:36:11 | M5 | +| LoopUnrolling.cs:39:18:39:47 | 3 | LoopUnrolling.cs:36:10:36:11 | M5 | +| LoopUnrolling.cs:39:18:39:47 | array creation of type String[] | LoopUnrolling.cs:36:10:36:11 | M5 | +| LoopUnrolling.cs:39:31:39:47 | { ..., ... } | LoopUnrolling.cs:36:10:36:11 | M5 | +| LoopUnrolling.cs:39:33:39:35 | "0" | LoopUnrolling.cs:36:10:36:11 | M5 | +| LoopUnrolling.cs:39:38:39:40 | "1" | LoopUnrolling.cs:36:10:36:11 | M5 | +| LoopUnrolling.cs:39:43:39:45 | "2" | LoopUnrolling.cs:36:10:36:11 | M5 | | LoopUnrolling.cs:40:9:42:41 | [unroll (line 40)] foreach (... ... in ...) ... | LoopUnrolling.cs:36:10:36:11 | M5 | | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:36:10:36:11 | M5 | -| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:36:10:36:11 | M5 | -| LoopUnrolling.cs:40:26:40:27 | access to local variable xs | LoopUnrolling.cs:36:10:36:11 | M5 | +| LoopUnrolling.cs:40:22:40:22 | String x | LoopUnrolling.cs:36:10:36:11 | M5 | +| LoopUnrolling.cs:40:27:40:28 | access to local variable xs | LoopUnrolling.cs:36:10:36:11 | M5 | | LoopUnrolling.cs:41:13:42:41 | [unroll (line 41)] foreach (... ... in ...) ... | LoopUnrolling.cs:36:10:36:11 | M5 | | LoopUnrolling.cs:41:13:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:36:10:36:11 | M5 | -| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:36:10:36:11 | M5 | -| LoopUnrolling.cs:41:30:41:31 | access to local variable ys | LoopUnrolling.cs:36:10:36:11 | M5 | +| LoopUnrolling.cs:41:26:41:26 | String y | LoopUnrolling.cs:36:10:36:11 | M5 | +| LoopUnrolling.cs:41:31:41:32 | access to local variable ys | LoopUnrolling.cs:36:10:36:11 | M5 | | LoopUnrolling.cs:42:17:42:40 | call to method WriteLine | LoopUnrolling.cs:36:10:36:11 | M5 | | LoopUnrolling.cs:42:17:42:41 | ...; | LoopUnrolling.cs:36:10:36:11 | M5 | | LoopUnrolling.cs:42:35:42:35 | access to local variable x | LoopUnrolling.cs:36:10:36:11 | M5 | @@ -2101,39 +2674,41 @@ nodeEnclosing | LoopUnrolling.cs:42:39:42:39 | access to local variable y | LoopUnrolling.cs:36:10:36:11 | M5 | | LoopUnrolling.cs:45:10:45:11 | enter M6 | LoopUnrolling.cs:45:10:45:11 | M6 | | LoopUnrolling.cs:46:5:53:5 | {...} | LoopUnrolling.cs:45:10:45:11 | M6 | -| LoopUnrolling.cs:47:9:47:47 | ... ...; | LoopUnrolling.cs:45:10:45:11 | M6 | -| LoopUnrolling.cs:47:13:47:46 | String[] xs = ... | LoopUnrolling.cs:45:10:45:11 | M6 | -| LoopUnrolling.cs:47:18:47:46 | array creation of type String[] | LoopUnrolling.cs:45:10:45:11 | M6 | -| LoopUnrolling.cs:47:30:47:46 | { ..., ... } | LoopUnrolling.cs:45:10:45:11 | M6 | -| LoopUnrolling.cs:47:32:47:34 | "a" | LoopUnrolling.cs:45:10:45:11 | M6 | -| LoopUnrolling.cs:47:37:47:39 | "b" | LoopUnrolling.cs:45:10:45:11 | M6 | -| LoopUnrolling.cs:47:42:47:44 | "c" | LoopUnrolling.cs:45:10:45:11 | M6 | +| LoopUnrolling.cs:47:9:47:48 | ... ...; | LoopUnrolling.cs:45:10:45:11 | M6 | +| LoopUnrolling.cs:47:13:47:47 | String[] xs = ... | LoopUnrolling.cs:45:10:45:11 | M6 | +| LoopUnrolling.cs:47:18:47:47 | 3 | LoopUnrolling.cs:45:10:45:11 | M6 | +| LoopUnrolling.cs:47:18:47:47 | array creation of type String[] | LoopUnrolling.cs:45:10:45:11 | M6 | +| LoopUnrolling.cs:47:31:47:47 | { ..., ... } | LoopUnrolling.cs:45:10:45:11 | M6 | +| LoopUnrolling.cs:47:33:47:35 | "a" | LoopUnrolling.cs:45:10:45:11 | M6 | +| LoopUnrolling.cs:47:38:47:40 | "b" | LoopUnrolling.cs:45:10:45:11 | M6 | +| LoopUnrolling.cs:47:43:47:45 | "c" | LoopUnrolling.cs:45:10:45:11 | M6 | | LoopUnrolling.cs:48:9:52:9 | [unroll (line 48)] foreach (... ... in ...) ... | LoopUnrolling.cs:45:10:45:11 | M6 | -| LoopUnrolling.cs:48:21:48:21 | String x | LoopUnrolling.cs:45:10:45:11 | M6 | -| LoopUnrolling.cs:48:26:48:27 | access to local variable xs | LoopUnrolling.cs:45:10:45:11 | M6 | +| LoopUnrolling.cs:48:22:48:22 | String x | LoopUnrolling.cs:45:10:45:11 | M6 | +| LoopUnrolling.cs:48:27:48:28 | access to local variable xs | LoopUnrolling.cs:45:10:45:11 | M6 | | LoopUnrolling.cs:49:9:52:9 | {...} | LoopUnrolling.cs:45:10:45:11 | M6 | -| LoopUnrolling.cs:50:13:50:17 | Label: | LoopUnrolling.cs:45:10:45:11 | M6 | -| LoopUnrolling.cs:50:20:50:39 | call to method WriteLine | LoopUnrolling.cs:45:10:45:11 | M6 | -| LoopUnrolling.cs:50:20:50:40 | ...; | LoopUnrolling.cs:45:10:45:11 | M6 | -| LoopUnrolling.cs:50:38:50:38 | access to local variable x | LoopUnrolling.cs:45:10:45:11 | M6 | +| LoopUnrolling.cs:50:9:50:13 | Label: | LoopUnrolling.cs:45:10:45:11 | M6 | +| LoopUnrolling.cs:50:16:50:35 | call to method WriteLine | LoopUnrolling.cs:45:10:45:11 | M6 | +| LoopUnrolling.cs:50:16:50:36 | ...; | LoopUnrolling.cs:45:10:45:11 | M6 | +| LoopUnrolling.cs:50:34:50:34 | access to local variable x | LoopUnrolling.cs:45:10:45:11 | M6 | | LoopUnrolling.cs:51:13:51:23 | goto ...; | LoopUnrolling.cs:45:10:45:11 | M6 | | LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:55:10:55:11 | M7 | | LoopUnrolling.cs:55:10:55:11 | exit M7 | LoopUnrolling.cs:55:10:55:11 | M7 | | LoopUnrolling.cs:56:5:65:5 | {...} | LoopUnrolling.cs:55:10:55:11 | M7 | -| LoopUnrolling.cs:57:9:57:47 | ... ...; | LoopUnrolling.cs:55:10:55:11 | M7 | -| LoopUnrolling.cs:57:13:57:46 | String[] xs = ... | LoopUnrolling.cs:55:10:55:11 | M7 | -| LoopUnrolling.cs:57:18:57:46 | array creation of type String[] | LoopUnrolling.cs:55:10:55:11 | M7 | -| LoopUnrolling.cs:57:30:57:46 | { ..., ... } | LoopUnrolling.cs:55:10:55:11 | M7 | -| LoopUnrolling.cs:57:32:57:34 | "a" | LoopUnrolling.cs:55:10:55:11 | M7 | -| LoopUnrolling.cs:57:37:57:39 | "b" | LoopUnrolling.cs:55:10:55:11 | M7 | -| LoopUnrolling.cs:57:42:57:44 | "c" | LoopUnrolling.cs:55:10:55:11 | M7 | +| LoopUnrolling.cs:57:9:57:48 | ... ...; | LoopUnrolling.cs:55:10:55:11 | M7 | +| LoopUnrolling.cs:57:13:57:47 | String[] xs = ... | LoopUnrolling.cs:55:10:55:11 | M7 | +| LoopUnrolling.cs:57:18:57:47 | 3 | LoopUnrolling.cs:55:10:55:11 | M7 | +| LoopUnrolling.cs:57:18:57:47 | array creation of type String[] | LoopUnrolling.cs:55:10:55:11 | M7 | +| LoopUnrolling.cs:57:31:57:47 | { ..., ... } | LoopUnrolling.cs:55:10:55:11 | M7 | +| LoopUnrolling.cs:57:33:57:35 | "a" | LoopUnrolling.cs:55:10:55:11 | M7 | +| LoopUnrolling.cs:57:38:57:40 | "b" | LoopUnrolling.cs:55:10:55:11 | M7 | +| LoopUnrolling.cs:57:43:57:45 | "c" | LoopUnrolling.cs:55:10:55:11 | M7 | | LoopUnrolling.cs:58:9:64:9 | [b (line 55): false] foreach (... ... in ...) ... | LoopUnrolling.cs:55:10:55:11 | M7 | | LoopUnrolling.cs:58:9:64:9 | [b (line 55): true] foreach (... ... in ...) ... | LoopUnrolling.cs:55:10:55:11 | M7 | | LoopUnrolling.cs:58:9:64:9 | [unroll (line 58)] foreach (... ... in ...) ... | LoopUnrolling.cs:55:10:55:11 | M7 | -| LoopUnrolling.cs:58:21:58:21 | String x | LoopUnrolling.cs:55:10:55:11 | M7 | -| LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | LoopUnrolling.cs:55:10:55:11 | M7 | -| LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | LoopUnrolling.cs:55:10:55:11 | M7 | -| LoopUnrolling.cs:58:26:58:27 | access to local variable xs | LoopUnrolling.cs:55:10:55:11 | M7 | +| LoopUnrolling.cs:58:22:58:22 | String x | LoopUnrolling.cs:55:10:55:11 | M7 | +| LoopUnrolling.cs:58:22:58:22 | [b (line 55): false] String x | LoopUnrolling.cs:55:10:55:11 | M7 | +| LoopUnrolling.cs:58:22:58:22 | [b (line 55): true] String x | LoopUnrolling.cs:55:10:55:11 | M7 | +| LoopUnrolling.cs:58:27:58:28 | access to local variable xs | LoopUnrolling.cs:55:10:55:11 | M7 | | LoopUnrolling.cs:59:9:64:9 | [b (line 55): false] {...} | LoopUnrolling.cs:55:10:55:11 | M7 | | LoopUnrolling.cs:59:9:64:9 | [b (line 55): true] {...} | LoopUnrolling.cs:55:10:55:11 | M7 | | LoopUnrolling.cs:59:9:64:9 | {...} | LoopUnrolling.cs:55:10:55:11 | M7 | @@ -2164,12 +2739,312 @@ nodeEnclosing | LoopUnrolling.cs:71:9:71:12 | access to parameter args | LoopUnrolling.cs:67:10:67:11 | M8 | | LoopUnrolling.cs:71:9:71:20 | call to method Clear | LoopUnrolling.cs:67:10:67:11 | M8 | | LoopUnrolling.cs:71:9:71:21 | ...; | LoopUnrolling.cs:67:10:67:11 | M8 | -| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:67:10:67:11 | M8 | -| LoopUnrolling.cs:72:21:72:23 | String arg | LoopUnrolling.cs:67:10:67:11 | M8 | -| LoopUnrolling.cs:72:28:72:31 | access to parameter args | LoopUnrolling.cs:67:10:67:11 | M8 | -| LoopUnrolling.cs:73:13:73:34 | call to method WriteLine | LoopUnrolling.cs:67:10:67:11 | M8 | -| LoopUnrolling.cs:73:13:73:35 | ...; | LoopUnrolling.cs:67:10:67:11 | M8 | -| LoopUnrolling.cs:73:31:73:33 | access to local variable arg | LoopUnrolling.cs:67:10:67:11 | M8 | +| LoopUnrolling.cs:72:9:73:35 | [skip (line 72)] foreach (... ... in ...) ... | LoopUnrolling.cs:67:10:67:11 | M8 | +| LoopUnrolling.cs:72:29:72:32 | access to parameter args | LoopUnrolling.cs:67:10:67:11 | M8 | +| LoopUnrolling.cs:76:10:76:11 | enter M9 | LoopUnrolling.cs:76:10:76:11 | M9 | +| LoopUnrolling.cs:76:10:76:11 | exit M9 | LoopUnrolling.cs:76:10:76:11 | M9 | +| LoopUnrolling.cs:77:5:83:5 | {...} | LoopUnrolling.cs:76:10:76:11 | M9 | +| LoopUnrolling.cs:78:9:78:34 | ... ...; | LoopUnrolling.cs:76:10:76:11 | M9 | +| LoopUnrolling.cs:78:13:78:33 | String[,] xs = ... | LoopUnrolling.cs:76:10:76:11 | M9 | +| LoopUnrolling.cs:78:18:78:33 | array creation of type String[,] | LoopUnrolling.cs:76:10:76:11 | M9 | +| LoopUnrolling.cs:78:29:78:29 | 2 | LoopUnrolling.cs:76:10:76:11 | M9 | +| LoopUnrolling.cs:78:32:78:32 | 0 | LoopUnrolling.cs:76:10:76:11 | M9 | +| LoopUnrolling.cs:79:9:82:9 | [skip (line 79)] foreach (... ... in ...) ... | LoopUnrolling.cs:76:10:76:11 | M9 | +| LoopUnrolling.cs:79:27:79:28 | access to local variable xs | LoopUnrolling.cs:76:10:76:11 | M9 | +| LoopUnrolling.cs:85:10:85:12 | enter M10 | LoopUnrolling.cs:85:10:85:12 | M10 | +| LoopUnrolling.cs:85:10:85:12 | exit M10 | LoopUnrolling.cs:85:10:85:12 | M10 | +| LoopUnrolling.cs:86:5:92:5 | {...} | LoopUnrolling.cs:85:10:85:12 | M10 | +| LoopUnrolling.cs:87:9:87:34 | ... ...; | LoopUnrolling.cs:85:10:85:12 | M10 | +| LoopUnrolling.cs:87:13:87:33 | String[,] xs = ... | LoopUnrolling.cs:85:10:85:12 | M10 | +| LoopUnrolling.cs:87:18:87:33 | array creation of type String[,] | LoopUnrolling.cs:85:10:85:12 | M10 | +| LoopUnrolling.cs:87:29:87:29 | 0 | LoopUnrolling.cs:85:10:85:12 | M10 | +| LoopUnrolling.cs:87:32:87:32 | 2 | LoopUnrolling.cs:85:10:85:12 | M10 | +| LoopUnrolling.cs:88:9:91:9 | [skip (line 88)] foreach (... ... in ...) ... | LoopUnrolling.cs:85:10:85:12 | M10 | +| LoopUnrolling.cs:88:27:88:28 | access to local variable xs | LoopUnrolling.cs:85:10:85:12 | M10 | +| LoopUnrolling.cs:94:10:94:12 | enter M11 | LoopUnrolling.cs:94:10:94:12 | M11 | +| LoopUnrolling.cs:94:10:94:12 | exit M11 | LoopUnrolling.cs:94:10:94:12 | M11 | +| LoopUnrolling.cs:95:5:101:5 | {...} | LoopUnrolling.cs:94:10:94:12 | M11 | +| LoopUnrolling.cs:96:9:96:34 | ... ...; | LoopUnrolling.cs:94:10:94:12 | M11 | +| LoopUnrolling.cs:96:13:96:33 | String[,] xs = ... | LoopUnrolling.cs:94:10:94:12 | M11 | +| LoopUnrolling.cs:96:18:96:33 | array creation of type String[,] | LoopUnrolling.cs:94:10:94:12 | M11 | +| LoopUnrolling.cs:96:29:96:29 | 2 | LoopUnrolling.cs:94:10:94:12 | M11 | +| LoopUnrolling.cs:96:32:96:32 | 2 | LoopUnrolling.cs:94:10:94:12 | M11 | +| LoopUnrolling.cs:97:9:100:9 | [unroll (line 97)] foreach (... ... in ...) ... | LoopUnrolling.cs:94:10:94:12 | M11 | +| LoopUnrolling.cs:97:9:100:9 | foreach (... ... in ...) ... | LoopUnrolling.cs:94:10:94:12 | M11 | +| LoopUnrolling.cs:97:22:97:22 | String x | LoopUnrolling.cs:94:10:94:12 | M11 | +| LoopUnrolling.cs:97:27:97:28 | access to local variable xs | LoopUnrolling.cs:94:10:94:12 | M11 | +| LoopUnrolling.cs:98:9:100:9 | {...} | LoopUnrolling.cs:94:10:94:12 | M11 | +| LoopUnrolling.cs:99:13:99:32 | call to method WriteLine | LoopUnrolling.cs:94:10:94:12 | M11 | +| LoopUnrolling.cs:99:13:99:33 | ...; | LoopUnrolling.cs:94:10:94:12 | M11 | +| LoopUnrolling.cs:99:31:99:31 | access to local variable x | LoopUnrolling.cs:94:10:94:12 | M11 | +| MultiImplementationA.cs:6:22:6:31 | enter get_P1 | MultiImplementationA.cs:6:22:6:31 | get_P1 | +| MultiImplementationA.cs:6:22:6:31 | enter get_P1 | MultiImplementationB.cs:3:22:3:22 | get_P1 | +| MultiImplementationA.cs:6:22:6:31 | exit get_P1 | MultiImplementationA.cs:6:22:6:31 | get_P1 | +| MultiImplementationA.cs:6:22:6:31 | exit get_P1 | MultiImplementationB.cs:3:22:3:22 | get_P1 | +| MultiImplementationA.cs:6:22:6:31 | throw ... | MultiImplementationA.cs:6:22:6:31 | get_P1 | +| MultiImplementationA.cs:6:22:6:31 | throw ... | MultiImplementationB.cs:3:22:3:22 | get_P1 | +| MultiImplementationA.cs:6:28:6:31 | null | MultiImplementationA.cs:6:22:6:31 | get_P1 | +| MultiImplementationA.cs:6:28:6:31 | null | MultiImplementationB.cs:3:22:3:22 | get_P1 | +| MultiImplementationA.cs:7:21:7:23 | enter get_P2 | MultiImplementationA.cs:7:21:7:23 | get_P2 | +| MultiImplementationA.cs:7:21:7:23 | enter get_P2 | MultiImplementationB.cs:4:21:4:23 | get_P2 | +| MultiImplementationA.cs:7:21:7:23 | exit get_P2 | MultiImplementationA.cs:7:21:7:23 | get_P2 | +| MultiImplementationA.cs:7:21:7:23 | exit get_P2 | MultiImplementationB.cs:4:21:4:23 | get_P2 | +| MultiImplementationA.cs:7:25:7:39 | {...} | MultiImplementationA.cs:7:21:7:23 | get_P2 | +| MultiImplementationA.cs:7:25:7:39 | {...} | MultiImplementationB.cs:4:21:4:23 | get_P2 | +| MultiImplementationA.cs:7:27:7:37 | throw ...; | MultiImplementationA.cs:7:21:7:23 | get_P2 | +| MultiImplementationA.cs:7:27:7:37 | throw ...; | MultiImplementationB.cs:4:21:4:23 | get_P2 | +| MultiImplementationA.cs:7:33:7:36 | null | MultiImplementationA.cs:7:21:7:23 | get_P2 | +| MultiImplementationA.cs:7:33:7:36 | null | MultiImplementationB.cs:4:21:4:23 | get_P2 | +| MultiImplementationA.cs:7:41:7:43 | enter set_P2 | MultiImplementationA.cs:7:41:7:43 | set_P2 | +| MultiImplementationA.cs:7:41:7:43 | enter set_P2 | MultiImplementationB.cs:4:39:4:41 | set_P2 | +| MultiImplementationA.cs:7:41:7:43 | exit set_P2 | MultiImplementationA.cs:7:41:7:43 | set_P2 | +| MultiImplementationA.cs:7:41:7:43 | exit set_P2 | MultiImplementationB.cs:4:39:4:41 | set_P2 | +| MultiImplementationA.cs:7:45:7:59 | {...} | MultiImplementationA.cs:7:41:7:43 | set_P2 | +| MultiImplementationA.cs:7:45:7:59 | {...} | MultiImplementationB.cs:4:39:4:41 | set_P2 | +| MultiImplementationA.cs:7:47:7:57 | throw ...; | MultiImplementationA.cs:7:41:7:43 | set_P2 | +| MultiImplementationA.cs:7:47:7:57 | throw ...; | MultiImplementationB.cs:4:39:4:41 | set_P2 | +| MultiImplementationA.cs:7:53:7:56 | null | MultiImplementationA.cs:7:41:7:43 | set_P2 | +| MultiImplementationA.cs:7:53:7:56 | null | MultiImplementationB.cs:4:39:4:41 | set_P2 | +| MultiImplementationA.cs:8:16:8:16 | enter M | MultiImplementationA.cs:8:16:8:16 | M | +| MultiImplementationA.cs:8:16:8:16 | enter M | MultiImplementationB.cs:5:16:5:16 | M | +| MultiImplementationA.cs:8:16:8:16 | exit M | MultiImplementationA.cs:8:16:8:16 | M | +| MultiImplementationA.cs:8:16:8:16 | exit M | MultiImplementationB.cs:5:16:5:16 | M | +| MultiImplementationA.cs:8:23:8:32 | throw ... | MultiImplementationA.cs:8:16:8:16 | M | +| MultiImplementationA.cs:8:23:8:32 | throw ... | MultiImplementationB.cs:5:16:5:16 | M | +| MultiImplementationA.cs:8:29:8:32 | null | MultiImplementationA.cs:8:16:8:16 | M | +| MultiImplementationA.cs:8:29:8:32 | null | MultiImplementationB.cs:5:16:5:16 | M | +| MultiImplementationA.cs:13:16:13:16 | this access | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationA.cs:13:16:13:16 | this access | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationA.cs:13:16:13:20 | ... = ... | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationA.cs:13:16:13:20 | ... = ... | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationA.cs:13:20:13:20 | 0 | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationA.cs:13:20:13:20 | 0 | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationA.cs:14:31:14:31 | access to parameter i | MultiImplementationA.cs:14:31:14:31 | get_Item | +| MultiImplementationA.cs:14:31:14:31 | access to parameter i | MultiImplementationB.cs:12:31:12:40 | get_Item | +| MultiImplementationA.cs:14:31:14:31 | enter get_Item | MultiImplementationA.cs:14:31:14:31 | get_Item | +| MultiImplementationA.cs:14:31:14:31 | enter get_Item | MultiImplementationB.cs:12:31:12:40 | get_Item | +| MultiImplementationA.cs:14:31:14:31 | exit get_Item | MultiImplementationA.cs:14:31:14:31 | get_Item | +| MultiImplementationA.cs:14:31:14:31 | exit get_Item | MultiImplementationB.cs:12:31:12:40 | get_Item | +| MultiImplementationA.cs:15:36:15:38 | enter get_Item | MultiImplementationA.cs:15:36:15:38 | get_Item | +| MultiImplementationA.cs:15:36:15:38 | enter get_Item | MultiImplementationB.cs:13:36:13:38 | get_Item | +| MultiImplementationA.cs:15:36:15:38 | exit get_Item | MultiImplementationA.cs:15:36:15:38 | get_Item | +| MultiImplementationA.cs:15:36:15:38 | exit get_Item | MultiImplementationB.cs:13:36:13:38 | get_Item | +| MultiImplementationA.cs:15:40:15:52 | {...} | MultiImplementationA.cs:15:36:15:38 | get_Item | +| MultiImplementationA.cs:15:40:15:52 | {...} | MultiImplementationB.cs:13:36:13:38 | get_Item | +| MultiImplementationA.cs:15:42:15:50 | return ...; | MultiImplementationA.cs:15:36:15:38 | get_Item | +| MultiImplementationA.cs:15:42:15:50 | return ...; | MultiImplementationB.cs:13:36:13:38 | get_Item | +| MultiImplementationA.cs:15:49:15:49 | access to parameter s | MultiImplementationA.cs:15:36:15:38 | get_Item | +| MultiImplementationA.cs:15:49:15:49 | access to parameter s | MultiImplementationB.cs:13:36:13:38 | get_Item | +| MultiImplementationA.cs:15:54:15:56 | enter set_Item | MultiImplementationA.cs:15:54:15:56 | set_Item | +| MultiImplementationA.cs:15:54:15:56 | enter set_Item | MultiImplementationB.cs:13:56:13:58 | set_Item | +| MultiImplementationA.cs:15:54:15:56 | exit set_Item | MultiImplementationA.cs:15:54:15:56 | set_Item | +| MultiImplementationA.cs:15:54:15:56 | exit set_Item | MultiImplementationB.cs:13:56:13:58 | set_Item | +| MultiImplementationA.cs:15:58:15:60 | {...} | MultiImplementationA.cs:15:54:15:56 | set_Item | +| MultiImplementationA.cs:15:58:15:60 | {...} | MultiImplementationB.cs:13:56:13:58 | set_Item | +| MultiImplementationA.cs:16:17:16:18 | enter M1 | MultiImplementationA.cs:16:17:16:18 | M1 | +| MultiImplementationA.cs:16:17:16:18 | enter M1 | MultiImplementationB.cs:14:17:14:18 | M1 | +| MultiImplementationA.cs:16:17:16:18 | exit M1 | MultiImplementationA.cs:16:17:16:18 | M1 | +| MultiImplementationA.cs:16:17:16:18 | exit M1 | MultiImplementationB.cs:14:17:14:18 | M1 | +| MultiImplementationA.cs:17:5:19:5 | {...} | MultiImplementationA.cs:16:17:16:18 | M1 | +| MultiImplementationA.cs:17:5:19:5 | {...} | MultiImplementationB.cs:14:17:14:18 | M1 | +| MultiImplementationA.cs:18:9:18:22 | M2(...) | MultiImplementationA.cs:16:17:16:18 | M1 | +| MultiImplementationA.cs:18:9:18:22 | M2(...) | MultiImplementationB.cs:14:17:14:18 | M1 | +| MultiImplementationA.cs:18:9:18:22 | enter M2 | MultiImplementationA.cs:18:9:18:22 | M2 | +| MultiImplementationA.cs:18:9:18:22 | exit M2 | MultiImplementationA.cs:18:9:18:22 | M2 | +| MultiImplementationA.cs:18:21:18:21 | 0 | MultiImplementationA.cs:18:9:18:22 | M2 | +| MultiImplementationA.cs:20:12:20:13 | enter C2 | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationA.cs:20:12:20:13 | enter C2 | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationA.cs:20:12:20:13 | exit C2 | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationA.cs:20:12:20:13 | exit C2 | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationA.cs:20:22:20:31 | {...} | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationA.cs:20:22:20:31 | {...} | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationA.cs:20:24:20:24 | this access | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationA.cs:20:24:20:24 | this access | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationA.cs:20:24:20:28 | ... = ... | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationA.cs:20:24:20:28 | ... = ... | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationA.cs:20:24:20:29 | ...; | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationA.cs:20:24:20:29 | ...; | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationA.cs:20:28:20:28 | access to parameter i | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationA.cs:20:28:20:28 | access to parameter i | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationA.cs:21:12:21:13 | enter C2 | MultiImplementationA.cs:21:12:21:13 | C2 | +| MultiImplementationA.cs:21:12:21:13 | enter C2 | MultiImplementationB.cs:19:12:19:13 | C2 | +| MultiImplementationA.cs:21:12:21:13 | exit C2 | MultiImplementationA.cs:21:12:21:13 | C2 | +| MultiImplementationA.cs:21:12:21:13 | exit C2 | MultiImplementationB.cs:19:12:19:13 | C2 | +| MultiImplementationA.cs:21:19:21:22 | call to constructor C2 | MultiImplementationA.cs:21:12:21:13 | C2 | +| MultiImplementationA.cs:21:19:21:22 | call to constructor C2 | MultiImplementationB.cs:19:12:19:13 | C2 | +| MultiImplementationA.cs:21:24:21:24 | 0 | MultiImplementationA.cs:21:12:21:13 | C2 | +| MultiImplementationA.cs:21:24:21:24 | 0 | MultiImplementationB.cs:19:12:19:13 | C2 | +| MultiImplementationA.cs:21:27:21:29 | {...} | MultiImplementationA.cs:21:12:21:13 | C2 | +| MultiImplementationA.cs:21:27:21:29 | {...} | MultiImplementationB.cs:19:12:19:13 | C2 | +| MultiImplementationA.cs:22:6:22:7 | enter ~C2 | MultiImplementationA.cs:22:6:22:7 | ~C2 | +| MultiImplementationA.cs:22:6:22:7 | enter ~C2 | MultiImplementationB.cs:20:6:20:7 | ~C2 | +| MultiImplementationA.cs:22:6:22:7 | exit ~C2 | MultiImplementationA.cs:22:6:22:7 | ~C2 | +| MultiImplementationA.cs:22:6:22:7 | exit ~C2 | MultiImplementationB.cs:20:6:20:7 | ~C2 | +| MultiImplementationA.cs:22:11:22:13 | {...} | MultiImplementationA.cs:22:6:22:7 | ~C2 | +| MultiImplementationA.cs:22:11:22:13 | {...} | MultiImplementationB.cs:20:6:20:7 | ~C2 | +| MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | MultiImplementationA.cs:23:28:23:35 | implicit conversion | +| MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | MultiImplementationB.cs:21:28:21:35 | implicit conversion | +| MultiImplementationA.cs:23:28:23:35 | exit implicit conversion | MultiImplementationA.cs:23:28:23:35 | implicit conversion | +| MultiImplementationA.cs:23:28:23:35 | exit implicit conversion | MultiImplementationB.cs:21:28:21:35 | implicit conversion | +| MultiImplementationA.cs:23:50:23:53 | null | MultiImplementationA.cs:23:28:23:35 | implicit conversion | +| MultiImplementationA.cs:23:50:23:53 | null | MultiImplementationB.cs:21:28:21:35 | implicit conversion | +| MultiImplementationA.cs:24:16:24:16 | access to property P | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationA.cs:24:16:24:16 | access to property P | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationA.cs:24:16:24:16 | this access | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationA.cs:24:16:24:16 | this access | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationA.cs:24:32:24:34 | ... = ... | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationA.cs:24:32:24:34 | ... = ... | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationA.cs:24:34:24:34 | 0 | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationA.cs:24:34:24:34 | 0 | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationA.cs:30:21:30:23 | enter get_P3 | MultiImplementationA.cs:30:21:30:23 | get_P3 | +| MultiImplementationA.cs:30:21:30:23 | enter get_P3 | MultiImplementationB.cs:27:21:27:23 | get_P3 | +| MultiImplementationA.cs:30:21:30:23 | exit get_P3 | MultiImplementationA.cs:30:21:30:23 | get_P3 | +| MultiImplementationA.cs:30:21:30:23 | exit get_P3 | MultiImplementationB.cs:27:21:27:23 | get_P3 | +| MultiImplementationA.cs:30:28:30:37 | throw ... | MultiImplementationA.cs:30:21:30:23 | get_P3 | +| MultiImplementationA.cs:30:28:30:37 | throw ... | MultiImplementationB.cs:27:21:27:23 | get_P3 | +| MultiImplementationA.cs:30:34:30:37 | null | MultiImplementationA.cs:30:21:30:23 | get_P3 | +| MultiImplementationA.cs:30:34:30:37 | null | MultiImplementationB.cs:27:21:27:23 | get_P3 | +| MultiImplementationA.cs:36:9:36:10 | enter M1 | MultiImplementationA.cs:36:9:36:10 | M1 | +| MultiImplementationA.cs:36:9:36:10 | enter M1 | MultiImplementationB.cs:32:9:32:10 | M1 | +| MultiImplementationA.cs:36:9:36:10 | exit M1 | MultiImplementationA.cs:36:9:36:10 | M1 | +| MultiImplementationA.cs:36:9:36:10 | exit M1 | MultiImplementationB.cs:32:9:32:10 | M1 | +| MultiImplementationA.cs:36:14:36:28 | {...} | MultiImplementationA.cs:36:9:36:10 | M1 | +| MultiImplementationA.cs:36:14:36:28 | {...} | MultiImplementationB.cs:32:9:32:10 | M1 | +| MultiImplementationA.cs:36:16:36:26 | throw ...; | MultiImplementationA.cs:36:9:36:10 | M1 | +| MultiImplementationA.cs:36:16:36:26 | throw ...; | MultiImplementationB.cs:32:9:32:10 | M1 | +| MultiImplementationA.cs:36:22:36:25 | null | MultiImplementationA.cs:36:9:36:10 | M1 | +| MultiImplementationA.cs:36:22:36:25 | null | MultiImplementationB.cs:32:9:32:10 | M1 | +| MultiImplementationA.cs:37:9:37:10 | enter M2 | MultiImplementationA.cs:37:9:37:10 | M2 | +| MultiImplementationA.cs:37:9:37:10 | exit M2 | MultiImplementationA.cs:37:9:37:10 | M2 | +| MultiImplementationA.cs:37:14:37:28 | {...} | MultiImplementationA.cs:37:9:37:10 | M2 | +| MultiImplementationA.cs:37:16:37:26 | throw ...; | MultiImplementationA.cs:37:9:37:10 | M2 | +| MultiImplementationA.cs:37:22:37:25 | null | MultiImplementationA.cs:37:9:37:10 | M2 | +| MultiImplementationB.cs:3:22:3:22 | 0 | MultiImplementationA.cs:6:22:6:31 | get_P1 | +| MultiImplementationB.cs:3:22:3:22 | 0 | MultiImplementationB.cs:3:22:3:22 | get_P1 | +| MultiImplementationB.cs:3:22:3:22 | enter get_P1 | MultiImplementationA.cs:6:22:6:31 | get_P1 | +| MultiImplementationB.cs:3:22:3:22 | enter get_P1 | MultiImplementationB.cs:3:22:3:22 | get_P1 | +| MultiImplementationB.cs:3:22:3:22 | exit get_P1 | MultiImplementationA.cs:6:22:6:31 | get_P1 | +| MultiImplementationB.cs:3:22:3:22 | exit get_P1 | MultiImplementationB.cs:3:22:3:22 | get_P1 | +| MultiImplementationB.cs:4:21:4:23 | enter get_P2 | MultiImplementationA.cs:7:21:7:23 | get_P2 | +| MultiImplementationB.cs:4:21:4:23 | enter get_P2 | MultiImplementationB.cs:4:21:4:23 | get_P2 | +| MultiImplementationB.cs:4:21:4:23 | exit get_P2 | MultiImplementationA.cs:7:21:7:23 | get_P2 | +| MultiImplementationB.cs:4:21:4:23 | exit get_P2 | MultiImplementationB.cs:4:21:4:23 | get_P2 | +| MultiImplementationB.cs:4:25:4:37 | {...} | MultiImplementationA.cs:7:21:7:23 | get_P2 | +| MultiImplementationB.cs:4:25:4:37 | {...} | MultiImplementationB.cs:4:21:4:23 | get_P2 | +| MultiImplementationB.cs:4:27:4:35 | return ...; | MultiImplementationA.cs:7:21:7:23 | get_P2 | +| MultiImplementationB.cs:4:27:4:35 | return ...; | MultiImplementationB.cs:4:21:4:23 | get_P2 | +| MultiImplementationB.cs:4:34:4:34 | 1 | MultiImplementationA.cs:7:21:7:23 | get_P2 | +| MultiImplementationB.cs:4:34:4:34 | 1 | MultiImplementationB.cs:4:21:4:23 | get_P2 | +| MultiImplementationB.cs:4:39:4:41 | enter set_P2 | MultiImplementationA.cs:7:41:7:43 | set_P2 | +| MultiImplementationB.cs:4:39:4:41 | enter set_P2 | MultiImplementationB.cs:4:39:4:41 | set_P2 | +| MultiImplementationB.cs:4:39:4:41 | exit set_P2 | MultiImplementationA.cs:7:41:7:43 | set_P2 | +| MultiImplementationB.cs:4:39:4:41 | exit set_P2 | MultiImplementationB.cs:4:39:4:41 | set_P2 | +| MultiImplementationB.cs:4:43:4:45 | {...} | MultiImplementationA.cs:7:41:7:43 | set_P2 | +| MultiImplementationB.cs:4:43:4:45 | {...} | MultiImplementationB.cs:4:39:4:41 | set_P2 | +| MultiImplementationB.cs:5:16:5:16 | enter M | MultiImplementationA.cs:8:16:8:16 | M | +| MultiImplementationB.cs:5:16:5:16 | enter M | MultiImplementationB.cs:5:16:5:16 | M | +| MultiImplementationB.cs:5:16:5:16 | exit M | MultiImplementationA.cs:8:16:8:16 | M | +| MultiImplementationB.cs:5:16:5:16 | exit M | MultiImplementationB.cs:5:16:5:16 | M | +| MultiImplementationB.cs:5:23:5:23 | 2 | MultiImplementationA.cs:8:16:8:16 | M | +| MultiImplementationB.cs:5:23:5:23 | 2 | MultiImplementationB.cs:5:16:5:16 | M | +| MultiImplementationB.cs:11:16:11:16 | this access | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationB.cs:11:16:11:16 | this access | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationB.cs:11:16:11:20 | ... = ... | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationB.cs:11:16:11:20 | ... = ... | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationB.cs:11:20:11:20 | 1 | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationB.cs:11:20:11:20 | 1 | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationB.cs:12:31:12:40 | enter get_Item | MultiImplementationA.cs:14:31:14:31 | get_Item | +| MultiImplementationB.cs:12:31:12:40 | enter get_Item | MultiImplementationB.cs:12:31:12:40 | get_Item | +| MultiImplementationB.cs:12:31:12:40 | exit get_Item | MultiImplementationA.cs:14:31:14:31 | get_Item | +| MultiImplementationB.cs:12:31:12:40 | exit get_Item | MultiImplementationB.cs:12:31:12:40 | get_Item | +| MultiImplementationB.cs:12:31:12:40 | throw ... | MultiImplementationA.cs:14:31:14:31 | get_Item | +| MultiImplementationB.cs:12:31:12:40 | throw ... | MultiImplementationB.cs:12:31:12:40 | get_Item | +| MultiImplementationB.cs:12:37:12:40 | null | MultiImplementationA.cs:14:31:14:31 | get_Item | +| MultiImplementationB.cs:12:37:12:40 | null | MultiImplementationB.cs:12:31:12:40 | get_Item | +| MultiImplementationB.cs:13:36:13:38 | enter get_Item | MultiImplementationA.cs:15:36:15:38 | get_Item | +| MultiImplementationB.cs:13:36:13:38 | enter get_Item | MultiImplementationB.cs:13:36:13:38 | get_Item | +| MultiImplementationB.cs:13:36:13:38 | exit get_Item | MultiImplementationA.cs:15:36:15:38 | get_Item | +| MultiImplementationB.cs:13:36:13:38 | exit get_Item | MultiImplementationB.cs:13:36:13:38 | get_Item | +| MultiImplementationB.cs:13:40:13:54 | {...} | MultiImplementationA.cs:15:36:15:38 | get_Item | +| MultiImplementationB.cs:13:40:13:54 | {...} | MultiImplementationB.cs:13:36:13:38 | get_Item | +| MultiImplementationB.cs:13:42:13:52 | throw ...; | MultiImplementationA.cs:15:36:15:38 | get_Item | +| MultiImplementationB.cs:13:42:13:52 | throw ...; | MultiImplementationB.cs:13:36:13:38 | get_Item | +| MultiImplementationB.cs:13:48:13:51 | null | MultiImplementationA.cs:15:36:15:38 | get_Item | +| MultiImplementationB.cs:13:48:13:51 | null | MultiImplementationB.cs:13:36:13:38 | get_Item | +| MultiImplementationB.cs:13:56:13:58 | enter set_Item | MultiImplementationA.cs:15:54:15:56 | set_Item | +| MultiImplementationB.cs:13:56:13:58 | enter set_Item | MultiImplementationB.cs:13:56:13:58 | set_Item | +| MultiImplementationB.cs:13:56:13:58 | exit set_Item | MultiImplementationA.cs:15:54:15:56 | set_Item | +| MultiImplementationB.cs:13:56:13:58 | exit set_Item | MultiImplementationB.cs:13:56:13:58 | set_Item | +| MultiImplementationB.cs:13:60:13:62 | {...} | MultiImplementationA.cs:15:54:15:56 | set_Item | +| MultiImplementationB.cs:13:60:13:62 | {...} | MultiImplementationB.cs:13:56:13:58 | set_Item | +| MultiImplementationB.cs:14:17:14:18 | enter M1 | MultiImplementationA.cs:16:17:16:18 | M1 | +| MultiImplementationB.cs:14:17:14:18 | enter M1 | MultiImplementationB.cs:14:17:14:18 | M1 | +| MultiImplementationB.cs:14:17:14:18 | exit M1 | MultiImplementationA.cs:16:17:16:18 | M1 | +| MultiImplementationB.cs:14:17:14:18 | exit M1 | MultiImplementationB.cs:14:17:14:18 | M1 | +| MultiImplementationB.cs:15:5:17:5 | {...} | MultiImplementationA.cs:16:17:16:18 | M1 | +| MultiImplementationB.cs:15:5:17:5 | {...} | MultiImplementationB.cs:14:17:14:18 | M1 | +| MultiImplementationB.cs:16:9:16:31 | M2(...) | MultiImplementationA.cs:16:17:16:18 | M1 | +| MultiImplementationB.cs:16:9:16:31 | M2(...) | MultiImplementationB.cs:14:17:14:18 | M1 | +| MultiImplementationB.cs:16:9:16:31 | enter M2 | MultiImplementationB.cs:16:9:16:31 | M2 | +| MultiImplementationB.cs:16:9:16:31 | exit M2 | MultiImplementationB.cs:16:9:16:31 | M2 | +| MultiImplementationB.cs:16:21:16:30 | throw ... | MultiImplementationB.cs:16:9:16:31 | M2 | +| MultiImplementationB.cs:16:27:16:30 | null | MultiImplementationB.cs:16:9:16:31 | M2 | +| MultiImplementationB.cs:18:12:18:13 | enter C2 | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationB.cs:18:12:18:13 | enter C2 | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationB.cs:18:12:18:13 | exit C2 | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationB.cs:18:12:18:13 | exit C2 | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationB.cs:18:22:18:36 | {...} | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationB.cs:18:22:18:36 | {...} | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationB.cs:18:24:18:34 | throw ...; | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationB.cs:18:24:18:34 | throw ...; | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationB.cs:18:30:18:33 | null | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationB.cs:18:30:18:33 | null | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationB.cs:19:12:19:13 | enter C2 | MultiImplementationA.cs:21:12:21:13 | C2 | +| MultiImplementationB.cs:19:12:19:13 | enter C2 | MultiImplementationB.cs:19:12:19:13 | C2 | +| MultiImplementationB.cs:19:12:19:13 | exit C2 | MultiImplementationA.cs:21:12:21:13 | C2 | +| MultiImplementationB.cs:19:12:19:13 | exit C2 | MultiImplementationB.cs:19:12:19:13 | C2 | +| MultiImplementationB.cs:19:19:19:22 | call to constructor C2 | MultiImplementationA.cs:21:12:21:13 | C2 | +| MultiImplementationB.cs:19:19:19:22 | call to constructor C2 | MultiImplementationB.cs:19:12:19:13 | C2 | +| MultiImplementationB.cs:19:24:19:24 | 1 | MultiImplementationA.cs:21:12:21:13 | C2 | +| MultiImplementationB.cs:19:24:19:24 | 1 | MultiImplementationB.cs:19:12:19:13 | C2 | +| MultiImplementationB.cs:19:27:19:29 | {...} | MultiImplementationA.cs:21:12:21:13 | C2 | +| MultiImplementationB.cs:19:27:19:29 | {...} | MultiImplementationB.cs:19:12:19:13 | C2 | +| MultiImplementationB.cs:20:6:20:7 | enter ~C2 | MultiImplementationA.cs:22:6:22:7 | ~C2 | +| MultiImplementationB.cs:20:6:20:7 | enter ~C2 | MultiImplementationB.cs:20:6:20:7 | ~C2 | +| MultiImplementationB.cs:20:6:20:7 | exit ~C2 | MultiImplementationA.cs:22:6:22:7 | ~C2 | +| MultiImplementationB.cs:20:6:20:7 | exit ~C2 | MultiImplementationB.cs:20:6:20:7 | ~C2 | +| MultiImplementationB.cs:20:11:20:25 | {...} | MultiImplementationA.cs:22:6:22:7 | ~C2 | +| MultiImplementationB.cs:20:11:20:25 | {...} | MultiImplementationB.cs:20:6:20:7 | ~C2 | +| MultiImplementationB.cs:20:13:20:23 | throw ...; | MultiImplementationA.cs:22:6:22:7 | ~C2 | +| MultiImplementationB.cs:20:13:20:23 | throw ...; | MultiImplementationB.cs:20:6:20:7 | ~C2 | +| MultiImplementationB.cs:20:19:20:22 | null | MultiImplementationA.cs:22:6:22:7 | ~C2 | +| MultiImplementationB.cs:20:19:20:22 | null | MultiImplementationB.cs:20:6:20:7 | ~C2 | +| MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | MultiImplementationA.cs:23:28:23:35 | implicit conversion | +| MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | MultiImplementationB.cs:21:28:21:35 | implicit conversion | +| MultiImplementationB.cs:21:28:21:35 | exit implicit conversion | MultiImplementationA.cs:23:28:23:35 | implicit conversion | +| MultiImplementationB.cs:21:28:21:35 | exit implicit conversion | MultiImplementationB.cs:21:28:21:35 | implicit conversion | +| MultiImplementationB.cs:21:50:21:59 | throw ... | MultiImplementationA.cs:23:28:23:35 | implicit conversion | +| MultiImplementationB.cs:21:50:21:59 | throw ... | MultiImplementationB.cs:21:28:21:35 | implicit conversion | +| MultiImplementationB.cs:21:56:21:59 | null | MultiImplementationA.cs:23:28:23:35 | implicit conversion | +| MultiImplementationB.cs:21:56:21:59 | null | MultiImplementationB.cs:21:28:21:35 | implicit conversion | +| MultiImplementationB.cs:22:16:22:16 | access to property P | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationB.cs:22:16:22:16 | access to property P | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationB.cs:22:16:22:16 | this access | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationB.cs:22:16:22:16 | this access | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationB.cs:22:32:22:34 | ... = ... | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationB.cs:22:32:22:34 | ... = ... | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationB.cs:22:34:22:34 | 1 | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationB.cs:22:34:22:34 | 1 | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationB.cs:27:21:27:23 | enter get_P3 | MultiImplementationA.cs:30:21:30:23 | get_P3 | +| MultiImplementationB.cs:27:21:27:23 | enter get_P3 | MultiImplementationB.cs:27:21:27:23 | get_P3 | +| MultiImplementationB.cs:27:21:27:23 | exit get_P3 | MultiImplementationA.cs:30:21:30:23 | get_P3 | +| MultiImplementationB.cs:27:21:27:23 | exit get_P3 | MultiImplementationB.cs:27:21:27:23 | get_P3 | +| MultiImplementationB.cs:32:9:32:10 | enter M1 | MultiImplementationA.cs:36:9:36:10 | M1 | +| MultiImplementationB.cs:32:9:32:10 | enter M1 | MultiImplementationB.cs:32:9:32:10 | M1 | +| MultiImplementationB.cs:32:9:32:10 | exit M1 | MultiImplementationA.cs:36:9:36:10 | M1 | +| MultiImplementationB.cs:32:9:32:10 | exit M1 | MultiImplementationB.cs:32:9:32:10 | M1 | +| MultiImplementationB.cs:32:17:32:17 | 0 | MultiImplementationA.cs:36:9:36:10 | M1 | +| MultiImplementationB.cs:32:17:32:17 | 0 | MultiImplementationB.cs:32:9:32:10 | M1 | | NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:9:3:10 | M1 | | NullCoalescing.cs:3:9:3:10 | exit M1 | NullCoalescing.cs:3:9:3:10 | M1 | | NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:9:3:10 | M1 | @@ -2409,7 +3284,7 @@ nodeEnclosing | Switch.cs:27:13:27:39 | case ...: | Switch.cs:10:10:10:11 | M2 | | Switch.cs:27:18:27:25 | Double d | Switch.cs:10:10:10:11 | M2 | | Switch.cs:27:32:27:38 | call to method Throw | Switch.cs:10:10:10:11 | M2 | -| Switch.cs:28:17:28:21 | Label: | Switch.cs:10:10:10:11 | M2 | +| Switch.cs:28:13:28:17 | Label: | Switch.cs:10:10:10:11 | M2 | | Switch.cs:29:17:29:23 | return ...; | Switch.cs:10:10:10:11 | M2 | | Switch.cs:30:13:30:20 | default: | Switch.cs:10:10:10:11 | M2 | | Switch.cs:31:17:31:27 | goto ...; | Switch.cs:10:10:10:11 | M2 | @@ -2439,40 +3314,40 @@ nodeEnclosing | Switch.cs:57:17:57:17 | 1 | Switch.cs:55:10:55:11 | M5 | | Switch.cs:57:17:57:21 | ... + ... | Switch.cs:55:10:55:11 | M5 | | Switch.cs:57:21:57:21 | 2 | Switch.cs:55:10:55:11 | M5 | -| Switch.cs:59:13:59:20 | case ...: | Switch.cs:55:10:55:11 | M5 | +| Switch.cs:59:13:59:19 | case ...: | Switch.cs:55:10:55:11 | M5 | | Switch.cs:59:18:59:18 | 2 | Switch.cs:55:10:55:11 | M5 | -| Switch.cs:61:13:61:20 | case ...: | Switch.cs:55:10:55:11 | M5 | +| Switch.cs:61:13:61:19 | case ...: | Switch.cs:55:10:55:11 | M5 | | Switch.cs:61:18:61:18 | 3 | Switch.cs:55:10:55:11 | M5 | -| Switch.cs:62:15:62:20 | break; | Switch.cs:55:10:55:11 | M5 | +| Switch.cs:62:17:62:22 | break; | Switch.cs:55:10:55:11 | M5 | | Switch.cs:66:10:66:11 | enter M6 | Switch.cs:66:10:66:11 | M6 | | Switch.cs:66:10:66:11 | exit M6 | Switch.cs:66:10:66:11 | M6 | | Switch.cs:67:5:75:5 | {...} | Switch.cs:66:10:66:11 | M6 | | Switch.cs:68:9:74:9 | switch (...) {...} | Switch.cs:66:10:66:11 | M6 | | Switch.cs:68:17:68:25 | (...) ... | Switch.cs:66:10:66:11 | M6 | | Switch.cs:68:25:68:25 | access to parameter s | Switch.cs:66:10:66:11 | M6 | -| Switch.cs:70:13:70:24 | case ...: | Switch.cs:66:10:66:11 | M6 | +| Switch.cs:70:13:70:23 | case ...: | Switch.cs:66:10:66:11 | M6 | | Switch.cs:70:18:70:20 | access to type Int32 | Switch.cs:66:10:66:11 | M6 | -| Switch.cs:72:13:72:21 | case ...: | Switch.cs:66:10:66:11 | M6 | +| Switch.cs:72:13:72:20 | case ...: | Switch.cs:66:10:66:11 | M6 | | Switch.cs:72:18:72:19 | "" | Switch.cs:66:10:66:11 | M6 | -| Switch.cs:73:15:73:20 | break; | Switch.cs:66:10:66:11 | M6 | +| Switch.cs:73:17:73:22 | break; | Switch.cs:66:10:66:11 | M6 | | Switch.cs:77:10:77:11 | enter M7 | Switch.cs:77:10:77:11 | M7 | | Switch.cs:77:10:77:11 | exit M7 | Switch.cs:77:10:77:11 | M7 | | Switch.cs:78:5:89:5 | {...} | Switch.cs:77:10:77:11 | M7 | | Switch.cs:79:9:87:9 | switch (...) {...} | Switch.cs:77:10:77:11 | M7 | | Switch.cs:79:17:79:17 | access to parameter i | Switch.cs:77:10:77:11 | M7 | -| Switch.cs:81:13:81:20 | case ...: | Switch.cs:77:10:77:11 | M7 | +| Switch.cs:81:13:81:19 | case ...: | Switch.cs:77:10:77:11 | M7 | | Switch.cs:81:18:81:18 | 1 | Switch.cs:77:10:77:11 | M7 | -| Switch.cs:82:15:82:26 | return ...; | Switch.cs:77:10:77:11 | M7 | -| Switch.cs:82:22:82:25 | true | Switch.cs:77:10:77:11 | M7 | -| Switch.cs:83:13:83:20 | case ...: | Switch.cs:77:10:77:11 | M7 | +| Switch.cs:82:17:82:28 | return ...; | Switch.cs:77:10:77:11 | M7 | +| Switch.cs:82:24:82:27 | true | Switch.cs:77:10:77:11 | M7 | +| Switch.cs:83:13:83:19 | case ...: | Switch.cs:77:10:77:11 | M7 | | Switch.cs:83:18:83:18 | 2 | Switch.cs:77:10:77:11 | M7 | -| Switch.cs:84:15:85:22 | if (...) ... | Switch.cs:77:10:77:11 | M7 | -| Switch.cs:84:19:84:19 | access to parameter j | Switch.cs:77:10:77:11 | M7 | -| Switch.cs:84:19:84:23 | ... > ... | Switch.cs:77:10:77:11 | M7 | -| Switch.cs:84:23:84:23 | 2 | Switch.cs:77:10:77:11 | M7 | -| Switch.cs:85:17:85:22 | break; | Switch.cs:77:10:77:11 | M7 | -| Switch.cs:86:15:86:26 | return ...; | Switch.cs:77:10:77:11 | M7 | -| Switch.cs:86:22:86:25 | true | Switch.cs:77:10:77:11 | M7 | +| Switch.cs:84:17:85:26 | if (...) ... | Switch.cs:77:10:77:11 | M7 | +| Switch.cs:84:21:84:21 | access to parameter j | Switch.cs:77:10:77:11 | M7 | +| Switch.cs:84:21:84:25 | ... > ... | Switch.cs:77:10:77:11 | M7 | +| Switch.cs:84:25:84:25 | 2 | Switch.cs:77:10:77:11 | M7 | +| Switch.cs:85:21:85:26 | break; | Switch.cs:77:10:77:11 | M7 | +| Switch.cs:86:17:86:28 | return ...; | Switch.cs:77:10:77:11 | M7 | +| Switch.cs:86:24:86:27 | true | Switch.cs:77:10:77:11 | M7 | | Switch.cs:88:9:88:21 | return ...; | Switch.cs:77:10:77:11 | M7 | | Switch.cs:88:16:88:20 | false | Switch.cs:77:10:77:11 | M7 | | Switch.cs:91:10:91:11 | enter M8 | Switch.cs:91:10:91:11 | M8 | @@ -2480,10 +3355,10 @@ nodeEnclosing | Switch.cs:92:5:99:5 | {...} | Switch.cs:91:10:91:11 | M8 | | Switch.cs:93:9:97:9 | switch (...) {...} | Switch.cs:91:10:91:11 | M8 | | Switch.cs:93:17:93:17 | access to parameter o | Switch.cs:91:10:91:11 | M8 | -| Switch.cs:95:13:95:24 | case ...: | Switch.cs:91:10:91:11 | M8 | +| Switch.cs:95:13:95:23 | case ...: | Switch.cs:91:10:91:11 | M8 | | Switch.cs:95:18:95:20 | access to type Int32 | Switch.cs:91:10:91:11 | M8 | -| Switch.cs:96:15:96:26 | return ...; | Switch.cs:91:10:91:11 | M8 | -| Switch.cs:96:22:96:25 | true | Switch.cs:91:10:91:11 | M8 | +| Switch.cs:96:17:96:28 | return ...; | Switch.cs:91:10:91:11 | M8 | +| Switch.cs:96:24:96:27 | true | Switch.cs:91:10:91:11 | M8 | | Switch.cs:98:9:98:21 | return ...; | Switch.cs:91:10:91:11 | M8 | | Switch.cs:98:16:98:20 | false | Switch.cs:91:10:91:11 | M8 | | Switch.cs:101:9:101:10 | enter M9 | Switch.cs:101:9:101:10 | M9 | @@ -2492,14 +3367,14 @@ nodeEnclosing | Switch.cs:103:9:107:9 | switch (...) {...} | Switch.cs:101:9:101:10 | M9 | | Switch.cs:103:17:103:17 | access to parameter s | Switch.cs:101:9:101:10 | M9 | | Switch.cs:103:19:103:25 | access to property Length | Switch.cs:101:9:101:10 | M9 | -| Switch.cs:105:13:105:20 | case ...: | Switch.cs:101:9:101:10 | M9 | +| Switch.cs:105:13:105:19 | case ...: | Switch.cs:101:9:101:10 | M9 | | Switch.cs:105:18:105:18 | 0 | Switch.cs:101:9:101:10 | M9 | -| Switch.cs:105:22:105:30 | return ...; | Switch.cs:101:9:101:10 | M9 | -| Switch.cs:105:29:105:29 | 0 | Switch.cs:101:9:101:10 | M9 | -| Switch.cs:106:13:106:20 | case ...: | Switch.cs:101:9:101:10 | M9 | +| Switch.cs:105:21:105:29 | return ...; | Switch.cs:101:9:101:10 | M9 | +| Switch.cs:105:28:105:28 | 0 | Switch.cs:101:9:101:10 | M9 | +| Switch.cs:106:13:106:19 | case ...: | Switch.cs:101:9:101:10 | M9 | | Switch.cs:106:18:106:18 | 1 | Switch.cs:101:9:101:10 | M9 | -| Switch.cs:106:22:106:30 | return ...; | Switch.cs:101:9:101:10 | M9 | -| Switch.cs:106:29:106:29 | 1 | Switch.cs:101:9:101:10 | M9 | +| Switch.cs:106:21:106:29 | return ...; | Switch.cs:101:9:101:10 | M9 | +| Switch.cs:106:28:106:28 | 1 | Switch.cs:101:9:101:10 | M9 | | Switch.cs:108:9:108:18 | return ...; | Switch.cs:101:9:101:10 | M9 | | Switch.cs:108:16:108:17 | -... | Switch.cs:101:9:101:10 | M9 | | Switch.cs:108:17:108:17 | 1 | Switch.cs:101:9:101:10 | M9 | @@ -2513,20 +3388,20 @@ nodeEnclosing | Switch.cs:115:9:119:9 | switch (...) {...} | Switch.cs:113:9:113:11 | M10 | | Switch.cs:115:17:115:17 | access to parameter s | Switch.cs:113:9:113:11 | M10 | | Switch.cs:115:17:115:24 | access to property Length | Switch.cs:113:9:113:11 | M10 | -| Switch.cs:117:13:117:34 | case ...: | Switch.cs:113:9:113:11 | M10 | +| Switch.cs:117:13:117:35 | case ...: | Switch.cs:113:9:113:11 | M10 | | Switch.cs:117:18:117:18 | 3 | Switch.cs:113:9:113:11 | M10 | | Switch.cs:117:25:117:25 | access to parameter s | Switch.cs:113:9:113:11 | M10 | -| Switch.cs:117:25:117:32 | ... == ... | Switch.cs:113:9:113:11 | M10 | -| Switch.cs:117:28:117:32 | "foo" | Switch.cs:113:9:113:11 | M10 | -| Switch.cs:117:36:117:44 | return ...; | Switch.cs:113:9:113:11 | M10 | -| Switch.cs:117:43:117:43 | 1 | Switch.cs:113:9:113:11 | M10 | -| Switch.cs:118:13:118:33 | case ...: | Switch.cs:113:9:113:11 | M10 | +| Switch.cs:117:25:117:34 | ... == ... | Switch.cs:113:9:113:11 | M10 | +| Switch.cs:117:30:117:34 | "foo" | Switch.cs:113:9:113:11 | M10 | +| Switch.cs:117:37:117:45 | return ...; | Switch.cs:113:9:113:11 | M10 | +| Switch.cs:117:44:117:44 | 1 | Switch.cs:113:9:113:11 | M10 | +| Switch.cs:118:13:118:34 | case ...: | Switch.cs:113:9:113:11 | M10 | | Switch.cs:118:18:118:18 | 2 | Switch.cs:113:9:113:11 | M10 | | Switch.cs:118:25:118:25 | access to parameter s | Switch.cs:113:9:113:11 | M10 | -| Switch.cs:118:25:118:31 | ... == ... | Switch.cs:113:9:113:11 | M10 | -| Switch.cs:118:28:118:31 | "fu" | Switch.cs:113:9:113:11 | M10 | -| Switch.cs:118:35:118:43 | return ...; | Switch.cs:113:9:113:11 | M10 | -| Switch.cs:118:42:118:42 | 2 | Switch.cs:113:9:113:11 | M10 | +| Switch.cs:118:25:118:33 | ... == ... | Switch.cs:113:9:113:11 | M10 | +| Switch.cs:118:30:118:33 | "fu" | Switch.cs:113:9:113:11 | M10 | +| Switch.cs:118:36:118:44 | return ...; | Switch.cs:113:9:113:11 | M10 | +| Switch.cs:118:43:118:43 | 2 | Switch.cs:113:9:113:11 | M10 | | Switch.cs:120:9:120:18 | return ...; | Switch.cs:113:9:113:11 | M10 | | Switch.cs:120:16:120:17 | -... | Switch.cs:113:9:113:11 | M10 | | Switch.cs:120:17:120:17 | 1 | Switch.cs:113:9:113:11 | M10 | @@ -2590,6 +3465,31 @@ nodeEnclosing | Switch.cs:150:18:150:18 | 2 | Switch.cs:144:9:144:11 | M14 | | Switch.cs:150:21:150:29 | return ...; | Switch.cs:144:9:144:11 | M14 | | Switch.cs:150:28:150:28 | 2 | Switch.cs:144:9:144:11 | M14 | +| Switch.cs:154:10:154:12 | enter M15 | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:154:10:154:12 | exit M15 | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:155:5:161:5 | {...} | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:156:9:156:55 | ... ...; | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:156:13:156:54 | String s = ... | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:156:17:156:17 | access to parameter b | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:156:17:156:54 | ... switch { ... } | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:156:28:156:31 | true | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:156:28:156:38 | ... => ... | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:156:36:156:38 | "a" | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:156:41:156:45 | false | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:156:41:156:52 | ... => ... | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:156:50:156:52 | "b" | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:157:9:160:49 | if (...) ... | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:157:13:157:13 | access to parameter b | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:158:13:158:48 | call to method WriteLine | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:158:13:158:49 | ...; | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:158:38:158:47 | $"..." | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:158:40:158:43 | "a = " | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:158:45:158:45 | access to local variable s | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:160:13:160:48 | call to method WriteLine | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:160:13:160:49 | ...; | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:160:38:160:47 | $"..." | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:160:40:160:43 | "b = " | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:160:45:160:45 | access to local variable s | Switch.cs:154:10:154:12 | M15 | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:3:10:3:10 | M | | TypeAccesses.cs:3:10:3:10 | exit M | TypeAccesses.cs:3:10:3:10 | M | | TypeAccesses.cs:4:5:9:5 | {...} | TypeAccesses.cs:3:10:3:10 | M | @@ -2615,10 +3515,12 @@ nodeEnclosing | VarDecls.cs:7:9:10:9 | fixed(...) { ... } | VarDecls.cs:5:18:5:19 | M1 | | VarDecls.cs:7:22:7:36 | Char* c1 = ... | VarDecls.cs:5:18:5:19 | M1 | | VarDecls.cs:7:27:7:33 | access to parameter strings | VarDecls.cs:5:18:5:19 | M1 | +| VarDecls.cs:7:27:7:36 | (...) ... | VarDecls.cs:5:18:5:19 | M1 | | VarDecls.cs:7:27:7:36 | access to array element | VarDecls.cs:5:18:5:19 | M1 | | VarDecls.cs:7:35:7:35 | 0 | VarDecls.cs:5:18:5:19 | M1 | | VarDecls.cs:7:39:7:53 | Char* c2 = ... | VarDecls.cs:5:18:5:19 | M1 | | VarDecls.cs:7:44:7:50 | access to parameter strings | VarDecls.cs:5:18:5:19 | M1 | +| VarDecls.cs:7:44:7:53 | (...) ... | VarDecls.cs:5:18:5:19 | M1 | | VarDecls.cs:7:44:7:53 | access to array element | VarDecls.cs:5:18:5:19 | M1 | | VarDecls.cs:7:52:7:52 | 1 | VarDecls.cs:5:18:5:19 | M1 | | VarDecls.cs:8:9:10:9 | {...} | VarDecls.cs:5:18:5:19 | M1 | @@ -3317,6 +4219,125 @@ blockEnclosing | ArrayCreation.cs:5:12:5:13 | enter M2 | ArrayCreation.cs:5:12:5:13 | M2 | | ArrayCreation.cs:7:11:7:12 | enter M3 | ArrayCreation.cs:7:11:7:12 | M3 | | ArrayCreation.cs:9:12:9:13 | enter M4 | ArrayCreation.cs:9:12:9:13 | M4 | +| Assert.cs:7:10:7:11 | enter M1 | Assert.cs:7:10:7:11 | M1 | +| Assert.cs:7:10:7:11 | exit M1 | Assert.cs:7:10:7:11 | M1 | +| Assert.cs:9:16:9:32 | String s = ... | Assert.cs:7:10:7:11 | M1 | +| Assert.cs:9:24:9:27 | null | Assert.cs:7:10:7:11 | M1 | +| Assert.cs:9:31:9:32 | "" | Assert.cs:7:10:7:11 | M1 | +| Assert.cs:10:9:10:31 | [assertion failure] call to method Assert | Assert.cs:7:10:7:11 | M1 | +| Assert.cs:10:9:10:31 | [assertion success] call to method Assert | Assert.cs:7:10:7:11 | M1 | +| Assert.cs:14:10:14:11 | enter M2 | Assert.cs:14:10:14:11 | M2 | +| Assert.cs:14:10:14:11 | exit M2 | Assert.cs:14:10:14:11 | M2 | +| Assert.cs:16:16:16:32 | String s = ... | Assert.cs:14:10:14:11 | M2 | +| Assert.cs:16:24:16:27 | null | Assert.cs:14:10:14:11 | M2 | +| Assert.cs:16:31:16:32 | "" | Assert.cs:14:10:14:11 | M2 | +| Assert.cs:17:9:17:24 | [assertion failure] call to method IsNull | Assert.cs:14:10:14:11 | M2 | +| Assert.cs:17:9:17:24 | [assertion success] call to method IsNull | Assert.cs:14:10:14:11 | M2 | +| Assert.cs:21:10:21:11 | enter M3 | Assert.cs:21:10:21:11 | M3 | +| Assert.cs:21:10:21:11 | exit M3 | Assert.cs:21:10:21:11 | M3 | +| Assert.cs:23:16:23:32 | String s = ... | Assert.cs:21:10:21:11 | M3 | +| Assert.cs:23:24:23:27 | null | Assert.cs:21:10:21:11 | M3 | +| Assert.cs:23:31:23:32 | "" | Assert.cs:21:10:21:11 | M3 | +| Assert.cs:24:9:24:27 | [assertion failure] call to method IsNotNull | Assert.cs:21:10:21:11 | M3 | +| Assert.cs:24:9:24:27 | [assertion success] call to method IsNotNull | Assert.cs:21:10:21:11 | M3 | +| Assert.cs:28:10:28:11 | enter M4 | Assert.cs:28:10:28:11 | M4 | +| Assert.cs:28:10:28:11 | exit M4 | Assert.cs:28:10:28:11 | M4 | +| Assert.cs:30:16:30:32 | String s = ... | Assert.cs:28:10:28:11 | M4 | +| Assert.cs:30:24:30:27 | null | Assert.cs:28:10:28:11 | M4 | +| Assert.cs:30:31:30:32 | "" | Assert.cs:28:10:28:11 | M4 | +| Assert.cs:31:9:31:32 | [assertion failure] call to method IsTrue | Assert.cs:28:10:28:11 | M4 | +| Assert.cs:31:9:31:32 | [assertion success] call to method IsTrue | Assert.cs:28:10:28:11 | M4 | +| Assert.cs:35:10:35:11 | enter M5 | Assert.cs:35:10:35:11 | M5 | +| Assert.cs:35:10:35:11 | exit M5 | Assert.cs:35:10:35:11 | M5 | +| Assert.cs:37:16:37:32 | String s = ... | Assert.cs:35:10:35:11 | M5 | +| Assert.cs:37:24:37:27 | null | Assert.cs:35:10:35:11 | M5 | +| Assert.cs:37:31:37:32 | "" | Assert.cs:35:10:35:11 | M5 | +| Assert.cs:38:9:38:32 | [assertion failure] call to method IsTrue | Assert.cs:35:10:35:11 | M5 | +| Assert.cs:38:9:38:32 | [assertion success] call to method IsTrue | Assert.cs:35:10:35:11 | M5 | +| Assert.cs:42:10:42:11 | enter M6 | Assert.cs:42:10:42:11 | M6 | +| Assert.cs:42:10:42:11 | exit M6 | Assert.cs:42:10:42:11 | M6 | +| Assert.cs:44:16:44:32 | String s = ... | Assert.cs:42:10:42:11 | M6 | +| Assert.cs:44:24:44:27 | null | Assert.cs:42:10:42:11 | M6 | +| Assert.cs:44:31:44:32 | "" | Assert.cs:42:10:42:11 | M6 | +| Assert.cs:45:9:45:33 | [assertion failure] call to method IsFalse | Assert.cs:42:10:42:11 | M6 | +| Assert.cs:45:9:45:33 | [assertion success] call to method IsFalse | Assert.cs:42:10:42:11 | M6 | +| Assert.cs:49:10:49:11 | enter M7 | Assert.cs:49:10:49:11 | M7 | +| Assert.cs:49:10:49:11 | exit M7 | Assert.cs:49:10:49:11 | M7 | +| Assert.cs:51:16:51:32 | String s = ... | Assert.cs:49:10:49:11 | M7 | +| Assert.cs:51:24:51:27 | null | Assert.cs:49:10:49:11 | M7 | +| Assert.cs:51:31:51:32 | "" | Assert.cs:49:10:49:11 | M7 | +| Assert.cs:52:9:52:33 | [assertion failure] call to method IsFalse | Assert.cs:49:10:49:11 | M7 | +| Assert.cs:52:9:52:33 | [assertion success] call to method IsFalse | Assert.cs:49:10:49:11 | M7 | +| Assert.cs:56:10:56:11 | enter M8 | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:56:10:56:11 | exit M8 | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:58:24:58:27 | [b (line 56): true] null | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:58:31:58:32 | [b (line 56): false] "" | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:59:9:59:37 | [assertion failure] call to method IsTrue | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:59:36:59:36 | [b (line 56): false] access to parameter b | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:59:36:59:36 | [b (line 56): true] access to parameter b | Assert.cs:56:10:56:11 | M8 | +| Assert.cs:63:10:63:11 | enter M9 | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:63:10:63:11 | exit M9 | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:65:24:65:27 | [b (line 63): true] null | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:65:31:65:32 | [b (line 63): false] "" | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:66:9:66:38 | [assertion failure] call to method IsFalse | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:66:37:66:37 | [b (line 63): false] access to parameter b | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:66:37:66:37 | [b (line 63): true] access to parameter b | Assert.cs:63:10:63:11 | M9 | +| Assert.cs:70:10:70:12 | enter M10 | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:70:10:70:12 | exit M10 | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:72:24:72:27 | [b (line 70): true] null | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:72:31:72:32 | [b (line 70): false] "" | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:73:9:73:37 | [assertion failure] call to method IsTrue | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:73:36:73:36 | [b (line 70): false] access to parameter b | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:73:36:73:36 | [b (line 70): true] access to parameter b | Assert.cs:70:10:70:12 | M10 | +| Assert.cs:77:10:77:12 | enter M11 | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:77:10:77:12 | exit M11 | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:79:24:79:27 | [b (line 77): true] null | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:79:31:79:32 | [b (line 77): false] "" | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:80:9:80:38 | [assertion failure] call to method IsFalse | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:80:37:80:37 | [b (line 77): false] access to parameter b | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:80:37:80:37 | [b (line 77): true] access to parameter b | Assert.cs:77:10:77:12 | M11 | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:84:10:84:12 | exit M12 | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:87:9:87:31 | [assertion failure, b (line 84): false] call to method Assert | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:87:9:87:31 | [assertion failure, b (line 84): true] call to method Assert | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:91:9:91:24 | [assertion failure, b (line 84): false] call to method IsNull | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:91:9:91:24 | [assertion failure, b (line 84): true] call to method IsNull | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:95:9:95:27 | [assertion failure, b (line 84): false] call to method IsNotNull | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:95:9:95:27 | [assertion failure, b (line 84): true] call to method IsNotNull | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:99:9:99:32 | [assertion failure, b (line 84): false] call to method IsTrue | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:99:9:99:32 | [assertion failure, b (line 84): true] call to method IsTrue | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:103:9:103:32 | [assertion failure, b (line 84): false] call to method IsTrue | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:103:9:103:32 | [assertion failure, b (line 84): true] call to method IsTrue | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:119:37:119:38 | [b (line 84): true] !... | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | Assert.cs:84:10:84:12 | M12 | +| Assert.cs:127:37:127:38 | [b (line 84): true] !... | Assert.cs:84:10:84:12 | M12 | | Assignments.cs:3:10:3:10 | enter M | Assignments.cs:3:10:3:10 | M | | Assignments.cs:14:18:14:35 | enter (...) => ... | Assignments.cs:14:18:14:35 | (...) => ... | | Assignments.cs:17:40:17:40 | enter + | Assignments.cs:17:40:17:40 | + | @@ -3361,6 +4382,8 @@ blockEnclosing | CompileTimeOperators.cs:15:10:15:15 | enter Typeof | CompileTimeOperators.cs:15:10:15:15 | Typeof | | CompileTimeOperators.cs:20:12:20:17 | enter Nameof | CompileTimeOperators.cs:20:12:20:17 | Nameof | | CompileTimeOperators.cs:28:10:28:10 | enter M | CompileTimeOperators.cs:28:10:28:10 | M | +| ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | ConditionalAccess | +| ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | ConditionalAccess | | ConditionalAccess.cs:3:12:3:13 | enter M1 | ConditionalAccess.cs:3:12:3:13 | M1 | | ConditionalAccess.cs:3:12:3:13 | exit M1 | ConditionalAccess.cs:3:12:3:13 | M1 | | ConditionalAccess.cs:3:28:3:38 | call to method ToString | ConditionalAccess.cs:3:12:3:13 | M1 | @@ -3386,7 +4409,12 @@ blockEnclosing | ConditionalAccess.cs:19:12:19:13 | exit M6 | ConditionalAccess.cs:19:12:19:13 | M6 | | ConditionalAccess.cs:19:58:19:59 | access to parameter s2 | ConditionalAccess.cs:19:12:19:13 | M6 | | ConditionalAccess.cs:21:10:21:11 | enter M7 | ConditionalAccess.cs:21:10:21:11 | M7 | -| ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | ConditionalAccess.cs:31:26:31:38 | CommaJoinWith | +| ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:30:10:30:12 | Out | +| ConditionalAccess.cs:30:10:30:12 | exit Out | ConditionalAccess.cs:30:10:30:12 | Out | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:35:14:35:24 | call to method Out | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:3:10:3:19 | IncrOrDecr | | Conditions.cs:3:10:3:19 | exit IncrOrDecr | Conditions.cs:3:10:3:19 | IncrOrDecr | | Conditions.cs:6:13:6:16 | [inc (line 3): true] ...; | Conditions.cs:3:10:3:19 | IncrOrDecr | @@ -3454,8 +4482,8 @@ blockEnclosing | Conditions.cs:110:16:110:16 | access to local variable x | Conditions.cs:102:12:102:13 | M8 | | Conditions.cs:113:10:113:11 | enter M9 | Conditions.cs:113:10:113:11 | M9 | | Conditions.cs:113:10:113:11 | exit M9 | Conditions.cs:113:10:113:11 | M9 | -| Conditions.cs:116:24:116:24 | access to local variable i | Conditions.cs:113:10:113:11 | M9 | -| Conditions.cs:116:41:116:41 | access to local variable i | Conditions.cs:113:10:113:11 | M9 | +| Conditions.cs:116:25:116:25 | access to local variable i | Conditions.cs:113:10:113:11 | M9 | +| Conditions.cs:116:42:116:42 | access to local variable i | Conditions.cs:113:10:113:11 | M9 | | Conditions.cs:117:9:123:9 | {...} | Conditions.cs:113:10:113:11 | M9 | | Conditions.cs:120:17:120:23 | [last (line 118): false] ...; | Conditions.cs:113:10:113:11 | M9 | | Conditions.cs:121:13:122:25 | [last (line 118): true] if (...) ... | Conditions.cs:113:10:113:11 | M9 | @@ -3464,6 +4492,10 @@ blockEnclosing | Conditions.cs:131:16:131:19 | [Field1 (line 129): true, Field2 (line 129): false] true | Conditions.cs:129:10:129:12 | M10 | | Conditions.cs:134:13:139:13 | [Field1 (line 129): true] {...} | Conditions.cs:129:10:129:12 | M10 | | Conditions.cs:136:17:138:17 | [Field1 (line 129): true, Field2 (line 129): true] {...} | Conditions.cs:129:10:129:12 | M10 | +| Conditions.cs:143:10:143:12 | enter M11 | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:143:10:143:12 | exit M11 | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:145:21:145:23 | [b (line 143): true] "a" | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:145:27:145:29 | [b (line 143): false] "b" | Conditions.cs:143:10:143:12 | M11 | | ExitMethods.cs:7:10:7:11 | enter M1 | ExitMethods.cs:7:10:7:11 | M1 | | ExitMethods.cs:13:10:13:11 | enter M2 | ExitMethods.cs:13:10:13:11 | M2 | | ExitMethods.cs:19:10:19:11 | enter M3 | ExitMethods.cs:19:10:19:11 | M3 | @@ -3500,6 +4532,9 @@ blockEnclosing | ExitMethods.cs:119:17:119:32 | enter FailingAssertion | ExitMethods.cs:119:17:119:32 | FailingAssertion | | ExitMethods.cs:125:17:125:33 | enter FailingAssertion2 | ExitMethods.cs:125:17:125:33 | FailingAssertion2 | | ExitMethods.cs:131:10:131:20 | enter AssertFalse | ExitMethods.cs:131:10:131:20 | AssertFalse | +| ExitMethods.cs:131:10:131:20 | exit AssertFalse | ExitMethods.cs:131:10:131:20 | AssertFalse | +| ExitMethods.cs:131:33:131:49 | [assertion failure] call to method IsFalse | ExitMethods.cs:131:10:131:20 | AssertFalse | +| ExitMethods.cs:131:33:131:49 | [assertion success] call to method IsFalse | ExitMethods.cs:131:10:131:20 | AssertFalse | | ExitMethods.cs:133:17:133:33 | enter FailingAssertion3 | ExitMethods.cs:133:17:133:33 | FailingAssertion3 | | Extensions.cs:5:23:5:29 | enter ToInt32 | Extensions.cs:5:23:5:29 | ToInt32 | | Extensions.cs:10:24:10:29 | enter ToBool | Extensions.cs:10:24:10:29 | ToBool | @@ -3713,39 +4748,214 @@ blockEnclosing | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:7:10:7:11 | M1 | | LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:7:10:7:11 | M1 | | LoopUnrolling.cs:10:13:10:19 | return ...; | LoopUnrolling.cs:7:10:7:11 | M1 | -| LoopUnrolling.cs:11:21:11:23 | String arg | LoopUnrolling.cs:7:10:7:11 | M1 | -| LoopUnrolling.cs:11:28:11:31 | access to parameter args | LoopUnrolling.cs:7:10:7:11 | M1 | +| LoopUnrolling.cs:11:22:11:24 | String arg | LoopUnrolling.cs:7:10:7:11 | M1 | +| LoopUnrolling.cs:11:29:11:32 | access to parameter args | LoopUnrolling.cs:7:10:7:11 | M1 | | LoopUnrolling.cs:15:10:15:11 | enter M2 | LoopUnrolling.cs:15:10:15:11 | M2 | | LoopUnrolling.cs:15:10:15:11 | exit M2 | LoopUnrolling.cs:15:10:15:11 | M2 | -| LoopUnrolling.cs:18:21:18:21 | String x | LoopUnrolling.cs:15:10:15:11 | M2 | +| LoopUnrolling.cs:18:22:18:22 | String x | LoopUnrolling.cs:15:10:15:11 | M2 | | LoopUnrolling.cs:22:10:22:11 | enter M3 | LoopUnrolling.cs:22:10:22:11 | M3 | | LoopUnrolling.cs:22:10:22:11 | exit M3 | LoopUnrolling.cs:22:10:22:11 | M3 | | LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:22:10:22:11 | M3 | | LoopUnrolling.cs:24:22:24:24 | Char arg | LoopUnrolling.cs:22:10:22:11 | M3 | | LoopUnrolling.cs:25:26:25:29 | Char arg0 | LoopUnrolling.cs:22:10:22:11 | M3 | | LoopUnrolling.cs:29:10:29:11 | enter M4 | LoopUnrolling.cs:29:10:29:11 | M4 | -| LoopUnrolling.cs:29:10:29:11 | exit M4 | LoopUnrolling.cs:29:10:29:11 | M4 | -| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:29:10:29:11 | M4 | -| LoopUnrolling.cs:32:21:32:21 | String x | LoopUnrolling.cs:29:10:29:11 | M4 | | LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:36:10:36:11 | M5 | | LoopUnrolling.cs:36:10:36:11 | exit M5 | LoopUnrolling.cs:36:10:36:11 | M5 | | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:36:10:36:11 | M5 | -| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:36:10:36:11 | M5 | -| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:36:10:36:11 | M5 | +| LoopUnrolling.cs:40:22:40:22 | String x | LoopUnrolling.cs:36:10:36:11 | M5 | +| LoopUnrolling.cs:41:26:41:26 | String y | LoopUnrolling.cs:36:10:36:11 | M5 | | LoopUnrolling.cs:45:10:45:11 | enter M6 | LoopUnrolling.cs:45:10:45:11 | M6 | -| LoopUnrolling.cs:50:13:50:17 | Label: | LoopUnrolling.cs:45:10:45:11 | M6 | +| LoopUnrolling.cs:50:9:50:13 | Label: | LoopUnrolling.cs:45:10:45:11 | M6 | | LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:55:10:55:11 | M7 | | LoopUnrolling.cs:55:10:55:11 | exit M7 | LoopUnrolling.cs:55:10:55:11 | M7 | -| LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | LoopUnrolling.cs:55:10:55:11 | M7 | -| LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | LoopUnrolling.cs:55:10:55:11 | M7 | +| LoopUnrolling.cs:58:22:58:22 | [b (line 55): false] String x | LoopUnrolling.cs:55:10:55:11 | M7 | +| LoopUnrolling.cs:58:22:58:22 | [b (line 55): true] String x | LoopUnrolling.cs:55:10:55:11 | M7 | | LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | LoopUnrolling.cs:55:10:55:11 | M7 | | LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | LoopUnrolling.cs:55:10:55:11 | M7 | | LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:67:10:67:11 | M8 | | LoopUnrolling.cs:67:10:67:11 | exit M8 | LoopUnrolling.cs:67:10:67:11 | M8 | | LoopUnrolling.cs:70:13:70:19 | return ...; | LoopUnrolling.cs:67:10:67:11 | M8 | | LoopUnrolling.cs:71:9:71:21 | ...; | LoopUnrolling.cs:67:10:67:11 | M8 | -| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:67:10:67:11 | M8 | -| LoopUnrolling.cs:72:21:72:23 | String arg | LoopUnrolling.cs:67:10:67:11 | M8 | +| LoopUnrolling.cs:76:10:76:11 | enter M9 | LoopUnrolling.cs:76:10:76:11 | M9 | +| LoopUnrolling.cs:85:10:85:12 | enter M10 | LoopUnrolling.cs:85:10:85:12 | M10 | +| LoopUnrolling.cs:94:10:94:12 | enter M11 | LoopUnrolling.cs:94:10:94:12 | M11 | +| LoopUnrolling.cs:94:10:94:12 | exit M11 | LoopUnrolling.cs:94:10:94:12 | M11 | +| LoopUnrolling.cs:97:22:97:22 | String x | LoopUnrolling.cs:94:10:94:12 | M11 | +| MultiImplementationA.cs:6:22:6:31 | enter get_P1 | MultiImplementationA.cs:6:22:6:31 | get_P1 | +| MultiImplementationA.cs:6:22:6:31 | enter get_P1 | MultiImplementationB.cs:3:22:3:22 | get_P1 | +| MultiImplementationA.cs:6:22:6:31 | exit get_P1 | MultiImplementationA.cs:6:22:6:31 | get_P1 | +| MultiImplementationA.cs:6:22:6:31 | exit get_P1 | MultiImplementationB.cs:3:22:3:22 | get_P1 | +| MultiImplementationA.cs:6:28:6:31 | null | MultiImplementationA.cs:6:22:6:31 | get_P1 | +| MultiImplementationA.cs:6:28:6:31 | null | MultiImplementationB.cs:3:22:3:22 | get_P1 | +| MultiImplementationA.cs:7:21:7:23 | enter get_P2 | MultiImplementationA.cs:7:21:7:23 | get_P2 | +| MultiImplementationA.cs:7:21:7:23 | enter get_P2 | MultiImplementationB.cs:4:21:4:23 | get_P2 | +| MultiImplementationA.cs:7:21:7:23 | exit get_P2 | MultiImplementationA.cs:7:21:7:23 | get_P2 | +| MultiImplementationA.cs:7:21:7:23 | exit get_P2 | MultiImplementationB.cs:4:21:4:23 | get_P2 | +| MultiImplementationA.cs:7:25:7:39 | {...} | MultiImplementationA.cs:7:21:7:23 | get_P2 | +| MultiImplementationA.cs:7:25:7:39 | {...} | MultiImplementationB.cs:4:21:4:23 | get_P2 | +| MultiImplementationA.cs:7:41:7:43 | enter set_P2 | MultiImplementationA.cs:7:41:7:43 | set_P2 | +| MultiImplementationA.cs:7:41:7:43 | enter set_P2 | MultiImplementationB.cs:4:39:4:41 | set_P2 | +| MultiImplementationA.cs:7:41:7:43 | exit set_P2 | MultiImplementationA.cs:7:41:7:43 | set_P2 | +| MultiImplementationA.cs:7:41:7:43 | exit set_P2 | MultiImplementationB.cs:4:39:4:41 | set_P2 | +| MultiImplementationA.cs:7:45:7:59 | {...} | MultiImplementationA.cs:7:41:7:43 | set_P2 | +| MultiImplementationA.cs:7:45:7:59 | {...} | MultiImplementationB.cs:4:39:4:41 | set_P2 | +| MultiImplementationA.cs:8:16:8:16 | enter M | MultiImplementationA.cs:8:16:8:16 | M | +| MultiImplementationA.cs:8:16:8:16 | enter M | MultiImplementationB.cs:5:16:5:16 | M | +| MultiImplementationA.cs:8:16:8:16 | exit M | MultiImplementationA.cs:8:16:8:16 | M | +| MultiImplementationA.cs:8:16:8:16 | exit M | MultiImplementationB.cs:5:16:5:16 | M | +| MultiImplementationA.cs:8:29:8:32 | null | MultiImplementationA.cs:8:16:8:16 | M | +| MultiImplementationA.cs:8:29:8:32 | null | MultiImplementationB.cs:5:16:5:16 | M | +| MultiImplementationA.cs:13:16:13:16 | this access | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationA.cs:13:16:13:16 | this access | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationA.cs:14:31:14:31 | access to parameter i | MultiImplementationA.cs:14:31:14:31 | get_Item | +| MultiImplementationA.cs:14:31:14:31 | access to parameter i | MultiImplementationB.cs:12:31:12:40 | get_Item | +| MultiImplementationA.cs:14:31:14:31 | enter get_Item | MultiImplementationA.cs:14:31:14:31 | get_Item | +| MultiImplementationA.cs:14:31:14:31 | enter get_Item | MultiImplementationB.cs:12:31:12:40 | get_Item | +| MultiImplementationA.cs:14:31:14:31 | exit get_Item | MultiImplementationA.cs:14:31:14:31 | get_Item | +| MultiImplementationA.cs:14:31:14:31 | exit get_Item | MultiImplementationB.cs:12:31:12:40 | get_Item | +| MultiImplementationA.cs:15:36:15:38 | enter get_Item | MultiImplementationA.cs:15:36:15:38 | get_Item | +| MultiImplementationA.cs:15:36:15:38 | enter get_Item | MultiImplementationB.cs:13:36:13:38 | get_Item | +| MultiImplementationA.cs:15:36:15:38 | exit get_Item | MultiImplementationA.cs:15:36:15:38 | get_Item | +| MultiImplementationA.cs:15:36:15:38 | exit get_Item | MultiImplementationB.cs:13:36:13:38 | get_Item | +| MultiImplementationA.cs:15:40:15:52 | {...} | MultiImplementationA.cs:15:36:15:38 | get_Item | +| MultiImplementationA.cs:15:40:15:52 | {...} | MultiImplementationB.cs:13:36:13:38 | get_Item | +| MultiImplementationA.cs:15:54:15:56 | enter set_Item | MultiImplementationA.cs:15:54:15:56 | set_Item | +| MultiImplementationA.cs:15:54:15:56 | enter set_Item | MultiImplementationB.cs:13:56:13:58 | set_Item | +| MultiImplementationA.cs:15:54:15:56 | exit set_Item | MultiImplementationA.cs:15:54:15:56 | set_Item | +| MultiImplementationA.cs:15:54:15:56 | exit set_Item | MultiImplementationB.cs:13:56:13:58 | set_Item | +| MultiImplementationA.cs:15:58:15:60 | {...} | MultiImplementationA.cs:15:54:15:56 | set_Item | +| MultiImplementationA.cs:15:58:15:60 | {...} | MultiImplementationB.cs:13:56:13:58 | set_Item | +| MultiImplementationA.cs:16:17:16:18 | enter M1 | MultiImplementationA.cs:16:17:16:18 | M1 | +| MultiImplementationA.cs:16:17:16:18 | enter M1 | MultiImplementationB.cs:14:17:14:18 | M1 | +| MultiImplementationA.cs:16:17:16:18 | exit M1 | MultiImplementationA.cs:16:17:16:18 | M1 | +| MultiImplementationA.cs:16:17:16:18 | exit M1 | MultiImplementationB.cs:14:17:14:18 | M1 | +| MultiImplementationA.cs:17:5:19:5 | {...} | MultiImplementationA.cs:16:17:16:18 | M1 | +| MultiImplementationA.cs:17:5:19:5 | {...} | MultiImplementationB.cs:14:17:14:18 | M1 | +| MultiImplementationA.cs:18:9:18:22 | enter M2 | MultiImplementationA.cs:18:9:18:22 | M2 | +| MultiImplementationA.cs:20:12:20:13 | enter C2 | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationA.cs:20:12:20:13 | enter C2 | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationA.cs:20:12:20:13 | exit C2 | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationA.cs:20:12:20:13 | exit C2 | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationA.cs:20:22:20:31 | {...} | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationA.cs:20:22:20:31 | {...} | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationA.cs:21:12:21:13 | enter C2 | MultiImplementationA.cs:21:12:21:13 | C2 | +| MultiImplementationA.cs:21:12:21:13 | enter C2 | MultiImplementationB.cs:19:12:19:13 | C2 | +| MultiImplementationA.cs:21:12:21:13 | exit C2 | MultiImplementationA.cs:21:12:21:13 | C2 | +| MultiImplementationA.cs:21:12:21:13 | exit C2 | MultiImplementationB.cs:19:12:19:13 | C2 | +| MultiImplementationA.cs:21:24:21:24 | 0 | MultiImplementationA.cs:21:12:21:13 | C2 | +| MultiImplementationA.cs:21:24:21:24 | 0 | MultiImplementationB.cs:19:12:19:13 | C2 | +| MultiImplementationA.cs:21:27:21:29 | {...} | MultiImplementationA.cs:21:12:21:13 | C2 | +| MultiImplementationA.cs:21:27:21:29 | {...} | MultiImplementationB.cs:19:12:19:13 | C2 | +| MultiImplementationA.cs:22:6:22:7 | enter ~C2 | MultiImplementationA.cs:22:6:22:7 | ~C2 | +| MultiImplementationA.cs:22:6:22:7 | enter ~C2 | MultiImplementationB.cs:20:6:20:7 | ~C2 | +| MultiImplementationA.cs:22:6:22:7 | exit ~C2 | MultiImplementationA.cs:22:6:22:7 | ~C2 | +| MultiImplementationA.cs:22:6:22:7 | exit ~C2 | MultiImplementationB.cs:20:6:20:7 | ~C2 | +| MultiImplementationA.cs:22:11:22:13 | {...} | MultiImplementationA.cs:22:6:22:7 | ~C2 | +| MultiImplementationA.cs:22:11:22:13 | {...} | MultiImplementationB.cs:20:6:20:7 | ~C2 | +| MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | MultiImplementationA.cs:23:28:23:35 | implicit conversion | +| MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | MultiImplementationB.cs:21:28:21:35 | implicit conversion | +| MultiImplementationA.cs:23:28:23:35 | exit implicit conversion | MultiImplementationA.cs:23:28:23:35 | implicit conversion | +| MultiImplementationA.cs:23:28:23:35 | exit implicit conversion | MultiImplementationB.cs:21:28:21:35 | implicit conversion | +| MultiImplementationA.cs:23:50:23:53 | null | MultiImplementationA.cs:23:28:23:35 | implicit conversion | +| MultiImplementationA.cs:23:50:23:53 | null | MultiImplementationB.cs:21:28:21:35 | implicit conversion | +| MultiImplementationA.cs:24:16:24:16 | this access | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationA.cs:24:16:24:16 | this access | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationA.cs:30:21:30:23 | enter get_P3 | MultiImplementationA.cs:30:21:30:23 | get_P3 | +| MultiImplementationA.cs:30:21:30:23 | enter get_P3 | MultiImplementationB.cs:27:21:27:23 | get_P3 | +| MultiImplementationA.cs:36:9:36:10 | enter M1 | MultiImplementationA.cs:36:9:36:10 | M1 | +| MultiImplementationA.cs:36:9:36:10 | enter M1 | MultiImplementationB.cs:32:9:32:10 | M1 | +| MultiImplementationA.cs:36:9:36:10 | exit M1 | MultiImplementationA.cs:36:9:36:10 | M1 | +| MultiImplementationA.cs:36:9:36:10 | exit M1 | MultiImplementationB.cs:32:9:32:10 | M1 | +| MultiImplementationA.cs:36:14:36:28 | {...} | MultiImplementationA.cs:36:9:36:10 | M1 | +| MultiImplementationA.cs:36:14:36:28 | {...} | MultiImplementationB.cs:32:9:32:10 | M1 | +| MultiImplementationA.cs:37:9:37:10 | enter M2 | MultiImplementationA.cs:37:9:37:10 | M2 | +| MultiImplementationB.cs:3:22:3:22 | 0 | MultiImplementationA.cs:6:22:6:31 | get_P1 | +| MultiImplementationB.cs:3:22:3:22 | 0 | MultiImplementationB.cs:3:22:3:22 | get_P1 | +| MultiImplementationB.cs:3:22:3:22 | enter get_P1 | MultiImplementationA.cs:6:22:6:31 | get_P1 | +| MultiImplementationB.cs:3:22:3:22 | enter get_P1 | MultiImplementationB.cs:3:22:3:22 | get_P1 | +| MultiImplementationB.cs:3:22:3:22 | exit get_P1 | MultiImplementationA.cs:6:22:6:31 | get_P1 | +| MultiImplementationB.cs:3:22:3:22 | exit get_P1 | MultiImplementationB.cs:3:22:3:22 | get_P1 | +| MultiImplementationB.cs:4:21:4:23 | enter get_P2 | MultiImplementationA.cs:7:21:7:23 | get_P2 | +| MultiImplementationB.cs:4:21:4:23 | enter get_P2 | MultiImplementationB.cs:4:21:4:23 | get_P2 | +| MultiImplementationB.cs:4:21:4:23 | exit get_P2 | MultiImplementationA.cs:7:21:7:23 | get_P2 | +| MultiImplementationB.cs:4:21:4:23 | exit get_P2 | MultiImplementationB.cs:4:21:4:23 | get_P2 | +| MultiImplementationB.cs:4:25:4:37 | {...} | MultiImplementationA.cs:7:21:7:23 | get_P2 | +| MultiImplementationB.cs:4:25:4:37 | {...} | MultiImplementationB.cs:4:21:4:23 | get_P2 | +| MultiImplementationB.cs:4:39:4:41 | enter set_P2 | MultiImplementationA.cs:7:41:7:43 | set_P2 | +| MultiImplementationB.cs:4:39:4:41 | enter set_P2 | MultiImplementationB.cs:4:39:4:41 | set_P2 | +| MultiImplementationB.cs:4:39:4:41 | exit set_P2 | MultiImplementationA.cs:7:41:7:43 | set_P2 | +| MultiImplementationB.cs:4:39:4:41 | exit set_P2 | MultiImplementationB.cs:4:39:4:41 | set_P2 | +| MultiImplementationB.cs:4:43:4:45 | {...} | MultiImplementationA.cs:7:41:7:43 | set_P2 | +| MultiImplementationB.cs:4:43:4:45 | {...} | MultiImplementationB.cs:4:39:4:41 | set_P2 | +| MultiImplementationB.cs:5:16:5:16 | enter M | MultiImplementationA.cs:8:16:8:16 | M | +| MultiImplementationB.cs:5:16:5:16 | enter M | MultiImplementationB.cs:5:16:5:16 | M | +| MultiImplementationB.cs:5:16:5:16 | exit M | MultiImplementationA.cs:8:16:8:16 | M | +| MultiImplementationB.cs:5:16:5:16 | exit M | MultiImplementationB.cs:5:16:5:16 | M | +| MultiImplementationB.cs:5:23:5:23 | 2 | MultiImplementationA.cs:8:16:8:16 | M | +| MultiImplementationB.cs:5:23:5:23 | 2 | MultiImplementationB.cs:5:16:5:16 | M | +| MultiImplementationB.cs:11:16:11:16 | this access | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationB.cs:11:16:11:16 | this access | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationB.cs:12:31:12:40 | enter get_Item | MultiImplementationA.cs:14:31:14:31 | get_Item | +| MultiImplementationB.cs:12:31:12:40 | enter get_Item | MultiImplementationB.cs:12:31:12:40 | get_Item | +| MultiImplementationB.cs:12:31:12:40 | exit get_Item | MultiImplementationA.cs:14:31:14:31 | get_Item | +| MultiImplementationB.cs:12:31:12:40 | exit get_Item | MultiImplementationB.cs:12:31:12:40 | get_Item | +| MultiImplementationB.cs:12:37:12:40 | null | MultiImplementationA.cs:14:31:14:31 | get_Item | +| MultiImplementationB.cs:12:37:12:40 | null | MultiImplementationB.cs:12:31:12:40 | get_Item | +| MultiImplementationB.cs:13:36:13:38 | enter get_Item | MultiImplementationA.cs:15:36:15:38 | get_Item | +| MultiImplementationB.cs:13:36:13:38 | enter get_Item | MultiImplementationB.cs:13:36:13:38 | get_Item | +| MultiImplementationB.cs:13:36:13:38 | exit get_Item | MultiImplementationA.cs:15:36:15:38 | get_Item | +| MultiImplementationB.cs:13:36:13:38 | exit get_Item | MultiImplementationB.cs:13:36:13:38 | get_Item | +| MultiImplementationB.cs:13:40:13:54 | {...} | MultiImplementationA.cs:15:36:15:38 | get_Item | +| MultiImplementationB.cs:13:40:13:54 | {...} | MultiImplementationB.cs:13:36:13:38 | get_Item | +| MultiImplementationB.cs:13:56:13:58 | enter set_Item | MultiImplementationA.cs:15:54:15:56 | set_Item | +| MultiImplementationB.cs:13:56:13:58 | enter set_Item | MultiImplementationB.cs:13:56:13:58 | set_Item | +| MultiImplementationB.cs:13:56:13:58 | exit set_Item | MultiImplementationA.cs:15:54:15:56 | set_Item | +| MultiImplementationB.cs:13:56:13:58 | exit set_Item | MultiImplementationB.cs:13:56:13:58 | set_Item | +| MultiImplementationB.cs:13:60:13:62 | {...} | MultiImplementationA.cs:15:54:15:56 | set_Item | +| MultiImplementationB.cs:13:60:13:62 | {...} | MultiImplementationB.cs:13:56:13:58 | set_Item | +| MultiImplementationB.cs:14:17:14:18 | enter M1 | MultiImplementationA.cs:16:17:16:18 | M1 | +| MultiImplementationB.cs:14:17:14:18 | enter M1 | MultiImplementationB.cs:14:17:14:18 | M1 | +| MultiImplementationB.cs:14:17:14:18 | exit M1 | MultiImplementationA.cs:16:17:16:18 | M1 | +| MultiImplementationB.cs:14:17:14:18 | exit M1 | MultiImplementationB.cs:14:17:14:18 | M1 | +| MultiImplementationB.cs:15:5:17:5 | {...} | MultiImplementationA.cs:16:17:16:18 | M1 | +| MultiImplementationB.cs:15:5:17:5 | {...} | MultiImplementationB.cs:14:17:14:18 | M1 | +| MultiImplementationB.cs:16:9:16:31 | enter M2 | MultiImplementationB.cs:16:9:16:31 | M2 | +| MultiImplementationB.cs:18:12:18:13 | enter C2 | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationB.cs:18:12:18:13 | enter C2 | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationB.cs:18:12:18:13 | exit C2 | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationB.cs:18:12:18:13 | exit C2 | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationB.cs:18:22:18:36 | {...} | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationB.cs:18:22:18:36 | {...} | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationB.cs:19:12:19:13 | enter C2 | MultiImplementationA.cs:21:12:21:13 | C2 | +| MultiImplementationB.cs:19:12:19:13 | enter C2 | MultiImplementationB.cs:19:12:19:13 | C2 | +| MultiImplementationB.cs:19:12:19:13 | exit C2 | MultiImplementationA.cs:21:12:21:13 | C2 | +| MultiImplementationB.cs:19:12:19:13 | exit C2 | MultiImplementationB.cs:19:12:19:13 | C2 | +| MultiImplementationB.cs:19:24:19:24 | 1 | MultiImplementationA.cs:21:12:21:13 | C2 | +| MultiImplementationB.cs:19:24:19:24 | 1 | MultiImplementationB.cs:19:12:19:13 | C2 | +| MultiImplementationB.cs:19:27:19:29 | {...} | MultiImplementationA.cs:21:12:21:13 | C2 | +| MultiImplementationB.cs:19:27:19:29 | {...} | MultiImplementationB.cs:19:12:19:13 | C2 | +| MultiImplementationB.cs:20:6:20:7 | enter ~C2 | MultiImplementationA.cs:22:6:22:7 | ~C2 | +| MultiImplementationB.cs:20:6:20:7 | enter ~C2 | MultiImplementationB.cs:20:6:20:7 | ~C2 | +| MultiImplementationB.cs:20:6:20:7 | exit ~C2 | MultiImplementationA.cs:22:6:22:7 | ~C2 | +| MultiImplementationB.cs:20:6:20:7 | exit ~C2 | MultiImplementationB.cs:20:6:20:7 | ~C2 | +| MultiImplementationB.cs:20:11:20:25 | {...} | MultiImplementationA.cs:22:6:22:7 | ~C2 | +| MultiImplementationB.cs:20:11:20:25 | {...} | MultiImplementationB.cs:20:6:20:7 | ~C2 | +| MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | MultiImplementationA.cs:23:28:23:35 | implicit conversion | +| MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | MultiImplementationB.cs:21:28:21:35 | implicit conversion | +| MultiImplementationB.cs:21:28:21:35 | exit implicit conversion | MultiImplementationA.cs:23:28:23:35 | implicit conversion | +| MultiImplementationB.cs:21:28:21:35 | exit implicit conversion | MultiImplementationB.cs:21:28:21:35 | implicit conversion | +| MultiImplementationB.cs:21:56:21:59 | null | MultiImplementationA.cs:23:28:23:35 | implicit conversion | +| MultiImplementationB.cs:21:56:21:59 | null | MultiImplementationB.cs:21:28:21:35 | implicit conversion | +| MultiImplementationB.cs:22:16:22:16 | this access | MultiImplementationA.cs:20:12:20:13 | C2 | +| MultiImplementationB.cs:22:16:22:16 | this access | MultiImplementationB.cs:18:12:18:13 | C2 | +| MultiImplementationB.cs:27:21:27:23 | enter get_P3 | MultiImplementationA.cs:30:21:30:23 | get_P3 | +| MultiImplementationB.cs:27:21:27:23 | enter get_P3 | MultiImplementationB.cs:27:21:27:23 | get_P3 | +| MultiImplementationB.cs:32:9:32:10 | enter M1 | MultiImplementationA.cs:36:9:36:10 | M1 | +| MultiImplementationB.cs:32:9:32:10 | enter M1 | MultiImplementationB.cs:32:9:32:10 | M1 | +| MultiImplementationB.cs:32:9:32:10 | exit M1 | MultiImplementationA.cs:36:9:36:10 | M1 | +| MultiImplementationB.cs:32:9:32:10 | exit M1 | MultiImplementationB.cs:32:9:32:10 | M1 | +| MultiImplementationB.cs:32:17:32:17 | 0 | MultiImplementationA.cs:36:9:36:10 | M1 | +| MultiImplementationB.cs:32:17:32:17 | 0 | MultiImplementationB.cs:32:9:32:10 | M1 | | NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:9:3:10 | M1 | | NullCoalescing.cs:3:9:3:10 | exit M1 | NullCoalescing.cs:3:9:3:10 | M1 | | NullCoalescing.cs:3:28:3:28 | 0 | NullCoalescing.cs:3:9:3:10 | M1 | @@ -3821,35 +5031,35 @@ blockEnclosing | Switch.cs:55:10:55:11 | enter M5 | Switch.cs:55:10:55:11 | M5 | | Switch.cs:66:10:66:11 | enter M6 | Switch.cs:66:10:66:11 | M6 | | Switch.cs:66:10:66:11 | exit M6 | Switch.cs:66:10:66:11 | M6 | -| Switch.cs:73:15:73:20 | break; | Switch.cs:66:10:66:11 | M6 | +| Switch.cs:73:17:73:22 | break; | Switch.cs:66:10:66:11 | M6 | | Switch.cs:77:10:77:11 | enter M7 | Switch.cs:77:10:77:11 | M7 | | Switch.cs:77:10:77:11 | exit M7 | Switch.cs:77:10:77:11 | M7 | -| Switch.cs:82:22:82:25 | true | Switch.cs:77:10:77:11 | M7 | -| Switch.cs:83:13:83:20 | case ...: | Switch.cs:77:10:77:11 | M7 | -| Switch.cs:84:15:85:22 | if (...) ... | Switch.cs:77:10:77:11 | M7 | -| Switch.cs:85:17:85:22 | break; | Switch.cs:77:10:77:11 | M7 | -| Switch.cs:86:22:86:25 | true | Switch.cs:77:10:77:11 | M7 | +| Switch.cs:82:24:82:27 | true | Switch.cs:77:10:77:11 | M7 | +| Switch.cs:83:13:83:19 | case ...: | Switch.cs:77:10:77:11 | M7 | +| Switch.cs:84:17:85:26 | if (...) ... | Switch.cs:77:10:77:11 | M7 | +| Switch.cs:85:21:85:26 | break; | Switch.cs:77:10:77:11 | M7 | +| Switch.cs:86:24:86:27 | true | Switch.cs:77:10:77:11 | M7 | | Switch.cs:88:16:88:20 | false | Switch.cs:77:10:77:11 | M7 | | Switch.cs:91:10:91:11 | enter M8 | Switch.cs:91:10:91:11 | M8 | | Switch.cs:91:10:91:11 | exit M8 | Switch.cs:91:10:91:11 | M8 | -| Switch.cs:96:22:96:25 | true | Switch.cs:91:10:91:11 | M8 | +| Switch.cs:96:24:96:27 | true | Switch.cs:91:10:91:11 | M8 | | Switch.cs:98:16:98:20 | false | Switch.cs:91:10:91:11 | M8 | | Switch.cs:101:9:101:10 | enter M9 | Switch.cs:101:9:101:10 | M9 | | Switch.cs:101:9:101:10 | exit M9 | Switch.cs:101:9:101:10 | M9 | | Switch.cs:103:19:103:25 | access to property Length | Switch.cs:101:9:101:10 | M9 | -| Switch.cs:105:13:105:20 | case ...: | Switch.cs:101:9:101:10 | M9 | -| Switch.cs:105:29:105:29 | 0 | Switch.cs:101:9:101:10 | M9 | -| Switch.cs:106:13:106:20 | case ...: | Switch.cs:101:9:101:10 | M9 | -| Switch.cs:106:29:106:29 | 1 | Switch.cs:101:9:101:10 | M9 | +| Switch.cs:105:13:105:19 | case ...: | Switch.cs:101:9:101:10 | M9 | +| Switch.cs:105:28:105:28 | 0 | Switch.cs:101:9:101:10 | M9 | +| Switch.cs:106:13:106:19 | case ...: | Switch.cs:101:9:101:10 | M9 | +| Switch.cs:106:28:106:28 | 1 | Switch.cs:101:9:101:10 | M9 | | Switch.cs:108:17:108:17 | 1 | Switch.cs:101:9:101:10 | M9 | | Switch.cs:111:17:111:21 | enter Throw | Switch.cs:111:17:111:21 | Throw | | Switch.cs:113:9:113:11 | enter M10 | Switch.cs:113:9:113:11 | M10 | | Switch.cs:113:9:113:11 | exit M10 | Switch.cs:113:9:113:11 | M10 | | Switch.cs:117:25:117:25 | access to parameter s | Switch.cs:113:9:113:11 | M10 | -| Switch.cs:117:43:117:43 | 1 | Switch.cs:113:9:113:11 | M10 | -| Switch.cs:118:13:118:33 | case ...: | Switch.cs:113:9:113:11 | M10 | +| Switch.cs:117:44:117:44 | 1 | Switch.cs:113:9:113:11 | M10 | +| Switch.cs:118:13:118:34 | case ...: | Switch.cs:113:9:113:11 | M10 | | Switch.cs:118:25:118:25 | access to parameter s | Switch.cs:113:9:113:11 | M10 | -| Switch.cs:118:42:118:42 | 2 | Switch.cs:113:9:113:11 | M10 | +| Switch.cs:118:43:118:43 | 2 | Switch.cs:113:9:113:11 | M10 | | Switch.cs:120:17:120:17 | 1 | Switch.cs:113:9:113:11 | M10 | | Switch.cs:123:10:123:12 | enter M11 | Switch.cs:123:10:123:12 | M11 | | Switch.cs:123:10:123:12 | exit M11 | Switch.cs:123:10:123:12 | M11 | @@ -3873,6 +5083,14 @@ blockEnclosing | Switch.cs:149:13:149:20 | default: | Switch.cs:144:9:144:11 | M14 | | Switch.cs:150:13:150:19 | case ...: | Switch.cs:144:9:144:11 | M14 | | Switch.cs:150:28:150:28 | 2 | Switch.cs:144:9:144:11 | M14 | +| Switch.cs:154:10:154:12 | enter M15 | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:154:10:154:12 | exit M15 | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:156:13:156:54 | String s = ... | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:156:36:156:38 | "a" | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:156:41:156:52 | ... => ... | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:156:50:156:52 | "b" | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:158:13:158:49 | ...; | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:160:13:160:49 | ...; | Switch.cs:154:10:154:12 | M15 | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:3:10:3:10 | M | | TypeAccesses.cs:7:25:7:25 | ; | TypeAccesses.cs:3:10:3:10 | M | | TypeAccesses.cs:8:9:8:28 | ... ...; | TypeAccesses.cs:3:10:3:10 | M | diff --git a/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected b/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected index 4cc60894d75b..a001b9b54178 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected @@ -293,13 +293,13 @@ | ArrayCreation.cs:5:28:5:28 | 0 | ArrayCreation.cs:5:28:5:28 | 0 | | ArrayCreation.cs:5:31:5:31 | 1 | ArrayCreation.cs:5:31:5:31 | 1 | | ArrayCreation.cs:7:19:7:36 | 2 | ArrayCreation.cs:7:19:7:36 | 2 | -| ArrayCreation.cs:7:19:7:36 | array creation of type Int32[] | ArrayCreation.cs:7:19:7:36 | array creation of type Int32[] | +| ArrayCreation.cs:7:19:7:36 | array creation of type Int32[] | ArrayCreation.cs:7:19:7:36 | 2 | | ArrayCreation.cs:7:29:7:36 | { ..., ... } | ArrayCreation.cs:7:31:7:31 | 0 | | ArrayCreation.cs:7:31:7:31 | 0 | ArrayCreation.cs:7:31:7:31 | 0 | | ArrayCreation.cs:7:34:7:34 | 1 | ArrayCreation.cs:7:34:7:34 | 1 | | ArrayCreation.cs:9:20:9:52 | 2 | ArrayCreation.cs:9:20:9:52 | 2 | | ArrayCreation.cs:9:20:9:52 | 2 | ArrayCreation.cs:9:20:9:52 | 2 | -| ArrayCreation.cs:9:20:9:52 | array creation of type Int32[,] | ArrayCreation.cs:9:20:9:52 | array creation of type Int32[,] | +| ArrayCreation.cs:9:20:9:52 | array creation of type Int32[,] | ArrayCreation.cs:9:20:9:52 | 2 | | ArrayCreation.cs:9:31:9:52 | { ..., ... } | ArrayCreation.cs:9:35:9:35 | 0 | | ArrayCreation.cs:9:33:9:40 | { ..., ... } | ArrayCreation.cs:9:35:9:35 | 0 | | ArrayCreation.cs:9:35:9:35 | 0 | ArrayCreation.cs:9:35:9:35 | 0 | @@ -307,6 +307,358 @@ | ArrayCreation.cs:9:43:9:50 | { ..., ... } | ArrayCreation.cs:9:45:9:45 | 2 | | ArrayCreation.cs:9:45:9:45 | 2 | ArrayCreation.cs:9:45:9:45 | 2 | | ArrayCreation.cs:9:48:9:48 | 3 | ArrayCreation.cs:9:48:9:48 | 3 | +| Assert.cs:8:5:12:5 | {...} | Assert.cs:8:5:12:5 | {...} | +| Assert.cs:9:9:9:33 | ... ...; | Assert.cs:9:9:9:33 | ... ...; | +| Assert.cs:9:16:9:32 | String s = ... | Assert.cs:9:20:9:32 | ... ? ... : ... | +| Assert.cs:9:20:9:20 | access to parameter b | Assert.cs:9:20:9:20 | access to parameter b | +| Assert.cs:9:20:9:32 | ... ? ... : ... | Assert.cs:9:20:9:32 | ... ? ... : ... | +| Assert.cs:9:24:9:27 | null | Assert.cs:9:24:9:27 | null | +| Assert.cs:9:31:9:32 | "" | Assert.cs:9:31:9:32 | "" | +| Assert.cs:10:9:10:31 | call to method Assert | Assert.cs:10:22:10:22 | access to local variable s | +| Assert.cs:10:9:10:32 | ...; | Assert.cs:10:9:10:32 | ...; | +| Assert.cs:10:22:10:22 | access to local variable s | Assert.cs:10:22:10:22 | access to local variable s | +| Assert.cs:10:22:10:30 | ... != ... | Assert.cs:10:22:10:22 | access to local variable s | +| Assert.cs:10:27:10:30 | null | Assert.cs:10:27:10:30 | null | +| Assert.cs:11:9:11:35 | call to method WriteLine | Assert.cs:11:27:11:27 | access to local variable s | +| Assert.cs:11:9:11:36 | ...; | Assert.cs:11:9:11:36 | ...; | +| Assert.cs:11:27:11:27 | access to local variable s | Assert.cs:11:27:11:27 | access to local variable s | +| Assert.cs:11:27:11:34 | access to property Length | Assert.cs:11:27:11:27 | access to local variable s | +| Assert.cs:15:5:19:5 | {...} | Assert.cs:15:5:19:5 | {...} | +| Assert.cs:16:9:16:33 | ... ...; | Assert.cs:16:9:16:33 | ... ...; | +| Assert.cs:16:16:16:32 | String s = ... | Assert.cs:16:20:16:32 | ... ? ... : ... | +| Assert.cs:16:20:16:20 | access to parameter b | Assert.cs:16:20:16:20 | access to parameter b | +| Assert.cs:16:20:16:32 | ... ? ... : ... | Assert.cs:16:20:16:32 | ... ? ... : ... | +| Assert.cs:16:24:16:27 | null | Assert.cs:16:24:16:27 | null | +| Assert.cs:16:31:16:32 | "" | Assert.cs:16:31:16:32 | "" | +| Assert.cs:17:9:17:24 | call to method IsNull | Assert.cs:17:23:17:23 | access to local variable s | +| Assert.cs:17:9:17:25 | ...; | Assert.cs:17:9:17:25 | ...; | +| Assert.cs:17:23:17:23 | access to local variable s | Assert.cs:17:23:17:23 | access to local variable s | +| Assert.cs:18:9:18:35 | call to method WriteLine | Assert.cs:18:27:18:27 | access to local variable s | +| Assert.cs:18:9:18:36 | ...; | Assert.cs:18:9:18:36 | ...; | +| Assert.cs:18:27:18:27 | access to local variable s | Assert.cs:18:27:18:27 | access to local variable s | +| Assert.cs:18:27:18:34 | access to property Length | Assert.cs:18:27:18:27 | access to local variable s | +| Assert.cs:22:5:26:5 | {...} | Assert.cs:22:5:26:5 | {...} | +| Assert.cs:23:9:23:33 | ... ...; | Assert.cs:23:9:23:33 | ... ...; | +| Assert.cs:23:16:23:32 | String s = ... | Assert.cs:23:20:23:32 | ... ? ... : ... | +| Assert.cs:23:20:23:20 | access to parameter b | Assert.cs:23:20:23:20 | access to parameter b | +| Assert.cs:23:20:23:32 | ... ? ... : ... | Assert.cs:23:20:23:32 | ... ? ... : ... | +| Assert.cs:23:24:23:27 | null | Assert.cs:23:24:23:27 | null | +| Assert.cs:23:31:23:32 | "" | Assert.cs:23:31:23:32 | "" | +| Assert.cs:24:9:24:27 | call to method IsNotNull | Assert.cs:24:26:24:26 | access to local variable s | +| Assert.cs:24:9:24:28 | ...; | Assert.cs:24:9:24:28 | ...; | +| Assert.cs:24:26:24:26 | access to local variable s | Assert.cs:24:26:24:26 | access to local variable s | +| Assert.cs:25:9:25:35 | call to method WriteLine | Assert.cs:25:27:25:27 | access to local variable s | +| Assert.cs:25:9:25:36 | ...; | Assert.cs:25:9:25:36 | ...; | +| Assert.cs:25:27:25:27 | access to local variable s | Assert.cs:25:27:25:27 | access to local variable s | +| Assert.cs:25:27:25:34 | access to property Length | Assert.cs:25:27:25:27 | access to local variable s | +| Assert.cs:29:5:33:5 | {...} | Assert.cs:29:5:33:5 | {...} | +| Assert.cs:30:9:30:33 | ... ...; | Assert.cs:30:9:30:33 | ... ...; | +| Assert.cs:30:16:30:32 | String s = ... | Assert.cs:30:20:30:32 | ... ? ... : ... | +| Assert.cs:30:20:30:20 | access to parameter b | Assert.cs:30:20:30:20 | access to parameter b | +| Assert.cs:30:20:30:32 | ... ? ... : ... | Assert.cs:30:20:30:32 | ... ? ... : ... | +| Assert.cs:30:24:30:27 | null | Assert.cs:30:24:30:27 | null | +| Assert.cs:30:31:30:32 | "" | Assert.cs:30:31:30:32 | "" | +| Assert.cs:31:9:31:32 | call to method IsTrue | Assert.cs:31:23:31:23 | access to local variable s | +| Assert.cs:31:9:31:33 | ...; | Assert.cs:31:9:31:33 | ...; | +| Assert.cs:31:23:31:23 | access to local variable s | Assert.cs:31:23:31:23 | access to local variable s | +| Assert.cs:31:23:31:31 | ... == ... | Assert.cs:31:23:31:23 | access to local variable s | +| Assert.cs:31:28:31:31 | null | Assert.cs:31:28:31:31 | null | +| Assert.cs:32:9:32:35 | call to method WriteLine | Assert.cs:32:27:32:27 | access to local variable s | +| Assert.cs:32:9:32:36 | ...; | Assert.cs:32:9:32:36 | ...; | +| Assert.cs:32:27:32:27 | access to local variable s | Assert.cs:32:27:32:27 | access to local variable s | +| Assert.cs:32:27:32:34 | access to property Length | Assert.cs:32:27:32:27 | access to local variable s | +| Assert.cs:36:5:40:5 | {...} | Assert.cs:36:5:40:5 | {...} | +| Assert.cs:37:9:37:33 | ... ...; | Assert.cs:37:9:37:33 | ... ...; | +| Assert.cs:37:16:37:32 | String s = ... | Assert.cs:37:20:37:32 | ... ? ... : ... | +| Assert.cs:37:20:37:20 | access to parameter b | Assert.cs:37:20:37:20 | access to parameter b | +| Assert.cs:37:20:37:32 | ... ? ... : ... | Assert.cs:37:20:37:32 | ... ? ... : ... | +| Assert.cs:37:24:37:27 | null | Assert.cs:37:24:37:27 | null | +| Assert.cs:37:31:37:32 | "" | Assert.cs:37:31:37:32 | "" | +| Assert.cs:38:9:38:32 | call to method IsTrue | Assert.cs:38:23:38:23 | access to local variable s | +| Assert.cs:38:9:38:33 | ...; | Assert.cs:38:9:38:33 | ...; | +| Assert.cs:38:23:38:23 | access to local variable s | Assert.cs:38:23:38:23 | access to local variable s | +| Assert.cs:38:23:38:31 | ... != ... | Assert.cs:38:23:38:23 | access to local variable s | +| Assert.cs:38:28:38:31 | null | Assert.cs:38:28:38:31 | null | +| Assert.cs:39:9:39:35 | call to method WriteLine | Assert.cs:39:27:39:27 | access to local variable s | +| Assert.cs:39:9:39:36 | ...; | Assert.cs:39:9:39:36 | ...; | +| Assert.cs:39:27:39:27 | access to local variable s | Assert.cs:39:27:39:27 | access to local variable s | +| Assert.cs:39:27:39:34 | access to property Length | Assert.cs:39:27:39:27 | access to local variable s | +| Assert.cs:43:5:47:5 | {...} | Assert.cs:43:5:47:5 | {...} | +| Assert.cs:44:9:44:33 | ... ...; | Assert.cs:44:9:44:33 | ... ...; | +| Assert.cs:44:16:44:32 | String s = ... | Assert.cs:44:20:44:32 | ... ? ... : ... | +| Assert.cs:44:20:44:20 | access to parameter b | Assert.cs:44:20:44:20 | access to parameter b | +| Assert.cs:44:20:44:32 | ... ? ... : ... | Assert.cs:44:20:44:32 | ... ? ... : ... | +| Assert.cs:44:24:44:27 | null | Assert.cs:44:24:44:27 | null | +| Assert.cs:44:31:44:32 | "" | Assert.cs:44:31:44:32 | "" | +| Assert.cs:45:9:45:33 | call to method IsFalse | Assert.cs:45:24:45:24 | access to local variable s | +| Assert.cs:45:9:45:34 | ...; | Assert.cs:45:9:45:34 | ...; | +| Assert.cs:45:24:45:24 | access to local variable s | Assert.cs:45:24:45:24 | access to local variable s | +| Assert.cs:45:24:45:32 | ... != ... | Assert.cs:45:24:45:24 | access to local variable s | +| Assert.cs:45:29:45:32 | null | Assert.cs:45:29:45:32 | null | +| Assert.cs:46:9:46:35 | call to method WriteLine | Assert.cs:46:27:46:27 | access to local variable s | +| Assert.cs:46:9:46:36 | ...; | Assert.cs:46:9:46:36 | ...; | +| Assert.cs:46:27:46:27 | access to local variable s | Assert.cs:46:27:46:27 | access to local variable s | +| Assert.cs:46:27:46:34 | access to property Length | Assert.cs:46:27:46:27 | access to local variable s | +| Assert.cs:50:5:54:5 | {...} | Assert.cs:50:5:54:5 | {...} | +| Assert.cs:51:9:51:33 | ... ...; | Assert.cs:51:9:51:33 | ... ...; | +| Assert.cs:51:16:51:32 | String s = ... | Assert.cs:51:20:51:32 | ... ? ... : ... | +| Assert.cs:51:20:51:20 | access to parameter b | Assert.cs:51:20:51:20 | access to parameter b | +| Assert.cs:51:20:51:32 | ... ? ... : ... | Assert.cs:51:20:51:32 | ... ? ... : ... | +| Assert.cs:51:24:51:27 | null | Assert.cs:51:24:51:27 | null | +| Assert.cs:51:31:51:32 | "" | Assert.cs:51:31:51:32 | "" | +| Assert.cs:52:9:52:33 | call to method IsFalse | Assert.cs:52:24:52:24 | access to local variable s | +| Assert.cs:52:9:52:34 | ...; | Assert.cs:52:9:52:34 | ...; | +| Assert.cs:52:24:52:24 | access to local variable s | Assert.cs:52:24:52:24 | access to local variable s | +| Assert.cs:52:24:52:32 | ... == ... | Assert.cs:52:24:52:24 | access to local variable s | +| Assert.cs:52:29:52:32 | null | Assert.cs:52:29:52:32 | null | +| Assert.cs:53:9:53:35 | call to method WriteLine | Assert.cs:53:27:53:27 | access to local variable s | +| Assert.cs:53:9:53:36 | ...; | Assert.cs:53:9:53:36 | ...; | +| Assert.cs:53:27:53:27 | access to local variable s | Assert.cs:53:27:53:27 | access to local variable s | +| Assert.cs:53:27:53:34 | access to property Length | Assert.cs:53:27:53:27 | access to local variable s | +| Assert.cs:57:5:61:5 | {...} | Assert.cs:57:5:61:5 | {...} | +| Assert.cs:58:9:58:33 | ... ...; | Assert.cs:58:9:58:33 | ... ...; | +| Assert.cs:58:16:58:32 | String s = ... | Assert.cs:58:20:58:32 | ... ? ... : ... | +| Assert.cs:58:20:58:20 | access to parameter b | Assert.cs:58:20:58:20 | access to parameter b | +| Assert.cs:58:20:58:32 | ... ? ... : ... | Assert.cs:58:20:58:32 | ... ? ... : ... | +| Assert.cs:58:24:58:27 | null | Assert.cs:58:24:58:27 | null | +| Assert.cs:58:31:58:32 | "" | Assert.cs:58:31:58:32 | "" | +| Assert.cs:59:9:59:37 | call to method IsTrue | Assert.cs:59:23:59:36 | ... && ... | +| Assert.cs:59:9:59:38 | ...; | Assert.cs:59:9:59:38 | ...; | +| Assert.cs:59:23:59:23 | access to local variable s | Assert.cs:59:23:59:23 | access to local variable s | +| Assert.cs:59:23:59:31 | ... != ... | Assert.cs:59:23:59:23 | access to local variable s | +| Assert.cs:59:23:59:36 | ... && ... | Assert.cs:59:23:59:36 | ... && ... | +| Assert.cs:59:28:59:31 | null | Assert.cs:59:28:59:31 | null | +| Assert.cs:59:36:59:36 | access to parameter b | Assert.cs:59:36:59:36 | access to parameter b | +| Assert.cs:60:9:60:35 | call to method WriteLine | Assert.cs:60:27:60:27 | access to local variable s | +| Assert.cs:60:9:60:36 | ...; | Assert.cs:60:9:60:36 | ...; | +| Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:60:27:60:27 | access to local variable s | +| Assert.cs:60:27:60:34 | access to property Length | Assert.cs:60:27:60:27 | access to local variable s | +| Assert.cs:64:5:68:5 | {...} | Assert.cs:64:5:68:5 | {...} | +| Assert.cs:65:9:65:33 | ... ...; | Assert.cs:65:9:65:33 | ... ...; | +| Assert.cs:65:16:65:32 | String s = ... | Assert.cs:65:20:65:32 | ... ? ... : ... | +| Assert.cs:65:20:65:20 | access to parameter b | Assert.cs:65:20:65:20 | access to parameter b | +| Assert.cs:65:20:65:32 | ... ? ... : ... | Assert.cs:65:20:65:32 | ... ? ... : ... | +| Assert.cs:65:24:65:27 | null | Assert.cs:65:24:65:27 | null | +| Assert.cs:65:31:65:32 | "" | Assert.cs:65:31:65:32 | "" | +| Assert.cs:66:9:66:38 | call to method IsFalse | Assert.cs:66:24:66:37 | ... \|\| ... | +| Assert.cs:66:9:66:39 | ...; | Assert.cs:66:9:66:39 | ...; | +| Assert.cs:66:24:66:24 | access to local variable s | Assert.cs:66:24:66:24 | access to local variable s | +| Assert.cs:66:24:66:32 | ... == ... | Assert.cs:66:24:66:24 | access to local variable s | +| Assert.cs:66:24:66:37 | ... \|\| ... | Assert.cs:66:24:66:37 | ... \|\| ... | +| Assert.cs:66:29:66:32 | null | Assert.cs:66:29:66:32 | null | +| Assert.cs:66:37:66:37 | access to parameter b | Assert.cs:66:37:66:37 | access to parameter b | +| Assert.cs:67:9:67:35 | call to method WriteLine | Assert.cs:67:27:67:27 | access to local variable s | +| Assert.cs:67:9:67:36 | ...; | Assert.cs:67:9:67:36 | ...; | +| Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:67:27:67:27 | access to local variable s | +| Assert.cs:67:27:67:34 | access to property Length | Assert.cs:67:27:67:27 | access to local variable s | +| Assert.cs:71:5:75:5 | {...} | Assert.cs:71:5:75:5 | {...} | +| Assert.cs:72:9:72:33 | ... ...; | Assert.cs:72:9:72:33 | ... ...; | +| Assert.cs:72:16:72:32 | String s = ... | Assert.cs:72:20:72:32 | ... ? ... : ... | +| Assert.cs:72:20:72:20 | access to parameter b | Assert.cs:72:20:72:20 | access to parameter b | +| Assert.cs:72:20:72:32 | ... ? ... : ... | Assert.cs:72:20:72:32 | ... ? ... : ... | +| Assert.cs:72:24:72:27 | null | Assert.cs:72:24:72:27 | null | +| Assert.cs:72:31:72:32 | "" | Assert.cs:72:31:72:32 | "" | +| Assert.cs:73:9:73:37 | call to method IsTrue | Assert.cs:73:23:73:36 | ... && ... | +| Assert.cs:73:9:73:38 | ...; | Assert.cs:73:9:73:38 | ...; | +| Assert.cs:73:23:73:23 | access to local variable s | Assert.cs:73:23:73:23 | access to local variable s | +| Assert.cs:73:23:73:31 | ... == ... | Assert.cs:73:23:73:23 | access to local variable s | +| Assert.cs:73:23:73:36 | ... && ... | Assert.cs:73:23:73:36 | ... && ... | +| Assert.cs:73:28:73:31 | null | Assert.cs:73:28:73:31 | null | +| Assert.cs:73:36:73:36 | access to parameter b | Assert.cs:73:36:73:36 | access to parameter b | +| Assert.cs:74:9:74:35 | call to method WriteLine | Assert.cs:74:27:74:27 | access to local variable s | +| Assert.cs:74:9:74:36 | ...; | Assert.cs:74:9:74:36 | ...; | +| Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:74:27:74:27 | access to local variable s | +| Assert.cs:74:27:74:34 | access to property Length | Assert.cs:74:27:74:27 | access to local variable s | +| Assert.cs:78:5:82:5 | {...} | Assert.cs:78:5:82:5 | {...} | +| Assert.cs:79:9:79:33 | ... ...; | Assert.cs:79:9:79:33 | ... ...; | +| Assert.cs:79:16:79:32 | String s = ... | Assert.cs:79:20:79:32 | ... ? ... : ... | +| Assert.cs:79:20:79:20 | access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | +| Assert.cs:79:20:79:32 | ... ? ... : ... | Assert.cs:79:20:79:32 | ... ? ... : ... | +| Assert.cs:79:24:79:27 | null | Assert.cs:79:24:79:27 | null | +| Assert.cs:79:31:79:32 | "" | Assert.cs:79:31:79:32 | "" | +| Assert.cs:80:9:80:38 | call to method IsFalse | Assert.cs:80:24:80:37 | ... \|\| ... | +| Assert.cs:80:9:80:39 | ...; | Assert.cs:80:9:80:39 | ...; | +| Assert.cs:80:24:80:24 | access to local variable s | Assert.cs:80:24:80:24 | access to local variable s | +| Assert.cs:80:24:80:32 | ... != ... | Assert.cs:80:24:80:24 | access to local variable s | +| Assert.cs:80:24:80:37 | ... \|\| ... | Assert.cs:80:24:80:37 | ... \|\| ... | +| Assert.cs:80:29:80:32 | null | Assert.cs:80:29:80:32 | null | +| Assert.cs:80:37:80:37 | access to parameter b | Assert.cs:80:37:80:37 | access to parameter b | +| Assert.cs:81:9:81:35 | call to method WriteLine | Assert.cs:81:27:81:27 | access to local variable s | +| Assert.cs:81:9:81:36 | ...; | Assert.cs:81:9:81:36 | ...; | +| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:81:27:81:27 | access to local variable s | +| Assert.cs:81:27:81:34 | access to property Length | Assert.cs:81:27:81:27 | access to local variable s | +| Assert.cs:85:5:129:5 | {...} | Assert.cs:85:5:129:5 | {...} | +| Assert.cs:86:9:86:33 | ... ...; | Assert.cs:86:9:86:33 | ... ...; | +| Assert.cs:86:16:86:32 | String s = ... | Assert.cs:86:20:86:32 | ... ? ... : ... | +| Assert.cs:86:20:86:20 | access to parameter b | Assert.cs:86:20:86:20 | access to parameter b | +| Assert.cs:86:20:86:32 | ... ? ... : ... | Assert.cs:86:20:86:32 | ... ? ... : ... | +| Assert.cs:86:24:86:27 | null | Assert.cs:86:24:86:27 | null | +| Assert.cs:86:31:86:32 | "" | Assert.cs:86:31:86:32 | "" | +| Assert.cs:87:9:87:31 | call to method Assert | Assert.cs:87:22:87:22 | access to local variable s | +| Assert.cs:87:9:87:32 | ...; | Assert.cs:87:9:87:32 | ...; | +| Assert.cs:87:22:87:22 | access to local variable s | Assert.cs:87:22:87:22 | access to local variable s | +| Assert.cs:87:22:87:30 | ... != ... | Assert.cs:87:22:87:22 | access to local variable s | +| Assert.cs:87:27:87:30 | null | Assert.cs:87:27:87:30 | null | +| Assert.cs:88:9:88:35 | call to method WriteLine | Assert.cs:88:27:88:27 | access to local variable s | +| Assert.cs:88:9:88:36 | ...; | Assert.cs:88:9:88:36 | ...; | +| Assert.cs:88:27:88:27 | access to local variable s | Assert.cs:88:27:88:27 | access to local variable s | +| Assert.cs:88:27:88:34 | access to property Length | Assert.cs:88:27:88:27 | access to local variable s | +| Assert.cs:90:9:90:25 | ... = ... | Assert.cs:90:13:90:25 | ... ? ... : ... | +| Assert.cs:90:9:90:26 | ...; | Assert.cs:90:9:90:26 | ...; | +| Assert.cs:90:13:90:13 | access to parameter b | Assert.cs:90:13:90:13 | access to parameter b | +| Assert.cs:90:13:90:25 | ... ? ... : ... | Assert.cs:90:13:90:25 | ... ? ... : ... | +| Assert.cs:90:17:90:20 | null | Assert.cs:90:17:90:20 | null | +| Assert.cs:90:24:90:25 | "" | Assert.cs:90:24:90:25 | "" | +| Assert.cs:91:9:91:24 | call to method IsNull | Assert.cs:91:23:91:23 | access to local variable s | +| Assert.cs:91:9:91:25 | ...; | Assert.cs:91:9:91:25 | ...; | +| Assert.cs:91:23:91:23 | access to local variable s | Assert.cs:91:23:91:23 | access to local variable s | +| Assert.cs:92:9:92:35 | call to method WriteLine | Assert.cs:92:27:92:27 | access to local variable s | +| Assert.cs:92:9:92:36 | ...; | Assert.cs:92:9:92:36 | ...; | +| Assert.cs:92:27:92:27 | access to local variable s | Assert.cs:92:27:92:27 | access to local variable s | +| Assert.cs:92:27:92:34 | access to property Length | Assert.cs:92:27:92:27 | access to local variable s | +| Assert.cs:94:9:94:25 | ... = ... | Assert.cs:94:13:94:25 | ... ? ... : ... | +| Assert.cs:94:9:94:26 | ...; | Assert.cs:94:9:94:26 | ...; | +| Assert.cs:94:13:94:13 | access to parameter b | Assert.cs:94:13:94:13 | access to parameter b | +| Assert.cs:94:13:94:25 | ... ? ... : ... | Assert.cs:94:13:94:25 | ... ? ... : ... | +| Assert.cs:94:17:94:20 | null | Assert.cs:94:17:94:20 | null | +| Assert.cs:94:24:94:25 | "" | Assert.cs:94:24:94:25 | "" | +| Assert.cs:95:9:95:27 | call to method IsNotNull | Assert.cs:95:26:95:26 | access to local variable s | +| Assert.cs:95:9:95:28 | ...; | Assert.cs:95:9:95:28 | ...; | +| Assert.cs:95:26:95:26 | access to local variable s | Assert.cs:95:26:95:26 | access to local variable s | +| Assert.cs:96:9:96:35 | call to method WriteLine | Assert.cs:96:27:96:27 | access to local variable s | +| Assert.cs:96:9:96:36 | ...; | Assert.cs:96:9:96:36 | ...; | +| Assert.cs:96:27:96:27 | access to local variable s | Assert.cs:96:27:96:27 | access to local variable s | +| Assert.cs:96:27:96:34 | access to property Length | Assert.cs:96:27:96:27 | access to local variable s | +| Assert.cs:98:9:98:25 | ... = ... | Assert.cs:98:13:98:25 | ... ? ... : ... | +| Assert.cs:98:9:98:26 | ...; | Assert.cs:98:9:98:26 | ...; | +| Assert.cs:98:13:98:13 | access to parameter b | Assert.cs:98:13:98:13 | access to parameter b | +| Assert.cs:98:13:98:25 | ... ? ... : ... | Assert.cs:98:13:98:25 | ... ? ... : ... | +| Assert.cs:98:17:98:20 | null | Assert.cs:98:17:98:20 | null | +| Assert.cs:98:24:98:25 | "" | Assert.cs:98:24:98:25 | "" | +| Assert.cs:99:9:99:32 | call to method IsTrue | Assert.cs:99:23:99:23 | access to local variable s | +| Assert.cs:99:9:99:33 | ...; | Assert.cs:99:9:99:33 | ...; | +| Assert.cs:99:23:99:23 | access to local variable s | Assert.cs:99:23:99:23 | access to local variable s | +| Assert.cs:99:23:99:31 | ... == ... | Assert.cs:99:23:99:23 | access to local variable s | +| Assert.cs:99:28:99:31 | null | Assert.cs:99:28:99:31 | null | +| Assert.cs:100:9:100:35 | call to method WriteLine | Assert.cs:100:27:100:27 | access to local variable s | +| Assert.cs:100:9:100:36 | ...; | Assert.cs:100:9:100:36 | ...; | +| Assert.cs:100:27:100:27 | access to local variable s | Assert.cs:100:27:100:27 | access to local variable s | +| Assert.cs:100:27:100:34 | access to property Length | Assert.cs:100:27:100:27 | access to local variable s | +| Assert.cs:102:9:102:25 | ... = ... | Assert.cs:102:13:102:25 | ... ? ... : ... | +| Assert.cs:102:9:102:26 | ...; | Assert.cs:102:9:102:26 | ...; | +| Assert.cs:102:13:102:13 | access to parameter b | Assert.cs:102:13:102:13 | access to parameter b | +| Assert.cs:102:13:102:25 | ... ? ... : ... | Assert.cs:102:13:102:25 | ... ? ... : ... | +| Assert.cs:102:17:102:20 | null | Assert.cs:102:17:102:20 | null | +| Assert.cs:102:24:102:25 | "" | Assert.cs:102:24:102:25 | "" | +| Assert.cs:103:9:103:32 | call to method IsTrue | Assert.cs:103:23:103:23 | access to local variable s | +| Assert.cs:103:9:103:33 | ...; | Assert.cs:103:9:103:33 | ...; | +| Assert.cs:103:23:103:23 | access to local variable s | Assert.cs:103:23:103:23 | access to local variable s | +| Assert.cs:103:23:103:31 | ... != ... | Assert.cs:103:23:103:23 | access to local variable s | +| Assert.cs:103:28:103:31 | null | Assert.cs:103:28:103:31 | null | +| Assert.cs:104:9:104:35 | call to method WriteLine | Assert.cs:104:27:104:27 | access to local variable s | +| Assert.cs:104:9:104:36 | ...; | Assert.cs:104:9:104:36 | ...; | +| Assert.cs:104:27:104:27 | access to local variable s | Assert.cs:104:27:104:27 | access to local variable s | +| Assert.cs:104:27:104:34 | access to property Length | Assert.cs:104:27:104:27 | access to local variable s | +| Assert.cs:106:9:106:25 | ... = ... | Assert.cs:106:13:106:25 | ... ? ... : ... | +| Assert.cs:106:9:106:26 | ...; | Assert.cs:106:9:106:26 | ...; | +| Assert.cs:106:13:106:13 | access to parameter b | Assert.cs:106:13:106:13 | access to parameter b | +| Assert.cs:106:13:106:25 | ... ? ... : ... | Assert.cs:106:13:106:25 | ... ? ... : ... | +| Assert.cs:106:17:106:20 | null | Assert.cs:106:17:106:20 | null | +| Assert.cs:106:24:106:25 | "" | Assert.cs:106:24:106:25 | "" | +| Assert.cs:107:9:107:33 | call to method IsFalse | Assert.cs:107:24:107:24 | access to local variable s | +| Assert.cs:107:9:107:34 | ...; | Assert.cs:107:9:107:34 | ...; | +| Assert.cs:107:24:107:24 | access to local variable s | Assert.cs:107:24:107:24 | access to local variable s | +| Assert.cs:107:24:107:32 | ... != ... | Assert.cs:107:24:107:24 | access to local variable s | +| Assert.cs:107:29:107:32 | null | Assert.cs:107:29:107:32 | null | +| Assert.cs:108:9:108:35 | call to method WriteLine | Assert.cs:108:27:108:27 | access to local variable s | +| Assert.cs:108:9:108:36 | ...; | Assert.cs:108:9:108:36 | ...; | +| Assert.cs:108:27:108:27 | access to local variable s | Assert.cs:108:27:108:27 | access to local variable s | +| Assert.cs:108:27:108:34 | access to property Length | Assert.cs:108:27:108:27 | access to local variable s | +| Assert.cs:110:9:110:25 | ... = ... | Assert.cs:110:13:110:25 | ... ? ... : ... | +| Assert.cs:110:9:110:26 | ...; | Assert.cs:110:9:110:26 | ...; | +| Assert.cs:110:13:110:13 | access to parameter b | Assert.cs:110:13:110:13 | access to parameter b | +| Assert.cs:110:13:110:25 | ... ? ... : ... | Assert.cs:110:13:110:25 | ... ? ... : ... | +| Assert.cs:110:17:110:20 | null | Assert.cs:110:17:110:20 | null | +| Assert.cs:110:24:110:25 | "" | Assert.cs:110:24:110:25 | "" | +| Assert.cs:111:9:111:33 | call to method IsFalse | Assert.cs:111:24:111:24 | access to local variable s | +| Assert.cs:111:9:111:34 | ...; | Assert.cs:111:9:111:34 | ...; | +| Assert.cs:111:24:111:24 | access to local variable s | Assert.cs:111:24:111:24 | access to local variable s | +| Assert.cs:111:24:111:32 | ... == ... | Assert.cs:111:24:111:24 | access to local variable s | +| Assert.cs:111:29:111:32 | null | Assert.cs:111:29:111:32 | null | +| Assert.cs:112:9:112:35 | call to method WriteLine | Assert.cs:112:27:112:27 | access to local variable s | +| Assert.cs:112:9:112:36 | ...; | Assert.cs:112:9:112:36 | ...; | +| Assert.cs:112:27:112:27 | access to local variable s | Assert.cs:112:27:112:27 | access to local variable s | +| Assert.cs:112:27:112:34 | access to property Length | Assert.cs:112:27:112:27 | access to local variable s | +| Assert.cs:114:9:114:25 | ... = ... | Assert.cs:114:13:114:25 | ... ? ... : ... | +| Assert.cs:114:9:114:26 | ...; | Assert.cs:114:9:114:26 | ...; | +| Assert.cs:114:13:114:13 | access to parameter b | Assert.cs:114:13:114:13 | access to parameter b | +| Assert.cs:114:13:114:25 | ... ? ... : ... | Assert.cs:114:13:114:25 | ... ? ... : ... | +| Assert.cs:114:17:114:20 | null | Assert.cs:114:17:114:20 | null | +| Assert.cs:114:24:114:25 | "" | Assert.cs:114:24:114:25 | "" | +| Assert.cs:115:9:115:37 | call to method IsTrue | Assert.cs:115:23:115:36 | ... && ... | +| Assert.cs:115:9:115:38 | ...; | Assert.cs:115:9:115:38 | ...; | +| Assert.cs:115:23:115:23 | access to local variable s | Assert.cs:115:23:115:23 | access to local variable s | +| Assert.cs:115:23:115:31 | ... != ... | Assert.cs:115:23:115:23 | access to local variable s | +| Assert.cs:115:23:115:36 | ... && ... | Assert.cs:115:23:115:36 | ... && ... | +| Assert.cs:115:28:115:31 | null | Assert.cs:115:28:115:31 | null | +| Assert.cs:115:36:115:36 | access to parameter b | Assert.cs:115:36:115:36 | access to parameter b | +| Assert.cs:116:9:116:35 | call to method WriteLine | Assert.cs:116:27:116:27 | access to local variable s | +| Assert.cs:116:9:116:36 | ...; | Assert.cs:116:9:116:36 | ...; | +| Assert.cs:116:27:116:27 | access to local variable s | Assert.cs:116:27:116:27 | access to local variable s | +| Assert.cs:116:27:116:34 | access to property Length | Assert.cs:116:27:116:27 | access to local variable s | +| Assert.cs:118:9:118:25 | ... = ... | Assert.cs:118:13:118:25 | ... ? ... : ... | +| Assert.cs:118:9:118:26 | ...; | Assert.cs:118:9:118:26 | ...; | +| Assert.cs:118:13:118:13 | access to parameter b | Assert.cs:118:13:118:13 | access to parameter b | +| Assert.cs:118:13:118:25 | ... ? ... : ... | Assert.cs:118:13:118:25 | ... ? ... : ... | +| Assert.cs:118:17:118:20 | null | Assert.cs:118:17:118:20 | null | +| Assert.cs:118:24:118:25 | "" | Assert.cs:118:24:118:25 | "" | +| Assert.cs:119:9:119:39 | call to method IsFalse | Assert.cs:119:24:119:38 | ... \|\| ... | +| Assert.cs:119:9:119:40 | ...; | Assert.cs:119:9:119:40 | ...; | +| Assert.cs:119:24:119:24 | access to local variable s | Assert.cs:119:24:119:24 | access to local variable s | +| Assert.cs:119:24:119:32 | ... == ... | Assert.cs:119:24:119:24 | access to local variable s | +| Assert.cs:119:24:119:38 | ... \|\| ... | Assert.cs:119:24:119:38 | ... \|\| ... | +| Assert.cs:119:29:119:32 | null | Assert.cs:119:29:119:32 | null | +| Assert.cs:119:37:119:38 | !... | Assert.cs:119:37:119:38 | !... | +| Assert.cs:119:38:119:38 | access to parameter b | Assert.cs:119:38:119:38 | access to parameter b | +| Assert.cs:120:9:120:35 | call to method WriteLine | Assert.cs:120:27:120:27 | access to local variable s | +| Assert.cs:120:9:120:36 | ...; | Assert.cs:120:9:120:36 | ...; | +| Assert.cs:120:27:120:27 | access to local variable s | Assert.cs:120:27:120:27 | access to local variable s | +| Assert.cs:120:27:120:34 | access to property Length | Assert.cs:120:27:120:27 | access to local variable s | +| Assert.cs:122:9:122:25 | ... = ... | Assert.cs:122:13:122:25 | ... ? ... : ... | +| Assert.cs:122:9:122:26 | ...; | Assert.cs:122:9:122:26 | ...; | +| Assert.cs:122:13:122:13 | access to parameter b | Assert.cs:122:13:122:13 | access to parameter b | +| Assert.cs:122:13:122:25 | ... ? ... : ... | Assert.cs:122:13:122:25 | ... ? ... : ... | +| Assert.cs:122:17:122:20 | null | Assert.cs:122:17:122:20 | null | +| Assert.cs:122:24:122:25 | "" | Assert.cs:122:24:122:25 | "" | +| Assert.cs:123:9:123:37 | call to method IsTrue | Assert.cs:123:23:123:36 | ... && ... | +| Assert.cs:123:9:123:38 | ...; | Assert.cs:123:9:123:38 | ...; | +| Assert.cs:123:23:123:23 | access to local variable s | Assert.cs:123:23:123:23 | access to local variable s | +| Assert.cs:123:23:123:31 | ... == ... | Assert.cs:123:23:123:23 | access to local variable s | +| Assert.cs:123:23:123:36 | ... && ... | Assert.cs:123:23:123:36 | ... && ... | +| Assert.cs:123:28:123:31 | null | Assert.cs:123:28:123:31 | null | +| Assert.cs:123:36:123:36 | access to parameter b | Assert.cs:123:36:123:36 | access to parameter b | +| Assert.cs:124:9:124:35 | call to method WriteLine | Assert.cs:124:27:124:27 | access to local variable s | +| Assert.cs:124:9:124:36 | ...; | Assert.cs:124:9:124:36 | ...; | +| Assert.cs:124:27:124:27 | access to local variable s | Assert.cs:124:27:124:27 | access to local variable s | +| Assert.cs:124:27:124:34 | access to property Length | Assert.cs:124:27:124:27 | access to local variable s | +| Assert.cs:126:9:126:25 | ... = ... | Assert.cs:126:13:126:25 | ... ? ... : ... | +| Assert.cs:126:9:126:26 | ...; | Assert.cs:126:9:126:26 | ...; | +| Assert.cs:126:13:126:13 | access to parameter b | Assert.cs:126:13:126:13 | access to parameter b | +| Assert.cs:126:13:126:25 | ... ? ... : ... | Assert.cs:126:13:126:25 | ... ? ... : ... | +| Assert.cs:126:17:126:20 | null | Assert.cs:126:17:126:20 | null | +| Assert.cs:126:24:126:25 | "" | Assert.cs:126:24:126:25 | "" | +| Assert.cs:127:9:127:39 | call to method IsFalse | Assert.cs:127:24:127:38 | ... \|\| ... | +| Assert.cs:127:9:127:40 | ...; | Assert.cs:127:9:127:40 | ...; | +| Assert.cs:127:24:127:24 | access to local variable s | Assert.cs:127:24:127:24 | access to local variable s | +| Assert.cs:127:24:127:32 | ... != ... | Assert.cs:127:24:127:24 | access to local variable s | +| Assert.cs:127:24:127:38 | ... \|\| ... | Assert.cs:127:24:127:38 | ... \|\| ... | +| Assert.cs:127:29:127:32 | null | Assert.cs:127:29:127:32 | null | +| Assert.cs:127:37:127:38 | !... | Assert.cs:127:37:127:38 | !... | +| Assert.cs:127:38:127:38 | access to parameter b | Assert.cs:127:38:127:38 | access to parameter b | +| Assert.cs:128:9:128:35 | call to method WriteLine | Assert.cs:128:27:128:27 | access to local variable s | +| Assert.cs:128:9:128:36 | ...; | Assert.cs:128:9:128:36 | ...; | +| Assert.cs:128:27:128:27 | access to local variable s | Assert.cs:128:27:128:27 | access to local variable s | +| Assert.cs:128:27:128:34 | access to property Length | Assert.cs:128:27:128:27 | access to local variable s | | Assignments.cs:4:5:15:5 | {...} | Assignments.cs:4:5:15:5 | {...} | | Assignments.cs:5:9:5:18 | ... ...; | Assignments.cs:5:9:5:18 | ... ...; | | Assignments.cs:5:13:5:17 | Int32 x = ... | Assignments.cs:5:17:5:17 | 0 | @@ -493,11 +845,21 @@ | ConditionalAccess.cs:25:13:25:14 | "" | ConditionalAccess.cs:25:13:25:14 | "" | | ConditionalAccess.cs:25:16:25:32 | call to method CommaJoinWith | ConditionalAccess.cs:25:13:25:14 | "" | | ConditionalAccess.cs:25:31:25:31 | access to local variable s | ConditionalAccess.cs:25:31:25:31 | access to local variable s | -| ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | -| ConditionalAccess.cs:31:70:31:78 | ... + ... | ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | -| ConditionalAccess.cs:31:70:31:83 | ... + ... | ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | -| ConditionalAccess.cs:31:75:31:78 | ", " | ConditionalAccess.cs:31:75:31:78 | ", " | -| ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:30:32:30:32 | 0 | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:32:30:32 | 0 | +| ConditionalAccess.cs:33:5:36:5 | {...} | ConditionalAccess.cs:33:5:36:5 | {...} | +| ConditionalAccess.cs:34:9:34:13 | ... = ... | ConditionalAccess.cs:34:13:34:13 | 0 | +| ConditionalAccess.cs:34:9:34:14 | ...; | ConditionalAccess.cs:34:9:34:14 | ...; | +| ConditionalAccess.cs:34:13:34:13 | 0 | ConditionalAccess.cs:34:13:34:13 | 0 | +| ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:35:9:35:12 | this access | +| ConditionalAccess.cs:35:9:35:12 | this access | ConditionalAccess.cs:35:9:35:12 | this access | +| ConditionalAccess.cs:35:9:35:25 | ...; | ConditionalAccess.cs:35:9:35:25 | ...; | +| ConditionalAccess.cs:35:14:35:24 | call to method Out | ConditionalAccess.cs:35:9:35:12 | this access | +| ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | +| ConditionalAccess.cs:41:70:41:78 | ... + ... | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | +| ConditionalAccess.cs:41:70:41:83 | ... + ... | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | +| ConditionalAccess.cs:41:75:41:78 | ", " | ConditionalAccess.cs:41:75:41:78 | ", " | +| ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | | Conditions.cs:4:5:9:5 | {...} | Conditions.cs:4:5:9:5 | {...} | | Conditions.cs:5:9:6:16 | if (...) ... | Conditions.cs:5:9:6:16 | if (...) ... | | Conditions.cs:5:13:5:15 | access to parameter inc | Conditions.cs:5:13:5:15 | access to parameter inc | @@ -639,7 +1001,7 @@ | Conditions.cs:79:17:79:26 | ...; | Conditions.cs:79:17:79:26 | ...; | | Conditions.cs:79:21:79:25 | false | Conditions.cs:79:21:79:25 | false | | Conditions.cs:81:9:82:16 | if (...) ... | Conditions.cs:81:9:82:16 | if (...) ... | -| Conditions.cs:81:12:81:12 | access to local variable b | Conditions.cs:81:12:81:12 | access to local variable b | +| Conditions.cs:81:13:81:13 | access to local variable b | Conditions.cs:81:13:81:13 | access to local variable b | | Conditions.cs:82:13:82:13 | access to local variable x | Conditions.cs:82:13:82:13 | access to local variable x | | Conditions.cs:82:13:82:15 | ...++ | Conditions.cs:82:13:82:13 | access to local variable x | | Conditions.cs:82:13:82:16 | ...; | Conditions.cs:82:13:82:16 | ...; | @@ -712,14 +1074,14 @@ | Conditions.cs:115:16:115:23 | String s = ... | Conditions.cs:115:20:115:23 | null | | Conditions.cs:115:20:115:23 | null | Conditions.cs:115:20:115:23 | null | | Conditions.cs:116:9:123:9 | for (...;...;...) ... | Conditions.cs:116:9:123:9 | for (...;...;...) ... | -| Conditions.cs:116:17:116:21 | Int32 i = ... | Conditions.cs:116:21:116:21 | 0 | -| Conditions.cs:116:21:116:21 | 0 | Conditions.cs:116:21:116:21 | 0 | -| Conditions.cs:116:24:116:24 | access to local variable i | Conditions.cs:116:24:116:24 | access to local variable i | -| Conditions.cs:116:24:116:38 | ... < ... | Conditions.cs:116:24:116:24 | access to local variable i | -| Conditions.cs:116:28:116:31 | access to parameter args | Conditions.cs:116:28:116:31 | access to parameter args | -| Conditions.cs:116:28:116:38 | access to property Length | Conditions.cs:116:28:116:31 | access to parameter args | -| Conditions.cs:116:41:116:41 | access to local variable i | Conditions.cs:116:41:116:41 | access to local variable i | -| Conditions.cs:116:41:116:43 | ...++ | Conditions.cs:116:41:116:41 | access to local variable i | +| Conditions.cs:116:18:116:22 | Int32 i = ... | Conditions.cs:116:22:116:22 | 0 | +| Conditions.cs:116:22:116:22 | 0 | Conditions.cs:116:22:116:22 | 0 | +| Conditions.cs:116:25:116:25 | access to local variable i | Conditions.cs:116:25:116:25 | access to local variable i | +| Conditions.cs:116:25:116:39 | ... < ... | Conditions.cs:116:25:116:25 | access to local variable i | +| Conditions.cs:116:29:116:32 | access to parameter args | Conditions.cs:116:29:116:32 | access to parameter args | +| Conditions.cs:116:29:116:39 | access to property Length | Conditions.cs:116:29:116:32 | access to parameter args | +| Conditions.cs:116:42:116:42 | access to local variable i | Conditions.cs:116:42:116:42 | access to local variable i | +| Conditions.cs:116:42:116:44 | ...++ | Conditions.cs:116:42:116:42 | access to local variable i | | Conditions.cs:117:9:123:9 | {...} | Conditions.cs:117:9:123:9 | {...} | | Conditions.cs:118:13:118:44 | ... ...; | Conditions.cs:118:13:118:44 | ... ...; | | Conditions.cs:118:17:118:43 | Boolean last = ... | Conditions.cs:118:24:118:24 | access to local variable i | @@ -756,6 +1118,25 @@ | Conditions.cs:137:21:137:26 | this access | Conditions.cs:137:21:137:26 | this access | | Conditions.cs:137:21:137:37 | call to method ToString | Conditions.cs:137:21:137:26 | this access | | Conditions.cs:137:21:137:38 | ...; | Conditions.cs:137:21:137:38 | ...; | +| Conditions.cs:144:5:150:5 | {...} | Conditions.cs:144:5:150:5 | {...} | +| Conditions.cs:145:9:145:30 | ... ...; | Conditions.cs:145:9:145:30 | ... ...; | +| Conditions.cs:145:13:145:29 | String s = ... | Conditions.cs:145:17:145:29 | ... ? ... : ... | +| Conditions.cs:145:17:145:17 | access to parameter b | Conditions.cs:145:17:145:17 | access to parameter b | +| Conditions.cs:145:17:145:29 | ... ? ... : ... | Conditions.cs:145:17:145:29 | ... ? ... : ... | +| Conditions.cs:145:21:145:23 | "a" | Conditions.cs:145:21:145:23 | "a" | +| Conditions.cs:145:27:145:29 | "b" | Conditions.cs:145:27:145:29 | "b" | +| Conditions.cs:146:9:149:49 | if (...) ... | Conditions.cs:146:9:149:49 | if (...) ... | +| Conditions.cs:146:13:146:13 | access to parameter b | Conditions.cs:146:13:146:13 | access to parameter b | +| Conditions.cs:147:13:147:48 | call to method WriteLine | Conditions.cs:147:40:147:43 | "a = " | +| Conditions.cs:147:13:147:49 | ...; | Conditions.cs:147:13:147:49 | ...; | +| Conditions.cs:147:38:147:47 | $"..." | Conditions.cs:147:40:147:43 | "a = " | +| Conditions.cs:147:40:147:43 | "a = " | Conditions.cs:147:40:147:43 | "a = " | +| Conditions.cs:147:45:147:45 | access to local variable s | Conditions.cs:147:45:147:45 | access to local variable s | +| Conditions.cs:149:13:149:48 | call to method WriteLine | Conditions.cs:149:40:149:43 | "b = " | +| Conditions.cs:149:13:149:49 | ...; | Conditions.cs:149:13:149:49 | ...; | +| Conditions.cs:149:38:149:47 | $"..." | Conditions.cs:149:40:149:43 | "b = " | +| Conditions.cs:149:40:149:43 | "b = " | Conditions.cs:149:40:149:43 | "b = " | +| Conditions.cs:149:45:149:45 | access to local variable s | Conditions.cs:149:45:149:45 | access to local variable s | | ExitMethods.cs:8:5:11:5 | {...} | ExitMethods.cs:8:5:11:5 | {...} | | ExitMethods.cs:9:9:9:24 | call to method ErrorMaybe | ExitMethods.cs:9:20:9:23 | true | | ExitMethods.cs:9:9:9:25 | ...; | ExitMethods.cs:9:9:9:25 | ...; | @@ -1251,9 +1632,9 @@ | Initializers.cs:14:47:14:51 | ... = ... | Initializers.cs:14:51:14:51 | 1 | | Initializers.cs:14:51:14:51 | 1 | Initializers.cs:14:51:14:51 | 1 | | Initializers.cs:15:9:15:64 | ... ...; | Initializers.cs:15:9:15:64 | ... ...; | -| Initializers.cs:15:13:15:63 | Initializers[] iz = ... | Initializers.cs:15:18:15:63 | array creation of type Initializers[] | +| Initializers.cs:15:13:15:63 | Initializers[] iz = ... | Initializers.cs:15:18:15:63 | 2 | | Initializers.cs:15:18:15:63 | 2 | Initializers.cs:15:18:15:63 | 2 | -| Initializers.cs:15:18:15:63 | array creation of type Initializers[] | Initializers.cs:15:18:15:63 | array creation of type Initializers[] | +| Initializers.cs:15:18:15:63 | array creation of type Initializers[] | Initializers.cs:15:18:15:63 | 2 | | Initializers.cs:15:37:15:63 | { ..., ... } | Initializers.cs:15:39:15:39 | access to local variable i | | Initializers.cs:15:39:15:39 | access to local variable i | Initializers.cs:15:39:15:39 | access to local variable i | | Initializers.cs:15:42:15:61 | object creation of type Initializers | Initializers.cs:15:59:15:60 | "" | @@ -1408,24 +1789,24 @@ | LoopUnrolling.cs:9:13:9:28 | ... == ... | LoopUnrolling.cs:9:13:9:16 | access to parameter args | | LoopUnrolling.cs:9:28:9:28 | 0 | LoopUnrolling.cs:9:28:9:28 | 0 | | LoopUnrolling.cs:10:13:10:19 | return ...; | LoopUnrolling.cs:10:13:10:19 | return ...; | -| LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:11:28:11:31 | access to parameter args | -| LoopUnrolling.cs:11:21:11:23 | String arg | LoopUnrolling.cs:11:21:11:23 | String arg | -| LoopUnrolling.cs:11:28:11:31 | access to parameter args | LoopUnrolling.cs:11:28:11:31 | access to parameter args | +| LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:11:29:11:32 | access to parameter args | +| LoopUnrolling.cs:11:22:11:24 | String arg | LoopUnrolling.cs:11:22:11:24 | String arg | +| LoopUnrolling.cs:11:29:11:32 | access to parameter args | LoopUnrolling.cs:11:29:11:32 | access to parameter args | | LoopUnrolling.cs:12:13:12:34 | call to method WriteLine | LoopUnrolling.cs:12:31:12:33 | access to local variable arg | | LoopUnrolling.cs:12:13:12:35 | ...; | LoopUnrolling.cs:12:13:12:35 | ...; | | LoopUnrolling.cs:12:31:12:33 | access to local variable arg | LoopUnrolling.cs:12:31:12:33 | access to local variable arg | | LoopUnrolling.cs:16:5:20:5 | {...} | LoopUnrolling.cs:16:5:20:5 | {...} | -| LoopUnrolling.cs:17:9:17:47 | ... ...; | LoopUnrolling.cs:17:9:17:47 | ... ...; | -| LoopUnrolling.cs:17:13:17:46 | String[] xs = ... | LoopUnrolling.cs:17:18:17:46 | array creation of type String[] | -| LoopUnrolling.cs:17:18:17:46 | 3 | LoopUnrolling.cs:17:18:17:46 | 3 | -| LoopUnrolling.cs:17:18:17:46 | array creation of type String[] | LoopUnrolling.cs:17:18:17:46 | array creation of type String[] | -| LoopUnrolling.cs:17:30:17:46 | { ..., ... } | LoopUnrolling.cs:17:32:17:34 | "a" | -| LoopUnrolling.cs:17:32:17:34 | "a" | LoopUnrolling.cs:17:32:17:34 | "a" | -| LoopUnrolling.cs:17:37:17:39 | "b" | LoopUnrolling.cs:17:37:17:39 | "b" | -| LoopUnrolling.cs:17:42:17:44 | "c" | LoopUnrolling.cs:17:42:17:44 | "c" | -| LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:18:26:18:27 | access to local variable xs | -| LoopUnrolling.cs:18:21:18:21 | String x | LoopUnrolling.cs:18:21:18:21 | String x | -| LoopUnrolling.cs:18:26:18:27 | access to local variable xs | LoopUnrolling.cs:18:26:18:27 | access to local variable xs | +| LoopUnrolling.cs:17:9:17:48 | ... ...; | LoopUnrolling.cs:17:9:17:48 | ... ...; | +| LoopUnrolling.cs:17:13:17:47 | String[] xs = ... | LoopUnrolling.cs:17:18:17:47 | 3 | +| LoopUnrolling.cs:17:18:17:47 | 3 | LoopUnrolling.cs:17:18:17:47 | 3 | +| LoopUnrolling.cs:17:18:17:47 | array creation of type String[] | LoopUnrolling.cs:17:18:17:47 | 3 | +| LoopUnrolling.cs:17:31:17:47 | { ..., ... } | LoopUnrolling.cs:17:33:17:35 | "a" | +| LoopUnrolling.cs:17:33:17:35 | "a" | LoopUnrolling.cs:17:33:17:35 | "a" | +| LoopUnrolling.cs:17:38:17:40 | "b" | LoopUnrolling.cs:17:38:17:40 | "b" | +| LoopUnrolling.cs:17:43:17:45 | "c" | LoopUnrolling.cs:17:43:17:45 | "c" | +| LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:18:27:18:28 | access to local variable xs | +| LoopUnrolling.cs:18:22:18:22 | String x | LoopUnrolling.cs:18:22:18:22 | String x | +| LoopUnrolling.cs:18:27:18:28 | access to local variable xs | LoopUnrolling.cs:18:27:18:28 | access to local variable xs | | LoopUnrolling.cs:19:13:19:32 | call to method WriteLine | LoopUnrolling.cs:19:31:19:31 | access to local variable x | | LoopUnrolling.cs:19:13:19:33 | ...; | LoopUnrolling.cs:19:13:19:33 | ...; | | LoopUnrolling.cs:19:31:19:31 | access to local variable x | LoopUnrolling.cs:19:31:19:31 | access to local variable x | @@ -1444,70 +1825,70 @@ | LoopUnrolling.cs:31:13:31:30 | String[] xs = ... | LoopUnrolling.cs:31:29:31:29 | 0 | | LoopUnrolling.cs:31:18:31:30 | array creation of type String[] | LoopUnrolling.cs:31:29:31:29 | 0 | | LoopUnrolling.cs:31:29:31:29 | 0 | LoopUnrolling.cs:31:29:31:29 | 0 | -| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:32:26:32:27 | access to local variable xs | -| LoopUnrolling.cs:32:21:32:21 | String x | LoopUnrolling.cs:32:21:32:21 | String x | -| LoopUnrolling.cs:32:26:32:27 | access to local variable xs | LoopUnrolling.cs:32:26:32:27 | access to local variable xs | +| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:32:27:32:28 | access to local variable xs | +| LoopUnrolling.cs:32:22:32:22 | String x | LoopUnrolling.cs:32:22:32:22 | String x | +| LoopUnrolling.cs:32:27:32:28 | access to local variable xs | LoopUnrolling.cs:32:27:32:28 | access to local variable xs | | LoopUnrolling.cs:33:13:33:32 | call to method WriteLine | LoopUnrolling.cs:33:31:33:31 | access to local variable x | | LoopUnrolling.cs:33:13:33:33 | ...; | LoopUnrolling.cs:33:13:33:33 | ...; | | LoopUnrolling.cs:33:31:33:31 | access to local variable x | LoopUnrolling.cs:33:31:33:31 | access to local variable x | | LoopUnrolling.cs:37:5:43:5 | {...} | LoopUnrolling.cs:37:5:43:5 | {...} | -| LoopUnrolling.cs:38:9:38:47 | ... ...; | LoopUnrolling.cs:38:9:38:47 | ... ...; | -| LoopUnrolling.cs:38:13:38:46 | String[] xs = ... | LoopUnrolling.cs:38:18:38:46 | array creation of type String[] | -| LoopUnrolling.cs:38:18:38:46 | 3 | LoopUnrolling.cs:38:18:38:46 | 3 | -| LoopUnrolling.cs:38:18:38:46 | array creation of type String[] | LoopUnrolling.cs:38:18:38:46 | array creation of type String[] | -| LoopUnrolling.cs:38:30:38:46 | { ..., ... } | LoopUnrolling.cs:38:32:38:34 | "a" | -| LoopUnrolling.cs:38:32:38:34 | "a" | LoopUnrolling.cs:38:32:38:34 | "a" | -| LoopUnrolling.cs:38:37:38:39 | "b" | LoopUnrolling.cs:38:37:38:39 | "b" | -| LoopUnrolling.cs:38:42:38:44 | "c" | LoopUnrolling.cs:38:42:38:44 | "c" | -| LoopUnrolling.cs:39:9:39:47 | ... ...; | LoopUnrolling.cs:39:9:39:47 | ... ...; | -| LoopUnrolling.cs:39:13:39:46 | String[] ys = ... | LoopUnrolling.cs:39:18:39:46 | array creation of type String[] | -| LoopUnrolling.cs:39:18:39:46 | 3 | LoopUnrolling.cs:39:18:39:46 | 3 | -| LoopUnrolling.cs:39:18:39:46 | array creation of type String[] | LoopUnrolling.cs:39:18:39:46 | array creation of type String[] | -| LoopUnrolling.cs:39:30:39:46 | { ..., ... } | LoopUnrolling.cs:39:32:39:34 | "0" | -| LoopUnrolling.cs:39:32:39:34 | "0" | LoopUnrolling.cs:39:32:39:34 | "0" | -| LoopUnrolling.cs:39:37:39:39 | "1" | LoopUnrolling.cs:39:37:39:39 | "1" | -| LoopUnrolling.cs:39:42:39:44 | "2" | LoopUnrolling.cs:39:42:39:44 | "2" | -| LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:40:26:40:27 | access to local variable xs | -| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:40:21:40:21 | String x | -| LoopUnrolling.cs:40:26:40:27 | access to local variable xs | LoopUnrolling.cs:40:26:40:27 | access to local variable xs | -| LoopUnrolling.cs:41:13:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:41:30:41:31 | access to local variable ys | -| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:41:25:41:25 | String y | -| LoopUnrolling.cs:41:30:41:31 | access to local variable ys | LoopUnrolling.cs:41:30:41:31 | access to local variable ys | +| LoopUnrolling.cs:38:9:38:48 | ... ...; | LoopUnrolling.cs:38:9:38:48 | ... ...; | +| LoopUnrolling.cs:38:13:38:47 | String[] xs = ... | LoopUnrolling.cs:38:18:38:47 | 3 | +| LoopUnrolling.cs:38:18:38:47 | 3 | LoopUnrolling.cs:38:18:38:47 | 3 | +| LoopUnrolling.cs:38:18:38:47 | array creation of type String[] | LoopUnrolling.cs:38:18:38:47 | 3 | +| LoopUnrolling.cs:38:31:38:47 | { ..., ... } | LoopUnrolling.cs:38:33:38:35 | "a" | +| LoopUnrolling.cs:38:33:38:35 | "a" | LoopUnrolling.cs:38:33:38:35 | "a" | +| LoopUnrolling.cs:38:38:38:40 | "b" | LoopUnrolling.cs:38:38:38:40 | "b" | +| LoopUnrolling.cs:38:43:38:45 | "c" | LoopUnrolling.cs:38:43:38:45 | "c" | +| LoopUnrolling.cs:39:9:39:48 | ... ...; | LoopUnrolling.cs:39:9:39:48 | ... ...; | +| LoopUnrolling.cs:39:13:39:47 | String[] ys = ... | LoopUnrolling.cs:39:18:39:47 | 3 | +| LoopUnrolling.cs:39:18:39:47 | 3 | LoopUnrolling.cs:39:18:39:47 | 3 | +| LoopUnrolling.cs:39:18:39:47 | array creation of type String[] | LoopUnrolling.cs:39:18:39:47 | 3 | +| LoopUnrolling.cs:39:31:39:47 | { ..., ... } | LoopUnrolling.cs:39:33:39:35 | "0" | +| LoopUnrolling.cs:39:33:39:35 | "0" | LoopUnrolling.cs:39:33:39:35 | "0" | +| LoopUnrolling.cs:39:38:39:40 | "1" | LoopUnrolling.cs:39:38:39:40 | "1" | +| LoopUnrolling.cs:39:43:39:45 | "2" | LoopUnrolling.cs:39:43:39:45 | "2" | +| LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:40:27:40:28 | access to local variable xs | +| LoopUnrolling.cs:40:22:40:22 | String x | LoopUnrolling.cs:40:22:40:22 | String x | +| LoopUnrolling.cs:40:27:40:28 | access to local variable xs | LoopUnrolling.cs:40:27:40:28 | access to local variable xs | +| LoopUnrolling.cs:41:13:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:41:31:41:32 | access to local variable ys | +| LoopUnrolling.cs:41:26:41:26 | String y | LoopUnrolling.cs:41:26:41:26 | String y | +| LoopUnrolling.cs:41:31:41:32 | access to local variable ys | LoopUnrolling.cs:41:31:41:32 | access to local variable ys | | LoopUnrolling.cs:42:17:42:40 | call to method WriteLine | LoopUnrolling.cs:42:35:42:35 | access to local variable x | | LoopUnrolling.cs:42:17:42:41 | ...; | LoopUnrolling.cs:42:17:42:41 | ...; | | LoopUnrolling.cs:42:35:42:35 | access to local variable x | LoopUnrolling.cs:42:35:42:35 | access to local variable x | | LoopUnrolling.cs:42:35:42:39 | ... + ... | LoopUnrolling.cs:42:35:42:35 | access to local variable x | | LoopUnrolling.cs:42:39:42:39 | access to local variable y | LoopUnrolling.cs:42:39:42:39 | access to local variable y | | LoopUnrolling.cs:46:5:53:5 | {...} | LoopUnrolling.cs:46:5:53:5 | {...} | -| LoopUnrolling.cs:47:9:47:47 | ... ...; | LoopUnrolling.cs:47:9:47:47 | ... ...; | -| LoopUnrolling.cs:47:13:47:46 | String[] xs = ... | LoopUnrolling.cs:47:18:47:46 | array creation of type String[] | -| LoopUnrolling.cs:47:18:47:46 | 3 | LoopUnrolling.cs:47:18:47:46 | 3 | -| LoopUnrolling.cs:47:18:47:46 | array creation of type String[] | LoopUnrolling.cs:47:18:47:46 | array creation of type String[] | -| LoopUnrolling.cs:47:30:47:46 | { ..., ... } | LoopUnrolling.cs:47:32:47:34 | "a" | -| LoopUnrolling.cs:47:32:47:34 | "a" | LoopUnrolling.cs:47:32:47:34 | "a" | -| LoopUnrolling.cs:47:37:47:39 | "b" | LoopUnrolling.cs:47:37:47:39 | "b" | -| LoopUnrolling.cs:47:42:47:44 | "c" | LoopUnrolling.cs:47:42:47:44 | "c" | -| LoopUnrolling.cs:48:9:52:9 | foreach (... ... in ...) ... | LoopUnrolling.cs:48:26:48:27 | access to local variable xs | -| LoopUnrolling.cs:48:21:48:21 | String x | LoopUnrolling.cs:48:21:48:21 | String x | -| LoopUnrolling.cs:48:26:48:27 | access to local variable xs | LoopUnrolling.cs:48:26:48:27 | access to local variable xs | +| LoopUnrolling.cs:47:9:47:48 | ... ...; | LoopUnrolling.cs:47:9:47:48 | ... ...; | +| LoopUnrolling.cs:47:13:47:47 | String[] xs = ... | LoopUnrolling.cs:47:18:47:47 | 3 | +| LoopUnrolling.cs:47:18:47:47 | 3 | LoopUnrolling.cs:47:18:47:47 | 3 | +| LoopUnrolling.cs:47:18:47:47 | array creation of type String[] | LoopUnrolling.cs:47:18:47:47 | 3 | +| LoopUnrolling.cs:47:31:47:47 | { ..., ... } | LoopUnrolling.cs:47:33:47:35 | "a" | +| LoopUnrolling.cs:47:33:47:35 | "a" | LoopUnrolling.cs:47:33:47:35 | "a" | +| LoopUnrolling.cs:47:38:47:40 | "b" | LoopUnrolling.cs:47:38:47:40 | "b" | +| LoopUnrolling.cs:47:43:47:45 | "c" | LoopUnrolling.cs:47:43:47:45 | "c" | +| LoopUnrolling.cs:48:9:52:9 | foreach (... ... in ...) ... | LoopUnrolling.cs:48:27:48:28 | access to local variable xs | +| LoopUnrolling.cs:48:22:48:22 | String x | LoopUnrolling.cs:48:22:48:22 | String x | +| LoopUnrolling.cs:48:27:48:28 | access to local variable xs | LoopUnrolling.cs:48:27:48:28 | access to local variable xs | | LoopUnrolling.cs:49:9:52:9 | {...} | LoopUnrolling.cs:49:9:52:9 | {...} | -| LoopUnrolling.cs:50:13:50:17 | Label: | LoopUnrolling.cs:50:13:50:17 | Label: | -| LoopUnrolling.cs:50:20:50:39 | call to method WriteLine | LoopUnrolling.cs:50:38:50:38 | access to local variable x | -| LoopUnrolling.cs:50:20:50:40 | ...; | LoopUnrolling.cs:50:20:50:40 | ...; | -| LoopUnrolling.cs:50:38:50:38 | access to local variable x | LoopUnrolling.cs:50:38:50:38 | access to local variable x | +| LoopUnrolling.cs:50:9:50:13 | Label: | LoopUnrolling.cs:50:9:50:13 | Label: | +| LoopUnrolling.cs:50:16:50:35 | call to method WriteLine | LoopUnrolling.cs:50:34:50:34 | access to local variable x | +| LoopUnrolling.cs:50:16:50:36 | ...; | LoopUnrolling.cs:50:16:50:36 | ...; | +| LoopUnrolling.cs:50:34:50:34 | access to local variable x | LoopUnrolling.cs:50:34:50:34 | access to local variable x | | LoopUnrolling.cs:51:13:51:23 | goto ...; | LoopUnrolling.cs:51:13:51:23 | goto ...; | | LoopUnrolling.cs:56:5:65:5 | {...} | LoopUnrolling.cs:56:5:65:5 | {...} | -| LoopUnrolling.cs:57:9:57:47 | ... ...; | LoopUnrolling.cs:57:9:57:47 | ... ...; | -| LoopUnrolling.cs:57:13:57:46 | String[] xs = ... | LoopUnrolling.cs:57:18:57:46 | array creation of type String[] | -| LoopUnrolling.cs:57:18:57:46 | 3 | LoopUnrolling.cs:57:18:57:46 | 3 | -| LoopUnrolling.cs:57:18:57:46 | array creation of type String[] | LoopUnrolling.cs:57:18:57:46 | array creation of type String[] | -| LoopUnrolling.cs:57:30:57:46 | { ..., ... } | LoopUnrolling.cs:57:32:57:34 | "a" | -| LoopUnrolling.cs:57:32:57:34 | "a" | LoopUnrolling.cs:57:32:57:34 | "a" | -| LoopUnrolling.cs:57:37:57:39 | "b" | LoopUnrolling.cs:57:37:57:39 | "b" | -| LoopUnrolling.cs:57:42:57:44 | "c" | LoopUnrolling.cs:57:42:57:44 | "c" | -| LoopUnrolling.cs:58:9:64:9 | foreach (... ... in ...) ... | LoopUnrolling.cs:58:26:58:27 | access to local variable xs | -| LoopUnrolling.cs:58:21:58:21 | String x | LoopUnrolling.cs:58:21:58:21 | String x | -| LoopUnrolling.cs:58:26:58:27 | access to local variable xs | LoopUnrolling.cs:58:26:58:27 | access to local variable xs | +| LoopUnrolling.cs:57:9:57:48 | ... ...; | LoopUnrolling.cs:57:9:57:48 | ... ...; | +| LoopUnrolling.cs:57:13:57:47 | String[] xs = ... | LoopUnrolling.cs:57:18:57:47 | 3 | +| LoopUnrolling.cs:57:18:57:47 | 3 | LoopUnrolling.cs:57:18:57:47 | 3 | +| LoopUnrolling.cs:57:18:57:47 | array creation of type String[] | LoopUnrolling.cs:57:18:57:47 | 3 | +| LoopUnrolling.cs:57:31:57:47 | { ..., ... } | LoopUnrolling.cs:57:33:57:35 | "a" | +| LoopUnrolling.cs:57:33:57:35 | "a" | LoopUnrolling.cs:57:33:57:35 | "a" | +| LoopUnrolling.cs:57:38:57:40 | "b" | LoopUnrolling.cs:57:38:57:40 | "b" | +| LoopUnrolling.cs:57:43:57:45 | "c" | LoopUnrolling.cs:57:43:57:45 | "c" | +| LoopUnrolling.cs:58:9:64:9 | foreach (... ... in ...) ... | LoopUnrolling.cs:58:27:58:28 | access to local variable xs | +| LoopUnrolling.cs:58:22:58:22 | String x | LoopUnrolling.cs:58:22:58:22 | String x | +| LoopUnrolling.cs:58:27:58:28 | access to local variable xs | LoopUnrolling.cs:58:27:58:28 | access to local variable xs | | LoopUnrolling.cs:59:9:64:9 | {...} | LoopUnrolling.cs:59:9:64:9 | {...} | | LoopUnrolling.cs:60:13:61:37 | if (...) ... | LoopUnrolling.cs:60:13:61:37 | if (...) ... | | LoopUnrolling.cs:60:17:60:17 | access to parameter b | LoopUnrolling.cs:60:17:60:17 | access to parameter b | @@ -1528,12 +1909,134 @@ | LoopUnrolling.cs:71:9:71:12 | access to parameter args | LoopUnrolling.cs:71:9:71:12 | access to parameter args | | LoopUnrolling.cs:71:9:71:20 | call to method Clear | LoopUnrolling.cs:71:9:71:12 | access to parameter args | | LoopUnrolling.cs:71:9:71:21 | ...; | LoopUnrolling.cs:71:9:71:21 | ...; | -| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:72:28:72:31 | access to parameter args | -| LoopUnrolling.cs:72:21:72:23 | String arg | LoopUnrolling.cs:72:21:72:23 | String arg | -| LoopUnrolling.cs:72:28:72:31 | access to parameter args | LoopUnrolling.cs:72:28:72:31 | access to parameter args | +| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:72:29:72:32 | access to parameter args | +| LoopUnrolling.cs:72:22:72:24 | String arg | LoopUnrolling.cs:72:22:72:24 | String arg | +| LoopUnrolling.cs:72:29:72:32 | access to parameter args | LoopUnrolling.cs:72:29:72:32 | access to parameter args | | LoopUnrolling.cs:73:13:73:34 | call to method WriteLine | LoopUnrolling.cs:73:31:73:33 | access to local variable arg | | LoopUnrolling.cs:73:13:73:35 | ...; | LoopUnrolling.cs:73:13:73:35 | ...; | | LoopUnrolling.cs:73:31:73:33 | access to local variable arg | LoopUnrolling.cs:73:31:73:33 | access to local variable arg | +| LoopUnrolling.cs:77:5:83:5 | {...} | LoopUnrolling.cs:77:5:83:5 | {...} | +| LoopUnrolling.cs:78:9:78:34 | ... ...; | LoopUnrolling.cs:78:9:78:34 | ... ...; | +| LoopUnrolling.cs:78:13:78:33 | String[,] xs = ... | LoopUnrolling.cs:78:29:78:29 | 2 | +| LoopUnrolling.cs:78:18:78:33 | array creation of type String[,] | LoopUnrolling.cs:78:29:78:29 | 2 | +| LoopUnrolling.cs:78:29:78:29 | 2 | LoopUnrolling.cs:78:29:78:29 | 2 | +| LoopUnrolling.cs:78:32:78:32 | 0 | LoopUnrolling.cs:78:32:78:32 | 0 | +| LoopUnrolling.cs:79:9:82:9 | foreach (... ... in ...) ... | LoopUnrolling.cs:79:27:79:28 | access to local variable xs | +| LoopUnrolling.cs:79:22:79:22 | String x | LoopUnrolling.cs:79:22:79:22 | String x | +| LoopUnrolling.cs:79:27:79:28 | access to local variable xs | LoopUnrolling.cs:79:27:79:28 | access to local variable xs | +| LoopUnrolling.cs:80:9:82:9 | {...} | LoopUnrolling.cs:80:9:82:9 | {...} | +| LoopUnrolling.cs:81:13:81:32 | call to method WriteLine | LoopUnrolling.cs:81:31:81:31 | access to local variable x | +| LoopUnrolling.cs:81:13:81:33 | ...; | LoopUnrolling.cs:81:13:81:33 | ...; | +| LoopUnrolling.cs:81:31:81:31 | access to local variable x | LoopUnrolling.cs:81:31:81:31 | access to local variable x | +| LoopUnrolling.cs:86:5:92:5 | {...} | LoopUnrolling.cs:86:5:92:5 | {...} | +| LoopUnrolling.cs:87:9:87:34 | ... ...; | LoopUnrolling.cs:87:9:87:34 | ... ...; | +| LoopUnrolling.cs:87:13:87:33 | String[,] xs = ... | LoopUnrolling.cs:87:29:87:29 | 0 | +| LoopUnrolling.cs:87:18:87:33 | array creation of type String[,] | LoopUnrolling.cs:87:29:87:29 | 0 | +| LoopUnrolling.cs:87:29:87:29 | 0 | LoopUnrolling.cs:87:29:87:29 | 0 | +| LoopUnrolling.cs:87:32:87:32 | 2 | LoopUnrolling.cs:87:32:87:32 | 2 | +| LoopUnrolling.cs:88:9:91:9 | foreach (... ... in ...) ... | LoopUnrolling.cs:88:27:88:28 | access to local variable xs | +| LoopUnrolling.cs:88:22:88:22 | String x | LoopUnrolling.cs:88:22:88:22 | String x | +| LoopUnrolling.cs:88:27:88:28 | access to local variable xs | LoopUnrolling.cs:88:27:88:28 | access to local variable xs | +| LoopUnrolling.cs:89:9:91:9 | {...} | LoopUnrolling.cs:89:9:91:9 | {...} | +| LoopUnrolling.cs:90:13:90:32 | call to method WriteLine | LoopUnrolling.cs:90:31:90:31 | access to local variable x | +| LoopUnrolling.cs:90:13:90:33 | ...; | LoopUnrolling.cs:90:13:90:33 | ...; | +| LoopUnrolling.cs:90:31:90:31 | access to local variable x | LoopUnrolling.cs:90:31:90:31 | access to local variable x | +| LoopUnrolling.cs:95:5:101:5 | {...} | LoopUnrolling.cs:95:5:101:5 | {...} | +| LoopUnrolling.cs:96:9:96:34 | ... ...; | LoopUnrolling.cs:96:9:96:34 | ... ...; | +| LoopUnrolling.cs:96:13:96:33 | String[,] xs = ... | LoopUnrolling.cs:96:29:96:29 | 2 | +| LoopUnrolling.cs:96:18:96:33 | array creation of type String[,] | LoopUnrolling.cs:96:29:96:29 | 2 | +| LoopUnrolling.cs:96:29:96:29 | 2 | LoopUnrolling.cs:96:29:96:29 | 2 | +| LoopUnrolling.cs:96:32:96:32 | 2 | LoopUnrolling.cs:96:32:96:32 | 2 | +| LoopUnrolling.cs:97:9:100:9 | foreach (... ... in ...) ... | LoopUnrolling.cs:97:27:97:28 | access to local variable xs | +| LoopUnrolling.cs:97:22:97:22 | String x | LoopUnrolling.cs:97:22:97:22 | String x | +| LoopUnrolling.cs:97:27:97:28 | access to local variable xs | LoopUnrolling.cs:97:27:97:28 | access to local variable xs | +| LoopUnrolling.cs:98:9:100:9 | {...} | LoopUnrolling.cs:98:9:100:9 | {...} | +| LoopUnrolling.cs:99:13:99:32 | call to method WriteLine | LoopUnrolling.cs:99:31:99:31 | access to local variable x | +| LoopUnrolling.cs:99:13:99:33 | ...; | LoopUnrolling.cs:99:13:99:33 | ...; | +| LoopUnrolling.cs:99:31:99:31 | access to local variable x | LoopUnrolling.cs:99:31:99:31 | access to local variable x | +| MultiImplementationA.cs:6:22:6:31 | throw ... | MultiImplementationA.cs:6:28:6:31 | null | +| MultiImplementationA.cs:6:28:6:31 | null | MultiImplementationA.cs:6:28:6:31 | null | +| MultiImplementationA.cs:7:25:7:39 | {...} | MultiImplementationA.cs:7:25:7:39 | {...} | +| MultiImplementationA.cs:7:27:7:37 | throw ...; | MultiImplementationA.cs:7:33:7:36 | null | +| MultiImplementationA.cs:7:33:7:36 | null | MultiImplementationA.cs:7:33:7:36 | null | +| MultiImplementationA.cs:7:45:7:59 | {...} | MultiImplementationA.cs:7:45:7:59 | {...} | +| MultiImplementationA.cs:7:47:7:57 | throw ...; | MultiImplementationA.cs:7:53:7:56 | null | +| MultiImplementationA.cs:7:53:7:56 | null | MultiImplementationA.cs:7:53:7:56 | null | +| MultiImplementationA.cs:8:23:8:32 | throw ... | MultiImplementationA.cs:8:29:8:32 | null | +| MultiImplementationA.cs:8:29:8:32 | null | MultiImplementationA.cs:8:29:8:32 | null | +| MultiImplementationA.cs:13:16:13:16 | access to field F | MultiImplementationA.cs:13:16:13:16 | this access | +| MultiImplementationA.cs:13:16:13:16 | this access | MultiImplementationA.cs:13:16:13:16 | this access | +| MultiImplementationA.cs:13:16:13:20 | ... = ... | MultiImplementationA.cs:13:16:13:16 | this access | +| MultiImplementationA.cs:13:20:13:20 | 0 | MultiImplementationA.cs:13:20:13:20 | 0 | +| MultiImplementationA.cs:14:31:14:31 | access to parameter i | MultiImplementationA.cs:14:31:14:31 | access to parameter i | +| MultiImplementationA.cs:15:40:15:52 | {...} | MultiImplementationA.cs:15:40:15:52 | {...} | +| MultiImplementationA.cs:15:42:15:50 | return ...; | MultiImplementationA.cs:15:49:15:49 | access to parameter s | +| MultiImplementationA.cs:15:49:15:49 | access to parameter s | MultiImplementationA.cs:15:49:15:49 | access to parameter s | +| MultiImplementationA.cs:15:58:15:60 | {...} | MultiImplementationA.cs:15:58:15:60 | {...} | +| MultiImplementationA.cs:16:28:16:28 | 0 | MultiImplementationA.cs:16:28:16:28 | 0 | +| MultiImplementationA.cs:17:5:19:5 | {...} | MultiImplementationA.cs:17:5:19:5 | {...} | +| MultiImplementationA.cs:18:9:18:22 | M2(...) | MultiImplementationA.cs:18:9:18:22 | M2(...) | +| MultiImplementationA.cs:18:21:18:21 | 0 | MultiImplementationA.cs:18:21:18:21 | 0 | +| MultiImplementationA.cs:20:22:20:31 | {...} | MultiImplementationA.cs:20:22:20:31 | {...} | +| MultiImplementationA.cs:20:24:20:24 | access to field F | MultiImplementationA.cs:20:24:20:24 | this access | +| MultiImplementationA.cs:20:24:20:24 | this access | MultiImplementationA.cs:20:24:20:24 | this access | +| MultiImplementationA.cs:20:24:20:28 | ... = ... | MultiImplementationA.cs:20:24:20:24 | this access | +| MultiImplementationA.cs:20:24:20:29 | ...; | MultiImplementationA.cs:20:24:20:29 | ...; | +| MultiImplementationA.cs:20:28:20:28 | access to parameter i | MultiImplementationA.cs:20:28:20:28 | access to parameter i | +| MultiImplementationA.cs:21:19:21:22 | call to constructor C2 | MultiImplementationA.cs:21:24:21:24 | 0 | +| MultiImplementationA.cs:21:24:21:24 | 0 | MultiImplementationA.cs:21:24:21:24 | 0 | +| MultiImplementationA.cs:21:27:21:29 | {...} | MultiImplementationA.cs:21:27:21:29 | {...} | +| MultiImplementationA.cs:22:11:22:13 | {...} | MultiImplementationA.cs:22:11:22:13 | {...} | +| MultiImplementationA.cs:23:50:23:53 | null | MultiImplementationA.cs:23:50:23:53 | null | +| MultiImplementationA.cs:24:16:24:16 | access to property P | MultiImplementationA.cs:24:16:24:16 | this access | +| MultiImplementationA.cs:24:16:24:16 | this access | MultiImplementationA.cs:24:16:24:16 | this access | +| MultiImplementationA.cs:24:32:24:34 | ... = ... | MultiImplementationA.cs:24:16:24:16 | this access | +| MultiImplementationA.cs:24:34:24:34 | 0 | MultiImplementationA.cs:24:34:24:34 | 0 | +| MultiImplementationA.cs:30:28:30:37 | throw ... | MultiImplementationA.cs:30:34:30:37 | null | +| MultiImplementationA.cs:30:34:30:37 | null | MultiImplementationA.cs:30:34:30:37 | null | +| MultiImplementationA.cs:36:14:36:28 | {...} | MultiImplementationA.cs:36:14:36:28 | {...} | +| MultiImplementationA.cs:36:16:36:26 | throw ...; | MultiImplementationA.cs:36:22:36:25 | null | +| MultiImplementationA.cs:36:22:36:25 | null | MultiImplementationA.cs:36:22:36:25 | null | +| MultiImplementationA.cs:37:14:37:28 | {...} | MultiImplementationA.cs:37:14:37:28 | {...} | +| MultiImplementationA.cs:37:16:37:26 | throw ...; | MultiImplementationA.cs:37:22:37:25 | null | +| MultiImplementationA.cs:37:22:37:25 | null | MultiImplementationA.cs:37:22:37:25 | null | +| MultiImplementationB.cs:3:22:3:22 | 0 | MultiImplementationB.cs:3:22:3:22 | 0 | +| MultiImplementationB.cs:4:25:4:37 | {...} | MultiImplementationB.cs:4:25:4:37 | {...} | +| MultiImplementationB.cs:4:27:4:35 | return ...; | MultiImplementationB.cs:4:34:4:34 | 1 | +| MultiImplementationB.cs:4:34:4:34 | 1 | MultiImplementationB.cs:4:34:4:34 | 1 | +| MultiImplementationB.cs:4:43:4:45 | {...} | MultiImplementationB.cs:4:43:4:45 | {...} | +| MultiImplementationB.cs:5:23:5:23 | 2 | MultiImplementationB.cs:5:23:5:23 | 2 | +| MultiImplementationB.cs:11:16:11:16 | access to field F | MultiImplementationB.cs:11:16:11:16 | this access | +| MultiImplementationB.cs:11:16:11:16 | this access | MultiImplementationB.cs:11:16:11:16 | this access | +| MultiImplementationB.cs:11:16:11:20 | ... = ... | MultiImplementationB.cs:11:16:11:16 | this access | +| MultiImplementationB.cs:11:20:11:20 | 1 | MultiImplementationB.cs:11:20:11:20 | 1 | +| MultiImplementationB.cs:12:31:12:40 | throw ... | MultiImplementationB.cs:12:37:12:40 | null | +| MultiImplementationB.cs:12:37:12:40 | null | MultiImplementationB.cs:12:37:12:40 | null | +| MultiImplementationB.cs:13:40:13:54 | {...} | MultiImplementationB.cs:13:40:13:54 | {...} | +| MultiImplementationB.cs:13:42:13:52 | throw ...; | MultiImplementationB.cs:13:48:13:51 | null | +| MultiImplementationB.cs:13:48:13:51 | null | MultiImplementationB.cs:13:48:13:51 | null | +| MultiImplementationB.cs:13:60:13:62 | {...} | MultiImplementationB.cs:13:60:13:62 | {...} | +| MultiImplementationB.cs:14:28:14:28 | 1 | MultiImplementationB.cs:14:28:14:28 | 1 | +| MultiImplementationB.cs:15:5:17:5 | {...} | MultiImplementationB.cs:15:5:17:5 | {...} | +| MultiImplementationB.cs:16:9:16:31 | M2(...) | MultiImplementationB.cs:16:9:16:31 | M2(...) | +| MultiImplementationB.cs:16:21:16:30 | throw ... | MultiImplementationB.cs:16:27:16:30 | null | +| MultiImplementationB.cs:16:27:16:30 | null | MultiImplementationB.cs:16:27:16:30 | null | +| MultiImplementationB.cs:18:22:18:36 | {...} | MultiImplementationB.cs:18:22:18:36 | {...} | +| MultiImplementationB.cs:18:24:18:34 | throw ...; | MultiImplementationB.cs:18:30:18:33 | null | +| MultiImplementationB.cs:18:30:18:33 | null | MultiImplementationB.cs:18:30:18:33 | null | +| MultiImplementationB.cs:19:19:19:22 | call to constructor C2 | MultiImplementationB.cs:19:24:19:24 | 1 | +| MultiImplementationB.cs:19:24:19:24 | 1 | MultiImplementationB.cs:19:24:19:24 | 1 | +| MultiImplementationB.cs:19:27:19:29 | {...} | MultiImplementationB.cs:19:27:19:29 | {...} | +| MultiImplementationB.cs:20:11:20:25 | {...} | MultiImplementationB.cs:20:11:20:25 | {...} | +| MultiImplementationB.cs:20:13:20:23 | throw ...; | MultiImplementationB.cs:20:19:20:22 | null | +| MultiImplementationB.cs:20:19:20:22 | null | MultiImplementationB.cs:20:19:20:22 | null | +| MultiImplementationB.cs:21:50:21:59 | throw ... | MultiImplementationB.cs:21:56:21:59 | null | +| MultiImplementationB.cs:21:56:21:59 | null | MultiImplementationB.cs:21:56:21:59 | null | +| MultiImplementationB.cs:22:16:22:16 | access to property P | MultiImplementationB.cs:22:16:22:16 | this access | +| MultiImplementationB.cs:22:16:22:16 | this access | MultiImplementationB.cs:22:16:22:16 | this access | +| MultiImplementationB.cs:22:32:22:34 | ... = ... | MultiImplementationB.cs:22:16:22:16 | this access | +| MultiImplementationB.cs:22:34:22:34 | 1 | MultiImplementationB.cs:22:34:22:34 | 1 | +| MultiImplementationB.cs:32:17:32:17 | 0 | MultiImplementationB.cs:32:17:32:17 | 0 | | NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:23:3:23 | access to parameter i | | NullCoalescing.cs:3:23:3:28 | ... ?? ... | NullCoalescing.cs:3:23:3:28 | ... ?? ... | | NullCoalescing.cs:3:28:3:28 | 0 | NullCoalescing.cs:3:28:3:28 | 0 | @@ -1752,7 +2255,7 @@ | Switch.cs:27:13:27:39 | case ...: | Switch.cs:27:13:27:39 | case ...: | | Switch.cs:27:18:27:25 | Double d | Switch.cs:27:18:27:25 | Double d | | Switch.cs:27:32:27:38 | call to method Throw | Switch.cs:27:32:27:38 | call to method Throw | -| Switch.cs:28:17:28:21 | Label: | Switch.cs:28:17:28:21 | Label: | +| Switch.cs:28:13:28:17 | Label: | Switch.cs:28:13:28:17 | Label: | | Switch.cs:29:17:29:23 | return ...; | Switch.cs:29:17:29:23 | return ...; | | Switch.cs:30:13:30:20 | default: | Switch.cs:30:13:30:20 | default: | | Switch.cs:31:17:31:27 | goto ...; | Switch.cs:31:17:31:27 | goto ...; | @@ -1778,61 +2281,61 @@ | Switch.cs:57:17:57:17 | 1 | Switch.cs:57:17:57:17 | 1 | | Switch.cs:57:17:57:21 | ... + ... | Switch.cs:57:17:57:17 | 1 | | Switch.cs:57:21:57:21 | 2 | Switch.cs:57:21:57:21 | 2 | -| Switch.cs:59:13:59:20 | case ...: | Switch.cs:59:13:59:20 | case ...: | +| Switch.cs:59:13:59:19 | case ...: | Switch.cs:59:13:59:19 | case ...: | | Switch.cs:59:18:59:18 | 2 | Switch.cs:59:18:59:18 | 2 | -| Switch.cs:60:15:60:20 | break; | Switch.cs:60:15:60:20 | break; | -| Switch.cs:61:13:61:20 | case ...: | Switch.cs:61:13:61:20 | case ...: | +| Switch.cs:60:17:60:22 | break; | Switch.cs:60:17:60:22 | break; | +| Switch.cs:61:13:61:19 | case ...: | Switch.cs:61:13:61:19 | case ...: | | Switch.cs:61:18:61:18 | 3 | Switch.cs:61:18:61:18 | 3 | -| Switch.cs:62:15:62:20 | break; | Switch.cs:62:15:62:20 | break; | +| Switch.cs:62:17:62:22 | break; | Switch.cs:62:17:62:22 | break; | | Switch.cs:67:5:75:5 | {...} | Switch.cs:67:5:75:5 | {...} | | Switch.cs:68:9:74:9 | switch (...) {...} | Switch.cs:68:9:74:9 | switch (...) {...} | | Switch.cs:68:17:68:25 | (...) ... | Switch.cs:68:25:68:25 | access to parameter s | | Switch.cs:68:25:68:25 | access to parameter s | Switch.cs:68:25:68:25 | access to parameter s | -| Switch.cs:70:13:70:24 | case ...: | Switch.cs:70:13:70:24 | case ...: | +| Switch.cs:70:13:70:23 | case ...: | Switch.cs:70:13:70:23 | case ...: | | Switch.cs:70:18:70:20 | access to type Int32 | Switch.cs:70:18:70:20 | access to type Int32 | -| Switch.cs:71:15:71:20 | break; | Switch.cs:71:15:71:20 | break; | -| Switch.cs:72:13:72:21 | case ...: | Switch.cs:72:13:72:21 | case ...: | +| Switch.cs:71:17:71:22 | break; | Switch.cs:71:17:71:22 | break; | +| Switch.cs:72:13:72:20 | case ...: | Switch.cs:72:13:72:20 | case ...: | | Switch.cs:72:18:72:19 | "" | Switch.cs:72:18:72:19 | "" | -| Switch.cs:73:15:73:20 | break; | Switch.cs:73:15:73:20 | break; | +| Switch.cs:73:17:73:22 | break; | Switch.cs:73:17:73:22 | break; | | Switch.cs:78:5:89:5 | {...} | Switch.cs:78:5:89:5 | {...} | | Switch.cs:79:9:87:9 | switch (...) {...} | Switch.cs:79:9:87:9 | switch (...) {...} | | Switch.cs:79:17:79:17 | access to parameter i | Switch.cs:79:17:79:17 | access to parameter i | -| Switch.cs:81:13:81:20 | case ...: | Switch.cs:81:13:81:20 | case ...: | +| Switch.cs:81:13:81:19 | case ...: | Switch.cs:81:13:81:19 | case ...: | | Switch.cs:81:18:81:18 | 1 | Switch.cs:81:18:81:18 | 1 | -| Switch.cs:82:15:82:26 | return ...; | Switch.cs:82:22:82:25 | true | -| Switch.cs:82:22:82:25 | true | Switch.cs:82:22:82:25 | true | -| Switch.cs:83:13:83:20 | case ...: | Switch.cs:83:13:83:20 | case ...: | +| Switch.cs:82:17:82:28 | return ...; | Switch.cs:82:24:82:27 | true | +| Switch.cs:82:24:82:27 | true | Switch.cs:82:24:82:27 | true | +| Switch.cs:83:13:83:19 | case ...: | Switch.cs:83:13:83:19 | case ...: | | Switch.cs:83:18:83:18 | 2 | Switch.cs:83:18:83:18 | 2 | -| Switch.cs:84:15:85:22 | if (...) ... | Switch.cs:84:15:85:22 | if (...) ... | -| Switch.cs:84:19:84:19 | access to parameter j | Switch.cs:84:19:84:19 | access to parameter j | -| Switch.cs:84:19:84:23 | ... > ... | Switch.cs:84:19:84:19 | access to parameter j | -| Switch.cs:84:23:84:23 | 2 | Switch.cs:84:23:84:23 | 2 | -| Switch.cs:85:17:85:22 | break; | Switch.cs:85:17:85:22 | break; | -| Switch.cs:86:15:86:26 | return ...; | Switch.cs:86:22:86:25 | true | -| Switch.cs:86:22:86:25 | true | Switch.cs:86:22:86:25 | true | +| Switch.cs:84:17:85:26 | if (...) ... | Switch.cs:84:17:85:26 | if (...) ... | +| Switch.cs:84:21:84:21 | access to parameter j | Switch.cs:84:21:84:21 | access to parameter j | +| Switch.cs:84:21:84:25 | ... > ... | Switch.cs:84:21:84:21 | access to parameter j | +| Switch.cs:84:25:84:25 | 2 | Switch.cs:84:25:84:25 | 2 | +| Switch.cs:85:21:85:26 | break; | Switch.cs:85:21:85:26 | break; | +| Switch.cs:86:17:86:28 | return ...; | Switch.cs:86:24:86:27 | true | +| Switch.cs:86:24:86:27 | true | Switch.cs:86:24:86:27 | true | | Switch.cs:88:9:88:21 | return ...; | Switch.cs:88:16:88:20 | false | | Switch.cs:88:16:88:20 | false | Switch.cs:88:16:88:20 | false | | Switch.cs:92:5:99:5 | {...} | Switch.cs:92:5:99:5 | {...} | | Switch.cs:93:9:97:9 | switch (...) {...} | Switch.cs:93:9:97:9 | switch (...) {...} | | Switch.cs:93:17:93:17 | access to parameter o | Switch.cs:93:17:93:17 | access to parameter o | -| Switch.cs:95:13:95:24 | case ...: | Switch.cs:95:13:95:24 | case ...: | +| Switch.cs:95:13:95:23 | case ...: | Switch.cs:95:13:95:23 | case ...: | | Switch.cs:95:18:95:20 | access to type Int32 | Switch.cs:95:18:95:20 | access to type Int32 | -| Switch.cs:96:15:96:26 | return ...; | Switch.cs:96:22:96:25 | true | -| Switch.cs:96:22:96:25 | true | Switch.cs:96:22:96:25 | true | +| Switch.cs:96:17:96:28 | return ...; | Switch.cs:96:24:96:27 | true | +| Switch.cs:96:24:96:27 | true | Switch.cs:96:24:96:27 | true | | Switch.cs:98:9:98:21 | return ...; | Switch.cs:98:16:98:20 | false | | Switch.cs:98:16:98:20 | false | Switch.cs:98:16:98:20 | false | | Switch.cs:102:5:109:5 | {...} | Switch.cs:102:5:109:5 | {...} | | Switch.cs:103:9:107:9 | switch (...) {...} | Switch.cs:103:9:107:9 | switch (...) {...} | | Switch.cs:103:17:103:17 | access to parameter s | Switch.cs:103:17:103:17 | access to parameter s | | Switch.cs:103:19:103:25 | access to property Length | Switch.cs:103:17:103:17 | access to parameter s | -| Switch.cs:105:13:105:20 | case ...: | Switch.cs:105:13:105:20 | case ...: | +| Switch.cs:105:13:105:19 | case ...: | Switch.cs:105:13:105:19 | case ...: | | Switch.cs:105:18:105:18 | 0 | Switch.cs:105:18:105:18 | 0 | -| Switch.cs:105:22:105:30 | return ...; | Switch.cs:105:29:105:29 | 0 | -| Switch.cs:105:29:105:29 | 0 | Switch.cs:105:29:105:29 | 0 | -| Switch.cs:106:13:106:20 | case ...: | Switch.cs:106:13:106:20 | case ...: | +| Switch.cs:105:21:105:29 | return ...; | Switch.cs:105:28:105:28 | 0 | +| Switch.cs:105:28:105:28 | 0 | Switch.cs:105:28:105:28 | 0 | +| Switch.cs:106:13:106:19 | case ...: | Switch.cs:106:13:106:19 | case ...: | | Switch.cs:106:18:106:18 | 1 | Switch.cs:106:18:106:18 | 1 | -| Switch.cs:106:22:106:30 | return ...; | Switch.cs:106:29:106:29 | 1 | -| Switch.cs:106:29:106:29 | 1 | Switch.cs:106:29:106:29 | 1 | +| Switch.cs:106:21:106:29 | return ...; | Switch.cs:106:28:106:28 | 1 | +| Switch.cs:106:28:106:28 | 1 | Switch.cs:106:28:106:28 | 1 | | Switch.cs:108:9:108:18 | return ...; | Switch.cs:108:17:108:17 | 1 | | Switch.cs:108:16:108:17 | -... | Switch.cs:108:17:108:17 | 1 | | Switch.cs:108:17:108:17 | 1 | Switch.cs:108:17:108:17 | 1 | @@ -1842,20 +2345,20 @@ | Switch.cs:115:9:119:9 | switch (...) {...} | Switch.cs:115:9:119:9 | switch (...) {...} | | Switch.cs:115:17:115:17 | access to parameter s | Switch.cs:115:17:115:17 | access to parameter s | | Switch.cs:115:17:115:24 | access to property Length | Switch.cs:115:17:115:17 | access to parameter s | -| Switch.cs:117:13:117:34 | case ...: | Switch.cs:117:13:117:34 | case ...: | +| Switch.cs:117:13:117:35 | case ...: | Switch.cs:117:13:117:35 | case ...: | | Switch.cs:117:18:117:18 | 3 | Switch.cs:117:18:117:18 | 3 | | Switch.cs:117:25:117:25 | access to parameter s | Switch.cs:117:25:117:25 | access to parameter s | -| Switch.cs:117:25:117:32 | ... == ... | Switch.cs:117:25:117:25 | access to parameter s | -| Switch.cs:117:28:117:32 | "foo" | Switch.cs:117:28:117:32 | "foo" | -| Switch.cs:117:36:117:44 | return ...; | Switch.cs:117:43:117:43 | 1 | -| Switch.cs:117:43:117:43 | 1 | Switch.cs:117:43:117:43 | 1 | -| Switch.cs:118:13:118:33 | case ...: | Switch.cs:118:13:118:33 | case ...: | +| Switch.cs:117:25:117:34 | ... == ... | Switch.cs:117:25:117:25 | access to parameter s | +| Switch.cs:117:30:117:34 | "foo" | Switch.cs:117:30:117:34 | "foo" | +| Switch.cs:117:37:117:45 | return ...; | Switch.cs:117:44:117:44 | 1 | +| Switch.cs:117:44:117:44 | 1 | Switch.cs:117:44:117:44 | 1 | +| Switch.cs:118:13:118:34 | case ...: | Switch.cs:118:13:118:34 | case ...: | | Switch.cs:118:18:118:18 | 2 | Switch.cs:118:18:118:18 | 2 | | Switch.cs:118:25:118:25 | access to parameter s | Switch.cs:118:25:118:25 | access to parameter s | -| Switch.cs:118:25:118:31 | ... == ... | Switch.cs:118:25:118:25 | access to parameter s | -| Switch.cs:118:28:118:31 | "fu" | Switch.cs:118:28:118:31 | "fu" | -| Switch.cs:118:35:118:43 | return ...; | Switch.cs:118:42:118:42 | 2 | -| Switch.cs:118:42:118:42 | 2 | Switch.cs:118:42:118:42 | 2 | +| Switch.cs:118:25:118:33 | ... == ... | Switch.cs:118:25:118:25 | access to parameter s | +| Switch.cs:118:30:118:33 | "fu" | Switch.cs:118:30:118:33 | "fu" | +| Switch.cs:118:36:118:44 | return ...; | Switch.cs:118:43:118:43 | 2 | +| Switch.cs:118:43:118:43 | 2 | Switch.cs:118:43:118:43 | 2 | | Switch.cs:120:9:120:18 | return ...; | Switch.cs:120:17:120:17 | 1 | | Switch.cs:120:16:120:17 | -... | Switch.cs:120:17:120:17 | 1 | | Switch.cs:120:17:120:17 | 1 | Switch.cs:120:17:120:17 | 1 | @@ -1911,6 +2414,29 @@ | Switch.cs:150:18:150:18 | 2 | Switch.cs:150:18:150:18 | 2 | | Switch.cs:150:21:150:29 | return ...; | Switch.cs:150:28:150:28 | 2 | | Switch.cs:150:28:150:28 | 2 | Switch.cs:150:28:150:28 | 2 | +| Switch.cs:155:5:161:5 | {...} | Switch.cs:155:5:161:5 | {...} | +| Switch.cs:156:9:156:55 | ... ...; | Switch.cs:156:9:156:55 | ... ...; | +| Switch.cs:156:13:156:54 | String s = ... | Switch.cs:156:17:156:54 | ... switch { ... } | +| Switch.cs:156:17:156:17 | access to parameter b | Switch.cs:156:17:156:17 | access to parameter b | +| Switch.cs:156:17:156:54 | ... switch { ... } | Switch.cs:156:17:156:54 | ... switch { ... } | +| Switch.cs:156:28:156:31 | true | Switch.cs:156:28:156:31 | true | +| Switch.cs:156:28:156:38 | ... => ... | Switch.cs:156:28:156:38 | ... => ... | +| Switch.cs:156:36:156:38 | "a" | Switch.cs:156:36:156:38 | "a" | +| Switch.cs:156:41:156:45 | false | Switch.cs:156:41:156:45 | false | +| Switch.cs:156:41:156:52 | ... => ... | Switch.cs:156:41:156:52 | ... => ... | +| Switch.cs:156:50:156:52 | "b" | Switch.cs:156:50:156:52 | "b" | +| Switch.cs:157:9:160:49 | if (...) ... | Switch.cs:157:9:160:49 | if (...) ... | +| Switch.cs:157:13:157:13 | access to parameter b | Switch.cs:157:13:157:13 | access to parameter b | +| Switch.cs:158:13:158:48 | call to method WriteLine | Switch.cs:158:40:158:43 | "a = " | +| Switch.cs:158:13:158:49 | ...; | Switch.cs:158:13:158:49 | ...; | +| Switch.cs:158:38:158:47 | $"..." | Switch.cs:158:40:158:43 | "a = " | +| Switch.cs:158:40:158:43 | "a = " | Switch.cs:158:40:158:43 | "a = " | +| Switch.cs:158:45:158:45 | access to local variable s | Switch.cs:158:45:158:45 | access to local variable s | +| Switch.cs:160:13:160:48 | call to method WriteLine | Switch.cs:160:40:160:43 | "b = " | +| Switch.cs:160:13:160:49 | ...; | Switch.cs:160:13:160:49 | ...; | +| Switch.cs:160:38:160:47 | $"..." | Switch.cs:160:40:160:43 | "b = " | +| Switch.cs:160:40:160:43 | "b = " | Switch.cs:160:40:160:43 | "b = " | +| Switch.cs:160:45:160:45 | access to local variable s | Switch.cs:160:45:160:45 | access to local variable s | | TypeAccesses.cs:4:5:9:5 | {...} | TypeAccesses.cs:4:5:9:5 | {...} | | TypeAccesses.cs:5:9:5:26 | ... ...; | TypeAccesses.cs:5:9:5:26 | ... ...; | | TypeAccesses.cs:5:13:5:25 | String s = ... | TypeAccesses.cs:5:25:5:25 | access to parameter o | @@ -1932,10 +2458,12 @@ | VarDecls.cs:7:9:10:9 | fixed(...) { ... } | VarDecls.cs:7:9:10:9 | fixed(...) { ... } | | VarDecls.cs:7:22:7:36 | Char* c1 = ... | VarDecls.cs:7:27:7:33 | access to parameter strings | | VarDecls.cs:7:27:7:33 | access to parameter strings | VarDecls.cs:7:27:7:33 | access to parameter strings | +| VarDecls.cs:7:27:7:36 | (...) ... | VarDecls.cs:7:27:7:33 | access to parameter strings | | VarDecls.cs:7:27:7:36 | access to array element | VarDecls.cs:7:27:7:33 | access to parameter strings | | VarDecls.cs:7:35:7:35 | 0 | VarDecls.cs:7:35:7:35 | 0 | | VarDecls.cs:7:39:7:53 | Char* c2 = ... | VarDecls.cs:7:44:7:50 | access to parameter strings | | VarDecls.cs:7:44:7:50 | access to parameter strings | VarDecls.cs:7:44:7:50 | access to parameter strings | +| VarDecls.cs:7:44:7:53 | (...) ... | VarDecls.cs:7:44:7:50 | access to parameter strings | | VarDecls.cs:7:44:7:53 | access to array element | VarDecls.cs:7:44:7:50 | access to parameter strings | | VarDecls.cs:7:52:7:52 | 1 | VarDecls.cs:7:52:7:52 | 1 | | VarDecls.cs:8:9:10:9 | {...} | VarDecls.cs:8:9:10:9 | {...} | diff --git a/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected b/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected index fb1a799cb55d..0f67af1f9c7a 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected @@ -307,6 +307,516 @@ | ArrayCreation.cs:9:43:9:50 | { ..., ... } | ArrayCreation.cs:9:43:9:50 | { ..., ... } | normal | | ArrayCreation.cs:9:45:9:45 | 2 | ArrayCreation.cs:9:45:9:45 | 2 | normal | | ArrayCreation.cs:9:48:9:48 | 3 | ArrayCreation.cs:9:48:9:48 | 3 | normal | +| Assert.cs:8:5:12:5 | {...} | Assert.cs:10:9:10:31 | call to method Assert | exit | +| Assert.cs:8:5:12:5 | {...} | Assert.cs:11:9:11:35 | call to method WriteLine | normal | +| Assert.cs:9:9:9:33 | ... ...; | Assert.cs:9:16:9:32 | String s = ... | normal | +| Assert.cs:9:16:9:32 | String s = ... | Assert.cs:9:16:9:32 | String s = ... | normal | +| Assert.cs:9:20:9:20 | access to parameter b | Assert.cs:9:20:9:20 | access to parameter b | false | +| Assert.cs:9:20:9:20 | access to parameter b | Assert.cs:9:20:9:20 | access to parameter b | true | +| Assert.cs:9:20:9:32 | ... ? ... : ... | Assert.cs:9:24:9:27 | null | normal | +| Assert.cs:9:20:9:32 | ... ? ... : ... | Assert.cs:9:31:9:32 | "" | normal | +| Assert.cs:9:24:9:27 | null | Assert.cs:9:24:9:27 | null | normal | +| Assert.cs:9:31:9:32 | "" | Assert.cs:9:31:9:32 | "" | normal | +| Assert.cs:10:9:10:31 | call to method Assert | Assert.cs:10:9:10:31 | call to method Assert | exit | +| Assert.cs:10:9:10:31 | call to method Assert | Assert.cs:10:9:10:31 | call to method Assert | normal | +| Assert.cs:10:9:10:32 | ...; | Assert.cs:10:9:10:31 | call to method Assert | exit | +| Assert.cs:10:9:10:32 | ...; | Assert.cs:10:9:10:31 | call to method Assert | normal | +| Assert.cs:10:22:10:22 | access to local variable s | Assert.cs:10:22:10:22 | access to local variable s | normal | +| Assert.cs:10:22:10:30 | ... != ... | Assert.cs:10:22:10:30 | ... != ... | false | +| Assert.cs:10:22:10:30 | ... != ... | Assert.cs:10:22:10:30 | ... != ... | true | +| Assert.cs:10:27:10:30 | null | Assert.cs:10:27:10:30 | null | normal | +| Assert.cs:11:9:11:35 | call to method WriteLine | Assert.cs:11:9:11:35 | call to method WriteLine | normal | +| Assert.cs:11:9:11:36 | ...; | Assert.cs:11:9:11:35 | call to method WriteLine | normal | +| Assert.cs:11:27:11:27 | access to local variable s | Assert.cs:11:27:11:27 | access to local variable s | normal | +| Assert.cs:11:27:11:34 | access to property Length | Assert.cs:11:27:11:34 | access to property Length | normal | +| Assert.cs:15:5:19:5 | {...} | Assert.cs:17:9:17:24 | call to method IsNull | throw(AssertFailedException) | +| Assert.cs:15:5:19:5 | {...} | Assert.cs:18:9:18:35 | call to method WriteLine | normal | +| Assert.cs:16:9:16:33 | ... ...; | Assert.cs:16:16:16:32 | String s = ... | normal | +| Assert.cs:16:16:16:32 | String s = ... | Assert.cs:16:16:16:32 | String s = ... | normal | +| Assert.cs:16:20:16:20 | access to parameter b | Assert.cs:16:20:16:20 | access to parameter b | false | +| Assert.cs:16:20:16:20 | access to parameter b | Assert.cs:16:20:16:20 | access to parameter b | true | +| Assert.cs:16:20:16:32 | ... ? ... : ... | Assert.cs:16:24:16:27 | null | normal | +| Assert.cs:16:20:16:32 | ... ? ... : ... | Assert.cs:16:31:16:32 | "" | normal | +| Assert.cs:16:24:16:27 | null | Assert.cs:16:24:16:27 | null | normal | +| Assert.cs:16:31:16:32 | "" | Assert.cs:16:31:16:32 | "" | normal | +| Assert.cs:17:9:17:24 | call to method IsNull | Assert.cs:17:9:17:24 | call to method IsNull | normal | +| Assert.cs:17:9:17:24 | call to method IsNull | Assert.cs:17:9:17:24 | call to method IsNull | throw(AssertFailedException) | +| Assert.cs:17:9:17:25 | ...; | Assert.cs:17:9:17:24 | call to method IsNull | normal | +| Assert.cs:17:9:17:25 | ...; | Assert.cs:17:9:17:24 | call to method IsNull | throw(AssertFailedException) | +| Assert.cs:17:23:17:23 | access to local variable s | Assert.cs:17:23:17:23 | access to local variable s | non-null | +| Assert.cs:17:23:17:23 | access to local variable s | Assert.cs:17:23:17:23 | access to local variable s | null | +| Assert.cs:18:9:18:35 | call to method WriteLine | Assert.cs:18:9:18:35 | call to method WriteLine | normal | +| Assert.cs:18:9:18:36 | ...; | Assert.cs:18:9:18:35 | call to method WriteLine | normal | +| Assert.cs:18:27:18:27 | access to local variable s | Assert.cs:18:27:18:27 | access to local variable s | normal | +| Assert.cs:18:27:18:34 | access to property Length | Assert.cs:18:27:18:34 | access to property Length | normal | +| Assert.cs:22:5:26:5 | {...} | Assert.cs:24:9:24:27 | call to method IsNotNull | throw(AssertFailedException) | +| Assert.cs:22:5:26:5 | {...} | Assert.cs:25:9:25:35 | call to method WriteLine | normal | +| Assert.cs:23:9:23:33 | ... ...; | Assert.cs:23:16:23:32 | String s = ... | normal | +| Assert.cs:23:16:23:32 | String s = ... | Assert.cs:23:16:23:32 | String s = ... | normal | +| Assert.cs:23:20:23:20 | access to parameter b | Assert.cs:23:20:23:20 | access to parameter b | false | +| Assert.cs:23:20:23:20 | access to parameter b | Assert.cs:23:20:23:20 | access to parameter b | true | +| Assert.cs:23:20:23:32 | ... ? ... : ... | Assert.cs:23:24:23:27 | null | normal | +| Assert.cs:23:20:23:32 | ... ? ... : ... | Assert.cs:23:31:23:32 | "" | normal | +| Assert.cs:23:24:23:27 | null | Assert.cs:23:24:23:27 | null | normal | +| Assert.cs:23:31:23:32 | "" | Assert.cs:23:31:23:32 | "" | normal | +| Assert.cs:24:9:24:27 | call to method IsNotNull | Assert.cs:24:9:24:27 | call to method IsNotNull | normal | +| Assert.cs:24:9:24:27 | call to method IsNotNull | Assert.cs:24:9:24:27 | call to method IsNotNull | throw(AssertFailedException) | +| Assert.cs:24:9:24:28 | ...; | Assert.cs:24:9:24:27 | call to method IsNotNull | normal | +| Assert.cs:24:9:24:28 | ...; | Assert.cs:24:9:24:27 | call to method IsNotNull | throw(AssertFailedException) | +| Assert.cs:24:26:24:26 | access to local variable s | Assert.cs:24:26:24:26 | access to local variable s | non-null | +| Assert.cs:24:26:24:26 | access to local variable s | Assert.cs:24:26:24:26 | access to local variable s | null | +| Assert.cs:25:9:25:35 | call to method WriteLine | Assert.cs:25:9:25:35 | call to method WriteLine | normal | +| Assert.cs:25:9:25:36 | ...; | Assert.cs:25:9:25:35 | call to method WriteLine | normal | +| Assert.cs:25:27:25:27 | access to local variable s | Assert.cs:25:27:25:27 | access to local variable s | normal | +| Assert.cs:25:27:25:34 | access to property Length | Assert.cs:25:27:25:34 | access to property Length | normal | +| Assert.cs:29:5:33:5 | {...} | Assert.cs:31:9:31:32 | call to method IsTrue | throw(AssertFailedException) | +| Assert.cs:29:5:33:5 | {...} | Assert.cs:32:9:32:35 | call to method WriteLine | normal | +| Assert.cs:30:9:30:33 | ... ...; | Assert.cs:30:16:30:32 | String s = ... | normal | +| Assert.cs:30:16:30:32 | String s = ... | Assert.cs:30:16:30:32 | String s = ... | normal | +| Assert.cs:30:20:30:20 | access to parameter b | Assert.cs:30:20:30:20 | access to parameter b | false | +| Assert.cs:30:20:30:20 | access to parameter b | Assert.cs:30:20:30:20 | access to parameter b | true | +| Assert.cs:30:20:30:32 | ... ? ... : ... | Assert.cs:30:24:30:27 | null | normal | +| Assert.cs:30:20:30:32 | ... ? ... : ... | Assert.cs:30:31:30:32 | "" | normal | +| Assert.cs:30:24:30:27 | null | Assert.cs:30:24:30:27 | null | normal | +| Assert.cs:30:31:30:32 | "" | Assert.cs:30:31:30:32 | "" | normal | +| Assert.cs:31:9:31:32 | call to method IsTrue | Assert.cs:31:9:31:32 | call to method IsTrue | normal | +| Assert.cs:31:9:31:32 | call to method IsTrue | Assert.cs:31:9:31:32 | call to method IsTrue | throw(AssertFailedException) | +| Assert.cs:31:9:31:33 | ...; | Assert.cs:31:9:31:32 | call to method IsTrue | normal | +| Assert.cs:31:9:31:33 | ...; | Assert.cs:31:9:31:32 | call to method IsTrue | throw(AssertFailedException) | +| Assert.cs:31:23:31:23 | access to local variable s | Assert.cs:31:23:31:23 | access to local variable s | normal | +| Assert.cs:31:23:31:31 | ... == ... | Assert.cs:31:23:31:31 | ... == ... | false | +| Assert.cs:31:23:31:31 | ... == ... | Assert.cs:31:23:31:31 | ... == ... | true | +| Assert.cs:31:28:31:31 | null | Assert.cs:31:28:31:31 | null | normal | +| Assert.cs:32:9:32:35 | call to method WriteLine | Assert.cs:32:9:32:35 | call to method WriteLine | normal | +| Assert.cs:32:9:32:36 | ...; | Assert.cs:32:9:32:35 | call to method WriteLine | normal | +| Assert.cs:32:27:32:27 | access to local variable s | Assert.cs:32:27:32:27 | access to local variable s | normal | +| Assert.cs:32:27:32:34 | access to property Length | Assert.cs:32:27:32:34 | access to property Length | normal | +| Assert.cs:36:5:40:5 | {...} | Assert.cs:38:9:38:32 | call to method IsTrue | throw(AssertFailedException) | +| Assert.cs:36:5:40:5 | {...} | Assert.cs:39:9:39:35 | call to method WriteLine | normal | +| Assert.cs:37:9:37:33 | ... ...; | Assert.cs:37:16:37:32 | String s = ... | normal | +| Assert.cs:37:16:37:32 | String s = ... | Assert.cs:37:16:37:32 | String s = ... | normal | +| Assert.cs:37:20:37:20 | access to parameter b | Assert.cs:37:20:37:20 | access to parameter b | false | +| Assert.cs:37:20:37:20 | access to parameter b | Assert.cs:37:20:37:20 | access to parameter b | true | +| Assert.cs:37:20:37:32 | ... ? ... : ... | Assert.cs:37:24:37:27 | null | normal | +| Assert.cs:37:20:37:32 | ... ? ... : ... | Assert.cs:37:31:37:32 | "" | normal | +| Assert.cs:37:24:37:27 | null | Assert.cs:37:24:37:27 | null | normal | +| Assert.cs:37:31:37:32 | "" | Assert.cs:37:31:37:32 | "" | normal | +| Assert.cs:38:9:38:32 | call to method IsTrue | Assert.cs:38:9:38:32 | call to method IsTrue | normal | +| Assert.cs:38:9:38:32 | call to method IsTrue | Assert.cs:38:9:38:32 | call to method IsTrue | throw(AssertFailedException) | +| Assert.cs:38:9:38:33 | ...; | Assert.cs:38:9:38:32 | call to method IsTrue | normal | +| Assert.cs:38:9:38:33 | ...; | Assert.cs:38:9:38:32 | call to method IsTrue | throw(AssertFailedException) | +| Assert.cs:38:23:38:23 | access to local variable s | Assert.cs:38:23:38:23 | access to local variable s | normal | +| Assert.cs:38:23:38:31 | ... != ... | Assert.cs:38:23:38:31 | ... != ... | false | +| Assert.cs:38:23:38:31 | ... != ... | Assert.cs:38:23:38:31 | ... != ... | true | +| Assert.cs:38:28:38:31 | null | Assert.cs:38:28:38:31 | null | normal | +| Assert.cs:39:9:39:35 | call to method WriteLine | Assert.cs:39:9:39:35 | call to method WriteLine | normal | +| Assert.cs:39:9:39:36 | ...; | Assert.cs:39:9:39:35 | call to method WriteLine | normal | +| Assert.cs:39:27:39:27 | access to local variable s | Assert.cs:39:27:39:27 | access to local variable s | normal | +| Assert.cs:39:27:39:34 | access to property Length | Assert.cs:39:27:39:34 | access to property Length | normal | +| Assert.cs:43:5:47:5 | {...} | Assert.cs:45:9:45:33 | call to method IsFalse | throw(AssertFailedException) | +| Assert.cs:43:5:47:5 | {...} | Assert.cs:46:9:46:35 | call to method WriteLine | normal | +| Assert.cs:44:9:44:33 | ... ...; | Assert.cs:44:16:44:32 | String s = ... | normal | +| Assert.cs:44:16:44:32 | String s = ... | Assert.cs:44:16:44:32 | String s = ... | normal | +| Assert.cs:44:20:44:20 | access to parameter b | Assert.cs:44:20:44:20 | access to parameter b | false | +| Assert.cs:44:20:44:20 | access to parameter b | Assert.cs:44:20:44:20 | access to parameter b | true | +| Assert.cs:44:20:44:32 | ... ? ... : ... | Assert.cs:44:24:44:27 | null | normal | +| Assert.cs:44:20:44:32 | ... ? ... : ... | Assert.cs:44:31:44:32 | "" | normal | +| Assert.cs:44:24:44:27 | null | Assert.cs:44:24:44:27 | null | normal | +| Assert.cs:44:31:44:32 | "" | Assert.cs:44:31:44:32 | "" | normal | +| Assert.cs:45:9:45:33 | call to method IsFalse | Assert.cs:45:9:45:33 | call to method IsFalse | normal | +| Assert.cs:45:9:45:33 | call to method IsFalse | Assert.cs:45:9:45:33 | call to method IsFalse | throw(AssertFailedException) | +| Assert.cs:45:9:45:34 | ...; | Assert.cs:45:9:45:33 | call to method IsFalse | normal | +| Assert.cs:45:9:45:34 | ...; | Assert.cs:45:9:45:33 | call to method IsFalse | throw(AssertFailedException) | +| Assert.cs:45:24:45:24 | access to local variable s | Assert.cs:45:24:45:24 | access to local variable s | normal | +| Assert.cs:45:24:45:32 | ... != ... | Assert.cs:45:24:45:32 | ... != ... | false | +| Assert.cs:45:24:45:32 | ... != ... | Assert.cs:45:24:45:32 | ... != ... | true | +| Assert.cs:45:29:45:32 | null | Assert.cs:45:29:45:32 | null | normal | +| Assert.cs:46:9:46:35 | call to method WriteLine | Assert.cs:46:9:46:35 | call to method WriteLine | normal | +| Assert.cs:46:9:46:36 | ...; | Assert.cs:46:9:46:35 | call to method WriteLine | normal | +| Assert.cs:46:27:46:27 | access to local variable s | Assert.cs:46:27:46:27 | access to local variable s | normal | +| Assert.cs:46:27:46:34 | access to property Length | Assert.cs:46:27:46:34 | access to property Length | normal | +| Assert.cs:50:5:54:5 | {...} | Assert.cs:52:9:52:33 | call to method IsFalse | throw(AssertFailedException) | +| Assert.cs:50:5:54:5 | {...} | Assert.cs:53:9:53:35 | call to method WriteLine | normal | +| Assert.cs:51:9:51:33 | ... ...; | Assert.cs:51:16:51:32 | String s = ... | normal | +| Assert.cs:51:16:51:32 | String s = ... | Assert.cs:51:16:51:32 | String s = ... | normal | +| Assert.cs:51:20:51:20 | access to parameter b | Assert.cs:51:20:51:20 | access to parameter b | false | +| Assert.cs:51:20:51:20 | access to parameter b | Assert.cs:51:20:51:20 | access to parameter b | true | +| Assert.cs:51:20:51:32 | ... ? ... : ... | Assert.cs:51:24:51:27 | null | normal | +| Assert.cs:51:20:51:32 | ... ? ... : ... | Assert.cs:51:31:51:32 | "" | normal | +| Assert.cs:51:24:51:27 | null | Assert.cs:51:24:51:27 | null | normal | +| Assert.cs:51:31:51:32 | "" | Assert.cs:51:31:51:32 | "" | normal | +| Assert.cs:52:9:52:33 | call to method IsFalse | Assert.cs:52:9:52:33 | call to method IsFalse | normal | +| Assert.cs:52:9:52:33 | call to method IsFalse | Assert.cs:52:9:52:33 | call to method IsFalse | throw(AssertFailedException) | +| Assert.cs:52:9:52:34 | ...; | Assert.cs:52:9:52:33 | call to method IsFalse | normal | +| Assert.cs:52:9:52:34 | ...; | Assert.cs:52:9:52:33 | call to method IsFalse | throw(AssertFailedException) | +| Assert.cs:52:24:52:24 | access to local variable s | Assert.cs:52:24:52:24 | access to local variable s | normal | +| Assert.cs:52:24:52:32 | ... == ... | Assert.cs:52:24:52:32 | ... == ... | false | +| Assert.cs:52:24:52:32 | ... == ... | Assert.cs:52:24:52:32 | ... == ... | true | +| Assert.cs:52:29:52:32 | null | Assert.cs:52:29:52:32 | null | normal | +| Assert.cs:53:9:53:35 | call to method WriteLine | Assert.cs:53:9:53:35 | call to method WriteLine | normal | +| Assert.cs:53:9:53:36 | ...; | Assert.cs:53:9:53:35 | call to method WriteLine | normal | +| Assert.cs:53:27:53:27 | access to local variable s | Assert.cs:53:27:53:27 | access to local variable s | normal | +| Assert.cs:53:27:53:34 | access to property Length | Assert.cs:53:27:53:34 | access to property Length | normal | +| Assert.cs:57:5:61:5 | {...} | Assert.cs:59:9:59:37 | call to method IsTrue | throw(AssertFailedException) | +| Assert.cs:57:5:61:5 | {...} | Assert.cs:60:9:60:35 | call to method WriteLine | normal | +| Assert.cs:58:9:58:33 | ... ...; | Assert.cs:58:16:58:32 | String s = ... | normal | +| Assert.cs:58:16:58:32 | String s = ... | Assert.cs:58:16:58:32 | String s = ... | normal | +| Assert.cs:58:20:58:20 | access to parameter b | Assert.cs:58:20:58:20 | access to parameter b | false | +| Assert.cs:58:20:58:20 | access to parameter b | Assert.cs:58:20:58:20 | access to parameter b | true | +| Assert.cs:58:20:58:32 | ... ? ... : ... | Assert.cs:58:24:58:27 | null | normal | +| Assert.cs:58:20:58:32 | ... ? ... : ... | Assert.cs:58:31:58:32 | "" | normal | +| Assert.cs:58:24:58:27 | null | Assert.cs:58:24:58:27 | null | normal | +| Assert.cs:58:31:58:32 | "" | Assert.cs:58:31:58:32 | "" | normal | +| Assert.cs:59:9:59:37 | call to method IsTrue | Assert.cs:59:9:59:37 | call to method IsTrue | normal | +| Assert.cs:59:9:59:37 | call to method IsTrue | Assert.cs:59:9:59:37 | call to method IsTrue | throw(AssertFailedException) | +| Assert.cs:59:9:59:38 | ...; | Assert.cs:59:9:59:37 | call to method IsTrue | normal | +| Assert.cs:59:9:59:38 | ...; | Assert.cs:59:9:59:37 | call to method IsTrue | throw(AssertFailedException) | +| Assert.cs:59:23:59:23 | access to local variable s | Assert.cs:59:23:59:23 | access to local variable s | normal | +| Assert.cs:59:23:59:31 | ... != ... | Assert.cs:59:23:59:31 | ... != ... | false | +| Assert.cs:59:23:59:31 | ... != ... | Assert.cs:59:23:59:31 | ... != ... | true | +| Assert.cs:59:23:59:36 | ... && ... | Assert.cs:59:23:59:31 | ... != ... | false | +| Assert.cs:59:23:59:36 | ... && ... | Assert.cs:59:36:59:36 | access to parameter b | false | +| Assert.cs:59:23:59:36 | ... && ... | Assert.cs:59:36:59:36 | access to parameter b | true | +| Assert.cs:59:28:59:31 | null | Assert.cs:59:28:59:31 | null | normal | +| Assert.cs:59:36:59:36 | access to parameter b | Assert.cs:59:36:59:36 | access to parameter b | false | +| Assert.cs:59:36:59:36 | access to parameter b | Assert.cs:59:36:59:36 | access to parameter b | true | +| Assert.cs:60:9:60:35 | call to method WriteLine | Assert.cs:60:9:60:35 | call to method WriteLine | normal | +| Assert.cs:60:9:60:36 | ...; | Assert.cs:60:9:60:35 | call to method WriteLine | normal | +| Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:60:27:60:27 | access to local variable s | normal | +| Assert.cs:60:27:60:34 | access to property Length | Assert.cs:60:27:60:34 | access to property Length | normal | +| Assert.cs:64:5:68:5 | {...} | Assert.cs:66:9:66:38 | call to method IsFalse | throw(AssertFailedException) | +| Assert.cs:64:5:68:5 | {...} | Assert.cs:67:9:67:35 | call to method WriteLine | normal | +| Assert.cs:65:9:65:33 | ... ...; | Assert.cs:65:16:65:32 | String s = ... | normal | +| Assert.cs:65:16:65:32 | String s = ... | Assert.cs:65:16:65:32 | String s = ... | normal | +| Assert.cs:65:20:65:20 | access to parameter b | Assert.cs:65:20:65:20 | access to parameter b | false | +| Assert.cs:65:20:65:20 | access to parameter b | Assert.cs:65:20:65:20 | access to parameter b | true | +| Assert.cs:65:20:65:32 | ... ? ... : ... | Assert.cs:65:24:65:27 | null | normal | +| Assert.cs:65:20:65:32 | ... ? ... : ... | Assert.cs:65:31:65:32 | "" | normal | +| Assert.cs:65:24:65:27 | null | Assert.cs:65:24:65:27 | null | normal | +| Assert.cs:65:31:65:32 | "" | Assert.cs:65:31:65:32 | "" | normal | +| Assert.cs:66:9:66:38 | call to method IsFalse | Assert.cs:66:9:66:38 | call to method IsFalse | normal | +| Assert.cs:66:9:66:38 | call to method IsFalse | Assert.cs:66:9:66:38 | call to method IsFalse | throw(AssertFailedException) | +| Assert.cs:66:9:66:39 | ...; | Assert.cs:66:9:66:38 | call to method IsFalse | normal | +| Assert.cs:66:9:66:39 | ...; | Assert.cs:66:9:66:38 | call to method IsFalse | throw(AssertFailedException) | +| Assert.cs:66:24:66:24 | access to local variable s | Assert.cs:66:24:66:24 | access to local variable s | normal | +| Assert.cs:66:24:66:32 | ... == ... | Assert.cs:66:24:66:32 | ... == ... | false | +| Assert.cs:66:24:66:32 | ... == ... | Assert.cs:66:24:66:32 | ... == ... | true | +| Assert.cs:66:24:66:37 | ... \|\| ... | Assert.cs:66:24:66:32 | ... == ... | true | +| Assert.cs:66:24:66:37 | ... \|\| ... | Assert.cs:66:37:66:37 | access to parameter b | false | +| Assert.cs:66:24:66:37 | ... \|\| ... | Assert.cs:66:37:66:37 | access to parameter b | true | +| Assert.cs:66:29:66:32 | null | Assert.cs:66:29:66:32 | null | normal | +| Assert.cs:66:37:66:37 | access to parameter b | Assert.cs:66:37:66:37 | access to parameter b | false | +| Assert.cs:66:37:66:37 | access to parameter b | Assert.cs:66:37:66:37 | access to parameter b | true | +| Assert.cs:67:9:67:35 | call to method WriteLine | Assert.cs:67:9:67:35 | call to method WriteLine | normal | +| Assert.cs:67:9:67:36 | ...; | Assert.cs:67:9:67:35 | call to method WriteLine | normal | +| Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:67:27:67:27 | access to local variable s | normal | +| Assert.cs:67:27:67:34 | access to property Length | Assert.cs:67:27:67:34 | access to property Length | normal | +| Assert.cs:71:5:75:5 | {...} | Assert.cs:73:9:73:37 | call to method IsTrue | throw(AssertFailedException) | +| Assert.cs:71:5:75:5 | {...} | Assert.cs:74:9:74:35 | call to method WriteLine | normal | +| Assert.cs:72:9:72:33 | ... ...; | Assert.cs:72:16:72:32 | String s = ... | normal | +| Assert.cs:72:16:72:32 | String s = ... | Assert.cs:72:16:72:32 | String s = ... | normal | +| Assert.cs:72:20:72:20 | access to parameter b | Assert.cs:72:20:72:20 | access to parameter b | false | +| Assert.cs:72:20:72:20 | access to parameter b | Assert.cs:72:20:72:20 | access to parameter b | true | +| Assert.cs:72:20:72:32 | ... ? ... : ... | Assert.cs:72:24:72:27 | null | normal | +| Assert.cs:72:20:72:32 | ... ? ... : ... | Assert.cs:72:31:72:32 | "" | normal | +| Assert.cs:72:24:72:27 | null | Assert.cs:72:24:72:27 | null | normal | +| Assert.cs:72:31:72:32 | "" | Assert.cs:72:31:72:32 | "" | normal | +| Assert.cs:73:9:73:37 | call to method IsTrue | Assert.cs:73:9:73:37 | call to method IsTrue | normal | +| Assert.cs:73:9:73:37 | call to method IsTrue | Assert.cs:73:9:73:37 | call to method IsTrue | throw(AssertFailedException) | +| Assert.cs:73:9:73:38 | ...; | Assert.cs:73:9:73:37 | call to method IsTrue | normal | +| Assert.cs:73:9:73:38 | ...; | Assert.cs:73:9:73:37 | call to method IsTrue | throw(AssertFailedException) | +| Assert.cs:73:23:73:23 | access to local variable s | Assert.cs:73:23:73:23 | access to local variable s | normal | +| Assert.cs:73:23:73:31 | ... == ... | Assert.cs:73:23:73:31 | ... == ... | false | +| Assert.cs:73:23:73:31 | ... == ... | Assert.cs:73:23:73:31 | ... == ... | true | +| Assert.cs:73:23:73:36 | ... && ... | Assert.cs:73:23:73:31 | ... == ... | false | +| Assert.cs:73:23:73:36 | ... && ... | Assert.cs:73:36:73:36 | access to parameter b | false | +| Assert.cs:73:23:73:36 | ... && ... | Assert.cs:73:36:73:36 | access to parameter b | true | +| Assert.cs:73:28:73:31 | null | Assert.cs:73:28:73:31 | null | normal | +| Assert.cs:73:36:73:36 | access to parameter b | Assert.cs:73:36:73:36 | access to parameter b | false | +| Assert.cs:73:36:73:36 | access to parameter b | Assert.cs:73:36:73:36 | access to parameter b | true | +| Assert.cs:74:9:74:35 | call to method WriteLine | Assert.cs:74:9:74:35 | call to method WriteLine | normal | +| Assert.cs:74:9:74:36 | ...; | Assert.cs:74:9:74:35 | call to method WriteLine | normal | +| Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:74:27:74:27 | access to local variable s | normal | +| Assert.cs:74:27:74:34 | access to property Length | Assert.cs:74:27:74:34 | access to property Length | normal | +| Assert.cs:78:5:82:5 | {...} | Assert.cs:80:9:80:38 | call to method IsFalse | throw(AssertFailedException) | +| Assert.cs:78:5:82:5 | {...} | Assert.cs:81:9:81:35 | call to method WriteLine | normal | +| Assert.cs:79:9:79:33 | ... ...; | Assert.cs:79:16:79:32 | String s = ... | normal | +| Assert.cs:79:16:79:32 | String s = ... | Assert.cs:79:16:79:32 | String s = ... | normal | +| Assert.cs:79:20:79:20 | access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | false | +| Assert.cs:79:20:79:20 | access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | true | +| Assert.cs:79:20:79:32 | ... ? ... : ... | Assert.cs:79:24:79:27 | null | normal | +| Assert.cs:79:20:79:32 | ... ? ... : ... | Assert.cs:79:31:79:32 | "" | normal | +| Assert.cs:79:24:79:27 | null | Assert.cs:79:24:79:27 | null | normal | +| Assert.cs:79:31:79:32 | "" | Assert.cs:79:31:79:32 | "" | normal | +| Assert.cs:80:9:80:38 | call to method IsFalse | Assert.cs:80:9:80:38 | call to method IsFalse | normal | +| Assert.cs:80:9:80:38 | call to method IsFalse | Assert.cs:80:9:80:38 | call to method IsFalse | throw(AssertFailedException) | +| Assert.cs:80:9:80:39 | ...; | Assert.cs:80:9:80:38 | call to method IsFalse | normal | +| Assert.cs:80:9:80:39 | ...; | Assert.cs:80:9:80:38 | call to method IsFalse | throw(AssertFailedException) | +| Assert.cs:80:24:80:24 | access to local variable s | Assert.cs:80:24:80:24 | access to local variable s | normal | +| Assert.cs:80:24:80:32 | ... != ... | Assert.cs:80:24:80:32 | ... != ... | false | +| Assert.cs:80:24:80:32 | ... != ... | Assert.cs:80:24:80:32 | ... != ... | true | +| Assert.cs:80:24:80:37 | ... \|\| ... | Assert.cs:80:24:80:32 | ... != ... | true | +| Assert.cs:80:24:80:37 | ... \|\| ... | Assert.cs:80:37:80:37 | access to parameter b | false | +| Assert.cs:80:24:80:37 | ... \|\| ... | Assert.cs:80:37:80:37 | access to parameter b | true | +| Assert.cs:80:29:80:32 | null | Assert.cs:80:29:80:32 | null | normal | +| Assert.cs:80:37:80:37 | access to parameter b | Assert.cs:80:37:80:37 | access to parameter b | false | +| Assert.cs:80:37:80:37 | access to parameter b | Assert.cs:80:37:80:37 | access to parameter b | true | +| Assert.cs:81:9:81:35 | call to method WriteLine | Assert.cs:81:9:81:35 | call to method WriteLine | normal | +| Assert.cs:81:9:81:36 | ...; | Assert.cs:81:9:81:35 | call to method WriteLine | normal | +| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:81:27:81:27 | access to local variable s | normal | +| Assert.cs:81:27:81:34 | access to property Length | Assert.cs:81:27:81:34 | access to property Length | normal | +| Assert.cs:85:5:129:5 | {...} | Assert.cs:87:9:87:31 | call to method Assert | exit | +| Assert.cs:85:5:129:5 | {...} | Assert.cs:91:9:91:24 | call to method IsNull | throw(AssertFailedException) | +| Assert.cs:85:5:129:5 | {...} | Assert.cs:95:9:95:27 | call to method IsNotNull | throw(AssertFailedException) | +| Assert.cs:85:5:129:5 | {...} | Assert.cs:99:9:99:32 | call to method IsTrue | throw(AssertFailedException) | +| Assert.cs:85:5:129:5 | {...} | Assert.cs:103:9:103:32 | call to method IsTrue | throw(AssertFailedException) | +| Assert.cs:85:5:129:5 | {...} | Assert.cs:107:9:107:33 | call to method IsFalse | throw(AssertFailedException) | +| Assert.cs:85:5:129:5 | {...} | Assert.cs:111:9:111:33 | call to method IsFalse | throw(AssertFailedException) | +| Assert.cs:85:5:129:5 | {...} | Assert.cs:115:9:115:37 | call to method IsTrue | throw(AssertFailedException) | +| Assert.cs:85:5:129:5 | {...} | Assert.cs:119:9:119:39 | call to method IsFalse | throw(AssertFailedException) | +| Assert.cs:85:5:129:5 | {...} | Assert.cs:123:9:123:37 | call to method IsTrue | throw(AssertFailedException) | +| Assert.cs:85:5:129:5 | {...} | Assert.cs:127:9:127:39 | call to method IsFalse | throw(AssertFailedException) | +| Assert.cs:85:5:129:5 | {...} | Assert.cs:128:9:128:35 | call to method WriteLine | normal | +| Assert.cs:86:9:86:33 | ... ...; | Assert.cs:86:16:86:32 | String s = ... | normal | +| Assert.cs:86:16:86:32 | String s = ... | Assert.cs:86:16:86:32 | String s = ... | normal | +| Assert.cs:86:20:86:20 | access to parameter b | Assert.cs:86:20:86:20 | access to parameter b | false | +| Assert.cs:86:20:86:20 | access to parameter b | Assert.cs:86:20:86:20 | access to parameter b | true | +| Assert.cs:86:20:86:32 | ... ? ... : ... | Assert.cs:86:24:86:27 | null | normal | +| Assert.cs:86:20:86:32 | ... ? ... : ... | Assert.cs:86:31:86:32 | "" | normal | +| Assert.cs:86:24:86:27 | null | Assert.cs:86:24:86:27 | null | normal | +| Assert.cs:86:31:86:32 | "" | Assert.cs:86:31:86:32 | "" | normal | +| Assert.cs:87:9:87:31 | call to method Assert | Assert.cs:87:9:87:31 | call to method Assert | exit | +| Assert.cs:87:9:87:31 | call to method Assert | Assert.cs:87:9:87:31 | call to method Assert | normal | +| Assert.cs:87:9:87:32 | ...; | Assert.cs:87:9:87:31 | call to method Assert | exit | +| Assert.cs:87:9:87:32 | ...; | Assert.cs:87:9:87:31 | call to method Assert | normal | +| Assert.cs:87:22:87:22 | access to local variable s | Assert.cs:87:22:87:22 | access to local variable s | normal | +| Assert.cs:87:22:87:30 | ... != ... | Assert.cs:87:22:87:30 | ... != ... | false | +| Assert.cs:87:22:87:30 | ... != ... | Assert.cs:87:22:87:30 | ... != ... | true | +| Assert.cs:87:27:87:30 | null | Assert.cs:87:27:87:30 | null | normal | +| Assert.cs:88:9:88:35 | call to method WriteLine | Assert.cs:88:9:88:35 | call to method WriteLine | normal | +| Assert.cs:88:9:88:36 | ...; | Assert.cs:88:9:88:35 | call to method WriteLine | normal | +| Assert.cs:88:27:88:27 | access to local variable s | Assert.cs:88:27:88:27 | access to local variable s | normal | +| Assert.cs:88:27:88:34 | access to property Length | Assert.cs:88:27:88:34 | access to property Length | normal | +| Assert.cs:90:9:90:25 | ... = ... | Assert.cs:90:9:90:25 | ... = ... | normal | +| Assert.cs:90:9:90:26 | ...; | Assert.cs:90:9:90:25 | ... = ... | normal | +| Assert.cs:90:13:90:13 | access to parameter b | Assert.cs:90:13:90:13 | access to parameter b | false | +| Assert.cs:90:13:90:13 | access to parameter b | Assert.cs:90:13:90:13 | access to parameter b | true | +| Assert.cs:90:13:90:25 | ... ? ... : ... | Assert.cs:90:17:90:20 | null | normal | +| Assert.cs:90:13:90:25 | ... ? ... : ... | Assert.cs:90:24:90:25 | "" | normal | +| Assert.cs:90:17:90:20 | null | Assert.cs:90:17:90:20 | null | normal | +| Assert.cs:90:24:90:25 | "" | Assert.cs:90:24:90:25 | "" | normal | +| Assert.cs:91:9:91:24 | call to method IsNull | Assert.cs:91:9:91:24 | call to method IsNull | normal | +| Assert.cs:91:9:91:24 | call to method IsNull | Assert.cs:91:9:91:24 | call to method IsNull | throw(AssertFailedException) | +| Assert.cs:91:9:91:25 | ...; | Assert.cs:91:9:91:24 | call to method IsNull | normal | +| Assert.cs:91:9:91:25 | ...; | Assert.cs:91:9:91:24 | call to method IsNull | throw(AssertFailedException) | +| Assert.cs:91:23:91:23 | access to local variable s | Assert.cs:91:23:91:23 | access to local variable s | non-null | +| Assert.cs:91:23:91:23 | access to local variable s | Assert.cs:91:23:91:23 | access to local variable s | null | +| Assert.cs:92:9:92:35 | call to method WriteLine | Assert.cs:92:9:92:35 | call to method WriteLine | normal | +| Assert.cs:92:9:92:36 | ...; | Assert.cs:92:9:92:35 | call to method WriteLine | normal | +| Assert.cs:92:27:92:27 | access to local variable s | Assert.cs:92:27:92:27 | access to local variable s | normal | +| Assert.cs:92:27:92:34 | access to property Length | Assert.cs:92:27:92:34 | access to property Length | normal | +| Assert.cs:94:9:94:25 | ... = ... | Assert.cs:94:9:94:25 | ... = ... | normal | +| Assert.cs:94:9:94:26 | ...; | Assert.cs:94:9:94:25 | ... = ... | normal | +| Assert.cs:94:13:94:13 | access to parameter b | Assert.cs:94:13:94:13 | access to parameter b | false | +| Assert.cs:94:13:94:13 | access to parameter b | Assert.cs:94:13:94:13 | access to parameter b | true | +| Assert.cs:94:13:94:25 | ... ? ... : ... | Assert.cs:94:17:94:20 | null | normal | +| Assert.cs:94:13:94:25 | ... ? ... : ... | Assert.cs:94:24:94:25 | "" | normal | +| Assert.cs:94:17:94:20 | null | Assert.cs:94:17:94:20 | null | normal | +| Assert.cs:94:24:94:25 | "" | Assert.cs:94:24:94:25 | "" | normal | +| Assert.cs:95:9:95:27 | call to method IsNotNull | Assert.cs:95:9:95:27 | call to method IsNotNull | normal | +| Assert.cs:95:9:95:27 | call to method IsNotNull | Assert.cs:95:9:95:27 | call to method IsNotNull | throw(AssertFailedException) | +| Assert.cs:95:9:95:28 | ...; | Assert.cs:95:9:95:27 | call to method IsNotNull | normal | +| Assert.cs:95:9:95:28 | ...; | Assert.cs:95:9:95:27 | call to method IsNotNull | throw(AssertFailedException) | +| Assert.cs:95:26:95:26 | access to local variable s | Assert.cs:95:26:95:26 | access to local variable s | non-null | +| Assert.cs:95:26:95:26 | access to local variable s | Assert.cs:95:26:95:26 | access to local variable s | null | +| Assert.cs:96:9:96:35 | call to method WriteLine | Assert.cs:96:9:96:35 | call to method WriteLine | normal | +| Assert.cs:96:9:96:36 | ...; | Assert.cs:96:9:96:35 | call to method WriteLine | normal | +| Assert.cs:96:27:96:27 | access to local variable s | Assert.cs:96:27:96:27 | access to local variable s | normal | +| Assert.cs:96:27:96:34 | access to property Length | Assert.cs:96:27:96:34 | access to property Length | normal | +| Assert.cs:98:9:98:25 | ... = ... | Assert.cs:98:9:98:25 | ... = ... | normal | +| Assert.cs:98:9:98:26 | ...; | Assert.cs:98:9:98:25 | ... = ... | normal | +| Assert.cs:98:13:98:13 | access to parameter b | Assert.cs:98:13:98:13 | access to parameter b | false | +| Assert.cs:98:13:98:13 | access to parameter b | Assert.cs:98:13:98:13 | access to parameter b | true | +| Assert.cs:98:13:98:25 | ... ? ... : ... | Assert.cs:98:17:98:20 | null | normal | +| Assert.cs:98:13:98:25 | ... ? ... : ... | Assert.cs:98:24:98:25 | "" | normal | +| Assert.cs:98:17:98:20 | null | Assert.cs:98:17:98:20 | null | normal | +| Assert.cs:98:24:98:25 | "" | Assert.cs:98:24:98:25 | "" | normal | +| Assert.cs:99:9:99:32 | call to method IsTrue | Assert.cs:99:9:99:32 | call to method IsTrue | normal | +| Assert.cs:99:9:99:32 | call to method IsTrue | Assert.cs:99:9:99:32 | call to method IsTrue | throw(AssertFailedException) | +| Assert.cs:99:9:99:33 | ...; | Assert.cs:99:9:99:32 | call to method IsTrue | normal | +| Assert.cs:99:9:99:33 | ...; | Assert.cs:99:9:99:32 | call to method IsTrue | throw(AssertFailedException) | +| Assert.cs:99:23:99:23 | access to local variable s | Assert.cs:99:23:99:23 | access to local variable s | normal | +| Assert.cs:99:23:99:31 | ... == ... | Assert.cs:99:23:99:31 | ... == ... | false | +| Assert.cs:99:23:99:31 | ... == ... | Assert.cs:99:23:99:31 | ... == ... | true | +| Assert.cs:99:28:99:31 | null | Assert.cs:99:28:99:31 | null | normal | +| Assert.cs:100:9:100:35 | call to method WriteLine | Assert.cs:100:9:100:35 | call to method WriteLine | normal | +| Assert.cs:100:9:100:36 | ...; | Assert.cs:100:9:100:35 | call to method WriteLine | normal | +| Assert.cs:100:27:100:27 | access to local variable s | Assert.cs:100:27:100:27 | access to local variable s | normal | +| Assert.cs:100:27:100:34 | access to property Length | Assert.cs:100:27:100:34 | access to property Length | normal | +| Assert.cs:102:9:102:25 | ... = ... | Assert.cs:102:9:102:25 | ... = ... | normal | +| Assert.cs:102:9:102:26 | ...; | Assert.cs:102:9:102:25 | ... = ... | normal | +| Assert.cs:102:13:102:13 | access to parameter b | Assert.cs:102:13:102:13 | access to parameter b | false | +| Assert.cs:102:13:102:13 | access to parameter b | Assert.cs:102:13:102:13 | access to parameter b | true | +| Assert.cs:102:13:102:25 | ... ? ... : ... | Assert.cs:102:17:102:20 | null | normal | +| Assert.cs:102:13:102:25 | ... ? ... : ... | Assert.cs:102:24:102:25 | "" | normal | +| Assert.cs:102:17:102:20 | null | Assert.cs:102:17:102:20 | null | normal | +| Assert.cs:102:24:102:25 | "" | Assert.cs:102:24:102:25 | "" | normal | +| Assert.cs:103:9:103:32 | call to method IsTrue | Assert.cs:103:9:103:32 | call to method IsTrue | normal | +| Assert.cs:103:9:103:32 | call to method IsTrue | Assert.cs:103:9:103:32 | call to method IsTrue | throw(AssertFailedException) | +| Assert.cs:103:9:103:33 | ...; | Assert.cs:103:9:103:32 | call to method IsTrue | normal | +| Assert.cs:103:9:103:33 | ...; | Assert.cs:103:9:103:32 | call to method IsTrue | throw(AssertFailedException) | +| Assert.cs:103:23:103:23 | access to local variable s | Assert.cs:103:23:103:23 | access to local variable s | normal | +| Assert.cs:103:23:103:31 | ... != ... | Assert.cs:103:23:103:31 | ... != ... | false | +| Assert.cs:103:23:103:31 | ... != ... | Assert.cs:103:23:103:31 | ... != ... | true | +| Assert.cs:103:28:103:31 | null | Assert.cs:103:28:103:31 | null | normal | +| Assert.cs:104:9:104:35 | call to method WriteLine | Assert.cs:104:9:104:35 | call to method WriteLine | normal | +| Assert.cs:104:9:104:36 | ...; | Assert.cs:104:9:104:35 | call to method WriteLine | normal | +| Assert.cs:104:27:104:27 | access to local variable s | Assert.cs:104:27:104:27 | access to local variable s | normal | +| Assert.cs:104:27:104:34 | access to property Length | Assert.cs:104:27:104:34 | access to property Length | normal | +| Assert.cs:106:9:106:25 | ... = ... | Assert.cs:106:9:106:25 | ... = ... | normal | +| Assert.cs:106:9:106:26 | ...; | Assert.cs:106:9:106:25 | ... = ... | normal | +| Assert.cs:106:13:106:13 | access to parameter b | Assert.cs:106:13:106:13 | access to parameter b | false | +| Assert.cs:106:13:106:13 | access to parameter b | Assert.cs:106:13:106:13 | access to parameter b | true | +| Assert.cs:106:13:106:25 | ... ? ... : ... | Assert.cs:106:17:106:20 | null | normal | +| Assert.cs:106:13:106:25 | ... ? ... : ... | Assert.cs:106:24:106:25 | "" | normal | +| Assert.cs:106:17:106:20 | null | Assert.cs:106:17:106:20 | null | normal | +| Assert.cs:106:24:106:25 | "" | Assert.cs:106:24:106:25 | "" | normal | +| Assert.cs:107:9:107:33 | call to method IsFalse | Assert.cs:107:9:107:33 | call to method IsFalse | normal | +| Assert.cs:107:9:107:33 | call to method IsFalse | Assert.cs:107:9:107:33 | call to method IsFalse | throw(AssertFailedException) | +| Assert.cs:107:9:107:34 | ...; | Assert.cs:107:9:107:33 | call to method IsFalse | normal | +| Assert.cs:107:9:107:34 | ...; | Assert.cs:107:9:107:33 | call to method IsFalse | throw(AssertFailedException) | +| Assert.cs:107:24:107:24 | access to local variable s | Assert.cs:107:24:107:24 | access to local variable s | normal | +| Assert.cs:107:24:107:32 | ... != ... | Assert.cs:107:24:107:32 | ... != ... | false | +| Assert.cs:107:24:107:32 | ... != ... | Assert.cs:107:24:107:32 | ... != ... | true | +| Assert.cs:107:29:107:32 | null | Assert.cs:107:29:107:32 | null | normal | +| Assert.cs:108:9:108:35 | call to method WriteLine | Assert.cs:108:9:108:35 | call to method WriteLine | normal | +| Assert.cs:108:9:108:36 | ...; | Assert.cs:108:9:108:35 | call to method WriteLine | normal | +| Assert.cs:108:27:108:27 | access to local variable s | Assert.cs:108:27:108:27 | access to local variable s | normal | +| Assert.cs:108:27:108:34 | access to property Length | Assert.cs:108:27:108:34 | access to property Length | normal | +| Assert.cs:110:9:110:25 | ... = ... | Assert.cs:110:9:110:25 | ... = ... | normal | +| Assert.cs:110:9:110:26 | ...; | Assert.cs:110:9:110:25 | ... = ... | normal | +| Assert.cs:110:13:110:13 | access to parameter b | Assert.cs:110:13:110:13 | access to parameter b | false | +| Assert.cs:110:13:110:13 | access to parameter b | Assert.cs:110:13:110:13 | access to parameter b | true | +| Assert.cs:110:13:110:25 | ... ? ... : ... | Assert.cs:110:17:110:20 | null | normal | +| Assert.cs:110:13:110:25 | ... ? ... : ... | Assert.cs:110:24:110:25 | "" | normal | +| Assert.cs:110:17:110:20 | null | Assert.cs:110:17:110:20 | null | normal | +| Assert.cs:110:24:110:25 | "" | Assert.cs:110:24:110:25 | "" | normal | +| Assert.cs:111:9:111:33 | call to method IsFalse | Assert.cs:111:9:111:33 | call to method IsFalse | normal | +| Assert.cs:111:9:111:33 | call to method IsFalse | Assert.cs:111:9:111:33 | call to method IsFalse | throw(AssertFailedException) | +| Assert.cs:111:9:111:34 | ...; | Assert.cs:111:9:111:33 | call to method IsFalse | normal | +| Assert.cs:111:9:111:34 | ...; | Assert.cs:111:9:111:33 | call to method IsFalse | throw(AssertFailedException) | +| Assert.cs:111:24:111:24 | access to local variable s | Assert.cs:111:24:111:24 | access to local variable s | normal | +| Assert.cs:111:24:111:32 | ... == ... | Assert.cs:111:24:111:32 | ... == ... | false | +| Assert.cs:111:24:111:32 | ... == ... | Assert.cs:111:24:111:32 | ... == ... | true | +| Assert.cs:111:29:111:32 | null | Assert.cs:111:29:111:32 | null | normal | +| Assert.cs:112:9:112:35 | call to method WriteLine | Assert.cs:112:9:112:35 | call to method WriteLine | normal | +| Assert.cs:112:9:112:36 | ...; | Assert.cs:112:9:112:35 | call to method WriteLine | normal | +| Assert.cs:112:27:112:27 | access to local variable s | Assert.cs:112:27:112:27 | access to local variable s | normal | +| Assert.cs:112:27:112:34 | access to property Length | Assert.cs:112:27:112:34 | access to property Length | normal | +| Assert.cs:114:9:114:25 | ... = ... | Assert.cs:114:9:114:25 | ... = ... | normal | +| Assert.cs:114:9:114:26 | ...; | Assert.cs:114:9:114:25 | ... = ... | normal | +| Assert.cs:114:13:114:13 | access to parameter b | Assert.cs:114:13:114:13 | access to parameter b | false | +| Assert.cs:114:13:114:13 | access to parameter b | Assert.cs:114:13:114:13 | access to parameter b | true | +| Assert.cs:114:13:114:25 | ... ? ... : ... | Assert.cs:114:17:114:20 | null | normal | +| Assert.cs:114:13:114:25 | ... ? ... : ... | Assert.cs:114:24:114:25 | "" | normal | +| Assert.cs:114:17:114:20 | null | Assert.cs:114:17:114:20 | null | normal | +| Assert.cs:114:24:114:25 | "" | Assert.cs:114:24:114:25 | "" | normal | +| Assert.cs:115:9:115:37 | call to method IsTrue | Assert.cs:115:9:115:37 | call to method IsTrue | normal | +| Assert.cs:115:9:115:37 | call to method IsTrue | Assert.cs:115:9:115:37 | call to method IsTrue | throw(AssertFailedException) | +| Assert.cs:115:9:115:38 | ...; | Assert.cs:115:9:115:37 | call to method IsTrue | normal | +| Assert.cs:115:9:115:38 | ...; | Assert.cs:115:9:115:37 | call to method IsTrue | throw(AssertFailedException) | +| Assert.cs:115:23:115:23 | access to local variable s | Assert.cs:115:23:115:23 | access to local variable s | normal | +| Assert.cs:115:23:115:31 | ... != ... | Assert.cs:115:23:115:31 | ... != ... | false | +| Assert.cs:115:23:115:31 | ... != ... | Assert.cs:115:23:115:31 | ... != ... | true | +| Assert.cs:115:23:115:36 | ... && ... | Assert.cs:115:23:115:31 | ... != ... | false | +| Assert.cs:115:23:115:36 | ... && ... | Assert.cs:115:36:115:36 | access to parameter b | false | +| Assert.cs:115:23:115:36 | ... && ... | Assert.cs:115:36:115:36 | access to parameter b | true | +| Assert.cs:115:28:115:31 | null | Assert.cs:115:28:115:31 | null | normal | +| Assert.cs:115:36:115:36 | access to parameter b | Assert.cs:115:36:115:36 | access to parameter b | false | +| Assert.cs:115:36:115:36 | access to parameter b | Assert.cs:115:36:115:36 | access to parameter b | true | +| Assert.cs:116:9:116:35 | call to method WriteLine | Assert.cs:116:9:116:35 | call to method WriteLine | normal | +| Assert.cs:116:9:116:36 | ...; | Assert.cs:116:9:116:35 | call to method WriteLine | normal | +| Assert.cs:116:27:116:27 | access to local variable s | Assert.cs:116:27:116:27 | access to local variable s | normal | +| Assert.cs:116:27:116:34 | access to property Length | Assert.cs:116:27:116:34 | access to property Length | normal | +| Assert.cs:118:9:118:25 | ... = ... | Assert.cs:118:9:118:25 | ... = ... | normal | +| Assert.cs:118:9:118:26 | ...; | Assert.cs:118:9:118:25 | ... = ... | normal | +| Assert.cs:118:13:118:13 | access to parameter b | Assert.cs:118:13:118:13 | access to parameter b | false | +| Assert.cs:118:13:118:13 | access to parameter b | Assert.cs:118:13:118:13 | access to parameter b | true | +| Assert.cs:118:13:118:25 | ... ? ... : ... | Assert.cs:118:17:118:20 | null | normal | +| Assert.cs:118:13:118:25 | ... ? ... : ... | Assert.cs:118:24:118:25 | "" | normal | +| Assert.cs:118:17:118:20 | null | Assert.cs:118:17:118:20 | null | normal | +| Assert.cs:118:24:118:25 | "" | Assert.cs:118:24:118:25 | "" | normal | +| Assert.cs:119:9:119:39 | call to method IsFalse | Assert.cs:119:9:119:39 | call to method IsFalse | normal | +| Assert.cs:119:9:119:39 | call to method IsFalse | Assert.cs:119:9:119:39 | call to method IsFalse | throw(AssertFailedException) | +| Assert.cs:119:9:119:40 | ...; | Assert.cs:119:9:119:39 | call to method IsFalse | normal | +| Assert.cs:119:9:119:40 | ...; | Assert.cs:119:9:119:39 | call to method IsFalse | throw(AssertFailedException) | +| Assert.cs:119:24:119:24 | access to local variable s | Assert.cs:119:24:119:24 | access to local variable s | normal | +| Assert.cs:119:24:119:32 | ... == ... | Assert.cs:119:24:119:32 | ... == ... | false | +| Assert.cs:119:24:119:32 | ... == ... | Assert.cs:119:24:119:32 | ... == ... | true | +| Assert.cs:119:24:119:38 | ... \|\| ... | Assert.cs:119:24:119:32 | ... == ... | true | +| Assert.cs:119:24:119:38 | ... \|\| ... | Assert.cs:119:38:119:38 | access to parameter b | false [true] | +| Assert.cs:119:24:119:38 | ... \|\| ... | Assert.cs:119:38:119:38 | access to parameter b | true [false] | +| Assert.cs:119:29:119:32 | null | Assert.cs:119:29:119:32 | null | normal | +| Assert.cs:119:37:119:38 | !... | Assert.cs:119:38:119:38 | access to parameter b | false [true] | +| Assert.cs:119:37:119:38 | !... | Assert.cs:119:38:119:38 | access to parameter b | true [false] | +| Assert.cs:119:38:119:38 | access to parameter b | Assert.cs:119:38:119:38 | access to parameter b | false | +| Assert.cs:119:38:119:38 | access to parameter b | Assert.cs:119:38:119:38 | access to parameter b | true | +| Assert.cs:120:9:120:35 | call to method WriteLine | Assert.cs:120:9:120:35 | call to method WriteLine | normal | +| Assert.cs:120:9:120:36 | ...; | Assert.cs:120:9:120:35 | call to method WriteLine | normal | +| Assert.cs:120:27:120:27 | access to local variable s | Assert.cs:120:27:120:27 | access to local variable s | normal | +| Assert.cs:120:27:120:34 | access to property Length | Assert.cs:120:27:120:34 | access to property Length | normal | +| Assert.cs:122:9:122:25 | ... = ... | Assert.cs:122:9:122:25 | ... = ... | normal | +| Assert.cs:122:9:122:26 | ...; | Assert.cs:122:9:122:25 | ... = ... | normal | +| Assert.cs:122:13:122:13 | access to parameter b | Assert.cs:122:13:122:13 | access to parameter b | false | +| Assert.cs:122:13:122:13 | access to parameter b | Assert.cs:122:13:122:13 | access to parameter b | true | +| Assert.cs:122:13:122:25 | ... ? ... : ... | Assert.cs:122:17:122:20 | null | normal | +| Assert.cs:122:13:122:25 | ... ? ... : ... | Assert.cs:122:24:122:25 | "" | normal | +| Assert.cs:122:17:122:20 | null | Assert.cs:122:17:122:20 | null | normal | +| Assert.cs:122:24:122:25 | "" | Assert.cs:122:24:122:25 | "" | normal | +| Assert.cs:123:9:123:37 | call to method IsTrue | Assert.cs:123:9:123:37 | call to method IsTrue | normal | +| Assert.cs:123:9:123:37 | call to method IsTrue | Assert.cs:123:9:123:37 | call to method IsTrue | throw(AssertFailedException) | +| Assert.cs:123:9:123:38 | ...; | Assert.cs:123:9:123:37 | call to method IsTrue | normal | +| Assert.cs:123:9:123:38 | ...; | Assert.cs:123:9:123:37 | call to method IsTrue | throw(AssertFailedException) | +| Assert.cs:123:23:123:23 | access to local variable s | Assert.cs:123:23:123:23 | access to local variable s | normal | +| Assert.cs:123:23:123:31 | ... == ... | Assert.cs:123:23:123:31 | ... == ... | false | +| Assert.cs:123:23:123:31 | ... == ... | Assert.cs:123:23:123:31 | ... == ... | true | +| Assert.cs:123:23:123:36 | ... && ... | Assert.cs:123:23:123:31 | ... == ... | false | +| Assert.cs:123:23:123:36 | ... && ... | Assert.cs:123:36:123:36 | access to parameter b | false | +| Assert.cs:123:23:123:36 | ... && ... | Assert.cs:123:36:123:36 | access to parameter b | true | +| Assert.cs:123:28:123:31 | null | Assert.cs:123:28:123:31 | null | normal | +| Assert.cs:123:36:123:36 | access to parameter b | Assert.cs:123:36:123:36 | access to parameter b | false | +| Assert.cs:123:36:123:36 | access to parameter b | Assert.cs:123:36:123:36 | access to parameter b | true | +| Assert.cs:124:9:124:35 | call to method WriteLine | Assert.cs:124:9:124:35 | call to method WriteLine | normal | +| Assert.cs:124:9:124:36 | ...; | Assert.cs:124:9:124:35 | call to method WriteLine | normal | +| Assert.cs:124:27:124:27 | access to local variable s | Assert.cs:124:27:124:27 | access to local variable s | normal | +| Assert.cs:124:27:124:34 | access to property Length | Assert.cs:124:27:124:34 | access to property Length | normal | +| Assert.cs:126:9:126:25 | ... = ... | Assert.cs:126:9:126:25 | ... = ... | normal | +| Assert.cs:126:9:126:26 | ...; | Assert.cs:126:9:126:25 | ... = ... | normal | +| Assert.cs:126:13:126:13 | access to parameter b | Assert.cs:126:13:126:13 | access to parameter b | false | +| Assert.cs:126:13:126:13 | access to parameter b | Assert.cs:126:13:126:13 | access to parameter b | true | +| Assert.cs:126:13:126:25 | ... ? ... : ... | Assert.cs:126:17:126:20 | null | normal | +| Assert.cs:126:13:126:25 | ... ? ... : ... | Assert.cs:126:24:126:25 | "" | normal | +| Assert.cs:126:17:126:20 | null | Assert.cs:126:17:126:20 | null | normal | +| Assert.cs:126:24:126:25 | "" | Assert.cs:126:24:126:25 | "" | normal | +| Assert.cs:127:9:127:39 | call to method IsFalse | Assert.cs:127:9:127:39 | call to method IsFalse | normal | +| Assert.cs:127:9:127:39 | call to method IsFalse | Assert.cs:127:9:127:39 | call to method IsFalse | throw(AssertFailedException) | +| Assert.cs:127:9:127:40 | ...; | Assert.cs:127:9:127:39 | call to method IsFalse | normal | +| Assert.cs:127:9:127:40 | ...; | Assert.cs:127:9:127:39 | call to method IsFalse | throw(AssertFailedException) | +| Assert.cs:127:24:127:24 | access to local variable s | Assert.cs:127:24:127:24 | access to local variable s | normal | +| Assert.cs:127:24:127:32 | ... != ... | Assert.cs:127:24:127:32 | ... != ... | false | +| Assert.cs:127:24:127:32 | ... != ... | Assert.cs:127:24:127:32 | ... != ... | true | +| Assert.cs:127:24:127:38 | ... \|\| ... | Assert.cs:127:24:127:32 | ... != ... | true | +| Assert.cs:127:24:127:38 | ... \|\| ... | Assert.cs:127:38:127:38 | access to parameter b | false [true] | +| Assert.cs:127:24:127:38 | ... \|\| ... | Assert.cs:127:38:127:38 | access to parameter b | true [false] | +| Assert.cs:127:29:127:32 | null | Assert.cs:127:29:127:32 | null | normal | +| Assert.cs:127:37:127:38 | !... | Assert.cs:127:38:127:38 | access to parameter b | false [true] | +| Assert.cs:127:37:127:38 | !... | Assert.cs:127:38:127:38 | access to parameter b | true [false] | +| Assert.cs:127:38:127:38 | access to parameter b | Assert.cs:127:38:127:38 | access to parameter b | false | +| Assert.cs:127:38:127:38 | access to parameter b | Assert.cs:127:38:127:38 | access to parameter b | true | +| Assert.cs:128:9:128:35 | call to method WriteLine | Assert.cs:128:9:128:35 | call to method WriteLine | normal | +| Assert.cs:128:9:128:36 | ...; | Assert.cs:128:9:128:35 | call to method WriteLine | normal | +| Assert.cs:128:27:128:27 | access to local variable s | Assert.cs:128:27:128:27 | access to local variable s | normal | +| Assert.cs:128:27:128:34 | access to property Length | Assert.cs:128:27:128:34 | access to property Length | normal | | Assignments.cs:4:5:15:5 | {...} | Assignments.cs:14:9:14:35 | ... += ... | normal | | Assignments.cs:5:9:5:18 | ... ...; | Assignments.cs:5:13:5:17 | Int32 x = ... | normal | | Assignments.cs:5:13:5:17 | Int32 x = ... | Assignments.cs:5:13:5:17 | Int32 x = ... | normal | @@ -582,11 +1092,25 @@ | ConditionalAccess.cs:25:13:25:14 | "" | ConditionalAccess.cs:25:13:25:14 | "" | non-null | | ConditionalAccess.cs:25:16:25:32 | call to method CommaJoinWith | ConditionalAccess.cs:25:16:25:32 | call to method CommaJoinWith | normal | | ConditionalAccess.cs:25:31:25:31 | access to local variable s | ConditionalAccess.cs:25:31:25:31 | access to local variable s | normal | -| ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | normal | -| ConditionalAccess.cs:31:70:31:78 | ... + ... | ConditionalAccess.cs:31:70:31:78 | ... + ... | normal | -| ConditionalAccess.cs:31:70:31:83 | ... + ... | ConditionalAccess.cs:31:70:31:83 | ... + ... | normal | -| ConditionalAccess.cs:31:75:31:78 | ", " | ConditionalAccess.cs:31:75:31:78 | ", " | normal | -| ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | normal | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:30:28:30:32 | ... = ... | normal | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:32:30:32 | 0 | normal | +| ConditionalAccess.cs:33:5:36:5 | {...} | ConditionalAccess.cs:35:9:35:12 | access to property Prop | null | +| ConditionalAccess.cs:33:5:36:5 | {...} | ConditionalAccess.cs:35:14:35:24 | call to method Out | normal | +| ConditionalAccess.cs:34:9:34:13 | ... = ... | ConditionalAccess.cs:34:9:34:13 | ... = ... | normal | +| ConditionalAccess.cs:34:9:34:14 | ...; | ConditionalAccess.cs:34:9:34:13 | ... = ... | normal | +| ConditionalAccess.cs:34:13:34:13 | 0 | ConditionalAccess.cs:34:13:34:13 | 0 | normal | +| ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:35:9:35:12 | access to property Prop | non-null | +| ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:35:9:35:12 | access to property Prop | null | +| ConditionalAccess.cs:35:9:35:12 | this access | ConditionalAccess.cs:35:9:35:12 | this access | normal | +| ConditionalAccess.cs:35:9:35:25 | ...; | ConditionalAccess.cs:35:9:35:12 | access to property Prop | null | +| ConditionalAccess.cs:35:9:35:25 | ...; | ConditionalAccess.cs:35:14:35:24 | call to method Out | normal | +| ConditionalAccess.cs:35:14:35:24 | call to method Out | ConditionalAccess.cs:35:9:35:12 | access to property Prop | null | +| ConditionalAccess.cs:35:14:35:24 | call to method Out | ConditionalAccess.cs:35:14:35:24 | call to method Out | normal | +| ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | normal | +| ConditionalAccess.cs:41:70:41:78 | ... + ... | ConditionalAccess.cs:41:70:41:78 | ... + ... | normal | +| ConditionalAccess.cs:41:70:41:83 | ... + ... | ConditionalAccess.cs:41:70:41:83 | ... + ... | normal | +| ConditionalAccess.cs:41:75:41:78 | ", " | ConditionalAccess.cs:41:75:41:78 | ", " | normal | +| ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | normal | | Conditions.cs:4:5:9:5 | {...} | Conditions.cs:7:14:7:16 | access to parameter inc | false [true] | | Conditions.cs:4:5:9:5 | {...} | Conditions.cs:8:13:8:15 | ...-- | normal | | Conditions.cs:5:9:6:16 | if (...) ... | Conditions.cs:5:13:5:15 | access to parameter inc | false | @@ -769,10 +1293,10 @@ | Conditions.cs:79:17:79:25 | ... = ... | Conditions.cs:79:17:79:25 | ... = ... | normal | | Conditions.cs:79:17:79:26 | ...; | Conditions.cs:79:17:79:25 | ... = ... | normal | | Conditions.cs:79:21:79:25 | false | Conditions.cs:79:21:79:25 | false | normal | -| Conditions.cs:81:9:82:16 | if (...) ... | Conditions.cs:81:12:81:12 | access to local variable b | false | +| Conditions.cs:81:9:82:16 | if (...) ... | Conditions.cs:81:13:81:13 | access to local variable b | false | | Conditions.cs:81:9:82:16 | if (...) ... | Conditions.cs:82:13:82:15 | ...++ | normal | -| Conditions.cs:81:12:81:12 | access to local variable b | Conditions.cs:81:12:81:12 | access to local variable b | false | -| Conditions.cs:81:12:81:12 | access to local variable b | Conditions.cs:81:12:81:12 | access to local variable b | true | +| Conditions.cs:81:13:81:13 | access to local variable b | Conditions.cs:81:13:81:13 | access to local variable b | false | +| Conditions.cs:81:13:81:13 | access to local variable b | Conditions.cs:81:13:81:13 | access to local variable b | true | | Conditions.cs:82:13:82:13 | access to local variable x | Conditions.cs:82:13:82:13 | access to local variable x | normal | | Conditions.cs:82:13:82:15 | ...++ | Conditions.cs:82:13:82:15 | ...++ | normal | | Conditions.cs:82:13:82:16 | ...; | Conditions.cs:82:13:82:15 | ...++ | normal | @@ -855,20 +1379,20 @@ | Conditions.cs:109:22:109:23 | "" | Conditions.cs:109:22:109:23 | "" | normal | | Conditions.cs:110:9:110:17 | return ...; | Conditions.cs:110:9:110:17 | return ...; | return | | Conditions.cs:110:16:110:16 | access to local variable x | Conditions.cs:110:16:110:16 | access to local variable x | normal | -| Conditions.cs:114:5:124:5 | {...} | Conditions.cs:116:24:116:38 | ... < ... | false | +| Conditions.cs:114:5:124:5 | {...} | Conditions.cs:116:25:116:39 | ... < ... | false | | Conditions.cs:115:9:115:24 | ... ...; | Conditions.cs:115:16:115:23 | String s = ... | normal | | Conditions.cs:115:16:115:23 | String s = ... | Conditions.cs:115:16:115:23 | String s = ... | normal | | Conditions.cs:115:20:115:23 | null | Conditions.cs:115:20:115:23 | null | normal | -| Conditions.cs:116:9:123:9 | for (...;...;...) ... | Conditions.cs:116:24:116:38 | ... < ... | false | -| Conditions.cs:116:17:116:21 | Int32 i = ... | Conditions.cs:116:17:116:21 | Int32 i = ... | normal | -| Conditions.cs:116:21:116:21 | 0 | Conditions.cs:116:21:116:21 | 0 | normal | -| Conditions.cs:116:24:116:24 | access to local variable i | Conditions.cs:116:24:116:24 | access to local variable i | normal | -| Conditions.cs:116:24:116:38 | ... < ... | Conditions.cs:116:24:116:38 | ... < ... | false | -| Conditions.cs:116:24:116:38 | ... < ... | Conditions.cs:116:24:116:38 | ... < ... | true | -| Conditions.cs:116:28:116:31 | access to parameter args | Conditions.cs:116:28:116:31 | access to parameter args | normal | -| Conditions.cs:116:28:116:38 | access to property Length | Conditions.cs:116:28:116:38 | access to property Length | normal | -| Conditions.cs:116:41:116:41 | access to local variable i | Conditions.cs:116:41:116:41 | access to local variable i | normal | -| Conditions.cs:116:41:116:43 | ...++ | Conditions.cs:116:41:116:43 | ...++ | normal | +| Conditions.cs:116:9:123:9 | for (...;...;...) ... | Conditions.cs:116:25:116:39 | ... < ... | false | +| Conditions.cs:116:18:116:22 | Int32 i = ... | Conditions.cs:116:18:116:22 | Int32 i = ... | normal | +| Conditions.cs:116:22:116:22 | 0 | Conditions.cs:116:22:116:22 | 0 | normal | +| Conditions.cs:116:25:116:25 | access to local variable i | Conditions.cs:116:25:116:25 | access to local variable i | normal | +| Conditions.cs:116:25:116:39 | ... < ... | Conditions.cs:116:25:116:39 | ... < ... | false | +| Conditions.cs:116:25:116:39 | ... < ... | Conditions.cs:116:25:116:39 | ... < ... | true | +| Conditions.cs:116:29:116:32 | access to parameter args | Conditions.cs:116:29:116:32 | access to parameter args | normal | +| Conditions.cs:116:29:116:39 | access to property Length | Conditions.cs:116:29:116:39 | access to property Length | normal | +| Conditions.cs:116:42:116:42 | access to local variable i | Conditions.cs:116:42:116:42 | access to local variable i | normal | +| Conditions.cs:116:42:116:44 | ...++ | Conditions.cs:116:42:116:44 | ...++ | normal | | Conditions.cs:117:9:123:9 | {...} | Conditions.cs:121:17:121:20 | access to local variable last | false | | Conditions.cs:117:9:123:9 | {...} | Conditions.cs:122:17:122:24 | ... = ... | normal | | Conditions.cs:118:13:118:44 | ... ...; | Conditions.cs:118:17:118:43 | Boolean last = ... | normal | @@ -917,6 +1441,30 @@ | Conditions.cs:137:21:137:26 | this access | Conditions.cs:137:21:137:26 | this access | normal | | Conditions.cs:137:21:137:37 | call to method ToString | Conditions.cs:137:21:137:37 | call to method ToString | normal | | Conditions.cs:137:21:137:38 | ...; | Conditions.cs:137:21:137:37 | call to method ToString | normal | +| Conditions.cs:144:5:150:5 | {...} | Conditions.cs:147:13:147:48 | call to method WriteLine | normal | +| Conditions.cs:144:5:150:5 | {...} | Conditions.cs:149:13:149:48 | call to method WriteLine | normal | +| Conditions.cs:145:9:145:30 | ... ...; | Conditions.cs:145:13:145:29 | String s = ... | normal | +| Conditions.cs:145:13:145:29 | String s = ... | Conditions.cs:145:13:145:29 | String s = ... | normal | +| Conditions.cs:145:17:145:17 | access to parameter b | Conditions.cs:145:17:145:17 | access to parameter b | false | +| Conditions.cs:145:17:145:17 | access to parameter b | Conditions.cs:145:17:145:17 | access to parameter b | true | +| Conditions.cs:145:17:145:29 | ... ? ... : ... | Conditions.cs:145:21:145:23 | "a" | normal | +| Conditions.cs:145:17:145:29 | ... ? ... : ... | Conditions.cs:145:27:145:29 | "b" | normal | +| Conditions.cs:145:21:145:23 | "a" | Conditions.cs:145:21:145:23 | "a" | normal | +| Conditions.cs:145:27:145:29 | "b" | Conditions.cs:145:27:145:29 | "b" | normal | +| Conditions.cs:146:9:149:49 | if (...) ... | Conditions.cs:147:13:147:48 | call to method WriteLine | normal | +| Conditions.cs:146:9:149:49 | if (...) ... | Conditions.cs:149:13:149:48 | call to method WriteLine | normal | +| Conditions.cs:146:13:146:13 | access to parameter b | Conditions.cs:146:13:146:13 | access to parameter b | false | +| Conditions.cs:146:13:146:13 | access to parameter b | Conditions.cs:146:13:146:13 | access to parameter b | true | +| Conditions.cs:147:13:147:48 | call to method WriteLine | Conditions.cs:147:13:147:48 | call to method WriteLine | normal | +| Conditions.cs:147:13:147:49 | ...; | Conditions.cs:147:13:147:48 | call to method WriteLine | normal | +| Conditions.cs:147:38:147:47 | $"..." | Conditions.cs:147:38:147:47 | $"..." | normal | +| Conditions.cs:147:40:147:43 | "a = " | Conditions.cs:147:40:147:43 | "a = " | normal | +| Conditions.cs:147:45:147:45 | access to local variable s | Conditions.cs:147:45:147:45 | access to local variable s | normal | +| Conditions.cs:149:13:149:48 | call to method WriteLine | Conditions.cs:149:13:149:48 | call to method WriteLine | normal | +| Conditions.cs:149:13:149:49 | ...; | Conditions.cs:149:13:149:48 | call to method WriteLine | normal | +| Conditions.cs:149:38:149:47 | $"..." | Conditions.cs:149:38:149:47 | $"..." | normal | +| Conditions.cs:149:40:149:43 | "b = " | Conditions.cs:149:40:149:43 | "b = " | normal | +| Conditions.cs:149:45:149:45 | access to local variable s | Conditions.cs:149:45:149:45 | access to local variable s | normal | | ExitMethods.cs:8:5:11:5 | {...} | ExitMethods.cs:10:9:10:15 | return ...; | return | | ExitMethods.cs:9:9:9:24 | call to method ErrorMaybe | ExitMethods.cs:9:9:9:24 | call to method ErrorMaybe | normal | | ExitMethods.cs:9:9:9:25 | ...; | ExitMethods.cs:9:9:9:24 | call to method ErrorMaybe | normal | @@ -1051,7 +1599,7 @@ | ExitMethods.cs:120:5:123:5 | {...} | ExitMethods.cs:122:13:122:17 | Int32 x = ... | normal | | ExitMethods.cs:121:9:121:28 | call to method IsTrue | ExitMethods.cs:121:9:121:28 | call to method IsTrue | throw(AssertFailedException) | | ExitMethods.cs:121:9:121:29 | ...; | ExitMethods.cs:121:9:121:28 | call to method IsTrue | throw(AssertFailedException) | -| ExitMethods.cs:121:23:121:27 | false | ExitMethods.cs:121:23:121:27 | false | normal | +| ExitMethods.cs:121:23:121:27 | false | ExitMethods.cs:121:23:121:27 | false | false | | ExitMethods.cs:122:9:122:18 | ... ...; | ExitMethods.cs:122:13:122:17 | Int32 x = ... | normal | | ExitMethods.cs:122:13:122:17 | Int32 x = ... | ExitMethods.cs:122:13:122:17 | Int32 x = ... | normal | | ExitMethods.cs:122:17:122:17 | 0 | ExitMethods.cs:122:17:122:17 | 0 | normal | @@ -1064,13 +1612,15 @@ | ExitMethods.cs:128:13:128:17 | Int32 x = ... | ExitMethods.cs:128:13:128:17 | Int32 x = ... | normal | | ExitMethods.cs:128:17:128:17 | 0 | ExitMethods.cs:128:17:128:17 | 0 | normal | | ExitMethods.cs:131:33:131:49 | call to method IsFalse | ExitMethods.cs:131:33:131:49 | call to method IsFalse | normal | -| ExitMethods.cs:131:48:131:48 | access to parameter b | ExitMethods.cs:131:48:131:48 | access to parameter b | normal | +| ExitMethods.cs:131:33:131:49 | call to method IsFalse | ExitMethods.cs:131:33:131:49 | call to method IsFalse | throw(AssertFailedException) | +| ExitMethods.cs:131:48:131:48 | access to parameter b | ExitMethods.cs:131:48:131:48 | access to parameter b | false | +| ExitMethods.cs:131:48:131:48 | access to parameter b | ExitMethods.cs:131:48:131:48 | access to parameter b | true | | ExitMethods.cs:134:5:137:5 | {...} | ExitMethods.cs:135:9:135:25 | call to method AssertFalse | throw(AssertFailedException) | | ExitMethods.cs:134:5:137:5 | {...} | ExitMethods.cs:136:13:136:17 | Int32 x = ... | normal | | ExitMethods.cs:135:9:135:25 | call to method AssertFalse | ExitMethods.cs:135:9:135:25 | call to method AssertFalse | throw(AssertFailedException) | | ExitMethods.cs:135:9:135:25 | this access | ExitMethods.cs:135:9:135:25 | this access | normal | | ExitMethods.cs:135:9:135:26 | ...; | ExitMethods.cs:135:9:135:25 | call to method AssertFalse | throw(AssertFailedException) | -| ExitMethods.cs:135:21:135:24 | true | ExitMethods.cs:135:21:135:24 | true | normal | +| ExitMethods.cs:135:21:135:24 | true | ExitMethods.cs:135:21:135:24 | true | true | | ExitMethods.cs:136:9:136:18 | ... ...; | ExitMethods.cs:136:13:136:17 | Int32 x = ... | normal | | ExitMethods.cs:136:13:136:17 | Int32 x = ... | ExitMethods.cs:136:13:136:17 | Int32 x = ... | normal | | ExitMethods.cs:136:17:136:17 | 0 | ExitMethods.cs:136:17:136:17 | 0 | normal | @@ -1906,23 +2456,23 @@ | LoopUnrolling.cs:9:28:9:28 | 0 | LoopUnrolling.cs:9:28:9:28 | 0 | normal | | LoopUnrolling.cs:10:13:10:19 | return ...; | LoopUnrolling.cs:10:13:10:19 | return ...; | return | | LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | empty | -| LoopUnrolling.cs:11:21:11:23 | String arg | LoopUnrolling.cs:11:21:11:23 | String arg | normal | -| LoopUnrolling.cs:11:28:11:31 | access to parameter args | LoopUnrolling.cs:11:28:11:31 | access to parameter args | normal | +| LoopUnrolling.cs:11:22:11:24 | String arg | LoopUnrolling.cs:11:22:11:24 | String arg | normal | +| LoopUnrolling.cs:11:29:11:32 | access to parameter args | LoopUnrolling.cs:11:29:11:32 | access to parameter args | normal | | LoopUnrolling.cs:12:13:12:34 | call to method WriteLine | LoopUnrolling.cs:12:13:12:34 | call to method WriteLine | normal | | LoopUnrolling.cs:12:13:12:35 | ...; | LoopUnrolling.cs:12:13:12:34 | call to method WriteLine | normal | | LoopUnrolling.cs:12:31:12:33 | access to local variable arg | LoopUnrolling.cs:12:31:12:33 | access to local variable arg | normal | | LoopUnrolling.cs:16:5:20:5 | {...} | LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... | empty | -| LoopUnrolling.cs:17:9:17:47 | ... ...; | LoopUnrolling.cs:17:13:17:46 | String[] xs = ... | normal | -| LoopUnrolling.cs:17:13:17:46 | String[] xs = ... | LoopUnrolling.cs:17:13:17:46 | String[] xs = ... | normal | -| LoopUnrolling.cs:17:18:17:46 | 3 | LoopUnrolling.cs:17:18:17:46 | 3 | normal | -| LoopUnrolling.cs:17:18:17:46 | array creation of type String[] | LoopUnrolling.cs:17:30:17:46 | { ..., ... } | normal | -| LoopUnrolling.cs:17:30:17:46 | { ..., ... } | LoopUnrolling.cs:17:30:17:46 | { ..., ... } | normal | -| LoopUnrolling.cs:17:32:17:34 | "a" | LoopUnrolling.cs:17:32:17:34 | "a" | normal | -| LoopUnrolling.cs:17:37:17:39 | "b" | LoopUnrolling.cs:17:37:17:39 | "b" | normal | -| LoopUnrolling.cs:17:42:17:44 | "c" | LoopUnrolling.cs:17:42:17:44 | "c" | normal | +| LoopUnrolling.cs:17:9:17:48 | ... ...; | LoopUnrolling.cs:17:13:17:47 | String[] xs = ... | normal | +| LoopUnrolling.cs:17:13:17:47 | String[] xs = ... | LoopUnrolling.cs:17:13:17:47 | String[] xs = ... | normal | +| LoopUnrolling.cs:17:18:17:47 | 3 | LoopUnrolling.cs:17:18:17:47 | 3 | normal | +| LoopUnrolling.cs:17:18:17:47 | array creation of type String[] | LoopUnrolling.cs:17:31:17:47 | { ..., ... } | normal | +| LoopUnrolling.cs:17:31:17:47 | { ..., ... } | LoopUnrolling.cs:17:31:17:47 | { ..., ... } | normal | +| LoopUnrolling.cs:17:33:17:35 | "a" | LoopUnrolling.cs:17:33:17:35 | "a" | normal | +| LoopUnrolling.cs:17:38:17:40 | "b" | LoopUnrolling.cs:17:38:17:40 | "b" | normal | +| LoopUnrolling.cs:17:43:17:45 | "c" | LoopUnrolling.cs:17:43:17:45 | "c" | normal | | LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... | empty | -| LoopUnrolling.cs:18:21:18:21 | String x | LoopUnrolling.cs:18:21:18:21 | String x | normal | -| LoopUnrolling.cs:18:26:18:27 | access to local variable xs | LoopUnrolling.cs:18:26:18:27 | access to local variable xs | normal | +| LoopUnrolling.cs:18:22:18:22 | String x | LoopUnrolling.cs:18:22:18:22 | String x | normal | +| LoopUnrolling.cs:18:27:18:28 | access to local variable xs | LoopUnrolling.cs:18:27:18:28 | access to local variable xs | normal | | LoopUnrolling.cs:19:13:19:32 | call to method WriteLine | LoopUnrolling.cs:19:13:19:32 | call to method WriteLine | normal | | LoopUnrolling.cs:19:13:19:33 | ...; | LoopUnrolling.cs:19:13:19:32 | call to method WriteLine | normal | | LoopUnrolling.cs:19:31:19:31 | access to local variable x | LoopUnrolling.cs:19:31:19:31 | access to local variable x | normal | @@ -1942,34 +2492,34 @@ | LoopUnrolling.cs:31:18:31:30 | array creation of type String[] | LoopUnrolling.cs:31:18:31:30 | array creation of type String[] | normal | | LoopUnrolling.cs:31:29:31:29 | 0 | LoopUnrolling.cs:31:29:31:29 | 0 | normal | | LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | empty | -| LoopUnrolling.cs:32:21:32:21 | String x | LoopUnrolling.cs:32:21:32:21 | String x | normal | -| LoopUnrolling.cs:32:26:32:27 | access to local variable xs | LoopUnrolling.cs:32:26:32:27 | access to local variable xs | normal | +| LoopUnrolling.cs:32:22:32:22 | String x | LoopUnrolling.cs:32:22:32:22 | String x | normal | +| LoopUnrolling.cs:32:27:32:28 | access to local variable xs | LoopUnrolling.cs:32:27:32:28 | access to local variable xs | normal | | LoopUnrolling.cs:33:13:33:32 | call to method WriteLine | LoopUnrolling.cs:33:13:33:32 | call to method WriteLine | normal | | LoopUnrolling.cs:33:13:33:33 | ...; | LoopUnrolling.cs:33:13:33:32 | call to method WriteLine | normal | | LoopUnrolling.cs:33:31:33:31 | access to local variable x | LoopUnrolling.cs:33:31:33:31 | access to local variable x | normal | | LoopUnrolling.cs:37:5:43:5 | {...} | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | empty | -| LoopUnrolling.cs:38:9:38:47 | ... ...; | LoopUnrolling.cs:38:13:38:46 | String[] xs = ... | normal | -| LoopUnrolling.cs:38:13:38:46 | String[] xs = ... | LoopUnrolling.cs:38:13:38:46 | String[] xs = ... | normal | -| LoopUnrolling.cs:38:18:38:46 | 3 | LoopUnrolling.cs:38:18:38:46 | 3 | normal | -| LoopUnrolling.cs:38:18:38:46 | array creation of type String[] | LoopUnrolling.cs:38:30:38:46 | { ..., ... } | normal | -| LoopUnrolling.cs:38:30:38:46 | { ..., ... } | LoopUnrolling.cs:38:30:38:46 | { ..., ... } | normal | -| LoopUnrolling.cs:38:32:38:34 | "a" | LoopUnrolling.cs:38:32:38:34 | "a" | normal | -| LoopUnrolling.cs:38:37:38:39 | "b" | LoopUnrolling.cs:38:37:38:39 | "b" | normal | -| LoopUnrolling.cs:38:42:38:44 | "c" | LoopUnrolling.cs:38:42:38:44 | "c" | normal | -| LoopUnrolling.cs:39:9:39:47 | ... ...; | LoopUnrolling.cs:39:13:39:46 | String[] ys = ... | normal | -| LoopUnrolling.cs:39:13:39:46 | String[] ys = ... | LoopUnrolling.cs:39:13:39:46 | String[] ys = ... | normal | -| LoopUnrolling.cs:39:18:39:46 | 3 | LoopUnrolling.cs:39:18:39:46 | 3 | normal | -| LoopUnrolling.cs:39:18:39:46 | array creation of type String[] | LoopUnrolling.cs:39:30:39:46 | { ..., ... } | normal | -| LoopUnrolling.cs:39:30:39:46 | { ..., ... } | LoopUnrolling.cs:39:30:39:46 | { ..., ... } | normal | -| LoopUnrolling.cs:39:32:39:34 | "0" | LoopUnrolling.cs:39:32:39:34 | "0" | normal | -| LoopUnrolling.cs:39:37:39:39 | "1" | LoopUnrolling.cs:39:37:39:39 | "1" | normal | -| LoopUnrolling.cs:39:42:39:44 | "2" | LoopUnrolling.cs:39:42:39:44 | "2" | normal | +| LoopUnrolling.cs:38:9:38:48 | ... ...; | LoopUnrolling.cs:38:13:38:47 | String[] xs = ... | normal | +| LoopUnrolling.cs:38:13:38:47 | String[] xs = ... | LoopUnrolling.cs:38:13:38:47 | String[] xs = ... | normal | +| LoopUnrolling.cs:38:18:38:47 | 3 | LoopUnrolling.cs:38:18:38:47 | 3 | normal | +| LoopUnrolling.cs:38:18:38:47 | array creation of type String[] | LoopUnrolling.cs:38:31:38:47 | { ..., ... } | normal | +| LoopUnrolling.cs:38:31:38:47 | { ..., ... } | LoopUnrolling.cs:38:31:38:47 | { ..., ... } | normal | +| LoopUnrolling.cs:38:33:38:35 | "a" | LoopUnrolling.cs:38:33:38:35 | "a" | normal | +| LoopUnrolling.cs:38:38:38:40 | "b" | LoopUnrolling.cs:38:38:38:40 | "b" | normal | +| LoopUnrolling.cs:38:43:38:45 | "c" | LoopUnrolling.cs:38:43:38:45 | "c" | normal | +| LoopUnrolling.cs:39:9:39:48 | ... ...; | LoopUnrolling.cs:39:13:39:47 | String[] ys = ... | normal | +| LoopUnrolling.cs:39:13:39:47 | String[] ys = ... | LoopUnrolling.cs:39:13:39:47 | String[] ys = ... | normal | +| LoopUnrolling.cs:39:18:39:47 | 3 | LoopUnrolling.cs:39:18:39:47 | 3 | normal | +| LoopUnrolling.cs:39:18:39:47 | array creation of type String[] | LoopUnrolling.cs:39:31:39:47 | { ..., ... } | normal | +| LoopUnrolling.cs:39:31:39:47 | { ..., ... } | LoopUnrolling.cs:39:31:39:47 | { ..., ... } | normal | +| LoopUnrolling.cs:39:33:39:35 | "0" | LoopUnrolling.cs:39:33:39:35 | "0" | normal | +| LoopUnrolling.cs:39:38:39:40 | "1" | LoopUnrolling.cs:39:38:39:40 | "1" | normal | +| LoopUnrolling.cs:39:43:39:45 | "2" | LoopUnrolling.cs:39:43:39:45 | "2" | normal | | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | empty | -| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:40:21:40:21 | String x | normal | -| LoopUnrolling.cs:40:26:40:27 | access to local variable xs | LoopUnrolling.cs:40:26:40:27 | access to local variable xs | normal | +| LoopUnrolling.cs:40:22:40:22 | String x | LoopUnrolling.cs:40:22:40:22 | String x | normal | +| LoopUnrolling.cs:40:27:40:28 | access to local variable xs | LoopUnrolling.cs:40:27:40:28 | access to local variable xs | normal | | LoopUnrolling.cs:41:13:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:41:13:42:41 | foreach (... ... in ...) ... | empty | -| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:41:25:41:25 | String y | normal | -| LoopUnrolling.cs:41:30:41:31 | access to local variable ys | LoopUnrolling.cs:41:30:41:31 | access to local variable ys | normal | +| LoopUnrolling.cs:41:26:41:26 | String y | LoopUnrolling.cs:41:26:41:26 | String y | normal | +| LoopUnrolling.cs:41:31:41:32 | access to local variable ys | LoopUnrolling.cs:41:31:41:32 | access to local variable ys | normal | | LoopUnrolling.cs:42:17:42:40 | call to method WriteLine | LoopUnrolling.cs:42:17:42:40 | call to method WriteLine | normal | | LoopUnrolling.cs:42:17:42:41 | ...; | LoopUnrolling.cs:42:17:42:40 | call to method WriteLine | normal | | LoopUnrolling.cs:42:35:42:35 | access to local variable x | LoopUnrolling.cs:42:35:42:35 | access to local variable x | normal | @@ -1977,36 +2527,36 @@ | LoopUnrolling.cs:42:39:42:39 | access to local variable y | LoopUnrolling.cs:42:39:42:39 | access to local variable y | normal | | LoopUnrolling.cs:46:5:53:5 | {...} | LoopUnrolling.cs:48:9:52:9 | foreach (... ... in ...) ... | empty | | LoopUnrolling.cs:46:5:53:5 | {...} | LoopUnrolling.cs:51:13:51:23 | goto ...; | goto(Label) | -| LoopUnrolling.cs:47:9:47:47 | ... ...; | LoopUnrolling.cs:47:13:47:46 | String[] xs = ... | normal | -| LoopUnrolling.cs:47:13:47:46 | String[] xs = ... | LoopUnrolling.cs:47:13:47:46 | String[] xs = ... | normal | -| LoopUnrolling.cs:47:18:47:46 | 3 | LoopUnrolling.cs:47:18:47:46 | 3 | normal | -| LoopUnrolling.cs:47:18:47:46 | array creation of type String[] | LoopUnrolling.cs:47:30:47:46 | { ..., ... } | normal | -| LoopUnrolling.cs:47:30:47:46 | { ..., ... } | LoopUnrolling.cs:47:30:47:46 | { ..., ... } | normal | -| LoopUnrolling.cs:47:32:47:34 | "a" | LoopUnrolling.cs:47:32:47:34 | "a" | normal | -| LoopUnrolling.cs:47:37:47:39 | "b" | LoopUnrolling.cs:47:37:47:39 | "b" | normal | -| LoopUnrolling.cs:47:42:47:44 | "c" | LoopUnrolling.cs:47:42:47:44 | "c" | normal | +| LoopUnrolling.cs:47:9:47:48 | ... ...; | LoopUnrolling.cs:47:13:47:47 | String[] xs = ... | normal | +| LoopUnrolling.cs:47:13:47:47 | String[] xs = ... | LoopUnrolling.cs:47:13:47:47 | String[] xs = ... | normal | +| LoopUnrolling.cs:47:18:47:47 | 3 | LoopUnrolling.cs:47:18:47:47 | 3 | normal | +| LoopUnrolling.cs:47:18:47:47 | array creation of type String[] | LoopUnrolling.cs:47:31:47:47 | { ..., ... } | normal | +| LoopUnrolling.cs:47:31:47:47 | { ..., ... } | LoopUnrolling.cs:47:31:47:47 | { ..., ... } | normal | +| LoopUnrolling.cs:47:33:47:35 | "a" | LoopUnrolling.cs:47:33:47:35 | "a" | normal | +| LoopUnrolling.cs:47:38:47:40 | "b" | LoopUnrolling.cs:47:38:47:40 | "b" | normal | +| LoopUnrolling.cs:47:43:47:45 | "c" | LoopUnrolling.cs:47:43:47:45 | "c" | normal | | LoopUnrolling.cs:48:9:52:9 | foreach (... ... in ...) ... | LoopUnrolling.cs:48:9:52:9 | foreach (... ... in ...) ... | empty | | LoopUnrolling.cs:48:9:52:9 | foreach (... ... in ...) ... | LoopUnrolling.cs:51:13:51:23 | goto ...; | goto(Label) | -| LoopUnrolling.cs:48:21:48:21 | String x | LoopUnrolling.cs:48:21:48:21 | String x | normal | -| LoopUnrolling.cs:48:26:48:27 | access to local variable xs | LoopUnrolling.cs:48:26:48:27 | access to local variable xs | normal | +| LoopUnrolling.cs:48:22:48:22 | String x | LoopUnrolling.cs:48:22:48:22 | String x | normal | +| LoopUnrolling.cs:48:27:48:28 | access to local variable xs | LoopUnrolling.cs:48:27:48:28 | access to local variable xs | normal | | LoopUnrolling.cs:49:9:52:9 | {...} | LoopUnrolling.cs:51:13:51:23 | goto ...; | goto(Label) | -| LoopUnrolling.cs:50:13:50:17 | Label: | LoopUnrolling.cs:50:13:50:17 | Label: | normal | -| LoopUnrolling.cs:50:20:50:39 | call to method WriteLine | LoopUnrolling.cs:50:20:50:39 | call to method WriteLine | normal | -| LoopUnrolling.cs:50:20:50:40 | ...; | LoopUnrolling.cs:50:20:50:39 | call to method WriteLine | normal | -| LoopUnrolling.cs:50:38:50:38 | access to local variable x | LoopUnrolling.cs:50:38:50:38 | access to local variable x | normal | +| LoopUnrolling.cs:50:9:50:13 | Label: | LoopUnrolling.cs:50:9:50:13 | Label: | normal | +| LoopUnrolling.cs:50:16:50:35 | call to method WriteLine | LoopUnrolling.cs:50:16:50:35 | call to method WriteLine | normal | +| LoopUnrolling.cs:50:16:50:36 | ...; | LoopUnrolling.cs:50:16:50:35 | call to method WriteLine | normal | +| LoopUnrolling.cs:50:34:50:34 | access to local variable x | LoopUnrolling.cs:50:34:50:34 | access to local variable x | normal | | LoopUnrolling.cs:51:13:51:23 | goto ...; | LoopUnrolling.cs:51:13:51:23 | goto ...; | goto(Label) | | LoopUnrolling.cs:56:5:65:5 | {...} | LoopUnrolling.cs:58:9:64:9 | foreach (... ... in ...) ... | empty | -| LoopUnrolling.cs:57:9:57:47 | ... ...; | LoopUnrolling.cs:57:13:57:46 | String[] xs = ... | normal | -| LoopUnrolling.cs:57:13:57:46 | String[] xs = ... | LoopUnrolling.cs:57:13:57:46 | String[] xs = ... | normal | -| LoopUnrolling.cs:57:18:57:46 | 3 | LoopUnrolling.cs:57:18:57:46 | 3 | normal | -| LoopUnrolling.cs:57:18:57:46 | array creation of type String[] | LoopUnrolling.cs:57:30:57:46 | { ..., ... } | normal | -| LoopUnrolling.cs:57:30:57:46 | { ..., ... } | LoopUnrolling.cs:57:30:57:46 | { ..., ... } | normal | -| LoopUnrolling.cs:57:32:57:34 | "a" | LoopUnrolling.cs:57:32:57:34 | "a" | normal | -| LoopUnrolling.cs:57:37:57:39 | "b" | LoopUnrolling.cs:57:37:57:39 | "b" | normal | -| LoopUnrolling.cs:57:42:57:44 | "c" | LoopUnrolling.cs:57:42:57:44 | "c" | normal | +| LoopUnrolling.cs:57:9:57:48 | ... ...; | LoopUnrolling.cs:57:13:57:47 | String[] xs = ... | normal | +| LoopUnrolling.cs:57:13:57:47 | String[] xs = ... | LoopUnrolling.cs:57:13:57:47 | String[] xs = ... | normal | +| LoopUnrolling.cs:57:18:57:47 | 3 | LoopUnrolling.cs:57:18:57:47 | 3 | normal | +| LoopUnrolling.cs:57:18:57:47 | array creation of type String[] | LoopUnrolling.cs:57:31:57:47 | { ..., ... } | normal | +| LoopUnrolling.cs:57:31:57:47 | { ..., ... } | LoopUnrolling.cs:57:31:57:47 | { ..., ... } | normal | +| LoopUnrolling.cs:57:33:57:35 | "a" | LoopUnrolling.cs:57:33:57:35 | "a" | normal | +| LoopUnrolling.cs:57:38:57:40 | "b" | LoopUnrolling.cs:57:38:57:40 | "b" | normal | +| LoopUnrolling.cs:57:43:57:45 | "c" | LoopUnrolling.cs:57:43:57:45 | "c" | normal | | LoopUnrolling.cs:58:9:64:9 | foreach (... ... in ...) ... | LoopUnrolling.cs:58:9:64:9 | foreach (... ... in ...) ... | empty | -| LoopUnrolling.cs:58:21:58:21 | String x | LoopUnrolling.cs:58:21:58:21 | String x | normal | -| LoopUnrolling.cs:58:26:58:27 | access to local variable xs | LoopUnrolling.cs:58:26:58:27 | access to local variable xs | normal | +| LoopUnrolling.cs:58:22:58:22 | String x | LoopUnrolling.cs:58:22:58:22 | String x | normal | +| LoopUnrolling.cs:58:27:58:28 | access to local variable xs | LoopUnrolling.cs:58:27:58:28 | access to local variable xs | normal | | LoopUnrolling.cs:59:9:64:9 | {...} | LoopUnrolling.cs:62:17:62:17 | access to parameter b | false | | LoopUnrolling.cs:59:9:64:9 | {...} | LoopUnrolling.cs:63:17:63:36 | call to method WriteLine | normal | | LoopUnrolling.cs:60:13:61:37 | if (...) ... | LoopUnrolling.cs:60:17:60:17 | access to parameter b | false | @@ -2037,11 +2587,133 @@ | LoopUnrolling.cs:71:9:71:20 | call to method Clear | LoopUnrolling.cs:71:9:71:20 | call to method Clear | normal | | LoopUnrolling.cs:71:9:71:21 | ...; | LoopUnrolling.cs:71:9:71:20 | call to method Clear | normal | | LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | empty | -| LoopUnrolling.cs:72:21:72:23 | String arg | LoopUnrolling.cs:72:21:72:23 | String arg | normal | -| LoopUnrolling.cs:72:28:72:31 | access to parameter args | LoopUnrolling.cs:72:28:72:31 | access to parameter args | normal | +| LoopUnrolling.cs:72:22:72:24 | String arg | LoopUnrolling.cs:72:22:72:24 | String arg | normal | +| LoopUnrolling.cs:72:29:72:32 | access to parameter args | LoopUnrolling.cs:72:29:72:32 | access to parameter args | normal | | LoopUnrolling.cs:73:13:73:34 | call to method WriteLine | LoopUnrolling.cs:73:13:73:34 | call to method WriteLine | normal | | LoopUnrolling.cs:73:13:73:35 | ...; | LoopUnrolling.cs:73:13:73:34 | call to method WriteLine | normal | | LoopUnrolling.cs:73:31:73:33 | access to local variable arg | LoopUnrolling.cs:73:31:73:33 | access to local variable arg | normal | +| LoopUnrolling.cs:77:5:83:5 | {...} | LoopUnrolling.cs:79:9:82:9 | foreach (... ... in ...) ... | empty | +| LoopUnrolling.cs:78:9:78:34 | ... ...; | LoopUnrolling.cs:78:13:78:33 | String[,] xs = ... | normal | +| LoopUnrolling.cs:78:13:78:33 | String[,] xs = ... | LoopUnrolling.cs:78:13:78:33 | String[,] xs = ... | normal | +| LoopUnrolling.cs:78:18:78:33 | array creation of type String[,] | LoopUnrolling.cs:78:18:78:33 | array creation of type String[,] | normal | +| LoopUnrolling.cs:78:29:78:29 | 2 | LoopUnrolling.cs:78:29:78:29 | 2 | normal | +| LoopUnrolling.cs:78:32:78:32 | 0 | LoopUnrolling.cs:78:32:78:32 | 0 | normal | +| LoopUnrolling.cs:79:9:82:9 | foreach (... ... in ...) ... | LoopUnrolling.cs:79:9:82:9 | foreach (... ... in ...) ... | empty | +| LoopUnrolling.cs:79:22:79:22 | String x | LoopUnrolling.cs:79:22:79:22 | String x | normal | +| LoopUnrolling.cs:79:27:79:28 | access to local variable xs | LoopUnrolling.cs:79:27:79:28 | access to local variable xs | normal | +| LoopUnrolling.cs:80:9:82:9 | {...} | LoopUnrolling.cs:81:13:81:32 | call to method WriteLine | normal | +| LoopUnrolling.cs:81:13:81:32 | call to method WriteLine | LoopUnrolling.cs:81:13:81:32 | call to method WriteLine | normal | +| LoopUnrolling.cs:81:13:81:33 | ...; | LoopUnrolling.cs:81:13:81:32 | call to method WriteLine | normal | +| LoopUnrolling.cs:81:31:81:31 | access to local variable x | LoopUnrolling.cs:81:31:81:31 | access to local variable x | normal | +| LoopUnrolling.cs:86:5:92:5 | {...} | LoopUnrolling.cs:88:9:91:9 | foreach (... ... in ...) ... | empty | +| LoopUnrolling.cs:87:9:87:34 | ... ...; | LoopUnrolling.cs:87:13:87:33 | String[,] xs = ... | normal | +| LoopUnrolling.cs:87:13:87:33 | String[,] xs = ... | LoopUnrolling.cs:87:13:87:33 | String[,] xs = ... | normal | +| LoopUnrolling.cs:87:18:87:33 | array creation of type String[,] | LoopUnrolling.cs:87:18:87:33 | array creation of type String[,] | normal | +| LoopUnrolling.cs:87:29:87:29 | 0 | LoopUnrolling.cs:87:29:87:29 | 0 | normal | +| LoopUnrolling.cs:87:32:87:32 | 2 | LoopUnrolling.cs:87:32:87:32 | 2 | normal | +| LoopUnrolling.cs:88:9:91:9 | foreach (... ... in ...) ... | LoopUnrolling.cs:88:9:91:9 | foreach (... ... in ...) ... | empty | +| LoopUnrolling.cs:88:22:88:22 | String x | LoopUnrolling.cs:88:22:88:22 | String x | normal | +| LoopUnrolling.cs:88:27:88:28 | access to local variable xs | LoopUnrolling.cs:88:27:88:28 | access to local variable xs | normal | +| LoopUnrolling.cs:89:9:91:9 | {...} | LoopUnrolling.cs:90:13:90:32 | call to method WriteLine | normal | +| LoopUnrolling.cs:90:13:90:32 | call to method WriteLine | LoopUnrolling.cs:90:13:90:32 | call to method WriteLine | normal | +| LoopUnrolling.cs:90:13:90:33 | ...; | LoopUnrolling.cs:90:13:90:32 | call to method WriteLine | normal | +| LoopUnrolling.cs:90:31:90:31 | access to local variable x | LoopUnrolling.cs:90:31:90:31 | access to local variable x | normal | +| LoopUnrolling.cs:95:5:101:5 | {...} | LoopUnrolling.cs:97:9:100:9 | foreach (... ... in ...) ... | empty | +| LoopUnrolling.cs:96:9:96:34 | ... ...; | LoopUnrolling.cs:96:13:96:33 | String[,] xs = ... | normal | +| LoopUnrolling.cs:96:13:96:33 | String[,] xs = ... | LoopUnrolling.cs:96:13:96:33 | String[,] xs = ... | normal | +| LoopUnrolling.cs:96:18:96:33 | array creation of type String[,] | LoopUnrolling.cs:96:18:96:33 | array creation of type String[,] | normal | +| LoopUnrolling.cs:96:29:96:29 | 2 | LoopUnrolling.cs:96:29:96:29 | 2 | normal | +| LoopUnrolling.cs:96:32:96:32 | 2 | LoopUnrolling.cs:96:32:96:32 | 2 | normal | +| LoopUnrolling.cs:97:9:100:9 | foreach (... ... in ...) ... | LoopUnrolling.cs:97:9:100:9 | foreach (... ... in ...) ... | empty | +| LoopUnrolling.cs:97:22:97:22 | String x | LoopUnrolling.cs:97:22:97:22 | String x | normal | +| LoopUnrolling.cs:97:27:97:28 | access to local variable xs | LoopUnrolling.cs:97:27:97:28 | access to local variable xs | normal | +| LoopUnrolling.cs:98:9:100:9 | {...} | LoopUnrolling.cs:99:13:99:32 | call to method WriteLine | normal | +| LoopUnrolling.cs:99:13:99:32 | call to method WriteLine | LoopUnrolling.cs:99:13:99:32 | call to method WriteLine | normal | +| LoopUnrolling.cs:99:13:99:33 | ...; | LoopUnrolling.cs:99:13:99:32 | call to method WriteLine | normal | +| LoopUnrolling.cs:99:31:99:31 | access to local variable x | LoopUnrolling.cs:99:31:99:31 | access to local variable x | normal | +| MultiImplementationA.cs:6:22:6:31 | throw ... | MultiImplementationA.cs:6:22:6:31 | throw ... | throw(NullReferenceException) | +| MultiImplementationA.cs:6:28:6:31 | null | MultiImplementationA.cs:6:28:6:31 | null | normal | +| MultiImplementationA.cs:7:25:7:39 | {...} | MultiImplementationA.cs:7:27:7:37 | throw ...; | throw(NullReferenceException) | +| MultiImplementationA.cs:7:27:7:37 | throw ...; | MultiImplementationA.cs:7:27:7:37 | throw ...; | throw(NullReferenceException) | +| MultiImplementationA.cs:7:33:7:36 | null | MultiImplementationA.cs:7:33:7:36 | null | normal | +| MultiImplementationA.cs:7:45:7:59 | {...} | MultiImplementationA.cs:7:47:7:57 | throw ...; | throw(NullReferenceException) | +| MultiImplementationA.cs:7:47:7:57 | throw ...; | MultiImplementationA.cs:7:47:7:57 | throw ...; | throw(NullReferenceException) | +| MultiImplementationA.cs:7:53:7:56 | null | MultiImplementationA.cs:7:53:7:56 | null | normal | +| MultiImplementationA.cs:8:23:8:32 | throw ... | MultiImplementationA.cs:8:23:8:32 | throw ... | throw(NullReferenceException) | +| MultiImplementationA.cs:8:29:8:32 | null | MultiImplementationA.cs:8:29:8:32 | null | normal | +| MultiImplementationA.cs:13:16:13:16 | access to field F | MultiImplementationA.cs:13:16:13:16 | this access | normal | +| MultiImplementationA.cs:13:16:13:16 | this access | MultiImplementationA.cs:13:16:13:16 | this access | normal | +| MultiImplementationA.cs:13:16:13:20 | ... = ... | MultiImplementationA.cs:13:16:13:20 | ... = ... | normal | +| MultiImplementationA.cs:13:20:13:20 | 0 | MultiImplementationA.cs:13:20:13:20 | 0 | normal | +| MultiImplementationA.cs:14:31:14:31 | access to parameter i | MultiImplementationA.cs:14:31:14:31 | access to parameter i | normal | +| MultiImplementationA.cs:15:40:15:52 | {...} | MultiImplementationA.cs:15:42:15:50 | return ...; | return | +| MultiImplementationA.cs:15:42:15:50 | return ...; | MultiImplementationA.cs:15:42:15:50 | return ...; | return | +| MultiImplementationA.cs:15:49:15:49 | access to parameter s | MultiImplementationA.cs:15:49:15:49 | access to parameter s | normal | +| MultiImplementationA.cs:15:58:15:60 | {...} | MultiImplementationA.cs:15:58:15:60 | {...} | normal | +| MultiImplementationA.cs:16:28:16:28 | 0 | MultiImplementationA.cs:16:28:16:28 | 0 | normal | +| MultiImplementationA.cs:17:5:19:5 | {...} | MultiImplementationA.cs:18:9:18:22 | M2(...) | normal | +| MultiImplementationA.cs:18:9:18:22 | M2(...) | MultiImplementationA.cs:18:9:18:22 | M2(...) | normal | +| MultiImplementationA.cs:18:21:18:21 | 0 | MultiImplementationA.cs:18:21:18:21 | 0 | normal | +| MultiImplementationA.cs:20:22:20:31 | {...} | MultiImplementationA.cs:20:24:20:28 | ... = ... | normal | +| MultiImplementationA.cs:20:24:20:24 | access to field F | MultiImplementationA.cs:20:24:20:24 | this access | normal | +| MultiImplementationA.cs:20:24:20:24 | this access | MultiImplementationA.cs:20:24:20:24 | this access | normal | +| MultiImplementationA.cs:20:24:20:28 | ... = ... | MultiImplementationA.cs:20:24:20:28 | ... = ... | normal | +| MultiImplementationA.cs:20:24:20:29 | ...; | MultiImplementationA.cs:20:24:20:28 | ... = ... | normal | +| MultiImplementationA.cs:20:28:20:28 | access to parameter i | MultiImplementationA.cs:20:28:20:28 | access to parameter i | normal | +| MultiImplementationA.cs:21:19:21:22 | call to constructor C2 | MultiImplementationA.cs:21:19:21:22 | call to constructor C2 | normal | +| MultiImplementationA.cs:21:24:21:24 | 0 | MultiImplementationA.cs:21:24:21:24 | 0 | normal | +| MultiImplementationA.cs:21:27:21:29 | {...} | MultiImplementationA.cs:21:27:21:29 | {...} | normal | +| MultiImplementationA.cs:22:11:22:13 | {...} | MultiImplementationA.cs:22:11:22:13 | {...} | normal | +| MultiImplementationA.cs:23:50:23:53 | null | MultiImplementationA.cs:23:50:23:53 | null | normal | +| MultiImplementationA.cs:24:16:24:16 | access to property P | MultiImplementationA.cs:24:16:24:16 | this access | normal | +| MultiImplementationA.cs:24:16:24:16 | this access | MultiImplementationA.cs:24:16:24:16 | this access | normal | +| MultiImplementationA.cs:24:32:24:34 | ... = ... | MultiImplementationA.cs:24:32:24:34 | ... = ... | normal | +| MultiImplementationA.cs:24:34:24:34 | 0 | MultiImplementationA.cs:24:34:24:34 | 0 | normal | +| MultiImplementationA.cs:30:28:30:37 | throw ... | MultiImplementationA.cs:30:28:30:37 | throw ... | throw(NullReferenceException) | +| MultiImplementationA.cs:30:34:30:37 | null | MultiImplementationA.cs:30:34:30:37 | null | normal | +| MultiImplementationA.cs:36:14:36:28 | {...} | MultiImplementationA.cs:36:16:36:26 | throw ...; | throw(NullReferenceException) | +| MultiImplementationA.cs:36:16:36:26 | throw ...; | MultiImplementationA.cs:36:16:36:26 | throw ...; | throw(NullReferenceException) | +| MultiImplementationA.cs:36:22:36:25 | null | MultiImplementationA.cs:36:22:36:25 | null | normal | +| MultiImplementationA.cs:37:14:37:28 | {...} | MultiImplementationA.cs:37:16:37:26 | throw ...; | throw(NullReferenceException) | +| MultiImplementationA.cs:37:16:37:26 | throw ...; | MultiImplementationA.cs:37:16:37:26 | throw ...; | throw(NullReferenceException) | +| MultiImplementationA.cs:37:22:37:25 | null | MultiImplementationA.cs:37:22:37:25 | null | normal | +| MultiImplementationB.cs:3:22:3:22 | 0 | MultiImplementationB.cs:3:22:3:22 | 0 | normal | +| MultiImplementationB.cs:4:25:4:37 | {...} | MultiImplementationB.cs:4:27:4:35 | return ...; | return | +| MultiImplementationB.cs:4:27:4:35 | return ...; | MultiImplementationB.cs:4:27:4:35 | return ...; | return | +| MultiImplementationB.cs:4:34:4:34 | 1 | MultiImplementationB.cs:4:34:4:34 | 1 | normal | +| MultiImplementationB.cs:4:43:4:45 | {...} | MultiImplementationB.cs:4:43:4:45 | {...} | normal | +| MultiImplementationB.cs:5:23:5:23 | 2 | MultiImplementationB.cs:5:23:5:23 | 2 | normal | +| MultiImplementationB.cs:11:16:11:16 | access to field F | MultiImplementationB.cs:11:16:11:16 | this access | normal | +| MultiImplementationB.cs:11:16:11:16 | this access | MultiImplementationB.cs:11:16:11:16 | this access | normal | +| MultiImplementationB.cs:11:16:11:20 | ... = ... | MultiImplementationB.cs:11:16:11:20 | ... = ... | normal | +| MultiImplementationB.cs:11:20:11:20 | 1 | MultiImplementationB.cs:11:20:11:20 | 1 | normal | +| MultiImplementationB.cs:12:31:12:40 | throw ... | MultiImplementationB.cs:12:31:12:40 | throw ... | throw(NullReferenceException) | +| MultiImplementationB.cs:12:37:12:40 | null | MultiImplementationB.cs:12:37:12:40 | null | normal | +| MultiImplementationB.cs:13:40:13:54 | {...} | MultiImplementationB.cs:13:42:13:52 | throw ...; | throw(NullReferenceException) | +| MultiImplementationB.cs:13:42:13:52 | throw ...; | MultiImplementationB.cs:13:42:13:52 | throw ...; | throw(NullReferenceException) | +| MultiImplementationB.cs:13:48:13:51 | null | MultiImplementationB.cs:13:48:13:51 | null | normal | +| MultiImplementationB.cs:13:60:13:62 | {...} | MultiImplementationB.cs:13:60:13:62 | {...} | normal | +| MultiImplementationB.cs:14:28:14:28 | 1 | MultiImplementationB.cs:14:28:14:28 | 1 | normal | +| MultiImplementationB.cs:15:5:17:5 | {...} | MultiImplementationB.cs:16:9:16:31 | M2(...) | normal | +| MultiImplementationB.cs:16:9:16:31 | M2(...) | MultiImplementationB.cs:16:9:16:31 | M2(...) | normal | +| MultiImplementationB.cs:16:21:16:30 | throw ... | MultiImplementationB.cs:16:21:16:30 | throw ... | throw(NullReferenceException) | +| MultiImplementationB.cs:16:27:16:30 | null | MultiImplementationB.cs:16:27:16:30 | null | normal | +| MultiImplementationB.cs:18:22:18:36 | {...} | MultiImplementationB.cs:18:24:18:34 | throw ...; | throw(NullReferenceException) | +| MultiImplementationB.cs:18:24:18:34 | throw ...; | MultiImplementationB.cs:18:24:18:34 | throw ...; | throw(NullReferenceException) | +| MultiImplementationB.cs:18:30:18:33 | null | MultiImplementationB.cs:18:30:18:33 | null | normal | +| MultiImplementationB.cs:19:19:19:22 | call to constructor C2 | MultiImplementationB.cs:19:19:19:22 | call to constructor C2 | normal | +| MultiImplementationB.cs:19:24:19:24 | 1 | MultiImplementationB.cs:19:24:19:24 | 1 | normal | +| MultiImplementationB.cs:19:27:19:29 | {...} | MultiImplementationB.cs:19:27:19:29 | {...} | normal | +| MultiImplementationB.cs:20:11:20:25 | {...} | MultiImplementationB.cs:20:13:20:23 | throw ...; | throw(NullReferenceException) | +| MultiImplementationB.cs:20:13:20:23 | throw ...; | MultiImplementationB.cs:20:13:20:23 | throw ...; | throw(NullReferenceException) | +| MultiImplementationB.cs:20:19:20:22 | null | MultiImplementationB.cs:20:19:20:22 | null | normal | +| MultiImplementationB.cs:21:50:21:59 | throw ... | MultiImplementationB.cs:21:50:21:59 | throw ... | throw(NullReferenceException) | +| MultiImplementationB.cs:21:56:21:59 | null | MultiImplementationB.cs:21:56:21:59 | null | normal | +| MultiImplementationB.cs:22:16:22:16 | access to property P | MultiImplementationB.cs:22:16:22:16 | this access | normal | +| MultiImplementationB.cs:22:16:22:16 | this access | MultiImplementationB.cs:22:16:22:16 | this access | normal | +| MultiImplementationB.cs:22:32:22:34 | ... = ... | MultiImplementationB.cs:22:32:22:34 | ... = ... | normal | +| MultiImplementationB.cs:22:34:22:34 | 1 | MultiImplementationB.cs:22:34:22:34 | 1 | normal | +| MultiImplementationB.cs:32:17:32:17 | 0 | MultiImplementationB.cs:32:17:32:17 | 0 | normal | | NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:23:3:23 | access to parameter i | non-null | | NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:23:3:23 | access to parameter i | null | | NullCoalescing.cs:3:23:3:28 | ... ?? ... | NullCoalescing.cs:3:23:3:23 | access to parameter i | non-null | @@ -2351,11 +3023,11 @@ | Switch.cs:26:17:26:23 | return ...; | Switch.cs:26:17:26:23 | return ...; | return | | Switch.cs:27:13:27:39 | case ...: | Switch.cs:27:18:27:25 | Double d | no-match | | Switch.cs:27:13:27:39 | case ...: | Switch.cs:27:32:27:38 | call to method Throw | throw(Exception) | -| Switch.cs:27:13:27:39 | case ...: | Switch.cs:28:17:28:21 | Label: | normal | +| Switch.cs:27:13:27:39 | case ...: | Switch.cs:28:13:28:17 | Label: | normal | | Switch.cs:27:18:27:25 | Double d | Switch.cs:27:18:27:25 | Double d | match | | Switch.cs:27:18:27:25 | Double d | Switch.cs:27:18:27:25 | Double d | no-match | | Switch.cs:27:32:27:38 | call to method Throw | Switch.cs:27:32:27:38 | call to method Throw | throw(Exception) | -| Switch.cs:28:17:28:21 | Label: | Switch.cs:28:17:28:21 | Label: | normal | +| Switch.cs:28:13:28:17 | Label: | Switch.cs:28:13:28:17 | Label: | normal | | Switch.cs:29:17:29:23 | return ...; | Switch.cs:29:17:29:23 | return ...; | return | | Switch.cs:30:13:30:20 | default: | Switch.cs:31:17:31:27 | goto ...; | goto(Label) | | Switch.cs:31:17:31:27 | goto ...; | Switch.cs:31:17:31:27 | goto ...; | goto(Label) | @@ -2390,138 +3062,138 @@ | Switch.cs:50:30:50:38 | ... != ... | Switch.cs:50:30:50:38 | ... != ... | true | | Switch.cs:50:35:50:38 | null | Switch.cs:50:35:50:38 | null | normal | | Switch.cs:51:17:51:22 | break; | Switch.cs:51:17:51:22 | break; | break | -| Switch.cs:56:5:64:5 | {...} | Switch.cs:60:15:60:20 | break; | normal (break) | -| Switch.cs:56:5:64:5 | {...} | Switch.cs:62:15:62:20 | break; | normal (break) | -| Switch.cs:57:9:63:9 | switch (...) {...} | Switch.cs:60:15:60:20 | break; | normal (break) | -| Switch.cs:57:9:63:9 | switch (...) {...} | Switch.cs:62:15:62:20 | break; | normal (break) | +| Switch.cs:56:5:64:5 | {...} | Switch.cs:60:17:60:22 | break; | normal (break) | +| Switch.cs:56:5:64:5 | {...} | Switch.cs:62:17:62:22 | break; | normal (break) | +| Switch.cs:57:9:63:9 | switch (...) {...} | Switch.cs:60:17:60:22 | break; | normal (break) | +| Switch.cs:57:9:63:9 | switch (...) {...} | Switch.cs:62:17:62:22 | break; | normal (break) | | Switch.cs:57:17:57:17 | 1 | Switch.cs:57:17:57:17 | 1 | normal | | Switch.cs:57:17:57:21 | ... + ... | Switch.cs:57:17:57:21 | ... + ... | normal | | Switch.cs:57:21:57:21 | 2 | Switch.cs:57:21:57:21 | 2 | normal | -| Switch.cs:59:13:59:20 | case ...: | Switch.cs:59:18:59:18 | 2 | no-match | -| Switch.cs:59:13:59:20 | case ...: | Switch.cs:60:15:60:20 | break; | break | +| Switch.cs:59:13:59:19 | case ...: | Switch.cs:59:18:59:18 | 2 | no-match | +| Switch.cs:59:13:59:19 | case ...: | Switch.cs:60:17:60:22 | break; | break | | Switch.cs:59:18:59:18 | 2 | Switch.cs:59:18:59:18 | 2 | no-match | -| Switch.cs:60:15:60:20 | break; | Switch.cs:60:15:60:20 | break; | break | -| Switch.cs:61:13:61:20 | case ...: | Switch.cs:62:15:62:20 | break; | break | +| Switch.cs:60:17:60:22 | break; | Switch.cs:60:17:60:22 | break; | break | +| Switch.cs:61:13:61:19 | case ...: | Switch.cs:62:17:62:22 | break; | break | | Switch.cs:61:18:61:18 | 3 | Switch.cs:61:18:61:18 | 3 | match | -| Switch.cs:62:15:62:20 | break; | Switch.cs:62:15:62:20 | break; | break | -| Switch.cs:67:5:75:5 | {...} | Switch.cs:71:15:71:20 | break; | normal (break) | +| Switch.cs:62:17:62:22 | break; | Switch.cs:62:17:62:22 | break; | break | +| Switch.cs:67:5:75:5 | {...} | Switch.cs:71:17:71:22 | break; | normal (break) | | Switch.cs:67:5:75:5 | {...} | Switch.cs:72:18:72:19 | "" | no-match | -| Switch.cs:67:5:75:5 | {...} | Switch.cs:73:15:73:20 | break; | normal (break) | -| Switch.cs:68:9:74:9 | switch (...) {...} | Switch.cs:71:15:71:20 | break; | normal (break) | +| Switch.cs:67:5:75:5 | {...} | Switch.cs:73:17:73:22 | break; | normal (break) | +| Switch.cs:68:9:74:9 | switch (...) {...} | Switch.cs:71:17:71:22 | break; | normal (break) | | Switch.cs:68:9:74:9 | switch (...) {...} | Switch.cs:72:18:72:19 | "" | no-match | -| Switch.cs:68:9:74:9 | switch (...) {...} | Switch.cs:73:15:73:20 | break; | normal (break) | +| Switch.cs:68:9:74:9 | switch (...) {...} | Switch.cs:73:17:73:22 | break; | normal (break) | | Switch.cs:68:17:68:25 | (...) ... | Switch.cs:68:17:68:25 | (...) ... | normal | | Switch.cs:68:25:68:25 | access to parameter s | Switch.cs:68:25:68:25 | access to parameter s | normal | -| Switch.cs:70:13:70:24 | case ...: | Switch.cs:70:18:70:20 | access to type Int32 | no-match | -| Switch.cs:70:13:70:24 | case ...: | Switch.cs:71:15:71:20 | break; | break | +| Switch.cs:70:13:70:23 | case ...: | Switch.cs:70:18:70:20 | access to type Int32 | no-match | +| Switch.cs:70:13:70:23 | case ...: | Switch.cs:71:17:71:22 | break; | break | | Switch.cs:70:18:70:20 | access to type Int32 | Switch.cs:70:18:70:20 | access to type Int32 | no-match | -| Switch.cs:71:15:71:20 | break; | Switch.cs:71:15:71:20 | break; | break | -| Switch.cs:72:13:72:21 | case ...: | Switch.cs:72:18:72:19 | "" | no-match | -| Switch.cs:72:13:72:21 | case ...: | Switch.cs:73:15:73:20 | break; | break | +| Switch.cs:71:17:71:22 | break; | Switch.cs:71:17:71:22 | break; | break | +| Switch.cs:72:13:72:20 | case ...: | Switch.cs:72:18:72:19 | "" | no-match | +| Switch.cs:72:13:72:20 | case ...: | Switch.cs:73:17:73:22 | break; | break | | Switch.cs:72:18:72:19 | "" | Switch.cs:72:18:72:19 | "" | match | | Switch.cs:72:18:72:19 | "" | Switch.cs:72:18:72:19 | "" | no-match | -| Switch.cs:73:15:73:20 | break; | Switch.cs:73:15:73:20 | break; | break | -| Switch.cs:78:5:89:5 | {...} | Switch.cs:82:15:82:26 | return ...; | return | -| Switch.cs:78:5:89:5 | {...} | Switch.cs:86:15:86:26 | return ...; | return | +| Switch.cs:73:17:73:22 | break; | Switch.cs:73:17:73:22 | break; | break | +| Switch.cs:78:5:89:5 | {...} | Switch.cs:82:17:82:28 | return ...; | return | +| Switch.cs:78:5:89:5 | {...} | Switch.cs:86:17:86:28 | return ...; | return | | Switch.cs:78:5:89:5 | {...} | Switch.cs:88:9:88:21 | return ...; | return | -| Switch.cs:79:9:87:9 | switch (...) {...} | Switch.cs:82:15:82:26 | return ...; | return | +| Switch.cs:79:9:87:9 | switch (...) {...} | Switch.cs:82:17:82:28 | return ...; | return | | Switch.cs:79:9:87:9 | switch (...) {...} | Switch.cs:83:18:83:18 | 2 | no-match | -| Switch.cs:79:9:87:9 | switch (...) {...} | Switch.cs:85:17:85:22 | break; | normal (break) | -| Switch.cs:79:9:87:9 | switch (...) {...} | Switch.cs:86:15:86:26 | return ...; | return | +| Switch.cs:79:9:87:9 | switch (...) {...} | Switch.cs:85:21:85:26 | break; | normal (break) | +| Switch.cs:79:9:87:9 | switch (...) {...} | Switch.cs:86:17:86:28 | return ...; | return | | Switch.cs:79:17:79:17 | access to parameter i | Switch.cs:79:17:79:17 | access to parameter i | normal | -| Switch.cs:81:13:81:20 | case ...: | Switch.cs:81:18:81:18 | 1 | no-match | -| Switch.cs:81:13:81:20 | case ...: | Switch.cs:82:15:82:26 | return ...; | return | +| Switch.cs:81:13:81:19 | case ...: | Switch.cs:81:18:81:18 | 1 | no-match | +| Switch.cs:81:13:81:19 | case ...: | Switch.cs:82:17:82:28 | return ...; | return | | Switch.cs:81:18:81:18 | 1 | Switch.cs:81:18:81:18 | 1 | match | | Switch.cs:81:18:81:18 | 1 | Switch.cs:81:18:81:18 | 1 | no-match | -| Switch.cs:82:15:82:26 | return ...; | Switch.cs:82:15:82:26 | return ...; | return | -| Switch.cs:82:22:82:25 | true | Switch.cs:82:22:82:25 | true | normal | -| Switch.cs:83:13:83:20 | case ...: | Switch.cs:83:18:83:18 | 2 | no-match | -| Switch.cs:83:13:83:20 | case ...: | Switch.cs:84:19:84:23 | ... > ... | false | -| Switch.cs:83:13:83:20 | case ...: | Switch.cs:85:17:85:22 | break; | break | +| Switch.cs:82:17:82:28 | return ...; | Switch.cs:82:17:82:28 | return ...; | return | +| Switch.cs:82:24:82:27 | true | Switch.cs:82:24:82:27 | true | normal | +| Switch.cs:83:13:83:19 | case ...: | Switch.cs:83:18:83:18 | 2 | no-match | +| Switch.cs:83:13:83:19 | case ...: | Switch.cs:84:21:84:25 | ... > ... | false | +| Switch.cs:83:13:83:19 | case ...: | Switch.cs:85:21:85:26 | break; | break | | Switch.cs:83:18:83:18 | 2 | Switch.cs:83:18:83:18 | 2 | match | | Switch.cs:83:18:83:18 | 2 | Switch.cs:83:18:83:18 | 2 | no-match | -| Switch.cs:84:15:85:22 | if (...) ... | Switch.cs:84:19:84:23 | ... > ... | false | -| Switch.cs:84:15:85:22 | if (...) ... | Switch.cs:85:17:85:22 | break; | break | -| Switch.cs:84:19:84:19 | access to parameter j | Switch.cs:84:19:84:19 | access to parameter j | normal | -| Switch.cs:84:19:84:23 | ... > ... | Switch.cs:84:19:84:23 | ... > ... | false | -| Switch.cs:84:19:84:23 | ... > ... | Switch.cs:84:19:84:23 | ... > ... | true | -| Switch.cs:84:23:84:23 | 2 | Switch.cs:84:23:84:23 | 2 | normal | -| Switch.cs:85:17:85:22 | break; | Switch.cs:85:17:85:22 | break; | break | -| Switch.cs:86:15:86:26 | return ...; | Switch.cs:86:15:86:26 | return ...; | return | -| Switch.cs:86:22:86:25 | true | Switch.cs:86:22:86:25 | true | normal | +| Switch.cs:84:17:85:26 | if (...) ... | Switch.cs:84:21:84:25 | ... > ... | false | +| Switch.cs:84:17:85:26 | if (...) ... | Switch.cs:85:21:85:26 | break; | break | +| Switch.cs:84:21:84:21 | access to parameter j | Switch.cs:84:21:84:21 | access to parameter j | normal | +| Switch.cs:84:21:84:25 | ... > ... | Switch.cs:84:21:84:25 | ... > ... | false | +| Switch.cs:84:21:84:25 | ... > ... | Switch.cs:84:21:84:25 | ... > ... | true | +| Switch.cs:84:25:84:25 | 2 | Switch.cs:84:25:84:25 | 2 | normal | +| Switch.cs:85:21:85:26 | break; | Switch.cs:85:21:85:26 | break; | break | +| Switch.cs:86:17:86:28 | return ...; | Switch.cs:86:17:86:28 | return ...; | return | +| Switch.cs:86:24:86:27 | true | Switch.cs:86:24:86:27 | true | normal | | Switch.cs:88:9:88:21 | return ...; | Switch.cs:88:9:88:21 | return ...; | return | | Switch.cs:88:16:88:20 | false | Switch.cs:88:16:88:20 | false | normal | -| Switch.cs:92:5:99:5 | {...} | Switch.cs:96:15:96:26 | return ...; | return | +| Switch.cs:92:5:99:5 | {...} | Switch.cs:96:17:96:28 | return ...; | return | | Switch.cs:92:5:99:5 | {...} | Switch.cs:98:9:98:21 | return ...; | return | | Switch.cs:93:9:97:9 | switch (...) {...} | Switch.cs:95:18:95:20 | access to type Int32 | no-match | -| Switch.cs:93:9:97:9 | switch (...) {...} | Switch.cs:96:15:96:26 | return ...; | return | +| Switch.cs:93:9:97:9 | switch (...) {...} | Switch.cs:96:17:96:28 | return ...; | return | | Switch.cs:93:17:93:17 | access to parameter o | Switch.cs:93:17:93:17 | access to parameter o | normal | -| Switch.cs:95:13:95:24 | case ...: | Switch.cs:95:18:95:20 | access to type Int32 | no-match | -| Switch.cs:95:13:95:24 | case ...: | Switch.cs:96:15:96:26 | return ...; | return | +| Switch.cs:95:13:95:23 | case ...: | Switch.cs:95:18:95:20 | access to type Int32 | no-match | +| Switch.cs:95:13:95:23 | case ...: | Switch.cs:96:17:96:28 | return ...; | return | | Switch.cs:95:18:95:20 | access to type Int32 | Switch.cs:95:18:95:20 | access to type Int32 | match | | Switch.cs:95:18:95:20 | access to type Int32 | Switch.cs:95:18:95:20 | access to type Int32 | no-match | -| Switch.cs:96:15:96:26 | return ...; | Switch.cs:96:15:96:26 | return ...; | return | -| Switch.cs:96:22:96:25 | true | Switch.cs:96:22:96:25 | true | normal | +| Switch.cs:96:17:96:28 | return ...; | Switch.cs:96:17:96:28 | return ...; | return | +| Switch.cs:96:24:96:27 | true | Switch.cs:96:24:96:27 | true | normal | | Switch.cs:98:9:98:21 | return ...; | Switch.cs:98:9:98:21 | return ...; | return | | Switch.cs:98:16:98:20 | false | Switch.cs:98:16:98:20 | false | normal | -| Switch.cs:102:5:109:5 | {...} | Switch.cs:105:22:105:30 | return ...; | return | -| Switch.cs:102:5:109:5 | {...} | Switch.cs:106:22:106:30 | return ...; | return | +| Switch.cs:102:5:109:5 | {...} | Switch.cs:105:21:105:29 | return ...; | return | +| Switch.cs:102:5:109:5 | {...} | Switch.cs:106:21:106:29 | return ...; | return | | Switch.cs:102:5:109:5 | {...} | Switch.cs:108:9:108:18 | return ...; | return | -| Switch.cs:103:9:107:9 | switch (...) {...} | Switch.cs:105:22:105:30 | return ...; | return | +| Switch.cs:103:9:107:9 | switch (...) {...} | Switch.cs:105:21:105:29 | return ...; | return | | Switch.cs:103:9:107:9 | switch (...) {...} | Switch.cs:106:18:106:18 | 1 | no-match | -| Switch.cs:103:9:107:9 | switch (...) {...} | Switch.cs:106:22:106:30 | return ...; | return | +| Switch.cs:103:9:107:9 | switch (...) {...} | Switch.cs:106:21:106:29 | return ...; | return | | Switch.cs:103:17:103:17 | access to parameter s | Switch.cs:103:17:103:17 | access to parameter s | non-null | | Switch.cs:103:17:103:17 | access to parameter s | Switch.cs:103:17:103:17 | access to parameter s | null | | Switch.cs:103:19:103:25 | access to property Length | Switch.cs:103:17:103:17 | access to parameter s | null | | Switch.cs:103:19:103:25 | access to property Length | Switch.cs:103:19:103:25 | access to property Length | normal | -| Switch.cs:105:13:105:20 | case ...: | Switch.cs:105:18:105:18 | 0 | no-match | -| Switch.cs:105:13:105:20 | case ...: | Switch.cs:105:22:105:30 | return ...; | return | +| Switch.cs:105:13:105:19 | case ...: | Switch.cs:105:18:105:18 | 0 | no-match | +| Switch.cs:105:13:105:19 | case ...: | Switch.cs:105:21:105:29 | return ...; | return | | Switch.cs:105:18:105:18 | 0 | Switch.cs:105:18:105:18 | 0 | match | | Switch.cs:105:18:105:18 | 0 | Switch.cs:105:18:105:18 | 0 | no-match | -| Switch.cs:105:22:105:30 | return ...; | Switch.cs:105:22:105:30 | return ...; | return | -| Switch.cs:105:29:105:29 | 0 | Switch.cs:105:29:105:29 | 0 | normal | -| Switch.cs:106:13:106:20 | case ...: | Switch.cs:106:18:106:18 | 1 | no-match | -| Switch.cs:106:13:106:20 | case ...: | Switch.cs:106:22:106:30 | return ...; | return | +| Switch.cs:105:21:105:29 | return ...; | Switch.cs:105:21:105:29 | return ...; | return | +| Switch.cs:105:28:105:28 | 0 | Switch.cs:105:28:105:28 | 0 | normal | +| Switch.cs:106:13:106:19 | case ...: | Switch.cs:106:18:106:18 | 1 | no-match | +| Switch.cs:106:13:106:19 | case ...: | Switch.cs:106:21:106:29 | return ...; | return | | Switch.cs:106:18:106:18 | 1 | Switch.cs:106:18:106:18 | 1 | match | | Switch.cs:106:18:106:18 | 1 | Switch.cs:106:18:106:18 | 1 | no-match | -| Switch.cs:106:22:106:30 | return ...; | Switch.cs:106:22:106:30 | return ...; | return | -| Switch.cs:106:29:106:29 | 1 | Switch.cs:106:29:106:29 | 1 | normal | +| Switch.cs:106:21:106:29 | return ...; | Switch.cs:106:21:106:29 | return ...; | return | +| Switch.cs:106:28:106:28 | 1 | Switch.cs:106:28:106:28 | 1 | normal | | Switch.cs:108:9:108:18 | return ...; | Switch.cs:108:9:108:18 | return ...; | return | | Switch.cs:108:16:108:17 | -... | Switch.cs:108:16:108:17 | -... | normal | | Switch.cs:108:17:108:17 | 1 | Switch.cs:108:17:108:17 | 1 | normal | | Switch.cs:111:28:111:48 | throw ... | Switch.cs:111:28:111:48 | throw ... | throw(Exception) | | Switch.cs:111:34:111:48 | object creation of type Exception | Switch.cs:111:34:111:48 | object creation of type Exception | normal | -| Switch.cs:114:5:121:5 | {...} | Switch.cs:117:36:117:44 | return ...; | return | -| Switch.cs:114:5:121:5 | {...} | Switch.cs:118:35:118:43 | return ...; | return | +| Switch.cs:114:5:121:5 | {...} | Switch.cs:117:37:117:45 | return ...; | return | +| Switch.cs:114:5:121:5 | {...} | Switch.cs:118:36:118:44 | return ...; | return | | Switch.cs:114:5:121:5 | {...} | Switch.cs:120:9:120:18 | return ...; | return | -| Switch.cs:115:9:119:9 | switch (...) {...} | Switch.cs:117:36:117:44 | return ...; | return | +| Switch.cs:115:9:119:9 | switch (...) {...} | Switch.cs:117:37:117:45 | return ...; | return | | Switch.cs:115:9:119:9 | switch (...) {...} | Switch.cs:118:18:118:18 | 2 | no-match | -| Switch.cs:115:9:119:9 | switch (...) {...} | Switch.cs:118:25:118:31 | ... == ... | false | -| Switch.cs:115:9:119:9 | switch (...) {...} | Switch.cs:118:35:118:43 | return ...; | return | +| Switch.cs:115:9:119:9 | switch (...) {...} | Switch.cs:118:25:118:33 | ... == ... | false | +| Switch.cs:115:9:119:9 | switch (...) {...} | Switch.cs:118:36:118:44 | return ...; | return | | Switch.cs:115:17:115:17 | access to parameter s | Switch.cs:115:17:115:17 | access to parameter s | normal | | Switch.cs:115:17:115:24 | access to property Length | Switch.cs:115:17:115:24 | access to property Length | normal | -| Switch.cs:117:13:117:34 | case ...: | Switch.cs:117:18:117:18 | 3 | no-match | -| Switch.cs:117:13:117:34 | case ...: | Switch.cs:117:25:117:32 | ... == ... | false | -| Switch.cs:117:13:117:34 | case ...: | Switch.cs:117:36:117:44 | return ...; | return | +| Switch.cs:117:13:117:35 | case ...: | Switch.cs:117:18:117:18 | 3 | no-match | +| Switch.cs:117:13:117:35 | case ...: | Switch.cs:117:25:117:34 | ... == ... | false | +| Switch.cs:117:13:117:35 | case ...: | Switch.cs:117:37:117:45 | return ...; | return | | Switch.cs:117:18:117:18 | 3 | Switch.cs:117:18:117:18 | 3 | match | | Switch.cs:117:18:117:18 | 3 | Switch.cs:117:18:117:18 | 3 | no-match | | Switch.cs:117:25:117:25 | access to parameter s | Switch.cs:117:25:117:25 | access to parameter s | normal | -| Switch.cs:117:25:117:32 | ... == ... | Switch.cs:117:25:117:32 | ... == ... | false | -| Switch.cs:117:25:117:32 | ... == ... | Switch.cs:117:25:117:32 | ... == ... | true | -| Switch.cs:117:28:117:32 | "foo" | Switch.cs:117:28:117:32 | "foo" | normal | -| Switch.cs:117:36:117:44 | return ...; | Switch.cs:117:36:117:44 | return ...; | return | -| Switch.cs:117:43:117:43 | 1 | Switch.cs:117:43:117:43 | 1 | normal | -| Switch.cs:118:13:118:33 | case ...: | Switch.cs:118:18:118:18 | 2 | no-match | -| Switch.cs:118:13:118:33 | case ...: | Switch.cs:118:25:118:31 | ... == ... | false | -| Switch.cs:118:13:118:33 | case ...: | Switch.cs:118:35:118:43 | return ...; | return | +| Switch.cs:117:25:117:34 | ... == ... | Switch.cs:117:25:117:34 | ... == ... | false | +| Switch.cs:117:25:117:34 | ... == ... | Switch.cs:117:25:117:34 | ... == ... | true | +| Switch.cs:117:30:117:34 | "foo" | Switch.cs:117:30:117:34 | "foo" | normal | +| Switch.cs:117:37:117:45 | return ...; | Switch.cs:117:37:117:45 | return ...; | return | +| Switch.cs:117:44:117:44 | 1 | Switch.cs:117:44:117:44 | 1 | normal | +| Switch.cs:118:13:118:34 | case ...: | Switch.cs:118:18:118:18 | 2 | no-match | +| Switch.cs:118:13:118:34 | case ...: | Switch.cs:118:25:118:33 | ... == ... | false | +| Switch.cs:118:13:118:34 | case ...: | Switch.cs:118:36:118:44 | return ...; | return | | Switch.cs:118:18:118:18 | 2 | Switch.cs:118:18:118:18 | 2 | match | | Switch.cs:118:18:118:18 | 2 | Switch.cs:118:18:118:18 | 2 | no-match | | Switch.cs:118:25:118:25 | access to parameter s | Switch.cs:118:25:118:25 | access to parameter s | normal | -| Switch.cs:118:25:118:31 | ... == ... | Switch.cs:118:25:118:31 | ... == ... | false | -| Switch.cs:118:25:118:31 | ... == ... | Switch.cs:118:25:118:31 | ... == ... | true | -| Switch.cs:118:28:118:31 | "fu" | Switch.cs:118:28:118:31 | "fu" | normal | -| Switch.cs:118:35:118:43 | return ...; | Switch.cs:118:35:118:43 | return ...; | return | -| Switch.cs:118:42:118:42 | 2 | Switch.cs:118:42:118:42 | 2 | normal | +| Switch.cs:118:25:118:33 | ... == ... | Switch.cs:118:25:118:33 | ... == ... | false | +| Switch.cs:118:25:118:33 | ... == ... | Switch.cs:118:25:118:33 | ... == ... | true | +| Switch.cs:118:30:118:33 | "fu" | Switch.cs:118:30:118:33 | "fu" | normal | +| Switch.cs:118:36:118:44 | return ...; | Switch.cs:118:36:118:44 | return ...; | return | +| Switch.cs:118:43:118:43 | 2 | Switch.cs:118:43:118:43 | 2 | normal | | Switch.cs:120:9:120:18 | return ...; | Switch.cs:120:9:120:18 | return ...; | return | | Switch.cs:120:16:120:17 | -... | Switch.cs:120:16:120:17 | -... | normal | | Switch.cs:120:17:120:17 | 1 | Switch.cs:120:17:120:17 | 1 | normal | @@ -2611,6 +3283,41 @@ | Switch.cs:150:18:150:18 | 2 | Switch.cs:150:18:150:18 | 2 | no-match | | Switch.cs:150:21:150:29 | return ...; | Switch.cs:150:21:150:29 | return ...; | return | | Switch.cs:150:28:150:28 | 2 | Switch.cs:150:28:150:28 | 2 | normal | +| Switch.cs:155:5:161:5 | {...} | Switch.cs:156:41:156:45 | false | throw(InvalidOperationException) [no-match] | +| Switch.cs:155:5:161:5 | {...} | Switch.cs:158:13:158:48 | call to method WriteLine | normal | +| Switch.cs:155:5:161:5 | {...} | Switch.cs:160:13:160:48 | call to method WriteLine | normal | +| Switch.cs:156:9:156:55 | ... ...; | Switch.cs:156:13:156:54 | String s = ... | normal | +| Switch.cs:156:9:156:55 | ... ...; | Switch.cs:156:41:156:45 | false | throw(InvalidOperationException) [no-match] | +| Switch.cs:156:13:156:54 | String s = ... | Switch.cs:156:13:156:54 | String s = ... | normal | +| Switch.cs:156:13:156:54 | String s = ... | Switch.cs:156:41:156:45 | false | throw(InvalidOperationException) [no-match] | +| Switch.cs:156:17:156:17 | access to parameter b | Switch.cs:156:17:156:17 | access to parameter b | normal | +| Switch.cs:156:17:156:54 | ... switch { ... } | Switch.cs:156:36:156:38 | "a" | normal | +| Switch.cs:156:17:156:54 | ... switch { ... } | Switch.cs:156:41:156:45 | false | throw(InvalidOperationException) [no-match] | +| Switch.cs:156:17:156:54 | ... switch { ... } | Switch.cs:156:50:156:52 | "b" | normal | +| Switch.cs:156:28:156:31 | true | Switch.cs:156:28:156:31 | true | match | +| Switch.cs:156:28:156:31 | true | Switch.cs:156:28:156:31 | true | no-match | +| Switch.cs:156:28:156:38 | ... => ... | Switch.cs:156:28:156:31 | true | no-match | +| Switch.cs:156:28:156:38 | ... => ... | Switch.cs:156:36:156:38 | "a" | normal | +| Switch.cs:156:36:156:38 | "a" | Switch.cs:156:36:156:38 | "a" | normal | +| Switch.cs:156:41:156:45 | false | Switch.cs:156:41:156:45 | false | match | +| Switch.cs:156:41:156:45 | false | Switch.cs:156:41:156:45 | false | no-match | +| Switch.cs:156:41:156:52 | ... => ... | Switch.cs:156:41:156:45 | false | no-match | +| Switch.cs:156:41:156:52 | ... => ... | Switch.cs:156:50:156:52 | "b" | normal | +| Switch.cs:156:50:156:52 | "b" | Switch.cs:156:50:156:52 | "b" | normal | +| Switch.cs:157:9:160:49 | if (...) ... | Switch.cs:158:13:158:48 | call to method WriteLine | normal | +| Switch.cs:157:9:160:49 | if (...) ... | Switch.cs:160:13:160:48 | call to method WriteLine | normal | +| Switch.cs:157:13:157:13 | access to parameter b | Switch.cs:157:13:157:13 | access to parameter b | false | +| Switch.cs:157:13:157:13 | access to parameter b | Switch.cs:157:13:157:13 | access to parameter b | true | +| Switch.cs:158:13:158:48 | call to method WriteLine | Switch.cs:158:13:158:48 | call to method WriteLine | normal | +| Switch.cs:158:13:158:49 | ...; | Switch.cs:158:13:158:48 | call to method WriteLine | normal | +| Switch.cs:158:38:158:47 | $"..." | Switch.cs:158:38:158:47 | $"..." | normal | +| Switch.cs:158:40:158:43 | "a = " | Switch.cs:158:40:158:43 | "a = " | normal | +| Switch.cs:158:45:158:45 | access to local variable s | Switch.cs:158:45:158:45 | access to local variable s | normal | +| Switch.cs:160:13:160:48 | call to method WriteLine | Switch.cs:160:13:160:48 | call to method WriteLine | normal | +| Switch.cs:160:13:160:49 | ...; | Switch.cs:160:13:160:48 | call to method WriteLine | normal | +| Switch.cs:160:38:160:47 | $"..." | Switch.cs:160:38:160:47 | $"..." | normal | +| Switch.cs:160:40:160:43 | "b = " | Switch.cs:160:40:160:43 | "b = " | normal | +| Switch.cs:160:45:160:45 | access to local variable s | Switch.cs:160:45:160:45 | access to local variable s | normal | | TypeAccesses.cs:4:5:9:5 | {...} | TypeAccesses.cs:8:13:8:27 | Type t = ... | normal | | TypeAccesses.cs:5:9:5:26 | ... ...; | TypeAccesses.cs:5:13:5:25 | String s = ... | normal | | TypeAccesses.cs:5:13:5:25 | String s = ... | TypeAccesses.cs:5:13:5:25 | String s = ... | normal | @@ -2634,10 +3341,12 @@ | VarDecls.cs:7:9:10:9 | fixed(...) { ... } | VarDecls.cs:9:13:9:29 | return ...; | return | | VarDecls.cs:7:22:7:36 | Char* c1 = ... | VarDecls.cs:7:22:7:36 | Char* c1 = ... | normal | | VarDecls.cs:7:27:7:33 | access to parameter strings | VarDecls.cs:7:27:7:33 | access to parameter strings | normal | +| VarDecls.cs:7:27:7:36 | (...) ... | VarDecls.cs:7:27:7:36 | (...) ... | normal | | VarDecls.cs:7:27:7:36 | access to array element | VarDecls.cs:7:27:7:36 | access to array element | normal | | VarDecls.cs:7:35:7:35 | 0 | VarDecls.cs:7:35:7:35 | 0 | normal | | VarDecls.cs:7:39:7:53 | Char* c2 = ... | VarDecls.cs:7:39:7:53 | Char* c2 = ... | normal | | VarDecls.cs:7:44:7:50 | access to parameter strings | VarDecls.cs:7:44:7:50 | access to parameter strings | normal | +| VarDecls.cs:7:44:7:53 | (...) ... | VarDecls.cs:7:44:7:53 | (...) ... | normal | | VarDecls.cs:7:44:7:53 | access to array element | VarDecls.cs:7:44:7:53 | access to array element | normal | | VarDecls.cs:7:52:7:52 | 1 | VarDecls.cs:7:52:7:52 | 1 | normal | | VarDecls.cs:8:9:10:9 | {...} | VarDecls.cs:9:13:9:29 | return ...; | return | diff --git a/csharp/ql/test/library-tests/controlflow/graph/LoopUnrolling.cs b/csharp/ql/test/library-tests/controlflow/graph/LoopUnrolling.cs index 5e38a524405f..0121251aa0a4 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/LoopUnrolling.cs +++ b/csharp/ql/test/library-tests/controlflow/graph/LoopUnrolling.cs @@ -8,14 +8,14 @@ void M1(string[] args) { if (args.Length == 0) return; - foreach(var arg in args) // unroll + foreach (var arg in args) // unroll Console.WriteLine(arg); } void M2() { - var xs = new string[]{ "a", "b", "c" }; - foreach(var x in xs) // unroll + var xs = new string[] { "a", "b", "c" }; + foreach (var x in xs) // unroll Console.WriteLine(x); } @@ -29,33 +29,33 @@ void M3(string args) void M4() { var xs = new string[0]; - foreach(var x in xs) // no unroll + foreach (var x in xs) // skip Console.WriteLine(x); } void M5() { - var xs = new string[]{ "a", "b", "c" }; - var ys = new string[]{ "0", "1", "2" }; - foreach(var x in xs) // unroll - foreach(var y in ys) // unroll + var xs = new string[] { "a", "b", "c" }; + var ys = new string[] { "0", "1", "2" }; + foreach (var x in xs) // unroll + foreach (var y in ys) // unroll Console.WriteLine(x + y); } void M6() { - var xs = new string[]{ "a", "b", "c" }; - foreach(var x in xs) // unroll + var xs = new string[] { "a", "b", "c" }; + foreach (var x in xs) // unroll { - Label: Console.WriteLine(x); + Label: Console.WriteLine(x); goto Label; } } void M7(bool b) { - var xs = new string[]{ "a", "b", "c" }; - foreach(var x in xs) // unroll + var xs = new string[] { "a", "b", "c" }; + foreach (var x in xs) // unroll { if (b) Console.WriteLine(x); @@ -69,7 +69,34 @@ void M8(List args) if (!args.Any()) return; args.Clear(); - foreach(var arg in args) // no unroll + foreach (var arg in args) // skip Console.WriteLine(arg); } + + void M9() + { + var xs = new string[2, 0]; + foreach (var x in xs) //skip + { + Console.WriteLine(x); + } + } + + void M10() + { + var xs = new string[0, 2]; + foreach (var x in xs) // skip + { + Console.WriteLine(x); + } + } + + void M11() + { + var xs = new string[2, 2]; + foreach (var x in xs) // unroll + { + Console.WriteLine(x); + } + } } diff --git a/csharp/ql/test/library-tests/controlflow/graph/MultiImplementationA.cs b/csharp/ql/test/library-tests/controlflow/graph/MultiImplementationA.cs new file mode 100644 index 000000000000..cf988d3723be --- /dev/null +++ b/csharp/ql/test/library-tests/controlflow/graph/MultiImplementationA.cs @@ -0,0 +1,38 @@ +// semmle-extractor-options: --separate-compilation + +// Stub implementation +class C1 +{ + public int P1 => throw null; + public int P2 { get { throw null; } set { throw null; } } + public int M() => throw null; +} + +class C2 +{ + public int F = 0; + public int this[int i] => i; + public string this[string s] { get { return s; } set { } } + public void M1(int i = 0) + { + int M2() => 0; + } + public C2(int i) { F = i; } + public C2() : this(0) { } + ~C2() { } + public static implicit operator C2(int i) => null; + public int P { get; set; } = 0; +} + +// Stub implementation +class C3 +{ + public int P3 { get => throw null; } +} + +// Stub implementation +partial class C4 +{ + int M1() { throw null; } + int M2() { throw null; } +} diff --git a/csharp/ql/test/library-tests/controlflow/graph/MultiImplementationB.cs b/csharp/ql/test/library-tests/controlflow/graph/MultiImplementationB.cs new file mode 100644 index 000000000000..1422c7d593fb --- /dev/null +++ b/csharp/ql/test/library-tests/controlflow/graph/MultiImplementationB.cs @@ -0,0 +1,33 @@ +class C1 +{ + public int P1 => 0; + public int P2 { get { return 1; } set { } } + public int M() => 2; +} + +// Stub implementation +class C2 +{ + public int F = 1; + public int this[int i] => throw null; + public string this[string s] { get { throw null; } set { } } + public void M1(int i = 1) + { + int M2() => throw null; + } + public C2(int i) { throw null; } + public C2() : this(1) { } + ~C2() { throw null; } + public static implicit operator C2(int i) => throw null; + public int P { get; set; } = 1; +} + +class C3 +{ + public int P3 { get; } +} + +partial class C4 +{ + int M1() => 0; +} diff --git a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected index f790cd0e90c2..4a853b45fbf0 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected @@ -293,12 +293,15 @@ | ArrayCreation.cs:5:20:5:32 | array creation of type Int32[,] | ArrayCreation.cs:5:12:5:13 | exit M2 | semmle.label | successor | | ArrayCreation.cs:5:28:5:28 | 0 | ArrayCreation.cs:5:31:5:31 | 1 | semmle.label | successor | | ArrayCreation.cs:5:31:5:31 | 1 | ArrayCreation.cs:5:20:5:32 | array creation of type Int32[,] | semmle.label | successor | -| ArrayCreation.cs:7:11:7:12 | enter M3 | ArrayCreation.cs:7:19:7:36 | array creation of type Int32[] | semmle.label | successor | +| ArrayCreation.cs:7:11:7:12 | enter M3 | ArrayCreation.cs:7:19:7:36 | 2 | semmle.label | successor | +| ArrayCreation.cs:7:19:7:36 | 2 | ArrayCreation.cs:7:19:7:36 | array creation of type Int32[] | semmle.label | successor | | ArrayCreation.cs:7:19:7:36 | array creation of type Int32[] | ArrayCreation.cs:7:31:7:31 | 0 | semmle.label | successor | | ArrayCreation.cs:7:29:7:36 | { ..., ... } | ArrayCreation.cs:7:11:7:12 | exit M3 | semmle.label | successor | | ArrayCreation.cs:7:31:7:31 | 0 | ArrayCreation.cs:7:34:7:34 | 1 | semmle.label | successor | | ArrayCreation.cs:7:34:7:34 | 1 | ArrayCreation.cs:7:29:7:36 | { ..., ... } | semmle.label | successor | -| ArrayCreation.cs:9:12:9:13 | enter M4 | ArrayCreation.cs:9:20:9:52 | array creation of type Int32[,] | semmle.label | successor | +| ArrayCreation.cs:9:12:9:13 | enter M4 | ArrayCreation.cs:9:20:9:52 | 2 | semmle.label | successor | +| ArrayCreation.cs:9:20:9:52 | 2 | ArrayCreation.cs:9:20:9:52 | 2 | semmle.label | successor | +| ArrayCreation.cs:9:20:9:52 | 2 | ArrayCreation.cs:9:20:9:52 | array creation of type Int32[,] | semmle.label | successor | | ArrayCreation.cs:9:20:9:52 | array creation of type Int32[,] | ArrayCreation.cs:9:35:9:35 | 0 | semmle.label | successor | | ArrayCreation.cs:9:31:9:52 | { ..., ... } | ArrayCreation.cs:9:12:9:13 | exit M4 | semmle.label | successor | | ArrayCreation.cs:9:33:9:40 | { ..., ... } | ArrayCreation.cs:9:45:9:45 | 2 | semmle.label | successor | @@ -307,6 +310,565 @@ | ArrayCreation.cs:9:43:9:50 | { ..., ... } | ArrayCreation.cs:9:31:9:52 | { ..., ... } | semmle.label | successor | | ArrayCreation.cs:9:45:9:45 | 2 | ArrayCreation.cs:9:48:9:48 | 3 | semmle.label | successor | | ArrayCreation.cs:9:48:9:48 | 3 | ArrayCreation.cs:9:43:9:50 | { ..., ... } | semmle.label | successor | +| Assert.cs:7:10:7:11 | enter M1 | Assert.cs:8:5:12:5 | {...} | semmle.label | successor | +| Assert.cs:8:5:12:5 | {...} | Assert.cs:9:9:9:33 | ... ...; | semmle.label | successor | +| Assert.cs:9:9:9:33 | ... ...; | Assert.cs:9:20:9:32 | ... ? ... : ... | semmle.label | successor | +| Assert.cs:9:16:9:32 | String s = ... | Assert.cs:10:9:10:32 | ...; | semmle.label | successor | +| Assert.cs:9:20:9:20 | access to parameter b | Assert.cs:9:24:9:27 | null | semmle.label | true | +| Assert.cs:9:20:9:20 | access to parameter b | Assert.cs:9:31:9:32 | "" | semmle.label | false | +| Assert.cs:9:20:9:32 | ... ? ... : ... | Assert.cs:9:20:9:20 | access to parameter b | semmle.label | successor | +| Assert.cs:9:24:9:27 | null | Assert.cs:9:16:9:32 | String s = ... | semmle.label | successor | +| Assert.cs:9:31:9:32 | "" | Assert.cs:9:16:9:32 | String s = ... | semmle.label | successor | +| Assert.cs:10:9:10:31 | [assertion failure] call to method Assert | Assert.cs:7:10:7:11 | exit M1 | semmle.label | exit | +| Assert.cs:10:9:10:31 | [assertion success] call to method Assert | Assert.cs:11:9:11:36 | ...; | semmle.label | successor | +| Assert.cs:10:9:10:32 | ...; | Assert.cs:10:22:10:22 | access to local variable s | semmle.label | successor | +| Assert.cs:10:22:10:22 | access to local variable s | Assert.cs:10:27:10:30 | null | semmle.label | successor | +| Assert.cs:10:22:10:30 | ... != ... | Assert.cs:10:9:10:31 | [assertion failure] call to method Assert | semmle.label | false | +| Assert.cs:10:22:10:30 | ... != ... | Assert.cs:10:9:10:31 | [assertion success] call to method Assert | semmle.label | true | +| Assert.cs:10:27:10:30 | null | Assert.cs:10:22:10:30 | ... != ... | semmle.label | successor | +| Assert.cs:11:9:11:35 | call to method WriteLine | Assert.cs:7:10:7:11 | exit M1 | semmle.label | successor | +| Assert.cs:11:9:11:36 | ...; | Assert.cs:11:27:11:27 | access to local variable s | semmle.label | successor | +| Assert.cs:11:27:11:27 | access to local variable s | Assert.cs:11:27:11:34 | access to property Length | semmle.label | successor | +| Assert.cs:11:27:11:34 | access to property Length | Assert.cs:11:9:11:35 | call to method WriteLine | semmle.label | successor | +| Assert.cs:14:10:14:11 | enter M2 | Assert.cs:15:5:19:5 | {...} | semmle.label | successor | +| Assert.cs:15:5:19:5 | {...} | Assert.cs:16:9:16:33 | ... ...; | semmle.label | successor | +| Assert.cs:16:9:16:33 | ... ...; | Assert.cs:16:20:16:32 | ... ? ... : ... | semmle.label | successor | +| Assert.cs:16:16:16:32 | String s = ... | Assert.cs:17:9:17:25 | ...; | semmle.label | successor | +| Assert.cs:16:20:16:20 | access to parameter b | Assert.cs:16:24:16:27 | null | semmle.label | true | +| Assert.cs:16:20:16:20 | access to parameter b | Assert.cs:16:31:16:32 | "" | semmle.label | false | +| Assert.cs:16:20:16:32 | ... ? ... : ... | Assert.cs:16:20:16:20 | access to parameter b | semmle.label | successor | +| Assert.cs:16:24:16:27 | null | Assert.cs:16:16:16:32 | String s = ... | semmle.label | successor | +| Assert.cs:16:31:16:32 | "" | Assert.cs:16:16:16:32 | String s = ... | semmle.label | successor | +| Assert.cs:17:9:17:24 | [assertion failure] call to method IsNull | Assert.cs:14:10:14:11 | exit M2 | semmle.label | exception(AssertFailedException) | +| Assert.cs:17:9:17:24 | [assertion success] call to method IsNull | Assert.cs:18:9:18:36 | ...; | semmle.label | successor | +| Assert.cs:17:9:17:25 | ...; | Assert.cs:17:23:17:23 | access to local variable s | semmle.label | successor | +| Assert.cs:17:23:17:23 | access to local variable s | Assert.cs:17:9:17:24 | [assertion failure] call to method IsNull | semmle.label | non-null | +| Assert.cs:17:23:17:23 | access to local variable s | Assert.cs:17:9:17:24 | [assertion success] call to method IsNull | semmle.label | null | +| Assert.cs:18:9:18:35 | call to method WriteLine | Assert.cs:14:10:14:11 | exit M2 | semmle.label | successor | +| Assert.cs:18:9:18:36 | ...; | Assert.cs:18:27:18:27 | access to local variable s | semmle.label | successor | +| Assert.cs:18:27:18:27 | access to local variable s | Assert.cs:18:27:18:34 | access to property Length | semmle.label | successor | +| Assert.cs:18:27:18:34 | access to property Length | Assert.cs:18:9:18:35 | call to method WriteLine | semmle.label | successor | +| Assert.cs:21:10:21:11 | enter M3 | Assert.cs:22:5:26:5 | {...} | semmle.label | successor | +| Assert.cs:22:5:26:5 | {...} | Assert.cs:23:9:23:33 | ... ...; | semmle.label | successor | +| Assert.cs:23:9:23:33 | ... ...; | Assert.cs:23:20:23:32 | ... ? ... : ... | semmle.label | successor | +| Assert.cs:23:16:23:32 | String s = ... | Assert.cs:24:9:24:28 | ...; | semmle.label | successor | +| Assert.cs:23:20:23:20 | access to parameter b | Assert.cs:23:24:23:27 | null | semmle.label | true | +| Assert.cs:23:20:23:20 | access to parameter b | Assert.cs:23:31:23:32 | "" | semmle.label | false | +| Assert.cs:23:20:23:32 | ... ? ... : ... | Assert.cs:23:20:23:20 | access to parameter b | semmle.label | successor | +| Assert.cs:23:24:23:27 | null | Assert.cs:23:16:23:32 | String s = ... | semmle.label | successor | +| Assert.cs:23:31:23:32 | "" | Assert.cs:23:16:23:32 | String s = ... | semmle.label | successor | +| Assert.cs:24:9:24:27 | [assertion failure] call to method IsNotNull | Assert.cs:21:10:21:11 | exit M3 | semmle.label | exception(AssertFailedException) | +| Assert.cs:24:9:24:27 | [assertion success] call to method IsNotNull | Assert.cs:25:9:25:36 | ...; | semmle.label | successor | +| Assert.cs:24:9:24:28 | ...; | Assert.cs:24:26:24:26 | access to local variable s | semmle.label | successor | +| Assert.cs:24:26:24:26 | access to local variable s | Assert.cs:24:9:24:27 | [assertion failure] call to method IsNotNull | semmle.label | null | +| Assert.cs:24:26:24:26 | access to local variable s | Assert.cs:24:9:24:27 | [assertion success] call to method IsNotNull | semmle.label | non-null | +| Assert.cs:25:9:25:35 | call to method WriteLine | Assert.cs:21:10:21:11 | exit M3 | semmle.label | successor | +| Assert.cs:25:9:25:36 | ...; | Assert.cs:25:27:25:27 | access to local variable s | semmle.label | successor | +| Assert.cs:25:27:25:27 | access to local variable s | Assert.cs:25:27:25:34 | access to property Length | semmle.label | successor | +| Assert.cs:25:27:25:34 | access to property Length | Assert.cs:25:9:25:35 | call to method WriteLine | semmle.label | successor | +| Assert.cs:28:10:28:11 | enter M4 | Assert.cs:29:5:33:5 | {...} | semmle.label | successor | +| Assert.cs:29:5:33:5 | {...} | Assert.cs:30:9:30:33 | ... ...; | semmle.label | successor | +| Assert.cs:30:9:30:33 | ... ...; | Assert.cs:30:20:30:32 | ... ? ... : ... | semmle.label | successor | +| Assert.cs:30:16:30:32 | String s = ... | Assert.cs:31:9:31:33 | ...; | semmle.label | successor | +| Assert.cs:30:20:30:20 | access to parameter b | Assert.cs:30:24:30:27 | null | semmle.label | true | +| Assert.cs:30:20:30:20 | access to parameter b | Assert.cs:30:31:30:32 | "" | semmle.label | false | +| Assert.cs:30:20:30:32 | ... ? ... : ... | Assert.cs:30:20:30:20 | access to parameter b | semmle.label | successor | +| Assert.cs:30:24:30:27 | null | Assert.cs:30:16:30:32 | String s = ... | semmle.label | successor | +| Assert.cs:30:31:30:32 | "" | Assert.cs:30:16:30:32 | String s = ... | semmle.label | successor | +| Assert.cs:31:9:31:32 | [assertion failure] call to method IsTrue | Assert.cs:28:10:28:11 | exit M4 | semmle.label | exception(AssertFailedException) | +| Assert.cs:31:9:31:32 | [assertion success] call to method IsTrue | Assert.cs:32:9:32:36 | ...; | semmle.label | successor | +| Assert.cs:31:9:31:33 | ...; | Assert.cs:31:23:31:23 | access to local variable s | semmle.label | successor | +| Assert.cs:31:23:31:23 | access to local variable s | Assert.cs:31:28:31:31 | null | semmle.label | successor | +| Assert.cs:31:23:31:31 | ... == ... | Assert.cs:31:9:31:32 | [assertion failure] call to method IsTrue | semmle.label | false | +| Assert.cs:31:23:31:31 | ... == ... | Assert.cs:31:9:31:32 | [assertion success] call to method IsTrue | semmle.label | true | +| Assert.cs:31:28:31:31 | null | Assert.cs:31:23:31:31 | ... == ... | semmle.label | successor | +| Assert.cs:32:9:32:35 | call to method WriteLine | Assert.cs:28:10:28:11 | exit M4 | semmle.label | successor | +| Assert.cs:32:9:32:36 | ...; | Assert.cs:32:27:32:27 | access to local variable s | semmle.label | successor | +| Assert.cs:32:27:32:27 | access to local variable s | Assert.cs:32:27:32:34 | access to property Length | semmle.label | successor | +| Assert.cs:32:27:32:34 | access to property Length | Assert.cs:32:9:32:35 | call to method WriteLine | semmle.label | successor | +| Assert.cs:35:10:35:11 | enter M5 | Assert.cs:36:5:40:5 | {...} | semmle.label | successor | +| Assert.cs:36:5:40:5 | {...} | Assert.cs:37:9:37:33 | ... ...; | semmle.label | successor | +| Assert.cs:37:9:37:33 | ... ...; | Assert.cs:37:20:37:32 | ... ? ... : ... | semmle.label | successor | +| Assert.cs:37:16:37:32 | String s = ... | Assert.cs:38:9:38:33 | ...; | semmle.label | successor | +| Assert.cs:37:20:37:20 | access to parameter b | Assert.cs:37:24:37:27 | null | semmle.label | true | +| Assert.cs:37:20:37:20 | access to parameter b | Assert.cs:37:31:37:32 | "" | semmle.label | false | +| Assert.cs:37:20:37:32 | ... ? ... : ... | Assert.cs:37:20:37:20 | access to parameter b | semmle.label | successor | +| Assert.cs:37:24:37:27 | null | Assert.cs:37:16:37:32 | String s = ... | semmle.label | successor | +| Assert.cs:37:31:37:32 | "" | Assert.cs:37:16:37:32 | String s = ... | semmle.label | successor | +| Assert.cs:38:9:38:32 | [assertion failure] call to method IsTrue | Assert.cs:35:10:35:11 | exit M5 | semmle.label | exception(AssertFailedException) | +| Assert.cs:38:9:38:32 | [assertion success] call to method IsTrue | Assert.cs:39:9:39:36 | ...; | semmle.label | successor | +| Assert.cs:38:9:38:33 | ...; | Assert.cs:38:23:38:23 | access to local variable s | semmle.label | successor | +| Assert.cs:38:23:38:23 | access to local variable s | Assert.cs:38:28:38:31 | null | semmle.label | successor | +| Assert.cs:38:23:38:31 | ... != ... | Assert.cs:38:9:38:32 | [assertion failure] call to method IsTrue | semmle.label | false | +| Assert.cs:38:23:38:31 | ... != ... | Assert.cs:38:9:38:32 | [assertion success] call to method IsTrue | semmle.label | true | +| Assert.cs:38:28:38:31 | null | Assert.cs:38:23:38:31 | ... != ... | semmle.label | successor | +| Assert.cs:39:9:39:35 | call to method WriteLine | Assert.cs:35:10:35:11 | exit M5 | semmle.label | successor | +| Assert.cs:39:9:39:36 | ...; | Assert.cs:39:27:39:27 | access to local variable s | semmle.label | successor | +| Assert.cs:39:27:39:27 | access to local variable s | Assert.cs:39:27:39:34 | access to property Length | semmle.label | successor | +| Assert.cs:39:27:39:34 | access to property Length | Assert.cs:39:9:39:35 | call to method WriteLine | semmle.label | successor | +| Assert.cs:42:10:42:11 | enter M6 | Assert.cs:43:5:47:5 | {...} | semmle.label | successor | +| Assert.cs:43:5:47:5 | {...} | Assert.cs:44:9:44:33 | ... ...; | semmle.label | successor | +| Assert.cs:44:9:44:33 | ... ...; | Assert.cs:44:20:44:32 | ... ? ... : ... | semmle.label | successor | +| Assert.cs:44:16:44:32 | String s = ... | Assert.cs:45:9:45:34 | ...; | semmle.label | successor | +| Assert.cs:44:20:44:20 | access to parameter b | Assert.cs:44:24:44:27 | null | semmle.label | true | +| Assert.cs:44:20:44:20 | access to parameter b | Assert.cs:44:31:44:32 | "" | semmle.label | false | +| Assert.cs:44:20:44:32 | ... ? ... : ... | Assert.cs:44:20:44:20 | access to parameter b | semmle.label | successor | +| Assert.cs:44:24:44:27 | null | Assert.cs:44:16:44:32 | String s = ... | semmle.label | successor | +| Assert.cs:44:31:44:32 | "" | Assert.cs:44:16:44:32 | String s = ... | semmle.label | successor | +| Assert.cs:45:9:45:33 | [assertion failure] call to method IsFalse | Assert.cs:42:10:42:11 | exit M6 | semmle.label | exception(AssertFailedException) | +| Assert.cs:45:9:45:33 | [assertion success] call to method IsFalse | Assert.cs:46:9:46:36 | ...; | semmle.label | successor | +| Assert.cs:45:9:45:34 | ...; | Assert.cs:45:24:45:24 | access to local variable s | semmle.label | successor | +| Assert.cs:45:24:45:24 | access to local variable s | Assert.cs:45:29:45:32 | null | semmle.label | successor | +| Assert.cs:45:24:45:32 | ... != ... | Assert.cs:45:9:45:33 | [assertion failure] call to method IsFalse | semmle.label | true | +| Assert.cs:45:24:45:32 | ... != ... | Assert.cs:45:9:45:33 | [assertion success] call to method IsFalse | semmle.label | false | +| Assert.cs:45:29:45:32 | null | Assert.cs:45:24:45:32 | ... != ... | semmle.label | successor | +| Assert.cs:46:9:46:35 | call to method WriteLine | Assert.cs:42:10:42:11 | exit M6 | semmle.label | successor | +| Assert.cs:46:9:46:36 | ...; | Assert.cs:46:27:46:27 | access to local variable s | semmle.label | successor | +| Assert.cs:46:27:46:27 | access to local variable s | Assert.cs:46:27:46:34 | access to property Length | semmle.label | successor | +| Assert.cs:46:27:46:34 | access to property Length | Assert.cs:46:9:46:35 | call to method WriteLine | semmle.label | successor | +| Assert.cs:49:10:49:11 | enter M7 | Assert.cs:50:5:54:5 | {...} | semmle.label | successor | +| Assert.cs:50:5:54:5 | {...} | Assert.cs:51:9:51:33 | ... ...; | semmle.label | successor | +| Assert.cs:51:9:51:33 | ... ...; | Assert.cs:51:20:51:32 | ... ? ... : ... | semmle.label | successor | +| Assert.cs:51:16:51:32 | String s = ... | Assert.cs:52:9:52:34 | ...; | semmle.label | successor | +| Assert.cs:51:20:51:20 | access to parameter b | Assert.cs:51:24:51:27 | null | semmle.label | true | +| Assert.cs:51:20:51:20 | access to parameter b | Assert.cs:51:31:51:32 | "" | semmle.label | false | +| Assert.cs:51:20:51:32 | ... ? ... : ... | Assert.cs:51:20:51:20 | access to parameter b | semmle.label | successor | +| Assert.cs:51:24:51:27 | null | Assert.cs:51:16:51:32 | String s = ... | semmle.label | successor | +| Assert.cs:51:31:51:32 | "" | Assert.cs:51:16:51:32 | String s = ... | semmle.label | successor | +| Assert.cs:52:9:52:33 | [assertion failure] call to method IsFalse | Assert.cs:49:10:49:11 | exit M7 | semmle.label | exception(AssertFailedException) | +| Assert.cs:52:9:52:33 | [assertion success] call to method IsFalse | Assert.cs:53:9:53:36 | ...; | semmle.label | successor | +| Assert.cs:52:9:52:34 | ...; | Assert.cs:52:24:52:24 | access to local variable s | semmle.label | successor | +| Assert.cs:52:24:52:24 | access to local variable s | Assert.cs:52:29:52:32 | null | semmle.label | successor | +| Assert.cs:52:24:52:32 | ... == ... | Assert.cs:52:9:52:33 | [assertion failure] call to method IsFalse | semmle.label | true | +| Assert.cs:52:24:52:32 | ... == ... | Assert.cs:52:9:52:33 | [assertion success] call to method IsFalse | semmle.label | false | +| Assert.cs:52:29:52:32 | null | Assert.cs:52:24:52:32 | ... == ... | semmle.label | successor | +| Assert.cs:53:9:53:35 | call to method WriteLine | Assert.cs:49:10:49:11 | exit M7 | semmle.label | successor | +| Assert.cs:53:9:53:36 | ...; | Assert.cs:53:27:53:27 | access to local variable s | semmle.label | successor | +| Assert.cs:53:27:53:27 | access to local variable s | Assert.cs:53:27:53:34 | access to property Length | semmle.label | successor | +| Assert.cs:53:27:53:34 | access to property Length | Assert.cs:53:9:53:35 | call to method WriteLine | semmle.label | successor | +| Assert.cs:56:10:56:11 | enter M8 | Assert.cs:57:5:61:5 | {...} | semmle.label | successor | +| Assert.cs:57:5:61:5 | {...} | Assert.cs:58:9:58:33 | ... ...; | semmle.label | successor | +| Assert.cs:58:9:58:33 | ... ...; | Assert.cs:58:20:58:32 | ... ? ... : ... | semmle.label | successor | +| Assert.cs:58:16:58:32 | [b (line 56): false] String s = ... | Assert.cs:59:9:59:38 | [b (line 56): false] ...; | semmle.label | successor | +| Assert.cs:58:16:58:32 | [b (line 56): true] String s = ... | Assert.cs:59:9:59:38 | [b (line 56): true] ...; | semmle.label | successor | +| Assert.cs:58:20:58:20 | access to parameter b | Assert.cs:58:24:58:27 | [b (line 56): true] null | semmle.label | true | +| Assert.cs:58:20:58:20 | access to parameter b | Assert.cs:58:31:58:32 | [b (line 56): false] "" | semmle.label | false | +| Assert.cs:58:20:58:32 | ... ? ... : ... | Assert.cs:58:20:58:20 | access to parameter b | semmle.label | successor | +| Assert.cs:58:24:58:27 | [b (line 56): true] null | Assert.cs:58:16:58:32 | [b (line 56): true] String s = ... | semmle.label | successor | +| Assert.cs:58:31:58:32 | [b (line 56): false] "" | Assert.cs:58:16:58:32 | [b (line 56): false] String s = ... | semmle.label | successor | +| Assert.cs:59:9:59:37 | [assertion failure] call to method IsTrue | Assert.cs:56:10:56:11 | exit M8 | semmle.label | exception(AssertFailedException) | +| Assert.cs:59:9:59:37 | [assertion success] call to method IsTrue | Assert.cs:60:9:60:36 | ...; | semmle.label | successor | +| Assert.cs:59:9:59:38 | [b (line 56): false] ...; | Assert.cs:59:23:59:36 | [b (line 56): false] ... && ... | semmle.label | successor | +| Assert.cs:59:9:59:38 | [b (line 56): true] ...; | Assert.cs:59:23:59:36 | [b (line 56): true] ... && ... | semmle.label | successor | +| Assert.cs:59:23:59:23 | [b (line 56): false] access to local variable s | Assert.cs:59:28:59:31 | [b (line 56): false] null | semmle.label | successor | +| Assert.cs:59:23:59:23 | [b (line 56): true] access to local variable s | Assert.cs:59:28:59:31 | [b (line 56): true] null | semmle.label | successor | +| Assert.cs:59:23:59:31 | [b (line 56): false] ... != ... | Assert.cs:59:9:59:37 | [assertion failure] call to method IsTrue | semmle.label | false | +| Assert.cs:59:23:59:31 | [b (line 56): false] ... != ... | Assert.cs:59:36:59:36 | [b (line 56): false] access to parameter b | semmle.label | true | +| Assert.cs:59:23:59:31 | [b (line 56): true] ... != ... | Assert.cs:59:9:59:37 | [assertion failure] call to method IsTrue | semmle.label | false | +| Assert.cs:59:23:59:31 | [b (line 56): true] ... != ... | Assert.cs:59:36:59:36 | [b (line 56): true] access to parameter b | semmle.label | true | +| Assert.cs:59:23:59:36 | [b (line 56): false] ... && ... | Assert.cs:59:23:59:23 | [b (line 56): false] access to local variable s | semmle.label | successor | +| Assert.cs:59:23:59:36 | [b (line 56): true] ... && ... | Assert.cs:59:23:59:23 | [b (line 56): true] access to local variable s | semmle.label | successor | +| Assert.cs:59:28:59:31 | [b (line 56): false] null | Assert.cs:59:23:59:31 | [b (line 56): false] ... != ... | semmle.label | successor | +| Assert.cs:59:28:59:31 | [b (line 56): true] null | Assert.cs:59:23:59:31 | [b (line 56): true] ... != ... | semmle.label | successor | +| Assert.cs:59:36:59:36 | [b (line 56): false] access to parameter b | Assert.cs:59:9:59:37 | [assertion failure] call to method IsTrue | semmle.label | false | +| Assert.cs:59:36:59:36 | [b (line 56): true] access to parameter b | Assert.cs:59:9:59:37 | [assertion success] call to method IsTrue | semmle.label | true | +| Assert.cs:60:9:60:35 | call to method WriteLine | Assert.cs:56:10:56:11 | exit M8 | semmle.label | successor | +| Assert.cs:60:9:60:36 | ...; | Assert.cs:60:27:60:27 | access to local variable s | semmle.label | successor | +| Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:60:27:60:34 | access to property Length | semmle.label | successor | +| Assert.cs:60:27:60:34 | access to property Length | Assert.cs:60:9:60:35 | call to method WriteLine | semmle.label | successor | +| Assert.cs:63:10:63:11 | enter M9 | Assert.cs:64:5:68:5 | {...} | semmle.label | successor | +| Assert.cs:64:5:68:5 | {...} | Assert.cs:65:9:65:33 | ... ...; | semmle.label | successor | +| Assert.cs:65:9:65:33 | ... ...; | Assert.cs:65:20:65:32 | ... ? ... : ... | semmle.label | successor | +| Assert.cs:65:16:65:32 | [b (line 63): false] String s = ... | Assert.cs:66:9:66:39 | [b (line 63): false] ...; | semmle.label | successor | +| Assert.cs:65:16:65:32 | [b (line 63): true] String s = ... | Assert.cs:66:9:66:39 | [b (line 63): true] ...; | semmle.label | successor | +| Assert.cs:65:20:65:20 | access to parameter b | Assert.cs:65:24:65:27 | [b (line 63): true] null | semmle.label | true | +| Assert.cs:65:20:65:20 | access to parameter b | Assert.cs:65:31:65:32 | [b (line 63): false] "" | semmle.label | false | +| Assert.cs:65:20:65:32 | ... ? ... : ... | Assert.cs:65:20:65:20 | access to parameter b | semmle.label | successor | +| Assert.cs:65:24:65:27 | [b (line 63): true] null | Assert.cs:65:16:65:32 | [b (line 63): true] String s = ... | semmle.label | successor | +| Assert.cs:65:31:65:32 | [b (line 63): false] "" | Assert.cs:65:16:65:32 | [b (line 63): false] String s = ... | semmle.label | successor | +| Assert.cs:66:9:66:38 | [assertion failure] call to method IsFalse | Assert.cs:63:10:63:11 | exit M9 | semmle.label | exception(AssertFailedException) | +| Assert.cs:66:9:66:38 | [assertion success] call to method IsFalse | Assert.cs:67:9:67:36 | ...; | semmle.label | successor | +| Assert.cs:66:9:66:39 | [b (line 63): false] ...; | Assert.cs:66:24:66:37 | [b (line 63): false] ... \|\| ... | semmle.label | successor | +| Assert.cs:66:9:66:39 | [b (line 63): true] ...; | Assert.cs:66:24:66:37 | [b (line 63): true] ... \|\| ... | semmle.label | successor | +| Assert.cs:66:24:66:24 | [b (line 63): false] access to local variable s | Assert.cs:66:29:66:32 | [b (line 63): false] null | semmle.label | successor | +| Assert.cs:66:24:66:24 | [b (line 63): true] access to local variable s | Assert.cs:66:29:66:32 | [b (line 63): true] null | semmle.label | successor | +| Assert.cs:66:24:66:32 | [b (line 63): false] ... == ... | Assert.cs:66:9:66:38 | [assertion failure] call to method IsFalse | semmle.label | true | +| Assert.cs:66:24:66:32 | [b (line 63): false] ... == ... | Assert.cs:66:37:66:37 | [b (line 63): false] access to parameter b | semmle.label | false | +| Assert.cs:66:24:66:32 | [b (line 63): true] ... == ... | Assert.cs:66:9:66:38 | [assertion failure] call to method IsFalse | semmle.label | true | +| Assert.cs:66:24:66:32 | [b (line 63): true] ... == ... | Assert.cs:66:37:66:37 | [b (line 63): true] access to parameter b | semmle.label | false | +| Assert.cs:66:24:66:37 | [b (line 63): false] ... \|\| ... | Assert.cs:66:24:66:24 | [b (line 63): false] access to local variable s | semmle.label | successor | +| Assert.cs:66:24:66:37 | [b (line 63): true] ... \|\| ... | Assert.cs:66:24:66:24 | [b (line 63): true] access to local variable s | semmle.label | successor | +| Assert.cs:66:29:66:32 | [b (line 63): false] null | Assert.cs:66:24:66:32 | [b (line 63): false] ... == ... | semmle.label | successor | +| Assert.cs:66:29:66:32 | [b (line 63): true] null | Assert.cs:66:24:66:32 | [b (line 63): true] ... == ... | semmle.label | successor | +| Assert.cs:66:37:66:37 | [b (line 63): false] access to parameter b | Assert.cs:66:9:66:38 | [assertion success] call to method IsFalse | semmle.label | false | +| Assert.cs:66:37:66:37 | [b (line 63): true] access to parameter b | Assert.cs:66:9:66:38 | [assertion failure] call to method IsFalse | semmle.label | true | +| Assert.cs:67:9:67:35 | call to method WriteLine | Assert.cs:63:10:63:11 | exit M9 | semmle.label | successor | +| Assert.cs:67:9:67:36 | ...; | Assert.cs:67:27:67:27 | access to local variable s | semmle.label | successor | +| Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:67:27:67:34 | access to property Length | semmle.label | successor | +| Assert.cs:67:27:67:34 | access to property Length | Assert.cs:67:9:67:35 | call to method WriteLine | semmle.label | successor | +| Assert.cs:70:10:70:12 | enter M10 | Assert.cs:71:5:75:5 | {...} | semmle.label | successor | +| Assert.cs:71:5:75:5 | {...} | Assert.cs:72:9:72:33 | ... ...; | semmle.label | successor | +| Assert.cs:72:9:72:33 | ... ...; | Assert.cs:72:20:72:32 | ... ? ... : ... | semmle.label | successor | +| Assert.cs:72:16:72:32 | [b (line 70): false] String s = ... | Assert.cs:73:9:73:38 | [b (line 70): false] ...; | semmle.label | successor | +| Assert.cs:72:16:72:32 | [b (line 70): true] String s = ... | Assert.cs:73:9:73:38 | [b (line 70): true] ...; | semmle.label | successor | +| Assert.cs:72:20:72:20 | access to parameter b | Assert.cs:72:24:72:27 | [b (line 70): true] null | semmle.label | true | +| Assert.cs:72:20:72:20 | access to parameter b | Assert.cs:72:31:72:32 | [b (line 70): false] "" | semmle.label | false | +| Assert.cs:72:20:72:32 | ... ? ... : ... | Assert.cs:72:20:72:20 | access to parameter b | semmle.label | successor | +| Assert.cs:72:24:72:27 | [b (line 70): true] null | Assert.cs:72:16:72:32 | [b (line 70): true] String s = ... | semmle.label | successor | +| Assert.cs:72:31:72:32 | [b (line 70): false] "" | Assert.cs:72:16:72:32 | [b (line 70): false] String s = ... | semmle.label | successor | +| Assert.cs:73:9:73:37 | [assertion failure] call to method IsTrue | Assert.cs:70:10:70:12 | exit M10 | semmle.label | exception(AssertFailedException) | +| Assert.cs:73:9:73:37 | [assertion success] call to method IsTrue | Assert.cs:74:9:74:36 | ...; | semmle.label | successor | +| Assert.cs:73:9:73:38 | [b (line 70): false] ...; | Assert.cs:73:23:73:36 | [b (line 70): false] ... && ... | semmle.label | successor | +| Assert.cs:73:9:73:38 | [b (line 70): true] ...; | Assert.cs:73:23:73:36 | [b (line 70): true] ... && ... | semmle.label | successor | +| Assert.cs:73:23:73:23 | [b (line 70): false] access to local variable s | Assert.cs:73:28:73:31 | [b (line 70): false] null | semmle.label | successor | +| Assert.cs:73:23:73:23 | [b (line 70): true] access to local variable s | Assert.cs:73:28:73:31 | [b (line 70): true] null | semmle.label | successor | +| Assert.cs:73:23:73:31 | [b (line 70): false] ... == ... | Assert.cs:73:9:73:37 | [assertion failure] call to method IsTrue | semmle.label | false | +| Assert.cs:73:23:73:31 | [b (line 70): false] ... == ... | Assert.cs:73:36:73:36 | [b (line 70): false] access to parameter b | semmle.label | true | +| Assert.cs:73:23:73:31 | [b (line 70): true] ... == ... | Assert.cs:73:9:73:37 | [assertion failure] call to method IsTrue | semmle.label | false | +| Assert.cs:73:23:73:31 | [b (line 70): true] ... == ... | Assert.cs:73:36:73:36 | [b (line 70): true] access to parameter b | semmle.label | true | +| Assert.cs:73:23:73:36 | [b (line 70): false] ... && ... | Assert.cs:73:23:73:23 | [b (line 70): false] access to local variable s | semmle.label | successor | +| Assert.cs:73:23:73:36 | [b (line 70): true] ... && ... | Assert.cs:73:23:73:23 | [b (line 70): true] access to local variable s | semmle.label | successor | +| Assert.cs:73:28:73:31 | [b (line 70): false] null | Assert.cs:73:23:73:31 | [b (line 70): false] ... == ... | semmle.label | successor | +| Assert.cs:73:28:73:31 | [b (line 70): true] null | Assert.cs:73:23:73:31 | [b (line 70): true] ... == ... | semmle.label | successor | +| Assert.cs:73:36:73:36 | [b (line 70): false] access to parameter b | Assert.cs:73:9:73:37 | [assertion failure] call to method IsTrue | semmle.label | false | +| Assert.cs:73:36:73:36 | [b (line 70): true] access to parameter b | Assert.cs:73:9:73:37 | [assertion success] call to method IsTrue | semmle.label | true | +| Assert.cs:74:9:74:35 | call to method WriteLine | Assert.cs:70:10:70:12 | exit M10 | semmle.label | successor | +| Assert.cs:74:9:74:36 | ...; | Assert.cs:74:27:74:27 | access to local variable s | semmle.label | successor | +| Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:74:27:74:34 | access to property Length | semmle.label | successor | +| Assert.cs:74:27:74:34 | access to property Length | Assert.cs:74:9:74:35 | call to method WriteLine | semmle.label | successor | +| Assert.cs:77:10:77:12 | enter M11 | Assert.cs:78:5:82:5 | {...} | semmle.label | successor | +| Assert.cs:78:5:82:5 | {...} | Assert.cs:79:9:79:33 | ... ...; | semmle.label | successor | +| Assert.cs:79:9:79:33 | ... ...; | Assert.cs:79:20:79:32 | ... ? ... : ... | semmle.label | successor | +| Assert.cs:79:16:79:32 | [b (line 77): false] String s = ... | Assert.cs:80:9:80:39 | [b (line 77): false] ...; | semmle.label | successor | +| Assert.cs:79:16:79:32 | [b (line 77): true] String s = ... | Assert.cs:80:9:80:39 | [b (line 77): true] ...; | semmle.label | successor | +| Assert.cs:79:20:79:20 | access to parameter b | Assert.cs:79:24:79:27 | [b (line 77): true] null | semmle.label | true | +| Assert.cs:79:20:79:20 | access to parameter b | Assert.cs:79:31:79:32 | [b (line 77): false] "" | semmle.label | false | +| Assert.cs:79:20:79:32 | ... ? ... : ... | Assert.cs:79:20:79:20 | access to parameter b | semmle.label | successor | +| Assert.cs:79:24:79:27 | [b (line 77): true] null | Assert.cs:79:16:79:32 | [b (line 77): true] String s = ... | semmle.label | successor | +| Assert.cs:79:31:79:32 | [b (line 77): false] "" | Assert.cs:79:16:79:32 | [b (line 77): false] String s = ... | semmle.label | successor | +| Assert.cs:80:9:80:38 | [assertion failure] call to method IsFalse | Assert.cs:77:10:77:12 | exit M11 | semmle.label | exception(AssertFailedException) | +| Assert.cs:80:9:80:38 | [assertion success] call to method IsFalse | Assert.cs:81:9:81:36 | ...; | semmle.label | successor | +| Assert.cs:80:9:80:39 | [b (line 77): false] ...; | Assert.cs:80:24:80:37 | [b (line 77): false] ... \|\| ... | semmle.label | successor | +| Assert.cs:80:9:80:39 | [b (line 77): true] ...; | Assert.cs:80:24:80:37 | [b (line 77): true] ... \|\| ... | semmle.label | successor | +| Assert.cs:80:24:80:24 | [b (line 77): false] access to local variable s | Assert.cs:80:29:80:32 | [b (line 77): false] null | semmle.label | successor | +| Assert.cs:80:24:80:24 | [b (line 77): true] access to local variable s | Assert.cs:80:29:80:32 | [b (line 77): true] null | semmle.label | successor | +| Assert.cs:80:24:80:32 | [b (line 77): false] ... != ... | Assert.cs:80:9:80:38 | [assertion failure] call to method IsFalse | semmle.label | true | +| Assert.cs:80:24:80:32 | [b (line 77): false] ... != ... | Assert.cs:80:37:80:37 | [b (line 77): false] access to parameter b | semmle.label | false | +| Assert.cs:80:24:80:32 | [b (line 77): true] ... != ... | Assert.cs:80:9:80:38 | [assertion failure] call to method IsFalse | semmle.label | true | +| Assert.cs:80:24:80:32 | [b (line 77): true] ... != ... | Assert.cs:80:37:80:37 | [b (line 77): true] access to parameter b | semmle.label | false | +| Assert.cs:80:24:80:37 | [b (line 77): false] ... \|\| ... | Assert.cs:80:24:80:24 | [b (line 77): false] access to local variable s | semmle.label | successor | +| Assert.cs:80:24:80:37 | [b (line 77): true] ... \|\| ... | Assert.cs:80:24:80:24 | [b (line 77): true] access to local variable s | semmle.label | successor | +| Assert.cs:80:29:80:32 | [b (line 77): false] null | Assert.cs:80:24:80:32 | [b (line 77): false] ... != ... | semmle.label | successor | +| Assert.cs:80:29:80:32 | [b (line 77): true] null | Assert.cs:80:24:80:32 | [b (line 77): true] ... != ... | semmle.label | successor | +| Assert.cs:80:37:80:37 | [b (line 77): false] access to parameter b | Assert.cs:80:9:80:38 | [assertion success] call to method IsFalse | semmle.label | false | +| Assert.cs:80:37:80:37 | [b (line 77): true] access to parameter b | Assert.cs:80:9:80:38 | [assertion failure] call to method IsFalse | semmle.label | true | +| Assert.cs:81:9:81:35 | call to method WriteLine | Assert.cs:77:10:77:12 | exit M11 | semmle.label | successor | +| Assert.cs:81:9:81:36 | ...; | Assert.cs:81:27:81:27 | access to local variable s | semmle.label | successor | +| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:81:27:81:34 | access to property Length | semmle.label | successor | +| Assert.cs:81:27:81:34 | access to property Length | Assert.cs:81:9:81:35 | call to method WriteLine | semmle.label | successor | +| Assert.cs:84:10:84:12 | enter M12 | Assert.cs:85:5:129:5 | {...} | semmle.label | successor | +| Assert.cs:85:5:129:5 | {...} | Assert.cs:86:9:86:33 | ... ...; | semmle.label | successor | +| Assert.cs:86:9:86:33 | ... ...; | Assert.cs:86:20:86:32 | ... ? ... : ... | semmle.label | successor | +| Assert.cs:86:16:86:32 | [b (line 84): false] String s = ... | Assert.cs:87:9:87:32 | [b (line 84): false] ...; | semmle.label | successor | +| Assert.cs:86:16:86:32 | [b (line 84): true] String s = ... | Assert.cs:87:9:87:32 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:86:20:86:20 | access to parameter b | Assert.cs:86:24:86:27 | [b (line 84): true] null | semmle.label | true | +| Assert.cs:86:20:86:20 | access to parameter b | Assert.cs:86:31:86:32 | [b (line 84): false] "" | semmle.label | false | +| Assert.cs:86:20:86:32 | ... ? ... : ... | Assert.cs:86:20:86:20 | access to parameter b | semmle.label | successor | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | Assert.cs:86:16:86:32 | [b (line 84): true] String s = ... | semmle.label | successor | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | Assert.cs:86:16:86:32 | [b (line 84): false] String s = ... | semmle.label | successor | +| Assert.cs:87:9:87:31 | [assertion failure, b (line 84): false] call to method Assert | Assert.cs:84:10:84:12 | exit M12 | semmle.label | exit | +| Assert.cs:87:9:87:31 | [assertion failure, b (line 84): true] call to method Assert | Assert.cs:84:10:84:12 | exit M12 | semmle.label | exit | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | Assert.cs:88:9:88:36 | [b (line 84): false] ...; | semmle.label | successor | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | Assert.cs:88:9:88:36 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:87:9:87:32 | [b (line 84): false] ...; | Assert.cs:87:22:87:22 | [b (line 84): false] access to local variable s | semmle.label | successor | +| Assert.cs:87:9:87:32 | [b (line 84): true] ...; | Assert.cs:87:22:87:22 | [b (line 84): true] access to local variable s | semmle.label | successor | +| Assert.cs:87:22:87:22 | [b (line 84): false] access to local variable s | Assert.cs:87:27:87:30 | [b (line 84): false] null | semmle.label | successor | +| Assert.cs:87:22:87:22 | [b (line 84): true] access to local variable s | Assert.cs:87:27:87:30 | [b (line 84): true] null | semmle.label | successor | +| Assert.cs:87:22:87:30 | [b (line 84): false] ... != ... | Assert.cs:87:9:87:31 | [assertion failure, b (line 84): false] call to method Assert | semmle.label | false | +| Assert.cs:87:22:87:30 | [b (line 84): false] ... != ... | Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | semmle.label | true | +| Assert.cs:87:22:87:30 | [b (line 84): true] ... != ... | Assert.cs:87:9:87:31 | [assertion failure, b (line 84): true] call to method Assert | semmle.label | false | +| Assert.cs:87:22:87:30 | [b (line 84): true] ... != ... | Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | semmle.label | true | +| Assert.cs:87:27:87:30 | [b (line 84): false] null | Assert.cs:87:22:87:30 | [b (line 84): false] ... != ... | semmle.label | successor | +| Assert.cs:87:27:87:30 | [b (line 84): true] null | Assert.cs:87:22:87:30 | [b (line 84): true] ... != ... | semmle.label | successor | +| Assert.cs:88:9:88:35 | [b (line 84): false] call to method WriteLine | Assert.cs:90:9:90:26 | [b (line 84): false] ...; | semmle.label | successor | +| Assert.cs:88:9:88:35 | [b (line 84): true] call to method WriteLine | Assert.cs:90:9:90:26 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:88:9:88:36 | [b (line 84): false] ...; | Assert.cs:88:27:88:27 | [b (line 84): false] access to local variable s | semmle.label | successor | +| Assert.cs:88:9:88:36 | [b (line 84): true] ...; | Assert.cs:88:27:88:27 | [b (line 84): true] access to local variable s | semmle.label | successor | +| Assert.cs:88:27:88:27 | [b (line 84): false] access to local variable s | Assert.cs:88:27:88:34 | [b (line 84): false] access to property Length | semmle.label | successor | +| Assert.cs:88:27:88:27 | [b (line 84): true] access to local variable s | Assert.cs:88:27:88:34 | [b (line 84): true] access to property Length | semmle.label | successor | +| Assert.cs:88:27:88:34 | [b (line 84): false] access to property Length | Assert.cs:88:9:88:35 | [b (line 84): false] call to method WriteLine | semmle.label | successor | +| Assert.cs:88:27:88:34 | [b (line 84): true] access to property Length | Assert.cs:88:9:88:35 | [b (line 84): true] call to method WriteLine | semmle.label | successor | +| Assert.cs:90:9:90:25 | [b (line 84): false] ... = ... | Assert.cs:91:9:91:25 | [b (line 84): false] ...; | semmle.label | successor | +| Assert.cs:90:9:90:25 | [b (line 84): true] ... = ... | Assert.cs:91:9:91:25 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:90:9:90:26 | [b (line 84): false] ...; | Assert.cs:90:13:90:25 | [b (line 84): false] ... ? ... : ... | semmle.label | successor | +| Assert.cs:90:9:90:26 | [b (line 84): true] ...; | Assert.cs:90:13:90:25 | [b (line 84): true] ... ? ... : ... | semmle.label | successor | +| Assert.cs:90:13:90:13 | [b (line 84): false] access to parameter b | Assert.cs:90:24:90:25 | [b (line 84): false] "" | semmle.label | false | +| Assert.cs:90:13:90:13 | [b (line 84): true] access to parameter b | Assert.cs:90:17:90:20 | [b (line 84): true] null | semmle.label | true | +| Assert.cs:90:13:90:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:90:13:90:13 | [b (line 84): false] access to parameter b | semmle.label | successor | +| Assert.cs:90:13:90:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:90:13:90:13 | [b (line 84): true] access to parameter b | semmle.label | successor | +| Assert.cs:90:17:90:20 | [b (line 84): true] null | Assert.cs:90:9:90:25 | [b (line 84): true] ... = ... | semmle.label | successor | +| Assert.cs:90:24:90:25 | [b (line 84): false] "" | Assert.cs:90:9:90:25 | [b (line 84): false] ... = ... | semmle.label | successor | +| Assert.cs:91:9:91:24 | [assertion failure, b (line 84): false] call to method IsNull | Assert.cs:84:10:84:12 | exit M12 | semmle.label | exception(AssertFailedException) | +| Assert.cs:91:9:91:24 | [assertion failure, b (line 84): true] call to method IsNull | Assert.cs:84:10:84:12 | exit M12 | semmle.label | exception(AssertFailedException) | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | Assert.cs:92:9:92:36 | [b (line 84): false] ...; | semmle.label | successor | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | Assert.cs:92:9:92:36 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:91:9:91:25 | [b (line 84): false] ...; | Assert.cs:91:23:91:23 | [b (line 84): false] access to local variable s | semmle.label | successor | +| Assert.cs:91:9:91:25 | [b (line 84): true] ...; | Assert.cs:91:23:91:23 | [b (line 84): true] access to local variable s | semmle.label | successor | +| Assert.cs:91:23:91:23 | [b (line 84): false] access to local variable s | Assert.cs:91:9:91:24 | [assertion failure, b (line 84): false] call to method IsNull | semmle.label | non-null | +| Assert.cs:91:23:91:23 | [b (line 84): false] access to local variable s | Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | semmle.label | null | +| Assert.cs:91:23:91:23 | [b (line 84): true] access to local variable s | Assert.cs:91:9:91:24 | [assertion failure, b (line 84): true] call to method IsNull | semmle.label | non-null | +| Assert.cs:91:23:91:23 | [b (line 84): true] access to local variable s | Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | semmle.label | null | +| Assert.cs:92:9:92:35 | [b (line 84): false] call to method WriteLine | Assert.cs:94:9:94:26 | [b (line 84): false] ...; | semmle.label | successor | +| Assert.cs:92:9:92:35 | [b (line 84): true] call to method WriteLine | Assert.cs:94:9:94:26 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:92:9:92:36 | [b (line 84): false] ...; | Assert.cs:92:27:92:27 | [b (line 84): false] access to local variable s | semmle.label | successor | +| Assert.cs:92:9:92:36 | [b (line 84): true] ...; | Assert.cs:92:27:92:27 | [b (line 84): true] access to local variable s | semmle.label | successor | +| Assert.cs:92:27:92:27 | [b (line 84): false] access to local variable s | Assert.cs:92:27:92:34 | [b (line 84): false] access to property Length | semmle.label | successor | +| Assert.cs:92:27:92:27 | [b (line 84): true] access to local variable s | Assert.cs:92:27:92:34 | [b (line 84): true] access to property Length | semmle.label | successor | +| Assert.cs:92:27:92:34 | [b (line 84): false] access to property Length | Assert.cs:92:9:92:35 | [b (line 84): false] call to method WriteLine | semmle.label | successor | +| Assert.cs:92:27:92:34 | [b (line 84): true] access to property Length | Assert.cs:92:9:92:35 | [b (line 84): true] call to method WriteLine | semmle.label | successor | +| Assert.cs:94:9:94:25 | [b (line 84): false] ... = ... | Assert.cs:95:9:95:28 | [b (line 84): false] ...; | semmle.label | successor | +| Assert.cs:94:9:94:25 | [b (line 84): true] ... = ... | Assert.cs:95:9:95:28 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:94:9:94:26 | [b (line 84): false] ...; | Assert.cs:94:13:94:25 | [b (line 84): false] ... ? ... : ... | semmle.label | successor | +| Assert.cs:94:9:94:26 | [b (line 84): true] ...; | Assert.cs:94:13:94:25 | [b (line 84): true] ... ? ... : ... | semmle.label | successor | +| Assert.cs:94:13:94:13 | [b (line 84): false] access to parameter b | Assert.cs:94:24:94:25 | [b (line 84): false] "" | semmle.label | false | +| Assert.cs:94:13:94:13 | [b (line 84): true] access to parameter b | Assert.cs:94:17:94:20 | [b (line 84): true] null | semmle.label | true | +| Assert.cs:94:13:94:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:94:13:94:13 | [b (line 84): false] access to parameter b | semmle.label | successor | +| Assert.cs:94:13:94:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:94:13:94:13 | [b (line 84): true] access to parameter b | semmle.label | successor | +| Assert.cs:94:17:94:20 | [b (line 84): true] null | Assert.cs:94:9:94:25 | [b (line 84): true] ... = ... | semmle.label | successor | +| Assert.cs:94:24:94:25 | [b (line 84): false] "" | Assert.cs:94:9:94:25 | [b (line 84): false] ... = ... | semmle.label | successor | +| Assert.cs:95:9:95:27 | [assertion failure, b (line 84): false] call to method IsNotNull | Assert.cs:84:10:84:12 | exit M12 | semmle.label | exception(AssertFailedException) | +| Assert.cs:95:9:95:27 | [assertion failure, b (line 84): true] call to method IsNotNull | Assert.cs:84:10:84:12 | exit M12 | semmle.label | exception(AssertFailedException) | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | Assert.cs:96:9:96:36 | [b (line 84): false] ...; | semmle.label | successor | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | Assert.cs:96:9:96:36 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:95:9:95:28 | [b (line 84): false] ...; | Assert.cs:95:26:95:26 | [b (line 84): false] access to local variable s | semmle.label | successor | +| Assert.cs:95:9:95:28 | [b (line 84): true] ...; | Assert.cs:95:26:95:26 | [b (line 84): true] access to local variable s | semmle.label | successor | +| Assert.cs:95:26:95:26 | [b (line 84): false] access to local variable s | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): false] call to method IsNotNull | semmle.label | null | +| Assert.cs:95:26:95:26 | [b (line 84): false] access to local variable s | Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | semmle.label | non-null | +| Assert.cs:95:26:95:26 | [b (line 84): true] access to local variable s | Assert.cs:95:9:95:27 | [assertion failure, b (line 84): true] call to method IsNotNull | semmle.label | null | +| Assert.cs:95:26:95:26 | [b (line 84): true] access to local variable s | Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | semmle.label | non-null | +| Assert.cs:96:9:96:35 | [b (line 84): false] call to method WriteLine | Assert.cs:98:9:98:26 | [b (line 84): false] ...; | semmle.label | successor | +| Assert.cs:96:9:96:35 | [b (line 84): true] call to method WriteLine | Assert.cs:98:9:98:26 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:96:9:96:36 | [b (line 84): false] ...; | Assert.cs:96:27:96:27 | [b (line 84): false] access to local variable s | semmle.label | successor | +| Assert.cs:96:9:96:36 | [b (line 84): true] ...; | Assert.cs:96:27:96:27 | [b (line 84): true] access to local variable s | semmle.label | successor | +| Assert.cs:96:27:96:27 | [b (line 84): false] access to local variable s | Assert.cs:96:27:96:34 | [b (line 84): false] access to property Length | semmle.label | successor | +| Assert.cs:96:27:96:27 | [b (line 84): true] access to local variable s | Assert.cs:96:27:96:34 | [b (line 84): true] access to property Length | semmle.label | successor | +| Assert.cs:96:27:96:34 | [b (line 84): false] access to property Length | Assert.cs:96:9:96:35 | [b (line 84): false] call to method WriteLine | semmle.label | successor | +| Assert.cs:96:27:96:34 | [b (line 84): true] access to property Length | Assert.cs:96:9:96:35 | [b (line 84): true] call to method WriteLine | semmle.label | successor | +| Assert.cs:98:9:98:25 | [b (line 84): false] ... = ... | Assert.cs:99:9:99:33 | [b (line 84): false] ...; | semmle.label | successor | +| Assert.cs:98:9:98:25 | [b (line 84): true] ... = ... | Assert.cs:99:9:99:33 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:98:9:98:26 | [b (line 84): false] ...; | Assert.cs:98:13:98:25 | [b (line 84): false] ... ? ... : ... | semmle.label | successor | +| Assert.cs:98:9:98:26 | [b (line 84): true] ...; | Assert.cs:98:13:98:25 | [b (line 84): true] ... ? ... : ... | semmle.label | successor | +| Assert.cs:98:13:98:13 | [b (line 84): false] access to parameter b | Assert.cs:98:24:98:25 | [b (line 84): false] "" | semmle.label | false | +| Assert.cs:98:13:98:13 | [b (line 84): true] access to parameter b | Assert.cs:98:17:98:20 | [b (line 84): true] null | semmle.label | true | +| Assert.cs:98:13:98:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:98:13:98:13 | [b (line 84): false] access to parameter b | semmle.label | successor | +| Assert.cs:98:13:98:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:98:13:98:13 | [b (line 84): true] access to parameter b | semmle.label | successor | +| Assert.cs:98:17:98:20 | [b (line 84): true] null | Assert.cs:98:9:98:25 | [b (line 84): true] ... = ... | semmle.label | successor | +| Assert.cs:98:24:98:25 | [b (line 84): false] "" | Assert.cs:98:9:98:25 | [b (line 84): false] ... = ... | semmle.label | successor | +| Assert.cs:99:9:99:32 | [assertion failure, b (line 84): false] call to method IsTrue | Assert.cs:84:10:84:12 | exit M12 | semmle.label | exception(AssertFailedException) | +| Assert.cs:99:9:99:32 | [assertion failure, b (line 84): true] call to method IsTrue | Assert.cs:84:10:84:12 | exit M12 | semmle.label | exception(AssertFailedException) | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:100:9:100:36 | [b (line 84): false] ...; | semmle.label | successor | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:100:9:100:36 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:99:9:99:33 | [b (line 84): false] ...; | Assert.cs:99:23:99:23 | [b (line 84): false] access to local variable s | semmle.label | successor | +| Assert.cs:99:9:99:33 | [b (line 84): true] ...; | Assert.cs:99:23:99:23 | [b (line 84): true] access to local variable s | semmle.label | successor | +| Assert.cs:99:23:99:23 | [b (line 84): false] access to local variable s | Assert.cs:99:28:99:31 | [b (line 84): false] null | semmle.label | successor | +| Assert.cs:99:23:99:23 | [b (line 84): true] access to local variable s | Assert.cs:99:28:99:31 | [b (line 84): true] null | semmle.label | successor | +| Assert.cs:99:23:99:31 | [b (line 84): false] ... == ... | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): false] call to method IsTrue | semmle.label | false | +| Assert.cs:99:23:99:31 | [b (line 84): false] ... == ... | Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | semmle.label | true | +| Assert.cs:99:23:99:31 | [b (line 84): true] ... == ... | Assert.cs:99:9:99:32 | [assertion failure, b (line 84): true] call to method IsTrue | semmle.label | false | +| Assert.cs:99:23:99:31 | [b (line 84): true] ... == ... | Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | semmle.label | true | +| Assert.cs:99:28:99:31 | [b (line 84): false] null | Assert.cs:99:23:99:31 | [b (line 84): false] ... == ... | semmle.label | successor | +| Assert.cs:99:28:99:31 | [b (line 84): true] null | Assert.cs:99:23:99:31 | [b (line 84): true] ... == ... | semmle.label | successor | +| Assert.cs:100:9:100:35 | [b (line 84): false] call to method WriteLine | Assert.cs:102:9:102:26 | [b (line 84): false] ...; | semmle.label | successor | +| Assert.cs:100:9:100:35 | [b (line 84): true] call to method WriteLine | Assert.cs:102:9:102:26 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:100:9:100:36 | [b (line 84): false] ...; | Assert.cs:100:27:100:27 | [b (line 84): false] access to local variable s | semmle.label | successor | +| Assert.cs:100:9:100:36 | [b (line 84): true] ...; | Assert.cs:100:27:100:27 | [b (line 84): true] access to local variable s | semmle.label | successor | +| Assert.cs:100:27:100:27 | [b (line 84): false] access to local variable s | Assert.cs:100:27:100:34 | [b (line 84): false] access to property Length | semmle.label | successor | +| Assert.cs:100:27:100:27 | [b (line 84): true] access to local variable s | Assert.cs:100:27:100:34 | [b (line 84): true] access to property Length | semmle.label | successor | +| Assert.cs:100:27:100:34 | [b (line 84): false] access to property Length | Assert.cs:100:9:100:35 | [b (line 84): false] call to method WriteLine | semmle.label | successor | +| Assert.cs:100:27:100:34 | [b (line 84): true] access to property Length | Assert.cs:100:9:100:35 | [b (line 84): true] call to method WriteLine | semmle.label | successor | +| Assert.cs:102:9:102:25 | [b (line 84): false] ... = ... | Assert.cs:103:9:103:33 | [b (line 84): false] ...; | semmle.label | successor | +| Assert.cs:102:9:102:25 | [b (line 84): true] ... = ... | Assert.cs:103:9:103:33 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:102:9:102:26 | [b (line 84): false] ...; | Assert.cs:102:13:102:25 | [b (line 84): false] ... ? ... : ... | semmle.label | successor | +| Assert.cs:102:9:102:26 | [b (line 84): true] ...; | Assert.cs:102:13:102:25 | [b (line 84): true] ... ? ... : ... | semmle.label | successor | +| Assert.cs:102:13:102:13 | [b (line 84): false] access to parameter b | Assert.cs:102:24:102:25 | [b (line 84): false] "" | semmle.label | false | +| Assert.cs:102:13:102:13 | [b (line 84): true] access to parameter b | Assert.cs:102:17:102:20 | [b (line 84): true] null | semmle.label | true | +| Assert.cs:102:13:102:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:102:13:102:13 | [b (line 84): false] access to parameter b | semmle.label | successor | +| Assert.cs:102:13:102:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:102:13:102:13 | [b (line 84): true] access to parameter b | semmle.label | successor | +| Assert.cs:102:17:102:20 | [b (line 84): true] null | Assert.cs:102:9:102:25 | [b (line 84): true] ... = ... | semmle.label | successor | +| Assert.cs:102:24:102:25 | [b (line 84): false] "" | Assert.cs:102:9:102:25 | [b (line 84): false] ... = ... | semmle.label | successor | +| Assert.cs:103:9:103:32 | [assertion failure, b (line 84): false] call to method IsTrue | Assert.cs:84:10:84:12 | exit M12 | semmle.label | exception(AssertFailedException) | +| Assert.cs:103:9:103:32 | [assertion failure, b (line 84): true] call to method IsTrue | Assert.cs:84:10:84:12 | exit M12 | semmle.label | exception(AssertFailedException) | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | Assert.cs:104:9:104:36 | [b (line 84): false] ...; | semmle.label | successor | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:104:9:104:36 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:103:9:103:33 | [b (line 84): false] ...; | Assert.cs:103:23:103:23 | [b (line 84): false] access to local variable s | semmle.label | successor | +| Assert.cs:103:9:103:33 | [b (line 84): true] ...; | Assert.cs:103:23:103:23 | [b (line 84): true] access to local variable s | semmle.label | successor | +| Assert.cs:103:23:103:23 | [b (line 84): false] access to local variable s | Assert.cs:103:28:103:31 | [b (line 84): false] null | semmle.label | successor | +| Assert.cs:103:23:103:23 | [b (line 84): true] access to local variable s | Assert.cs:103:28:103:31 | [b (line 84): true] null | semmle.label | successor | +| Assert.cs:103:23:103:31 | [b (line 84): false] ... != ... | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): false] call to method IsTrue | semmle.label | false | +| Assert.cs:103:23:103:31 | [b (line 84): false] ... != ... | Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | semmle.label | true | +| Assert.cs:103:23:103:31 | [b (line 84): true] ... != ... | Assert.cs:103:9:103:32 | [assertion failure, b (line 84): true] call to method IsTrue | semmle.label | false | +| Assert.cs:103:23:103:31 | [b (line 84): true] ... != ... | Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | semmle.label | true | +| Assert.cs:103:28:103:31 | [b (line 84): false] null | Assert.cs:103:23:103:31 | [b (line 84): false] ... != ... | semmle.label | successor | +| Assert.cs:103:28:103:31 | [b (line 84): true] null | Assert.cs:103:23:103:31 | [b (line 84): true] ... != ... | semmle.label | successor | +| Assert.cs:104:9:104:35 | [b (line 84): false] call to method WriteLine | Assert.cs:106:9:106:26 | [b (line 84): false] ...; | semmle.label | successor | +| Assert.cs:104:9:104:35 | [b (line 84): true] call to method WriteLine | Assert.cs:106:9:106:26 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:104:9:104:36 | [b (line 84): false] ...; | Assert.cs:104:27:104:27 | [b (line 84): false] access to local variable s | semmle.label | successor | +| Assert.cs:104:9:104:36 | [b (line 84): true] ...; | Assert.cs:104:27:104:27 | [b (line 84): true] access to local variable s | semmle.label | successor | +| Assert.cs:104:27:104:27 | [b (line 84): false] access to local variable s | Assert.cs:104:27:104:34 | [b (line 84): false] access to property Length | semmle.label | successor | +| Assert.cs:104:27:104:27 | [b (line 84): true] access to local variable s | Assert.cs:104:27:104:34 | [b (line 84): true] access to property Length | semmle.label | successor | +| Assert.cs:104:27:104:34 | [b (line 84): false] access to property Length | Assert.cs:104:9:104:35 | [b (line 84): false] call to method WriteLine | semmle.label | successor | +| Assert.cs:104:27:104:34 | [b (line 84): true] access to property Length | Assert.cs:104:9:104:35 | [b (line 84): true] call to method WriteLine | semmle.label | successor | +| Assert.cs:106:9:106:25 | [b (line 84): false] ... = ... | Assert.cs:107:9:107:34 | [b (line 84): false] ...; | semmle.label | successor | +| Assert.cs:106:9:106:25 | [b (line 84): true] ... = ... | Assert.cs:107:9:107:34 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:106:9:106:26 | [b (line 84): false] ...; | Assert.cs:106:13:106:25 | [b (line 84): false] ... ? ... : ... | semmle.label | successor | +| Assert.cs:106:9:106:26 | [b (line 84): true] ...; | Assert.cs:106:13:106:25 | [b (line 84): true] ... ? ... : ... | semmle.label | successor | +| Assert.cs:106:13:106:13 | [b (line 84): false] access to parameter b | Assert.cs:106:24:106:25 | [b (line 84): false] "" | semmle.label | false | +| Assert.cs:106:13:106:13 | [b (line 84): true] access to parameter b | Assert.cs:106:17:106:20 | [b (line 84): true] null | semmle.label | true | +| Assert.cs:106:13:106:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:106:13:106:13 | [b (line 84): false] access to parameter b | semmle.label | successor | +| Assert.cs:106:13:106:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:106:13:106:13 | [b (line 84): true] access to parameter b | semmle.label | successor | +| Assert.cs:106:17:106:20 | [b (line 84): true] null | Assert.cs:106:9:106:25 | [b (line 84): true] ... = ... | semmle.label | successor | +| Assert.cs:106:24:106:25 | [b (line 84): false] "" | Assert.cs:106:9:106:25 | [b (line 84): false] ... = ... | semmle.label | successor | +| Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | Assert.cs:84:10:84:12 | exit M12 | semmle.label | exception(AssertFailedException) | +| Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | Assert.cs:84:10:84:12 | exit M12 | semmle.label | exception(AssertFailedException) | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | Assert.cs:108:9:108:36 | [b (line 84): false] ...; | semmle.label | successor | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:108:9:108:36 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:107:9:107:34 | [b (line 84): false] ...; | Assert.cs:107:24:107:24 | [b (line 84): false] access to local variable s | semmle.label | successor | +| Assert.cs:107:9:107:34 | [b (line 84): true] ...; | Assert.cs:107:24:107:24 | [b (line 84): true] access to local variable s | semmle.label | successor | +| Assert.cs:107:24:107:24 | [b (line 84): false] access to local variable s | Assert.cs:107:29:107:32 | [b (line 84): false] null | semmle.label | successor | +| Assert.cs:107:24:107:24 | [b (line 84): true] access to local variable s | Assert.cs:107:29:107:32 | [b (line 84): true] null | semmle.label | successor | +| Assert.cs:107:24:107:32 | [b (line 84): false] ... != ... | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | semmle.label | true | +| Assert.cs:107:24:107:32 | [b (line 84): false] ... != ... | Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | semmle.label | false | +| Assert.cs:107:24:107:32 | [b (line 84): true] ... != ... | Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | semmle.label | true | +| Assert.cs:107:24:107:32 | [b (line 84): true] ... != ... | Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | semmle.label | false | +| Assert.cs:107:29:107:32 | [b (line 84): false] null | Assert.cs:107:24:107:32 | [b (line 84): false] ... != ... | semmle.label | successor | +| Assert.cs:107:29:107:32 | [b (line 84): true] null | Assert.cs:107:24:107:32 | [b (line 84): true] ... != ... | semmle.label | successor | +| Assert.cs:108:9:108:35 | [b (line 84): false] call to method WriteLine | Assert.cs:110:9:110:26 | [b (line 84): false] ...; | semmle.label | successor | +| Assert.cs:108:9:108:35 | [b (line 84): true] call to method WriteLine | Assert.cs:110:9:110:26 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:108:9:108:36 | [b (line 84): false] ...; | Assert.cs:108:27:108:27 | [b (line 84): false] access to local variable s | semmle.label | successor | +| Assert.cs:108:9:108:36 | [b (line 84): true] ...; | Assert.cs:108:27:108:27 | [b (line 84): true] access to local variable s | semmle.label | successor | +| Assert.cs:108:27:108:27 | [b (line 84): false] access to local variable s | Assert.cs:108:27:108:34 | [b (line 84): false] access to property Length | semmle.label | successor | +| Assert.cs:108:27:108:27 | [b (line 84): true] access to local variable s | Assert.cs:108:27:108:34 | [b (line 84): true] access to property Length | semmle.label | successor | +| Assert.cs:108:27:108:34 | [b (line 84): false] access to property Length | Assert.cs:108:9:108:35 | [b (line 84): false] call to method WriteLine | semmle.label | successor | +| Assert.cs:108:27:108:34 | [b (line 84): true] access to property Length | Assert.cs:108:9:108:35 | [b (line 84): true] call to method WriteLine | semmle.label | successor | +| Assert.cs:110:9:110:25 | [b (line 84): false] ... = ... | Assert.cs:111:9:111:34 | [b (line 84): false] ...; | semmle.label | successor | +| Assert.cs:110:9:110:25 | [b (line 84): true] ... = ... | Assert.cs:111:9:111:34 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:110:9:110:26 | [b (line 84): false] ...; | Assert.cs:110:13:110:25 | [b (line 84): false] ... ? ... : ... | semmle.label | successor | +| Assert.cs:110:9:110:26 | [b (line 84): true] ...; | Assert.cs:110:13:110:25 | [b (line 84): true] ... ? ... : ... | semmle.label | successor | +| Assert.cs:110:13:110:13 | [b (line 84): false] access to parameter b | Assert.cs:110:24:110:25 | [b (line 84): false] "" | semmle.label | false | +| Assert.cs:110:13:110:13 | [b (line 84): true] access to parameter b | Assert.cs:110:17:110:20 | [b (line 84): true] null | semmle.label | true | +| Assert.cs:110:13:110:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:110:13:110:13 | [b (line 84): false] access to parameter b | semmle.label | successor | +| Assert.cs:110:13:110:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:110:13:110:13 | [b (line 84): true] access to parameter b | semmle.label | successor | +| Assert.cs:110:17:110:20 | [b (line 84): true] null | Assert.cs:110:9:110:25 | [b (line 84): true] ... = ... | semmle.label | successor | +| Assert.cs:110:24:110:25 | [b (line 84): false] "" | Assert.cs:110:9:110:25 | [b (line 84): false] ... = ... | semmle.label | successor | +| Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | Assert.cs:84:10:84:12 | exit M12 | semmle.label | exception(AssertFailedException) | +| Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | Assert.cs:84:10:84:12 | exit M12 | semmle.label | exception(AssertFailedException) | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | Assert.cs:112:9:112:36 | [b (line 84): false] ...; | semmle.label | successor | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:112:9:112:36 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:111:9:111:34 | [b (line 84): false] ...; | Assert.cs:111:24:111:24 | [b (line 84): false] access to local variable s | semmle.label | successor | +| Assert.cs:111:9:111:34 | [b (line 84): true] ...; | Assert.cs:111:24:111:24 | [b (line 84): true] access to local variable s | semmle.label | successor | +| Assert.cs:111:24:111:24 | [b (line 84): false] access to local variable s | Assert.cs:111:29:111:32 | [b (line 84): false] null | semmle.label | successor | +| Assert.cs:111:24:111:24 | [b (line 84): true] access to local variable s | Assert.cs:111:29:111:32 | [b (line 84): true] null | semmle.label | successor | +| Assert.cs:111:24:111:32 | [b (line 84): false] ... == ... | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | semmle.label | true | +| Assert.cs:111:24:111:32 | [b (line 84): false] ... == ... | Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | semmle.label | false | +| Assert.cs:111:24:111:32 | [b (line 84): true] ... == ... | Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | semmle.label | true | +| Assert.cs:111:24:111:32 | [b (line 84): true] ... == ... | Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | semmle.label | false | +| Assert.cs:111:29:111:32 | [b (line 84): false] null | Assert.cs:111:24:111:32 | [b (line 84): false] ... == ... | semmle.label | successor | +| Assert.cs:111:29:111:32 | [b (line 84): true] null | Assert.cs:111:24:111:32 | [b (line 84): true] ... == ... | semmle.label | successor | +| Assert.cs:112:9:112:35 | [b (line 84): false] call to method WriteLine | Assert.cs:114:9:114:26 | [b (line 84): false] ...; | semmle.label | successor | +| Assert.cs:112:9:112:35 | [b (line 84): true] call to method WriteLine | Assert.cs:114:9:114:26 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:112:9:112:36 | [b (line 84): false] ...; | Assert.cs:112:27:112:27 | [b (line 84): false] access to local variable s | semmle.label | successor | +| Assert.cs:112:9:112:36 | [b (line 84): true] ...; | Assert.cs:112:27:112:27 | [b (line 84): true] access to local variable s | semmle.label | successor | +| Assert.cs:112:27:112:27 | [b (line 84): false] access to local variable s | Assert.cs:112:27:112:34 | [b (line 84): false] access to property Length | semmle.label | successor | +| Assert.cs:112:27:112:27 | [b (line 84): true] access to local variable s | Assert.cs:112:27:112:34 | [b (line 84): true] access to property Length | semmle.label | successor | +| Assert.cs:112:27:112:34 | [b (line 84): false] access to property Length | Assert.cs:112:9:112:35 | [b (line 84): false] call to method WriteLine | semmle.label | successor | +| Assert.cs:112:27:112:34 | [b (line 84): true] access to property Length | Assert.cs:112:9:112:35 | [b (line 84): true] call to method WriteLine | semmle.label | successor | +| Assert.cs:114:9:114:25 | [b (line 84): false] ... = ... | Assert.cs:115:9:115:38 | [b (line 84): false] ...; | semmle.label | successor | +| Assert.cs:114:9:114:25 | [b (line 84): true] ... = ... | Assert.cs:115:9:115:38 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:114:9:114:26 | [b (line 84): false] ...; | Assert.cs:114:13:114:25 | [b (line 84): false] ... ? ... : ... | semmle.label | successor | +| Assert.cs:114:9:114:26 | [b (line 84): true] ...; | Assert.cs:114:13:114:25 | [b (line 84): true] ... ? ... : ... | semmle.label | successor | +| Assert.cs:114:13:114:13 | [b (line 84): false] access to parameter b | Assert.cs:114:24:114:25 | [b (line 84): false] "" | semmle.label | false | +| Assert.cs:114:13:114:13 | [b (line 84): true] access to parameter b | Assert.cs:114:17:114:20 | [b (line 84): true] null | semmle.label | true | +| Assert.cs:114:13:114:25 | [b (line 84): false] ... ? ... : ... | Assert.cs:114:13:114:13 | [b (line 84): false] access to parameter b | semmle.label | successor | +| Assert.cs:114:13:114:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:114:13:114:13 | [b (line 84): true] access to parameter b | semmle.label | successor | +| Assert.cs:114:17:114:20 | [b (line 84): true] null | Assert.cs:114:9:114:25 | [b (line 84): true] ... = ... | semmle.label | successor | +| Assert.cs:114:24:114:25 | [b (line 84): false] "" | Assert.cs:114:9:114:25 | [b (line 84): false] ... = ... | semmle.label | successor | +| Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | Assert.cs:84:10:84:12 | exit M12 | semmle.label | exception(AssertFailedException) | +| Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | Assert.cs:84:10:84:12 | exit M12 | semmle.label | exception(AssertFailedException) | +| Assert.cs:115:9:115:37 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:116:9:116:36 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:115:9:115:38 | [b (line 84): false] ...; | Assert.cs:115:23:115:36 | [b (line 84): false] ... && ... | semmle.label | successor | +| Assert.cs:115:9:115:38 | [b (line 84): true] ...; | Assert.cs:115:23:115:36 | [b (line 84): true] ... && ... | semmle.label | successor | +| Assert.cs:115:23:115:23 | [b (line 84): false] access to local variable s | Assert.cs:115:28:115:31 | [b (line 84): false] null | semmle.label | successor | +| Assert.cs:115:23:115:23 | [b (line 84): true] access to local variable s | Assert.cs:115:28:115:31 | [b (line 84): true] null | semmle.label | successor | +| Assert.cs:115:23:115:31 | [b (line 84): false] ... != ... | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | semmle.label | false | +| Assert.cs:115:23:115:31 | [b (line 84): false] ... != ... | Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | semmle.label | true | +| Assert.cs:115:23:115:31 | [b (line 84): true] ... != ... | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | semmle.label | false | +| Assert.cs:115:23:115:31 | [b (line 84): true] ... != ... | Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | semmle.label | true | +| Assert.cs:115:23:115:36 | [b (line 84): false] ... && ... | Assert.cs:115:23:115:23 | [b (line 84): false] access to local variable s | semmle.label | successor | +| Assert.cs:115:23:115:36 | [b (line 84): true] ... && ... | Assert.cs:115:23:115:23 | [b (line 84): true] access to local variable s | semmle.label | successor | +| Assert.cs:115:28:115:31 | [b (line 84): false] null | Assert.cs:115:23:115:31 | [b (line 84): false] ... != ... | semmle.label | successor | +| Assert.cs:115:28:115:31 | [b (line 84): true] null | Assert.cs:115:23:115:31 | [b (line 84): true] ... != ... | semmle.label | successor | +| Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | semmle.label | false | +| Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | Assert.cs:115:9:115:37 | [assertion success, b (line 84): true] call to method IsTrue | semmle.label | true | +| Assert.cs:116:9:116:35 | [b (line 84): true] call to method WriteLine | Assert.cs:118:9:118:26 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:116:9:116:36 | [b (line 84): true] ...; | Assert.cs:116:27:116:27 | [b (line 84): true] access to local variable s | semmle.label | successor | +| Assert.cs:116:27:116:27 | [b (line 84): true] access to local variable s | Assert.cs:116:27:116:34 | [b (line 84): true] access to property Length | semmle.label | successor | +| Assert.cs:116:27:116:34 | [b (line 84): true] access to property Length | Assert.cs:116:9:116:35 | [b (line 84): true] call to method WriteLine | semmle.label | successor | +| Assert.cs:118:9:118:25 | [b (line 84): true] ... = ... | Assert.cs:119:9:119:40 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:118:9:118:26 | [b (line 84): true] ...; | Assert.cs:118:13:118:25 | [b (line 84): true] ... ? ... : ... | semmle.label | successor | +| Assert.cs:118:13:118:13 | [b (line 84): true] access to parameter b | Assert.cs:118:17:118:20 | [b (line 84): true] null | semmle.label | true | +| Assert.cs:118:13:118:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:118:13:118:13 | [b (line 84): true] access to parameter b | semmle.label | successor | +| Assert.cs:118:17:118:20 | [b (line 84): true] null | Assert.cs:118:9:118:25 | [b (line 84): true] ... = ... | semmle.label | successor | +| Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | Assert.cs:84:10:84:12 | exit M12 | semmle.label | exception(AssertFailedException) | +| Assert.cs:119:9:119:39 | [assertion success, b (line 84): true] call to method IsFalse | Assert.cs:120:9:120:36 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:119:9:119:40 | [b (line 84): true] ...; | Assert.cs:119:24:119:38 | [b (line 84): true] ... \|\| ... | semmle.label | successor | +| Assert.cs:119:24:119:24 | [b (line 84): true] access to local variable s | Assert.cs:119:29:119:32 | [b (line 84): true] null | semmle.label | successor | +| Assert.cs:119:24:119:32 | [b (line 84): true] ... == ... | Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | semmle.label | true | +| Assert.cs:119:24:119:32 | [b (line 84): true] ... == ... | Assert.cs:119:37:119:38 | [b (line 84): true] !... | semmle.label | false | +| Assert.cs:119:24:119:38 | [b (line 84): true] ... \|\| ... | Assert.cs:119:24:119:24 | [b (line 84): true] access to local variable s | semmle.label | successor | +| Assert.cs:119:29:119:32 | [b (line 84): true] null | Assert.cs:119:24:119:32 | [b (line 84): true] ... == ... | semmle.label | successor | +| Assert.cs:119:37:119:38 | [b (line 84): true] !... | Assert.cs:119:38:119:38 | [b (line 84): true] access to parameter b | semmle.label | successor | +| Assert.cs:119:38:119:38 | [b (line 84): true] access to parameter b | Assert.cs:119:9:119:39 | [assertion success, b (line 84): true] call to method IsFalse | semmle.label | true | +| Assert.cs:120:9:120:35 | [b (line 84): true] call to method WriteLine | Assert.cs:122:9:122:26 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:120:9:120:36 | [b (line 84): true] ...; | Assert.cs:120:27:120:27 | [b (line 84): true] access to local variable s | semmle.label | successor | +| Assert.cs:120:27:120:27 | [b (line 84): true] access to local variable s | Assert.cs:120:27:120:34 | [b (line 84): true] access to property Length | semmle.label | successor | +| Assert.cs:120:27:120:34 | [b (line 84): true] access to property Length | Assert.cs:120:9:120:35 | [b (line 84): true] call to method WriteLine | semmle.label | successor | +| Assert.cs:122:9:122:25 | [b (line 84): true] ... = ... | Assert.cs:123:9:123:38 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:122:9:122:26 | [b (line 84): true] ...; | Assert.cs:122:13:122:25 | [b (line 84): true] ... ? ... : ... | semmle.label | successor | +| Assert.cs:122:13:122:13 | [b (line 84): true] access to parameter b | Assert.cs:122:17:122:20 | [b (line 84): true] null | semmle.label | true | +| Assert.cs:122:13:122:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:122:13:122:13 | [b (line 84): true] access to parameter b | semmle.label | successor | +| Assert.cs:122:17:122:20 | [b (line 84): true] null | Assert.cs:122:9:122:25 | [b (line 84): true] ... = ... | semmle.label | successor | +| Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | Assert.cs:84:10:84:12 | exit M12 | semmle.label | exception(AssertFailedException) | +| Assert.cs:123:9:123:37 | [assertion success, b (line 84): true] call to method IsTrue | Assert.cs:124:9:124:36 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:123:9:123:38 | [b (line 84): true] ...; | Assert.cs:123:23:123:36 | [b (line 84): true] ... && ... | semmle.label | successor | +| Assert.cs:123:23:123:23 | [b (line 84): true] access to local variable s | Assert.cs:123:28:123:31 | [b (line 84): true] null | semmle.label | successor | +| Assert.cs:123:23:123:31 | [b (line 84): true] ... == ... | Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | semmle.label | false | +| Assert.cs:123:23:123:31 | [b (line 84): true] ... == ... | Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | semmle.label | true | +| Assert.cs:123:23:123:36 | [b (line 84): true] ... && ... | Assert.cs:123:23:123:23 | [b (line 84): true] access to local variable s | semmle.label | successor | +| Assert.cs:123:28:123:31 | [b (line 84): true] null | Assert.cs:123:23:123:31 | [b (line 84): true] ... == ... | semmle.label | successor | +| Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | Assert.cs:123:9:123:37 | [assertion success, b (line 84): true] call to method IsTrue | semmle.label | true | +| Assert.cs:124:9:124:35 | [b (line 84): true] call to method WriteLine | Assert.cs:126:9:126:26 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:124:9:124:36 | [b (line 84): true] ...; | Assert.cs:124:27:124:27 | [b (line 84): true] access to local variable s | semmle.label | successor | +| Assert.cs:124:27:124:27 | [b (line 84): true] access to local variable s | Assert.cs:124:27:124:34 | [b (line 84): true] access to property Length | semmle.label | successor | +| Assert.cs:124:27:124:34 | [b (line 84): true] access to property Length | Assert.cs:124:9:124:35 | [b (line 84): true] call to method WriteLine | semmle.label | successor | +| Assert.cs:126:9:126:25 | [b (line 84): true] ... = ... | Assert.cs:127:9:127:40 | [b (line 84): true] ...; | semmle.label | successor | +| Assert.cs:126:9:126:26 | [b (line 84): true] ...; | Assert.cs:126:13:126:25 | [b (line 84): true] ... ? ... : ... | semmle.label | successor | +| Assert.cs:126:13:126:13 | [b (line 84): true] access to parameter b | Assert.cs:126:17:126:20 | [b (line 84): true] null | semmle.label | true | +| Assert.cs:126:13:126:25 | [b (line 84): true] ... ? ... : ... | Assert.cs:126:13:126:13 | [b (line 84): true] access to parameter b | semmle.label | successor | +| Assert.cs:126:17:126:20 | [b (line 84): true] null | Assert.cs:126:9:126:25 | [b (line 84): true] ... = ... | semmle.label | successor | +| Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | Assert.cs:84:10:84:12 | exit M12 | semmle.label | exception(AssertFailedException) | +| Assert.cs:127:9:127:39 | [assertion success] call to method IsFalse | Assert.cs:128:9:128:36 | ...; | semmle.label | successor | +| Assert.cs:127:9:127:40 | [b (line 84): true] ...; | Assert.cs:127:24:127:38 | [b (line 84): true] ... \|\| ... | semmle.label | successor | +| Assert.cs:127:24:127:24 | [b (line 84): true] access to local variable s | Assert.cs:127:29:127:32 | [b (line 84): true] null | semmle.label | successor | +| Assert.cs:127:24:127:32 | [b (line 84): true] ... != ... | Assert.cs:127:9:127:39 | [assertion failure] call to method IsFalse | semmle.label | true | +| Assert.cs:127:24:127:32 | [b (line 84): true] ... != ... | Assert.cs:127:37:127:38 | [b (line 84): true] !... | semmle.label | false | +| Assert.cs:127:24:127:38 | [b (line 84): true] ... \|\| ... | Assert.cs:127:24:127:24 | [b (line 84): true] access to local variable s | semmle.label | successor | +| Assert.cs:127:29:127:32 | [b (line 84): true] null | Assert.cs:127:24:127:32 | [b (line 84): true] ... != ... | semmle.label | successor | +| Assert.cs:127:37:127:38 | [b (line 84): true] !... | Assert.cs:127:38:127:38 | [b (line 84): true] access to parameter b | semmle.label | successor | +| Assert.cs:127:38:127:38 | [b (line 84): true] access to parameter b | Assert.cs:127:9:127:39 | [assertion success] call to method IsFalse | semmle.label | true | +| Assert.cs:128:9:128:35 | call to method WriteLine | Assert.cs:84:10:84:12 | exit M12 | semmle.label | successor | +| Assert.cs:128:9:128:36 | ...; | Assert.cs:128:27:128:27 | access to local variable s | semmle.label | successor | +| Assert.cs:128:27:128:27 | access to local variable s | Assert.cs:128:27:128:34 | access to property Length | semmle.label | successor | +| Assert.cs:128:27:128:34 | access to property Length | Assert.cs:128:9:128:35 | call to method WriteLine | semmle.label | successor | | Assignments.cs:3:10:3:10 | enter M | Assignments.cs:4:5:15:5 | {...} | semmle.label | successor | | Assignments.cs:4:5:15:5 | {...} | Assignments.cs:5:9:5:18 | ... ...; | semmle.label | successor | | Assignments.cs:5:9:5:18 | ... ...; | Assignments.cs:5:17:5:17 | 0 | semmle.label | successor | @@ -495,6 +1057,7 @@ | CompileTimeOperators.cs:40:14:40:37 | call to method WriteLine | CompileTimeOperators.cs:28:10:28:10 | exit M | semmle.label | successor | | CompileTimeOperators.cs:40:14:40:38 | ...; | CompileTimeOperators.cs:40:32:40:36 | "End" | semmle.label | successor | | CompileTimeOperators.cs:40:32:40:36 | "End" | CompileTimeOperators.cs:40:14:40:37 | call to method WriteLine | semmle.label | successor | +| ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | ConditionalAccess.cs:30:32:30:32 | 0 | semmle.label | successor | | ConditionalAccess.cs:3:12:3:13 | enter M1 | ConditionalAccess.cs:3:26:3:26 | access to parameter i | semmle.label | successor | | ConditionalAccess.cs:3:26:3:26 | access to parameter i | ConditionalAccess.cs:3:12:3:13 | exit M1 | semmle.label | null | | ConditionalAccess.cs:3:26:3:26 | access to parameter i | ConditionalAccess.cs:3:28:3:38 | call to method ToString | semmle.label | non-null | @@ -554,12 +1117,28 @@ | ConditionalAccess.cs:25:13:25:14 | "" | ConditionalAccess.cs:25:31:25:31 | access to local variable s | semmle.label | non-null | | ConditionalAccess.cs:25:16:25:32 | call to method CommaJoinWith | ConditionalAccess.cs:25:9:25:32 | ... = ... | semmle.label | successor | | ConditionalAccess.cs:25:31:25:31 | access to local variable s | ConditionalAccess.cs:25:16:25:32 | call to method CommaJoinWith | semmle.label | successor | -| ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | semmle.label | successor | -| ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | ConditionalAccess.cs:31:75:31:78 | ", " | semmle.label | successor | -| ConditionalAccess.cs:31:70:31:78 | ... + ... | ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | semmle.label | successor | -| ConditionalAccess.cs:31:70:31:83 | ... + ... | ConditionalAccess.cs:31:26:31:38 | exit CommaJoinWith | semmle.label | successor | -| ConditionalAccess.cs:31:75:31:78 | ", " | ConditionalAccess.cs:31:70:31:78 | ... + ... | semmle.label | successor | -| ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | ConditionalAccess.cs:31:70:31:83 | ... + ... | semmle.label | successor | +| ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:30:32:30:32 | 0 | semmle.label | successor | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | semmle.label | successor | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | semmle.label | successor | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:30:10:30:12 | exit Out | semmle.label | successor | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:28:30:32 | ... = ... | semmle.label | successor | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:28:30:32 | ... = ... | semmle.label | successor | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:33:5:36:5 | {...} | semmle.label | successor | +| ConditionalAccess.cs:33:5:36:5 | {...} | ConditionalAccess.cs:34:9:34:14 | ...; | semmle.label | successor | +| ConditionalAccess.cs:34:9:34:13 | ... = ... | ConditionalAccess.cs:35:9:35:25 | ...; | semmle.label | successor | +| ConditionalAccess.cs:34:9:34:14 | ...; | ConditionalAccess.cs:34:13:34:13 | 0 | semmle.label | successor | +| ConditionalAccess.cs:34:13:34:13 | 0 | ConditionalAccess.cs:34:9:34:13 | ... = ... | semmle.label | successor | +| ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:32:10:32:11 | exit M8 | semmle.label | null | +| ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:35:14:35:24 | call to method Out | semmle.label | non-null | +| ConditionalAccess.cs:35:9:35:12 | this access | ConditionalAccess.cs:35:9:35:12 | access to property Prop | semmle.label | successor | +| ConditionalAccess.cs:35:9:35:25 | ...; | ConditionalAccess.cs:35:9:35:12 | this access | semmle.label | successor | +| ConditionalAccess.cs:35:14:35:24 | call to method Out | ConditionalAccess.cs:32:10:32:11 | exit M8 | semmle.label | successor | +| ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | semmle.label | successor | +| ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | ConditionalAccess.cs:41:75:41:78 | ", " | semmle.label | successor | +| ConditionalAccess.cs:41:70:41:78 | ... + ... | ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | semmle.label | successor | +| ConditionalAccess.cs:41:70:41:83 | ... + ... | ConditionalAccess.cs:41:26:41:38 | exit CommaJoinWith | semmle.label | successor | +| ConditionalAccess.cs:41:75:41:78 | ", " | ConditionalAccess.cs:41:70:41:78 | ... + ... | semmle.label | successor | +| ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | ConditionalAccess.cs:41:70:41:83 | ... + ... | semmle.label | successor | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:4:5:9:5 | {...} | semmle.label | successor | | Conditions.cs:4:5:9:5 | {...} | Conditions.cs:5:9:6:16 | if (...) ... | semmle.label | successor | | Conditions.cs:5:9:6:16 | if (...) ... | Conditions.cs:5:13:5:15 | access to parameter inc | semmle.label | successor | @@ -776,9 +1355,9 @@ | Conditions.cs:79:17:79:25 | ... = ... | Conditions.cs:74:9:80:9 | foreach (... ... in ...) ... | semmle.label | successor | | Conditions.cs:79:17:79:26 | ...; | Conditions.cs:79:21:79:25 | false | semmle.label | successor | | Conditions.cs:79:21:79:25 | false | Conditions.cs:79:17:79:25 | ... = ... | semmle.label | successor | -| Conditions.cs:81:9:82:16 | if (...) ... | Conditions.cs:81:12:81:12 | access to local variable b | semmle.label | successor | -| Conditions.cs:81:12:81:12 | access to local variable b | Conditions.cs:82:13:82:16 | ...; | semmle.label | true | -| Conditions.cs:81:12:81:12 | access to local variable b | Conditions.cs:83:16:83:16 | access to local variable x | semmle.label | false | +| Conditions.cs:81:9:82:16 | if (...) ... | Conditions.cs:81:13:81:13 | access to local variable b | semmle.label | successor | +| Conditions.cs:81:13:81:13 | access to local variable b | Conditions.cs:82:13:82:16 | ...; | semmle.label | true | +| Conditions.cs:81:13:81:13 | access to local variable b | Conditions.cs:83:16:83:16 | access to local variable x | semmle.label | false | | Conditions.cs:82:13:82:13 | access to local variable x | Conditions.cs:82:13:82:15 | ...++ | semmle.label | successor | | Conditions.cs:82:13:82:15 | ...++ | Conditions.cs:83:16:83:16 | access to local variable x | semmle.label | successor | | Conditions.cs:82:13:82:16 | ...; | Conditions.cs:82:13:82:13 | access to local variable x | semmle.label | successor | @@ -866,16 +1445,16 @@ | Conditions.cs:115:9:115:24 | ... ...; | Conditions.cs:115:20:115:23 | null | semmle.label | successor | | Conditions.cs:115:16:115:23 | String s = ... | Conditions.cs:116:9:123:9 | for (...;...;...) ... | semmle.label | successor | | Conditions.cs:115:20:115:23 | null | Conditions.cs:115:16:115:23 | String s = ... | semmle.label | successor | -| Conditions.cs:116:9:123:9 | for (...;...;...) ... | Conditions.cs:116:21:116:21 | 0 | semmle.label | successor | -| Conditions.cs:116:17:116:21 | Int32 i = ... | Conditions.cs:116:24:116:24 | access to local variable i | semmle.label | successor | -| Conditions.cs:116:21:116:21 | 0 | Conditions.cs:116:17:116:21 | Int32 i = ... | semmle.label | successor | -| Conditions.cs:116:24:116:24 | access to local variable i | Conditions.cs:116:28:116:31 | access to parameter args | semmle.label | successor | -| Conditions.cs:116:24:116:38 | ... < ... | Conditions.cs:113:10:113:11 | exit M9 | semmle.label | false | -| Conditions.cs:116:24:116:38 | ... < ... | Conditions.cs:117:9:123:9 | {...} | semmle.label | true | -| Conditions.cs:116:28:116:31 | access to parameter args | Conditions.cs:116:28:116:38 | access to property Length | semmle.label | successor | -| Conditions.cs:116:28:116:38 | access to property Length | Conditions.cs:116:24:116:38 | ... < ... | semmle.label | successor | -| Conditions.cs:116:41:116:41 | access to local variable i | Conditions.cs:116:41:116:43 | ...++ | semmle.label | successor | -| Conditions.cs:116:41:116:43 | ...++ | Conditions.cs:116:24:116:24 | access to local variable i | semmle.label | successor | +| Conditions.cs:116:9:123:9 | for (...;...;...) ... | Conditions.cs:116:22:116:22 | 0 | semmle.label | successor | +| Conditions.cs:116:18:116:22 | Int32 i = ... | Conditions.cs:116:25:116:25 | access to local variable i | semmle.label | successor | +| Conditions.cs:116:22:116:22 | 0 | Conditions.cs:116:18:116:22 | Int32 i = ... | semmle.label | successor | +| Conditions.cs:116:25:116:25 | access to local variable i | Conditions.cs:116:29:116:32 | access to parameter args | semmle.label | successor | +| Conditions.cs:116:25:116:39 | ... < ... | Conditions.cs:113:10:113:11 | exit M9 | semmle.label | false | +| Conditions.cs:116:25:116:39 | ... < ... | Conditions.cs:117:9:123:9 | {...} | semmle.label | true | +| Conditions.cs:116:29:116:32 | access to parameter args | Conditions.cs:116:29:116:39 | access to property Length | semmle.label | successor | +| Conditions.cs:116:29:116:39 | access to property Length | Conditions.cs:116:25:116:39 | ... < ... | semmle.label | successor | +| Conditions.cs:116:42:116:42 | access to local variable i | Conditions.cs:116:42:116:44 | ...++ | semmle.label | successor | +| Conditions.cs:116:42:116:44 | ...++ | Conditions.cs:116:25:116:25 | access to local variable i | semmle.label | successor | | Conditions.cs:117:9:123:9 | {...} | Conditions.cs:118:13:118:44 | ... ...; | semmle.label | successor | | Conditions.cs:118:13:118:44 | ... ...; | Conditions.cs:118:24:118:24 | access to local variable i | semmle.label | successor | | Conditions.cs:118:17:118:43 | Boolean last = ... | Conditions.cs:119:13:120:23 | if (...) ... | semmle.label | successor | @@ -894,9 +1473,9 @@ | Conditions.cs:120:21:120:22 | [last (line 118): false] "" | Conditions.cs:120:17:120:22 | [last (line 118): false] ... = ... | semmle.label | successor | | Conditions.cs:121:13:122:25 | [last (line 118): false] if (...) ... | Conditions.cs:121:17:121:20 | [last (line 118): false] access to local variable last | semmle.label | successor | | Conditions.cs:121:13:122:25 | [last (line 118): true] if (...) ... | Conditions.cs:121:17:121:20 | [last (line 118): true] access to local variable last | semmle.label | successor | -| Conditions.cs:121:17:121:20 | [last (line 118): false] access to local variable last | Conditions.cs:116:41:116:41 | access to local variable i | semmle.label | false | +| Conditions.cs:121:17:121:20 | [last (line 118): false] access to local variable last | Conditions.cs:116:42:116:42 | access to local variable i | semmle.label | false | | Conditions.cs:121:17:121:20 | [last (line 118): true] access to local variable last | Conditions.cs:122:17:122:25 | ...; | semmle.label | true | -| Conditions.cs:122:17:122:24 | ... = ... | Conditions.cs:116:41:116:41 | access to local variable i | semmle.label | successor | +| Conditions.cs:122:17:122:24 | ... = ... | Conditions.cs:116:42:116:42 | access to local variable i | semmle.label | successor | | Conditions.cs:122:17:122:25 | ...; | Conditions.cs:122:21:122:24 | null | semmle.label | successor | | Conditions.cs:122:21:122:24 | null | Conditions.cs:122:17:122:24 | ... = ... | semmle.label | successor | | Conditions.cs:129:10:129:12 | enter M10 | Conditions.cs:130:5:141:5 | {...} | semmle.label | successor | @@ -941,6 +1520,30 @@ | Conditions.cs:137:21:137:26 | [Field1 (line 129): true, Field2 (line 129): true] this access | Conditions.cs:137:21:137:26 | [Field1 (line 129): true, Field2 (line 129): true] access to field Field1 | semmle.label | successor | | Conditions.cs:137:21:137:37 | [Field1 (line 129): true, Field2 (line 129): true] call to method ToString | Conditions.cs:131:16:131:19 | [Field1 (line 129): true, Field2 (line 129): true] true | semmle.label | successor | | Conditions.cs:137:21:137:38 | [Field1 (line 129): true, Field2 (line 129): true] ...; | Conditions.cs:137:21:137:26 | [Field1 (line 129): true, Field2 (line 129): true] this access | semmle.label | successor | +| Conditions.cs:143:10:143:12 | enter M11 | Conditions.cs:144:5:150:5 | {...} | semmle.label | successor | +| Conditions.cs:144:5:150:5 | {...} | Conditions.cs:145:9:145:30 | ... ...; | semmle.label | successor | +| Conditions.cs:145:9:145:30 | ... ...; | Conditions.cs:145:17:145:29 | ... ? ... : ... | semmle.label | successor | +| Conditions.cs:145:13:145:29 | [b (line 143): false] String s = ... | Conditions.cs:146:9:149:49 | [b (line 143): false] if (...) ... | semmle.label | successor | +| Conditions.cs:145:13:145:29 | [b (line 143): true] String s = ... | Conditions.cs:146:9:149:49 | [b (line 143): true] if (...) ... | semmle.label | successor | +| Conditions.cs:145:17:145:17 | access to parameter b | Conditions.cs:145:21:145:23 | [b (line 143): true] "a" | semmle.label | true | +| Conditions.cs:145:17:145:17 | access to parameter b | Conditions.cs:145:27:145:29 | [b (line 143): false] "b" | semmle.label | false | +| Conditions.cs:145:17:145:29 | ... ? ... : ... | Conditions.cs:145:17:145:17 | access to parameter b | semmle.label | successor | +| Conditions.cs:145:21:145:23 | [b (line 143): true] "a" | Conditions.cs:145:13:145:29 | [b (line 143): true] String s = ... | semmle.label | successor | +| Conditions.cs:145:27:145:29 | [b (line 143): false] "b" | Conditions.cs:145:13:145:29 | [b (line 143): false] String s = ... | semmle.label | successor | +| Conditions.cs:146:9:149:49 | [b (line 143): false] if (...) ... | Conditions.cs:146:13:146:13 | [b (line 143): false] access to parameter b | semmle.label | successor | +| Conditions.cs:146:9:149:49 | [b (line 143): true] if (...) ... | Conditions.cs:146:13:146:13 | [b (line 143): true] access to parameter b | semmle.label | successor | +| Conditions.cs:146:13:146:13 | [b (line 143): false] access to parameter b | Conditions.cs:149:13:149:49 | ...; | semmle.label | false | +| Conditions.cs:146:13:146:13 | [b (line 143): true] access to parameter b | Conditions.cs:147:13:147:49 | ...; | semmle.label | true | +| Conditions.cs:147:13:147:48 | call to method WriteLine | Conditions.cs:143:10:143:12 | exit M11 | semmle.label | successor | +| Conditions.cs:147:13:147:49 | ...; | Conditions.cs:147:40:147:43 | "a = " | semmle.label | successor | +| Conditions.cs:147:38:147:47 | $"..." | Conditions.cs:147:13:147:48 | call to method WriteLine | semmle.label | successor | +| Conditions.cs:147:40:147:43 | "a = " | Conditions.cs:147:45:147:45 | access to local variable s | semmle.label | successor | +| Conditions.cs:147:45:147:45 | access to local variable s | Conditions.cs:147:38:147:47 | $"..." | semmle.label | successor | +| Conditions.cs:149:13:149:48 | call to method WriteLine | Conditions.cs:143:10:143:12 | exit M11 | semmle.label | successor | +| Conditions.cs:149:13:149:49 | ...; | Conditions.cs:149:40:149:43 | "b = " | semmle.label | successor | +| Conditions.cs:149:38:149:47 | $"..." | Conditions.cs:149:13:149:48 | call to method WriteLine | semmle.label | successor | +| Conditions.cs:149:40:149:43 | "b = " | Conditions.cs:149:45:149:45 | access to local variable s | semmle.label | successor | +| Conditions.cs:149:45:149:45 | access to local variable s | Conditions.cs:149:38:149:47 | $"..." | semmle.label | successor | | ExitMethods.cs:7:10:7:11 | enter M1 | ExitMethods.cs:8:5:11:5 | {...} | semmle.label | successor | | ExitMethods.cs:8:5:11:5 | {...} | ExitMethods.cs:9:9:9:25 | ...; | semmle.label | successor | | ExitMethods.cs:9:9:9:24 | call to method ErrorMaybe | ExitMethods.cs:10:9:10:15 | return ...; | semmle.label | successor | @@ -1061,23 +1664,25 @@ | ExitMethods.cs:116:38:116:38 | 1 | ExitMethods.cs:116:9:116:39 | return ...; | semmle.label | successor | | ExitMethods.cs:119:17:119:32 | enter FailingAssertion | ExitMethods.cs:120:5:123:5 | {...} | semmle.label | successor | | ExitMethods.cs:120:5:123:5 | {...} | ExitMethods.cs:121:9:121:29 | ...; | semmle.label | successor | -| ExitMethods.cs:121:9:121:28 | call to method IsTrue | ExitMethods.cs:119:17:119:32 | exit FailingAssertion | semmle.label | exception(AssertFailedException) | +| ExitMethods.cs:121:9:121:28 | [assertion failure] call to method IsTrue | ExitMethods.cs:119:17:119:32 | exit FailingAssertion | semmle.label | exception(AssertFailedException) | | ExitMethods.cs:121:9:121:29 | ...; | ExitMethods.cs:121:23:121:27 | false | semmle.label | successor | -| ExitMethods.cs:121:23:121:27 | false | ExitMethods.cs:121:9:121:28 | call to method IsTrue | semmle.label | successor | +| ExitMethods.cs:121:23:121:27 | false | ExitMethods.cs:121:9:121:28 | [assertion failure] call to method IsTrue | semmle.label | false | | ExitMethods.cs:125:17:125:33 | enter FailingAssertion2 | ExitMethods.cs:126:5:129:5 | {...} | semmle.label | successor | | ExitMethods.cs:126:5:129:5 | {...} | ExitMethods.cs:127:9:127:27 | ...; | semmle.label | successor | | ExitMethods.cs:127:9:127:26 | call to method FailingAssertion | ExitMethods.cs:125:17:125:33 | exit FailingAssertion2 | semmle.label | exception(AssertFailedException) | | ExitMethods.cs:127:9:127:26 | this access | ExitMethods.cs:127:9:127:26 | call to method FailingAssertion | semmle.label | successor | | ExitMethods.cs:127:9:127:27 | ...; | ExitMethods.cs:127:9:127:26 | this access | semmle.label | successor | | ExitMethods.cs:131:10:131:20 | enter AssertFalse | ExitMethods.cs:131:48:131:48 | access to parameter b | semmle.label | successor | -| ExitMethods.cs:131:33:131:49 | call to method IsFalse | ExitMethods.cs:131:10:131:20 | exit AssertFalse | semmle.label | successor | -| ExitMethods.cs:131:48:131:48 | access to parameter b | ExitMethods.cs:131:33:131:49 | call to method IsFalse | semmle.label | successor | +| ExitMethods.cs:131:33:131:49 | [assertion failure] call to method IsFalse | ExitMethods.cs:131:10:131:20 | exit AssertFalse | semmle.label | exception(AssertFailedException) | +| ExitMethods.cs:131:33:131:49 | [assertion success] call to method IsFalse | ExitMethods.cs:131:10:131:20 | exit AssertFalse | semmle.label | successor | +| ExitMethods.cs:131:48:131:48 | access to parameter b | ExitMethods.cs:131:33:131:49 | [assertion failure] call to method IsFalse | semmle.label | true | +| ExitMethods.cs:131:48:131:48 | access to parameter b | ExitMethods.cs:131:33:131:49 | [assertion success] call to method IsFalse | semmle.label | false | | ExitMethods.cs:133:17:133:33 | enter FailingAssertion3 | ExitMethods.cs:134:5:137:5 | {...} | semmle.label | successor | | ExitMethods.cs:134:5:137:5 | {...} | ExitMethods.cs:135:9:135:26 | ...; | semmle.label | successor | -| ExitMethods.cs:135:9:135:25 | call to method AssertFalse | ExitMethods.cs:133:17:133:33 | exit FailingAssertion3 | semmle.label | exception(AssertFailedException) | +| ExitMethods.cs:135:9:135:25 | [assertion failure] call to method AssertFalse | ExitMethods.cs:133:17:133:33 | exit FailingAssertion3 | semmle.label | exception(AssertFailedException) | | ExitMethods.cs:135:9:135:25 | this access | ExitMethods.cs:135:21:135:24 | true | semmle.label | successor | | ExitMethods.cs:135:9:135:26 | ...; | ExitMethods.cs:135:9:135:25 | this access | semmle.label | successor | -| ExitMethods.cs:135:21:135:24 | true | ExitMethods.cs:135:9:135:25 | call to method AssertFalse | semmle.label | successor | +| ExitMethods.cs:135:21:135:24 | true | ExitMethods.cs:135:9:135:25 | [assertion failure] call to method AssertFalse | semmle.label | true | | Extensions.cs:5:23:5:29 | enter ToInt32 | Extensions.cs:6:5:8:5 | {...} | semmle.label | successor | | Extensions.cs:6:5:8:5 | {...} | Extensions.cs:7:28:7:28 | access to parameter s | semmle.label | successor | | Extensions.cs:7:9:7:30 | return ...; | Extensions.cs:5:23:5:29 | exit ToInt32 | semmle.label | return | @@ -1930,8 +2535,9 @@ | Initializers.cs:14:47:14:47 | access to property G | Initializers.cs:14:47:14:51 | ... = ... | semmle.label | successor | | Initializers.cs:14:47:14:51 | ... = ... | Initializers.cs:14:38:14:53 | { ..., ... } | semmle.label | successor | | Initializers.cs:14:51:14:51 | 1 | Initializers.cs:14:47:14:47 | access to property G | semmle.label | successor | -| Initializers.cs:15:9:15:64 | ... ...; | Initializers.cs:15:18:15:63 | array creation of type Initializers[] | semmle.label | successor | +| Initializers.cs:15:9:15:64 | ... ...; | Initializers.cs:15:18:15:63 | 2 | semmle.label | successor | | Initializers.cs:15:13:15:63 | Initializers[] iz = ... | Initializers.cs:12:10:12:10 | exit M | semmle.label | successor | +| Initializers.cs:15:18:15:63 | 2 | Initializers.cs:15:18:15:63 | array creation of type Initializers[] | semmle.label | successor | | Initializers.cs:15:18:15:63 | array creation of type Initializers[] | Initializers.cs:15:39:15:39 | access to local variable i | semmle.label | successor | | Initializers.cs:15:37:15:63 | { ..., ... } | Initializers.cs:15:13:15:63 | Initializers[] iz = ... | semmle.label | successor | | Initializers.cs:15:39:15:39 | access to local variable i | Initializers.cs:15:59:15:60 | "" | semmle.label | successor | @@ -2088,31 +2694,32 @@ | LoopUnrolling.cs:9:13:9:16 | access to parameter args | LoopUnrolling.cs:9:13:9:23 | access to property Length | semmle.label | successor | | LoopUnrolling.cs:9:13:9:23 | access to property Length | LoopUnrolling.cs:9:28:9:28 | 0 | semmle.label | successor | | LoopUnrolling.cs:9:13:9:28 | ... == ... | LoopUnrolling.cs:10:13:10:19 | return ...; | semmle.label | true | -| LoopUnrolling.cs:9:13:9:28 | ... == ... | LoopUnrolling.cs:11:28:11:31 | access to parameter args | semmle.label | false | +| LoopUnrolling.cs:9:13:9:28 | ... == ... | LoopUnrolling.cs:11:29:11:32 | access to parameter args | semmle.label | false | | LoopUnrolling.cs:9:28:9:28 | 0 | LoopUnrolling.cs:9:13:9:28 | ... == ... | semmle.label | successor | | LoopUnrolling.cs:10:13:10:19 | return ...; | LoopUnrolling.cs:7:10:7:11 | exit M1 | semmle.label | return | -| LoopUnrolling.cs:11:9:12:35 | [unroll (line 11)] foreach (... ... in ...) ... | LoopUnrolling.cs:11:21:11:23 | String arg | semmle.label | non-empty | +| LoopUnrolling.cs:11:9:12:35 | [unroll (line 11)] foreach (... ... in ...) ... | LoopUnrolling.cs:11:22:11:24 | String arg | semmle.label | non-empty | | LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:7:10:7:11 | exit M1 | semmle.label | empty | -| LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:11:21:11:23 | String arg | semmle.label | non-empty | -| LoopUnrolling.cs:11:21:11:23 | String arg | LoopUnrolling.cs:12:13:12:35 | ...; | semmle.label | successor | -| LoopUnrolling.cs:11:28:11:31 | access to parameter args | LoopUnrolling.cs:11:9:12:35 | [unroll (line 11)] foreach (... ... in ...) ... | semmle.label | successor | +| LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:11:22:11:24 | String arg | semmle.label | non-empty | +| LoopUnrolling.cs:11:22:11:24 | String arg | LoopUnrolling.cs:12:13:12:35 | ...; | semmle.label | successor | +| LoopUnrolling.cs:11:29:11:32 | access to parameter args | LoopUnrolling.cs:11:9:12:35 | [unroll (line 11)] foreach (... ... in ...) ... | semmle.label | successor | | LoopUnrolling.cs:12:13:12:34 | call to method WriteLine | LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | semmle.label | successor | | LoopUnrolling.cs:12:13:12:35 | ...; | LoopUnrolling.cs:12:31:12:33 | access to local variable arg | semmle.label | successor | | LoopUnrolling.cs:12:31:12:33 | access to local variable arg | LoopUnrolling.cs:12:13:12:34 | call to method WriteLine | semmle.label | successor | | LoopUnrolling.cs:15:10:15:11 | enter M2 | LoopUnrolling.cs:16:5:20:5 | {...} | semmle.label | successor | -| LoopUnrolling.cs:16:5:20:5 | {...} | LoopUnrolling.cs:17:9:17:47 | ... ...; | semmle.label | successor | -| LoopUnrolling.cs:17:9:17:47 | ... ...; | LoopUnrolling.cs:17:18:17:46 | array creation of type String[] | semmle.label | successor | -| LoopUnrolling.cs:17:13:17:46 | String[] xs = ... | LoopUnrolling.cs:18:26:18:27 | access to local variable xs | semmle.label | successor | -| LoopUnrolling.cs:17:18:17:46 | array creation of type String[] | LoopUnrolling.cs:17:32:17:34 | "a" | semmle.label | successor | -| LoopUnrolling.cs:17:30:17:46 | { ..., ... } | LoopUnrolling.cs:17:13:17:46 | String[] xs = ... | semmle.label | successor | -| LoopUnrolling.cs:17:32:17:34 | "a" | LoopUnrolling.cs:17:37:17:39 | "b" | semmle.label | successor | -| LoopUnrolling.cs:17:37:17:39 | "b" | LoopUnrolling.cs:17:42:17:44 | "c" | semmle.label | successor | -| LoopUnrolling.cs:17:42:17:44 | "c" | LoopUnrolling.cs:17:30:17:46 | { ..., ... } | semmle.label | successor | -| LoopUnrolling.cs:18:9:19:33 | [unroll (line 18)] foreach (... ... in ...) ... | LoopUnrolling.cs:18:21:18:21 | String x | semmle.label | non-empty | +| LoopUnrolling.cs:16:5:20:5 | {...} | LoopUnrolling.cs:17:9:17:48 | ... ...; | semmle.label | successor | +| LoopUnrolling.cs:17:9:17:48 | ... ...; | LoopUnrolling.cs:17:18:17:47 | 3 | semmle.label | successor | +| LoopUnrolling.cs:17:13:17:47 | String[] xs = ... | LoopUnrolling.cs:18:27:18:28 | access to local variable xs | semmle.label | successor | +| LoopUnrolling.cs:17:18:17:47 | 3 | LoopUnrolling.cs:17:18:17:47 | array creation of type String[] | semmle.label | successor | +| LoopUnrolling.cs:17:18:17:47 | array creation of type String[] | LoopUnrolling.cs:17:33:17:35 | "a" | semmle.label | successor | +| LoopUnrolling.cs:17:31:17:47 | { ..., ... } | LoopUnrolling.cs:17:13:17:47 | String[] xs = ... | semmle.label | successor | +| LoopUnrolling.cs:17:33:17:35 | "a" | LoopUnrolling.cs:17:38:17:40 | "b" | semmle.label | successor | +| LoopUnrolling.cs:17:38:17:40 | "b" | LoopUnrolling.cs:17:43:17:45 | "c" | semmle.label | successor | +| LoopUnrolling.cs:17:43:17:45 | "c" | LoopUnrolling.cs:17:31:17:47 | { ..., ... } | semmle.label | successor | +| LoopUnrolling.cs:18:9:19:33 | [unroll (line 18)] foreach (... ... in ...) ... | LoopUnrolling.cs:18:22:18:22 | String x | semmle.label | non-empty | | LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:15:10:15:11 | exit M2 | semmle.label | empty | -| LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:18:21:18:21 | String x | semmle.label | non-empty | -| LoopUnrolling.cs:18:21:18:21 | String x | LoopUnrolling.cs:19:13:19:33 | ...; | semmle.label | successor | -| LoopUnrolling.cs:18:26:18:27 | access to local variable xs | LoopUnrolling.cs:18:9:19:33 | [unroll (line 18)] foreach (... ... in ...) ... | semmle.label | successor | +| LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:18:22:18:22 | String x | semmle.label | non-empty | +| LoopUnrolling.cs:18:22:18:22 | String x | LoopUnrolling.cs:19:13:19:33 | ...; | semmle.label | successor | +| LoopUnrolling.cs:18:27:18:28 | access to local variable xs | LoopUnrolling.cs:18:9:19:33 | [unroll (line 18)] foreach (... ... in ...) ... | semmle.label | successor | | LoopUnrolling.cs:19:13:19:32 | call to method WriteLine | LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... | semmle.label | successor | | LoopUnrolling.cs:19:13:19:33 | ...; | LoopUnrolling.cs:19:31:19:31 | access to local variable x | semmle.label | successor | | LoopUnrolling.cs:19:31:19:31 | access to local variable x | LoopUnrolling.cs:19:13:19:32 | call to method WriteLine | semmle.label | successor | @@ -2133,83 +2740,82 @@ | LoopUnrolling.cs:29:10:29:11 | enter M4 | LoopUnrolling.cs:30:5:34:5 | {...} | semmle.label | successor | | LoopUnrolling.cs:30:5:34:5 | {...} | LoopUnrolling.cs:31:9:31:31 | ... ...; | semmle.label | successor | | LoopUnrolling.cs:31:9:31:31 | ... ...; | LoopUnrolling.cs:31:29:31:29 | 0 | semmle.label | successor | -| LoopUnrolling.cs:31:13:31:30 | String[] xs = ... | LoopUnrolling.cs:32:26:32:27 | access to local variable xs | semmle.label | successor | +| LoopUnrolling.cs:31:13:31:30 | String[] xs = ... | LoopUnrolling.cs:32:27:32:28 | access to local variable xs | semmle.label | successor | | LoopUnrolling.cs:31:18:31:30 | array creation of type String[] | LoopUnrolling.cs:31:13:31:30 | String[] xs = ... | semmle.label | successor | | LoopUnrolling.cs:31:29:31:29 | 0 | LoopUnrolling.cs:31:18:31:30 | array creation of type String[] | semmle.label | successor | -| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:29:10:29:11 | exit M4 | semmle.label | empty | -| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:32:21:32:21 | String x | semmle.label | non-empty | -| LoopUnrolling.cs:32:21:32:21 | String x | LoopUnrolling.cs:33:13:33:33 | ...; | semmle.label | successor | -| LoopUnrolling.cs:32:26:32:27 | access to local variable xs | LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | semmle.label | successor | -| LoopUnrolling.cs:33:13:33:32 | call to method WriteLine | LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | semmle.label | successor | -| LoopUnrolling.cs:33:13:33:33 | ...; | LoopUnrolling.cs:33:31:33:31 | access to local variable x | semmle.label | successor | -| LoopUnrolling.cs:33:31:33:31 | access to local variable x | LoopUnrolling.cs:33:13:33:32 | call to method WriteLine | semmle.label | successor | +| LoopUnrolling.cs:32:9:33:33 | [skip (line 32)] foreach (... ... in ...) ... | LoopUnrolling.cs:29:10:29:11 | exit M4 | semmle.label | empty | +| LoopUnrolling.cs:32:27:32:28 | access to local variable xs | LoopUnrolling.cs:32:9:33:33 | [skip (line 32)] foreach (... ... in ...) ... | semmle.label | successor | | LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:37:5:43:5 | {...} | semmle.label | successor | -| LoopUnrolling.cs:37:5:43:5 | {...} | LoopUnrolling.cs:38:9:38:47 | ... ...; | semmle.label | successor | -| LoopUnrolling.cs:38:9:38:47 | ... ...; | LoopUnrolling.cs:38:18:38:46 | array creation of type String[] | semmle.label | successor | -| LoopUnrolling.cs:38:13:38:46 | String[] xs = ... | LoopUnrolling.cs:39:9:39:47 | ... ...; | semmle.label | successor | -| LoopUnrolling.cs:38:18:38:46 | array creation of type String[] | LoopUnrolling.cs:38:32:38:34 | "a" | semmle.label | successor | -| LoopUnrolling.cs:38:30:38:46 | { ..., ... } | LoopUnrolling.cs:38:13:38:46 | String[] xs = ... | semmle.label | successor | -| LoopUnrolling.cs:38:32:38:34 | "a" | LoopUnrolling.cs:38:37:38:39 | "b" | semmle.label | successor | -| LoopUnrolling.cs:38:37:38:39 | "b" | LoopUnrolling.cs:38:42:38:44 | "c" | semmle.label | successor | -| LoopUnrolling.cs:38:42:38:44 | "c" | LoopUnrolling.cs:38:30:38:46 | { ..., ... } | semmle.label | successor | -| LoopUnrolling.cs:39:9:39:47 | ... ...; | LoopUnrolling.cs:39:18:39:46 | array creation of type String[] | semmle.label | successor | -| LoopUnrolling.cs:39:13:39:46 | String[] ys = ... | LoopUnrolling.cs:40:26:40:27 | access to local variable xs | semmle.label | successor | -| LoopUnrolling.cs:39:18:39:46 | array creation of type String[] | LoopUnrolling.cs:39:32:39:34 | "0" | semmle.label | successor | -| LoopUnrolling.cs:39:30:39:46 | { ..., ... } | LoopUnrolling.cs:39:13:39:46 | String[] ys = ... | semmle.label | successor | -| LoopUnrolling.cs:39:32:39:34 | "0" | LoopUnrolling.cs:39:37:39:39 | "1" | semmle.label | successor | -| LoopUnrolling.cs:39:37:39:39 | "1" | LoopUnrolling.cs:39:42:39:44 | "2" | semmle.label | successor | -| LoopUnrolling.cs:39:42:39:44 | "2" | LoopUnrolling.cs:39:30:39:46 | { ..., ... } | semmle.label | successor | -| LoopUnrolling.cs:40:9:42:41 | [unroll (line 40)] foreach (... ... in ...) ... | LoopUnrolling.cs:40:21:40:21 | String x | semmle.label | non-empty | +| LoopUnrolling.cs:37:5:43:5 | {...} | LoopUnrolling.cs:38:9:38:48 | ... ...; | semmle.label | successor | +| LoopUnrolling.cs:38:9:38:48 | ... ...; | LoopUnrolling.cs:38:18:38:47 | 3 | semmle.label | successor | +| LoopUnrolling.cs:38:13:38:47 | String[] xs = ... | LoopUnrolling.cs:39:9:39:48 | ... ...; | semmle.label | successor | +| LoopUnrolling.cs:38:18:38:47 | 3 | LoopUnrolling.cs:38:18:38:47 | array creation of type String[] | semmle.label | successor | +| LoopUnrolling.cs:38:18:38:47 | array creation of type String[] | LoopUnrolling.cs:38:33:38:35 | "a" | semmle.label | successor | +| LoopUnrolling.cs:38:31:38:47 | { ..., ... } | LoopUnrolling.cs:38:13:38:47 | String[] xs = ... | semmle.label | successor | +| LoopUnrolling.cs:38:33:38:35 | "a" | LoopUnrolling.cs:38:38:38:40 | "b" | semmle.label | successor | +| LoopUnrolling.cs:38:38:38:40 | "b" | LoopUnrolling.cs:38:43:38:45 | "c" | semmle.label | successor | +| LoopUnrolling.cs:38:43:38:45 | "c" | LoopUnrolling.cs:38:31:38:47 | { ..., ... } | semmle.label | successor | +| LoopUnrolling.cs:39:9:39:48 | ... ...; | LoopUnrolling.cs:39:18:39:47 | 3 | semmle.label | successor | +| LoopUnrolling.cs:39:13:39:47 | String[] ys = ... | LoopUnrolling.cs:40:27:40:28 | access to local variable xs | semmle.label | successor | +| LoopUnrolling.cs:39:18:39:47 | 3 | LoopUnrolling.cs:39:18:39:47 | array creation of type String[] | semmle.label | successor | +| LoopUnrolling.cs:39:18:39:47 | array creation of type String[] | LoopUnrolling.cs:39:33:39:35 | "0" | semmle.label | successor | +| LoopUnrolling.cs:39:31:39:47 | { ..., ... } | LoopUnrolling.cs:39:13:39:47 | String[] ys = ... | semmle.label | successor | +| LoopUnrolling.cs:39:33:39:35 | "0" | LoopUnrolling.cs:39:38:39:40 | "1" | semmle.label | successor | +| LoopUnrolling.cs:39:38:39:40 | "1" | LoopUnrolling.cs:39:43:39:45 | "2" | semmle.label | successor | +| LoopUnrolling.cs:39:43:39:45 | "2" | LoopUnrolling.cs:39:31:39:47 | { ..., ... } | semmle.label | successor | +| LoopUnrolling.cs:40:9:42:41 | [unroll (line 40)] foreach (... ... in ...) ... | LoopUnrolling.cs:40:22:40:22 | String x | semmle.label | non-empty | | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:36:10:36:11 | exit M5 | semmle.label | empty | -| LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:40:21:40:21 | String x | semmle.label | non-empty | -| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:41:30:41:31 | access to local variable ys | semmle.label | successor | -| LoopUnrolling.cs:40:26:40:27 | access to local variable xs | LoopUnrolling.cs:40:9:42:41 | [unroll (line 40)] foreach (... ... in ...) ... | semmle.label | successor | -| LoopUnrolling.cs:41:13:42:41 | [unroll (line 41)] foreach (... ... in ...) ... | LoopUnrolling.cs:41:25:41:25 | String y | semmle.label | non-empty | +| LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:40:22:40:22 | String x | semmle.label | non-empty | +| LoopUnrolling.cs:40:22:40:22 | String x | LoopUnrolling.cs:41:31:41:32 | access to local variable ys | semmle.label | successor | +| LoopUnrolling.cs:40:27:40:28 | access to local variable xs | LoopUnrolling.cs:40:9:42:41 | [unroll (line 40)] foreach (... ... in ...) ... | semmle.label | successor | +| LoopUnrolling.cs:41:13:42:41 | [unroll (line 41)] foreach (... ... in ...) ... | LoopUnrolling.cs:41:26:41:26 | String y | semmle.label | non-empty | | LoopUnrolling.cs:41:13:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | semmle.label | empty | -| LoopUnrolling.cs:41:13:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:41:25:41:25 | String y | semmle.label | non-empty | -| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:42:17:42:41 | ...; | semmle.label | successor | -| LoopUnrolling.cs:41:30:41:31 | access to local variable ys | LoopUnrolling.cs:41:13:42:41 | [unroll (line 41)] foreach (... ... in ...) ... | semmle.label | successor | +| LoopUnrolling.cs:41:13:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:41:26:41:26 | String y | semmle.label | non-empty | +| LoopUnrolling.cs:41:26:41:26 | String y | LoopUnrolling.cs:42:17:42:41 | ...; | semmle.label | successor | +| LoopUnrolling.cs:41:31:41:32 | access to local variable ys | LoopUnrolling.cs:41:13:42:41 | [unroll (line 41)] foreach (... ... in ...) ... | semmle.label | successor | | LoopUnrolling.cs:42:17:42:40 | call to method WriteLine | LoopUnrolling.cs:41:13:42:41 | foreach (... ... in ...) ... | semmle.label | successor | | LoopUnrolling.cs:42:17:42:41 | ...; | LoopUnrolling.cs:42:35:42:35 | access to local variable x | semmle.label | successor | | LoopUnrolling.cs:42:35:42:35 | access to local variable x | LoopUnrolling.cs:42:39:42:39 | access to local variable y | semmle.label | successor | | LoopUnrolling.cs:42:35:42:39 | ... + ... | LoopUnrolling.cs:42:17:42:40 | call to method WriteLine | semmle.label | successor | | LoopUnrolling.cs:42:39:42:39 | access to local variable y | LoopUnrolling.cs:42:35:42:39 | ... + ... | semmle.label | successor | | LoopUnrolling.cs:45:10:45:11 | enter M6 | LoopUnrolling.cs:46:5:53:5 | {...} | semmle.label | successor | -| LoopUnrolling.cs:46:5:53:5 | {...} | LoopUnrolling.cs:47:9:47:47 | ... ...; | semmle.label | successor | -| LoopUnrolling.cs:47:9:47:47 | ... ...; | LoopUnrolling.cs:47:18:47:46 | array creation of type String[] | semmle.label | successor | -| LoopUnrolling.cs:47:13:47:46 | String[] xs = ... | LoopUnrolling.cs:48:26:48:27 | access to local variable xs | semmle.label | successor | -| LoopUnrolling.cs:47:18:47:46 | array creation of type String[] | LoopUnrolling.cs:47:32:47:34 | "a" | semmle.label | successor | -| LoopUnrolling.cs:47:30:47:46 | { ..., ... } | LoopUnrolling.cs:47:13:47:46 | String[] xs = ... | semmle.label | successor | -| LoopUnrolling.cs:47:32:47:34 | "a" | LoopUnrolling.cs:47:37:47:39 | "b" | semmle.label | successor | -| LoopUnrolling.cs:47:37:47:39 | "b" | LoopUnrolling.cs:47:42:47:44 | "c" | semmle.label | successor | -| LoopUnrolling.cs:47:42:47:44 | "c" | LoopUnrolling.cs:47:30:47:46 | { ..., ... } | semmle.label | successor | -| LoopUnrolling.cs:48:9:52:9 | [unroll (line 48)] foreach (... ... in ...) ... | LoopUnrolling.cs:48:21:48:21 | String x | semmle.label | non-empty | -| LoopUnrolling.cs:48:21:48:21 | String x | LoopUnrolling.cs:49:9:52:9 | {...} | semmle.label | successor | -| LoopUnrolling.cs:48:26:48:27 | access to local variable xs | LoopUnrolling.cs:48:9:52:9 | [unroll (line 48)] foreach (... ... in ...) ... | semmle.label | successor | -| LoopUnrolling.cs:49:9:52:9 | {...} | LoopUnrolling.cs:50:13:50:17 | Label: | semmle.label | successor | -| LoopUnrolling.cs:50:13:50:17 | Label: | LoopUnrolling.cs:50:20:50:40 | ...; | semmle.label | successor | -| LoopUnrolling.cs:50:20:50:39 | call to method WriteLine | LoopUnrolling.cs:51:13:51:23 | goto ...; | semmle.label | successor | -| LoopUnrolling.cs:50:20:50:40 | ...; | LoopUnrolling.cs:50:38:50:38 | access to local variable x | semmle.label | successor | -| LoopUnrolling.cs:50:38:50:38 | access to local variable x | LoopUnrolling.cs:50:20:50:39 | call to method WriteLine | semmle.label | successor | -| LoopUnrolling.cs:51:13:51:23 | goto ...; | LoopUnrolling.cs:50:13:50:17 | Label: | semmle.label | goto(Label) | +| LoopUnrolling.cs:46:5:53:5 | {...} | LoopUnrolling.cs:47:9:47:48 | ... ...; | semmle.label | successor | +| LoopUnrolling.cs:47:9:47:48 | ... ...; | LoopUnrolling.cs:47:18:47:47 | 3 | semmle.label | successor | +| LoopUnrolling.cs:47:13:47:47 | String[] xs = ... | LoopUnrolling.cs:48:27:48:28 | access to local variable xs | semmle.label | successor | +| LoopUnrolling.cs:47:18:47:47 | 3 | LoopUnrolling.cs:47:18:47:47 | array creation of type String[] | semmle.label | successor | +| LoopUnrolling.cs:47:18:47:47 | array creation of type String[] | LoopUnrolling.cs:47:33:47:35 | "a" | semmle.label | successor | +| LoopUnrolling.cs:47:31:47:47 | { ..., ... } | LoopUnrolling.cs:47:13:47:47 | String[] xs = ... | semmle.label | successor | +| LoopUnrolling.cs:47:33:47:35 | "a" | LoopUnrolling.cs:47:38:47:40 | "b" | semmle.label | successor | +| LoopUnrolling.cs:47:38:47:40 | "b" | LoopUnrolling.cs:47:43:47:45 | "c" | semmle.label | successor | +| LoopUnrolling.cs:47:43:47:45 | "c" | LoopUnrolling.cs:47:31:47:47 | { ..., ... } | semmle.label | successor | +| LoopUnrolling.cs:48:9:52:9 | [unroll (line 48)] foreach (... ... in ...) ... | LoopUnrolling.cs:48:22:48:22 | String x | semmle.label | non-empty | +| LoopUnrolling.cs:48:22:48:22 | String x | LoopUnrolling.cs:49:9:52:9 | {...} | semmle.label | successor | +| LoopUnrolling.cs:48:27:48:28 | access to local variable xs | LoopUnrolling.cs:48:9:52:9 | [unroll (line 48)] foreach (... ... in ...) ... | semmle.label | successor | +| LoopUnrolling.cs:49:9:52:9 | {...} | LoopUnrolling.cs:50:9:50:13 | Label: | semmle.label | successor | +| LoopUnrolling.cs:50:9:50:13 | Label: | LoopUnrolling.cs:50:16:50:36 | ...; | semmle.label | successor | +| LoopUnrolling.cs:50:16:50:35 | call to method WriteLine | LoopUnrolling.cs:51:13:51:23 | goto ...; | semmle.label | successor | +| LoopUnrolling.cs:50:16:50:36 | ...; | LoopUnrolling.cs:50:34:50:34 | access to local variable x | semmle.label | successor | +| LoopUnrolling.cs:50:34:50:34 | access to local variable x | LoopUnrolling.cs:50:16:50:35 | call to method WriteLine | semmle.label | successor | +| LoopUnrolling.cs:51:13:51:23 | goto ...; | LoopUnrolling.cs:50:9:50:13 | Label: | semmle.label | goto(Label) | | LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:56:5:65:5 | {...} | semmle.label | successor | -| LoopUnrolling.cs:56:5:65:5 | {...} | LoopUnrolling.cs:57:9:57:47 | ... ...; | semmle.label | successor | -| LoopUnrolling.cs:57:9:57:47 | ... ...; | LoopUnrolling.cs:57:18:57:46 | array creation of type String[] | semmle.label | successor | -| LoopUnrolling.cs:57:13:57:46 | String[] xs = ... | LoopUnrolling.cs:58:26:58:27 | access to local variable xs | semmle.label | successor | -| LoopUnrolling.cs:57:18:57:46 | array creation of type String[] | LoopUnrolling.cs:57:32:57:34 | "a" | semmle.label | successor | -| LoopUnrolling.cs:57:30:57:46 | { ..., ... } | LoopUnrolling.cs:57:13:57:46 | String[] xs = ... | semmle.label | successor | -| LoopUnrolling.cs:57:32:57:34 | "a" | LoopUnrolling.cs:57:37:57:39 | "b" | semmle.label | successor | -| LoopUnrolling.cs:57:37:57:39 | "b" | LoopUnrolling.cs:57:42:57:44 | "c" | semmle.label | successor | -| LoopUnrolling.cs:57:42:57:44 | "c" | LoopUnrolling.cs:57:30:57:46 | { ..., ... } | semmle.label | successor | +| LoopUnrolling.cs:56:5:65:5 | {...} | LoopUnrolling.cs:57:9:57:48 | ... ...; | semmle.label | successor | +| LoopUnrolling.cs:57:9:57:48 | ... ...; | LoopUnrolling.cs:57:18:57:47 | 3 | semmle.label | successor | +| LoopUnrolling.cs:57:13:57:47 | String[] xs = ... | LoopUnrolling.cs:58:27:58:28 | access to local variable xs | semmle.label | successor | +| LoopUnrolling.cs:57:18:57:47 | 3 | LoopUnrolling.cs:57:18:57:47 | array creation of type String[] | semmle.label | successor | +| LoopUnrolling.cs:57:18:57:47 | array creation of type String[] | LoopUnrolling.cs:57:33:57:35 | "a" | semmle.label | successor | +| LoopUnrolling.cs:57:31:57:47 | { ..., ... } | LoopUnrolling.cs:57:13:57:47 | String[] xs = ... | semmle.label | successor | +| LoopUnrolling.cs:57:33:57:35 | "a" | LoopUnrolling.cs:57:38:57:40 | "b" | semmle.label | successor | +| LoopUnrolling.cs:57:38:57:40 | "b" | LoopUnrolling.cs:57:43:57:45 | "c" | semmle.label | successor | +| LoopUnrolling.cs:57:43:57:45 | "c" | LoopUnrolling.cs:57:31:57:47 | { ..., ... } | semmle.label | successor | | LoopUnrolling.cs:58:9:64:9 | [b (line 55): false] foreach (... ... in ...) ... | LoopUnrolling.cs:55:10:55:11 | exit M7 | semmle.label | empty | -| LoopUnrolling.cs:58:9:64:9 | [b (line 55): false] foreach (... ... in ...) ... | LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | semmle.label | non-empty | +| LoopUnrolling.cs:58:9:64:9 | [b (line 55): false] foreach (... ... in ...) ... | LoopUnrolling.cs:58:22:58:22 | [b (line 55): false] String x | semmle.label | non-empty | | LoopUnrolling.cs:58:9:64:9 | [b (line 55): true] foreach (... ... in ...) ... | LoopUnrolling.cs:55:10:55:11 | exit M7 | semmle.label | empty | -| LoopUnrolling.cs:58:9:64:9 | [b (line 55): true] foreach (... ... in ...) ... | LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | semmle.label | non-empty | -| LoopUnrolling.cs:58:9:64:9 | [unroll (line 58)] foreach (... ... in ...) ... | LoopUnrolling.cs:58:21:58:21 | String x | semmle.label | non-empty | -| LoopUnrolling.cs:58:21:58:21 | String x | LoopUnrolling.cs:59:9:64:9 | {...} | semmle.label | successor | -| LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | LoopUnrolling.cs:59:9:64:9 | [b (line 55): false] {...} | semmle.label | successor | -| LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | LoopUnrolling.cs:59:9:64:9 | [b (line 55): true] {...} | semmle.label | successor | -| LoopUnrolling.cs:58:26:58:27 | access to local variable xs | LoopUnrolling.cs:58:9:64:9 | [unroll (line 58)] foreach (... ... in ...) ... | semmle.label | successor | +| LoopUnrolling.cs:58:9:64:9 | [b (line 55): true] foreach (... ... in ...) ... | LoopUnrolling.cs:58:22:58:22 | [b (line 55): true] String x | semmle.label | non-empty | +| LoopUnrolling.cs:58:9:64:9 | [unroll (line 58)] foreach (... ... in ...) ... | LoopUnrolling.cs:58:22:58:22 | String x | semmle.label | non-empty | +| LoopUnrolling.cs:58:22:58:22 | String x | LoopUnrolling.cs:59:9:64:9 | {...} | semmle.label | successor | +| LoopUnrolling.cs:58:22:58:22 | [b (line 55): false] String x | LoopUnrolling.cs:59:9:64:9 | [b (line 55): false] {...} | semmle.label | successor | +| LoopUnrolling.cs:58:22:58:22 | [b (line 55): true] String x | LoopUnrolling.cs:59:9:64:9 | [b (line 55): true] {...} | semmle.label | successor | +| LoopUnrolling.cs:58:27:58:28 | access to local variable xs | LoopUnrolling.cs:58:9:64:9 | [unroll (line 58)] foreach (... ... in ...) ... | semmle.label | successor | | LoopUnrolling.cs:59:9:64:9 | [b (line 55): false] {...} | LoopUnrolling.cs:60:13:61:37 | [b (line 55): false] if (...) ... | semmle.label | successor | | LoopUnrolling.cs:59:9:64:9 | [b (line 55): true] {...} | LoopUnrolling.cs:60:13:61:37 | [b (line 55): true] if (...) ... | semmle.label | successor | | LoopUnrolling.cs:59:9:64:9 | {...} | LoopUnrolling.cs:60:13:61:37 | if (...) ... | semmle.label | successor | @@ -2239,15 +2845,220 @@ | LoopUnrolling.cs:69:14:69:23 | call to method Any | LoopUnrolling.cs:71:9:71:21 | ...; | semmle.label | true | | LoopUnrolling.cs:70:13:70:19 | return ...; | LoopUnrolling.cs:67:10:67:11 | exit M8 | semmle.label | return | | LoopUnrolling.cs:71:9:71:12 | access to parameter args | LoopUnrolling.cs:71:9:71:20 | call to method Clear | semmle.label | successor | -| LoopUnrolling.cs:71:9:71:20 | call to method Clear | LoopUnrolling.cs:72:28:72:31 | access to parameter args | semmle.label | successor | +| LoopUnrolling.cs:71:9:71:20 | call to method Clear | LoopUnrolling.cs:72:29:72:32 | access to parameter args | semmle.label | successor | | LoopUnrolling.cs:71:9:71:21 | ...; | LoopUnrolling.cs:71:9:71:12 | access to parameter args | semmle.label | successor | -| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:67:10:67:11 | exit M8 | semmle.label | empty | -| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:72:21:72:23 | String arg | semmle.label | non-empty | -| LoopUnrolling.cs:72:21:72:23 | String arg | LoopUnrolling.cs:73:13:73:35 | ...; | semmle.label | successor | -| LoopUnrolling.cs:72:28:72:31 | access to parameter args | LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | semmle.label | successor | -| LoopUnrolling.cs:73:13:73:34 | call to method WriteLine | LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | semmle.label | successor | -| LoopUnrolling.cs:73:13:73:35 | ...; | LoopUnrolling.cs:73:31:73:33 | access to local variable arg | semmle.label | successor | -| LoopUnrolling.cs:73:31:73:33 | access to local variable arg | LoopUnrolling.cs:73:13:73:34 | call to method WriteLine | semmle.label | successor | +| LoopUnrolling.cs:72:9:73:35 | [skip (line 72)] foreach (... ... in ...) ... | LoopUnrolling.cs:67:10:67:11 | exit M8 | semmle.label | empty | +| LoopUnrolling.cs:72:29:72:32 | access to parameter args | LoopUnrolling.cs:72:9:73:35 | [skip (line 72)] foreach (... ... in ...) ... | semmle.label | successor | +| LoopUnrolling.cs:76:10:76:11 | enter M9 | LoopUnrolling.cs:77:5:83:5 | {...} | semmle.label | successor | +| LoopUnrolling.cs:77:5:83:5 | {...} | LoopUnrolling.cs:78:9:78:34 | ... ...; | semmle.label | successor | +| LoopUnrolling.cs:78:9:78:34 | ... ...; | LoopUnrolling.cs:78:29:78:29 | 2 | semmle.label | successor | +| LoopUnrolling.cs:78:13:78:33 | String[,] xs = ... | LoopUnrolling.cs:79:27:79:28 | access to local variable xs | semmle.label | successor | +| LoopUnrolling.cs:78:18:78:33 | array creation of type String[,] | LoopUnrolling.cs:78:13:78:33 | String[,] xs = ... | semmle.label | successor | +| LoopUnrolling.cs:78:29:78:29 | 2 | LoopUnrolling.cs:78:32:78:32 | 0 | semmle.label | successor | +| LoopUnrolling.cs:78:32:78:32 | 0 | LoopUnrolling.cs:78:18:78:33 | array creation of type String[,] | semmle.label | successor | +| LoopUnrolling.cs:79:9:82:9 | [skip (line 79)] foreach (... ... in ...) ... | LoopUnrolling.cs:76:10:76:11 | exit M9 | semmle.label | empty | +| LoopUnrolling.cs:79:27:79:28 | access to local variable xs | LoopUnrolling.cs:79:9:82:9 | [skip (line 79)] foreach (... ... in ...) ... | semmle.label | successor | +| LoopUnrolling.cs:85:10:85:12 | enter M10 | LoopUnrolling.cs:86:5:92:5 | {...} | semmle.label | successor | +| LoopUnrolling.cs:86:5:92:5 | {...} | LoopUnrolling.cs:87:9:87:34 | ... ...; | semmle.label | successor | +| LoopUnrolling.cs:87:9:87:34 | ... ...; | LoopUnrolling.cs:87:29:87:29 | 0 | semmle.label | successor | +| LoopUnrolling.cs:87:13:87:33 | String[,] xs = ... | LoopUnrolling.cs:88:27:88:28 | access to local variable xs | semmle.label | successor | +| LoopUnrolling.cs:87:18:87:33 | array creation of type String[,] | LoopUnrolling.cs:87:13:87:33 | String[,] xs = ... | semmle.label | successor | +| LoopUnrolling.cs:87:29:87:29 | 0 | LoopUnrolling.cs:87:32:87:32 | 2 | semmle.label | successor | +| LoopUnrolling.cs:87:32:87:32 | 2 | LoopUnrolling.cs:87:18:87:33 | array creation of type String[,] | semmle.label | successor | +| LoopUnrolling.cs:88:9:91:9 | [skip (line 88)] foreach (... ... in ...) ... | LoopUnrolling.cs:85:10:85:12 | exit M10 | semmle.label | empty | +| LoopUnrolling.cs:88:27:88:28 | access to local variable xs | LoopUnrolling.cs:88:9:91:9 | [skip (line 88)] foreach (... ... in ...) ... | semmle.label | successor | +| LoopUnrolling.cs:94:10:94:12 | enter M11 | LoopUnrolling.cs:95:5:101:5 | {...} | semmle.label | successor | +| LoopUnrolling.cs:95:5:101:5 | {...} | LoopUnrolling.cs:96:9:96:34 | ... ...; | semmle.label | successor | +| LoopUnrolling.cs:96:9:96:34 | ... ...; | LoopUnrolling.cs:96:29:96:29 | 2 | semmle.label | successor | +| LoopUnrolling.cs:96:13:96:33 | String[,] xs = ... | LoopUnrolling.cs:97:27:97:28 | access to local variable xs | semmle.label | successor | +| LoopUnrolling.cs:96:18:96:33 | array creation of type String[,] | LoopUnrolling.cs:96:13:96:33 | String[,] xs = ... | semmle.label | successor | +| LoopUnrolling.cs:96:29:96:29 | 2 | LoopUnrolling.cs:96:32:96:32 | 2 | semmle.label | successor | +| LoopUnrolling.cs:96:32:96:32 | 2 | LoopUnrolling.cs:96:18:96:33 | array creation of type String[,] | semmle.label | successor | +| LoopUnrolling.cs:97:9:100:9 | [unroll (line 97)] foreach (... ... in ...) ... | LoopUnrolling.cs:97:22:97:22 | String x | semmle.label | non-empty | +| LoopUnrolling.cs:97:9:100:9 | foreach (... ... in ...) ... | LoopUnrolling.cs:94:10:94:12 | exit M11 | semmle.label | empty | +| LoopUnrolling.cs:97:9:100:9 | foreach (... ... in ...) ... | LoopUnrolling.cs:97:22:97:22 | String x | semmle.label | non-empty | +| LoopUnrolling.cs:97:22:97:22 | String x | LoopUnrolling.cs:98:9:100:9 | {...} | semmle.label | successor | +| LoopUnrolling.cs:97:27:97:28 | access to local variable xs | LoopUnrolling.cs:97:9:100:9 | [unroll (line 97)] foreach (... ... in ...) ... | semmle.label | successor | +| LoopUnrolling.cs:98:9:100:9 | {...} | LoopUnrolling.cs:99:13:99:33 | ...; | semmle.label | successor | +| LoopUnrolling.cs:99:13:99:32 | call to method WriteLine | LoopUnrolling.cs:97:9:100:9 | foreach (... ... in ...) ... | semmle.label | successor | +| LoopUnrolling.cs:99:13:99:33 | ...; | LoopUnrolling.cs:99:31:99:31 | access to local variable x | semmle.label | successor | +| LoopUnrolling.cs:99:31:99:31 | access to local variable x | LoopUnrolling.cs:99:13:99:32 | call to method WriteLine | semmle.label | successor | +| MultiImplementationA.cs:6:22:6:31 | enter get_P1 | MultiImplementationA.cs:6:28:6:31 | null | semmle.label | successor | +| MultiImplementationA.cs:6:22:6:31 | enter get_P1 | MultiImplementationB.cs:3:22:3:22 | 0 | semmle.label | successor | +| MultiImplementationA.cs:6:22:6:31 | throw ... | MultiImplementationA.cs:6:22:6:31 | exit get_P1 | semmle.label | exception(NullReferenceException) | +| MultiImplementationA.cs:6:22:6:31 | throw ... | MultiImplementationB.cs:3:22:3:22 | exit get_P1 | semmle.label | exception(NullReferenceException) | +| MultiImplementationA.cs:6:28:6:31 | null | MultiImplementationA.cs:6:22:6:31 | throw ... | semmle.label | successor | +| MultiImplementationA.cs:7:21:7:23 | enter get_P2 | MultiImplementationA.cs:7:25:7:39 | {...} | semmle.label | successor | +| MultiImplementationA.cs:7:21:7:23 | enter get_P2 | MultiImplementationB.cs:4:25:4:37 | {...} | semmle.label | successor | +| MultiImplementationA.cs:7:25:7:39 | {...} | MultiImplementationA.cs:7:33:7:36 | null | semmle.label | successor | +| MultiImplementationA.cs:7:27:7:37 | throw ...; | MultiImplementationA.cs:7:21:7:23 | exit get_P2 | semmle.label | exception(NullReferenceException) | +| MultiImplementationA.cs:7:27:7:37 | throw ...; | MultiImplementationB.cs:4:21:4:23 | exit get_P2 | semmle.label | exception(NullReferenceException) | +| MultiImplementationA.cs:7:33:7:36 | null | MultiImplementationA.cs:7:27:7:37 | throw ...; | semmle.label | successor | +| MultiImplementationA.cs:7:41:7:43 | enter set_P2 | MultiImplementationA.cs:7:45:7:59 | {...} | semmle.label | successor | +| MultiImplementationA.cs:7:41:7:43 | enter set_P2 | MultiImplementationB.cs:4:43:4:45 | {...} | semmle.label | successor | +| MultiImplementationA.cs:7:45:7:59 | {...} | MultiImplementationA.cs:7:53:7:56 | null | semmle.label | successor | +| MultiImplementationA.cs:7:47:7:57 | throw ...; | MultiImplementationA.cs:7:41:7:43 | exit set_P2 | semmle.label | exception(NullReferenceException) | +| MultiImplementationA.cs:7:47:7:57 | throw ...; | MultiImplementationB.cs:4:39:4:41 | exit set_P2 | semmle.label | exception(NullReferenceException) | +| MultiImplementationA.cs:7:53:7:56 | null | MultiImplementationA.cs:7:47:7:57 | throw ...; | semmle.label | successor | +| MultiImplementationA.cs:8:16:8:16 | enter M | MultiImplementationA.cs:8:29:8:32 | null | semmle.label | successor | +| MultiImplementationA.cs:8:16:8:16 | enter M | MultiImplementationB.cs:5:23:5:23 | 2 | semmle.label | successor | +| MultiImplementationA.cs:8:23:8:32 | throw ... | MultiImplementationA.cs:8:16:8:16 | exit M | semmle.label | exception(NullReferenceException) | +| MultiImplementationA.cs:8:23:8:32 | throw ... | MultiImplementationB.cs:5:16:5:16 | exit M | semmle.label | exception(NullReferenceException) | +| MultiImplementationA.cs:8:29:8:32 | null | MultiImplementationA.cs:8:23:8:32 | throw ... | semmle.label | successor | +| MultiImplementationA.cs:13:16:13:16 | this access | MultiImplementationA.cs:13:20:13:20 | 0 | semmle.label | successor | +| MultiImplementationA.cs:13:16:13:20 | ... = ... | MultiImplementationA.cs:13:16:13:16 | this access | semmle.label | successor | +| MultiImplementationA.cs:13:16:13:20 | ... = ... | MultiImplementationA.cs:24:16:24:16 | this access | semmle.label | successor | +| MultiImplementationA.cs:13:16:13:20 | ... = ... | MultiImplementationB.cs:11:16:11:16 | this access | semmle.label | successor | +| MultiImplementationA.cs:13:16:13:20 | ... = ... | MultiImplementationB.cs:22:16:22:16 | this access | semmle.label | successor | +| MultiImplementationA.cs:13:20:13:20 | 0 | MultiImplementationA.cs:13:16:13:20 | ... = ... | semmle.label | successor | +| MultiImplementationA.cs:14:31:14:31 | access to parameter i | MultiImplementationA.cs:14:31:14:31 | exit get_Item | semmle.label | successor | +| MultiImplementationA.cs:14:31:14:31 | access to parameter i | MultiImplementationB.cs:12:31:12:40 | exit get_Item | semmle.label | successor | +| MultiImplementationA.cs:14:31:14:31 | enter get_Item | MultiImplementationA.cs:14:31:14:31 | access to parameter i | semmle.label | successor | +| MultiImplementationA.cs:14:31:14:31 | enter get_Item | MultiImplementationB.cs:12:37:12:40 | null | semmle.label | successor | +| MultiImplementationA.cs:15:36:15:38 | enter get_Item | MultiImplementationA.cs:15:40:15:52 | {...} | semmle.label | successor | +| MultiImplementationA.cs:15:36:15:38 | enter get_Item | MultiImplementationB.cs:13:40:13:54 | {...} | semmle.label | successor | +| MultiImplementationA.cs:15:40:15:52 | {...} | MultiImplementationA.cs:15:49:15:49 | access to parameter s | semmle.label | successor | +| MultiImplementationA.cs:15:42:15:50 | return ...; | MultiImplementationA.cs:15:36:15:38 | exit get_Item | semmle.label | return | +| MultiImplementationA.cs:15:42:15:50 | return ...; | MultiImplementationB.cs:13:36:13:38 | exit get_Item | semmle.label | return | +| MultiImplementationA.cs:15:49:15:49 | access to parameter s | MultiImplementationA.cs:15:42:15:50 | return ...; | semmle.label | successor | +| MultiImplementationA.cs:15:54:15:56 | enter set_Item | MultiImplementationA.cs:15:58:15:60 | {...} | semmle.label | successor | +| MultiImplementationA.cs:15:54:15:56 | enter set_Item | MultiImplementationB.cs:13:60:13:62 | {...} | semmle.label | successor | +| MultiImplementationA.cs:15:58:15:60 | {...} | MultiImplementationA.cs:15:54:15:56 | exit set_Item | semmle.label | successor | +| MultiImplementationA.cs:15:58:15:60 | {...} | MultiImplementationB.cs:13:56:13:58 | exit set_Item | semmle.label | successor | +| MultiImplementationA.cs:16:17:16:18 | enter M1 | MultiImplementationA.cs:17:5:19:5 | {...} | semmle.label | successor | +| MultiImplementationA.cs:16:17:16:18 | enter M1 | MultiImplementationB.cs:15:5:17:5 | {...} | semmle.label | successor | +| MultiImplementationA.cs:17:5:19:5 | {...} | MultiImplementationA.cs:18:9:18:22 | M2(...) | semmle.label | successor | +| MultiImplementationA.cs:18:9:18:22 | M2(...) | MultiImplementationA.cs:16:17:16:18 | exit M1 | semmle.label | successor | +| MultiImplementationA.cs:18:9:18:22 | M2(...) | MultiImplementationB.cs:14:17:14:18 | exit M1 | semmle.label | successor | +| MultiImplementationA.cs:18:9:18:22 | enter M2 | MultiImplementationA.cs:18:21:18:21 | 0 | semmle.label | successor | +| MultiImplementationA.cs:18:21:18:21 | 0 | MultiImplementationA.cs:18:9:18:22 | exit M2 | semmle.label | successor | +| MultiImplementationA.cs:20:12:20:13 | enter C2 | MultiImplementationA.cs:13:16:13:16 | this access | semmle.label | successor | +| MultiImplementationA.cs:20:12:20:13 | enter C2 | MultiImplementationB.cs:11:16:11:16 | this access | semmle.label | successor | +| MultiImplementationA.cs:20:22:20:31 | {...} | MultiImplementationA.cs:20:24:20:29 | ...; | semmle.label | successor | +| MultiImplementationA.cs:20:24:20:24 | this access | MultiImplementationA.cs:20:28:20:28 | access to parameter i | semmle.label | successor | +| MultiImplementationA.cs:20:24:20:28 | ... = ... | MultiImplementationA.cs:20:12:20:13 | exit C2 | semmle.label | successor | +| MultiImplementationA.cs:20:24:20:28 | ... = ... | MultiImplementationB.cs:18:12:18:13 | exit C2 | semmle.label | successor | +| MultiImplementationA.cs:20:24:20:29 | ...; | MultiImplementationA.cs:20:24:20:24 | this access | semmle.label | successor | +| MultiImplementationA.cs:20:28:20:28 | access to parameter i | MultiImplementationA.cs:20:24:20:28 | ... = ... | semmle.label | successor | +| MultiImplementationA.cs:21:12:21:13 | enter C2 | MultiImplementationA.cs:21:24:21:24 | 0 | semmle.label | successor | +| MultiImplementationA.cs:21:12:21:13 | enter C2 | MultiImplementationB.cs:19:24:19:24 | 1 | semmle.label | successor | +| MultiImplementationA.cs:21:19:21:22 | call to constructor C2 | MultiImplementationA.cs:21:27:21:29 | {...} | semmle.label | successor | +| MultiImplementationA.cs:21:19:21:22 | call to constructor C2 | MultiImplementationB.cs:19:27:19:29 | {...} | semmle.label | successor | +| MultiImplementationA.cs:21:24:21:24 | 0 | MultiImplementationA.cs:21:19:21:22 | call to constructor C2 | semmle.label | successor | +| MultiImplementationA.cs:21:27:21:29 | {...} | MultiImplementationA.cs:21:12:21:13 | exit C2 | semmle.label | successor | +| MultiImplementationA.cs:21:27:21:29 | {...} | MultiImplementationB.cs:19:12:19:13 | exit C2 | semmle.label | successor | +| MultiImplementationA.cs:22:6:22:7 | enter ~C2 | MultiImplementationA.cs:22:11:22:13 | {...} | semmle.label | successor | +| MultiImplementationA.cs:22:6:22:7 | enter ~C2 | MultiImplementationB.cs:20:11:20:25 | {...} | semmle.label | successor | +| MultiImplementationA.cs:22:11:22:13 | {...} | MultiImplementationA.cs:22:6:22:7 | exit ~C2 | semmle.label | successor | +| MultiImplementationA.cs:22:11:22:13 | {...} | MultiImplementationB.cs:20:6:20:7 | exit ~C2 | semmle.label | successor | +| MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | MultiImplementationA.cs:23:50:23:53 | null | semmle.label | successor | +| MultiImplementationA.cs:23:28:23:35 | enter implicit conversion | MultiImplementationB.cs:21:56:21:59 | null | semmle.label | successor | +| MultiImplementationA.cs:23:50:23:53 | null | MultiImplementationA.cs:23:28:23:35 | exit implicit conversion | semmle.label | successor | +| MultiImplementationA.cs:23:50:23:53 | null | MultiImplementationB.cs:21:28:21:35 | exit implicit conversion | semmle.label | successor | +| MultiImplementationA.cs:24:16:24:16 | access to property P | MultiImplementationA.cs:24:32:24:34 | ... = ... | semmle.label | successor | +| MultiImplementationA.cs:24:16:24:16 | this access | MultiImplementationA.cs:24:34:24:34 | 0 | semmle.label | successor | +| MultiImplementationA.cs:24:32:24:34 | ... = ... | MultiImplementationA.cs:20:22:20:31 | {...} | semmle.label | successor | +| MultiImplementationA.cs:24:32:24:34 | ... = ... | MultiImplementationA.cs:24:16:24:16 | this access | semmle.label | successor | +| MultiImplementationA.cs:24:32:24:34 | ... = ... | MultiImplementationB.cs:18:22:18:36 | {...} | semmle.label | successor | +| MultiImplementationA.cs:24:32:24:34 | ... = ... | MultiImplementationB.cs:22:16:22:16 | this access | semmle.label | successor | +| MultiImplementationA.cs:24:34:24:34 | 0 | MultiImplementationA.cs:24:16:24:16 | access to property P | semmle.label | successor | +| MultiImplementationA.cs:30:21:30:23 | enter get_P3 | MultiImplementationA.cs:30:34:30:37 | null | semmle.label | successor | +| MultiImplementationA.cs:30:28:30:37 | throw ... | MultiImplementationA.cs:30:21:30:23 | exit get_P3 | semmle.label | exception(NullReferenceException) | +| MultiImplementationA.cs:30:28:30:37 | throw ... | MultiImplementationB.cs:27:21:27:23 | exit get_P3 | semmle.label | exception(NullReferenceException) | +| MultiImplementationA.cs:30:34:30:37 | null | MultiImplementationA.cs:30:28:30:37 | throw ... | semmle.label | successor | +| MultiImplementationA.cs:36:9:36:10 | enter M1 | MultiImplementationA.cs:36:14:36:28 | {...} | semmle.label | successor | +| MultiImplementationA.cs:36:9:36:10 | enter M1 | MultiImplementationB.cs:32:17:32:17 | 0 | semmle.label | successor | +| MultiImplementationA.cs:36:14:36:28 | {...} | MultiImplementationA.cs:36:22:36:25 | null | semmle.label | successor | +| MultiImplementationA.cs:36:16:36:26 | throw ...; | MultiImplementationA.cs:36:9:36:10 | exit M1 | semmle.label | exception(NullReferenceException) | +| MultiImplementationA.cs:36:16:36:26 | throw ...; | MultiImplementationB.cs:32:9:32:10 | exit M1 | semmle.label | exception(NullReferenceException) | +| MultiImplementationA.cs:36:22:36:25 | null | MultiImplementationA.cs:36:16:36:26 | throw ...; | semmle.label | successor | +| MultiImplementationA.cs:37:9:37:10 | enter M2 | MultiImplementationA.cs:37:14:37:28 | {...} | semmle.label | successor | +| MultiImplementationA.cs:37:14:37:28 | {...} | MultiImplementationA.cs:37:22:37:25 | null | semmle.label | successor | +| MultiImplementationA.cs:37:16:37:26 | throw ...; | MultiImplementationA.cs:37:9:37:10 | exit M2 | semmle.label | exception(NullReferenceException) | +| MultiImplementationA.cs:37:22:37:25 | null | MultiImplementationA.cs:37:16:37:26 | throw ...; | semmle.label | successor | +| MultiImplementationB.cs:3:22:3:22 | 0 | MultiImplementationA.cs:6:22:6:31 | exit get_P1 | semmle.label | successor | +| MultiImplementationB.cs:3:22:3:22 | 0 | MultiImplementationB.cs:3:22:3:22 | exit get_P1 | semmle.label | successor | +| MultiImplementationB.cs:3:22:3:22 | enter get_P1 | MultiImplementationA.cs:6:28:6:31 | null | semmle.label | successor | +| MultiImplementationB.cs:3:22:3:22 | enter get_P1 | MultiImplementationB.cs:3:22:3:22 | 0 | semmle.label | successor | +| MultiImplementationB.cs:4:21:4:23 | enter get_P2 | MultiImplementationA.cs:7:25:7:39 | {...} | semmle.label | successor | +| MultiImplementationB.cs:4:21:4:23 | enter get_P2 | MultiImplementationB.cs:4:25:4:37 | {...} | semmle.label | successor | +| MultiImplementationB.cs:4:25:4:37 | {...} | MultiImplementationB.cs:4:34:4:34 | 1 | semmle.label | successor | +| MultiImplementationB.cs:4:27:4:35 | return ...; | MultiImplementationA.cs:7:21:7:23 | exit get_P2 | semmle.label | return | +| MultiImplementationB.cs:4:27:4:35 | return ...; | MultiImplementationB.cs:4:21:4:23 | exit get_P2 | semmle.label | return | +| MultiImplementationB.cs:4:34:4:34 | 1 | MultiImplementationB.cs:4:27:4:35 | return ...; | semmle.label | successor | +| MultiImplementationB.cs:4:39:4:41 | enter set_P2 | MultiImplementationA.cs:7:45:7:59 | {...} | semmle.label | successor | +| MultiImplementationB.cs:4:39:4:41 | enter set_P2 | MultiImplementationB.cs:4:43:4:45 | {...} | semmle.label | successor | +| MultiImplementationB.cs:4:43:4:45 | {...} | MultiImplementationA.cs:7:41:7:43 | exit set_P2 | semmle.label | successor | +| MultiImplementationB.cs:4:43:4:45 | {...} | MultiImplementationB.cs:4:39:4:41 | exit set_P2 | semmle.label | successor | +| MultiImplementationB.cs:5:16:5:16 | enter M | MultiImplementationA.cs:8:29:8:32 | null | semmle.label | successor | +| MultiImplementationB.cs:5:16:5:16 | enter M | MultiImplementationB.cs:5:23:5:23 | 2 | semmle.label | successor | +| MultiImplementationB.cs:5:23:5:23 | 2 | MultiImplementationA.cs:8:16:8:16 | exit M | semmle.label | successor | +| MultiImplementationB.cs:5:23:5:23 | 2 | MultiImplementationB.cs:5:16:5:16 | exit M | semmle.label | successor | +| MultiImplementationB.cs:11:16:11:16 | this access | MultiImplementationB.cs:11:20:11:20 | 1 | semmle.label | successor | +| MultiImplementationB.cs:11:16:11:20 | ... = ... | MultiImplementationA.cs:13:16:13:16 | this access | semmle.label | successor | +| MultiImplementationB.cs:11:16:11:20 | ... = ... | MultiImplementationA.cs:24:16:24:16 | this access | semmle.label | successor | +| MultiImplementationB.cs:11:16:11:20 | ... = ... | MultiImplementationB.cs:11:16:11:16 | this access | semmle.label | successor | +| MultiImplementationB.cs:11:16:11:20 | ... = ... | MultiImplementationB.cs:22:16:22:16 | this access | semmle.label | successor | +| MultiImplementationB.cs:11:20:11:20 | 1 | MultiImplementationB.cs:11:16:11:20 | ... = ... | semmle.label | successor | +| MultiImplementationB.cs:12:31:12:40 | enter get_Item | MultiImplementationA.cs:14:31:14:31 | access to parameter i | semmle.label | successor | +| MultiImplementationB.cs:12:31:12:40 | enter get_Item | MultiImplementationB.cs:12:37:12:40 | null | semmle.label | successor | +| MultiImplementationB.cs:12:31:12:40 | throw ... | MultiImplementationA.cs:14:31:14:31 | exit get_Item | semmle.label | exception(NullReferenceException) | +| MultiImplementationB.cs:12:31:12:40 | throw ... | MultiImplementationB.cs:12:31:12:40 | exit get_Item | semmle.label | exception(NullReferenceException) | +| MultiImplementationB.cs:12:37:12:40 | null | MultiImplementationB.cs:12:31:12:40 | throw ... | semmle.label | successor | +| MultiImplementationB.cs:13:36:13:38 | enter get_Item | MultiImplementationA.cs:15:40:15:52 | {...} | semmle.label | successor | +| MultiImplementationB.cs:13:36:13:38 | enter get_Item | MultiImplementationB.cs:13:40:13:54 | {...} | semmle.label | successor | +| MultiImplementationB.cs:13:40:13:54 | {...} | MultiImplementationB.cs:13:48:13:51 | null | semmle.label | successor | +| MultiImplementationB.cs:13:42:13:52 | throw ...; | MultiImplementationA.cs:15:36:15:38 | exit get_Item | semmle.label | exception(NullReferenceException) | +| MultiImplementationB.cs:13:42:13:52 | throw ...; | MultiImplementationB.cs:13:36:13:38 | exit get_Item | semmle.label | exception(NullReferenceException) | +| MultiImplementationB.cs:13:48:13:51 | null | MultiImplementationB.cs:13:42:13:52 | throw ...; | semmle.label | successor | +| MultiImplementationB.cs:13:56:13:58 | enter set_Item | MultiImplementationA.cs:15:58:15:60 | {...} | semmle.label | successor | +| MultiImplementationB.cs:13:56:13:58 | enter set_Item | MultiImplementationB.cs:13:60:13:62 | {...} | semmle.label | successor | +| MultiImplementationB.cs:13:60:13:62 | {...} | MultiImplementationA.cs:15:54:15:56 | exit set_Item | semmle.label | successor | +| MultiImplementationB.cs:13:60:13:62 | {...} | MultiImplementationB.cs:13:56:13:58 | exit set_Item | semmle.label | successor | +| MultiImplementationB.cs:14:17:14:18 | enter M1 | MultiImplementationA.cs:17:5:19:5 | {...} | semmle.label | successor | +| MultiImplementationB.cs:14:17:14:18 | enter M1 | MultiImplementationB.cs:15:5:17:5 | {...} | semmle.label | successor | +| MultiImplementationB.cs:15:5:17:5 | {...} | MultiImplementationB.cs:16:9:16:31 | M2(...) | semmle.label | successor | +| MultiImplementationB.cs:16:9:16:31 | M2(...) | MultiImplementationA.cs:16:17:16:18 | exit M1 | semmle.label | successor | +| MultiImplementationB.cs:16:9:16:31 | M2(...) | MultiImplementationB.cs:14:17:14:18 | exit M1 | semmle.label | successor | +| MultiImplementationB.cs:16:9:16:31 | enter M2 | MultiImplementationB.cs:16:27:16:30 | null | semmle.label | successor | +| MultiImplementationB.cs:16:21:16:30 | throw ... | MultiImplementationB.cs:16:9:16:31 | exit M2 | semmle.label | exception(NullReferenceException) | +| MultiImplementationB.cs:16:27:16:30 | null | MultiImplementationB.cs:16:21:16:30 | throw ... | semmle.label | successor | +| MultiImplementationB.cs:18:12:18:13 | enter C2 | MultiImplementationA.cs:13:16:13:16 | this access | semmle.label | successor | +| MultiImplementationB.cs:18:12:18:13 | enter C2 | MultiImplementationB.cs:11:16:11:16 | this access | semmle.label | successor | +| MultiImplementationB.cs:18:22:18:36 | {...} | MultiImplementationB.cs:18:30:18:33 | null | semmle.label | successor | +| MultiImplementationB.cs:18:24:18:34 | throw ...; | MultiImplementationA.cs:20:12:20:13 | exit C2 | semmle.label | exception(NullReferenceException) | +| MultiImplementationB.cs:18:24:18:34 | throw ...; | MultiImplementationB.cs:18:12:18:13 | exit C2 | semmle.label | exception(NullReferenceException) | +| MultiImplementationB.cs:18:30:18:33 | null | MultiImplementationB.cs:18:24:18:34 | throw ...; | semmle.label | successor | +| MultiImplementationB.cs:19:12:19:13 | enter C2 | MultiImplementationA.cs:21:24:21:24 | 0 | semmle.label | successor | +| MultiImplementationB.cs:19:12:19:13 | enter C2 | MultiImplementationB.cs:19:24:19:24 | 1 | semmle.label | successor | +| MultiImplementationB.cs:19:19:19:22 | call to constructor C2 | MultiImplementationA.cs:21:27:21:29 | {...} | semmle.label | successor | +| MultiImplementationB.cs:19:19:19:22 | call to constructor C2 | MultiImplementationB.cs:19:27:19:29 | {...} | semmle.label | successor | +| MultiImplementationB.cs:19:24:19:24 | 1 | MultiImplementationB.cs:19:19:19:22 | call to constructor C2 | semmle.label | successor | +| MultiImplementationB.cs:19:27:19:29 | {...} | MultiImplementationA.cs:21:12:21:13 | exit C2 | semmle.label | successor | +| MultiImplementationB.cs:19:27:19:29 | {...} | MultiImplementationB.cs:19:12:19:13 | exit C2 | semmle.label | successor | +| MultiImplementationB.cs:20:6:20:7 | enter ~C2 | MultiImplementationA.cs:22:11:22:13 | {...} | semmle.label | successor | +| MultiImplementationB.cs:20:6:20:7 | enter ~C2 | MultiImplementationB.cs:20:11:20:25 | {...} | semmle.label | successor | +| MultiImplementationB.cs:20:11:20:25 | {...} | MultiImplementationB.cs:20:19:20:22 | null | semmle.label | successor | +| MultiImplementationB.cs:20:13:20:23 | throw ...; | MultiImplementationA.cs:22:6:22:7 | exit ~C2 | semmle.label | exception(NullReferenceException) | +| MultiImplementationB.cs:20:13:20:23 | throw ...; | MultiImplementationB.cs:20:6:20:7 | exit ~C2 | semmle.label | exception(NullReferenceException) | +| MultiImplementationB.cs:20:19:20:22 | null | MultiImplementationB.cs:20:13:20:23 | throw ...; | semmle.label | successor | +| MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | MultiImplementationA.cs:23:50:23:53 | null | semmle.label | successor | +| MultiImplementationB.cs:21:28:21:35 | enter implicit conversion | MultiImplementationB.cs:21:56:21:59 | null | semmle.label | successor | +| MultiImplementationB.cs:21:50:21:59 | throw ... | MultiImplementationA.cs:23:28:23:35 | exit implicit conversion | semmle.label | exception(NullReferenceException) | +| MultiImplementationB.cs:21:50:21:59 | throw ... | MultiImplementationB.cs:21:28:21:35 | exit implicit conversion | semmle.label | exception(NullReferenceException) | +| MultiImplementationB.cs:21:56:21:59 | null | MultiImplementationB.cs:21:50:21:59 | throw ... | semmle.label | successor | +| MultiImplementationB.cs:22:16:22:16 | access to property P | MultiImplementationB.cs:22:32:22:34 | ... = ... | semmle.label | successor | +| MultiImplementationB.cs:22:16:22:16 | this access | MultiImplementationB.cs:22:34:22:34 | 1 | semmle.label | successor | +| MultiImplementationB.cs:22:32:22:34 | ... = ... | MultiImplementationA.cs:20:22:20:31 | {...} | semmle.label | successor | +| MultiImplementationB.cs:22:32:22:34 | ... = ... | MultiImplementationA.cs:24:16:24:16 | this access | semmle.label | successor | +| MultiImplementationB.cs:22:32:22:34 | ... = ... | MultiImplementationB.cs:18:22:18:36 | {...} | semmle.label | successor | +| MultiImplementationB.cs:22:32:22:34 | ... = ... | MultiImplementationB.cs:22:16:22:16 | this access | semmle.label | successor | +| MultiImplementationB.cs:22:34:22:34 | 1 | MultiImplementationB.cs:22:16:22:16 | access to property P | semmle.label | successor | +| MultiImplementationB.cs:27:21:27:23 | enter get_P3 | MultiImplementationA.cs:30:34:30:37 | null | semmle.label | successor | +| MultiImplementationB.cs:32:9:32:10 | enter M1 | MultiImplementationA.cs:36:14:36:28 | {...} | semmle.label | successor | +| MultiImplementationB.cs:32:9:32:10 | enter M1 | MultiImplementationB.cs:32:17:32:17 | 0 | semmle.label | successor | +| MultiImplementationB.cs:32:17:32:17 | 0 | MultiImplementationA.cs:36:9:36:10 | exit M1 | semmle.label | successor | +| MultiImplementationB.cs:32:17:32:17 | 0 | MultiImplementationB.cs:32:9:32:10 | exit M1 | semmle.label | successor | | NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:23:3:28 | ... ?? ... | semmle.label | successor | | NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:9:3:10 | exit M1 | semmle.label | non-null | | NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:28:3:28 | 0 | semmle.label | null | @@ -2505,10 +3316,10 @@ | Switch.cs:27:18:27:25 | Double d | Switch.cs:27:32:27:38 | call to method Throw | semmle.label | match | | Switch.cs:27:18:27:25 | Double d | Switch.cs:30:13:30:20 | default: | semmle.label | no-match | | Switch.cs:27:32:27:38 | call to method Throw | Switch.cs:10:10:10:11 | exit M2 | semmle.label | exception(Exception) | -| Switch.cs:28:17:28:21 | Label: | Switch.cs:29:17:29:23 | return ...; | semmle.label | successor | +| Switch.cs:28:13:28:17 | Label: | Switch.cs:29:17:29:23 | return ...; | semmle.label | successor | | Switch.cs:29:17:29:23 | return ...; | Switch.cs:10:10:10:11 | exit M2 | semmle.label | return | | Switch.cs:30:13:30:20 | default: | Switch.cs:31:17:31:27 | goto ...; | semmle.label | successor | -| Switch.cs:31:17:31:27 | goto ...; | Switch.cs:28:17:28:21 | Label: | semmle.label | goto(Label) | +| Switch.cs:31:17:31:27 | goto ...; | Switch.cs:28:13:28:17 | Label: | semmle.label | goto(Label) | | Switch.cs:35:10:35:11 | enter M3 | Switch.cs:36:5:42:5 | {...} | semmle.label | successor | | Switch.cs:36:5:42:5 | {...} | Switch.cs:37:9:41:9 | switch (...) {...} | semmle.label | successor | | Switch.cs:37:9:41:9 | switch (...) {...} | Switch.cs:37:17:37:23 | call to method Throw | semmle.label | successor | @@ -2533,73 +3344,73 @@ | Switch.cs:56:5:64:5 | {...} | Switch.cs:57:9:63:9 | switch (...) {...} | semmle.label | successor | | Switch.cs:57:9:63:9 | switch (...) {...} | Switch.cs:57:17:57:17 | 1 | semmle.label | successor | | Switch.cs:57:17:57:17 | 1 | Switch.cs:57:21:57:21 | 2 | semmle.label | successor | -| Switch.cs:57:17:57:21 | ... + ... | Switch.cs:59:13:59:20 | case ...: | semmle.label | successor | +| Switch.cs:57:17:57:21 | ... + ... | Switch.cs:59:13:59:19 | case ...: | semmle.label | successor | | Switch.cs:57:21:57:21 | 2 | Switch.cs:57:17:57:21 | ... + ... | semmle.label | successor | -| Switch.cs:59:13:59:20 | case ...: | Switch.cs:59:18:59:18 | 2 | semmle.label | successor | -| Switch.cs:59:18:59:18 | 2 | Switch.cs:61:13:61:20 | case ...: | semmle.label | no-match | -| Switch.cs:61:13:61:20 | case ...: | Switch.cs:61:18:61:18 | 3 | semmle.label | successor | -| Switch.cs:61:18:61:18 | 3 | Switch.cs:62:15:62:20 | break; | semmle.label | match | -| Switch.cs:62:15:62:20 | break; | Switch.cs:55:10:55:11 | exit M5 | semmle.label | break | +| Switch.cs:59:13:59:19 | case ...: | Switch.cs:59:18:59:18 | 2 | semmle.label | successor | +| Switch.cs:59:18:59:18 | 2 | Switch.cs:61:13:61:19 | case ...: | semmle.label | no-match | +| Switch.cs:61:13:61:19 | case ...: | Switch.cs:61:18:61:18 | 3 | semmle.label | successor | +| Switch.cs:61:18:61:18 | 3 | Switch.cs:62:17:62:22 | break; | semmle.label | match | +| Switch.cs:62:17:62:22 | break; | Switch.cs:55:10:55:11 | exit M5 | semmle.label | break | | Switch.cs:66:10:66:11 | enter M6 | Switch.cs:67:5:75:5 | {...} | semmle.label | successor | | Switch.cs:67:5:75:5 | {...} | Switch.cs:68:9:74:9 | switch (...) {...} | semmle.label | successor | | Switch.cs:68:9:74:9 | switch (...) {...} | Switch.cs:68:25:68:25 | access to parameter s | semmle.label | successor | -| Switch.cs:68:17:68:25 | (...) ... | Switch.cs:70:13:70:24 | case ...: | semmle.label | successor | +| Switch.cs:68:17:68:25 | (...) ... | Switch.cs:70:13:70:23 | case ...: | semmle.label | successor | | Switch.cs:68:25:68:25 | access to parameter s | Switch.cs:68:17:68:25 | (...) ... | semmle.label | successor | -| Switch.cs:70:13:70:24 | case ...: | Switch.cs:70:18:70:20 | access to type Int32 | semmle.label | successor | -| Switch.cs:70:18:70:20 | access to type Int32 | Switch.cs:72:13:72:21 | case ...: | semmle.label | no-match | -| Switch.cs:72:13:72:21 | case ...: | Switch.cs:72:18:72:19 | "" | semmle.label | successor | +| Switch.cs:70:13:70:23 | case ...: | Switch.cs:70:18:70:20 | access to type Int32 | semmle.label | successor | +| Switch.cs:70:18:70:20 | access to type Int32 | Switch.cs:72:13:72:20 | case ...: | semmle.label | no-match | +| Switch.cs:72:13:72:20 | case ...: | Switch.cs:72:18:72:19 | "" | semmle.label | successor | | Switch.cs:72:18:72:19 | "" | Switch.cs:66:10:66:11 | exit M6 | semmle.label | no-match | -| Switch.cs:72:18:72:19 | "" | Switch.cs:73:15:73:20 | break; | semmle.label | match | -| Switch.cs:73:15:73:20 | break; | Switch.cs:66:10:66:11 | exit M6 | semmle.label | break | +| Switch.cs:72:18:72:19 | "" | Switch.cs:73:17:73:22 | break; | semmle.label | match | +| Switch.cs:73:17:73:22 | break; | Switch.cs:66:10:66:11 | exit M6 | semmle.label | break | | Switch.cs:77:10:77:11 | enter M7 | Switch.cs:78:5:89:5 | {...} | semmle.label | successor | | Switch.cs:78:5:89:5 | {...} | Switch.cs:79:9:87:9 | switch (...) {...} | semmle.label | successor | | Switch.cs:79:9:87:9 | switch (...) {...} | Switch.cs:79:17:79:17 | access to parameter i | semmle.label | successor | -| Switch.cs:79:17:79:17 | access to parameter i | Switch.cs:81:13:81:20 | case ...: | semmle.label | successor | -| Switch.cs:81:13:81:20 | case ...: | Switch.cs:81:18:81:18 | 1 | semmle.label | successor | -| Switch.cs:81:18:81:18 | 1 | Switch.cs:82:22:82:25 | true | semmle.label | match | -| Switch.cs:81:18:81:18 | 1 | Switch.cs:83:13:83:20 | case ...: | semmle.label | no-match | -| Switch.cs:82:15:82:26 | return ...; | Switch.cs:77:10:77:11 | exit M7 | semmle.label | return | -| Switch.cs:82:22:82:25 | true | Switch.cs:82:15:82:26 | return ...; | semmle.label | successor | -| Switch.cs:83:13:83:20 | case ...: | Switch.cs:83:18:83:18 | 2 | semmle.label | successor | -| Switch.cs:83:18:83:18 | 2 | Switch.cs:84:15:85:22 | if (...) ... | semmle.label | match | +| Switch.cs:79:17:79:17 | access to parameter i | Switch.cs:81:13:81:19 | case ...: | semmle.label | successor | +| Switch.cs:81:13:81:19 | case ...: | Switch.cs:81:18:81:18 | 1 | semmle.label | successor | +| Switch.cs:81:18:81:18 | 1 | Switch.cs:82:24:82:27 | true | semmle.label | match | +| Switch.cs:81:18:81:18 | 1 | Switch.cs:83:13:83:19 | case ...: | semmle.label | no-match | +| Switch.cs:82:17:82:28 | return ...; | Switch.cs:77:10:77:11 | exit M7 | semmle.label | return | +| Switch.cs:82:24:82:27 | true | Switch.cs:82:17:82:28 | return ...; | semmle.label | successor | +| Switch.cs:83:13:83:19 | case ...: | Switch.cs:83:18:83:18 | 2 | semmle.label | successor | +| Switch.cs:83:18:83:18 | 2 | Switch.cs:84:17:85:26 | if (...) ... | semmle.label | match | | Switch.cs:83:18:83:18 | 2 | Switch.cs:88:16:88:20 | false | semmle.label | no-match | -| Switch.cs:84:15:85:22 | if (...) ... | Switch.cs:84:19:84:19 | access to parameter j | semmle.label | successor | -| Switch.cs:84:19:84:19 | access to parameter j | Switch.cs:84:23:84:23 | 2 | semmle.label | successor | -| Switch.cs:84:19:84:23 | ... > ... | Switch.cs:85:17:85:22 | break; | semmle.label | true | -| Switch.cs:84:19:84:23 | ... > ... | Switch.cs:86:22:86:25 | true | semmle.label | false | -| Switch.cs:84:23:84:23 | 2 | Switch.cs:84:19:84:23 | ... > ... | semmle.label | successor | -| Switch.cs:85:17:85:22 | break; | Switch.cs:88:16:88:20 | false | semmle.label | break | -| Switch.cs:86:15:86:26 | return ...; | Switch.cs:77:10:77:11 | exit M7 | semmle.label | return | -| Switch.cs:86:22:86:25 | true | Switch.cs:86:15:86:26 | return ...; | semmle.label | successor | +| Switch.cs:84:17:85:26 | if (...) ... | Switch.cs:84:21:84:21 | access to parameter j | semmle.label | successor | +| Switch.cs:84:21:84:21 | access to parameter j | Switch.cs:84:25:84:25 | 2 | semmle.label | successor | +| Switch.cs:84:21:84:25 | ... > ... | Switch.cs:85:21:85:26 | break; | semmle.label | true | +| Switch.cs:84:21:84:25 | ... > ... | Switch.cs:86:24:86:27 | true | semmle.label | false | +| Switch.cs:84:25:84:25 | 2 | Switch.cs:84:21:84:25 | ... > ... | semmle.label | successor | +| Switch.cs:85:21:85:26 | break; | Switch.cs:88:16:88:20 | false | semmle.label | break | +| Switch.cs:86:17:86:28 | return ...; | Switch.cs:77:10:77:11 | exit M7 | semmle.label | return | +| Switch.cs:86:24:86:27 | true | Switch.cs:86:17:86:28 | return ...; | semmle.label | successor | | Switch.cs:88:9:88:21 | return ...; | Switch.cs:77:10:77:11 | exit M7 | semmle.label | return | | Switch.cs:88:16:88:20 | false | Switch.cs:88:9:88:21 | return ...; | semmle.label | successor | | Switch.cs:91:10:91:11 | enter M8 | Switch.cs:92:5:99:5 | {...} | semmle.label | successor | | Switch.cs:92:5:99:5 | {...} | Switch.cs:93:9:97:9 | switch (...) {...} | semmle.label | successor | | Switch.cs:93:9:97:9 | switch (...) {...} | Switch.cs:93:17:93:17 | access to parameter o | semmle.label | successor | -| Switch.cs:93:17:93:17 | access to parameter o | Switch.cs:95:13:95:24 | case ...: | semmle.label | successor | -| Switch.cs:95:13:95:24 | case ...: | Switch.cs:95:18:95:20 | access to type Int32 | semmle.label | successor | -| Switch.cs:95:18:95:20 | access to type Int32 | Switch.cs:96:22:96:25 | true | semmle.label | match | +| Switch.cs:93:17:93:17 | access to parameter o | Switch.cs:95:13:95:23 | case ...: | semmle.label | successor | +| Switch.cs:95:13:95:23 | case ...: | Switch.cs:95:18:95:20 | access to type Int32 | semmle.label | successor | +| Switch.cs:95:18:95:20 | access to type Int32 | Switch.cs:96:24:96:27 | true | semmle.label | match | | Switch.cs:95:18:95:20 | access to type Int32 | Switch.cs:98:16:98:20 | false | semmle.label | no-match | -| Switch.cs:96:15:96:26 | return ...; | Switch.cs:91:10:91:11 | exit M8 | semmle.label | return | -| Switch.cs:96:22:96:25 | true | Switch.cs:96:15:96:26 | return ...; | semmle.label | successor | +| Switch.cs:96:17:96:28 | return ...; | Switch.cs:91:10:91:11 | exit M8 | semmle.label | return | +| Switch.cs:96:24:96:27 | true | Switch.cs:96:17:96:28 | return ...; | semmle.label | successor | | Switch.cs:98:9:98:21 | return ...; | Switch.cs:91:10:91:11 | exit M8 | semmle.label | return | | Switch.cs:98:16:98:20 | false | Switch.cs:98:9:98:21 | return ...; | semmle.label | successor | | Switch.cs:101:9:101:10 | enter M9 | Switch.cs:102:5:109:5 | {...} | semmle.label | successor | | Switch.cs:102:5:109:5 | {...} | Switch.cs:103:9:107:9 | switch (...) {...} | semmle.label | successor | | Switch.cs:103:9:107:9 | switch (...) {...} | Switch.cs:103:17:103:17 | access to parameter s | semmle.label | successor | | Switch.cs:103:17:103:17 | access to parameter s | Switch.cs:103:19:103:25 | access to property Length | semmle.label | non-null | -| Switch.cs:103:17:103:17 | access to parameter s | Switch.cs:105:13:105:20 | case ...: | semmle.label | null | -| Switch.cs:103:19:103:25 | access to property Length | Switch.cs:105:13:105:20 | case ...: | semmle.label | successor | -| Switch.cs:105:13:105:20 | case ...: | Switch.cs:105:18:105:18 | 0 | semmle.label | successor | -| Switch.cs:105:18:105:18 | 0 | Switch.cs:105:29:105:29 | 0 | semmle.label | match | -| Switch.cs:105:18:105:18 | 0 | Switch.cs:106:13:106:20 | case ...: | semmle.label | no-match | -| Switch.cs:105:22:105:30 | return ...; | Switch.cs:101:9:101:10 | exit M9 | semmle.label | return | -| Switch.cs:105:29:105:29 | 0 | Switch.cs:105:22:105:30 | return ...; | semmle.label | successor | -| Switch.cs:106:13:106:20 | case ...: | Switch.cs:106:18:106:18 | 1 | semmle.label | successor | -| Switch.cs:106:18:106:18 | 1 | Switch.cs:106:29:106:29 | 1 | semmle.label | match | +| Switch.cs:103:17:103:17 | access to parameter s | Switch.cs:105:13:105:19 | case ...: | semmle.label | null | +| Switch.cs:103:19:103:25 | access to property Length | Switch.cs:105:13:105:19 | case ...: | semmle.label | successor | +| Switch.cs:105:13:105:19 | case ...: | Switch.cs:105:18:105:18 | 0 | semmle.label | successor | +| Switch.cs:105:18:105:18 | 0 | Switch.cs:105:28:105:28 | 0 | semmle.label | match | +| Switch.cs:105:18:105:18 | 0 | Switch.cs:106:13:106:19 | case ...: | semmle.label | no-match | +| Switch.cs:105:21:105:29 | return ...; | Switch.cs:101:9:101:10 | exit M9 | semmle.label | return | +| Switch.cs:105:28:105:28 | 0 | Switch.cs:105:21:105:29 | return ...; | semmle.label | successor | +| Switch.cs:106:13:106:19 | case ...: | Switch.cs:106:18:106:18 | 1 | semmle.label | successor | +| Switch.cs:106:18:106:18 | 1 | Switch.cs:106:28:106:28 | 1 | semmle.label | match | | Switch.cs:106:18:106:18 | 1 | Switch.cs:108:17:108:17 | 1 | semmle.label | no-match | -| Switch.cs:106:22:106:30 | return ...; | Switch.cs:101:9:101:10 | exit M9 | semmle.label | return | -| Switch.cs:106:29:106:29 | 1 | Switch.cs:106:22:106:30 | return ...; | semmle.label | successor | +| Switch.cs:106:21:106:29 | return ...; | Switch.cs:101:9:101:10 | exit M9 | semmle.label | return | +| Switch.cs:106:28:106:28 | 1 | Switch.cs:106:21:106:29 | return ...; | semmle.label | successor | | Switch.cs:108:9:108:18 | return ...; | Switch.cs:101:9:101:10 | exit M9 | semmle.label | return | | Switch.cs:108:16:108:17 | -... | Switch.cs:108:9:108:18 | return ...; | semmle.label | successor | | Switch.cs:108:17:108:17 | 1 | Switch.cs:108:16:108:17 | -... | semmle.label | successor | @@ -2610,25 +3421,25 @@ | Switch.cs:114:5:121:5 | {...} | Switch.cs:115:9:119:9 | switch (...) {...} | semmle.label | successor | | Switch.cs:115:9:119:9 | switch (...) {...} | Switch.cs:115:17:115:17 | access to parameter s | semmle.label | successor | | Switch.cs:115:17:115:17 | access to parameter s | Switch.cs:115:17:115:24 | access to property Length | semmle.label | successor | -| Switch.cs:115:17:115:24 | access to property Length | Switch.cs:117:13:117:34 | case ...: | semmle.label | successor | -| Switch.cs:117:13:117:34 | case ...: | Switch.cs:117:18:117:18 | 3 | semmle.label | successor | +| Switch.cs:115:17:115:24 | access to property Length | Switch.cs:117:13:117:35 | case ...: | semmle.label | successor | +| Switch.cs:117:13:117:35 | case ...: | Switch.cs:117:18:117:18 | 3 | semmle.label | successor | | Switch.cs:117:18:117:18 | 3 | Switch.cs:117:25:117:25 | access to parameter s | semmle.label | match | -| Switch.cs:117:18:117:18 | 3 | Switch.cs:118:13:118:33 | case ...: | semmle.label | no-match | -| Switch.cs:117:25:117:25 | access to parameter s | Switch.cs:117:28:117:32 | "foo" | semmle.label | successor | -| Switch.cs:117:25:117:32 | ... == ... | Switch.cs:117:43:117:43 | 1 | semmle.label | true | -| Switch.cs:117:25:117:32 | ... == ... | Switch.cs:118:13:118:33 | case ...: | semmle.label | false | -| Switch.cs:117:28:117:32 | "foo" | Switch.cs:117:25:117:32 | ... == ... | semmle.label | successor | -| Switch.cs:117:36:117:44 | return ...; | Switch.cs:113:9:113:11 | exit M10 | semmle.label | return | -| Switch.cs:117:43:117:43 | 1 | Switch.cs:117:36:117:44 | return ...; | semmle.label | successor | -| Switch.cs:118:13:118:33 | case ...: | Switch.cs:118:18:118:18 | 2 | semmle.label | successor | +| Switch.cs:117:18:117:18 | 3 | Switch.cs:118:13:118:34 | case ...: | semmle.label | no-match | +| Switch.cs:117:25:117:25 | access to parameter s | Switch.cs:117:30:117:34 | "foo" | semmle.label | successor | +| Switch.cs:117:25:117:34 | ... == ... | Switch.cs:117:44:117:44 | 1 | semmle.label | true | +| Switch.cs:117:25:117:34 | ... == ... | Switch.cs:118:13:118:34 | case ...: | semmle.label | false | +| Switch.cs:117:30:117:34 | "foo" | Switch.cs:117:25:117:34 | ... == ... | semmle.label | successor | +| Switch.cs:117:37:117:45 | return ...; | Switch.cs:113:9:113:11 | exit M10 | semmle.label | return | +| Switch.cs:117:44:117:44 | 1 | Switch.cs:117:37:117:45 | return ...; | semmle.label | successor | +| Switch.cs:118:13:118:34 | case ...: | Switch.cs:118:18:118:18 | 2 | semmle.label | successor | | Switch.cs:118:18:118:18 | 2 | Switch.cs:118:25:118:25 | access to parameter s | semmle.label | match | | Switch.cs:118:18:118:18 | 2 | Switch.cs:120:17:120:17 | 1 | semmle.label | no-match | -| Switch.cs:118:25:118:25 | access to parameter s | Switch.cs:118:28:118:31 | "fu" | semmle.label | successor | -| Switch.cs:118:25:118:31 | ... == ... | Switch.cs:118:42:118:42 | 2 | semmle.label | true | -| Switch.cs:118:25:118:31 | ... == ... | Switch.cs:120:17:120:17 | 1 | semmle.label | false | -| Switch.cs:118:28:118:31 | "fu" | Switch.cs:118:25:118:31 | ... == ... | semmle.label | successor | -| Switch.cs:118:35:118:43 | return ...; | Switch.cs:113:9:113:11 | exit M10 | semmle.label | return | -| Switch.cs:118:42:118:42 | 2 | Switch.cs:118:35:118:43 | return ...; | semmle.label | successor | +| Switch.cs:118:25:118:25 | access to parameter s | Switch.cs:118:30:118:33 | "fu" | semmle.label | successor | +| Switch.cs:118:25:118:33 | ... == ... | Switch.cs:118:43:118:43 | 2 | semmle.label | true | +| Switch.cs:118:25:118:33 | ... == ... | Switch.cs:120:17:120:17 | 1 | semmle.label | false | +| Switch.cs:118:30:118:33 | "fu" | Switch.cs:118:25:118:33 | ... == ... | semmle.label | successor | +| Switch.cs:118:36:118:44 | return ...; | Switch.cs:113:9:113:11 | exit M10 | semmle.label | return | +| Switch.cs:118:43:118:43 | 2 | Switch.cs:118:36:118:44 | return ...; | semmle.label | successor | | Switch.cs:120:9:120:18 | return ...; | Switch.cs:113:9:113:11 | exit M10 | semmle.label | return | | Switch.cs:120:16:120:17 | -... | Switch.cs:120:9:120:18 | return ...; | semmle.label | successor | | Switch.cs:120:17:120:17 | 1 | Switch.cs:120:16:120:17 | -... | semmle.label | successor | @@ -2696,6 +3507,33 @@ | Switch.cs:150:18:150:18 | 2 | Switch.cs:150:28:150:28 | 2 | semmle.label | match | | Switch.cs:150:21:150:29 | return ...; | Switch.cs:144:9:144:11 | exit M14 | semmle.label | return | | Switch.cs:150:28:150:28 | 2 | Switch.cs:150:21:150:29 | return ...; | semmle.label | successor | +| Switch.cs:154:10:154:12 | enter M15 | Switch.cs:155:5:161:5 | {...} | semmle.label | successor | +| Switch.cs:155:5:161:5 | {...} | Switch.cs:156:9:156:55 | ... ...; | semmle.label | successor | +| Switch.cs:156:9:156:55 | ... ...; | Switch.cs:156:17:156:54 | ... switch { ... } | semmle.label | successor | +| Switch.cs:156:13:156:54 | String s = ... | Switch.cs:157:9:160:49 | if (...) ... | semmle.label | successor | +| Switch.cs:156:17:156:17 | access to parameter b | Switch.cs:156:28:156:38 | ... => ... | semmle.label | successor | +| Switch.cs:156:17:156:54 | ... switch { ... } | Switch.cs:156:17:156:17 | access to parameter b | semmle.label | successor | +| Switch.cs:156:28:156:31 | true | Switch.cs:156:36:156:38 | "a" | semmle.label | match | +| Switch.cs:156:28:156:31 | true | Switch.cs:156:41:156:52 | ... => ... | semmle.label | no-match | +| Switch.cs:156:28:156:38 | ... => ... | Switch.cs:156:28:156:31 | true | semmle.label | successor | +| Switch.cs:156:36:156:38 | "a" | Switch.cs:156:13:156:54 | String s = ... | semmle.label | successor | +| Switch.cs:156:41:156:45 | false | Switch.cs:154:10:154:12 | exit M15 | semmle.label | exception(InvalidOperationException) | +| Switch.cs:156:41:156:45 | false | Switch.cs:156:50:156:52 | "b" | semmle.label | match | +| Switch.cs:156:41:156:52 | ... => ... | Switch.cs:156:41:156:45 | false | semmle.label | successor | +| Switch.cs:156:50:156:52 | "b" | Switch.cs:156:13:156:54 | String s = ... | semmle.label | successor | +| Switch.cs:157:9:160:49 | if (...) ... | Switch.cs:157:13:157:13 | access to parameter b | semmle.label | successor | +| Switch.cs:157:13:157:13 | access to parameter b | Switch.cs:158:13:158:49 | ...; | semmle.label | true | +| Switch.cs:157:13:157:13 | access to parameter b | Switch.cs:160:13:160:49 | ...; | semmle.label | false | +| Switch.cs:158:13:158:48 | call to method WriteLine | Switch.cs:154:10:154:12 | exit M15 | semmle.label | successor | +| Switch.cs:158:13:158:49 | ...; | Switch.cs:158:40:158:43 | "a = " | semmle.label | successor | +| Switch.cs:158:38:158:47 | $"..." | Switch.cs:158:13:158:48 | call to method WriteLine | semmle.label | successor | +| Switch.cs:158:40:158:43 | "a = " | Switch.cs:158:45:158:45 | access to local variable s | semmle.label | successor | +| Switch.cs:158:45:158:45 | access to local variable s | Switch.cs:158:38:158:47 | $"..." | semmle.label | successor | +| Switch.cs:160:13:160:48 | call to method WriteLine | Switch.cs:154:10:154:12 | exit M15 | semmle.label | successor | +| Switch.cs:160:13:160:49 | ...; | Switch.cs:160:40:160:43 | "b = " | semmle.label | successor | +| Switch.cs:160:38:160:47 | $"..." | Switch.cs:160:13:160:48 | call to method WriteLine | semmle.label | successor | +| Switch.cs:160:40:160:43 | "b = " | Switch.cs:160:45:160:45 | access to local variable s | semmle.label | successor | +| Switch.cs:160:45:160:45 | access to local variable s | Switch.cs:160:38:160:47 | $"..." | semmle.label | successor | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:4:5:9:5 | {...} | semmle.label | successor | | TypeAccesses.cs:4:5:9:5 | {...} | TypeAccesses.cs:5:9:5:26 | ... ...; | semmle.label | successor | | TypeAccesses.cs:5:9:5:26 | ... ...; | TypeAccesses.cs:5:25:5:25 | access to parameter o | semmle.label | successor | @@ -2720,11 +3558,13 @@ | VarDecls.cs:7:9:10:9 | fixed(...) { ... } | VarDecls.cs:7:27:7:33 | access to parameter strings | semmle.label | successor | | VarDecls.cs:7:22:7:36 | Char* c1 = ... | VarDecls.cs:7:44:7:50 | access to parameter strings | semmle.label | successor | | VarDecls.cs:7:27:7:33 | access to parameter strings | VarDecls.cs:7:35:7:35 | 0 | semmle.label | successor | -| VarDecls.cs:7:27:7:36 | access to array element | VarDecls.cs:7:22:7:36 | Char* c1 = ... | semmle.label | successor | +| VarDecls.cs:7:27:7:36 | (...) ... | VarDecls.cs:7:22:7:36 | Char* c1 = ... | semmle.label | successor | +| VarDecls.cs:7:27:7:36 | access to array element | VarDecls.cs:7:27:7:36 | (...) ... | semmle.label | successor | | VarDecls.cs:7:35:7:35 | 0 | VarDecls.cs:7:27:7:36 | access to array element | semmle.label | successor | | VarDecls.cs:7:39:7:53 | Char* c2 = ... | VarDecls.cs:8:9:10:9 | {...} | semmle.label | successor | | VarDecls.cs:7:44:7:50 | access to parameter strings | VarDecls.cs:7:52:7:52 | 1 | semmle.label | successor | -| VarDecls.cs:7:44:7:53 | access to array element | VarDecls.cs:7:39:7:53 | Char* c2 = ... | semmle.label | successor | +| VarDecls.cs:7:44:7:53 | (...) ... | VarDecls.cs:7:39:7:53 | Char* c2 = ... | semmle.label | successor | +| VarDecls.cs:7:44:7:53 | access to array element | VarDecls.cs:7:44:7:53 | (...) ... | semmle.label | successor | | VarDecls.cs:7:52:7:52 | 1 | VarDecls.cs:7:44:7:53 | access to array element | semmle.label | successor | | VarDecls.cs:8:9:10:9 | {...} | VarDecls.cs:9:27:9:28 | access to local variable c1 | semmle.label | successor | | VarDecls.cs:9:13:9:29 | return ...; | VarDecls.cs:5:18:5:19 | exit M1 | semmle.label | return | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected b/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected index f6d10fdb2ba7..caa10ca9d348 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected @@ -1,4 +1,340 @@ booleanNode +| Assert.cs:58:16:58:32 | [b (line 56): false] String s = ... | b (line 56): false | +| Assert.cs:58:16:58:32 | [b (line 56): true] String s = ... | b (line 56): true | +| Assert.cs:58:24:58:27 | [b (line 56): true] null | b (line 56): true | +| Assert.cs:58:31:58:32 | [b (line 56): false] "" | b (line 56): false | +| Assert.cs:59:9:59:38 | [b (line 56): false] ...; | b (line 56): false | +| Assert.cs:59:9:59:38 | [b (line 56): true] ...; | b (line 56): true | +| Assert.cs:59:23:59:23 | [b (line 56): false] access to local variable s | b (line 56): false | +| Assert.cs:59:23:59:23 | [b (line 56): true] access to local variable s | b (line 56): true | +| Assert.cs:59:23:59:31 | [b (line 56): false] ... != ... | b (line 56): false | +| Assert.cs:59:23:59:31 | [b (line 56): true] ... != ... | b (line 56): true | +| Assert.cs:59:23:59:36 | [b (line 56): false] ... && ... | b (line 56): false | +| Assert.cs:59:23:59:36 | [b (line 56): true] ... && ... | b (line 56): true | +| Assert.cs:59:28:59:31 | [b (line 56): false] null | b (line 56): false | +| Assert.cs:59:28:59:31 | [b (line 56): true] null | b (line 56): true | +| Assert.cs:59:36:59:36 | [b (line 56): false] access to parameter b | b (line 56): false | +| Assert.cs:59:36:59:36 | [b (line 56): true] access to parameter b | b (line 56): true | +| Assert.cs:65:16:65:32 | [b (line 63): false] String s = ... | b (line 63): false | +| Assert.cs:65:16:65:32 | [b (line 63): true] String s = ... | b (line 63): true | +| Assert.cs:65:24:65:27 | [b (line 63): true] null | b (line 63): true | +| Assert.cs:65:31:65:32 | [b (line 63): false] "" | b (line 63): false | +| Assert.cs:66:9:66:39 | [b (line 63): false] ...; | b (line 63): false | +| Assert.cs:66:9:66:39 | [b (line 63): true] ...; | b (line 63): true | +| Assert.cs:66:24:66:24 | [b (line 63): false] access to local variable s | b (line 63): false | +| Assert.cs:66:24:66:24 | [b (line 63): true] access to local variable s | b (line 63): true | +| Assert.cs:66:24:66:32 | [b (line 63): false] ... == ... | b (line 63): false | +| Assert.cs:66:24:66:32 | [b (line 63): true] ... == ... | b (line 63): true | +| Assert.cs:66:24:66:37 | [b (line 63): false] ... \|\| ... | b (line 63): false | +| Assert.cs:66:24:66:37 | [b (line 63): true] ... \|\| ... | b (line 63): true | +| Assert.cs:66:29:66:32 | [b (line 63): false] null | b (line 63): false | +| Assert.cs:66:29:66:32 | [b (line 63): true] null | b (line 63): true | +| Assert.cs:66:37:66:37 | [b (line 63): false] access to parameter b | b (line 63): false | +| Assert.cs:66:37:66:37 | [b (line 63): true] access to parameter b | b (line 63): true | +| Assert.cs:72:16:72:32 | [b (line 70): false] String s = ... | b (line 70): false | +| Assert.cs:72:16:72:32 | [b (line 70): true] String s = ... | b (line 70): true | +| Assert.cs:72:24:72:27 | [b (line 70): true] null | b (line 70): true | +| Assert.cs:72:31:72:32 | [b (line 70): false] "" | b (line 70): false | +| Assert.cs:73:9:73:38 | [b (line 70): false] ...; | b (line 70): false | +| Assert.cs:73:9:73:38 | [b (line 70): true] ...; | b (line 70): true | +| Assert.cs:73:23:73:23 | [b (line 70): false] access to local variable s | b (line 70): false | +| Assert.cs:73:23:73:23 | [b (line 70): true] access to local variable s | b (line 70): true | +| Assert.cs:73:23:73:31 | [b (line 70): false] ... == ... | b (line 70): false | +| Assert.cs:73:23:73:31 | [b (line 70): true] ... == ... | b (line 70): true | +| Assert.cs:73:23:73:36 | [b (line 70): false] ... && ... | b (line 70): false | +| Assert.cs:73:23:73:36 | [b (line 70): true] ... && ... | b (line 70): true | +| Assert.cs:73:28:73:31 | [b (line 70): false] null | b (line 70): false | +| Assert.cs:73:28:73:31 | [b (line 70): true] null | b (line 70): true | +| Assert.cs:73:36:73:36 | [b (line 70): false] access to parameter b | b (line 70): false | +| Assert.cs:73:36:73:36 | [b (line 70): true] access to parameter b | b (line 70): true | +| Assert.cs:79:16:79:32 | [b (line 77): false] String s = ... | b (line 77): false | +| Assert.cs:79:16:79:32 | [b (line 77): true] String s = ... | b (line 77): true | +| Assert.cs:79:24:79:27 | [b (line 77): true] null | b (line 77): true | +| Assert.cs:79:31:79:32 | [b (line 77): false] "" | b (line 77): false | +| Assert.cs:80:9:80:39 | [b (line 77): false] ...; | b (line 77): false | +| Assert.cs:80:9:80:39 | [b (line 77): true] ...; | b (line 77): true | +| Assert.cs:80:24:80:24 | [b (line 77): false] access to local variable s | b (line 77): false | +| Assert.cs:80:24:80:24 | [b (line 77): true] access to local variable s | b (line 77): true | +| Assert.cs:80:24:80:32 | [b (line 77): false] ... != ... | b (line 77): false | +| Assert.cs:80:24:80:32 | [b (line 77): true] ... != ... | b (line 77): true | +| Assert.cs:80:24:80:37 | [b (line 77): false] ... \|\| ... | b (line 77): false | +| Assert.cs:80:24:80:37 | [b (line 77): true] ... \|\| ... | b (line 77): true | +| Assert.cs:80:29:80:32 | [b (line 77): false] null | b (line 77): false | +| Assert.cs:80:29:80:32 | [b (line 77): true] null | b (line 77): true | +| Assert.cs:80:37:80:37 | [b (line 77): false] access to parameter b | b (line 77): false | +| Assert.cs:80:37:80:37 | [b (line 77): true] access to parameter b | b (line 77): true | +| Assert.cs:86:16:86:32 | [b (line 84): false] String s = ... | b (line 84): false | +| Assert.cs:86:16:86:32 | [b (line 84): true] String s = ... | b (line 84): true | +| Assert.cs:86:24:86:27 | [b (line 84): true] null | b (line 84): true | +| Assert.cs:86:31:86:32 | [b (line 84): false] "" | b (line 84): false | +| Assert.cs:87:9:87:31 | [assertion failure, b (line 84): false] call to method Assert | b (line 84): false | +| Assert.cs:87:9:87:31 | [assertion failure, b (line 84): true] call to method Assert | b (line 84): true | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): false] call to method Assert | b (line 84): false | +| Assert.cs:87:9:87:31 | [assertion success, b (line 84): true] call to method Assert | b (line 84): true | +| Assert.cs:87:9:87:32 | [b (line 84): false] ...; | b (line 84): false | +| Assert.cs:87:9:87:32 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:87:22:87:22 | [b (line 84): false] access to local variable s | b (line 84): false | +| Assert.cs:87:22:87:22 | [b (line 84): true] access to local variable s | b (line 84): true | +| Assert.cs:87:22:87:30 | [b (line 84): false] ... != ... | b (line 84): false | +| Assert.cs:87:22:87:30 | [b (line 84): true] ... != ... | b (line 84): true | +| Assert.cs:87:27:87:30 | [b (line 84): false] null | b (line 84): false | +| Assert.cs:87:27:87:30 | [b (line 84): true] null | b (line 84): true | +| Assert.cs:88:9:88:35 | [b (line 84): false] call to method WriteLine | b (line 84): false | +| Assert.cs:88:9:88:35 | [b (line 84): true] call to method WriteLine | b (line 84): true | +| Assert.cs:88:9:88:36 | [b (line 84): false] ...; | b (line 84): false | +| Assert.cs:88:9:88:36 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:88:27:88:27 | [b (line 84): false] access to local variable s | b (line 84): false | +| Assert.cs:88:27:88:27 | [b (line 84): true] access to local variable s | b (line 84): true | +| Assert.cs:88:27:88:34 | [b (line 84): false] access to property Length | b (line 84): false | +| Assert.cs:88:27:88:34 | [b (line 84): true] access to property Length | b (line 84): true | +| Assert.cs:90:9:90:25 | [b (line 84): false] ... = ... | b (line 84): false | +| Assert.cs:90:9:90:25 | [b (line 84): true] ... = ... | b (line 84): true | +| Assert.cs:90:9:90:26 | [b (line 84): false] ...; | b (line 84): false | +| Assert.cs:90:9:90:26 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:90:13:90:13 | [b (line 84): false] access to parameter b | b (line 84): false | +| Assert.cs:90:13:90:13 | [b (line 84): true] access to parameter b | b (line 84): true | +| Assert.cs:90:13:90:25 | [b (line 84): false] ... ? ... : ... | b (line 84): false | +| Assert.cs:90:13:90:25 | [b (line 84): true] ... ? ... : ... | b (line 84): true | +| Assert.cs:90:17:90:20 | [b (line 84): true] null | b (line 84): true | +| Assert.cs:90:24:90:25 | [b (line 84): false] "" | b (line 84): false | +| Assert.cs:91:9:91:24 | [assertion failure, b (line 84): false] call to method IsNull | b (line 84): false | +| Assert.cs:91:9:91:24 | [assertion failure, b (line 84): true] call to method IsNull | b (line 84): true | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): false] call to method IsNull | b (line 84): false | +| Assert.cs:91:9:91:24 | [assertion success, b (line 84): true] call to method IsNull | b (line 84): true | +| Assert.cs:91:9:91:25 | [b (line 84): false] ...; | b (line 84): false | +| Assert.cs:91:9:91:25 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:91:23:91:23 | [b (line 84): false] access to local variable s | b (line 84): false | +| Assert.cs:91:23:91:23 | [b (line 84): true] access to local variable s | b (line 84): true | +| Assert.cs:92:9:92:35 | [b (line 84): false] call to method WriteLine | b (line 84): false | +| Assert.cs:92:9:92:35 | [b (line 84): true] call to method WriteLine | b (line 84): true | +| Assert.cs:92:9:92:36 | [b (line 84): false] ...; | b (line 84): false | +| Assert.cs:92:9:92:36 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:92:27:92:27 | [b (line 84): false] access to local variable s | b (line 84): false | +| Assert.cs:92:27:92:27 | [b (line 84): true] access to local variable s | b (line 84): true | +| Assert.cs:92:27:92:34 | [b (line 84): false] access to property Length | b (line 84): false | +| Assert.cs:92:27:92:34 | [b (line 84): true] access to property Length | b (line 84): true | +| Assert.cs:94:9:94:25 | [b (line 84): false] ... = ... | b (line 84): false | +| Assert.cs:94:9:94:25 | [b (line 84): true] ... = ... | b (line 84): true | +| Assert.cs:94:9:94:26 | [b (line 84): false] ...; | b (line 84): false | +| Assert.cs:94:9:94:26 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:94:13:94:13 | [b (line 84): false] access to parameter b | b (line 84): false | +| Assert.cs:94:13:94:13 | [b (line 84): true] access to parameter b | b (line 84): true | +| Assert.cs:94:13:94:25 | [b (line 84): false] ... ? ... : ... | b (line 84): false | +| Assert.cs:94:13:94:25 | [b (line 84): true] ... ? ... : ... | b (line 84): true | +| Assert.cs:94:17:94:20 | [b (line 84): true] null | b (line 84): true | +| Assert.cs:94:24:94:25 | [b (line 84): false] "" | b (line 84): false | +| Assert.cs:95:9:95:27 | [assertion failure, b (line 84): false] call to method IsNotNull | b (line 84): false | +| Assert.cs:95:9:95:27 | [assertion failure, b (line 84): true] call to method IsNotNull | b (line 84): true | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): false] call to method IsNotNull | b (line 84): false | +| Assert.cs:95:9:95:27 | [assertion success, b (line 84): true] call to method IsNotNull | b (line 84): true | +| Assert.cs:95:9:95:28 | [b (line 84): false] ...; | b (line 84): false | +| Assert.cs:95:9:95:28 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:95:26:95:26 | [b (line 84): false] access to local variable s | b (line 84): false | +| Assert.cs:95:26:95:26 | [b (line 84): true] access to local variable s | b (line 84): true | +| Assert.cs:96:9:96:35 | [b (line 84): false] call to method WriteLine | b (line 84): false | +| Assert.cs:96:9:96:35 | [b (line 84): true] call to method WriteLine | b (line 84): true | +| Assert.cs:96:9:96:36 | [b (line 84): false] ...; | b (line 84): false | +| Assert.cs:96:9:96:36 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:96:27:96:27 | [b (line 84): false] access to local variable s | b (line 84): false | +| Assert.cs:96:27:96:27 | [b (line 84): true] access to local variable s | b (line 84): true | +| Assert.cs:96:27:96:34 | [b (line 84): false] access to property Length | b (line 84): false | +| Assert.cs:96:27:96:34 | [b (line 84): true] access to property Length | b (line 84): true | +| Assert.cs:98:9:98:25 | [b (line 84): false] ... = ... | b (line 84): false | +| Assert.cs:98:9:98:25 | [b (line 84): true] ... = ... | b (line 84): true | +| Assert.cs:98:9:98:26 | [b (line 84): false] ...; | b (line 84): false | +| Assert.cs:98:9:98:26 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:98:13:98:13 | [b (line 84): false] access to parameter b | b (line 84): false | +| Assert.cs:98:13:98:13 | [b (line 84): true] access to parameter b | b (line 84): true | +| Assert.cs:98:13:98:25 | [b (line 84): false] ... ? ... : ... | b (line 84): false | +| Assert.cs:98:13:98:25 | [b (line 84): true] ... ? ... : ... | b (line 84): true | +| Assert.cs:98:17:98:20 | [b (line 84): true] null | b (line 84): true | +| Assert.cs:98:24:98:25 | [b (line 84): false] "" | b (line 84): false | +| Assert.cs:99:9:99:32 | [assertion failure, b (line 84): false] call to method IsTrue | b (line 84): false | +| Assert.cs:99:9:99:32 | [assertion failure, b (line 84): true] call to method IsTrue | b (line 84): true | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): false] call to method IsTrue | b (line 84): false | +| Assert.cs:99:9:99:32 | [assertion success, b (line 84): true] call to method IsTrue | b (line 84): true | +| Assert.cs:99:9:99:33 | [b (line 84): false] ...; | b (line 84): false | +| Assert.cs:99:9:99:33 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:99:23:99:23 | [b (line 84): false] access to local variable s | b (line 84): false | +| Assert.cs:99:23:99:23 | [b (line 84): true] access to local variable s | b (line 84): true | +| Assert.cs:99:23:99:31 | [b (line 84): false] ... == ... | b (line 84): false | +| Assert.cs:99:23:99:31 | [b (line 84): true] ... == ... | b (line 84): true | +| Assert.cs:99:28:99:31 | [b (line 84): false] null | b (line 84): false | +| Assert.cs:99:28:99:31 | [b (line 84): true] null | b (line 84): true | +| Assert.cs:100:9:100:35 | [b (line 84): false] call to method WriteLine | b (line 84): false | +| Assert.cs:100:9:100:35 | [b (line 84): true] call to method WriteLine | b (line 84): true | +| Assert.cs:100:9:100:36 | [b (line 84): false] ...; | b (line 84): false | +| Assert.cs:100:9:100:36 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:100:27:100:27 | [b (line 84): false] access to local variable s | b (line 84): false | +| Assert.cs:100:27:100:27 | [b (line 84): true] access to local variable s | b (line 84): true | +| Assert.cs:100:27:100:34 | [b (line 84): false] access to property Length | b (line 84): false | +| Assert.cs:100:27:100:34 | [b (line 84): true] access to property Length | b (line 84): true | +| Assert.cs:102:9:102:25 | [b (line 84): false] ... = ... | b (line 84): false | +| Assert.cs:102:9:102:25 | [b (line 84): true] ... = ... | b (line 84): true | +| Assert.cs:102:9:102:26 | [b (line 84): false] ...; | b (line 84): false | +| Assert.cs:102:9:102:26 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:102:13:102:13 | [b (line 84): false] access to parameter b | b (line 84): false | +| Assert.cs:102:13:102:13 | [b (line 84): true] access to parameter b | b (line 84): true | +| Assert.cs:102:13:102:25 | [b (line 84): false] ... ? ... : ... | b (line 84): false | +| Assert.cs:102:13:102:25 | [b (line 84): true] ... ? ... : ... | b (line 84): true | +| Assert.cs:102:17:102:20 | [b (line 84): true] null | b (line 84): true | +| Assert.cs:102:24:102:25 | [b (line 84): false] "" | b (line 84): false | +| Assert.cs:103:9:103:32 | [assertion failure, b (line 84): false] call to method IsTrue | b (line 84): false | +| Assert.cs:103:9:103:32 | [assertion failure, b (line 84): true] call to method IsTrue | b (line 84): true | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): false] call to method IsTrue | b (line 84): false | +| Assert.cs:103:9:103:32 | [assertion success, b (line 84): true] call to method IsTrue | b (line 84): true | +| Assert.cs:103:9:103:33 | [b (line 84): false] ...; | b (line 84): false | +| Assert.cs:103:9:103:33 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:103:23:103:23 | [b (line 84): false] access to local variable s | b (line 84): false | +| Assert.cs:103:23:103:23 | [b (line 84): true] access to local variable s | b (line 84): true | +| Assert.cs:103:23:103:31 | [b (line 84): false] ... != ... | b (line 84): false | +| Assert.cs:103:23:103:31 | [b (line 84): true] ... != ... | b (line 84): true | +| Assert.cs:103:28:103:31 | [b (line 84): false] null | b (line 84): false | +| Assert.cs:103:28:103:31 | [b (line 84): true] null | b (line 84): true | +| Assert.cs:104:9:104:35 | [b (line 84): false] call to method WriteLine | b (line 84): false | +| Assert.cs:104:9:104:35 | [b (line 84): true] call to method WriteLine | b (line 84): true | +| Assert.cs:104:9:104:36 | [b (line 84): false] ...; | b (line 84): false | +| Assert.cs:104:9:104:36 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:104:27:104:27 | [b (line 84): false] access to local variable s | b (line 84): false | +| Assert.cs:104:27:104:27 | [b (line 84): true] access to local variable s | b (line 84): true | +| Assert.cs:104:27:104:34 | [b (line 84): false] access to property Length | b (line 84): false | +| Assert.cs:104:27:104:34 | [b (line 84): true] access to property Length | b (line 84): true | +| Assert.cs:106:9:106:25 | [b (line 84): false] ... = ... | b (line 84): false | +| Assert.cs:106:9:106:25 | [b (line 84): true] ... = ... | b (line 84): true | +| Assert.cs:106:9:106:26 | [b (line 84): false] ...; | b (line 84): false | +| Assert.cs:106:9:106:26 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:106:13:106:13 | [b (line 84): false] access to parameter b | b (line 84): false | +| Assert.cs:106:13:106:13 | [b (line 84): true] access to parameter b | b (line 84): true | +| Assert.cs:106:13:106:25 | [b (line 84): false] ... ? ... : ... | b (line 84): false | +| Assert.cs:106:13:106:25 | [b (line 84): true] ... ? ... : ... | b (line 84): true | +| Assert.cs:106:17:106:20 | [b (line 84): true] null | b (line 84): true | +| Assert.cs:106:24:106:25 | [b (line 84): false] "" | b (line 84): false | +| Assert.cs:107:9:107:33 | [assertion failure, b (line 84): false] call to method IsFalse | b (line 84): false | +| Assert.cs:107:9:107:33 | [assertion failure, b (line 84): true] call to method IsFalse | b (line 84): true | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): false] call to method IsFalse | b (line 84): false | +| Assert.cs:107:9:107:33 | [assertion success, b (line 84): true] call to method IsFalse | b (line 84): true | +| Assert.cs:107:9:107:34 | [b (line 84): false] ...; | b (line 84): false | +| Assert.cs:107:9:107:34 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:107:24:107:24 | [b (line 84): false] access to local variable s | b (line 84): false | +| Assert.cs:107:24:107:24 | [b (line 84): true] access to local variable s | b (line 84): true | +| Assert.cs:107:24:107:32 | [b (line 84): false] ... != ... | b (line 84): false | +| Assert.cs:107:24:107:32 | [b (line 84): true] ... != ... | b (line 84): true | +| Assert.cs:107:29:107:32 | [b (line 84): false] null | b (line 84): false | +| Assert.cs:107:29:107:32 | [b (line 84): true] null | b (line 84): true | +| Assert.cs:108:9:108:35 | [b (line 84): false] call to method WriteLine | b (line 84): false | +| Assert.cs:108:9:108:35 | [b (line 84): true] call to method WriteLine | b (line 84): true | +| Assert.cs:108:9:108:36 | [b (line 84): false] ...; | b (line 84): false | +| Assert.cs:108:9:108:36 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:108:27:108:27 | [b (line 84): false] access to local variable s | b (line 84): false | +| Assert.cs:108:27:108:27 | [b (line 84): true] access to local variable s | b (line 84): true | +| Assert.cs:108:27:108:34 | [b (line 84): false] access to property Length | b (line 84): false | +| Assert.cs:108:27:108:34 | [b (line 84): true] access to property Length | b (line 84): true | +| Assert.cs:110:9:110:25 | [b (line 84): false] ... = ... | b (line 84): false | +| Assert.cs:110:9:110:25 | [b (line 84): true] ... = ... | b (line 84): true | +| Assert.cs:110:9:110:26 | [b (line 84): false] ...; | b (line 84): false | +| Assert.cs:110:9:110:26 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:110:13:110:13 | [b (line 84): false] access to parameter b | b (line 84): false | +| Assert.cs:110:13:110:13 | [b (line 84): true] access to parameter b | b (line 84): true | +| Assert.cs:110:13:110:25 | [b (line 84): false] ... ? ... : ... | b (line 84): false | +| Assert.cs:110:13:110:25 | [b (line 84): true] ... ? ... : ... | b (line 84): true | +| Assert.cs:110:17:110:20 | [b (line 84): true] null | b (line 84): true | +| Assert.cs:110:24:110:25 | [b (line 84): false] "" | b (line 84): false | +| Assert.cs:111:9:111:33 | [assertion failure, b (line 84): false] call to method IsFalse | b (line 84): false | +| Assert.cs:111:9:111:33 | [assertion failure, b (line 84): true] call to method IsFalse | b (line 84): true | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): false] call to method IsFalse | b (line 84): false | +| Assert.cs:111:9:111:33 | [assertion success, b (line 84): true] call to method IsFalse | b (line 84): true | +| Assert.cs:111:9:111:34 | [b (line 84): false] ...; | b (line 84): false | +| Assert.cs:111:9:111:34 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:111:24:111:24 | [b (line 84): false] access to local variable s | b (line 84): false | +| Assert.cs:111:24:111:24 | [b (line 84): true] access to local variable s | b (line 84): true | +| Assert.cs:111:24:111:32 | [b (line 84): false] ... == ... | b (line 84): false | +| Assert.cs:111:24:111:32 | [b (line 84): true] ... == ... | b (line 84): true | +| Assert.cs:111:29:111:32 | [b (line 84): false] null | b (line 84): false | +| Assert.cs:111:29:111:32 | [b (line 84): true] null | b (line 84): true | +| Assert.cs:112:9:112:35 | [b (line 84): false] call to method WriteLine | b (line 84): false | +| Assert.cs:112:9:112:35 | [b (line 84): true] call to method WriteLine | b (line 84): true | +| Assert.cs:112:9:112:36 | [b (line 84): false] ...; | b (line 84): false | +| Assert.cs:112:9:112:36 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:112:27:112:27 | [b (line 84): false] access to local variable s | b (line 84): false | +| Assert.cs:112:27:112:27 | [b (line 84): true] access to local variable s | b (line 84): true | +| Assert.cs:112:27:112:34 | [b (line 84): false] access to property Length | b (line 84): false | +| Assert.cs:112:27:112:34 | [b (line 84): true] access to property Length | b (line 84): true | +| Assert.cs:114:9:114:25 | [b (line 84): false] ... = ... | b (line 84): false | +| Assert.cs:114:9:114:25 | [b (line 84): true] ... = ... | b (line 84): true | +| Assert.cs:114:9:114:26 | [b (line 84): false] ...; | b (line 84): false | +| Assert.cs:114:9:114:26 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:114:13:114:13 | [b (line 84): false] access to parameter b | b (line 84): false | +| Assert.cs:114:13:114:13 | [b (line 84): true] access to parameter b | b (line 84): true | +| Assert.cs:114:13:114:25 | [b (line 84): false] ... ? ... : ... | b (line 84): false | +| Assert.cs:114:13:114:25 | [b (line 84): true] ... ? ... : ... | b (line 84): true | +| Assert.cs:114:17:114:20 | [b (line 84): true] null | b (line 84): true | +| Assert.cs:114:24:114:25 | [b (line 84): false] "" | b (line 84): false | +| Assert.cs:115:9:115:37 | [assertion failure, b (line 84): false] call to method IsTrue | b (line 84): false | +| Assert.cs:115:9:115:37 | [assertion failure, b (line 84): true] call to method IsTrue | b (line 84): true | +| Assert.cs:115:9:115:37 | [assertion success, b (line 84): true] call to method IsTrue | b (line 84): true | +| Assert.cs:115:9:115:38 | [b (line 84): false] ...; | b (line 84): false | +| Assert.cs:115:9:115:38 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:115:23:115:23 | [b (line 84): false] access to local variable s | b (line 84): false | +| Assert.cs:115:23:115:23 | [b (line 84): true] access to local variable s | b (line 84): true | +| Assert.cs:115:23:115:31 | [b (line 84): false] ... != ... | b (line 84): false | +| Assert.cs:115:23:115:31 | [b (line 84): true] ... != ... | b (line 84): true | +| Assert.cs:115:23:115:36 | [b (line 84): false] ... && ... | b (line 84): false | +| Assert.cs:115:23:115:36 | [b (line 84): true] ... && ... | b (line 84): true | +| Assert.cs:115:28:115:31 | [b (line 84): false] null | b (line 84): false | +| Assert.cs:115:28:115:31 | [b (line 84): true] null | b (line 84): true | +| Assert.cs:115:36:115:36 | [b (line 84): false] access to parameter b | b (line 84): false | +| Assert.cs:115:36:115:36 | [b (line 84): true] access to parameter b | b (line 84): true | +| Assert.cs:116:9:116:35 | [b (line 84): true] call to method WriteLine | b (line 84): true | +| Assert.cs:116:9:116:36 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:116:27:116:27 | [b (line 84): true] access to local variable s | b (line 84): true | +| Assert.cs:116:27:116:34 | [b (line 84): true] access to property Length | b (line 84): true | +| Assert.cs:118:9:118:25 | [b (line 84): true] ... = ... | b (line 84): true | +| Assert.cs:118:9:118:26 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:118:13:118:13 | [b (line 84): true] access to parameter b | b (line 84): true | +| Assert.cs:118:13:118:25 | [b (line 84): true] ... ? ... : ... | b (line 84): true | +| Assert.cs:118:17:118:20 | [b (line 84): true] null | b (line 84): true | +| Assert.cs:119:9:119:39 | [assertion failure, b (line 84): true] call to method IsFalse | b (line 84): true | +| Assert.cs:119:9:119:39 | [assertion success, b (line 84): true] call to method IsFalse | b (line 84): true | +| Assert.cs:119:9:119:40 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:119:24:119:24 | [b (line 84): true] access to local variable s | b (line 84): true | +| Assert.cs:119:24:119:32 | [b (line 84): true] ... == ... | b (line 84): true | +| Assert.cs:119:24:119:38 | [b (line 84): true] ... \|\| ... | b (line 84): true | +| Assert.cs:119:29:119:32 | [b (line 84): true] null | b (line 84): true | +| Assert.cs:119:37:119:38 | [b (line 84): true] !... | b (line 84): true | +| Assert.cs:119:38:119:38 | [b (line 84): true] access to parameter b | b (line 84): true | +| Assert.cs:120:9:120:35 | [b (line 84): true] call to method WriteLine | b (line 84): true | +| Assert.cs:120:9:120:36 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:120:27:120:27 | [b (line 84): true] access to local variable s | b (line 84): true | +| Assert.cs:120:27:120:34 | [b (line 84): true] access to property Length | b (line 84): true | +| Assert.cs:122:9:122:25 | [b (line 84): true] ... = ... | b (line 84): true | +| Assert.cs:122:9:122:26 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:122:13:122:13 | [b (line 84): true] access to parameter b | b (line 84): true | +| Assert.cs:122:13:122:25 | [b (line 84): true] ... ? ... : ... | b (line 84): true | +| Assert.cs:122:17:122:20 | [b (line 84): true] null | b (line 84): true | +| Assert.cs:123:9:123:37 | [assertion failure, b (line 84): true] call to method IsTrue | b (line 84): true | +| Assert.cs:123:9:123:37 | [assertion success, b (line 84): true] call to method IsTrue | b (line 84): true | +| Assert.cs:123:9:123:38 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:123:23:123:23 | [b (line 84): true] access to local variable s | b (line 84): true | +| Assert.cs:123:23:123:31 | [b (line 84): true] ... == ... | b (line 84): true | +| Assert.cs:123:23:123:36 | [b (line 84): true] ... && ... | b (line 84): true | +| Assert.cs:123:28:123:31 | [b (line 84): true] null | b (line 84): true | +| Assert.cs:123:36:123:36 | [b (line 84): true] access to parameter b | b (line 84): true | +| Assert.cs:124:9:124:35 | [b (line 84): true] call to method WriteLine | b (line 84): true | +| Assert.cs:124:9:124:36 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:124:27:124:27 | [b (line 84): true] access to local variable s | b (line 84): true | +| Assert.cs:124:27:124:34 | [b (line 84): true] access to property Length | b (line 84): true | +| Assert.cs:126:9:126:25 | [b (line 84): true] ... = ... | b (line 84): true | +| Assert.cs:126:9:126:26 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:126:13:126:13 | [b (line 84): true] access to parameter b | b (line 84): true | +| Assert.cs:126:13:126:25 | [b (line 84): true] ... ? ... : ... | b (line 84): true | +| Assert.cs:126:17:126:20 | [b (line 84): true] null | b (line 84): true | +| Assert.cs:127:9:127:40 | [b (line 84): true] ...; | b (line 84): true | +| Assert.cs:127:24:127:24 | [b (line 84): true] access to local variable s | b (line 84): true | +| Assert.cs:127:24:127:32 | [b (line 84): true] ... != ... | b (line 84): true | +| Assert.cs:127:24:127:38 | [b (line 84): true] ... \|\| ... | b (line 84): true | +| Assert.cs:127:29:127:32 | [b (line 84): true] null | b (line 84): true | +| Assert.cs:127:37:127:38 | [b (line 84): true] !... | b (line 84): true | +| Assert.cs:127:38:127:38 | [b (line 84): true] access to parameter b | b (line 84): true | | Conditions.cs:6:13:6:13 | [inc (line 3): true] access to parameter x | inc (line 3): true | | Conditions.cs:6:13:6:15 | [inc (line 3): true] ...++ | inc (line 3): true | | Conditions.cs:6:13:6:16 | [inc (line 3): true] ...; | inc (line 3): true | @@ -160,6 +496,14 @@ booleanNode | Conditions.cs:137:21:137:37 | [Field1 (line 129): true, Field2 (line 129): true] call to method ToString | Field2 (line 129): true | | Conditions.cs:137:21:137:38 | [Field1 (line 129): true, Field2 (line 129): true] ...; | Field1 (line 129): true | | Conditions.cs:137:21:137:38 | [Field1 (line 129): true, Field2 (line 129): true] ...; | Field2 (line 129): true | +| Conditions.cs:145:13:145:29 | [b (line 143): false] String s = ... | b (line 143): false | +| Conditions.cs:145:13:145:29 | [b (line 143): true] String s = ... | b (line 143): true | +| Conditions.cs:145:21:145:23 | [b (line 143): true] "a" | b (line 143): true | +| Conditions.cs:145:27:145:29 | [b (line 143): false] "b" | b (line 143): false | +| Conditions.cs:146:9:149:49 | [b (line 143): false] if (...) ... | b (line 143): false | +| Conditions.cs:146:9:149:49 | [b (line 143): true] if (...) ... | b (line 143): true | +| Conditions.cs:146:13:146:13 | [b (line 143): false] access to parameter b | b (line 143): false | +| Conditions.cs:146:13:146:13 | [b (line 143): true] access to parameter b | b (line 143): true | | Finally.cs:180:21:180:43 | [b1 (line 176): true] throw ...; | b1 (line 176): true | | Finally.cs:180:27:180:42 | [b1 (line 176): true] object creation of type ExceptionA | b1 (line 176): true | | Finally.cs:183:9:192:9 | [b1 (line 176): false] {...} | b1 (line 176): false | @@ -224,8 +568,8 @@ booleanNode | Finally.cs:190:21:190:22 | [finally: exception(ExceptionA), b1 (line 176): true] access to parameter b1 | b1 (line 176): true | | LoopUnrolling.cs:58:9:64:9 | [b (line 55): false] foreach (... ... in ...) ... | b (line 55): false | | LoopUnrolling.cs:58:9:64:9 | [b (line 55): true] foreach (... ... in ...) ... | b (line 55): true | -| LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | b (line 55): false | -| LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | b (line 55): true | +| LoopUnrolling.cs:58:22:58:22 | [b (line 55): false] String x | b (line 55): false | +| LoopUnrolling.cs:58:22:58:22 | [b (line 55): true] String x | b (line 55): true | | LoopUnrolling.cs:59:9:64:9 | [b (line 55): false] {...} | b (line 55): false | | LoopUnrolling.cs:59:9:64:9 | [b (line 55): true] {...} | b (line 55): true | | LoopUnrolling.cs:60:13:61:37 | [b (line 55): false] if (...) ... | b (line 55): false | @@ -642,8 +986,20 @@ entryPoint | AccessorCalls.cs:66:10:66:11 | M9 | AccessorCalls.cs:67:5:74:5 | {...} | | ArrayCreation.cs:3:11:3:12 | M1 | ArrayCreation.cs:3:27:3:27 | 0 | | ArrayCreation.cs:5:12:5:13 | M2 | ArrayCreation.cs:5:28:5:28 | 0 | -| ArrayCreation.cs:7:11:7:12 | M3 | ArrayCreation.cs:7:19:7:36 | array creation of type Int32[] | -| ArrayCreation.cs:9:12:9:13 | M4 | ArrayCreation.cs:9:20:9:52 | array creation of type Int32[,] | +| ArrayCreation.cs:7:11:7:12 | M3 | ArrayCreation.cs:7:19:7:36 | 2 | +| ArrayCreation.cs:9:12:9:13 | M4 | ArrayCreation.cs:9:20:9:52 | 2 | +| Assert.cs:7:10:7:11 | M1 | Assert.cs:8:5:12:5 | {...} | +| Assert.cs:14:10:14:11 | M2 | Assert.cs:15:5:19:5 | {...} | +| Assert.cs:21:10:21:11 | M3 | Assert.cs:22:5:26:5 | {...} | +| Assert.cs:28:10:28:11 | M4 | Assert.cs:29:5:33:5 | {...} | +| Assert.cs:35:10:35:11 | M5 | Assert.cs:36:5:40:5 | {...} | +| Assert.cs:42:10:42:11 | M6 | Assert.cs:43:5:47:5 | {...} | +| Assert.cs:49:10:49:11 | M7 | Assert.cs:50:5:54:5 | {...} | +| Assert.cs:56:10:56:11 | M8 | Assert.cs:57:5:61:5 | {...} | +| Assert.cs:63:10:63:11 | M9 | Assert.cs:64:5:68:5 | {...} | +| Assert.cs:70:10:70:12 | M10 | Assert.cs:71:5:75:5 | {...} | +| Assert.cs:77:10:77:12 | M11 | Assert.cs:78:5:82:5 | {...} | +| Assert.cs:84:10:84:12 | M12 | Assert.cs:85:5:129:5 | {...} | | Assignments.cs:3:10:3:10 | M | Assignments.cs:4:5:15:5 | {...} | | Assignments.cs:14:18:14:35 | (...) => ... | Assignments.cs:14:33:14:35 | {...} | | Assignments.cs:17:40:17:40 | + | Assignments.cs:18:5:20:5 | {...} | @@ -656,6 +1012,7 @@ entryPoint | CompileTimeOperators.cs:15:10:15:15 | Typeof | CompileTimeOperators.cs:16:5:18:5 | {...} | | CompileTimeOperators.cs:20:12:20:17 | Nameof | CompileTimeOperators.cs:21:5:23:5 | {...} | | CompileTimeOperators.cs:28:10:28:10 | M | CompileTimeOperators.cs:29:5:41:5 | {...} | +| ConditionalAccess.cs:1:7:1:23 | ConditionalAccess | ConditionalAccess.cs:30:32:30:32 | 0 | | ConditionalAccess.cs:3:12:3:13 | M1 | ConditionalAccess.cs:3:26:3:26 | access to parameter i | | ConditionalAccess.cs:5:10:5:11 | M2 | ConditionalAccess.cs:5:26:5:26 | access to parameter s | | ConditionalAccess.cs:7:10:7:11 | M3 | ConditionalAccess.cs:7:39:7:46 | ... ?? ... | @@ -663,7 +1020,9 @@ entryPoint | ConditionalAccess.cs:11:9:11:10 | M5 | ConditionalAccess.cs:12:5:17:5 | {...} | | ConditionalAccess.cs:19:12:19:13 | M6 | ConditionalAccess.cs:19:40:19:41 | access to parameter s1 | | ConditionalAccess.cs:21:10:21:11 | M7 | ConditionalAccess.cs:22:5:26:5 | {...} | -| ConditionalAccess.cs:31:26:31:38 | CommaJoinWith | ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | +| ConditionalAccess.cs:30:10:30:12 | Out | ConditionalAccess.cs:30:32:30:32 | 0 | +| ConditionalAccess.cs:32:10:32:11 | M8 | ConditionalAccess.cs:33:5:36:5 | {...} | +| ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | | Conditions.cs:3:10:3:19 | IncrOrDecr | Conditions.cs:4:5:9:5 | {...} | | Conditions.cs:11:9:11:10 | M1 | Conditions.cs:12:5:20:5 | {...} | | Conditions.cs:22:9:22:10 | M2 | Conditions.cs:23:5:31:5 | {...} | @@ -675,6 +1034,7 @@ entryPoint | Conditions.cs:102:12:102:13 | M8 | Conditions.cs:103:5:111:5 | {...} | | Conditions.cs:113:10:113:11 | M9 | Conditions.cs:114:5:124:5 | {...} | | Conditions.cs:129:10:129:12 | M10 | Conditions.cs:130:5:141:5 | {...} | +| Conditions.cs:143:10:143:12 | M11 | Conditions.cs:144:5:150:5 | {...} | | ExitMethods.cs:7:10:7:11 | M1 | ExitMethods.cs:8:5:11:5 | {...} | | ExitMethods.cs:13:10:13:11 | M2 | ExitMethods.cs:14:5:17:5 | {...} | | ExitMethods.cs:19:10:19:11 | M3 | ExitMethods.cs:20:5:23:5 | {...} | @@ -733,6 +1093,66 @@ entryPoint | LoopUnrolling.cs:45:10:45:11 | M6 | LoopUnrolling.cs:46:5:53:5 | {...} | | LoopUnrolling.cs:55:10:55:11 | M7 | LoopUnrolling.cs:56:5:65:5 | {...} | | LoopUnrolling.cs:67:10:67:11 | M8 | LoopUnrolling.cs:68:5:74:5 | {...} | +| LoopUnrolling.cs:76:10:76:11 | M9 | LoopUnrolling.cs:77:5:83:5 | {...} | +| LoopUnrolling.cs:85:10:85:12 | M10 | LoopUnrolling.cs:86:5:92:5 | {...} | +| LoopUnrolling.cs:94:10:94:12 | M11 | LoopUnrolling.cs:95:5:101:5 | {...} | +| MultiImplementationA.cs:6:22:6:31 | get_P1 | MultiImplementationA.cs:6:28:6:31 | null | +| MultiImplementationA.cs:6:22:6:31 | get_P1 | MultiImplementationB.cs:3:22:3:22 | 0 | +| MultiImplementationA.cs:7:21:7:23 | get_P2 | MultiImplementationA.cs:7:25:7:39 | {...} | +| MultiImplementationA.cs:7:21:7:23 | get_P2 | MultiImplementationB.cs:4:25:4:37 | {...} | +| MultiImplementationA.cs:7:41:7:43 | set_P2 | MultiImplementationA.cs:7:45:7:59 | {...} | +| MultiImplementationA.cs:7:41:7:43 | set_P2 | MultiImplementationB.cs:4:43:4:45 | {...} | +| MultiImplementationA.cs:8:16:8:16 | M | MultiImplementationA.cs:8:29:8:32 | null | +| MultiImplementationA.cs:8:16:8:16 | M | MultiImplementationB.cs:5:23:5:23 | 2 | +| MultiImplementationA.cs:14:31:14:31 | get_Item | MultiImplementationA.cs:14:31:14:31 | access to parameter i | +| MultiImplementationA.cs:14:31:14:31 | get_Item | MultiImplementationB.cs:12:37:12:40 | null | +| MultiImplementationA.cs:15:36:15:38 | get_Item | MultiImplementationA.cs:15:40:15:52 | {...} | +| MultiImplementationA.cs:15:36:15:38 | get_Item | MultiImplementationB.cs:13:40:13:54 | {...} | +| MultiImplementationA.cs:15:54:15:56 | set_Item | MultiImplementationA.cs:15:58:15:60 | {...} | +| MultiImplementationA.cs:15:54:15:56 | set_Item | MultiImplementationB.cs:13:60:13:62 | {...} | +| MultiImplementationA.cs:16:17:16:18 | M1 | MultiImplementationA.cs:17:5:19:5 | {...} | +| MultiImplementationA.cs:16:17:16:18 | M1 | MultiImplementationB.cs:15:5:17:5 | {...} | +| MultiImplementationA.cs:18:9:18:22 | M2 | MultiImplementationA.cs:18:21:18:21 | 0 | +| MultiImplementationA.cs:20:12:20:13 | C2 | MultiImplementationA.cs:13:16:13:16 | this access | +| MultiImplementationA.cs:20:12:20:13 | C2 | MultiImplementationB.cs:11:16:11:16 | this access | +| MultiImplementationA.cs:21:12:21:13 | C2 | MultiImplementationA.cs:21:24:21:24 | 0 | +| MultiImplementationA.cs:21:12:21:13 | C2 | MultiImplementationB.cs:19:24:19:24 | 1 | +| MultiImplementationA.cs:22:6:22:7 | ~C2 | MultiImplementationA.cs:22:11:22:13 | {...} | +| MultiImplementationA.cs:22:6:22:7 | ~C2 | MultiImplementationB.cs:20:11:20:25 | {...} | +| MultiImplementationA.cs:23:28:23:35 | implicit conversion | MultiImplementationA.cs:23:50:23:53 | null | +| MultiImplementationA.cs:23:28:23:35 | implicit conversion | MultiImplementationB.cs:21:56:21:59 | null | +| MultiImplementationA.cs:30:21:30:23 | get_P3 | MultiImplementationA.cs:30:34:30:37 | null | +| MultiImplementationA.cs:36:9:36:10 | M1 | MultiImplementationA.cs:36:14:36:28 | {...} | +| MultiImplementationA.cs:36:9:36:10 | M1 | MultiImplementationB.cs:32:17:32:17 | 0 | +| MultiImplementationA.cs:37:9:37:10 | M2 | MultiImplementationA.cs:37:14:37:28 | {...} | +| MultiImplementationB.cs:3:22:3:22 | get_P1 | MultiImplementationA.cs:6:28:6:31 | null | +| MultiImplementationB.cs:3:22:3:22 | get_P1 | MultiImplementationB.cs:3:22:3:22 | 0 | +| MultiImplementationB.cs:4:21:4:23 | get_P2 | MultiImplementationA.cs:7:25:7:39 | {...} | +| MultiImplementationB.cs:4:21:4:23 | get_P2 | MultiImplementationB.cs:4:25:4:37 | {...} | +| MultiImplementationB.cs:4:39:4:41 | set_P2 | MultiImplementationA.cs:7:45:7:59 | {...} | +| MultiImplementationB.cs:4:39:4:41 | set_P2 | MultiImplementationB.cs:4:43:4:45 | {...} | +| MultiImplementationB.cs:5:16:5:16 | M | MultiImplementationA.cs:8:29:8:32 | null | +| MultiImplementationB.cs:5:16:5:16 | M | MultiImplementationB.cs:5:23:5:23 | 2 | +| MultiImplementationB.cs:12:31:12:40 | get_Item | MultiImplementationA.cs:14:31:14:31 | access to parameter i | +| MultiImplementationB.cs:12:31:12:40 | get_Item | MultiImplementationB.cs:12:37:12:40 | null | +| MultiImplementationB.cs:13:36:13:38 | get_Item | MultiImplementationA.cs:15:40:15:52 | {...} | +| MultiImplementationB.cs:13:36:13:38 | get_Item | MultiImplementationB.cs:13:40:13:54 | {...} | +| MultiImplementationB.cs:13:56:13:58 | set_Item | MultiImplementationA.cs:15:58:15:60 | {...} | +| MultiImplementationB.cs:13:56:13:58 | set_Item | MultiImplementationB.cs:13:60:13:62 | {...} | +| MultiImplementationB.cs:14:17:14:18 | M1 | MultiImplementationA.cs:17:5:19:5 | {...} | +| MultiImplementationB.cs:14:17:14:18 | M1 | MultiImplementationB.cs:15:5:17:5 | {...} | +| MultiImplementationB.cs:16:9:16:31 | M2 | MultiImplementationB.cs:16:27:16:30 | null | +| MultiImplementationB.cs:18:12:18:13 | C2 | MultiImplementationA.cs:13:16:13:16 | this access | +| MultiImplementationB.cs:18:12:18:13 | C2 | MultiImplementationB.cs:11:16:11:16 | this access | +| MultiImplementationB.cs:19:12:19:13 | C2 | MultiImplementationA.cs:21:24:21:24 | 0 | +| MultiImplementationB.cs:19:12:19:13 | C2 | MultiImplementationB.cs:19:24:19:24 | 1 | +| MultiImplementationB.cs:20:6:20:7 | ~C2 | MultiImplementationA.cs:22:11:22:13 | {...} | +| MultiImplementationB.cs:20:6:20:7 | ~C2 | MultiImplementationB.cs:20:11:20:25 | {...} | +| MultiImplementationB.cs:21:28:21:35 | implicit conversion | MultiImplementationA.cs:23:50:23:53 | null | +| MultiImplementationB.cs:21:28:21:35 | implicit conversion | MultiImplementationB.cs:21:56:21:59 | null | +| MultiImplementationB.cs:27:21:27:23 | get_P3 | MultiImplementationA.cs:30:34:30:37 | null | +| MultiImplementationB.cs:32:9:32:10 | M1 | MultiImplementationA.cs:36:14:36:28 | {...} | +| MultiImplementationB.cs:32:9:32:10 | M1 | MultiImplementationB.cs:32:17:32:17 | 0 | | NullCoalescing.cs:3:9:3:10 | M1 | NullCoalescing.cs:3:23:3:28 | ... ?? ... | | NullCoalescing.cs:5:9:5:10 | M2 | NullCoalescing.cs:5:24:5:43 | ... ? ... : ... | | NullCoalescing.cs:7:12:7:13 | M3 | NullCoalescing.cs:7:40:7:53 | ... ?? ... | @@ -758,6 +1178,7 @@ entryPoint | Switch.cs:129:12:129:14 | M12 | Switch.cs:130:5:132:5 | {...} | | Switch.cs:134:9:134:11 | M13 | Switch.cs:135:5:142:5 | {...} | | Switch.cs:144:9:144:11 | M14 | Switch.cs:145:5:152:5 | {...} | +| Switch.cs:154:10:154:12 | M15 | Switch.cs:155:5:161:5 | {...} | | TypeAccesses.cs:3:10:3:10 | M | TypeAccesses.cs:4:5:9:5 | {...} | | VarDecls.cs:5:18:5:19 | M1 | VarDecls.cs:6:5:11:5 | {...} | | VarDecls.cs:13:12:13:13 | M2 | VarDecls.cs:14:5:17:5 | {...} | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Switch.cs b/csharp/ql/test/library-tests/controlflow/graph/Switch.cs index 6b670908224d..45912ead10e5 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Switch.cs +++ b/csharp/ql/test/library-tests/controlflow/graph/Switch.cs @@ -25,7 +25,7 @@ void M2(object o) Console.WriteLine(s); return; case double d when Throw(): - Label: + Label: return; default: goto Label; @@ -56,10 +56,10 @@ void M5() { switch (1 + 2) { - case 2 : - break; - case 3 : - break; + case 2: + break; + case 3: + break; } } @@ -67,10 +67,10 @@ void M6(string s) { switch ((object)s) { - case int _ : - break; - case "" : - break; + case int _: + break; + case "": + break; } } @@ -78,12 +78,12 @@ bool M7(int i, int j) { switch (i) { - case 1 : - return true; - case 2 : - if (j > 2) - break; - return true; + case 1: + return true; + case 2: + if (j > 2) + break; + return true; } return false; } @@ -92,8 +92,8 @@ bool M8(object o) { switch (o) { - case int _ : - return true; + case int _: + return true; } return false; } @@ -102,8 +102,8 @@ int M9(string s) { switch (s?.Length) { - case 0 : return 0; - case 1 : return 1; + case 0: return 0; + case 1: return 1; } return -1; } @@ -114,8 +114,8 @@ int M10(string s) { switch (s.Length) { - case 3 when s=="foo" : return 1; - case 2 when s=="fu" : return 2; + case 3 when s == "foo": return 1; + case 2 when s == "fu": return 2; } return -1; } @@ -150,4 +150,13 @@ int M14(int i) case 2: return 2; } } + + void M15(bool b) + { + var s = b switch { true => "a", false => "b" }; + if (b) + System.Console.WriteLine($"a = {s}"); + else + System.Console.WriteLine($"b = {s}"); + } } diff --git a/csharp/ql/test/library-tests/controlflow/guards/AbstractValue.expected b/csharp/ql/test/library-tests/controlflow/guards/AbstractValue.expected index 25bc436216bf..cff9d3249ef8 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/AbstractValue.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/AbstractValue.expected @@ -18,7 +18,7 @@ abstractValue | 0 | Collections.cs:78:36:78:36 | 0 | | 0 | Collections.cs:80:35:80:35 | 0 | | 0 | Collections.cs:81:36:81:36 | 0 | -| 0 | Collections.cs:87:17:87:31 | 0 | +| 0 | Collections.cs:87:17:87:32 | 0 | | 0 | Guards.cs:12:24:12:24 | 0 | | 0 | Guards.cs:78:26:78:26 | 0 | | 0 | Guards.cs:80:25:80:25 | 0 | @@ -32,7 +32,7 @@ abstractValue | 0 | Guards.cs:322:18:322:18 | 0 | | 0 | Guards.cs:329:17:329:19 | access to constant A | | 0 | Guards.cs:334:20:334:20 | 0 | -| 0 | Splitting.cs:136:20:136:20 | 0 | +| 0 | Splitting.cs:137:20:137:20 | 0 | | 1 | Collections.cs:13:28:13:28 | 1 | | 1 | Collections.cs:15:28:15:28 | 1 | | 1 | Collections.cs:18:28:18:28 | 1 | @@ -59,8 +59,8 @@ abstractValue | 1 | Guards.cs:331:17:331:19 | access to constant B | | 1 | Guards.cs:334:13:334:15 | access to constant B | | 1 | Guards.cs:335:18:335:18 | 1 | -| 3 | Collections.cs:55:13:55:41 | 3 | -| 3 | Collections.cs:63:17:63:45 | 3 | +| 3 | Collections.cs:55:13:55:42 | 3 | +| 3 | Collections.cs:63:17:63:46 | 3 | | 10 | Guards.cs:84:25:84:26 | 10 | | 10 | Guards.cs:86:26:86:27 | 10 | | empty | Collections.cs:54:13:54:16 | access to parameter args | @@ -69,22 +69,22 @@ abstractValue | empty | Collections.cs:58:9:58:13 | ... = ... | | empty | Collections.cs:58:13:58:13 | access to local variable x | | empty | Collections.cs:65:13:65:13 | access to local variable x | -| empty | Collections.cs:87:17:87:31 | array creation of type String[] | -| empty | Collections.cs:87:30:87:31 | { ..., ... } | -| empty | Collections.cs:88:22:88:23 | { ..., ... } | +| empty | Collections.cs:87:17:87:32 | array creation of type String[] | +| empty | Collections.cs:87:30:87:32 | { ..., ... } | +| empty | Collections.cs:88:22:88:24 | { ..., ... } | | false | Guards.cs:178:16:178:20 | false | | false | Guards.cs:181:53:181:57 | false | | false | Guards.cs:217:18:217:22 | false | | false | Guards.cs:228:18:228:22 | false | | false | Guards.cs:295:18:295:22 | false | | false | Guards.cs:305:18:305:22 | false | -| non-empty | Collections.cs:55:9:55:41 | ... = ... | -| non-empty | Collections.cs:55:13:55:41 | array creation of type String[] | -| non-empty | Collections.cs:55:25:55:41 | { ..., ... } | +| non-empty | Collections.cs:55:9:55:42 | ... = ... | +| non-empty | Collections.cs:55:13:55:42 | array creation of type String[] | +| non-empty | Collections.cs:55:26:55:42 | { ..., ... } | | non-empty | Collections.cs:56:9:56:13 | ... = ... | | non-empty | Collections.cs:56:13:56:13 | access to local variable x | -| non-empty | Collections.cs:63:17:63:45 | array creation of type String[] | -| non-empty | Collections.cs:63:29:63:45 | { ..., ... } | +| non-empty | Collections.cs:63:17:63:46 | array creation of type String[] | +| non-empty | Collections.cs:63:30:63:46 | { ..., ... } | | non-empty | Collections.cs:68:13:68:13 | access to local variable x | | non-empty | Collections.cs:89:9:89:32 | ... = ... | | non-empty | Collections.cs:89:13:89:32 | array creation of type String[] | @@ -155,11 +155,11 @@ abstractValue | non-null | Collections.cs:54:13:54:16 | access to parameter args | | non-null | Collections.cs:54:13:54:26 | call to method ToArray | | non-null | Collections.cs:55:9:55:9 | access to local variable x | -| non-null | Collections.cs:55:9:55:41 | ... = ... | -| non-null | Collections.cs:55:13:55:41 | array creation of type String[] | -| non-null | Collections.cs:55:27:55:29 | "a" | -| non-null | Collections.cs:55:32:55:34 | "b" | -| non-null | Collections.cs:55:37:55:39 | "c" | +| non-null | Collections.cs:55:9:55:42 | ... = ... | +| non-null | Collections.cs:55:13:55:42 | array creation of type String[] | +| non-null | Collections.cs:55:28:55:30 | "a" | +| non-null | Collections.cs:55:33:55:35 | "b" | +| non-null | Collections.cs:55:38:55:40 | "c" | | non-null | Collections.cs:56:9:56:9 | access to local variable x | | non-null | Collections.cs:56:9:56:13 | ... = ... | | non-null | Collections.cs:56:13:56:13 | access to local variable x | @@ -169,11 +169,11 @@ abstractValue | non-null | Collections.cs:58:9:58:9 | access to local variable x | | non-null | Collections.cs:58:9:58:13 | ... = ... | | non-null | Collections.cs:58:13:58:13 | access to local variable x | -| non-null | Collections.cs:63:17:63:45 | array creation of type String[] | -| non-null | Collections.cs:63:17:63:54 | call to method ToList | -| non-null | Collections.cs:63:31:63:33 | "a" | -| non-null | Collections.cs:63:36:63:38 | "b" | -| non-null | Collections.cs:63:41:63:43 | "c" | +| non-null | Collections.cs:63:17:63:46 | array creation of type String[] | +| non-null | Collections.cs:63:17:63:55 | call to method ToList | +| non-null | Collections.cs:63:32:63:34 | "a" | +| non-null | Collections.cs:63:37:63:39 | "b" | +| non-null | Collections.cs:63:42:63:44 | "c" | | non-null | Collections.cs:64:9:64:9 | access to local variable x | | non-null | Collections.cs:65:13:65:13 | access to local variable x | | non-null | Collections.cs:67:13:67:13 | access to local variable x | @@ -214,14 +214,20 @@ abstractValue | non-null | Collections.cs:82:24:82:30 | access to local function IsEmpty | | non-null | Collections.cs:82:24:82:30 | delegate creation of type Func | | non-null | Collections.cs:82:24:82:30 | this access | -| non-null | Collections.cs:87:17:87:31 | array creation of type String[] | -| non-null | Collections.cs:88:22:88:23 | array creation of type String[] | +| non-null | Collections.cs:87:17:87:32 | array creation of type String[] | +| non-null | Collections.cs:88:22:88:24 | array creation of type String[] | | non-null | Collections.cs:89:9:89:9 | access to local variable x | | non-null | Collections.cs:89:9:89:32 | ... = ... | | non-null | Collections.cs:89:13:89:32 | array creation of type String[] | | non-null | Collections.cs:89:28:89:30 | "a" | | non-null | Collections.cs:90:22:90:28 | array creation of type String[] | | non-null | Collections.cs:90:24:90:26 | "a" | +| non-null | Collections.cs:95:29:95:32 | access to parameter args | +| non-null | Collections.cs:96:13:96:19 | access to type Console | +| non-null | Collections.cs:96:31:96:34 | access to parameter args | +| non-null | Collections.cs:101:29:101:32 | access to parameter args | +| non-null | Collections.cs:103:9:103:15 | access to type Console | +| non-null | Collections.cs:103:27:103:30 | access to parameter args | | non-null | Guards.cs:12:13:12:13 | access to parameter s | | non-null | Guards.cs:14:13:14:19 | access to type Console | | non-null | Guards.cs:14:31:14:31 | access to parameter s | @@ -359,6 +365,9 @@ abstractValue | non-null | Guards.cs:281:17:281:17 | access to local variable a | | non-null | Guards.cs:283:17:283:17 | access to parameter o | | non-null | Guards.cs:287:17:287:17 | access to parameter o | +| non-null | Guards.cs:341:31:341:32 | "" | +| non-null | Guards.cs:343:13:343:19 | access to type Console | +| non-null | Guards.cs:343:31:343:31 | access to local variable s | | non-null | Splitting.cs:13:17:13:17 | access to parameter o | | non-null | Splitting.cs:23:24:23:24 | access to parameter o | | non-null | Splitting.cs:33:24:33:25 | "" | @@ -378,12 +387,13 @@ abstractValue | non-null | Splitting.cs:117:9:117:9 | access to parameter o | | non-null | Splitting.cs:119:13:119:13 | access to parameter o | | non-null | Splitting.cs:120:16:120:16 | access to parameter o | -| non-null | Splitting.cs:132:17:132:17 | access to local variable o | -| non-null | Splitting.cs:132:17:132:29 | ... = ... | -| non-null | Splitting.cs:132:21:132:29 | call to method M11 | -| non-null | Splitting.cs:132:21:132:29 | this access | -| non-null | Splitting.cs:132:28:132:28 | access to local variable o | +| non-null | Splitting.cs:129:17:129:17 | access to local variable o | | non-null | Splitting.cs:133:17:133:17 | access to local variable o | +| non-null | Splitting.cs:133:17:133:29 | ... = ... | +| non-null | Splitting.cs:133:21:133:29 | call to method M11 | +| non-null | Splitting.cs:133:21:133:29 | this access | +| non-null | Splitting.cs:133:28:133:28 | access to local variable o | +| non-null | Splitting.cs:134:17:134:17 | access to local variable o | | null | Assert.cs:9:24:9:27 | null | | null | Assert.cs:10:27:10:30 | null | | null | Assert.cs:16:24:16:27 | null | @@ -432,6 +442,8 @@ abstractValue | null | Guards.cs:181:39:181:42 | null | | null | Guards.cs:185:43:185:46 | null | | null | Guards.cs:203:18:203:21 | null | +| null | Guards.cs:341:24:341:27 | null | +| null | Guards.cs:342:18:342:21 | null | | null | Splitting.cs:12:22:12:25 | null | | null | Splitting.cs:22:22:22:25 | null | | null | Splitting.cs:32:22:32:25 | null | @@ -444,7 +456,7 @@ abstractValue | null | Splitting.cs:105:27:105:30 | null | | null | Splitting.cs:116:27:116:30 | null | | null | Splitting.cs:125:21:125:24 | null | -| null | Splitting.cs:128:22:128:25 | null | +| null | Splitting.cs:129:22:129:25 | null | | true | Guards.cs:177:20:177:23 | true | | true | Guards.cs:181:46:181:49 | true | | true | Guards.cs:185:50:185:53 | true | diff --git a/csharp/ql/test/library-tests/controlflow/guards/BooleanGuardedExpr.expected b/csharp/ql/test/library-tests/controlflow/guards/BooleanGuardedExpr.expected index 2aa76cde6a0c..2264c96644f6 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/BooleanGuardedExpr.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/BooleanGuardedExpr.expected @@ -5,16 +5,12 @@ | Assert.cs:53:27:53:27 | access to local variable s | Assert.cs:52:24:52:32 | ... == ... | Assert.cs:52:24:52:24 | access to local variable s | false | | Assert.cs:59:36:59:36 | access to parameter b | Assert.cs:58:20:58:20 | access to parameter b | Assert.cs:58:20:58:20 | access to parameter b | false | | Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:31 | ... != ... | Assert.cs:59:23:59:23 | access to local variable s | true | -| Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:36 | ... && ... | Assert.cs:59:23:59:23 | access to local variable s | true | | Assert.cs:66:37:66:37 | access to parameter b | Assert.cs:65:20:65:20 | access to parameter b | Assert.cs:65:20:65:20 | access to parameter b | false | | Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:32 | ... == ... | Assert.cs:66:24:66:24 | access to local variable s | false | -| Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:37 | ... \|\| ... | Assert.cs:66:24:66:24 | access to local variable s | false | | Assert.cs:73:36:73:36 | access to parameter b | Assert.cs:72:20:72:20 | access to parameter b | Assert.cs:72:20:72:20 | access to parameter b | true | | Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:31 | ... == ... | Assert.cs:73:23:73:23 | access to local variable s | true | -| Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:36 | ... && ... | Assert.cs:73:23:73:23 | access to local variable s | true | | Assert.cs:80:37:80:37 | access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | true | | Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:32 | ... != ... | Assert.cs:80:24:80:24 | access to local variable s | false | -| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:37 | ... \|\| ... | Assert.cs:80:24:80:24 | access to local variable s | false | | Collections.cs:52:17:52:20 | access to parameter args | Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | false | | Collections.cs:53:9:53:12 | access to parameter args | Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | false | | Collections.cs:54:13:54:16 | access to parameter args | Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | false | @@ -75,6 +71,8 @@ | Guards.cs:208:17:208:17 | access to parameter o | Guards.cs:203:13:203:21 | ... != ... | Guards.cs:203:13:203:13 | access to parameter o | true | | Guards.cs:269:13:269:14 | access to parameter o1 | Guards.cs:268:13:268:41 | call to operator == | Guards.cs:268:13:268:14 | access to parameter o1 | true | | Guards.cs:271:13:271:14 | access to parameter o1 | Guards.cs:270:13:270:42 | call to operator == | Guards.cs:270:13:270:14 | access to parameter o1 | true | +| Guards.cs:342:27:342:27 | access to parameter b | Guards.cs:341:20:341:20 | access to parameter b | Guards.cs:341:20:341:20 | access to parameter b | false | +| Guards.cs:343:31:343:31 | access to local variable s | Guards.cs:342:13:342:21 | ... != ... | Guards.cs:342:13:342:13 | access to local variable s | true | | Splitting.cs:13:17:13:17 | access to parameter o | Splitting.cs:12:17:12:25 | ... != ... | Splitting.cs:12:17:12:17 | access to parameter o | true | | Splitting.cs:23:24:23:24 | access to parameter o | Splitting.cs:22:17:22:25 | ... != ... | Splitting.cs:22:17:22:17 | access to parameter o | true | | Splitting.cs:25:13:25:13 | access to parameter o | Splitting.cs:22:17:22:25 | ... != ... | Splitting.cs:22:17:22:17 | access to parameter o | false | @@ -93,4 +91,4 @@ | Splitting.cs:117:9:117:9 | access to parameter o | Splitting.cs:116:22:116:30 | ... != ... | Splitting.cs:116:22:116:22 | access to parameter o | true | | Splitting.cs:119:13:119:13 | access to parameter o | Splitting.cs:116:22:116:30 | ... != ... | Splitting.cs:116:22:116:22 | access to parameter o | true | | Splitting.cs:120:16:120:16 | access to parameter o | Splitting.cs:116:22:116:30 | ... != ... | Splitting.cs:116:22:116:22 | access to parameter o | true | -| Splitting.cs:132:25:132:25 | access to parameter b | Splitting.cs:130:21:130:21 | access to parameter b | Splitting.cs:130:21:130:21 | access to parameter b | false | +| Splitting.cs:133:25:133:25 | access to parameter b | Splitting.cs:131:21:131:21 | access to parameter b | Splitting.cs:131:21:131:21 | access to parameter b | false | diff --git a/csharp/ql/test/library-tests/controlflow/guards/Collections.cs b/csharp/ql/test/library-tests/controlflow/guards/Collections.cs index 65f07491ae54..93a19595c84e 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/Collections.cs +++ b/csharp/ql/test/library-tests/controlflow/guards/Collections.cs @@ -52,7 +52,7 @@ void M5(List args) var x = args.ToArray(); args.Clear(); x = args.ToArray(); - x = new string[]{ "a", "b", "c" }; + x = new string[] { "a", "b", "c" }; x = x; x = new string[0]; x = x; @@ -60,7 +60,7 @@ void M5(List args) void M6() { - var x = new string[]{ "a", "b", "c" }.ToList(); + var x = new string[] { "a", "b", "c" }.ToList(); x.Clear(); if (x.Count == 0) { @@ -84,10 +84,23 @@ void M7(string[] args) void M8() { - var x = new string[] {}; - string[] y = {}; + var x = new string[] { }; + string[] y = { }; x = new string[] { "a" }; string[] z = { "a" }; } + + void M9(string[] args) + { + foreach (var arg in args) + Console.WriteLine(args); // guarded by `args` being non-empty + } + + void M10(string[] args) + { + foreach (var arg in args) + ; + Console.WriteLine(args); + } } diff --git a/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.expected b/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.expected index 7a4cbaf0df49..a61814184f7e 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.expected @@ -10,26 +10,34 @@ | Assert.cs:46:27:46:27 | access to local variable s | Assert.cs:45:24:45:32 | ... != ... | Assert.cs:45:24:45:24 | access to local variable s | false | | Assert.cs:53:27:53:27 | access to local variable s | Assert.cs:52:24:52:24 | access to local variable s | Assert.cs:52:24:52:24 | access to local variable s | non-null | | Assert.cs:53:27:53:27 | access to local variable s | Assert.cs:52:24:52:32 | ... == ... | Assert.cs:52:24:52:24 | access to local variable s | false | -| Assert.cs:59:36:59:36 | access to parameter b | Assert.cs:58:20:58:20 | access to parameter b | Assert.cs:58:20:58:20 | access to parameter b | false | -| Assert.cs:59:36:59:36 | access to parameter b | Assert.cs:58:20:58:32 | ... ? ... : ... | Assert.cs:58:20:58:20 | access to parameter b | non-null | +| Assert.cs:59:36:59:36 | [b (line 56): false] access to parameter b | Assert.cs:58:20:58:20 | access to parameter b | Assert.cs:58:20:58:20 | access to parameter b | false | +| Assert.cs:59:36:59:36 | [b (line 56): false] access to parameter b | Assert.cs:58:20:58:32 | ... ? ... : ... | Assert.cs:58:20:58:20 | access to parameter b | non-null | +| Assert.cs:59:36:59:36 | [b (line 56): true] access to parameter b | Assert.cs:58:20:58:20 | access to parameter b | Assert.cs:58:20:58:20 | access to parameter b | false | +| Assert.cs:59:36:59:36 | [b (line 56): true] access to parameter b | Assert.cs:58:20:58:20 | access to parameter b | Assert.cs:58:20:58:20 | access to parameter b | true | +| Assert.cs:59:36:59:36 | [b (line 56): true] access to parameter b | Assert.cs:58:20:58:32 | ... ? ... : ... | Assert.cs:58:20:58:20 | access to parameter b | non-null | | Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:23 | access to local variable s | Assert.cs:59:23:59:23 | access to local variable s | non-null | | Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:31 | ... != ... | Assert.cs:59:23:59:23 | access to local variable s | true | -| Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:36 | ... && ... | Assert.cs:59:23:59:23 | access to local variable s | true | -| Assert.cs:66:37:66:37 | access to parameter b | Assert.cs:65:20:65:20 | access to parameter b | Assert.cs:65:20:65:20 | access to parameter b | false | -| Assert.cs:66:37:66:37 | access to parameter b | Assert.cs:65:20:65:32 | ... ? ... : ... | Assert.cs:65:20:65:20 | access to parameter b | non-null | +| Assert.cs:66:37:66:37 | [b (line 63): false] access to parameter b | Assert.cs:65:20:65:20 | access to parameter b | Assert.cs:65:20:65:20 | access to parameter b | false | +| Assert.cs:66:37:66:37 | [b (line 63): false] access to parameter b | Assert.cs:65:20:65:32 | ... ? ... : ... | Assert.cs:65:20:65:20 | access to parameter b | non-null | +| Assert.cs:66:37:66:37 | [b (line 63): true] access to parameter b | Assert.cs:65:20:65:20 | access to parameter b | Assert.cs:65:20:65:20 | access to parameter b | false | +| Assert.cs:66:37:66:37 | [b (line 63): true] access to parameter b | Assert.cs:65:20:65:20 | access to parameter b | Assert.cs:65:20:65:20 | access to parameter b | true | +| Assert.cs:66:37:66:37 | [b (line 63): true] access to parameter b | Assert.cs:65:20:65:32 | ... ? ... : ... | Assert.cs:65:20:65:20 | access to parameter b | non-null | | Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:24 | access to local variable s | Assert.cs:66:24:66:24 | access to local variable s | non-null | | Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:32 | ... == ... | Assert.cs:66:24:66:24 | access to local variable s | false | -| Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:37 | ... \|\| ... | Assert.cs:66:24:66:24 | access to local variable s | false | -| Assert.cs:73:36:73:36 | access to parameter b | Assert.cs:72:20:72:20 | access to parameter b | Assert.cs:72:20:72:20 | access to parameter b | true | -| Assert.cs:73:36:73:36 | access to parameter b | Assert.cs:72:20:72:32 | ... ? ... : ... | Assert.cs:72:20:72:20 | access to parameter b | null | +| Assert.cs:73:36:73:36 | [b (line 70): false] access to parameter b | Assert.cs:72:20:72:20 | access to parameter b | Assert.cs:72:20:72:20 | access to parameter b | false | +| Assert.cs:73:36:73:36 | [b (line 70): false] access to parameter b | Assert.cs:72:20:72:20 | access to parameter b | Assert.cs:72:20:72:20 | access to parameter b | true | +| Assert.cs:73:36:73:36 | [b (line 70): false] access to parameter b | Assert.cs:72:20:72:32 | ... ? ... : ... | Assert.cs:72:20:72:20 | access to parameter b | null | +| Assert.cs:73:36:73:36 | [b (line 70): true] access to parameter b | Assert.cs:72:20:72:20 | access to parameter b | Assert.cs:72:20:72:20 | access to parameter b | true | +| Assert.cs:73:36:73:36 | [b (line 70): true] access to parameter b | Assert.cs:72:20:72:32 | ... ? ... : ... | Assert.cs:72:20:72:20 | access to parameter b | null | | Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:23 | access to local variable s | Assert.cs:73:23:73:23 | access to local variable s | null | | Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:31 | ... == ... | Assert.cs:73:23:73:23 | access to local variable s | true | -| Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:36 | ... && ... | Assert.cs:73:23:73:23 | access to local variable s | true | -| Assert.cs:80:37:80:37 | access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | true | -| Assert.cs:80:37:80:37 | access to parameter b | Assert.cs:79:20:79:32 | ... ? ... : ... | Assert.cs:79:20:79:20 | access to parameter b | null | +| Assert.cs:80:37:80:37 | [b (line 77): false] access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | false | +| Assert.cs:80:37:80:37 | [b (line 77): false] access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | true | +| Assert.cs:80:37:80:37 | [b (line 77): false] access to parameter b | Assert.cs:79:20:79:32 | ... ? ... : ... | Assert.cs:79:20:79:20 | access to parameter b | null | +| Assert.cs:80:37:80:37 | [b (line 77): true] access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | true | +| Assert.cs:80:37:80:37 | [b (line 77): true] access to parameter b | Assert.cs:79:20:79:32 | ... ? ... : ... | Assert.cs:79:20:79:20 | access to parameter b | null | | Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:24 | access to local variable s | Assert.cs:80:24:80:24 | access to local variable s | null | | Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:32 | ... != ... | Assert.cs:80:24:80:24 | access to local variable s | false | -| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:37 | ... \|\| ... | Assert.cs:80:24:80:24 | access to local variable s | false | | Collections.cs:52:17:52:20 | access to parameter args | Collections.cs:50:13:50:16 | access to parameter args | Collections.cs:50:13:50:16 | access to parameter args | non-empty | | Collections.cs:52:17:52:20 | access to parameter args | Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | false | | Collections.cs:53:9:53:12 | access to parameter args | Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | false | @@ -37,6 +45,7 @@ | Collections.cs:67:13:67:13 | access to local variable x | Collections.cs:65:13:65:13 | access to local variable x | Collections.cs:65:13:65:13 | access to local variable x | empty | | Collections.cs:67:13:67:13 | access to local variable x | Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | true | | Collections.cs:68:13:68:13 | access to local variable x | Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | true | +| Collections.cs:96:31:96:34 | access to parameter args | Collections.cs:95:29:95:32 | access to parameter args | Collections.cs:95:29:95:32 | access to parameter args | non-empty | | Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null | | Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:24 | ... == ... | Guards.cs:10:16:10:16 | access to parameter s | false | | Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null | @@ -191,6 +200,13 @@ | Guards.cs:287:17:287:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match access to type Action | | Guards.cs:287:17:287:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match null | | Guards.cs:287:17:287:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-null | +| Guards.cs:342:27:342:27 | [b (line 339): false] access to parameter b | Guards.cs:341:20:341:20 | access to parameter b | Guards.cs:341:20:341:20 | access to parameter b | false | +| Guards.cs:342:27:342:27 | [b (line 339): false] access to parameter b | Guards.cs:341:20:341:32 | ... ? ... : ... | Guards.cs:341:20:341:20 | access to parameter b | non-null | +| Guards.cs:342:27:342:27 | [b (line 339): true] access to parameter b | Guards.cs:341:20:341:20 | access to parameter b | Guards.cs:341:20:341:20 | access to parameter b | false | +| Guards.cs:342:27:342:27 | [b (line 339): true] access to parameter b | Guards.cs:341:20:341:20 | access to parameter b | Guards.cs:341:20:341:20 | access to parameter b | true | +| Guards.cs:342:27:342:27 | [b (line 339): true] access to parameter b | Guards.cs:341:20:341:32 | ... ? ... : ... | Guards.cs:341:20:341:20 | access to parameter b | non-null | +| Guards.cs:343:31:343:31 | access to local variable s | Guards.cs:342:13:342:13 | access to local variable s | Guards.cs:342:13:342:13 | access to local variable s | non-null | +| Guards.cs:343:31:343:31 | access to local variable s | Guards.cs:342:13:342:21 | ... != ... | Guards.cs:342:13:342:13 | access to local variable s | true | | Splitting.cs:13:17:13:17 | [b (line 9): true] access to parameter o | Splitting.cs:12:17:12:17 | access to parameter o | Splitting.cs:12:17:12:17 | access to parameter o | non-null | | Splitting.cs:13:17:13:17 | [b (line 9): true] access to parameter o | Splitting.cs:12:17:12:25 | ... != ... | Splitting.cs:12:17:12:17 | access to parameter o | true | | Splitting.cs:14:13:14:13 | [b (line 9): false] access to parameter b | Splitting.cs:11:13:11:13 | access to parameter b | Splitting.cs:11:13:11:13 | access to parameter b | false | @@ -255,5 +271,5 @@ | Splitting.cs:119:13:119:13 | access to parameter o | Splitting.cs:116:22:116:30 | ... != ... | Splitting.cs:116:22:116:22 | access to parameter o | true | | Splitting.cs:120:16:120:16 | access to parameter o | Splitting.cs:116:22:116:22 | access to parameter o | Splitting.cs:116:22:116:22 | access to parameter o | non-null | | Splitting.cs:120:16:120:16 | access to parameter o | Splitting.cs:116:22:116:30 | ... != ... | Splitting.cs:116:22:116:22 | access to parameter o | true | -| Splitting.cs:130:21:130:21 | [b (line 123): false] access to parameter b | Splitting.cs:130:21:130:21 | access to parameter b | Splitting.cs:130:21:130:21 | access to parameter b | false | -| Splitting.cs:132:25:132:25 | [b (line 123): false] access to parameter b | Splitting.cs:130:21:130:21 | access to parameter b | Splitting.cs:130:21:130:21 | access to parameter b | false | +| Splitting.cs:131:21:131:21 | [b (line 123): false] access to parameter b | Splitting.cs:131:21:131:21 | access to parameter b | Splitting.cs:131:21:131:21 | access to parameter b | false | +| Splitting.cs:133:25:133:25 | [b (line 123): false] access to parameter b | Splitting.cs:131:21:131:21 | access to parameter b | Splitting.cs:131:21:131:21 | access to parameter b | false | diff --git a/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected b/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected index e8d85631cb76..7e74adb0fc67 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected @@ -14,22 +14,18 @@ | Assert.cs:59:36:59:36 | access to parameter b | Assert.cs:58:20:58:32 | ... ? ... : ... | Assert.cs:58:20:58:20 | access to parameter b | non-null | | Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:23 | access to local variable s | Assert.cs:59:23:59:23 | access to local variable s | non-null | | Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:31 | ... != ... | Assert.cs:59:23:59:23 | access to local variable s | true | -| Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:36 | ... && ... | Assert.cs:59:23:59:23 | access to local variable s | true | | Assert.cs:66:37:66:37 | access to parameter b | Assert.cs:65:20:65:20 | access to parameter b | Assert.cs:65:20:65:20 | access to parameter b | false | | Assert.cs:66:37:66:37 | access to parameter b | Assert.cs:65:20:65:32 | ... ? ... : ... | Assert.cs:65:20:65:20 | access to parameter b | non-null | | Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:24 | access to local variable s | Assert.cs:66:24:66:24 | access to local variable s | non-null | | Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:32 | ... == ... | Assert.cs:66:24:66:24 | access to local variable s | false | -| Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:37 | ... \|\| ... | Assert.cs:66:24:66:24 | access to local variable s | false | | Assert.cs:73:36:73:36 | access to parameter b | Assert.cs:72:20:72:20 | access to parameter b | Assert.cs:72:20:72:20 | access to parameter b | true | | Assert.cs:73:36:73:36 | access to parameter b | Assert.cs:72:20:72:32 | ... ? ... : ... | Assert.cs:72:20:72:20 | access to parameter b | null | | Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:23 | access to local variable s | Assert.cs:73:23:73:23 | access to local variable s | null | | Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:31 | ... == ... | Assert.cs:73:23:73:23 | access to local variable s | true | -| Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:36 | ... && ... | Assert.cs:73:23:73:23 | access to local variable s | true | | Assert.cs:80:37:80:37 | access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | true | | Assert.cs:80:37:80:37 | access to parameter b | Assert.cs:79:20:79:32 | ... ? ... : ... | Assert.cs:79:20:79:20 | access to parameter b | null | | Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:24 | access to local variable s | Assert.cs:80:24:80:24 | access to local variable s | null | | Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:32 | ... != ... | Assert.cs:80:24:80:24 | access to local variable s | false | -| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:37 | ... \|\| ... | Assert.cs:80:24:80:24 | access to local variable s | false | | Collections.cs:52:17:52:20 | access to parameter args | Collections.cs:50:13:50:16 | access to parameter args | Collections.cs:50:13:50:16 | access to parameter args | non-empty | | Collections.cs:52:17:52:20 | access to parameter args | Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | false | | Collections.cs:53:9:53:12 | access to parameter args | Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | false | @@ -37,6 +33,7 @@ | Collections.cs:67:13:67:13 | access to local variable x | Collections.cs:65:13:65:13 | access to local variable x | Collections.cs:65:13:65:13 | access to local variable x | empty | | Collections.cs:67:13:67:13 | access to local variable x | Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | true | | Collections.cs:68:13:68:13 | access to local variable x | Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | true | +| Collections.cs:96:31:96:34 | access to parameter args | Collections.cs:95:29:95:32 | access to parameter args | Collections.cs:95:29:95:32 | access to parameter args | non-empty | | Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null | | Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:24 | ... == ... | Guards.cs:10:16:10:16 | access to parameter s | false | | Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null | @@ -191,6 +188,10 @@ | Guards.cs:287:17:287:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match access to type Action | | Guards.cs:287:17:287:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-match null | | Guards.cs:287:17:287:17 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | Guards.cs:276:16:276:16 | access to parameter o | non-null | +| Guards.cs:342:27:342:27 | access to parameter b | Guards.cs:341:20:341:20 | access to parameter b | Guards.cs:341:20:341:20 | access to parameter b | false | +| Guards.cs:342:27:342:27 | access to parameter b | Guards.cs:341:20:341:32 | ... ? ... : ... | Guards.cs:341:20:341:20 | access to parameter b | non-null | +| Guards.cs:343:31:343:31 | access to local variable s | Guards.cs:342:13:342:13 | access to local variable s | Guards.cs:342:13:342:13 | access to local variable s | non-null | +| Guards.cs:343:31:343:31 | access to local variable s | Guards.cs:342:13:342:21 | ... != ... | Guards.cs:342:13:342:13 | access to local variable s | true | | Splitting.cs:13:17:13:17 | access to parameter o | Splitting.cs:12:17:12:17 | access to parameter o | Splitting.cs:12:17:12:17 | access to parameter o | non-null | | Splitting.cs:13:17:13:17 | access to parameter o | Splitting.cs:12:17:12:25 | ... != ... | Splitting.cs:12:17:12:17 | access to parameter o | true | | Splitting.cs:23:24:23:24 | access to parameter o | Splitting.cs:22:17:22:17 | access to parameter o | Splitting.cs:22:17:22:17 | access to parameter o | non-null | @@ -227,4 +228,4 @@ | Splitting.cs:119:13:119:13 | access to parameter o | Splitting.cs:116:22:116:30 | ... != ... | Splitting.cs:116:22:116:22 | access to parameter o | true | | Splitting.cs:120:16:120:16 | access to parameter o | Splitting.cs:116:22:116:22 | access to parameter o | Splitting.cs:116:22:116:22 | access to parameter o | non-null | | Splitting.cs:120:16:120:16 | access to parameter o | Splitting.cs:116:22:116:30 | ... != ... | Splitting.cs:116:22:116:22 | access to parameter o | true | -| Splitting.cs:132:25:132:25 | access to parameter b | Splitting.cs:130:21:130:21 | access to parameter b | Splitting.cs:130:21:130:21 | access to parameter b | false | +| Splitting.cs:133:25:133:25 | access to parameter b | Splitting.cs:131:21:131:21 | access to parameter b | Splitting.cs:131:21:131:21 | access to parameter b | false | diff --git a/csharp/ql/test/library-tests/controlflow/guards/Guards.cs b/csharp/ql/test/library-tests/controlflow/guards/Guards.cs index 67a58f59aac7..0c4563b3c9fa 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/Guards.cs +++ b/csharp/ql/test/library-tests/controlflow/guards/Guards.cs @@ -335,5 +335,12 @@ int M27(bool b) _ => 1 }; } + + void M28(bool b) + { + string s = b ? null : ""; + if (s != null && !b) + Console.WriteLine(s.Length); // null guarded + } } diff --git a/csharp/ql/test/library-tests/controlflow/guards/Implications.expected b/csharp/ql/test/library-tests/controlflow/guards/Implications.expected index 69bfefd6d9f5..1f2bdd595ed8 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/Implications.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/Implications.expected @@ -18,7 +18,9 @@ | Assert.cs:16:20:16:32 | ... ? ... : ... | null | Assert.cs:16:24:16:27 | null | null | | Assert.cs:17:23:17:23 | access to local variable s | empty | Assert.cs:16:20:16:32 | ... ? ... : ... | empty | | Assert.cs:17:23:17:23 | access to local variable s | non-empty | Assert.cs:16:20:16:32 | ... ? ... : ... | non-empty | +| Assert.cs:17:23:17:23 | access to local variable s | non-null | Assert.cs:16:20:16:20 | access to parameter b | false | | Assert.cs:17:23:17:23 | access to local variable s | non-null | Assert.cs:16:20:16:32 | ... ? ... : ... | non-null | +| Assert.cs:17:23:17:23 | access to local variable s | null | Assert.cs:16:20:16:20 | access to parameter b | true | | Assert.cs:17:23:17:23 | access to local variable s | null | Assert.cs:16:20:16:32 | ... ? ... : ... | null | | Assert.cs:18:27:18:27 | access to local variable s | non-null | Assert.cs:16:20:16:32 | ... ? ... : ... | non-null | | Assert.cs:18:27:18:27 | access to local variable s | null | Assert.cs:16:20:16:32 | ... ? ... : ... | null | @@ -28,7 +30,9 @@ | Assert.cs:23:20:23:32 | ... ? ... : ... | null | Assert.cs:23:24:23:27 | null | null | | Assert.cs:24:26:24:26 | access to local variable s | empty | Assert.cs:23:20:23:32 | ... ? ... : ... | empty | | Assert.cs:24:26:24:26 | access to local variable s | non-empty | Assert.cs:23:20:23:32 | ... ? ... : ... | non-empty | +| Assert.cs:24:26:24:26 | access to local variable s | non-null | Assert.cs:23:20:23:20 | access to parameter b | false | | Assert.cs:24:26:24:26 | access to local variable s | non-null | Assert.cs:23:20:23:32 | ... ? ... : ... | non-null | +| Assert.cs:24:26:24:26 | access to local variable s | null | Assert.cs:23:20:23:20 | access to parameter b | true | | Assert.cs:24:26:24:26 | access to local variable s | null | Assert.cs:23:20:23:32 | ... ? ... : ... | null | | Assert.cs:25:27:25:27 | access to local variable s | non-null | Assert.cs:23:20:23:32 | ... ? ... : ... | non-null | | Assert.cs:25:27:25:27 | access to local variable s | null | Assert.cs:23:20:23:32 | ... ? ... : ... | null | @@ -180,26 +184,26 @@ | Collections.cs:45:17:45:26 | call to method Any | true | Collections.cs:45:17:45:20 | access to parameter args | non-empty | | Collections.cs:50:13:50:27 | ... == ... | false | Collections.cs:50:13:50:16 | access to parameter args | non-empty | | Collections.cs:50:13:50:27 | ... == ... | true | Collections.cs:50:13:50:16 | access to parameter args | empty | -| Collections.cs:56:13:56:13 | access to local variable x | empty | Collections.cs:55:13:55:41 | array creation of type String[] | empty | -| Collections.cs:56:13:56:13 | access to local variable x | non-empty | Collections.cs:55:13:55:41 | array creation of type String[] | non-empty | -| Collections.cs:56:13:56:13 | access to local variable x | non-null | Collections.cs:55:13:55:41 | array creation of type String[] | non-null | -| Collections.cs:56:13:56:13 | access to local variable x | null | Collections.cs:55:13:55:41 | array creation of type String[] | null | +| Collections.cs:56:13:56:13 | access to local variable x | empty | Collections.cs:55:13:55:42 | array creation of type String[] | empty | +| Collections.cs:56:13:56:13 | access to local variable x | non-empty | Collections.cs:55:13:55:42 | array creation of type String[] | non-empty | +| Collections.cs:56:13:56:13 | access to local variable x | non-null | Collections.cs:55:13:55:42 | array creation of type String[] | non-null | +| Collections.cs:56:13:56:13 | access to local variable x | null | Collections.cs:55:13:55:42 | array creation of type String[] | null | | Collections.cs:58:13:58:13 | access to local variable x | empty | Collections.cs:57:13:57:25 | array creation of type String[] | empty | | Collections.cs:58:13:58:13 | access to local variable x | non-empty | Collections.cs:57:13:57:25 | array creation of type String[] | non-empty | | Collections.cs:58:13:58:13 | access to local variable x | non-null | Collections.cs:57:13:57:25 | array creation of type String[] | non-null | | Collections.cs:58:13:58:13 | access to local variable x | null | Collections.cs:57:13:57:25 | array creation of type String[] | null | -| Collections.cs:64:9:64:9 | access to local variable x | empty | Collections.cs:63:17:63:54 | call to method ToList | empty | -| Collections.cs:64:9:64:9 | access to local variable x | non-empty | Collections.cs:63:17:63:54 | call to method ToList | non-empty | -| Collections.cs:64:9:64:9 | access to local variable x | non-null | Collections.cs:63:17:63:54 | call to method ToList | non-null | -| Collections.cs:64:9:64:9 | access to local variable x | null | Collections.cs:63:17:63:54 | call to method ToList | null | -| Collections.cs:65:13:65:13 | access to local variable x | non-null | Collections.cs:63:17:63:54 | call to method ToList | non-null | -| Collections.cs:65:13:65:13 | access to local variable x | null | Collections.cs:63:17:63:54 | call to method ToList | null | +| Collections.cs:64:9:64:9 | access to local variable x | empty | Collections.cs:63:17:63:55 | call to method ToList | empty | +| Collections.cs:64:9:64:9 | access to local variable x | non-empty | Collections.cs:63:17:63:55 | call to method ToList | non-empty | +| Collections.cs:64:9:64:9 | access to local variable x | non-null | Collections.cs:63:17:63:55 | call to method ToList | non-null | +| Collections.cs:64:9:64:9 | access to local variable x | null | Collections.cs:63:17:63:55 | call to method ToList | null | +| Collections.cs:65:13:65:13 | access to local variable x | non-null | Collections.cs:63:17:63:55 | call to method ToList | non-null | +| Collections.cs:65:13:65:13 | access to local variable x | null | Collections.cs:63:17:63:55 | call to method ToList | null | | Collections.cs:65:13:65:24 | ... == ... | false | Collections.cs:65:13:65:13 | access to local variable x | non-empty | | Collections.cs:65:13:65:24 | ... == ... | true | Collections.cs:65:13:65:13 | access to local variable x | empty | -| Collections.cs:67:13:67:13 | access to local variable x | non-null | Collections.cs:63:17:63:54 | call to method ToList | non-null | -| Collections.cs:67:13:67:13 | access to local variable x | null | Collections.cs:63:17:63:54 | call to method ToList | null | -| Collections.cs:68:13:68:13 | access to local variable x | non-null | Collections.cs:63:17:63:54 | call to method ToList | non-null | -| Collections.cs:68:13:68:13 | access to local variable x | null | Collections.cs:63:17:63:54 | call to method ToList | null | +| Collections.cs:67:13:67:13 | access to local variable x | non-null | Collections.cs:63:17:63:55 | call to method ToList | non-null | +| Collections.cs:67:13:67:13 | access to local variable x | null | Collections.cs:63:17:63:55 | call to method ToList | null | +| Collections.cs:68:13:68:13 | access to local variable x | non-null | Collections.cs:63:17:63:55 | call to method ToList | non-null | +| Collections.cs:68:13:68:13 | access to local variable x | null | Collections.cs:63:17:63:55 | call to method ToList | null | | Collections.cs:74:35:74:41 | ... == ... | true | Collections.cs:74:35:74:35 | access to parameter s | non-null | | Collections.cs:74:35:74:41 | ... == ... | true | Collections.cs:74:40:74:41 | "" | non-null | | Collections.cs:75:17:75:33 | call to method Any | true | Collections.cs:75:17:75:20 | access to parameter args | non-empty | @@ -397,8 +401,14 @@ | Guards.cs:276:16:276:16 | access to parameter o | match access to type Action | Guards.cs:276:16:276:16 | access to parameter o | non-null | | Guards.cs:276:16:276:16 | access to parameter o | match null | Guards.cs:276:16:276:16 | access to parameter o | null | | Guards.cs:276:16:276:16 | access to parameter o | non-match null | Guards.cs:276:16:276:16 | access to parameter o | non-null | +| Guards.cs:278:13:279:28 | ... => ... | true | Guards.cs:276:16:276:16 | access to parameter o | non-null | +| Guards.cs:280:13:281:28 | ... => ... | true | Guards.cs:276:16:276:16 | access to parameter o | non-null | | Guards.cs:281:17:281:17 | access to local variable a | non-null | Guards.cs:276:16:276:16 | access to parameter o | non-null | | Guards.cs:281:17:281:17 | access to local variable a | null | Guards.cs:276:16:276:16 | access to parameter o | null | +| Guards.cs:282:13:283:28 | ... => ... | true | Guards.cs:276:16:276:16 | access to parameter o | non-null | +| Guards.cs:284:13:285:28 | ... => ... | false | Guards.cs:276:16:276:16 | access to parameter o | non-null | +| Guards.cs:284:13:285:28 | ... => ... | true | Guards.cs:276:16:276:16 | access to parameter o | null | +| Guards.cs:286:13:287:28 | ... => ... | true | Guards.cs:276:16:276:16 | access to parameter o | non-null | | Guards.cs:296:16:296:17 | access to local variable b2 | match true | Guards.cs:294:13:294:14 | access to parameter b1 | false | | Guards.cs:296:16:296:17 | access to local variable b2 | match true | Guards.cs:296:16:296:17 | access to local variable b2 | true | | Guards.cs:308:16:308:17 | access to local variable b2 | match true | Guards.cs:306:13:306:14 | access to parameter b1 | true | @@ -410,6 +420,24 @@ | Guards.cs:332:16:332:16 | access to local variable e | match access to constant B | Guards.cs:330:13:330:13 | access to parameter b | true | | Guards.cs:332:16:332:16 | access to local variable e | match access to constant B | Guards.cs:332:16:332:16 | access to local variable e | 1 | | Guards.cs:332:16:332:16 | access to local variable e | non-match access to constant B | Guards.cs:330:13:330:13 | access to parameter b | false | +| Guards.cs:341:20:341:32 | ... ? ... : ... | non-null | Guards.cs:341:20:341:20 | access to parameter b | false | +| Guards.cs:341:20:341:32 | ... ? ... : ... | non-null | Guards.cs:341:31:341:32 | "" | non-null | +| Guards.cs:341:20:341:32 | ... ? ... : ... | null | Guards.cs:341:20:341:20 | access to parameter b | true | +| Guards.cs:341:20:341:32 | ... ? ... : ... | null | Guards.cs:341:24:341:27 | null | null | +| Guards.cs:342:13:342:13 | access to local variable s | empty | Guards.cs:341:20:341:32 | ... ? ... : ... | empty | +| Guards.cs:342:13:342:13 | access to local variable s | non-empty | Guards.cs:341:20:341:32 | ... ? ... : ... | non-empty | +| Guards.cs:342:13:342:13 | access to local variable s | non-null | Guards.cs:341:20:341:32 | ... ? ... : ... | non-null | +| Guards.cs:342:13:342:13 | access to local variable s | null | Guards.cs:341:20:341:32 | ... ? ... : ... | null | +| Guards.cs:342:13:342:21 | ... != ... | false | Guards.cs:341:20:341:20 | access to parameter b | true | +| Guards.cs:342:13:342:21 | ... != ... | false | Guards.cs:342:13:342:13 | access to local variable s | null | +| Guards.cs:342:13:342:21 | ... != ... | true | Guards.cs:341:20:341:20 | access to parameter b | false | +| Guards.cs:342:13:342:21 | ... != ... | true | Guards.cs:342:13:342:13 | access to local variable s | non-null | +| Guards.cs:342:13:342:27 | ... && ... | true | Guards.cs:342:13:342:21 | ... != ... | true | +| Guards.cs:342:13:342:27 | ... && ... | true | Guards.cs:342:26:342:27 | !... | true | +| Guards.cs:342:26:342:27 | !... | false | Guards.cs:342:27:342:27 | access to parameter b | true | +| Guards.cs:342:26:342:27 | !... | true | Guards.cs:342:27:342:27 | access to parameter b | false | +| Guards.cs:343:31:343:31 | access to local variable s | non-null | Guards.cs:341:20:341:32 | ... ? ... : ... | non-null | +| Guards.cs:343:31:343:31 | access to local variable s | null | Guards.cs:341:20:341:32 | ... ? ... : ... | null | | Splitting.cs:12:17:12:25 | ... != ... | false | Splitting.cs:12:17:12:17 | access to parameter o | null | | Splitting.cs:12:17:12:25 | ... != ... | true | Splitting.cs:12:17:12:17 | access to parameter o | non-null | | Splitting.cs:22:17:22:25 | ... != ... | false | Splitting.cs:22:17:22:17 | access to parameter o | null | @@ -432,7 +460,8 @@ | Splitting.cs:105:22:105:30 | ... != ... | true | Splitting.cs:105:22:105:22 | access to parameter o | non-null | | Splitting.cs:116:22:116:30 | ... != ... | false | Splitting.cs:116:22:116:22 | access to parameter o | null | | Splitting.cs:116:22:116:30 | ... != ... | true | Splitting.cs:116:22:116:22 | access to parameter o | non-null | -| Splitting.cs:128:17:128:25 | ... != ... | false | Splitting.cs:128:17:128:17 | access to local variable o | null | -| Splitting.cs:128:17:128:25 | ... != ... | true | Splitting.cs:128:17:128:17 | access to local variable o | non-null | -| Splitting.cs:133:17:133:17 | access to local variable o | non-null | Splitting.cs:132:21:132:29 | call to method M11 | non-null | -| Splitting.cs:133:17:133:17 | access to local variable o | null | Splitting.cs:132:21:132:29 | call to method M11 | null | +| Splitting.cs:129:17:129:25 | ... != ... | false | Splitting.cs:129:17:129:17 | access to local variable o | null | +| Splitting.cs:129:17:129:25 | ... != ... | false | Splitting.cs:129:22:129:25 | null | non-null | +| Splitting.cs:129:17:129:25 | ... != ... | true | Splitting.cs:129:17:129:17 | access to local variable o | non-null | +| Splitting.cs:134:17:134:17 | access to local variable o | non-null | Splitting.cs:133:21:133:29 | call to method M11 | non-null | +| Splitting.cs:134:17:134:17 | access to local variable o | null | Splitting.cs:133:21:133:29 | call to method M11 | null | diff --git a/csharp/ql/test/library-tests/controlflow/guards/NullGuardedExpr.expected b/csharp/ql/test/library-tests/controlflow/guards/NullGuardedExpr.expected index 7c153f6e7aaa..eea5a4dadd34 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/NullGuardedExpr.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/NullGuardedExpr.expected @@ -45,6 +45,7 @@ | Guards.cs:279:17:279:17 | access to parameter o | | Guards.cs:283:17:283:17 | access to parameter o | | Guards.cs:287:17:287:17 | access to parameter o | +| Guards.cs:343:31:343:31 | access to local variable s | | Splitting.cs:13:17:13:17 | access to parameter o | | Splitting.cs:23:24:23:24 | access to parameter o | | Splitting.cs:35:13:35:13 | access to parameter o | diff --git a/csharp/ql/test/library-tests/controlflow/guards/Splitting.cs b/csharp/ql/test/library-tests/controlflow/guards/Splitting.cs index 1efbaa8251ff..76ccdd0f6336 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/Splitting.cs +++ b/csharp/ql/test/library-tests/controlflow/guards/Splitting.cs @@ -125,6 +125,7 @@ public void M12(int i, bool b) object? o = null; do { + o.GetHashCode(); // not null guarded if (o != null) { if (b) diff --git a/csharp/ql/test/library-tests/conversion/nullable/Nullable.cs b/csharp/ql/test/library-tests/conversion/nullable/Nullable.cs index 08d714f123f7..af9c518b2384 100644 --- a/csharp/ql/test/library-tests/conversion/nullable/Nullable.cs +++ b/csharp/ql/test/library-tests/conversion/nullable/Nullable.cs @@ -1,20 +1,29 @@ using System; +using System.Runtime.Serialization; class C { - sbyte x1; - sbyte? x2; + int x1; + int? x2; Nullable x3; Nullable x4; // Verify conversions void M() { - x2 = x1; - x3 = x4; + x2 = x1; // T -> T? conversion: implicit, nullable -> implicit cast + x3 = x4; // T1? -> T2? conversion: implicit, nullable -> implicit cast + + x12 = x1; // T1 -> T2? conversion: implicit, nullable -> implicit cast + x12 = null; // null -> T? conversion: implicit, null literal -> no cast + + x3 = x2; // T? -> T? no conversion + + x14 = x15; // T1? -> T2? conversion: implicit, user defined -> implicit cast } // Cause the following types to exist in the database: + sbyte? x0; byte? x5; short? x6; ushort? x7; @@ -24,4 +33,19 @@ void M() double? x11; long? x12; float? x13; + + A? x14; + B? x15; + + struct A + { + } + + struct B + { + public static implicit operator A(B value) + { + return new A(); + } + } } diff --git a/csharp/ql/test/library-tests/conversion/operator/PrintAst.expected b/csharp/ql/test/library-tests/conversion/operator/PrintAst.expected new file mode 100644 index 000000000000..9ce74d7c956f --- /dev/null +++ b/csharp/ql/test/library-tests/conversion/operator/PrintAst.expected @@ -0,0 +1,17 @@ +Operator.cs: +# 3| [Class] C +# 5| 5: [ImplicitConversionOperator] implicit conversion +#-----| 2: (Parameters) +# 5| 0: [Parameter] i +# 5| 4: [BlockStmt] {...} +# 5| 0: [ReturnStmt] return ...; +# 5| 0: [NullLiteral] null +# 7| 6: [Field] x1 +# 8| 7: [Field] x2 +# 11| 8: [Method] M +# 12| 4: [BlockStmt] {...} +# 13| 0: [ExprStmt] ...; +# 13| 0: [AssignExpr] ... = ... +# 13| 0: [OperatorCall] call to operator implicit conversion +# 13| 0: [FieldAccess] access to field x1 +# 13| 1: [FieldAccess] access to field x2 diff --git a/csharp/ql/test/library-tests/conversion/operator/PrintAst.qlref b/csharp/ql/test/library-tests/conversion/operator/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/conversion/operator/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/conversion/pointer/Pointer.cs b/csharp/ql/test/library-tests/conversion/pointer/Pointer.cs new file mode 100644 index 000000000000..c7e12ac39b49 --- /dev/null +++ b/csharp/ql/test/library-tests/conversion/pointer/Pointer.cs @@ -0,0 +1,28 @@ +using System; + +class C +{ + unsafe static void M1(int[] arr) + { + fixed (int* i1 = arr) + { + } + + fixed (int* i2 = &arr[0]) + { + int* i3 = i2; + i3 = i3 + 1; + *i2 = *i2 + 1; + void* v2 = i2; + } + + int* i4 = null; + + int number = 1024; + byte* p = (byte*)&number; + + var s = "some string"; + fixed (char* c1 = s) + { } + } +} diff --git a/csharp/ql/test/library-tests/conversion/pointer/Pointer.expected b/csharp/ql/test/library-tests/conversion/pointer/Pointer.expected new file mode 100644 index 000000000000..5aca5582d142 --- /dev/null +++ b/csharp/ql/test/library-tests/conversion/pointer/Pointer.expected @@ -0,0 +1,11 @@ +| Pointer.cs:7:21:7:28 | Pointer.cs:7:21:7:28 | Int32* | Int32* | (...) ... | +| Pointer.cs:11:21:11:32 | Pointer.cs:11:21:11:32 | Int32* | Int32* | &... | +| Pointer.cs:13:18:13:24 | Pointer.cs:13:18:13:24 | Int32* | Int32* | access to local variable i2 | +| Pointer.cs:14:13:14:23 | Pointer.cs:14:13:14:23 | Int32* | Int32* | ... + ... | +| Pointer.cs:15:13:15:25 | Pointer.cs:15:13:15:25 | Int32 | Int32 | ... + ... | +| Pointer.cs:16:19:16:25 | Pointer.cs:16:19:16:25 | Void* | Void* | (...) ... | +| Pointer.cs:19:14:19:22 | Pointer.cs:19:14:19:22 | Int32* | null | null | +| Pointer.cs:21:13:21:25 | Pointer.cs:21:13:21:25 | Int32 | Int32 | 1024 | +| Pointer.cs:22:15:22:32 | Pointer.cs:22:15:22:32 | Byte* | Byte* | (...) ... | +| Pointer.cs:24:13:24:29 | Pointer.cs:24:13:24:29 | String | String | "some string" | +| Pointer.cs:25:22:25:27 | Pointer.cs:25:22:25:27 | Char* | Char* | (...) ... | diff --git a/csharp/ql/test/library-tests/conversion/pointer/Pointer.ql b/csharp/ql/test/library-tests/conversion/pointer/Pointer.ql new file mode 100644 index 000000000000..69e7db8c1cf1 --- /dev/null +++ b/csharp/ql/test/library-tests/conversion/pointer/Pointer.ql @@ -0,0 +1,5 @@ +import csharp + +from Assignment a +select a.getLocation(), a.getLValue().getType().toString(), a.getRValue().getType().toString(), + a.getRValue().toString() diff --git a/csharp/ql/test/library-tests/csharp6/PrintAst.expected b/csharp/ql/test/library-tests/csharp6/PrintAst.expected new file mode 100644 index 000000000000..92a1d2f8709a --- /dev/null +++ b/csharp/ql/test/library-tests/csharp6/PrintAst.expected @@ -0,0 +1,236 @@ +csharp6.cs: +# 10| [Class] TestCSharp6 +# 12| 6: [Property] Value +# 15| 2: [AssignExpr] ... = ... +# 15| 0: [IntLiteral] 20 +# 12| 1: [PropertyCall] access to property Value +# 14| 3: [Getter] get_Value +# 17| 7: [Method] Fn +#-----| 2: (Parameters) +# 17| 0: [Parameter] x +# 17| 4: [MethodCall] call to method WriteLine +# 17| 0: [ParameterAccess] access to parameter x +# 19| 8: [Method] Main +# 20| 4: [BlockStmt] {...} +# 21| 0: [TryStmt] try {...} ... +# 22| 0: [BlockStmt] {...} +# 23| 0: [LocalVariableDeclStmt] ... ...; +# 23| 0: [LocalVariableDeclAndInitExpr] String foo = ... +# 23| 0: [NameOfExpr] nameof(...) +# 23| 0: [TypeAccess] access to type TestCSharp6 +# 23| 1: [LocalVariableAccess] access to local variable foo +# 23| 1: [LocalVariableDeclAndInitExpr] String bar = ... +# 23| 0: [NullLiteral] null +# 23| 1: [LocalVariableAccess] access to local variable bar +# 25| 1: [ExprStmt] ...; +# 25| 0: [MethodCall] call to method WriteLine +# 25| 0: [InterpolatedStringExpr] $"..." +# 25| 0: [NameOfExpr] nameof(...) +# 25| 0: [LocalVariableAccess] access to local variable foo +# 25| 1: [StringLiteral] " is " +# 25| 2: [LocalVariableAccess] access to local variable foo +# 25| 3: [StringLiteral] ", and " +# 25| 4: [NameOfExpr] nameof(...) +# 25| 0: [LocalVariableAccess] access to local variable bar +# 25| 5: [StringLiteral] " has length " +# 25| 6: [NullCoalescingExpr] ... ?? ... +# 25| 0: [PropertyCall] access to property Length +# 25| -1: [LocalVariableAccess] access to local variable bar +# 25| 1: [IntLiteral] 0 +# 27| 2: [ExprStmt] ...; +# 27| 0: [MethodCall] call to method Fn +# 27| 0: [InterpolatedStringExpr] $"..." +# 27| 0: [NameOfExpr] nameof(...) +# 27| 0: [LocalVariableAccess] access to local variable foo +# 27| 1: [StringLiteral] " is " +# 27| 2: [LocalVariableAccess] access to local variable foo +# 27| 3: [StringLiteral] ", and " +# 27| 4: [NameOfExpr] nameof(...) +# 27| 0: [LocalVariableAccess] access to local variable bar +# 27| 5: [StringLiteral] " has length " +# 27| 6: [NullCoalescingExpr] ... ?? ... +# 27| 0: [PropertyCall] access to property Length +# 27| -1: [LocalVariableAccess] access to local variable bar +# 27| 1: [IntLiteral] 0 +# 29| 3: [LocalVariableDeclStmt] ... ...; +# 29| 0: [LocalVariableDeclAndInitExpr] Nullable anythingInBar = ... +# 29| 0: [MethodCall] call to method Any +# 29| -1: [LocalVariableAccess] access to local variable bar +# 29| 1: [LocalVariableAccess] access to local variable anythingInBar +# 30| 4: [LocalVariableDeclStmt] ... ...; +# 30| 0: [LocalVariableDeclAndInitExpr] Nullable countTInFoo = ... +# 30| 0: [MethodCall] call to method Count +# 30| -1: [MethodCall] call to method Select +# 30| -1: [MethodCall] call to method ToUpper +# 30| -1: [LocalVariableAccess] access to local variable foo +# 30| 0: [LambdaExpr] (...) => ... +#-----| 2: (Parameters) +# 30| 0: [Parameter] c +# 30| 4: [EQExpr] ... == ... +# 30| 0: [CastExpr] (...) ... +# 30| 0: [ParameterAccess] access to parameter c +# 30| 1: [CastExpr] (...) ... +# 30| 0: [CharLiteral] T +# 30| 1: [LocalVariableAccess] access to local variable countTInFoo +# 32| 5: [LocalVariableDeclStmt] ... ...; +# 32| 0: [LocalVariableDeclAndInitExpr] Nullable testElementBinding = ... +# 32| 0: [IndexerCall] access to indexer +# 32| -1: [IndexerCall] access to indexer +# 32| -1: [ObjectCreation] object creation of type Dictionary +# 32| 0: [IntLiteral] 2 +# 32| 0: [IntLiteral] 1 +# 32| 1: [LocalVariableAccess] access to local variable testElementBinding +# 34| 1: [SpecificCatchClause] catch (...) {...} +# 35| 1: [BlockStmt] {...} +# 34| 2: [EQExpr] ... == ... +# 34| 0: [PropertyCall] access to property Value +# 34| 1: [IntLiteral] 20 +# 37| 2: [GeneralCatchClause] catch {...} +# 38| 1: [BlockStmt] {...} +# 37| 2: [EQExpr] ... == ... +# 37| 0: [PropertyCall] access to property Value +# 37| 1: [IntLiteral] 30 +# 40| 3: [GeneralCatchClause] catch {...} +# 41| 1: [BlockStmt] {...} +# 45| 9: [EQOperator] == +#-----| 2: (Parameters) +# 45| 0: [Parameter] t1 +# 45| 1: [Parameter] t2 +# 45| 4: [BoolLiteral] true +# 46| 10: [NEOperator] != +#-----| 2: (Parameters) +# 46| 0: [Parameter] t1 +# 46| 1: [Parameter] t2 +# 46| 4: [BoolLiteral] false +# 48| 11: [Property] ExprProperty +# 48| 3: [Getter] get_ExprProperty +# 48| 4: [IntLiteral] 3 +# 50| 12: [Indexer] Item +#-----| 1: (Parameters) +# 50| 0: [Parameter] i +# 50| 3: [Getter] get_Item +#-----| 2: (Parameters) +# 50| 0: [Parameter] i +# 50| 4: [ParameterAccess] access to parameter i +# 53| [Class] IndexInitializers +# 55| 5: [Class] Compound +# 57| 5: [Field] DictionaryField +# 58| 6: [IndexerProperty] DictionaryProperty +# 58| 3: [Getter] get_DictionaryProperty +# 58| 4: [Setter] set_DictionaryProperty +#-----| 2: (Parameters) +# 58| 0: [Parameter] value +# 59| 7: [Field] ArrayField +# 60| 8: [Property] ArrayProperty +# 60| 3: [Getter] get_ArrayProperty +# 60| 4: [Setter] set_ArrayProperty +#-----| 2: (Parameters) +# 60| 0: [Parameter] value +# 61| 9: [Field] ArrayField2 +# 62| 10: [Property] ArrayProperty2 +# 62| 3: [Getter] get_ArrayProperty2 +# 62| 4: [Setter] set_ArrayProperty2 +#-----| 2: (Parameters) +# 62| 0: [Parameter] value +# 65| 6: [Method] Test +# 66| 4: [BlockStmt] {...} +# 68| 0: [LocalVariableDeclStmt] ... ...; +# 68| 0: [LocalVariableDeclAndInitExpr] Dictionary dict = ... +# 68| 0: [ObjectCreation] object creation of type Dictionary +# 68| -1: [ObjectInitializer] { ..., ... } +# 68| 0: [MemberInitializer] ... = ... +# 68| 0: [StringLiteral] "Zero" +# 68| 1: [IndexerCall] access to indexer +# 68| 0: [IntLiteral] 0 +# 68| 1: [MemberInitializer] ... = ... +# 68| 0: [StringLiteral] "One" +# 68| 1: [IndexerCall] access to indexer +# 68| 0: [IntLiteral] 1 +# 68| 2: [MemberInitializer] ... = ... +# 68| 0: [StringLiteral] "Two" +# 68| 1: [IndexerCall] access to indexer +# 68| 0: [IntLiteral] 2 +# 68| 1: [LocalVariableAccess] access to local variable dict +# 71| 1: [LocalVariableDeclStmt] ... ...; +# 71| 0: [LocalVariableDeclAndInitExpr] Compound compound = ... +# 71| 0: [ObjectCreation] object creation of type Compound +# 72| -1: [ObjectInitializer] { ..., ... } +# 73| 0: [MemberInitializer] ... = ... +# 73| 0: [ObjectInitializer] { ..., ... } +# 73| 0: [MemberInitializer] ... = ... +# 73| 0: [StringLiteral] "Zero" +# 73| 1: [IndexerCall] access to indexer +# 73| 0: [IntLiteral] 0 +# 73| 1: [MemberInitializer] ... = ... +# 73| 0: [StringLiteral] "One" +# 73| 1: [IndexerCall] access to indexer +# 73| 0: [IntLiteral] 1 +# 73| 2: [MemberInitializer] ... = ... +# 73| 0: [StringLiteral] "Two" +# 73| 1: [IndexerCall] access to indexer +# 73| 0: [IntLiteral] 2 +# 73| 1: [FieldAccess] access to field DictionaryField +# 74| 1: [MemberInitializer] ... = ... +# 74| 0: [ObjectInitializer] { ..., ... } +# 74| 0: [MemberInitializer] ... = ... +# 74| 0: [StringLiteral] "Three" +# 74| 1: [IndexerCall] access to indexer +# 74| 0: [IntLiteral] 3 +# 74| 1: [MemberInitializer] ... = ... +# 74| 0: [StringLiteral] "Two" +# 74| 1: [IndexerCall] access to indexer +# 74| 0: [IntLiteral] 2 +# 74| 2: [MemberInitializer] ... = ... +# 74| 0: [StringLiteral] "One" +# 74| 1: [IndexerCall] access to indexer +# 74| 0: [IntLiteral] 1 +# 74| 1: [PropertyCall] access to property DictionaryProperty +# 75| 2: [MemberInitializer] ... = ... +# 75| 0: [ObjectInitializer] { ..., ... } +# 75| 0: [MemberInitializer] ... = ... +# 75| 0: [StringLiteral] "Zero" +# 75| 1: [ArrayAccess] access to array element +# 75| 0: [IntLiteral] 0 +# 75| 1: [MemberInitializer] ... = ... +# 75| 0: [StringLiteral] "One" +# 75| 1: [ArrayAccess] access to array element +# 75| 0: [IntLiteral] 1 +# 75| 1: [FieldAccess] access to field ArrayField +# 76| 3: [MemberInitializer] ... = ... +# 76| 0: [ObjectInitializer] { ..., ... } +# 76| 0: [MemberInitializer] ... = ... +# 76| 0: [StringLiteral] "i" +# 76| 1: [ArrayAccess] access to array element +# 76| 0: [IntLiteral] 0 +# 76| 1: [IntLiteral] 1 +# 76| 1: [MemberInitializer] ... = ... +# 76| 0: [StringLiteral] "1" +# 76| 1: [ArrayAccess] access to array element +# 76| 0: [IntLiteral] 1 +# 76| 1: [IntLiteral] 0 +# 76| 1: [FieldAccess] access to field ArrayField2 +# 77| 4: [MemberInitializer] ... = ... +# 77| 0: [ObjectInitializer] { ..., ... } +# 77| 0: [MemberInitializer] ... = ... +# 77| 0: [StringLiteral] "One" +# 77| 1: [ArrayAccess] access to array element +# 77| 0: [IntLiteral] 1 +# 77| 1: [MemberInitializer] ... = ... +# 77| 0: [StringLiteral] "Two" +# 77| 1: [ArrayAccess] access to array element +# 77| 0: [IntLiteral] 2 +# 77| 1: [PropertyCall] access to property ArrayProperty +# 78| 5: [MemberInitializer] ... = ... +# 78| 0: [ObjectInitializer] { ..., ... } +# 78| 0: [MemberInitializer] ... = ... +# 78| 0: [StringLiteral] "i" +# 78| 1: [ArrayAccess] access to array element +# 78| 0: [IntLiteral] 0 +# 78| 1: [IntLiteral] 1 +# 78| 1: [MemberInitializer] ... = ... +# 78| 0: [StringLiteral] "1" +# 78| 1: [ArrayAccess] access to array element +# 78| 0: [IntLiteral] 1 +# 78| 1: [IntLiteral] 0 +# 78| 1: [PropertyCall] access to property ArrayProperty2 +# 71| 1: [LocalVariableAccess] access to local variable compound diff --git a/csharp/ql/test/library-tests/csharp6/PrintAst.qlref b/csharp/ql/test/library-tests/csharp6/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/csharp6/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/csharp7.1/PrintAst.expected b/csharp/ql/test/library-tests/csharp7.1/PrintAst.expected new file mode 100644 index 000000000000..381ae9dee74b --- /dev/null +++ b/csharp/ql/test/library-tests/csharp7.1/PrintAst.expected @@ -0,0 +1,67 @@ +csharp71.cs: +# 3| [Class] DefaultLiterals +# 5| 5: [Method] f +# 6| 4: [BlockStmt] {...} +# 7| 0: [LocalVariableDeclStmt] ... ...; +# 7| 0: [LocalVariableDeclAndInitExpr] Int32 x = ... +# 7| 0: [CastExpr] (...) ... +# 7| 0: [DefaultValueExpr] default +# 7| 1: [LocalVariableAccess] access to local variable x +# 7| 1: [LocalVariableDeclAndInitExpr] Int32 y = ... +# 7| 0: [DefaultValueExpr] default(...) +# 7| 0: [TypeAccess] access to type Int32 +# 7| 1: [LocalVariableAccess] access to local variable y +# 8| 1: [IfStmt] if (...) ... +# 8| 0: [EQExpr] ... == ... +# 8| 0: [LocalVariableAccess] access to local variable x +# 8| 1: [CastExpr] (...) ... +# 8| 0: [DefaultValueExpr] default +# 9| 1: [EmptyStmt] ; +# 10| 2: [SwitchStmt] switch (...) {...} +# 10| 0: [LocalVariableAccess] access to local variable x +# 12| 0: [CaseStmt] case ...: +# 12| 0: [DiscardPatternExpr] _ +# 12| 1: [BreakStmt] break; +# 14| 3: [ExprStmt] ...; +# 14| 0: [AssignExpr] ... = ... +# 14| 0: [CastExpr] (...) ... +# 14| 0: [DefaultValueExpr] default +# 14| 1: [LocalVariableAccess] access to local variable x +# 15| 4: [LocalVariableDeclStmt] ... ...; +# 15| 0: [LocalVariableDeclAndInitExpr] String s = ... +# 15| 0: [CastExpr] (...) ... +# 15| 0: [DefaultValueExpr] default +# 15| 1: [LocalVariableAccess] access to local variable s +# 16| 5: [LocalVariableDeclStmt] ... ...; +# 16| 0: [LocalVariableDeclAndInitExpr] Boolean b = ... +# 16| 0: [CastExpr] (...) ... +# 16| 0: [DefaultValueExpr] default +# 16| 1: [LocalVariableAccess] access to local variable b +# 17| 6: [LocalVariableDeclStmt] ... ...; +# 17| 0: [LocalVariableDeclAndInitExpr] Double d = ... +# 17| 0: [CastExpr] (...) ... +# 17| 0: [DefaultValueExpr] default +# 17| 1: [LocalVariableAccess] access to local variable d +# 21| [Class] IsConstants +# 23| 5: [Method] f +# 24| 4: [BlockStmt] {...} +# 25| 0: [LocalVariableDeclStmt] ... ...; +# 25| 0: [LocalVariableDeclExpr] Boolean b +# 26| 1: [ExprStmt] ...; +# 26| 0: [AssignExpr] ... = ... +# 26| 0: [IsExpr] ... is ... +# 26| 0: [ObjectCreation] object creation of type Object +# 26| 1: [ConstantPatternExpr,StringLiteral] "abc" +# 26| 1: [LocalVariableAccess] access to local variable b +# 27| 2: [ExprStmt] ...; +# 27| 0: [AssignExpr] ... = ... +# 27| 0: [IsExpr] ... is ... +# 27| 0: [StringLiteral] "" +# 27| 1: [ConstantPatternExpr,NullLiteral] null +# 27| 1: [LocalVariableAccess] access to local variable b +# 28| 3: [ExprStmt] ...; +# 28| 0: [AssignExpr] ... = ... +# 28| 0: [IsExpr] ... is ... +# 28| 0: [LocalVariableAccess] access to local variable b +# 28| 1: [BoolLiteral,ConstantPatternExpr] true +# 28| 1: [LocalVariableAccess] access to local variable b diff --git a/csharp/ql/test/library-tests/csharp7.1/PrintAst.qlref b/csharp/ql/test/library-tests/csharp7.1/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/csharp7.1/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/csharp7.2/PrintAst.expected b/csharp/ql/test/library-tests/csharp7.2/PrintAst.expected new file mode 100644 index 000000000000..d6c9866cc088 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp7.2/PrintAst.expected @@ -0,0 +1,39 @@ +csharp72.cs: +# 5| [Class] InModifiers +# 7| 5: [Struct] S +# 11| 6: [Method] F +#-----| 2: (Parameters) +# 11| 0: [Parameter] s +# 12| 4: [BlockStmt] {...} +# 15| 7: [Method] CallF +# 16| 4: [BlockStmt] {...} +# 17| 0: [LocalVariableDeclStmt] ... ...; +# 17| 0: [LocalVariableDeclAndInitExpr] S s = ... +# 17| 0: [ObjectCreation] object creation of type S +# 17| 1: [LocalVariableAccess] access to local variable s +# 18| 1: [ExprStmt] ...; +# 18| 0: [MethodCall] call to method F +# 18| 0: [LocalVariableAccess] access to local variable s +# 22| [Class] RefReadonlyReturns +# 24| 5: [Field] s +# 26| 6: [Method] F +# 27| 4: [BlockStmt] {...} +# 28| 0: [ReturnStmt] return ...; +# 28| 0: [RefExpr] ref ... +# 28| 0: [FieldAccess] access to field s +# 31| 7: [DelegateType] Del +# 34| [Struct] ReadonlyStruct +# 38| [Struct] RefStruct +# 42| [Struct] ReadonlyRefStruct +# 46| [Class] NumericLiterals +# 48| 5: [Field] binaryValue +# 48| 1: [AssignExpr] ... = ... +# 48| 0: [IntLiteral] 85 +# 48| 1: [FieldAccess] access to field binaryValue +# 51| [Class] PrivateProtected +# 53| 5: [Field] X +# 53| 1: [AssignExpr] ... = ... +# 53| 0: [IntLiteral] 1 +# 53| 1: [FieldAccess] access to field X +# 55| 6: [Method] F +# 55| 4: [BlockStmt] {...} diff --git a/csharp/ql/test/library-tests/csharp7.2/PrintAst.qlref b/csharp/ql/test/library-tests/csharp7.2/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/csharp7.2/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/csharp7.3/PrintAst.expected b/csharp/ql/test/library-tests/csharp7.3/PrintAst.expected new file mode 100644 index 000000000000..4574aa105900 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp7.3/PrintAst.expected @@ -0,0 +1,80 @@ +csharp73.cs: +# 5| [Class] StackAllocs +# 7| 5: [Method] Fn +# 8| 4: [BlockStmt] {...} +# 9| 0: [LocalVariableDeclStmt] ... ...; +# 9| 0: [LocalVariableDeclAndInitExpr] Char* arr1 = ... +# 9| 0: [Stackalloc] array creation of type Char* +# 9| -1: [ArrayInitializer] { ..., ... } +# 9| 0: [CharLiteral] x +# 9| 1: [CharLiteral] y +# 9| 1: [LocalVariableAccess] access to local variable arr1 +# 10| 1: [LocalVariableDeclStmt] ... ...; +# 10| 0: [LocalVariableDeclAndInitExpr] Char* arr2 = ... +# 10| 0: [Stackalloc] array creation of type Char* +# 10| -1: [ArrayInitializer] { ..., ... } +# 10| 0: [CharLiteral] x +# 10| 0: [IntLiteral] 1 +# 10| 1: [LocalVariableAccess] access to local variable arr2 +# 11| 2: [LocalVariableDeclStmt] ... ...; +# 11| 0: [LocalVariableDeclAndInitExpr] Char[] arr3 = ... +# 11| 0: [ArrayCreation] array creation of type Char[] +# 11| -1: [ArrayInitializer] { ..., ... } +# 11| 0: [CharLiteral] x +# 11| 1: [LocalVariableAccess] access to local variable arr3 +# 12| 3: [LocalVariableDeclStmt] ... ...; +# 12| 0: [LocalVariableDeclAndInitExpr] Char* arr4 = ... +# 12| 0: [Stackalloc] array creation of type Char* +# 12| 0: [IntLiteral] 10 +# 12| 1: [LocalVariableAccess] access to local variable arr4 +# 13| 4: [LocalVariableDeclStmt] ... ...; +# 13| 0: [LocalVariableDeclAndInitExpr] Char[] arr5 = ... +# 13| 0: [ArrayCreation] array creation of type Char[] +# 13| 0: [IntLiteral] 10 +# 13| 1: [LocalVariableAccess] access to local variable arr5 +# 14| 5: [LocalVariableDeclStmt] ... ...; +# 14| 0: [LocalVariableDeclAndInitExpr] Int32* arr6 = ... +# 14| 0: [Stackalloc] array creation of type Int32* +# 14| -1: [ArrayInitializer] { ..., ... } +# 14| 0: [IntLiteral] 1 +# 14| 1: [IntLiteral] 2 +# 14| 2: [IntLiteral] 3 +# 14| 1: [LocalVariableAccess] access to local variable arr6 +# 18| [Class] PinnedReference +# 20| 5: [Method] F +# 21| 4: [BlockStmt] {...} +# 22| 0: [LocalVariableDeclStmt] ... ...; +# 22| 0: [LocalVariableDeclAndInitExpr] Span t = ... +# 22| 0: [OperatorCall] call to operator implicit conversion +# 22| 0: [ArrayCreation] array creation of type Int32[] +# 22| 0: [IntLiteral] 10 +# 22| 1: [LocalVariableAccess] access to local variable t +# 25| 1: [BlockStmt] {...} +# 30| [Class] UnmanagedConstraint<> +#-----| 1: (Type parameters) +# 30| 0: [TypeParameter] T +# 34| [Class] EnumConstraint<> +#-----| 1: (Type parameters) +# 34| 0: [TypeParameter] T +# 38| [Class] DelegateConstraint<> +#-----| 1: (Type parameters) +# 38| 0: [TypeParameter] T +# 42| [Class] ExpressionVariables +# 44| 4: [InstanceConstructor] ExpressionVariables +#-----| 2: (Parameters) +# 44| 0: [Parameter] x +# 45| 4: [BlockStmt] {...} +# 46| 0: [ExprStmt] ...; +# 46| 0: [AssignExpr] ... = ... +# 46| 0: [IntLiteral] 5 +# 46| 1: [ParameterAccess] access to parameter x +# 49| 5: [InstanceConstructor] ExpressionVariables +# 49| 3: [ConstructorInitializer] call to constructor ExpressionVariables +# 49| 0: [LocalVariableDeclExpr] Int32 x +# 50| 4: [BlockStmt] {...} +# 51| 0: [ExprStmt] ...; +# 51| 0: [MethodCall] call to method WriteLine +# 51| -1: [TypeAccess] access to type Console +# 51| 0: [InterpolatedStringExpr] $"..." +# 51| 0: [StringLiteral] "x is " +# 51| 1: [LocalVariableAccess] access to local variable x diff --git a/csharp/ql/test/library-tests/csharp7.3/PrintAst.qlref b/csharp/ql/test/library-tests/csharp7.3/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/csharp7.3/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/csharp7/CSharp7.cs b/csharp/ql/test/library-tests/csharp7/CSharp7.cs index 0b42403f6c0a..0339ccc87284 100644 --- a/csharp/ql/test/library-tests/csharp7/CSharp7.cs +++ b/csharp/ql/test/library-tests/csharp7/CSharp7.cs @@ -61,9 +61,9 @@ void G() class Tuples { - (int, int) F() + (int A, int B) F() { - return (1, 2); + return (A: 1, B: 2); } void Expressions() @@ -71,7 +71,7 @@ void Expressions() (var x, var y) = F(); var z = F(); (x, y) = F(); - x = F().Item1; + x = F().A; (x, y, z.Item1) = (1, 2, 3); (x, y) = (x, y) = (1, 2); (var a, (var b, var c)) = (1, z); @@ -148,7 +148,8 @@ int f8() return f9(1); } - Action a = () => { + Action a = () => + { int f9() => 0; }; @@ -295,7 +296,7 @@ class ForLoops { void Test() { - for(int x=0; x<10 && x is int y; ++x) + for (int x = 0; x < 10 && x is int y; ++x) { Console.WriteLine(y); } diff --git a/csharp/ql/test/library-tests/csharp7/CaseCondition.expected b/csharp/ql/test/library-tests/csharp7/CaseCondition.expected index 67bff16713d0..f538575183e2 100644 --- a/csharp/ql/test/library-tests/csharp7/CaseCondition.expected +++ b/csharp/ql/test/library-tests/csharp7/CaseCondition.expected @@ -1,3 +1,3 @@ -| CSharp7.cs:253:13:253:31 | case ...: | CSharp7.cs:253:26:253:30 | ... < ... | -| CSharp7.cs:255:13:255:41 | case ...: | CSharp7.cs:255:27:255:40 | ... is ... | -| CSharp7.cs:258:13:258:36 | case ...: | CSharp7.cs:258:30:258:35 | ... > ... | +| CSharp7.cs:254:13:254:31 | case ...: | CSharp7.cs:254:26:254:30 | ... < ... | +| CSharp7.cs:256:13:256:41 | case ...: | CSharp7.cs:256:27:256:40 | ... is ... | +| CSharp7.cs:259:13:259:36 | case ...: | CSharp7.cs:259:30:259:35 | ... > ... | diff --git a/csharp/ql/test/library-tests/csharp7/ConstructedLocalFunctions.expected b/csharp/ql/test/library-tests/csharp7/ConstructedLocalFunctions.expected index 0b67eaba5dff..a945d2621982 100644 --- a/csharp/ql/test/library-tests/csharp7/ConstructedLocalFunctions.expected +++ b/csharp/ql/test/library-tests/csharp7/ConstructedLocalFunctions.expected @@ -1,4 +1,4 @@ -| CSharp7.cs:160:9:160:24 | f | f() | f() | -| CSharp7.cs:161:9:161:25 | g | g(U) | g(T) | -| CSharp7.cs:163:9:168:9 | h | h(int, int) | h(T, U) | -| CSharp7.cs:163:9:168:9 | h | h(string, bool) | h(T, U) | +| CSharp7.cs:161:9:161:24 | f | f() | f() | +| CSharp7.cs:162:9:162:25 | g | g(U) | g(T) | +| CSharp7.cs:164:9:169:9 | h | h(int, int) | h(T, U) | +| CSharp7.cs:164:9:169:9 | h | h(string, bool) | h(T, U) | diff --git a/csharp/ql/test/library-tests/csharp7/DefUse.expected b/csharp/ql/test/library-tests/csharp7/DefUse.expected index 93bdff568c26..62cc5ea4b1bf 100644 --- a/csharp/ql/test/library-tests/csharp7/DefUse.expected +++ b/csharp/ql/test/library-tests/csharp7/DefUse.expected @@ -29,47 +29,47 @@ | CSharp7.cs:141:20:141:20 | x | CSharp7.cs:141:41:141:41 | access to parameter x | | CSharp7.cs:143:20:143:20 | x | CSharp7.cs:143:29:143:29 | access to parameter x | | CSharp7.cs:147:24:147:24 | x | CSharp7.cs:147:33:147:33 | access to parameter x | -| CSharp7.cs:161:18:161:18 | t | CSharp7.cs:161:24:161:24 | access to parameter t | -| CSharp7.cs:163:26:163:26 | u | CSharp7.cs:167:22:167:22 | access to parameter u | -| CSharp7.cs:176:16:176:30 | String src = ... | CSharp7.cs:181:23:181:25 | access to local variable src | -| CSharp7.cs:176:16:176:30 | String src = ... | CSharp7.cs:182:23:182:25 | access to local variable src | -| CSharp7.cs:176:16:176:30 | String src = ... | CSharp7.cs:183:23:183:25 | access to local variable src | -| CSharp7.cs:177:25:177:25 | s | CSharp7.cs:177:33:177:33 | access to parameter s | -| CSharp7.cs:178:25:178:25 | s | CSharp7.cs:178:31:178:31 | access to parameter s | -| CSharp7.cs:179:25:179:25 | s | CSharp7.cs:179:37:179:37 | access to parameter s | -| CSharp7.cs:191:13:191:18 | Int32 v1 = ... | CSharp7.cs:192:26:192:27 | access to local variable v1 | -| CSharp7.cs:191:13:191:18 | Int32 v1 = ... | CSharp7.cs:198:21:198:22 | access to local variable v1 | -| CSharp7.cs:193:13:193:31 | Int32[] array = ... | CSharp7.cs:195:14:195:18 | access to local variable array | -| CSharp7.cs:193:13:193:31 | Int32[] array = ... | CSharp7.cs:196:26:196:30 | access to local variable array | -| CSharp7.cs:195:9:195:21 | ... = ... | CSharp7.cs:197:26:197:27 | access to local variable r1 | -| CSharp7.cs:195:9:195:21 | ... = ... | CSharp7.cs:199:33:199:34 | access to local variable r1 | -| CSharp7.cs:195:9:195:21 | ... = ... | CSharp7.cs:200:16:200:17 | access to local variable r1 | -| CSharp7.cs:203:24:203:24 | p | CSharp7.cs:206:20:206:20 | access to parameter p | -| CSharp7.cs:205:28:205:28 | q | CSharp7.cs:205:44:205:44 | access to parameter q | -| CSharp7.cs:233:16:233:23 | Object o = ... | CSharp7.cs:234:13:234:13 | access to local variable o | -| CSharp7.cs:233:16:233:23 | Object o = ... | CSharp7.cs:238:18:238:18 | access to local variable o | -| CSharp7.cs:233:16:233:23 | Object o = ... | CSharp7.cs:242:18:242:18 | access to local variable o | -| CSharp7.cs:233:16:233:23 | Object o = ... | CSharp7.cs:245:18:245:18 | access to local variable o | -| CSharp7.cs:233:16:233:23 | Object o = ... | CSharp7.cs:249:17:249:17 | access to local variable o | -| CSharp7.cs:233:16:233:23 | Object o = ... | CSharp7.cs:255:27:255:27 | access to local variable o | -| CSharp7.cs:234:18:234:23 | Int32 i1 | CSharp7.cs:234:28:234:29 | access to local variable i1 | -| CSharp7.cs:234:18:234:23 | Int32 i1 | CSharp7.cs:236:38:236:39 | access to local variable i1 | -| CSharp7.cs:238:23:238:31 | String s1 | CSharp7.cs:240:41:240:42 | access to local variable s1 | -| CSharp7.cs:255:32:255:40 | String s4 | CSharp7.cs:256:40:256:41 | access to local variable s4 | -| CSharp7.cs:258:18:258:23 | Int32 i2 | CSharp7.cs:258:30:258:31 | access to local variable i2 | -| CSharp7.cs:258:18:258:23 | Int32 i2 | CSharp7.cs:259:47:259:48 | access to local variable i2 | -| CSharp7.cs:261:18:261:23 | Int32 i3 | CSharp7.cs:262:42:262:43 | access to local variable i3 | -| CSharp7.cs:264:18:264:26 | String s2 | CSharp7.cs:265:45:265:46 | access to local variable s2 | -| CSharp7.cs:283:13:283:48 | Dictionary dict = ... | CSharp7.cs:284:20:284:23 | access to local variable dict | -| CSharp7.cs:284:13:284:62 | IEnumerable<(Int32,String)> list = ... | CSharp7.cs:286:39:286:42 | access to local variable list | -| CSharp7.cs:284:13:284:62 | IEnumerable<(Int32,String)> list = ... | CSharp7.cs:288:36:288:39 | access to local variable list | -| CSharp7.cs:284:13:284:62 | IEnumerable<(Int32,String)> list = ... | CSharp7.cs:290:32:290:35 | access to local variable list | -| CSharp7.cs:284:32:284:35 | item | CSharp7.cs:284:41:284:44 | access to parameter item | -| CSharp7.cs:284:32:284:35 | item | CSharp7.cs:284:51:284:54 | access to parameter item | -| CSharp7.cs:298:17:298:19 | Int32 x = ... | CSharp7.cs:298:22:298:22 | access to local variable x | -| CSharp7.cs:298:17:298:19 | Int32 x = ... | CSharp7.cs:298:30:298:30 | access to local variable x | -| CSharp7.cs:298:17:298:19 | Int32 x = ... | CSharp7.cs:298:44:298:44 | access to local variable x | -| CSharp7.cs:298:35:298:39 | Int32 y | CSharp7.cs:300:31:300:31 | access to local variable y | -| CSharp7.cs:298:42:298:44 | ++... | CSharp7.cs:298:22:298:22 | access to local variable x | -| CSharp7.cs:298:42:298:44 | ++... | CSharp7.cs:298:30:298:30 | access to local variable x | -| CSharp7.cs:298:42:298:44 | ++... | CSharp7.cs:298:44:298:44 | access to local variable x | +| CSharp7.cs:162:18:162:18 | t | CSharp7.cs:162:24:162:24 | access to parameter t | +| CSharp7.cs:164:26:164:26 | u | CSharp7.cs:168:22:168:22 | access to parameter u | +| CSharp7.cs:177:16:177:30 | String src = ... | CSharp7.cs:182:23:182:25 | access to local variable src | +| CSharp7.cs:177:16:177:30 | String src = ... | CSharp7.cs:183:23:183:25 | access to local variable src | +| CSharp7.cs:177:16:177:30 | String src = ... | CSharp7.cs:184:23:184:25 | access to local variable src | +| CSharp7.cs:178:25:178:25 | s | CSharp7.cs:178:33:178:33 | access to parameter s | +| CSharp7.cs:179:25:179:25 | s | CSharp7.cs:179:31:179:31 | access to parameter s | +| CSharp7.cs:180:25:180:25 | s | CSharp7.cs:180:37:180:37 | access to parameter s | +| CSharp7.cs:192:13:192:18 | Int32 v1 = ... | CSharp7.cs:193:26:193:27 | access to local variable v1 | +| CSharp7.cs:192:13:192:18 | Int32 v1 = ... | CSharp7.cs:199:21:199:22 | access to local variable v1 | +| CSharp7.cs:194:13:194:31 | Int32[] array = ... | CSharp7.cs:196:14:196:18 | access to local variable array | +| CSharp7.cs:194:13:194:31 | Int32[] array = ... | CSharp7.cs:197:26:197:30 | access to local variable array | +| CSharp7.cs:196:9:196:21 | ... = ... | CSharp7.cs:198:26:198:27 | access to local variable r1 | +| CSharp7.cs:196:9:196:21 | ... = ... | CSharp7.cs:200:33:200:34 | access to local variable r1 | +| CSharp7.cs:196:9:196:21 | ... = ... | CSharp7.cs:201:16:201:17 | access to local variable r1 | +| CSharp7.cs:204:24:204:24 | p | CSharp7.cs:207:20:207:20 | access to parameter p | +| CSharp7.cs:206:28:206:28 | q | CSharp7.cs:206:44:206:44 | access to parameter q | +| CSharp7.cs:234:16:234:23 | Object o = ... | CSharp7.cs:235:13:235:13 | access to local variable o | +| CSharp7.cs:234:16:234:23 | Object o = ... | CSharp7.cs:239:18:239:18 | access to local variable o | +| CSharp7.cs:234:16:234:23 | Object o = ... | CSharp7.cs:243:18:243:18 | access to local variable o | +| CSharp7.cs:234:16:234:23 | Object o = ... | CSharp7.cs:246:18:246:18 | access to local variable o | +| CSharp7.cs:234:16:234:23 | Object o = ... | CSharp7.cs:250:17:250:17 | access to local variable o | +| CSharp7.cs:234:16:234:23 | Object o = ... | CSharp7.cs:256:27:256:27 | access to local variable o | +| CSharp7.cs:235:18:235:23 | Int32 i1 | CSharp7.cs:235:28:235:29 | access to local variable i1 | +| CSharp7.cs:235:18:235:23 | Int32 i1 | CSharp7.cs:237:38:237:39 | access to local variable i1 | +| CSharp7.cs:239:23:239:31 | String s1 | CSharp7.cs:241:41:241:42 | access to local variable s1 | +| CSharp7.cs:256:32:256:40 | String s4 | CSharp7.cs:257:40:257:41 | access to local variable s4 | +| CSharp7.cs:259:18:259:23 | Int32 i2 | CSharp7.cs:259:30:259:31 | access to local variable i2 | +| CSharp7.cs:259:18:259:23 | Int32 i2 | CSharp7.cs:260:47:260:48 | access to local variable i2 | +| CSharp7.cs:262:18:262:23 | Int32 i3 | CSharp7.cs:263:42:263:43 | access to local variable i3 | +| CSharp7.cs:265:18:265:26 | String s2 | CSharp7.cs:266:45:266:46 | access to local variable s2 | +| CSharp7.cs:284:13:284:48 | Dictionary dict = ... | CSharp7.cs:285:20:285:23 | access to local variable dict | +| CSharp7.cs:285:13:285:62 | IEnumerable<(Int32,String)> list = ... | CSharp7.cs:287:39:287:42 | access to local variable list | +| CSharp7.cs:285:13:285:62 | IEnumerable<(Int32,String)> list = ... | CSharp7.cs:289:36:289:39 | access to local variable list | +| CSharp7.cs:285:13:285:62 | IEnumerable<(Int32,String)> list = ... | CSharp7.cs:291:32:291:35 | access to local variable list | +| CSharp7.cs:285:32:285:35 | item | CSharp7.cs:285:41:285:44 | access to parameter item | +| CSharp7.cs:285:32:285:35 | item | CSharp7.cs:285:51:285:54 | access to parameter item | +| CSharp7.cs:299:18:299:22 | Int32 x = ... | CSharp7.cs:299:25:299:25 | access to local variable x | +| CSharp7.cs:299:18:299:22 | Int32 x = ... | CSharp7.cs:299:35:299:35 | access to local variable x | +| CSharp7.cs:299:18:299:22 | Int32 x = ... | CSharp7.cs:299:49:299:49 | access to local variable x | +| CSharp7.cs:299:40:299:44 | Int32 y | CSharp7.cs:301:31:301:31 | access to local variable y | +| CSharp7.cs:299:47:299:49 | ++... | CSharp7.cs:299:25:299:25 | access to local variable x | +| CSharp7.cs:299:47:299:49 | ++... | CSharp7.cs:299:35:299:35 | access to local variable x | +| CSharp7.cs:299:47:299:49 | ++... | CSharp7.cs:299:49:299:49 | access to local variable x | diff --git a/csharp/ql/test/library-tests/csharp7/Discards.expected b/csharp/ql/test/library-tests/csharp7/Discards.expected index 41f6e47ac17e..0fffde7c1c0a 100644 --- a/csharp/ql/test/library-tests/csharp7/Discards.expected +++ b/csharp/ql/test/library-tests/csharp7/Discards.expected @@ -1,8 +1,8 @@ -| CSharp7.cs:222:9:222:9 | _ | (Int32,Double) | -| CSharp7.cs:222:19:222:19 | _ | Boolean | -| CSharp7.cs:223:10:223:10 | _ | Int32 | -| CSharp7.cs:223:13:223:13 | _ | Double | -| CSharp7.cs:223:24:223:24 | _ | Boolean | -| CSharp7.cs:224:17:224:17 | _ | Double | -| CSharp7.cs:224:28:224:28 | _ | Boolean | -| CSharp7.cs:225:10:225:10 | _ | Int32 | +| CSharp7.cs:223:9:223:9 | _ | (Int32,Double) | +| CSharp7.cs:223:19:223:19 | _ | Boolean | +| CSharp7.cs:224:10:224:10 | _ | Int32 | +| CSharp7.cs:224:13:224:13 | _ | Double | +| CSharp7.cs:224:24:224:24 | _ | Boolean | +| CSharp7.cs:225:17:225:17 | _ | Double | +| CSharp7.cs:225:28:225:28 | _ | Boolean | +| CSharp7.cs:226:10:226:10 | _ | Int32 | diff --git a/csharp/ql/test/library-tests/csharp7/ExpressionBodies.expected b/csharp/ql/test/library-tests/csharp7/ExpressionBodies.expected index b7dd392b22ab..5a09ce22d438 100644 --- a/csharp/ql/test/library-tests/csharp7/ExpressionBodies.expected +++ b/csharp/ql/test/library-tests/csharp7/ExpressionBodies.expected @@ -9,10 +9,10 @@ | CSharp7.cs:141:9:141:51 | f6 | CSharp7.cs:141:26:141:50 | ... ? ... : ... | | CSharp7.cs:143:9:143:31 | f7 | CSharp7.cs:143:26:143:30 | call to local function f6 | | CSharp7.cs:147:13:147:35 | f9 | CSharp7.cs:147:30:147:34 | call to local function f7 | -| CSharp7.cs:152:13:152:26 | f9 | CSharp7.cs:152:25:152:25 | 0 | -| CSharp7.cs:160:9:160:24 | f | CSharp7.cs:160:23:160:23 | 1 | -| CSharp7.cs:161:9:161:25 | g | CSharp7.cs:161:24:161:24 | access to parameter t | -| CSharp7.cs:165:13:165:43 | f2 | CSharp7.cs:165:37:165:42 | call to local function f | -| CSharp7.cs:177:9:177:40 | f | CSharp7.cs:177:31:177:39 | ... + ... | -| CSharp7.cs:178:9:178:32 | g | CSharp7.cs:178:31:178:31 | access to parameter s | -| CSharp7.cs:284:32:284:61 | (...) => ... | CSharp7.cs:284:40:284:61 | (..., ...) | +| CSharp7.cs:153:13:153:26 | f9 | CSharp7.cs:153:25:153:25 | 0 | +| CSharp7.cs:161:9:161:24 | f | CSharp7.cs:161:23:161:23 | 1 | +| CSharp7.cs:162:9:162:25 | g | CSharp7.cs:162:24:162:24 | access to parameter t | +| CSharp7.cs:166:13:166:43 | f2 | CSharp7.cs:166:37:166:42 | call to local function f | +| CSharp7.cs:178:9:178:40 | f | CSharp7.cs:178:31:178:39 | ... + ... | +| CSharp7.cs:179:9:179:32 | g | CSharp7.cs:179:31:179:31 | access to parameter s | +| CSharp7.cs:285:32:285:61 | (...) => ... | CSharp7.cs:285:40:285:61 | (..., ...) | diff --git a/csharp/ql/test/library-tests/csharp7/ForEach.expected b/csharp/ql/test/library-tests/csharp7/ForEach.expected index 71f3d7cb0ae1..d0699faabf07 100644 --- a/csharp/ql/test/library-tests/csharp7/ForEach.expected +++ b/csharp/ql/test/library-tests/csharp7/ForEach.expected @@ -1,6 +1,6 @@ -| CSharp7.cs:286:9:286:47 | foreach (... ... in ...) ... | 0 | CSharp7.cs:286:23:286:23 | Int32 a | CSharp7.cs:286:23:286:23 | a | CSharp7.cs:286:39:286:42 | access to local variable list | CSharp7.cs:286:45:286:47 | {...} | -| CSharp7.cs:286:9:286:47 | foreach (... ... in ...) ... | 1 | CSharp7.cs:286:33:286:33 | String b | CSharp7.cs:286:33:286:33 | b | CSharp7.cs:286:39:286:42 | access to local variable list | CSharp7.cs:286:45:286:47 | {...} | -| CSharp7.cs:288:9:288:44 | foreach (... ... in ...) ... | 0 | CSharp7.cs:288:23:288:23 | Int32 a | CSharp7.cs:288:23:288:23 | a | CSharp7.cs:288:36:288:39 | access to local variable list | CSharp7.cs:288:42:288:44 | {...} | -| CSharp7.cs:288:9:288:44 | foreach (... ... in ...) ... | 1 | CSharp7.cs:288:30:288:30 | String b | CSharp7.cs:288:30:288:30 | b | CSharp7.cs:288:36:288:39 | access to local variable list | CSharp7.cs:288:42:288:44 | {...} | -| CSharp7.cs:290:9:290:40 | foreach (... ... in ...) ... | 0 | CSharp7.cs:290:23:290:23 | Int32 a | CSharp7.cs:290:23:290:23 | a | CSharp7.cs:290:32:290:35 | access to local variable list | CSharp7.cs:290:38:290:40 | {...} | -| CSharp7.cs:290:9:290:40 | foreach (... ... in ...) ... | 1 | CSharp7.cs:290:26:290:26 | String b | CSharp7.cs:290:26:290:26 | b | CSharp7.cs:290:32:290:35 | access to local variable list | CSharp7.cs:290:38:290:40 | {...} | +| CSharp7.cs:287:9:287:47 | foreach (... ... in ...) ... | 0 | CSharp7.cs:287:23:287:23 | Int32 a | CSharp7.cs:287:23:287:23 | a | CSharp7.cs:287:39:287:42 | access to local variable list | CSharp7.cs:287:45:287:47 | {...} | +| CSharp7.cs:287:9:287:47 | foreach (... ... in ...) ... | 1 | CSharp7.cs:287:33:287:33 | String b | CSharp7.cs:287:33:287:33 | b | CSharp7.cs:287:39:287:42 | access to local variable list | CSharp7.cs:287:45:287:47 | {...} | +| CSharp7.cs:289:9:289:44 | foreach (... ... in ...) ... | 0 | CSharp7.cs:289:23:289:23 | Int32 a | CSharp7.cs:289:23:289:23 | a | CSharp7.cs:289:36:289:39 | access to local variable list | CSharp7.cs:289:42:289:44 | {...} | +| CSharp7.cs:289:9:289:44 | foreach (... ... in ...) ... | 1 | CSharp7.cs:289:30:289:30 | String b | CSharp7.cs:289:30:289:30 | b | CSharp7.cs:289:36:289:39 | access to local variable list | CSharp7.cs:289:42:289:44 | {...} | +| CSharp7.cs:291:9:291:40 | foreach (... ... in ...) ... | 0 | CSharp7.cs:291:23:291:23 | Int32 a | CSharp7.cs:291:23:291:23 | a | CSharp7.cs:291:32:291:35 | access to local variable list | CSharp7.cs:291:38:291:40 | {...} | +| CSharp7.cs:291:9:291:40 | foreach (... ... in ...) ... | 1 | CSharp7.cs:291:26:291:26 | String b | CSharp7.cs:291:26:291:26 | b | CSharp7.cs:291:32:291:35 | access to local variable list | CSharp7.cs:291:38:291:40 | {...} | diff --git a/csharp/ql/test/library-tests/csharp7/GlobalFlow.expected b/csharp/ql/test/library-tests/csharp7/GlobalFlow.expected index ffe1e741542a..b0b50f92ff6c 100644 --- a/csharp/ql/test/library-tests/csharp7/GlobalFlow.expected +++ b/csharp/ql/test/library-tests/csharp7/GlobalFlow.expected @@ -1,5 +1,5 @@ | CSharp7.cs:41:13:41:21 | "tainted" | CSharp7.cs:53:18:53:19 | access to local variable t1 | | CSharp7.cs:57:11:57:19 | "tainted" | CSharp7.cs:58:18:58:19 | access to local variable t4 | -| CSharp7.cs:176:22:176:30 | "tainted" | CSharp7.cs:176:22:176:30 | "tainted" | -| CSharp7.cs:176:22:176:30 | "tainted" | CSharp7.cs:182:21:182:26 | call to local function g | -| CSharp7.cs:176:22:176:30 | "tainted" | CSharp7.cs:183:21:183:26 | call to local function h | +| CSharp7.cs:177:22:177:30 | "tainted" | CSharp7.cs:177:22:177:30 | "tainted" | +| CSharp7.cs:177:22:177:30 | "tainted" | CSharp7.cs:183:21:183:26 | call to local function g | +| CSharp7.cs:177:22:177:30 | "tainted" | CSharp7.cs:184:21:184:26 | call to local function h | diff --git a/csharp/ql/test/library-tests/csharp7/GlobalTaintTracking.expected b/csharp/ql/test/library-tests/csharp7/GlobalTaintTracking.expected index 46a09f16377c..e22bec46795a 100644 --- a/csharp/ql/test/library-tests/csharp7/GlobalTaintTracking.expected +++ b/csharp/ql/test/library-tests/csharp7/GlobalTaintTracking.expected @@ -2,7 +2,7 @@ | CSharp7.cs:57:11:57:19 | "tainted" | CSharp7.cs:58:18:58:19 | access to local variable t4 | | CSharp7.cs:89:19:89:27 | "tainted" | CSharp7.cs:89:18:89:34 | (..., ...) | | CSharp7.cs:89:19:89:27 | "tainted" | CSharp7.cs:92:18:92:28 | call to method I | -| CSharp7.cs:176:22:176:30 | "tainted" | CSharp7.cs:176:22:176:30 | "tainted" | -| CSharp7.cs:176:22:176:30 | "tainted" | CSharp7.cs:181:21:181:26 | call to local function f | -| CSharp7.cs:176:22:176:30 | "tainted" | CSharp7.cs:182:21:182:26 | call to local function g | -| CSharp7.cs:176:22:176:30 | "tainted" | CSharp7.cs:183:21:183:26 | call to local function h | +| CSharp7.cs:177:22:177:30 | "tainted" | CSharp7.cs:177:22:177:30 | "tainted" | +| CSharp7.cs:177:22:177:30 | "tainted" | CSharp7.cs:182:21:182:26 | call to local function f | +| CSharp7.cs:177:22:177:30 | "tainted" | CSharp7.cs:183:21:183:26 | call to local function g | +| CSharp7.cs:177:22:177:30 | "tainted" | CSharp7.cs:184:21:184:26 | call to local function h | diff --git a/csharp/ql/test/library-tests/csharp7/IsFlow.expected b/csharp/ql/test/library-tests/csharp7/IsFlow.expected index 345e2f6347e2..5652f980d7ee 100644 --- a/csharp/ql/test/library-tests/csharp7/IsFlow.expected +++ b/csharp/ql/test/library-tests/csharp7/IsFlow.expected @@ -1,73 +1,73 @@ -| CSharp7.cs:249:9:275:9 | switch (...) {...} | CSharp7.cs:249:17:249:17 | access to local variable o | semmle.label | successor | -| CSharp7.cs:249:17:249:17 | access to local variable o | CSharp7.cs:251:13:251:23 | case ...: | semmle.label | successor | -| CSharp7.cs:251:13:251:23 | case ...: | CSharp7.cs:251:18:251:22 | "xyz" | semmle.label | successor | -| CSharp7.cs:251:18:251:22 | "xyz" | CSharp7.cs:252:17:252:22 | break; | semmle.label | match | -| CSharp7.cs:251:18:251:22 | "xyz" | CSharp7.cs:253:13:253:31 | case ...: | semmle.label | no-match | -| CSharp7.cs:252:17:252:22 | break; | CSharp7.cs:231:10:231:13 | exit Test | semmle.label | break | -| CSharp7.cs:253:13:253:31 | case ...: | CSharp7.cs:253:18:253:19 | "" | semmle.label | successor | -| CSharp7.cs:253:18:253:19 | "" | CSharp7.cs:253:26:253:26 | 1 | semmle.label | match | -| CSharp7.cs:253:18:253:19 | "" | CSharp7.cs:255:13:255:41 | case ...: | semmle.label | no-match | -| CSharp7.cs:253:26:253:26 | 1 | CSharp7.cs:253:30:253:30 | 2 | semmle.label | successor | -| CSharp7.cs:253:26:253:30 | ... < ... | CSharp7.cs:254:17:254:22 | break; | semmle.label | true | -| CSharp7.cs:253:30:253:30 | 2 | CSharp7.cs:253:26:253:30 | ... < ... | semmle.label | successor | -| CSharp7.cs:254:17:254:22 | break; | CSharp7.cs:231:10:231:13 | exit Test | semmle.label | break | -| CSharp7.cs:255:13:255:41 | case ...: | CSharp7.cs:255:18:255:20 | "x" | semmle.label | successor | -| CSharp7.cs:255:18:255:20 | "x" | CSharp7.cs:255:27:255:27 | access to local variable o | semmle.label | match | -| CSharp7.cs:255:18:255:20 | "x" | CSharp7.cs:258:13:258:36 | case ...: | semmle.label | no-match | -| CSharp7.cs:255:27:255:27 | access to local variable o | CSharp7.cs:255:32:255:40 | String s4 | semmle.label | successor | -| CSharp7.cs:255:27:255:40 | ... is ... | CSharp7.cs:256:17:256:45 | ...; | semmle.label | true | -| CSharp7.cs:255:27:255:40 | ... is ... | CSharp7.cs:258:13:258:36 | case ...: | semmle.label | false | -| CSharp7.cs:255:32:255:40 | String s4 | CSharp7.cs:255:27:255:40 | ... is ... | semmle.label | successor | -| CSharp7.cs:256:17:256:44 | call to method WriteLine | CSharp7.cs:257:17:257:22 | break; | semmle.label | successor | -| CSharp7.cs:256:17:256:45 | ...; | CSharp7.cs:256:37:256:38 | "x " | semmle.label | successor | -| CSharp7.cs:256:35:256:43 | $"..." | CSharp7.cs:256:17:256:44 | call to method WriteLine | semmle.label | successor | -| CSharp7.cs:256:37:256:38 | "x " | CSharp7.cs:256:40:256:41 | access to local variable s4 | semmle.label | successor | -| CSharp7.cs:256:40:256:41 | access to local variable s4 | CSharp7.cs:256:35:256:43 | $"..." | semmle.label | successor | -| CSharp7.cs:257:17:257:22 | break; | CSharp7.cs:231:10:231:13 | exit Test | semmle.label | break | -| CSharp7.cs:258:13:258:36 | case ...: | CSharp7.cs:258:18:258:23 | Int32 i2 | semmle.label | successor | -| CSharp7.cs:258:18:258:23 | Int32 i2 | CSharp7.cs:258:30:258:31 | access to local variable i2 | semmle.label | match | -| CSharp7.cs:258:18:258:23 | Int32 i2 | CSharp7.cs:261:13:261:24 | case ...: | semmle.label | no-match | -| CSharp7.cs:258:30:258:31 | access to local variable i2 | CSharp7.cs:258:35:258:35 | 0 | semmle.label | successor | -| CSharp7.cs:258:30:258:35 | ... > ... | CSharp7.cs:259:17:259:52 | ...; | semmle.label | true | -| CSharp7.cs:258:30:258:35 | ... > ... | CSharp7.cs:261:13:261:24 | case ...: | semmle.label | false | -| CSharp7.cs:258:35:258:35 | 0 | CSharp7.cs:258:30:258:35 | ... > ... | semmle.label | successor | -| CSharp7.cs:259:17:259:51 | call to method WriteLine | CSharp7.cs:260:17:260:22 | break; | semmle.label | successor | -| CSharp7.cs:259:17:259:52 | ...; | CSharp7.cs:259:37:259:45 | "positive " | semmle.label | successor | -| CSharp7.cs:259:35:259:50 | $"..." | CSharp7.cs:259:17:259:51 | call to method WriteLine | semmle.label | successor | -| CSharp7.cs:259:37:259:45 | "positive " | CSharp7.cs:259:47:259:48 | access to local variable i2 | semmle.label | successor | -| CSharp7.cs:259:47:259:48 | access to local variable i2 | CSharp7.cs:259:35:259:50 | $"..." | semmle.label | successor | -| CSharp7.cs:260:17:260:22 | break; | CSharp7.cs:231:10:231:13 | exit Test | semmle.label | break | -| CSharp7.cs:261:13:261:24 | case ...: | CSharp7.cs:261:18:261:23 | Int32 i3 | semmle.label | successor | -| CSharp7.cs:261:18:261:23 | Int32 i3 | CSharp7.cs:262:17:262:47 | ...; | semmle.label | match | -| CSharp7.cs:261:18:261:23 | Int32 i3 | CSharp7.cs:264:13:264:27 | case ...: | semmle.label | no-match | -| CSharp7.cs:262:17:262:46 | call to method WriteLine | CSharp7.cs:263:17:263:22 | break; | semmle.label | successor | -| CSharp7.cs:262:17:262:47 | ...; | CSharp7.cs:262:37:262:40 | "int " | semmle.label | successor | -| CSharp7.cs:262:35:262:45 | $"..." | CSharp7.cs:262:17:262:46 | call to method WriteLine | semmle.label | successor | -| CSharp7.cs:262:37:262:40 | "int " | CSharp7.cs:262:42:262:43 | access to local variable i3 | semmle.label | successor | -| CSharp7.cs:262:42:262:43 | access to local variable i3 | CSharp7.cs:262:35:262:45 | $"..." | semmle.label | successor | -| CSharp7.cs:263:17:263:22 | break; | CSharp7.cs:231:10:231:13 | exit Test | semmle.label | break | -| CSharp7.cs:264:13:264:27 | case ...: | CSharp7.cs:264:18:264:26 | String s2 | semmle.label | successor | -| CSharp7.cs:264:18:264:26 | String s2 | CSharp7.cs:265:17:265:50 | ...; | semmle.label | match | -| CSharp7.cs:264:18:264:26 | String s2 | CSharp7.cs:267:13:267:26 | case ...: | semmle.label | no-match | -| CSharp7.cs:265:17:265:49 | call to method WriteLine | CSharp7.cs:266:17:266:22 | break; | semmle.label | successor | -| CSharp7.cs:265:17:265:50 | ...; | CSharp7.cs:265:37:265:43 | "string " | semmle.label | successor | -| CSharp7.cs:265:35:265:48 | $"..." | CSharp7.cs:265:17:265:49 | call to method WriteLine | semmle.label | successor | -| CSharp7.cs:265:37:265:43 | "string " | CSharp7.cs:265:45:265:46 | access to local variable s2 | semmle.label | successor | -| CSharp7.cs:265:45:265:46 | access to local variable s2 | CSharp7.cs:265:35:265:48 | $"..." | semmle.label | successor | -| CSharp7.cs:266:17:266:22 | break; | CSharp7.cs:231:10:231:13 | exit Test | semmle.label | break | -| CSharp7.cs:267:13:267:26 | case ...: | CSharp7.cs:267:18:267:23 | access to type Double | semmle.label | successor | -| CSharp7.cs:267:18:267:23 | access to type Double | CSharp7.cs:268:17:268:44 | ...; | semmle.label | match | -| CSharp7.cs:267:18:267:23 | access to type Double | CSharp7.cs:270:13:270:24 | case ...: | semmle.label | no-match | -| CSharp7.cs:268:17:268:43 | call to method WriteLine | CSharp7.cs:269:17:269:22 | break; | semmle.label | successor | -| CSharp7.cs:268:17:268:44 | ...; | CSharp7.cs:268:35:268:42 | "Double" | semmle.label | successor | -| CSharp7.cs:268:35:268:42 | "Double" | CSharp7.cs:268:17:268:43 | call to method WriteLine | semmle.label | successor | -| CSharp7.cs:269:17:269:22 | break; | CSharp7.cs:231:10:231:13 | exit Test | semmle.label | break | -| CSharp7.cs:270:13:270:24 | case ...: | CSharp7.cs:270:18:270:23 | Object v2 | semmle.label | successor | -| CSharp7.cs:270:18:270:23 | Object v2 | CSharp7.cs:271:17:271:22 | break; | semmle.label | match | -| CSharp7.cs:270:18:270:23 | Object v2 | CSharp7.cs:272:13:272:20 | default: | semmle.label | no-match | -| CSharp7.cs:271:17:271:22 | break; | CSharp7.cs:231:10:231:13 | exit Test | semmle.label | break | -| CSharp7.cs:272:13:272:20 | default: | CSharp7.cs:273:17:273:52 | ...; | semmle.label | successor | -| CSharp7.cs:273:17:273:51 | call to method WriteLine | CSharp7.cs:274:17:274:22 | break; | semmle.label | successor | -| CSharp7.cs:273:17:273:52 | ...; | CSharp7.cs:273:35:273:50 | "Something else" | semmle.label | successor | -| CSharp7.cs:273:35:273:50 | "Something else" | CSharp7.cs:273:17:273:51 | call to method WriteLine | semmle.label | successor | -| CSharp7.cs:274:17:274:22 | break; | CSharp7.cs:231:10:231:13 | exit Test | semmle.label | break | +| CSharp7.cs:250:9:276:9 | switch (...) {...} | CSharp7.cs:250:17:250:17 | access to local variable o | semmle.label | successor | +| CSharp7.cs:250:17:250:17 | access to local variable o | CSharp7.cs:252:13:252:23 | case ...: | semmle.label | successor | +| CSharp7.cs:252:13:252:23 | case ...: | CSharp7.cs:252:18:252:22 | "xyz" | semmle.label | successor | +| CSharp7.cs:252:18:252:22 | "xyz" | CSharp7.cs:253:17:253:22 | break; | semmle.label | match | +| CSharp7.cs:252:18:252:22 | "xyz" | CSharp7.cs:254:13:254:31 | case ...: | semmle.label | no-match | +| CSharp7.cs:253:17:253:22 | break; | CSharp7.cs:232:10:232:13 | exit Test | semmle.label | break | +| CSharp7.cs:254:13:254:31 | case ...: | CSharp7.cs:254:18:254:19 | "" | semmle.label | successor | +| CSharp7.cs:254:18:254:19 | "" | CSharp7.cs:254:26:254:26 | 1 | semmle.label | match | +| CSharp7.cs:254:18:254:19 | "" | CSharp7.cs:256:13:256:41 | case ...: | semmle.label | no-match | +| CSharp7.cs:254:26:254:26 | 1 | CSharp7.cs:254:30:254:30 | 2 | semmle.label | successor | +| CSharp7.cs:254:26:254:30 | ... < ... | CSharp7.cs:255:17:255:22 | break; | semmle.label | true | +| CSharp7.cs:254:30:254:30 | 2 | CSharp7.cs:254:26:254:30 | ... < ... | semmle.label | successor | +| CSharp7.cs:255:17:255:22 | break; | CSharp7.cs:232:10:232:13 | exit Test | semmle.label | break | +| CSharp7.cs:256:13:256:41 | case ...: | CSharp7.cs:256:18:256:20 | "x" | semmle.label | successor | +| CSharp7.cs:256:18:256:20 | "x" | CSharp7.cs:256:27:256:27 | access to local variable o | semmle.label | match | +| CSharp7.cs:256:18:256:20 | "x" | CSharp7.cs:259:13:259:36 | case ...: | semmle.label | no-match | +| CSharp7.cs:256:27:256:27 | access to local variable o | CSharp7.cs:256:32:256:40 | String s4 | semmle.label | successor | +| CSharp7.cs:256:27:256:40 | ... is ... | CSharp7.cs:257:17:257:45 | ...; | semmle.label | true | +| CSharp7.cs:256:27:256:40 | ... is ... | CSharp7.cs:259:13:259:36 | case ...: | semmle.label | false | +| CSharp7.cs:256:32:256:40 | String s4 | CSharp7.cs:256:27:256:40 | ... is ... | semmle.label | successor | +| CSharp7.cs:257:17:257:44 | call to method WriteLine | CSharp7.cs:258:17:258:22 | break; | semmle.label | successor | +| CSharp7.cs:257:17:257:45 | ...; | CSharp7.cs:257:37:257:38 | "x " | semmle.label | successor | +| CSharp7.cs:257:35:257:43 | $"..." | CSharp7.cs:257:17:257:44 | call to method WriteLine | semmle.label | successor | +| CSharp7.cs:257:37:257:38 | "x " | CSharp7.cs:257:40:257:41 | access to local variable s4 | semmle.label | successor | +| CSharp7.cs:257:40:257:41 | access to local variable s4 | CSharp7.cs:257:35:257:43 | $"..." | semmle.label | successor | +| CSharp7.cs:258:17:258:22 | break; | CSharp7.cs:232:10:232:13 | exit Test | semmle.label | break | +| CSharp7.cs:259:13:259:36 | case ...: | CSharp7.cs:259:18:259:23 | Int32 i2 | semmle.label | successor | +| CSharp7.cs:259:18:259:23 | Int32 i2 | CSharp7.cs:259:30:259:31 | access to local variable i2 | semmle.label | match | +| CSharp7.cs:259:18:259:23 | Int32 i2 | CSharp7.cs:262:13:262:24 | case ...: | semmle.label | no-match | +| CSharp7.cs:259:30:259:31 | access to local variable i2 | CSharp7.cs:259:35:259:35 | 0 | semmle.label | successor | +| CSharp7.cs:259:30:259:35 | ... > ... | CSharp7.cs:260:17:260:52 | ...; | semmle.label | true | +| CSharp7.cs:259:30:259:35 | ... > ... | CSharp7.cs:262:13:262:24 | case ...: | semmle.label | false | +| CSharp7.cs:259:35:259:35 | 0 | CSharp7.cs:259:30:259:35 | ... > ... | semmle.label | successor | +| CSharp7.cs:260:17:260:51 | call to method WriteLine | CSharp7.cs:261:17:261:22 | break; | semmle.label | successor | +| CSharp7.cs:260:17:260:52 | ...; | CSharp7.cs:260:37:260:45 | "positive " | semmle.label | successor | +| CSharp7.cs:260:35:260:50 | $"..." | CSharp7.cs:260:17:260:51 | call to method WriteLine | semmle.label | successor | +| CSharp7.cs:260:37:260:45 | "positive " | CSharp7.cs:260:47:260:48 | access to local variable i2 | semmle.label | successor | +| CSharp7.cs:260:47:260:48 | access to local variable i2 | CSharp7.cs:260:35:260:50 | $"..." | semmle.label | successor | +| CSharp7.cs:261:17:261:22 | break; | CSharp7.cs:232:10:232:13 | exit Test | semmle.label | break | +| CSharp7.cs:262:13:262:24 | case ...: | CSharp7.cs:262:18:262:23 | Int32 i3 | semmle.label | successor | +| CSharp7.cs:262:18:262:23 | Int32 i3 | CSharp7.cs:263:17:263:47 | ...; | semmle.label | match | +| CSharp7.cs:262:18:262:23 | Int32 i3 | CSharp7.cs:265:13:265:27 | case ...: | semmle.label | no-match | +| CSharp7.cs:263:17:263:46 | call to method WriteLine | CSharp7.cs:264:17:264:22 | break; | semmle.label | successor | +| CSharp7.cs:263:17:263:47 | ...; | CSharp7.cs:263:37:263:40 | "int " | semmle.label | successor | +| CSharp7.cs:263:35:263:45 | $"..." | CSharp7.cs:263:17:263:46 | call to method WriteLine | semmle.label | successor | +| CSharp7.cs:263:37:263:40 | "int " | CSharp7.cs:263:42:263:43 | access to local variable i3 | semmle.label | successor | +| CSharp7.cs:263:42:263:43 | access to local variable i3 | CSharp7.cs:263:35:263:45 | $"..." | semmle.label | successor | +| CSharp7.cs:264:17:264:22 | break; | CSharp7.cs:232:10:232:13 | exit Test | semmle.label | break | +| CSharp7.cs:265:13:265:27 | case ...: | CSharp7.cs:265:18:265:26 | String s2 | semmle.label | successor | +| CSharp7.cs:265:18:265:26 | String s2 | CSharp7.cs:266:17:266:50 | ...; | semmle.label | match | +| CSharp7.cs:265:18:265:26 | String s2 | CSharp7.cs:268:13:268:26 | case ...: | semmle.label | no-match | +| CSharp7.cs:266:17:266:49 | call to method WriteLine | CSharp7.cs:267:17:267:22 | break; | semmle.label | successor | +| CSharp7.cs:266:17:266:50 | ...; | CSharp7.cs:266:37:266:43 | "string " | semmle.label | successor | +| CSharp7.cs:266:35:266:48 | $"..." | CSharp7.cs:266:17:266:49 | call to method WriteLine | semmle.label | successor | +| CSharp7.cs:266:37:266:43 | "string " | CSharp7.cs:266:45:266:46 | access to local variable s2 | semmle.label | successor | +| CSharp7.cs:266:45:266:46 | access to local variable s2 | CSharp7.cs:266:35:266:48 | $"..." | semmle.label | successor | +| CSharp7.cs:267:17:267:22 | break; | CSharp7.cs:232:10:232:13 | exit Test | semmle.label | break | +| CSharp7.cs:268:13:268:26 | case ...: | CSharp7.cs:268:18:268:23 | access to type Double | semmle.label | successor | +| CSharp7.cs:268:18:268:23 | access to type Double | CSharp7.cs:269:17:269:44 | ...; | semmle.label | match | +| CSharp7.cs:268:18:268:23 | access to type Double | CSharp7.cs:271:13:271:24 | case ...: | semmle.label | no-match | +| CSharp7.cs:269:17:269:43 | call to method WriteLine | CSharp7.cs:270:17:270:22 | break; | semmle.label | successor | +| CSharp7.cs:269:17:269:44 | ...; | CSharp7.cs:269:35:269:42 | "Double" | semmle.label | successor | +| CSharp7.cs:269:35:269:42 | "Double" | CSharp7.cs:269:17:269:43 | call to method WriteLine | semmle.label | successor | +| CSharp7.cs:270:17:270:22 | break; | CSharp7.cs:232:10:232:13 | exit Test | semmle.label | break | +| CSharp7.cs:271:13:271:24 | case ...: | CSharp7.cs:271:18:271:23 | Object v2 | semmle.label | successor | +| CSharp7.cs:271:18:271:23 | Object v2 | CSharp7.cs:272:17:272:22 | break; | semmle.label | match | +| CSharp7.cs:271:18:271:23 | Object v2 | CSharp7.cs:273:13:273:20 | default: | semmle.label | no-match | +| CSharp7.cs:272:17:272:22 | break; | CSharp7.cs:232:10:232:13 | exit Test | semmle.label | break | +| CSharp7.cs:273:13:273:20 | default: | CSharp7.cs:274:17:274:52 | ...; | semmle.label | successor | +| CSharp7.cs:274:17:274:51 | call to method WriteLine | CSharp7.cs:275:17:275:22 | break; | semmle.label | successor | +| CSharp7.cs:274:17:274:52 | ...; | CSharp7.cs:274:35:274:50 | "Something else" | semmle.label | successor | +| CSharp7.cs:274:35:274:50 | "Something else" | CSharp7.cs:274:17:274:51 | call to method WriteLine | semmle.label | successor | +| CSharp7.cs:275:17:275:22 | break; | CSharp7.cs:232:10:232:13 | exit Test | semmle.label | break | diff --git a/csharp/ql/test/library-tests/csharp7/IsPatterns.expected b/csharp/ql/test/library-tests/csharp7/IsPatterns.expected index 63bc44144904..d40737bd4620 100644 --- a/csharp/ql/test/library-tests/csharp7/IsPatterns.expected +++ b/csharp/ql/test/library-tests/csharp7/IsPatterns.expected @@ -1,5 +1,5 @@ -| CSharp7.cs:234:13:234:23 | ... is ... | Int32 | CSharp7.cs:234:18:234:23 | Int32 i1 | false | -| CSharp7.cs:238:18:238:31 | ... is ... | String | CSharp7.cs:238:23:238:31 | String s1 | false | -| CSharp7.cs:245:18:245:28 | ... is ... | Object | CSharp7.cs:245:23:245:28 | Object v1 | true | -| CSharp7.cs:255:27:255:40 | ... is ... | String | CSharp7.cs:255:32:255:40 | String s4 | false | -| CSharp7.cs:298:30:298:39 | ... is ... | Int32 | CSharp7.cs:298:35:298:39 | Int32 y | false | +| CSharp7.cs:235:13:235:23 | ... is ... | Int32 | CSharp7.cs:235:18:235:23 | Int32 i1 | false | +| CSharp7.cs:239:18:239:31 | ... is ... | String | CSharp7.cs:239:23:239:31 | String s1 | false | +| CSharp7.cs:246:18:246:28 | ... is ... | Object | CSharp7.cs:246:23:246:28 | Object v1 | true | +| CSharp7.cs:256:27:256:40 | ... is ... | String | CSharp7.cs:256:32:256:40 | String s4 | false | +| CSharp7.cs:299:35:299:44 | ... is ... | Int32 | CSharp7.cs:299:40:299:44 | Int32 y | false | diff --git a/csharp/ql/test/library-tests/csharp7/LocalFunctionCallArguments.expected b/csharp/ql/test/library-tests/csharp7/LocalFunctionCallArguments.expected index 52772ab037e2..2cf7be36a117 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalFunctionCallArguments.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalFunctionCallArguments.expected @@ -2,13 +2,13 @@ | CSharp7.cs:143:26:143:30 | call to local function f6 | 0 | CSharp7.cs:143:29:143:29 | access to parameter x | | CSharp7.cs:147:30:147:34 | call to local function f7 | 0 | CSharp7.cs:147:33:147:33 | access to parameter x | | CSharp7.cs:148:20:148:24 | call to local function f9 | 0 | CSharp7.cs:148:23:148:23 | 1 | -| CSharp7.cs:155:16:155:20 | call to local function f1 | 0 | CSharp7.cs:155:19:155:19 | 2 | -| CSharp7.cs:167:20:167:23 | call to local function g | 0 | CSharp7.cs:167:22:167:22 | access to parameter u | -| CSharp7.cs:170:9:170:15 | call to local function h | 0 | CSharp7.cs:170:11:170:11 | 0 | -| CSharp7.cs:170:9:170:15 | call to local function h | 1 | CSharp7.cs:170:14:170:14 | 0 | -| CSharp7.cs:171:9:171:19 | call to local function h | 0 | CSharp7.cs:171:11:171:12 | "" | -| CSharp7.cs:171:9:171:19 | call to local function h | 1 | CSharp7.cs:171:15:171:18 | true | -| CSharp7.cs:177:31:177:34 | call to local function g | 0 | CSharp7.cs:177:33:177:33 | access to parameter s | -| CSharp7.cs:181:21:181:26 | call to local function f | 0 | CSharp7.cs:181:23:181:25 | access to local variable src | -| CSharp7.cs:182:21:182:26 | call to local function g | 0 | CSharp7.cs:182:23:182:25 | access to local variable src | -| CSharp7.cs:183:21:183:26 | call to local function h | 0 | CSharp7.cs:183:23:183:25 | access to local variable src | +| CSharp7.cs:156:16:156:20 | call to local function f1 | 0 | CSharp7.cs:156:19:156:19 | 2 | +| CSharp7.cs:168:20:168:23 | call to local function g | 0 | CSharp7.cs:168:22:168:22 | access to parameter u | +| CSharp7.cs:171:9:171:15 | call to local function h | 0 | CSharp7.cs:171:11:171:11 | 0 | +| CSharp7.cs:171:9:171:15 | call to local function h | 1 | CSharp7.cs:171:14:171:14 | 0 | +| CSharp7.cs:172:9:172:19 | call to local function h | 0 | CSharp7.cs:172:11:172:12 | "" | +| CSharp7.cs:172:9:172:19 | call to local function h | 1 | CSharp7.cs:172:15:172:18 | true | +| CSharp7.cs:178:31:178:34 | call to local function g | 0 | CSharp7.cs:178:33:178:33 | access to parameter s | +| CSharp7.cs:182:21:182:26 | call to local function f | 0 | CSharp7.cs:182:23:182:25 | access to local variable src | +| CSharp7.cs:183:21:183:26 | call to local function g | 0 | CSharp7.cs:183:23:183:25 | access to local variable src | +| CSharp7.cs:184:21:184:26 | call to local function h | 0 | CSharp7.cs:184:23:184:25 | access to local variable src | diff --git a/csharp/ql/test/library-tests/csharp7/LocalFunctionCalls.expected b/csharp/ql/test/library-tests/csharp7/LocalFunctionCalls.expected index 9ecf8790464b..f465839b3cfb 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalFunctionCalls.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalFunctionCalls.expected @@ -2,13 +2,13 @@ | CSharp7.cs:143:26:143:30 | call to local function f6 | CSharp7.cs:141:9:141:51 | f6 | CSharp7.cs:141:9:141:51 | f6 | | CSharp7.cs:147:30:147:34 | call to local function f7 | CSharp7.cs:143:9:143:31 | f7 | CSharp7.cs:143:9:143:31 | f7 | | CSharp7.cs:148:20:148:24 | call to local function f9 | CSharp7.cs:147:13:147:35 | f9 | CSharp7.cs:147:13:147:35 | f9 | -| CSharp7.cs:155:16:155:20 | call to local function f1 | CSharp7.cs:131:9:131:39 | f1 | CSharp7.cs:131:9:131:39 | f1 | -| CSharp7.cs:165:37:165:42 | call to local function f | CSharp7.cs:160:9:160:24 | f | CSharp7.cs:160:9:160:24 | f | -| CSharp7.cs:166:13:166:18 | call to local function f | CSharp7.cs:160:9:160:24 | f | CSharp7.cs:160:9:160:24 | f | -| CSharp7.cs:167:20:167:23 | call to local function g | CSharp7.cs:161:9:161:25 | g | CSharp7.cs:161:9:161:25 | g | -| CSharp7.cs:170:9:170:15 | call to local function h | CSharp7.cs:163:9:168:9 | h | CSharp7.cs:163:9:168:9 | h | -| CSharp7.cs:171:9:171:19 | call to local function h | CSharp7.cs:163:9:168:9 | h | CSharp7.cs:163:9:168:9 | h | -| CSharp7.cs:177:31:177:34 | call to local function g | CSharp7.cs:178:9:178:32 | g | CSharp7.cs:178:9:178:32 | g | -| CSharp7.cs:181:21:181:26 | call to local function f | CSharp7.cs:177:9:177:40 | f | CSharp7.cs:177:9:177:40 | f | -| CSharp7.cs:182:21:182:26 | call to local function g | CSharp7.cs:178:9:178:32 | g | CSharp7.cs:178:9:178:32 | g | -| CSharp7.cs:183:21:183:26 | call to local function h | CSharp7.cs:179:9:179:40 | h | CSharp7.cs:179:9:179:40 | h | +| CSharp7.cs:156:16:156:20 | call to local function f1 | CSharp7.cs:131:9:131:39 | f1 | CSharp7.cs:131:9:131:39 | f1 | +| CSharp7.cs:166:37:166:42 | call to local function f | CSharp7.cs:161:9:161:24 | f | CSharp7.cs:161:9:161:24 | f | +| CSharp7.cs:167:13:167:18 | call to local function f | CSharp7.cs:161:9:161:24 | f | CSharp7.cs:161:9:161:24 | f | +| CSharp7.cs:168:20:168:23 | call to local function g | CSharp7.cs:162:9:162:25 | g | CSharp7.cs:162:9:162:25 | g | +| CSharp7.cs:171:9:171:15 | call to local function h | CSharp7.cs:164:9:169:9 | h | CSharp7.cs:164:9:169:9 | h | +| CSharp7.cs:172:9:172:19 | call to local function h | CSharp7.cs:164:9:169:9 | h | CSharp7.cs:164:9:169:9 | h | +| CSharp7.cs:178:31:178:34 | call to local function g | CSharp7.cs:179:9:179:32 | g | CSharp7.cs:179:9:179:32 | g | +| CSharp7.cs:182:21:182:26 | call to local function f | CSharp7.cs:178:9:178:40 | f | CSharp7.cs:178:9:178:40 | f | +| CSharp7.cs:183:21:183:26 | call to local function g | CSharp7.cs:179:9:179:32 | g | CSharp7.cs:179:9:179:32 | g | +| CSharp7.cs:184:21:184:26 | call to local function h | CSharp7.cs:180:9:180:40 | h | CSharp7.cs:180:9:180:40 | h | diff --git a/csharp/ql/test/library-tests/csharp7/LocalFunctionParameters.expected b/csharp/ql/test/library-tests/csharp7/LocalFunctionParameters.expected index a3aabd4f16ff..a9ae61c7b868 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalFunctionParameters.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalFunctionParameters.expected @@ -4,17 +4,17 @@ | CSharp7.cs:141:9:141:51 | f6 | 0 | CSharp7.cs:141:20:141:20 | x | Int32 | | CSharp7.cs:143:9:143:31 | f7 | 0 | CSharp7.cs:143:20:143:20 | x | Int32 | | CSharp7.cs:147:13:147:35 | f9 | 0 | CSharp7.cs:147:24:147:24 | x | Int32 | -| CSharp7.cs:161:9:161:25 | g | 0 | CSharp7.cs:161:18:161:18 | t | T | -| CSharp7.cs:161:9:161:25 | g | 0 | CSharp7.cs:161:18:161:18 | t | U | -| CSharp7.cs:163:9:168:9 | h | 0 | CSharp7.cs:163:21:163:21 | t | Int32 | -| CSharp7.cs:163:9:168:9 | h | 0 | CSharp7.cs:163:21:163:21 | t | String | -| CSharp7.cs:163:9:168:9 | h | 0 | CSharp7.cs:163:21:163:21 | t | T | -| CSharp7.cs:163:9:168:9 | h | 1 | CSharp7.cs:163:26:163:26 | u | Boolean | -| CSharp7.cs:163:9:168:9 | h | 1 | CSharp7.cs:163:26:163:26 | u | Int32 | -| CSharp7.cs:163:9:168:9 | h | 1 | CSharp7.cs:163:26:163:26 | u | U | -| CSharp7.cs:165:13:165:43 | f2 | 0 | CSharp7.cs:165:25:165:25 | s | S | -| CSharp7.cs:165:13:165:43 | f2 | 1 | CSharp7.cs:165:30:165:31 | _t | T | -| CSharp7.cs:177:9:177:40 | f | 0 | CSharp7.cs:177:25:177:25 | s | String | -| CSharp7.cs:178:9:178:32 | g | 0 | CSharp7.cs:178:25:178:25 | s | String | -| CSharp7.cs:179:9:179:40 | h | 0 | CSharp7.cs:179:25:179:25 | s | String | -| CSharp7.cs:205:9:205:47 | F3 | 0 | CSharp7.cs:205:28:205:28 | q | Int32 | +| CSharp7.cs:162:9:162:25 | g | 0 | CSharp7.cs:162:18:162:18 | t | T | +| CSharp7.cs:162:9:162:25 | g | 0 | CSharp7.cs:162:18:162:18 | t | U | +| CSharp7.cs:164:9:169:9 | h | 0 | CSharp7.cs:164:21:164:21 | t | Int32 | +| CSharp7.cs:164:9:169:9 | h | 0 | CSharp7.cs:164:21:164:21 | t | String | +| CSharp7.cs:164:9:169:9 | h | 0 | CSharp7.cs:164:21:164:21 | t | T | +| CSharp7.cs:164:9:169:9 | h | 1 | CSharp7.cs:164:26:164:26 | u | Boolean | +| CSharp7.cs:164:9:169:9 | h | 1 | CSharp7.cs:164:26:164:26 | u | Int32 | +| CSharp7.cs:164:9:169:9 | h | 1 | CSharp7.cs:164:26:164:26 | u | U | +| CSharp7.cs:166:13:166:43 | f2 | 0 | CSharp7.cs:166:25:166:25 | s | S | +| CSharp7.cs:166:13:166:43 | f2 | 1 | CSharp7.cs:166:30:166:31 | _t | T | +| CSharp7.cs:178:9:178:40 | f | 0 | CSharp7.cs:178:25:178:25 | s | String | +| CSharp7.cs:179:9:179:32 | g | 0 | CSharp7.cs:179:25:179:25 | s | String | +| CSharp7.cs:180:9:180:40 | h | 0 | CSharp7.cs:180:25:180:25 | s | String | +| CSharp7.cs:206:9:206:47 | F3 | 0 | CSharp7.cs:206:28:206:28 | q | Int32 | diff --git a/csharp/ql/test/library-tests/csharp7/LocalFunctionStmts.expected b/csharp/ql/test/library-tests/csharp7/LocalFunctionStmts.expected index 06375392141c..748bef67d7e9 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalFunctionStmts.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalFunctionStmts.expected @@ -5,12 +5,12 @@ | CSharp7.cs:143:9:143:31 | f7(...) | CSharp7.cs:143:9:143:31 | f7 | | CSharp7.cs:145:9:149:9 | f8(...) | CSharp7.cs:145:9:149:9 | f8 | | CSharp7.cs:147:13:147:35 | f9(...) | CSharp7.cs:147:13:147:35 | f9 | -| CSharp7.cs:152:13:152:26 | f9(...) | CSharp7.cs:152:13:152:26 | f9 | -| CSharp7.cs:160:9:160:24 | f(...) | CSharp7.cs:160:9:160:24 | f | -| CSharp7.cs:161:9:161:25 | g(...) | CSharp7.cs:161:9:161:25 | g | -| CSharp7.cs:163:9:168:9 | h(...) | CSharp7.cs:163:9:168:9 | h | -| CSharp7.cs:165:13:165:43 | f2(...) | CSharp7.cs:165:13:165:43 | f2 | -| CSharp7.cs:177:9:177:40 | f(...) | CSharp7.cs:177:9:177:40 | f | -| CSharp7.cs:178:9:178:32 | g(...) | CSharp7.cs:178:9:178:32 | g | -| CSharp7.cs:179:9:179:40 | h(...) | CSharp7.cs:179:9:179:40 | h | -| CSharp7.cs:205:9:205:47 | F3(...) | CSharp7.cs:205:9:205:47 | F3 | +| CSharp7.cs:153:13:153:26 | f9(...) | CSharp7.cs:153:13:153:26 | f9 | +| CSharp7.cs:161:9:161:24 | f(...) | CSharp7.cs:161:9:161:24 | f | +| CSharp7.cs:162:9:162:25 | g(...) | CSharp7.cs:162:9:162:25 | g | +| CSharp7.cs:164:9:169:9 | h(...) | CSharp7.cs:164:9:169:9 | h | +| CSharp7.cs:166:13:166:43 | f2(...) | CSharp7.cs:166:13:166:43 | f2 | +| CSharp7.cs:178:9:178:40 | f(...) | CSharp7.cs:178:9:178:40 | f | +| CSharp7.cs:179:9:179:32 | g(...) | CSharp7.cs:179:9:179:32 | g | +| CSharp7.cs:180:9:180:40 | h(...) | CSharp7.cs:180:9:180:40 | h | +| CSharp7.cs:206:9:206:47 | F3(...) | CSharp7.cs:206:9:206:47 | F3 | diff --git a/csharp/ql/test/library-tests/csharp7/LocalFunctions.expected b/csharp/ql/test/library-tests/csharp7/LocalFunctions.expected index 89c25f6102d4..789895f434d5 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalFunctions.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalFunctions.expected @@ -1,20 +1,20 @@ -| CSharp7.cs:131:9:131:39 | f1 | f1 | Int32 | CSharp7.cs:130:5:156:5 | {...} | CSharp7.cs:131:9:131:39 | f1(...) | f1(int) | -| CSharp7.cs:133:9:133:42 | f2 | f2 | T | CSharp7.cs:130:5:156:5 | {...} | CSharp7.cs:133:9:133:42 | f2(...) | f2(T, U) | -| CSharp7.cs:137:9:137:22 | f3 | f3 | Int32 | CSharp7.cs:130:5:156:5 | {...} | CSharp7.cs:137:9:137:22 | f3(...) | f3() | -| CSharp7.cs:141:9:141:51 | f6 | f6 | Int32 | CSharp7.cs:130:5:156:5 | {...} | CSharp7.cs:141:9:141:51 | f6(...) | f6(int) | -| CSharp7.cs:143:9:143:31 | f7 | f7 | Int32 | CSharp7.cs:130:5:156:5 | {...} | CSharp7.cs:143:9:143:31 | f7(...) | f7(int) | -| CSharp7.cs:145:9:149:9 | f8 | f8 | Int32 | CSharp7.cs:130:5:156:5 | {...} | CSharp7.cs:145:9:149:9 | f8(...) | f8() | +| CSharp7.cs:131:9:131:39 | f1 | f1 | Int32 | CSharp7.cs:130:5:157:5 | {...} | CSharp7.cs:131:9:131:39 | f1(...) | f1(int) | +| CSharp7.cs:133:9:133:42 | f2 | f2 | T | CSharp7.cs:130:5:157:5 | {...} | CSharp7.cs:133:9:133:42 | f2(...) | f2(T, U) | +| CSharp7.cs:137:9:137:22 | f3 | f3 | Int32 | CSharp7.cs:130:5:157:5 | {...} | CSharp7.cs:137:9:137:22 | f3(...) | f3() | +| CSharp7.cs:141:9:141:51 | f6 | f6 | Int32 | CSharp7.cs:130:5:157:5 | {...} | CSharp7.cs:141:9:141:51 | f6(...) | f6(int) | +| CSharp7.cs:143:9:143:31 | f7 | f7 | Int32 | CSharp7.cs:130:5:157:5 | {...} | CSharp7.cs:143:9:143:31 | f7(...) | f7(int) | +| CSharp7.cs:145:9:149:9 | f8 | f8 | Int32 | CSharp7.cs:130:5:157:5 | {...} | CSharp7.cs:145:9:149:9 | f8(...) | f8() | | CSharp7.cs:147:13:147:35 | f9 | f9 | Int32 | CSharp7.cs:146:9:149:9 | {...} | CSharp7.cs:147:13:147:35 | f9(...) | f9(int) | -| CSharp7.cs:152:13:152:26 | f9 | f9 | Int32 | CSharp7.cs:151:26:153:9 | {...} | CSharp7.cs:152:13:152:26 | f9(...) | f9() | -| CSharp7.cs:160:9:160:24 | f | f | Int32 | CSharp7.cs:159:5:172:5 | {...} | CSharp7.cs:160:9:160:24 | f(...) | f() | -| CSharp7.cs:160:9:160:24 | f | f | Int32 | CSharp7.cs:159:5:172:5 | {...} | CSharp7.cs:160:9:160:24 | f(...) | f() | -| CSharp7.cs:161:9:161:25 | g | g | T | CSharp7.cs:159:5:172:5 | {...} | CSharp7.cs:161:9:161:25 | g(...) | g(T) | -| CSharp7.cs:161:9:161:25 | g | g | U | CSharp7.cs:159:5:172:5 | {...} | CSharp7.cs:161:9:161:25 | g(...) | g(U) | -| CSharp7.cs:163:9:168:9 | h | h | Boolean | CSharp7.cs:159:5:172:5 | {...} | CSharp7.cs:163:9:168:9 | h(...) | h(string, bool) | -| CSharp7.cs:163:9:168:9 | h | h | Int32 | CSharp7.cs:159:5:172:5 | {...} | CSharp7.cs:163:9:168:9 | h(...) | h(int, int) | -| CSharp7.cs:163:9:168:9 | h | h | U | CSharp7.cs:159:5:172:5 | {...} | CSharp7.cs:163:9:168:9 | h(...) | h(T, U) | -| CSharp7.cs:165:13:165:43 | f2 | f2 | Int32 | CSharp7.cs:164:9:168:9 | {...} | CSharp7.cs:165:13:165:43 | f2(...) | f2(S, T) | -| CSharp7.cs:177:9:177:40 | f | f | String | CSharp7.cs:175:5:184:5 | {...} | CSharp7.cs:177:9:177:40 | f(...) | f(string) | -| CSharp7.cs:178:9:178:32 | g | g | String | CSharp7.cs:175:5:184:5 | {...} | CSharp7.cs:178:9:178:32 | g(...) | g(string) | -| CSharp7.cs:179:9:179:40 | h | h | String | CSharp7.cs:175:5:184:5 | {...} | CSharp7.cs:179:9:179:40 | h(...) | h(string) | -| CSharp7.cs:205:9:205:47 | F3 | F3 | Int32 | CSharp7.cs:204:5:207:5 | {...} | CSharp7.cs:205:9:205:47 | F3(...) | F3(ref int) | +| CSharp7.cs:153:13:153:26 | f9 | f9 | Int32 | CSharp7.cs:152:9:154:9 | {...} | CSharp7.cs:153:13:153:26 | f9(...) | f9() | +| CSharp7.cs:161:9:161:24 | f | f | Int32 | CSharp7.cs:160:5:173:5 | {...} | CSharp7.cs:161:9:161:24 | f(...) | f() | +| CSharp7.cs:161:9:161:24 | f | f | Int32 | CSharp7.cs:160:5:173:5 | {...} | CSharp7.cs:161:9:161:24 | f(...) | f() | +| CSharp7.cs:162:9:162:25 | g | g | T | CSharp7.cs:160:5:173:5 | {...} | CSharp7.cs:162:9:162:25 | g(...) | g(T) | +| CSharp7.cs:162:9:162:25 | g | g | U | CSharp7.cs:160:5:173:5 | {...} | CSharp7.cs:162:9:162:25 | g(...) | g(U) | +| CSharp7.cs:164:9:169:9 | h | h | Boolean | CSharp7.cs:160:5:173:5 | {...} | CSharp7.cs:164:9:169:9 | h(...) | h(string, bool) | +| CSharp7.cs:164:9:169:9 | h | h | Int32 | CSharp7.cs:160:5:173:5 | {...} | CSharp7.cs:164:9:169:9 | h(...) | h(int, int) | +| CSharp7.cs:164:9:169:9 | h | h | U | CSharp7.cs:160:5:173:5 | {...} | CSharp7.cs:164:9:169:9 | h(...) | h(T, U) | +| CSharp7.cs:166:13:166:43 | f2 | f2 | Int32 | CSharp7.cs:165:9:169:9 | {...} | CSharp7.cs:166:13:166:43 | f2(...) | f2(S, T) | +| CSharp7.cs:178:9:178:40 | f | f | String | CSharp7.cs:176:5:185:5 | {...} | CSharp7.cs:178:9:178:40 | f(...) | f(string) | +| CSharp7.cs:179:9:179:32 | g | g | String | CSharp7.cs:176:5:185:5 | {...} | CSharp7.cs:179:9:179:32 | g(...) | g(string) | +| CSharp7.cs:180:9:180:40 | h | h | String | CSharp7.cs:176:5:185:5 | {...} | CSharp7.cs:180:9:180:40 | h(...) | h(string) | +| CSharp7.cs:206:9:206:47 | F3 | F3 | Int32 | CSharp7.cs:205:5:208:5 | {...} | CSharp7.cs:206:9:206:47 | F3(...) | F3(ref int) | diff --git a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected index cad303fa914f..e5201d0df7d5 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected @@ -29,8 +29,8 @@ | CSharp7.cs:54:9:54:17 | this access | CSharp7.cs:57:9:57:32 | this access | | CSharp7.cs:54:15:54:16 | SSA def(t1) | CSharp7.cs:55:14:55:15 | access to local variable t1 | | CSharp7.cs:57:30:57:31 | SSA def(t4) | CSharp7.cs:58:18:58:19 | access to local variable t4 | -| CSharp7.cs:66:17:66:17 | 1 | CSharp7.cs:66:16:66:21 | (..., ...) | -| CSharp7.cs:66:20:66:20 | 2 | CSharp7.cs:66:16:66:21 | (..., ...) | +| CSharp7.cs:66:20:66:20 | 1 | CSharp7.cs:66:16:66:27 | (..., ...) | +| CSharp7.cs:66:26:66:26 | 2 | CSharp7.cs:66:16:66:27 | (..., ...) | | CSharp7.cs:69:10:69:20 | this | CSharp7.cs:71:26:71:28 | this access | | CSharp7.cs:71:26:71:28 | [post] this access | CSharp7.cs:72:17:72:19 | this access | | CSharp7.cs:71:26:71:28 | this access | CSharp7.cs:72:17:72:19 | this access | @@ -40,7 +40,7 @@ | CSharp7.cs:72:17:72:19 | this access | CSharp7.cs:73:18:73:20 | this access | | CSharp7.cs:73:18:73:20 | [post] this access | CSharp7.cs:74:13:74:15 | this access | | CSharp7.cs:73:18:73:20 | this access | CSharp7.cs:74:13:74:15 | this access | -| CSharp7.cs:74:13:74:15 | call to method F | CSharp7.cs:74:13:74:21 | access to field Item1 | +| CSharp7.cs:74:13:74:15 | call to method F | CSharp7.cs:74:13:74:17 | access to field A | | CSharp7.cs:75:16:75:16 | [post] access to local variable z | CSharp7.cs:77:39:77:39 | access to local variable z | | CSharp7.cs:75:16:75:16 | access to local variable z | CSharp7.cs:77:39:77:39 | access to local variable z | | CSharp7.cs:75:28:75:28 | 1 | CSharp7.cs:75:27:75:35 | (..., ...) | @@ -116,7 +116,7 @@ | CSharp7.cs:131:32:131:32 | access to parameter x | CSharp7.cs:131:32:131:36 | ... + ... | | CSharp7.cs:131:36:131:36 | 1 | CSharp7.cs:131:32:131:36 | ... + ... | | CSharp7.cs:133:22:133:22 | t | CSharp7.cs:133:39:133:39 | access to parameter t | -| CSharp7.cs:135:24:135:25 | this access | CSharp7.cs:155:16:155:17 | this access | +| CSharp7.cs:135:24:135:25 | this access | CSharp7.cs:156:16:156:17 | this access | | CSharp7.cs:139:29:139:29 | x | CSharp7.cs:139:34:139:34 | access to parameter x | | CSharp7.cs:139:34:139:34 | access to parameter x | CSharp7.cs:139:34:139:38 | ... + ... | | CSharp7.cs:139:38:139:38 | 1 | CSharp7.cs:139:34:139:38 | ... + ... | @@ -133,125 +133,119 @@ | CSharp7.cs:145:9:149:9 | this | CSharp7.cs:148:20:148:21 | this access | | CSharp7.cs:147:13:147:35 | this | CSharp7.cs:147:30:147:31 | this access | | CSharp7.cs:147:24:147:24 | x | CSharp7.cs:147:33:147:33 | access to parameter x | -| CSharp7.cs:158:10:158:17 | this | CSharp7.cs:170:9:170:9 | this access | -| CSharp7.cs:161:18:161:18 | t | CSharp7.cs:161:24:161:24 | access to parameter t | -| CSharp7.cs:163:9:168:9 | this | CSharp7.cs:166:13:166:16 | this access | -| CSharp7.cs:163:26:163:26 | u | CSharp7.cs:167:22:167:22 | access to parameter u | -| CSharp7.cs:165:13:165:43 | this | CSharp7.cs:165:37:165:40 | this access | -| CSharp7.cs:166:13:166:16 | this access | CSharp7.cs:167:20:167:20 | this access | -| CSharp7.cs:170:9:170:9 | this access | CSharp7.cs:171:9:171:9 | this access | -| CSharp7.cs:174:10:174:19 | this | CSharp7.cs:181:21:181:21 | this access | -| CSharp7.cs:176:16:176:30 | SSA def(src) | CSharp7.cs:181:23:181:25 | access to local variable src | -| CSharp7.cs:176:22:176:30 | "tainted" | CSharp7.cs:176:16:176:30 | SSA def(src) | -| CSharp7.cs:177:9:177:40 | this | CSharp7.cs:177:31:177:31 | this access | -| CSharp7.cs:177:25:177:25 | s | CSharp7.cs:177:33:177:33 | access to parameter s | -| CSharp7.cs:177:31:177:34 | call to local function g | CSharp7.cs:177:31:177:39 | ... + ... | -| CSharp7.cs:177:38:177:39 | "" | CSharp7.cs:177:31:177:39 | ... + ... | -| CSharp7.cs:178:25:178:25 | s | CSharp7.cs:178:31:178:31 | access to parameter s | -| CSharp7.cs:179:25:179:25 | s | CSharp7.cs:179:37:179:37 | access to parameter s | -| CSharp7.cs:181:21:181:21 | this access | CSharp7.cs:182:21:182:21 | this access | -| CSharp7.cs:181:23:181:25 | [post] access to local variable src | CSharp7.cs:182:23:182:25 | access to local variable src | -| CSharp7.cs:181:23:181:25 | access to local variable src | CSharp7.cs:182:23:182:25 | access to local variable src | +| CSharp7.cs:159:10:159:17 | this | CSharp7.cs:171:9:171:9 | this access | +| CSharp7.cs:162:18:162:18 | t | CSharp7.cs:162:24:162:24 | access to parameter t | +| CSharp7.cs:164:9:169:9 | this | CSharp7.cs:167:13:167:16 | this access | +| CSharp7.cs:164:26:164:26 | u | CSharp7.cs:168:22:168:22 | access to parameter u | +| CSharp7.cs:166:13:166:43 | this | CSharp7.cs:166:37:166:40 | this access | +| CSharp7.cs:167:13:167:16 | this access | CSharp7.cs:168:20:168:20 | this access | +| CSharp7.cs:171:9:171:9 | this access | CSharp7.cs:172:9:172:9 | this access | +| CSharp7.cs:175:10:175:19 | this | CSharp7.cs:182:21:182:21 | this access | +| CSharp7.cs:177:16:177:30 | SSA def(src) | CSharp7.cs:182:23:182:25 | access to local variable src | +| CSharp7.cs:177:22:177:30 | "tainted" | CSharp7.cs:177:16:177:30 | SSA def(src) | +| CSharp7.cs:178:9:178:40 | this | CSharp7.cs:178:31:178:31 | this access | +| CSharp7.cs:178:25:178:25 | s | CSharp7.cs:178:33:178:33 | access to parameter s | +| CSharp7.cs:178:31:178:34 | call to local function g | CSharp7.cs:178:31:178:39 | ... + ... | +| CSharp7.cs:178:38:178:39 | "" | CSharp7.cs:178:31:178:39 | ... + ... | +| CSharp7.cs:179:25:179:25 | s | CSharp7.cs:179:31:179:31 | access to parameter s | +| CSharp7.cs:180:25:180:25 | s | CSharp7.cs:180:37:180:37 | access to parameter s | | CSharp7.cs:182:21:182:21 | this access | CSharp7.cs:183:21:183:21 | this access | | CSharp7.cs:182:23:182:25 | [post] access to local variable src | CSharp7.cs:183:23:183:25 | access to local variable src | | CSharp7.cs:182:23:182:25 | access to local variable src | CSharp7.cs:183:23:183:25 | access to local variable src | -| CSharp7.cs:189:10:189:11 | this | CSharp7.cs:198:14:198:23 | this access | -| CSharp7.cs:191:13:191:18 | SSA def(v1) | CSharp7.cs:192:26:192:27 | access to local variable v1 | -| CSharp7.cs:191:18:191:18 | 2 | CSharp7.cs:191:13:191:18 | SSA def(v1) | -| CSharp7.cs:192:22:192:27 | ref ... | CSharp7.cs:192:17:192:27 | SSA def(r1) | -| CSharp7.cs:192:26:192:27 | access to local variable v1 | CSharp7.cs:198:21:198:22 | access to local variable v1 | -| CSharp7.cs:193:13:193:31 | SSA def(array) | CSharp7.cs:195:14:195:18 | access to local variable array | -| CSharp7.cs:193:21:193:31 | array creation of type Int32[] | CSharp7.cs:193:13:193:31 | SSA def(array) | -| CSharp7.cs:194:14:194:14 | 3 | CSharp7.cs:194:9:194:14 | SSA def(r1) | -| CSharp7.cs:195:9:195:21 | SSA def(r1) | CSharp7.cs:197:26:197:27 | access to local variable r1 | -| CSharp7.cs:195:14:195:18 | access to local variable array | CSharp7.cs:195:14:195:21 | access to array element | -| CSharp7.cs:195:14:195:18 | access to local variable array | CSharp7.cs:196:26:196:30 | access to local variable array | -| CSharp7.cs:195:14:195:21 | access to array element | CSharp7.cs:195:9:195:21 | SSA def(r1) | -| CSharp7.cs:196:26:196:30 | access to local variable array | CSharp7.cs:196:26:196:33 | access to array element | -| CSharp7.cs:197:26:197:27 | access to local variable r1 | CSharp7.cs:199:33:199:34 | access to local variable r1 | -| CSharp7.cs:198:14:198:23 | [post] this access | CSharp7.cs:199:26:199:35 | this access | -| CSharp7.cs:198:14:198:23 | this access | CSharp7.cs:199:26:199:35 | this access | -| CSharp7.cs:199:26:199:35 | [post] this access | CSharp7.cs:200:9:200:18 | this access | -| CSharp7.cs:199:26:199:35 | this access | CSharp7.cs:200:9:200:18 | this access | -| CSharp7.cs:199:33:199:34 | access to local variable r1 | CSharp7.cs:200:16:200:17 | access to local variable r1 | -| CSharp7.cs:203:24:203:24 | p | CSharp7.cs:206:20:206:20 | access to parameter p | -| CSharp7.cs:205:28:205:28 | q | CSharp7.cs:205:44:205:44 | access to parameter q | -| CSharp7.cs:216:13:216:17 | false | CSharp7.cs:216:9:216:17 | SSA def(x) | -| CSharp7.cs:217:17:217:17 | 0 | CSharp7.cs:217:16:217:23 | (..., ...) | -| CSharp7.cs:217:20:217:22 | 0 | CSharp7.cs:217:16:217:23 | (..., ...) | -| CSharp7.cs:220:10:220:13 | this | CSharp7.cs:222:13:222:20 | this access | -| CSharp7.cs:222:13:222:20 | [post] this access | CSharp7.cs:223:18:223:25 | this access | -| CSharp7.cs:222:13:222:20 | this access | CSharp7.cs:223:18:223:25 | this access | -| CSharp7.cs:223:18:223:25 | [post] this access | CSharp7.cs:224:22:224:29 | this access | -| CSharp7.cs:223:18:223:25 | this access | CSharp7.cs:224:22:224:29 | this access | -| CSharp7.cs:224:22:224:29 | [post] this access | CSharp7.cs:225:22:225:33 | this access | -| CSharp7.cs:224:22:224:29 | this access | CSharp7.cs:225:22:225:33 | this access | -| CSharp7.cs:233:16:233:23 | SSA def(o) | CSharp7.cs:234:13:234:13 | access to local variable o | -| CSharp7.cs:233:20:233:23 | null | CSharp7.cs:233:16:233:23 | SSA def(o) | -| CSharp7.cs:234:13:234:13 | access to local variable o | CSharp7.cs:234:18:234:23 | SSA def(i1) | -| CSharp7.cs:234:13:234:13 | access to local variable o | CSharp7.cs:238:18:238:18 | access to local variable o | -| CSharp7.cs:234:13:234:13 | access to local variable o | CSharp7.cs:249:17:249:17 | access to local variable o | -| CSharp7.cs:234:13:234:23 | ... is ... | CSharp7.cs:234:13:234:33 | ... && ... | -| CSharp7.cs:234:18:234:23 | SSA def(i1) | CSharp7.cs:234:28:234:29 | access to local variable i1 | -| CSharp7.cs:234:28:234:29 | access to local variable i1 | CSharp7.cs:234:28:234:33 | ... > ... | -| CSharp7.cs:234:28:234:29 | access to local variable i1 | CSharp7.cs:236:38:236:39 | access to local variable i1 | -| CSharp7.cs:234:28:234:33 | ... > ... | CSharp7.cs:234:13:234:33 | ... && ... | -| CSharp7.cs:236:33:236:36 | "int " | CSharp7.cs:236:31:236:41 | $"..." | -| CSharp7.cs:236:38:236:39 | access to local variable i1 | CSharp7.cs:236:31:236:41 | $"..." | -| CSharp7.cs:238:18:238:18 | access to local variable o | CSharp7.cs:238:23:238:31 | SSA def(s1) | -| CSharp7.cs:238:18:238:18 | access to local variable o | CSharp7.cs:242:18:242:18 | access to local variable o | -| CSharp7.cs:238:18:238:18 | access to local variable o | CSharp7.cs:249:17:249:17 | access to local variable o | -| CSharp7.cs:238:23:238:31 | SSA def(s1) | CSharp7.cs:240:41:240:42 | access to local variable s1 | -| CSharp7.cs:240:33:240:39 | "string " | CSharp7.cs:240:31:240:44 | $"..." | -| CSharp7.cs:240:41:240:42 | access to local variable s1 | CSharp7.cs:240:31:240:44 | $"..." | -| CSharp7.cs:242:18:242:18 | access to local variable o | CSharp7.cs:245:18:245:18 | access to local variable o | -| CSharp7.cs:242:18:242:18 | access to local variable o | CSharp7.cs:249:17:249:17 | access to local variable o | -| CSharp7.cs:245:18:245:18 | access to local variable o | CSharp7.cs:249:17:249:17 | access to local variable o | -| CSharp7.cs:249:17:249:17 | access to local variable o | CSharp7.cs:255:27:255:27 | access to local variable o | -| CSharp7.cs:249:17:249:17 | access to local variable o | CSharp7.cs:258:18:258:23 | SSA def(i2) | -| CSharp7.cs:249:17:249:17 | access to local variable o | CSharp7.cs:261:18:261:23 | SSA def(i3) | -| CSharp7.cs:249:17:249:17 | access to local variable o | CSharp7.cs:264:18:264:26 | SSA def(s2) | -| CSharp7.cs:253:26:253:26 | 1 | CSharp7.cs:253:26:253:30 | ... < ... | -| CSharp7.cs:253:30:253:30 | 2 | CSharp7.cs:253:26:253:30 | ... < ... | -| CSharp7.cs:255:27:255:27 | access to local variable o | CSharp7.cs:255:32:255:40 | SSA def(s4) | -| CSharp7.cs:255:32:255:40 | SSA def(s4) | CSharp7.cs:256:40:256:41 | access to local variable s4 | -| CSharp7.cs:256:37:256:38 | "x " | CSharp7.cs:256:35:256:43 | $"..." | -| CSharp7.cs:256:40:256:41 | access to local variable s4 | CSharp7.cs:256:35:256:43 | $"..." | -| CSharp7.cs:258:18:258:23 | SSA def(i2) | CSharp7.cs:258:30:258:31 | access to local variable i2 | -| CSharp7.cs:258:30:258:31 | access to local variable i2 | CSharp7.cs:258:30:258:35 | ... > ... | -| CSharp7.cs:258:30:258:31 | access to local variable i2 | CSharp7.cs:259:47:259:48 | access to local variable i2 | -| CSharp7.cs:259:37:259:45 | "positive " | CSharp7.cs:259:35:259:50 | $"..." | -| CSharp7.cs:259:47:259:48 | access to local variable i2 | CSharp7.cs:259:35:259:50 | $"..." | -| CSharp7.cs:261:18:261:23 | SSA def(i3) | CSharp7.cs:262:42:262:43 | access to local variable i3 | -| CSharp7.cs:262:37:262:40 | "int " | CSharp7.cs:262:35:262:45 | $"..." | -| CSharp7.cs:262:42:262:43 | access to local variable i3 | CSharp7.cs:262:35:262:45 | $"..." | -| CSharp7.cs:264:18:264:26 | SSA def(s2) | CSharp7.cs:265:45:265:46 | access to local variable s2 | -| CSharp7.cs:265:37:265:43 | "string " | CSharp7.cs:265:35:265:48 | $"..." | -| CSharp7.cs:265:45:265:46 | access to local variable s2 | CSharp7.cs:265:35:265:48 | $"..." | -| CSharp7.cs:283:13:283:48 | SSA def(dict) | CSharp7.cs:284:20:284:23 | access to local variable dict | -| CSharp7.cs:283:20:283:48 | object creation of type Dictionary | CSharp7.cs:283:13:283:48 | SSA def(dict) | -| CSharp7.cs:284:13:284:62 | SSA def(list) | CSharp7.cs:286:39:286:42 | access to local variable list | -| CSharp7.cs:284:20:284:23 | access to local variable dict | CSharp7.cs:284:20:284:62 | [library code] call to method Select | -| CSharp7.cs:284:20:284:62 | [library code] call to method Select | CSharp7.cs:284:20:284:62 | call to method Select | -| CSharp7.cs:284:20:284:62 | [library code] call to method Select | CSharp7.cs:284:32:284:61 | [implicit argument 0] (...) => ... | -| CSharp7.cs:284:20:284:62 | call to method Select | CSharp7.cs:284:13:284:62 | SSA def(list) | -| CSharp7.cs:284:32:284:35 | item | CSharp7.cs:284:41:284:44 | access to parameter item | -| CSharp7.cs:284:32:284:61 | [output] (...) => ... | CSharp7.cs:284:20:284:62 | [library code] call to method Select | -| CSharp7.cs:284:41:284:44 | access to parameter item | CSharp7.cs:284:51:284:54 | access to parameter item | -| CSharp7.cs:284:41:284:48 | access to property Key | CSharp7.cs:284:40:284:61 | (..., ...) | -| CSharp7.cs:284:51:284:54 | access to parameter item | CSharp7.cs:284:51:284:60 | [library code] access to property Value | -| CSharp7.cs:284:51:284:60 | [library code] access to property Value | CSharp7.cs:284:51:284:60 | access to property Value | -| CSharp7.cs:284:51:284:60 | access to property Value | CSharp7.cs:284:40:284:61 | (..., ...) | -| CSharp7.cs:286:39:286:42 | access to local variable list | CSharp7.cs:288:36:288:39 | access to local variable list | -| CSharp7.cs:288:36:288:39 | access to local variable list | CSharp7.cs:290:32:290:35 | access to local variable list | -| CSharp7.cs:298:17:298:19 | SSA def(x) | CSharp7.cs:298:22:298:39 | SSA phi(x) | -| CSharp7.cs:298:19:298:19 | 0 | CSharp7.cs:298:17:298:19 | SSA def(x) | -| CSharp7.cs:298:22:298:22 | access to local variable x | CSharp7.cs:298:22:298:25 | ... < ... | -| CSharp7.cs:298:22:298:22 | access to local variable x | CSharp7.cs:298:30:298:30 | access to local variable x | -| CSharp7.cs:298:22:298:25 | ... < ... | CSharp7.cs:298:22:298:39 | ... && ... | -| CSharp7.cs:298:22:298:39 | SSA phi(x) | CSharp7.cs:298:22:298:22 | access to local variable x | -| CSharp7.cs:298:30:298:30 | access to local variable x | CSharp7.cs:298:35:298:39 | SSA def(y) | -| CSharp7.cs:298:30:298:30 | access to local variable x | CSharp7.cs:298:44:298:44 | access to local variable x | -| CSharp7.cs:298:30:298:39 | ... is ... | CSharp7.cs:298:22:298:39 | ... && ... | -| CSharp7.cs:298:35:298:39 | SSA def(y) | CSharp7.cs:300:31:300:31 | access to local variable y | -| CSharp7.cs:298:42:298:44 | SSA def(x) | CSharp7.cs:298:22:298:39 | SSA phi(x) | +| CSharp7.cs:183:21:183:21 | this access | CSharp7.cs:184:21:184:21 | this access | +| CSharp7.cs:183:23:183:25 | [post] access to local variable src | CSharp7.cs:184:23:184:25 | access to local variable src | +| CSharp7.cs:183:23:183:25 | access to local variable src | CSharp7.cs:184:23:184:25 | access to local variable src | +| CSharp7.cs:190:10:190:11 | this | CSharp7.cs:199:14:199:23 | this access | +| CSharp7.cs:192:13:192:18 | SSA def(v1) | CSharp7.cs:193:26:193:27 | access to local variable v1 | +| CSharp7.cs:192:18:192:18 | 2 | CSharp7.cs:192:13:192:18 | SSA def(v1) | +| CSharp7.cs:193:22:193:27 | ref ... | CSharp7.cs:193:17:193:27 | SSA def(r1) | +| CSharp7.cs:193:26:193:27 | access to local variable v1 | CSharp7.cs:199:21:199:22 | access to local variable v1 | +| CSharp7.cs:194:13:194:31 | SSA def(array) | CSharp7.cs:196:14:196:18 | access to local variable array | +| CSharp7.cs:194:21:194:31 | array creation of type Int32[] | CSharp7.cs:194:13:194:31 | SSA def(array) | +| CSharp7.cs:195:14:195:14 | 3 | CSharp7.cs:195:9:195:14 | SSA def(r1) | +| CSharp7.cs:196:9:196:21 | SSA def(r1) | CSharp7.cs:198:26:198:27 | access to local variable r1 | +| CSharp7.cs:196:14:196:18 | access to local variable array | CSharp7.cs:196:14:196:21 | access to array element | +| CSharp7.cs:196:14:196:18 | access to local variable array | CSharp7.cs:197:26:197:30 | access to local variable array | +| CSharp7.cs:196:14:196:21 | access to array element | CSharp7.cs:196:9:196:21 | SSA def(r1) | +| CSharp7.cs:197:26:197:30 | access to local variable array | CSharp7.cs:197:26:197:33 | access to array element | +| CSharp7.cs:198:26:198:27 | access to local variable r1 | CSharp7.cs:200:33:200:34 | access to local variable r1 | +| CSharp7.cs:199:14:199:23 | [post] this access | CSharp7.cs:200:26:200:35 | this access | +| CSharp7.cs:199:14:199:23 | this access | CSharp7.cs:200:26:200:35 | this access | +| CSharp7.cs:200:26:200:35 | [post] this access | CSharp7.cs:201:9:201:18 | this access | +| CSharp7.cs:200:26:200:35 | this access | CSharp7.cs:201:9:201:18 | this access | +| CSharp7.cs:200:33:200:34 | access to local variable r1 | CSharp7.cs:201:16:201:17 | access to local variable r1 | +| CSharp7.cs:204:24:204:24 | p | CSharp7.cs:207:20:207:20 | access to parameter p | +| CSharp7.cs:206:28:206:28 | q | CSharp7.cs:206:44:206:44 | access to parameter q | +| CSharp7.cs:217:13:217:17 | false | CSharp7.cs:217:9:217:17 | SSA def(x) | +| CSharp7.cs:218:17:218:17 | 0 | CSharp7.cs:218:16:218:23 | (..., ...) | +| CSharp7.cs:218:20:218:22 | 0 | CSharp7.cs:218:16:218:23 | (..., ...) | +| CSharp7.cs:221:10:221:13 | this | CSharp7.cs:223:13:223:20 | this access | +| CSharp7.cs:223:13:223:20 | [post] this access | CSharp7.cs:224:18:224:25 | this access | +| CSharp7.cs:223:13:223:20 | this access | CSharp7.cs:224:18:224:25 | this access | +| CSharp7.cs:224:18:224:25 | [post] this access | CSharp7.cs:225:22:225:29 | this access | +| CSharp7.cs:224:18:224:25 | this access | CSharp7.cs:225:22:225:29 | this access | +| CSharp7.cs:225:22:225:29 | [post] this access | CSharp7.cs:226:22:226:33 | this access | +| CSharp7.cs:225:22:225:29 | this access | CSharp7.cs:226:22:226:33 | this access | +| CSharp7.cs:234:16:234:23 | SSA def(o) | CSharp7.cs:235:13:235:13 | access to local variable o | +| CSharp7.cs:234:20:234:23 | null | CSharp7.cs:234:16:234:23 | SSA def(o) | +| CSharp7.cs:235:13:235:13 | access to local variable o | CSharp7.cs:235:18:235:23 | SSA def(i1) | +| CSharp7.cs:235:13:235:13 | access to local variable o | CSharp7.cs:239:18:239:18 | access to local variable o | +| CSharp7.cs:235:13:235:13 | access to local variable o | CSharp7.cs:250:17:250:17 | access to local variable o | +| CSharp7.cs:235:13:235:23 | ... is ... | CSharp7.cs:235:13:235:33 | ... && ... | +| CSharp7.cs:235:18:235:23 | SSA def(i1) | CSharp7.cs:235:28:235:29 | access to local variable i1 | +| CSharp7.cs:235:28:235:29 | access to local variable i1 | CSharp7.cs:235:28:235:33 | ... > ... | +| CSharp7.cs:235:28:235:29 | access to local variable i1 | CSharp7.cs:237:38:237:39 | access to local variable i1 | +| CSharp7.cs:235:28:235:33 | ... > ... | CSharp7.cs:235:13:235:33 | ... && ... | +| CSharp7.cs:237:33:237:36 | "int " | CSharp7.cs:237:31:237:41 | $"..." | +| CSharp7.cs:237:38:237:39 | access to local variable i1 | CSharp7.cs:237:31:237:41 | $"..." | +| CSharp7.cs:239:18:239:18 | access to local variable o | CSharp7.cs:239:23:239:31 | SSA def(s1) | +| CSharp7.cs:239:18:239:18 | access to local variable o | CSharp7.cs:243:18:243:18 | access to local variable o | +| CSharp7.cs:239:18:239:18 | access to local variable o | CSharp7.cs:250:17:250:17 | access to local variable o | +| CSharp7.cs:239:23:239:31 | SSA def(s1) | CSharp7.cs:241:41:241:42 | access to local variable s1 | +| CSharp7.cs:241:33:241:39 | "string " | CSharp7.cs:241:31:241:44 | $"..." | +| CSharp7.cs:241:41:241:42 | access to local variable s1 | CSharp7.cs:241:31:241:44 | $"..." | +| CSharp7.cs:243:18:243:18 | access to local variable o | CSharp7.cs:246:18:246:18 | access to local variable o | +| CSharp7.cs:243:18:243:18 | access to local variable o | CSharp7.cs:250:17:250:17 | access to local variable o | +| CSharp7.cs:246:18:246:18 | access to local variable o | CSharp7.cs:250:17:250:17 | access to local variable o | +| CSharp7.cs:250:17:250:17 | access to local variable o | CSharp7.cs:256:27:256:27 | access to local variable o | +| CSharp7.cs:250:17:250:17 | access to local variable o | CSharp7.cs:259:18:259:23 | SSA def(i2) | +| CSharp7.cs:250:17:250:17 | access to local variable o | CSharp7.cs:262:18:262:23 | SSA def(i3) | +| CSharp7.cs:250:17:250:17 | access to local variable o | CSharp7.cs:265:18:265:26 | SSA def(s2) | +| CSharp7.cs:254:26:254:26 | 1 | CSharp7.cs:254:26:254:30 | ... < ... | +| CSharp7.cs:254:30:254:30 | 2 | CSharp7.cs:254:26:254:30 | ... < ... | +| CSharp7.cs:256:27:256:27 | access to local variable o | CSharp7.cs:256:32:256:40 | SSA def(s4) | +| CSharp7.cs:256:32:256:40 | SSA def(s4) | CSharp7.cs:257:40:257:41 | access to local variable s4 | +| CSharp7.cs:257:37:257:38 | "x " | CSharp7.cs:257:35:257:43 | $"..." | +| CSharp7.cs:257:40:257:41 | access to local variable s4 | CSharp7.cs:257:35:257:43 | $"..." | +| CSharp7.cs:259:18:259:23 | SSA def(i2) | CSharp7.cs:259:30:259:31 | access to local variable i2 | +| CSharp7.cs:259:30:259:31 | access to local variable i2 | CSharp7.cs:259:30:259:35 | ... > ... | +| CSharp7.cs:259:30:259:31 | access to local variable i2 | CSharp7.cs:260:47:260:48 | access to local variable i2 | +| CSharp7.cs:260:37:260:45 | "positive " | CSharp7.cs:260:35:260:50 | $"..." | +| CSharp7.cs:260:47:260:48 | access to local variable i2 | CSharp7.cs:260:35:260:50 | $"..." | +| CSharp7.cs:262:18:262:23 | SSA def(i3) | CSharp7.cs:263:42:263:43 | access to local variable i3 | +| CSharp7.cs:263:37:263:40 | "int " | CSharp7.cs:263:35:263:45 | $"..." | +| CSharp7.cs:263:42:263:43 | access to local variable i3 | CSharp7.cs:263:35:263:45 | $"..." | +| CSharp7.cs:265:18:265:26 | SSA def(s2) | CSharp7.cs:266:45:266:46 | access to local variable s2 | +| CSharp7.cs:266:37:266:43 | "string " | CSharp7.cs:266:35:266:48 | $"..." | +| CSharp7.cs:266:45:266:46 | access to local variable s2 | CSharp7.cs:266:35:266:48 | $"..." | +| CSharp7.cs:284:13:284:48 | SSA def(dict) | CSharp7.cs:285:20:285:23 | access to local variable dict | +| CSharp7.cs:284:20:284:48 | object creation of type Dictionary | CSharp7.cs:284:13:284:48 | SSA def(dict) | +| CSharp7.cs:285:13:285:62 | SSA def(list) | CSharp7.cs:287:39:287:42 | access to local variable list | +| CSharp7.cs:285:20:285:62 | call to method Select | CSharp7.cs:285:13:285:62 | SSA def(list) | +| CSharp7.cs:285:32:285:35 | item | CSharp7.cs:285:41:285:44 | access to parameter item | +| CSharp7.cs:285:41:285:44 | access to parameter item | CSharp7.cs:285:51:285:54 | access to parameter item | +| CSharp7.cs:285:41:285:48 | access to property Key | CSharp7.cs:285:40:285:61 | (..., ...) | +| CSharp7.cs:285:51:285:60 | access to property Value | CSharp7.cs:285:40:285:61 | (..., ...) | +| CSharp7.cs:287:39:287:42 | access to local variable list | CSharp7.cs:289:36:289:39 | access to local variable list | +| CSharp7.cs:289:36:289:39 | access to local variable list | CSharp7.cs:291:32:291:35 | access to local variable list | +| CSharp7.cs:299:18:299:22 | SSA def(x) | CSharp7.cs:299:25:299:44 | SSA phi(x) | +| CSharp7.cs:299:22:299:22 | 0 | CSharp7.cs:299:18:299:22 | SSA def(x) | +| CSharp7.cs:299:25:299:25 | access to local variable x | CSharp7.cs:299:25:299:30 | ... < ... | +| CSharp7.cs:299:25:299:25 | access to local variable x | CSharp7.cs:299:35:299:35 | access to local variable x | +| CSharp7.cs:299:25:299:30 | ... < ... | CSharp7.cs:299:25:299:44 | ... && ... | +| CSharp7.cs:299:25:299:44 | SSA phi(x) | CSharp7.cs:299:25:299:25 | access to local variable x | +| CSharp7.cs:299:35:299:35 | access to local variable x | CSharp7.cs:299:40:299:44 | SSA def(y) | +| CSharp7.cs:299:35:299:35 | access to local variable x | CSharp7.cs:299:49:299:49 | access to local variable x | +| CSharp7.cs:299:35:299:44 | ... is ... | CSharp7.cs:299:25:299:44 | ... && ... | +| CSharp7.cs:299:40:299:44 | SSA def(y) | CSharp7.cs:301:31:301:31 | access to local variable y | +| CSharp7.cs:299:47:299:49 | SSA def(x) | CSharp7.cs:299:25:299:44 | SSA phi(x) | diff --git a/csharp/ql/test/library-tests/csharp7/LocalVariables.expected b/csharp/ql/test/library-tests/csharp7/LocalVariables.expected index 06f61a52f91e..7e0793d3b434 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalVariables.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalVariables.expected @@ -36,35 +36,35 @@ | CSharp7.cs:135:19:135:20 | f4 | Func | | CSharp7.cs:139:24:139:25 | f5 | Func | | CSharp7.cs:151:16:151:16 | a | Action | -| CSharp7.cs:176:16:176:18 | src | string | -| CSharp7.cs:181:13:181:17 | sink1 | string | -| CSharp7.cs:182:13:182:17 | sink2 | string | -| CSharp7.cs:183:13:183:17 | sink3 | string | -| CSharp7.cs:191:13:191:14 | v1 | int | -| CSharp7.cs:192:17:192:18 | r1 | int | -| CSharp7.cs:193:13:193:17 | array | Int32[] | -| CSharp7.cs:196:17:196:18 | r2 | int | -| CSharp7.cs:197:17:197:18 | r3 | int | -| CSharp7.cs:199:17:199:18 | r4 | int | -| CSharp7.cs:224:14:224:14 | x | int | -| CSharp7.cs:225:17:225:17 | y | double | -| CSharp7.cs:225:32:225:32 | z | bool | -| CSharp7.cs:233:16:233:16 | o | object | -| CSharp7.cs:234:22:234:23 | i1 | int | -| CSharp7.cs:238:30:238:31 | s1 | string | -| CSharp7.cs:245:27:245:28 | v1 | object | -| CSharp7.cs:255:39:255:40 | s4 | string | -| CSharp7.cs:258:22:258:23 | i2 | int | -| CSharp7.cs:261:22:261:23 | i3 | int | -| CSharp7.cs:264:25:264:26 | s2 | string | -| CSharp7.cs:270:22:270:23 | v2 | object | -| CSharp7.cs:283:13:283:16 | dict | Dictionary | -| CSharp7.cs:284:13:284:16 | list | IEnumerable<(Int32,String)> | -| CSharp7.cs:286:23:286:23 | a | int | -| CSharp7.cs:286:33:286:33 | b | string | -| CSharp7.cs:288:23:288:23 | a | int | -| CSharp7.cs:288:30:288:30 | b | string | -| CSharp7.cs:290:23:290:23 | a | int | -| CSharp7.cs:290:26:290:26 | b | string | -| CSharp7.cs:298:17:298:17 | x | int | -| CSharp7.cs:298:39:298:39 | y | int | +| CSharp7.cs:177:16:177:18 | src | string | +| CSharp7.cs:182:13:182:17 | sink1 | string | +| CSharp7.cs:183:13:183:17 | sink2 | string | +| CSharp7.cs:184:13:184:17 | sink3 | string | +| CSharp7.cs:192:13:192:14 | v1 | int | +| CSharp7.cs:193:17:193:18 | r1 | int | +| CSharp7.cs:194:13:194:17 | array | Int32[] | +| CSharp7.cs:197:17:197:18 | r2 | int | +| CSharp7.cs:198:17:198:18 | r3 | int | +| CSharp7.cs:200:17:200:18 | r4 | int | +| CSharp7.cs:225:14:225:14 | x | int | +| CSharp7.cs:226:17:226:17 | y | double | +| CSharp7.cs:226:32:226:32 | z | bool | +| CSharp7.cs:234:16:234:16 | o | object | +| CSharp7.cs:235:22:235:23 | i1 | int | +| CSharp7.cs:239:30:239:31 | s1 | string | +| CSharp7.cs:246:27:246:28 | v1 | object | +| CSharp7.cs:256:39:256:40 | s4 | string | +| CSharp7.cs:259:22:259:23 | i2 | int | +| CSharp7.cs:262:22:262:23 | i3 | int | +| CSharp7.cs:265:25:265:26 | s2 | string | +| CSharp7.cs:271:22:271:23 | v2 | object | +| CSharp7.cs:284:13:284:16 | dict | Dictionary | +| CSharp7.cs:285:13:285:16 | list | IEnumerable<(Int32,String)> | +| CSharp7.cs:287:23:287:23 | a | int | +| CSharp7.cs:287:33:287:33 | b | string | +| CSharp7.cs:289:23:289:23 | a | int | +| CSharp7.cs:289:30:289:30 | b | string | +| CSharp7.cs:291:23:291:23 | a | int | +| CSharp7.cs:291:26:291:26 | b | string | +| CSharp7.cs:299:18:299:18 | x | int | +| CSharp7.cs:299:44:299:44 | y | int | diff --git a/csharp/ql/test/library-tests/csharp7/PrintAst.expected b/csharp/ql/test/library-tests/csharp7/PrintAst.expected new file mode 100644 index 000000000000..a3d0e25e815e --- /dev/null +++ b/csharp/ql/test/library-tests/csharp7/PrintAst.expected @@ -0,0 +1,793 @@ +CSharp7.cs: +# 7| [Class] Literals +# 9| 5: [Field] x +# 9| 1: [AssignExpr] ... = ... +# 9| 0: [IntLiteral] 11 +# 9| 1: [FieldAccess] access to field x +# 10| 6: [Field] y +# 10| 1: [AssignExpr] ... = ... +# 10| 0: [IntLiteral] 123456 +# 10| 1: [FieldAccess] access to field y +# 11| 7: [Field] z +# 11| 1: [AssignExpr] ... = ... +# 11| 0: [IntLiteral] 128 +# 11| 1: [FieldAccess] access to field z +# 14| [Class] ExpressionBodiedMembers +# 16| 4: [Field] field +# 16| 1: [AssignExpr] ... = ... +# 16| 0: [IntLiteral] 0 +# 16| 1: [FieldAccess] access to field field +# 17| 5: [Method] Foo +# 17| 4: [FieldAccess] access to field field +# 18| 6: [Property] P +# 18| 3: [Getter] get_P +# 18| 4: [IntLiteral] 5 +# 19| 7: [Property] Q +# 21| 3: [Getter] get_Q +# 21| 4: [MethodCall] call to method Foo +# 22| 4: [Setter] set_Q +#-----| 2: (Parameters) +# 22| 0: [Parameter] value +# 22| 4: [AssignExpr] ... = ... +# 22| 0: [ParameterAccess] access to parameter value +# 22| 1: [FieldAccess] access to field field +# 24| 8: [InstanceConstructor] ExpressionBodiedMembers +# 24| 3: [ConstructorInitializer] call to constructor ExpressionBodiedMembers +# 24| 0: [IntLiteral] 1 +# 24| 4: [BlockStmt] {...} +# 25| 9: [InstanceConstructor] ExpressionBodiedMembers +#-----| 2: (Parameters) +# 25| 0: [Parameter] x +# 25| 4: [MethodCall] call to method Foo +# 26| 10: [Destructor] ~ExpressionBodiedMembers +# 26| 4: [MethodCall] call to method Foo +# 29| [Class] ThrowExpr +# 31| 5: [Method] Throw +#-----| 2: (Parameters) +# 31| 0: [Parameter] i +# 32| 4: [BlockStmt] {...} +# 33| 0: [ReturnStmt] return ...; +# 33| 0: [ConditionalExpr] ... ? ... : ... +# 33| 0: [GTExpr] ... > ... +# 33| 0: [ParameterAccess] access to parameter i +# 33| 1: [IntLiteral] 0 +# 33| 1: [ParameterAccess] access to parameter i +# 33| 2: [ThrowExpr] throw ... +# 33| 0: [ObjectCreation] object creation of type ArgumentException +# 33| 0: [StringLiteral] "i" +# 37| [Class] OutVariables +# 39| 5: [Method] F +#-----| 2: (Parameters) +# 39| 0: [Parameter] x +# 40| 4: [BlockStmt] {...} +# 41| 0: [ExprStmt] ...; +# 41| 0: [AssignExpr] ... = ... +# 41| 0: [StringLiteral] "tainted" +# 41| 1: [ParameterAccess] access to parameter x +# 44| 6: [Method] G +#-----| 2: (Parameters) +# 44| 0: [Parameter] x +# 44| 1: [Parameter] y +# 45| 4: [BlockStmt] {...} +# 46| 0: [ExprStmt] ...; +# 46| 0: [AssignExpr] ... = ... +# 46| 0: [ParameterAccess] access to parameter x +# 46| 1: [ParameterAccess] access to parameter y +# 49| 7: [Method] G +# 50| 4: [BlockStmt] {...} +# 51| 0: [ExprStmt] ...; +# 51| 0: [MethodCall] call to method F +# 51| 0: [LocalVariableAccess,LocalVariableDeclExpr] String t1 +# 52| 1: [ExprStmt] ...; +# 52| 0: [MethodCall] call to method F +# 52| 0: [LocalVariableAccess,LocalVariableDeclExpr] String t2 +# 53| 2: [LocalVariableDeclStmt] ... ...; +# 53| 0: [LocalVariableDeclAndInitExpr] String t3 = ... +# 53| 0: [LocalVariableAccess] access to local variable t1 +# 53| 1: [LocalVariableAccess] access to local variable t3 +# 54| 3: [ExprStmt] ...; +# 54| 0: [MethodCall] call to method F +# 54| 0: [LocalVariableAccess] access to local variable t1 +# 55| 4: [ExprStmt] ...; +# 55| 0: [AssignExpr] ... = ... +# 55| 0: [LocalVariableAccess] access to local variable t1 +# 55| 1: [LocalVariableAccess] access to local variable t3 +# 56| 5: [ExprStmt] ...; +# 56| 0: [AssignExpr] ... = ... +# 56| 0: [LocalVariableAccess] access to local variable t2 +# 56| 1: [LocalVariableAccess] access to local variable t3 +# 57| 6: [ExprStmt] ...; +# 57| 0: [MethodCall] call to method G +# 57| 0: [StringLiteral] "tainted" +# 57| 1: [LocalVariableAccess,LocalVariableDeclExpr] String t4 +# 58| 7: [LocalVariableDeclStmt] ... ...; +# 58| 0: [LocalVariableDeclAndInitExpr] String t5 = ... +# 58| 0: [LocalVariableAccess] access to local variable t4 +# 58| 1: [LocalVariableAccess] access to local variable t5 +# 62| [Class] Tuples +# 64| 5: [Method] F +# 65| 4: [BlockStmt] {...} +# 66| 0: [ReturnStmt] return ...; +# 66| 0: [TupleExpr] (..., ...) +# 66| 0: [IntLiteral] 1 +# 66| 1: [IntLiteral] 2 +# 69| 6: [Method] Expressions +# 70| 4: [BlockStmt] {...} +# 71| 0: [ExprStmt] ...; +# 71| 0: [AssignExpr] ... = ... +# 71| 0: [MethodCall] call to method F +# 71| 1: [TupleExpr] (..., ...) +# 71| 0: [LocalVariableDeclExpr] Int32 x +# 71| 1: [LocalVariableDeclExpr] Int32 y +# 72| 1: [LocalVariableDeclStmt] ... ...; +# 72| 0: [LocalVariableDeclAndInitExpr] (Int32,Int32) z = ... +# 72| 0: [MethodCall] call to method F +# 72| 1: [LocalVariableAccess] access to local variable z +# 73| 2: [ExprStmt] ...; +# 73| 0: [AssignExpr] ... = ... +# 73| 0: [MethodCall] call to method F +# 73| 1: [TupleExpr] (..., ...) +# 73| 0: [LocalVariableAccess] access to local variable x +# 73| 1: [LocalVariableAccess] access to local variable y +# 74| 3: [ExprStmt] ...; +# 74| 0: [AssignExpr] ... = ... +# 74| 0: [FieldAccess] access to field A +# 74| -1: [MethodCall] call to method F +# 74| 1: [LocalVariableAccess] access to local variable x +# 75| 4: [ExprStmt] ...; +# 75| 0: [AssignExpr] ... = ... +# 75| 0: [TupleExpr] (..., ...) +# 75| 0: [IntLiteral] 1 +# 75| 1: [IntLiteral] 2 +# 75| 2: [IntLiteral] 3 +# 75| 1: [TupleExpr] (..., ...) +# 75| 0: [LocalVariableAccess] access to local variable x +# 75| 1: [LocalVariableAccess] access to local variable y +# 75| 2: [FieldAccess] access to field Item1 +# 75| -1: [LocalVariableAccess] access to local variable z +# 76| 5: [ExprStmt] ...; +# 76| 0: [AssignExpr] ... = ... +# 76| 0: [AssignExpr] ... = ... +# 76| 0: [TupleExpr] (..., ...) +# 76| 0: [IntLiteral] 1 +# 76| 1: [IntLiteral] 2 +# 76| 1: [TupleExpr] (..., ...) +# 76| 0: [LocalVariableAccess] access to local variable x +# 76| 1: [LocalVariableAccess] access to local variable y +# 76| 1: [TupleExpr] (..., ...) +# 76| 0: [LocalVariableAccess] access to local variable x +# 76| 1: [LocalVariableAccess] access to local variable y +# 77| 6: [ExprStmt] ...; +# 77| 0: [AssignExpr] ... = ... +# 77| 0: [TupleExpr] (..., ...) +# 77| 0: [IntLiteral] 1 +# 77| 1: [LocalVariableAccess] access to local variable z +# 77| 1: [TupleExpr] (..., ...) +# 77| 0: [LocalVariableDeclExpr] Int32 a +# 77| 1: [TupleExpr] (..., ...) +# 77| 0: [LocalVariableDeclExpr] Int32 b +# 77| 1: [LocalVariableDeclExpr] Int32 c +# 78| 7: [ExprStmt] ...; +# 78| 0: [AssignExpr] ... = ... +# 78| 0: [TupleExpr] (..., ...) +# 78| 0: [LocalVariableAccess] access to local variable b +# 78| 1: [TupleExpr] (..., ...) +# 78| 0: [LocalVariableAccess] access to local variable c +# 78| 1: [LocalVariableAccess] access to local variable a +# 78| 1: [TupleExpr] (..., ...) +# 78| 0: [LocalVariableAccess] access to local variable a +# 78| 1: [TupleExpr] (..., ...) +# 78| 0: [LocalVariableAccess] access to local variable b +# 78| 1: [LocalVariableAccess] access to local variable c +# 79| 8: [ExprStmt] ...; +# 79| 0: [AssignExpr] ... = ... +# 79| 0: [TupleExpr] (..., ...) +# 79| 0: [StringLiteral] "" +# 79| 1: [LocalVariableAccess] access to local variable x +# 79| 1: [TupleExpr] (..., ...) +# 79| 0: [LocalVariableDeclExpr] String i +# 79| 1: [LocalVariableDeclExpr] Int32 j +# 82| 7: [Method] I +#-----| 2: (Parameters) +# 82| 0: [Parameter] x +# 83| 4: [BlockStmt] {...} +# 84| 0: [ReturnStmt] return ...; +# 84| 0: [FieldAccess] access to field a +# 84| -1: [TupleExpr] (..., ...) +# 84| 0: [ParameterAccess] access to parameter x +# 84| 1: [IntLiteral] 2 +# 87| 8: [Method] TaintFlow +# 88| 4: [BlockStmt] {...} +# 89| 0: [LocalVariableDeclStmt] ... ...; +# 89| 0: [LocalVariableDeclAndInitExpr] (String,String) t1 = ... +# 89| 0: [TupleExpr] (..., ...) +# 89| 0: [StringLiteral] "tainted" +# 89| 1: [StringLiteral] "X2" +# 89| 1: [LocalVariableAccess] access to local variable t1 +# 90| 1: [ExprStmt] ...; +# 90| 0: [AssignExpr] ... = ... +# 90| 0: [LocalVariableAccess] access to local variable t1 +# 90| 1: [TupleExpr] (..., ...) +# 90| 0: [LocalVariableDeclExpr] String t2 +# 90| 1: [LocalVariableDeclExpr] String t3 +# 91| 2: [LocalVariableDeclStmt] ... ...; +# 91| 0: [LocalVariableDeclAndInitExpr] String t4 = ... +# 91| 0: [LocalVariableAccess] access to local variable t3 +# 91| 1: [LocalVariableAccess] access to local variable t4 +# 92| 3: [LocalVariableDeclStmt] ... ...; +# 92| 0: [LocalVariableDeclAndInitExpr] String t5 = ... +# 92| 0: [MethodCall] call to method I +# 92| 0: [FieldAccess] access to field Item1 +# 92| -1: [LocalVariableAccess] access to local variable t1 +# 92| 1: [LocalVariableAccess] access to local variable t5 +# 95| 9: [Method] TupleExprNode +# 96| 4: [BlockStmt] {...} +# 97| 0: [LocalVariableDeclStmt] ... ...; +# 97| 0: [LocalVariableDeclAndInitExpr] (Int32,String) m1 = ... +# 97| 0: [TupleExpr] (..., ...) +# 97| 0: [IntLiteral] 1 +# 97| 1: [StringLiteral] "TupleExprNode1" +# 97| 1: [LocalVariableAccess] access to local variable m1 +# 98| 1: [LocalVariableDeclStmt] ... ...; +# 98| 0: [LocalVariableDeclAndInitExpr] (Int32,(String,Int32)) m2 = ... +# 98| 0: [TupleExpr] (..., ...) +# 98| 0: [IntLiteral] 1 +# 98| 1: [TupleExpr] (..., ...) +# 98| 0: [StringLiteral] "TupleExprNode2" +# 98| 1: [IntLiteral] 2 +# 98| 1: [LocalVariableAccess] access to local variable m2 +# 101| 10: [Method] TupleMemberAccess +# 102| 4: [BlockStmt] {...} +# 103| 0: [LocalVariableDeclStmt] ... ...; +# 103| 0: [LocalVariableDeclAndInitExpr] String m1 = ... +# 103| 0: [FieldAccess] access to field Item1 +# 103| -1: [TupleExpr] (..., ...) +# 103| 0: [StringLiteral] "TupleMemberAccess1" +# 103| 1: [IntLiteral] 0 +# 103| 1: [LocalVariableAccess] access to local variable m1 +# 104| 1: [LocalVariableDeclStmt] ... ...; +# 104| 0: [LocalVariableDeclAndInitExpr] (String,Int32) m2 = ... +# 104| 0: [FieldAccess] access to field Item2 +# 104| -1: [TupleExpr] (..., ...) +# 104| 0: [IntLiteral] 0 +# 104| 1: [TupleExpr] (..., ...) +# 104| 0: [StringLiteral] "TupleMemberAccess2" +# 104| 1: [IntLiteral] 1 +# 104| 1: [LocalVariableAccess] access to local variable m2 +# 107| 11: [Method] DefUse +# 108| 4: [BlockStmt] {...} +# 109| 0: [ExprStmt] ...; +# 109| 0: [AssignExpr] ... = ... +# 109| 0: [TupleExpr] (..., ...) +# 109| 0: [StringLiteral] "DefUse1" +# 109| 1: [TupleExpr] (..., ...) +# 109| 0: [IntLiteral] 0 +# 109| 1: [IntLiteral] 1 +# 109| 1: [TupleExpr] (..., ...) +# 109| 0: [LocalVariableDeclExpr] String m1 +# 109| 1: [LocalVariableDeclExpr] (Int32,Int32) m2 +# 110| 1: [LocalVariableDeclStmt] ... ...; +# 110| 0: [LocalVariableDeclExpr] String m3 +# 111| 2: [LocalVariableDeclStmt] ... ...; +# 111| 0: [LocalVariableDeclExpr] Int32 m4 +# 111| 1: [LocalVariableDeclExpr] Int32 m5 +# 112| 3: [ExprStmt] ...; +# 112| 0: [AssignExpr] ... = ... +# 112| 0: [TupleExpr] (..., ...) +# 112| 0: [LocalVariableAccess] access to local variable m1 +# 112| 1: [LocalVariableAccess] access to local variable m2 +# 112| 1: [TupleExpr] (..., ...) +# 112| 0: [LocalVariableAccess] access to local variable m3 +# 112| 1: [TupleExpr] (..., ...) +# 112| 0: [LocalVariableAccess] access to local variable m4 +# 112| 1: [LocalVariableAccess] access to local variable m5 +# 113| 4: [LocalVariableDeclStmt] ... ...; +# 113| 0: [LocalVariableDeclAndInitExpr] Int32 m6 = ... +# 113| 0: [LocalVariableAccess] access to local variable m4 +# 113| 1: [LocalVariableAccess] access to local variable m6 +# 114| 5: [ExprStmt] ...; +# 114| 0: [AssignExpr] ... = ... +# 114| 0: [AssignExpr] ... = ... +# 114| 0: [TupleExpr] (..., ...) +# 114| 0: [StringLiteral] "DefUse2" +# 114| 1: [TupleExpr] (..., ...) +# 114| 0: [IntLiteral] 0 +# 114| 1: [IntLiteral] 1 +# 114| 1: [TupleExpr] (..., ...) +# 114| 0: [LocalVariableAccess] access to local variable m1 +# 114| 1: [LocalVariableAccess] access to local variable m2 +# 114| 1: [TupleExpr] (..., ...) +# 114| 0: [LocalVariableDeclExpr] String m7 +# 114| 1: [TupleExpr] (..., ...) +# 114| 0: [LocalVariableDeclExpr] Int32 m8 +# 114| 1: [LocalVariableDeclExpr] Int32 m9 +# 115| 6: [LocalVariableDeclStmt] ... ...; +# 115| 0: [LocalVariableDeclAndInitExpr] Int32 m10 = ... +# 115| 0: [LocalVariableAccess] access to local variable m9 +# 115| 1: [LocalVariableAccess] access to local variable m10 +# 118| 7: [ExprStmt] ...; +# 118| 0: [AssignExpr] ... = ... +# 118| 0: [IntLiteral] 0 +# 118| 1: [FieldAccess] access to field Item2 +# 118| -1: [LocalVariableAccess] access to local variable m2 +# 119| 8: [LocalVariableDeclStmt] ... ...; +# 119| 0: [LocalVariableDeclAndInitExpr] Int32 m11 = ... +# 119| 0: [FieldAccess] access to field Item1 +# 119| -1: [LocalVariableAccess] access to local variable m2 +# 119| 1: [LocalVariableAccess] access to local variable m11 +# 122| 9: [LocalVariableDeclStmt] ... ...; +# 122| 0: [LocalVariableDeclExpr] String m12 +# 123| 10: [LocalVariableDeclStmt] ... ...; +# 123| 0: [LocalVariableDeclAndInitExpr] String m13 = ... +# 123| 0: [AssignExpr] ... = ... +# 123| 0: [StringLiteral] "DefUse3" +# 123| 1: [LocalVariableAccess] access to local variable m12 +# 123| 1: [LocalVariableAccess] access to local variable m13 +# 127| [Class] LocalFunctions +# 129| 5: [Method] Main +# 130| 4: [BlockStmt] {...} +# 131| 0: [LocalFunctionStmt] f1(...) +# 131| 0: [LocalFunction] f1 +#-----| 2: (Parameters) +# 131| 0: [Parameter] x +# 131| 4: [BlockStmt] {...} +# 131| 0: [ReturnStmt] return ...; +# 131| 0: [AddExpr] ... + ... +# 131| 0: [ParameterAccess] access to parameter x +# 131| 1: [IntLiteral] 1 +# 133| 1: [LocalFunctionStmt] f2(...) +# 133| 0: [LocalFunction] f2 +#-----| 1: (Type parameters) +# 133| 0: [TypeParameter] T +# 133| 1: [TypeParameter] U +#-----| 2: (Parameters) +# 133| 0: [Parameter] t +# 133| 1: [Parameter] u +# 133| 4: [BlockStmt] {...} +# 133| 0: [ReturnStmt] return ...; +# 133| 0: [ParameterAccess] access to parameter t +# 135| 2: [LocalVariableDeclStmt] ... ...; +# 135| 0: [LocalVariableDeclAndInitExpr] Func f4 = ... +# 135| 0: [ImplicitDelegateCreation] delegate creation of type Func +# 135| 0: [LocalFunctionAccess] access to local function f3 +# 135| 1: [LocalVariableAccess] access to local variable f4 +# 137| 3: [LocalFunctionStmt] f3(...) +# 137| 0: [LocalFunction] f3 +# 137| 4: [IntLiteral] 2 +# 139| 4: [LocalVariableDeclStmt] ... ...; +# 139| 0: [LocalVariableDeclAndInitExpr] Func f5 = ... +# 139| 0: [LambdaExpr] (...) => ... +#-----| 2: (Parameters) +# 139| 0: [Parameter] x +# 139| 4: [AddExpr] ... + ... +# 139| 0: [ParameterAccess] access to parameter x +# 139| 1: [IntLiteral] 1 +# 139| 1: [LocalVariableAccess] access to local variable f5 +# 141| 5: [LocalFunctionStmt] f6(...) +# 141| 0: [LocalFunction] f6 +#-----| 2: (Parameters) +# 141| 0: [Parameter] x +# 141| 4: [ConditionalExpr] ... ? ... : ... +# 141| 0: [GTExpr] ... > ... +# 141| 0: [ParameterAccess] access to parameter x +# 141| 1: [IntLiteral] 0 +# 141| 1: [AddExpr] ... + ... +# 141| 0: [IntLiteral] 1 +# 141| 1: [LocalFunctionCall] call to local function f7 +# 141| -1: [LocalFunctionAccess] access to local function f7 +# 141| 0: [SubExpr] ... - ... +# 141| 0: [ParameterAccess] access to parameter x +# 141| 1: [IntLiteral] 1 +# 141| 2: [IntLiteral] 0 +# 143| 6: [LocalFunctionStmt] f7(...) +# 143| 0: [LocalFunction] f7 +#-----| 2: (Parameters) +# 143| 0: [Parameter] x +# 143| 4: [LocalFunctionCall] call to local function f6 +# 143| -1: [LocalFunctionAccess] access to local function f6 +# 143| 0: [ParameterAccess] access to parameter x +# 145| 7: [LocalFunctionStmt] f8(...) +# 145| 0: [LocalFunction] f8 +# 146| 4: [BlockStmt] {...} +# 147| 0: [LocalFunctionStmt] f9(...) +# 147| 0: [LocalFunction] f9 +#-----| 2: (Parameters) +# 147| 0: [Parameter] x +# 147| 4: [LocalFunctionCall] call to local function f7 +# 147| -1: [LocalFunctionAccess] access to local function f7 +# 147| 0: [ParameterAccess] access to parameter x +# 148| 1: [ReturnStmt] return ...; +# 148| 0: [LocalFunctionCall] call to local function f9 +# 148| -1: [LocalFunctionAccess] access to local function f9 +# 148| 0: [IntLiteral] 1 +# 151| 8: [LocalVariableDeclStmt] ... ...; +# 151| 0: [LocalVariableDeclAndInitExpr] Action a = ... +# 151| 0: [LambdaExpr] (...) => ... +# 152| 4: [BlockStmt] {...} +# 153| 0: [LocalFunctionStmt] f9(...) +# 153| 0: [LocalFunction] f9 +# 153| 4: [IntLiteral] 0 +# 151| 1: [LocalVariableAccess] access to local variable a +# 156| 9: [ReturnStmt] return ...; +# 156| 0: [LocalFunctionCall] call to local function f1 +# 156| -1: [LocalFunctionAccess] access to local function f1 +# 156| 0: [IntLiteral] 2 +# 159| 6: [Method] Generics +# 160| 4: [BlockStmt] {...} +# 161| 0: [LocalFunctionStmt] f(...) +# 161| 0: [LocalFunction] f +#-----| 1: (Type parameters) +# 161| 0: [TypeParameter] T +# 161| 4: [IntLiteral] 1 +# 162| 1: [LocalFunctionStmt] g(...) +# 162| 0: [LocalFunction] g +#-----| 1: (Type parameters) +# 162| 0: [TypeParameter] T +#-----| 2: (Parameters) +# 162| 0: [Parameter] t +# 162| 4: [ParameterAccess] access to parameter t +# 164| 2: [LocalFunctionStmt] h(...) +# 164| 0: [LocalFunction] h +#-----| 1: (Type parameters) +# 164| 0: [TypeParameter] T +# 164| 1: [TypeParameter] U +#-----| 2: (Parameters) +# 164| 0: [Parameter] t +# 164| 1: [Parameter] u +# 165| 4: [BlockStmt] {...} +# 166| 0: [LocalFunctionStmt] f2(...) +# 166| 0: [LocalFunction] f2 +#-----| 1: (Type parameters) +# 166| 0: [TypeParameter] S +#-----| 2: (Parameters) +# 166| 0: [Parameter] s +# 166| 1: [Parameter] _t +# 166| 4: [LocalFunctionCall] call to local function f +# 166| -1: [LocalFunctionAccess] access to local function f +# 167| 1: [ExprStmt] ...; +# 167| 0: [LocalFunctionCall] call to local function f +# 167| -1: [LocalFunctionAccess] access to local function f +# 168| 2: [ReturnStmt] return ...; +# 168| 0: [LocalFunctionCall] call to local function g +# 168| -1: [LocalFunctionAccess] access to local function g +# 168| 0: [ParameterAccess] access to parameter u +# 171| 3: [ExprStmt] ...; +# 171| 0: [LocalFunctionCall] call to local function h +# 171| -1: [LocalFunctionAccess] access to local function h +# 171| 0: [IntLiteral] 0 +# 171| 1: [IntLiteral] 0 +# 172| 4: [ExprStmt] ...; +# 172| 0: [LocalFunctionCall] call to local function h +# 172| -1: [LocalFunctionAccess] access to local function h +# 172| 0: [StringLiteral] "" +# 172| 1: [BoolLiteral] true +# 175| 7: [Method] GlobalFlow +# 176| 4: [BlockStmt] {...} +# 177| 0: [LocalVariableDeclStmt] ... ...; +# 177| 0: [LocalVariableDeclAndInitExpr] String src = ... +# 177| 0: [StringLiteral] "tainted" +# 177| 1: [LocalVariableAccess] access to local variable src +# 178| 1: [LocalFunctionStmt] f(...) +# 178| 0: [LocalFunction] f +#-----| 2: (Parameters) +# 178| 0: [Parameter] s +# 178| 4: [AddExpr] ... + ... +# 178| 0: [LocalFunctionCall] call to local function g +# 178| -1: [LocalFunctionAccess] access to local function g +# 178| 0: [ParameterAccess] access to parameter s +# 178| 1: [StringLiteral] "" +# 179| 2: [LocalFunctionStmt] g(...) +# 179| 0: [LocalFunction] g +#-----| 2: (Parameters) +# 179| 0: [Parameter] s +# 179| 4: [ParameterAccess] access to parameter s +# 180| 3: [LocalFunctionStmt] h(...) +# 180| 0: [LocalFunction] h +#-----| 2: (Parameters) +# 180| 0: [Parameter] s +# 180| 4: [BlockStmt] {...} +# 180| 0: [ReturnStmt] return ...; +# 180| 0: [ParameterAccess] access to parameter s +# 182| 4: [LocalVariableDeclStmt] ... ...; +# 182| 0: [LocalVariableDeclAndInitExpr] String sink1 = ... +# 182| 0: [LocalFunctionCall] call to local function f +# 182| -1: [LocalFunctionAccess] access to local function f +# 182| 0: [LocalVariableAccess] access to local variable src +# 182| 1: [LocalVariableAccess] access to local variable sink1 +# 183| 5: [LocalVariableDeclStmt] ... ...; +# 183| 0: [LocalVariableDeclAndInitExpr] String sink2 = ... +# 183| 0: [LocalFunctionCall] call to local function g +# 183| -1: [LocalFunctionAccess] access to local function g +# 183| 0: [LocalVariableAccess] access to local variable src +# 183| 1: [LocalVariableAccess] access to local variable sink2 +# 184| 6: [LocalVariableDeclStmt] ... ...; +# 184| 0: [LocalVariableDeclAndInitExpr] String sink3 = ... +# 184| 0: [LocalFunctionCall] call to local function h +# 184| -1: [LocalFunctionAccess] access to local function h +# 184| 0: [LocalVariableAccess] access to local variable src +# 184| 1: [LocalVariableAccess] access to local variable sink3 +# 188| [Class] Refs +# 190| 5: [Method] F1 +# 191| 4: [BlockStmt] {...} +# 192| 0: [LocalVariableDeclStmt] ... ...; +# 192| 0: [LocalVariableDeclAndInitExpr] Int32 v1 = ... +# 192| 0: [IntLiteral] 2 +# 192| 1: [LocalVariableAccess] access to local variable v1 +# 193| 1: [LocalVariableDeclStmt] ... ...; +# 193| 0: [LocalVariableDeclAndInitExpr] Int32 r1 = ... +# 193| 0: [RefExpr] ref ... +# 193| 0: [LocalVariableAccess] access to local variable v1 +# 193| 1: [LocalVariableAccess] access to local variable r1 +# 194| 2: [LocalVariableDeclStmt] ... ...; +# 194| 0: [LocalVariableDeclAndInitExpr] Int32[] array = ... +# 194| 0: [ArrayCreation] array creation of type Int32[] +# 194| 0: [IntLiteral] 10 +# 194| 1: [LocalVariableAccess] access to local variable array +# 195| 3: [ExprStmt] ...; +# 195| 0: [AssignExpr] ... = ... +# 195| 0: [IntLiteral] 3 +# 195| 1: [LocalVariableAccess] access to local variable r1 +# 196| 4: [ExprStmt] ...; +# 196| 0: [AssignExpr] ... = ... +# 196| 0: [ArrayAccess] access to array element +# 196| -1: [LocalVariableAccess] access to local variable array +# 196| 0: [IntLiteral] 1 +# 196| 1: [LocalVariableAccess] access to local variable r1 +# 197| 5: [LocalVariableDeclStmt] ... ...; +# 197| 0: [LocalVariableDeclAndInitExpr] Int32 r2 = ... +# 197| 0: [RefExpr] ref ... +# 197| 0: [ArrayAccess] access to array element +# 197| -1: [LocalVariableAccess] access to local variable array +# 197| 0: [IntLiteral] 3 +# 197| 1: [LocalVariableAccess] access to local variable r2 +# 198| 6: [LocalVariableDeclStmt] ... ...; +# 198| 0: [LocalVariableDeclAndInitExpr] Int32 r3 = ... +# 198| 0: [RefExpr] ref ... +# 198| 0: [LocalVariableAccess] access to local variable r1 +# 198| 1: [LocalVariableAccess] access to local variable r3 +# 199| 7: [ExprStmt] ...; +# 199| 0: [AssignExpr] ... = ... +# 199| 0: [MethodCall] call to method F2 +# 199| 0: [LocalVariableAccess] access to local variable v1 +# 199| 1: [LocalVariableAccess] access to local variable v1 +# 200| 8: [LocalVariableDeclStmt] ... ...; +# 200| 0: [LocalVariableDeclAndInitExpr] Int32 r4 = ... +# 200| 0: [RefExpr] ref ... +# 200| 0: [MethodCall] call to method F2 +# 200| 0: [LocalVariableAccess] access to local variable r1 +# 200| 1: [LocalVariableAccess] access to local variable r4 +# 201| 9: [ExprStmt] ...; +# 201| 0: [AssignExpr] ... = ... +# 201| 0: [IntLiteral] 3 +# 201| 1: [MethodCall] call to method F2 +# 201| 0: [LocalVariableAccess] access to local variable r1 +# 204| 6: [Method] F2 +#-----| 2: (Parameters) +# 204| 0: [Parameter] p +# 205| 4: [BlockStmt] {...} +# 206| 0: [LocalFunctionStmt] F3(...) +# 206| 0: [LocalFunction] F3 +#-----| 2: (Parameters) +# 206| 0: [Parameter] q +# 206| 4: [BlockStmt] {...} +# 206| 0: [ReturnStmt] return ...; +# 206| 0: [RefExpr] ref ... +# 206| 0: [ParameterAccess] access to parameter q +# 207| 1: [ReturnStmt] return ...; +# 207| 0: [RefExpr] ref ... +# 207| 0: [ParameterAccess] access to parameter p +# 210| 7: [DelegateType] RefFn +#-----| 2: (Parameters) +# 210| 0: [Parameter] p +# 213| [Class] Discards +# 215| 5: [Method] f +#-----| 2: (Parameters) +# 215| 0: [Parameter] x +# 216| 4: [BlockStmt] {...} +# 217| 0: [ExprStmt] ...; +# 217| 0: [AssignExpr] ... = ... +# 217| 0: [BoolLiteral] false +# 217| 1: [ParameterAccess] access to parameter x +# 218| 1: [ReturnStmt] return ...; +# 218| 0: [TupleExpr] (..., ...) +# 218| 0: [IntLiteral] 0 +# 218| 1: [DoubleLiteral] 0 +# 221| 6: [Method] Test +# 222| 4: [BlockStmt] {...} +# 223| 0: [ExprStmt] ...; +# 223| 0: [AssignExpr] ... = ... +# 223| 0: [MethodCall] call to method f +# 223| 0: [DiscardExpr] _ +# 223| 1: [DiscardExpr] _ +# 224| 1: [ExprStmt] ...; +# 224| 0: [AssignExpr] ... = ... +# 224| 0: [MethodCall] call to method f +# 224| 0: [DiscardExpr] _ +# 224| 1: [TupleExpr] (..., ...) +# 224| 0: [DiscardExpr] _ +# 224| 1: [DiscardExpr] _ +# 225| 2: [ExprStmt] ...; +# 225| 0: [AssignExpr] ... = ... +# 225| 0: [MethodCall] call to method f +# 225| 0: [DiscardExpr] _ +# 225| 1: [TupleExpr] (..., ...) +# 225| 0: [LocalVariableDeclExpr] Int32 x +# 225| 1: [DiscardExpr] _ +# 226| 3: [ExprStmt] ...; +# 226| 0: [AssignExpr] ... = ... +# 226| 0: [MethodCall] call to method f +# 226| 0: [LocalVariableAccess,LocalVariableDeclExpr] Boolean z +# 226| 1: [TupleExpr] (..., ...) +# 226| 0: [DiscardExpr] _ +# 226| 1: [LocalVariableDeclExpr] Double y +# 230| [Class] Patterns +# 232| 5: [Method] Test +# 233| 4: [BlockStmt] {...} +# 234| 0: [LocalVariableDeclStmt] ... ...; +# 234| 0: [LocalVariableDeclAndInitExpr] Object o = ... +# 234| 0: [NullLiteral] null +# 234| 1: [LocalVariableAccess] access to local variable o +# 235| 1: [IfStmt] if (...) ... +# 235| 0: [LogicalAndExpr] ... && ... +# 235| 0: [IsExpr] ... is ... +# 235| 0: [LocalVariableAccess] access to local variable o +# 235| 1: [VariablePatternExpr] Int32 i1 +# 235| 1: [GTExpr] ... > ... +# 235| 0: [LocalVariableAccess] access to local variable i1 +# 235| 1: [IntLiteral] 0 +# 236| 1: [BlockStmt] {...} +# 237| 0: [ExprStmt] ...; +# 237| 0: [MethodCall] call to method WriteLine +# 237| -1: [TypeAccess] access to type Console +# 237| 0: [InterpolatedStringExpr] $"..." +# 237| 0: [StringLiteral] "int " +# 237| 1: [LocalVariableAccess] access to local variable i1 +# 239| 2: [IfStmt] if (...) ... +# 239| 0: [IsExpr] ... is ... +# 239| 0: [LocalVariableAccess] access to local variable o +# 239| 1: [VariablePatternExpr] String s1 +# 240| 1: [BlockStmt] {...} +# 241| 0: [ExprStmt] ...; +# 241| 0: [MethodCall] call to method WriteLine +# 241| -1: [TypeAccess] access to type Console +# 241| 0: [InterpolatedStringExpr] $"..." +# 241| 0: [StringLiteral] "string " +# 241| 1: [LocalVariableAccess] access to local variable s1 +# 243| 2: [IfStmt] if (...) ... +# 243| 0: [IsExpr] ... is ... +# 243| 0: [LocalVariableAccess] access to local variable o +# 243| 1: [TypeAccessPatternExpr] access to type Double +# 244| 1: [BlockStmt] {...} +# 246| 2: [IfStmt] if (...) ... +# 246| 0: [IsExpr] ... is ... +# 246| 0: [LocalVariableAccess] access to local variable o +# 246| 1: [VariablePatternExpr] Object v1 +# 247| 1: [BlockStmt] {...} +# 250| 2: [SwitchStmt] switch (...) {...} +# 250| 0: [LocalVariableAccess] access to local variable o +# 252| 0: [ConstCase] case ...: +# 252| 0: [ConstantPatternExpr,StringLiteral] "xyz" +# 253| 1: [BreakStmt] break; +# 254| 2: [ConstCase] case ...: +# 254| 0: [ConstantPatternExpr,StringLiteral] "" +# 254| 1: [LTExpr] ... < ... +# 254| 0: [IntLiteral] 1 +# 254| 1: [IntLiteral] 2 +# 255| 3: [BreakStmt] break; +# 256| 4: [ConstCase] case ...: +# 256| 0: [ConstantPatternExpr,StringLiteral] "x" +# 256| 1: [IsExpr] ... is ... +# 256| 0: [LocalVariableAccess] access to local variable o +# 256| 1: [VariablePatternExpr] String s4 +# 257| 5: [ExprStmt] ...; +# 257| 0: [MethodCall] call to method WriteLine +# 257| -1: [TypeAccess] access to type Console +# 257| 0: [InterpolatedStringExpr] $"..." +# 257| 0: [StringLiteral] "x " +# 257| 1: [LocalVariableAccess] access to local variable s4 +# 258| 6: [BreakStmt] break; +# 259| 7: [CaseStmt] case ...: +# 259| 0: [VariablePatternExpr] Int32 i2 +# 259| 1: [GTExpr] ... > ... +# 259| 0: [LocalVariableAccess] access to local variable i2 +# 259| 1: [IntLiteral] 0 +# 260| 8: [ExprStmt] ...; +# 260| 0: [MethodCall] call to method WriteLine +# 260| -1: [TypeAccess] access to type Console +# 260| 0: [InterpolatedStringExpr] $"..." +# 260| 0: [StringLiteral] "positive " +# 260| 1: [LocalVariableAccess] access to local variable i2 +# 261| 9: [BreakStmt] break; +# 262| 10: [CaseStmt] case ...: +# 262| 0: [VariablePatternExpr] Int32 i3 +# 263| 11: [ExprStmt] ...; +# 263| 0: [MethodCall] call to method WriteLine +# 263| -1: [TypeAccess] access to type Console +# 263| 0: [InterpolatedStringExpr] $"..." +# 263| 0: [StringLiteral] "int " +# 263| 1: [LocalVariableAccess] access to local variable i3 +# 264| 12: [BreakStmt] break; +# 265| 13: [CaseStmt] case ...: +# 265| 0: [VariablePatternExpr] String s2 +# 266| 14: [ExprStmt] ...; +# 266| 0: [MethodCall] call to method WriteLine +# 266| -1: [TypeAccess] access to type Console +# 266| 0: [InterpolatedStringExpr] $"..." +# 266| 0: [StringLiteral] "string " +# 266| 1: [LocalVariableAccess] access to local variable s2 +# 267| 15: [BreakStmt] break; +# 268| 16: [CaseStmt] case ...: +# 268| 0: [TypeAccessPatternExpr] access to type Double +# 269| 17: [ExprStmt] ...; +# 269| 0: [MethodCall] call to method WriteLine +# 269| -1: [TypeAccess] access to type Console +# 269| 0: [StringLiteral] "Double" +# 270| 18: [BreakStmt] break; +# 271| 19: [CaseStmt] case ...: +# 271| 0: [VariablePatternExpr] Object v2 +# 272| 20: [BreakStmt] break; +# 273| 21: [DefaultCase] default: +# 274| 22: [ExprStmt] ...; +# 274| 0: [MethodCall] call to method WriteLine +# 274| -1: [TypeAccess] access to type Console +# 274| 0: [StringLiteral] "Something else" +# 275| 23: [BreakStmt] break; +# 280| [Class] ForeachStatements +# 282| 5: [Method] Test +# 283| 4: [BlockStmt] {...} +# 284| 0: [LocalVariableDeclStmt] ... ...; +# 284| 0: [LocalVariableDeclAndInitExpr] Dictionary dict = ... +# 284| 0: [ObjectCreation] object creation of type Dictionary +# 284| 1: [LocalVariableAccess] access to local variable dict +# 285| 1: [LocalVariableDeclStmt] ... ...; +# 285| 0: [LocalVariableDeclAndInitExpr] IEnumerable<(Int32,String)> list = ... +# 285| 0: [MethodCall] call to method Select +# 285| -1: [LocalVariableAccess] access to local variable dict +# 285| 0: [LambdaExpr] (...) => ... +#-----| 2: (Parameters) +# 285| 0: [Parameter] item +# 285| 4: [TupleExpr] (..., ...) +# 285| 0: [PropertyCall] access to property Key +# 285| -1: [ParameterAccess] access to parameter item +# 285| 1: [PropertyCall] access to property Value +# 285| -1: [ParameterAccess] access to parameter item +# 285| 1: [LocalVariableAccess] access to local variable list +# 287| 2: [ForeachStmt] foreach (... ... in ...) ... +# 287| 0: [TupleExpr] (..., ...) +# 287| 0: [LocalVariableDeclExpr] Int32 a +# 287| 1: [LocalVariableDeclExpr] String b +# 287| 1: [LocalVariableAccess] access to local variable list +# 287| 2: [BlockStmt] {...} +# 289| 3: [ForeachStmt] foreach (... ... in ...) ... +# 289| 0: [TupleExpr] (..., ...) +# 289| 0: [LocalVariableDeclExpr] Int32 a +# 289| 1: [LocalVariableDeclExpr] String b +# 289| 1: [LocalVariableAccess] access to local variable list +# 289| 2: [BlockStmt] {...} +# 291| 4: [ForeachStmt] foreach (... ... in ...) ... +# 291| 0: [TupleExpr] (..., ...) +# 291| 0: [LocalVariableDeclExpr] Int32 a +# 291| 1: [LocalVariableDeclExpr] String b +# 291| 1: [LocalVariableAccess] access to local variable list +# 291| 2: [BlockStmt] {...} +# 295| [Class] ForLoops +# 297| 5: [Method] Test +# 298| 4: [BlockStmt] {...} +# 299| 0: [ForStmt] for (...;...;...) ... +# 299| -1: [LocalVariableDeclAndInitExpr] Int32 x = ... +# 299| 0: [IntLiteral] 0 +# 299| 1: [LocalVariableAccess] access to local variable x +# 299| 0: [LogicalAndExpr] ... && ... +# 299| 0: [LTExpr] ... < ... +# 299| 0: [LocalVariableAccess] access to local variable x +# 299| 1: [IntLiteral] 10 +# 299| 1: [IsExpr] ... is ... +# 299| 0: [LocalVariableAccess] access to local variable x +# 299| 1: [VariablePatternExpr] Int32 y +# 299| 1: [PreIncrExpr] ++... +# 299| 0: [LocalVariableAccess] access to local variable x +# 300| 2: [BlockStmt] {...} +# 301| 0: [ExprStmt] ...; +# 301| 0: [MethodCall] call to method WriteLine +# 301| -1: [TypeAccess] access to type Console +# 301| 0: [LocalVariableAccess] access to local variable y diff --git a/csharp/ql/test/library-tests/csharp7/PrintAst.qlref b/csharp/ql/test/library-tests/csharp7/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/csharp7/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/csharp7/RefDelegates.expected b/csharp/ql/test/library-tests/csharp7/RefDelegates.expected index b84804d88c36..b26c77efc50d 100644 --- a/csharp/ql/test/library-tests/csharp7/RefDelegates.expected +++ b/csharp/ql/test/library-tests/csharp7/RefDelegates.expected @@ -1 +1 @@ -| CSharp7.cs:209:22:209:26 | RefFn | +| CSharp7.cs:210:22:210:26 | RefFn | diff --git a/csharp/ql/test/library-tests/csharp7/RefExprs.expected b/csharp/ql/test/library-tests/csharp7/RefExprs.expected index f8882edbe6b6..bb1a22d1e19f 100644 --- a/csharp/ql/test/library-tests/csharp7/RefExprs.expected +++ b/csharp/ql/test/library-tests/csharp7/RefExprs.expected @@ -1,6 +1,6 @@ -| CSharp7.cs:192:22:192:27 | ref ... | CSharp7.cs:192:26:192:27 | access to local variable v1 | Int32 | -| CSharp7.cs:196:22:196:33 | ref ... | CSharp7.cs:196:26:196:33 | access to array element | Int32 | -| CSharp7.cs:197:22:197:27 | ref ... | CSharp7.cs:197:26:197:27 | access to local variable r1 | Int32 | -| CSharp7.cs:199:22:199:35 | ref ... | CSharp7.cs:199:26:199:35 | call to method F2 | Int32 | -| CSharp7.cs:205:40:205:44 | ref ... | CSharp7.cs:205:44:205:44 | access to parameter q | Int32 | -| CSharp7.cs:206:16:206:20 | ref ... | CSharp7.cs:206:20:206:20 | access to parameter p | Int32 | +| CSharp7.cs:193:22:193:27 | ref ... | CSharp7.cs:193:26:193:27 | access to local variable v1 | Int32 | +| CSharp7.cs:197:22:197:33 | ref ... | CSharp7.cs:197:26:197:33 | access to array element | Int32 | +| CSharp7.cs:198:22:198:27 | ref ... | CSharp7.cs:198:26:198:27 | access to local variable r1 | Int32 | +| CSharp7.cs:200:22:200:35 | ref ... | CSharp7.cs:200:26:200:35 | call to method F2 | Int32 | +| CSharp7.cs:206:40:206:44 | ref ... | CSharp7.cs:206:44:206:44 | access to parameter q | Int32 | +| CSharp7.cs:207:16:207:20 | ref ... | CSharp7.cs:207:20:207:20 | access to parameter p | Int32 | diff --git a/csharp/ql/test/library-tests/csharp7/RefFunctions.expected b/csharp/ql/test/library-tests/csharp7/RefFunctions.expected index a9740121ee4b..c2899f5443fd 100644 --- a/csharp/ql/test/library-tests/csharp7/RefFunctions.expected +++ b/csharp/ql/test/library-tests/csharp7/RefFunctions.expected @@ -1,2 +1,2 @@ -| CSharp7.cs:203:13:203:14 | F2 | -| CSharp7.cs:205:9:205:47 | F3 | +| CSharp7.cs:204:13:204:14 | F2 | +| CSharp7.cs:206:9:206:47 | F3 | diff --git a/csharp/ql/test/library-tests/csharp7/RefVariables.expected b/csharp/ql/test/library-tests/csharp7/RefVariables.expected index 5d065352dd2a..ed8f2d59b450 100644 --- a/csharp/ql/test/library-tests/csharp7/RefVariables.expected +++ b/csharp/ql/test/library-tests/csharp7/RefVariables.expected @@ -1,4 +1,4 @@ -| CSharp7.cs:192:17:192:18 | r1 | -| CSharp7.cs:196:17:196:18 | r2 | -| CSharp7.cs:197:17:197:18 | r3 | -| CSharp7.cs:199:17:199:18 | r4 | +| CSharp7.cs:193:17:193:18 | r1 | +| CSharp7.cs:197:17:197:18 | r2 | +| CSharp7.cs:198:17:198:18 | r3 | +| CSharp7.cs:200:17:200:18 | r4 | diff --git a/csharp/ql/test/library-tests/csharp7/TaintReaches.expected b/csharp/ql/test/library-tests/csharp7/TaintReaches.expected index d5d232488ad0..88c531506d9d 100644 --- a/csharp/ql/test/library-tests/csharp7/TaintReaches.expected +++ b/csharp/ql/test/library-tests/csharp7/TaintReaches.expected @@ -25,14 +25,14 @@ | CSharp7.cs:114:50:114:58 | "DefUse2" | CSharp7.cs:114:38:114:67 | ... = ... | | CSharp7.cs:114:50:114:58 | "DefUse2" | CSharp7.cs:114:49:114:67 | (..., ...) | | CSharp7.cs:123:28:123:36 | "DefUse3" | CSharp7.cs:123:22:123:36 | ... = ... | -| CSharp7.cs:176:22:176:30 | "tainted" | CSharp7.cs:176:16:176:30 | SSA def(src) | -| CSharp7.cs:176:22:176:30 | "tainted" | CSharp7.cs:181:23:181:25 | access to local variable src | -| CSharp7.cs:176:22:176:30 | "tainted" | CSharp7.cs:182:23:182:25 | access to local variable src | -| CSharp7.cs:176:22:176:30 | "tainted" | CSharp7.cs:183:23:183:25 | access to local variable src | -| CSharp7.cs:177:38:177:39 | "" | CSharp7.cs:177:31:177:39 | ... + ... | -| CSharp7.cs:236:33:236:36 | "int " | CSharp7.cs:236:31:236:41 | $"..." | -| CSharp7.cs:240:33:240:39 | "string " | CSharp7.cs:240:31:240:44 | $"..." | -| CSharp7.cs:256:37:256:38 | "x " | CSharp7.cs:256:35:256:43 | $"..." | -| CSharp7.cs:259:37:259:45 | "positive " | CSharp7.cs:259:35:259:50 | $"..." | -| CSharp7.cs:262:37:262:40 | "int " | CSharp7.cs:262:35:262:45 | $"..." | -| CSharp7.cs:265:37:265:43 | "string " | CSharp7.cs:265:35:265:48 | $"..." | +| CSharp7.cs:177:22:177:30 | "tainted" | CSharp7.cs:177:16:177:30 | SSA def(src) | +| CSharp7.cs:177:22:177:30 | "tainted" | CSharp7.cs:182:23:182:25 | access to local variable src | +| CSharp7.cs:177:22:177:30 | "tainted" | CSharp7.cs:183:23:183:25 | access to local variable src | +| CSharp7.cs:177:22:177:30 | "tainted" | CSharp7.cs:184:23:184:25 | access to local variable src | +| CSharp7.cs:178:38:178:39 | "" | CSharp7.cs:178:31:178:39 | ... + ... | +| CSharp7.cs:237:33:237:36 | "int " | CSharp7.cs:237:31:237:41 | $"..." | +| CSharp7.cs:241:33:241:39 | "string " | CSharp7.cs:241:31:241:44 | $"..." | +| CSharp7.cs:257:37:257:38 | "x " | CSharp7.cs:257:35:257:43 | $"..." | +| CSharp7.cs:260:37:260:45 | "positive " | CSharp7.cs:260:35:260:50 | $"..." | +| CSharp7.cs:263:37:263:40 | "int " | CSharp7.cs:263:35:263:45 | $"..." | +| CSharp7.cs:266:37:266:43 | "string " | CSharp7.cs:266:35:266:48 | $"..." | diff --git a/csharp/ql/test/library-tests/csharp7/TupleAccess.expected b/csharp/ql/test/library-tests/csharp7/TupleAccess.expected index 437ee46820d1..978a9b041c0d 100644 --- a/csharp/ql/test/library-tests/csharp7/TupleAccess.expected +++ b/csharp/ql/test/library-tests/csharp7/TupleAccess.expected @@ -1,4 +1,4 @@ -| CSharp7.cs:66:16:66:21 | (..., ...) | read | +| CSharp7.cs:66:16:66:27 | (..., ...) | read | | CSharp7.cs:71:9:71:22 | (..., ...) | write | | CSharp7.cs:73:9:73:14 | (..., ...) | write | | CSharp7.cs:75:9:75:23 | (..., ...) | write | @@ -35,11 +35,11 @@ | CSharp7.cs:114:38:114:45 | (..., ...) | write | | CSharp7.cs:114:49:114:67 | (..., ...) | read | | CSharp7.cs:114:61:114:66 | (..., ...) | read | -| CSharp7.cs:217:16:217:23 | (..., ...) | read | -| CSharp7.cs:223:9:223:14 | (..., ...) | write | -| CSharp7.cs:224:9:224:18 | (..., ...) | write | +| CSharp7.cs:218:16:218:23 | (..., ...) | read | +| CSharp7.cs:224:9:224:14 | (..., ...) | write | | CSharp7.cs:225:9:225:18 | (..., ...) | write | -| CSharp7.cs:284:40:284:61 | (..., ...) | read | -| CSharp7.cs:286:18:286:34 | (..., ...) | write | -| CSharp7.cs:288:18:288:31 | (..., ...) | write | -| CSharp7.cs:290:18:290:27 | (..., ...) | write | +| CSharp7.cs:226:9:226:18 | (..., ...) | write | +| CSharp7.cs:285:40:285:61 | (..., ...) | read | +| CSharp7.cs:287:18:287:34 | (..., ...) | write | +| CSharp7.cs:289:18:289:31 | (..., ...) | write | +| CSharp7.cs:291:18:291:27 | (..., ...) | write | diff --git a/csharp/ql/test/library-tests/csharp7/TupleExpr.expected b/csharp/ql/test/library-tests/csharp7/TupleExpr.expected index ec92d01d1eeb..7e3a52e86cde 100644 --- a/csharp/ql/test/library-tests/csharp7/TupleExpr.expected +++ b/csharp/ql/test/library-tests/csharp7/TupleExpr.expected @@ -1,5 +1,5 @@ -| CSharp7.cs:66:16:66:21 | (..., ...) | 0 | CSharp7.cs:66:17:66:17 | 1 | -| CSharp7.cs:66:16:66:21 | (..., ...) | 1 | CSharp7.cs:66:20:66:20 | 2 | +| CSharp7.cs:66:16:66:27 | (..., ...) | 0 | CSharp7.cs:66:20:66:20 | 1 | +| CSharp7.cs:66:16:66:27 | (..., ...) | 1 | CSharp7.cs:66:26:66:26 | 2 | | CSharp7.cs:71:9:71:22 | (..., ...) | 0 | CSharp7.cs:71:14:71:14 | Int32 x | | CSharp7.cs:71:9:71:22 | (..., ...) | 1 | CSharp7.cs:71:21:71:21 | Int32 y | | CSharp7.cs:73:9:73:14 | (..., ...) | 0 | CSharp7.cs:73:10:73:10 | access to local variable x | @@ -74,19 +74,19 @@ | CSharp7.cs:114:49:114:67 | (..., ...) | 1 | CSharp7.cs:114:61:114:66 | (..., ...) | | CSharp7.cs:114:61:114:66 | (..., ...) | 0 | CSharp7.cs:114:62:114:62 | 0 | | CSharp7.cs:114:61:114:66 | (..., ...) | 1 | CSharp7.cs:114:65:114:65 | 1 | -| CSharp7.cs:217:16:217:23 | (..., ...) | 0 | CSharp7.cs:217:17:217:17 | 0 | -| CSharp7.cs:217:16:217:23 | (..., ...) | 1 | CSharp7.cs:217:20:217:22 | 0 | -| CSharp7.cs:223:9:223:14 | (..., ...) | 0 | CSharp7.cs:223:10:223:10 | _ | -| CSharp7.cs:223:9:223:14 | (..., ...) | 1 | CSharp7.cs:223:13:223:13 | _ | -| CSharp7.cs:224:9:224:18 | (..., ...) | 0 | CSharp7.cs:224:14:224:14 | Int32 x | -| CSharp7.cs:224:9:224:18 | (..., ...) | 1 | CSharp7.cs:224:17:224:17 | _ | -| CSharp7.cs:225:9:225:18 | (..., ...) | 0 | CSharp7.cs:225:10:225:10 | _ | -| CSharp7.cs:225:9:225:18 | (..., ...) | 1 | CSharp7.cs:225:17:225:17 | Double y | -| CSharp7.cs:284:40:284:61 | (..., ...) | 0 | CSharp7.cs:284:41:284:48 | access to property Key | -| CSharp7.cs:284:40:284:61 | (..., ...) | 1 | CSharp7.cs:284:51:284:60 | access to property Value | -| CSharp7.cs:286:18:286:34 | (..., ...) | 0 | CSharp7.cs:286:23:286:23 | Int32 a | -| CSharp7.cs:286:18:286:34 | (..., ...) | 1 | CSharp7.cs:286:33:286:33 | String b | -| CSharp7.cs:288:18:288:31 | (..., ...) | 0 | CSharp7.cs:288:23:288:23 | Int32 a | -| CSharp7.cs:288:18:288:31 | (..., ...) | 1 | CSharp7.cs:288:30:288:30 | String b | -| CSharp7.cs:290:18:290:27 | (..., ...) | 0 | CSharp7.cs:290:23:290:23 | Int32 a | -| CSharp7.cs:290:18:290:27 | (..., ...) | 1 | CSharp7.cs:290:26:290:26 | String b | +| CSharp7.cs:218:16:218:23 | (..., ...) | 0 | CSharp7.cs:218:17:218:17 | 0 | +| CSharp7.cs:218:16:218:23 | (..., ...) | 1 | CSharp7.cs:218:20:218:22 | 0 | +| CSharp7.cs:224:9:224:14 | (..., ...) | 0 | CSharp7.cs:224:10:224:10 | _ | +| CSharp7.cs:224:9:224:14 | (..., ...) | 1 | CSharp7.cs:224:13:224:13 | _ | +| CSharp7.cs:225:9:225:18 | (..., ...) | 0 | CSharp7.cs:225:14:225:14 | Int32 x | +| CSharp7.cs:225:9:225:18 | (..., ...) | 1 | CSharp7.cs:225:17:225:17 | _ | +| CSharp7.cs:226:9:226:18 | (..., ...) | 0 | CSharp7.cs:226:10:226:10 | _ | +| CSharp7.cs:226:9:226:18 | (..., ...) | 1 | CSharp7.cs:226:17:226:17 | Double y | +| CSharp7.cs:285:40:285:61 | (..., ...) | 0 | CSharp7.cs:285:41:285:48 | access to property Key | +| CSharp7.cs:285:40:285:61 | (..., ...) | 1 | CSharp7.cs:285:51:285:60 | access to property Value | +| CSharp7.cs:287:18:287:34 | (..., ...) | 0 | CSharp7.cs:287:23:287:23 | Int32 a | +| CSharp7.cs:287:18:287:34 | (..., ...) | 1 | CSharp7.cs:287:33:287:33 | String b | +| CSharp7.cs:289:18:289:31 | (..., ...) | 0 | CSharp7.cs:289:23:289:23 | Int32 a | +| CSharp7.cs:289:18:289:31 | (..., ...) | 1 | CSharp7.cs:289:30:289:30 | String b | +| CSharp7.cs:291:18:291:27 | (..., ...) | 0 | CSharp7.cs:291:23:291:23 | Int32 a | +| CSharp7.cs:291:18:291:27 | (..., ...) | 1 | CSharp7.cs:291:26:291:26 | String b | diff --git a/csharp/ql/test/library-tests/csharp7/TupleTypes.expected b/csharp/ql/test/library-tests/csharp7/TupleTypes.expected index 7168e2b833f7..7a375de1fb8d 100644 --- a/csharp/ql/test/library-tests/csharp7/TupleTypes.expected +++ b/csharp/ql/test/library-tests/csharp7/TupleTypes.expected @@ -6,19 +6,19 @@ | (Int32,(Int32,Int32)) | (int, (int, int)) | ValueTuple | 2 | 1 | CSharp7.cs:78:27:78:32 | Item2 | | (Int32,(String,Int32)) | (int, (string, int)) | ValueTuple | 2 | 0 | CSharp7.cs:98:19:98:19 | Item1 | | (Int32,(String,Int32)) | (int, (string, int)) | ValueTuple | 2 | 1 | CSharp7.cs:98:22:98:42 | Item2 | -| (Int32,Double) | (int, double) | ValueTuple | 2 | 0 | CSharp7.cs:214:6:214:8 | Item1 | -| (Int32,Double) | (int, double) | ValueTuple | 2 | 0 | CSharp7.cs:224:10:224:14 | x | -| (Int32,Double) | (int, double) | ValueTuple | 2 | 0 | CSharp7.cs:225:10:225:10 | Item1 | -| (Int32,Double) | (int, double) | ValueTuple | 2 | 1 | CSharp7.cs:214:11:214:16 | Item2 | -| (Int32,Double) | (int, double) | ValueTuple | 2 | 1 | CSharp7.cs:224:17:224:17 | Item2 | -| (Int32,Double) | (int, double) | ValueTuple | 2 | 1 | CSharp7.cs:225:13:225:17 | y | -| (Int32,Int32) | (int, int) | ValueTuple | 2 | 0 | CSharp7.cs:64:6:64:8 | Item1 | +| (Int32,Double) | (int, double) | ValueTuple | 2 | 0 | CSharp7.cs:215:6:215:8 | Item1 | +| (Int32,Double) | (int, double) | ValueTuple | 2 | 0 | CSharp7.cs:225:10:225:14 | x | +| (Int32,Double) | (int, double) | ValueTuple | 2 | 0 | CSharp7.cs:226:10:226:10 | Item1 | +| (Int32,Double) | (int, double) | ValueTuple | 2 | 1 | CSharp7.cs:215:11:215:16 | Item2 | +| (Int32,Double) | (int, double) | ValueTuple | 2 | 1 | CSharp7.cs:225:17:225:17 | Item2 | +| (Int32,Double) | (int, double) | ValueTuple | 2 | 1 | CSharp7.cs:226:13:226:17 | y | +| (Int32,Int32) | (int, int) | ValueTuple | 2 | 0 | CSharp7.cs:64:10:64:10 | A | | (Int32,Int32) | (int, int) | ValueTuple | 2 | 0 | CSharp7.cs:71:10:71:14 | x | | (Int32,Int32) | (int, int) | ValueTuple | 2 | 0 | CSharp7.cs:77:18:77:22 | b | | (Int32,Int32) | (int, int) | ValueTuple | 2 | 0 | CSharp7.cs:78:28:78:28 | c | | (Int32,Int32) | (int, int) | ValueTuple | 2 | 0 | CSharp7.cs:112:15:112:16 | m4 | | (Int32,Int32) | (int, int) | ValueTuple | 2 | 0 | CSharp7.cs:114:19:114:24 | m8 | -| (Int32,Int32) | (int, int) | ValueTuple | 2 | 1 | CSharp7.cs:64:11:64:13 | Item2 | +| (Int32,Int32) | (int, int) | ValueTuple | 2 | 1 | CSharp7.cs:64:17:64:17 | B | | (Int32,Int32) | (int, int) | ValueTuple | 2 | 1 | CSharp7.cs:71:17:71:21 | y | | (Int32,Int32) | (int, int) | ValueTuple | 2 | 1 | CSharp7.cs:77:25:77:29 | c | | (Int32,Int32) | (int, int) | ValueTuple | 2 | 1 | CSharp7.cs:78:31:78:31 | a | @@ -27,10 +27,10 @@ | (Int32,Int32,Int32) | (int, int, int) | ValueTuple | 3 | 0 | CSharp7.cs:75:10:75:10 | x | | (Int32,Int32,Int32) | (int, int, int) | ValueTuple | 3 | 1 | CSharp7.cs:75:13:75:13 | y | | (Int32,Int32,Int32) | (int, int, int) | ValueTuple | 3 | 2 | CSharp7.cs:75:16:75:22 | Item3 | -| (Int32,String) | (int, string) | ValueTuple | 2 | 0 | CSharp7.cs:284:41:284:48 | Key | -| (Int32,String) | (int, string) | ValueTuple | 2 | 0 | CSharp7.cs:286:19:286:23 | a | -| (Int32,String) | (int, string) | ValueTuple | 2 | 1 | CSharp7.cs:284:51:284:60 | Value | -| (Int32,String) | (int, string) | ValueTuple | 2 | 1 | CSharp7.cs:286:26:286:33 | b | +| (Int32,String) | (int, string) | ValueTuple | 2 | 0 | CSharp7.cs:285:41:285:48 | Key | +| (Int32,String) | (int, string) | ValueTuple | 2 | 0 | CSharp7.cs:287:19:287:23 | a | +| (Int32,String) | (int, string) | ValueTuple | 2 | 1 | CSharp7.cs:285:51:285:60 | Value | +| (Int32,String) | (int, string) | ValueTuple | 2 | 1 | CSharp7.cs:287:26:287:33 | b | | (String,(Int32,Int32)) | (string, (int, int)) | ValueTuple | 2 | 0 | CSharp7.cs:109:10:109:15 | m1 | | (String,(Int32,Int32)) | (string, (int, int)) | ValueTuple | 2 | 0 | CSharp7.cs:112:10:112:11 | m3 | | (String,(Int32,Int32)) | (string, (int, int)) | ValueTuple | 2 | 0 | CSharp7.cs:114:10:114:15 | m7 | diff --git a/csharp/ql/test/library-tests/csharp7/TypeCase1.expected b/csharp/ql/test/library-tests/csharp7/TypeCase1.expected index 92c23564233f..f5feda6b24bf 100644 --- a/csharp/ql/test/library-tests/csharp7/TypeCase1.expected +++ b/csharp/ql/test/library-tests/csharp7/TypeCase1.expected @@ -1,9 +1,9 @@ -| CSharp7.cs:251:13:251:23 | case ...: | -| CSharp7.cs:253:13:253:31 | case ...: | -| CSharp7.cs:255:13:255:41 | case ...: | -| CSharp7.cs:258:13:258:36 | case ...: | -| CSharp7.cs:261:13:261:24 | case ...: | -| CSharp7.cs:264:13:264:27 | case ...: | -| CSharp7.cs:267:13:267:26 | case ...: | -| CSharp7.cs:270:13:270:24 | case ...: | -| CSharp7.cs:272:13:272:20 | default: | +| CSharp7.cs:252:13:252:23 | case ...: | +| CSharp7.cs:254:13:254:31 | case ...: | +| CSharp7.cs:256:13:256:41 | case ...: | +| CSharp7.cs:259:13:259:36 | case ...: | +| CSharp7.cs:262:13:262:24 | case ...: | +| CSharp7.cs:265:13:265:27 | case ...: | +| CSharp7.cs:268:13:268:26 | case ...: | +| CSharp7.cs:271:13:271:24 | case ...: | +| CSharp7.cs:273:13:273:20 | default: | diff --git a/csharp/ql/test/library-tests/csharp7/TypeCase2.expected b/csharp/ql/test/library-tests/csharp7/TypeCase2.expected index 3825dd93fe6e..bace5da4c04e 100644 --- a/csharp/ql/test/library-tests/csharp7/TypeCase2.expected +++ b/csharp/ql/test/library-tests/csharp7/TypeCase2.expected @@ -1,4 +1,4 @@ -| CSharp7.cs:258:13:258:36 | case ...: | CSharp7.cs:258:18:258:23 | Int32 i2 | Int32 | false | -| CSharp7.cs:261:13:261:24 | case ...: | CSharp7.cs:261:18:261:23 | Int32 i3 | Int32 | false | -| CSharp7.cs:264:13:264:27 | case ...: | CSharp7.cs:264:18:264:26 | String s2 | String | false | -| CSharp7.cs:270:13:270:24 | case ...: | CSharp7.cs:270:18:270:23 | Object v2 | Object | true | +| CSharp7.cs:259:13:259:36 | case ...: | CSharp7.cs:259:18:259:23 | Int32 i2 | Int32 | false | +| CSharp7.cs:262:13:262:24 | case ...: | CSharp7.cs:262:18:262:23 | Int32 i3 | Int32 | false | +| CSharp7.cs:265:13:265:27 | case ...: | CSharp7.cs:265:18:265:26 | String s2 | String | false | +| CSharp7.cs:271:13:271:24 | case ...: | CSharp7.cs:271:18:271:23 | Object v2 | Object | true | diff --git a/csharp/ql/test/library-tests/csharp7/TypeCase3.expected b/csharp/ql/test/library-tests/csharp7/TypeCase3.expected index 93eb7af459b0..abab42820f88 100644 --- a/csharp/ql/test/library-tests/csharp7/TypeCase3.expected +++ b/csharp/ql/test/library-tests/csharp7/TypeCase3.expected @@ -1 +1 @@ -| CSharp7.cs:258:13:258:36 | case ...: | CSharp7.cs:258:30:258:35 | ... > ... | +| CSharp7.cs:259:13:259:36 | case ...: | CSharp7.cs:259:30:259:35 | ... > ... | diff --git a/csharp/ql/test/library-tests/csharp7/UnboundLocalFunctions.expected b/csharp/ql/test/library-tests/csharp7/UnboundLocalFunctions.expected index 594f51bac569..8629d9d496c6 100644 --- a/csharp/ql/test/library-tests/csharp7/UnboundLocalFunctions.expected +++ b/csharp/ql/test/library-tests/csharp7/UnboundLocalFunctions.expected @@ -1,7 +1,7 @@ | CSharp7.cs:133:9:133:42 | f2 | 0 | CSharp7.cs:133:14:133:14 | T | | CSharp7.cs:133:9:133:42 | f2 | 1 | CSharp7.cs:133:17:133:17 | U | -| CSharp7.cs:160:9:160:24 | f | 0 | CSharp7.cs:160:15:160:15 | T | -| CSharp7.cs:161:9:161:25 | g | 0 | CSharp7.cs:161:13:161:13 | T | -| CSharp7.cs:163:9:168:9 | h | 0 | CSharp7.cs:163:13:163:13 | T | -| CSharp7.cs:163:9:168:9 | h | 1 | CSharp7.cs:163:16:163:16 | U | -| CSharp7.cs:165:13:165:43 | f2 | 0 | CSharp7.cs:165:20:165:20 | S | +| CSharp7.cs:161:9:161:24 | f | 0 | CSharp7.cs:161:15:161:15 | T | +| CSharp7.cs:162:9:162:25 | g | 0 | CSharp7.cs:162:13:162:13 | T | +| CSharp7.cs:164:9:169:9 | h | 0 | CSharp7.cs:164:13:164:13 | T | +| CSharp7.cs:164:9:169:9 | h | 1 | CSharp7.cs:164:16:164:16 | U | +| CSharp7.cs:166:13:166:43 | f2 | 0 | CSharp7.cs:166:20:166:20 | S | diff --git a/csharp/ql/test/library-tests/csharp8/NullableRefTypes.expected b/csharp/ql/test/library-tests/csharp8/NullableRefTypes.expected index db4f3c6fb5d8..891ba1602cb0 100644 --- a/csharp/ql/test/library-tests/csharp8/NullableRefTypes.expected +++ b/csharp/ql/test/library-tests/csharp8/NullableRefTypes.expected @@ -243,7 +243,7 @@ expressionTypes | NullableRefTypes.cs:19:33:19:36 | this access | MyClass! | | NullableRefTypes.cs:26:44:26:53 | throw ... | MyClass![]! | | NullableRefTypes.cs:26:50:26:53 | null | null | -| NullableRefTypes.cs:27:44:27:53 | throw ... | MyClass![]! | +| NullableRefTypes.cs:27:44:27:53 | throw ... | MyClass?[]! | | NullableRefTypes.cs:27:50:27:53 | null | null | | NullableRefTypes.cs:30:21:30:24 | null | null | | NullableRefTypes.cs:31:20:31:23 | this access | MyClass! | diff --git a/csharp/ql/test/library-tests/csharp8/PrintAst.expected b/csharp/ql/test/library-tests/csharp8/PrintAst.expected new file mode 100644 index 000000000000..0a9d89972e10 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp8/PrintAst.expected @@ -0,0 +1,1021 @@ +AlternateInterpolatedStrings.cs: +# 3| [Class] AlternateInterpolatedStrings +# 5| 5: [Field] s1 +# 5| 1: [AssignExpr] ... = ... +# 5| 0: [InterpolatedStringExpr] $"..." +# 5| 0: [StringLiteral] "C:" +# 5| 1: [IntLiteral] 12 +# 5| 1: [FieldAccess] access to field s1 +# 6| 6: [Field] s2 +# 6| 1: [AssignExpr] ... = ... +# 6| 0: [InterpolatedStringExpr] $"..." +# 6| 0: [StringLiteral] "C:" +# 6| 1: [IntLiteral] 12 +# 6| 1: [FieldAccess] access to field s2 +AsyncStreams.cs: +# 8| [Class] AsyncStreams +# 10| 5: [Method] Items +# 10| 4: [BlockStmt] {...} +# 11| 0: [YieldReturnStmt] yield return ...; +# 11| 0: [IntLiteral] 1 +# 12| 1: [YieldReturnStmt] yield return ...; +# 12| 0: [IntLiteral] 2 +# 13| 2: [ExprStmt] ...; +# 13| 0: [AwaitExpr] await ... +# 13| 0: [MethodCall] call to method Delay +# 13| -1: [TypeAccess] access to type Task +# 13| 0: [IntLiteral] 1000 +# 14| 3: [YieldReturnStmt] yield return ...; +# 14| 0: [IntLiteral] 3 +# 17| 6: [Method] F +# 18| 4: [BlockStmt] {...} +# 19| 0: [ForeachStmt] foreach (... ... in ...) ... +# 19| 0: [LocalVariableDeclExpr] Int32 item +# 19| 1: [MethodCall] call to method Items +# 20| 2: [ExprStmt] ...; +# 20| 0: [MethodCall] call to method WriteLine +# 20| -1: [TypeAccess] access to type Console +# 20| 0: [LocalVariableAccess] access to local variable item +# 24| [NamespaceDeclaration] namespace ... { ... } +# 26| 1: [Interface] IAsyncDisposable +# 28| 4: [Method] DisposeAsync +# 32| [NamespaceDeclaration] namespace ... { ... } +# 34| 1: [Interface] IAsyncEnumerable<> +#-----| 1: (Type parameters) +# 34| 0: [TypeParameter] T +# 36| 4: [Method] GetAsyncEnumerator +#-----| 2: (Parameters) +# 36| 0: [Parameter] cancellationToken +# 36| 1: [DefaultValueExpr] default(...) +# 36| 0: [TypeAccess] access to type CancellationToken +# 39| 2: [Interface] IAsyncEnumerator<> +#-----| 1: (Type parameters) +# 39| 0: [TypeParameter] T +#-----| 3: (Base types) +# 39| 1: [Interface] IAsyncDisposable +# 41| 4: [Property] Current +# 41| 3: [Getter] get_Current +# 42| 5: [Method] MoveNextAsync +DefaultInterfaceMethods.cs: +# 3| [Interface] IPerson +# 5| 4: [IndexerProperty] Name +# 5| 3: [Getter] get_Name +# 7| 5: [IndexerProperty] Greeting +# 9| 3: [Getter] get_Greeting +# 9| 4: [StringLiteral] "Hello" +# 10| 4: [Setter] set_Greeting +#-----| 2: (Parameters) +# 10| 0: [Parameter] value +# 10| 4: [BlockStmt] {...} +# 13| 6: [Method] Greet +#-----| 2: (Parameters) +# 13| 0: [Parameter] name +# 13| 4: [AddExpr] ... + ... +# 13| 0: [AddExpr] ... + ... +# 13| 0: [PropertyCall] access to property Greeting +# 13| 1: [StringLiteral] " " +# 13| 1: [ParameterAccess] access to parameter name +# 15| 7: [IndexerProperty] GreetingString +# 15| 3: [Getter] get_GreetingString +# 15| 4: [MethodCall] call to method Greet +# 15| 0: [PropertyCall] access to property Name +# 17| 8: [Method] Greet +# 20| [Class] Person +#-----| 3: (Base types) +# 20| 1: [Interface] IPerson +# 22| 5: [IndexerProperty] Name +# 22| 3: [Getter] get_Name +# 22| 4: [StringLiteral] "Petra" +# 24| 6: [IndexerProperty] Greeting +# 24| 3: [Getter] get_Greeting +# 24| 4: [StringLiteral] "Howdy" +# 24| 4: [Setter] set_Greeting +#-----| 2: (Parameters) +# 24| 0: [Parameter] value +# 24| 4: [BlockStmt] {...} +# 26| 7: [Method] Greet +# 26| 4: [BlockStmt] {...} +NullCoalescingAssignment.cs: +# 3| [Class] NullCoalescingAssignment +# 5| 5: [Method] NullCoalescing +# 6| 4: [BlockStmt] {...} +# 7| 0: [LocalVariableDeclStmt] ... ...; +# 7| 0: [LocalVariableDeclAndInitExpr] Object o = ... +# 7| 0: [NullLiteral] null +# 7| 1: [LocalVariableAccess] access to local variable o +# 8| 1: [ExprStmt] ...; +# 8| 0: [AssignCoalesceExpr] ... ??= ... +# 8| 0: [ThisAccess] this access +# 8| 1: [LocalVariableAccess] access to local variable o +NullableRefTypes.cs: +# 6| [Class] MyClass +# 9| 5: [Field] A +# 10| 6: [Field] B +# 13| 7: [IndexerProperty] C +# 13| 3: [Getter] get_C +# 13| 4: [NullLiteral] null +# 14| 8: [IndexerProperty] D +# 14| 3: [Getter] get_D +# 14| 4: [ThisAccess] this access +# 17| 9: [Indexer] Item +#-----| 1: (Parameters) +# 17| 0: [Parameter] i +# 17| 3: [Getter] get_Item +#-----| 2: (Parameters) +# 17| 0: [Parameter] i +# 17| 4: [NullLiteral] null +# 18| 10: [Indexer] Item +#-----| 1: (Parameters) +# 18| 0: [Parameter] i +# 18| 3: [Getter] get_Item +#-----| 2: (Parameters) +# 18| 0: [Parameter] i +# 18| 4: [ThisAccess] this access +# 19| 11: [Indexer] Item +#-----| 1: (Parameters) +# 19| 0: [Parameter] i +# 19| 3: [Getter] get_Item +#-----| 2: (Parameters) +# 19| 0: [Parameter] i +# 19| 4: [ThisAccess] this access +# 22| 12: [Field] G1 +# 23| 13: [Field] G2 +# 24| 14: [Field] G3 +# 25| 15: [Field] H +# 26| 16: [Method] ArrayFn1 +#-----| 2: (Parameters) +# 26| 0: [Parameter] x +# 26| 4: [ThrowExpr] throw ... +# 26| 0: [NullLiteral] null +# 27| 17: [Method] ArrayFn2 +#-----| 2: (Parameters) +# 27| 0: [Parameter] x +# 27| 4: [ThrowExpr] throw ... +# 27| 0: [NullLiteral] null +# 30| 18: [Method] M +# 30| 4: [NullLiteral] null +# 31| 19: [Method] N +# 31| 4: [ThisAccess] this access +# 32| 20: [Method] O +#-----| 2: (Parameters) +# 32| 0: [Parameter] a +# 32| 1: [Parameter] b +# 32| 4: [BlockStmt] {...} +# 35| 21: [Method] Locals +# 36| 4: [BlockStmt] {...} +# 37| 0: [LocalVariableDeclStmt] ... ...; +# 37| 0: [LocalVariableDeclAndInitExpr] MyClass a = ... +# 37| 0: [ObjectCreation] object creation of type MyClass +# 37| 1: [LocalVariableAccess] access to local variable a +# 38| 1: [LocalVariableDeclStmt] ... ...; +# 38| 0: [LocalVariableDeclAndInitExpr] MyClass b = ... +# 38| 0: [NullLiteral] null +# 38| 1: [LocalVariableAccess] access to local variable b +# 39| 2: [LocalVariableDeclStmt] ... ...; +# 39| 0: [LocalVariableDeclAndInitExpr] MyClass c = ... +# 39| 0: [RefExpr] ref ... +# 39| 0: [LocalVariableAccess] access to local variable b +# 39| 1: [LocalVariableAccess] access to local variable c +# 40| 3: [LocalVariableDeclStmt] ... ...; +# 40| 0: [LocalVariableDeclAndInitExpr] MyClass d = ... +# 40| 0: [RefExpr] ref ... +# 40| 0: [LocalVariableAccess] access to local variable b +# 40| 1: [LocalVariableAccess] access to local variable d +# 44| 22: [DelegateType] Del1 +# 47| 23: [DelegateType] Del +#-----| 2: (Parameters) +# 47| 0: [Parameter] x +# 48| 24: [Event] P +# 48| 3: [AddEventAccessor] add_P +#-----| 2: (Parameters) +# 48| 0: [Parameter] value +# 48| 4: [RemoveEventAccessor] remove_P +#-----| 2: (Parameters) +# 48| 0: [Parameter] value +# 51| 25: [Method] Q +#-----| 1: (Type parameters) +# 51| 0: [TypeParameter] T +#-----| 2: (Parameters) +# 51| 0: [Parameter] t +# 51| 4: [NullLiteral] null +# 54| 27: [Class] Generic<,,,> +#-----| 1: (Type parameters) +# 54| 0: [TypeParameter] T1 +# 54| 1: [TypeParameter] T2 +# 54| 2: [TypeParameter] T3 +# 54| 3: [TypeParameter] T4 +# 58| 30: [Class] Generic2<,> +#-----| 1: (Type parameters) +# 58| 0: [TypeParameter] T1 +# 58| 1: [TypeParameter] T2 +# 65| 31: [Field] items2 +# 67| 32: [Method] GenericFn +#-----| 1: (Type parameters) +# 67| 0: [TypeParameter] T +#-----| 2: (Parameters) +# 67| 0: [Parameter] x +# 68| 4: [BlockStmt] {...} +# 71| 34: [Method] CallF +# 72| 4: [BlockStmt] {...} +# 73| 0: [LocalVariableDeclStmt] ... ...; +# 73| 0: [LocalVariableDeclAndInitExpr] MyClass x = ... +# 73| 0: [NullLiteral] null +# 73| 1: [LocalVariableAccess] access to local variable x +# 74| 1: [ExprStmt] ...; +# 74| 0: [MethodCall] call to method GenericFn +# 74| 0: [LocalVariableAccess] access to local variable x +# 75| 2: [ExprStmt] ...; +# 75| 0: [MethodCall] call to method Q +# 75| 0: [LocalVariableAccess] access to local variable x +# 76| 3: [ReturnStmt] return ...; +# 76| 0: [DefaultValueExpr] default(...) +# 76| 0: [TypeAccess] access to type MyStruct +# 80| [Class] NullableRefTypes +# 82| 5: [Method] TestSuppressNullableWarningExpr +# 83| 4: [BlockStmt] {...} +# 84| 0: [LocalVariableDeclStmt] ... ...; +# 84| 0: [LocalVariableDeclAndInitExpr] String x = ... +# 84| 0: [StringLiteral] "source" +# 84| 1: [LocalVariableAccess] access to local variable x +# 85| 1: [LocalVariableDeclStmt] ... ...; +# 85| 0: [LocalVariableDeclAndInitExpr] String y = ... +# 85| 0: [SuppressNullableWarningExpr] ...! +# 85| 0: [LocalVariableAccess] access to local variable x +# 85| 1: [LocalVariableAccess] access to local variable y +# 86| 2: [ExprStmt] ...; +# 86| 0: [AssignExpr] ... = ... +# 86| 0: [SuppressNullableWarningExpr] ...! +# 86| 0: [LocalVariableAccess] access to local variable x +# 86| 1: [LocalVariableAccess] access to local variable y +# 87| 3: [ExprStmt] ...; +# 87| 0: [AssignExpr] ... = ... +# 87| 0: [NullLiteral] null +# 87| 1: [LocalVariableAccess] access to local variable x +# 88| 4: [ExprStmt] ...; +# 88| 0: [AssignExpr] ... = ... +# 88| 0: [SuppressNullableWarningExpr] ...! +# 88| 0: [LocalVariableAccess] access to local variable x +# 88| 1: [LocalVariableAccess] access to local variable y +# 91| 6: [Method] FunctionInNullableContext +# 92| 4: [BlockStmt] {...} +# 93| 0: [LocalVariableDeclStmt] ... ...; +# 93| 0: [LocalVariableDeclAndInitExpr] String x = ... +# 93| 0: [StringLiteral] "source" +# 93| 1: [LocalVariableAccess] access to local variable x +# 94| 1: [LocalVariableDeclStmt] ... ...; +# 94| 0: [LocalVariableDeclAndInitExpr] String y = ... +# 94| 0: [NullCoalescingExpr] ... ?? ... +# 94| 0: [LocalVariableAccess] access to local variable x +# 94| 1: [NullLiteral] null +# 94| 1: [LocalVariableAccess] access to local variable y +# 95| 2: [LocalVariableDeclStmt] ... ...; +# 95| 0: [LocalVariableDeclAndInitExpr] String z = ... +# 95| 0: [LocalVariableAccess] access to local variable x +# 95| 1: [LocalVariableAccess] access to local variable z +# 96| 3: [ExprStmt] ...; +# 96| 0: [MethodCall] call to method WriteLine +# 96| -1: [TypeAccess] access to type Console +# 96| 0: [LocalVariableAccess] access to local variable x +# 100| [Class] RefTypes +# 103| 5: [Method] ReturnsRef1 +#-----| 2: (Parameters) +# 103| 0: [Parameter] r +# 103| 4: [RefExpr] ref ... +# 103| 0: [ParameterAccess] access to parameter r +# 104| 6: [Method] ReturnsRef2 +#-----| 2: (Parameters) +# 104| 0: [Parameter] r +# 104| 4: [RefExpr] ref ... +# 104| 0: [ParameterAccess] access to parameter r +# 105| 7: [Method] ReturnsRef3 +#-----| 2: (Parameters) +# 105| 0: [Parameter] r +# 105| 4: [RefExpr] ref ... +# 105| 0: [ParameterAccess] access to parameter r +# 106| 8: [Method] ReturnsRef4 +#-----| 2: (Parameters) +# 106| 0: [Parameter] r +# 106| 4: [RefExpr] ref ... +# 106| 0: [ParameterAccess] access to parameter r +# 107| 9: [Method] ReturnsRef5 +#-----| 2: (Parameters) +# 107| 0: [Parameter] r +# 107| 4: [RefExpr] ref ... +# 107| 0: [ParameterAccess] access to parameter r +# 108| 10: [Method] ReturnsRef6 +#-----| 2: (Parameters) +# 108| 0: [Parameter] r +# 108| 4: [RefExpr] ref ... +# 108| 0: [ParameterAccess] access to parameter r +# 110| 11: [Method] Parameters1 +#-----| 2: (Parameters) +# 110| 0: [Parameter] p1 +# 110| 1: [Parameter] p2 +# 110| 4: [ThrowExpr] throw ... +# 110| 0: [NullLiteral] null +# 112| 12: [Field] Property +# 113| 13: [IndexerProperty] RefProperty +# 113| 3: [Getter] get_RefProperty +# 113| 4: [RefExpr] ref ... +# 113| 0: [SuppressNullableWarningExpr] ...! +# 113| 0: [FieldAccess] access to field Property +# 116| [Class] ToStringWithTypes +# 118| 5: [Field] a +# 119| 6: [Field] b +# 120| 7: [Field] c +# 121| 8: [Field] d +# 123| 9: [Field] e +# 124| 10: [Field] f +# 125| 11: [Field] g +# 126| 12: [Field] h +# 128| 13: [Field] i +# 129| 14: [Field] j +# 130| 15: [Field] k +# 131| 16: [Field] l +# 136| [Class] ToStringWithTypes2 +# 138| 5: [Field] a +# 139| 6: [Field] b +# 140| 7: [Field] c +# 141| 8: [Field] d +# 143| 9: [Field] e +# 144| 10: [Field] f +# 145| 11: [Field] g +# 146| 12: [Field] h +# 148| 13: [Field] i +# 149| 14: [Field] j +# 150| 15: [Field] k +# 151| 16: [Field] l +# 154| [Class] DisabledNullability +# 156| 5: [Field] f1 +# 157| 6: [IndexerProperty] P +# 157| 3: [Getter] get_P +# 157| 4: [ObjectCreation] object creation of type MyClass +# 158| 7: [Method] Fn +#-----| 2: (Parameters) +# 158| 0: [Parameter] p +# 159| 4: [BlockStmt] {...} +# 160| 0: [LocalVariableDeclStmt] ... ...; +# 160| 0: [LocalVariableDeclAndInitExpr] MyClass a = ... +# 160| 0: [ParameterAccess] access to parameter p +# 160| 1: [LocalVariableAccess] access to local variable a +# 161| 1: [ReturnStmt] return ...; +# 161| 0: [LocalVariableAccess] access to local variable a +# 165| [Struct] MyStruct +# 171| [Class] TestNullableFlowStates +# 173| 5: [Method] MaybeNull +# 175| 6: [Method] Check +#-----| 2: (Parameters) +# 175| 0: [Parameter] isNull +# 177| 7: [Method] Count +# 179| 8: [Method] LoopUnrolling +# 180| 4: [BlockStmt] {...} +# 181| 0: [LocalVariableDeclStmt] ... ...; +# 181| 0: [LocalVariableDeclAndInitExpr] String x = ... +# 181| 0: [MethodCall] call to method MaybeNull +# 181| 1: [LocalVariableAccess] access to local variable x +# 183| 1: [ExprStmt] ...; +# 183| 0: [MethodCall] call to method Check +# 183| 0: [LocalVariableAccess] access to local variable x +# 185| 2: [ForStmt] for (...;...;...) ... +# 185| -1: [LocalVariableDeclAndInitExpr] Int32 i = ... +# 185| 0: [IntLiteral] 0 +# 185| 1: [LocalVariableAccess] access to local variable i +# 185| 0: [LTExpr] ... < ... +# 185| 0: [LocalVariableAccess] access to local variable i +# 185| 1: [IntLiteral] 10 +# 185| 1: [PreIncrExpr] ++... +# 185| 0: [LocalVariableAccess] access to local variable i +# 186| 2: [BlockStmt] {...} +# 187| 0: [ExprStmt] ...; +# 187| 0: [AssignExpr] ... = ... +# 187| 0: [StringLiteral] "not null any more" +# 187| 1: [LocalVariableAccess] access to local variable x +# 190| 3: [ExprStmt] ...; +# 190| 0: [MethodCall] call to method Check +# 190| 0: [LocalVariableAccess] access to local variable x +# 193| 9: [Method] ExceptionFlow +# 194| 4: [BlockStmt] {...} +# 195| 0: [LocalVariableDeclStmt] ... ...; +# 195| 0: [LocalVariableDeclAndInitExpr] String y = ... +# 195| 0: [MethodCall] call to method MaybeNull +# 195| 1: [LocalVariableAccess] access to local variable y +# 197| 1: [TryStmt] try {...} ... +# 202| -1: [BlockStmt] {...} +# 203| 0: [ExprStmt] ...; +# 203| 0: [AssignExpr] ... = ... +# 203| 0: [StringLiteral] "not null" +# 203| 1: [LocalVariableAccess] access to local variable y +# 198| 0: [BlockStmt] {...} +# 199| 0: [ThrowStmt] throw ...; +# 199| 0: [ObjectCreation] object creation of type ArgumentException +# 206| 2: [ExprStmt] ...; +# 206| 0: [MethodCall] call to method Check +# 206| 0: [LocalVariableAccess] access to local variable y +# 209| 10: [Method] InvocationTest +#-----| 2: (Parameters) +# 209| 0: [Parameter] o +# 210| 4: [BlockStmt] {...} +# 211| 0: [LocalVariableDeclStmt] ... ...; +# 211| 0: [LocalVariableDeclAndInitExpr] Type t = ... +# 211| 0: [MethodCall] call to method GetType +# 211| -1: [ParameterAccess] access to parameter o +# 211| 1: [LocalVariableAccess] access to local variable t +# 212| 1: [ReturnStmt] return ...; +# 212| 0: [MethodCall] call to method ToString +# 212| -1: [LocalVariableAccess] access to local variable t +# 215| 11: [Method] ElementTest +#-----| 2: (Parameters) +# 215| 0: [Parameter] list +# 216| 4: [BlockStmt] {...} +# 217| 0: [LocalVariableDeclStmt] ... ...; +# 217| 0: [LocalVariableDeclAndInitExpr] String a = ... +# 217| 0: [FieldAccess] access to field Field +# 217| -1: [MethodCall] call to method GetSelf +# 217| 1: [LocalVariableAccess] access to local variable a +# 218| 1: [LocalVariableDeclStmt] ... ...; +# 218| 0: [LocalVariableDeclAndInitExpr] String b = ... +# 218| 0: [IndexerCall] access to indexer +# 218| -1: [ParameterAccess] access to parameter list +# 218| 0: [IntLiteral] 0 +# 218| 1: [LocalVariableAccess] access to local variable b +# 219| 2: [LocalVariableDeclStmt] ... ...; +# 219| 0: [LocalVariableDeclAndInitExpr] String c = ... +# 219| 0: [IndexerCall] access to indexer +# 219| -1: [ParameterAccess] access to parameter list +# 219| 0: [IntLiteral] 0 +# 219| 1: [LocalVariableAccess] access to local variable c +# 220| 3: [LocalVariableDeclStmt] ... ...; +# 220| 0: [LocalVariableDeclAndInitExpr] String d = ... +# 220| 0: [FieldAccess] access to field Field +# 220| -1: [MethodCall] call to method GetSelf +# 220| 1: [LocalVariableAccess] access to local variable d +# 223| 12: [Method] GetSelf +# 225| 13: [Field] Field +StaticLocalFunctions.cs: +# 5| [Class] StaticLocalFunctions +# 7| 5: [Method] Fn +#-----| 2: (Parameters) +# 7| 0: [Parameter] x +# 8| 4: [BlockStmt] {...} +# 9| 0: [LocalFunctionStmt] I(...) +# 9| 0: [LocalFunction] I +#-----| 2: (Parameters) +# 9| 0: [Parameter] y +# 9| 4: [ParameterAccess] access to parameter y +# 10| 1: [LocalFunctionStmt] J(...) +# 10| 0: [LocalFunction] J +#-----| 2: (Parameters) +# 10| 0: [Parameter] y +# 10| 4: [AddExpr] ... + ... +# 10| 0: [ParameterAccess] access to parameter x +# 10| 1: [ParameterAccess] access to parameter y +# 11| 2: [ReturnStmt] return ...; +# 11| 0: [AddExpr] ... + ... +# 11| 0: [LocalFunctionCall] call to local function I +# 11| -1: [LocalFunctionAccess] access to local function I +# 11| 0: [ParameterAccess] access to parameter x +# 11| 1: [LocalFunctionCall] call to local function J +# 11| -1: [LocalFunctionAccess] access to local function J +# 11| 0: [ParameterAccess] access to parameter x +UnmanagedGenericStructs.cs: +# 3| [Struct] S<,> +#-----| 1: (Type parameters) +# 3| 0: [TypeParameter] T +# 3| 1: [TypeParameter] U +# 5| 5: [Field] id +# 6| 6: [Field] value1 +# 7| 7: [Field] value2 +UsingDeclarations.cs: +# 4| [Class] UsingDeclarations +# 6| 5: [Method] TestUsingDeclarations +# 7| 4: [BlockStmt] {...} +# 8| 0: [UsingDeclStmt] using ... ...; +# 8| 0: [LocalVariableDeclAndInitExpr] FileStream file1 = ... +# 8| 0: [ObjectCreation] object creation of type FileStream +# 8| 0: [StringLiteral] "..." +# 8| 1: [MemberConstantAccess] access to constant Open +# 8| -1: [TypeAccess] access to type FileMode +# 8| 1: [LocalVariableAccess] access to local variable file1 +# 8| 1: [LocalVariableDeclAndInitExpr] FileStream file2 = ... +# 8| 0: [ObjectCreation] object creation of type FileStream +# 8| 0: [StringLiteral] "..." +# 8| 1: [MemberConstantAccess] access to constant Open +# 8| -1: [TypeAccess] access to type FileMode +# 8| 1: [LocalVariableAccess] access to local variable file2 +# 10| 1: [UsingBlockStmt] using (...) {...} +# 10| -2: [LocalVariableDeclAndInitExpr] FileStream file4 = ... +# 10| 0: [ObjectCreation] object creation of type FileStream +# 10| 0: [StringLiteral] "..." +# 10| 1: [MemberConstantAccess] access to constant Open +# 10| -1: [TypeAccess] access to type FileMode +# 10| 1: [LocalVariableAccess] access to local variable file4 +# 10| -1: [LocalVariableDeclAndInitExpr] FileStream file3 = ... +# 10| 0: [ObjectCreation] object creation of type FileStream +# 10| 0: [StringLiteral] "..." +# 10| 1: [MemberConstantAccess] access to constant Open +# 10| -1: [TypeAccess] access to type FileMode +# 10| 1: [LocalVariableAccess] access to local variable file3 +# 11| 1: [BlockStmt] {...} +# 14| 2: [UsingBlockStmt] using (...) {...} +# 14| 0: [ObjectCreation] object creation of type FileStream +# 14| 0: [StringLiteral] "..." +# 14| 1: [MemberConstantAccess] access to constant Open +# 14| -1: [TypeAccess] access to type FileMode +# 15| 1: [EmptyStmt] ; +patterns.cs: +# 3| [Class] Patterns +# 5| 5: [Method] IsPatterns +# 6| 4: [BlockStmt] {...} +# 7| 0: [LocalVariableDeclStmt] ... ...; +# 7| 0: [LocalVariableDeclAndInitExpr] Object o = ... +# 7| 0: [CastExpr] (...) ... +# 7| 0: [ObjectCreation] object creation of type MyStruct +# 7| -1: [ObjectInitializer] { ..., ... } +# 7| 0: [MemberInitializer] ... = ... +# 7| 0: [IntLiteral] 2 +# 7| 1: [FieldAccess] access to field X +# 7| 1: [LocalVariableAccess] access to local variable o +# 9| 1: [IfStmt] if (...) ... +# 9| 0: [IsExpr] ... is ... +# 9| 0: [LocalVariableAccess] access to local variable o +# 9| 1: [VariablePatternExpr] MyStruct ms1 +# 10| 1: [BlockStmt] {...} +# 13| 2: [IfStmt] if (...) ... +# 13| 0: [LogicalAndExpr] ... && ... +# 13| 0: [LogicalAndExpr] ... && ... +# 13| 0: [IsExpr] ... is ... +# 13| 0: [LocalVariableAccess] access to local variable o +# 13| 1: [RecursivePatternExpr] { ... } +# 13| 0: [LocalVariableDeclExpr] MyStruct s +# 13| 1: [TypeAccess] access to type MyStruct +# 13| 3: [PropertyPatternExpr] { ... } +# 13| 0: [LabeledPatternExpr,VariablePatternExpr] Int32 x +# 13| 1: [LTExpr] ... < ... +# 13| 0: [LocalVariableAccess] access to local variable x +# 13| 1: [IntLiteral] 4 +# 13| 1: [LTExpr] ... < ... +# 13| 0: [PropertyCall] access to property Y +# 13| -1: [LocalVariableAccess] access to local variable s +# 13| 1: [IntLiteral] 2 +# 14| 1: [BlockStmt] {...} +# 17| 3: [IfStmt] if (...) ... +# 17| 0: [IsExpr] ... is ... +# 17| 0: [LocalVariableAccess] access to local variable o +# 17| 1: [RecursivePatternExpr] { ... } +# 17| 0: [LocalVariableDeclExpr] Object p +# 17| 3: [PropertyPatternExpr] { ... } +# 18| 1: [BlockStmt] {...} +# 22| 4: [IfStmt] if (...) ... +# 22| 0: [IsExpr] ... is ... +# 22| 0: [LocalVariableAccess] access to local variable o +# 22| 1: [RecursivePatternExpr] { ... } +# 22| 1: [TypeAccess] access to type MyStruct +# 22| 3: [PropertyPatternExpr] { ... } +# 22| 0: [ConstantPatternExpr,IntLiteral,LabeledPatternExpr] 12 +# 22| 1: [LabeledPatternExpr,RecursivePatternExpr] { ... } +# 22| 3: [PropertyPatternExpr] { ... } +# 22| 0: [LabeledPatternExpr,VariablePatternExpr] Int32 subX +# 23| 1: [BlockStmt] {...} +# 27| 5: [IfStmt] if (...) ... +# 27| 0: [IsExpr] ... is ... +# 27| 0: [LocalVariableAccess] access to local variable o +# 27| 1: [RecursivePatternExpr] { ... } +# 27| 1: [TypeAccess] access to type MyStruct +# 27| 3: [PropertyPatternExpr] { ... } +# 27| 0: [ConstantPatternExpr,IntLiteral,LabeledPatternExpr] 12 +# 27| 1: [LabeledPatternExpr,RecursivePatternExpr] { ... } +# 27| 0: [LocalVariableDeclExpr] MyStruct ms +# 27| 1: [TypeAccess] access to type MyStruct +# 27| 3: [PropertyPatternExpr] { ... } +# 27| 0: [DiscardPatternExpr,LabeledPatternExpr] _ +# 28| 1: [BlockStmt] {...} +# 32| 6: [Method] SwitchStatements +# 33| 4: [BlockStmt] {...} +# 34| 0: [LocalVariableDeclStmt] ... ...; +# 34| 0: [LocalVariableDeclAndInitExpr] MyStruct s = ... +# 34| 0: [ObjectCreation] object creation of type MyStruct +# 34| -1: [ObjectInitializer] { ..., ... } +# 34| 0: [MemberInitializer] ... = ... +# 34| 0: [IntLiteral] 0 +# 34| 1: [FieldAccess] access to field X +# 34| 1: [LocalVariableAccess] access to local variable s +# 36| 1: [SwitchStmt] switch (...) {...} +# 36| 0: [LocalVariableAccess] access to local variable s +# 38| 0: [CaseStmt] case ...: +# 38| 0: [VariablePatternExpr] MyStruct ms1 +# 38| 1: [EQExpr] ... == ... +# 38| 0: [FieldAccess] access to field X +# 38| -1: [LocalVariableAccess] access to local variable ms1 +# 38| 1: [IntLiteral] 10 +# 39| 1: [ExprStmt] ...; +# 39| 0: [MethodCall] call to method WriteLine +# 39| -1: [TypeAccess] access to type Console +# 39| 0: [StringLiteral] "Hit the breakpoint" +# 40| 2: [BreakStmt] break; +# 41| 3: [CaseStmt] case ...: +# 41| 0: [VariablePatternExpr] MyStruct ms2 +# 41| 1: [LTExpr] ... < ... +# 41| 0: [FieldAccess] access to field X +# 41| -1: [LocalVariableAccess] access to local variable ms2 +# 41| 1: [IntLiteral] 10 +# 42| 4: [ExprStmt] ...; +# 42| 0: [MethodCall] call to method WriteLine +# 42| -1: [TypeAccess] access to type Console +# 42| 0: [StringLiteral] "Missed the breakpoint" +# 43| 5: [BreakStmt] break; +# 46| 2: [SwitchStmt] switch (...) {...} +# 46| 0: [LocalVariableAccess] access to local variable s +# 48| 0: [CaseStmt] case ...: +# 48| 0: [RecursivePatternExpr] { ... } +# 48| 1: [TypeAccess] access to type MyStruct +# 48| 3: [PropertyPatternExpr] { ... } +# 48| 0: [LabeledPatternExpr,VariablePatternExpr] Int32 x +# 48| 1: [GTExpr] ... > ... +# 48| 0: [LocalVariableAccess] access to local variable x +# 48| 1: [IntLiteral] 2 +# 49| 1: [ExprStmt] ...; +# 49| 0: [MethodCall] call to method WriteLine +# 49| -1: [TypeAccess] access to type Console +# 49| 0: [LocalVariableAccess] access to local variable x +# 50| 2: [BreakStmt] break; +# 51| 3: [CaseStmt] case ...: +# 51| 0: [RecursivePatternExpr] { ... } +# 51| 0: [LocalVariableDeclExpr] MyStruct ms +# 51| 1: [TypeAccess] access to type MyStruct +# 51| 3: [PropertyPatternExpr] { ... } +# 51| 0: [ConstantPatternExpr,IntLiteral,LabeledPatternExpr] 10 +# 52| 4: [ExprStmt] ...; +# 52| 0: [MethodCall] call to method WriteLine +# 52| -1: [TypeAccess] access to type Console +# 52| 0: [StringLiteral] "Hit the breakpoint" +# 53| 5: [BreakStmt] break; +# 54| 6: [CaseStmt] case ...: +# 54| 0: [RecursivePatternExpr] { ... } +# 54| 3: [PropertyPatternExpr] { ... } +# 54| 0: [LabeledPatternExpr,VariablePatternExpr] Int32 x2 +# 54| 1: [GTExpr] ... > ... +# 54| 0: [LocalVariableAccess] access to local variable x2 +# 54| 1: [IntLiteral] 2 +# 55| 7: [ExprStmt] ...; +# 55| 0: [MethodCall] call to method WriteLine +# 55| -1: [TypeAccess] access to type Console +# 55| 0: [LocalVariableAccess] access to local variable x2 +# 56| 8: [BreakStmt] break; +# 57| 9: [CaseStmt] case ...: +# 57| 0: [RecursivePatternExpr] { ... } +# 57| 2: [PositionalPatternExpr] ( ... ) +# 57| 0: [ConstantPatternExpr,IntLiteral] 1 +# 57| 1: [ConstantPatternExpr,IntLiteral] 2 +# 58| 10: [BreakStmt] break; +# 59| 11: [CaseStmt] case ...: +# 59| 0: [TupleExpr] (..., ...) +# 59| 0: [LocalVariableDeclExpr] Int32 x +# 59| 1: [LocalVariableDeclExpr] Int32 y +# 60| 12: [BreakStmt] break; +# 61| 13: [DefaultCase] default: +# 62| 14: [BreakStmt] break; +# 65| 3: [SwitchStmt] switch (...) {...} +# 65| 0: [LocalVariableAccess] access to local variable s +# 67| 0: [CaseStmt] case ...: +# 67| 0: [RecursivePatternExpr] { ... } +# 67| 1: [TypeAccess] access to type MyStruct +# 67| 3: [PropertyPatternExpr] { ... } +# 67| 0: [LabeledPatternExpr,VariablePatternExpr] Int32 x +# 67| 1: [GTExpr] ... > ... +# 67| 0: [LocalVariableAccess] access to local variable x +# 67| 1: [IntLiteral] 2 +# 68| 1: [ExprStmt] ...; +# 68| 0: [MethodCall] call to method WriteLine +# 68| -1: [TypeAccess] access to type Console +# 68| 0: [LocalVariableAccess] access to local variable x +# 69| 2: [BreakStmt] break; +# 70| 3: [CaseStmt] case ...: +# 70| 0: [RecursivePatternExpr] { ... } +# 70| 0: [LocalVariableDeclExpr] MyStruct ms +# 70| 1: [TypeAccess] access to type MyStruct +# 70| 3: [PropertyPatternExpr] { ... } +# 70| 0: [ConstantPatternExpr,IntLiteral,LabeledPatternExpr] 10 +# 70| 1: [EQExpr] ... == ... +# 70| 0: [FieldAccess] access to field X +# 70| -1: [LocalVariableAccess] access to local variable s +# 70| 1: [IntLiteral] 0 +# 71| 4: [ExprStmt] ...; +# 71| 0: [MethodCall] call to method WriteLine +# 71| -1: [TypeAccess] access to type Console +# 71| 0: [StringLiteral] "Hit the breakpoint" +# 72| 5: [BreakStmt] break; +# 76| 4: [SwitchStmt] switch (...) {...} +# 76| 0: [ObjectCreation] object creation of type Object +# 78| 0: [CaseStmt] case ...: +# 78| 0: [RecursivePatternExpr] { ... } +# 78| 2: [PositionalPatternExpr] ( ... ) +# 78| 0: [VariablePatternExpr] Int32 x +# 78| 1: [VariablePatternExpr] Single y +# 78| 1: [LTExpr] ... < ... +# 78| 0: [CastExpr] (...) ... +# 78| 0: [LocalVariableAccess] access to local variable x +# 78| 1: [LocalVariableAccess] access to local variable y +# 79| 1: [BreakStmt] break; +# 80| 2: [CaseStmt] case ...: +# 80| 0: [RecursivePatternExpr] { ... } +# 80| 2: [PositionalPatternExpr] ( ... ) +# 81| 3: [BreakStmt] break; +# 82| 4: [CaseStmt] case ...: +# 82| 0: [RecursivePatternExpr] { ... } +# 82| 3: [PropertyPatternExpr] { ... } +# 83| 5: [BreakStmt] break; +# 86| 5: [SwitchStmt] switch (...) {...} +# 86| 0: [TupleExpr] (..., ...) +# 86| 0: [IntLiteral] 1 +# 86| 1: [IntLiteral] 2 +# 88| 0: [CaseStmt] case ...: +# 88| 0: [RecursivePatternExpr] { ... } +# 88| 2: [PositionalPatternExpr] ( ... ) +# 88| 0: [ConstantPatternExpr,IntLiteral] 1 +# 88| 1: [ConstantPatternExpr,IntLiteral] 2 +# 88| 1: [BreakStmt] break; +# 91| 6: [SwitchStmt] switch (...) {...} +# 91| 0: [TupleExpr] (..., ...) +# 91| 0: [IntLiteral] 1 +# 91| 1: [IntLiteral] 2 +# 93| 0: [CaseStmt] case ...: +# 93| 0: [RecursivePatternExpr] { ... } +# 93| 2: [PositionalPatternExpr] ( ... ) +# 93| 0: [ConstantPatternExpr,IntLiteral] 1 +# 93| 1: [VariablePatternExpr] Int32 x +# 93| 1: [BreakStmt] break; +# 94| 2: [CaseStmt] case ...: +# 94| 0: [RecursivePatternExpr] { ... } +# 94| 2: [PositionalPatternExpr] ( ... ) +# 94| 0: [ConstantPatternExpr,IntLiteral] 2 +# 94| 1: [DiscardPatternExpr] _ +# 94| 3: [BreakStmt] break; +# 98| 7: [Method] Expressions +#-----| 2: (Parameters) +# 98| 0: [Parameter] x +# 99| 4: [BlockStmt] {...} +# 100| 0: [LocalVariableDeclStmt] ... ...; +# 100| 0: [LocalVariableDeclAndInitExpr] String size = ... +# 100| 0: [SwitchExpr] ... switch { ... } +# 100| -1: [ParameterAccess] access to parameter x +# 101| 0: [SwitchCaseExpr] ... => ... +# 101| 0: [VariablePatternExpr] Int32 y +# 101| 1: [GTExpr] ... > ... +# 101| 0: [LocalVariableAccess] access to local variable y +# 101| 1: [IntLiteral] 10 +# 101| 2: [StringLiteral] "large" +# 102| 1: [SwitchCaseExpr] ... => ... +# 102| 0: [DiscardPatternExpr] _ +# 102| 2: [StringLiteral] "small" +# 100| 1: [LocalVariableAccess] access to local variable size +# 105| 1: [LocalVariableDeclStmt] ... ...; +# 105| 0: [LocalVariableDeclAndInitExpr] Int32 x0 = ... +# 105| 0: [IntLiteral] 0 +# 105| 1: [LocalVariableAccess] access to local variable x0 +# 105| 1: [LocalVariableDeclAndInitExpr] Int32 y0 = ... +# 105| 0: [IntLiteral] 0 +# 105| 1: [LocalVariableAccess] access to local variable y0 +# 108| 2: [ExprStmt] ...; +# 108| 0: [AssignExpr] ... = ... +# 108| 0: [SwitchExpr] ... switch { ... } +# 108| -1: [TupleExpr] (..., ...) +# 108| 0: [LocalVariableAccess] access to local variable x0 +# 108| 1: [LocalVariableAccess] access to local variable y0 +# 110| 0: [SwitchCaseExpr] ... => ... +# 110| 0: [RecursivePatternExpr] { ... } +# 110| 2: [PositionalPatternExpr] ( ... ) +# 110| 0: [ConstantPatternExpr,IntLiteral] 0 +# 110| 1: [ConstantPatternExpr,IntLiteral] 1 +# 110| 2: [TupleExpr] (..., ...) +# 110| 0: [IntLiteral] 1 +# 110| 1: [IntLiteral] 0 +# 111| 1: [SwitchCaseExpr] ... => ... +# 111| 0: [RecursivePatternExpr] { ... } +# 111| 2: [PositionalPatternExpr] ( ... ) +# 111| 0: [ConstantPatternExpr,IntLiteral] 1 +# 111| 1: [ConstantPatternExpr,IntLiteral] 0 +# 111| 2: [TupleExpr] (..., ...) +# 111| 0: [IntLiteral] 0 +# 111| 1: [IntLiteral] 1 +# 108| 1: [TupleExpr] (..., ...) +# 108| 0: [LocalVariableDeclExpr] Int32 x1 +# 108| 1: [LocalVariableDeclExpr] Int32 y1 +# 115| 3: [ExprStmt] ...; +# 115| 0: [AssignExpr] ... = ... +# 115| 0: [SwitchExpr] ... switch { ... } +# 115| -1: [TupleExpr] (..., ...) +# 115| 0: [LocalVariableAccess] access to local variable x0 +# 115| 1: [LocalVariableAccess] access to local variable y0 +# 117| 0: [SwitchCaseExpr] ... => ... +# 117| 0: [RecursivePatternExpr] { ... } +# 117| 2: [PositionalPatternExpr] ( ... ) +# 117| 0: [ConstantPatternExpr,IntLiteral] 0 +# 117| 1: [VariablePatternExpr] Int32 y2 +# 117| 2: [TupleExpr] (..., ...) +# 117| 0: [LocalVariableAccess] access to local variable y2 +# 117| 1: [IntLiteral] 0 +# 118| 1: [SwitchCaseExpr] ... => ... +# 118| 0: [RecursivePatternExpr] { ... } +# 118| 2: [PositionalPatternExpr] ( ... ) +# 118| 0: [VariablePatternExpr] Int32 x2 +# 118| 1: [ConstantPatternExpr,IntLiteral] 0 +# 118| 2: [TupleExpr] (..., ...) +# 118| 0: [IntLiteral] 0 +# 118| 1: [LocalVariableAccess] access to local variable x2 +# 119| 2: [SwitchCaseExpr] ... => ... +# 119| 0: [RecursivePatternExpr] { ... } +# 119| 2: [PositionalPatternExpr] ( ... ) +# 119| 0: [VariablePatternExpr] Int32 x2 +# 119| 1: [VariablePatternExpr] Int32 y2 +# 119| 2: [TupleExpr] (..., ...) +# 119| 0: [IntLiteral] 0 +# 119| 1: [IntLiteral] 0 +# 115| 1: [TupleExpr] (..., ...) +# 115| 0: [LocalVariableAccess] access to local variable x1 +# 115| 1: [LocalVariableAccess] access to local variable y1 +# 123| 8: [Method] Expressions2 +#-----| 2: (Parameters) +# 123| 0: [Parameter] o +# 124| 4: [BlockStmt] {...} +# 125| 0: [LocalVariableDeclStmt] ... ...; +# 125| 0: [LocalVariableDeclAndInitExpr] MyStruct s = ... +# 125| 0: [ObjectCreation] object creation of type MyStruct +# 125| -1: [ObjectInitializer] { ..., ... } +# 125| 0: [MemberInitializer] ... = ... +# 125| 0: [IntLiteral] 0 +# 125| 1: [FieldAccess] access to field X +# 125| 1: [LocalVariableAccess] access to local variable s +# 126| 1: [LocalVariableDeclStmt] ... ...; +# 126| 0: [LocalVariableDeclAndInitExpr] Int32 r = ... +# 126| 0: [SwitchExpr] ... switch { ... } +# 126| -1: [LocalVariableAccess] access to local variable s +# 128| 0: [SwitchCaseExpr] ... => ... +# 128| 0: [RecursivePatternExpr] { ... } +# 128| 1: [TypeAccess] access to type MyStruct +# 128| 3: [PropertyPatternExpr] { ... } +# 128| 0: [LabeledPatternExpr,VariablePatternExpr] Int32 x +# 128| 1: [GTExpr] ... > ... +# 128| 0: [LocalVariableAccess] access to local variable x +# 128| 1: [IntLiteral] 2 +# 128| 2: [IntLiteral] 0 +# 129| 1: [SwitchCaseExpr] ... => ... +# 129| 0: [RecursivePatternExpr] { ... } +# 129| 0: [LocalVariableDeclExpr] MyStruct ms +# 129| 1: [TypeAccess] access to type MyStruct +# 129| 3: [PropertyPatternExpr] { ... } +# 129| 0: [ConstantPatternExpr,IntLiteral,LabeledPatternExpr] 10 +# 129| 2: [IntLiteral] 1 +# 130| 2: [SwitchCaseExpr] ... => ... +# 130| 0: [RecursivePatternExpr] { ... } +# 130| 2: [PositionalPatternExpr] ( ... ) +# 130| 0: [ConstantPatternExpr,IntLiteral] 1 +# 130| 1: [ConstantPatternExpr,IntLiteral] 2 +# 130| 2: [IntLiteral] 2 +# 131| 3: [SwitchCaseExpr] ... => ... +# 131| 0: [TupleExpr] (..., ...) +# 131| 0: [LocalVariableDeclExpr] Int32 x +# 131| 1: [DiscardExpr] _ +# 131| 2: [IntLiteral] 3 +# 126| 1: [LocalVariableAccess] access to local variable r +# 134| 2: [TryStmt] try {...} ... +# 135| 0: [BlockStmt] {...} +# 136| 0: [ExprStmt] ...; +# 136| 0: [AssignExpr] ... = ... +# 136| 0: [SwitchExpr] ... switch { ... } +# 136| -1: [ParameterAccess] access to parameter o +# 138| 0: [SwitchCaseExpr] ... => ... +# 138| 0: [ConstantPatternExpr,IntLiteral] 1 +# 138| 2: [ThrowExpr] throw ... +# 138| 0: [ObjectCreation] object creation of type ArgumentException +# 139| 1: [SwitchCaseExpr] ... => ... +# 139| 0: [ConstantPatternExpr,IntLiteral] 2 +# 139| 2: [IntLiteral] 3 +# 140| 2: [SwitchCaseExpr] ... => ... +# 140| 0: [VariablePatternExpr] Object y +# 140| 1: [IsExpr] ... is ... +# 140| 0: [LocalVariableAccess] access to local variable y +# 140| 1: [RecursivePatternExpr] { ... } +# 140| 3: [PropertyPatternExpr] { ... } +# 140| 2: [IntLiteral] 4 +# 141| 3: [SwitchCaseExpr] ... => ... +# 141| 0: [TypeAccessPatternExpr] access to type String +# 141| 2: [IntLiteral] 5 +# 142| 4: [SwitchCaseExpr] ... => ... +# 142| 0: [RecursivePatternExpr] { ... } +# 142| 1: [TypeAccess] access to type MyStruct +# 142| 3: [PropertyPatternExpr] { ... } +# 142| 0: [ConstantPatternExpr,IntLiteral,LabeledPatternExpr] 10 +# 142| 2: [IntLiteral] 6 +# 136| 1: [LocalVariableAccess] access to local variable r +# 145| 1: [SpecificCatchClause] catch (...) {...} +# 145| 0: [LocalVariableDeclExpr] InvalidOperationException ex +# 146| 1: [BlockStmt] {...} +# 147| 0: [ExprStmt] ...; +# 147| 0: [MethodCall] call to method WriteLine +# 147| -1: [TypeAccess] access to type Console +# 147| 0: [StringLiteral] "Invalid operation" +# 151| 9: [Struct] MyStruct +# 153| 5: [Field] X +# 154| 6: [Property] Y +# 154| 3: [Getter] get_Y +# 154| 4: [IntLiteral] 10 +# 156| 7: [Property] S +# 156| 3: [Getter] get_S +# 156| 4: [ThisAccess] this access +# 158| 8: [Method] Deconstruct +#-----| 2: (Parameters) +# 158| 0: [Parameter] x +# 158| 1: [Parameter] y +# 159| 4: [BlockStmt] {...} +# 160| 0: [ExprStmt] ...; +# 160| 0: [AssignExpr] ... = ... +# 160| 0: [FieldAccess] access to field X +# 160| 1: [ParameterAccess] access to parameter x +# 161| 1: [ExprStmt] ...; +# 161| 0: [AssignExpr] ... = ... +# 161| 0: [PropertyCall] access to property Y +# 161| 1: [ParameterAccess] access to parameter y +# 164| 9: [Method] Deconstruct +# 165| 4: [BlockStmt] {...} +ranges.cs: +# 5| [Class] Ranges +# 7| 5: [Method] F +# 8| 4: [BlockStmt] {...} +# 9| 0: [LocalVariableDeclStmt] ... ...; +# 9| 0: [LocalVariableDeclAndInitExpr] Int32[] array = ... +# 9| 0: [ArrayCreation] array creation of type Int32[] +# 9| -1: [ArrayInitializer] { ..., ... } +# 9| 0: [IntLiteral] 1 +# 9| 1: [IntLiteral] 2 +# 9| 2: [IntLiteral] 3 +# 9| 3: [IntLiteral] 4 +# 9| 1: [LocalVariableAccess] access to local variable array +# 11| 1: [LocalVariableDeclStmt] ... ...; +# 11| 0: [LocalVariableDeclAndInitExpr] Int32[] slice1 = ... +# 11| 0: [ArrayAccess] access to array element +# 11| -1: [LocalVariableAccess] access to local variable array +# 11| 0: [RangeExpr] ... .. ... +# 11| 0: [OperatorCall] call to operator implicit conversion +# 11| 0: [IntLiteral] 1 +# 11| 1: [OperatorCall] call to operator implicit conversion +# 11| 0: [IntLiteral] 3 +# 11| 1: [LocalVariableAccess] access to local variable slice1 +# 12| 2: [LocalVariableDeclStmt] ... ...; +# 12| 0: [LocalVariableDeclAndInitExpr] Int32[] slice2 = ... +# 12| 0: [ArrayAccess] access to array element +# 12| -1: [LocalVariableAccess] access to local variable array +# 12| 0: [RangeExpr] ... .. ... +# 12| 0: [OperatorCall] call to operator implicit conversion +# 12| 0: [IntLiteral] 0 +# 12| 1: [IndexExpr] ^... +# 12| 0: [IntLiteral] 1 +# 12| 1: [LocalVariableAccess] access to local variable slice2 +# 13| 3: [LocalVariableDeclStmt] ... ...; +# 13| 0: [LocalVariableDeclAndInitExpr] Int32 x = ... +# 13| 0: [IntLiteral] 2 +# 13| 1: [LocalVariableAccess] access to local variable x +# 13| 1: [LocalVariableDeclAndInitExpr] Int32 y = ... +# 13| 0: [IntLiteral] 3 +# 13| 1: [LocalVariableAccess] access to local variable y +# 14| 4: [LocalVariableDeclStmt] ... ...; +# 14| 0: [LocalVariableDeclAndInitExpr] Int32[] slice3 = ... +# 14| 0: [ArrayAccess] access to array element +# 14| -1: [LocalVariableAccess] access to local variable array +# 14| 0: [RangeExpr] ... .. ... +# 14| 0: [OperatorCall] call to operator implicit conversion +# 14| 0: [LocalVariableAccess] access to local variable x +# 14| 1: [OperatorCall] call to operator implicit conversion +# 14| 0: [LocalVariableAccess] access to local variable y +# 14| 1: [LocalVariableAccess] access to local variable slice3 +# 15| 5: [LocalVariableDeclStmt] ... ...; +# 15| 0: [LocalVariableDeclAndInitExpr] Int32[] slice4 = ... +# 15| 0: [ArrayAccess] access to array element +# 15| -1: [LocalVariableAccess] access to local variable array +# 15| 0: [RangeExpr] ... .. ... +# 15| 1: [OperatorCall] call to operator implicit conversion +# 15| 0: [LocalVariableAccess] access to local variable y +# 15| 1: [LocalVariableAccess] access to local variable slice4 +# 16| 6: [LocalVariableDeclStmt] ... ...; +# 16| 0: [LocalVariableDeclAndInitExpr] Int32[] slice5 = ... +# 16| 0: [ArrayAccess] access to array element +# 16| -1: [LocalVariableAccess] access to local variable array +# 16| 0: [RangeExpr] ... .. ... +# 16| 0: [OperatorCall] call to operator implicit conversion +# 16| 0: [LocalVariableAccess] access to local variable x +# 16| 1: [LocalVariableAccess] access to local variable slice5 +# 17| 7: [LocalVariableDeclStmt] ... ...; +# 17| 0: [LocalVariableDeclAndInitExpr] Int32[] slice6 = ... +# 17| 0: [ArrayAccess] access to array element +# 17| -1: [LocalVariableAccess] access to local variable array +# 17| 0: [RangeExpr] ... .. ... +# 17| 1: [LocalVariableAccess] access to local variable slice6 +# 18| 8: [LocalVariableDeclStmt] ... ...; +# 18| 0: [LocalVariableDeclAndInitExpr] Int32[] slice7 = ... +# 18| 0: [ArrayAccess] access to array element +# 18| -1: [LocalVariableAccess] access to local variable array +# 18| 0: [RangeExpr] ... .. ... +# 18| 0: [IndexExpr] ^... +# 18| 0: [IntLiteral] 10 +# 18| 1: [IndexExpr] ^... +# 18| 0: [IntLiteral] 5 +# 18| 1: [LocalVariableAccess] access to local variable slice7 diff --git a/csharp/ql/test/library-tests/csharp8/PrintAst.qlref b/csharp/ql/test/library-tests/csharp8/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/csharp8/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/csharp8/ranges.cs b/csharp/ql/test/library-tests/csharp8/ranges.cs index 006e239f629b..e076b9ac4d2d 100644 --- a/csharp/ql/test/library-tests/csharp8/ranges.cs +++ b/csharp/ql/test/library-tests/csharp8/ranges.cs @@ -7,36 +7,14 @@ class Ranges void F() { var array = new int[] { 1, 2, 3, 4 }; - var array2 = new int[2, 3]; var slice1 = array[1..3]; var slice2 = array[0..^1]; - int x=2, y=3; + int x = 2, y = 3; var slice3 = array[x..y]; var slice4 = array[..y]; var slice5 = array[x..]; var slice6 = array[..]; var slice7 = array[^10..^5]; - var slice8 = array2[1..2, ..]; - } -} - -// These are temporary until qltest uses .NET Core 3.0. -namespace System -{ - public readonly struct Index - { - public Index(int value, bool fromEnd = false) { } - public static implicit operator Index(int value) => default(Index); - } - - public readonly struct Range - { - public Range(Index start, Index end) => throw null; - public static Range StartAt(System.Index start) => throw null; - public static Range EndAt(System.Index end) => throw null; - public static Range All => throw null; - public static Range Create(Index start, Index end) => throw null; - public static implicit operator int(Range r) => throw null; } } diff --git a/csharp/ql/test/library-tests/csharp8/ranges.expected b/csharp/ql/test/library-tests/csharp8/ranges.expected index 1e8411c6806f..914f8c82a357 100644 --- a/csharp/ql/test/library-tests/csharp8/ranges.expected +++ b/csharp/ql/test/library-tests/csharp8/ranges.expected @@ -1,28 +1,24 @@ indexes -| ranges.cs:13:31:13:32 | ^... | ranges.cs:13:32:13:32 | 1 | -| ranges.cs:19:28:19:30 | ^... | ranges.cs:19:29:19:30 | 10 | -| ranges.cs:19:33:19:34 | ^... | ranges.cs:19:34:19:34 | 5 | +| ranges.cs:12:31:12:32 | ^... | ranges.cs:12:32:12:32 | 1 | +| ranges.cs:18:28:18:30 | ^... | ranges.cs:18:29:18:30 | 10 | +| ranges.cs:18:33:18:34 | ^... | ranges.cs:18:34:18:34 | 5 | ranges -| ranges.cs:12:28:12:31 | ... .. ... | -| ranges.cs:13:28:13:32 | ... .. ... | -| ranges.cs:15:28:15:31 | ... .. ... | +| ranges.cs:11:28:11:31 | ... .. ... | +| ranges.cs:12:28:12:32 | ... .. ... | +| ranges.cs:14:28:14:31 | ... .. ... | +| ranges.cs:15:28:15:30 | ... .. ... | | ranges.cs:16:28:16:30 | ... .. ... | -| ranges.cs:17:28:17:30 | ... .. ... | -| ranges.cs:18:28:18:29 | ... .. ... | -| ranges.cs:19:28:19:34 | ... .. ... | -| ranges.cs:20:29:20:32 | ... .. ... | -| ranges.cs:20:35:20:36 | ... .. ... | +| ranges.cs:17:28:17:29 | ... .. ... | +| ranges.cs:18:28:18:34 | ... .. ... | rangeStart -| ranges.cs:12:28:12:31 | ... .. ... | ranges.cs:12:28:12:28 | 1 | -| ranges.cs:13:28:13:32 | ... .. ... | ranges.cs:13:28:13:28 | 0 | -| ranges.cs:15:28:15:31 | ... .. ... | ranges.cs:15:28:15:28 | access to local variable x | -| ranges.cs:17:28:17:30 | ... .. ... | ranges.cs:17:28:17:28 | access to local variable x | -| ranges.cs:19:28:19:34 | ... .. ... | ranges.cs:19:28:19:30 | ^... | -| ranges.cs:20:29:20:32 | ... .. ... | ranges.cs:20:29:20:29 | 1 | +| ranges.cs:11:28:11:31 | ... .. ... | ranges.cs:11:28:11:28 | 1 | +| ranges.cs:12:28:12:32 | ... .. ... | ranges.cs:12:28:12:28 | 0 | +| ranges.cs:14:28:14:31 | ... .. ... | ranges.cs:14:28:14:28 | access to local variable x | +| ranges.cs:16:28:16:30 | ... .. ... | ranges.cs:16:28:16:28 | access to local variable x | +| ranges.cs:18:28:18:34 | ... .. ... | ranges.cs:18:28:18:30 | ^... | rangeEnd -| ranges.cs:12:28:12:31 | ... .. ... | ranges.cs:12:31:12:31 | 3 | -| ranges.cs:13:28:13:32 | ... .. ... | ranges.cs:13:31:13:32 | ^... | -| ranges.cs:15:28:15:31 | ... .. ... | ranges.cs:15:31:15:31 | access to local variable y | -| ranges.cs:16:28:16:30 | ... .. ... | ranges.cs:16:30:16:30 | access to local variable y | -| ranges.cs:19:28:19:34 | ... .. ... | ranges.cs:19:33:19:34 | ^... | -| ranges.cs:20:29:20:32 | ... .. ... | ranges.cs:20:32:20:32 | 2 | +| ranges.cs:11:28:11:31 | ... .. ... | ranges.cs:11:31:11:31 | 3 | +| ranges.cs:12:28:12:32 | ... .. ... | ranges.cs:12:31:12:32 | ^... | +| ranges.cs:14:28:14:31 | ... .. ... | ranges.cs:14:31:14:31 | access to local variable y | +| ranges.cs:15:28:15:30 | ... .. ... | ranges.cs:15:30:15:30 | access to local variable y | +| ranges.cs:18:28:18:34 | ... .. ... | ranges.cs:18:33:18:34 | ^... | diff --git a/csharp/ql/test/library-tests/csharp8/switchCaseExprTypes.expected b/csharp/ql/test/library-tests/csharp8/switchCaseExprTypes.expected new file mode 100644 index 000000000000..06e2fd994c5a --- /dev/null +++ b/csharp/ql/test/library-tests/csharp8/switchCaseExprTypes.expected @@ -0,0 +1,16 @@ +| patterns.cs:101:34:101:40 | "large" | String | +| patterns.cs:102:18:102:24 | "small" | String | +| patterns.cs:110:22:110:26 | (..., ...) | (Int32,Int32) | +| patterns.cs:111:22:111:26 | (..., ...) | (Int32,Int32) | +| patterns.cs:117:27:117:33 | (..., ...) | (Int32,Int32) | +| patterns.cs:118:28:118:34 | (..., ...) | (Int32,Int32) | +| patterns.cs:119:33:119:38 | (..., ...) | (Int32,Int32) | +| patterns.cs:128:49:128:49 | 0 | Int32 | +| patterns.cs:129:38:129:38 | 1 | Int32 | +| patterns.cs:130:23:130:23 | 2 | Int32 | +| patterns.cs:131:27:131:27 | 3 | Int32 | +| patterns.cs:138:22:138:50 | throw ... | null | +| patterns.cs:139:22:139:22 | 3 | Int32 | +| patterns.cs:140:42:140:42 | 4 | Int32 | +| patterns.cs:141:29:141:29 | 5 | Int32 | +| patterns.cs:142:41:142:41 | 6 | Int32 | diff --git a/csharp/ql/test/library-tests/csharp8/switchCaseExprTypes.ql b/csharp/ql/test/library-tests/csharp8/switchCaseExprTypes.ql new file mode 100644 index 000000000000..a9ad01da2f18 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp8/switchCaseExprTypes.ql @@ -0,0 +1,4 @@ +import csharp + +from SwitchCaseExpr case +select case.getBody(), case.getType().toString() diff --git a/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.cs b/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.cs index db4cd4b643d4..948d0498983f 100644 --- a/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.cs @@ -161,9 +161,14 @@ public static void Sink(object o) { } - public void M() + public virtual void M(object o) { + Sink(o); + } + public static void CallM(A2 a2, object o) + { + a2.M(o); } public void Callsite(InterfaceB intF) @@ -172,28 +177,31 @@ public void Callsite(InterfaceB intF) // in both possible implementations of foo, this callsite is relevant // in IntA, it improves virtual dispatch, // and in IntB, it improves the dataflow analysis. - intF.Foo(b, new object(), false); + intF.Foo(b, new object(), false); // no flow to `Sink()` via `A2.M()`, but flow via `IntA.Foo()` + + CallM(b, new object()); // no flow to `Sink()` + CallM(this, new object()); // flow to `Sink()` } - private class B : A2 + public class B : A2 { - public void M() + public override void M(object o) { } } - private class IntA : InterfaceB + public class IntA : InterfaceB { public void Foo(A2 obj, object o, bool cond) { - obj.M(); + obj.M(o); Sink(o); } } - private class IntB : InterfaceB + public class IntB : InterfaceB { public void Foo(A2 obj, object o, bool cond) diff --git a/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.expected b/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.expected index 0a39a463c578..c17fa754c4fa 100644 --- a/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.expected @@ -26,8 +26,12 @@ edges | CallSensitivityFlow.cs:124:43:124:43 | o : Object | CallSensitivityFlow.cs:128:22:128:22 | access to parameter o | | CallSensitivityFlow.cs:133:44:133:44 | o : Object | CallSensitivityFlow.cs:137:22:137:22 | access to parameter o | | CallSensitivityFlow.cs:142:49:142:49 | o : Object | CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 | -| CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object : Object | CallSensitivityFlow.cs:189:40:189:40 | o : Object | -| CallSensitivityFlow.cs:189:40:189:40 | o : Object | CallSensitivityFlow.cs:192:18:192:18 | access to parameter o | +| CallSensitivityFlow.cs:164:34:164:34 | o : Object | CallSensitivityFlow.cs:166:14:166:14 | access to parameter o | +| CallSensitivityFlow.cs:169:44:169:44 | o : Object | CallSensitivityFlow.cs:171:14:171:14 | access to parameter o : Object | +| CallSensitivityFlow.cs:171:14:171:14 | access to parameter o : Object | CallSensitivityFlow.cs:164:34:164:34 | o : Object | +| CallSensitivityFlow.cs:180:21:180:32 | object creation of type Object : Object | CallSensitivityFlow.cs:197:40:197:40 | o : Object | +| CallSensitivityFlow.cs:183:21:183:32 | object creation of type Object : Object | CallSensitivityFlow.cs:169:44:169:44 | o : Object | +| CallSensitivityFlow.cs:197:40:197:40 | o : Object | CallSensitivityFlow.cs:200:18:200:18 | access to parameter o | nodes | CallSensitivityFlow.cs:19:39:19:39 | o : Object | semmle.label | o : Object | | CallSensitivityFlow.cs:23:18:23:18 | access to parameter o | semmle.label | access to parameter o | @@ -66,9 +70,14 @@ nodes | CallSensitivityFlow.cs:137:22:137:22 | access to parameter o | semmle.label | access to parameter o | | CallSensitivityFlow.cs:142:49:142:49 | o : Object | semmle.label | o : Object | | CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 | semmle.label | access to local variable o3 | -| CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | -| CallSensitivityFlow.cs:189:40:189:40 | o : Object | semmle.label | o : Object | -| CallSensitivityFlow.cs:192:18:192:18 | access to parameter o | semmle.label | access to parameter o | +| CallSensitivityFlow.cs:164:34:164:34 | o : Object | semmle.label | o : Object | +| CallSensitivityFlow.cs:166:14:166:14 | access to parameter o | semmle.label | access to parameter o | +| CallSensitivityFlow.cs:169:44:169:44 | o : Object | semmle.label | o : Object | +| CallSensitivityFlow.cs:171:14:171:14 | access to parameter o : Object | semmle.label | access to parameter o : Object | +| CallSensitivityFlow.cs:180:21:180:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| CallSensitivityFlow.cs:183:21:183:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| CallSensitivityFlow.cs:197:40:197:40 | o : Object | semmle.label | o : Object | +| CallSensitivityFlow.cs:200:18:200:18 | access to parameter o | semmle.label | access to parameter o | #select | CallSensitivityFlow.cs:78:24:78:35 | object creation of type Object : Object | CallSensitivityFlow.cs:78:24:78:35 | object creation of type Object : Object | CallSensitivityFlow.cs:23:18:23:18 | access to parameter o | $@ | CallSensitivityFlow.cs:23:18:23:18 | access to parameter o | access to parameter o | | CallSensitivityFlow.cs:79:25:79:36 | object creation of type Object : Object | CallSensitivityFlow.cs:79:25:79:36 | object creation of type Object : Object | CallSensitivityFlow.cs:31:18:31:18 | access to parameter o | $@ | CallSensitivityFlow.cs:31:18:31:18 | access to parameter o | access to parameter o | @@ -87,4 +96,5 @@ nodes | CallSensitivityFlow.cs:117:26:117:37 | object creation of type Object : Object | CallSensitivityFlow.cs:117:26:117:37 | object creation of type Object : Object | CallSensitivityFlow.cs:128:22:128:22 | access to parameter o | $@ | CallSensitivityFlow.cs:128:22:128:22 | access to parameter o | access to parameter o | | CallSensitivityFlow.cs:118:27:118:38 | object creation of type Object : Object | CallSensitivityFlow.cs:118:27:118:38 | object creation of type Object : Object | CallSensitivityFlow.cs:137:22:137:22 | access to parameter o | $@ | CallSensitivityFlow.cs:137:22:137:22 | access to parameter o | access to parameter o | | CallSensitivityFlow.cs:119:32:119:43 | object creation of type Object : Object | CallSensitivityFlow.cs:119:32:119:43 | object creation of type Object : Object | CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 | $@ | CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 | access to local variable o3 | -| CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object : Object | CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object : Object | CallSensitivityFlow.cs:192:18:192:18 | access to parameter o | $@ | CallSensitivityFlow.cs:192:18:192:18 | access to parameter o | access to parameter o | +| CallSensitivityFlow.cs:180:21:180:32 | object creation of type Object : Object | CallSensitivityFlow.cs:180:21:180:32 | object creation of type Object : Object | CallSensitivityFlow.cs:200:18:200:18 | access to parameter o | $@ | CallSensitivityFlow.cs:200:18:200:18 | access to parameter o | access to parameter o | +| CallSensitivityFlow.cs:183:21:183:32 | object creation of type Object : Object | CallSensitivityFlow.cs:183:21:183:32 | object creation of type Object : Object | CallSensitivityFlow.cs:166:14:166:14 | access to parameter o | $@ | CallSensitivityFlow.cs:166:14:166:14 | access to parameter o | access to parameter o | diff --git a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs index 3565ba0b6eae..5f1bf2a6731b 100644 --- a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs @@ -7,6 +7,8 @@ public class CollectionFlow { public class A { } + public A[] As; + public void ArrayInitializerFlow() { var a = new A(); @@ -25,6 +27,24 @@ public void ArrayInitializerNoFlow(A other) Sink(First(@as)); // no flow } + public void ArrayInitializerCSharp6Flow() + { + var a = new A(); + var c = new CollectionFlow() { As = { [0] = a } }; + Sink(c.As[0]); // flow + SinkElem(c.As); // flow + Sink(First(c.As)); // flow + } + + public void ArrayInitializerCSharp6NoFlow(A other) + { + var a = new A(); + var c = new CollectionFlow() { As = { [0] = other } }; + Sink(c.As[0]); // no flow + SinkElem(c.As); // no flow + Sink(First(c.As)); // no flow + } + public void ArrayAssignmentFlow() { var a = new A(); @@ -108,7 +128,7 @@ public void DictionaryAssignmentFlow() Sink(dict[0]); // flow SinkDictValue(dict); // flow Sink(DictIndexZero(dict)); // flow - Sink(DictFirstValue(dict)); // flow [MISSING] + Sink(DictFirstValue(dict)); // flow Sink(DictValuesFirst(dict)); // flow } @@ -130,7 +150,7 @@ public void DictionaryValueInitializerFlow() Sink(dict[0]); // flow SinkDictValue(dict); // flow Sink(DictIndexZero(dict)); // flow - Sink(DictFirstValue(dict)); // flow [MISSING] + Sink(DictFirstValue(dict)); // flow Sink(DictValuesFirst(dict)); // flow } @@ -144,14 +164,36 @@ public void DictionaryValueInitializerNoFlow(A other) Sink(DictValuesFirst(dict)); // no flow } + public void DictionaryValueInitializerCSharp6Flow() + { + var a = new A(); + var dict = new Dictionary() { [0] = a }; + Sink(dict[0]); // flow + SinkDictValue(dict); // flow + Sink(DictIndexZero(dict)); // flow + Sink(DictFirstValue(dict)); // flow + Sink(DictValuesFirst(dict)); // flow + } + + public void DictionaryValueInitializerCSharp6NoFlow(A other) + { + var a = new A(); + var dict = new Dictionary() { [0] = other }; + Sink(dict[0]); // no flow + SinkDictValue(dict); // no flow + Sink(DictIndexZero(dict)); // no flow + Sink(DictFirstValue(dict)); // no flow + Sink(DictValuesFirst(dict)); // no flow + } + public void DictionaryKeyInitializerFlow() { var a = new A(); var dict = new Dictionary() { { a, 0 } }; - Sink(dict.Keys.First()); // flow [MISSING] - SinkDictKey(dict); // flow [MISSING] - Sink(DictKeysFirst(dict)); // flow [MISSING] - Sink(DictFirstKey(dict)); // flow [MISSING] + Sink(dict.Keys.First()); // flow + SinkDictKey(dict); // flow + Sink(DictKeysFirst(dict)); // flow + Sink(DictFirstKey(dict)); // flow } public void DictionaryKeyInitializerNoFlow(A other) @@ -163,6 +205,25 @@ public void DictionaryKeyInitializerNoFlow(A other) Sink(DictFirstKey(dict)); // no flow } + public void DictionaryKeyInitializerCSharp6Flow() + { + var a = new A(); + var dict = new Dictionary() { [a] = 0 }; + Sink(dict.Keys.First()); // flow + SinkDictKey(dict); // flow + Sink(DictKeysFirst(dict)); // flow + Sink(DictFirstKey(dict)); // flow + } + + public void DictionaryKeyInitializerCSharp6NoFlow(A other) + { + var dict = new Dictionary() { [other] = 0 }; + Sink(dict.Keys.First()); // no flow + SinkDictKey(dict); // no flow + Sink(DictKeysFirst(dict)); // no flow + Sink(DictFirstKey(dict)); // no flow + } + public void ForeachFlow() { var a = new A(); @@ -202,7 +263,110 @@ public void ListGetEnumeratorFlow() list.Add(a); var enumerator = list.GetEnumerator(); while (enumerator.MoveNext()) - Sink(enumerator.Current); // flow [MISSING] + Sink(enumerator.Current); // flow + } + + public void ListGetEnumeratorNoFlow(A other) + { + var list = new List(); + list.Add(other); + var enumerator = list.GetEnumerator(); + while (enumerator.MoveNext()) + Sink(enumerator.Current); // no flow + } + + public void SelectFlow() + { + var a = new A(); + var list = new List>(); + list.Add(new KeyValuePair(a, 0)); + list.Select(kvp => + { + Sink(kvp.Key); // flow + return kvp.Value; + }); + } + + public void SelectNoFlow() + { + var a = new A(); + var list = new List>(); + list.Add(new KeyValuePair(a, 0)); + list.Select(kvp => + { + Sink(kvp.Value); // no flow + return kvp.Value; + }); + } + + void SetArray(A[] array, A element) => array[0] = element; + + public void ArraySetterFlow() + { + var a = new A(); + var @as = new A[1]; + SetArray(@as, a); + Sink(@as[0]); // flow + SinkElem(@as); // flow + Sink(First(@as)); // flow + } + + public void ArraySetterNoFlow(A other) + { + var a = new A(); + var @as = new A[1]; + SetArray(@as, other); + Sink(@as[0]); // no flow + SinkElem(@as); // no flow + Sink(First(@as)); // no flow + } + + void SetList(List list, A element) => list.Add(element); + + public void ListSetterFlow() + { + var a = new A(); + var list = new List(); + SetList(list, a); + Sink(list[0]); // flow + SinkListElem(list); // flow + Sink(ListFirst(list)); // flow + } + + public void ListSetterNoFlow(A other) + { + var list = new List(); + SetList(list, other); + Sink(list[0]); // no flow + SinkListElem(list); // no flow + Sink(ListFirst(list)); // no flow + } + + public void ParamsFlow() + { + SinkParams(new A()); // flow + SinkParams(null, new A()); // flow + SinkParams(null, new A(), null); // flow + SinkParams(new A[] { new A() }); // flow + } + + public void ParamsNoFlow(A other) + { + SinkParams(other); // no flow + SinkParams(null, other); // no flow + SinkParams(null, other, null); // no flow + SinkParams(new A[] { other }); // no flow + } + + public void ListAddClearNoFlow() + { + var a = new A(); + var list = new List(); + list.Add(a); + list.Clear(); + Sink(list[0]); // no flow + SinkListElem(list); // no flow + Sink(ListFirst(list)); // no flow } public static void Sink(T t) { } @@ -228,4 +392,6 @@ public static void Sink(T t) { } public static T DictKeysFirst(IDictionary dict) => dict.Keys.First(); public static T DictFirstKey(IDictionary dict) => dict.First().Key; + + public static void SinkParams(params T[] args) => Sink(args[0]); } diff --git a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected index c6cc298ea94b..3c27e96311bb 100644 --- a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected @@ -1,235 +1,421 @@ edges -| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:14:14:14:19 | access to array element | -| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:15:18:15:20 | access to local variable as : A[] | -| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:16:20:16:22 | access to local variable as : A[] | -| CollectionFlow.cs:15:18:15:20 | access to local variable as : A[] | CollectionFlow.cs:210:40:210:41 | ts : A[] | -| CollectionFlow.cs:16:20:16:22 | access to local variable as : A[] | CollectionFlow.cs:16:14:16:23 | call to method First | -| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:33:14:33:19 | access to array element | -| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:34:18:34:20 | access to local variable as : A[] | -| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:35:20:35:22 | access to local variable as : A[] | -| CollectionFlow.cs:34:18:34:20 | access to local variable as : A[] | CollectionFlow.cs:210:40:210:41 | ts : A[] | -| CollectionFlow.cs:35:20:35:22 | access to local variable as : A[] | CollectionFlow.cs:35:14:35:23 | call to method First | -| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:53:14:53:20 | access to indexer | -| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:54:22:54:25 | access to local variable list : List | -| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:55:24:55:27 | access to local variable list : List | -| CollectionFlow.cs:51:20:51:32 | object creation of type List : List | CollectionFlow.cs:53:14:53:20 | access to indexer | -| CollectionFlow.cs:51:20:51:32 | object creation of type List : List | CollectionFlow.cs:54:22:54:25 | access to local variable list : List | -| CollectionFlow.cs:51:20:51:32 | object creation of type List : List | CollectionFlow.cs:55:24:55:27 | access to local variable list : List | -| CollectionFlow.cs:54:22:54:25 | access to local variable list : List | CollectionFlow.cs:212:49:212:52 | list : List | -| CollectionFlow.cs:55:24:55:27 | access to local variable list : List | CollectionFlow.cs:55:14:55:28 | call to method ListFirst | -| CollectionFlow.cs:60:20:60:32 | object creation of type List : List | CollectionFlow.cs:62:14:62:20 | access to indexer | -| CollectionFlow.cs:60:20:60:32 | object creation of type List : List | CollectionFlow.cs:63:22:63:25 | access to local variable list : List | -| CollectionFlow.cs:60:20:60:32 | object creation of type List : List | CollectionFlow.cs:64:24:64:27 | access to local variable list : List | -| CollectionFlow.cs:63:22:63:25 | access to local variable list : List | CollectionFlow.cs:212:49:212:52 | list : List | -| CollectionFlow.cs:64:24:64:27 | access to local variable list : List | CollectionFlow.cs:64:14:64:28 | call to method ListFirst | -| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:71:14:71:20 | access to indexer | -| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:72:22:72:25 | access to local variable list : List | -| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:73:24:73:27 | access to local variable list : List | -| CollectionFlow.cs:70:20:70:38 | object creation of type List : List | CollectionFlow.cs:71:14:71:20 | access to indexer | -| CollectionFlow.cs:70:20:70:38 | object creation of type List : List | CollectionFlow.cs:72:22:72:25 | access to local variable list : List | -| CollectionFlow.cs:70:20:70:38 | object creation of type List : List | CollectionFlow.cs:73:24:73:27 | access to local variable list : List | -| CollectionFlow.cs:72:22:72:25 | access to local variable list : List | CollectionFlow.cs:212:49:212:52 | list : List | -| CollectionFlow.cs:73:24:73:27 | access to local variable list : List | CollectionFlow.cs:73:14:73:28 | call to method ListFirst | -| CollectionFlow.cs:78:20:78:42 | object creation of type List : List | CollectionFlow.cs:79:14:79:20 | access to indexer | -| CollectionFlow.cs:78:20:78:42 | object creation of type List : List | CollectionFlow.cs:80:22:80:25 | access to local variable list : List | -| CollectionFlow.cs:78:20:78:42 | object creation of type List : List | CollectionFlow.cs:81:24:81:27 | access to local variable list : List | -| CollectionFlow.cs:80:22:80:25 | access to local variable list : List | CollectionFlow.cs:212:49:212:52 | list : List | -| CollectionFlow.cs:81:24:81:27 | access to local variable list : List | CollectionFlow.cs:81:14:81:28 | call to method ListFirst | -| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:89:14:89:20 | access to indexer | -| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:90:22:90:25 | access to local variable list : List | -| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:91:24:91:27 | access to local variable list : List | -| CollectionFlow.cs:87:20:87:32 | object creation of type List : List | CollectionFlow.cs:89:14:89:20 | access to indexer | -| CollectionFlow.cs:87:20:87:32 | object creation of type List : List | CollectionFlow.cs:90:22:90:25 | access to local variable list : List | -| CollectionFlow.cs:87:20:87:32 | object creation of type List : List | CollectionFlow.cs:91:24:91:27 | access to local variable list : List | -| CollectionFlow.cs:90:22:90:25 | access to local variable list : List | CollectionFlow.cs:212:49:212:52 | list : List | -| CollectionFlow.cs:91:24:91:27 | access to local variable list : List | CollectionFlow.cs:91:14:91:28 | call to method ListFirst | -| CollectionFlow.cs:96:20:96:32 | object creation of type List : List | CollectionFlow.cs:98:14:98:20 | access to indexer | -| CollectionFlow.cs:96:20:96:32 | object creation of type List : List | CollectionFlow.cs:99:22:99:25 | access to local variable list : List | -| CollectionFlow.cs:96:20:96:32 | object creation of type List : List | CollectionFlow.cs:100:24:100:27 | access to local variable list : List | -| CollectionFlow.cs:99:22:99:25 | access to local variable list : List | CollectionFlow.cs:212:49:212:52 | list : List | -| CollectionFlow.cs:100:24:100:27 | access to local variable list : List | CollectionFlow.cs:100:14:100:28 | call to method ListFirst | -| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:108:14:108:20 | access to indexer | -| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:109:23:109:26 | access to local variable dict : Dictionary | -| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:110:28:110:31 | access to local variable dict : Dictionary | -| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:112:30:112:33 | access to local variable dict : Dictionary | -| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:108:14:108:20 | access to indexer | -| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:109:23:109:26 | access to local variable dict : Dictionary | -| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:110:28:110:31 | access to local variable dict : Dictionary | -| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:112:30:112:33 | access to local variable dict : Dictionary | -| CollectionFlow.cs:109:23:109:26 | access to local variable dict : Dictionary | CollectionFlow.cs:214:61:214:64 | dict : Dictionary | -| CollectionFlow.cs:110:28:110:31 | access to local variable dict : Dictionary | CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | -| CollectionFlow.cs:112:30:112:33 | access to local variable dict : Dictionary | CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | -| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:119:14:119:20 | access to indexer | -| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:120:23:120:26 | access to local variable dict : Dictionary | -| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:121:28:121:31 | access to local variable dict : Dictionary | -| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:123:30:123:33 | access to local variable dict : Dictionary | -| CollectionFlow.cs:120:23:120:26 | access to local variable dict : Dictionary | CollectionFlow.cs:214:61:214:64 | dict : Dictionary | -| CollectionFlow.cs:121:28:121:31 | access to local variable dict : Dictionary | CollectionFlow.cs:121:14:121:32 | call to method DictIndexZero | -| CollectionFlow.cs:123:30:123:33 | access to local variable dict : Dictionary | CollectionFlow.cs:123:14:123:34 | call to method DictValuesFirst | -| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:130:14:130:20 | access to indexer | -| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:131:23:131:26 | access to local variable dict : Dictionary | -| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:132:28:132:31 | access to local variable dict : Dictionary | -| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:134:30:134:33 | access to local variable dict : Dictionary | -| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:130:14:130:20 | access to indexer | -| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:131:23:131:26 | access to local variable dict : Dictionary | -| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:132:28:132:31 | access to local variable dict : Dictionary | -| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:134:30:134:33 | access to local variable dict : Dictionary | -| CollectionFlow.cs:131:23:131:26 | access to local variable dict : Dictionary | CollectionFlow.cs:214:61:214:64 | dict : Dictionary | -| CollectionFlow.cs:132:28:132:31 | access to local variable dict : Dictionary | CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | -| CollectionFlow.cs:134:30:134:33 | access to local variable dict : Dictionary | CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | -| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:140:14:140:20 | access to indexer | -| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:141:23:141:26 | access to local variable dict : Dictionary | -| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:142:28:142:31 | access to local variable dict : Dictionary | -| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:144:30:144:33 | access to local variable dict : Dictionary | -| CollectionFlow.cs:141:23:141:26 | access to local variable dict : Dictionary | CollectionFlow.cs:214:61:214:64 | dict : Dictionary | -| CollectionFlow.cs:142:28:142:31 | access to local variable dict : Dictionary | CollectionFlow.cs:142:14:142:32 | call to method DictIndexZero | -| CollectionFlow.cs:144:30:144:33 | access to local variable dict : Dictionary | CollectionFlow.cs:144:14:144:34 | call to method DictValuesFirst | -| CollectionFlow.cs:168:17:168:23 | object creation of type A : A | CollectionFlow.cs:171:18:171:18 | access to local variable x | -| CollectionFlow.cs:183:17:183:23 | object creation of type A : A | CollectionFlow.cs:187:18:187:35 | access to property Current | -| CollectionFlow.cs:210:40:210:41 | ts : A[] | CollectionFlow.cs:210:52:210:56 | access to array element | -| CollectionFlow.cs:212:49:212:52 | list : List | CollectionFlow.cs:212:63:212:69 | access to indexer | -| CollectionFlow.cs:214:61:214:64 | dict : Dictionary | CollectionFlow.cs:214:75:214:81 | access to indexer | +| CollectionFlow.cs:14:17:14:23 | object creation of type A : A | CollectionFlow.cs:15:27:15:27 | access to local variable a : A | +| CollectionFlow.cs:15:25:15:29 | { ..., ... } [[]] : A | CollectionFlow.cs:16:14:16:16 | access to local variable as [[]] : A | +| CollectionFlow.cs:15:25:15:29 | { ..., ... } [[]] : A | CollectionFlow.cs:17:18:17:20 | access to local variable as [[]] : A | +| CollectionFlow.cs:15:25:15:29 | { ..., ... } [[]] : A | CollectionFlow.cs:18:20:18:22 | access to local variable as [[]] : A | +| CollectionFlow.cs:15:27:15:27 | access to local variable a : A | CollectionFlow.cs:15:25:15:29 | { ..., ... } [[]] : A | +| CollectionFlow.cs:16:14:16:16 | access to local variable as [[]] : A | CollectionFlow.cs:16:14:16:19 | access to array element | +| CollectionFlow.cs:17:18:17:20 | access to local variable as [[]] : A | CollectionFlow.cs:374:40:374:41 | ts [[]] : A | +| CollectionFlow.cs:18:20:18:22 | access to local variable as [[]] : A | CollectionFlow.cs:18:14:18:23 | call to method First | +| CollectionFlow.cs:32:17:32:23 | object creation of type A : A | CollectionFlow.cs:33:53:33:53 | access to local variable a : A | +| CollectionFlow.cs:33:38:33:57 | { ..., ... } [As, []] : A | CollectionFlow.cs:34:14:34:14 | access to local variable c [As, []] : A | +| CollectionFlow.cs:33:38:33:57 | { ..., ... } [As, []] : A | CollectionFlow.cs:35:18:35:18 | access to local variable c [As, []] : A | +| CollectionFlow.cs:33:38:33:57 | { ..., ... } [As, []] : A | CollectionFlow.cs:36:20:36:20 | access to local variable c [As, []] : A | +| CollectionFlow.cs:33:45:33:55 | { ..., ... } [[]] : A | CollectionFlow.cs:33:38:33:57 | { ..., ... } [As, []] : A | +| CollectionFlow.cs:33:53:33:53 | access to local variable a : A | CollectionFlow.cs:33:45:33:55 | { ..., ... } [[]] : A | +| CollectionFlow.cs:34:14:34:14 | access to local variable c [As, []] : A | CollectionFlow.cs:34:14:34:17 | access to field As [[]] : A | +| CollectionFlow.cs:34:14:34:17 | access to field As [[]] : A | CollectionFlow.cs:34:14:34:20 | access to array element | +| CollectionFlow.cs:35:18:35:18 | access to local variable c [As, []] : A | CollectionFlow.cs:35:18:35:21 | access to field As [[]] : A | +| CollectionFlow.cs:35:18:35:21 | access to field As [[]] : A | CollectionFlow.cs:374:40:374:41 | ts [[]] : A | +| CollectionFlow.cs:36:20:36:20 | access to local variable c [As, []] : A | CollectionFlow.cs:36:20:36:23 | access to field As [[]] : A | +| CollectionFlow.cs:36:20:36:23 | access to field As [[]] : A | CollectionFlow.cs:36:14:36:24 | call to method First | +| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:52:18:52:18 | access to local variable a : A | +| CollectionFlow.cs:52:9:52:11 | [post] access to local variable as [[]] : A | CollectionFlow.cs:53:14:53:16 | access to local variable as [[]] : A | +| CollectionFlow.cs:52:9:52:11 | [post] access to local variable as [[]] : A | CollectionFlow.cs:54:18:54:20 | access to local variable as [[]] : A | +| CollectionFlow.cs:52:9:52:11 | [post] access to local variable as [[]] : A | CollectionFlow.cs:55:20:55:22 | access to local variable as [[]] : A | +| CollectionFlow.cs:52:18:52:18 | access to local variable a : A | CollectionFlow.cs:52:9:52:11 | [post] access to local variable as [[]] : A | +| CollectionFlow.cs:53:14:53:16 | access to local variable as [[]] : A | CollectionFlow.cs:53:14:53:19 | access to array element | +| CollectionFlow.cs:54:18:54:20 | access to local variable as [[]] : A | CollectionFlow.cs:374:40:374:41 | ts [[]] : A | +| CollectionFlow.cs:55:20:55:22 | access to local variable as [[]] : A | CollectionFlow.cs:55:14:55:23 | call to method First | +| CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:72:19:72:19 | access to local variable a : A | +| CollectionFlow.cs:72:9:72:12 | [post] access to local variable list [[]] : A | CollectionFlow.cs:73:14:73:17 | access to local variable list [[]] : A | +| CollectionFlow.cs:72:9:72:12 | [post] access to local variable list [[]] : A | CollectionFlow.cs:74:22:74:25 | access to local variable list [[]] : A | +| CollectionFlow.cs:72:9:72:12 | [post] access to local variable list [[]] : A | CollectionFlow.cs:75:24:75:27 | access to local variable list [[]] : A | +| CollectionFlow.cs:72:19:72:19 | access to local variable a : A | CollectionFlow.cs:72:9:72:12 | [post] access to local variable list [[]] : A | +| CollectionFlow.cs:73:14:73:17 | access to local variable list [[]] : A | CollectionFlow.cs:73:14:73:20 | access to indexer | +| CollectionFlow.cs:74:22:74:25 | access to local variable list [[]] : A | CollectionFlow.cs:376:49:376:52 | list [[]] : A | +| CollectionFlow.cs:75:24:75:27 | access to local variable list [[]] : A | CollectionFlow.cs:75:14:75:28 | call to method ListFirst | +| CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:90:36:90:36 | access to local variable a : A | +| CollectionFlow.cs:90:34:90:38 | { ..., ... } [[]] : A | CollectionFlow.cs:91:14:91:17 | access to local variable list [[]] : A | +| CollectionFlow.cs:90:34:90:38 | { ..., ... } [[]] : A | CollectionFlow.cs:92:22:92:25 | access to local variable list [[]] : A | +| CollectionFlow.cs:90:34:90:38 | { ..., ... } [[]] : A | CollectionFlow.cs:93:24:93:27 | access to local variable list [[]] : A | +| CollectionFlow.cs:90:36:90:36 | access to local variable a : A | CollectionFlow.cs:90:34:90:38 | { ..., ... } [[]] : A | +| CollectionFlow.cs:91:14:91:17 | access to local variable list [[]] : A | CollectionFlow.cs:91:14:91:20 | access to indexer | +| CollectionFlow.cs:92:22:92:25 | access to local variable list [[]] : A | CollectionFlow.cs:376:49:376:52 | list [[]] : A | +| CollectionFlow.cs:93:24:93:27 | access to local variable list [[]] : A | CollectionFlow.cs:93:14:93:28 | call to method ListFirst | +| CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:108:18:108:18 | access to local variable a : A | +| CollectionFlow.cs:108:9:108:12 | [post] access to local variable list [[]] : A | CollectionFlow.cs:109:14:109:17 | access to local variable list [[]] : A | +| CollectionFlow.cs:108:9:108:12 | [post] access to local variable list [[]] : A | CollectionFlow.cs:110:22:110:25 | access to local variable list [[]] : A | +| CollectionFlow.cs:108:9:108:12 | [post] access to local variable list [[]] : A | CollectionFlow.cs:111:24:111:27 | access to local variable list [[]] : A | +| CollectionFlow.cs:108:18:108:18 | access to local variable a : A | CollectionFlow.cs:108:9:108:12 | [post] access to local variable list [[]] : A | +| CollectionFlow.cs:109:14:109:17 | access to local variable list [[]] : A | CollectionFlow.cs:109:14:109:20 | access to indexer | +| CollectionFlow.cs:110:22:110:25 | access to local variable list [[]] : A | CollectionFlow.cs:376:49:376:52 | list [[]] : A | +| CollectionFlow.cs:111:24:111:27 | access to local variable list [[]] : A | CollectionFlow.cs:111:14:111:28 | call to method ListFirst | +| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:127:19:127:19 | access to local variable a : A | +| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] : A | CollectionFlow.cs:128:14:128:17 | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] : A | CollectionFlow.cs:129:23:129:26 | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] : A | CollectionFlow.cs:130:28:130:31 | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] : A | CollectionFlow.cs:131:29:131:32 | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] : A | CollectionFlow.cs:132:30:132:33 | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:127:19:127:19 | access to local variable a : A | CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] : A | +| CollectionFlow.cs:128:14:128:17 | access to local variable dict [[], Value] : A | CollectionFlow.cs:128:14:128:20 | access to indexer | +| CollectionFlow.cs:129:23:129:26 | access to local variable dict [[], Value] : A | CollectionFlow.cs:378:61:378:64 | dict [[], Value] : A | +| CollectionFlow.cs:130:28:130:31 | access to local variable dict [[], Value] : A | CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | +| CollectionFlow.cs:131:29:131:32 | access to local variable dict [[], Value] : A | CollectionFlow.cs:131:14:131:33 | call to method DictFirstValue | +| CollectionFlow.cs:132:30:132:33 | access to local variable dict [[], Value] : A | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | +| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:149:52:149:52 | access to local variable a : A | +| CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] : A | CollectionFlow.cs:150:14:150:17 | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] : A | CollectionFlow.cs:151:23:151:26 | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] : A | CollectionFlow.cs:152:28:152:31 | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] : A | CollectionFlow.cs:153:29:153:32 | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] : A | CollectionFlow.cs:154:30:154:33 | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:149:52:149:52 | access to local variable a : A | CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] : A | +| CollectionFlow.cs:150:14:150:17 | access to local variable dict [[], Value] : A | CollectionFlow.cs:150:14:150:20 | access to indexer | +| CollectionFlow.cs:151:23:151:26 | access to local variable dict [[], Value] : A | CollectionFlow.cs:378:61:378:64 | dict [[], Value] : A | +| CollectionFlow.cs:152:28:152:31 | access to local variable dict [[], Value] : A | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | +| CollectionFlow.cs:153:29:153:32 | access to local variable dict [[], Value] : A | CollectionFlow.cs:153:14:153:33 | call to method DictFirstValue | +| CollectionFlow.cs:154:30:154:33 | access to local variable dict [[], Value] : A | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | +| CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:170:53:170:53 | access to local variable a : A | +| CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] : A | CollectionFlow.cs:171:14:171:17 | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] : A | CollectionFlow.cs:172:23:172:26 | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] : A | CollectionFlow.cs:173:28:173:31 | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] : A | CollectionFlow.cs:174:29:174:32 | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] : A | CollectionFlow.cs:175:30:175:33 | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:170:53:170:53 | access to local variable a : A | CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] : A | +| CollectionFlow.cs:171:14:171:17 | access to local variable dict [[], Value] : A | CollectionFlow.cs:171:14:171:20 | access to indexer | +| CollectionFlow.cs:172:23:172:26 | access to local variable dict [[], Value] : A | CollectionFlow.cs:378:61:378:64 | dict [[], Value] : A | +| CollectionFlow.cs:173:28:173:31 | access to local variable dict [[], Value] : A | CollectionFlow.cs:173:14:173:32 | call to method DictIndexZero | +| CollectionFlow.cs:174:29:174:32 | access to local variable dict [[], Value] : A | CollectionFlow.cs:174:14:174:33 | call to method DictFirstValue | +| CollectionFlow.cs:175:30:175:33 | access to local variable dict [[], Value] : A | CollectionFlow.cs:175:14:175:34 | call to method DictValuesFirst | +| CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:192:49:192:49 | access to local variable a : A | +| CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] : A | CollectionFlow.cs:193:14:193:17 | access to local variable dict [[], Key] : A | +| CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] : A | CollectionFlow.cs:194:21:194:24 | access to local variable dict [[], Key] : A | +| CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] : A | CollectionFlow.cs:195:28:195:31 | access to local variable dict [[], Key] : A | +| CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] : A | CollectionFlow.cs:196:27:196:30 | access to local variable dict [[], Key] : A | +| CollectionFlow.cs:192:49:192:49 | access to local variable a : A | CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] : A | +| CollectionFlow.cs:193:14:193:17 | access to local variable dict [[], Key] : A | CollectionFlow.cs:193:14:193:22 | access to property Keys [[]] : A | +| CollectionFlow.cs:193:14:193:22 | access to property Keys [[]] : A | CollectionFlow.cs:193:14:193:30 | call to method First | +| CollectionFlow.cs:194:21:194:24 | access to local variable dict [[], Key] : A | CollectionFlow.cs:380:59:380:62 | dict [[], Key] : A | +| CollectionFlow.cs:195:28:195:31 | access to local variable dict [[], Key] : A | CollectionFlow.cs:195:14:195:32 | call to method DictKeysFirst | +| CollectionFlow.cs:196:27:196:30 | access to local variable dict [[], Key] : A | CollectionFlow.cs:196:14:196:31 | call to method DictFirstKey | +| CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:211:48:211:48 | access to local variable a : A | +| CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] : A | CollectionFlow.cs:212:14:212:17 | access to local variable dict [[], Key] : A | +| CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] : A | CollectionFlow.cs:213:21:213:24 | access to local variable dict [[], Key] : A | +| CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] : A | CollectionFlow.cs:214:28:214:31 | access to local variable dict [[], Key] : A | +| CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] : A | CollectionFlow.cs:215:27:215:30 | access to local variable dict [[], Key] : A | +| CollectionFlow.cs:211:48:211:48 | access to local variable a : A | CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] : A | +| CollectionFlow.cs:212:14:212:17 | access to local variable dict [[], Key] : A | CollectionFlow.cs:212:14:212:22 | access to property Keys [[]] : A | +| CollectionFlow.cs:212:14:212:22 | access to property Keys [[]] : A | CollectionFlow.cs:212:14:212:30 | call to method First | +| CollectionFlow.cs:213:21:213:24 | access to local variable dict [[], Key] : A | CollectionFlow.cs:380:59:380:62 | dict [[], Key] : A | +| CollectionFlow.cs:214:28:214:31 | access to local variable dict [[], Key] : A | CollectionFlow.cs:214:14:214:32 | call to method DictKeysFirst | +| CollectionFlow.cs:215:27:215:30 | access to local variable dict [[], Key] : A | CollectionFlow.cs:215:14:215:31 | call to method DictFirstKey | +| CollectionFlow.cs:229:17:229:23 | object creation of type A : A | CollectionFlow.cs:230:27:230:27 | access to local variable a : A | +| CollectionFlow.cs:230:25:230:29 | { ..., ... } [[]] : A | CollectionFlow.cs:231:27:231:29 | access to local variable as [[]] : A | +| CollectionFlow.cs:230:27:230:27 | access to local variable a : A | CollectionFlow.cs:230:25:230:29 | { ..., ... } [[]] : A | +| CollectionFlow.cs:231:22:231:22 | SSA def(x) : A | CollectionFlow.cs:232:18:232:18 | access to local variable x | +| CollectionFlow.cs:231:27:231:29 | access to local variable as [[]] : A | CollectionFlow.cs:231:22:231:22 | SSA def(x) : A | +| CollectionFlow.cs:244:17:244:23 | object creation of type A : A | CollectionFlow.cs:245:27:245:27 | access to local variable a : A | +| CollectionFlow.cs:245:25:245:29 | { ..., ... } [[]] : A | CollectionFlow.cs:246:26:246:28 | access to local variable as [[]] : A | +| CollectionFlow.cs:245:27:245:27 | access to local variable a : A | CollectionFlow.cs:245:25:245:29 | { ..., ... } [[]] : A | +| CollectionFlow.cs:246:26:246:28 | access to local variable as [[]] : A | CollectionFlow.cs:246:26:246:44 | call to method GetEnumerator [Current] : A | +| CollectionFlow.cs:246:26:246:44 | call to method GetEnumerator [Current] : A | CollectionFlow.cs:248:18:248:27 | access to local variable enumerator [Current] : A | +| CollectionFlow.cs:248:18:248:27 | access to local variable enumerator [Current] : A | CollectionFlow.cs:248:18:248:35 | access to property Current | +| CollectionFlow.cs:261:17:261:23 | object creation of type A : A | CollectionFlow.cs:263:18:263:18 | access to local variable a : A | +| CollectionFlow.cs:263:9:263:12 | [post] access to local variable list [[]] : A | CollectionFlow.cs:264:26:264:29 | access to local variable list [[]] : A | +| CollectionFlow.cs:263:18:263:18 | access to local variable a : A | CollectionFlow.cs:263:9:263:12 | [post] access to local variable list [[]] : A | +| CollectionFlow.cs:264:26:264:29 | access to local variable list [[]] : A | CollectionFlow.cs:264:26:264:45 | call to method GetEnumerator [Current] : A | +| CollectionFlow.cs:264:26:264:45 | call to method GetEnumerator [Current] : A | CollectionFlow.cs:266:18:266:27 | access to local variable enumerator [Current] : A | +| CollectionFlow.cs:266:18:266:27 | access to local variable enumerator [Current] : A | CollectionFlow.cs:266:18:266:35 | access to property Current | +| CollectionFlow.cs:280:17:280:23 | object creation of type A : A | CollectionFlow.cs:282:43:282:43 | access to local variable a : A | +| CollectionFlow.cs:282:9:282:12 | [post] access to local variable list [[], Key] : A | CollectionFlow.cs:283:9:283:12 | access to local variable list [[], Key] : A | +| CollectionFlow.cs:282:18:282:47 | object creation of type KeyValuePair [Key] : A | CollectionFlow.cs:282:9:282:12 | [post] access to local variable list [[], Key] : A | +| CollectionFlow.cs:282:43:282:43 | access to local variable a : A | CollectionFlow.cs:282:18:282:47 | object creation of type KeyValuePair [Key] : A | +| CollectionFlow.cs:283:9:283:12 | access to local variable list [[], Key] : A | CollectionFlow.cs:283:21:283:23 | kvp [Key] : A | +| CollectionFlow.cs:283:21:283:23 | kvp [Key] : A | CollectionFlow.cs:285:18:285:20 | access to parameter kvp [Key] : A | +| CollectionFlow.cs:285:18:285:20 | access to parameter kvp [Key] : A | CollectionFlow.cs:285:18:285:24 | access to property Key | +| CollectionFlow.cs:306:17:306:23 | object creation of type A : A | CollectionFlow.cs:308:23:308:23 | access to local variable a : A | +| CollectionFlow.cs:308:18:308:20 | [post] access to local variable as [[]] : A | CollectionFlow.cs:309:14:309:16 | access to local variable as [[]] : A | +| CollectionFlow.cs:308:18:308:20 | [post] access to local variable as [[]] : A | CollectionFlow.cs:310:18:310:20 | access to local variable as [[]] : A | +| CollectionFlow.cs:308:18:308:20 | [post] access to local variable as [[]] : A | CollectionFlow.cs:311:20:311:22 | access to local variable as [[]] : A | +| CollectionFlow.cs:308:23:308:23 | access to local variable a : A | CollectionFlow.cs:308:18:308:20 | [post] access to local variable as [[]] : A | +| CollectionFlow.cs:309:14:309:16 | access to local variable as [[]] : A | CollectionFlow.cs:309:14:309:19 | access to array element | +| CollectionFlow.cs:310:18:310:20 | access to local variable as [[]] : A | CollectionFlow.cs:374:40:374:41 | ts [[]] : A | +| CollectionFlow.cs:311:20:311:22 | access to local variable as [[]] : A | CollectionFlow.cs:311:14:311:23 | call to method First | +| CollectionFlow.cs:328:17:328:23 | object creation of type A : A | CollectionFlow.cs:330:23:330:23 | access to local variable a : A | +| CollectionFlow.cs:330:17:330:20 | [post] access to local variable list [[]] : A | CollectionFlow.cs:331:14:331:17 | access to local variable list [[]] : A | +| CollectionFlow.cs:330:17:330:20 | [post] access to local variable list [[]] : A | CollectionFlow.cs:332:22:332:25 | access to local variable list [[]] : A | +| CollectionFlow.cs:330:17:330:20 | [post] access to local variable list [[]] : A | CollectionFlow.cs:333:24:333:27 | access to local variable list [[]] : A | +| CollectionFlow.cs:330:23:330:23 | access to local variable a : A | CollectionFlow.cs:330:17:330:20 | [post] access to local variable list [[]] : A | +| CollectionFlow.cs:331:14:331:17 | access to local variable list [[]] : A | CollectionFlow.cs:331:14:331:20 | access to indexer | +| CollectionFlow.cs:332:22:332:25 | access to local variable list [[]] : A | CollectionFlow.cs:376:49:376:52 | list [[]] : A | +| CollectionFlow.cs:333:24:333:27 | access to local variable list [[]] : A | CollectionFlow.cs:333:14:333:28 | call to method ListFirst | +| CollectionFlow.cs:347:20:347:26 | object creation of type A : A | CollectionFlow.cs:396:49:396:52 | args [[]] : A | +| CollectionFlow.cs:348:26:348:32 | object creation of type A : A | CollectionFlow.cs:396:49:396:52 | args [[]] : A | +| CollectionFlow.cs:349:26:349:32 | object creation of type A : A | CollectionFlow.cs:396:49:396:52 | args [[]] : A | +| CollectionFlow.cs:350:20:350:38 | array creation of type A[] [[]] : A | CollectionFlow.cs:396:49:396:52 | args [[]] : A | +| CollectionFlow.cs:350:28:350:38 | { ..., ... } [[]] : A | CollectionFlow.cs:350:20:350:38 | array creation of type A[] [[]] : A | +| CollectionFlow.cs:350:30:350:36 | object creation of type A : A | CollectionFlow.cs:350:28:350:38 | { ..., ... } [[]] : A | +| CollectionFlow.cs:374:40:374:41 | ts [[]] : A | CollectionFlow.cs:374:52:374:53 | access to parameter ts [[]] : A | +| CollectionFlow.cs:374:40:374:41 | ts [[]] : A | CollectionFlow.cs:374:52:374:53 | access to parameter ts [[]] : A | +| CollectionFlow.cs:374:52:374:53 | access to parameter ts [[]] : A | CollectionFlow.cs:374:52:374:56 | access to array element | +| CollectionFlow.cs:374:52:374:53 | access to parameter ts [[]] : A | CollectionFlow.cs:374:52:374:56 | access to array element | +| CollectionFlow.cs:376:49:376:52 | list [[]] : A | CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | +| CollectionFlow.cs:376:49:376:52 | list [[]] : A | CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | +| CollectionFlow.cs:376:49:376:52 | list [[]] : A | CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | +| CollectionFlow.cs:376:49:376:52 | list [[]] : A | CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | +| CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | CollectionFlow.cs:376:63:376:69 | access to indexer | +| CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | CollectionFlow.cs:376:63:376:69 | access to indexer | +| CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | CollectionFlow.cs:376:63:376:69 | access to indexer | +| CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | CollectionFlow.cs:376:63:376:69 | access to indexer | +| CollectionFlow.cs:378:61:378:64 | dict [[], Value] : A | CollectionFlow.cs:378:75:378:78 | access to parameter dict [[], Value] : A | +| CollectionFlow.cs:378:75:378:78 | access to parameter dict [[], Value] : A | CollectionFlow.cs:378:75:378:81 | access to indexer | +| CollectionFlow.cs:380:59:380:62 | dict [[], Key] : A | CollectionFlow.cs:380:73:380:76 | access to parameter dict [[], Key] : A | +| CollectionFlow.cs:380:73:380:76 | access to parameter dict [[], Key] : A | CollectionFlow.cs:380:73:380:81 | access to property Keys [[]] : A | +| CollectionFlow.cs:380:73:380:81 | access to property Keys [[]] : A | CollectionFlow.cs:380:73:380:89 | call to method First | +| CollectionFlow.cs:396:49:396:52 | args [[]] : A | CollectionFlow.cs:396:63:396:66 | access to parameter args [[]] : A | +| CollectionFlow.cs:396:49:396:52 | args [[]] : A | CollectionFlow.cs:396:63:396:66 | access to parameter args [[]] : A | +| CollectionFlow.cs:396:63:396:66 | access to parameter args [[]] : A | CollectionFlow.cs:396:63:396:69 | access to array element | +| CollectionFlow.cs:396:63:396:66 | access to parameter args [[]] : A | CollectionFlow.cs:396:63:396:69 | access to array element | nodes -| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:14:14:14:19 | access to array element | semmle.label | access to array element | -| CollectionFlow.cs:15:18:15:20 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | -| CollectionFlow.cs:16:14:16:23 | call to method First | semmle.label | call to method First | -| CollectionFlow.cs:16:20:16:22 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | -| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:33:14:33:19 | access to array element | semmle.label | access to array element | -| CollectionFlow.cs:34:18:34:20 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | -| CollectionFlow.cs:35:14:35:23 | call to method First | semmle.label | call to method First | -| CollectionFlow.cs:35:20:35:22 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | +| CollectionFlow.cs:14:17:14:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:15:25:15:29 | { ..., ... } [[]] : A | semmle.label | { ..., ... } [[]] : A | +| CollectionFlow.cs:15:27:15:27 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:16:14:16:16 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:16:14:16:19 | access to array element | semmle.label | access to array element | +| CollectionFlow.cs:17:18:17:20 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:18:14:18:23 | call to method First | semmle.label | call to method First | +| CollectionFlow.cs:18:20:18:22 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:32:17:32:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:33:38:33:57 | { ..., ... } [As, []] : A | semmle.label | { ..., ... } [As, []] : A | +| CollectionFlow.cs:33:45:33:55 | { ..., ... } [[]] : A | semmle.label | { ..., ... } [[]] : A | +| CollectionFlow.cs:33:53:33:53 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:34:14:34:14 | access to local variable c [As, []] : A | semmle.label | access to local variable c [As, []] : A | +| CollectionFlow.cs:34:14:34:17 | access to field As [[]] : A | semmle.label | access to field As [[]] : A | +| CollectionFlow.cs:34:14:34:20 | access to array element | semmle.label | access to array element | +| CollectionFlow.cs:35:18:35:18 | access to local variable c [As, []] : A | semmle.label | access to local variable c [As, []] : A | +| CollectionFlow.cs:35:18:35:21 | access to field As [[]] : A | semmle.label | access to field As [[]] : A | +| CollectionFlow.cs:36:14:36:24 | call to method First | semmle.label | call to method First | +| CollectionFlow.cs:36:20:36:20 | access to local variable c [As, []] : A | semmle.label | access to local variable c [As, []] : A | +| CollectionFlow.cs:36:20:36:23 | access to field As [[]] : A | semmle.label | access to field As [[]] : A | | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:51:20:51:32 | object creation of type List : List | semmle.label | object creation of type List : List | -| CollectionFlow.cs:53:14:53:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:54:22:54:25 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:55:14:55:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:55:24:55:27 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:60:20:60:32 | object creation of type List : List | semmle.label | object creation of type List : List | -| CollectionFlow.cs:62:14:62:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:63:22:63:25 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:64:14:64:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:64:24:64:27 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:70:20:70:38 | object creation of type List : List | semmle.label | object creation of type List : List | -| CollectionFlow.cs:71:14:71:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:72:22:72:25 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:73:14:73:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:73:24:73:27 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:78:20:78:42 | object creation of type List : List | semmle.label | object creation of type List : List | -| CollectionFlow.cs:79:14:79:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:80:22:80:25 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:81:14:81:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:81:24:81:27 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:87:20:87:32 | object creation of type List : List | semmle.label | object creation of type List : List | -| CollectionFlow.cs:89:14:89:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:90:22:90:25 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:91:14:91:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:91:24:91:27 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:96:20:96:32 | object creation of type List : List | semmle.label | object creation of type List : List | -| CollectionFlow.cs:98:14:98:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:99:22:99:25 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:100:14:100:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:100:24:100:27 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | -| CollectionFlow.cs:108:14:108:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:109:23:109:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | -| CollectionFlow.cs:110:28:110:31 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | -| CollectionFlow.cs:112:30:112:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | -| CollectionFlow.cs:119:14:119:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:120:23:120:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:121:14:121:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | -| CollectionFlow.cs:121:28:121:31 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:123:14:123:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | -| CollectionFlow.cs:123:30:123:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | -| CollectionFlow.cs:130:14:130:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:131:23:131:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | -| CollectionFlow.cs:132:28:132:31 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | -| CollectionFlow.cs:134:30:134:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | -| CollectionFlow.cs:140:14:140:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:141:23:141:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:142:14:142:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | -| CollectionFlow.cs:142:28:142:31 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:144:14:144:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | -| CollectionFlow.cs:144:30:144:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:168:17:168:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:171:18:171:18 | access to local variable x | semmle.label | access to local variable x | -| CollectionFlow.cs:183:17:183:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:187:18:187:35 | access to property Current | semmle.label | access to property Current | -| CollectionFlow.cs:210:40:210:41 | ts : A[] | semmle.label | ts : A[] | -| CollectionFlow.cs:210:52:210:56 | access to array element | semmle.label | access to array element | -| CollectionFlow.cs:212:49:212:52 | list : List | semmle.label | list : List | -| CollectionFlow.cs:212:63:212:69 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:214:61:214:64 | dict : Dictionary | semmle.label | dict : Dictionary | -| CollectionFlow.cs:214:75:214:81 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:52:9:52:11 | [post] access to local variable as [[]] : A | semmle.label | [post] access to local variable as [[]] : A | +| CollectionFlow.cs:52:18:52:18 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:53:14:53:16 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:53:14:53:19 | access to array element | semmle.label | access to array element | +| CollectionFlow.cs:54:18:54:20 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:55:14:55:23 | call to method First | semmle.label | call to method First | +| CollectionFlow.cs:55:20:55:22 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:70:17:70:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:72:9:72:12 | [post] access to local variable list [[]] : A | semmle.label | [post] access to local variable list [[]] : A | +| CollectionFlow.cs:72:19:72:19 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:73:14:73:17 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:73:14:73:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:74:22:74:25 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:75:14:75:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| CollectionFlow.cs:75:24:75:27 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:89:17:89:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:90:34:90:38 | { ..., ... } [[]] : A | semmle.label | { ..., ... } [[]] : A | +| CollectionFlow.cs:90:36:90:36 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:91:14:91:17 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:91:14:91:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:92:22:92:25 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:93:14:93:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| CollectionFlow.cs:93:24:93:27 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:106:17:106:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:108:9:108:12 | [post] access to local variable list [[]] : A | semmle.label | [post] access to local variable list [[]] : A | +| CollectionFlow.cs:108:18:108:18 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:109:14:109:17 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:109:14:109:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:110:22:110:25 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:111:14:111:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| CollectionFlow.cs:111:24:111:27 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] : A | semmle.label | [post] access to local variable dict [[], Value] : A | +| CollectionFlow.cs:127:19:127:19 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:128:14:128:17 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:128:14:128:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:129:23:129:26 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | +| CollectionFlow.cs:130:28:130:31 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:131:14:131:33 | call to method DictFirstValue | semmle.label | call to method DictFirstValue | +| CollectionFlow.cs:131:29:131:32 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | +| CollectionFlow.cs:132:30:132:33 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] : A | semmle.label | { ..., ... } [[], Value] : A | +| CollectionFlow.cs:149:52:149:52 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:150:14:150:17 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:150:14:150:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:151:23:151:26 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | +| CollectionFlow.cs:152:28:152:31 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:153:14:153:33 | call to method DictFirstValue | semmle.label | call to method DictFirstValue | +| CollectionFlow.cs:153:29:153:32 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | +| CollectionFlow.cs:154:30:154:33 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:169:17:169:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] : A | semmle.label | { ..., ... } [[], Value] : A | +| CollectionFlow.cs:170:53:170:53 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:171:14:171:17 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:171:14:171:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:172:23:172:26 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:173:14:173:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | +| CollectionFlow.cs:173:28:173:31 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:174:14:174:33 | call to method DictFirstValue | semmle.label | call to method DictFirstValue | +| CollectionFlow.cs:174:29:174:32 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:175:14:175:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | +| CollectionFlow.cs:175:30:175:33 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:191:17:191:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] : A | semmle.label | { ..., ... } [[], Key] : A | +| CollectionFlow.cs:192:49:192:49 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:193:14:193:17 | access to local variable dict [[], Key] : A | semmle.label | access to local variable dict [[], Key] : A | +| CollectionFlow.cs:193:14:193:22 | access to property Keys [[]] : A | semmle.label | access to property Keys [[]] : A | +| CollectionFlow.cs:193:14:193:30 | call to method First | semmle.label | call to method First | +| CollectionFlow.cs:194:21:194:24 | access to local variable dict [[], Key] : A | semmle.label | access to local variable dict [[], Key] : A | +| CollectionFlow.cs:195:14:195:32 | call to method DictKeysFirst | semmle.label | call to method DictKeysFirst | +| CollectionFlow.cs:195:28:195:31 | access to local variable dict [[], Key] : A | semmle.label | access to local variable dict [[], Key] : A | +| CollectionFlow.cs:196:14:196:31 | call to method DictFirstKey | semmle.label | call to method DictFirstKey | +| CollectionFlow.cs:196:27:196:30 | access to local variable dict [[], Key] : A | semmle.label | access to local variable dict [[], Key] : A | +| CollectionFlow.cs:210:17:210:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] : A | semmle.label | { ..., ... } [[], Key] : A | +| CollectionFlow.cs:211:48:211:48 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:212:14:212:17 | access to local variable dict [[], Key] : A | semmle.label | access to local variable dict [[], Key] : A | +| CollectionFlow.cs:212:14:212:22 | access to property Keys [[]] : A | semmle.label | access to property Keys [[]] : A | +| CollectionFlow.cs:212:14:212:30 | call to method First | semmle.label | call to method First | +| CollectionFlow.cs:213:21:213:24 | access to local variable dict [[], Key] : A | semmle.label | access to local variable dict [[], Key] : A | +| CollectionFlow.cs:214:14:214:32 | call to method DictKeysFirst | semmle.label | call to method DictKeysFirst | +| CollectionFlow.cs:214:28:214:31 | access to local variable dict [[], Key] : A | semmle.label | access to local variable dict [[], Key] : A | +| CollectionFlow.cs:215:14:215:31 | call to method DictFirstKey | semmle.label | call to method DictFirstKey | +| CollectionFlow.cs:215:27:215:30 | access to local variable dict [[], Key] : A | semmle.label | access to local variable dict [[], Key] : A | +| CollectionFlow.cs:229:17:229:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:230:25:230:29 | { ..., ... } [[]] : A | semmle.label | { ..., ... } [[]] : A | +| CollectionFlow.cs:230:27:230:27 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:231:22:231:22 | SSA def(x) : A | semmle.label | SSA def(x) : A | +| CollectionFlow.cs:231:27:231:29 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:232:18:232:18 | access to local variable x | semmle.label | access to local variable x | +| CollectionFlow.cs:244:17:244:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:245:25:245:29 | { ..., ... } [[]] : A | semmle.label | { ..., ... } [[]] : A | +| CollectionFlow.cs:245:27:245:27 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:246:26:246:28 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:246:26:246:44 | call to method GetEnumerator [Current] : A | semmle.label | call to method GetEnumerator [Current] : A | +| CollectionFlow.cs:248:18:248:27 | access to local variable enumerator [Current] : A | semmle.label | access to local variable enumerator [Current] : A | +| CollectionFlow.cs:248:18:248:35 | access to property Current | semmle.label | access to property Current | +| CollectionFlow.cs:261:17:261:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:263:9:263:12 | [post] access to local variable list [[]] : A | semmle.label | [post] access to local variable list [[]] : A | +| CollectionFlow.cs:263:18:263:18 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:264:26:264:29 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:264:26:264:45 | call to method GetEnumerator [Current] : A | semmle.label | call to method GetEnumerator [Current] : A | +| CollectionFlow.cs:266:18:266:27 | access to local variable enumerator [Current] : A | semmle.label | access to local variable enumerator [Current] : A | +| CollectionFlow.cs:266:18:266:35 | access to property Current | semmle.label | access to property Current | +| CollectionFlow.cs:280:17:280:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:282:9:282:12 | [post] access to local variable list [[], Key] : A | semmle.label | [post] access to local variable list [[], Key] : A | +| CollectionFlow.cs:282:18:282:47 | object creation of type KeyValuePair [Key] : A | semmle.label | object creation of type KeyValuePair [Key] : A | +| CollectionFlow.cs:282:43:282:43 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:283:9:283:12 | access to local variable list [[], Key] : A | semmle.label | access to local variable list [[], Key] : A | +| CollectionFlow.cs:283:21:283:23 | kvp [Key] : A | semmle.label | kvp [Key] : A | +| CollectionFlow.cs:285:18:285:20 | access to parameter kvp [Key] : A | semmle.label | access to parameter kvp [Key] : A | +| CollectionFlow.cs:285:18:285:24 | access to property Key | semmle.label | access to property Key | +| CollectionFlow.cs:306:17:306:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:308:18:308:20 | [post] access to local variable as [[]] : A | semmle.label | [post] access to local variable as [[]] : A | +| CollectionFlow.cs:308:23:308:23 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:309:14:309:16 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:309:14:309:19 | access to array element | semmle.label | access to array element | +| CollectionFlow.cs:310:18:310:20 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:311:14:311:23 | call to method First | semmle.label | call to method First | +| CollectionFlow.cs:311:20:311:22 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:328:17:328:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:330:17:330:20 | [post] access to local variable list [[]] : A | semmle.label | [post] access to local variable list [[]] : A | +| CollectionFlow.cs:330:23:330:23 | access to local variable a : A | semmle.label | access to local variable a : A | +| CollectionFlow.cs:331:14:331:17 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:331:14:331:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:332:22:332:25 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:333:14:333:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| CollectionFlow.cs:333:24:333:27 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:347:20:347:26 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:348:26:348:32 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:349:26:349:32 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:350:20:350:38 | array creation of type A[] [[]] : A | semmle.label | array creation of type A[] [[]] : A | +| CollectionFlow.cs:350:28:350:38 | { ..., ... } [[]] : A | semmle.label | { ..., ... } [[]] : A | +| CollectionFlow.cs:350:30:350:36 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:374:40:374:41 | ts [[]] : A | semmle.label | ts [[]] : A | +| CollectionFlow.cs:374:40:374:41 | ts [[]] : A | semmle.label | ts [[]] : A | +| CollectionFlow.cs:374:52:374:53 | access to parameter ts [[]] : A | semmle.label | access to parameter ts [[]] : A | +| CollectionFlow.cs:374:52:374:53 | access to parameter ts [[]] : A | semmle.label | access to parameter ts [[]] : A | +| CollectionFlow.cs:374:52:374:56 | access to array element | semmle.label | access to array element | +| CollectionFlow.cs:376:49:376:52 | list [[]] : A | semmle.label | list [[]] : A | +| CollectionFlow.cs:376:49:376:52 | list [[]] : A | semmle.label | list [[]] : A | +| CollectionFlow.cs:376:49:376:52 | list [[]] : A | semmle.label | list [[]] : A | +| CollectionFlow.cs:376:49:376:52 | list [[]] : A | semmle.label | list [[]] : A | +| CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | semmle.label | access to parameter list [[]] : A | +| CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | semmle.label | access to parameter list [[]] : A | +| CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | semmle.label | access to parameter list [[]] : A | +| CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | semmle.label | access to parameter list [[]] : A | +| CollectionFlow.cs:376:63:376:69 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:378:61:378:64 | dict [[], Value] : A | semmle.label | dict [[], Value] : A | +| CollectionFlow.cs:378:75:378:78 | access to parameter dict [[], Value] : A | semmle.label | access to parameter dict [[], Value] : A | +| CollectionFlow.cs:378:75:378:81 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:380:59:380:62 | dict [[], Key] : A | semmle.label | dict [[], Key] : A | +| CollectionFlow.cs:380:73:380:76 | access to parameter dict [[], Key] : A | semmle.label | access to parameter dict [[], Key] : A | +| CollectionFlow.cs:380:73:380:81 | access to property Keys [[]] : A | semmle.label | access to property Keys [[]] : A | +| CollectionFlow.cs:380:73:380:89 | call to method First | semmle.label | call to method First | +| CollectionFlow.cs:396:49:396:52 | args [[]] : A | semmle.label | args [[]] : A | +| CollectionFlow.cs:396:49:396:52 | args [[]] : A | semmle.label | args [[]] : A | +| CollectionFlow.cs:396:63:396:66 | access to parameter args [[]] : A | semmle.label | access to parameter args [[]] : A | +| CollectionFlow.cs:396:63:396:66 | access to parameter args [[]] : A | semmle.label | access to parameter args [[]] : A | +| CollectionFlow.cs:396:63:396:69 | access to array element | semmle.label | access to array element | #select -| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:14:14:14:19 | access to array element | $@ | CollectionFlow.cs:14:14:14:19 | access to array element | access to array element | -| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:16:14:16:23 | call to method First | $@ | CollectionFlow.cs:16:14:16:23 | call to method First | call to method First | -| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:210:52:210:56 | access to array element | $@ | CollectionFlow.cs:210:52:210:56 | access to array element | access to array element | -| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:33:14:33:19 | access to array element | $@ | CollectionFlow.cs:33:14:33:19 | access to array element | access to array element | -| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:35:14:35:23 | call to method First | $@ | CollectionFlow.cs:35:14:35:23 | call to method First | call to method First | -| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:210:52:210:56 | access to array element | $@ | CollectionFlow.cs:210:52:210:56 | access to array element | access to array element | -| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:53:14:53:20 | access to indexer | $@ | CollectionFlow.cs:53:14:53:20 | access to indexer | access to indexer | -| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:55:14:55:28 | call to method ListFirst | $@ | CollectionFlow.cs:55:14:55:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | -| CollectionFlow.cs:51:20:51:32 | object creation of type List : List | CollectionFlow.cs:51:20:51:32 | object creation of type List : List | CollectionFlow.cs:53:14:53:20 | access to indexer | $@ | CollectionFlow.cs:53:14:53:20 | access to indexer | access to indexer | -| CollectionFlow.cs:51:20:51:32 | object creation of type List : List | CollectionFlow.cs:51:20:51:32 | object creation of type List : List | CollectionFlow.cs:55:14:55:28 | call to method ListFirst | $@ | CollectionFlow.cs:55:14:55:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:51:20:51:32 | object creation of type List : List | CollectionFlow.cs:51:20:51:32 | object creation of type List : List | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | -| CollectionFlow.cs:60:20:60:32 | object creation of type List : List | CollectionFlow.cs:60:20:60:32 | object creation of type List : List | CollectionFlow.cs:62:14:62:20 | access to indexer | $@ | CollectionFlow.cs:62:14:62:20 | access to indexer | access to indexer | -| CollectionFlow.cs:60:20:60:32 | object creation of type List : List | CollectionFlow.cs:60:20:60:32 | object creation of type List : List | CollectionFlow.cs:64:14:64:28 | call to method ListFirst | $@ | CollectionFlow.cs:64:14:64:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:60:20:60:32 | object creation of type List : List | CollectionFlow.cs:60:20:60:32 | object creation of type List : List | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | -| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:71:14:71:20 | access to indexer | $@ | CollectionFlow.cs:71:14:71:20 | access to indexer | access to indexer | -| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:73:14:73:28 | call to method ListFirst | $@ | CollectionFlow.cs:73:14:73:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | -| CollectionFlow.cs:70:20:70:38 | object creation of type List : List | CollectionFlow.cs:70:20:70:38 | object creation of type List : List | CollectionFlow.cs:71:14:71:20 | access to indexer | $@ | CollectionFlow.cs:71:14:71:20 | access to indexer | access to indexer | -| CollectionFlow.cs:70:20:70:38 | object creation of type List : List | CollectionFlow.cs:70:20:70:38 | object creation of type List : List | CollectionFlow.cs:73:14:73:28 | call to method ListFirst | $@ | CollectionFlow.cs:73:14:73:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:70:20:70:38 | object creation of type List : List | CollectionFlow.cs:70:20:70:38 | object creation of type List : List | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | -| CollectionFlow.cs:78:20:78:42 | object creation of type List : List | CollectionFlow.cs:78:20:78:42 | object creation of type List : List | CollectionFlow.cs:79:14:79:20 | access to indexer | $@ | CollectionFlow.cs:79:14:79:20 | access to indexer | access to indexer | -| CollectionFlow.cs:78:20:78:42 | object creation of type List : List | CollectionFlow.cs:78:20:78:42 | object creation of type List : List | CollectionFlow.cs:81:14:81:28 | call to method ListFirst | $@ | CollectionFlow.cs:81:14:81:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:78:20:78:42 | object creation of type List : List | CollectionFlow.cs:78:20:78:42 | object creation of type List : List | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | -| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:89:14:89:20 | access to indexer | $@ | CollectionFlow.cs:89:14:89:20 | access to indexer | access to indexer | -| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:91:14:91:28 | call to method ListFirst | $@ | CollectionFlow.cs:91:14:91:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | -| CollectionFlow.cs:87:20:87:32 | object creation of type List : List | CollectionFlow.cs:87:20:87:32 | object creation of type List : List | CollectionFlow.cs:89:14:89:20 | access to indexer | $@ | CollectionFlow.cs:89:14:89:20 | access to indexer | access to indexer | -| CollectionFlow.cs:87:20:87:32 | object creation of type List : List | CollectionFlow.cs:87:20:87:32 | object creation of type List : List | CollectionFlow.cs:91:14:91:28 | call to method ListFirst | $@ | CollectionFlow.cs:91:14:91:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:87:20:87:32 | object creation of type List : List | CollectionFlow.cs:87:20:87:32 | object creation of type List : List | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | -| CollectionFlow.cs:96:20:96:32 | object creation of type List : List | CollectionFlow.cs:96:20:96:32 | object creation of type List : List | CollectionFlow.cs:98:14:98:20 | access to indexer | $@ | CollectionFlow.cs:98:14:98:20 | access to indexer | access to indexer | -| CollectionFlow.cs:96:20:96:32 | object creation of type List : List | CollectionFlow.cs:96:20:96:32 | object creation of type List : List | CollectionFlow.cs:100:14:100:28 | call to method ListFirst | $@ | CollectionFlow.cs:100:14:100:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:96:20:96:32 | object creation of type List : List | CollectionFlow.cs:96:20:96:32 | object creation of type List : List | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | -| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:108:14:108:20 | access to indexer | $@ | CollectionFlow.cs:108:14:108:20 | access to indexer | access to indexer | -| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | call to method DictIndexZero | -| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer | -| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:108:14:108:20 | access to indexer | $@ | CollectionFlow.cs:108:14:108:20 | access to indexer | access to indexer | -| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | call to method DictIndexZero | -| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer | -| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:119:14:119:20 | access to indexer | $@ | CollectionFlow.cs:119:14:119:20 | access to indexer | access to indexer | -| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:121:14:121:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:121:14:121:32 | call to method DictIndexZero | call to method DictIndexZero | -| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:123:14:123:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:123:14:123:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer | -| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:130:14:130:20 | access to indexer | $@ | CollectionFlow.cs:130:14:130:20 | access to indexer | access to indexer | -| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | call to method DictIndexZero | -| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer | -| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:130:14:130:20 | access to indexer | $@ | CollectionFlow.cs:130:14:130:20 | access to indexer | access to indexer | -| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | call to method DictIndexZero | -| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer | -| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:140:14:140:20 | access to indexer | $@ | CollectionFlow.cs:140:14:140:20 | access to indexer | access to indexer | -| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:142:14:142:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:142:14:142:32 | call to method DictIndexZero | call to method DictIndexZero | -| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:144:14:144:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:144:14:144:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer | -| CollectionFlow.cs:168:17:168:23 | object creation of type A : A | CollectionFlow.cs:168:17:168:23 | object creation of type A : A | CollectionFlow.cs:171:18:171:18 | access to local variable x | $@ | CollectionFlow.cs:171:18:171:18 | access to local variable x | access to local variable x | -| CollectionFlow.cs:183:17:183:23 | object creation of type A : A | CollectionFlow.cs:183:17:183:23 | object creation of type A : A | CollectionFlow.cs:187:18:187:35 | access to property Current | $@ | CollectionFlow.cs:187:18:187:35 | access to property Current | access to property Current | +| CollectionFlow.cs:14:17:14:23 | object creation of type A : A | CollectionFlow.cs:14:17:14:23 | object creation of type A : A | CollectionFlow.cs:16:14:16:19 | access to array element | $@ | CollectionFlow.cs:16:14:16:19 | access to array element | access to array element | +| CollectionFlow.cs:14:17:14:23 | object creation of type A : A | CollectionFlow.cs:14:17:14:23 | object creation of type A : A | CollectionFlow.cs:18:14:18:23 | call to method First | $@ | CollectionFlow.cs:18:14:18:23 | call to method First | call to method First | +| CollectionFlow.cs:14:17:14:23 | object creation of type A : A | CollectionFlow.cs:14:17:14:23 | object creation of type A : A | CollectionFlow.cs:374:52:374:56 | access to array element | $@ | CollectionFlow.cs:374:52:374:56 | access to array element | access to array element | +| CollectionFlow.cs:32:17:32:23 | object creation of type A : A | CollectionFlow.cs:32:17:32:23 | object creation of type A : A | CollectionFlow.cs:34:14:34:20 | access to array element | $@ | CollectionFlow.cs:34:14:34:20 | access to array element | access to array element | +| CollectionFlow.cs:32:17:32:23 | object creation of type A : A | CollectionFlow.cs:32:17:32:23 | object creation of type A : A | CollectionFlow.cs:36:14:36:24 | call to method First | $@ | CollectionFlow.cs:36:14:36:24 | call to method First | call to method First | +| CollectionFlow.cs:32:17:32:23 | object creation of type A : A | CollectionFlow.cs:32:17:32:23 | object creation of type A : A | CollectionFlow.cs:374:52:374:56 | access to array element | $@ | CollectionFlow.cs:374:52:374:56 | access to array element | access to array element | +| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:53:14:53:19 | access to array element | $@ | CollectionFlow.cs:53:14:53:19 | access to array element | access to array element | +| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:55:14:55:23 | call to method First | $@ | CollectionFlow.cs:55:14:55:23 | call to method First | call to method First | +| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:374:52:374:56 | access to array element | $@ | CollectionFlow.cs:374:52:374:56 | access to array element | access to array element | +| CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:73:14:73:20 | access to indexer | $@ | CollectionFlow.cs:73:14:73:20 | access to indexer | access to indexer | +| CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:75:14:75:28 | call to method ListFirst | $@ | CollectionFlow.cs:75:14:75:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | +| CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:91:14:91:20 | access to indexer | $@ | CollectionFlow.cs:91:14:91:20 | access to indexer | access to indexer | +| CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:93:14:93:28 | call to method ListFirst | $@ | CollectionFlow.cs:93:14:93:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | +| CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:109:14:109:20 | access to indexer | $@ | CollectionFlow.cs:109:14:109:20 | access to indexer | access to indexer | +| CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:111:14:111:28 | call to method ListFirst | $@ | CollectionFlow.cs:111:14:111:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | +| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:128:14:128:20 | access to indexer | $@ | CollectionFlow.cs:128:14:128:20 | access to indexer | access to indexer | +| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | call to method DictIndexZero | +| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:131:14:131:33 | call to method DictFirstValue | $@ | CollectionFlow.cs:131:14:131:33 | call to method DictFirstValue | call to method DictFirstValue | +| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | call to method DictValuesFirst | +| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:378:75:378:81 | access to indexer | $@ | CollectionFlow.cs:378:75:378:81 | access to indexer | access to indexer | +| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:150:14:150:20 | access to indexer | $@ | CollectionFlow.cs:150:14:150:20 | access to indexer | access to indexer | +| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | call to method DictIndexZero | +| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:153:14:153:33 | call to method DictFirstValue | $@ | CollectionFlow.cs:153:14:153:33 | call to method DictFirstValue | call to method DictFirstValue | +| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | call to method DictValuesFirst | +| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:378:75:378:81 | access to indexer | $@ | CollectionFlow.cs:378:75:378:81 | access to indexer | access to indexer | +| CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:171:14:171:20 | access to indexer | $@ | CollectionFlow.cs:171:14:171:20 | access to indexer | access to indexer | +| CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:173:14:173:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:173:14:173:32 | call to method DictIndexZero | call to method DictIndexZero | +| CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:174:14:174:33 | call to method DictFirstValue | $@ | CollectionFlow.cs:174:14:174:33 | call to method DictFirstValue | call to method DictFirstValue | +| CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:175:14:175:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:175:14:175:34 | call to method DictValuesFirst | call to method DictValuesFirst | +| CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:378:75:378:81 | access to indexer | $@ | CollectionFlow.cs:378:75:378:81 | access to indexer | access to indexer | +| CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:193:14:193:30 | call to method First | $@ | CollectionFlow.cs:193:14:193:30 | call to method First | call to method First | +| CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:195:14:195:32 | call to method DictKeysFirst | $@ | CollectionFlow.cs:195:14:195:32 | call to method DictKeysFirst | call to method DictKeysFirst | +| CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:196:14:196:31 | call to method DictFirstKey | $@ | CollectionFlow.cs:196:14:196:31 | call to method DictFirstKey | call to method DictFirstKey | +| CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:380:73:380:89 | call to method First | $@ | CollectionFlow.cs:380:73:380:89 | call to method First | call to method First | +| CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:212:14:212:30 | call to method First | $@ | CollectionFlow.cs:212:14:212:30 | call to method First | call to method First | +| CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:214:14:214:32 | call to method DictKeysFirst | $@ | CollectionFlow.cs:214:14:214:32 | call to method DictKeysFirst | call to method DictKeysFirst | +| CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:215:14:215:31 | call to method DictFirstKey | $@ | CollectionFlow.cs:215:14:215:31 | call to method DictFirstKey | call to method DictFirstKey | +| CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:380:73:380:89 | call to method First | $@ | CollectionFlow.cs:380:73:380:89 | call to method First | call to method First | +| CollectionFlow.cs:229:17:229:23 | object creation of type A : A | CollectionFlow.cs:229:17:229:23 | object creation of type A : A | CollectionFlow.cs:232:18:232:18 | access to local variable x | $@ | CollectionFlow.cs:232:18:232:18 | access to local variable x | access to local variable x | +| CollectionFlow.cs:244:17:244:23 | object creation of type A : A | CollectionFlow.cs:244:17:244:23 | object creation of type A : A | CollectionFlow.cs:248:18:248:35 | access to property Current | $@ | CollectionFlow.cs:248:18:248:35 | access to property Current | access to property Current | +| CollectionFlow.cs:261:17:261:23 | object creation of type A : A | CollectionFlow.cs:261:17:261:23 | object creation of type A : A | CollectionFlow.cs:266:18:266:35 | access to property Current | $@ | CollectionFlow.cs:266:18:266:35 | access to property Current | access to property Current | +| CollectionFlow.cs:280:17:280:23 | object creation of type A : A | CollectionFlow.cs:280:17:280:23 | object creation of type A : A | CollectionFlow.cs:285:18:285:24 | access to property Key | $@ | CollectionFlow.cs:285:18:285:24 | access to property Key | access to property Key | +| CollectionFlow.cs:306:17:306:23 | object creation of type A : A | CollectionFlow.cs:306:17:306:23 | object creation of type A : A | CollectionFlow.cs:309:14:309:19 | access to array element | $@ | CollectionFlow.cs:309:14:309:19 | access to array element | access to array element | +| CollectionFlow.cs:306:17:306:23 | object creation of type A : A | CollectionFlow.cs:306:17:306:23 | object creation of type A : A | CollectionFlow.cs:311:14:311:23 | call to method First | $@ | CollectionFlow.cs:311:14:311:23 | call to method First | call to method First | +| CollectionFlow.cs:306:17:306:23 | object creation of type A : A | CollectionFlow.cs:306:17:306:23 | object creation of type A : A | CollectionFlow.cs:374:52:374:56 | access to array element | $@ | CollectionFlow.cs:374:52:374:56 | access to array element | access to array element | +| CollectionFlow.cs:328:17:328:23 | object creation of type A : A | CollectionFlow.cs:328:17:328:23 | object creation of type A : A | CollectionFlow.cs:331:14:331:20 | access to indexer | $@ | CollectionFlow.cs:331:14:331:20 | access to indexer | access to indexer | +| CollectionFlow.cs:328:17:328:23 | object creation of type A : A | CollectionFlow.cs:328:17:328:23 | object creation of type A : A | CollectionFlow.cs:333:14:333:28 | call to method ListFirst | $@ | CollectionFlow.cs:333:14:333:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:328:17:328:23 | object creation of type A : A | CollectionFlow.cs:328:17:328:23 | object creation of type A : A | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | +| CollectionFlow.cs:347:20:347:26 | object creation of type A : A | CollectionFlow.cs:347:20:347:26 | object creation of type A : A | CollectionFlow.cs:396:63:396:69 | access to array element | $@ | CollectionFlow.cs:396:63:396:69 | access to array element | access to array element | +| CollectionFlow.cs:348:26:348:32 | object creation of type A : A | CollectionFlow.cs:348:26:348:32 | object creation of type A : A | CollectionFlow.cs:396:63:396:69 | access to array element | $@ | CollectionFlow.cs:396:63:396:69 | access to array element | access to array element | +| CollectionFlow.cs:349:26:349:32 | object creation of type A : A | CollectionFlow.cs:349:26:349:32 | object creation of type A : A | CollectionFlow.cs:396:63:396:69 | access to array element | $@ | CollectionFlow.cs:396:63:396:69 | access to array element | access to array element | +| CollectionFlow.cs:350:30:350:36 | object creation of type A : A | CollectionFlow.cs:350:30:350:36 | object creation of type A : A | CollectionFlow.cs:396:63:396:69 | access to array element | $@ | CollectionFlow.cs:396:63:396:69 | access to array element | access to array element | diff --git a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.ql b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.ql index d1290562252c..7d02ffa7bcb1 100644 --- a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.ql +++ b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.ql @@ -5,7 +5,7 @@ import csharp import DataFlow::PathGraph -class Conf extends TaintTracking::Configuration { +class Conf extends DataFlow::Configuration { Conf() { this = "ArrayFlowConf" } override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ObjectCreation } @@ -16,6 +16,8 @@ class Conf extends TaintTracking::Configuration { mc.getAnArgument() = sink.asExpr() ) } + + override int fieldFlowBranchLimit() { result = 10 } } from DataFlow::PathNode source, DataFlow::PathNode sink, Conf conf diff --git a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.cs b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.cs index 7a50bcc057d9..9479cca940d7 100644 --- a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.cs @@ -99,5 +99,13 @@ public void M14() M2(LocalFunction); } + public void M15() + { + Func f = () => 42; + new Lazy(f); + f = () => 43; + new Lazy(f); + } + public delegate void MyDelegate(); } diff --git a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected index ecdd7f9e5f82..c8893ec9b0e2 100644 --- a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected @@ -1,3 +1,7 @@ +summaryDelegateCall +| file://:0:0:0:0 | [summary] valueFactory | DelegateFlow.cs:104:23:104:30 | (...) => ... | DelegateFlow.cs:105:23:105:23 | access to local variable f | +| file://:0:0:0:0 | [summary] valueFactory | DelegateFlow.cs:106:13:106:20 | (...) => ... | DelegateFlow.cs:107:23:107:23 | access to local variable f | +delegateCall | DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:5:10:5:11 | M1 | DelegateFlow.cs:17:12:17:13 | delegate creation of type Action | | DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:5:10:5:11 | M1 | DelegateFlow.cs:22:12:22:12 | access to parameter a | | DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:16:12:16:19 | (...) => ... | DelegateFlow.cs:16:12:16:19 | (...) => ... | diff --git a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.ql b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.ql index 2b0386491eac..c01feabc2f97 100644 --- a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.ql +++ b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.ql @@ -1,5 +1,22 @@ import csharp +import semmle.code.csharp.dataflow.internal.DataFlowPrivate +import semmle.code.csharp.dataflow.internal.DelegateDataFlow -from DelegateCall dc, Callable c, CallContext::CallContext cc -where c = dc.getARuntimeTarget(cc) -select dc, c, cc +private class NodeAdjusted extends TNode { + string toString() { result = this.(DataFlow::Node).toString() } + + Location getLocation() { + exists(Location l | + l = this.(DataFlow::Node).getLocation() and + if l instanceof SourceLocation then result = l else result instanceof EmptyLocation + ) + } +} + +query predicate summaryDelegateCall(NodeAdjusted sink, Callable c, CallContext::CallContext cc) { + c = sink.(SummaryDelegateParameterSink).getARuntimeTarget(cc) +} + +query predicate delegateCall(DelegateCall dc, Callable c, CallContext::CallContext cc) { + c = dc.getARuntimeTarget(cc) +} diff --git a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected index 3d0a0a83ed54..8f1a95d58c75 100644 --- a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected @@ -27,49 +27,49 @@ edges | A.cs:97:13:97:13 | [post] access to parameter b [c] : C | A.cs:98:22:98:36 | ... ? ... : ... [c] : C | | A.cs:97:13:97:13 | [post] access to parameter b [c] : C | A.cs:105:23:105:23 | [post] access to local variable b [c] : C | | A.cs:97:19:97:25 | object creation of type C : C | A.cs:97:13:97:13 | [post] access to parameter b [c] : C | -| A.cs:98:13:98:16 | [post] this access [b, c] | A.cs:105:17:105:29 | object creation of type D [b, c] | +| A.cs:98:13:98:16 | [post] this access [b, c] : C | A.cs:105:17:105:29 | object creation of type D [b, c] : C | | A.cs:98:13:98:16 | [post] this access [b] : B | A.cs:105:17:105:29 | object creation of type D [b] : B | | A.cs:98:22:98:36 | ... ? ... : ... : B | A.cs:98:13:98:16 | [post] this access [b] : B | -| A.cs:98:22:98:36 | ... ? ... : ... [c] : C | A.cs:98:13:98:16 | [post] this access [b, c] | +| A.cs:98:22:98:36 | ... ? ... : ... [c] : C | A.cs:98:13:98:16 | [post] this access [b, c] : C | | A.cs:98:30:98:36 | object creation of type B : B | A.cs:98:22:98:36 | ... ? ... : ... : B | | A.cs:104:17:104:23 | object creation of type B : B | A.cs:105:23:105:23 | access to local variable b : B | -| A.cs:105:17:105:29 | object creation of type D [b, c] | A.cs:107:14:107:14 | access to local variable d [b, c] | +| A.cs:105:17:105:29 | object creation of type D [b, c] : C | A.cs:107:14:107:14 | access to local variable d [b, c] : C | | A.cs:105:17:105:29 | object creation of type D [b] : B | A.cs:106:14:106:14 | access to local variable d [b] : B | | A.cs:105:23:105:23 | [post] access to local variable b [c] : C | A.cs:108:14:108:14 | access to local variable b [c] : C | | A.cs:105:23:105:23 | access to local variable b : B | A.cs:105:17:105:29 | object creation of type D [b] : B | | A.cs:106:14:106:14 | access to local variable d [b] : B | A.cs:106:14:106:16 | access to field b | -| A.cs:107:14:107:14 | access to local variable d [b, c] | A.cs:107:14:107:16 | access to field b [c] : C | +| A.cs:107:14:107:14 | access to local variable d [b, c] : C | A.cs:107:14:107:16 | access to field b [c] : C | | A.cs:107:14:107:16 | access to field b [c] : C | A.cs:107:14:107:18 | access to field c | | A.cs:108:14:108:14 | access to local variable b [c] : C | A.cs:108:14:108:16 | access to field c | | A.cs:113:17:113:23 | object creation of type B : B | A.cs:114:29:114:29 | access to local variable b : B | | A.cs:114:18:114:54 | object creation of type MyList [head] : B | A.cs:115:35:115:36 | access to local variable l1 [head] : B | | A.cs:114:29:114:29 | access to local variable b : B | A.cs:114:18:114:54 | object creation of type MyList [head] : B | -| A.cs:115:18:115:37 | object creation of type MyList [next, head] | A.cs:116:35:116:36 | access to local variable l2 [next, head] | -| A.cs:115:35:115:36 | access to local variable l1 [head] : B | A.cs:115:18:115:37 | object creation of type MyList [next, head] | -| A.cs:116:18:116:37 | object creation of type MyList [next, next, ... (3)] | A.cs:119:14:119:15 | access to local variable l3 [next, next, ... (3)] | -| A.cs:116:18:116:37 | object creation of type MyList [next, next, ... (3)] | A.cs:121:41:121:41 | access to local variable l [next, next, ... (3)] | -| A.cs:116:35:116:36 | access to local variable l2 [next, head] | A.cs:116:18:116:37 | object creation of type MyList [next, next, ... (3)] | -| A.cs:119:14:119:15 | access to local variable l3 [next, next, ... (3)] | A.cs:119:14:119:20 | access to field next [next, head] | -| A.cs:119:14:119:20 | access to field next [next, head] | A.cs:119:14:119:25 | access to field next [head] : B | +| A.cs:115:18:115:37 | object creation of type MyList [next, head] : B | A.cs:116:35:116:36 | access to local variable l2 [next, head] : B | +| A.cs:115:35:115:36 | access to local variable l1 [head] : B | A.cs:115:18:115:37 | object creation of type MyList [next, head] : B | +| A.cs:116:18:116:37 | object creation of type MyList [next, next, head] : B | A.cs:119:14:119:15 | access to local variable l3 [next, next, head] : B | +| A.cs:116:18:116:37 | object creation of type MyList [next, next, head] : B | A.cs:121:41:121:41 | access to local variable l [next, next, head] : B | +| A.cs:116:35:116:36 | access to local variable l2 [next, head] : B | A.cs:116:18:116:37 | object creation of type MyList [next, next, head] : B | +| A.cs:119:14:119:15 | access to local variable l3 [next, next, head] : B | A.cs:119:14:119:20 | access to field next [next, head] : B | +| A.cs:119:14:119:20 | access to field next [next, head] : B | A.cs:119:14:119:25 | access to field next [head] : B | | A.cs:119:14:119:25 | access to field next [head] : B | A.cs:119:14:119:30 | access to field head | -| A.cs:121:41:121:41 | access to local variable l [next, head] | A.cs:121:41:121:46 | access to field next [head] : B | -| A.cs:121:41:121:41 | access to local variable l [next, next, ... (3)] | A.cs:121:41:121:46 | access to field next [next, head] | +| A.cs:121:41:121:41 | access to local variable l [next, head] : B | A.cs:121:41:121:46 | access to field next [head] : B | +| A.cs:121:41:121:41 | access to local variable l [next, next, head] : B | A.cs:121:41:121:46 | access to field next [next, head] : B | | A.cs:121:41:121:46 | access to field next [head] : B | A.cs:123:18:123:18 | access to local variable l [head] : B | -| A.cs:121:41:121:46 | access to field next [next, head] | A.cs:121:41:121:41 | access to local variable l [next, head] | +| A.cs:121:41:121:46 | access to field next [next, head] : B | A.cs:121:41:121:41 | access to local variable l [next, head] : B | | A.cs:123:18:123:18 | access to local variable l [head] : B | A.cs:123:18:123:23 | access to field head | | B.cs:5:17:5:26 | object creation of type Elem : Elem | B.cs:6:27:6:27 | access to local variable e : Elem | | B.cs:6:18:6:34 | object creation of type Box1 [elem1] : Elem | B.cs:7:27:7:28 | access to local variable b1 [elem1] : Elem | | B.cs:6:27:6:27 | access to local variable e : Elem | B.cs:6:18:6:34 | object creation of type Box1 [elem1] : Elem | -| B.cs:7:18:7:29 | object creation of type Box2 [box1, elem1] | B.cs:8:14:8:15 | access to local variable b2 [box1, elem1] | -| B.cs:7:27:7:28 | access to local variable b1 [elem1] : Elem | B.cs:7:18:7:29 | object creation of type Box2 [box1, elem1] | -| B.cs:8:14:8:15 | access to local variable b2 [box1, elem1] | B.cs:8:14:8:20 | access to field box1 [elem1] : Elem | +| B.cs:7:18:7:29 | object creation of type Box2 [box1, elem1] : Elem | B.cs:8:14:8:15 | access to local variable b2 [box1, elem1] : Elem | +| B.cs:7:27:7:28 | access to local variable b1 [elem1] : Elem | B.cs:7:18:7:29 | object creation of type Box2 [box1, elem1] : Elem | +| B.cs:8:14:8:15 | access to local variable b2 [box1, elem1] : Elem | B.cs:8:14:8:20 | access to field box1 [elem1] : Elem | | B.cs:8:14:8:20 | access to field box1 [elem1] : Elem | B.cs:8:14:8:26 | access to field elem1 | | B.cs:14:17:14:26 | object creation of type Elem : Elem | B.cs:15:33:15:33 | access to local variable e : Elem | | B.cs:15:18:15:34 | object creation of type Box1 [elem2] : Elem | B.cs:16:27:16:28 | access to local variable b1 [elem2] : Elem | | B.cs:15:33:15:33 | access to local variable e : Elem | B.cs:15:18:15:34 | object creation of type Box1 [elem2] : Elem | -| B.cs:16:18:16:29 | object creation of type Box2 [box1, elem2] | B.cs:18:14:18:15 | access to local variable b2 [box1, elem2] | -| B.cs:16:27:16:28 | access to local variable b1 [elem2] : Elem | B.cs:16:18:16:29 | object creation of type Box2 [box1, elem2] | -| B.cs:18:14:18:15 | access to local variable b2 [box1, elem2] | B.cs:18:14:18:20 | access to field box1 [elem2] : Elem | +| B.cs:16:18:16:29 | object creation of type Box2 [box1, elem2] : Elem | B.cs:18:14:18:15 | access to local variable b2 [box1, elem2] : Elem | +| B.cs:16:27:16:28 | access to local variable b1 [elem2] : Elem | B.cs:16:18:16:29 | object creation of type Box2 [box1, elem2] : Elem | +| B.cs:18:14:18:15 | access to local variable b2 [box1, elem2] : Elem | B.cs:18:14:18:20 | access to field box1 [elem2] : Elem | | B.cs:18:14:18:20 | access to field box1 [elem2] : Elem | B.cs:18:14:18:26 | access to field elem2 | | C.cs:3:18:3:19 | [post] this access [s1] : Elem | C.cs:12:15:12:21 | object creation of type C [s1] : Elem | | C.cs:3:23:3:32 | object creation of type Elem : Elem | C.cs:3:18:3:19 | [post] this access [s1] : Elem | @@ -124,51 +124,51 @@ edges | F.cs:10:17:10:28 | object creation of type Object : Object | F.cs:11:24:11:24 | access to local variable o : Object | | F.cs:10:17:10:28 | object creation of type Object : Object | F.cs:15:26:15:26 | access to local variable o : Object | | F.cs:10:17:10:28 | object creation of type Object : Object | F.cs:19:32:19:32 | access to local variable o : Object | +| F.cs:10:17:10:28 | object creation of type Object : Object | F.cs:23:32:23:32 | access to local variable o : Object | | F.cs:11:17:11:31 | call to method Create [Field1] : Object | F.cs:12:14:12:14 | access to local variable f [Field1] : Object | | F.cs:11:24:11:24 | access to local variable o : Object | F.cs:11:17:11:31 | call to method Create [Field1] : Object | | F.cs:12:14:12:14 | access to local variable f [Field1] : Object | F.cs:12:14:12:21 | access to field Field1 | | F.cs:15:13:15:27 | call to method Create [Field2] : Object | F.cs:17:14:17:14 | access to local variable f [Field2] : Object | | F.cs:15:26:15:26 | access to local variable o : Object | F.cs:15:13:15:27 | call to method Create [Field2] : Object | | F.cs:17:14:17:14 | access to local variable f [Field2] : Object | F.cs:17:14:17:21 | access to field Field2 | -| F.cs:19:13:19:34 | object creation of type F [Field1] : Object | F.cs:20:14:20:14 | access to local variable f [Field1] : Object | -| F.cs:19:32:19:32 | access to local variable o : Object | F.cs:19:13:19:34 | object creation of type F [Field1] : Object | -| F.cs:19:32:19:32 | access to local variable o : Object | F.cs:23:32:23:32 | access to local variable o : Object | +| F.cs:19:21:19:34 | { ..., ... } [Field1] : Object | F.cs:20:14:20:14 | access to local variable f [Field1] : Object | +| F.cs:19:32:19:32 | access to local variable o : Object | F.cs:19:21:19:34 | { ..., ... } [Field1] : Object | | F.cs:20:14:20:14 | access to local variable f [Field1] : Object | F.cs:20:14:20:21 | access to field Field1 | -| F.cs:23:13:23:34 | object creation of type F [Field2] : Object | F.cs:25:14:25:14 | access to local variable f [Field2] : Object | -| F.cs:23:32:23:32 | access to local variable o : Object | F.cs:23:13:23:34 | object creation of type F [Field2] : Object | +| F.cs:23:21:23:34 | { ..., ... } [Field2] : Object | F.cs:25:14:25:14 | access to local variable f [Field2] : Object | +| F.cs:23:32:23:32 | access to local variable o : Object | F.cs:23:21:23:34 | { ..., ... } [Field2] : Object | | F.cs:25:14:25:14 | access to local variable f [Field2] : Object | F.cs:25:14:25:21 | access to field Field2 | | G.cs:7:18:7:27 | object creation of type Elem : Elem | G.cs:9:23:9:23 | access to local variable e : Elem | -| G.cs:9:9:9:9 | [post] access to local variable b [Box1, Elem] | G.cs:10:18:10:18 | access to local variable b [Box1, Elem] | -| G.cs:9:9:9:14 | [post] access to field Box1 [Elem] : Elem | G.cs:9:9:9:9 | [post] access to local variable b [Box1, Elem] | +| G.cs:9:9:9:9 | [post] access to local variable b [Box1, Elem] : Elem | G.cs:10:18:10:18 | access to local variable b [Box1, Elem] : Elem | +| G.cs:9:9:9:14 | [post] access to field Box1 [Elem] : Elem | G.cs:9:9:9:9 | [post] access to local variable b [Box1, Elem] : Elem | | G.cs:9:23:9:23 | access to local variable e : Elem | G.cs:9:9:9:14 | [post] access to field Box1 [Elem] : Elem | -| G.cs:10:18:10:18 | access to local variable b [Box1, Elem] | G.cs:37:38:37:39 | b2 [Box1, Elem] | +| G.cs:10:18:10:18 | access to local variable b [Box1, Elem] : Elem | G.cs:37:38:37:39 | b2 [Box1, Elem] : Elem | | G.cs:15:18:15:27 | object creation of type Elem : Elem | G.cs:17:24:17:24 | access to local variable e : Elem | -| G.cs:17:9:17:9 | [post] access to local variable b [Box1, Elem] | G.cs:18:18:18:18 | access to local variable b [Box1, Elem] | -| G.cs:17:9:17:14 | [post] access to field Box1 [Elem] : Elem | G.cs:17:9:17:9 | [post] access to local variable b [Box1, Elem] | +| G.cs:17:9:17:9 | [post] access to local variable b [Box1, Elem] : Elem | G.cs:18:18:18:18 | access to local variable b [Box1, Elem] : Elem | +| G.cs:17:9:17:14 | [post] access to field Box1 [Elem] : Elem | G.cs:17:9:17:9 | [post] access to local variable b [Box1, Elem] : Elem | | G.cs:17:24:17:24 | access to local variable e : Elem | G.cs:17:9:17:14 | [post] access to field Box1 [Elem] : Elem | -| G.cs:18:18:18:18 | access to local variable b [Box1, Elem] | G.cs:37:38:37:39 | b2 [Box1, Elem] | +| G.cs:18:18:18:18 | access to local variable b [Box1, Elem] : Elem | G.cs:37:38:37:39 | b2 [Box1, Elem] : Elem | | G.cs:23:18:23:27 | object creation of type Elem : Elem | G.cs:25:28:25:28 | access to local variable e : Elem | -| G.cs:25:9:25:9 | [post] access to local variable b [Box1, Elem] | G.cs:26:18:26:18 | access to local variable b [Box1, Elem] | -| G.cs:25:9:25:19 | [post] call to method GetBox1 [Elem] : Elem | G.cs:25:9:25:9 | [post] access to local variable b [Box1, Elem] | +| G.cs:25:9:25:9 | [post] access to local variable b [Box1, Elem] : Elem | G.cs:26:18:26:18 | access to local variable b [Box1, Elem] : Elem | +| G.cs:25:9:25:19 | [post] call to method GetBox1 [Elem] : Elem | G.cs:25:9:25:9 | [post] access to local variable b [Box1, Elem] : Elem | | G.cs:25:28:25:28 | access to local variable e : Elem | G.cs:25:9:25:19 | [post] call to method GetBox1 [Elem] : Elem | -| G.cs:26:18:26:18 | access to local variable b [Box1, Elem] | G.cs:37:38:37:39 | b2 [Box1, Elem] | +| G.cs:26:18:26:18 | access to local variable b [Box1, Elem] : Elem | G.cs:37:38:37:39 | b2 [Box1, Elem] : Elem | | G.cs:31:18:31:27 | object creation of type Elem : Elem | G.cs:33:29:33:29 | access to local variable e : Elem | -| G.cs:33:9:33:9 | [post] access to local variable b [Box1, Elem] | G.cs:34:18:34:18 | access to local variable b [Box1, Elem] | -| G.cs:33:9:33:19 | [post] call to method GetBox1 [Elem] : Elem | G.cs:33:9:33:9 | [post] access to local variable b [Box1, Elem] | +| G.cs:33:9:33:9 | [post] access to local variable b [Box1, Elem] : Elem | G.cs:34:18:34:18 | access to local variable b [Box1, Elem] : Elem | +| G.cs:33:9:33:19 | [post] call to method GetBox1 [Elem] : Elem | G.cs:33:9:33:9 | [post] access to local variable b [Box1, Elem] : Elem | | G.cs:33:29:33:29 | access to local variable e : Elem | G.cs:33:9:33:19 | [post] call to method GetBox1 [Elem] : Elem | -| G.cs:34:18:34:18 | access to local variable b [Box1, Elem] | G.cs:37:38:37:39 | b2 [Box1, Elem] | -| G.cs:37:38:37:39 | b2 [Box1, Elem] | G.cs:39:14:39:15 | access to parameter b2 [Box1, Elem] | -| G.cs:39:14:39:15 | access to parameter b2 [Box1, Elem] | G.cs:39:14:39:25 | call to method GetBox1 [Elem] : Elem | +| G.cs:34:18:34:18 | access to local variable b [Box1, Elem] : Elem | G.cs:37:38:37:39 | b2 [Box1, Elem] : Elem | +| G.cs:37:38:37:39 | b2 [Box1, Elem] : Elem | G.cs:39:14:39:15 | access to parameter b2 [Box1, Elem] : Elem | +| G.cs:39:14:39:15 | access to parameter b2 [Box1, Elem] : Elem | G.cs:39:14:39:25 | call to method GetBox1 [Elem] : Elem | | G.cs:39:14:39:25 | call to method GetBox1 [Elem] : Elem | G.cs:39:14:39:35 | call to method GetElem | | G.cs:44:18:44:27 | object creation of type Elem : Elem | G.cs:46:30:46:30 | access to local variable e : Elem | -| G.cs:46:9:46:16 | [post] access to field boxfield [Box1, Elem] | G.cs:46:9:46:16 | [post] this access [boxfield, Box1, ... (3)] | -| G.cs:46:9:46:16 | [post] this access [boxfield, Box1, ... (3)] | G.cs:47:9:47:13 | this access [boxfield, Box1, ... (3)] | -| G.cs:46:9:46:21 | [post] access to field Box1 [Elem] : Elem | G.cs:46:9:46:16 | [post] access to field boxfield [Box1, Elem] | +| G.cs:46:9:46:16 | [post] access to field boxfield [Box1, Elem] : Elem | G.cs:46:9:46:16 | [post] this access [boxfield, Box1, Elem] : Elem | +| G.cs:46:9:46:16 | [post] this access [boxfield, Box1, Elem] : Elem | G.cs:47:9:47:13 | this access [boxfield, Box1, Elem] : Elem | +| G.cs:46:9:46:21 | [post] access to field Box1 [Elem] : Elem | G.cs:46:9:46:16 | [post] access to field boxfield [Box1, Elem] : Elem | | G.cs:46:30:46:30 | access to local variable e : Elem | G.cs:46:9:46:21 | [post] access to field Box1 [Elem] : Elem | -| G.cs:47:9:47:13 | this access [boxfield, Box1, ... (3)] | G.cs:50:18:50:20 | this [boxfield, Box1, ... (3)] | -| G.cs:50:18:50:20 | this [boxfield, Box1, ... (3)] | G.cs:52:14:52:21 | this access [boxfield, Box1, ... (3)] | -| G.cs:52:14:52:21 | access to field boxfield [Box1, Elem] | G.cs:52:14:52:26 | access to field Box1 [Elem] : Elem | -| G.cs:52:14:52:21 | this access [boxfield, Box1, ... (3)] | G.cs:52:14:52:21 | access to field boxfield [Box1, Elem] | +| G.cs:47:9:47:13 | this access [boxfield, Box1, Elem] : Elem | G.cs:50:18:50:20 | this [boxfield, Box1, Elem] : Elem | +| G.cs:50:18:50:20 | this [boxfield, Box1, Elem] : Elem | G.cs:52:14:52:21 | this access [boxfield, Box1, Elem] : Elem | +| G.cs:52:14:52:21 | access to field boxfield [Box1, Elem] : Elem | G.cs:52:14:52:26 | access to field Box1 [Elem] : Elem | +| G.cs:52:14:52:21 | this access [boxfield, Box1, Elem] : Elem | G.cs:52:14:52:21 | access to field boxfield [Box1, Elem] : Elem | | G.cs:52:14:52:26 | access to field Box1 [Elem] : Elem | G.cs:52:14:52:31 | access to field Elem | | H.cs:23:9:23:9 | [post] access to local variable a [FieldA] : Object | H.cs:24:27:24:27 | access to local variable a [FieldA] : Object | | H.cs:23:20:23:31 | object creation of type Object : Object | H.cs:23:9:23:9 | [post] access to local variable a [FieldA] : Object | @@ -201,20 +201,43 @@ edges | H.cs:131:18:131:18 | access to local variable a [FieldA] : Object | H.cs:131:14:131:19 | call to method Get | | H.cs:147:17:147:32 | call to method Through : A | H.cs:148:14:148:14 | access to local variable a | | H.cs:147:25:147:31 | object creation of type A : A | H.cs:147:17:147:32 | call to method Through : A | -| H.cs:155:17:155:23 | object creation of type B : B | H.cs:157:20:157:20 | access to local variable b : B | +| H.cs:155:17:155:23 | object creation of type B : B | H.cs:156:9:156:9 | access to local variable b : B | +| H.cs:156:9:156:9 | access to local variable b : B | H.cs:157:20:157:20 | access to local variable b : B | | H.cs:157:9:157:9 | [post] access to parameter a [FieldA] : B | H.cs:164:19:164:19 | [post] access to local variable a [FieldA] : B | | H.cs:157:20:157:20 | access to local variable b : B | H.cs:157:9:157:9 | [post] access to parameter a [FieldA] : B | | H.cs:163:17:163:28 | object creation of type Object : Object | H.cs:164:22:164:22 | access to local variable o : Object | -| H.cs:164:19:164:19 | [post] access to local variable a [FieldA, FieldB] | H.cs:165:21:165:21 | access to local variable a [FieldA, FieldB] | +| H.cs:164:19:164:19 | [post] access to local variable a [FieldA, FieldB] : Object | H.cs:165:21:165:21 | access to local variable a [FieldA, FieldB] : Object | | H.cs:164:19:164:19 | [post] access to local variable a [FieldA] : B | H.cs:165:21:165:21 | access to local variable a [FieldA] : B | -| H.cs:164:22:164:22 | access to local variable o : Object | H.cs:164:19:164:19 | [post] access to local variable a [FieldA, FieldB] | +| H.cs:164:22:164:22 | access to local variable o : Object | H.cs:164:19:164:19 | [post] access to local variable a [FieldA, FieldB] : Object | | H.cs:165:17:165:28 | (...) ... : B | H.cs:166:14:166:14 | access to local variable b | | H.cs:165:17:165:28 | (...) ... [FieldB] : Object | H.cs:167:14:167:14 | access to local variable b [FieldB] : Object | -| H.cs:165:21:165:21 | access to local variable a [FieldA, FieldB] | H.cs:165:21:165:28 | access to field FieldA [FieldB] : Object | +| H.cs:165:21:165:21 | access to local variable a [FieldA, FieldB] : Object | H.cs:165:21:165:28 | access to field FieldA [FieldB] : Object | | H.cs:165:21:165:21 | access to local variable a [FieldA] : B | H.cs:165:21:165:28 | access to field FieldA : B | | H.cs:165:21:165:28 | access to field FieldA : B | H.cs:165:17:165:28 | (...) ... : B | | H.cs:165:21:165:28 | access to field FieldA [FieldB] : Object | H.cs:165:17:165:28 | (...) ... [FieldB] : Object | | H.cs:167:14:167:14 | access to local variable b [FieldB] : Object | H.cs:167:14:167:21 | access to field FieldB | +| I.cs:7:9:7:14 | [post] this access [Field1] : Object | I.cs:21:13:21:19 | object creation of type I [Field1] : Object | +| I.cs:7:9:7:14 | [post] this access [Field1] : Object | I.cs:26:13:26:37 | [pre-initializer] object creation of type I [Field1] : Object | +| I.cs:7:18:7:29 | object creation of type Object : Object | I.cs:7:9:7:14 | [post] this access [Field1] : Object | +| I.cs:13:17:13:28 | object creation of type Object : Object | I.cs:15:20:15:20 | access to local variable o : Object | +| I.cs:15:9:15:9 | [post] access to local variable i [Field1] : Object | I.cs:16:9:16:9 | access to local variable i [Field1] : Object | +| I.cs:15:20:15:20 | access to local variable o : Object | I.cs:15:9:15:9 | [post] access to local variable i [Field1] : Object | +| I.cs:16:9:16:9 | access to local variable i [Field1] : Object | I.cs:17:9:17:9 | access to local variable i [Field1] : Object | +| I.cs:17:9:17:9 | access to local variable i [Field1] : Object | I.cs:18:14:18:14 | access to local variable i [Field1] : Object | +| I.cs:18:14:18:14 | access to local variable i [Field1] : Object | I.cs:18:14:18:21 | access to field Field1 | +| I.cs:21:13:21:19 | object creation of type I [Field1] : Object | I.cs:22:9:22:9 | access to local variable i [Field1] : Object | +| I.cs:22:9:22:9 | access to local variable i [Field1] : Object | I.cs:23:14:23:14 | access to local variable i [Field1] : Object | +| I.cs:23:14:23:14 | access to local variable i [Field1] : Object | I.cs:23:14:23:21 | access to field Field1 | +| I.cs:26:13:26:37 | [pre-initializer] object creation of type I [Field1] : Object | I.cs:27:14:27:14 | access to local variable i [Field1] : Object | +| I.cs:27:14:27:14 | access to local variable i [Field1] : Object | I.cs:27:14:27:21 | access to field Field1 | +| I.cs:31:13:31:24 | object creation of type Object : Object | I.cs:32:20:32:20 | access to local variable o : Object | +| I.cs:32:9:32:9 | [post] access to local variable i [Field1] : Object | I.cs:33:9:33:9 | access to local variable i [Field1] : Object | +| I.cs:32:20:32:20 | access to local variable o : Object | I.cs:32:9:32:9 | [post] access to local variable i [Field1] : Object | +| I.cs:33:9:33:9 | access to local variable i [Field1] : Object | I.cs:34:12:34:12 | access to local variable i [Field1] : Object | +| I.cs:34:12:34:12 | access to local variable i [Field1] : Object | I.cs:37:23:37:23 | i [Field1] : Object | +| I.cs:37:23:37:23 | i [Field1] : Object | I.cs:39:9:39:9 | access to parameter i [Field1] : Object | +| I.cs:39:9:39:9 | access to parameter i [Field1] : Object | I.cs:40:14:40:14 | access to parameter i [Field1] : Object | +| I.cs:40:14:40:14 | access to parameter i [Field1] : Object | I.cs:40:14:40:21 | access to field Field1 | nodes | A.cs:5:17:5:23 | object creation of type C : C | semmle.label | object creation of type C : C | | A.cs:6:17:6:25 | call to method Make [c] : C | semmle.label | call to method Make [c] : C | @@ -250,19 +273,19 @@ nodes | A.cs:89:14:89:16 | access to field c | semmle.label | access to field c | | A.cs:97:13:97:13 | [post] access to parameter b [c] : C | semmle.label | [post] access to parameter b [c] : C | | A.cs:97:19:97:25 | object creation of type C : C | semmle.label | object creation of type C : C | -| A.cs:98:13:98:16 | [post] this access [b, c] | semmle.label | [post] this access [b, c] | +| A.cs:98:13:98:16 | [post] this access [b, c] : C | semmle.label | [post] this access [b, c] : C | | A.cs:98:13:98:16 | [post] this access [b] : B | semmle.label | [post] this access [b] : B | | A.cs:98:22:98:36 | ... ? ... : ... : B | semmle.label | ... ? ... : ... : B | | A.cs:98:22:98:36 | ... ? ... : ... [c] : C | semmle.label | ... ? ... : ... [c] : C | | A.cs:98:30:98:36 | object creation of type B : B | semmle.label | object creation of type B : B | | A.cs:104:17:104:23 | object creation of type B : B | semmle.label | object creation of type B : B | -| A.cs:105:17:105:29 | object creation of type D [b, c] | semmle.label | object creation of type D [b, c] | +| A.cs:105:17:105:29 | object creation of type D [b, c] : C | semmle.label | object creation of type D [b, c] : C | | A.cs:105:17:105:29 | object creation of type D [b] : B | semmle.label | object creation of type D [b] : B | | A.cs:105:23:105:23 | [post] access to local variable b [c] : C | semmle.label | [post] access to local variable b [c] : C | | A.cs:105:23:105:23 | access to local variable b : B | semmle.label | access to local variable b : B | | A.cs:106:14:106:14 | access to local variable d [b] : B | semmle.label | access to local variable d [b] : B | | A.cs:106:14:106:16 | access to field b | semmle.label | access to field b | -| A.cs:107:14:107:14 | access to local variable d [b, c] | semmle.label | access to local variable d [b, c] | +| A.cs:107:14:107:14 | access to local variable d [b, c] : C | semmle.label | access to local variable d [b, c] : C | | A.cs:107:14:107:16 | access to field b [c] : C | semmle.label | access to field b [c] : C | | A.cs:107:14:107:18 | access to field c | semmle.label | access to field c | | A.cs:108:14:108:14 | access to local variable b [c] : C | semmle.label | access to local variable b [c] : C | @@ -270,34 +293,34 @@ nodes | A.cs:113:17:113:23 | object creation of type B : B | semmle.label | object creation of type B : B | | A.cs:114:18:114:54 | object creation of type MyList [head] : B | semmle.label | object creation of type MyList [head] : B | | A.cs:114:29:114:29 | access to local variable b : B | semmle.label | access to local variable b : B | -| A.cs:115:18:115:37 | object creation of type MyList [next, head] | semmle.label | object creation of type MyList [next, head] | +| A.cs:115:18:115:37 | object creation of type MyList [next, head] : B | semmle.label | object creation of type MyList [next, head] : B | | A.cs:115:35:115:36 | access to local variable l1 [head] : B | semmle.label | access to local variable l1 [head] : B | -| A.cs:116:18:116:37 | object creation of type MyList [next, next, ... (3)] | semmle.label | object creation of type MyList [next, next, ... (3)] | -| A.cs:116:35:116:36 | access to local variable l2 [next, head] | semmle.label | access to local variable l2 [next, head] | -| A.cs:119:14:119:15 | access to local variable l3 [next, next, ... (3)] | semmle.label | access to local variable l3 [next, next, ... (3)] | -| A.cs:119:14:119:20 | access to field next [next, head] | semmle.label | access to field next [next, head] | +| A.cs:116:18:116:37 | object creation of type MyList [next, next, head] : B | semmle.label | object creation of type MyList [next, next, head] : B | +| A.cs:116:35:116:36 | access to local variable l2 [next, head] : B | semmle.label | access to local variable l2 [next, head] : B | +| A.cs:119:14:119:15 | access to local variable l3 [next, next, head] : B | semmle.label | access to local variable l3 [next, next, head] : B | +| A.cs:119:14:119:20 | access to field next [next, head] : B | semmle.label | access to field next [next, head] : B | | A.cs:119:14:119:25 | access to field next [head] : B | semmle.label | access to field next [head] : B | | A.cs:119:14:119:30 | access to field head | semmle.label | access to field head | -| A.cs:121:41:121:41 | access to local variable l [next, head] | semmle.label | access to local variable l [next, head] | -| A.cs:121:41:121:41 | access to local variable l [next, next, ... (3)] | semmle.label | access to local variable l [next, next, ... (3)] | +| A.cs:121:41:121:41 | access to local variable l [next, head] : B | semmle.label | access to local variable l [next, head] : B | +| A.cs:121:41:121:41 | access to local variable l [next, next, head] : B | semmle.label | access to local variable l [next, next, head] : B | | A.cs:121:41:121:46 | access to field next [head] : B | semmle.label | access to field next [head] : B | -| A.cs:121:41:121:46 | access to field next [next, head] | semmle.label | access to field next [next, head] | +| A.cs:121:41:121:46 | access to field next [next, head] : B | semmle.label | access to field next [next, head] : B | | A.cs:123:18:123:18 | access to local variable l [head] : B | semmle.label | access to local variable l [head] : B | | A.cs:123:18:123:23 | access to field head | semmle.label | access to field head | | B.cs:5:17:5:26 | object creation of type Elem : Elem | semmle.label | object creation of type Elem : Elem | | B.cs:6:18:6:34 | object creation of type Box1 [elem1] : Elem | semmle.label | object creation of type Box1 [elem1] : Elem | | B.cs:6:27:6:27 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | -| B.cs:7:18:7:29 | object creation of type Box2 [box1, elem1] | semmle.label | object creation of type Box2 [box1, elem1] | +| B.cs:7:18:7:29 | object creation of type Box2 [box1, elem1] : Elem | semmle.label | object creation of type Box2 [box1, elem1] : Elem | | B.cs:7:27:7:28 | access to local variable b1 [elem1] : Elem | semmle.label | access to local variable b1 [elem1] : Elem | -| B.cs:8:14:8:15 | access to local variable b2 [box1, elem1] | semmle.label | access to local variable b2 [box1, elem1] | +| B.cs:8:14:8:15 | access to local variable b2 [box1, elem1] : Elem | semmle.label | access to local variable b2 [box1, elem1] : Elem | | B.cs:8:14:8:20 | access to field box1 [elem1] : Elem | semmle.label | access to field box1 [elem1] : Elem | | B.cs:8:14:8:26 | access to field elem1 | semmle.label | access to field elem1 | | B.cs:14:17:14:26 | object creation of type Elem : Elem | semmle.label | object creation of type Elem : Elem | | B.cs:15:18:15:34 | object creation of type Box1 [elem2] : Elem | semmle.label | object creation of type Box1 [elem2] : Elem | | B.cs:15:33:15:33 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | -| B.cs:16:18:16:29 | object creation of type Box2 [box1, elem2] | semmle.label | object creation of type Box2 [box1, elem2] | +| B.cs:16:18:16:29 | object creation of type Box2 [box1, elem2] : Elem | semmle.label | object creation of type Box2 [box1, elem2] : Elem | | B.cs:16:27:16:28 | access to local variable b1 [elem2] : Elem | semmle.label | access to local variable b1 [elem2] : Elem | -| B.cs:18:14:18:15 | access to local variable b2 [box1, elem2] | semmle.label | access to local variable b2 [box1, elem2] | +| B.cs:18:14:18:15 | access to local variable b2 [box1, elem2] : Elem | semmle.label | access to local variable b2 [box1, elem2] : Elem | | B.cs:18:14:18:20 | access to field box1 [elem2] : Elem | semmle.label | access to field box1 [elem2] : Elem | | B.cs:18:14:18:26 | access to field elem2 | semmle.label | access to field elem2 | | C.cs:3:18:3:19 | [post] this access [s1] : Elem | semmle.label | [post] this access [s1] : Elem | @@ -367,47 +390,47 @@ nodes | F.cs:15:26:15:26 | access to local variable o : Object | semmle.label | access to local variable o : Object | | F.cs:17:14:17:14 | access to local variable f [Field2] : Object | semmle.label | access to local variable f [Field2] : Object | | F.cs:17:14:17:21 | access to field Field2 | semmle.label | access to field Field2 | -| F.cs:19:13:19:34 | object creation of type F [Field1] : Object | semmle.label | object creation of type F [Field1] : Object | +| F.cs:19:21:19:34 | { ..., ... } [Field1] : Object | semmle.label | { ..., ... } [Field1] : Object | | F.cs:19:32:19:32 | access to local variable o : Object | semmle.label | access to local variable o : Object | | F.cs:20:14:20:14 | access to local variable f [Field1] : Object | semmle.label | access to local variable f [Field1] : Object | | F.cs:20:14:20:21 | access to field Field1 | semmle.label | access to field Field1 | -| F.cs:23:13:23:34 | object creation of type F [Field2] : Object | semmle.label | object creation of type F [Field2] : Object | +| F.cs:23:21:23:34 | { ..., ... } [Field2] : Object | semmle.label | { ..., ... } [Field2] : Object | | F.cs:23:32:23:32 | access to local variable o : Object | semmle.label | access to local variable o : Object | | F.cs:25:14:25:14 | access to local variable f [Field2] : Object | semmle.label | access to local variable f [Field2] : Object | | F.cs:25:14:25:21 | access to field Field2 | semmle.label | access to field Field2 | | G.cs:7:18:7:27 | object creation of type Elem : Elem | semmle.label | object creation of type Elem : Elem | -| G.cs:9:9:9:9 | [post] access to local variable b [Box1, Elem] | semmle.label | [post] access to local variable b [Box1, Elem] | +| G.cs:9:9:9:9 | [post] access to local variable b [Box1, Elem] : Elem | semmle.label | [post] access to local variable b [Box1, Elem] : Elem | | G.cs:9:9:9:14 | [post] access to field Box1 [Elem] : Elem | semmle.label | [post] access to field Box1 [Elem] : Elem | | G.cs:9:23:9:23 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | -| G.cs:10:18:10:18 | access to local variable b [Box1, Elem] | semmle.label | access to local variable b [Box1, Elem] | +| G.cs:10:18:10:18 | access to local variable b [Box1, Elem] : Elem | semmle.label | access to local variable b [Box1, Elem] : Elem | | G.cs:15:18:15:27 | object creation of type Elem : Elem | semmle.label | object creation of type Elem : Elem | -| G.cs:17:9:17:9 | [post] access to local variable b [Box1, Elem] | semmle.label | [post] access to local variable b [Box1, Elem] | +| G.cs:17:9:17:9 | [post] access to local variable b [Box1, Elem] : Elem | semmle.label | [post] access to local variable b [Box1, Elem] : Elem | | G.cs:17:9:17:14 | [post] access to field Box1 [Elem] : Elem | semmle.label | [post] access to field Box1 [Elem] : Elem | | G.cs:17:24:17:24 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | -| G.cs:18:18:18:18 | access to local variable b [Box1, Elem] | semmle.label | access to local variable b [Box1, Elem] | +| G.cs:18:18:18:18 | access to local variable b [Box1, Elem] : Elem | semmle.label | access to local variable b [Box1, Elem] : Elem | | G.cs:23:18:23:27 | object creation of type Elem : Elem | semmle.label | object creation of type Elem : Elem | -| G.cs:25:9:25:9 | [post] access to local variable b [Box1, Elem] | semmle.label | [post] access to local variable b [Box1, Elem] | +| G.cs:25:9:25:9 | [post] access to local variable b [Box1, Elem] : Elem | semmle.label | [post] access to local variable b [Box1, Elem] : Elem | | G.cs:25:9:25:19 | [post] call to method GetBox1 [Elem] : Elem | semmle.label | [post] call to method GetBox1 [Elem] : Elem | | G.cs:25:28:25:28 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | -| G.cs:26:18:26:18 | access to local variable b [Box1, Elem] | semmle.label | access to local variable b [Box1, Elem] | +| G.cs:26:18:26:18 | access to local variable b [Box1, Elem] : Elem | semmle.label | access to local variable b [Box1, Elem] : Elem | | G.cs:31:18:31:27 | object creation of type Elem : Elem | semmle.label | object creation of type Elem : Elem | -| G.cs:33:9:33:9 | [post] access to local variable b [Box1, Elem] | semmle.label | [post] access to local variable b [Box1, Elem] | +| G.cs:33:9:33:9 | [post] access to local variable b [Box1, Elem] : Elem | semmle.label | [post] access to local variable b [Box1, Elem] : Elem | | G.cs:33:9:33:19 | [post] call to method GetBox1 [Elem] : Elem | semmle.label | [post] call to method GetBox1 [Elem] : Elem | | G.cs:33:29:33:29 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | -| G.cs:34:18:34:18 | access to local variable b [Box1, Elem] | semmle.label | access to local variable b [Box1, Elem] | -| G.cs:37:38:37:39 | b2 [Box1, Elem] | semmle.label | b2 [Box1, Elem] | -| G.cs:39:14:39:15 | access to parameter b2 [Box1, Elem] | semmle.label | access to parameter b2 [Box1, Elem] | +| G.cs:34:18:34:18 | access to local variable b [Box1, Elem] : Elem | semmle.label | access to local variable b [Box1, Elem] : Elem | +| G.cs:37:38:37:39 | b2 [Box1, Elem] : Elem | semmle.label | b2 [Box1, Elem] : Elem | +| G.cs:39:14:39:15 | access to parameter b2 [Box1, Elem] : Elem | semmle.label | access to parameter b2 [Box1, Elem] : Elem | | G.cs:39:14:39:25 | call to method GetBox1 [Elem] : Elem | semmle.label | call to method GetBox1 [Elem] : Elem | | G.cs:39:14:39:35 | call to method GetElem | semmle.label | call to method GetElem | | G.cs:44:18:44:27 | object creation of type Elem : Elem | semmle.label | object creation of type Elem : Elem | -| G.cs:46:9:46:16 | [post] access to field boxfield [Box1, Elem] | semmle.label | [post] access to field boxfield [Box1, Elem] | -| G.cs:46:9:46:16 | [post] this access [boxfield, Box1, ... (3)] | semmle.label | [post] this access [boxfield, Box1, ... (3)] | +| G.cs:46:9:46:16 | [post] access to field boxfield [Box1, Elem] : Elem | semmle.label | [post] access to field boxfield [Box1, Elem] : Elem | +| G.cs:46:9:46:16 | [post] this access [boxfield, Box1, Elem] : Elem | semmle.label | [post] this access [boxfield, Box1, Elem] : Elem | | G.cs:46:9:46:21 | [post] access to field Box1 [Elem] : Elem | semmle.label | [post] access to field Box1 [Elem] : Elem | | G.cs:46:30:46:30 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | -| G.cs:47:9:47:13 | this access [boxfield, Box1, ... (3)] | semmle.label | this access [boxfield, Box1, ... (3)] | -| G.cs:50:18:50:20 | this [boxfield, Box1, ... (3)] | semmle.label | this [boxfield, Box1, ... (3)] | -| G.cs:52:14:52:21 | access to field boxfield [Box1, Elem] | semmle.label | access to field boxfield [Box1, Elem] | -| G.cs:52:14:52:21 | this access [boxfield, Box1, ... (3)] | semmle.label | this access [boxfield, Box1, ... (3)] | +| G.cs:47:9:47:13 | this access [boxfield, Box1, Elem] : Elem | semmle.label | this access [boxfield, Box1, Elem] : Elem | +| G.cs:50:18:50:20 | this [boxfield, Box1, Elem] : Elem | semmle.label | this [boxfield, Box1, Elem] : Elem | +| G.cs:52:14:52:21 | access to field boxfield [Box1, Elem] : Elem | semmle.label | access to field boxfield [Box1, Elem] : Elem | +| G.cs:52:14:52:21 | this access [boxfield, Box1, Elem] : Elem | semmle.label | this access [boxfield, Box1, Elem] : Elem | | G.cs:52:14:52:26 | access to field Box1 [Elem] : Elem | semmle.label | access to field Box1 [Elem] : Elem | | G.cs:52:14:52:31 | access to field Elem | semmle.label | access to field Elem | | H.cs:23:9:23:9 | [post] access to local variable a [FieldA] : Object | semmle.label | [post] access to local variable a [FieldA] : Object | @@ -449,21 +472,47 @@ nodes | H.cs:147:25:147:31 | object creation of type A : A | semmle.label | object creation of type A : A | | H.cs:148:14:148:14 | access to local variable a | semmle.label | access to local variable a | | H.cs:155:17:155:23 | object creation of type B : B | semmle.label | object creation of type B : B | +| H.cs:156:9:156:9 | access to local variable b : B | semmle.label | access to local variable b : B | | H.cs:157:9:157:9 | [post] access to parameter a [FieldA] : B | semmle.label | [post] access to parameter a [FieldA] : B | | H.cs:157:20:157:20 | access to local variable b : B | semmle.label | access to local variable b : B | | H.cs:163:17:163:28 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | -| H.cs:164:19:164:19 | [post] access to local variable a [FieldA, FieldB] | semmle.label | [post] access to local variable a [FieldA, FieldB] | +| H.cs:164:19:164:19 | [post] access to local variable a [FieldA, FieldB] : Object | semmle.label | [post] access to local variable a [FieldA, FieldB] : Object | | H.cs:164:19:164:19 | [post] access to local variable a [FieldA] : B | semmle.label | [post] access to local variable a [FieldA] : B | | H.cs:164:22:164:22 | access to local variable o : Object | semmle.label | access to local variable o : Object | | H.cs:165:17:165:28 | (...) ... : B | semmle.label | (...) ... : B | | H.cs:165:17:165:28 | (...) ... [FieldB] : Object | semmle.label | (...) ... [FieldB] : Object | -| H.cs:165:21:165:21 | access to local variable a [FieldA, FieldB] | semmle.label | access to local variable a [FieldA, FieldB] | +| H.cs:165:21:165:21 | access to local variable a [FieldA, FieldB] : Object | semmle.label | access to local variable a [FieldA, FieldB] : Object | | H.cs:165:21:165:21 | access to local variable a [FieldA] : B | semmle.label | access to local variable a [FieldA] : B | | H.cs:165:21:165:28 | access to field FieldA : B | semmle.label | access to field FieldA : B | | H.cs:165:21:165:28 | access to field FieldA [FieldB] : Object | semmle.label | access to field FieldA [FieldB] : Object | | H.cs:166:14:166:14 | access to local variable b | semmle.label | access to local variable b | | H.cs:167:14:167:14 | access to local variable b [FieldB] : Object | semmle.label | access to local variable b [FieldB] : Object | | H.cs:167:14:167:21 | access to field FieldB | semmle.label | access to field FieldB | +| I.cs:7:9:7:14 | [post] this access [Field1] : Object | semmle.label | [post] this access [Field1] : Object | +| I.cs:7:18:7:29 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| I.cs:13:17:13:28 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| I.cs:15:9:15:9 | [post] access to local variable i [Field1] : Object | semmle.label | [post] access to local variable i [Field1] : Object | +| I.cs:15:20:15:20 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| I.cs:16:9:16:9 | access to local variable i [Field1] : Object | semmle.label | access to local variable i [Field1] : Object | +| I.cs:17:9:17:9 | access to local variable i [Field1] : Object | semmle.label | access to local variable i [Field1] : Object | +| I.cs:18:14:18:14 | access to local variable i [Field1] : Object | semmle.label | access to local variable i [Field1] : Object | +| I.cs:18:14:18:21 | access to field Field1 | semmle.label | access to field Field1 | +| I.cs:21:13:21:19 | object creation of type I [Field1] : Object | semmle.label | object creation of type I [Field1] : Object | +| I.cs:22:9:22:9 | access to local variable i [Field1] : Object | semmle.label | access to local variable i [Field1] : Object | +| I.cs:23:14:23:14 | access to local variable i [Field1] : Object | semmle.label | access to local variable i [Field1] : Object | +| I.cs:23:14:23:21 | access to field Field1 | semmle.label | access to field Field1 | +| I.cs:26:13:26:37 | [pre-initializer] object creation of type I [Field1] : Object | semmle.label | [pre-initializer] object creation of type I [Field1] : Object | +| I.cs:27:14:27:14 | access to local variable i [Field1] : Object | semmle.label | access to local variable i [Field1] : Object | +| I.cs:27:14:27:21 | access to field Field1 | semmle.label | access to field Field1 | +| I.cs:31:13:31:24 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| I.cs:32:9:32:9 | [post] access to local variable i [Field1] : Object | semmle.label | [post] access to local variable i [Field1] : Object | +| I.cs:32:20:32:20 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| I.cs:33:9:33:9 | access to local variable i [Field1] : Object | semmle.label | access to local variable i [Field1] : Object | +| I.cs:34:12:34:12 | access to local variable i [Field1] : Object | semmle.label | access to local variable i [Field1] : Object | +| I.cs:37:23:37:23 | i [Field1] : Object | semmle.label | i [Field1] : Object | +| I.cs:39:9:39:9 | access to parameter i [Field1] : Object | semmle.label | access to parameter i [Field1] : Object | +| I.cs:40:14:40:14 | access to parameter i [Field1] : Object | semmle.label | access to parameter i [Field1] : Object | +| I.cs:40:14:40:21 | access to field Field1 | semmle.label | access to field Field1 | #select | A.cs:7:14:7:16 | access to field c | A.cs:5:17:5:23 | object creation of type C : C | A.cs:7:14:7:16 | access to field c | $@ | A.cs:5:17:5:23 | object creation of type C : C | object creation of type C : C | | A.cs:14:14:14:20 | call to method Get | A.cs:13:15:13:22 | object creation of type C1 : C1 | A.cs:14:14:14:20 | call to method Get | $@ | A.cs:13:15:13:22 | object creation of type C1 : C1 | object creation of type C1 : C1 | @@ -513,3 +562,7 @@ nodes | H.cs:148:14:148:14 | access to local variable a | H.cs:147:25:147:31 | object creation of type A : A | H.cs:148:14:148:14 | access to local variable a | $@ | H.cs:147:25:147:31 | object creation of type A : A | object creation of type A : A | | H.cs:166:14:166:14 | access to local variable b | H.cs:155:17:155:23 | object creation of type B : B | H.cs:166:14:166:14 | access to local variable b | $@ | H.cs:155:17:155:23 | object creation of type B : B | object creation of type B : B | | H.cs:167:14:167:21 | access to field FieldB | H.cs:163:17:163:28 | object creation of type Object : Object | H.cs:167:14:167:21 | access to field FieldB | $@ | H.cs:163:17:163:28 | object creation of type Object : Object | object creation of type Object : Object | +| I.cs:18:14:18:21 | access to field Field1 | I.cs:13:17:13:28 | object creation of type Object : Object | I.cs:18:14:18:21 | access to field Field1 | $@ | I.cs:13:17:13:28 | object creation of type Object : Object | object creation of type Object : Object | +| I.cs:23:14:23:21 | access to field Field1 | I.cs:7:18:7:29 | object creation of type Object : Object | I.cs:23:14:23:21 | access to field Field1 | $@ | I.cs:7:18:7:29 | object creation of type Object : Object | object creation of type Object : Object | +| I.cs:27:14:27:21 | access to field Field1 | I.cs:7:18:7:29 | object creation of type Object : Object | I.cs:27:14:27:21 | access to field Field1 | $@ | I.cs:7:18:7:29 | object creation of type Object : Object | object creation of type Object : Object | +| I.cs:40:14:40:21 | access to field Field1 | I.cs:31:13:31:24 | object creation of type Object : Object | I.cs:40:14:40:21 | access to field Field1 | $@ | I.cs:31:13:31:24 | object creation of type Object : Object | object creation of type Object : Object | diff --git a/csharp/ql/test/library-tests/dataflow/fields/I.cs b/csharp/ql/test/library-tests/dataflow/fields/I.cs new file mode 100644 index 000000000000..99aed3b0df7b --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/fields/I.cs @@ -0,0 +1,46 @@ +public class I +{ + object Field1; + object Field2; + public I() + { + Field1 = new object(); + Field2 = new object(); + } + + private void M() + { + var o = new object(); + var i = new I(); + i.Field1 = o; + i.Field2 = o; + i.Field2 = null; + Sink(i.Field1); // flow + Sink(i.Field2); // no flow + + i = new I(); + i.Field2 = null; + Sink(i.Field1); // flow + Sink(i.Field2); // no flow + + i = new I() { Field2 = null }; + Sink(i.Field1); // flow + Sink(i.Field2); // no flow + + i = new I(); + o = new object(); + i.Field1 = o; + i.Field2 = o; + M2(i); + } + + private void M2(I i) + { + i.Field2 = null; + Sink(i.Field1); // flow + Sink(i.Field2); // no flow + + } + + public static void Sink(object o) { } +} diff --git a/csharp/ql/test/library-tests/dataflow/global/Common.qll b/csharp/ql/test/library-tests/dataflow/global/Common.qll index 1ecaebd9f949..17d4b2208763 100644 --- a/csharp/ql/test/library-tests/dataflow/global/Common.qll +++ b/csharp/ql/test/library-tests/dataflow/global/Common.qll @@ -10,10 +10,9 @@ class Config extends DataFlow::Configuration { } override predicate isSink(DataFlow::Node sink) { - sink.asExpr() instanceof Access and exists(MethodCall mc | mc.getTarget().getName() = "Check" and - mc.getAnArgument() = sink.asExpr().getParent*() + mc.getAnArgument() = sink.asExpr() ) } } diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected b/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected index ca81fb559045..596f6f532743 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected @@ -12,35 +12,53 @@ | Capture.cs:161:15:161:20 | access to local variable sink36 | | Capture.cs:169:15:169:20 | access to local variable sink37 | | Capture.cs:195:15:195:20 | access to local variable sink38 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | -| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | -| GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | -| GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | -| GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | -| GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | -| GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | -| GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | +| GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | +| GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | +| GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | +| GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | +| GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | +| GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | +| GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | +| GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | +| GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | +| GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | +| GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | +| GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | +| GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | +| GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | +| GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | +| GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | +| GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | +| GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | +| GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | +| GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | +| GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | +| GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | +| GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | +| GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | +| GlobalDataFlow.cs:240:15:240:20 | access to local variable sink41 | +| GlobalDataFlow.cs:242:15:242:20 | access to local variable sink42 | +| GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:272:15:272:24 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:277:15:277:24 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:282:15:282:24 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:287:15:287:24 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:314:15:314:24 | access to parameter sinkParam8 | +| GlobalDataFlow.cs:320:15:320:24 | access to parameter sinkParam9 | +| GlobalDataFlow.cs:326:15:326:25 | access to parameter sinkParam11 | +| GlobalDataFlow.cs:401:15:401:20 | access to local variable sink11 | +| GlobalDataFlow.cs:424:41:424:46 | access to local variable sink20 | | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:21:28:21:32 | access to parameter value | +| Splitting.cs:21:21:21:33 | call to method Return | | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | | Splitting.cs:34:19:34:19 | access to local variable x | +| Splitting.cs:41:19:41:19 | access to local variable s | +| Splitting.cs:43:19:43:19 | access to local variable s | +| Splitting.cs:50:19:50:19 | access to local variable s | +| Splitting.cs:52:19:52:19 | access to local variable s | diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected index a46026ba3da8..c13ef765d937 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected @@ -1,189 +1,226 @@ edges -| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:14:9:14:20 | [implicit argument] tainted : String | -| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:25:9:25:20 | [implicit argument] tainted : String | -| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:33:9:33:40 | [implicit argument] tainted : String | +| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:12:19:12:24 | access to local variable sink27 | +| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:21:23:21:28 | access to local variable sink28 | +| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:30:19:30:24 | access to local variable sink29 | | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:61:36:61:42 | access to parameter tainted : String | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:12:19:12:24 | access to local variable sink27 | -| Capture.cs:14:9:14:20 | [implicit argument] tainted : String | Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:21:23:21:28 | access to local variable sink28 | -| Capture.cs:25:9:25:20 | [implicit argument] tainted : String | Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:30:19:30:24 | access to local variable sink29 | -| Capture.cs:33:9:33:40 | [implicit argument] tainted : String | Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | -| Capture.cs:50:50:50:55 | sink39 : String | Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | -| Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | -| Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | Capture.cs:57:27:57:32 | access to parameter sink39 | +| Capture.cs:50:50:50:55 | sink39 : String | Capture.cs:57:27:57:32 | access to parameter sink39 | | Capture.cs:61:36:61:42 | access to parameter tainted : String | Capture.cs:50:50:50:55 | sink39 : String | -| Capture.cs:69:13:69:35 | SSA def(sink30) : String | Capture.cs:71:9:71:21 | SSA call def(sink30) : String | +| Capture.cs:69:13:69:35 | SSA def(sink30) : String | Capture.cs:72:15:72:20 | access to local variable sink30 | | Capture.cs:69:22:69:35 | "taint source" : String | Capture.cs:69:13:69:35 | SSA def(sink30) : String | -| Capture.cs:71:9:71:21 | SSA call def(sink30) : String | Capture.cs:72:15:72:20 | access to local variable sink30 | -| Capture.cs:79:17:79:39 | SSA def(sink31) : String | Capture.cs:83:9:83:21 | SSA call def(sink31) : String | +| Capture.cs:79:17:79:39 | SSA def(sink31) : String | Capture.cs:84:15:84:20 | access to local variable sink31 | | Capture.cs:79:26:79:39 | "taint source" : String | Capture.cs:79:17:79:39 | SSA def(sink31) : String | -| Capture.cs:83:9:83:21 | SSA call def(sink31) : String | Capture.cs:84:15:84:20 | access to local variable sink31 | -| Capture.cs:89:13:89:35 | SSA def(sink32) : String | Capture.cs:92:9:92:41 | SSA call def(sink32) : String | +| Capture.cs:89:13:89:35 | SSA def(sink32) : String | Capture.cs:93:15:93:20 | access to local variable sink32 | | Capture.cs:89:22:89:35 | "taint source" : String | Capture.cs:89:13:89:35 | SSA def(sink32) : String | -| Capture.cs:92:9:92:41 | SSA call def(sink32) : String | Capture.cs:93:15:93:20 | access to local variable sink32 | -| Capture.cs:115:17:115:39 | SSA def(sink40) : String | Capture.cs:121:9:121:35 | SSA call def(sink40) : String | +| Capture.cs:115:17:115:39 | SSA def(sink40) : String | Capture.cs:122:15:122:20 | access to local variable sink40 | | Capture.cs:115:26:115:39 | "taint source" : String | Capture.cs:115:17:115:39 | SSA def(sink40) : String | -| Capture.cs:121:9:121:35 | SSA call def(sink40) : String | Capture.cs:122:15:122:20 | access to local variable sink40 | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:132:9:132:25 | [implicit argument] tainted : String | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:144:9:144:25 | [implicit argument] tainted : String | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:153:9:153:45 | [implicit argument] tainted : String | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:160:22:160:38 | [implicit argument] tainted : String | +| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:133:15:133:20 | access to local variable sink33 | +| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:145:15:145:20 | access to local variable sink34 | +| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:154:15:154:20 | access to local variable sink35 | +| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:168:25:168:31 | access to parameter tainted : String | | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:194:25:194:31 | access to parameter tainted : String | -| Capture.cs:132:9:132:25 | SSA call def(sink33) : String | Capture.cs:133:15:133:20 | access to local variable sink33 | -| Capture.cs:132:9:132:25 | [implicit argument] tainted : String | Capture.cs:132:9:132:25 | SSA call def(sink33) : String | -| Capture.cs:144:9:144:25 | SSA call def(sink34) : String | Capture.cs:145:15:145:20 | access to local variable sink34 | -| Capture.cs:144:9:144:25 | [implicit argument] tainted : String | Capture.cs:144:9:144:25 | SSA call def(sink34) : String | -| Capture.cs:153:9:153:45 | SSA call def(sink35) : String | Capture.cs:154:15:154:20 | access to local variable sink35 | -| Capture.cs:153:9:153:45 | [implicit argument] tainted : String | Capture.cs:153:9:153:45 | SSA call def(sink35) : String | -| Capture.cs:160:22:160:38 | [implicit argument] tainted : String | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | Capture.cs:161:15:161:20 | access to local variable sink36 | -| Capture.cs:168:9:168:32 | SSA call def(sink37) : String | Capture.cs:169:15:169:20 | access to local variable sink37 | -| Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:168:9:168:32 | SSA call def(sink37) : String | +| Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:169:15:169:20 | access to local variable sink37 | | Capture.cs:194:22:194:32 | call to local function Id : String | Capture.cs:195:15:195:20 | access to local variable sink38 | | Capture.cs:194:25:194:31 | access to parameter tainted : String | Capture.cs:194:22:194:32 | call to local function Id : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:242:26:242:35 | sinkParam1 : String | -| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:361:41:361:41 | x : String | -| GlobalDataFlow.cs:53:15:53:15 | x : String | GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | GlobalDataFlow.cs:252:26:252:35 | sinkParam4 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:361:41:361:41 | x : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:375:52:375:52 | x : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:375:52:375:52 | x : String | -| GlobalDataFlow.cs:56:37:56:37 | x : String | GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:375:52:375:52 | x : String | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:406:9:406:11 | value : String | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | GlobalDataFlow.cs:135:21:135:34 | delegate call : String | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | -| GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | -| GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | GlobalDataFlow.cs:180:21:180:26 | delegate call : String | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | -| GlobalDataFlow.cs:189:22:189:42 | [library code] object creation of type Lazy : String | GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy [Value] : String | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy [Value] : String | GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | -| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:189:22:189:42 | [library code] object creation of type Lazy : String | -| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | -| GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | -| GlobalDataFlow.cs:242:26:242:35 | sinkParam1 : String | GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:252:26:252:35 | sinkParam4 : String | GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | -| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | -| GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | -| GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | -| GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | -| GlobalDataFlow.cs:361:41:361:41 | x : String | GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | -| GlobalDataFlow.cs:361:41:361:41 | x : String | GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | -| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | GlobalDataFlow.cs:53:15:53:15 | x : String | -| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | -| GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | -| GlobalDataFlow.cs:406:9:406:11 | value : String | GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | -| GlobalDataFlow.cs:417:22:417:35 | "taint source" : String | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:254:26:254:35 | sinkParam0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:260:26:260:35 | sinkParam1 : String | +| GlobalDataFlow.cs:45:30:45:39 | sinkParam2 : String | GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:30:45:39 | sinkParam2 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:379:41:379:41 | x : String | +| GlobalDataFlow.cs:54:15:54:15 | x : String | GlobalDataFlow.cs:54:24:54:24 | access to parameter x : String | +| GlobalDataFlow.cs:54:24:54:24 | access to parameter x : String | GlobalDataFlow.cs:270:26:270:35 | sinkParam4 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:379:41:379:41 | x : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:393:52:393:52 | x : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:393:52:393:52 | x : String | +| GlobalDataFlow.cs:57:37:57:37 | x : String | GlobalDataFlow.cs:57:46:57:46 | access to parameter x : String | +| GlobalDataFlow.cs:57:46:57:46 | access to parameter x : String | GlobalDataFlow.cs:285:26:285:35 | sinkParam7 : String | +| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:393:52:393:52 | x : String | +| GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:424:9:424:11 | value : String | +| GlobalDataFlow.cs:71:21:71:46 | call to method Return : String | GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | +| GlobalDataFlow.cs:71:21:71:46 | call to method Return : String | GlobalDataFlow.cs:73:94:73:98 | access to local variable sink0 : String | +| GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:21:71:46 | call to method Return : String | +| GlobalDataFlow.cs:73:21:73:101 | (...) ... : String | GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | +| GlobalDataFlow.cs:73:21:73:101 | (...) ... : String | GlobalDataFlow.cs:76:19:76:23 | access to local variable sink1 : String | +| GlobalDataFlow.cs:73:29:73:101 | call to method Invoke : String | GlobalDataFlow.cs:73:21:73:101 | (...) ... : String | +| GlobalDataFlow.cs:73:94:73:98 | access to local variable sink0 : String | GlobalDataFlow.cs:73:29:73:101 | call to method Invoke : String | +| GlobalDataFlow.cs:76:19:76:23 | access to local variable sink1 : String | GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) : String | +| GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) : String | GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | +| GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) : String | GlobalDataFlow.cs:79:19:79:23 | access to local variable sink2 : String | +| GlobalDataFlow.cs:79:19:79:23 | access to local variable sink2 : String | GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | +| GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | +| GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | GlobalDataFlow.cs:81:59:81:63 | access to local variable sink3 : String | +| GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | GlobalDataFlow.cs:136:29:136:33 | access to local variable sink3 : String | +| GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven [[]] : String | GlobalDataFlow.cs:81:22:81:93 | call to method First : String | +| GlobalDataFlow.cs:81:22:81:93 | call to method First : String | GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | +| GlobalDataFlow.cs:81:22:81:93 | call to method First : String | GlobalDataFlow.cs:83:59:83:64 | access to local variable sink13 : String | +| GlobalDataFlow.cs:81:23:81:65 | (...) ... [[]] : String | GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven [[]] : String | +| GlobalDataFlow.cs:81:57:81:65 | { ..., ... } [[]] : String | GlobalDataFlow.cs:81:23:81:65 | (...) ... [[]] : String | +| GlobalDataFlow.cs:81:59:81:63 | access to local variable sink3 : String | GlobalDataFlow.cs:81:57:81:65 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:83:22:83:87 | call to method Select [[]] : String | GlobalDataFlow.cs:83:22:83:95 | call to method First : String | +| GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | +| GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:85:59:85:64 | access to local variable sink14 : String | +| GlobalDataFlow.cs:83:23:83:66 | (...) ... [[]] : String | GlobalDataFlow.cs:83:22:83:87 | call to method Select [[]] : String | +| GlobalDataFlow.cs:83:23:83:66 | (...) ... [[]] : String | GlobalDataFlow.cs:312:31:312:40 | sinkParam8 : String | +| GlobalDataFlow.cs:83:57:83:66 | { ..., ... } [[]] : String | GlobalDataFlow.cs:83:23:83:66 | (...) ... [[]] : String | +| GlobalDataFlow.cs:83:59:83:64 | access to local variable sink13 : String | GlobalDataFlow.cs:83:57:83:66 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:85:22:85:128 | call to method Zip [[]] : String | GlobalDataFlow.cs:85:22:85:136 | call to method First : String | +| GlobalDataFlow.cs:85:22:85:136 | call to method First : String | GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | +| GlobalDataFlow.cs:85:22:85:136 | call to method First : String | GlobalDataFlow.cs:87:106:87:111 | access to local variable sink15 : String | +| GlobalDataFlow.cs:85:23:85:66 | (...) ... [[]] : String | GlobalDataFlow.cs:85:22:85:128 | call to method Zip [[]] : String | +| GlobalDataFlow.cs:85:57:85:66 | { ..., ... } [[]] : String | GlobalDataFlow.cs:85:23:85:66 | (...) ... [[]] : String | +| GlobalDataFlow.cs:85:59:85:64 | access to local variable sink14 : String | GlobalDataFlow.cs:85:57:85:66 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:87:22:87:128 | call to method Zip [[]] : String | GlobalDataFlow.cs:87:22:87:136 | call to method First : String | +| GlobalDataFlow.cs:87:22:87:136 | call to method First : String | GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | +| GlobalDataFlow.cs:87:70:87:113 | (...) ... [[]] : String | GlobalDataFlow.cs:87:22:87:128 | call to method Zip [[]] : String | +| GlobalDataFlow.cs:87:104:87:113 | { ..., ... } [[]] : String | GlobalDataFlow.cs:87:70:87:113 | (...) ... [[]] : String | +| GlobalDataFlow.cs:87:106:87:111 | access to local variable sink15 : String | GlobalDataFlow.cs:87:104:87:113 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:136:21:136:34 | delegate call : String | GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | +| GlobalDataFlow.cs:136:21:136:34 | delegate call : String | GlobalDataFlow.cs:144:39:144:43 | access to local variable sink4 : String | +| GlobalDataFlow.cs:136:29:136:33 | access to local variable sink3 : String | GlobalDataFlow.cs:136:21:136:34 | delegate call : String | +| GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | +| GlobalDataFlow.cs:144:39:144:43 | access to local variable sink4 : String | GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc : String | +| GlobalDataFlow.cs:154:21:154:25 | call to method Out : String | GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | +| GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) : String | GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | +| GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) : String | GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | +| GlobalDataFlow.cs:162:22:162:31 | call to method OutYield [[]] : String | GlobalDataFlow.cs:162:22:162:39 | call to method First : String | +| GlobalDataFlow.cs:162:22:162:39 | call to method First : String | GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | +| GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam : String | GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | +| GlobalDataFlow.cs:180:35:180:48 | "taint source" : String | GlobalDataFlow.cs:181:21:181:26 | delegate call : String | +| GlobalDataFlow.cs:181:21:181:26 | delegate call : String | GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | +| GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy [Value] : String | GlobalDataFlow.cs:190:22:190:48 | access to property Value : String | +| GlobalDataFlow.cs:190:22:190:48 | access to property Value : String | GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | +| GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty : String | GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | +| GlobalDataFlow.cs:208:38:208:61 | array creation of type String[] [[]] : String | GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | +| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [[]] : String | +| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [[]] : String | +| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [[]] : String | +| GlobalDataFlow.cs:208:44:208:61 | { ..., ... } [[]] : String | GlobalDataFlow.cs:208:38:208:61 | array creation of type String[] [[]] : String | +| GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:208:44:208:61 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:211:35:211:45 | sinkParam10 : String | GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | +| GlobalDataFlow.cs:212:71:212:71 | x : String | GlobalDataFlow.cs:212:89:212:89 | access to parameter x : String | +| GlobalDataFlow.cs:212:89:212:89 | access to parameter x : String | GlobalDataFlow.cs:318:32:318:41 | sinkParam9 : String | +| GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:211:35:211:45 | sinkParam10 : String | +| GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:213:22:213:39 | call to method Select [[]] : String | +| GlobalDataFlow.cs:213:22:213:39 | call to method Select [[]] : String | GlobalDataFlow.cs:213:22:213:47 | call to method First : String | +| GlobalDataFlow.cs:213:22:213:47 | call to method First : String | GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | +| GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:212:71:212:71 | x : String | +| GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:215:22:215:39 | call to method Select [[]] : String | +| GlobalDataFlow.cs:215:22:215:39 | call to method Select [[]] : String | GlobalDataFlow.cs:215:22:215:47 | call to method First : String | +| GlobalDataFlow.cs:215:22:215:47 | call to method First : String | GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | +| GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:217:22:217:49 | call to method Select [[]] : String | +| GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:324:32:324:42 | sinkParam11 : String | +| GlobalDataFlow.cs:217:22:217:49 | call to method Select [[]] : String | GlobalDataFlow.cs:217:22:217:57 | call to method First : String | +| GlobalDataFlow.cs:217:22:217:57 | call to method First : String | GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | +| GlobalDataFlow.cs:238:20:238:49 | call to method Run [Result] : String | GlobalDataFlow.cs:239:22:239:25 | access to local variable task [Result] : String | +| GlobalDataFlow.cs:238:20:238:49 | call to method Run [Result] : String | GlobalDataFlow.cs:241:28:241:31 | access to local variable task [Result] : String | +| GlobalDataFlow.cs:238:35:238:48 | "taint source" : String | GlobalDataFlow.cs:238:20:238:49 | call to method Run [Result] : String | +| GlobalDataFlow.cs:239:22:239:25 | access to local variable task [Result] : String | GlobalDataFlow.cs:239:22:239:32 | access to property Result : String | +| GlobalDataFlow.cs:239:22:239:32 | access to property Result : String | GlobalDataFlow.cs:240:15:240:20 | access to local variable sink41 | +| GlobalDataFlow.cs:241:22:241:31 | await ... : String | GlobalDataFlow.cs:242:15:242:20 | access to local variable sink42 | +| GlobalDataFlow.cs:241:28:241:31 | access to local variable task [Result] : String | GlobalDataFlow.cs:241:22:241:31 | await ... : String | +| GlobalDataFlow.cs:254:26:254:35 | sinkParam0 : String | GlobalDataFlow.cs:256:16:256:25 | access to parameter sinkParam0 : String | +| GlobalDataFlow.cs:254:26:254:35 | sinkParam0 : String | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:256:16:256:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:254:26:254:35 | sinkParam0 : String | +| GlobalDataFlow.cs:260:26:260:35 | sinkParam1 : String | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:265:26:265:35 | sinkParam3 : String | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:270:26:270:35 | sinkParam4 : String | GlobalDataFlow.cs:272:15:272:24 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:275:26:275:35 | sinkParam5 : String | GlobalDataFlow.cs:277:15:277:24 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:280:26:280:35 | sinkParam6 : String | GlobalDataFlow.cs:282:15:282:24 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:285:26:285:35 | sinkParam7 : String | GlobalDataFlow.cs:287:15:287:24 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:312:31:312:40 | sinkParam8 : String | GlobalDataFlow.cs:314:15:314:24 | access to parameter sinkParam8 | +| GlobalDataFlow.cs:318:32:318:41 | sinkParam9 : String | GlobalDataFlow.cs:320:15:320:24 | access to parameter sinkParam9 | +| GlobalDataFlow.cs:324:32:324:42 | sinkParam11 : String | GlobalDataFlow.cs:326:15:326:25 | access to parameter sinkParam11 | +| GlobalDataFlow.cs:338:16:338:29 | "taint source" : String | GlobalDataFlow.cs:154:21:154:25 | call to method Out : String | +| GlobalDataFlow.cs:338:16:338:29 | "taint source" : String | GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy [Value] : String | +| GlobalDataFlow.cs:343:9:343:26 | SSA def(x) : String | GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) : String | +| GlobalDataFlow.cs:343:13:343:26 | "taint source" : String | GlobalDataFlow.cs:343:9:343:26 | SSA def(x) : String | +| GlobalDataFlow.cs:348:9:348:26 | SSA def(x) : String | GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) : String | +| GlobalDataFlow.cs:348:13:348:26 | "taint source" : String | GlobalDataFlow.cs:348:9:348:26 | SSA def(x) : String | +| GlobalDataFlow.cs:354:22:354:35 | "taint source" : String | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield [[]] : String | +| GlobalDataFlow.cs:379:41:379:41 | x : String | GlobalDataFlow.cs:381:11:381:11 | access to parameter x : String | +| GlobalDataFlow.cs:379:41:379:41 | x : String | GlobalDataFlow.cs:381:11:381:11 | access to parameter x : String | +| GlobalDataFlow.cs:381:11:381:11 | access to parameter x : String | GlobalDataFlow.cs:54:15:54:15 | x : String | +| GlobalDataFlow.cs:381:11:381:11 | access to parameter x : String | GlobalDataFlow.cs:265:26:265:35 | sinkParam3 : String | +| GlobalDataFlow.cs:393:52:393:52 | x : String | GlobalDataFlow.cs:395:11:395:11 | access to parameter x : String | +| GlobalDataFlow.cs:393:52:393:52 | x : String | GlobalDataFlow.cs:395:11:395:11 | access to parameter x : String | +| GlobalDataFlow.cs:393:52:393:52 | x : String | GlobalDataFlow.cs:395:11:395:11 | access to parameter x : String | +| GlobalDataFlow.cs:395:11:395:11 | access to parameter x : String | GlobalDataFlow.cs:57:37:57:37 | x : String | +| GlobalDataFlow.cs:395:11:395:11 | access to parameter x : String | GlobalDataFlow.cs:275:26:275:35 | sinkParam5 : String | +| GlobalDataFlow.cs:395:11:395:11 | access to parameter x : String | GlobalDataFlow.cs:280:26:280:35 | sinkParam6 : String | +| GlobalDataFlow.cs:398:39:398:45 | tainted : String | GlobalDataFlow.cs:401:15:401:20 | access to local variable sink11 | +| GlobalDataFlow.cs:398:39:398:45 | tainted : String | GlobalDataFlow.cs:402:16:402:21 | access to local variable sink11 : String | +| GlobalDataFlow.cs:402:16:402:21 | access to local variable sink11 : String | GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam : String | +| GlobalDataFlow.cs:424:9:424:11 | value : String | GlobalDataFlow.cs:424:41:424:46 | access to local variable sink20 | +| GlobalDataFlow.cs:435:22:435:35 | "taint source" : String | GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty : String | | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | @@ -191,7 +228,8 @@ edges | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:11:19:11:19 | access to local variable x | | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | -| Splitting.cs:21:9:21:11 | value : String | Splitting.cs:21:28:21:32 | access to parameter value | +| Splitting.cs:21:9:21:11 | value : String | Splitting.cs:21:28:21:32 | access to parameter value : String | +| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:21:21:21:33 | call to method Return | | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | @@ -203,149 +241,193 @@ edges | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | Splitting.cs:34:19:34:19 | access to local variable x | | Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : String | | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | +| Splitting.cs:39:21:39:34 | [b (line 37): true] "taint source" : String | Splitting.cs:41:19:41:19 | access to local variable s | +| Splitting.cs:39:21:39:34 | [b (line 37): true] "taint source" : String | Splitting.cs:43:19:43:19 | access to local variable s | +| Splitting.cs:48:36:48:49 | "taint source" : String | Splitting.cs:50:19:50:19 | access to local variable s | +| Splitting.cs:48:36:48:49 | "taint source" : String | Splitting.cs:52:19:52:19 | access to local variable s | nodes | Capture.cs:7:20:7:26 | tainted : String | semmle.label | tainted : String | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | semmle.label | SSA capture def(tainted) : String | | Capture.cs:12:19:12:24 | access to local variable sink27 | semmle.label | access to local variable sink27 | -| Capture.cs:14:9:14:20 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | semmle.label | SSA capture def(tainted) : String | | Capture.cs:21:23:21:28 | access to local variable sink28 | semmle.label | access to local variable sink28 | -| Capture.cs:25:9:25:20 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | semmle.label | SSA capture def(tainted) : String | | Capture.cs:30:19:30:24 | access to local variable sink29 | semmle.label | access to local variable sink29 | -| Capture.cs:33:9:33:40 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:50:50:50:55 | sink39 : String | semmle.label | sink39 : String | -| Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | semmle.label | [implicit argument] sink39 : String | -| Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | semmle.label | SSA capture def(sink39) : String | | Capture.cs:57:27:57:32 | access to parameter sink39 | semmle.label | access to parameter sink39 | | Capture.cs:61:36:61:42 | access to parameter tainted : String | semmle.label | access to parameter tainted : String | | Capture.cs:69:13:69:35 | SSA def(sink30) : String | semmle.label | SSA def(sink30) : String | | Capture.cs:69:22:69:35 | "taint source" : String | semmle.label | "taint source" : String | -| Capture.cs:71:9:71:21 | SSA call def(sink30) : String | semmle.label | SSA call def(sink30) : String | | Capture.cs:72:15:72:20 | access to local variable sink30 | semmle.label | access to local variable sink30 | | Capture.cs:79:17:79:39 | SSA def(sink31) : String | semmle.label | SSA def(sink31) : String | | Capture.cs:79:26:79:39 | "taint source" : String | semmle.label | "taint source" : String | -| Capture.cs:83:9:83:21 | SSA call def(sink31) : String | semmle.label | SSA call def(sink31) : String | | Capture.cs:84:15:84:20 | access to local variable sink31 | semmle.label | access to local variable sink31 | | Capture.cs:89:13:89:35 | SSA def(sink32) : String | semmle.label | SSA def(sink32) : String | | Capture.cs:89:22:89:35 | "taint source" : String | semmle.label | "taint source" : String | -| Capture.cs:92:9:92:41 | SSA call def(sink32) : String | semmle.label | SSA call def(sink32) : String | | Capture.cs:93:15:93:20 | access to local variable sink32 | semmle.label | access to local variable sink32 | | Capture.cs:115:17:115:39 | SSA def(sink40) : String | semmle.label | SSA def(sink40) : String | | Capture.cs:115:26:115:39 | "taint source" : String | semmle.label | "taint source" : String | -| Capture.cs:121:9:121:35 | SSA call def(sink40) : String | semmle.label | SSA call def(sink40) : String | | Capture.cs:122:15:122:20 | access to local variable sink40 | semmle.label | access to local variable sink40 | | Capture.cs:125:25:125:31 | tainted : String | semmle.label | tainted : String | -| Capture.cs:132:9:132:25 | SSA call def(sink33) : String | semmle.label | SSA call def(sink33) : String | -| Capture.cs:132:9:132:25 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:133:15:133:20 | access to local variable sink33 | semmle.label | access to local variable sink33 | -| Capture.cs:144:9:144:25 | SSA call def(sink34) : String | semmle.label | SSA call def(sink34) : String | -| Capture.cs:144:9:144:25 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:145:15:145:20 | access to local variable sink34 | semmle.label | access to local variable sink34 | -| Capture.cs:153:9:153:45 | SSA call def(sink35) : String | semmle.label | SSA call def(sink35) : String | -| Capture.cs:153:9:153:45 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:154:15:154:20 | access to local variable sink35 | semmle.label | access to local variable sink35 | -| Capture.cs:160:22:160:38 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | semmle.label | call to local function CaptureThrough4 : String | | Capture.cs:161:15:161:20 | access to local variable sink36 | semmle.label | access to local variable sink36 | -| Capture.cs:168:9:168:32 | SSA call def(sink37) : String | semmle.label | SSA call def(sink37) : String | | Capture.cs:168:25:168:31 | access to parameter tainted : String | semmle.label | access to parameter tainted : String | | Capture.cs:169:15:169:20 | access to local variable sink37 | semmle.label | access to local variable sink37 | | Capture.cs:194:22:194:32 | call to local function Id : String | semmle.label | call to local function Id : String | | Capture.cs:194:25:194:31 | access to parameter tainted : String | semmle.label | access to parameter tainted : String | | Capture.cs:195:15:195:20 | access to local variable sink38 | semmle.label | access to local variable sink38 | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | semmle.label | access to field SinkField0 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | semmle.label | sinkParam2 : String | -| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | semmle.label | access to parameter sinkParam2 | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:15:53:15 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:56:37:56:37 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | semmle.label | call to method Return : String | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | semmle.label | access to local variable sink0 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | semmle.label | (...) ... : String | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | semmle.label | call to method Invoke : String | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | semmle.label | access to local variable sink0 : String | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | semmle.label | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | semmle.label | access to local variable sink1 : String | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | semmle.label | SSA def(sink2) : String | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | semmle.label | access to local variable sink2 | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | semmle.label | access to local variable sink2 : String | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | semmle.label | SSA def(sink3) : String | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | semmle.label | access to local variable sink3 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | semmle.label | delegate call : String | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | semmle.label | access to local variable sink3 : String | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | semmle.label | access to local variable sink4 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | semmle.label | call to method ApplyFunc : String | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | semmle.label | access to local variable sink4 : String | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | semmle.label | access to local variable sink5 | -| GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | semmle.label | call to method Out : String | -| GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | semmle.label | access to local variable sink6 | -| GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | semmle.label | SSA def(sink7) : String | -| GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | semmle.label | access to local variable sink7 | -| GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | semmle.label | SSA def(sink8) : String | -| GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | semmle.label | access to local variable sink8 | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | semmle.label | call to method TaintedParam : String | -| GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | semmle.label | access to local variable sink23 | -| GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | semmle.label | delegate call : String | -| GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | semmle.label | access to local variable sink9 | -| GlobalDataFlow.cs:189:22:189:42 | [library code] object creation of type Lazy : String | semmle.label | [library code] object creation of type Lazy : String | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy [Value] : String | semmle.label | object creation of type Lazy [Value] : String | -| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | semmle.label | access to property Value : String | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | semmle.label | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | semmle.label | access to local variable sink10 | -| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | semmle.label | access to property OutProperty : String | -| GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | semmle.label | access to local variable sink19 | -| GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | semmle.label | sinkParam0 : String | -| GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | semmle.label | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | semmle.label | access to parameter sinkParam0 | -| GlobalDataFlow.cs:242:26:242:35 | sinkParam1 : String | semmle.label | sinkParam1 : String | -| GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | semmle.label | access to parameter sinkParam1 | -| GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | semmle.label | sinkParam3 : String | -| GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | semmle.label | access to parameter sinkParam3 | -| GlobalDataFlow.cs:252:26:252:35 | sinkParam4 : String | semmle.label | sinkParam4 : String | -| GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | semmle.label | access to parameter sinkParam4 | -| GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | semmle.label | sinkParam5 : String | -| GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | semmle.label | access to parameter sinkParam5 | -| GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | semmle.label | sinkParam6 : String | -| GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | semmle.label | access to parameter sinkParam6 | -| GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | semmle.label | sinkParam7 : String | -| GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | semmle.label | access to parameter sinkParam7 | -| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | -| GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | -| GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:361:41:361:41 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:361:41:361:41 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:380:39:380:45 | tainted : String | semmle.label | tainted : String | -| GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | semmle.label | access to local variable sink11 | -| GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | semmle.label | access to local variable sink11 : String | -| GlobalDataFlow.cs:406:9:406:11 | value : String | semmle.label | value : String | -| GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | semmle.label | access to local variable sink20 | -| GlobalDataFlow.cs:417:22:417:35 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | semmle.label | access to field SinkField0 | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:45:30:45:39 | sinkParam2 : String | semmle.label | sinkParam2 : String | +| GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | semmle.label | access to parameter sinkParam2 | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:15:54:15 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:54:24:54:24 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:57:37:57:37 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:57:46:57:46 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:71:21:71:46 | call to method Return : String | semmle.label | call to method Return : String | +| GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | semmle.label | access to local variable sink0 | +| GlobalDataFlow.cs:73:21:73:101 | (...) ... : String | semmle.label | (...) ... : String | +| GlobalDataFlow.cs:73:29:73:101 | call to method Invoke : String | semmle.label | call to method Invoke : String | +| GlobalDataFlow.cs:73:94:73:98 | access to local variable sink0 : String | semmle.label | access to local variable sink0 : String | +| GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | semmle.label | access to local variable sink1 | +| GlobalDataFlow.cs:76:19:76:23 | access to local variable sink1 : String | semmle.label | access to local variable sink1 : String | +| GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) : String | semmle.label | SSA def(sink2) : String | +| GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | semmle.label | access to local variable sink2 | +| GlobalDataFlow.cs:79:19:79:23 | access to local variable sink2 : String | semmle.label | access to local variable sink2 : String | +| GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | semmle.label | SSA def(sink3) : String | +| GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | semmle.label | access to local variable sink3 | +| GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven [[]] : String | semmle.label | call to method SelectEven [[]] : String | +| GlobalDataFlow.cs:81:22:81:93 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:81:23:81:65 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | +| GlobalDataFlow.cs:81:57:81:65 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:81:59:81:63 | access to local variable sink3 : String | semmle.label | access to local variable sink3 : String | +| GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | semmle.label | access to local variable sink13 | +| GlobalDataFlow.cs:83:22:83:87 | call to method Select [[]] : String | semmle.label | call to method Select [[]] : String | +| GlobalDataFlow.cs:83:22:83:95 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:83:23:83:66 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | +| GlobalDataFlow.cs:83:57:83:66 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:83:59:83:64 | access to local variable sink13 : String | semmle.label | access to local variable sink13 : String | +| GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | semmle.label | access to local variable sink14 | +| GlobalDataFlow.cs:85:22:85:128 | call to method Zip [[]] : String | semmle.label | call to method Zip [[]] : String | +| GlobalDataFlow.cs:85:22:85:136 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:85:23:85:66 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | +| GlobalDataFlow.cs:85:57:85:66 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:85:59:85:64 | access to local variable sink14 : String | semmle.label | access to local variable sink14 : String | +| GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | semmle.label | access to local variable sink15 | +| GlobalDataFlow.cs:87:22:87:128 | call to method Zip [[]] : String | semmle.label | call to method Zip [[]] : String | +| GlobalDataFlow.cs:87:22:87:136 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:87:70:87:113 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | +| GlobalDataFlow.cs:87:104:87:113 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:87:106:87:111 | access to local variable sink15 : String | semmle.label | access to local variable sink15 : String | +| GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | semmle.label | access to local variable sink16 | +| GlobalDataFlow.cs:136:21:136:34 | delegate call : String | semmle.label | delegate call : String | +| GlobalDataFlow.cs:136:29:136:33 | access to local variable sink3 : String | semmle.label | access to local variable sink3 : String | +| GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | semmle.label | access to local variable sink4 | +| GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc : String | semmle.label | call to method ApplyFunc : String | +| GlobalDataFlow.cs:144:39:144:43 | access to local variable sink4 : String | semmle.label | access to local variable sink4 : String | +| GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | semmle.label | access to local variable sink5 | +| GlobalDataFlow.cs:154:21:154:25 | call to method Out : String | semmle.label | call to method Out : String | +| GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | semmle.label | access to local variable sink6 | +| GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) : String | semmle.label | SSA def(sink7) : String | +| GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | semmle.label | access to local variable sink7 | +| GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) : String | semmle.label | SSA def(sink8) : String | +| GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | semmle.label | access to local variable sink8 | +| GlobalDataFlow.cs:162:22:162:31 | call to method OutYield [[]] : String | semmle.label | call to method OutYield [[]] : String | +| GlobalDataFlow.cs:162:22:162:39 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | semmle.label | access to local variable sink12 | +| GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam : String | semmle.label | call to method TaintedParam : String | +| GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | semmle.label | access to local variable sink23 | +| GlobalDataFlow.cs:180:35:180:48 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:181:21:181:26 | delegate call : String | semmle.label | delegate call : String | +| GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | semmle.label | access to local variable sink9 | +| GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy [Value] : String | semmle.label | object creation of type Lazy [Value] : String | +| GlobalDataFlow.cs:190:22:190:48 | access to property Value : String | semmle.label | access to property Value : String | +| GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | semmle.label | access to local variable sink10 | +| GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty : String | semmle.label | access to property OutProperty : String | +| GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | semmle.label | access to local variable sink19 | +| GlobalDataFlow.cs:208:38:208:61 | array creation of type String[] [[]] : String | semmle.label | array creation of type String[] [[]] : String | +| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | semmle.label | call to method AsQueryable [[]] : String | +| GlobalDataFlow.cs:208:44:208:61 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:211:35:211:45 | sinkParam10 : String | semmle.label | sinkParam10 : String | +| GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | semmle.label | access to parameter sinkParam10 | +| GlobalDataFlow.cs:212:71:212:71 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:212:89:212:89 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [[]] : String | semmle.label | access to local variable tainted [[]] : String | +| GlobalDataFlow.cs:213:22:213:39 | call to method Select [[]] : String | semmle.label | call to method Select [[]] : String | +| GlobalDataFlow.cs:213:22:213:47 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | semmle.label | access to local variable sink24 | +| GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [[]] : String | semmle.label | access to local variable tainted [[]] : String | +| GlobalDataFlow.cs:215:22:215:39 | call to method Select [[]] : String | semmle.label | call to method Select [[]] : String | +| GlobalDataFlow.cs:215:22:215:47 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | semmle.label | access to local variable sink25 | +| GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [[]] : String | semmle.label | access to local variable tainted [[]] : String | +| GlobalDataFlow.cs:217:22:217:49 | call to method Select [[]] : String | semmle.label | call to method Select [[]] : String | +| GlobalDataFlow.cs:217:22:217:57 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | semmle.label | access to local variable sink26 | +| GlobalDataFlow.cs:238:20:238:49 | call to method Run [Result] : String | semmle.label | call to method Run [Result] : String | +| GlobalDataFlow.cs:238:35:238:48 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:239:22:239:25 | access to local variable task [Result] : String | semmle.label | access to local variable task [Result] : String | +| GlobalDataFlow.cs:239:22:239:32 | access to property Result : String | semmle.label | access to property Result : String | +| GlobalDataFlow.cs:240:15:240:20 | access to local variable sink41 | semmle.label | access to local variable sink41 | +| GlobalDataFlow.cs:241:22:241:31 | await ... : String | semmle.label | await ... : String | +| GlobalDataFlow.cs:241:28:241:31 | access to local variable task [Result] : String | semmle.label | access to local variable task [Result] : String | +| GlobalDataFlow.cs:242:15:242:20 | access to local variable sink42 | semmle.label | access to local variable sink42 | +| GlobalDataFlow.cs:254:26:254:35 | sinkParam0 : String | semmle.label | sinkParam0 : String | +| GlobalDataFlow.cs:256:16:256:25 | access to parameter sinkParam0 : String | semmle.label | access to parameter sinkParam0 : String | +| GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam0 | semmle.label | access to parameter sinkParam0 | +| GlobalDataFlow.cs:260:26:260:35 | sinkParam1 : String | semmle.label | sinkParam1 : String | +| GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam1 | semmle.label | access to parameter sinkParam1 | +| GlobalDataFlow.cs:265:26:265:35 | sinkParam3 : String | semmle.label | sinkParam3 : String | +| GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam3 | semmle.label | access to parameter sinkParam3 | +| GlobalDataFlow.cs:270:26:270:35 | sinkParam4 : String | semmle.label | sinkParam4 : String | +| GlobalDataFlow.cs:272:15:272:24 | access to parameter sinkParam4 | semmle.label | access to parameter sinkParam4 | +| GlobalDataFlow.cs:275:26:275:35 | sinkParam5 : String | semmle.label | sinkParam5 : String | +| GlobalDataFlow.cs:277:15:277:24 | access to parameter sinkParam5 | semmle.label | access to parameter sinkParam5 | +| GlobalDataFlow.cs:280:26:280:35 | sinkParam6 : String | semmle.label | sinkParam6 : String | +| GlobalDataFlow.cs:282:15:282:24 | access to parameter sinkParam6 | semmle.label | access to parameter sinkParam6 | +| GlobalDataFlow.cs:285:26:285:35 | sinkParam7 : String | semmle.label | sinkParam7 : String | +| GlobalDataFlow.cs:287:15:287:24 | access to parameter sinkParam7 | semmle.label | access to parameter sinkParam7 | +| GlobalDataFlow.cs:312:31:312:40 | sinkParam8 : String | semmle.label | sinkParam8 : String | +| GlobalDataFlow.cs:314:15:314:24 | access to parameter sinkParam8 | semmle.label | access to parameter sinkParam8 | +| GlobalDataFlow.cs:318:32:318:41 | sinkParam9 : String | semmle.label | sinkParam9 : String | +| GlobalDataFlow.cs:320:15:320:24 | access to parameter sinkParam9 | semmle.label | access to parameter sinkParam9 | +| GlobalDataFlow.cs:324:32:324:42 | sinkParam11 : String | semmle.label | sinkParam11 : String | +| GlobalDataFlow.cs:326:15:326:25 | access to parameter sinkParam11 | semmle.label | access to parameter sinkParam11 | +| GlobalDataFlow.cs:338:16:338:29 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:343:9:343:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | +| GlobalDataFlow.cs:343:13:343:26 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:348:9:348:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | +| GlobalDataFlow.cs:348:13:348:26 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:354:22:354:35 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:379:41:379:41 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:379:41:379:41 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:381:11:381:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:381:11:381:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:393:52:393:52 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:393:52:393:52 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:393:52:393:52 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:395:11:395:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:395:11:395:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:395:11:395:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:398:39:398:45 | tainted : String | semmle.label | tainted : String | +| GlobalDataFlow.cs:401:15:401:20 | access to local variable sink11 | semmle.label | access to local variable sink11 | +| GlobalDataFlow.cs:402:16:402:21 | access to local variable sink11 : String | semmle.label | access to local variable sink11 : String | +| GlobalDataFlow.cs:424:9:424:11 | value : String | semmle.label | value : String | +| GlobalDataFlow.cs:424:41:424:46 | access to local variable sink20 | semmle.label | access to local variable sink20 | +| GlobalDataFlow.cs:435:22:435:35 | "taint source" : String | semmle.label | "taint source" : String | | Splitting.cs:3:28:3:34 | tainted : String | semmle.label | tainted : String | | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | semmle.label | [b (line 3): false] call to method Return : String | | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | semmle.label | [b (line 3): true] call to method Return : String | @@ -355,7 +437,8 @@ nodes | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | semmle.label | [b (line 3): true] access to local variable x | | Splitting.cs:11:19:11:19 | access to local variable x | semmle.label | access to local variable x | | Splitting.cs:21:9:21:11 | value : String | semmle.label | value : String | -| Splitting.cs:21:28:21:32 | access to parameter value | semmle.label | access to parameter value | +| Splitting.cs:21:21:21:33 | call to method Return | semmle.label | call to method Return | +| Splitting.cs:21:28:21:32 | access to parameter value : String | semmle.label | access to parameter value : String | | Splitting.cs:24:28:24:34 | tainted : String | semmle.label | tainted : String | | Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | semmle.label | [b (line 24): false] access to parameter tainted : String | | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | semmle.label | [b (line 24): true] access to parameter tainted : String | @@ -366,24 +449,42 @@ nodes | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | semmle.label | [b (line 24): false] access to local variable x | | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | semmle.label | [b (line 24): true] access to local variable x | | Splitting.cs:34:19:34:19 | access to local variable x | semmle.label | access to local variable x | +| Splitting.cs:39:21:39:34 | [b (line 37): true] "taint source" : String | semmle.label | [b (line 37): true] "taint source" : String | +| Splitting.cs:41:19:41:19 | access to local variable s | semmle.label | access to local variable s | +| Splitting.cs:43:19:43:19 | access to local variable s | semmle.label | access to local variable s | +| Splitting.cs:48:36:48:49 | "taint source" : String | semmle.label | "taint source" : String | +| Splitting.cs:50:19:50:19 | access to local variable s | semmle.label | access to local variable s | +| Splitting.cs:52:19:52:19 | access to local variable s | semmle.label | access to local variable s | #select | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | [b (line 24): false] access to local variable x | | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | [b (line 24): true] access to local variable x | | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | [b (line 3): false] access to local variable x | | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | [b (line 3): true] access to local variable x | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | access to field SinkField0 | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | access to local variable sink0 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | access to local variable sink1 | -| GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | access to local variable sink10 | -| GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | access to local variable sink11 | -| GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | GlobalDataFlow.cs:417:22:417:35 | "taint source" : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | access to local variable sink19 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | access to local variable sink2 | -| GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | access to local variable sink20 | -| GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | access to local variable sink23 | +| GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | access to field SinkField0 | +| Splitting.cs:41:19:41:19 | access to local variable s | Splitting.cs:39:21:39:34 | [b (line 37): true] "taint source" : String | Splitting.cs:41:19:41:19 | access to local variable s | access to local variable s | +| Splitting.cs:43:19:43:19 | access to local variable s | Splitting.cs:39:21:39:34 | [b (line 37): true] "taint source" : String | Splitting.cs:43:19:43:19 | access to local variable s | access to local variable s | +| Splitting.cs:50:19:50:19 | access to local variable s | Splitting.cs:48:36:48:49 | "taint source" : String | Splitting.cs:50:19:50:19 | access to local variable s | access to local variable s | +| Splitting.cs:52:19:52:19 | access to local variable s | Splitting.cs:48:36:48:49 | "taint source" : String | Splitting.cs:52:19:52:19 | access to local variable s | access to local variable s | +| GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | access to local variable sink0 | +| GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | access to local variable sink1 | +| GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | GlobalDataFlow.cs:338:16:338:29 | "taint source" : String | GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | access to local variable sink10 | +| GlobalDataFlow.cs:401:15:401:20 | access to local variable sink11 | GlobalDataFlow.cs:398:39:398:45 | tainted : String | GlobalDataFlow.cs:401:15:401:20 | access to local variable sink11 | access to local variable sink11 | +| GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | GlobalDataFlow.cs:354:22:354:35 | "taint source" : String | GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | access to local variable sink12 | +| GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | access to local variable sink13 | +| GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | access to local variable sink14 | +| GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | access to local variable sink15 | +| GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | access to local variable sink16 | +| GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | GlobalDataFlow.cs:435:22:435:35 | "taint source" : String | GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | access to local variable sink19 | +| GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | access to local variable sink2 | +| GlobalDataFlow.cs:424:41:424:46 | access to local variable sink20 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:424:41:424:46 | access to local variable sink20 | access to local variable sink20 | +| GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | GlobalDataFlow.cs:398:39:398:45 | tainted : String | GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | access to local variable sink23 | +| GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | access to local variable sink24 | +| GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | access to local variable sink25 | +| GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | access to local variable sink26 | | Capture.cs:12:19:12:24 | access to local variable sink27 | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:12:19:12:24 | access to local variable sink27 | access to local variable sink27 | | Capture.cs:21:23:21:28 | access to local variable sink28 | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:21:23:21:28 | access to local variable sink28 | access to local variable sink28 | | Capture.cs:30:19:30:24 | access to local variable sink29 | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:30:19:30:24 | access to local variable sink29 | access to local variable sink29 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | access to local variable sink3 | +| GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | access to local variable sink3 | | Capture.cs:72:15:72:20 | access to local variable sink30 | Capture.cs:69:22:69:35 | "taint source" : String | Capture.cs:72:15:72:20 | access to local variable sink30 | access to local variable sink30 | | Capture.cs:84:15:84:20 | access to local variable sink31 | Capture.cs:79:26:79:39 | "taint source" : String | Capture.cs:84:15:84:20 | access to local variable sink31 | access to local variable sink31 | | Capture.cs:93:15:93:20 | access to local variable sink32 | Capture.cs:89:22:89:35 | "taint source" : String | Capture.cs:93:15:93:20 | access to local variable sink32 | access to local variable sink32 | @@ -393,23 +494,29 @@ nodes | Capture.cs:161:15:161:20 | access to local variable sink36 | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:161:15:161:20 | access to local variable sink36 | access to local variable sink36 | | Capture.cs:169:15:169:20 | access to local variable sink37 | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:169:15:169:20 | access to local variable sink37 | access to local variable sink37 | | Capture.cs:195:15:195:20 | access to local variable sink38 | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:195:15:195:20 | access to local variable sink38 | access to local variable sink38 | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | access to local variable sink4 | +| GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | access to local variable sink4 | | Capture.cs:122:15:122:20 | access to local variable sink40 | Capture.cs:115:26:115:39 | "taint source" : String | Capture.cs:122:15:122:20 | access to local variable sink40 | access to local variable sink40 | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | access to local variable sink5 | -| GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | access to local variable sink6 | -| GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | access to local variable sink7 | -| GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | access to local variable sink8 | -| GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | access to local variable sink9 | +| GlobalDataFlow.cs:240:15:240:20 | access to local variable sink41 | GlobalDataFlow.cs:238:35:238:48 | "taint source" : String | GlobalDataFlow.cs:240:15:240:20 | access to local variable sink41 | access to local variable sink41 | +| GlobalDataFlow.cs:242:15:242:20 | access to local variable sink42 | GlobalDataFlow.cs:238:35:238:48 | "taint source" : String | GlobalDataFlow.cs:242:15:242:20 | access to local variable sink42 | access to local variable sink42 | +| GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | access to local variable sink5 | +| GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | GlobalDataFlow.cs:338:16:338:29 | "taint source" : String | GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | access to local variable sink6 | +| GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | GlobalDataFlow.cs:343:13:343:26 | "taint source" : String | GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | access to local variable sink7 | +| GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | GlobalDataFlow.cs:348:13:348:26 | "taint source" : String | GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | access to local variable sink8 | +| GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | GlobalDataFlow.cs:180:35:180:48 | "taint source" : String | GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | access to local variable sink9 | | Splitting.cs:11:19:11:19 | access to local variable x | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:11:19:11:19 | access to local variable x | access to local variable x | | Splitting.cs:34:19:34:19 | access to local variable x | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:34:19:34:19 | access to local variable x | access to local variable x | | Capture.cs:57:27:57:32 | access to parameter sink39 | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:57:27:57:32 | access to parameter sink39 | access to parameter sink39 | -| GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | -| Splitting.cs:21:28:21:32 | access to parameter value | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:21:28:21:32 | access to parameter value | access to parameter value | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | access to property SinkProperty0 | +| GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam1 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | access to parameter sinkParam10 | +| GlobalDataFlow.cs:326:15:326:25 | access to parameter sinkParam11 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:326:15:326:25 | access to parameter sinkParam11 | access to parameter sinkParam11 | +| GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | access to parameter sinkParam2 | +| GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam3 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam3 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:272:15:272:24 | access to parameter sinkParam4 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:272:15:272:24 | access to parameter sinkParam4 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:277:15:277:24 | access to parameter sinkParam5 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:277:15:277:24 | access to parameter sinkParam5 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:282:15:282:24 | access to parameter sinkParam6 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:282:15:282:24 | access to parameter sinkParam6 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:287:15:287:24 | access to parameter sinkParam7 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:287:15:287:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:314:15:314:24 | access to parameter sinkParam8 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:314:15:314:24 | access to parameter sinkParam8 | access to parameter sinkParam8 | +| GlobalDataFlow.cs:320:15:320:24 | access to parameter sinkParam9 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:320:15:320:24 | access to parameter sinkParam9 | access to parameter sinkParam9 | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | access to property SinkProperty0 | +| Splitting.cs:21:21:21:33 | call to method Return | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:21:21:21:33 | call to method Return | call to method Return | diff --git a/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected b/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected index 2b712d5c2f8c..1acaa3082567 100644 --- a/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected +++ b/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected @@ -1,204 +1,359 @@ | Capture.cs:33:9:33:40 | call to method Select | return | Capture.cs:33:9:33:40 | call to method Select | | Capture.cs:33:9:33:40 | call to method Select | yield return | Capture.cs:33:9:33:40 | call to method Select | | Capture.cs:33:9:33:50 | call to method ToArray | return | Capture.cs:33:9:33:50 | call to method ToArray | -| Capture.cs:33:30:33:39 | [implicit call] access to local variable captureIn3 | return | Capture.cs:33:30:33:39 | [output] access to local variable captureIn3 | | Capture.cs:71:9:71:21 | call to local function CaptureOut1 | captured sink30 | Capture.cs:71:9:71:21 | SSA call def(sink30) | | Capture.cs:83:9:83:21 | [transitive] call to local function CaptureOut2 | captured sink31 | Capture.cs:83:9:83:21 | SSA call def(sink31) | -| Capture.cs:92:9:92:41 | call to method Select | captured sink32 | Capture.cs:92:9:92:41 | SSA call def(sink32) | +| Capture.cs:92:9:92:41 | [transitive] call to method Select | captured sink32 | Capture.cs:92:9:92:41 | SSA call def(sink32) | | Capture.cs:92:9:92:41 | call to method Select | return | Capture.cs:92:9:92:41 | call to method Select | | Capture.cs:92:9:92:41 | call to method Select | yield return | Capture.cs:92:9:92:41 | call to method Select | | Capture.cs:92:9:92:51 | call to method ToArray | return | Capture.cs:92:9:92:51 | call to method ToArray | -| Capture.cs:92:30:92:40 | [implicit call] access to local variable captureOut3 | captured sink32 | Capture.cs:92:9:92:41 | SSA call def(sink32) | -| Capture.cs:92:30:92:40 | [implicit call] access to local variable captureOut3 | return | Capture.cs:92:30:92:40 | [output] access to local variable captureOut3 | | Capture.cs:121:9:121:35 | [transitive] call to local function CaptureOutMultipleLambdas | captured nonSink0 | Capture.cs:121:9:121:35 | SSA call def(nonSink0) | | Capture.cs:121:9:121:35 | [transitive] call to local function CaptureOutMultipleLambdas | captured sink40 | Capture.cs:121:9:121:35 | SSA call def(sink40) | | Capture.cs:132:9:132:25 | call to local function CaptureThrough1 | captured sink33 | Capture.cs:132:9:132:25 | SSA call def(sink33) | | Capture.cs:144:9:144:25 | [transitive] call to local function CaptureThrough2 | captured sink34 | Capture.cs:144:9:144:25 | SSA call def(sink34) | -| Capture.cs:153:9:153:45 | call to method Select | captured sink35 | Capture.cs:153:9:153:45 | SSA call def(sink35) | +| Capture.cs:153:9:153:45 | [transitive] call to method Select | captured sink35 | Capture.cs:153:9:153:45 | SSA call def(sink35) | | Capture.cs:153:9:153:45 | call to method Select | return | Capture.cs:153:9:153:45 | call to method Select | | Capture.cs:153:9:153:45 | call to method Select | yield return | Capture.cs:153:9:153:45 | call to method Select | | Capture.cs:153:9:153:55 | call to method ToArray | return | Capture.cs:153:9:153:55 | call to method ToArray | -| Capture.cs:153:30:153:44 | [implicit call] access to local variable captureThrough3 | captured sink35 | Capture.cs:153:9:153:45 | SSA call def(sink35) | -| Capture.cs:153:30:153:44 | [implicit call] access to local variable captureThrough3 | return | Capture.cs:153:30:153:44 | [output] access to local variable captureThrough3 | | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 | return | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 | | Capture.cs:168:9:168:32 | call to local function CaptureThrough5 | captured sink37 | Capture.cs:168:9:168:32 | SSA call def(sink37) | | Capture.cs:191:20:191:22 | call to local function M | return | Capture.cs:191:20:191:22 | call to local function M | | Capture.cs:194:22:194:32 | call to local function Id | return | Capture.cs:194:22:194:32 | call to local function Id | | Capture.cs:196:20:196:25 | call to local function Id | return | Capture.cs:196:20:196:25 | call to local function Id | -| GlobalDataFlow.cs:25:9:25:26 | access to property SinkProperty0 | return | GlobalDataFlow.cs:25:9:25:26 | access to property SinkProperty0 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | return | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | -| GlobalDataFlow.cs:29:9:29:29 | access to property NonSinkProperty0 | return | GlobalDataFlow.cs:29:9:29:29 | access to property NonSinkProperty0 | -| GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 | return | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 | -| GlobalDataFlow.cs:31:9:31:29 | access to property NonSinkProperty1 | return | GlobalDataFlow.cs:31:9:31:29 | access to property NonSinkProperty1 | -| GlobalDataFlow.cs:32:15:32:35 | access to property NonSinkProperty1 | return | GlobalDataFlow.cs:32:15:32:35 | access to property NonSinkProperty1 | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 | return | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 | -| GlobalDataFlow.cs:36:26:36:58 | call to method GetMethod | return | GlobalDataFlow.cs:36:26:36:58 | call to method GetMethod | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 | return | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:38:9:38:37 | call to method Invoke | return | GlobalDataFlow.cs:38:9:38:37 | call to method Invoke | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 | return | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 | return | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 | return | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 | return | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 | return | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 | return | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:64:9:64:18 | access to property InProperty | return | GlobalDataFlow.cs:64:9:64:18 | access to property InProperty | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | return | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | -| GlobalDataFlow.cs:67:9:67:21 | access to property NonInProperty | return | GlobalDataFlow.cs:67:9:67:21 | access to property NonInProperty | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return | return | GlobalDataFlow.cs:70:21:70:46 | call to method Return | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | return | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:72:29:72:64 | call to method GetMethod | return | GlobalDataFlow.cs:72:29:72:64 | call to method GetMethod | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke | return | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke | -| GlobalDataFlow.cs:75:9:75:46 | call to method ReturnOut | out | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) | -| GlobalDataFlow.cs:75:9:75:46 | call to method ReturnOut | ref | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) | -| GlobalDataFlow.cs:78:9:78:46 | call to method ReturnRef | out | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) | -| GlobalDataFlow.cs:78:9:78:46 | call to method ReturnRef | ref | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven | return | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven | yield return | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven | -| GlobalDataFlow.cs:80:22:80:93 | call to method First | return | GlobalDataFlow.cs:80:22:80:93 | call to method First | -| GlobalDataFlow.cs:82:22:82:87 | call to method Select | return | GlobalDataFlow.cs:82:22:82:87 | call to method Select | -| GlobalDataFlow.cs:82:22:82:87 | call to method Select | yield return | GlobalDataFlow.cs:82:22:82:87 | call to method Select | -| GlobalDataFlow.cs:82:22:82:95 | call to method First | return | GlobalDataFlow.cs:82:22:82:95 | call to method First | -| GlobalDataFlow.cs:82:76:82:86 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:84:22:84:128 | call to method Zip | return | GlobalDataFlow.cs:84:22:84:128 | call to method Zip | -| GlobalDataFlow.cs:84:22:84:128 | call to method Zip | yield return | GlobalDataFlow.cs:84:22:84:128 | call to method Zip | -| GlobalDataFlow.cs:84:22:84:136 | call to method First | return | GlobalDataFlow.cs:84:22:84:136 | call to method First | -| GlobalDataFlow.cs:84:117:84:127 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... | -| GlobalDataFlow.cs:86:22:86:128 | call to method Zip | return | GlobalDataFlow.cs:86:22:86:128 | call to method Zip | -| GlobalDataFlow.cs:86:22:86:128 | call to method Zip | yield return | GlobalDataFlow.cs:86:22:86:128 | call to method Zip | -| GlobalDataFlow.cs:86:22:86:136 | call to method First | return | GlobalDataFlow.cs:86:22:86:136 | call to method First | -| GlobalDataFlow.cs:86:117:86:127 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:86:117:86:127 | [output] (...) => ... | -| GlobalDataFlow.cs:88:22:88:110 | call to method Aggregate | return | GlobalDataFlow.cs:88:22:88:110 | call to method Aggregate | -| GlobalDataFlow.cs:88:83:88:101 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:88:83:88:101 | [output] (...) => ... | -| GlobalDataFlow.cs:88:104:88:109 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:88:104:88:109 | [output] (...) => ... | -| GlobalDataFlow.cs:90:22:90:110 | call to method Aggregate | return | GlobalDataFlow.cs:90:22:90:110 | call to method Aggregate | -| GlobalDataFlow.cs:90:83:90:101 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:90:83:90:101 | [output] (...) => ... | -| GlobalDataFlow.cs:90:104:90:109 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... | -| GlobalDataFlow.cs:93:9:93:42 | call to method TryParse | out | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) | -| GlobalDataFlow.cs:93:9:93:42 | call to method TryParse | ref | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) | -| GlobalDataFlow.cs:93:9:93:42 | call to method TryParse | return | GlobalDataFlow.cs:93:9:93:42 | call to method TryParse | -| GlobalDataFlow.cs:96:9:96:41 | call to method TryParse | out | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) | -| GlobalDataFlow.cs:96:9:96:41 | call to method TryParse | ref | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) | -| GlobalDataFlow.cs:96:9:96:41 | call to method TryParse | return | GlobalDataFlow.cs:96:9:96:41 | call to method TryParse | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return | return | GlobalDataFlow.cs:100:24:100:33 | call to method Return | -| GlobalDataFlow.cs:102:28:102:63 | call to method GetMethod | return | GlobalDataFlow.cs:102:28:102:63 | call to method GetMethod | -| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke | return | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke | -| GlobalDataFlow.cs:104:9:104:49 | call to method ReturnOut | out | GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:104:9:104:49 | call to method ReturnOut | ref | GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:106:9:106:49 | call to method ReturnOut | out | GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) | -| GlobalDataFlow.cs:108:9:108:49 | call to method ReturnRef | out | GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:108:9:108:49 | call to method ReturnRef | ref | GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:110:9:110:49 | call to method ReturnRef | out | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) | -| GlobalDataFlow.cs:110:9:110:49 | call to method ReturnRef | ref | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) | -| GlobalDataFlow.cs:112:20:112:86 | call to method SelectEven | return | GlobalDataFlow.cs:112:20:112:86 | call to method SelectEven | -| GlobalDataFlow.cs:112:20:112:86 | call to method SelectEven | yield return | GlobalDataFlow.cs:112:20:112:86 | call to method SelectEven | -| GlobalDataFlow.cs:112:20:112:94 | call to method First | return | GlobalDataFlow.cs:112:20:112:94 | call to method First | -| GlobalDataFlow.cs:114:20:114:82 | call to method Select | return | GlobalDataFlow.cs:114:20:114:82 | call to method Select | -| GlobalDataFlow.cs:114:20:114:82 | call to method Select | yield return | GlobalDataFlow.cs:114:20:114:82 | call to method Select | -| GlobalDataFlow.cs:114:20:114:90 | call to method First | return | GlobalDataFlow.cs:114:20:114:90 | call to method First | -| GlobalDataFlow.cs:114:76:114:81 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... | -| GlobalDataFlow.cs:116:20:116:126 | call to method Zip | return | GlobalDataFlow.cs:116:20:116:126 | call to method Zip | -| GlobalDataFlow.cs:116:20:116:126 | call to method Zip | yield return | GlobalDataFlow.cs:116:20:116:126 | call to method Zip | -| GlobalDataFlow.cs:116:20:116:134 | call to method First | return | GlobalDataFlow.cs:116:20:116:134 | call to method First | -| GlobalDataFlow.cs:116:115:116:125 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:116:115:116:125 | [output] (...) => ... | -| GlobalDataFlow.cs:118:20:118:126 | call to method Zip | return | GlobalDataFlow.cs:118:20:118:126 | call to method Zip | -| GlobalDataFlow.cs:118:20:118:126 | call to method Zip | yield return | GlobalDataFlow.cs:118:20:118:126 | call to method Zip | -| GlobalDataFlow.cs:118:20:118:134 | call to method First | return | GlobalDataFlow.cs:118:20:118:134 | call to method First | -| GlobalDataFlow.cs:118:115:118:125 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:118:115:118:125 | [output] (...) => ... | -| GlobalDataFlow.cs:120:20:120:104 | call to method Aggregate | return | GlobalDataFlow.cs:120:20:120:104 | call to method Aggregate | -| GlobalDataFlow.cs:120:81:120:95 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:120:81:120:95 | [output] (...) => ... | -| GlobalDataFlow.cs:120:98:120:103 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:120:98:120:103 | [output] (...) => ... | -| GlobalDataFlow.cs:122:20:122:109 | call to method Aggregate | return | GlobalDataFlow.cs:122:20:122:109 | call to method Aggregate | -| GlobalDataFlow.cs:122:81:122:99 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:122:81:122:99 | [output] (...) => ... | -| GlobalDataFlow.cs:122:102:122:108 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:122:102:122:108 | [output] (...) => ... | -| GlobalDataFlow.cs:124:20:124:107 | call to method Aggregate | return | GlobalDataFlow.cs:124:20:124:107 | call to method Aggregate | -| GlobalDataFlow.cs:124:86:124:98 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:124:86:124:98 | [output] (...) => ... | -| GlobalDataFlow.cs:124:101:124:106 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:124:101:124:106 | [output] (...) => ... | -| GlobalDataFlow.cs:127:9:127:46 | call to method TryParse | out | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) | -| GlobalDataFlow.cs:127:9:127:46 | call to method TryParse | ref | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) | -| GlobalDataFlow.cs:127:9:127:46 | call to method TryParse | return | GlobalDataFlow.cs:127:9:127:46 | call to method TryParse | -| GlobalDataFlow.cs:130:9:130:45 | call to method TryParse | out | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) | -| GlobalDataFlow.cs:130:9:130:45 | call to method TryParse | ref | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) | -| GlobalDataFlow.cs:130:9:130:45 | call to method TryParse | return | GlobalDataFlow.cs:130:9:130:45 | call to method TryParse | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | return | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:135:21:135:34 | delegate call | return | GlobalDataFlow.cs:135:21:135:34 | delegate call | -| GlobalDataFlow.cs:139:20:139:36 | delegate call | return | GlobalDataFlow.cs:139:20:139:36 | delegate call | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | return | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc | return | GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc | return | GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:153:21:153:25 | call to method Out | return | GlobalDataFlow.cs:153:21:153:25 | call to method Out | -| GlobalDataFlow.cs:156:9:156:25 | call to method OutOut | out | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) | -| GlobalDataFlow.cs:156:9:156:25 | call to method OutOut | ref | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) | -| GlobalDataFlow.cs:159:9:159:25 | call to method OutRef | out | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) | -| GlobalDataFlow.cs:159:9:159:25 | call to method OutRef | ref | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | return | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | yield return | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | -| GlobalDataFlow.cs:161:22:161:39 | call to method First | return | GlobalDataFlow.cs:161:22:161:39 | call to method First | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam | return | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam | -| GlobalDataFlow.cs:167:20:167:27 | call to method NonOut | return | GlobalDataFlow.cs:167:20:167:27 | call to method NonOut | -| GlobalDataFlow.cs:169:9:169:31 | call to method NonOutOut | out | GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) | -| GlobalDataFlow.cs:169:9:169:31 | call to method NonOutOut | ref | GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) | -| GlobalDataFlow.cs:171:9:171:31 | call to method NonOutRef | out | GlobalDataFlow.cs:171:23:171:30 | SSA def(nonSink0) | -| GlobalDataFlow.cs:171:9:171:31 | call to method NonOutRef | ref | GlobalDataFlow.cs:171:23:171:30 | SSA def(nonSink0) | -| GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield | return | GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield | -| GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield | yield return | GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield | -| GlobalDataFlow.cs:173:20:173:40 | call to method First | return | GlobalDataFlow.cs:173:20:173:40 | call to method First | -| GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam | return | GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam | -| GlobalDataFlow.cs:180:21:180:26 | delegate call | return | GlobalDataFlow.cs:180:21:180:26 | delegate call | -| GlobalDataFlow.cs:185:20:185:27 | delegate call | return | GlobalDataFlow.cs:185:20:185:27 | delegate call | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy | return | GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy | -| GlobalDataFlow.cs:189:22:189:48 | access to property Value | return | GlobalDataFlow.cs:189:22:189:48 | access to property Value | -| GlobalDataFlow.cs:189:39:189:41 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:193:20:193:43 | object creation of type Lazy | return | GlobalDataFlow.cs:193:20:193:43 | object creation of type Lazy | -| GlobalDataFlow.cs:193:20:193:49 | access to property Value | return | GlobalDataFlow.cs:193:20:193:49 | access to property Value | -| GlobalDataFlow.cs:193:37:193:42 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty | return | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty | -| GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty | return | GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty | -| GlobalDataFlow.cs:207:38:207:75 | call to method AsQueryable | return | GlobalDataFlow.cs:207:38:207:75 | call to method AsQueryable | -| GlobalDataFlow.cs:208:41:208:77 | call to method AsQueryable | return | GlobalDataFlow.cs:208:41:208:77 | call to method AsQueryable | -| GlobalDataFlow.cs:211:76:211:90 | call to method ReturnCheck2 | return | GlobalDataFlow.cs:211:76:211:90 | call to method ReturnCheck2 | -| GlobalDataFlow.cs:212:22:212:39 | call to method Select | return | GlobalDataFlow.cs:212:22:212:39 | call to method Select | -| GlobalDataFlow.cs:212:22:212:39 | call to method Select | yield return | GlobalDataFlow.cs:212:22:212:39 | call to method Select | -| GlobalDataFlow.cs:212:22:212:47 | call to method First | return | GlobalDataFlow.cs:212:22:212:47 | call to method First | -| GlobalDataFlow.cs:212:37:212:38 | [implicit call] access to local variable f1 | return | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f1 | -| GlobalDataFlow.cs:214:22:214:39 | call to method Select | return | GlobalDataFlow.cs:214:22:214:39 | call to method Select | -| GlobalDataFlow.cs:214:22:214:47 | call to method First | return | GlobalDataFlow.cs:214:22:214:47 | call to method First | -| GlobalDataFlow.cs:214:37:214:38 | [implicit call] access to local variable f2 | return | GlobalDataFlow.cs:214:37:214:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:216:22:216:49 | call to method Select | return | GlobalDataFlow.cs:216:22:216:49 | call to method Select | -| GlobalDataFlow.cs:216:22:216:49 | call to method Select | yield return | GlobalDataFlow.cs:216:22:216:49 | call to method Select | -| GlobalDataFlow.cs:216:22:216:57 | call to method First | return | GlobalDataFlow.cs:216:22:216:57 | call to method First | -| GlobalDataFlow.cs:216:37:216:48 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:216:37:216:48 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:221:76:221:92 | call to method NonReturnCheck | return | GlobalDataFlow.cs:221:76:221:92 | call to method NonReturnCheck | -| GlobalDataFlow.cs:222:23:222:43 | call to method Select | return | GlobalDataFlow.cs:222:23:222:43 | call to method Select | -| GlobalDataFlow.cs:222:23:222:43 | call to method Select | yield return | GlobalDataFlow.cs:222:23:222:43 | call to method Select | -| GlobalDataFlow.cs:222:23:222:51 | call to method First | return | GlobalDataFlow.cs:222:23:222:51 | call to method First | -| GlobalDataFlow.cs:222:41:222:42 | [implicit call] access to local variable f1 | return | GlobalDataFlow.cs:222:41:222:42 | [output] access to local variable f1 | -| GlobalDataFlow.cs:224:19:224:39 | call to method Select | return | GlobalDataFlow.cs:224:19:224:39 | call to method Select | -| GlobalDataFlow.cs:224:19:224:47 | call to method First | return | GlobalDataFlow.cs:224:19:224:47 | call to method First | -| GlobalDataFlow.cs:224:37:224:38 | [implicit call] access to local variable f2 | return | GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:226:19:226:39 | call to method Select | return | GlobalDataFlow.cs:226:19:226:39 | call to method Select | -| GlobalDataFlow.cs:226:19:226:39 | call to method Select | yield return | GlobalDataFlow.cs:226:19:226:39 | call to method Select | -| GlobalDataFlow.cs:226:19:226:47 | call to method First | return | GlobalDataFlow.cs:226:19:226:47 | call to method First | -| GlobalDataFlow.cs:226:37:226:38 | [implicit call] access to local variable f3 | return | GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f3 | -| GlobalDataFlow.cs:228:19:228:39 | call to method Select | return | GlobalDataFlow.cs:228:19:228:39 | call to method Select | -| GlobalDataFlow.cs:228:19:228:47 | call to method First | return | GlobalDataFlow.cs:228:19:228:47 | call to method First | -| GlobalDataFlow.cs:228:37:228:38 | [implicit call] access to local variable f4 | return | GlobalDataFlow.cs:228:37:228:38 | [output] access to local variable f4 | -| GlobalDataFlow.cs:230:19:230:49 | call to method Select | return | GlobalDataFlow.cs:230:19:230:49 | call to method Select | -| GlobalDataFlow.cs:230:19:230:49 | call to method Select | yield return | GlobalDataFlow.cs:230:19:230:49 | call to method Select | -| GlobalDataFlow.cs:230:19:230:57 | call to method First | return | GlobalDataFlow.cs:230:19:230:57 | call to method First | -| GlobalDataFlow.cs:230:37:230:48 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:230:37:230:48 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:279:17:279:38 | call to method ApplyFunc | return | GlobalDataFlow.cs:279:17:279:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:368:16:368:19 | delegate call | return | GlobalDataFlow.cs:368:16:368:19 | delegate call | -| GlobalDataFlow.cs:433:44:433:47 | delegate call | return | GlobalDataFlow.cs:433:44:433:47 | delegate call | +| GlobalDataFlow.cs:26:9:26:26 | access to property SinkProperty0 | return | GlobalDataFlow.cs:26:9:26:26 | access to property SinkProperty0 | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | return | GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | +| GlobalDataFlow.cs:30:9:30:29 | access to property NonSinkProperty0 | return | GlobalDataFlow.cs:30:9:30:29 | access to property NonSinkProperty0 | +| GlobalDataFlow.cs:31:15:31:35 | access to property NonSinkProperty0 | return | GlobalDataFlow.cs:31:15:31:35 | access to property NonSinkProperty0 | +| GlobalDataFlow.cs:32:9:32:29 | access to property NonSinkProperty1 | return | GlobalDataFlow.cs:32:9:32:29 | access to property NonSinkProperty1 | +| GlobalDataFlow.cs:33:15:33:35 | access to property NonSinkProperty1 | return | GlobalDataFlow.cs:33:15:33:35 | access to property NonSinkProperty1 | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 | return | GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 | +| GlobalDataFlow.cs:37:26:37:58 | call to method GetMethod | qualifier | GlobalDataFlow.cs:37:26:37:41 | [post] typeof(...) | +| GlobalDataFlow.cs:37:26:37:58 | call to method GetMethod | return | GlobalDataFlow.cs:37:26:37:58 | call to method GetMethod | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 | return | GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 | +| GlobalDataFlow.cs:39:9:39:37 | call to method Invoke | return | GlobalDataFlow.cs:39:9:39:37 | call to method Invoke | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 | return | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 | return | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 | return | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 | return | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 | return | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 | +| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 | return | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 | +| GlobalDataFlow.cs:65:9:65:18 | access to property InProperty | qualifier | GlobalDataFlow.cs:65:9:65:18 | [post] this access | +| GlobalDataFlow.cs:65:9:65:18 | access to property InProperty | return | GlobalDataFlow.cs:65:9:65:18 | access to property InProperty | +| GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 | return | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 | +| GlobalDataFlow.cs:68:9:68:21 | access to property NonInProperty | qualifier | GlobalDataFlow.cs:68:9:68:21 | [post] this access | +| GlobalDataFlow.cs:68:9:68:21 | access to property NonInProperty | return | GlobalDataFlow.cs:68:9:68:21 | access to property NonInProperty | +| GlobalDataFlow.cs:71:21:71:46 | call to method Return | return | GlobalDataFlow.cs:71:21:71:46 | call to method Return | +| GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 | return | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 | +| GlobalDataFlow.cs:73:29:73:64 | call to method GetMethod | qualifier | GlobalDataFlow.cs:73:29:73:44 | [post] typeof(...) | +| GlobalDataFlow.cs:73:29:73:64 | call to method GetMethod | return | GlobalDataFlow.cs:73:29:73:64 | call to method GetMethod | +| GlobalDataFlow.cs:73:29:73:101 | call to method Invoke | return | GlobalDataFlow.cs:73:29:73:101 | call to method Invoke | +| GlobalDataFlow.cs:76:9:76:46 | call to method ReturnOut | out | GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) | +| GlobalDataFlow.cs:76:9:76:46 | call to method ReturnOut | ref | GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) | +| GlobalDataFlow.cs:79:9:79:46 | call to method ReturnRef | out | GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) | +| GlobalDataFlow.cs:79:9:79:46 | call to method ReturnRef | ref | GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) | +| GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven | return | GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven | +| GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven | yield return | GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven | +| GlobalDataFlow.cs:81:22:81:93 | call to method First | return | GlobalDataFlow.cs:81:22:81:93 | call to method First | +| GlobalDataFlow.cs:83:22:83:87 | call to method Select | return | GlobalDataFlow.cs:83:22:83:87 | call to method Select | +| GlobalDataFlow.cs:83:22:83:87 | call to method Select | yield return | GlobalDataFlow.cs:83:22:83:87 | call to method Select | +| GlobalDataFlow.cs:83:22:83:95 | call to method First | return | GlobalDataFlow.cs:83:22:83:95 | call to method First | +| GlobalDataFlow.cs:85:22:85:128 | call to method Zip | return | GlobalDataFlow.cs:85:22:85:128 | call to method Zip | +| GlobalDataFlow.cs:85:22:85:128 | call to method Zip | yield return | GlobalDataFlow.cs:85:22:85:128 | call to method Zip | +| GlobalDataFlow.cs:85:22:85:136 | call to method First | return | GlobalDataFlow.cs:85:22:85:136 | call to method First | +| GlobalDataFlow.cs:87:22:87:128 | call to method Zip | return | GlobalDataFlow.cs:87:22:87:128 | call to method Zip | +| GlobalDataFlow.cs:87:22:87:128 | call to method Zip | yield return | GlobalDataFlow.cs:87:22:87:128 | call to method Zip | +| GlobalDataFlow.cs:87:22:87:136 | call to method First | return | GlobalDataFlow.cs:87:22:87:136 | call to method First | +| GlobalDataFlow.cs:89:22:89:110 | call to method Aggregate | return | GlobalDataFlow.cs:89:22:89:110 | call to method Aggregate | +| GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate | return | GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate | +| GlobalDataFlow.cs:94:9:94:42 | call to method TryParse | out | GlobalDataFlow.cs:94:36:94:41 | SSA def(sink21) | +| GlobalDataFlow.cs:94:9:94:42 | call to method TryParse | ref | GlobalDataFlow.cs:94:36:94:41 | SSA def(sink21) | +| GlobalDataFlow.cs:94:9:94:42 | call to method TryParse | return | GlobalDataFlow.cs:94:9:94:42 | call to method TryParse | +| GlobalDataFlow.cs:97:9:97:41 | call to method TryParse | out | GlobalDataFlow.cs:97:35:97:40 | SSA def(sink22) | +| GlobalDataFlow.cs:97:9:97:41 | call to method TryParse | ref | GlobalDataFlow.cs:97:35:97:40 | SSA def(sink22) | +| GlobalDataFlow.cs:97:9:97:41 | call to method TryParse | return | GlobalDataFlow.cs:97:9:97:41 | call to method TryParse | +| GlobalDataFlow.cs:101:24:101:33 | call to method Return | return | GlobalDataFlow.cs:101:24:101:33 | call to method Return | +| GlobalDataFlow.cs:103:28:103:63 | call to method GetMethod | qualifier | GlobalDataFlow.cs:103:28:103:43 | [post] typeof(...) | +| GlobalDataFlow.cs:103:28:103:63 | call to method GetMethod | return | GlobalDataFlow.cs:103:28:103:63 | call to method GetMethod | +| GlobalDataFlow.cs:103:28:103:103 | call to method Invoke | return | GlobalDataFlow.cs:103:28:103:103 | call to method Invoke | +| GlobalDataFlow.cs:105:9:105:49 | call to method ReturnOut | out | GlobalDataFlow.cs:105:27:105:34 | SSA def(nonSink0) | +| GlobalDataFlow.cs:105:9:105:49 | call to method ReturnOut | ref | GlobalDataFlow.cs:105:27:105:34 | SSA def(nonSink0) | +| GlobalDataFlow.cs:107:9:107:49 | call to method ReturnOut | out | GlobalDataFlow.cs:107:41:107:48 | SSA def(nonSink0) | +| GlobalDataFlow.cs:109:9:109:49 | call to method ReturnRef | out | GlobalDataFlow.cs:109:27:109:34 | SSA def(nonSink0) | +| GlobalDataFlow.cs:109:9:109:49 | call to method ReturnRef | ref | GlobalDataFlow.cs:109:27:109:34 | SSA def(nonSink0) | +| GlobalDataFlow.cs:111:9:111:49 | call to method ReturnRef | out | GlobalDataFlow.cs:111:30:111:34 | SSA def(sink1) | +| GlobalDataFlow.cs:111:9:111:49 | call to method ReturnRef | ref | GlobalDataFlow.cs:111:30:111:34 | SSA def(sink1) | +| GlobalDataFlow.cs:113:20:113:86 | call to method SelectEven | return | GlobalDataFlow.cs:113:20:113:86 | call to method SelectEven | +| GlobalDataFlow.cs:113:20:113:86 | call to method SelectEven | yield return | GlobalDataFlow.cs:113:20:113:86 | call to method SelectEven | +| GlobalDataFlow.cs:113:20:113:94 | call to method First | return | GlobalDataFlow.cs:113:20:113:94 | call to method First | +| GlobalDataFlow.cs:115:20:115:82 | call to method Select | return | GlobalDataFlow.cs:115:20:115:82 | call to method Select | +| GlobalDataFlow.cs:115:20:115:82 | call to method Select | yield return | GlobalDataFlow.cs:115:20:115:82 | call to method Select | +| GlobalDataFlow.cs:115:20:115:90 | call to method First | return | GlobalDataFlow.cs:115:20:115:90 | call to method First | +| GlobalDataFlow.cs:117:20:117:126 | call to method Zip | return | GlobalDataFlow.cs:117:20:117:126 | call to method Zip | +| GlobalDataFlow.cs:117:20:117:126 | call to method Zip | yield return | GlobalDataFlow.cs:117:20:117:126 | call to method Zip | +| GlobalDataFlow.cs:117:20:117:134 | call to method First | return | GlobalDataFlow.cs:117:20:117:134 | call to method First | +| GlobalDataFlow.cs:119:20:119:126 | call to method Zip | return | GlobalDataFlow.cs:119:20:119:126 | call to method Zip | +| GlobalDataFlow.cs:119:20:119:126 | call to method Zip | yield return | GlobalDataFlow.cs:119:20:119:126 | call to method Zip | +| GlobalDataFlow.cs:119:20:119:134 | call to method First | return | GlobalDataFlow.cs:119:20:119:134 | call to method First | +| GlobalDataFlow.cs:121:20:121:104 | call to method Aggregate | return | GlobalDataFlow.cs:121:20:121:104 | call to method Aggregate | +| GlobalDataFlow.cs:123:20:123:109 | call to method Aggregate | return | GlobalDataFlow.cs:123:20:123:109 | call to method Aggregate | +| GlobalDataFlow.cs:125:20:125:107 | call to method Aggregate | return | GlobalDataFlow.cs:125:20:125:107 | call to method Aggregate | +| GlobalDataFlow.cs:128:9:128:46 | call to method TryParse | out | GlobalDataFlow.cs:128:38:128:45 | SSA def(nonSink2) | +| GlobalDataFlow.cs:128:9:128:46 | call to method TryParse | ref | GlobalDataFlow.cs:128:38:128:45 | SSA def(nonSink2) | +| GlobalDataFlow.cs:128:9:128:46 | call to method TryParse | return | GlobalDataFlow.cs:128:9:128:46 | call to method TryParse | +| GlobalDataFlow.cs:131:9:131:45 | call to method TryParse | out | GlobalDataFlow.cs:131:37:131:44 | SSA def(nonSink3) | +| GlobalDataFlow.cs:131:9:131:45 | call to method TryParse | ref | GlobalDataFlow.cs:131:37:131:44 | SSA def(nonSink3) | +| GlobalDataFlow.cs:131:9:131:45 | call to method TryParse | return | GlobalDataFlow.cs:131:9:131:45 | call to method TryParse | +| GlobalDataFlow.cs:135:45:135:64 | call to method ApplyFunc | return | GlobalDataFlow.cs:135:45:135:64 | call to method ApplyFunc | +| GlobalDataFlow.cs:136:21:136:34 | delegate call | return | GlobalDataFlow.cs:136:21:136:34 | delegate call | +| GlobalDataFlow.cs:140:20:140:36 | delegate call | return | GlobalDataFlow.cs:140:20:140:36 | delegate call | +| GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc | return | GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc | +| GlobalDataFlow.cs:148:20:148:40 | call to method ApplyFunc | return | GlobalDataFlow.cs:148:20:148:40 | call to method ApplyFunc | +| GlobalDataFlow.cs:150:20:150:44 | call to method ApplyFunc | return | GlobalDataFlow.cs:150:20:150:44 | call to method ApplyFunc | +| GlobalDataFlow.cs:154:21:154:25 | call to method Out | qualifier | GlobalDataFlow.cs:154:21:154:25 | [post] this access | +| GlobalDataFlow.cs:154:21:154:25 | call to method Out | return | GlobalDataFlow.cs:154:21:154:25 | call to method Out | +| GlobalDataFlow.cs:157:9:157:25 | call to method OutOut | out | GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) | +| GlobalDataFlow.cs:157:9:157:25 | call to method OutOut | qualifier | GlobalDataFlow.cs:157:9:157:25 | [post] this access | +| GlobalDataFlow.cs:157:9:157:25 | call to method OutOut | ref | GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) | +| GlobalDataFlow.cs:160:9:160:25 | call to method OutRef | out | GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) | +| GlobalDataFlow.cs:160:9:160:25 | call to method OutRef | qualifier | GlobalDataFlow.cs:160:9:160:25 | [post] this access | +| GlobalDataFlow.cs:160:9:160:25 | call to method OutRef | ref | GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) | +| GlobalDataFlow.cs:162:22:162:31 | call to method OutYield | qualifier | GlobalDataFlow.cs:162:22:162:31 | [post] this access | +| GlobalDataFlow.cs:162:22:162:31 | call to method OutYield | return | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield | +| GlobalDataFlow.cs:162:22:162:31 | call to method OutYield | yield return | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield | +| GlobalDataFlow.cs:162:22:162:39 | call to method First | return | GlobalDataFlow.cs:162:22:162:39 | call to method First | +| GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam | return | GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam | +| GlobalDataFlow.cs:168:20:168:27 | call to method NonOut | qualifier | GlobalDataFlow.cs:168:20:168:27 | [post] this access | +| GlobalDataFlow.cs:168:20:168:27 | call to method NonOut | return | GlobalDataFlow.cs:168:20:168:27 | call to method NonOut | +| GlobalDataFlow.cs:170:9:170:31 | call to method NonOutOut | out | GlobalDataFlow.cs:170:23:170:30 | SSA def(nonSink0) | +| GlobalDataFlow.cs:170:9:170:31 | call to method NonOutOut | qualifier | GlobalDataFlow.cs:170:9:170:31 | [post] this access | +| GlobalDataFlow.cs:170:9:170:31 | call to method NonOutOut | ref | GlobalDataFlow.cs:170:23:170:30 | SSA def(nonSink0) | +| GlobalDataFlow.cs:172:9:172:31 | call to method NonOutRef | out | GlobalDataFlow.cs:172:23:172:30 | SSA def(nonSink0) | +| GlobalDataFlow.cs:172:9:172:31 | call to method NonOutRef | qualifier | GlobalDataFlow.cs:172:9:172:31 | [post] this access | +| GlobalDataFlow.cs:172:9:172:31 | call to method NonOutRef | ref | GlobalDataFlow.cs:172:23:172:30 | SSA def(nonSink0) | +| GlobalDataFlow.cs:174:20:174:32 | call to method NonOutYield | qualifier | GlobalDataFlow.cs:174:20:174:32 | [post] this access | +| GlobalDataFlow.cs:174:20:174:32 | call to method NonOutYield | return | GlobalDataFlow.cs:174:20:174:32 | call to method NonOutYield | +| GlobalDataFlow.cs:174:20:174:32 | call to method NonOutYield | yield return | GlobalDataFlow.cs:174:20:174:32 | call to method NonOutYield | +| GlobalDataFlow.cs:174:20:174:40 | call to method First | return | GlobalDataFlow.cs:174:20:174:40 | call to method First | +| GlobalDataFlow.cs:176:20:176:44 | call to method NonTaintedParam | return | GlobalDataFlow.cs:176:20:176:44 | call to method NonTaintedParam | +| GlobalDataFlow.cs:181:21:181:26 | delegate call | return | GlobalDataFlow.cs:181:21:181:26 | delegate call | +| GlobalDataFlow.cs:186:20:186:27 | delegate call | return | GlobalDataFlow.cs:186:20:186:27 | delegate call | +| GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy | return | GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy | +| GlobalDataFlow.cs:190:22:190:48 | access to property Value | qualifier | GlobalDataFlow.cs:190:22:190:42 | [post] object creation of type Lazy | +| GlobalDataFlow.cs:190:22:190:48 | access to property Value | return | GlobalDataFlow.cs:190:22:190:48 | access to property Value | +| GlobalDataFlow.cs:194:20:194:43 | object creation of type Lazy | return | GlobalDataFlow.cs:194:20:194:43 | object creation of type Lazy | +| GlobalDataFlow.cs:194:20:194:49 | access to property Value | qualifier | GlobalDataFlow.cs:194:20:194:43 | [post] object creation of type Lazy | +| GlobalDataFlow.cs:194:20:194:49 | access to property Value | return | GlobalDataFlow.cs:194:20:194:49 | access to property Value | +| GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty | qualifier | GlobalDataFlow.cs:198:22:198:32 | [post] this access | +| GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty | return | GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty | +| GlobalDataFlow.cs:202:20:202:33 | access to property NonOutProperty | qualifier | GlobalDataFlow.cs:202:20:202:33 | [post] this access | +| GlobalDataFlow.cs:202:20:202:33 | access to property NonOutProperty | return | GlobalDataFlow.cs:202:20:202:33 | access to property NonOutProperty | +| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable | return | GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable | +| GlobalDataFlow.cs:209:41:209:77 | call to method AsQueryable | return | GlobalDataFlow.cs:209:41:209:77 | call to method AsQueryable | +| GlobalDataFlow.cs:212:76:212:90 | call to method ReturnCheck2 | return | GlobalDataFlow.cs:212:76:212:90 | call to method ReturnCheck2 | +| GlobalDataFlow.cs:213:22:213:39 | call to method Select | return | GlobalDataFlow.cs:213:22:213:39 | call to method Select | +| GlobalDataFlow.cs:213:22:213:39 | call to method Select | yield return | GlobalDataFlow.cs:213:22:213:39 | call to method Select | +| GlobalDataFlow.cs:213:22:213:47 | call to method First | return | GlobalDataFlow.cs:213:22:213:47 | call to method First | +| GlobalDataFlow.cs:215:22:215:39 | call to method Select | return | GlobalDataFlow.cs:215:22:215:39 | call to method Select | +| GlobalDataFlow.cs:215:22:215:47 | call to method First | return | GlobalDataFlow.cs:215:22:215:47 | call to method First | +| GlobalDataFlow.cs:217:22:217:49 | call to method Select | return | GlobalDataFlow.cs:217:22:217:49 | call to method Select | +| GlobalDataFlow.cs:217:22:217:49 | call to method Select | yield return | GlobalDataFlow.cs:217:22:217:49 | call to method Select | +| GlobalDataFlow.cs:217:22:217:57 | call to method First | return | GlobalDataFlow.cs:217:22:217:57 | call to method First | +| GlobalDataFlow.cs:222:76:222:92 | call to method NonReturnCheck | return | GlobalDataFlow.cs:222:76:222:92 | call to method NonReturnCheck | +| GlobalDataFlow.cs:223:23:223:43 | call to method Select | return | GlobalDataFlow.cs:223:23:223:43 | call to method Select | +| GlobalDataFlow.cs:223:23:223:43 | call to method Select | yield return | GlobalDataFlow.cs:223:23:223:43 | call to method Select | +| GlobalDataFlow.cs:223:23:223:51 | call to method First | return | GlobalDataFlow.cs:223:23:223:51 | call to method First | +| GlobalDataFlow.cs:225:19:225:39 | call to method Select | return | GlobalDataFlow.cs:225:19:225:39 | call to method Select | +| GlobalDataFlow.cs:225:19:225:47 | call to method First | return | GlobalDataFlow.cs:225:19:225:47 | call to method First | +| GlobalDataFlow.cs:227:19:227:39 | call to method Select | return | GlobalDataFlow.cs:227:19:227:39 | call to method Select | +| GlobalDataFlow.cs:227:19:227:39 | call to method Select | yield return | GlobalDataFlow.cs:227:19:227:39 | call to method Select | +| GlobalDataFlow.cs:227:19:227:47 | call to method First | return | GlobalDataFlow.cs:227:19:227:47 | call to method First | +| GlobalDataFlow.cs:229:19:229:39 | call to method Select | return | GlobalDataFlow.cs:229:19:229:39 | call to method Select | +| GlobalDataFlow.cs:229:19:229:47 | call to method First | return | GlobalDataFlow.cs:229:19:229:47 | call to method First | +| GlobalDataFlow.cs:231:19:231:49 | call to method Select | return | GlobalDataFlow.cs:231:19:231:49 | call to method Select | +| GlobalDataFlow.cs:231:19:231:49 | call to method Select | yield return | GlobalDataFlow.cs:231:19:231:49 | call to method Select | +| GlobalDataFlow.cs:231:19:231:57 | call to method First | return | GlobalDataFlow.cs:231:19:231:57 | call to method First | +| GlobalDataFlow.cs:238:20:238:49 | call to method Run | return | GlobalDataFlow.cs:238:20:238:49 | call to method Run | +| GlobalDataFlow.cs:239:22:239:32 | access to property Result | qualifier | GlobalDataFlow.cs:239:22:239:25 | [post] access to local variable task | +| GlobalDataFlow.cs:239:22:239:32 | access to property Result | return | GlobalDataFlow.cs:239:22:239:32 | access to property Result | +| GlobalDataFlow.cs:245:16:245:33 | call to method Run | return | GlobalDataFlow.cs:245:16:245:33 | call to method Run | +| GlobalDataFlow.cs:246:24:246:34 | access to property Result | qualifier | GlobalDataFlow.cs:246:24:246:27 | [post] access to local variable task | +| GlobalDataFlow.cs:246:24:246:34 | access to property Result | return | GlobalDataFlow.cs:246:24:246:34 | access to property Result | +| GlobalDataFlow.cs:297:17:297:38 | call to method ApplyFunc | return | GlobalDataFlow.cs:297:17:297:38 | call to method ApplyFunc | +| GlobalDataFlow.cs:386:16:386:19 | delegate call | return | GlobalDataFlow.cs:386:16:386:19 | delegate call | +| GlobalDataFlow.cs:445:9:445:20 | call to method Append | qualifier | GlobalDataFlow.cs:445:9:445:10 | [post] access to parameter sb | +| GlobalDataFlow.cs:445:9:445:20 | call to method Append | return | GlobalDataFlow.cs:445:9:445:20 | call to method Append | +| GlobalDataFlow.cs:450:18:450:36 | object creation of type StringBuilder | return | GlobalDataFlow.cs:450:18:450:36 | object creation of type StringBuilder | +| GlobalDataFlow.cs:452:22:452:34 | call to method ToString | qualifier | GlobalDataFlow.cs:452:22:452:23 | [post] access to local variable sb | +| GlobalDataFlow.cs:452:22:452:34 | call to method ToString | return | GlobalDataFlow.cs:452:22:452:34 | call to method ToString | +| GlobalDataFlow.cs:455:9:455:18 | call to method Clear | qualifier | GlobalDataFlow.cs:455:9:455:10 | [post] access to local variable sb | +| GlobalDataFlow.cs:455:9:455:18 | call to method Clear | return | GlobalDataFlow.cs:455:9:455:18 | call to method Clear | +| GlobalDataFlow.cs:456:23:456:35 | call to method ToString | qualifier | GlobalDataFlow.cs:456:23:456:24 | [post] access to local variable sb | +| GlobalDataFlow.cs:456:23:456:35 | call to method ToString | return | GlobalDataFlow.cs:456:23:456:35 | call to method ToString | +| GlobalDataFlow.cs:462:22:462:65 | call to method Join | return | GlobalDataFlow.cs:462:22:462:65 | call to method Join | +| GlobalDataFlow.cs:465:23:465:65 | call to method Join | return | GlobalDataFlow.cs:465:23:465:65 | call to method Join | +| GlobalDataFlow.cs:477:44:477:47 | delegate call | return | GlobalDataFlow.cs:477:44:477:47 | delegate call | | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | return | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | return | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | | Splitting.cs:20:22:20:30 | call to method Return | return | Splitting.cs:20:22:20:30 | call to method Return | | Splitting.cs:21:21:21:33 | call to method Return | return | Splitting.cs:21:21:21:33 | call to method Return | +| Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | qualifier | Splitting.cs:30:9:30:9 | [post] [b (line 24): false] access to local variable d | | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | return | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | +| Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | qualifier | Splitting.cs:30:9:30:9 | [post] [b (line 24): true] access to local variable d | | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | return | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | +| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | qualifier | Splitting.cs:31:17:31:17 | [post] [b (line 24): false] access to local variable d | | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | return | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | +| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | qualifier | Splitting.cs:31:17:31:17 | [post] [b (line 24): true] access to local variable d | | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | return | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | | Splitting.cs:32:9:32:16 | [b (line 24): false] dynamic call to method Check | return | Splitting.cs:32:9:32:16 | [b (line 24): false] dynamic call to method Check | | Splitting.cs:32:9:32:16 | [b (line 24): true] dynamic call to method Check | return | Splitting.cs:32:9:32:16 | [b (line 24): true] dynamic call to method Check | | Splitting.cs:34:13:34:20 | dynamic call to method Check | return | Splitting.cs:34:13:34:20 | dynamic call to method Check | +| This.cs:12:9:12:20 | call to method M | qualifier | This.cs:12:9:12:12 | [post] this access | +| This.cs:13:9:13:15 | call to method M | qualifier | This.cs:13:9:13:15 | [post] this access | +| This.cs:15:9:15:21 | call to method M | qualifier | This.cs:15:9:15:12 | [post] this access | +| This.cs:16:9:16:16 | call to method M | qualifier | This.cs:16:9:16:16 | [post] this access | | This.cs:17:9:17:18 | object creation of type This | return | This.cs:17:9:17:18 | object creation of type This | +| This.cs:26:13:26:24 | call to method M | qualifier | This.cs:26:13:26:16 | [post] this access | +| This.cs:27:13:27:24 | call to method M | qualifier | This.cs:27:13:27:16 | [post] base access | | This.cs:28:13:28:21 | object creation of type Sub | return | This.cs:28:13:28:21 | object creation of type Sub | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Lazy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Lazy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Lazy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Lazy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Lazy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Lazy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Run | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Run] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Run | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Run] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Run | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Run] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Run | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Run] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Aggregate | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Aggregate] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Aggregate | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Aggregate] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Select | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Select] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Select | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Select] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Select | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Select] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Select | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Select] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Aggregate | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Aggregate] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Aggregate | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Aggregate] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Aggregate | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Aggregate] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Aggregate | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Aggregate] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of ToDictionary | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of ToDictionary] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of ToDictionary | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of ToDictionary] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of ToLookup | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of ToLookup] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of ToLookup | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of ToLookup] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Zip | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Zip] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Zip | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Zip] | +| file://:0:0:0:0 | [summary] delegate call, parameter 3 of Aggregate | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of Aggregate] | +| file://:0:0:0:0 | [summary] delegate call, parameter 3 of Aggregate | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of Aggregate] | +| file://:0:0:0:0 | [summary] delegate call, parameter 3 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 3 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 3 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 3 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 4 of GroupJoin | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of GroupJoin] | +| file://:0:0:0:0 | [summary] delegate call, parameter 4 of GroupJoin | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of GroupJoin] | +| file://:0:0:0:0 | [summary] delegate call, parameter 4 of GroupJoin | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of GroupJoin] | +| file://:0:0:0:0 | [summary] delegate call, parameter 4 of GroupJoin | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of GroupJoin] | +| file://:0:0:0:0 | [summary] delegate call, parameter 4 of Join | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of Join] | +| file://:0:0:0:0 | [summary] delegate call, parameter 4 of Join | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of Join] | +| file://:0:0:0:0 | [summary] delegate call, parameter 4 of Join | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of Join] | +| file://:0:0:0:0 | [summary] delegate call, parameter 4 of Join | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of Join] | diff --git a/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.ql b/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.ql index e3cee19f7245..a850a6af8d53 100644 --- a/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.ql +++ b/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.ql @@ -1,5 +1,29 @@ import csharp import semmle.code.csharp.dataflow.internal.DataFlowDispatch +import semmle.code.csharp.dataflow.internal.DataFlowPrivate -from DataFlowCall call, ReturnKind kind -select call, kind, getAnOutNode(call, kind) +private class DataFlowCallAdjusted extends TDataFlowCall { + string toString() { result = this.(DataFlowCall).toString() } + + Location getLocation() { + exists(Location l | + l = this.(DataFlowCall).getLocation() and + if l instanceof SourceLocation then result = l else result instanceof EmptyLocation + ) + } +} + +private class NodeAdjusted extends TNode { + string toString() { result = this.(DataFlow::Node).toString() } + + Location getLocation() { + exists(Location l | + l = this.(DataFlow::Node).getLocation() and + if l instanceof SourceLocation then result = l else result instanceof EmptyLocation + ) + } +} + +from DataFlowCallAdjusted call, NodeAdjusted n, ReturnKind kind +where n = getAnOutNode(call, kind) +select call, kind, n diff --git a/csharp/ql/test/library-tests/dataflow/global/GlobalDataFlow.cs b/csharp/ql/test/library-tests/dataflow/global/GlobalDataFlow.cs index 83003aaea668..35c38fb809b1 100644 --- a/csharp/ql/test/library-tests/dataflow/global/GlobalDataFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/global/GlobalDataFlow.cs @@ -2,6 +2,7 @@ using System.Text; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; /// /// All (tainted) sinks are named `sink[Param|Field|Property]N`, for some N, and all @@ -231,6 +232,23 @@ public void M2() Check(nonSink); } + public async void M3() + { + // async await, tainted + var task = Task.Run(() => "taint source"); + var sink41 = task.Result; + Check(sink41); + var sink42 = await task; + Check(sink42); + + // async await, not tainted + task = Task.Run(() => ""); + var nonSink0 = task.Result; + Check(nonSink0); + var nonSink1 = await task; + Check(nonSink1); + } + static void Check(T x) { } static void In0(T sinkParam0) @@ -421,6 +439,32 @@ string NonOutProperty { get { return ""; } } + + static void AppendToStringBuilder(StringBuilder sb, string s) + { + sb.Append(s); + } + + void TestStringBuilderFlow() + { + var sb = new StringBuilder(); + AppendToStringBuilder(sb, "taint source"); + var sink43 = sb.ToString(); + Check(sink43); + + sb.Clear(); + var nonSink = sb.ToString(); + Check(nonSink); + } + + void TestStringFlow() + { + var sink44 = string.Join(",", "whatever", "taint source"); + Check(sink44); + + var nonSink = string.Join(",", "whatever", "not tainted"); + Check(nonSink); + } } static class IEnumerableExtensions diff --git a/csharp/ql/test/library-tests/dataflow/global/Splitting.cs b/csharp/ql/test/library-tests/dataflow/global/Splitting.cs index 8749c4c44c79..30b9a1b9d719 100644 --- a/csharp/ql/test/library-tests/dataflow/global/Splitting.cs +++ b/csharp/ql/test/library-tests/dataflow/global/Splitting.cs @@ -33,4 +33,22 @@ void M2(bool b, string tainted) if (b) Check(x); } + + void M3(bool b) + { + var s = b ? "taint source" : "not tainted"; + if (b) + Check(s); // flow + else + Check(s); // no flow [FALSE POSITIVE] + } + + void M4(bool b) + { + var s = b switch { true => "taint source", false => "not tainted" }; + if (b) + Check(s); // flow + else + Check(s); // no flow [FALSE POSITIVE] + } } diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected b/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected index 57fd2c9e0c3d..aee973d855b7 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected @@ -12,51 +12,59 @@ | Capture.cs:161:15:161:20 | access to local variable sink36 | | Capture.cs:169:15:169:20 | access to local variable sink37 | | Capture.cs:195:15:195:20 | access to local variable sink38 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | -| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | -| GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | -| GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | -| GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | -| GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | -| GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | -| GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | -| GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | -| GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | -| GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | -| GlobalDataFlow.cs:210:58:210:68 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | -| GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | -| GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | -| GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:296:15:296:24 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:302:15:302:24 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:308:15:308:25 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | -| GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | +| GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | +| GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | +| GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | +| GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | +| GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | +| GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | +| GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | +| GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | +| GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | +| GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | +| GlobalDataFlow.cs:90:15:90:20 | access to local variable sink17 | +| GlobalDataFlow.cs:92:15:92:20 | access to local variable sink18 | +| GlobalDataFlow.cs:95:15:95:20 | access to local variable sink21 | +| GlobalDataFlow.cs:98:15:98:20 | access to local variable sink22 | +| GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | +| GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | +| GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | +| GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | +| GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | +| GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | +| GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | +| GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | +| GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | +| GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | +| GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | +| GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | +| GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | +| GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | +| GlobalDataFlow.cs:240:15:240:20 | access to local variable sink41 | +| GlobalDataFlow.cs:242:15:242:20 | access to local variable sink42 | +| GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:272:15:272:24 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:277:15:277:24 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:282:15:282:24 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:287:15:287:24 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:314:15:314:24 | access to parameter sinkParam8 | +| GlobalDataFlow.cs:320:15:320:24 | access to parameter sinkParam9 | +| GlobalDataFlow.cs:326:15:326:25 | access to parameter sinkParam11 | +| GlobalDataFlow.cs:401:15:401:20 | access to local variable sink11 | +| GlobalDataFlow.cs:424:41:424:46 | access to local variable sink20 | +| GlobalDataFlow.cs:453:15:453:20 | access to local variable sink43 | +| GlobalDataFlow.cs:463:15:463:20 | access to local variable sink44 | | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:21:28:21:32 | access to parameter value | +| Splitting.cs:21:21:21:33 | call to method Return | | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | | Splitting.cs:34:19:34:19 | access to local variable x | +| Splitting.cs:41:19:41:19 | access to local variable s | +| Splitting.cs:43:19:43:19 | access to local variable s | +| Splitting.cs:50:19:50:19 | access to local variable s | +| Splitting.cs:52:19:52:19 | access to local variable s | diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected index c0422a5f0f57..a0ac519a6c65 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected @@ -1,239 +1,246 @@ edges -| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:14:9:14:20 | [implicit argument] tainted : String | -| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:25:9:25:20 | [implicit argument] tainted : String | -| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:33:9:33:40 | [implicit argument] tainted : String | +| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:12:19:12:24 | access to local variable sink27 | +| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:21:23:21:28 | access to local variable sink28 | +| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:30:19:30:24 | access to local variable sink29 | | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:61:36:61:42 | access to parameter tainted : String | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:12:19:12:24 | access to local variable sink27 | -| Capture.cs:14:9:14:20 | [implicit argument] tainted : String | Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:21:23:21:28 | access to local variable sink28 | -| Capture.cs:25:9:25:20 | [implicit argument] tainted : String | Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:30:19:30:24 | access to local variable sink29 | -| Capture.cs:33:9:33:40 | [implicit argument] tainted : String | Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | -| Capture.cs:50:50:50:55 | sink39 : String | Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | -| Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | -| Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | Capture.cs:57:27:57:32 | access to parameter sink39 | +| Capture.cs:50:50:50:55 | sink39 : String | Capture.cs:57:27:57:32 | access to parameter sink39 | | Capture.cs:61:36:61:42 | access to parameter tainted : String | Capture.cs:50:50:50:55 | sink39 : String | -| Capture.cs:69:13:69:35 | SSA def(sink30) : String | Capture.cs:71:9:71:21 | SSA call def(sink30) : String | +| Capture.cs:69:13:69:35 | SSA def(sink30) : String | Capture.cs:72:15:72:20 | access to local variable sink30 | | Capture.cs:69:22:69:35 | "taint source" : String | Capture.cs:69:13:69:35 | SSA def(sink30) : String | -| Capture.cs:71:9:71:21 | SSA call def(sink30) : String | Capture.cs:72:15:72:20 | access to local variable sink30 | -| Capture.cs:79:17:79:39 | SSA def(sink31) : String | Capture.cs:83:9:83:21 | SSA call def(sink31) : String | +| Capture.cs:79:17:79:39 | SSA def(sink31) : String | Capture.cs:84:15:84:20 | access to local variable sink31 | | Capture.cs:79:26:79:39 | "taint source" : String | Capture.cs:79:17:79:39 | SSA def(sink31) : String | -| Capture.cs:83:9:83:21 | SSA call def(sink31) : String | Capture.cs:84:15:84:20 | access to local variable sink31 | -| Capture.cs:89:13:89:35 | SSA def(sink32) : String | Capture.cs:92:9:92:41 | SSA call def(sink32) : String | +| Capture.cs:89:13:89:35 | SSA def(sink32) : String | Capture.cs:93:15:93:20 | access to local variable sink32 | | Capture.cs:89:22:89:35 | "taint source" : String | Capture.cs:89:13:89:35 | SSA def(sink32) : String | -| Capture.cs:92:9:92:41 | SSA call def(sink32) : String | Capture.cs:93:15:93:20 | access to local variable sink32 | -| Capture.cs:115:17:115:39 | SSA def(sink40) : String | Capture.cs:121:9:121:35 | SSA call def(sink40) : String | +| Capture.cs:115:17:115:39 | SSA def(sink40) : String | Capture.cs:122:15:122:20 | access to local variable sink40 | | Capture.cs:115:26:115:39 | "taint source" : String | Capture.cs:115:17:115:39 | SSA def(sink40) : String | -| Capture.cs:121:9:121:35 | SSA call def(sink40) : String | Capture.cs:122:15:122:20 | access to local variable sink40 | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:132:9:132:25 | [implicit argument] tainted : String | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:144:9:144:25 | [implicit argument] tainted : String | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:153:9:153:45 | [implicit argument] tainted : String | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:160:22:160:38 | [implicit argument] tainted : String | +| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:133:15:133:20 | access to local variable sink33 | +| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:145:15:145:20 | access to local variable sink34 | +| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:154:15:154:20 | access to local variable sink35 | +| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:168:25:168:31 | access to parameter tainted : String | | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:194:25:194:31 | access to parameter tainted : String | -| Capture.cs:132:9:132:25 | SSA call def(sink33) : String | Capture.cs:133:15:133:20 | access to local variable sink33 | -| Capture.cs:132:9:132:25 | [implicit argument] tainted : String | Capture.cs:132:9:132:25 | SSA call def(sink33) : String | -| Capture.cs:144:9:144:25 | SSA call def(sink34) : String | Capture.cs:145:15:145:20 | access to local variable sink34 | -| Capture.cs:144:9:144:25 | [implicit argument] tainted : String | Capture.cs:144:9:144:25 | SSA call def(sink34) : String | -| Capture.cs:153:9:153:45 | SSA call def(sink35) : String | Capture.cs:154:15:154:20 | access to local variable sink35 | -| Capture.cs:153:9:153:45 | [implicit argument] tainted : String | Capture.cs:153:9:153:45 | SSA call def(sink35) : String | -| Capture.cs:160:22:160:38 | [implicit argument] tainted : String | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | Capture.cs:161:15:161:20 | access to local variable sink36 | -| Capture.cs:168:9:168:32 | SSA call def(sink37) : String | Capture.cs:169:15:169:20 | access to local variable sink37 | -| Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:168:9:168:32 | SSA call def(sink37) : String | +| Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:169:15:169:20 | access to local variable sink37 | | Capture.cs:194:22:194:32 | call to local function Id : String | Capture.cs:195:15:195:20 | access to local variable sink38 | | Capture.cs:194:25:194:31 | access to parameter tainted : String | Capture.cs:194:22:194:32 | call to local function Id : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:242:26:242:35 | sinkParam1 : String | -| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:361:41:361:41 | x : String | -| GlobalDataFlow.cs:53:15:53:15 | x : String | GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | GlobalDataFlow.cs:252:26:252:35 | sinkParam4 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:361:41:361:41 | x : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:375:52:375:52 | x : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:375:52:375:52 | x : String | -| GlobalDataFlow.cs:56:37:56:37 | x : String | GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:375:52:375:52 | x : String | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:406:9:406:11 | value : String | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | -| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:82:76:82:86 | [implicit argument 0] delegate creation of type Func : String | -| GlobalDataFlow.cs:82:76:82:86 | [implicit argument 0] delegate creation of type Func : String | GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:82:76:82:86 | [implicit argument 0] delegate creation of type Func : String | GlobalDataFlow.cs:294:31:294:40 | sinkParam8 : String | -| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | -| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | -| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:88:23:88:66 | (...) ... : String[] | -| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:90:83:90:101 | [implicit argument 0] (...) => ... : String | -| GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | GlobalDataFlow.cs:84:117:84:127 | [implicit argument 0] (...) => ... : String | -| GlobalDataFlow.cs:84:117:84:127 | [implicit argument 0] (...) => ... : String | GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... : String | -| GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... : String | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | -| GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... : String | GlobalDataFlow.cs:86:70:86:113 | (...) ... : String[] | -| GlobalDataFlow.cs:86:70:86:113 | (...) ... : String[] | GlobalDataFlow.cs:86:117:86:127 | [implicit argument 1] (...) => ... : String | -| GlobalDataFlow.cs:86:117:86:127 | [implicit argument 1] (...) => ... : String | GlobalDataFlow.cs:86:117:86:127 | [output] (...) => ... : String | -| GlobalDataFlow.cs:86:117:86:127 | [output] (...) => ... : String | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | -| GlobalDataFlow.cs:88:23:88:66 | (...) ... : String[] | GlobalDataFlow.cs:88:83:88:101 | [implicit argument 1] (...) => ... : String | -| GlobalDataFlow.cs:88:83:88:101 | [implicit argument 1] (...) => ... : String | GlobalDataFlow.cs:88:83:88:101 | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:83:88:101 | [output] (...) => ... : String | GlobalDataFlow.cs:88:104:88:109 | [implicit argument 0] (...) => ... : String | -| GlobalDataFlow.cs:88:104:88:109 | [implicit argument 0] (...) => ... : String | GlobalDataFlow.cs:88:104:88:109 | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:104:88:109 | [output] (...) => ... : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | -| GlobalDataFlow.cs:90:83:90:101 | [implicit argument 0] (...) => ... : String | GlobalDataFlow.cs:90:83:90:101 | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:83:90:101 | [output] (...) => ... : String | GlobalDataFlow.cs:90:104:90:109 | [implicit argument 0] (...) => ... : String | -| GlobalDataFlow.cs:90:104:90:109 | [implicit argument 0] (...) => ... : String | GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | -| GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | -| GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | GlobalDataFlow.cs:135:21:135:34 | delegate call : String | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | -| GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | -| GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | GlobalDataFlow.cs:180:21:180:26 | delegate call : String | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | -| GlobalDataFlow.cs:189:22:189:42 | [library code] object creation of type Lazy : String | GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy [Value] : String | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy [Value] : String | GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | -| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:189:22:189:42 | [library code] object creation of type Lazy : String | -| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | -| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:212:37:212:38 | [implicit argument 0] access to local variable f1 : String | -| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:214:37:214:38 | [implicit argument 0] access to local variable f2 : String | -| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:216:37:216:48 | [implicit argument 0] delegate creation of type Func : String | -| GlobalDataFlow.cs:210:35:210:45 | sinkParam10 : String | GlobalDataFlow.cs:210:58:210:68 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:211:71:211:71 | x : String | GlobalDataFlow.cs:211:89:211:89 | access to parameter x : String | -| GlobalDataFlow.cs:211:89:211:89 | access to parameter x : String | GlobalDataFlow.cs:300:32:300:41 | sinkParam9 : String | -| GlobalDataFlow.cs:212:37:212:38 | [implicit argument 0] access to local variable f1 : String | GlobalDataFlow.cs:210:35:210:45 | sinkParam10 : String | -| GlobalDataFlow.cs:212:37:212:38 | [implicit argument 0] access to local variable f1 : String | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f1 : String | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f1 : String | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | -| GlobalDataFlow.cs:214:37:214:38 | [implicit argument 0] access to local variable f2 : String | GlobalDataFlow.cs:211:71:211:71 | x : String | -| GlobalDataFlow.cs:214:37:214:38 | [implicit argument 0] access to local variable f2 : String | GlobalDataFlow.cs:214:37:214:38 | [output] access to local variable f2 : String | -| GlobalDataFlow.cs:214:37:214:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | -| GlobalDataFlow.cs:216:37:216:48 | [implicit argument 0] delegate creation of type Func : String | GlobalDataFlow.cs:216:37:216:48 | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:216:37:216:48 | [implicit argument 0] delegate creation of type Func : String | GlobalDataFlow.cs:306:32:306:42 | sinkParam11 : String | -| GlobalDataFlow.cs:216:37:216:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | -| GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | -| GlobalDataFlow.cs:242:26:242:35 | sinkParam1 : String | GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:252:26:252:35 | sinkParam4 : String | GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:294:31:294:40 | sinkParam8 : String | GlobalDataFlow.cs:296:15:296:24 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:300:32:300:41 | sinkParam9 : String | GlobalDataFlow.cs:302:15:302:24 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:306:32:306:42 | sinkParam11 : String | GlobalDataFlow.cs:308:15:308:25 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | -| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | -| GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | -| GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | -| GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | -| GlobalDataFlow.cs:336:9:336:36 | yield return ...; : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | -| GlobalDataFlow.cs:336:22:336:35 | "taint source" : String | GlobalDataFlow.cs:336:9:336:36 | yield return ...; : IEnumerable | -| GlobalDataFlow.cs:361:41:361:41 | x : String | GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | -| GlobalDataFlow.cs:361:41:361:41 | x : String | GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | -| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | GlobalDataFlow.cs:53:15:53:15 | x : String | -| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | -| GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | -| GlobalDataFlow.cs:406:9:406:11 | value : String | GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | -| GlobalDataFlow.cs:417:22:417:35 | "taint source" : String | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:254:26:254:35 | sinkParam0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:260:26:260:35 | sinkParam1 : String | +| GlobalDataFlow.cs:45:30:45:39 | sinkParam2 : String | GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:30:45:39 | sinkParam2 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:379:41:379:41 | x : String | +| GlobalDataFlow.cs:54:15:54:15 | x : String | GlobalDataFlow.cs:54:24:54:24 | access to parameter x : String | +| GlobalDataFlow.cs:54:24:54:24 | access to parameter x : String | GlobalDataFlow.cs:270:26:270:35 | sinkParam4 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:379:41:379:41 | x : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:393:52:393:52 | x : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:393:52:393:52 | x : String | +| GlobalDataFlow.cs:57:37:57:37 | x : String | GlobalDataFlow.cs:57:46:57:46 | access to parameter x : String | +| GlobalDataFlow.cs:57:46:57:46 | access to parameter x : String | GlobalDataFlow.cs:285:26:285:35 | sinkParam7 : String | +| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:393:52:393:52 | x : String | +| GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:424:9:424:11 | value : String | +| GlobalDataFlow.cs:71:21:71:46 | call to method Return : String | GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | +| GlobalDataFlow.cs:71:21:71:46 | call to method Return : String | GlobalDataFlow.cs:73:94:73:98 | access to local variable sink0 : String | +| GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:21:71:46 | call to method Return : String | +| GlobalDataFlow.cs:73:21:73:101 | (...) ... : String | GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | +| GlobalDataFlow.cs:73:21:73:101 | (...) ... : String | GlobalDataFlow.cs:76:19:76:23 | access to local variable sink1 : String | +| GlobalDataFlow.cs:73:29:73:101 | call to method Invoke : String | GlobalDataFlow.cs:73:21:73:101 | (...) ... : String | +| GlobalDataFlow.cs:73:94:73:98 | access to local variable sink0 : String | GlobalDataFlow.cs:73:29:73:101 | call to method Invoke : String | +| GlobalDataFlow.cs:76:19:76:23 | access to local variable sink1 : String | GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) : String | +| GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) : String | GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | +| GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) : String | GlobalDataFlow.cs:79:19:79:23 | access to local variable sink2 : String | +| GlobalDataFlow.cs:79:19:79:23 | access to local variable sink2 : String | GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | +| GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | +| GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | GlobalDataFlow.cs:81:59:81:63 | access to local variable sink3 : String | +| GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | GlobalDataFlow.cs:136:29:136:33 | access to local variable sink3 : String | +| GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven [[]] : String | GlobalDataFlow.cs:81:22:81:93 | call to method First : String | +| GlobalDataFlow.cs:81:22:81:93 | call to method First : String | GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | +| GlobalDataFlow.cs:81:22:81:93 | call to method First : String | GlobalDataFlow.cs:83:59:83:64 | access to local variable sink13 : String | +| GlobalDataFlow.cs:81:23:81:65 | (...) ... [[]] : String | GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven [[]] : String | +| GlobalDataFlow.cs:81:57:81:65 | { ..., ... } [[]] : String | GlobalDataFlow.cs:81:23:81:65 | (...) ... [[]] : String | +| GlobalDataFlow.cs:81:59:81:63 | access to local variable sink3 : String | GlobalDataFlow.cs:81:57:81:65 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:83:22:83:87 | call to method Select [[]] : String | GlobalDataFlow.cs:83:22:83:95 | call to method First : String | +| GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | +| GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:85:59:85:64 | access to local variable sink14 : String | +| GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:89:59:89:64 | access to local variable sink14 : String | +| GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:91:75:91:80 | access to local variable sink14 : String | +| GlobalDataFlow.cs:83:23:83:66 | (...) ... [[]] : String | GlobalDataFlow.cs:83:22:83:87 | call to method Select [[]] : String | +| GlobalDataFlow.cs:83:23:83:66 | (...) ... [[]] : String | GlobalDataFlow.cs:312:31:312:40 | sinkParam8 : String | +| GlobalDataFlow.cs:83:57:83:66 | { ..., ... } [[]] : String | GlobalDataFlow.cs:83:23:83:66 | (...) ... [[]] : String | +| GlobalDataFlow.cs:83:59:83:64 | access to local variable sink13 : String | GlobalDataFlow.cs:83:57:83:66 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:85:22:85:128 | call to method Zip [[]] : String | GlobalDataFlow.cs:85:22:85:136 | call to method First : String | +| GlobalDataFlow.cs:85:22:85:136 | call to method First : String | GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | +| GlobalDataFlow.cs:85:22:85:136 | call to method First : String | GlobalDataFlow.cs:87:106:87:111 | access to local variable sink15 : String | +| GlobalDataFlow.cs:85:23:85:66 | (...) ... [[]] : String | GlobalDataFlow.cs:85:22:85:128 | call to method Zip [[]] : String | +| GlobalDataFlow.cs:85:57:85:66 | { ..., ... } [[]] : String | GlobalDataFlow.cs:85:23:85:66 | (...) ... [[]] : String | +| GlobalDataFlow.cs:85:59:85:64 | access to local variable sink14 : String | GlobalDataFlow.cs:85:57:85:66 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:87:22:87:128 | call to method Zip [[]] : String | GlobalDataFlow.cs:87:22:87:136 | call to method First : String | +| GlobalDataFlow.cs:87:22:87:136 | call to method First : String | GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | +| GlobalDataFlow.cs:87:70:87:113 | (...) ... [[]] : String | GlobalDataFlow.cs:87:22:87:128 | call to method Zip [[]] : String | +| GlobalDataFlow.cs:87:104:87:113 | { ..., ... } [[]] : String | GlobalDataFlow.cs:87:70:87:113 | (...) ... [[]] : String | +| GlobalDataFlow.cs:87:106:87:111 | access to local variable sink15 : String | GlobalDataFlow.cs:87:104:87:113 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:89:22:89:110 | call to method Aggregate : String | GlobalDataFlow.cs:90:15:90:20 | access to local variable sink17 | +| GlobalDataFlow.cs:89:23:89:66 | (...) ... [[]] : String | GlobalDataFlow.cs:89:22:89:110 | call to method Aggregate : String | +| GlobalDataFlow.cs:89:57:89:66 | { ..., ... } [[]] : String | GlobalDataFlow.cs:89:23:89:66 | (...) ... [[]] : String | +| GlobalDataFlow.cs:89:59:89:64 | access to local variable sink14 : String | GlobalDataFlow.cs:89:57:89:66 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate : String | GlobalDataFlow.cs:92:15:92:20 | access to local variable sink18 | +| GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate : String | GlobalDataFlow.cs:94:24:94:29 | access to local variable sink18 : String | +| GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate : String | GlobalDataFlow.cs:97:23:97:28 | access to local variable sink18 : String | +| GlobalDataFlow.cs:91:75:91:80 | access to local variable sink14 : String | GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate : String | +| GlobalDataFlow.cs:94:24:94:29 | access to local variable sink18 : String | GlobalDataFlow.cs:94:36:94:41 | SSA def(sink21) : Int32 | +| GlobalDataFlow.cs:94:36:94:41 | SSA def(sink21) : Int32 | GlobalDataFlow.cs:95:15:95:20 | access to local variable sink21 | +| GlobalDataFlow.cs:97:23:97:28 | access to local variable sink18 : String | GlobalDataFlow.cs:97:35:97:40 | SSA def(sink22) : Boolean | +| GlobalDataFlow.cs:97:35:97:40 | SSA def(sink22) : Boolean | GlobalDataFlow.cs:98:15:98:20 | access to local variable sink22 | +| GlobalDataFlow.cs:136:21:136:34 | delegate call : String | GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | +| GlobalDataFlow.cs:136:21:136:34 | delegate call : String | GlobalDataFlow.cs:144:39:144:43 | access to local variable sink4 : String | +| GlobalDataFlow.cs:136:29:136:33 | access to local variable sink3 : String | GlobalDataFlow.cs:136:21:136:34 | delegate call : String | +| GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | +| GlobalDataFlow.cs:144:39:144:43 | access to local variable sink4 : String | GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc : String | +| GlobalDataFlow.cs:154:21:154:25 | call to method Out : String | GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | +| GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) : String | GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | +| GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) : String | GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | +| GlobalDataFlow.cs:162:22:162:31 | call to method OutYield [[]] : String | GlobalDataFlow.cs:162:22:162:39 | call to method First : String | +| GlobalDataFlow.cs:162:22:162:39 | call to method First : String | GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | +| GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam : String | GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | +| GlobalDataFlow.cs:180:35:180:48 | "taint source" : String | GlobalDataFlow.cs:181:21:181:26 | delegate call : String | +| GlobalDataFlow.cs:181:21:181:26 | delegate call : String | GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | +| GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy [Value] : String | GlobalDataFlow.cs:190:22:190:48 | access to property Value : String | +| GlobalDataFlow.cs:190:22:190:48 | access to property Value : String | GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | +| GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty : String | GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | +| GlobalDataFlow.cs:208:38:208:61 | array creation of type String[] [[]] : String | GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | +| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [[]] : String | +| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [[]] : String | +| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [[]] : String | +| GlobalDataFlow.cs:208:44:208:61 | { ..., ... } [[]] : String | GlobalDataFlow.cs:208:38:208:61 | array creation of type String[] [[]] : String | +| GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:208:44:208:61 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:211:35:211:45 | sinkParam10 : String | GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | +| GlobalDataFlow.cs:212:71:212:71 | x : String | GlobalDataFlow.cs:212:89:212:89 | access to parameter x : String | +| GlobalDataFlow.cs:212:89:212:89 | access to parameter x : String | GlobalDataFlow.cs:318:32:318:41 | sinkParam9 : String | +| GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:211:35:211:45 | sinkParam10 : String | +| GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:213:22:213:39 | call to method Select [[]] : String | +| GlobalDataFlow.cs:213:22:213:39 | call to method Select [[]] : String | GlobalDataFlow.cs:213:22:213:47 | call to method First : String | +| GlobalDataFlow.cs:213:22:213:47 | call to method First : String | GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | +| GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:212:71:212:71 | x : String | +| GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:215:22:215:39 | call to method Select [[]] : String | +| GlobalDataFlow.cs:215:22:215:39 | call to method Select [[]] : String | GlobalDataFlow.cs:215:22:215:47 | call to method First : String | +| GlobalDataFlow.cs:215:22:215:47 | call to method First : String | GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | +| GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:217:22:217:49 | call to method Select [[]] : String | +| GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:324:32:324:42 | sinkParam11 : String | +| GlobalDataFlow.cs:217:22:217:49 | call to method Select [[]] : String | GlobalDataFlow.cs:217:22:217:57 | call to method First : String | +| GlobalDataFlow.cs:217:22:217:57 | call to method First : String | GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | +| GlobalDataFlow.cs:238:20:238:49 | call to method Run [Result] : String | GlobalDataFlow.cs:239:22:239:25 | access to local variable task [Result] : String | +| GlobalDataFlow.cs:238:20:238:49 | call to method Run [Result] : String | GlobalDataFlow.cs:241:28:241:31 | access to local variable task [Result] : String | +| GlobalDataFlow.cs:238:35:238:48 | "taint source" : String | GlobalDataFlow.cs:238:20:238:49 | call to method Run [Result] : String | +| GlobalDataFlow.cs:239:22:239:25 | access to local variable task [Result] : String | GlobalDataFlow.cs:239:22:239:32 | access to property Result : String | +| GlobalDataFlow.cs:239:22:239:32 | access to property Result : String | GlobalDataFlow.cs:240:15:240:20 | access to local variable sink41 | +| GlobalDataFlow.cs:241:22:241:31 | await ... : String | GlobalDataFlow.cs:242:15:242:20 | access to local variable sink42 | +| GlobalDataFlow.cs:241:28:241:31 | access to local variable task [Result] : String | GlobalDataFlow.cs:241:22:241:31 | await ... : String | +| GlobalDataFlow.cs:254:26:254:35 | sinkParam0 : String | GlobalDataFlow.cs:256:16:256:25 | access to parameter sinkParam0 : String | +| GlobalDataFlow.cs:254:26:254:35 | sinkParam0 : String | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:256:16:256:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:254:26:254:35 | sinkParam0 : String | +| GlobalDataFlow.cs:260:26:260:35 | sinkParam1 : String | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:265:26:265:35 | sinkParam3 : String | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:270:26:270:35 | sinkParam4 : String | GlobalDataFlow.cs:272:15:272:24 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:275:26:275:35 | sinkParam5 : String | GlobalDataFlow.cs:277:15:277:24 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:280:26:280:35 | sinkParam6 : String | GlobalDataFlow.cs:282:15:282:24 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:285:26:285:35 | sinkParam7 : String | GlobalDataFlow.cs:287:15:287:24 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:312:31:312:40 | sinkParam8 : String | GlobalDataFlow.cs:314:15:314:24 | access to parameter sinkParam8 | +| GlobalDataFlow.cs:318:32:318:41 | sinkParam9 : String | GlobalDataFlow.cs:320:15:320:24 | access to parameter sinkParam9 | +| GlobalDataFlow.cs:324:32:324:42 | sinkParam11 : String | GlobalDataFlow.cs:326:15:326:25 | access to parameter sinkParam11 | +| GlobalDataFlow.cs:338:16:338:29 | "taint source" : String | GlobalDataFlow.cs:154:21:154:25 | call to method Out : String | +| GlobalDataFlow.cs:338:16:338:29 | "taint source" : String | GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy [Value] : String | +| GlobalDataFlow.cs:343:9:343:26 | SSA def(x) : String | GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) : String | +| GlobalDataFlow.cs:343:13:343:26 | "taint source" : String | GlobalDataFlow.cs:343:9:343:26 | SSA def(x) : String | +| GlobalDataFlow.cs:348:9:348:26 | SSA def(x) : String | GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) : String | +| GlobalDataFlow.cs:348:13:348:26 | "taint source" : String | GlobalDataFlow.cs:348:9:348:26 | SSA def(x) : String | +| GlobalDataFlow.cs:354:22:354:35 | "taint source" : String | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield [[]] : String | +| GlobalDataFlow.cs:379:41:379:41 | x : String | GlobalDataFlow.cs:381:11:381:11 | access to parameter x : String | +| GlobalDataFlow.cs:379:41:379:41 | x : String | GlobalDataFlow.cs:381:11:381:11 | access to parameter x : String | +| GlobalDataFlow.cs:381:11:381:11 | access to parameter x : String | GlobalDataFlow.cs:54:15:54:15 | x : String | +| GlobalDataFlow.cs:381:11:381:11 | access to parameter x : String | GlobalDataFlow.cs:265:26:265:35 | sinkParam3 : String | +| GlobalDataFlow.cs:393:52:393:52 | x : String | GlobalDataFlow.cs:395:11:395:11 | access to parameter x : String | +| GlobalDataFlow.cs:393:52:393:52 | x : String | GlobalDataFlow.cs:395:11:395:11 | access to parameter x : String | +| GlobalDataFlow.cs:393:52:393:52 | x : String | GlobalDataFlow.cs:395:11:395:11 | access to parameter x : String | +| GlobalDataFlow.cs:395:11:395:11 | access to parameter x : String | GlobalDataFlow.cs:57:37:57:37 | x : String | +| GlobalDataFlow.cs:395:11:395:11 | access to parameter x : String | GlobalDataFlow.cs:275:26:275:35 | sinkParam5 : String | +| GlobalDataFlow.cs:395:11:395:11 | access to parameter x : String | GlobalDataFlow.cs:280:26:280:35 | sinkParam6 : String | +| GlobalDataFlow.cs:398:39:398:45 | tainted : String | GlobalDataFlow.cs:401:15:401:20 | access to local variable sink11 | +| GlobalDataFlow.cs:398:39:398:45 | tainted : String | GlobalDataFlow.cs:402:16:402:21 | access to local variable sink11 : String | +| GlobalDataFlow.cs:402:16:402:21 | access to local variable sink11 : String | GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam : String | +| GlobalDataFlow.cs:424:9:424:11 | value : String | GlobalDataFlow.cs:424:41:424:46 | access to local variable sink20 | +| GlobalDataFlow.cs:435:22:435:35 | "taint source" : String | GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty : String | +| GlobalDataFlow.cs:451:31:451:32 | [post] access to local variable sb [[]] : String | GlobalDataFlow.cs:452:22:452:23 | access to local variable sb [[]] : String | +| GlobalDataFlow.cs:451:35:451:48 | "taint source" : String | GlobalDataFlow.cs:451:31:451:32 | [post] access to local variable sb [[]] : String | +| GlobalDataFlow.cs:452:22:452:23 | access to local variable sb [[]] : String | GlobalDataFlow.cs:452:22:452:34 | call to method ToString : String | +| GlobalDataFlow.cs:452:22:452:34 | call to method ToString : String | GlobalDataFlow.cs:453:15:453:20 | access to local variable sink43 | +| GlobalDataFlow.cs:462:22:462:65 | call to method Join : String | GlobalDataFlow.cs:463:15:463:20 | access to local variable sink44 | +| GlobalDataFlow.cs:462:51:462:64 | "taint source" : String | GlobalDataFlow.cs:462:22:462:65 | call to method Join : String | | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | @@ -241,14 +248,12 @@ edges | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:11:19:11:19 | access to local variable x | | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | -| Splitting.cs:21:9:21:11 | value : String | Splitting.cs:21:28:21:32 | access to parameter value | +| Splitting.cs:21:9:21:11 | value : String | Splitting.cs:21:28:21:32 | access to parameter value : String | +| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:21:21:21:33 | call to method Return | | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:34:19:34:19 | access to local variable x | | Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:21:9:21:11 | value : String | | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:21:9:21:11 | value : String | | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : String | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | @@ -256,201 +261,215 @@ edges | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | Splitting.cs:34:19:34:19 | access to local variable x | | Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : String | | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | +| Splitting.cs:39:21:39:34 | [b (line 37): true] "taint source" : String | Splitting.cs:41:19:41:19 | access to local variable s | +| Splitting.cs:39:21:39:34 | [b (line 37): true] "taint source" : String | Splitting.cs:43:19:43:19 | access to local variable s | +| Splitting.cs:48:36:48:49 | "taint source" : String | Splitting.cs:50:19:50:19 | access to local variable s | +| Splitting.cs:48:36:48:49 | "taint source" : String | Splitting.cs:52:19:52:19 | access to local variable s | nodes | Capture.cs:7:20:7:26 | tainted : String | semmle.label | tainted : String | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | semmle.label | SSA capture def(tainted) : String | | Capture.cs:12:19:12:24 | access to local variable sink27 | semmle.label | access to local variable sink27 | -| Capture.cs:14:9:14:20 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | semmle.label | SSA capture def(tainted) : String | | Capture.cs:21:23:21:28 | access to local variable sink28 | semmle.label | access to local variable sink28 | -| Capture.cs:25:9:25:20 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | semmle.label | SSA capture def(tainted) : String | | Capture.cs:30:19:30:24 | access to local variable sink29 | semmle.label | access to local variable sink29 | -| Capture.cs:33:9:33:40 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:50:50:50:55 | sink39 : String | semmle.label | sink39 : String | -| Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | semmle.label | [implicit argument] sink39 : String | -| Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | semmle.label | SSA capture def(sink39) : String | | Capture.cs:57:27:57:32 | access to parameter sink39 | semmle.label | access to parameter sink39 | | Capture.cs:61:36:61:42 | access to parameter tainted : String | semmle.label | access to parameter tainted : String | | Capture.cs:69:13:69:35 | SSA def(sink30) : String | semmle.label | SSA def(sink30) : String | | Capture.cs:69:22:69:35 | "taint source" : String | semmle.label | "taint source" : String | -| Capture.cs:71:9:71:21 | SSA call def(sink30) : String | semmle.label | SSA call def(sink30) : String | | Capture.cs:72:15:72:20 | access to local variable sink30 | semmle.label | access to local variable sink30 | | Capture.cs:79:17:79:39 | SSA def(sink31) : String | semmle.label | SSA def(sink31) : String | | Capture.cs:79:26:79:39 | "taint source" : String | semmle.label | "taint source" : String | -| Capture.cs:83:9:83:21 | SSA call def(sink31) : String | semmle.label | SSA call def(sink31) : String | | Capture.cs:84:15:84:20 | access to local variable sink31 | semmle.label | access to local variable sink31 | | Capture.cs:89:13:89:35 | SSA def(sink32) : String | semmle.label | SSA def(sink32) : String | | Capture.cs:89:22:89:35 | "taint source" : String | semmle.label | "taint source" : String | -| Capture.cs:92:9:92:41 | SSA call def(sink32) : String | semmle.label | SSA call def(sink32) : String | | Capture.cs:93:15:93:20 | access to local variable sink32 | semmle.label | access to local variable sink32 | | Capture.cs:115:17:115:39 | SSA def(sink40) : String | semmle.label | SSA def(sink40) : String | | Capture.cs:115:26:115:39 | "taint source" : String | semmle.label | "taint source" : String | -| Capture.cs:121:9:121:35 | SSA call def(sink40) : String | semmle.label | SSA call def(sink40) : String | | Capture.cs:122:15:122:20 | access to local variable sink40 | semmle.label | access to local variable sink40 | | Capture.cs:125:25:125:31 | tainted : String | semmle.label | tainted : String | -| Capture.cs:132:9:132:25 | SSA call def(sink33) : String | semmle.label | SSA call def(sink33) : String | -| Capture.cs:132:9:132:25 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:133:15:133:20 | access to local variable sink33 | semmle.label | access to local variable sink33 | -| Capture.cs:144:9:144:25 | SSA call def(sink34) : String | semmle.label | SSA call def(sink34) : String | -| Capture.cs:144:9:144:25 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:145:15:145:20 | access to local variable sink34 | semmle.label | access to local variable sink34 | -| Capture.cs:153:9:153:45 | SSA call def(sink35) : String | semmle.label | SSA call def(sink35) : String | -| Capture.cs:153:9:153:45 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:154:15:154:20 | access to local variable sink35 | semmle.label | access to local variable sink35 | -| Capture.cs:160:22:160:38 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | semmle.label | call to local function CaptureThrough4 : String | | Capture.cs:161:15:161:20 | access to local variable sink36 | semmle.label | access to local variable sink36 | -| Capture.cs:168:9:168:32 | SSA call def(sink37) : String | semmle.label | SSA call def(sink37) : String | | Capture.cs:168:25:168:31 | access to parameter tainted : String | semmle.label | access to parameter tainted : String | | Capture.cs:169:15:169:20 | access to local variable sink37 | semmle.label | access to local variable sink37 | | Capture.cs:194:22:194:32 | call to local function Id : String | semmle.label | call to local function Id : String | | Capture.cs:194:25:194:31 | access to parameter tainted : String | semmle.label | access to parameter tainted : String | | Capture.cs:195:15:195:20 | access to local variable sink38 | semmle.label | access to local variable sink38 | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | semmle.label | access to field SinkField0 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | semmle.label | sinkParam2 : String | -| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | semmle.label | access to parameter sinkParam2 | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:15:53:15 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:56:37:56:37 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | semmle.label | call to method Return : String | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | semmle.label | access to local variable sink0 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | semmle.label | (...) ... : String | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | semmle.label | call to method Invoke : String | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | semmle.label | access to local variable sink0 : String | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | semmle.label | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | semmle.label | access to local variable sink1 : String | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | semmle.label | SSA def(sink2) : String | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | semmle.label | access to local variable sink2 | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | semmle.label | access to local variable sink2 : String | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | semmle.label | SSA def(sink3) : String | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | semmle.label | access to local variable sink3 | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | semmle.label | call to method SelectEven : IEnumerable | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | semmle.label | (...) ... : String[] | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | semmle.label | access to local variable sink13 | -| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | semmle.label | (...) ... : String[] | -| GlobalDataFlow.cs:82:76:82:86 | [implicit argument 0] delegate creation of type Func : String | semmle.label | [implicit argument 0] delegate creation of type Func : String | -| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : String | semmle.label | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | semmle.label | access to local variable sink14 | -| GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | semmle.label | (...) ... : String[] | -| GlobalDataFlow.cs:84:117:84:127 | [implicit argument 0] (...) => ... : String | semmle.label | [implicit argument 0] (...) => ... : String | -| GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | semmle.label | access to local variable sink15 | -| GlobalDataFlow.cs:86:70:86:113 | (...) ... : String[] | semmle.label | (...) ... : String[] | -| GlobalDataFlow.cs:86:117:86:127 | [implicit argument 1] (...) => ... : String | semmle.label | [implicit argument 1] (...) => ... : String | -| GlobalDataFlow.cs:86:117:86:127 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | -| GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | semmle.label | access to local variable sink16 | -| GlobalDataFlow.cs:88:23:88:66 | (...) ... : String[] | semmle.label | (...) ... : String[] | -| GlobalDataFlow.cs:88:83:88:101 | [implicit argument 1] (...) => ... : String | semmle.label | [implicit argument 1] (...) => ... : String | -| GlobalDataFlow.cs:88:83:88:101 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:104:88:109 | [implicit argument 0] (...) => ... : String | semmle.label | [implicit argument 0] (...) => ... : String | -| GlobalDataFlow.cs:88:104:88:109 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | -| GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | semmle.label | access to local variable sink17 | -| GlobalDataFlow.cs:90:83:90:101 | [implicit argument 0] (...) => ... : String | semmle.label | [implicit argument 0] (...) => ... : String | -| GlobalDataFlow.cs:90:83:90:101 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:104:90:109 | [implicit argument 0] (...) => ... : String | semmle.label | [implicit argument 0] (...) => ... : String | -| GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | semmle.label | access to local variable sink18 | -| GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | semmle.label | access to local variable sink21 | -| GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | semmle.label | access to local variable sink22 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | semmle.label | delegate call : String | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | semmle.label | access to local variable sink3 : String | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | semmle.label | access to local variable sink4 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | semmle.label | call to method ApplyFunc : String | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | semmle.label | access to local variable sink4 : String | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | semmle.label | access to local variable sink5 | -| GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | semmle.label | call to method Out : String | -| GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | semmle.label | access to local variable sink6 | -| GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | semmle.label | SSA def(sink7) : String | -| GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | semmle.label | access to local variable sink7 | -| GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | semmle.label | SSA def(sink8) : String | -| GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | semmle.label | access to local variable sink8 | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | semmle.label | call to method OutYield : IEnumerable | -| GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | semmle.label | access to local variable sink12 | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | semmle.label | call to method TaintedParam : String | -| GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | semmle.label | access to local variable sink23 | -| GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | semmle.label | delegate call : String | -| GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | semmle.label | access to local variable sink9 | -| GlobalDataFlow.cs:189:22:189:42 | [library code] object creation of type Lazy : String | semmle.label | [library code] object creation of type Lazy : String | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy [Value] : String | semmle.label | object creation of type Lazy [Value] : String | -| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | semmle.label | access to property Value : String | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | semmle.label | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | semmle.label | access to local variable sink10 | -| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | semmle.label | access to property OutProperty : String | -| GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | semmle.label | access to local variable sink19 | -| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:210:35:210:45 | sinkParam10 : String | semmle.label | sinkParam10 : String | -| GlobalDataFlow.cs:210:58:210:68 | access to parameter sinkParam10 | semmle.label | access to parameter sinkParam10 | -| GlobalDataFlow.cs:211:71:211:71 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:211:89:211:89 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:212:37:212:38 | [implicit argument 0] access to local variable f1 : String | semmle.label | [implicit argument 0] access to local variable f1 : String | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f1 : String | semmle.label | [output] access to local variable f1 : String | -| GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | semmle.label | access to local variable sink24 | -| GlobalDataFlow.cs:214:37:214:38 | [implicit argument 0] access to local variable f2 : String | semmle.label | [implicit argument 0] access to local variable f2 : String | -| GlobalDataFlow.cs:214:37:214:38 | [output] access to local variable f2 : String | semmle.label | [output] access to local variable f2 : String | -| GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | semmle.label | access to local variable sink25 | -| GlobalDataFlow.cs:216:37:216:48 | [implicit argument 0] delegate creation of type Func : String | semmle.label | [implicit argument 0] delegate creation of type Func : String | -| GlobalDataFlow.cs:216:37:216:48 | [output] delegate creation of type Func : String | semmle.label | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | semmle.label | access to local variable sink26 | -| GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | semmle.label | sinkParam0 : String | -| GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | semmle.label | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | semmle.label | access to parameter sinkParam0 | -| GlobalDataFlow.cs:242:26:242:35 | sinkParam1 : String | semmle.label | sinkParam1 : String | -| GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | semmle.label | access to parameter sinkParam1 | -| GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | semmle.label | sinkParam3 : String | -| GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | semmle.label | access to parameter sinkParam3 | -| GlobalDataFlow.cs:252:26:252:35 | sinkParam4 : String | semmle.label | sinkParam4 : String | -| GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | semmle.label | access to parameter sinkParam4 | -| GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | semmle.label | sinkParam5 : String | -| GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | semmle.label | access to parameter sinkParam5 | -| GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | semmle.label | sinkParam6 : String | -| GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | semmle.label | access to parameter sinkParam6 | -| GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | semmle.label | sinkParam7 : String | -| GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | semmle.label | access to parameter sinkParam7 | -| GlobalDataFlow.cs:294:31:294:40 | sinkParam8 : String | semmle.label | sinkParam8 : String | -| GlobalDataFlow.cs:296:15:296:24 | access to parameter sinkParam8 | semmle.label | access to parameter sinkParam8 | -| GlobalDataFlow.cs:300:32:300:41 | sinkParam9 : String | semmle.label | sinkParam9 : String | -| GlobalDataFlow.cs:302:15:302:24 | access to parameter sinkParam9 | semmle.label | access to parameter sinkParam9 | -| GlobalDataFlow.cs:306:32:306:42 | sinkParam11 : String | semmle.label | sinkParam11 : String | -| GlobalDataFlow.cs:308:15:308:25 | access to parameter sinkParam11 | semmle.label | access to parameter sinkParam11 | -| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | -| GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | -| GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:336:9:336:36 | yield return ...; : IEnumerable | semmle.label | yield return ...; : IEnumerable | -| GlobalDataFlow.cs:336:22:336:35 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:361:41:361:41 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:361:41:361:41 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:380:39:380:45 | tainted : String | semmle.label | tainted : String | -| GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | semmle.label | access to local variable sink11 | -| GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | semmle.label | access to local variable sink11 : String | -| GlobalDataFlow.cs:406:9:406:11 | value : String | semmle.label | value : String | -| GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | semmle.label | access to local variable sink20 | -| GlobalDataFlow.cs:417:22:417:35 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | semmle.label | access to field SinkField0 | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:45:30:45:39 | sinkParam2 : String | semmle.label | sinkParam2 : String | +| GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | semmle.label | access to parameter sinkParam2 | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:15:54:15 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:54:24:54:24 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:57:37:57:37 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:57:46:57:46 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:71:21:71:46 | call to method Return : String | semmle.label | call to method Return : String | +| GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | semmle.label | access to local variable sink0 | +| GlobalDataFlow.cs:73:21:73:101 | (...) ... : String | semmle.label | (...) ... : String | +| GlobalDataFlow.cs:73:29:73:101 | call to method Invoke : String | semmle.label | call to method Invoke : String | +| GlobalDataFlow.cs:73:94:73:98 | access to local variable sink0 : String | semmle.label | access to local variable sink0 : String | +| GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | semmle.label | access to local variable sink1 | +| GlobalDataFlow.cs:76:19:76:23 | access to local variable sink1 : String | semmle.label | access to local variable sink1 : String | +| GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) : String | semmle.label | SSA def(sink2) : String | +| GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | semmle.label | access to local variable sink2 | +| GlobalDataFlow.cs:79:19:79:23 | access to local variable sink2 : String | semmle.label | access to local variable sink2 : String | +| GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | semmle.label | SSA def(sink3) : String | +| GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | semmle.label | access to local variable sink3 | +| GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven [[]] : String | semmle.label | call to method SelectEven [[]] : String | +| GlobalDataFlow.cs:81:22:81:93 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:81:23:81:65 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | +| GlobalDataFlow.cs:81:57:81:65 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:81:59:81:63 | access to local variable sink3 : String | semmle.label | access to local variable sink3 : String | +| GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | semmle.label | access to local variable sink13 | +| GlobalDataFlow.cs:83:22:83:87 | call to method Select [[]] : String | semmle.label | call to method Select [[]] : String | +| GlobalDataFlow.cs:83:22:83:95 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:83:23:83:66 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | +| GlobalDataFlow.cs:83:57:83:66 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:83:59:83:64 | access to local variable sink13 : String | semmle.label | access to local variable sink13 : String | +| GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | semmle.label | access to local variable sink14 | +| GlobalDataFlow.cs:85:22:85:128 | call to method Zip [[]] : String | semmle.label | call to method Zip [[]] : String | +| GlobalDataFlow.cs:85:22:85:136 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:85:23:85:66 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | +| GlobalDataFlow.cs:85:57:85:66 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:85:59:85:64 | access to local variable sink14 : String | semmle.label | access to local variable sink14 : String | +| GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | semmle.label | access to local variable sink15 | +| GlobalDataFlow.cs:87:22:87:128 | call to method Zip [[]] : String | semmle.label | call to method Zip [[]] : String | +| GlobalDataFlow.cs:87:22:87:136 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:87:70:87:113 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | +| GlobalDataFlow.cs:87:104:87:113 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:87:106:87:111 | access to local variable sink15 : String | semmle.label | access to local variable sink15 : String | +| GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | semmle.label | access to local variable sink16 | +| GlobalDataFlow.cs:89:22:89:110 | call to method Aggregate : String | semmle.label | call to method Aggregate : String | +| GlobalDataFlow.cs:89:23:89:66 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | +| GlobalDataFlow.cs:89:57:89:66 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:89:59:89:64 | access to local variable sink14 : String | semmle.label | access to local variable sink14 : String | +| GlobalDataFlow.cs:90:15:90:20 | access to local variable sink17 | semmle.label | access to local variable sink17 | +| GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate : String | semmle.label | call to method Aggregate : String | +| GlobalDataFlow.cs:91:75:91:80 | access to local variable sink14 : String | semmle.label | access to local variable sink14 : String | +| GlobalDataFlow.cs:92:15:92:20 | access to local variable sink18 | semmle.label | access to local variable sink18 | +| GlobalDataFlow.cs:94:24:94:29 | access to local variable sink18 : String | semmle.label | access to local variable sink18 : String | +| GlobalDataFlow.cs:94:36:94:41 | SSA def(sink21) : Int32 | semmle.label | SSA def(sink21) : Int32 | +| GlobalDataFlow.cs:95:15:95:20 | access to local variable sink21 | semmle.label | access to local variable sink21 | +| GlobalDataFlow.cs:97:23:97:28 | access to local variable sink18 : String | semmle.label | access to local variable sink18 : String | +| GlobalDataFlow.cs:97:35:97:40 | SSA def(sink22) : Boolean | semmle.label | SSA def(sink22) : Boolean | +| GlobalDataFlow.cs:98:15:98:20 | access to local variable sink22 | semmle.label | access to local variable sink22 | +| GlobalDataFlow.cs:136:21:136:34 | delegate call : String | semmle.label | delegate call : String | +| GlobalDataFlow.cs:136:29:136:33 | access to local variable sink3 : String | semmle.label | access to local variable sink3 : String | +| GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | semmle.label | access to local variable sink4 | +| GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc : String | semmle.label | call to method ApplyFunc : String | +| GlobalDataFlow.cs:144:39:144:43 | access to local variable sink4 : String | semmle.label | access to local variable sink4 : String | +| GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | semmle.label | access to local variable sink5 | +| GlobalDataFlow.cs:154:21:154:25 | call to method Out : String | semmle.label | call to method Out : String | +| GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | semmle.label | access to local variable sink6 | +| GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) : String | semmle.label | SSA def(sink7) : String | +| GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | semmle.label | access to local variable sink7 | +| GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) : String | semmle.label | SSA def(sink8) : String | +| GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | semmle.label | access to local variable sink8 | +| GlobalDataFlow.cs:162:22:162:31 | call to method OutYield [[]] : String | semmle.label | call to method OutYield [[]] : String | +| GlobalDataFlow.cs:162:22:162:39 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | semmle.label | access to local variable sink12 | +| GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam : String | semmle.label | call to method TaintedParam : String | +| GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | semmle.label | access to local variable sink23 | +| GlobalDataFlow.cs:180:35:180:48 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:181:21:181:26 | delegate call : String | semmle.label | delegate call : String | +| GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | semmle.label | access to local variable sink9 | +| GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy [Value] : String | semmle.label | object creation of type Lazy [Value] : String | +| GlobalDataFlow.cs:190:22:190:48 | access to property Value : String | semmle.label | access to property Value : String | +| GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | semmle.label | access to local variable sink10 | +| GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty : String | semmle.label | access to property OutProperty : String | +| GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | semmle.label | access to local variable sink19 | +| GlobalDataFlow.cs:208:38:208:61 | array creation of type String[] [[]] : String | semmle.label | array creation of type String[] [[]] : String | +| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | semmle.label | call to method AsQueryable [[]] : String | +| GlobalDataFlow.cs:208:44:208:61 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:211:35:211:45 | sinkParam10 : String | semmle.label | sinkParam10 : String | +| GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | semmle.label | access to parameter sinkParam10 | +| GlobalDataFlow.cs:212:71:212:71 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:212:89:212:89 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [[]] : String | semmle.label | access to local variable tainted [[]] : String | +| GlobalDataFlow.cs:213:22:213:39 | call to method Select [[]] : String | semmle.label | call to method Select [[]] : String | +| GlobalDataFlow.cs:213:22:213:47 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | semmle.label | access to local variable sink24 | +| GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [[]] : String | semmle.label | access to local variable tainted [[]] : String | +| GlobalDataFlow.cs:215:22:215:39 | call to method Select [[]] : String | semmle.label | call to method Select [[]] : String | +| GlobalDataFlow.cs:215:22:215:47 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | semmle.label | access to local variable sink25 | +| GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [[]] : String | semmle.label | access to local variable tainted [[]] : String | +| GlobalDataFlow.cs:217:22:217:49 | call to method Select [[]] : String | semmle.label | call to method Select [[]] : String | +| GlobalDataFlow.cs:217:22:217:57 | call to method First : String | semmle.label | call to method First : String | +| GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | semmle.label | access to local variable sink26 | +| GlobalDataFlow.cs:238:20:238:49 | call to method Run [Result] : String | semmle.label | call to method Run [Result] : String | +| GlobalDataFlow.cs:238:35:238:48 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:239:22:239:25 | access to local variable task [Result] : String | semmle.label | access to local variable task [Result] : String | +| GlobalDataFlow.cs:239:22:239:32 | access to property Result : String | semmle.label | access to property Result : String | +| GlobalDataFlow.cs:240:15:240:20 | access to local variable sink41 | semmle.label | access to local variable sink41 | +| GlobalDataFlow.cs:241:22:241:31 | await ... : String | semmle.label | await ... : String | +| GlobalDataFlow.cs:241:28:241:31 | access to local variable task [Result] : String | semmle.label | access to local variable task [Result] : String | +| GlobalDataFlow.cs:242:15:242:20 | access to local variable sink42 | semmle.label | access to local variable sink42 | +| GlobalDataFlow.cs:254:26:254:35 | sinkParam0 : String | semmle.label | sinkParam0 : String | +| GlobalDataFlow.cs:256:16:256:25 | access to parameter sinkParam0 : String | semmle.label | access to parameter sinkParam0 : String | +| GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam0 | semmle.label | access to parameter sinkParam0 | +| GlobalDataFlow.cs:260:26:260:35 | sinkParam1 : String | semmle.label | sinkParam1 : String | +| GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam1 | semmle.label | access to parameter sinkParam1 | +| GlobalDataFlow.cs:265:26:265:35 | sinkParam3 : String | semmle.label | sinkParam3 : String | +| GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam3 | semmle.label | access to parameter sinkParam3 | +| GlobalDataFlow.cs:270:26:270:35 | sinkParam4 : String | semmle.label | sinkParam4 : String | +| GlobalDataFlow.cs:272:15:272:24 | access to parameter sinkParam4 | semmle.label | access to parameter sinkParam4 | +| GlobalDataFlow.cs:275:26:275:35 | sinkParam5 : String | semmle.label | sinkParam5 : String | +| GlobalDataFlow.cs:277:15:277:24 | access to parameter sinkParam5 | semmle.label | access to parameter sinkParam5 | +| GlobalDataFlow.cs:280:26:280:35 | sinkParam6 : String | semmle.label | sinkParam6 : String | +| GlobalDataFlow.cs:282:15:282:24 | access to parameter sinkParam6 | semmle.label | access to parameter sinkParam6 | +| GlobalDataFlow.cs:285:26:285:35 | sinkParam7 : String | semmle.label | sinkParam7 : String | +| GlobalDataFlow.cs:287:15:287:24 | access to parameter sinkParam7 | semmle.label | access to parameter sinkParam7 | +| GlobalDataFlow.cs:312:31:312:40 | sinkParam8 : String | semmle.label | sinkParam8 : String | +| GlobalDataFlow.cs:314:15:314:24 | access to parameter sinkParam8 | semmle.label | access to parameter sinkParam8 | +| GlobalDataFlow.cs:318:32:318:41 | sinkParam9 : String | semmle.label | sinkParam9 : String | +| GlobalDataFlow.cs:320:15:320:24 | access to parameter sinkParam9 | semmle.label | access to parameter sinkParam9 | +| GlobalDataFlow.cs:324:32:324:42 | sinkParam11 : String | semmle.label | sinkParam11 : String | +| GlobalDataFlow.cs:326:15:326:25 | access to parameter sinkParam11 | semmle.label | access to parameter sinkParam11 | +| GlobalDataFlow.cs:338:16:338:29 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:343:9:343:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | +| GlobalDataFlow.cs:343:13:343:26 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:348:9:348:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | +| GlobalDataFlow.cs:348:13:348:26 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:354:22:354:35 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:379:41:379:41 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:379:41:379:41 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:381:11:381:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:381:11:381:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:393:52:393:52 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:393:52:393:52 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:393:52:393:52 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:395:11:395:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:395:11:395:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:395:11:395:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:398:39:398:45 | tainted : String | semmle.label | tainted : String | +| GlobalDataFlow.cs:401:15:401:20 | access to local variable sink11 | semmle.label | access to local variable sink11 | +| GlobalDataFlow.cs:402:16:402:21 | access to local variable sink11 : String | semmle.label | access to local variable sink11 : String | +| GlobalDataFlow.cs:424:9:424:11 | value : String | semmle.label | value : String | +| GlobalDataFlow.cs:424:41:424:46 | access to local variable sink20 | semmle.label | access to local variable sink20 | +| GlobalDataFlow.cs:435:22:435:35 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:451:31:451:32 | [post] access to local variable sb [[]] : String | semmle.label | [post] access to local variable sb [[]] : String | +| GlobalDataFlow.cs:451:35:451:48 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:452:22:452:23 | access to local variable sb [[]] : String | semmle.label | access to local variable sb [[]] : String | +| GlobalDataFlow.cs:452:22:452:34 | call to method ToString : String | semmle.label | call to method ToString : String | +| GlobalDataFlow.cs:453:15:453:20 | access to local variable sink43 | semmle.label | access to local variable sink43 | +| GlobalDataFlow.cs:462:22:462:65 | call to method Join : String | semmle.label | call to method Join : String | +| GlobalDataFlow.cs:462:51:462:64 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:463:15:463:20 | access to local variable sink44 | semmle.label | access to local variable sink44 | | Splitting.cs:3:28:3:34 | tainted : String | semmle.label | tainted : String | | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | semmle.label | [b (line 3): false] call to method Return : String | | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | semmle.label | [b (line 3): true] call to method Return : String | @@ -460,7 +479,8 @@ nodes | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | semmle.label | [b (line 3): true] access to local variable x | | Splitting.cs:11:19:11:19 | access to local variable x | semmle.label | access to local variable x | | Splitting.cs:21:9:21:11 | value : String | semmle.label | value : String | -| Splitting.cs:21:28:21:32 | access to parameter value | semmle.label | access to parameter value | +| Splitting.cs:21:21:21:33 | call to method Return | semmle.label | call to method Return | +| Splitting.cs:21:28:21:32 | access to parameter value : String | semmle.label | access to parameter value : String | | Splitting.cs:24:28:24:34 | tainted : String | semmle.label | tainted : String | | Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | semmle.label | [b (line 24): false] access to parameter tainted : String | | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | semmle.label | [b (line 24): true] access to parameter tainted : String | @@ -471,6 +491,12 @@ nodes | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | semmle.label | [b (line 24): false] access to local variable x | | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | semmle.label | [b (line 24): true] access to local variable x | | Splitting.cs:34:19:34:19 | access to local variable x | semmle.label | access to local variable x | +| Splitting.cs:39:21:39:34 | [b (line 37): true] "taint source" : String | semmle.label | [b (line 37): true] "taint source" : String | +| Splitting.cs:41:19:41:19 | access to local variable s | semmle.label | access to local variable s | +| Splitting.cs:43:19:43:19 | access to local variable s | semmle.label | access to local variable s | +| Splitting.cs:48:36:48:49 | "taint source" : String | semmle.label | "taint source" : String | +| Splitting.cs:50:19:50:19 | access to local variable s | semmle.label | access to local variable s | +| Splitting.cs:52:19:52:19 | access to local variable s | semmle.label | access to local variable s | #select | Capture.cs:12:19:12:24 | access to local variable sink27 | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:12:19:12:24 | access to local variable sink27 | access to local variable sink27 | | Capture.cs:21:23:21:28 | access to local variable sink28 | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:21:23:21:28 | access to local variable sink28 | access to local variable sink28 | @@ -486,51 +512,59 @@ nodes | Capture.cs:161:15:161:20 | access to local variable sink36 | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:161:15:161:20 | access to local variable sink36 | access to local variable sink36 | | Capture.cs:169:15:169:20 | access to local variable sink37 | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:169:15:169:20 | access to local variable sink37 | access to local variable sink37 | | Capture.cs:195:15:195:20 | access to local variable sink38 | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:195:15:195:20 | access to local variable sink38 | access to local variable sink38 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | access to field SinkField0 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | access to property SinkProperty0 | -| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | access to local variable sink0 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | access to local variable sink1 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | access to local variable sink2 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | access to local variable sink3 | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | access to local variable sink13 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | access to local variable sink14 | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | access to local variable sink15 | -| GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | access to local variable sink16 | -| GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | access to local variable sink17 | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | access to local variable sink18 | -| GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | access to local variable sink21 | -| GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | access to local variable sink22 | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | access to local variable sink4 | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | access to local variable sink5 | -| GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | access to local variable sink6 | -| GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | access to local variable sink7 | -| GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | access to local variable sink8 | -| GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | GlobalDataFlow.cs:336:22:336:35 | "taint source" : String | GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | access to local variable sink12 | -| GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | access to local variable sink23 | -| GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | access to local variable sink9 | -| GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | access to local variable sink10 | -| GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | GlobalDataFlow.cs:417:22:417:35 | "taint source" : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | access to local variable sink19 | -| GlobalDataFlow.cs:210:58:210:68 | access to parameter sinkParam10 | GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:210:58:210:68 | access to parameter sinkParam10 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | access to local variable sink24 | -| GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | access to local variable sink25 | -| GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | access to local variable sink26 | -| GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:296:15:296:24 | access to parameter sinkParam8 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:296:15:296:24 | access to parameter sinkParam8 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:302:15:302:24 | access to parameter sinkParam9 | GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:302:15:302:24 | access to parameter sinkParam9 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:308:15:308:25 | access to parameter sinkParam11 | GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:308:15:308:25 | access to parameter sinkParam11 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | access to local variable sink11 | -| GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | access to local variable sink20 | +| GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | access to field SinkField0 | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | access to property SinkProperty0 | +| GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | access to parameter sinkParam2 | +| GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | access to local variable sink0 | +| GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | access to local variable sink1 | +| GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | access to local variable sink2 | +| GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | access to local variable sink3 | +| GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | access to local variable sink13 | +| GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | access to local variable sink14 | +| GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | access to local variable sink15 | +| GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | access to local variable sink16 | +| GlobalDataFlow.cs:90:15:90:20 | access to local variable sink17 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:90:15:90:20 | access to local variable sink17 | access to local variable sink17 | +| GlobalDataFlow.cs:92:15:92:20 | access to local variable sink18 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:92:15:92:20 | access to local variable sink18 | access to local variable sink18 | +| GlobalDataFlow.cs:95:15:95:20 | access to local variable sink21 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:95:15:95:20 | access to local variable sink21 | access to local variable sink21 | +| GlobalDataFlow.cs:98:15:98:20 | access to local variable sink22 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:98:15:98:20 | access to local variable sink22 | access to local variable sink22 | +| GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | access to local variable sink4 | +| GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | access to local variable sink5 | +| GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | GlobalDataFlow.cs:338:16:338:29 | "taint source" : String | GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | access to local variable sink6 | +| GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | GlobalDataFlow.cs:343:13:343:26 | "taint source" : String | GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | access to local variable sink7 | +| GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | GlobalDataFlow.cs:348:13:348:26 | "taint source" : String | GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | access to local variable sink8 | +| GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | GlobalDataFlow.cs:354:22:354:35 | "taint source" : String | GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | access to local variable sink12 | +| GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | GlobalDataFlow.cs:398:39:398:45 | tainted : String | GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | access to local variable sink23 | +| GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | GlobalDataFlow.cs:180:35:180:48 | "taint source" : String | GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | access to local variable sink9 | +| GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | GlobalDataFlow.cs:338:16:338:29 | "taint source" : String | GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | access to local variable sink10 | +| GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | GlobalDataFlow.cs:435:22:435:35 | "taint source" : String | GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | access to local variable sink19 | +| GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | access to parameter sinkParam10 | +| GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | access to local variable sink24 | +| GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | access to local variable sink25 | +| GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | access to local variable sink26 | +| GlobalDataFlow.cs:240:15:240:20 | access to local variable sink41 | GlobalDataFlow.cs:238:35:238:48 | "taint source" : String | GlobalDataFlow.cs:240:15:240:20 | access to local variable sink41 | access to local variable sink41 | +| GlobalDataFlow.cs:242:15:242:20 | access to local variable sink42 | GlobalDataFlow.cs:238:35:238:48 | "taint source" : String | GlobalDataFlow.cs:242:15:242:20 | access to local variable sink42 | access to local variable sink42 | +| GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam1 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam3 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam3 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:272:15:272:24 | access to parameter sinkParam4 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:272:15:272:24 | access to parameter sinkParam4 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:277:15:277:24 | access to parameter sinkParam5 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:277:15:277:24 | access to parameter sinkParam5 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:282:15:282:24 | access to parameter sinkParam6 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:282:15:282:24 | access to parameter sinkParam6 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:287:15:287:24 | access to parameter sinkParam7 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:287:15:287:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:314:15:314:24 | access to parameter sinkParam8 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:314:15:314:24 | access to parameter sinkParam8 | access to parameter sinkParam8 | +| GlobalDataFlow.cs:320:15:320:24 | access to parameter sinkParam9 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:320:15:320:24 | access to parameter sinkParam9 | access to parameter sinkParam9 | +| GlobalDataFlow.cs:326:15:326:25 | access to parameter sinkParam11 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:326:15:326:25 | access to parameter sinkParam11 | access to parameter sinkParam11 | +| GlobalDataFlow.cs:401:15:401:20 | access to local variable sink11 | GlobalDataFlow.cs:398:39:398:45 | tainted : String | GlobalDataFlow.cs:401:15:401:20 | access to local variable sink11 | access to local variable sink11 | +| GlobalDataFlow.cs:424:41:424:46 | access to local variable sink20 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:424:41:424:46 | access to local variable sink20 | access to local variable sink20 | +| GlobalDataFlow.cs:453:15:453:20 | access to local variable sink43 | GlobalDataFlow.cs:451:35:451:48 | "taint source" : String | GlobalDataFlow.cs:453:15:453:20 | access to local variable sink43 | access to local variable sink43 | +| GlobalDataFlow.cs:463:15:463:20 | access to local variable sink44 | GlobalDataFlow.cs:462:51:462:64 | "taint source" : String | GlobalDataFlow.cs:463:15:463:20 | access to local variable sink44 | access to local variable sink44 | | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | [b (line 3): false] access to local variable x | | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | [b (line 3): true] access to local variable x | | Splitting.cs:11:19:11:19 | access to local variable x | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:11:19:11:19 | access to local variable x | access to local variable x | -| Splitting.cs:21:28:21:32 | access to parameter value | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:21:28:21:32 | access to parameter value | access to parameter value | +| Splitting.cs:21:21:21:33 | call to method Return | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:21:21:21:33 | call to method Return | call to method Return | | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | [b (line 24): false] access to local variable x | | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | [b (line 24): true] access to local variable x | | Splitting.cs:34:19:34:19 | access to local variable x | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:34:19:34:19 | access to local variable x | access to local variable x | +| Splitting.cs:41:19:41:19 | access to local variable s | Splitting.cs:39:21:39:34 | [b (line 37): true] "taint source" : String | Splitting.cs:41:19:41:19 | access to local variable s | access to local variable s | +| Splitting.cs:43:19:43:19 | access to local variable s | Splitting.cs:39:21:39:34 | [b (line 37): true] "taint source" : String | Splitting.cs:43:19:43:19 | access to local variable s | access to local variable s | +| Splitting.cs:50:19:50:19 | access to local variable s | Splitting.cs:48:36:48:49 | "taint source" : String | Splitting.cs:50:19:50:19 | access to local variable s | access to local variable s | +| Splitting.cs:52:19:52:19 | access to local variable s | Splitting.cs:48:36:48:49 | "taint source" : String | Splitting.cs:52:19:52:19 | access to local variable s | access to local variable s | diff --git a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.cs b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.cs index f6bf395eef2b..431cb6843e9c 100644 --- a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.cs @@ -45,6 +45,7 @@ void M() ieint.Select(x => x); List list = null; list.Find(x => x > 0); + list.Insert(0, 0); Stack stack = null; stack.Peek(); ArrayList al = null; @@ -83,6 +84,8 @@ void M() Path.GetPathRoot(""); HttpContextBase context = null; string name = context.Request.QueryString["name"]; + + var dict = new Dictionary() { { "abc", 0 } }; } [DataContract] diff --git a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected index 6769e2a14118..7a8df6dd4706 100644 --- a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected @@ -1,223 +1,7 @@ callableFlow -| LibraryTypeDataFlow.DataContract.get_AString() | qualifier -> return | false | -| System.Array.Add(object) | argument 0 -> qualifier | false | -| System.Array.AsReadOnly(T[]) | qualifier -> return | false | -| System.Array.Clone() | qualifier -> return | false | -| System.Array.Find(T[], Predicate) | argument 0 -> parameter 0 of argument 1 | false | -| System.Array.Find(T[], Predicate) | argument 0 -> return | false | -| System.Array.FindAll(T[], Predicate) | argument 0 -> parameter 0 of argument 1 | false | -| System.Array.FindAll(T[], Predicate) | argument 0 -> return | false | -| System.Array.FindLast(T[], Predicate) | argument 0 -> parameter 0 of argument 1 | false | -| System.Array.FindLast(T[], Predicate) | argument 0 -> return | false | -| System.Array.GetEnumerator() | qualifier -> return | false | -| System.Array.Insert(int, object) | argument 1 -> qualifier | false | -| System.Array.Reverse(Array) | qualifier -> return | false | -| System.Array.Reverse(Array, int, int) | qualifier -> return | false | -| System.Array.Reverse(T[]) | qualifier -> return | false | -| System.Array.Reverse(T[], int, int) | qualifier -> return | false | | System.Boolean.Parse(string) | argument 0 -> return | false | | System.Boolean.TryParse(string, out bool) | argument 0 -> argument 1 | false | | System.Boolean.TryParse(string, out bool) | argument 0 -> return | false | -| System.Collections.ArrayList.Add(object) | argument 0 -> qualifier | false | -| System.Collections.ArrayList.AddRange(ICollection) | argument 0 -> qualifier | false | -| System.Collections.ArrayList.Clone() | qualifier -> return | false | -| System.Collections.ArrayList.FixedSize(ArrayList) | argument 0 -> return | false | -| System.Collections.ArrayList.FixedSize(IList) | argument 0 -> return | false | -| System.Collections.ArrayList.GetEnumerator() | qualifier -> return | false | -| System.Collections.ArrayList.GetEnumerator(int, int) | qualifier -> return | false | -| System.Collections.ArrayList.GetRange(int, int) | qualifier -> return | false | -| System.Collections.ArrayList.Insert(int, object) | argument 1 -> qualifier | false | -| System.Collections.ArrayList.InsertRange(int, ICollection) | argument 1 -> qualifier | false | -| System.Collections.ArrayList.Reverse() | qualifier -> return | false | -| System.Collections.ArrayList.Reverse(int, int) | qualifier -> return | false | -| System.Collections.BitArray.Clone() | qualifier -> return | false | -| System.Collections.BitArray.GetEnumerator() | qualifier -> return | false | -| System.Collections.CollectionBase.Add(object) | argument 0 -> qualifier | false | -| System.Collections.CollectionBase.GetEnumerator() | qualifier -> return | false | -| System.Collections.CollectionBase.Insert(int, object) | argument 1 -> qualifier | false | -| System.Collections.Concurrent.BlockingCollection<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.Concurrent.BlockingCollection<>.Add(T, CancellationToken) | argument 1 -> qualifier | false | -| System.Collections.Concurrent.BlockingCollection<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Concurrent.ConcurrentBag<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.Concurrent.ConcurrentBag<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(KeyValuePair) | argument 0 -> qualifier | false | -| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(TKey, TValue) | argument 1 -> qualifier | false | -| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.Concurrent.ConcurrentDictionary<,>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Values() | qualifier -> return | false | -| System.Collections.Concurrent.ConcurrentQueue<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Concurrent.ConcurrentStack<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.DictionaryBase.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.DictionaryBase.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.Dictionary<,>.Add(KeyValuePair) | argument 0 -> qualifier | false | -| System.Collections.Generic.Dictionary<,>.Add(TKey, TValue) | argument 1 -> qualifier | false | -| System.Collections.Generic.Dictionary<,>.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.Generic.Dictionary<,>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.Dictionary<,>.KeyCollection.Add(TKey) | argument 0 -> qualifier | false | -| System.Collections.Generic.Dictionary<,>.KeyCollection.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.Dictionary<,>.ValueCollection.Add(TValue) | argument 0 -> qualifier | false | -| System.Collections.Generic.Dictionary<,>.ValueCollection.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.Dictionary<,>.get_Values() | qualifier -> return | false | -| System.Collections.Generic.HashSet<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.Generic.HashSet<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.ICollection<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.Generic.IDictionary<,>.Add(TKey, TValue) | argument 1 -> qualifier | false | -| System.Collections.Generic.IDictionary<,>.get_Values() | qualifier -> return | false | -| System.Collections.Generic.IEnumerable<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.IEnumerator<>.get_Current() | qualifier -> return | true | -| System.Collections.Generic.IList<>.Insert(int, T) | argument 1 -> qualifier | false | -| System.Collections.Generic.IReadOnlyDictionary<,>.get_Values() | qualifier -> return | false | -| System.Collections.Generic.ISet<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.Generic.KeyValuePair<,>.KeyValuePair(TKey, TValue) | argument 1 -> return | true | -| System.Collections.Generic.KeyValuePair<,>.get_Value() | qualifier -> return | true | -| System.Collections.Generic.LinkedList<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.Generic.LinkedList<>.Find(T) | qualifier -> return | false | -| System.Collections.Generic.LinkedList<>.FindLast(T) | qualifier -> return | false | -| System.Collections.Generic.LinkedList<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.List<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.Generic.List<>.Add(object) | argument 0 -> qualifier | false | -| System.Collections.Generic.List<>.AddRange(IEnumerable) | argument 0 -> qualifier | false | -| System.Collections.Generic.List<>.AsReadOnly() | qualifier -> return | false | -| System.Collections.Generic.List<>.Find(Predicate) | qualifier -> parameter 0 of argument 0 | false | -| System.Collections.Generic.List<>.Find(Predicate) | qualifier -> return | false | -| System.Collections.Generic.List<>.FindAll(Predicate) | qualifier -> parameter 0 of argument 0 | false | -| System.Collections.Generic.List<>.FindAll(Predicate) | qualifier -> return | false | -| System.Collections.Generic.List<>.FindLast(Predicate) | qualifier -> parameter 0 of argument 0 | false | -| System.Collections.Generic.List<>.FindLast(Predicate) | qualifier -> return | false | -| System.Collections.Generic.List<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.List<>.GetRange(int, int) | qualifier -> return | false | -| System.Collections.Generic.List<>.Insert(int, T) | argument 1 -> qualifier | false | -| System.Collections.Generic.List<>.Insert(int, object) | argument 1 -> qualifier | false | -| System.Collections.Generic.List<>.InsertRange(int, IEnumerable) | argument 1 -> qualifier | false | -| System.Collections.Generic.List<>.Reverse() | qualifier -> return | false | -| System.Collections.Generic.List<>.Reverse(int, int) | qualifier -> return | false | -| System.Collections.Generic.Queue<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.Queue<>.Peek() | qualifier -> return | false | -| System.Collections.Generic.SortedDictionary<,>.Add(KeyValuePair) | argument 0 -> qualifier | false | -| System.Collections.Generic.SortedDictionary<,>.Add(TKey, TValue) | argument 1 -> qualifier | false | -| System.Collections.Generic.SortedDictionary<,>.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.Generic.SortedDictionary<,>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.SortedDictionary<,>.KeyCollection.Add(TKey) | argument 0 -> qualifier | false | -| System.Collections.Generic.SortedDictionary<,>.KeyCollection.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.SortedDictionary<,>.ValueCollection.Add(TValue) | argument 0 -> qualifier | false | -| System.Collections.Generic.SortedDictionary<,>.ValueCollection.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.SortedDictionary<,>.get_Values() | qualifier -> return | false | -| System.Collections.Generic.SortedList<,>.Add(KeyValuePair) | argument 0 -> qualifier | false | -| System.Collections.Generic.SortedList<,>.Add(TKey, TValue) | argument 1 -> qualifier | false | -| System.Collections.Generic.SortedList<,>.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.Generic.SortedList<,>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.SortedList<,>.KeyList.Add(TKey) | argument 0 -> qualifier | false | -| System.Collections.Generic.SortedList<,>.KeyList.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.SortedList<,>.KeyList.Insert(int, TKey) | argument 1 -> qualifier | false | -| System.Collections.Generic.SortedList<,>.ValueList.Add(TValue) | argument 0 -> qualifier | false | -| System.Collections.Generic.SortedList<,>.ValueList.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.SortedList<,>.ValueList.Insert(int, TValue) | argument 1 -> qualifier | false | -| System.Collections.Generic.SortedList<,>.get_Values() | qualifier -> return | false | -| System.Collections.Generic.SortedSet<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.Generic.SortedSet<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.SortedSet<>.Reverse() | qualifier -> return | false | -| System.Collections.Generic.Stack<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.Stack<>.Peek() | qualifier -> return | false | -| System.Collections.Generic.Stack<>.Pop() | qualifier -> return | false | -| System.Collections.Hashtable.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.Hashtable.Clone() | qualifier -> return | false | -| System.Collections.Hashtable.GetEnumerator() | qualifier -> return | false | -| System.Collections.Hashtable.get_Values() | qualifier -> return | false | -| System.Collections.IDictionary.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.IDictionary.GetEnumerator() | qualifier -> return | false | -| System.Collections.IDictionary.get_Values() | qualifier -> return | false | -| System.Collections.IEnumerable.GetEnumerator() | qualifier -> return | false | -| System.Collections.IEnumerator.get_Current() | qualifier -> return | true | -| System.Collections.IList.Add(object) | argument 0 -> qualifier | false | -| System.Collections.IList.Insert(int, object) | argument 1 -> qualifier | false | -| System.Collections.ListDictionaryInternal.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.ListDictionaryInternal.GetEnumerator() | qualifier -> return | false | -| System.Collections.ListDictionaryInternal.get_Values() | qualifier -> return | false | -| System.Collections.ObjectModel.Collection<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.ObjectModel.Collection<>.Add(object) | argument 0 -> qualifier | false | -| System.Collections.ObjectModel.Collection<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.ObjectModel.Collection<>.Insert(int, T) | argument 1 -> qualifier | false | -| System.Collections.ObjectModel.Collection<>.Insert(int, object) | argument 1 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyCollection<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyCollection<>.Add(object) | argument 0 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyCollection<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.ObjectModel.ReadOnlyCollection<>.Insert(int, T) | argument 1 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyCollection<>.Insert(int, object) | argument 1 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(KeyValuePair) | argument 0 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(TKey, TValue) | argument 1 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.GetEnumerator() | qualifier -> return | false | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.Add(TKey) | argument 0 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.GetEnumerator() | qualifier -> return | false | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.Add(TValue) | argument 0 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.GetEnumerator() | qualifier -> return | false | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Values() | qualifier -> return | false | -| System.Collections.Queue.Clone() | qualifier -> return | false | -| System.Collections.Queue.GetEnumerator() | qualifier -> return | false | -| System.Collections.Queue.Peek() | qualifier -> return | false | -| System.Collections.ReadOnlyCollectionBase.GetEnumerator() | qualifier -> return | false | -| System.Collections.SortedList.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.SortedList.Clone() | qualifier -> return | false | -| System.Collections.SortedList.GetByIndex(int) | qualifier -> return | false | -| System.Collections.SortedList.GetEnumerator() | qualifier -> return | false | -| System.Collections.SortedList.GetValueList() | qualifier -> return | false | -| System.Collections.SortedList.get_Values() | qualifier -> return | false | -| System.Collections.Specialized.HybridDictionary.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.Specialized.HybridDictionary.GetEnumerator() | qualifier -> return | false | -| System.Collections.Specialized.HybridDictionary.get_Values() | qualifier -> return | false | -| System.Collections.Specialized.IOrderedDictionary.GetEnumerator() | qualifier -> return | false | -| System.Collections.Specialized.ListDictionary.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.Specialized.ListDictionary.GetEnumerator() | qualifier -> return | false | -| System.Collections.Specialized.ListDictionary.get_Values() | qualifier -> return | false | -| System.Collections.Specialized.NameObjectCollectionBase.GetEnumerator() | qualifier -> return | false | -| System.Collections.Specialized.NameObjectCollectionBase.KeysCollection.GetEnumerator() | qualifier -> return | false | -| System.Collections.Specialized.NameValueCollection.Add(NameValueCollection) | argument 0 -> qualifier | false | -| System.Collections.Specialized.NameValueCollection.Add(string, string) | argument 1 -> qualifier | false | -| System.Collections.Specialized.OrderedDictionary.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.Specialized.OrderedDictionary.AsReadOnly() | qualifier -> return | false | -| System.Collections.Specialized.OrderedDictionary.GetEnumerator() | qualifier -> return | false | -| System.Collections.Specialized.OrderedDictionary.get_Values() | qualifier -> return | false | -| System.Collections.Specialized.StringCollection.Add(object) | argument 0 -> qualifier | false | -| System.Collections.Specialized.StringCollection.Add(string) | argument 0 -> qualifier | false | -| System.Collections.Specialized.StringCollection.AddRange(String[]) | argument 0 -> qualifier | false | -| System.Collections.Specialized.StringCollection.GetEnumerator() | qualifier -> return | false | -| System.Collections.Specialized.StringCollection.Insert(int, object) | argument 1 -> qualifier | false | -| System.Collections.Specialized.StringCollection.Insert(int, string) | argument 1 -> qualifier | false | -| System.Collections.Specialized.StringDictionary.Add(string, string) | argument 1 -> qualifier | false | -| System.Collections.Specialized.StringDictionary.GetEnumerator() | qualifier -> return | false | -| System.Collections.Specialized.StringDictionary.get_Values() | qualifier -> return | false | -| System.Collections.Stack.Clone() | qualifier -> return | false | -| System.Collections.Stack.GetEnumerator() | qualifier -> return | false | -| System.Collections.Stack.Peek() | qualifier -> return | false | -| System.Collections.Stack.Pop() | qualifier -> return | false | -| System.ComponentModel.AttributeCollection.GetEnumerator() | qualifier -> return | false | -| System.ComponentModel.BindingList<>.Find(PropertyDescriptor, object) | qualifier -> return | false | -| System.ComponentModel.Design.DesignerCollection.GetEnumerator() | qualifier -> return | false | -| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.Add(object) | argument 0 -> qualifier | false | -| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.GetEnumerator() | qualifier -> return | false | -| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.Insert(int, object) | argument 1 -> qualifier | false | -| System.ComponentModel.Design.DesignerVerbCollection.Add(DesignerVerb) | argument 0 -> qualifier | false | -| System.ComponentModel.Design.DesignerVerbCollection.AddRange(DesignerVerbCollection) | argument 0 -> qualifier | false | -| System.ComponentModel.Design.DesignerVerbCollection.AddRange(DesignerVerb[]) | argument 0 -> qualifier | false | -| System.ComponentModel.Design.DesignerVerbCollection.Insert(int, DesignerVerb) | argument 1 -> qualifier | false | -| System.ComponentModel.EventDescriptorCollection.Add(EventDescriptor) | argument 0 -> qualifier | false | -| System.ComponentModel.EventDescriptorCollection.Add(object) | argument 0 -> qualifier | false | -| System.ComponentModel.EventDescriptorCollection.Find(string, bool) | qualifier -> return | false | -| System.ComponentModel.EventDescriptorCollection.GetEnumerator() | qualifier -> return | false | -| System.ComponentModel.EventDescriptorCollection.Insert(int, EventDescriptor) | argument 1 -> qualifier | false | -| System.ComponentModel.EventDescriptorCollection.Insert(int, object) | argument 1 -> qualifier | false | -| System.ComponentModel.IBindingList.Find(PropertyDescriptor, object) | qualifier -> return | false | -| System.ComponentModel.ListSortDescriptionCollection.Add(object) | argument 0 -> qualifier | false | -| System.ComponentModel.ListSortDescriptionCollection.GetEnumerator() | qualifier -> return | false | -| System.ComponentModel.ListSortDescriptionCollection.Insert(int, object) | argument 1 -> qualifier | false | -| System.ComponentModel.PropertyDescriptorCollection.Add(PropertyDescriptor) | argument 0 -> qualifier | false | -| System.ComponentModel.PropertyDescriptorCollection.Add(object) | argument 0 -> qualifier | false | -| System.ComponentModel.PropertyDescriptorCollection.Add(object, object) | argument 1 -> qualifier | false | -| System.ComponentModel.PropertyDescriptorCollection.Find(string, bool) | qualifier -> return | false | -| System.ComponentModel.PropertyDescriptorCollection.GetEnumerator() | qualifier -> return | false | -| System.ComponentModel.PropertyDescriptorCollection.Insert(int, PropertyDescriptor) | argument 1 -> qualifier | false | -| System.ComponentModel.PropertyDescriptorCollection.Insert(int, object) | argument 1 -> qualifier | false | -| System.ComponentModel.TypeConverter.StandardValuesCollection.GetEnumerator() | qualifier -> return | false | | System.Convert.ChangeType(object, Type) | argument 0 -> return | false | | System.Convert.ChangeType(object, Type, IFormatProvider) | argument 0 -> return | false | | System.Convert.ChangeType(object, TypeCode) | argument 0 -> return | false | @@ -532,10 +316,6 @@ callableFlow | System.Convert.TryFromBase64Chars(ReadOnlySpan, Span, out int) | argument 0 -> return | false | | System.Convert.TryFromBase64String(string, Span, out int) | argument 0 -> return | false | | System.Convert.TryToBase64Chars(ReadOnlySpan, Span, out int, Base64FormattingOptions) | argument 0 -> return | false | -| System.Dynamic.ExpandoObject.Add(KeyValuePair) | argument 0 -> qualifier | false | -| System.Dynamic.ExpandoObject.Add(string, object) | argument 1 -> qualifier | false | -| System.Dynamic.ExpandoObject.GetEnumerator() | qualifier -> return | false | -| System.ICloneable.Clone() | qualifier -> return | false | | System.IO.BufferedStream.BeginRead(Byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false | | System.IO.BufferedStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false | | System.IO.BufferedStream.CopyTo(Stream, int) | qualifier -> argument 0 | false | @@ -662,644 +442,45 @@ callableFlow | System.Int32.TryParse(string, NumberStyles, IFormatProvider, out int) | argument 0 -> return | false | | System.Int32.TryParse(string, out int) | argument 0 -> argument 1 | false | | System.Int32.TryParse(string, out int) | argument 0 -> return | false | -| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | argument 0 -> parameter 1 of argument 2 | false | -| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | argument 1 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | output from argument 2 -> parameter 0 of argument 3 | false | -| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | output from argument 3 -> return | false | -| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func) | argument 0 -> parameter 1 of argument 2 | false | -| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func) | argument 1 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func) | output from argument 2 -> return | false | -| System.Linq.Enumerable.Aggregate(IEnumerable, Func) | argument 0 -> parameter 1 of argument 1 | false | -| System.Linq.Enumerable.Aggregate(IEnumerable, Func) | output from argument 1 -> return | false | -| System.Linq.Enumerable.All(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Any(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.AsEnumerable(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Cast(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.Concat(IEnumerable, IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.Concat(IEnumerable, IEnumerable) | argument 1 -> return | false | -| System.Linq.Enumerable.Count(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.DefaultIfEmpty(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.DefaultIfEmpty(IEnumerable, TSource) | argument 0 -> return | false | -| System.Linq.Enumerable.DefaultIfEmpty(IEnumerable, TSource) | argument 1 -> return | false | -| System.Linq.Enumerable.Distinct(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.Distinct(IEnumerable, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.Enumerable.ElementAt(IEnumerable, int) | argument 0 -> return | false | -| System.Linq.Enumerable.ElementAtOrDefault(IEnumerable, int) | argument 0 -> return | false | -| System.Linq.Enumerable.Except(IEnumerable, IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.Except(IEnumerable, IEnumerable, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.Enumerable.First(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.First(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.First(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.FirstOrDefault(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.FirstOrDefault(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.FirstOrDefault(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | output from argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | output from argument 2 -> parameter 1 of argument 3 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | output from argument 3 -> return | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 2 -> parameter 1 of argument 3 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 3 -> return | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func) | output from argument 2 -> return | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | argument 0 -> parameter 1 of argument 2 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | output from argument 1 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | output from argument 2 -> return | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | output from argument 4 -> return | false | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 4 -> return | false | -| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable) | argument 1 -> return | false | -| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable, IEqualityComparer) | argument 1 -> return | false | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | output from argument 4 -> return | false | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | output from argument 4 -> return | false | -| System.Linq.Enumerable.Last(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.Last(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Last(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.LastOrDefault(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.LastOrDefault(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.LastOrDefault(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.LongCount(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.OfType(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.OrderBy(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.OrderBy(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.OrderBy(IEnumerable, Func, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.OrderBy(IEnumerable, Func, IComparer) | argument 0 -> return | false | -| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func, IComparer) | argument 0 -> return | false | -| System.Linq.Enumerable.Reverse(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.Select(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Select(IEnumerable, Func) | output from argument 1 -> return | false | -| System.Linq.Enumerable.Select(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Select(IEnumerable, Func) | output from argument 1 -> return | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | output from argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | output from argument 2 -> return | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | output from argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | output from argument 2 -> return | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | output from argument 1 -> return | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | output from argument 1 -> return | false | -| System.Linq.Enumerable.Single(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.Single(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Single(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.SingleOrDefault(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.SingleOrDefault(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.SingleOrDefault(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.Skip(IEnumerable, int) | argument 0 -> return | false | -| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Take(IEnumerable, int) | argument 0 -> return | false | -| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func, IComparer) | argument 0 -> return | false | -| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func, IComparer) | argument 0 -> return | false | -| System.Linq.Enumerable.ToArray(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func) | output from argument 2 -> return | false | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func, IEqualityComparer) | output from argument 2 -> return | false | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.Enumerable.ToList(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func) | output from argument 2 -> return | false | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func, IEqualityComparer) | output from argument 2 -> return | false | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.Enumerable.Union(IEnumerable, IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.Union(IEnumerable, IEnumerable) | argument 1 -> return | false | -| System.Linq.Enumerable.Union(IEnumerable, IEnumerable, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.Enumerable.Union(IEnumerable, IEnumerable, IEqualityComparer) | argument 1 -> return | false | -| System.Linq.Enumerable.Where(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Where(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.Where(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Where(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.Zip(IEnumerable, IEnumerable, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.Zip(IEnumerable, IEnumerable, Func) | argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.Enumerable.Zip(IEnumerable, IEnumerable, Func) | output from argument 2 -> return | false | -| System.Linq.EnumerableQuery<>.GetEnumerator() | qualifier -> return | false | -| System.Linq.Grouping<,>.Add(TElement) | argument 0 -> qualifier | false | -| System.Linq.Grouping<,>.GetEnumerator() | qualifier -> return | false | -| System.Linq.Grouping<,>.Insert(int, TElement) | argument 1 -> qualifier | false | -| System.Linq.Lookup<,>.GetEnumerator() | qualifier -> return | false | -| System.Linq.OrderedParallelQuery<>.GetEnumerator() | qualifier -> return | false | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | argument 0 -> parameter 1 of argument 2 | false | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | argument 1 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | output from argument 2 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | output from argument 3 -> return | false | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func) | argument 0 -> parameter 1 of argument 2 | false | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func) | argument 1 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, Func) | argument 0 -> parameter 1 of argument 1 | false | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, Func) | output from argument 1 -> return | false | -| System.Linq.ParallelEnumerable.All(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Any(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.AsEnumerable(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Cast(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Concat(ParallelQuery, IEnumerable) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Concat(ParallelQuery, IEnumerable) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Concat(ParallelQuery, ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Concat(ParallelQuery, ParallelQuery) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Count(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.DefaultIfEmpty(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.DefaultIfEmpty(ParallelQuery, TSource) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.DefaultIfEmpty(ParallelQuery, TSource) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Distinct(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Distinct(ParallelQuery, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ElementAt(ParallelQuery, int) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ElementAtOrDefault(ParallelQuery, int) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Except(ParallelQuery, IEnumerable) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Except(ParallelQuery, IEnumerable, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Except(ParallelQuery, ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Except(ParallelQuery, ParallelQuery, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.First(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.First(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.First(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | output from argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | output from argument 2 -> parameter 1 of argument 3 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | output from argument 3 -> return | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 2 -> parameter 1 of argument 3 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 3 -> return | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | argument 0 -> parameter 1 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | output from argument 1 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | output from argument 4 -> return | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 4 -> return | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | output from argument 4 -> return | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 4 -> return | false | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable, IEqualityComparer) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery, IEqualityComparer) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | output from argument 4 -> return | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | output from argument 4 -> return | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | output from argument 4 -> return | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | output from argument 4 -> return | false | -| System.Linq.ParallelEnumerable.Last(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Last(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Last(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.LongCount(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.OfType(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func, IComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func, IComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Reverse(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | output from argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | output from argument 1 -> return | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | output from argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | output from argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | output from argument 1 -> return | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | output from argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Single(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Single(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Single(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Skip(ParallelQuery, int) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Take(ParallelQuery, int) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func, IComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func, IComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ToArray(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func, IEqualityComparer) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ToList(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func, IEqualityComparer) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable, IEqualityComparer) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery, IEqualityComparer) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Zip(ParallelQuery, IEnumerable, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.Zip(ParallelQuery, IEnumerable, Func) | argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.ParallelEnumerable.Zip(ParallelQuery, IEnumerable, Func) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.Zip(ParallelQuery, ParallelQuery, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.Zip(ParallelQuery, ParallelQuery, Func) | argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.ParallelEnumerable.Zip(ParallelQuery, ParallelQuery, Func) | output from argument 2 -> return | false | -| System.Linq.ParallelQuery.GetEnumerator() | qualifier -> return | false | -| System.Linq.ParallelQuery<>.GetEnumerator() | qualifier -> return | false | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | argument 0 -> parameter 1 of argument 2 | false | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | argument 1 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | output from argument 2 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | output from argument 3 -> return | false | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | argument 0 -> parameter 1 of argument 2 | false | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | argument 1 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | output from argument 2 -> return | false | -| System.Linq.Queryable.Aggregate(IQueryable, Expression>) | argument 0 -> parameter 1 of argument 1 | false | -| System.Linq.Queryable.Aggregate(IQueryable, Expression>) | output from argument 1 -> return | false | -| System.Linq.Queryable.All(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Any(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.AsQueryable(IEnumerable) | argument 0 -> return | false | -| System.Linq.Queryable.AsQueryable(IEnumerable) | argument 0 -> return | false | -| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Cast(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.Concat(IQueryable, IEnumerable) | argument 0 -> return | false | -| System.Linq.Queryable.Concat(IQueryable, IEnumerable) | argument 1 -> return | false | -| System.Linq.Queryable.Count(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.DefaultIfEmpty(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.DefaultIfEmpty(IQueryable, TSource) | argument 0 -> return | false | -| System.Linq.Queryable.DefaultIfEmpty(IQueryable, TSource) | argument 1 -> return | false | -| System.Linq.Queryable.Distinct(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.Distinct(IQueryable, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.Queryable.ElementAt(IQueryable, int) | argument 0 -> return | false | -| System.Linq.Queryable.ElementAtOrDefault(IQueryable, int) | argument 0 -> return | false | -| System.Linq.Queryable.Except(IQueryable, IEnumerable) | argument 0 -> return | false | -| System.Linq.Queryable.Except(IQueryable, IEnumerable, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.Queryable.First(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.First(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.First(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.FirstOrDefault(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.FirstOrDefault(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.FirstOrDefault(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | output from argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | output from argument 2 -> parameter 1 of argument 3 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | output from argument 3 -> return | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | output from argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | output from argument 2 -> parameter 1 of argument 3 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | output from argument 3 -> return | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>) | output from argument 2 -> return | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>) | output from argument 2 -> return | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | output from argument 4 -> return | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | output from argument 4 -> return | false | -| System.Linq.Queryable.Intersect(IQueryable, IEnumerable) | argument 0 -> return | false | -| System.Linq.Queryable.Intersect(IQueryable, IEnumerable) | argument 1 -> return | false | -| System.Linq.Queryable.Intersect(IQueryable, IEnumerable, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.Queryable.Intersect(IQueryable, IEnumerable, IEqualityComparer) | argument 1 -> return | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | output from argument 4 -> return | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | output from argument 4 -> return | false | -| System.Linq.Queryable.Last(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.Last(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Last(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.LastOrDefault(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.LastOrDefault(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.LastOrDefault(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.LongCount(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Max(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Min(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.OfType(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.OrderBy(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.OrderBy(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.OrderBy(IQueryable, Expression>, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.OrderBy(IQueryable, Expression>, IComparer) | argument 0 -> return | false | -| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>, IComparer) | argument 0 -> return | false | -| System.Linq.Queryable.Reverse(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.Select(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Select(IQueryable, Expression>) | output from argument 1 -> return | false | -| System.Linq.Queryable.Select(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Select(IQueryable, Expression>) | output from argument 1 -> return | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | output from argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | output from argument 2 -> return | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | output from argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | output from argument 2 -> return | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | output from argument 1 -> return | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | output from argument 1 -> return | false | -| System.Linq.Queryable.Single(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.Single(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Single(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.SingleOrDefault(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.SingleOrDefault(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SingleOrDefault(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.Skip(IQueryable, int) | argument 0 -> return | false | -| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Take(IQueryable, int) | argument 0 -> return | false | -| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>, IComparer) | argument 0 -> return | false | -| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>, IComparer) | argument 0 -> return | false | -| System.Linq.Queryable.Union(IQueryable, IEnumerable) | argument 0 -> return | false | -| System.Linq.Queryable.Union(IQueryable, IEnumerable) | argument 1 -> return | false | -| System.Linq.Queryable.Union(IQueryable, IEnumerable, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.Queryable.Union(IQueryable, IEnumerable, IEqualityComparer) | argument 1 -> return | false | -| System.Linq.Queryable.Where(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Where(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.Where(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Where(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | output from argument 2 -> return | false | +| System.Lazy<>.get_Value() | qualifier -> return | false | +| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | output from argument 2 -> parameter 0 of argument 3 | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | output from argument 3 -> return | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func) | argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func) | output from argument 2 -> return | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, Func) | output from argument 1 -> return | true | +| System.Linq.Enumerable.DefaultIfEmpty(IEnumerable, TSource) | argument 1 -> return | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, IEqualityComparer) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | argument 0 -> parameter 1 of argument 2 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>, IEqualityComparer) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | output from argument 2 -> parameter 0 of argument 3 | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | output from argument 3 -> return | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func) | argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func) | output from argument 2 -> return | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, Func) | output from argument 1 -> return | true | +| System.Linq.ParallelEnumerable.DefaultIfEmpty(ParallelQuery, TSource) | argument 1 -> return | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, IEqualityComparer) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | argument 0 -> parameter 1 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>, IEqualityComparer) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | output from argument 2 -> parameter 0 of argument 3 | true | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | output from argument 3 -> return | true | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | output from argument 2 -> return | true | +| System.Linq.Queryable.Aggregate(IQueryable, Expression>) | output from argument 1 -> return | true | +| System.Linq.Queryable.DefaultIfEmpty(IQueryable, TSource) | argument 1 -> return | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, IEqualityComparer) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>, IEqualityComparer) | output from argument 1 -> parameter 0 of argument 2 | true | | System.Net.Cookie.get_Value() | qualifier -> return | false | -| System.Net.CookieCollection.Add(Cookie) | argument 0 -> qualifier | false | -| System.Net.CookieCollection.Add(CookieCollection) | argument 0 -> qualifier | false | -| System.Net.CookieCollection.GetEnumerator() | qualifier -> return | false | -| System.Net.CredentialCache.GetEnumerator() | qualifier -> return | false | -| System.Net.HttpListenerPrefixCollection.Add(string) | argument 0 -> qualifier | false | -| System.Net.HttpListenerPrefixCollection.GetEnumerator() | qualifier -> return | false | -| System.Net.NetworkInformation.IPAddressCollection.Add(IPAddress) | argument 0 -> qualifier | false | -| System.Net.NetworkInformation.IPAddressCollection.GetEnumerator() | qualifier -> return | false | | System.Net.Security.NegotiateStream.BeginRead(Byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false | | System.Net.Security.NegotiateStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false | | System.Net.Security.NegotiateStream.Read(Byte[], int, int) | qualifier -> argument 0 | false | @@ -1313,29 +494,15 @@ callableFlow | System.Net.WebUtility.HtmlEncode(string) | argument 0 -> return | false | | System.Net.WebUtility.HtmlEncode(string, TextWriter) | argument 0 -> return | false | | System.Net.WebUtility.UrlEncode(string) | argument 0 -> return | false | -| System.Object.ToString() | qualifier -> return | false | -| System.Resources.IResourceReader.GetEnumerator() | qualifier -> return | false | -| System.Resources.ResourceReader.GetEnumerator() | qualifier -> return | false | -| System.Resources.ResourceSet.GetEnumerator() | qualifier -> return | false | -| System.Runtime.CompilerServices.ConditionalWeakTable<,>.Add(TKey, TValue) | argument 1 -> qualifier | false | -| System.Runtime.CompilerServices.ConditionalWeakTable<,>.GetEnumerator() | qualifier -> return | false | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Add(T) | argument 0 -> qualifier | false | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Add(object) | argument 0 -> qualifier | false | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.GetEnumerator() | qualifier -> return | false | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Insert(int, T) | argument 1 -> qualifier | false | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Insert(int, object) | argument 1 -> qualifier | false | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Reverse() | qualifier -> return | false | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Reverse(int, int) | qualifier -> return | false | +| System.Nullable<>.GetValueOrDefault(T) | argument 0 -> return | true | +| System.Nullable<>.get_Value() | qualifier -> return | false | | System.Security.Cryptography.CryptoStream.BeginRead(Byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false | | System.Security.Cryptography.CryptoStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false | | System.Security.Cryptography.CryptoStream.Read(Byte[], int, int) | qualifier -> argument 0 | false | | System.Security.Cryptography.CryptoStream.ReadAsync(Byte[], int, int, CancellationToken) | qualifier -> argument 0 | false | | System.Security.Cryptography.CryptoStream.Write(Byte[], int, int) | argument 0 -> qualifier | false | | System.Security.Cryptography.CryptoStream.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> qualifier | false | -| System.Security.PermissionSet.GetEnumerator() | qualifier -> return | false | -| System.String.Clone() | qualifier -> return | false | | System.String.Clone() | qualifier -> return | true | -| System.String.Concat(IEnumerable) | argument 0 -> return | false | | System.String.Concat(ReadOnlySpan, ReadOnlySpan) | argument 0 -> return | false | | System.String.Concat(ReadOnlySpan, ReadOnlySpan) | argument 1 -> return | false | | System.String.Concat(ReadOnlySpan, ReadOnlySpan, ReadOnlySpan) | argument 0 -> return | false | @@ -1360,7 +527,6 @@ callableFlow | System.String.Concat(string, string, string, string) | argument 1 -> return | false | | System.String.Concat(string, string, string, string) | argument 2 -> return | false | | System.String.Concat(string, string, string, string) | argument 3 -> return | false | -| System.String.Concat(IEnumerable) | argument 0 -> return | false | | System.String.Copy(string) | argument 0 -> return | true | | System.String.Format(IFormatProvider, string, object) | argument 1 -> return | false | | System.String.Format(IFormatProvider, string, object) | argument 2 -> return | false | @@ -1371,6 +537,7 @@ callableFlow | System.String.Format(IFormatProvider, string, object, object, object) | argument 2 -> return | false | | System.String.Format(IFormatProvider, string, object, object, object) | argument 3 -> return | false | | System.String.Format(IFormatProvider, string, object, object, object) | argument 4 -> return | false | +| System.String.Format(IFormatProvider, string, params Object[]) | argument 1 -> return | false | | System.String.Format(string, object) | argument 0 -> return | false | | System.String.Format(string, object) | argument 1 -> return | false | | System.String.Format(string, object, object) | argument 0 -> return | false | @@ -1380,21 +547,18 @@ callableFlow | System.String.Format(string, object, object, object) | argument 1 -> return | false | | System.String.Format(string, object, object, object) | argument 2 -> return | false | | System.String.Format(string, object, object, object) | argument 3 -> return | false | -| System.String.GetEnumerator() | qualifier -> return | false | +| System.String.Format(string, params Object[]) | argument 0 -> return | false | | System.String.Insert(int, string) | argument 1 -> return | false | | System.String.Insert(int, string) | qualifier -> return | false | +| System.String.Join(char, String[], int, int) | argument 0 -> return | false | +| System.String.Join(char, params Object[]) | argument 0 -> return | false | +| System.String.Join(char, params String[]) | argument 0 -> return | false | | System.String.Join(string, IEnumerable) | argument 0 -> return | false | -| System.String.Join(string, IEnumerable) | argument 1 -> return | false | | System.String.Join(string, String[], int, int) | argument 0 -> return | false | -| System.String.Join(string, String[], int, int) | argument 1 -> return | false | -| System.String.Join(string, String[], int, int) | argument 2 -> return | false | -| System.String.Join(string, String[], int, int) | argument 3 -> return | false | +| System.String.Join(string, params Object[]) | argument 0 -> return | false | | System.String.Join(string, params String[]) | argument 0 -> return | false | -| System.String.Join(string, params String[]) | argument 1 -> return | false | -| System.String.Join(string, params String[]) | argument 2 -> return | false | -| System.String.Join(string, params String[]) | argument 3 -> return | false | +| System.String.Join(char, IEnumerable) | argument 0 -> return | false | | System.String.Join(string, IEnumerable) | argument 0 -> return | false | -| System.String.Join(string, IEnumerable) | argument 1 -> return | false | | System.String.Normalize() | qualifier -> return | false | | System.String.Normalize(NormalizationForm) | qualifier -> return | false | | System.String.PadLeft(int) | qualifier -> return | false | @@ -1407,24 +571,13 @@ callableFlow | System.String.Replace(char, char) | qualifier -> return | false | | System.String.Replace(string, string) | argument 1 -> return | false | | System.String.Replace(string, string) | qualifier -> return | false | -| System.String.Split(Char[], StringSplitOptions) | qualifier -> return | false | -| System.String.Split(Char[], int) | qualifier -> return | false | -| System.String.Split(Char[], int, StringSplitOptions) | qualifier -> return | false | -| System.String.Split(String[], StringSplitOptions) | qualifier -> return | false | -| System.String.Split(String[], int, StringSplitOptions) | qualifier -> return | false | -| System.String.Split(char, StringSplitOptions) | qualifier -> return | false | -| System.String.Split(char, int, StringSplitOptions) | qualifier -> return | false | -| System.String.Split(params Char[]) | qualifier -> return | false | -| System.String.Split(string, StringSplitOptions) | qualifier -> return | false | -| System.String.Split(string, int, StringSplitOptions) | qualifier -> return | false | -| System.String.String(Char[]) | argument 0 -> return | false | -| System.String.String(Char[], int, int) | argument 0 -> return | false | | System.String.Substring(int) | qualifier -> return | false | | System.String.Substring(int, int) | qualifier -> return | false | | System.String.ToLower() | qualifier -> return | false | | System.String.ToLower(CultureInfo) | qualifier -> return | false | | System.String.ToLowerInvariant() | qualifier -> return | false | | System.String.ToString() | qualifier -> return | true | +| System.String.ToString(IFormatProvider) | qualifier -> return | true | | System.String.ToUpper() | qualifier -> return | false | | System.String.ToUpper(CultureInfo) | qualifier -> return | false | | System.String.ToUpperInvariant() | qualifier -> return | false | @@ -1437,100 +590,25 @@ callableFlow | System.String.TrimStart() | qualifier -> return | false | | System.String.TrimStart(char) | qualifier -> return | false | | System.String.TrimStart(params Char[]) | qualifier -> return | false | -| System.Text.Encoding.GetBytes(Char[]) | argument 0 -> return | false | -| System.Text.Encoding.GetBytes(Char[], int, int) | argument 0 -> return | false | -| System.Text.Encoding.GetBytes(Char[], int, int, Byte[], int) | argument 0 -> return | false | | System.Text.Encoding.GetBytes(ReadOnlySpan, Span) | argument 0 -> return | false | | System.Text.Encoding.GetBytes(char*, int, byte*, int) | argument 0 -> return | false | | System.Text.Encoding.GetBytes(string) | argument 0 -> return | false | | System.Text.Encoding.GetBytes(string, int, int) | argument 0 -> return | false | | System.Text.Encoding.GetBytes(string, int, int, Byte[], int) | argument 0 -> return | false | -| System.Text.Encoding.GetChars(Byte[]) | argument 0 -> return | false | -| System.Text.Encoding.GetChars(Byte[], int, int) | argument 0 -> return | false | -| System.Text.Encoding.GetChars(Byte[], int, int, Char[], int) | argument 0 -> return | false | -| System.Text.Encoding.GetChars(ReadOnlySpan, Span) | argument 0 -> return | false | -| System.Text.Encoding.GetChars(byte*, int, char*, int) | argument 0 -> return | false | -| System.Text.Encoding.GetString(Byte[]) | argument 0 -> return | false | -| System.Text.Encoding.GetString(Byte[], int, int) | argument 0 -> return | false | -| System.Text.Encoding.GetString(ReadOnlySpan) | argument 0 -> return | false | -| System.Text.Encoding.GetString(byte*, int) | argument 0 -> return | false | -| System.Text.RegularExpressions.CaptureCollection.Add(Capture) | argument 0 -> qualifier | false | -| System.Text.RegularExpressions.CaptureCollection.Add(object) | argument 0 -> qualifier | false | -| System.Text.RegularExpressions.CaptureCollection.GetEnumerator() | qualifier -> return | false | -| System.Text.RegularExpressions.CaptureCollection.Insert(int, Capture) | argument 1 -> qualifier | false | -| System.Text.RegularExpressions.CaptureCollection.Insert(int, object) | argument 1 -> qualifier | false | -| System.Text.RegularExpressions.GroupCollection.Add(Group) | argument 0 -> qualifier | false | -| System.Text.RegularExpressions.GroupCollection.Add(object) | argument 0 -> qualifier | false | -| System.Text.RegularExpressions.GroupCollection.GetEnumerator() | qualifier -> return | false | -| System.Text.RegularExpressions.GroupCollection.Insert(int, Group) | argument 1 -> qualifier | false | -| System.Text.RegularExpressions.GroupCollection.Insert(int, object) | argument 1 -> qualifier | false | -| System.Text.RegularExpressions.GroupCollection.get_Values() | qualifier -> return | false | -| System.Text.RegularExpressions.MatchCollection.Add(Match) | argument 0 -> qualifier | false | -| System.Text.RegularExpressions.MatchCollection.Add(object) | argument 0 -> qualifier | false | -| System.Text.RegularExpressions.MatchCollection.GetEnumerator() | qualifier -> return | false | -| System.Text.RegularExpressions.MatchCollection.Insert(int, Match) | argument 1 -> qualifier | false | -| System.Text.RegularExpressions.MatchCollection.Insert(int, object) | argument 1 -> qualifier | false | -| System.Text.StringBuilder.Append(object) | argument 0 -> qualifier | false | -| System.Text.StringBuilder.Append(string) | argument 0 -> qualifier | false | -| System.Text.StringBuilder.Append(string, int, int) | argument 0 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | argument 1 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | argument 2 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 1 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 2 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 3 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 1 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 2 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 3 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 4 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(string, object) | argument 0 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(string, object) | argument 1 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 0 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 1 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 2 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 0 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 1 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 2 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 3 -> qualifier | false | -| System.Text.StringBuilder.AppendLine(string) | argument 0 -> qualifier | false | -| System.Text.StringBuilder.StringBuilder(string) | argument 0 -> return | false | -| System.Text.StringBuilder.StringBuilder(string, int) | argument 0 -> return | false | -| System.Text.StringBuilder.StringBuilder(string, int, int, int) | argument 0 -> return | false | -| System.Text.StringBuilder.ToString() | qualifier -> return | false | | System.Threading.Tasks.Task.ContinueWith(Action, object) | argument 1 -> parameter 1 of argument 0 | true | | System.Threading.Tasks.Task.ContinueWith(Action, object, CancellationToken) | argument 1 -> parameter 1 of argument 0 | true | | System.Threading.Tasks.Task.ContinueWith(Action, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | | System.Threading.Tasks.Task.ContinueWith(Action, object, TaskContinuationOptions) | argument 1 -> parameter 1 of argument 0 | true | | System.Threading.Tasks.Task.ContinueWith(Action, object, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | | System.Threading.Tasks.Task.ContinueWith(Func, object) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object) | output from argument 0 -> return | true | | System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken) | output from argument 0 -> return | true | | System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 0 -> return | true | | System.Threading.Tasks.Task.ContinueWith(Func, object, TaskContinuationOptions) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object, TaskContinuationOptions) | output from argument 0 -> return | true | | System.Threading.Tasks.Task.ContinueWith(Func, object, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object, TaskScheduler) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task.ContinueWith(Func) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task.ContinueWith(Func, CancellationToken) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task.ContinueWith(Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task.ContinueWith(Func, TaskContinuationOptions) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task.ContinueWith(Func, TaskScheduler) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task.FromResult(TResult) | argument 0 -> return | true | -| System.Threading.Tasks.Task.Run(Func) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task.Run(Func, CancellationToken) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task.Run(Func>) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task.Run(Func>, CancellationToken) | output from argument 0 -> return | true | | System.Threading.Tasks.Task.Task(Action, object) | argument 1 -> parameter 0 of argument 0 | true | | System.Threading.Tasks.Task.Task(Action, object, CancellationToken) | argument 1 -> parameter 0 of argument 0 | true | | System.Threading.Tasks.Task.Task(Action, object, CancellationToken, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | | System.Threading.Tasks.Task.Task(Action, object, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task.WhenAll(IEnumerable>) | argument 0 -> return | true | -| System.Threading.Tasks.Task.WhenAll(params Task[]) | argument 0 -> return | true | -| System.Threading.Tasks.Task.WhenAll(params Task[]) | argument 1 -> return | true | -| System.Threading.Tasks.Task.WhenAny(IEnumerable>) | argument 0 -> return | true | -| System.Threading.Tasks.Task.WhenAny(params Task[]) | argument 0 -> return | true | -| System.Threading.Tasks.Task.WhenAny(params Task[]) | argument 1 -> return | true | | System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object) | argument 1 -> parameter 1 of argument 0 | true | | System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object) | qualifier -> parameter 0 of argument 0 | true | | System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object, CancellationToken) | argument 1 -> parameter 1 of argument 0 | true | @@ -1547,127 +625,61 @@ callableFlow | System.Threading.Tasks.Task<>.ContinueWith(Action>, TaskContinuationOptions) | qualifier -> parameter 0 of argument 0 | true | | System.Threading.Tasks.Task<>.ContinueWith(Action>, TaskScheduler) | qualifier -> parameter 0 of argument 0 | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object) | output from argument 0 -> return | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object) | qualifier -> parameter 0 of argument 0 | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken) | output from argument 0 -> return | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken) | qualifier -> parameter 0 of argument 0 | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 0 -> return | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | qualifier -> parameter 0 of argument 0 | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskContinuationOptions) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskContinuationOptions) | output from argument 0 -> return | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskContinuationOptions) | qualifier -> parameter 0 of argument 0 | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskScheduler) | output from argument 0 -> return | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskScheduler) | qualifier -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>) | output from argument 0 -> return | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>) | qualifier -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken) | output from argument 0 -> return | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken) | qualifier -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 0 -> return | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | qualifier -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskContinuationOptions) | output from argument 0 -> return | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskContinuationOptions) | qualifier -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskScheduler) | output from argument 0 -> return | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskScheduler) | qualifier -> parameter 0 of argument 0 | true | | System.Threading.Tasks.Task<>.Task(Func, object) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.Task(Func, object) | output from argument 0 -> return | true | | System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken) | output from argument 0 -> return | true | | System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken, TaskCreationOptions) | output from argument 0 -> return | true | | System.Threading.Tasks.Task<>.Task(Func, object, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.Task(Func, object, TaskCreationOptions) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task<>.Task(Func) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task<>.Task(Func, CancellationToken) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task<>.Task(Func, CancellationToken, TaskCreationOptions) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task<>.Task(Func, TaskCreationOptions) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task<>.get_Result() | qualifier -> return | true | +| System.Threading.Tasks.Task<>.get_Result() | qualifier -> return | false | | System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Action) | argument 0 -> parameter 0 of argument 1 | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Action, CancellationToken) | argument 0 -> parameter 0 of argument 1 | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Action, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 0 -> parameter 0 of argument 1 | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Action, TaskContinuationOptions) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func) | output from argument 1 -> return | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken) | output from argument 1 -> return | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 1 -> return | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, CancellationToken) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, CancellationToken) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, TaskContinuationOptions) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, TaskContinuationOptions) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Action>) | argument 0 -> parameter 0 of argument 1 | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Action>, CancellationToken) | argument 0 -> parameter 0 of argument 1 | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Action>, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 0 -> parameter 0 of argument 1 | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Action>, TaskContinuationOptions) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func) | output from argument 1 -> return | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, CancellationToken) | output from argument 1 -> return | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 1 -> return | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TaskContinuationOptions) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory.StartNew(Action, object) | argument 1 -> parameter 0 of argument 0 | true | | System.Threading.Tasks.TaskFactory.StartNew(Action, object, CancellationToken) | argument 1 -> parameter 0 of argument 0 | true | | System.Threading.Tasks.TaskFactory.StartNew(Action, object, CancellationToken, TaskCreationOptions, TaskScheduler) | argument 1 -> parameter 0 of argument 0 | true | | System.Threading.Tasks.TaskFactory.StartNew(Action, object, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | | System.Threading.Tasks.TaskFactory.StartNew(Func, object) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, object) | output from argument 0 -> return | true | | System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken) | output from argument 0 -> return | true | | System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | output from argument 0 -> return | true | | System.Threading.Tasks.TaskFactory.StartNew(Func, object, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, object, TaskCreationOptions) | output from argument 0 -> return | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func) | output from argument 0 -> return | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, CancellationToken) | output from argument 0 -> return | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, CancellationToken, TaskCreationOptions, TaskScheduler) | output from argument 0 -> return | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, TaskCreationOptions) | output from argument 0 -> return | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func) | output from argument 1 -> return | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken) | output from argument 1 -> return | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 1 -> return | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | output from argument 1 -> return | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func) | output from argument 1 -> return | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, CancellationToken) | output from argument 1 -> return | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 1 -> return | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TaskContinuationOptions) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, CancellationToken) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, CancellationToken) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, TaskContinuationOptions) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, TaskContinuationOptions) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory<>.StartNew(Func, object) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object) | output from argument 0 -> return | true | | System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken) | output from argument 0 -> return | true | | System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | output from argument 0 -> return | true | | System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, TaskCreationOptions) | output from argument 0 -> return | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func) | output from argument 0 -> return | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, CancellationToken) | output from argument 0 -> return | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, CancellationToken, TaskCreationOptions, TaskScheduler) | output from argument 0 -> return | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, TaskCreationOptions) | output from argument 0 -> return | true | | System.Uri.ToString() | qualifier -> return | false | | System.Uri.Uri(string) | argument 0 -> return | false | | System.Uri.Uri(string, UriKind) | argument 0 -> return | false | @@ -1684,6 +696,1383 @@ callableFlow | System.Web.HttpUtility.UrlEncode(string) | argument 0 -> return | false | | System.Web.UI.WebControls.TextBox.get_Text() | qualifier -> return | false | callableFlowAccessPath -| System.Lazy<>.Lazy(Func) | output from argument 0 [] -> return [Value] | -| System.Lazy<>.Lazy(Func, LazyThreadSafetyMode) | output from argument 0 [] -> return [Value] | -| System.Lazy<>.Lazy(Func, bool) | output from argument 0 [] -> return [Value] | +| System.Array.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.Array.AsReadOnly(T[]) | argument 0 [[]] -> return [[]] | true | +| System.Array.Clone() | argument 0 [[]] -> return [[]] | true | +| System.Array.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Array.CopyTo(Array, long) | qualifier [[]] -> argument 0 [[]] | true | +| System.Array.Find(T[], Predicate) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Array.Find(T[], Predicate) | argument 0 [[]] -> return [] | true | +| System.Array.FindAll(T[], Predicate) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Array.FindAll(T[], Predicate) | argument 0 [[]] -> return [] | true | +| System.Array.FindLast(T[], Predicate) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Array.FindLast(T[], Predicate) | argument 0 [[]] -> return [] | true | +| System.Array.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Array.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Array.Reverse(Array) | argument 0 [[]] -> return [[]] | true | +| System.Array.Reverse(Array, int, int) | argument 0 [[]] -> return [[]] | true | +| System.Array.Reverse(T[]) | argument 0 [[]] -> return [[]] | true | +| System.Array.Reverse(T[], int, int) | argument 0 [[]] -> return [[]] | true | +| System.Collections.ArrayList.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.ArrayList.AddRange(ICollection) | argument 0 [[]] -> qualifier [[]] | true | +| System.Collections.ArrayList.Clone() | argument 0 [[]] -> return [[]] | true | +| System.Collections.ArrayList.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ArrayList.FixedSize(ArrayList) | argument 0 [[]] -> return [[]] | true | +| System.Collections.ArrayList.FixedSize(IList) | argument 0 [[]] -> return [[]] | true | +| System.Collections.ArrayList.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.ArrayList.GetEnumerator(int, int) | qualifier [[]] -> return [Current] | true | +| System.Collections.ArrayList.GetRange(int, int) | argument 0 [[]] -> return [[]] | true | +| System.Collections.ArrayList.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.ArrayList.InsertRange(int, ICollection) | argument 1 [[]] -> qualifier [[]] | true | +| System.Collections.ArrayList.Repeat(object, int) | argument 0 [] -> return [[]] | true | +| System.Collections.ArrayList.Reverse() | argument 0 [[]] -> return [[]] | true | +| System.Collections.ArrayList.Reverse(int, int) | argument 0 [[]] -> return [[]] | true | +| System.Collections.ArrayList.get_Item(int) | qualifier [[]] -> return [] | true | +| System.Collections.ArrayList.set_Item(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.BitArray.Clone() | argument 0 [[]] -> return [[]] | true | +| System.Collections.BitArray.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.BitArray.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.CollectionBase.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.CollectionBase.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.CollectionBase.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.CollectionBase.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.Concurrent.BlockingCollection<>.Add(T) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Concurrent.BlockingCollection<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.BlockingCollection<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.BlockingCollection<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Concurrent.ConcurrentBag<>.Add(T) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Concurrent.ConcurrentBag<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.ConcurrentBag<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.ConcurrentBag<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(KeyValuePair) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(KeyValuePair) | argument 0 [Key] -> qualifier [[], Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(KeyValuePair) | argument 0 [Value] -> qualifier [[], Value] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(TKey, TValue) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(TKey, TValue) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable>) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable>) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable>, IEqualityComparer) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable>, IEqualityComparer) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(int, IEnumerable>, IEqualityComparer) | argument 1 [[], Key] -> return [[], Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(int, IEnumerable>, IEqualityComparer) | argument 1 [[], Value] -> return [[], Value] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.CopyTo(KeyValuePair[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Item(TKey) | qualifier [[], Value] -> return [] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.set_Item(TKey, TValue) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.set_Item(TKey, TValue) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Concurrent.ConcurrentQueue<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.ConcurrentQueue<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.ConcurrentQueue<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Concurrent.ConcurrentStack<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.ConcurrentStack<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.ConcurrentStack<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Concurrent.IProducerConsumerCollection<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.DictionaryBase.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.DictionaryBase.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.DictionaryBase.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.DictionaryBase.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.Dictionary<,>.Add(KeyValuePair) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.Dictionary<,>.Add(KeyValuePair) | argument 0 [Key] -> qualifier [[], Key] | true | +| System.Collections.Generic.Dictionary<,>.Add(KeyValuePair) | argument 0 [Value] -> qualifier [[], Value] | true | +| System.Collections.Generic.Dictionary<,>.Add(TKey, TValue) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Generic.Dictionary<,>.Add(TKey, TValue) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Generic.Dictionary<,>.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Generic.Dictionary<,>.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Generic.Dictionary<,>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Dictionary<,>.CopyTo(KeyValuePair[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary, IEqualityComparer) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary, IEqualityComparer) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable>) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable>) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable>, IEqualityComparer) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable>, IEqualityComparer) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Generic.Dictionary<,>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.Dictionary<,>.KeyCollection.Add(TKey) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.Dictionary<,>.KeyCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Dictionary<,>.KeyCollection.CopyTo(TKey[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Dictionary<,>.KeyCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.Dictionary<,>.ValueCollection.Add(TValue) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.Dictionary<,>.ValueCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Dictionary<,>.ValueCollection.CopyTo(TValue[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Dictionary<,>.ValueCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.Dictionary<,>.get_Item(TKey) | qualifier [[], Value] -> return [] | true | +| System.Collections.Generic.Dictionary<,>.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.Generic.Dictionary<,>.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Generic.Dictionary<,>.set_Item(TKey, TValue) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Generic.Dictionary<,>.set_Item(TKey, TValue) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Generic.HashSet<>.Add(T) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.HashSet<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.HashSet<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.ICollection<>.Add(T) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.ICollection<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.IDictionary<,>.Add(TKey, TValue) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Generic.IDictionary<,>.Add(TKey, TValue) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Generic.IDictionary<,>.get_Item(TKey) | qualifier [[], Value] -> return [] | true | +| System.Collections.Generic.IDictionary<,>.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.Generic.IDictionary<,>.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Generic.IDictionary<,>.set_Item(TKey, TValue) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Generic.IDictionary<,>.set_Item(TKey, TValue) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Generic.IList<>.Insert(int, T) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.Generic.IList<>.get_Item(int) | qualifier [[]] -> return [] | true | +| System.Collections.Generic.IList<>.set_Item(int, T) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.Generic.ISet<>.Add(T) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.KeyValuePair<,>.KeyValuePair() | argument 0 [] -> return [Key] | true | +| System.Collections.Generic.KeyValuePair<,>.KeyValuePair() | argument 1 [] -> return [Value] | true | +| System.Collections.Generic.KeyValuePair<,>.KeyValuePair(TKey, TValue) | argument 0 [] -> return [Key] | true | +| System.Collections.Generic.KeyValuePair<,>.KeyValuePair(TKey, TValue) | argument 1 [] -> return [Value] | true | +| System.Collections.Generic.LinkedList<>.Add(T) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.LinkedList<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.LinkedList<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.LinkedList<>.Find(T) | qualifier [[]] -> return [] | true | +| System.Collections.Generic.LinkedList<>.FindLast(T) | qualifier [[]] -> return [] | true | +| System.Collections.Generic.LinkedList<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.List<>.Add(T) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.List<>.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.List<>.AddRange(IEnumerable) | argument 0 [[]] -> qualifier [[]] | true | +| System.Collections.Generic.List<>.AsReadOnly() | argument 0 [[]] -> return [[]] | true | +| System.Collections.Generic.List<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.List<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.List<>.Find(Predicate) | qualifier [[]] -> parameter 0 of argument 0 [] | true | +| System.Collections.Generic.List<>.Find(Predicate) | qualifier [[]] -> return [] | true | +| System.Collections.Generic.List<>.FindAll(Predicate) | qualifier [[]] -> parameter 0 of argument 0 [] | true | +| System.Collections.Generic.List<>.FindAll(Predicate) | qualifier [[]] -> return [] | true | +| System.Collections.Generic.List<>.FindLast(Predicate) | qualifier [[]] -> parameter 0 of argument 0 [] | true | +| System.Collections.Generic.List<>.FindLast(Predicate) | qualifier [[]] -> return [] | true | +| System.Collections.Generic.List<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.List<>.GetRange(int, int) | argument 0 [[]] -> return [[]] | true | +| System.Collections.Generic.List<>.Insert(int, T) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.Generic.List<>.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.Generic.List<>.InsertRange(int, IEnumerable) | argument 1 [[]] -> qualifier [[]] | true | +| System.Collections.Generic.List<>.Reverse() | argument 0 [[]] -> return [[]] | true | +| System.Collections.Generic.List<>.Reverse(int, int) | argument 0 [[]] -> return [[]] | true | +| System.Collections.Generic.List<>.get_Item(int) | qualifier [[]] -> return [] | true | +| System.Collections.Generic.List<>.set_Item(int, T) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.Generic.Queue<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Queue<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Queue<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.Queue<>.Peek() | qualifier [[]] -> return [] | true | +| System.Collections.Generic.SortedDictionary<,>.Add(KeyValuePair) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.Add(KeyValuePair) | argument 0 [Key] -> qualifier [[], Key] | true | +| System.Collections.Generic.SortedDictionary<,>.Add(KeyValuePair) | argument 0 [Value] -> qualifier [[], Value] | true | +| System.Collections.Generic.SortedDictionary<,>.Add(TKey, TValue) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Generic.SortedDictionary<,>.Add(TKey, TValue) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Generic.SortedDictionary<,>.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Generic.SortedDictionary<,>.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Generic.SortedDictionary<,>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.CopyTo(KeyValuePair[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.SortedDictionary<,>.KeyCollection.Add(TKey) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.KeyCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.KeyCollection.CopyTo(TKey[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.KeyCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary, IComparer) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary, IComparer) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Generic.SortedDictionary<,>.ValueCollection.Add(TValue) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.ValueCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.ValueCollection.CopyTo(TValue[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.ValueCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.SortedDictionary<,>.get_Item(TKey) | qualifier [[], Value] -> return [] | true | +| System.Collections.Generic.SortedDictionary<,>.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.set_Item(TKey, TValue) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Generic.SortedDictionary<,>.set_Item(TKey, TValue) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Generic.SortedList<,>.Add(KeyValuePair) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.SortedList<,>.Add(KeyValuePair) | argument 0 [Key] -> qualifier [[], Key] | true | +| System.Collections.Generic.SortedList<,>.Add(KeyValuePair) | argument 0 [Value] -> qualifier [[], Value] | true | +| System.Collections.Generic.SortedList<,>.Add(TKey, TValue) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Generic.SortedList<,>.Add(TKey, TValue) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Generic.SortedList<,>.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Generic.SortedList<,>.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Generic.SortedList<,>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedList<,>.CopyTo(KeyValuePair[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedList<,>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.SortedList<,>.KeyList.Add(TKey) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.SortedList<,>.KeyList.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedList<,>.KeyList.CopyTo(TKey[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedList<,>.KeyList.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.SortedList<,>.KeyList.Insert(int, TKey) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.Generic.SortedList<,>.KeyList.get_Item(int) | qualifier [[]] -> return [] | true | +| System.Collections.Generic.SortedList<,>.KeyList.set_Item(int, TKey) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.Generic.SortedList<,>.SortedList(IDictionary) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Generic.SortedList<,>.SortedList(IDictionary) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Generic.SortedList<,>.SortedList(IDictionary, IComparer) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Generic.SortedList<,>.SortedList(IDictionary, IComparer) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Generic.SortedList<,>.ValueList.Add(TValue) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.SortedList<,>.ValueList.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedList<,>.ValueList.CopyTo(TValue[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedList<,>.ValueList.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.SortedList<,>.ValueList.Insert(int, TValue) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.Generic.SortedList<,>.ValueList.get_Item(int) | qualifier [[]] -> return [] | true | +| System.Collections.Generic.SortedList<,>.ValueList.set_Item(int, TValue) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.Generic.SortedList<,>.get_Item(TKey) | qualifier [[], Value] -> return [] | true | +| System.Collections.Generic.SortedList<,>.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.Generic.SortedList<,>.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Generic.SortedList<,>.set_Item(TKey, TValue) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Generic.SortedList<,>.set_Item(TKey, TValue) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Generic.SortedSet<>.Add(T) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Generic.SortedSet<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedSet<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedSet<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.SortedSet<>.Reverse() | argument 0 [[]] -> return [[]] | true | +| System.Collections.Generic.Stack<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Stack<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Stack<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.Stack<>.Peek() | qualifier [[]] -> return [] | true | +| System.Collections.Generic.Stack<>.Pop() | qualifier [[]] -> return [] | true | +| System.Collections.Hashtable.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Hashtable.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Hashtable.Clone() | argument 0 [[]] -> return [[]] | true | +| System.Collections.Hashtable.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Hashtable.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Hashtable.Hashtable(IDictionary) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Hashtable.Hashtable(IDictionary) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, IEqualityComparer) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, IEqualityComparer) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, IHashCodeProvider, IComparer) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, IHashCodeProvider, IComparer) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float, IEqualityComparer) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float, IEqualityComparer) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float, IHashCodeProvider, IComparer) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float, IHashCodeProvider, IComparer) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Hashtable.get_Item(object) | qualifier [[], Value] -> return [] | true | +| System.Collections.Hashtable.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.Hashtable.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Hashtable.set_Item(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Hashtable.set_Item(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.ICollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.IDictionary.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.IDictionary.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.IDictionary.get_Item(object) | qualifier [[], Value] -> return [] | true | +| System.Collections.IDictionary.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.IDictionary.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.IDictionary.set_Item(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.IDictionary.set_Item(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.IEnumerable.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.IList.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.IList.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.IList.get_Item(int) | qualifier [[]] -> return [] | true | +| System.Collections.IList.set_Item(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.ListDictionaryInternal.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.ListDictionaryInternal.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.ListDictionaryInternal.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ListDictionaryInternal.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.ListDictionaryInternal.get_Item(object) | qualifier [[], Value] -> return [] | true | +| System.Collections.ListDictionaryInternal.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.ListDictionaryInternal.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.ListDictionaryInternal.set_Item(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.ListDictionaryInternal.set_Item(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.ObjectModel.Collection<>.Add(T) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.ObjectModel.Collection<>.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.ObjectModel.Collection<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.Collection<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.Collection<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.ObjectModel.Collection<>.Insert(int, T) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.ObjectModel.Collection<>.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.ObjectModel.Collection<>.get_Item(int) | qualifier [[]] -> return [] | true | +| System.Collections.ObjectModel.Collection<>.set_Item(int, T) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.ObjectModel.KeyedCollection<,>.get_Item(TKey) | qualifier [[]] -> return [] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.Add(T) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.Insert(int, T) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.get_Item(int) | qualifier [[]] -> return [] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(KeyValuePair) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(KeyValuePair) | argument 0 [Key] -> qualifier [[], Key] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(KeyValuePair) | argument 0 [Value] -> qualifier [[], Value] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(TKey, TValue) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(TKey, TValue) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.CopyTo(KeyValuePair[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.Add(TKey) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.CopyTo(TKey[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ReadOnlyDictionary(IDictionary) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ReadOnlyDictionary(IDictionary) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.Add(TValue) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.CopyTo(TValue[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Item(TKey) | qualifier [[], Value] -> return [] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Queue.Clone() | argument 0 [[]] -> return [[]] | true | +| System.Collections.Queue.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Queue.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Queue.Peek() | qualifier [[]] -> return [] | true | +| System.Collections.ReadOnlyCollectionBase.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ReadOnlyCollectionBase.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.SortedList.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.SortedList.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.SortedList.Clone() | argument 0 [[]] -> return [[]] | true | +| System.Collections.SortedList.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.SortedList.GetByIndex(int) | qualifier [[], Value] -> return [] | true | +| System.Collections.SortedList.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.SortedList.GetValueList() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.SortedList.SortedList(IDictionary) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.SortedList.SortedList(IDictionary) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.SortedList.SortedList(IDictionary, IComparer) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.SortedList.SortedList(IDictionary, IComparer) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.SortedList.get_Item(object) | qualifier [[], Value] -> return [] | true | +| System.Collections.SortedList.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.SortedList.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.SortedList.set_Item(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.SortedList.set_Item(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Specialized.HybridDictionary.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Specialized.HybridDictionary.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Specialized.HybridDictionary.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Specialized.HybridDictionary.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Specialized.HybridDictionary.get_Item(object) | qualifier [[], Value] -> return [] | true | +| System.Collections.Specialized.HybridDictionary.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.Specialized.HybridDictionary.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Specialized.HybridDictionary.set_Item(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Specialized.HybridDictionary.set_Item(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Specialized.IOrderedDictionary.get_Item(int) | qualifier [[], Value] -> return [] | true | +| System.Collections.Specialized.IOrderedDictionary.set_Item(int, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Specialized.IOrderedDictionary.set_Item(int, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Specialized.ListDictionary.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Specialized.ListDictionary.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Specialized.ListDictionary.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Specialized.ListDictionary.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Specialized.ListDictionary.get_Item(object) | qualifier [[], Value] -> return [] | true | +| System.Collections.Specialized.ListDictionary.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.Specialized.ListDictionary.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Specialized.ListDictionary.set_Item(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Specialized.ListDictionary.set_Item(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Specialized.NameObjectCollectionBase.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Specialized.NameObjectCollectionBase.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Specialized.NameObjectCollectionBase.KeysCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Specialized.NameObjectCollectionBase.KeysCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Specialized.NameValueCollection.Add(NameValueCollection) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Specialized.NameValueCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Specialized.OrderedDictionary.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Specialized.OrderedDictionary.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Specialized.OrderedDictionary.AsReadOnly() | argument 0 [[]] -> return [[]] | true | +| System.Collections.Specialized.OrderedDictionary.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Specialized.OrderedDictionary.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Specialized.OrderedDictionary.get_Item(int) | qualifier [[], Value] -> return [] | true | +| System.Collections.Specialized.OrderedDictionary.get_Item(object) | qualifier [[], Value] -> return [] | true | +| System.Collections.Specialized.OrderedDictionary.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.Specialized.OrderedDictionary.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Specialized.OrderedDictionary.set_Item(int, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Specialized.OrderedDictionary.set_Item(int, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Specialized.OrderedDictionary.set_Item(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Collections.Specialized.OrderedDictionary.set_Item(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Collections.Specialized.StringCollection.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Specialized.StringCollection.Add(string) | argument 0 [] -> qualifier [[]] | true | +| System.Collections.Specialized.StringCollection.AddRange(String[]) | argument 0 [[]] -> qualifier [[]] | true | +| System.Collections.Specialized.StringCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Specialized.StringCollection.CopyTo(String[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Specialized.StringCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Specialized.StringCollection.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.Specialized.StringCollection.Insert(int, string) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.Specialized.StringCollection.get_Item(int) | qualifier [[]] -> return [] | true | +| System.Collections.Specialized.StringCollection.set_Item(int, string) | argument 1 [] -> qualifier [[]] | true | +| System.Collections.Specialized.StringDictionary.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Stack.Clone() | argument 0 [[]] -> return [[]] | true | +| System.Collections.Stack.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Stack.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Stack.Peek() | qualifier [[]] -> return [] | true | +| System.Collections.Stack.Pop() | qualifier [[]] -> return [] | true | +| System.ComponentModel.AttributeCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.ComponentModel.AttributeCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.ComponentModel.BindingList<>.Find(PropertyDescriptor, object) | qualifier [[]] -> return [] | true | +| System.ComponentModel.Design.DesignerCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.ComponentModel.Design.DesignerCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.get_Item(int) | qualifier [[]] -> return [] | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.get_Item(string) | qualifier [[]] -> return [] | true | +| System.ComponentModel.Design.DesignerVerbCollection.Add(DesignerVerb) | argument 0 [] -> qualifier [[]] | true | +| System.ComponentModel.Design.DesignerVerbCollection.AddRange(DesignerVerbCollection) | argument 0 [[]] -> qualifier [[]] | true | +| System.ComponentModel.Design.DesignerVerbCollection.AddRange(DesignerVerb[]) | argument 0 [[]] -> qualifier [[]] | true | +| System.ComponentModel.Design.DesignerVerbCollection.CopyTo(DesignerVerb[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.ComponentModel.Design.DesignerVerbCollection.Insert(int, DesignerVerb) | argument 1 [] -> qualifier [[]] | true | +| System.ComponentModel.Design.DesignerVerbCollection.get_Item(int) | qualifier [[]] -> return [] | true | +| System.ComponentModel.Design.DesignerVerbCollection.set_Item(int, DesignerVerb) | argument 1 [] -> qualifier [[]] | true | +| System.ComponentModel.EventDescriptorCollection.Add(EventDescriptor) | argument 0 [] -> qualifier [[]] | true | +| System.ComponentModel.EventDescriptorCollection.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.ComponentModel.EventDescriptorCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.ComponentModel.EventDescriptorCollection.Find(string, bool) | qualifier [[]] -> return [] | true | +| System.ComponentModel.EventDescriptorCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.ComponentModel.EventDescriptorCollection.Insert(int, EventDescriptor) | argument 1 [] -> qualifier [[]] | true | +| System.ComponentModel.EventDescriptorCollection.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.ComponentModel.EventDescriptorCollection.get_Item(int) | qualifier [[]] -> return [] | true | +| System.ComponentModel.EventDescriptorCollection.get_Item(string) | qualifier [[]] -> return [] | true | +| System.ComponentModel.IBindingList.Find(PropertyDescriptor, object) | qualifier [[]] -> return [] | true | +| System.ComponentModel.ListSortDescriptionCollection.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.ComponentModel.ListSortDescriptionCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.ComponentModel.ListSortDescriptionCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.ComponentModel.ListSortDescriptionCollection.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.ComponentModel.ListSortDescriptionCollection.get_Item(int) | qualifier [[]] -> return [] | true | +| System.ComponentModel.ListSortDescriptionCollection.set_Item(int, ListSortDescription) | argument 1 [] -> qualifier [[]] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(PropertyDescriptor) | argument 0 [] -> qualifier [[]] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(PropertyDescriptor) | argument 0 [Key] -> qualifier [[], Key] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(PropertyDescriptor) | argument 0 [Value] -> qualifier [[], Value] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(object) | argument 0 [Key] -> qualifier [[], Key] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(object) | argument 0 [Value] -> qualifier [[], Value] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(object, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(object, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.ComponentModel.PropertyDescriptorCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.ComponentModel.PropertyDescriptorCollection.Find(string, bool) | qualifier [[]] -> return [] | true | +| System.ComponentModel.PropertyDescriptorCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.ComponentModel.PropertyDescriptorCollection.Insert(int, PropertyDescriptor) | argument 1 [] -> qualifier [[]] | true | +| System.ComponentModel.PropertyDescriptorCollection.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[]) | argument 0 [[], Key] -> return [[], Key] | true | +| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[]) | argument 0 [[], Value] -> return [[], Value] | true | +| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[], bool) | argument 0 [[], Key] -> return [[], Key] | true | +| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[], bool) | argument 0 [[], Value] -> return [[], Value] | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Item(int) | qualifier [[], Value] -> return [] | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Item(int) | qualifier [[]] -> return [] | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Item(string) | qualifier [[], Value] -> return [] | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Item(string) | qualifier [[]] -> return [] | true | +| System.ComponentModel.TypeConverter.StandardValuesCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.ComponentModel.TypeConverter.StandardValuesCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Dynamic.ExpandoObject.Add(KeyValuePair) | argument 0 [] -> qualifier [[]] | true | +| System.Dynamic.ExpandoObject.Add(KeyValuePair) | argument 0 [Key] -> qualifier [[], Key] | true | +| System.Dynamic.ExpandoObject.Add(KeyValuePair) | argument 0 [Value] -> qualifier [[], Value] | true | +| System.Dynamic.ExpandoObject.Add(string, object) | argument 0 [] -> qualifier [[], Key] | true | +| System.Dynamic.ExpandoObject.Add(string, object) | argument 1 [] -> qualifier [[], Value] | true | +| System.Dynamic.ExpandoObject.CopyTo(KeyValuePair[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Dynamic.ExpandoObject.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.IO.Path.Combine(params String[]) | argument 0 [[]] -> return [] | false | +| System.Lazy<>.Lazy(Func) | output from argument 0 [] -> return [Value] | true | +| System.Lazy<>.Lazy(Func, LazyThreadSafetyMode) | output from argument 0 [] -> return [Value] | true | +| System.Lazy<>.Lazy(Func, bool) | output from argument 0 [] -> return [Value] | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | argument 0 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func) | argument 0 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, Func) | argument 0 [[]] -> parameter 1 of argument 1 [] | true | +| System.Linq.Enumerable.All(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Any(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.AsEnumerable(IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Average(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Average(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Average(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Average(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Average(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Cast(IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Concat(IEnumerable, IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Concat(IEnumerable, IEnumerable) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Count(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.DefaultIfEmpty(IEnumerable) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.DefaultIfEmpty(IEnumerable, TSource) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.Distinct(IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Distinct(IEnumerable, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ElementAt(IEnumerable, int) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.ElementAtOrDefault(IEnumerable, int) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.Except(IEnumerable, IEnumerable) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.Except(IEnumerable, IEnumerable, IEqualityComparer) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.First(IEnumerable) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.First(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.First(IEnumerable, Func) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.FirstOrDefault(IEnumerable) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.FirstOrDefault(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.FirstOrDefault(IEnumerable, Func) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | output from argument 2 [] -> parameter 1 of argument 3 [[]] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | output from argument 3 [] -> return [[]] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 2 [] -> parameter 1 of argument 3 [[]] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 3 [] -> return [[]] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func) | output from argument 2 [] -> return [[]] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | output from argument 2 [] -> return [[]] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | output from argument 4 [] -> return [[]] | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 4 [] -> return [[]] | true | +| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable, IEqualityComparer) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | output from argument 4 [] -> return [[]] | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | output from argument 4 [] -> return [[]] | true | +| System.Linq.Enumerable.Last(IEnumerable) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.Last(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Last(IEnumerable, Func) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.LastOrDefault(IEnumerable) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.LastOrDefault(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.LastOrDefault(IEnumerable, Func) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.LongCount(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Max(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Max(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Max(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Max(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Max(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Min(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Min(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Min(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Min(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Min(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.OfType(IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.OrderBy(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.OrderBy(IEnumerable, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.OrderBy(IEnumerable, Func, IComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.OrderBy(IEnumerable, Func, IComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func, IComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func, IComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Reverse(IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Select(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Select(IEnumerable, Func) | output from argument 1 [] -> return [[]] | true | +| System.Linq.Enumerable.Select(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Select(IEnumerable, Func) | output from argument 1 [] -> return [[]] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | output from argument 1 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | output from argument 2 [] -> return [[]] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | output from argument 1 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | output from argument 2 [] -> return [[]] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | output from argument 1 [] -> return [[]] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | output from argument 1 [] -> return [[]] | true | +| System.Linq.Enumerable.Single(IEnumerable) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.Single(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Single(IEnumerable, Func) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.SingleOrDefault(IEnumerable) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.SingleOrDefault(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.SingleOrDefault(IEnumerable, Func) | argument 0 [[]] -> return [] | true | +| System.Linq.Enumerable.Skip(IEnumerable, int) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Take(IEnumerable, int) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func, IComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func, IComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func, IComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func, IComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ToArray(IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func) | output from argument 2 [] -> return [[]] | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func, IEqualityComparer) | output from argument 2 [] -> return [[]] | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ToList(IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func) | output from argument 2 [] -> return [[]] | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func, IEqualityComparer) | output from argument 2 [] -> return [[]] | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Union(IEnumerable, IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Union(IEnumerable, IEnumerable) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Union(IEnumerable, IEnumerable, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Union(IEnumerable, IEnumerable, IEqualityComparer) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Where(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Where(IEnumerable, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Where(IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Enumerable.Where(IEnumerable, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Zip(IEnumerable, IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Enumerable.Zip(IEnumerable, IEnumerable, Func) | argument 1 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.Enumerable.Zip(IEnumerable, IEnumerable, Func) | output from argument 2 [] -> return [[]] | true | +| System.Linq.EnumerableQuery<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Linq.Grouping<,>.Add(TElement) | argument 0 [] -> qualifier [[]] | true | +| System.Linq.Grouping<,>.CopyTo(TElement[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Linq.Grouping<,>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Linq.Grouping<,>.Insert(int, TElement) | argument 1 [] -> qualifier [[]] | true | +| System.Linq.Lookup<,>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | argument 0 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func) | argument 0 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, Func) | argument 0 [[]] -> parameter 1 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.All(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Any(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.AsEnumerable(ParallelQuery) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Cast(ParallelQuery) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Concat(ParallelQuery, IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Concat(ParallelQuery, IEnumerable) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Concat(ParallelQuery, ParallelQuery) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Concat(ParallelQuery, ParallelQuery) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Count(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.DefaultIfEmpty(ParallelQuery) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.DefaultIfEmpty(ParallelQuery, TSource) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.Distinct(ParallelQuery) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Distinct(ParallelQuery, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ElementAt(ParallelQuery, int) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.ElementAtOrDefault(ParallelQuery, int) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.Except(ParallelQuery, IEnumerable) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.Except(ParallelQuery, IEnumerable, IEqualityComparer) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.Except(ParallelQuery, ParallelQuery) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.Except(ParallelQuery, ParallelQuery, IEqualityComparer) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.First(ParallelQuery) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.First(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.First(ParallelQuery, Func) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery, Func) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | output from argument 2 [] -> parameter 1 of argument 3 [[]] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | output from argument 3 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 2 [] -> parameter 1 of argument 3 [[]] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 3 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func) | output from argument 2 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | output from argument 2 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | output from argument 4 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 4 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | output from argument 4 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | output from argument 4 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable, IEqualityComparer) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery, IEqualityComparer) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | output from argument 4 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | output from argument 4 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | output from argument 4 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | output from argument 4 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Last(ParallelQuery) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.Last(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Last(ParallelQuery, Func) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery, Func) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.LongCount(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.OfType(ParallelQuery) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func, IComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func, IComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func, IComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func, IComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Reverse(ParallelQuery) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | output from argument 1 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | output from argument 1 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | output from argument 1 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | output from argument 2 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | output from argument 1 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | output from argument 2 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | output from argument 1 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | output from argument 1 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Single(ParallelQuery) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.Single(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Single(ParallelQuery, Func) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery, Func) | argument 0 [[]] -> return [] | true | +| System.Linq.ParallelEnumerable.Skip(ParallelQuery, int) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Take(ParallelQuery, int) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func, IComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func, IComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func, IComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func, IComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToArray(ParallelQuery) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func) | output from argument 2 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func, IEqualityComparer) | output from argument 2 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToList(ParallelQuery) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func) | output from argument 2 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func, IEqualityComparer) | output from argument 2 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable, IEqualityComparer) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery, IEqualityComparer) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Zip(ParallelQuery, IEnumerable, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.Zip(ParallelQuery, IEnumerable, Func) | argument 1 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.Zip(ParallelQuery, IEnumerable, Func) | output from argument 2 [] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Zip(ParallelQuery, ParallelQuery, Func) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.Zip(ParallelQuery, ParallelQuery, Func) | argument 1 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.ParallelEnumerable.Zip(ParallelQuery, ParallelQuery, Func) | output from argument 2 [] -> return [[]] | true | +| System.Linq.ParallelQuery.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | argument 0 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | argument 0 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.Queryable.Aggregate(IQueryable, Expression>) | argument 0 [[]] -> parameter 1 of argument 1 [] | true | +| System.Linq.Queryable.All(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Any(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.AsQueryable(IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.AsQueryable(IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Average(IQueryable, Expression>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Average(IQueryable, Expression>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Average(IQueryable, Expression>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Average(IQueryable, Expression>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Average(IQueryable, Expression>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Cast(IQueryable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Concat(IQueryable, IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Concat(IQueryable, IEnumerable) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Queryable.Count(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.DefaultIfEmpty(IQueryable) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.DefaultIfEmpty(IQueryable, TSource) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.Distinct(IQueryable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Distinct(IQueryable, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.ElementAt(IQueryable, int) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.ElementAtOrDefault(IQueryable, int) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.Except(IQueryable, IEnumerable) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.Except(IQueryable, IEnumerable, IEqualityComparer) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.First(IQueryable) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.First(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.First(IQueryable, Expression>) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.FirstOrDefault(IQueryable) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.FirstOrDefault(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.FirstOrDefault(IQueryable, Expression>) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | output from argument 2 [] -> parameter 1 of argument 3 [[]] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | output from argument 3 [] -> return [[]] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | output from argument 2 [] -> parameter 1 of argument 3 [[]] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | output from argument 3 [] -> return [[]] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>) | output from argument 2 [] -> return [[]] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>) | output from argument 2 [] -> return [[]] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | output from argument 4 [] -> return [[]] | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | output from argument 4 [] -> return [[]] | true | +| System.Linq.Queryable.Intersect(IQueryable, IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Intersect(IQueryable, IEnumerable) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Queryable.Intersect(IQueryable, IEnumerable, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Intersect(IQueryable, IEnumerable, IEqualityComparer) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | output from argument 4 [] -> return [[]] | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | argument 0 [[]] -> parameter 0 of argument 4 [] | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | argument 1 [[]] -> parameter 0 of argument 3 [] | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | argument 1 [[]] -> parameter 1 of argument 4 [] | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | output from argument 4 [] -> return [[]] | true | +| System.Linq.Queryable.Last(IQueryable) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.Last(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Last(IQueryable, Expression>) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.LastOrDefault(IQueryable) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.LastOrDefault(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.LastOrDefault(IQueryable, Expression>) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.LongCount(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Max(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Min(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.OfType(IQueryable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.OrderBy(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.OrderBy(IQueryable, Expression>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.OrderBy(IQueryable, Expression>, IComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.OrderBy(IQueryable, Expression>, IComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>, IComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>, IComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Reverse(IQueryable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Select(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Select(IQueryable, Expression>) | output from argument 1 [] -> return [[]] | true | +| System.Linq.Queryable.Select(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Select(IQueryable, Expression>) | output from argument 1 [] -> return [[]] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | output from argument 1 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | output from argument 2 [] -> return [[]] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | output from argument 1 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | output from argument 2 [] -> return [[]] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | output from argument 1 [] -> return [[]] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | output from argument 1 [] -> return [[]] | true | +| System.Linq.Queryable.Single(IQueryable) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.Single(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Single(IQueryable, Expression>) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.SingleOrDefault(IQueryable) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.SingleOrDefault(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.SingleOrDefault(IQueryable, Expression>) | argument 0 [[]] -> return [] | true | +| System.Linq.Queryable.Skip(IQueryable, int) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Take(IQueryable, int) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>, IComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>, IComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>, IComparer) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>, IComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Union(IQueryable, IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Union(IQueryable, IEnumerable) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Queryable.Union(IQueryable, IEnumerable, IEqualityComparer) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Union(IQueryable, IEnumerable, IEqualityComparer) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Queryable.Where(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Where(IQueryable, Expression>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Where(IQueryable, Expression>) | argument 0 [[]] -> parameter 0 of argument 1 [] | true | +| System.Linq.Queryable.Where(IQueryable, Expression>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | argument 0 [[]] -> parameter 0 of argument 2 [] | true | +| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | argument 1 [[]] -> parameter 1 of argument 2 [] | true | +| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | output from argument 2 [] -> return [[]] | true | +| System.Net.CookieCollection.Add(Cookie) | argument 0 [] -> qualifier [[]] | true | +| System.Net.CookieCollection.Add(CookieCollection) | argument 0 [] -> qualifier [[]] | true | +| System.Net.CookieCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Net.CookieCollection.CopyTo(Cookie[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Net.CookieCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Net.CredentialCache.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Net.HttpListenerPrefixCollection.Add(string) | argument 0 [] -> qualifier [[]] | true | +| System.Net.HttpListenerPrefixCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Net.HttpListenerPrefixCollection.CopyTo(String[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Net.HttpListenerPrefixCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Net.NetworkInformation.IPAddressCollection.Add(IPAddress) | argument 0 [] -> qualifier [[]] | true | +| System.Net.NetworkInformation.IPAddressCollection.CopyTo(IPAddress[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Net.NetworkInformation.IPAddressCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Nullable<>.GetValueOrDefault() | qualifier [Value] -> return [] | true | +| System.Nullable<>.GetValueOrDefault(T) | qualifier [Value] -> return [] | true | +| System.Nullable<>.Nullable(T) | argument 0 [] -> return [Value] | true | +| System.Nullable<>.get_HasValue() | qualifier [Value] -> return [] | false | +| System.Resources.ResourceReader.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Resources.ResourceSet.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Runtime.CompilerServices.ConditionalWeakTable<,>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Add(T) | argument 0 [] -> qualifier [[]] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Insert(int, T) | argument 1 [] -> qualifier [[]] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Reverse() | argument 0 [[]] -> return [[]] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Reverse(int, int) | argument 0 [[]] -> return [[]] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.get_Item(int) | qualifier [[]] -> return [] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.set_Item(int, T) | argument 1 [] -> qualifier [[]] | true | +| System.Runtime.CompilerServices.TaskAwaiter<>.GetResult() | qualifier [m_task, Result] -> return [] | true | +| System.Security.PermissionSet.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Security.PermissionSet.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.String.Concat(IEnumerable) | argument 0 [[]] -> return [] | false | +| System.String.Concat(params Object[]) | argument 0 [[]] -> return [] | false | +| System.String.Concat(params String[]) | argument 0 [[]] -> return [] | false | +| System.String.Concat(IEnumerable) | argument 0 [[]] -> return [] | false | +| System.String.Format(IFormatProvider, string, params Object[]) | argument 2 [[]] -> return [] | false | +| System.String.Format(string, params Object[]) | argument 1 [[]] -> return [] | false | +| System.String.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.String.Join(char, String[], int, int) | argument 1 [[]] -> return [] | false | +| System.String.Join(char, params Object[]) | argument 1 [[]] -> return [] | false | +| System.String.Join(char, params String[]) | argument 1 [[]] -> return [] | false | +| System.String.Join(string, IEnumerable) | argument 1 [[]] -> return [] | false | +| System.String.Join(string, String[], int, int) | argument 1 [[]] -> return [] | false | +| System.String.Join(string, params Object[]) | argument 1 [[]] -> return [] | false | +| System.String.Join(string, params String[]) | argument 1 [[]] -> return [] | false | +| System.String.Join(char, IEnumerable) | argument 1 [[]] -> return [] | false | +| System.String.Join(string, IEnumerable) | argument 1 [[]] -> return [] | false | +| System.String.Split(Char[], StringSplitOptions) | qualifier [] -> return [[]] | false | +| System.String.Split(Char[], int) | qualifier [] -> return [[]] | false | +| System.String.Split(Char[], int, StringSplitOptions) | qualifier [] -> return [[]] | false | +| System.String.Split(String[], StringSplitOptions) | qualifier [] -> return [[]] | false | +| System.String.Split(String[], int, StringSplitOptions) | qualifier [] -> return [[]] | false | +| System.String.Split(char, StringSplitOptions) | qualifier [] -> return [[]] | false | +| System.String.Split(char, int, StringSplitOptions) | qualifier [] -> return [[]] | false | +| System.String.Split(params Char[]) | qualifier [] -> return [[]] | false | +| System.String.Split(string, StringSplitOptions) | qualifier [] -> return [[]] | false | +| System.String.Split(string, int, StringSplitOptions) | qualifier [] -> return [[]] | false | +| System.String.String(Char[]) | argument 0 [[]] -> return [] | false | +| System.String.String(Char[], int, int) | argument 0 [[]] -> return [] | false | +| System.Text.Encoding.GetBytes(Char[]) | argument 0 [[]] -> return [] | false | +| System.Text.Encoding.GetBytes(Char[], int, int) | argument 0 [[]] -> return [] | false | +| System.Text.Encoding.GetBytes(Char[], int, int, Byte[], int) | argument 0 [[]] -> return [] | false | +| System.Text.Encoding.GetChars(Byte[]) | argument 0 [[]] -> return [] | false | +| System.Text.Encoding.GetChars(Byte[], int, int) | argument 0 [[]] -> return [] | false | +| System.Text.Encoding.GetChars(Byte[], int, int, Char[], int) | argument 0 [[]] -> return [] | false | +| System.Text.Encoding.GetChars(ReadOnlySpan, Span) | argument 0 [[]] -> return [] | false | +| System.Text.Encoding.GetChars(byte*, int, char*, int) | argument 0 [[]] -> return [] | false | +| System.Text.Encoding.GetString(Byte[]) | argument 0 [[]] -> return [] | false | +| System.Text.Encoding.GetString(Byte[], int, int) | argument 0 [[]] -> return [] | false | +| System.Text.Encoding.GetString(ReadOnlySpan) | argument 0 [[]] -> return [] | false | +| System.Text.Encoding.GetString(byte*, int) | argument 0 [[]] -> return [] | false | +| System.Text.RegularExpressions.CaptureCollection.Add(Capture) | argument 0 [] -> qualifier [[]] | true | +| System.Text.RegularExpressions.CaptureCollection.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.Text.RegularExpressions.CaptureCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Text.RegularExpressions.CaptureCollection.CopyTo(Capture[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Text.RegularExpressions.CaptureCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Text.RegularExpressions.CaptureCollection.Insert(int, Capture) | argument 1 [] -> qualifier [[]] | true | +| System.Text.RegularExpressions.CaptureCollection.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Text.RegularExpressions.CaptureCollection.get_Item(int) | qualifier [[]] -> return [] | true | +| System.Text.RegularExpressions.GroupCollection.Add(Group) | argument 0 [] -> qualifier [[]] | true | +| System.Text.RegularExpressions.GroupCollection.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.Text.RegularExpressions.GroupCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Text.RegularExpressions.GroupCollection.CopyTo(Group[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Text.RegularExpressions.GroupCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Text.RegularExpressions.GroupCollection.Insert(int, Group) | argument 1 [] -> qualifier [[]] | true | +| System.Text.RegularExpressions.GroupCollection.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Text.RegularExpressions.GroupCollection.get_Item(int) | qualifier [[]] -> return [] | true | +| System.Text.RegularExpressions.GroupCollection.get_Item(string) | qualifier [[]] -> return [] | true | +| System.Text.RegularExpressions.MatchCollection.Add(Match) | argument 0 [] -> qualifier [[]] | true | +| System.Text.RegularExpressions.MatchCollection.Add(object) | argument 0 [] -> qualifier [[]] | true | +| System.Text.RegularExpressions.MatchCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Text.RegularExpressions.MatchCollection.CopyTo(Match[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Text.RegularExpressions.MatchCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Text.RegularExpressions.MatchCollection.Insert(int, Match) | argument 1 [] -> qualifier [[]] | true | +| System.Text.RegularExpressions.MatchCollection.Insert(int, object) | argument 1 [] -> qualifier [[]] | true | +| System.Text.RegularExpressions.MatchCollection.get_Item(int) | qualifier [[]] -> return [] | true | +| System.Text.StringBuilder.Append(object) | argument 0 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.Append(object) | argument 0 [] -> return [[]] | true | +| System.Text.StringBuilder.Append(string) | argument 0 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.Append(string) | argument 0 [] -> return [[]] | true | +| System.Text.StringBuilder.Append(string, int, int) | argument 0 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.Append(string, int, int) | argument 0 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | argument 1 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | argument 1 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | argument 2 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | argument 2 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 1 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 1 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 2 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 2 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 3 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 3 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 1 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 1 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 2 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 2 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 3 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 3 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 4 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 4 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, params Object[]) | argument 1 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, params Object[]) | argument 1 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object) | argument 0 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object) | argument 0 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object) | argument 1 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object) | argument 1 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 0 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 0 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 1 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 1 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 2 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 2 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 0 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 0 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 1 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 1 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 2 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 2 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 3 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 3 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, params Object[]) | argument 0 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, params Object[]) | argument 0 [] -> return [[]] | true | +| System.Text.StringBuilder.AppendLine(string) | argument 0 [] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendLine(string) | argument 0 [] -> return [[]] | true | +| System.Text.StringBuilder.StringBuilder(string) | argument 0 [] -> return [[]] | true | +| System.Text.StringBuilder.StringBuilder(string, int) | argument 0 [] -> return [[]] | true | +| System.Text.StringBuilder.StringBuilder(string, int, int, int) | argument 0 [] -> return [[]] | true | +| System.Text.StringBuilder.ToString() | qualifier [[]] -> return [] | false | +| System.Text.StringBuilder.ToString(int, int) | qualifier [[]] -> return [] | false | +| System.Threading.Tasks.Task.ContinueWith(Func, object) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object, TaskContinuationOptions) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object, TaskScheduler) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task.ContinueWith(Func) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task.ContinueWith(Func, CancellationToken) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task.ContinueWith(Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task.ContinueWith(Func, TaskContinuationOptions) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task.ContinueWith(Func, TaskScheduler) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task.FromResult(TResult) | argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task.Run(Func) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task.Run(Func, CancellationToken) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task.Run(Func>) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task.Run(Func>, CancellationToken) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task.WhenAll(IEnumerable>) | argument 0 [[], Result] -> return [Result, []] | true | +| System.Threading.Tasks.Task.WhenAll(params Task[]) | argument 0 [[], Result] -> return [Result, []] | true | +| System.Threading.Tasks.Task.WhenAny(IEnumerable>) | argument 0 [[], Result] -> return [Result, []] | true | +| System.Threading.Tasks.Task.WhenAny(params Task[]) | argument 0 [[], Result] -> return [Result, []] | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskContinuationOptions) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskScheduler) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskContinuationOptions) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskScheduler) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task<>.GetAwaiter() | qualifier [] -> return [m_task] | true | +| System.Threading.Tasks.Task<>.Task(Func, object) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken, TaskCreationOptions) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task<>.Task(Func, object, TaskCreationOptions) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task<>.Task(Func) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task<>.Task(Func, CancellationToken) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task<>.Task(Func, CancellationToken, TaskCreationOptions) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.Task<>.Task(Func, TaskCreationOptions) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, CancellationToken) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, TaskContinuationOptions) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, CancellationToken) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TaskContinuationOptions) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, object) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, object, TaskCreationOptions) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, CancellationToken) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, CancellationToken, TaskCreationOptions, TaskScheduler) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, TaskCreationOptions) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, CancellationToken) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TaskContinuationOptions) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, CancellationToken) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, TaskContinuationOptions) | output from argument 1 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, TaskCreationOptions) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, CancellationToken) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, CancellationToken, TaskCreationOptions, TaskScheduler) | output from argument 0 [] -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, TaskCreationOptions) | output from argument 0 [] -> return [Result] | true | +clearsContent +| System.Array.Clear() | qualifier | [] | +| System.Array.Clear(Array, int, int) | qualifier | [] | +| System.Collections.ArrayList.Clear() | qualifier | [] | +| System.Collections.ArrayList.FixedSizeArrayList.Clear() | qualifier | [] | +| System.Collections.ArrayList.FixedSizeList.Clear() | qualifier | [] | +| System.Collections.ArrayList.IListWrapper.Clear() | qualifier | [] | +| System.Collections.ArrayList.Range.Clear() | qualifier | [] | +| System.Collections.ArrayList.ReadOnlyArrayList.Clear() | qualifier | [] | +| System.Collections.ArrayList.ReadOnlyList.Clear() | qualifier | [] | +| System.Collections.ArrayList.SyncArrayList.Clear() | qualifier | [] | +| System.Collections.ArrayList.SyncIList.Clear() | qualifier | [] | +| System.Collections.CollectionBase.Clear() | qualifier | [] | +| System.Collections.Concurrent.ConcurrentBag<>.Clear() | qualifier | [] | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Clear() | qualifier | [] | +| System.Collections.Concurrent.ConcurrentQueue<>.Clear() | qualifier | [] | +| System.Collections.Concurrent.ConcurrentStack<>.Clear() | qualifier | [] | +| System.Collections.DictionaryBase.Clear() | qualifier | [] | +| System.Collections.EmptyReadOnlyDictionaryInternal.Clear() | qualifier | [] | +| System.Collections.Generic.Dictionary<,>.Clear() | qualifier | [] | +| System.Collections.Generic.Dictionary<,>.KeyCollection.Clear() | qualifier | [] | +| System.Collections.Generic.Dictionary<,>.ValueCollection.Clear() | qualifier | [] | +| System.Collections.Generic.HashSet<>.Clear() | qualifier | [] | +| System.Collections.Generic.ICollection<>.Clear() | qualifier | [] | +| System.Collections.Generic.LinkedList<>.Clear() | qualifier | [] | +| System.Collections.Generic.List<>.Clear() | qualifier | [] | +| System.Collections.Generic.Queue<>.Clear() | qualifier | [] | +| System.Collections.Generic.SortedDictionary<,>.Clear() | qualifier | [] | +| System.Collections.Generic.SortedDictionary<,>.KeyCollection.Clear() | qualifier | [] | +| System.Collections.Generic.SortedDictionary<,>.ValueCollection.Clear() | qualifier | [] | +| System.Collections.Generic.SortedList<,>.Clear() | qualifier | [] | +| System.Collections.Generic.SortedList<,>.KeyList.Clear() | qualifier | [] | +| System.Collections.Generic.SortedList<,>.ValueList.Clear() | qualifier | [] | +| System.Collections.Generic.SortedSet<>.Clear() | qualifier | [] | +| System.Collections.Generic.SortedSet<>.TreeSubSet.Clear() | qualifier | [] | +| System.Collections.Generic.Stack<>.Clear() | qualifier | [] | +| System.Collections.Hashtable.Clear() | qualifier | [] | +| System.Collections.Hashtable.SyncHashtable.Clear() | qualifier | [] | +| System.Collections.IDictionary.Clear() | qualifier | [] | +| System.Collections.IList.Clear() | qualifier | [] | +| System.Collections.ListDictionaryInternal.Clear() | qualifier | [] | +| System.Collections.ObjectModel.Collection<>.Clear() | qualifier | [] | +| System.Collections.ObjectModel.ReadOnlyCollection<>.Clear() | qualifier | [] | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Clear() | qualifier | [] | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.Clear() | qualifier | [] | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.Clear() | qualifier | [] | +| System.Collections.Queue.Clear() | qualifier | [] | +| System.Collections.Queue.SynchronizedQueue.Clear() | qualifier | [] | +| System.Collections.SortedList.Clear() | qualifier | [] | +| System.Collections.SortedList.KeyList.Clear() | qualifier | [] | +| System.Collections.SortedList.SyncSortedList.Clear() | qualifier | [] | +| System.Collections.SortedList.ValueList.Clear() | qualifier | [] | +| System.Collections.Specialized.HybridDictionary.Clear() | qualifier | [] | +| System.Collections.Specialized.ListDictionary.Clear() | qualifier | [] | +| System.Collections.Specialized.NameValueCollection.Clear() | qualifier | [] | +| System.Collections.Specialized.OrderedDictionary.Clear() | qualifier | [] | +| System.Collections.Specialized.ReadOnlyList.Clear() | qualifier | [] | +| System.Collections.Specialized.StringCollection.Clear() | qualifier | [] | +| System.Collections.Specialized.StringDictionary.Clear() | qualifier | [] | +| System.Collections.Stack.Clear() | qualifier | [] | +| System.Collections.Stack.SyncStack.Clear() | qualifier | [] | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.Clear() | qualifier | [] | +| System.ComponentModel.EventDescriptorCollection.Clear() | qualifier | [] | +| System.ComponentModel.ListSortDescriptionCollection.Clear() | qualifier | [] | +| System.ComponentModel.PropertyDescriptorCollection.Clear() | qualifier | [] | +| System.Diagnostics.Tracing.EventPayload.Clear() | qualifier | [] | +| System.Dynamic.ExpandoObject.Clear() | qualifier | [] | +| System.Dynamic.ExpandoObject.KeyCollection.Clear() | qualifier | [] | +| System.Dynamic.ExpandoObject.ValueCollection.Clear() | qualifier | [] | +| System.Dynamic.Utils.ListProvider<>.Clear() | qualifier | [] | +| System.Linq.Expressions.BlockExpressionList.Clear() | qualifier | [] | +| System.Linq.Grouping<,>.Clear() | qualifier | [] | +| System.Linq.Parallel.QueryResults<>.Clear() | qualifier | [] | +| System.Net.CookieCollection.Clear() | qualifier | [] | +| System.Net.HttpListenerPrefixCollection.Clear() | qualifier | [] | +| System.Net.NetworkInformation.IPAddressCollection.Clear() | qualifier | [] | +| System.Runtime.CompilerServices.ConditionalWeakTable<,>.Clear() | qualifier | [] | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Clear() | qualifier | [] | +| System.Text.RegularExpressions.CaptureCollection.Clear() | qualifier | [] | +| System.Text.RegularExpressions.GroupCollection.Clear() | qualifier | [] | +| System.Text.RegularExpressions.MatchCollection.Clear() | qualifier | [] | +| System.Text.StringBuilder.Clear() | qualifier | [] | diff --git a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.ql b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.ql index a5d65c711a37..fa11e138d1ff 100644 --- a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.ql +++ b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.ql @@ -1,27 +1,43 @@ +import csharp import semmle.code.csharp.dataflow.LibraryTypeDataFlow query predicate callableFlow(string callable, string flow, boolean preservesValue) { exists(LibraryTypeDataFlow x, CallableFlowSource source, CallableFlowSink sink, Callable c | c.(Modifiable).isPublic() and c.getDeclaringType().isPublic() and - x.callableFlow(source, sink, c, preservesValue) and callable = c.getQualifiedNameWithTypes() and flow = source + " -> " + sink and // Remove certain results to make the test output consistent // between different versions of .NET Core. not callable = "System.IO.FileStream.CopyToAsync(Stream, int, CancellationToken)" + | + x.callableFlow(source, sink, c, preservesValue) + or + x.callableFlow(source, AccessPath::empty(), sink, AccessPath::empty(), c, preservesValue) ) } -query predicate callableFlowAccessPath(string callable, string flow) { +query predicate callableFlowAccessPath(string callable, string flow, boolean preservesValue) { exists( LibraryTypeDataFlow x, CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, Callable c | c.(Modifiable).isPublic() and c.getDeclaringType().isPublic() and - x.callableFlow(source, sourceAp, sink, sinkAp, c) and + x.callableFlow(source, sourceAp, sink, sinkAp, c, preservesValue) and callable = c.getQualifiedNameWithTypes() and flow = source + " [" + sourceAp + "] -> " + sink + " [" + sinkAp + "]" + | + sourceAp.length() > 0 + or + sinkAp.length() > 0 + ) +} + +query predicate clearsContent(string callable, CallableFlowSource source, string content) { + exists(LibraryTypeDataFlow x, Callable callable0, DataFlow::Content content0 | + x.clearsContent(source, content0, callable0) and + callable = callable0.getQualifiedNameWithTypes() and + content = content0.toString() ) } diff --git a/csharp/ql/test/library-tests/dataflow/library/TaintedMember.expected b/csharp/ql/test/library-tests/dataflow/library/TaintedMember.expected new file mode 100644 index 000000000000..6e924a05cc21 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/library/TaintedMember.expected @@ -0,0 +1 @@ +| LibraryTypeDataFlow.cs:95:23:95:29 | AString | diff --git a/csharp/ql/test/library-tests/dataflow/library/TaintedMember.ql b/csharp/ql/test/library-tests/dataflow/library/TaintedMember.ql new file mode 100644 index 000000000000..a2460ac9b199 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/library/TaintedMember.ql @@ -0,0 +1,5 @@ +import csharp + +from TaintTracking::TaintedMember m +where m.fromSource() +select m diff --git a/csharp/ql/test/library-tests/dataflow/local/Common.qll b/csharp/ql/test/library-tests/dataflow/local/Common.qll index 5c65005407db..4a5be2f007ee 100644 --- a/csharp/ql/test/library-tests/dataflow/local/Common.qll +++ b/csharp/ql/test/library-tests/dataflow/local/Common.qll @@ -13,9 +13,9 @@ class MyFlowSource extends DataFlow::Node { or this.asParameter().hasName("tainted") or - exists(Expr e | this = TImplicitDelegateOutNode(e.getAControlFlowNode(), _) | - e.(DelegateCreation).getArgument().(MethodAccess).getTarget().hasName("TaintedMethod") or - e.(LambdaExpr).getExpressionBody().(StringLiteral).getValue() = "taint source" + exists(MyFlowSource mid, DataFlow::ExprNode e | + TaintTracking::localTaintStep+(mid, e) and + e.getExpr() = this.asExpr().(ArrayCreation).getInitializer().getAnElement() ) } } diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected b/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected index e9a03e58b0a1..005d84b1c97f 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected @@ -1,12 +1,10 @@ -| LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | -| LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | -| LocalDataFlow.cs:277:15:277:20 | access to local variable sink68 | -| LocalDataFlow.cs:295:15:295:20 | access to local variable sink70 | -| LocalDataFlow.cs:303:19:303:24 | access to local variable sink71 | -| LocalDataFlow.cs:313:23:313:28 | access to local variable sink72 | -| LocalDataFlow.cs:328:15:328:20 | access to local variable sink73 | -| LocalDataFlow.cs:329:15:329:20 | access to local variable sink74 | -| LocalDataFlow.cs:355:15:355:21 | access to parameter tainted | +| LocalDataFlow.cs:52:15:52:19 | access to local variable sink0 | +| LocalDataFlow.cs:282:15:282:20 | access to local variable sink70 | +| LocalDataFlow.cs:290:19:290:24 | access to local variable sink71 | +| LocalDataFlow.cs:300:23:300:28 | access to local variable sink72 | +| LocalDataFlow.cs:315:15:315:20 | access to local variable sink73 | +| LocalDataFlow.cs:316:15:316:20 | access to local variable sink74 | +| LocalDataFlow.cs:342:15:342:21 | access to parameter tainted | | SSA.cs:9:15:9:22 | access to local variable ssaSink0 | | SSA.cs:25:15:25:22 | access to local variable ssaSink1 | | SSA.cs:43:15:43:22 | access to local variable ssaSink2 | diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected index f641a355f833..26fc8fffd3a0 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected @@ -1,7 +1,4 @@ | Capture.cs:5:17:5:17 | this | Capture.cs:13:9:13:14 | this access | -| Capture.cs:7:13:7:17 | SSA def(i) | Capture.cs:13:9:13:16 | [implicit argument] i | -| Capture.cs:7:13:7:17 | SSA def(i) | Capture.cs:23:9:23:16 | [implicit argument] i | -| Capture.cs:7:13:7:17 | SSA def(i) | Capture.cs:34:9:34:16 | [implicit argument] i | | Capture.cs:7:17:7:17 | 0 | Capture.cs:7:13:7:17 | SSA def(i) | | Capture.cs:9:9:12:9 | SSA capture def(i) | Capture.cs:11:17:11:17 | access to local variable i | | Capture.cs:13:9:13:14 | this access | Capture.cs:23:9:23:14 | this access | @@ -10,7 +7,6 @@ | Capture.cs:23:9:23:14 | this access | Capture.cs:34:9:34:14 | this access | | Capture.cs:25:9:33:9 | this | Capture.cs:32:13:32:18 | this access | | Capture.cs:27:13:30:13 | SSA capture def(i) | Capture.cs:29:21:29:21 | access to local variable i | -| Capture.cs:31:13:31:17 | SSA def(i) | Capture.cs:32:13:32:20 | [implicit argument] i | | Capture.cs:31:17:31:17 | 1 | Capture.cs:31:13:31:17 | SSA def(i) | | Capture.cs:34:9:34:14 | this access | Capture.cs:40:9:40:15 | this access | | Capture.cs:38:17:38:17 | 0 | Capture.cs:38:13:38:17 | SSA def(i) | @@ -24,415 +20,395 @@ | Capture.cs:58:21:58:21 | 1 | Capture.cs:58:17:58:21 | SSA def(i) | | Capture.cs:61:17:61:17 | 1 | Capture.cs:61:13:61:17 | SSA def(i) | | Capture.cs:63:9:63:17 | SSA call def(i) | Capture.cs:64:13:64:13 | access to local variable i | -| LocalDataFlow.cs:49:30:49:30 | b | LocalDataFlow.cs:85:21:85:21 | access to parameter b | -| LocalDataFlow.cs:52:13:52:34 | SSA def(sink0) | LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | -| LocalDataFlow.cs:52:21:52:34 | "taint source" | LocalDataFlow.cs:52:13:52:34 | SSA def(sink0) | -| LocalDataFlow.cs:53:15:53:19 | [post] access to local variable sink0 | LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | -| LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | -| LocalDataFlow.cs:56:13:56:25 | SSA def(nonSink0) | LocalDataFlow.cs:57:15:57:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:56:24:56:25 | "" | LocalDataFlow.cs:56:13:56:25 | SSA def(nonSink0) | -| LocalDataFlow.cs:57:15:57:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:65:9:65:16 | access to local variable nonSink0 | -| LocalDataFlow.cs:57:15:57:22 | access to local variable nonSink0 | LocalDataFlow.cs:65:9:65:16 | access to local variable nonSink0 | -| LocalDataFlow.cs:60:13:60:25 | SSA def(sink1) | LocalDataFlow.cs:61:9:61:13 | access to local variable sink1 | -| LocalDataFlow.cs:60:21:60:25 | "abc" | LocalDataFlow.cs:60:13:60:25 | SSA def(sink1) | -| LocalDataFlow.cs:61:9:61:22 | ... + ... | LocalDataFlow.cs:61:9:61:22 | SSA def(sink1) | -| LocalDataFlow.cs:61:9:61:22 | SSA def(sink1) | LocalDataFlow.cs:62:15:62:19 | access to local variable sink1 | -| LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | LocalDataFlow.cs:169:20:169:24 | access to local variable sink0 | -| LocalDataFlow.cs:62:15:62:19 | [post] access to local variable sink1 | LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | -| LocalDataFlow.cs:62:15:62:19 | access to local variable sink1 | LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | -| LocalDataFlow.cs:65:9:65:25 | ... + ... | LocalDataFlow.cs:65:9:65:25 | SSA def(nonSink0) | -| LocalDataFlow.cs:65:9:65:25 | SSA def(nonSink0) | LocalDataFlow.cs:66:15:66:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:66:15:66:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:73:20:73:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:66:15:66:22 | access to local variable nonSink0 | LocalDataFlow.cs:73:20:73:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:69:13:69:32 | SSA def(sink5) | LocalDataFlow.cs:70:15:70:19 | access to local variable sink5 | -| LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | LocalDataFlow.cs:169:33:169:37 | access to local variable sink1 | -| LocalDataFlow.cs:69:21:69:32 | ... + ... | LocalDataFlow.cs:69:13:69:32 | SSA def(sink5) | -| LocalDataFlow.cs:70:15:70:19 | [post] access to local variable sink5 | LocalDataFlow.cs:77:22:77:26 | access to local variable sink5 | -| LocalDataFlow.cs:70:15:70:19 | access to local variable sink5 | LocalDataFlow.cs:77:22:77:26 | access to local variable sink5 | -| LocalDataFlow.cs:73:9:73:36 | SSA def(nonSink0) | LocalDataFlow.cs:74:15:74:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:73:20:73:36 | ... + ... | LocalDataFlow.cs:73:9:73:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:74:15:74:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:81:21:81:28 | access to local variable nonSink0 | -| LocalDataFlow.cs:74:15:74:22 | access to local variable nonSink0 | LocalDataFlow.cs:81:21:81:28 | access to local variable nonSink0 | -| LocalDataFlow.cs:77:13:77:27 | SSA def(sink6) | LocalDataFlow.cs:78:15:78:19 | access to local variable sink6 | -| LocalDataFlow.cs:77:22:77:26 | access to local variable sink5 | LocalDataFlow.cs:77:13:77:27 | SSA def(sink6) | -| LocalDataFlow.cs:78:15:78:19 | [post] access to local variable sink6 | LocalDataFlow.cs:85:31:85:35 | [b (line 49): false] access to local variable sink6 | -| LocalDataFlow.cs:78:15:78:19 | access to local variable sink6 | LocalDataFlow.cs:85:31:85:35 | [b (line 49): false] access to local variable sink6 | -| LocalDataFlow.cs:81:9:81:29 | SSA def(nonSink0) | LocalDataFlow.cs:82:15:82:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:81:21:81:28 | access to local variable nonSink0 | LocalDataFlow.cs:81:9:81:29 | SSA def(nonSink0) | -| LocalDataFlow.cs:85:13:85:35 | [b (line 49): false] SSA def(sink7) | LocalDataFlow.cs:86:15:86:19 | [b (line 49): false] access to local variable sink7 | -| LocalDataFlow.cs:85:13:85:35 | [b (line 49): true] SSA def(sink7) | LocalDataFlow.cs:86:15:86:19 | [b (line 49): true] access to local variable sink7 | -| LocalDataFlow.cs:85:21:85:21 | access to parameter b | LocalDataFlow.cs:89:20:89:20 | [b (line 49): false] access to parameter b | -| LocalDataFlow.cs:85:21:85:21 | access to parameter b | LocalDataFlow.cs:89:20:89:20 | [b (line 49): true] access to parameter b | -| LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | LocalDataFlow.cs:85:13:85:35 | [b (line 49): false] SSA def(sink7) | -| LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | LocalDataFlow.cs:85:13:85:35 | [b (line 49): true] SSA def(sink7) | -| LocalDataFlow.cs:85:25:85:27 | [b (line 49): true] "a" | LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | -| LocalDataFlow.cs:85:31:85:35 | [b (line 49): false] access to local variable sink6 | LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | -| LocalDataFlow.cs:86:15:86:19 | [b (line 49): false] access to local variable sink7 | LocalDataFlow.cs:89:9:89:36 | SSA phi(sink7) | -| LocalDataFlow.cs:86:15:86:19 | [b (line 49): true] access to local variable sink7 | LocalDataFlow.cs:89:9:89:36 | SSA phi(sink7) | -| LocalDataFlow.cs:89:9:89:36 | SSA def(nonSink0) | LocalDataFlow.cs:90:15:90:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:89:9:89:36 | SSA phi(sink7) | LocalDataFlow.cs:93:29:93:33 | access to local variable sink7 | -| LocalDataFlow.cs:89:20:89:36 | [b (line 49): false] ... ? ... : ... | LocalDataFlow.cs:89:9:89:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:89:20:89:36 | [b (line 49): true] ... ? ... : ... | LocalDataFlow.cs:89:9:89:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:89:24:89:28 | "abc" | LocalDataFlow.cs:89:20:89:36 | [b (line 49): true] ... ? ... : ... | -| LocalDataFlow.cs:89:32:89:36 | "def" | LocalDataFlow.cs:89:20:89:36 | [b (line 49): false] ... ? ... : ... | -| LocalDataFlow.cs:90:15:90:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:90:15:90:22 | access to local variable nonSink0 | LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:93:13:93:33 | SSA def(sink8) | LocalDataFlow.cs:94:15:94:19 | access to local variable sink8 | -| LocalDataFlow.cs:93:21:93:33 | (...) ... | LocalDataFlow.cs:93:13:93:33 | SSA def(sink8) | -| LocalDataFlow.cs:93:29:93:33 | access to local variable sink7 | LocalDataFlow.cs:93:21:93:33 | (...) ... | -| LocalDataFlow.cs:94:15:94:19 | [post] access to local variable sink8 | LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | -| LocalDataFlow.cs:94:15:94:19 | access to local variable sink8 | LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | -| LocalDataFlow.cs:97:13:97:39 | SSA def(nonSink3) | LocalDataFlow.cs:98:15:98:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:97:24:97:39 | (...) ... | LocalDataFlow.cs:97:13:97:39 | SSA def(nonSink3) | -| LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | LocalDataFlow.cs:97:24:97:39 | (...) ... | -| LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | LocalDataFlow.cs:105:20:105:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:101:13:101:35 | SSA def(sink9) | LocalDataFlow.cs:102:15:102:19 | access to local variable sink9 | -| LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | LocalDataFlow.cs:101:21:101:35 | ... as ... | -| LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | LocalDataFlow.cs:165:22:165:26 | access to local variable sink8 | -| LocalDataFlow.cs:101:21:101:35 | ... as ... | LocalDataFlow.cs:101:13:101:35 | SSA def(sink9) | -| LocalDataFlow.cs:102:15:102:19 | [post] access to local variable sink9 | LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | -| LocalDataFlow.cs:102:15:102:19 | access to local variable sink9 | LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | -| LocalDataFlow.cs:105:9:105:37 | SSA def(nonSink3) | LocalDataFlow.cs:106:15:106:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:105:20:105:27 | access to local variable nonSink0 | LocalDataFlow.cs:105:20:105:37 | ... as ... | -| LocalDataFlow.cs:105:20:105:27 | access to local variable nonSink0 | LocalDataFlow.cs:114:22:114:29 | access to local variable nonSink0 | -| LocalDataFlow.cs:105:20:105:37 | ... as ... | LocalDataFlow.cs:105:9:105:37 | SSA def(nonSink3) | -| LocalDataFlow.cs:106:15:106:22 | [post] access to local variable nonSink3 | LocalDataFlow.cs:171:33:171:40 | access to local variable nonSink3 | -| LocalDataFlow.cs:106:15:106:22 | access to local variable nonSink3 | LocalDataFlow.cs:171:33:171:40 | access to local variable nonSink3 | -| LocalDataFlow.cs:109:13:109:39 | SSA def(sink15) | LocalDataFlow.cs:110:15:110:20 | access to local variable sink15 | -| LocalDataFlow.cs:109:22:109:39 | call to method Parse | LocalDataFlow.cs:109:13:109:39 | SSA def(sink15) | -| LocalDataFlow.cs:109:34:109:38 | [post] access to local variable sink9 | LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | -| LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | -| LocalDataFlow.cs:110:15:110:20 | access to local variable sink15 | LocalDataFlow.cs:161:22:161:27 | access to local variable sink15 | -| LocalDataFlow.cs:112:13:112:56 | SSA def(sink16) | LocalDataFlow.cs:113:15:113:20 | access to local variable sink16 | -| LocalDataFlow.cs:112:22:112:56 | call to method TryParse | LocalDataFlow.cs:112:13:112:56 | SSA def(sink16) | -| LocalDataFlow.cs:112:37:112:41 | [post] access to local variable sink9 | LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | -| LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | -| LocalDataFlow.cs:114:13:114:49 | SSA def(sink17) | LocalDataFlow.cs:115:15:115:20 | access to local variable sink17 | -| LocalDataFlow.cs:114:22:114:29 | [post] access to local variable nonSink0 | LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | -| LocalDataFlow.cs:114:22:114:29 | access to local variable nonSink0 | LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | -| LocalDataFlow.cs:114:22:114:49 | call to method Replace | LocalDataFlow.cs:114:13:114:49 | SSA def(sink17) | -| LocalDataFlow.cs:114:44:114:48 | [post] access to local variable sink9 | LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | -| LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | -| LocalDataFlow.cs:116:13:116:51 | SSA def(sink18) | LocalDataFlow.cs:117:15:117:20 | access to local variable sink18 | -| LocalDataFlow.cs:116:22:116:51 | call to method Format | LocalDataFlow.cs:116:13:116:51 | SSA def(sink18) | -| LocalDataFlow.cs:116:36:116:43 | [post] access to local variable nonSink0 | LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:116:46:116:50 | [post] access to local variable sink9 | LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | -| LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | -| LocalDataFlow.cs:117:15:117:20 | [post] access to local variable sink18 | LocalDataFlow.cs:118:36:118:41 | access to local variable sink18 | -| LocalDataFlow.cs:117:15:117:20 | access to local variable sink18 | LocalDataFlow.cs:118:36:118:41 | access to local variable sink18 | -| LocalDataFlow.cs:118:13:118:52 | SSA def(sink19) | LocalDataFlow.cs:119:15:119:20 | access to local variable sink19 | -| LocalDataFlow.cs:118:22:118:52 | call to method Format | LocalDataFlow.cs:118:13:118:52 | SSA def(sink19) | -| LocalDataFlow.cs:118:44:118:51 | [post] access to local variable nonSink0 | LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:120:13:120:38 | SSA def(sink45) | LocalDataFlow.cs:121:15:121:20 | access to local variable sink45 | -| LocalDataFlow.cs:120:22:120:38 | call to method Parse | LocalDataFlow.cs:120:13:120:38 | SSA def(sink45) | -| LocalDataFlow.cs:120:33:120:37 | [post] access to local variable sink9 | LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | -| LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | -| LocalDataFlow.cs:123:13:123:56 | SSA def(sink46) | LocalDataFlow.cs:124:15:124:20 | access to local variable sink46 | -| LocalDataFlow.cs:123:22:123:56 | call to method TryParse | LocalDataFlow.cs:123:13:123:56 | SSA def(sink46) | -| LocalDataFlow.cs:123:36:123:40 | [post] access to local variable sink9 | LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | -| LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | -| LocalDataFlow.cs:124:15:124:20 | access to local variable sink46 | LocalDataFlow.cs:125:37:125:42 | access to local variable sink46 | -| LocalDataFlow.cs:125:13:125:43 | SSA def(sink47) | LocalDataFlow.cs:126:15:126:20 | access to local variable sink47 | -| LocalDataFlow.cs:125:22:125:43 | call to method ToByte | LocalDataFlow.cs:125:13:125:43 | SSA def(sink47) | -| LocalDataFlow.cs:126:15:126:20 | access to local variable sink47 | LocalDataFlow.cs:127:40:127:45 | access to local variable sink47 | -| LocalDataFlow.cs:127:13:127:46 | SSA def(sink49) | LocalDataFlow.cs:128:15:128:20 | access to local variable sink49 | -| LocalDataFlow.cs:127:22:127:46 | call to method Concat | LocalDataFlow.cs:127:13:127:46 | SSA def(sink49) | -| LocalDataFlow.cs:127:40:127:45 | access to local variable sink47 | LocalDataFlow.cs:127:40:127:45 | (...) ... | -| LocalDataFlow.cs:128:15:128:20 | [post] access to local variable sink49 | LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | -| LocalDataFlow.cs:128:15:128:20 | access to local variable sink49 | LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | -| LocalDataFlow.cs:129:13:129:40 | SSA def(sink50) | LocalDataFlow.cs:130:15:130:20 | access to local variable sink50 | -| LocalDataFlow.cs:129:22:129:40 | [library code] call to method Copy | LocalDataFlow.cs:129:22:129:40 | call to method Copy | -| LocalDataFlow.cs:129:22:129:40 | call to method Copy | LocalDataFlow.cs:129:13:129:40 | SSA def(sink50) | -| LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | LocalDataFlow.cs:129:22:129:40 | [library code] call to method Copy | -| LocalDataFlow.cs:130:15:130:20 | [post] access to local variable sink50 | LocalDataFlow.cs:131:44:131:49 | access to local variable sink50 | -| LocalDataFlow.cs:130:15:130:20 | access to local variable sink50 | LocalDataFlow.cs:131:44:131:49 | access to local variable sink50 | -| LocalDataFlow.cs:131:13:131:54 | SSA def(sink51) | LocalDataFlow.cs:132:15:132:20 | access to local variable sink51 | -| LocalDataFlow.cs:131:22:131:54 | call to method Join | LocalDataFlow.cs:131:13:131:54 | SSA def(sink51) | -| LocalDataFlow.cs:132:15:132:20 | [post] access to local variable sink51 | LocalDataFlow.cs:133:35:133:40 | access to local variable sink51 | -| LocalDataFlow.cs:132:15:132:20 | access to local variable sink51 | LocalDataFlow.cs:133:35:133:40 | access to local variable sink51 | -| LocalDataFlow.cs:133:13:133:41 | SSA def(sink52) | LocalDataFlow.cs:134:15:134:20 | access to local variable sink52 | -| LocalDataFlow.cs:133:22:133:41 | call to method Insert | LocalDataFlow.cs:133:13:133:41 | SSA def(sink52) | -| LocalDataFlow.cs:137:9:137:40 | SSA def(nonSink2) | LocalDataFlow.cs:138:15:138:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:137:20:137:40 | call to method Parse | LocalDataFlow.cs:137:9:137:40 | SSA def(nonSink2) | -| LocalDataFlow.cs:137:32:137:39 | [post] access to local variable nonSink0 | LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:139:13:139:61 | SSA def(nonSink7) | LocalDataFlow.cs:140:15:140:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:139:24:139:61 | call to method TryParse | LocalDataFlow.cs:139:13:139:61 | SSA def(nonSink7) | -| LocalDataFlow.cs:139:39:139:46 | [post] access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:141:9:141:50 | SSA def(nonSink0) | LocalDataFlow.cs:142:15:142:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:141:20:141:27 | [post] access to local variable nonSink0 | LocalDataFlow.cs:141:42:141:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | LocalDataFlow.cs:141:42:141:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:141:20:141:50 | call to method Replace | LocalDataFlow.cs:141:9:141:50 | SSA def(nonSink0) | -| LocalDataFlow.cs:142:15:142:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:142:15:142:22 | access to local variable nonSink0 | LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:143:9:143:52 | SSA def(nonSink0) | LocalDataFlow.cs:144:15:144:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:143:20:143:52 | call to method Format | LocalDataFlow.cs:143:9:143:52 | SSA def(nonSink0) | -| LocalDataFlow.cs:143:34:143:41 | [post] access to local variable nonSink0 | LocalDataFlow.cs:143:44:143:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | LocalDataFlow.cs:143:44:143:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:144:15:144:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:144:15:144:22 | access to local variable nonSink0 | LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:145:9:145:39 | SSA def(nonSink7) | LocalDataFlow.cs:146:15:146:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:145:20:145:39 | call to method Parse | LocalDataFlow.cs:145:9:145:39 | SSA def(nonSink7) | -| LocalDataFlow.cs:145:31:145:38 | [post] access to local variable nonSink0 | LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:147:9:147:57 | SSA def(nonSink7) | LocalDataFlow.cs:148:15:148:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:147:20:147:57 | call to method TryParse | LocalDataFlow.cs:147:9:147:57 | SSA def(nonSink7) | -| LocalDataFlow.cs:148:15:148:22 | access to local variable nonSink7 | LocalDataFlow.cs:149:40:149:47 | access to local variable nonSink7 | -| LocalDataFlow.cs:149:13:149:48 | SSA def(nonSink14) | LocalDataFlow.cs:150:15:150:23 | access to local variable nonSink14 | -| LocalDataFlow.cs:149:25:149:48 | call to method ToByte | LocalDataFlow.cs:149:13:149:48 | SSA def(nonSink14) | -| LocalDataFlow.cs:149:40:149:47 | access to local variable nonSink7 | LocalDataFlow.cs:151:38:151:45 | access to local variable nonSink7 | -| LocalDataFlow.cs:151:9:151:46 | SSA def(nonSink0) | LocalDataFlow.cs:152:15:152:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:151:20:151:46 | call to method Concat | LocalDataFlow.cs:151:9:151:46 | SSA def(nonSink0) | -| LocalDataFlow.cs:151:38:151:45 | access to local variable nonSink7 | LocalDataFlow.cs:151:38:151:45 | (...) ... | -| LocalDataFlow.cs:152:15:152:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:152:15:152:22 | access to local variable nonSink0 | LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:153:9:153:40 | SSA def(nonSink0) | LocalDataFlow.cs:154:15:154:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:153:20:153:40 | [library code] call to method Copy | LocalDataFlow.cs:153:20:153:40 | call to method Copy | -| LocalDataFlow.cs:153:20:153:40 | call to method Copy | LocalDataFlow.cs:153:9:153:40 | SSA def(nonSink0) | -| LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | LocalDataFlow.cs:153:20:153:40 | [library code] call to method Copy | -| LocalDataFlow.cs:154:15:154:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:155:42:155:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:154:15:154:22 | access to local variable nonSink0 | LocalDataFlow.cs:155:42:155:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:155:9:155:54 | SSA def(nonSink0) | LocalDataFlow.cs:156:15:156:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:155:20:155:54 | call to method Join | LocalDataFlow.cs:155:9:155:54 | SSA def(nonSink0) | -| LocalDataFlow.cs:156:15:156:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:157:33:157:40 | access to local variable nonSink0 | -| LocalDataFlow.cs:156:15:156:22 | access to local variable nonSink0 | LocalDataFlow.cs:157:33:157:40 | access to local variable nonSink0 | -| LocalDataFlow.cs:157:9:157:41 | SSA def(nonSink0) | LocalDataFlow.cs:158:15:158:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:157:20:157:41 | call to method Insert | LocalDataFlow.cs:157:9:157:41 | SSA def(nonSink0) | -| LocalDataFlow.cs:158:15:158:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:195:39:195:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:158:15:158:22 | access to local variable nonSink0 | LocalDataFlow.cs:195:39:195:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:161:13:161:32 | SSA def(sink20) | LocalDataFlow.cs:162:15:162:20 | access to local variable sink20 | -| LocalDataFlow.cs:161:22:161:32 | ... > ... | LocalDataFlow.cs:161:13:161:32 | SSA def(sink20) | -| LocalDataFlow.cs:162:15:162:20 | access to local variable sink20 | LocalDataFlow.cs:175:22:175:27 | access to local variable sink20 | -| LocalDataFlow.cs:163:13:163:40 | SSA def(sink21) | LocalDataFlow.cs:164:15:164:20 | access to local variable sink21 | -| LocalDataFlow.cs:163:22:163:26 | [post] access to local variable sink9 | LocalDataFlow.cs:183:37:183:41 | access to local variable sink9 | -| LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | LocalDataFlow.cs:183:37:183:41 | access to local variable sink9 | -| LocalDataFlow.cs:163:22:163:40 | call to method Equals | LocalDataFlow.cs:163:13:163:40 | SSA def(sink21) | -| LocalDataFlow.cs:165:13:165:45 | SSA def(sink22) | LocalDataFlow.cs:166:15:166:20 | access to local variable sink22 | -| LocalDataFlow.cs:165:22:165:26 | [post] access to local variable sink8 | LocalDataFlow.cs:171:20:171:24 | access to local variable sink8 | -| LocalDataFlow.cs:165:22:165:26 | access to local variable sink8 | LocalDataFlow.cs:171:20:171:24 | access to local variable sink8 | -| LocalDataFlow.cs:165:22:165:45 | call to method Equals | LocalDataFlow.cs:165:13:165:45 | SSA def(sink22) | -| LocalDataFlow.cs:165:43:165:44 | 41 | LocalDataFlow.cs:165:35:165:44 | (...) ... | -| LocalDataFlow.cs:169:9:169:38 | SSA def(nonSink7) | LocalDataFlow.cs:170:15:170:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:169:20:169:24 | [post] access to local variable sink0 | LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | -| LocalDataFlow.cs:169:20:169:24 | access to local variable sink0 | LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | -| LocalDataFlow.cs:169:20:169:38 | call to method Equals | LocalDataFlow.cs:169:9:169:38 | SSA def(nonSink7) | -| LocalDataFlow.cs:169:33:169:37 | [post] access to local variable sink1 | LocalDataFlow.cs:286:30:286:34 | access to local variable sink1 | -| LocalDataFlow.cs:169:33:169:37 | access to local variable sink1 | LocalDataFlow.cs:286:30:286:34 | access to local variable sink1 | -| LocalDataFlow.cs:171:9:171:41 | SSA def(nonSink7) | LocalDataFlow.cs:172:15:172:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:171:20:171:41 | call to method Equals | LocalDataFlow.cs:171:9:171:41 | SSA def(nonSink7) | -| LocalDataFlow.cs:172:15:172:22 | access to local variable nonSink7 | LocalDataFlow.cs:179:20:179:27 | access to local variable nonSink7 | -| LocalDataFlow.cs:175:13:175:36 | SSA def(sink25) | LocalDataFlow.cs:176:15:176:20 | access to local variable sink25 | -| LocalDataFlow.cs:175:22:175:36 | ... \|\| ... | LocalDataFlow.cs:175:13:175:36 | SSA def(sink25) | -| LocalDataFlow.cs:179:9:179:36 | SSA def(nonSink7) | LocalDataFlow.cs:180:15:180:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:179:20:179:36 | ... \|\| ... | LocalDataFlow.cs:179:9:179:36 | SSA def(nonSink7) | -| LocalDataFlow.cs:183:13:183:42 | SSA def(sink26) | LocalDataFlow.cs:184:15:184:20 | access to local variable sink26 | -| LocalDataFlow.cs:183:22:183:42 | object creation of type Uri | LocalDataFlow.cs:183:13:183:42 | SSA def(sink26) | -| LocalDataFlow.cs:184:15:184:20 | [post] access to local variable sink26 | LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | -| LocalDataFlow.cs:184:15:184:20 | access to local variable sink26 | LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | -| LocalDataFlow.cs:185:13:185:38 | SSA def(sink27) | LocalDataFlow.cs:186:15:186:20 | access to local variable sink27 | -| LocalDataFlow.cs:185:22:185:27 | [post] access to local variable sink26 | LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | -| LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | -| LocalDataFlow.cs:185:22:185:38 | call to method ToString | LocalDataFlow.cs:185:13:185:38 | SSA def(sink27) | -| LocalDataFlow.cs:187:13:187:40 | SSA def(sink28) | LocalDataFlow.cs:188:15:188:20 | access to local variable sink28 | -| LocalDataFlow.cs:187:22:187:27 | [post] access to local variable sink26 | LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | -| LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | -| LocalDataFlow.cs:187:22:187:40 | access to property PathAndQuery | LocalDataFlow.cs:187:13:187:40 | SSA def(sink28) | -| LocalDataFlow.cs:189:13:189:33 | SSA def(sink29) | LocalDataFlow.cs:190:15:190:20 | access to local variable sink29 | -| LocalDataFlow.cs:189:22:189:27 | [post] access to local variable sink26 | LocalDataFlow.cs:191:22:191:27 | access to local variable sink26 | -| LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | LocalDataFlow.cs:191:22:191:27 | access to local variable sink26 | -| LocalDataFlow.cs:189:22:189:33 | access to property Query | LocalDataFlow.cs:189:13:189:33 | SSA def(sink29) | -| LocalDataFlow.cs:191:13:191:42 | SSA def(sink30) | LocalDataFlow.cs:192:15:192:20 | access to local variable sink30 | -| LocalDataFlow.cs:191:22:191:42 | access to property OriginalString | LocalDataFlow.cs:191:13:191:42 | SSA def(sink30) | -| LocalDataFlow.cs:192:15:192:20 | [post] access to local variable sink30 | LocalDataFlow.cs:207:49:207:54 | access to local variable sink30 | -| LocalDataFlow.cs:192:15:192:20 | access to local variable sink30 | LocalDataFlow.cs:207:49:207:54 | access to local variable sink30 | -| LocalDataFlow.cs:195:13:195:47 | SSA def(nonSink8) | LocalDataFlow.cs:196:15:196:22 | access to local variable nonSink8 | -| LocalDataFlow.cs:195:24:195:47 | object creation of type Uri | LocalDataFlow.cs:195:13:195:47 | SSA def(nonSink8) | -| LocalDataFlow.cs:196:15:196:22 | [post] access to local variable nonSink8 | LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:196:15:196:22 | access to local variable nonSink8 | LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:197:9:197:38 | SSA def(nonSink0) | LocalDataFlow.cs:198:15:198:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:197:20:197:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:197:20:197:38 | call to method ToString | LocalDataFlow.cs:197:9:197:38 | SSA def(nonSink0) | -| LocalDataFlow.cs:199:9:199:40 | SSA def(nonSink0) | LocalDataFlow.cs:200:15:200:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:199:20:199:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:199:20:199:40 | access to property PathAndQuery | LocalDataFlow.cs:199:9:199:40 | SSA def(nonSink0) | -| LocalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) | LocalDataFlow.cs:202:15:202:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:201:20:201:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:203:20:203:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | LocalDataFlow.cs:203:20:203:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:201:20:201:33 | access to property Query | LocalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) | -| LocalDataFlow.cs:203:9:203:42 | SSA def(nonSink0) | LocalDataFlow.cs:204:15:204:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:203:20:203:42 | access to property OriginalString | LocalDataFlow.cs:203:9:203:42 | SSA def(nonSink0) | -| LocalDataFlow.cs:204:15:204:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:213:51:213:58 | access to local variable nonSink0 | -| LocalDataFlow.cs:204:15:204:22 | access to local variable nonSink0 | LocalDataFlow.cs:213:51:213:58 | access to local variable nonSink0 | -| LocalDataFlow.cs:207:13:207:55 | SSA def(sink31) | LocalDataFlow.cs:208:15:208:20 | access to local variable sink31 | -| LocalDataFlow.cs:207:22:207:55 | object creation of type StringReader | LocalDataFlow.cs:207:13:207:55 | SSA def(sink31) | -| LocalDataFlow.cs:208:15:208:20 | [post] access to local variable sink31 | LocalDataFlow.cs:209:22:209:27 | access to local variable sink31 | -| LocalDataFlow.cs:208:15:208:20 | access to local variable sink31 | LocalDataFlow.cs:209:22:209:27 | access to local variable sink31 | -| LocalDataFlow.cs:209:13:209:39 | SSA def(sink32) | LocalDataFlow.cs:210:15:210:20 | access to local variable sink32 | -| LocalDataFlow.cs:209:22:209:39 | call to method ReadToEnd | LocalDataFlow.cs:209:13:209:39 | SSA def(sink32) | -| LocalDataFlow.cs:210:15:210:20 | [post] access to local variable sink32 | LocalDataFlow.cs:219:30:219:35 | access to local variable sink32 | -| LocalDataFlow.cs:210:15:210:20 | access to local variable sink32 | LocalDataFlow.cs:219:30:219:35 | access to local variable sink32 | -| LocalDataFlow.cs:213:13:213:59 | SSA def(nonSink9) | LocalDataFlow.cs:214:15:214:22 | access to local variable nonSink9 | -| LocalDataFlow.cs:213:24:213:59 | object creation of type StringReader | LocalDataFlow.cs:213:13:213:59 | SSA def(nonSink9) | -| LocalDataFlow.cs:214:15:214:22 | [post] access to local variable nonSink9 | LocalDataFlow.cs:215:20:215:27 | access to local variable nonSink9 | -| LocalDataFlow.cs:214:15:214:22 | access to local variable nonSink9 | LocalDataFlow.cs:215:20:215:27 | access to local variable nonSink9 | -| LocalDataFlow.cs:215:9:215:39 | SSA def(nonSink0) | LocalDataFlow.cs:216:15:216:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:215:20:215:39 | call to method ReadToEnd | LocalDataFlow.cs:215:9:215:39 | SSA def(nonSink0) | -| LocalDataFlow.cs:216:15:216:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:225:28:225:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:216:15:216:22 | access to local variable nonSink0 | LocalDataFlow.cs:225:28:225:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:219:13:219:127 | SSA def(sink33) | LocalDataFlow.cs:220:15:220:20 | access to local variable sink33 | -| LocalDataFlow.cs:219:22:219:127 | (...) ... | LocalDataFlow.cs:219:13:219:127 | SSA def(sink33) | -| LocalDataFlow.cs:219:30:219:119 | call to method Insert | LocalDataFlow.cs:219:30:219:127 | [library code] call to method Clone | -| LocalDataFlow.cs:219:30:219:127 | [library code] call to method Clone | LocalDataFlow.cs:219:30:219:127 | call to method Clone | -| LocalDataFlow.cs:219:30:219:127 | call to method Clone | LocalDataFlow.cs:219:22:219:127 | (...) ... | -| LocalDataFlow.cs:220:15:220:20 | [post] access to local variable sink33 | LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | -| LocalDataFlow.cs:220:15:220:20 | access to local variable sink33 | LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | -| LocalDataFlow.cs:221:13:221:63 | SSA def(sink48) | LocalDataFlow.cs:222:15:222:20 | access to local variable sink48 | -| LocalDataFlow.cs:221:22:221:27 | [post] access to local variable sink33 | LocalDataFlow.cs:231:40:231:45 | access to local variable sink33 | -| LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | LocalDataFlow.cs:231:40:231:45 | access to local variable sink33 | -| LocalDataFlow.cs:221:22:221:63 | call to method Split | LocalDataFlow.cs:221:13:221:63 | SSA def(sink48) | -| LocalDataFlow.cs:225:9:225:127 | SSA def(nonSink0) | LocalDataFlow.cs:226:15:226:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:225:20:225:127 | (...) ... | LocalDataFlow.cs:225:9:225:127 | SSA def(nonSink0) | -| LocalDataFlow.cs:225:28:225:119 | call to method Insert | LocalDataFlow.cs:225:28:225:127 | [library code] call to method Clone | -| LocalDataFlow.cs:225:28:225:127 | [library code] call to method Clone | LocalDataFlow.cs:225:28:225:127 | call to method Clone | -| LocalDataFlow.cs:225:28:225:127 | call to method Clone | LocalDataFlow.cs:225:20:225:127 | (...) ... | -| LocalDataFlow.cs:226:15:226:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | -| LocalDataFlow.cs:226:15:226:22 | access to local variable nonSink0 | LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | -| LocalDataFlow.cs:227:13:227:68 | SSA def(nonSink15) | LocalDataFlow.cs:228:15:228:23 | access to local variable nonSink15 | -| LocalDataFlow.cs:227:25:227:32 | [post] access to local variable nonSink0 | LocalDataFlow.cs:240:43:240:50 | access to local variable nonSink0 | -| LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | LocalDataFlow.cs:240:43:240:50 | access to local variable nonSink0 | -| LocalDataFlow.cs:227:25:227:68 | call to method Split | LocalDataFlow.cs:227:13:227:68 | SSA def(nonSink15) | -| LocalDataFlow.cs:231:13:231:46 | SSA def(sink34) | LocalDataFlow.cs:232:15:232:20 | access to local variable sink34 | -| LocalDataFlow.cs:231:22:231:46 | object creation of type StringBuilder | LocalDataFlow.cs:231:13:231:46 | SSA def(sink34) | -| LocalDataFlow.cs:232:15:232:20 | [post] access to local variable sink34 | LocalDataFlow.cs:233:22:233:27 | access to local variable sink34 | -| LocalDataFlow.cs:232:15:232:20 | access to local variable sink34 | LocalDataFlow.cs:233:22:233:27 | access to local variable sink34 | -| LocalDataFlow.cs:233:13:233:38 | SSA def(sink35) | LocalDataFlow.cs:234:15:234:20 | access to local variable sink35 | -| LocalDataFlow.cs:233:22:233:38 | call to method ToString | LocalDataFlow.cs:233:13:233:38 | SSA def(sink35) | -| LocalDataFlow.cs:234:15:234:20 | [post] access to local variable sink35 | LocalDataFlow.cs:236:27:236:32 | access to local variable sink35 | -| LocalDataFlow.cs:234:15:234:20 | access to local variable sink35 | LocalDataFlow.cs:236:27:236:32 | access to local variable sink35 | -| LocalDataFlow.cs:235:13:235:42 | SSA def(sink36) | LocalDataFlow.cs:236:9:236:14 | access to local variable sink36 | -| LocalDataFlow.cs:235:22:235:42 | object creation of type StringBuilder | LocalDataFlow.cs:235:13:235:42 | SSA def(sink36) | -| LocalDataFlow.cs:236:9:236:14 | [post] access to local variable sink36 | LocalDataFlow.cs:237:15:237:20 | access to local variable sink36 | -| LocalDataFlow.cs:236:9:236:14 | access to local variable sink36 | LocalDataFlow.cs:237:15:237:20 | access to local variable sink36 | -| LocalDataFlow.cs:240:13:240:51 | SSA def(nonSink10) | LocalDataFlow.cs:241:15:241:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:240:25:240:51 | object creation of type StringBuilder | LocalDataFlow.cs:240:13:240:51 | SSA def(nonSink10) | -| LocalDataFlow.cs:241:15:241:23 | [post] access to local variable nonSink10 | LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | -| LocalDataFlow.cs:241:15:241:23 | access to local variable nonSink10 | LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | -| LocalDataFlow.cs:242:9:242:39 | SSA def(nonSink0) | LocalDataFlow.cs:243:15:243:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:242:20:242:28 | [post] access to local variable nonSink10 | LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:242:20:242:39 | call to method ToString | LocalDataFlow.cs:242:9:242:39 | SSA def(nonSink0) | -| LocalDataFlow.cs:243:15:243:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:244:30:244:37 | access to local variable nonSink0 | -| LocalDataFlow.cs:243:15:243:22 | access to local variable nonSink0 | LocalDataFlow.cs:244:30:244:37 | access to local variable nonSink0 | -| LocalDataFlow.cs:244:9:244:17 | [post] access to local variable nonSink10 | LocalDataFlow.cs:245:15:245:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | LocalDataFlow.cs:245:15:245:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:248:13:248:52 | SSA def(taintedDataContract) | LocalDataFlow.cs:249:22:249:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:248:13:248:52 | SSA qualifier def(taintedDataContract.AList) | LocalDataFlow.cs:251:22:251:46 | access to property AList | -| LocalDataFlow.cs:248:35:248:52 | object creation of type DataContract | LocalDataFlow.cs:248:13:248:52 | SSA def(taintedDataContract) | -| LocalDataFlow.cs:249:13:249:48 | SSA def(sink53) | LocalDataFlow.cs:250:15:250:20 | access to local variable sink53 | -| LocalDataFlow.cs:249:22:249:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:249:22:249:40 | access to local variable taintedDataContract | LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:249:22:249:48 | access to property AString | LocalDataFlow.cs:249:13:249:48 | SSA def(sink53) | -| LocalDataFlow.cs:251:13:251:57 | SSA def(sink54) | LocalDataFlow.cs:252:15:252:20 | access to local variable sink54 | -| LocalDataFlow.cs:251:22:251:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:258:20:258:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | LocalDataFlow.cs:258:20:258:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:251:22:251:46 | [post] access to property AList | LocalDataFlow.cs:260:20:260:44 | access to property AList | -| LocalDataFlow.cs:251:22:251:46 | access to property AList | LocalDataFlow.cs:260:20:260:44 | access to property AList | -| LocalDataFlow.cs:251:22:251:57 | access to property AString | LocalDataFlow.cs:251:13:251:57 | SSA def(sink54) | -| LocalDataFlow.cs:255:13:255:55 | SSA def(nonTaintedDataContract) | LocalDataFlow.cs:256:20:256:41 | access to local variable nonTaintedDataContract | -| LocalDataFlow.cs:255:38:255:55 | object creation of type DataContract | LocalDataFlow.cs:255:13:255:55 | SSA def(nonTaintedDataContract) | -| LocalDataFlow.cs:256:9:256:49 | SSA def(nonSink0) | LocalDataFlow.cs:257:15:257:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:256:20:256:49 | access to property AString | LocalDataFlow.cs:256:9:256:49 | SSA def(nonSink0) | -| LocalDataFlow.cs:258:9:258:44 | SSA def(nonSink2) | LocalDataFlow.cs:259:15:259:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:258:20:258:38 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:260:20:260:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:258:20:258:38 | access to local variable taintedDataContract | LocalDataFlow.cs:260:20:260:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:258:20:258:44 | access to property AnInt | LocalDataFlow.cs:258:9:258:44 | SSA def(nonSink2) | -| LocalDataFlow.cs:260:9:260:53 | SSA def(nonSink2) | LocalDataFlow.cs:261:15:261:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:260:20:260:53 | access to property AnInt | LocalDataFlow.cs:260:9:260:53 | SSA def(nonSink2) | -| LocalDataFlow.cs:264:17:264:37 | SSA def(taintedTextBox) | LocalDataFlow.cs:265:22:265:35 | access to local variable taintedTextBox | -| LocalDataFlow.cs:264:34:264:37 | null | LocalDataFlow.cs:264:17:264:37 | SSA def(taintedTextBox) | -| LocalDataFlow.cs:265:13:265:40 | SSA def(sink60) | LocalDataFlow.cs:266:15:266:20 | access to local variable sink60 | -| LocalDataFlow.cs:265:22:265:40 | access to property Text | LocalDataFlow.cs:265:13:265:40 | SSA def(sink60) | -| LocalDataFlow.cs:269:17:269:40 | SSA def(nonTaintedTextBox) | LocalDataFlow.cs:270:20:270:36 | access to local variable nonTaintedTextBox | -| LocalDataFlow.cs:269:37:269:40 | null | LocalDataFlow.cs:269:17:269:40 | SSA def(nonTaintedTextBox) | -| LocalDataFlow.cs:270:9:270:41 | SSA def(nonSink0) | LocalDataFlow.cs:271:15:271:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:270:20:270:41 | access to property Text | LocalDataFlow.cs:270:9:270:41 | SSA def(nonSink0) | -| LocalDataFlow.cs:274:13:274:51 | SSA def(sink67) | LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | -| LocalDataFlow.cs:274:22:274:51 | [library code] call to method Run | LocalDataFlow.cs:274:22:274:51 | call to method Run | -| LocalDataFlow.cs:274:22:274:51 | call to method Run | LocalDataFlow.cs:274:13:274:51 | SSA def(sink67) | -| LocalDataFlow.cs:274:31:274:50 | [output] (...) => ... | LocalDataFlow.cs:274:22:274:51 | [library code] call to method Run | -| LocalDataFlow.cs:275:15:275:20 | [post] access to local variable sink67 | LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | -| LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | -| LocalDataFlow.cs:276:13:276:33 | SSA def(sink68) | LocalDataFlow.cs:277:15:277:20 | access to local variable sink68 | -| LocalDataFlow.cs:276:22:276:33 | await ... | LocalDataFlow.cs:276:13:276:33 | SSA def(sink68) | -| LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | LocalDataFlow.cs:276:22:276:33 | await ... | -| LocalDataFlow.cs:280:13:280:42 | SSA def(nonSink21) | LocalDataFlow.cs:281:15:281:23 | access to local variable nonSink21 | -| LocalDataFlow.cs:280:25:280:42 | [library code] call to method Run | LocalDataFlow.cs:280:25:280:42 | call to method Run | -| LocalDataFlow.cs:280:25:280:42 | call to method Run | LocalDataFlow.cs:280:13:280:42 | SSA def(nonSink21) | -| LocalDataFlow.cs:280:34:280:41 | [output] (...) => ... | LocalDataFlow.cs:280:25:280:42 | [library code] call to method Run | -| LocalDataFlow.cs:281:15:281:23 | [post] access to local variable nonSink21 | LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | -| LocalDataFlow.cs:281:15:281:23 | access to local variable nonSink21 | LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | -| LocalDataFlow.cs:282:9:282:34 | SSA def(nonSink0) | LocalDataFlow.cs:283:15:283:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:282:20:282:34 | await ... | LocalDataFlow.cs:282:9:282:34 | SSA def(nonSink0) | -| LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | LocalDataFlow.cs:282:20:282:34 | await ... | -| LocalDataFlow.cs:283:15:283:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:290:28:290:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:283:15:283:22 | access to local variable nonSink0 | LocalDataFlow.cs:290:28:290:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:286:13:286:36 | SSA def(sink69) | LocalDataFlow.cs:287:15:287:20 | access to local variable sink69 | -| LocalDataFlow.cs:286:22:286:36 | $"..." | LocalDataFlow.cs:286:13:286:36 | SSA def(sink69) | -| LocalDataFlow.cs:290:9:290:37 | SSA def(nonSink0) | LocalDataFlow.cs:291:15:291:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:290:20:290:37 | $"..." | LocalDataFlow.cs:290:9:290:37 | SSA def(nonSink0) | -| LocalDataFlow.cs:291:15:291:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:298:31:298:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:291:15:291:22 | access to local variable nonSink0 | LocalDataFlow.cs:298:31:298:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:294:13:294:34 | SSA def(sink70) | LocalDataFlow.cs:295:15:295:20 | access to local variable sink70 | -| LocalDataFlow.cs:294:22:294:34 | ... = ... | LocalDataFlow.cs:294:13:294:34 | SSA def(sink70) | -| LocalDataFlow.cs:294:22:294:34 | SSA def(sink0) | LocalDataFlow.cs:326:34:326:38 | access to local variable sink0 | -| LocalDataFlow.cs:294:22:294:34 | SSA def(sink0) | LocalDataFlow.cs:327:22:327:26 | access to local variable sink0 | -| LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | LocalDataFlow.cs:294:22:294:34 | ... = ... | -| LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | LocalDataFlow.cs:294:22:294:34 | SSA def(sink0) | -| LocalDataFlow.cs:295:15:295:20 | [post] access to local variable sink70 | LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | -| LocalDataFlow.cs:295:15:295:20 | access to local variable sink70 | LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | -| LocalDataFlow.cs:298:9:298:38 | SSA def(nonSink0) | LocalDataFlow.cs:299:15:299:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:298:20:298:38 | ... = ... | LocalDataFlow.cs:298:9:298:38 | SSA def(nonSink0) | -| LocalDataFlow.cs:298:31:298:38 | access to local variable nonSink0 | LocalDataFlow.cs:298:20:298:38 | ... = ... | -| LocalDataFlow.cs:299:15:299:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | -| LocalDataFlow.cs:299:15:299:22 | access to local variable nonSink0 | LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | -| LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | LocalDataFlow.cs:302:23:302:35 | SSA def(sink71) | -| LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | LocalDataFlow.cs:310:17:310:22 | access to local variable sink70 | -| LocalDataFlow.cs:302:23:302:35 | SSA def(sink71) | LocalDataFlow.cs:303:19:303:24 | access to local variable sink71 | -| LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | LocalDataFlow.cs:306:25:306:40 | SSA def(nonSink16) | -| LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | LocalDataFlow.cs:318:17:318:24 | access to local variable nonSink0 | -| LocalDataFlow.cs:306:25:306:40 | SSA def(nonSink16) | LocalDataFlow.cs:307:19:307:27 | access to local variable nonSink16 | -| LocalDataFlow.cs:310:17:310:22 | access to local variable sink70 | LocalDataFlow.cs:312:18:312:30 | SSA def(sink72) | -| LocalDataFlow.cs:312:18:312:30 | SSA def(sink72) | LocalDataFlow.cs:313:23:313:28 | access to local variable sink72 | -| LocalDataFlow.cs:318:17:318:24 | access to local variable nonSink0 | LocalDataFlow.cs:320:18:320:33 | SSA def(nonSink17) | -| LocalDataFlow.cs:318:17:318:24 | access to local variable nonSink0 | LocalDataFlow.cs:326:22:326:29 | access to local variable nonSink0 | -| LocalDataFlow.cs:320:18:320:33 | SSA def(nonSink17) | LocalDataFlow.cs:321:23:321:31 | access to local variable nonSink17 | -| LocalDataFlow.cs:326:13:326:38 | SSA def(sink73) | LocalDataFlow.cs:328:15:328:20 | access to local variable sink73 | -| LocalDataFlow.cs:326:22:326:29 | access to local variable nonSink0 | LocalDataFlow.cs:326:22:326:38 | ... ?? ... | -| LocalDataFlow.cs:326:22:326:29 | access to local variable nonSink0 | LocalDataFlow.cs:327:31:327:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:326:22:326:38 | ... ?? ... | LocalDataFlow.cs:326:13:326:38 | SSA def(sink73) | -| LocalDataFlow.cs:326:34:326:38 | access to local variable sink0 | LocalDataFlow.cs:326:22:326:38 | ... ?? ... | -| LocalDataFlow.cs:326:34:326:38 | access to local variable sink0 | LocalDataFlow.cs:327:22:327:26 | access to local variable sink0 | -| LocalDataFlow.cs:327:13:327:38 | SSA def(sink74) | LocalDataFlow.cs:329:15:329:20 | access to local variable sink74 | -| LocalDataFlow.cs:327:22:327:26 | access to local variable sink0 | LocalDataFlow.cs:327:22:327:38 | ... ?? ... | -| LocalDataFlow.cs:327:22:327:38 | ... ?? ... | LocalDataFlow.cs:327:13:327:38 | SSA def(sink74) | -| LocalDataFlow.cs:327:31:327:38 | access to local variable nonSink0 | LocalDataFlow.cs:327:22:327:38 | ... ?? ... | -| LocalDataFlow.cs:347:28:347:30 | this | LocalDataFlow.cs:347:41:347:45 | this access | -| LocalDataFlow.cs:347:50:347:52 | this | LocalDataFlow.cs:347:56:347:60 | this access | -| LocalDataFlow.cs:347:50:347:52 | value | LocalDataFlow.cs:347:64:347:68 | access to parameter value | -| LocalDataFlow.cs:353:41:353:47 | tainted | LocalDataFlow.cs:355:15:355:21 | access to parameter tainted | -| LocalDataFlow.cs:358:44:358:53 | nonTainted | LocalDataFlow.cs:360:15:360:24 | access to parameter nonTainted | -| LocalDataFlow.cs:363:44:363:44 | x | LocalDataFlow.cs:366:21:366:21 | access to parameter x | -| LocalDataFlow.cs:363:67:363:68 | os | LocalDataFlow.cs:369:32:369:33 | access to parameter os | -| LocalDataFlow.cs:366:21:366:21 | access to parameter x | LocalDataFlow.cs:366:16:366:21 | ... = ... | -| LocalDataFlow.cs:369:32:369:33 | access to parameter os | LocalDataFlow.cs:369:26:369:33 | ... = ... | -| LocalDataFlow.cs:374:41:374:44 | args | LocalDataFlow.cs:376:29:376:32 | access to parameter args | -| LocalDataFlow.cs:376:29:376:32 | [post] access to parameter args | LocalDataFlow.cs:377:27:377:30 | access to parameter args | -| LocalDataFlow.cs:376:29:376:32 | access to parameter args | LocalDataFlow.cs:377:27:377:30 | access to parameter args | +| LocalDataFlow.cs:48:24:48:24 | b | LocalDataFlow.cs:84:21:84:21 | access to parameter b | +| LocalDataFlow.cs:51:13:51:34 | SSA def(sink0) | LocalDataFlow.cs:52:15:52:19 | access to local variable sink0 | +| LocalDataFlow.cs:51:21:51:34 | "taint source" | LocalDataFlow.cs:51:13:51:34 | SSA def(sink0) | +| LocalDataFlow.cs:52:15:52:19 | [post] access to local variable sink0 | LocalDataFlow.cs:60:18:60:22 | access to local variable sink0 | +| LocalDataFlow.cs:52:15:52:19 | access to local variable sink0 | LocalDataFlow.cs:60:18:60:22 | access to local variable sink0 | +| LocalDataFlow.cs:55:13:55:25 | SSA def(nonSink0) | LocalDataFlow.cs:56:15:56:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:55:24:55:25 | "" | LocalDataFlow.cs:55:13:55:25 | SSA def(nonSink0) | +| LocalDataFlow.cs:56:15:56:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:64:9:64:16 | access to local variable nonSink0 | +| LocalDataFlow.cs:56:15:56:22 | access to local variable nonSink0 | LocalDataFlow.cs:64:9:64:16 | access to local variable nonSink0 | +| LocalDataFlow.cs:59:13:59:25 | SSA def(sink1) | LocalDataFlow.cs:60:9:60:13 | access to local variable sink1 | +| LocalDataFlow.cs:59:21:59:25 | "abc" | LocalDataFlow.cs:59:13:59:25 | SSA def(sink1) | +| LocalDataFlow.cs:60:9:60:22 | ... + ... | LocalDataFlow.cs:60:9:60:22 | SSA def(sink1) | +| LocalDataFlow.cs:60:9:60:22 | SSA def(sink1) | LocalDataFlow.cs:61:15:61:19 | access to local variable sink1 | +| LocalDataFlow.cs:60:18:60:22 | access to local variable sink0 | LocalDataFlow.cs:168:20:168:24 | access to local variable sink0 | +| LocalDataFlow.cs:61:15:61:19 | [post] access to local variable sink1 | LocalDataFlow.cs:68:21:68:25 | access to local variable sink1 | +| LocalDataFlow.cs:61:15:61:19 | access to local variable sink1 | LocalDataFlow.cs:68:21:68:25 | access to local variable sink1 | +| LocalDataFlow.cs:64:9:64:25 | ... + ... | LocalDataFlow.cs:64:9:64:25 | SSA def(nonSink0) | +| LocalDataFlow.cs:64:9:64:25 | SSA def(nonSink0) | LocalDataFlow.cs:65:15:65:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:65:15:65:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:72:20:72:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:65:15:65:22 | access to local variable nonSink0 | LocalDataFlow.cs:72:20:72:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:68:13:68:32 | SSA def(sink5) | LocalDataFlow.cs:69:15:69:19 | access to local variable sink5 | +| LocalDataFlow.cs:68:21:68:25 | access to local variable sink1 | LocalDataFlow.cs:168:33:168:37 | access to local variable sink1 | +| LocalDataFlow.cs:68:21:68:32 | ... + ... | LocalDataFlow.cs:68:13:68:32 | SSA def(sink5) | +| LocalDataFlow.cs:69:15:69:19 | [post] access to local variable sink5 | LocalDataFlow.cs:76:22:76:26 | access to local variable sink5 | +| LocalDataFlow.cs:69:15:69:19 | access to local variable sink5 | LocalDataFlow.cs:76:22:76:26 | access to local variable sink5 | +| LocalDataFlow.cs:72:9:72:36 | SSA def(nonSink0) | LocalDataFlow.cs:73:15:73:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:72:20:72:36 | ... + ... | LocalDataFlow.cs:72:9:72:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:73:15:73:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:80:21:80:28 | access to local variable nonSink0 | +| LocalDataFlow.cs:73:15:73:22 | access to local variable nonSink0 | LocalDataFlow.cs:80:21:80:28 | access to local variable nonSink0 | +| LocalDataFlow.cs:76:13:76:27 | SSA def(sink6) | LocalDataFlow.cs:77:15:77:19 | access to local variable sink6 | +| LocalDataFlow.cs:76:22:76:26 | access to local variable sink5 | LocalDataFlow.cs:76:13:76:27 | SSA def(sink6) | +| LocalDataFlow.cs:77:15:77:19 | [post] access to local variable sink6 | LocalDataFlow.cs:84:31:84:35 | [b (line 48): false] access to local variable sink6 | +| LocalDataFlow.cs:77:15:77:19 | access to local variable sink6 | LocalDataFlow.cs:84:31:84:35 | [b (line 48): false] access to local variable sink6 | +| LocalDataFlow.cs:80:9:80:29 | SSA def(nonSink0) | LocalDataFlow.cs:81:15:81:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:80:21:80:28 | access to local variable nonSink0 | LocalDataFlow.cs:80:9:80:29 | SSA def(nonSink0) | +| LocalDataFlow.cs:84:13:84:35 | [b (line 48): false] SSA def(sink7) | LocalDataFlow.cs:85:15:85:19 | [b (line 48): false] access to local variable sink7 | +| LocalDataFlow.cs:84:13:84:35 | [b (line 48): true] SSA def(sink7) | LocalDataFlow.cs:85:15:85:19 | [b (line 48): true] access to local variable sink7 | +| LocalDataFlow.cs:84:21:84:21 | access to parameter b | LocalDataFlow.cs:88:20:88:20 | [b (line 48): false] access to parameter b | +| LocalDataFlow.cs:84:21:84:21 | access to parameter b | LocalDataFlow.cs:88:20:88:20 | [b (line 48): true] access to parameter b | +| LocalDataFlow.cs:84:21:84:35 | ... ? ... : ... | LocalDataFlow.cs:84:13:84:35 | [b (line 48): false] SSA def(sink7) | +| LocalDataFlow.cs:84:21:84:35 | ... ? ... : ... | LocalDataFlow.cs:84:13:84:35 | [b (line 48): true] SSA def(sink7) | +| LocalDataFlow.cs:84:25:84:27 | [b (line 48): true] "a" | LocalDataFlow.cs:84:21:84:35 | ... ? ... : ... | +| LocalDataFlow.cs:84:31:84:35 | [b (line 48): false] access to local variable sink6 | LocalDataFlow.cs:84:21:84:35 | ... ? ... : ... | +| LocalDataFlow.cs:85:15:85:19 | [b (line 48): false] access to local variable sink7 | LocalDataFlow.cs:88:9:88:36 | SSA phi(sink7) | +| LocalDataFlow.cs:85:15:85:19 | [b (line 48): true] access to local variable sink7 | LocalDataFlow.cs:88:9:88:36 | SSA phi(sink7) | +| LocalDataFlow.cs:88:9:88:36 | SSA def(nonSink0) | LocalDataFlow.cs:89:15:89:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:88:9:88:36 | SSA phi(sink7) | LocalDataFlow.cs:92:29:92:33 | access to local variable sink7 | +| LocalDataFlow.cs:88:20:88:36 | [b (line 48): false] ... ? ... : ... | LocalDataFlow.cs:88:9:88:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:88:20:88:36 | [b (line 48): true] ... ? ... : ... | LocalDataFlow.cs:88:9:88:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:88:24:88:28 | "abc" | LocalDataFlow.cs:88:20:88:36 | [b (line 48): true] ... ? ... : ... | +| LocalDataFlow.cs:88:32:88:36 | "def" | LocalDataFlow.cs:88:20:88:36 | [b (line 48): false] ... ? ... : ... | +| LocalDataFlow.cs:89:15:89:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:96:32:96:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:89:15:89:22 | access to local variable nonSink0 | LocalDataFlow.cs:96:32:96:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:92:13:92:33 | SSA def(sink8) | LocalDataFlow.cs:93:15:93:19 | access to local variable sink8 | +| LocalDataFlow.cs:92:21:92:33 | (...) ... | LocalDataFlow.cs:92:13:92:33 | SSA def(sink8) | +| LocalDataFlow.cs:92:29:92:33 | access to local variable sink7 | LocalDataFlow.cs:92:21:92:33 | (...) ... | +| LocalDataFlow.cs:93:15:93:19 | [post] access to local variable sink8 | LocalDataFlow.cs:100:21:100:25 | access to local variable sink8 | +| LocalDataFlow.cs:93:15:93:19 | access to local variable sink8 | LocalDataFlow.cs:100:21:100:25 | access to local variable sink8 | +| LocalDataFlow.cs:96:13:96:39 | SSA def(nonSink3) | LocalDataFlow.cs:97:15:97:22 | access to local variable nonSink3 | +| LocalDataFlow.cs:96:24:96:39 | (...) ... | LocalDataFlow.cs:96:13:96:39 | SSA def(nonSink3) | +| LocalDataFlow.cs:96:32:96:39 | access to local variable nonSink0 | LocalDataFlow.cs:96:24:96:39 | (...) ... | +| LocalDataFlow.cs:96:32:96:39 | access to local variable nonSink0 | LocalDataFlow.cs:104:20:104:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:100:13:100:35 | SSA def(sink9) | LocalDataFlow.cs:101:15:101:19 | access to local variable sink9 | +| LocalDataFlow.cs:100:21:100:25 | access to local variable sink8 | LocalDataFlow.cs:100:21:100:35 | ... as ... | +| LocalDataFlow.cs:100:21:100:25 | access to local variable sink8 | LocalDataFlow.cs:164:22:164:26 | access to local variable sink8 | +| LocalDataFlow.cs:100:21:100:35 | ... as ... | LocalDataFlow.cs:100:13:100:35 | SSA def(sink9) | +| LocalDataFlow.cs:101:15:101:19 | [post] access to local variable sink9 | LocalDataFlow.cs:108:34:108:38 | access to local variable sink9 | +| LocalDataFlow.cs:101:15:101:19 | access to local variable sink9 | LocalDataFlow.cs:108:34:108:38 | access to local variable sink9 | +| LocalDataFlow.cs:104:9:104:37 | SSA def(nonSink3) | LocalDataFlow.cs:105:15:105:22 | access to local variable nonSink3 | +| LocalDataFlow.cs:104:20:104:27 | access to local variable nonSink0 | LocalDataFlow.cs:104:20:104:37 | ... as ... | +| LocalDataFlow.cs:104:20:104:27 | access to local variable nonSink0 | LocalDataFlow.cs:113:22:113:29 | access to local variable nonSink0 | +| LocalDataFlow.cs:104:20:104:37 | ... as ... | LocalDataFlow.cs:104:9:104:37 | SSA def(nonSink3) | +| LocalDataFlow.cs:105:15:105:22 | [post] access to local variable nonSink3 | LocalDataFlow.cs:170:33:170:40 | access to local variable nonSink3 | +| LocalDataFlow.cs:105:15:105:22 | access to local variable nonSink3 | LocalDataFlow.cs:170:33:170:40 | access to local variable nonSink3 | +| LocalDataFlow.cs:108:13:108:39 | SSA def(sink15) | LocalDataFlow.cs:109:15:109:20 | access to local variable sink15 | +| LocalDataFlow.cs:108:22:108:39 | call to method Parse | LocalDataFlow.cs:108:13:108:39 | SSA def(sink15) | +| LocalDataFlow.cs:108:34:108:38 | [post] access to local variable sink9 | LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | +| LocalDataFlow.cs:108:34:108:38 | access to local variable sink9 | LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | +| LocalDataFlow.cs:109:15:109:20 | access to local variable sink15 | LocalDataFlow.cs:160:22:160:27 | access to local variable sink15 | +| LocalDataFlow.cs:111:13:111:56 | SSA def(sink16) | LocalDataFlow.cs:112:15:112:20 | access to local variable sink16 | +| LocalDataFlow.cs:111:22:111:56 | call to method TryParse | LocalDataFlow.cs:111:13:111:56 | SSA def(sink16) | +| LocalDataFlow.cs:111:37:111:41 | [post] access to local variable sink9 | LocalDataFlow.cs:113:44:113:48 | access to local variable sink9 | +| LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | LocalDataFlow.cs:113:44:113:48 | access to local variable sink9 | +| LocalDataFlow.cs:113:13:113:49 | SSA def(sink17) | LocalDataFlow.cs:114:15:114:20 | access to local variable sink17 | +| LocalDataFlow.cs:113:22:113:29 | [post] access to local variable nonSink0 | LocalDataFlow.cs:115:36:115:43 | access to local variable nonSink0 | +| LocalDataFlow.cs:113:22:113:29 | access to local variable nonSink0 | LocalDataFlow.cs:115:36:115:43 | access to local variable nonSink0 | +| LocalDataFlow.cs:113:22:113:49 | call to method Replace | LocalDataFlow.cs:113:13:113:49 | SSA def(sink17) | +| LocalDataFlow.cs:113:44:113:48 | [post] access to local variable sink9 | LocalDataFlow.cs:115:46:115:50 | access to local variable sink9 | +| LocalDataFlow.cs:113:44:113:48 | access to local variable sink9 | LocalDataFlow.cs:115:46:115:50 | access to local variable sink9 | +| LocalDataFlow.cs:115:13:115:51 | SSA def(sink18) | LocalDataFlow.cs:116:15:116:20 | access to local variable sink18 | +| LocalDataFlow.cs:115:22:115:51 | call to method Format | LocalDataFlow.cs:115:13:115:51 | SSA def(sink18) | +| LocalDataFlow.cs:115:36:115:43 | [post] access to local variable nonSink0 | LocalDataFlow.cs:117:44:117:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:115:36:115:43 | access to local variable nonSink0 | LocalDataFlow.cs:117:44:117:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:115:46:115:50 | [post] access to local variable sink9 | LocalDataFlow.cs:119:33:119:37 | access to local variable sink9 | +| LocalDataFlow.cs:115:46:115:50 | access to local variable sink9 | LocalDataFlow.cs:119:33:119:37 | access to local variable sink9 | +| LocalDataFlow.cs:116:15:116:20 | [post] access to local variable sink18 | LocalDataFlow.cs:117:36:117:41 | access to local variable sink18 | +| LocalDataFlow.cs:116:15:116:20 | access to local variable sink18 | LocalDataFlow.cs:117:36:117:41 | access to local variable sink18 | +| LocalDataFlow.cs:117:13:117:52 | SSA def(sink19) | LocalDataFlow.cs:118:15:118:20 | access to local variable sink19 | +| LocalDataFlow.cs:117:22:117:52 | call to method Format | LocalDataFlow.cs:117:13:117:52 | SSA def(sink19) | +| LocalDataFlow.cs:117:44:117:51 | [post] access to local variable nonSink0 | LocalDataFlow.cs:136:32:136:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:117:44:117:51 | access to local variable nonSink0 | LocalDataFlow.cs:136:32:136:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:119:13:119:38 | SSA def(sink45) | LocalDataFlow.cs:120:15:120:20 | access to local variable sink45 | +| LocalDataFlow.cs:119:22:119:38 | call to method Parse | LocalDataFlow.cs:119:13:119:38 | SSA def(sink45) | +| LocalDataFlow.cs:119:33:119:37 | [post] access to local variable sink9 | LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | +| LocalDataFlow.cs:119:33:119:37 | access to local variable sink9 | LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | +| LocalDataFlow.cs:122:13:122:56 | SSA def(sink46) | LocalDataFlow.cs:123:15:123:20 | access to local variable sink46 | +| LocalDataFlow.cs:122:22:122:56 | call to method TryParse | LocalDataFlow.cs:122:13:122:56 | SSA def(sink46) | +| LocalDataFlow.cs:122:36:122:40 | [post] access to local variable sink9 | LocalDataFlow.cs:162:22:162:26 | access to local variable sink9 | +| LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | LocalDataFlow.cs:162:22:162:26 | access to local variable sink9 | +| LocalDataFlow.cs:123:15:123:20 | access to local variable sink46 | LocalDataFlow.cs:124:37:124:42 | access to local variable sink46 | +| LocalDataFlow.cs:124:13:124:43 | SSA def(sink47) | LocalDataFlow.cs:125:15:125:20 | access to local variable sink47 | +| LocalDataFlow.cs:124:22:124:43 | call to method ToByte | LocalDataFlow.cs:124:13:124:43 | SSA def(sink47) | +| LocalDataFlow.cs:125:15:125:20 | access to local variable sink47 | LocalDataFlow.cs:126:40:126:45 | access to local variable sink47 | +| LocalDataFlow.cs:126:13:126:46 | SSA def(sink49) | LocalDataFlow.cs:127:15:127:20 | access to local variable sink49 | +| LocalDataFlow.cs:126:22:126:46 | call to method Concat | LocalDataFlow.cs:126:13:126:46 | SSA def(sink49) | +| LocalDataFlow.cs:126:40:126:45 | access to local variable sink47 | LocalDataFlow.cs:126:40:126:45 | (...) ... | +| LocalDataFlow.cs:127:15:127:20 | [post] access to local variable sink49 | LocalDataFlow.cs:128:34:128:39 | access to local variable sink49 | +| LocalDataFlow.cs:127:15:127:20 | access to local variable sink49 | LocalDataFlow.cs:128:34:128:39 | access to local variable sink49 | +| LocalDataFlow.cs:128:13:128:40 | SSA def(sink50) | LocalDataFlow.cs:129:15:129:20 | access to local variable sink50 | +| LocalDataFlow.cs:128:22:128:40 | call to method Copy | LocalDataFlow.cs:128:13:128:40 | SSA def(sink50) | +| LocalDataFlow.cs:128:34:128:39 | access to local variable sink49 | LocalDataFlow.cs:128:22:128:40 | call to method Copy | +| LocalDataFlow.cs:129:15:129:20 | [post] access to local variable sink50 | LocalDataFlow.cs:130:59:130:64 | access to local variable sink50 | +| LocalDataFlow.cs:129:15:129:20 | access to local variable sink50 | LocalDataFlow.cs:130:59:130:64 | access to local variable sink50 | +| LocalDataFlow.cs:130:13:130:71 | SSA def(sink51) | LocalDataFlow.cs:131:15:131:20 | access to local variable sink51 | +| LocalDataFlow.cs:130:22:130:71 | call to method Join | LocalDataFlow.cs:130:13:130:71 | SSA def(sink51) | +| LocalDataFlow.cs:130:53:130:70 | { ..., ... } | LocalDataFlow.cs:130:40:130:70 | array creation of type String[] | +| LocalDataFlow.cs:131:15:131:20 | [post] access to local variable sink51 | LocalDataFlow.cs:132:35:132:40 | access to local variable sink51 | +| LocalDataFlow.cs:131:15:131:20 | access to local variable sink51 | LocalDataFlow.cs:132:35:132:40 | access to local variable sink51 | +| LocalDataFlow.cs:132:13:132:41 | SSA def(sink52) | LocalDataFlow.cs:133:15:133:20 | access to local variable sink52 | +| LocalDataFlow.cs:132:22:132:41 | call to method Insert | LocalDataFlow.cs:132:13:132:41 | SSA def(sink52) | +| LocalDataFlow.cs:136:9:136:40 | SSA def(nonSink2) | LocalDataFlow.cs:137:15:137:22 | access to local variable nonSink2 | +| LocalDataFlow.cs:136:20:136:40 | call to method Parse | LocalDataFlow.cs:136:9:136:40 | SSA def(nonSink2) | +| LocalDataFlow.cs:136:32:136:39 | [post] access to local variable nonSink0 | LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:136:32:136:39 | access to local variable nonSink0 | LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:138:13:138:61 | SSA def(nonSink7) | LocalDataFlow.cs:139:15:139:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:138:24:138:61 | call to method TryParse | LocalDataFlow.cs:138:13:138:61 | SSA def(nonSink7) | +| LocalDataFlow.cs:138:39:138:46 | [post] access to local variable nonSink0 | LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:140:9:140:50 | SSA def(nonSink0) | LocalDataFlow.cs:141:15:141:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:140:20:140:27 | [post] access to local variable nonSink0 | LocalDataFlow.cs:140:42:140:49 | access to local variable nonSink0 | +| LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink0 | LocalDataFlow.cs:140:42:140:49 | access to local variable nonSink0 | +| LocalDataFlow.cs:140:20:140:50 | call to method Replace | LocalDataFlow.cs:140:9:140:50 | SSA def(nonSink0) | +| LocalDataFlow.cs:141:15:141:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:142:34:142:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:141:15:141:22 | access to local variable nonSink0 | LocalDataFlow.cs:142:34:142:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:142:9:142:52 | SSA def(nonSink0) | LocalDataFlow.cs:143:15:143:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:142:20:142:52 | call to method Format | LocalDataFlow.cs:142:9:142:52 | SSA def(nonSink0) | +| LocalDataFlow.cs:142:34:142:41 | [post] access to local variable nonSink0 | LocalDataFlow.cs:142:44:142:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:142:34:142:41 | access to local variable nonSink0 | LocalDataFlow.cs:142:44:142:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:143:15:143:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:144:31:144:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:143:15:143:22 | access to local variable nonSink0 | LocalDataFlow.cs:144:31:144:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:144:9:144:39 | SSA def(nonSink7) | LocalDataFlow.cs:145:15:145:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:144:20:144:39 | call to method Parse | LocalDataFlow.cs:144:9:144:39 | SSA def(nonSink7) | +| LocalDataFlow.cs:144:31:144:38 | [post] access to local variable nonSink0 | LocalDataFlow.cs:146:34:146:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:144:31:144:38 | access to local variable nonSink0 | LocalDataFlow.cs:146:34:146:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:146:9:146:57 | SSA def(nonSink7) | LocalDataFlow.cs:147:15:147:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:146:20:146:57 | call to method TryParse | LocalDataFlow.cs:146:9:146:57 | SSA def(nonSink7) | +| LocalDataFlow.cs:147:15:147:22 | access to local variable nonSink7 | LocalDataFlow.cs:148:40:148:47 | access to local variable nonSink7 | +| LocalDataFlow.cs:148:13:148:48 | SSA def(nonSink14) | LocalDataFlow.cs:149:15:149:23 | access to local variable nonSink14 | +| LocalDataFlow.cs:148:25:148:48 | call to method ToByte | LocalDataFlow.cs:148:13:148:48 | SSA def(nonSink14) | +| LocalDataFlow.cs:148:40:148:47 | access to local variable nonSink7 | LocalDataFlow.cs:150:38:150:45 | access to local variable nonSink7 | +| LocalDataFlow.cs:150:9:150:46 | SSA def(nonSink0) | LocalDataFlow.cs:151:15:151:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:150:20:150:46 | call to method Concat | LocalDataFlow.cs:150:9:150:46 | SSA def(nonSink0) | +| LocalDataFlow.cs:150:38:150:45 | access to local variable nonSink7 | LocalDataFlow.cs:150:38:150:45 | (...) ... | +| LocalDataFlow.cs:151:15:151:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:152:32:152:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:151:15:151:22 | access to local variable nonSink0 | LocalDataFlow.cs:152:32:152:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:152:9:152:40 | SSA def(nonSink0) | LocalDataFlow.cs:153:15:153:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:152:20:152:40 | call to method Copy | LocalDataFlow.cs:152:9:152:40 | SSA def(nonSink0) | +| LocalDataFlow.cs:152:32:152:39 | access to local variable nonSink0 | LocalDataFlow.cs:152:20:152:40 | call to method Copy | +| LocalDataFlow.cs:153:15:153:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:154:57:154:64 | access to local variable nonSink0 | +| LocalDataFlow.cs:153:15:153:22 | access to local variable nonSink0 | LocalDataFlow.cs:154:57:154:64 | access to local variable nonSink0 | +| LocalDataFlow.cs:154:9:154:71 | SSA def(nonSink0) | LocalDataFlow.cs:155:15:155:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:154:20:154:71 | call to method Join | LocalDataFlow.cs:154:9:154:71 | SSA def(nonSink0) | +| LocalDataFlow.cs:154:51:154:70 | { ..., ... } | LocalDataFlow.cs:154:38:154:70 | array creation of type String[] | +| LocalDataFlow.cs:155:15:155:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:156:33:156:40 | access to local variable nonSink0 | +| LocalDataFlow.cs:155:15:155:22 | access to local variable nonSink0 | LocalDataFlow.cs:156:33:156:40 | access to local variable nonSink0 | +| LocalDataFlow.cs:156:9:156:41 | SSA def(nonSink0) | LocalDataFlow.cs:157:15:157:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:156:20:156:41 | call to method Insert | LocalDataFlow.cs:156:9:156:41 | SSA def(nonSink0) | +| LocalDataFlow.cs:157:15:157:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:194:39:194:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:157:15:157:22 | access to local variable nonSink0 | LocalDataFlow.cs:194:39:194:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:160:13:160:32 | SSA def(sink20) | LocalDataFlow.cs:161:15:161:20 | access to local variable sink20 | +| LocalDataFlow.cs:160:22:160:32 | ... > ... | LocalDataFlow.cs:160:13:160:32 | SSA def(sink20) | +| LocalDataFlow.cs:161:15:161:20 | access to local variable sink20 | LocalDataFlow.cs:174:22:174:27 | access to local variable sink20 | +| LocalDataFlow.cs:162:13:162:40 | SSA def(sink21) | LocalDataFlow.cs:163:15:163:20 | access to local variable sink21 | +| LocalDataFlow.cs:162:22:162:26 | [post] access to local variable sink9 | LocalDataFlow.cs:182:37:182:41 | access to local variable sink9 | +| LocalDataFlow.cs:162:22:162:26 | access to local variable sink9 | LocalDataFlow.cs:182:37:182:41 | access to local variable sink9 | +| LocalDataFlow.cs:162:22:162:40 | call to method Equals | LocalDataFlow.cs:162:13:162:40 | SSA def(sink21) | +| LocalDataFlow.cs:164:13:164:45 | SSA def(sink22) | LocalDataFlow.cs:165:15:165:20 | access to local variable sink22 | +| LocalDataFlow.cs:164:22:164:26 | [post] access to local variable sink8 | LocalDataFlow.cs:170:20:170:24 | access to local variable sink8 | +| LocalDataFlow.cs:164:22:164:26 | access to local variable sink8 | LocalDataFlow.cs:170:20:170:24 | access to local variable sink8 | +| LocalDataFlow.cs:164:22:164:45 | call to method Equals | LocalDataFlow.cs:164:13:164:45 | SSA def(sink22) | +| LocalDataFlow.cs:164:43:164:44 | 41 | LocalDataFlow.cs:164:35:164:44 | (...) ... | +| LocalDataFlow.cs:168:9:168:38 | SSA def(nonSink7) | LocalDataFlow.cs:169:15:169:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:168:20:168:24 | [post] access to local variable sink0 | LocalDataFlow.cs:281:30:281:34 | access to local variable sink0 | +| LocalDataFlow.cs:168:20:168:24 | access to local variable sink0 | LocalDataFlow.cs:281:30:281:34 | access to local variable sink0 | +| LocalDataFlow.cs:168:20:168:38 | call to method Equals | LocalDataFlow.cs:168:9:168:38 | SSA def(nonSink7) | +| LocalDataFlow.cs:168:33:168:37 | [post] access to local variable sink1 | LocalDataFlow.cs:273:30:273:34 | access to local variable sink1 | +| LocalDataFlow.cs:168:33:168:37 | access to local variable sink1 | LocalDataFlow.cs:273:30:273:34 | access to local variable sink1 | +| LocalDataFlow.cs:170:9:170:41 | SSA def(nonSink7) | LocalDataFlow.cs:171:15:171:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:170:20:170:41 | call to method Equals | LocalDataFlow.cs:170:9:170:41 | SSA def(nonSink7) | +| LocalDataFlow.cs:171:15:171:22 | access to local variable nonSink7 | LocalDataFlow.cs:178:20:178:27 | access to local variable nonSink7 | +| LocalDataFlow.cs:174:13:174:36 | SSA def(sink25) | LocalDataFlow.cs:175:15:175:20 | access to local variable sink25 | +| LocalDataFlow.cs:174:22:174:36 | ... \|\| ... | LocalDataFlow.cs:174:13:174:36 | SSA def(sink25) | +| LocalDataFlow.cs:178:9:178:36 | SSA def(nonSink7) | LocalDataFlow.cs:179:15:179:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:178:20:178:36 | ... \|\| ... | LocalDataFlow.cs:178:9:178:36 | SSA def(nonSink7) | +| LocalDataFlow.cs:182:13:182:42 | SSA def(sink26) | LocalDataFlow.cs:183:15:183:20 | access to local variable sink26 | +| LocalDataFlow.cs:182:22:182:42 | object creation of type Uri | LocalDataFlow.cs:182:13:182:42 | SSA def(sink26) | +| LocalDataFlow.cs:183:15:183:20 | [post] access to local variable sink26 | LocalDataFlow.cs:184:22:184:27 | access to local variable sink26 | +| LocalDataFlow.cs:183:15:183:20 | access to local variable sink26 | LocalDataFlow.cs:184:22:184:27 | access to local variable sink26 | +| LocalDataFlow.cs:184:13:184:38 | SSA def(sink27) | LocalDataFlow.cs:185:15:185:20 | access to local variable sink27 | +| LocalDataFlow.cs:184:22:184:27 | [post] access to local variable sink26 | LocalDataFlow.cs:186:22:186:27 | access to local variable sink26 | +| LocalDataFlow.cs:184:22:184:27 | access to local variable sink26 | LocalDataFlow.cs:186:22:186:27 | access to local variable sink26 | +| LocalDataFlow.cs:184:22:184:38 | call to method ToString | LocalDataFlow.cs:184:13:184:38 | SSA def(sink27) | +| LocalDataFlow.cs:186:13:186:40 | SSA def(sink28) | LocalDataFlow.cs:187:15:187:20 | access to local variable sink28 | +| LocalDataFlow.cs:186:22:186:27 | [post] access to local variable sink26 | LocalDataFlow.cs:188:22:188:27 | access to local variable sink26 | +| LocalDataFlow.cs:186:22:186:27 | access to local variable sink26 | LocalDataFlow.cs:188:22:188:27 | access to local variable sink26 | +| LocalDataFlow.cs:186:22:186:40 | access to property PathAndQuery | LocalDataFlow.cs:186:13:186:40 | SSA def(sink28) | +| LocalDataFlow.cs:188:13:188:33 | SSA def(sink29) | LocalDataFlow.cs:189:15:189:20 | access to local variable sink29 | +| LocalDataFlow.cs:188:22:188:27 | [post] access to local variable sink26 | LocalDataFlow.cs:190:22:190:27 | access to local variable sink26 | +| LocalDataFlow.cs:188:22:188:27 | access to local variable sink26 | LocalDataFlow.cs:190:22:190:27 | access to local variable sink26 | +| LocalDataFlow.cs:188:22:188:33 | access to property Query | LocalDataFlow.cs:188:13:188:33 | SSA def(sink29) | +| LocalDataFlow.cs:190:13:190:42 | SSA def(sink30) | LocalDataFlow.cs:191:15:191:20 | access to local variable sink30 | +| LocalDataFlow.cs:190:22:190:42 | access to property OriginalString | LocalDataFlow.cs:190:13:190:42 | SSA def(sink30) | +| LocalDataFlow.cs:191:15:191:20 | [post] access to local variable sink30 | LocalDataFlow.cs:206:49:206:54 | access to local variable sink30 | +| LocalDataFlow.cs:191:15:191:20 | access to local variable sink30 | LocalDataFlow.cs:206:49:206:54 | access to local variable sink30 | +| LocalDataFlow.cs:194:13:194:47 | SSA def(nonSink8) | LocalDataFlow.cs:195:15:195:22 | access to local variable nonSink8 | +| LocalDataFlow.cs:194:24:194:47 | object creation of type Uri | LocalDataFlow.cs:194:13:194:47 | SSA def(nonSink8) | +| LocalDataFlow.cs:195:15:195:22 | [post] access to local variable nonSink8 | LocalDataFlow.cs:196:20:196:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:195:15:195:22 | access to local variable nonSink8 | LocalDataFlow.cs:196:20:196:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:196:9:196:38 | SSA def(nonSink0) | LocalDataFlow.cs:197:15:197:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:196:20:196:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:198:20:198:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:196:20:196:27 | access to local variable nonSink8 | LocalDataFlow.cs:198:20:198:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:196:20:196:38 | call to method ToString | LocalDataFlow.cs:196:9:196:38 | SSA def(nonSink0) | +| LocalDataFlow.cs:198:9:198:40 | SSA def(nonSink0) | LocalDataFlow.cs:199:15:199:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:198:20:198:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:200:20:200:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:198:20:198:27 | access to local variable nonSink8 | LocalDataFlow.cs:200:20:200:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:198:20:198:40 | access to property PathAndQuery | LocalDataFlow.cs:198:9:198:40 | SSA def(nonSink0) | +| LocalDataFlow.cs:200:9:200:33 | SSA def(nonSink0) | LocalDataFlow.cs:201:15:201:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:200:20:200:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:202:20:202:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:200:20:200:27 | access to local variable nonSink8 | LocalDataFlow.cs:202:20:202:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:200:20:200:33 | access to property Query | LocalDataFlow.cs:200:9:200:33 | SSA def(nonSink0) | +| LocalDataFlow.cs:202:9:202:42 | SSA def(nonSink0) | LocalDataFlow.cs:203:15:203:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:202:20:202:42 | access to property OriginalString | LocalDataFlow.cs:202:9:202:42 | SSA def(nonSink0) | +| LocalDataFlow.cs:203:15:203:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:212:51:212:58 | access to local variable nonSink0 | +| LocalDataFlow.cs:203:15:203:22 | access to local variable nonSink0 | LocalDataFlow.cs:212:51:212:58 | access to local variable nonSink0 | +| LocalDataFlow.cs:206:13:206:55 | SSA def(sink31) | LocalDataFlow.cs:207:15:207:20 | access to local variable sink31 | +| LocalDataFlow.cs:206:22:206:55 | object creation of type StringReader | LocalDataFlow.cs:206:13:206:55 | SSA def(sink31) | +| LocalDataFlow.cs:207:15:207:20 | [post] access to local variable sink31 | LocalDataFlow.cs:208:22:208:27 | access to local variable sink31 | +| LocalDataFlow.cs:207:15:207:20 | access to local variable sink31 | LocalDataFlow.cs:208:22:208:27 | access to local variable sink31 | +| LocalDataFlow.cs:208:13:208:39 | SSA def(sink32) | LocalDataFlow.cs:209:15:209:20 | access to local variable sink32 | +| LocalDataFlow.cs:208:22:208:39 | call to method ReadToEnd | LocalDataFlow.cs:208:13:208:39 | SSA def(sink32) | +| LocalDataFlow.cs:209:15:209:20 | [post] access to local variable sink32 | LocalDataFlow.cs:218:30:218:35 | access to local variable sink32 | +| LocalDataFlow.cs:209:15:209:20 | access to local variable sink32 | LocalDataFlow.cs:218:30:218:35 | access to local variable sink32 | +| LocalDataFlow.cs:212:13:212:59 | SSA def(nonSink9) | LocalDataFlow.cs:213:15:213:22 | access to local variable nonSink9 | +| LocalDataFlow.cs:212:24:212:59 | object creation of type StringReader | LocalDataFlow.cs:212:13:212:59 | SSA def(nonSink9) | +| LocalDataFlow.cs:213:15:213:22 | [post] access to local variable nonSink9 | LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink9 | +| LocalDataFlow.cs:213:15:213:22 | access to local variable nonSink9 | LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink9 | +| LocalDataFlow.cs:214:9:214:39 | SSA def(nonSink0) | LocalDataFlow.cs:215:15:215:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:214:20:214:39 | call to method ReadToEnd | LocalDataFlow.cs:214:9:214:39 | SSA def(nonSink0) | +| LocalDataFlow.cs:215:15:215:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:224:28:224:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:215:15:215:22 | access to local variable nonSink0 | LocalDataFlow.cs:224:28:224:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:218:13:218:127 | SSA def(sink33) | LocalDataFlow.cs:219:15:219:20 | access to local variable sink33 | +| LocalDataFlow.cs:218:22:218:127 | (...) ... | LocalDataFlow.cs:218:13:218:127 | SSA def(sink33) | +| LocalDataFlow.cs:218:30:218:119 | call to method Insert | LocalDataFlow.cs:218:30:218:127 | call to method Clone | +| LocalDataFlow.cs:218:30:218:127 | call to method Clone | LocalDataFlow.cs:218:22:218:127 | (...) ... | +| LocalDataFlow.cs:219:15:219:20 | [post] access to local variable sink33 | LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | +| LocalDataFlow.cs:219:15:219:20 | access to local variable sink33 | LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | +| LocalDataFlow.cs:220:13:220:52 | SSA def(sink48) | LocalDataFlow.cs:221:15:221:20 | access to local variable sink48 | +| LocalDataFlow.cs:220:22:220:27 | [post] access to local variable sink33 | LocalDataFlow.cs:230:40:230:45 | access to local variable sink33 | +| LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | LocalDataFlow.cs:230:40:230:45 | access to local variable sink33 | +| LocalDataFlow.cs:220:22:220:52 | call to method Remove | LocalDataFlow.cs:220:13:220:52 | SSA def(sink48) | +| LocalDataFlow.cs:224:9:224:127 | SSA def(nonSink0) | LocalDataFlow.cs:225:15:225:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:224:20:224:127 | (...) ... | LocalDataFlow.cs:224:9:224:127 | SSA def(nonSink0) | +| LocalDataFlow.cs:224:28:224:119 | call to method Insert | LocalDataFlow.cs:224:28:224:127 | call to method Clone | +| LocalDataFlow.cs:224:28:224:127 | call to method Clone | LocalDataFlow.cs:224:20:224:127 | (...) ... | +| LocalDataFlow.cs:225:15:225:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | +| LocalDataFlow.cs:225:15:225:22 | access to local variable nonSink0 | LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | +| LocalDataFlow.cs:226:13:226:57 | SSA def(nonSink15) | LocalDataFlow.cs:227:15:227:23 | access to local variable nonSink15 | +| LocalDataFlow.cs:226:25:226:32 | [post] access to local variable nonSink0 | LocalDataFlow.cs:239:43:239:50 | access to local variable nonSink0 | +| LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | LocalDataFlow.cs:239:43:239:50 | access to local variable nonSink0 | +| LocalDataFlow.cs:226:25:226:57 | call to method Remove | LocalDataFlow.cs:226:13:226:57 | SSA def(nonSink15) | +| LocalDataFlow.cs:230:13:230:46 | SSA def(sink34) | LocalDataFlow.cs:231:15:231:20 | access to local variable sink34 | +| LocalDataFlow.cs:230:22:230:46 | object creation of type StringBuilder | LocalDataFlow.cs:230:13:230:46 | SSA def(sink34) | +| LocalDataFlow.cs:231:15:231:20 | [post] access to local variable sink34 | LocalDataFlow.cs:232:22:232:27 | access to local variable sink34 | +| LocalDataFlow.cs:231:15:231:20 | access to local variable sink34 | LocalDataFlow.cs:232:22:232:27 | access to local variable sink34 | +| LocalDataFlow.cs:232:13:232:38 | SSA def(sink35) | LocalDataFlow.cs:233:15:233:20 | access to local variable sink35 | +| LocalDataFlow.cs:232:22:232:38 | call to method ToString | LocalDataFlow.cs:232:13:232:38 | SSA def(sink35) | +| LocalDataFlow.cs:233:15:233:20 | [post] access to local variable sink35 | LocalDataFlow.cs:235:27:235:32 | access to local variable sink35 | +| LocalDataFlow.cs:233:15:233:20 | access to local variable sink35 | LocalDataFlow.cs:235:27:235:32 | access to local variable sink35 | +| LocalDataFlow.cs:234:13:234:42 | SSA def(sink36) | LocalDataFlow.cs:235:9:235:14 | access to local variable sink36 | +| LocalDataFlow.cs:234:22:234:42 | object creation of type StringBuilder | LocalDataFlow.cs:234:13:234:42 | SSA def(sink36) | +| LocalDataFlow.cs:235:9:235:14 | [post] access to local variable sink36 | LocalDataFlow.cs:236:15:236:20 | access to local variable sink36 | +| LocalDataFlow.cs:235:9:235:14 | access to local variable sink36 | LocalDataFlow.cs:236:15:236:20 | access to local variable sink36 | +| LocalDataFlow.cs:239:13:239:51 | SSA def(nonSink10) | LocalDataFlow.cs:240:15:240:23 | access to local variable nonSink10 | +| LocalDataFlow.cs:239:25:239:51 | object creation of type StringBuilder | LocalDataFlow.cs:239:13:239:51 | SSA def(nonSink10) | +| LocalDataFlow.cs:240:15:240:23 | [post] access to local variable nonSink10 | LocalDataFlow.cs:241:20:241:28 | access to local variable nonSink10 | +| LocalDataFlow.cs:240:15:240:23 | access to local variable nonSink10 | LocalDataFlow.cs:241:20:241:28 | access to local variable nonSink10 | +| LocalDataFlow.cs:241:9:241:39 | SSA def(nonSink0) | LocalDataFlow.cs:242:15:242:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:241:20:241:28 | [post] access to local variable nonSink10 | LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | +| LocalDataFlow.cs:241:20:241:28 | access to local variable nonSink10 | LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | +| LocalDataFlow.cs:241:20:241:39 | call to method ToString | LocalDataFlow.cs:241:9:241:39 | SSA def(nonSink0) | +| LocalDataFlow.cs:242:15:242:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:243:30:243:37 | access to local variable nonSink0 | +| LocalDataFlow.cs:242:15:242:22 | access to local variable nonSink0 | LocalDataFlow.cs:243:30:243:37 | access to local variable nonSink0 | +| LocalDataFlow.cs:243:9:243:17 | [post] access to local variable nonSink10 | LocalDataFlow.cs:244:15:244:23 | access to local variable nonSink10 | +| LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | LocalDataFlow.cs:244:15:244:23 | access to local variable nonSink10 | +| LocalDataFlow.cs:247:13:247:52 | SSA def(taintedDataContract) | LocalDataFlow.cs:248:22:248:40 | access to local variable taintedDataContract | +| LocalDataFlow.cs:247:13:247:52 | SSA qualifier def(taintedDataContract.AList) | LocalDataFlow.cs:250:22:250:46 | access to property AList | +| LocalDataFlow.cs:247:35:247:52 | object creation of type DataContract | LocalDataFlow.cs:247:13:247:52 | SSA def(taintedDataContract) | +| LocalDataFlow.cs:248:13:248:48 | SSA def(sink53) | LocalDataFlow.cs:249:15:249:20 | access to local variable sink53 | +| LocalDataFlow.cs:248:22:248:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | +| LocalDataFlow.cs:248:22:248:40 | access to local variable taintedDataContract | LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | +| LocalDataFlow.cs:248:22:248:48 | access to property AString | LocalDataFlow.cs:248:13:248:48 | SSA def(sink53) | +| LocalDataFlow.cs:250:13:250:57 | SSA def(sink54) | LocalDataFlow.cs:251:15:251:20 | access to local variable sink54 | +| LocalDataFlow.cs:250:22:250:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:257:20:257:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | LocalDataFlow.cs:257:20:257:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:250:22:250:46 | [post] access to property AList | LocalDataFlow.cs:259:20:259:44 | access to property AList | +| LocalDataFlow.cs:250:22:250:46 | access to property AList | LocalDataFlow.cs:259:20:259:44 | access to property AList | +| LocalDataFlow.cs:250:22:250:57 | access to property AString | LocalDataFlow.cs:250:13:250:57 | SSA def(sink54) | +| LocalDataFlow.cs:254:13:254:55 | SSA def(nonTaintedDataContract) | LocalDataFlow.cs:255:20:255:41 | access to local variable nonTaintedDataContract | +| LocalDataFlow.cs:254:38:254:55 | object creation of type DataContract | LocalDataFlow.cs:254:13:254:55 | SSA def(nonTaintedDataContract) | +| LocalDataFlow.cs:255:9:255:49 | SSA def(nonSink0) | LocalDataFlow.cs:256:15:256:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:255:20:255:49 | access to property AString | LocalDataFlow.cs:255:9:255:49 | SSA def(nonSink0) | +| LocalDataFlow.cs:257:9:257:44 | SSA def(nonSink2) | LocalDataFlow.cs:258:15:258:22 | access to local variable nonSink2 | +| LocalDataFlow.cs:257:20:257:38 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:259:20:259:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:257:20:257:38 | access to local variable taintedDataContract | LocalDataFlow.cs:259:20:259:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:257:20:257:44 | access to property AnInt | LocalDataFlow.cs:257:9:257:44 | SSA def(nonSink2) | +| LocalDataFlow.cs:259:9:259:53 | SSA def(nonSink2) | LocalDataFlow.cs:260:15:260:22 | access to local variable nonSink2 | +| LocalDataFlow.cs:259:20:259:53 | access to property AnInt | LocalDataFlow.cs:259:9:259:53 | SSA def(nonSink2) | +| LocalDataFlow.cs:263:17:263:37 | SSA def(taintedTextBox) | LocalDataFlow.cs:264:22:264:35 | access to local variable taintedTextBox | +| LocalDataFlow.cs:263:34:263:37 | null | LocalDataFlow.cs:263:17:263:37 | SSA def(taintedTextBox) | +| LocalDataFlow.cs:264:13:264:40 | SSA def(sink60) | LocalDataFlow.cs:265:15:265:20 | access to local variable sink60 | +| LocalDataFlow.cs:264:22:264:40 | access to property Text | LocalDataFlow.cs:264:13:264:40 | SSA def(sink60) | +| LocalDataFlow.cs:268:17:268:40 | SSA def(nonTaintedTextBox) | LocalDataFlow.cs:269:20:269:36 | access to local variable nonTaintedTextBox | +| LocalDataFlow.cs:268:37:268:40 | null | LocalDataFlow.cs:268:17:268:40 | SSA def(nonTaintedTextBox) | +| LocalDataFlow.cs:269:9:269:41 | SSA def(nonSink0) | LocalDataFlow.cs:270:15:270:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:269:20:269:41 | access to property Text | LocalDataFlow.cs:269:9:269:41 | SSA def(nonSink0) | +| LocalDataFlow.cs:270:15:270:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:277:28:277:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:270:15:270:22 | access to local variable nonSink0 | LocalDataFlow.cs:277:28:277:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:273:13:273:36 | SSA def(sink69) | LocalDataFlow.cs:274:15:274:20 | access to local variable sink69 | +| LocalDataFlow.cs:273:22:273:36 | $"..." | LocalDataFlow.cs:273:13:273:36 | SSA def(sink69) | +| LocalDataFlow.cs:277:9:277:37 | SSA def(nonSink0) | LocalDataFlow.cs:278:15:278:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:277:20:277:37 | $"..." | LocalDataFlow.cs:277:9:277:37 | SSA def(nonSink0) | +| LocalDataFlow.cs:278:15:278:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:285:31:285:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:278:15:278:22 | access to local variable nonSink0 | LocalDataFlow.cs:285:31:285:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:281:13:281:34 | SSA def(sink70) | LocalDataFlow.cs:282:15:282:20 | access to local variable sink70 | +| LocalDataFlow.cs:281:22:281:34 | ... = ... | LocalDataFlow.cs:281:13:281:34 | SSA def(sink70) | +| LocalDataFlow.cs:281:22:281:34 | SSA def(sink0) | LocalDataFlow.cs:313:34:313:38 | access to local variable sink0 | +| LocalDataFlow.cs:281:22:281:34 | SSA def(sink0) | LocalDataFlow.cs:314:22:314:26 | access to local variable sink0 | +| LocalDataFlow.cs:281:30:281:34 | access to local variable sink0 | LocalDataFlow.cs:281:22:281:34 | ... = ... | +| LocalDataFlow.cs:281:30:281:34 | access to local variable sink0 | LocalDataFlow.cs:281:22:281:34 | SSA def(sink0) | +| LocalDataFlow.cs:282:15:282:20 | [post] access to local variable sink70 | LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | +| LocalDataFlow.cs:282:15:282:20 | access to local variable sink70 | LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | +| LocalDataFlow.cs:285:9:285:38 | SSA def(nonSink0) | LocalDataFlow.cs:286:15:286:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:285:20:285:38 | ... = ... | LocalDataFlow.cs:285:9:285:38 | SSA def(nonSink0) | +| LocalDataFlow.cs:285:31:285:38 | access to local variable nonSink0 | LocalDataFlow.cs:285:20:285:38 | ... = ... | +| LocalDataFlow.cs:286:15:286:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | +| LocalDataFlow.cs:286:15:286:22 | access to local variable nonSink0 | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | +| LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | LocalDataFlow.cs:289:23:289:35 | SSA def(sink71) | +| LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | LocalDataFlow.cs:297:17:297:22 | access to local variable sink70 | +| LocalDataFlow.cs:289:23:289:35 | SSA def(sink71) | LocalDataFlow.cs:290:19:290:24 | access to local variable sink71 | +| LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | LocalDataFlow.cs:293:25:293:40 | SSA def(nonSink16) | +| LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | +| LocalDataFlow.cs:293:25:293:40 | SSA def(nonSink16) | LocalDataFlow.cs:294:19:294:27 | access to local variable nonSink16 | +| LocalDataFlow.cs:297:17:297:22 | access to local variable sink70 | LocalDataFlow.cs:299:18:299:30 | SSA def(sink72) | +| LocalDataFlow.cs:299:18:299:30 | SSA def(sink72) | LocalDataFlow.cs:300:23:300:28 | access to local variable sink72 | +| LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | LocalDataFlow.cs:307:18:307:33 | SSA def(nonSink17) | +| LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | LocalDataFlow.cs:313:22:313:29 | access to local variable nonSink0 | +| LocalDataFlow.cs:307:18:307:33 | SSA def(nonSink17) | LocalDataFlow.cs:308:23:308:31 | access to local variable nonSink17 | +| LocalDataFlow.cs:313:13:313:38 | SSA def(sink73) | LocalDataFlow.cs:315:15:315:20 | access to local variable sink73 | +| LocalDataFlow.cs:313:22:313:29 | access to local variable nonSink0 | LocalDataFlow.cs:313:22:313:38 | ... ?? ... | +| LocalDataFlow.cs:313:22:313:29 | access to local variable nonSink0 | LocalDataFlow.cs:314:31:314:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:313:22:313:38 | ... ?? ... | LocalDataFlow.cs:313:13:313:38 | SSA def(sink73) | +| LocalDataFlow.cs:313:34:313:38 | access to local variable sink0 | LocalDataFlow.cs:313:22:313:38 | ... ?? ... | +| LocalDataFlow.cs:313:34:313:38 | access to local variable sink0 | LocalDataFlow.cs:314:22:314:26 | access to local variable sink0 | +| LocalDataFlow.cs:314:13:314:38 | SSA def(sink74) | LocalDataFlow.cs:316:15:316:20 | access to local variable sink74 | +| LocalDataFlow.cs:314:22:314:26 | access to local variable sink0 | LocalDataFlow.cs:314:22:314:38 | ... ?? ... | +| LocalDataFlow.cs:314:22:314:38 | ... ?? ... | LocalDataFlow.cs:314:13:314:38 | SSA def(sink74) | +| LocalDataFlow.cs:314:31:314:38 | access to local variable nonSink0 | LocalDataFlow.cs:314:22:314:38 | ... ?? ... | +| LocalDataFlow.cs:334:28:334:30 | this | LocalDataFlow.cs:334:41:334:45 | this access | +| LocalDataFlow.cs:334:50:334:52 | this | LocalDataFlow.cs:334:56:334:60 | this access | +| LocalDataFlow.cs:334:50:334:52 | value | LocalDataFlow.cs:334:64:334:68 | access to parameter value | +| LocalDataFlow.cs:340:41:340:47 | tainted | LocalDataFlow.cs:342:15:342:21 | access to parameter tainted | +| LocalDataFlow.cs:345:44:345:53 | nonTainted | LocalDataFlow.cs:347:15:347:24 | access to parameter nonTainted | +| LocalDataFlow.cs:350:44:350:44 | x | LocalDataFlow.cs:353:21:353:21 | access to parameter x | +| LocalDataFlow.cs:350:67:350:68 | os | LocalDataFlow.cs:356:33:356:34 | access to parameter os | +| LocalDataFlow.cs:353:21:353:21 | access to parameter x | LocalDataFlow.cs:353:16:353:21 | ... = ... | +| LocalDataFlow.cs:356:33:356:34 | access to parameter os | LocalDataFlow.cs:356:27:356:34 | ... = ... | +| LocalDataFlow.cs:361:41:361:44 | args | LocalDataFlow.cs:363:29:363:32 | access to parameter args | +| LocalDataFlow.cs:363:29:363:32 | [post] access to parameter args | LocalDataFlow.cs:364:27:364:30 | access to parameter args | +| LocalDataFlow.cs:363:29:363:32 | access to parameter args | LocalDataFlow.cs:364:27:364:30 | access to parameter args | | SSA.cs:5:17:5:17 | SSA entry def(this.S) | SSA.cs:67:9:67:14 | access to field S | | SSA.cs:5:17:5:17 | this | SSA.cs:67:9:67:12 | this access | | SSA.cs:5:26:5:32 | tainted | SSA.cs:8:24:8:30 | access to parameter tainted | @@ -785,8 +761,12 @@ | Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | Splitting.cs:52:9:52:9 | [b (line 46): true] access to local variable y | | Splitting.cs:51:17:51:36 | [b (line 46): false] array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): false] SSA def(y) | | Splitting.cs:51:17:51:36 | [b (line 46): true] array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | +| Splitting.cs:51:30:51:36 | [b (line 46): false] { ..., ... } | Splitting.cs:51:17:51:36 | [b (line 46): false] array creation of type String[] | +| Splitting.cs:51:30:51:36 | [b (line 46): true] { ..., ... } | Splitting.cs:51:17:51:36 | [b (line 46): true] array creation of type String[] | | Splitting.cs:52:9:52:9 | [b (line 46): false] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): false] access to local variable y | | Splitting.cs:52:9:52:9 | [b (line 46): true] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): true] access to local variable y | +| Splitting.cs:52:9:52:9 | [post] [b (line 46): false] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): false] access to local variable y | +| Splitting.cs:52:9:52:9 | [post] [b (line 46): true] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): true] access to local variable y | | Splitting.cs:53:9:53:20 | [b (line 46): false] SSA def(x) | Splitting.cs:54:17:54:17 | [b (line 46): false] access to local variable x | | Splitting.cs:53:9:53:20 | [b (line 46): true] SSA def(x) | Splitting.cs:54:17:54:17 | [b (line 46): true] access to local variable x | | Splitting.cs:53:13:53:20 | [b (line 46): false] ... + ... | Splitting.cs:53:9:53:20 | [b (line 46): false] SSA def(x) | diff --git a/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs b/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs index eea365281044..a5a1e34178fe 100644 --- a/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs @@ -5,7 +5,6 @@ using System.Collections.Specialized; using System.Linq; using System.Runtime.Serialization; -using System.Threading.Tasks; using System.Web; using System.Web.UI.WebControls; @@ -46,7 +45,7 @@ public sealed class DataMemberAttribute : Attribute { } /// public class LocalDataFlow { - public async void M(bool b) + public void M(bool b) { // Assignment, tainted var sink0 = "taint source"; @@ -128,7 +127,7 @@ public async void M(bool b) Check(sink49); var sink50 = String.Copy(sink49); Check(sink50); - var sink51 = String.Join(", ", "", sink50, ""); + var sink51 = String.Join(", ", new string[] { "", sink50, "" }); Check(sink51); var sink52 = "".Insert(0, sink51); Check(sink52); @@ -152,7 +151,7 @@ public async void M(bool b) Check(nonSink0); nonSink0 = String.Copy(nonSink0); Check(nonSink0); - nonSink0 = String.Join(", ", "", nonSink0, ""); + nonSink0 = String.Join(", ", new string[] { "", nonSink0, "" }); Check(nonSink0); nonSink0 = "".Insert(0, nonSink0); Check(nonSink0); @@ -218,13 +217,13 @@ public async void M(bool b) // Ad hoc tracking (System.String), tainted var sink33 = (string)sink32.Substring(0).ToLowerInvariant().ToUpper().Trim(' ').Replace("a", "b").Insert(0, "").Clone(); Check(sink33); - var sink48 = sink33.Normalize().Remove(4, 5).Split(' '); + var sink48 = sink33.Normalize().Remove(4, 5); Check(sink48); // Ad hoc tracking (System.String), not tainted nonSink0 = (string)nonSink0.Substring(0).ToLowerInvariant().ToUpper().Trim(' ').Replace("a", "b").Insert(0, "").Clone(); Check(nonSink0); - var nonSink15 = nonSink0.Normalize().Remove(4, 5).Split(' '); + var nonSink15 = nonSink0.Normalize().Remove(4, 5); Check(nonSink15); // Ad hoc tracking (System.Text.StringBuilder), tainted @@ -270,18 +269,6 @@ public async void M(bool b) nonSink0 = nonTaintedTextBox.Text; Check(nonSink0); - // async await, tainted - var sink67 = Task.Run(() => "taint source"); - Check(sink67); - var sink68 = await sink67; - Check(sink68); - - // async await, not tainted - var nonSink21 = Task.Run(() => ""); - Check(nonSink21); - nonSink0 = await nonSink21; - Check(nonSink0); - // Interpolated string, tainted var sink69 = $"test {sink1}"; Check(sink69); @@ -366,7 +353,7 @@ public void AssignmentFlow(IDisposable x, IEnumerable os) using (x1 = x) { } IEnumerable os2; - foreach(var o in os2 = os) { } + foreach (var o in os2 = os) { } } public static implicit operator LocalDataFlow(string[] args) => null; diff --git a/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected b/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected index e8a0153dc92b..30a274af50df 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected @@ -1,51 +1,49 @@ -| LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | -| LocalDataFlow.cs:62:15:62:19 | access to local variable sink1 | -| LocalDataFlow.cs:70:15:70:19 | access to local variable sink5 | -| LocalDataFlow.cs:78:15:78:19 | access to local variable sink6 | -| LocalDataFlow.cs:86:15:86:19 | [b (line 49): false] access to local variable sink7 | -| LocalDataFlow.cs:86:15:86:19 | [b (line 49): true] access to local variable sink7 | -| LocalDataFlow.cs:94:15:94:19 | access to local variable sink8 | -| LocalDataFlow.cs:102:15:102:19 | access to local variable sink9 | -| LocalDataFlow.cs:110:15:110:20 | access to local variable sink15 | -| LocalDataFlow.cs:113:15:113:20 | access to local variable sink16 | -| LocalDataFlow.cs:115:15:115:20 | access to local variable sink17 | -| LocalDataFlow.cs:117:15:117:20 | access to local variable sink18 | -| LocalDataFlow.cs:119:15:119:20 | access to local variable sink19 | -| LocalDataFlow.cs:121:15:121:20 | access to local variable sink45 | -| LocalDataFlow.cs:124:15:124:20 | access to local variable sink46 | -| LocalDataFlow.cs:126:15:126:20 | access to local variable sink47 | -| LocalDataFlow.cs:128:15:128:20 | access to local variable sink49 | -| LocalDataFlow.cs:130:15:130:20 | access to local variable sink50 | -| LocalDataFlow.cs:132:15:132:20 | access to local variable sink51 | -| LocalDataFlow.cs:134:15:134:20 | access to local variable sink52 | -| LocalDataFlow.cs:162:15:162:20 | access to local variable sink20 | -| LocalDataFlow.cs:164:15:164:20 | access to local variable sink21 | -| LocalDataFlow.cs:166:15:166:20 | access to local variable sink22 | -| LocalDataFlow.cs:176:15:176:20 | access to local variable sink25 | -| LocalDataFlow.cs:184:15:184:20 | access to local variable sink26 | -| LocalDataFlow.cs:186:15:186:20 | access to local variable sink27 | -| LocalDataFlow.cs:188:15:188:20 | access to local variable sink28 | -| LocalDataFlow.cs:190:15:190:20 | access to local variable sink29 | -| LocalDataFlow.cs:192:15:192:20 | access to local variable sink30 | -| LocalDataFlow.cs:208:15:208:20 | access to local variable sink31 | -| LocalDataFlow.cs:210:15:210:20 | access to local variable sink32 | -| LocalDataFlow.cs:220:15:220:20 | access to local variable sink33 | -| LocalDataFlow.cs:222:15:222:20 | access to local variable sink48 | -| LocalDataFlow.cs:232:15:232:20 | access to local variable sink34 | -| LocalDataFlow.cs:234:15:234:20 | access to local variable sink35 | -| LocalDataFlow.cs:237:15:237:20 | access to local variable sink36 | -| LocalDataFlow.cs:250:15:250:20 | access to local variable sink53 | -| LocalDataFlow.cs:252:15:252:20 | access to local variable sink54 | -| LocalDataFlow.cs:266:15:266:20 | access to local variable sink60 | -| LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | -| LocalDataFlow.cs:277:15:277:20 | access to local variable sink68 | -| LocalDataFlow.cs:287:15:287:20 | access to local variable sink69 | -| LocalDataFlow.cs:295:15:295:20 | access to local variable sink70 | -| LocalDataFlow.cs:303:19:303:24 | access to local variable sink71 | -| LocalDataFlow.cs:313:23:313:28 | access to local variable sink72 | -| LocalDataFlow.cs:328:15:328:20 | access to local variable sink73 | -| LocalDataFlow.cs:329:15:329:20 | access to local variable sink74 | -| LocalDataFlow.cs:355:15:355:21 | access to parameter tainted | +| LocalDataFlow.cs:52:15:52:19 | access to local variable sink0 | +| LocalDataFlow.cs:61:15:61:19 | access to local variable sink1 | +| LocalDataFlow.cs:69:15:69:19 | access to local variable sink5 | +| LocalDataFlow.cs:77:15:77:19 | access to local variable sink6 | +| LocalDataFlow.cs:85:15:85:19 | [b (line 48): false] access to local variable sink7 | +| LocalDataFlow.cs:85:15:85:19 | [b (line 48): true] access to local variable sink7 | +| LocalDataFlow.cs:93:15:93:19 | access to local variable sink8 | +| LocalDataFlow.cs:101:15:101:19 | access to local variable sink9 | +| LocalDataFlow.cs:109:15:109:20 | access to local variable sink15 | +| LocalDataFlow.cs:112:15:112:20 | access to local variable sink16 | +| LocalDataFlow.cs:114:15:114:20 | access to local variable sink17 | +| LocalDataFlow.cs:116:15:116:20 | access to local variable sink18 | +| LocalDataFlow.cs:118:15:118:20 | access to local variable sink19 | +| LocalDataFlow.cs:120:15:120:20 | access to local variable sink45 | +| LocalDataFlow.cs:123:15:123:20 | access to local variable sink46 | +| LocalDataFlow.cs:125:15:125:20 | access to local variable sink47 | +| LocalDataFlow.cs:127:15:127:20 | access to local variable sink49 | +| LocalDataFlow.cs:129:15:129:20 | access to local variable sink50 | +| LocalDataFlow.cs:131:15:131:20 | access to local variable sink51 | +| LocalDataFlow.cs:133:15:133:20 | access to local variable sink52 | +| LocalDataFlow.cs:161:15:161:20 | access to local variable sink20 | +| LocalDataFlow.cs:163:15:163:20 | access to local variable sink21 | +| LocalDataFlow.cs:165:15:165:20 | access to local variable sink22 | +| LocalDataFlow.cs:175:15:175:20 | access to local variable sink25 | +| LocalDataFlow.cs:183:15:183:20 | access to local variable sink26 | +| LocalDataFlow.cs:185:15:185:20 | access to local variable sink27 | +| LocalDataFlow.cs:187:15:187:20 | access to local variable sink28 | +| LocalDataFlow.cs:189:15:189:20 | access to local variable sink29 | +| LocalDataFlow.cs:191:15:191:20 | access to local variable sink30 | +| LocalDataFlow.cs:207:15:207:20 | access to local variable sink31 | +| LocalDataFlow.cs:209:15:209:20 | access to local variable sink32 | +| LocalDataFlow.cs:219:15:219:20 | access to local variable sink33 | +| LocalDataFlow.cs:221:15:221:20 | access to local variable sink48 | +| LocalDataFlow.cs:231:15:231:20 | access to local variable sink34 | +| LocalDataFlow.cs:233:15:233:20 | access to local variable sink35 | +| LocalDataFlow.cs:236:15:236:20 | access to local variable sink36 | +| LocalDataFlow.cs:249:15:249:20 | access to local variable sink53 | +| LocalDataFlow.cs:251:15:251:20 | access to local variable sink54 | +| LocalDataFlow.cs:265:15:265:20 | access to local variable sink60 | +| LocalDataFlow.cs:274:15:274:20 | access to local variable sink69 | +| LocalDataFlow.cs:282:15:282:20 | access to local variable sink70 | +| LocalDataFlow.cs:290:19:290:24 | access to local variable sink71 | +| LocalDataFlow.cs:300:23:300:28 | access to local variable sink72 | +| LocalDataFlow.cs:315:15:315:20 | access to local variable sink73 | +| LocalDataFlow.cs:316:15:316:20 | access to local variable sink74 | +| LocalDataFlow.cs:342:15:342:21 | access to parameter tainted | | SSA.cs:9:15:9:22 | access to local variable ssaSink0 | | SSA.cs:25:15:25:22 | access to local variable ssaSink1 | | SSA.cs:43:15:43:22 | access to local variable ssaSink2 | diff --git a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected index 77195b49f3de..fd781d984dd4 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected @@ -1,7 +1,4 @@ | Capture.cs:5:17:5:17 | this | Capture.cs:13:9:13:14 | this access | -| Capture.cs:7:13:7:17 | SSA def(i) | Capture.cs:13:9:13:16 | [implicit argument] i | -| Capture.cs:7:13:7:17 | SSA def(i) | Capture.cs:23:9:23:16 | [implicit argument] i | -| Capture.cs:7:13:7:17 | SSA def(i) | Capture.cs:34:9:34:16 | [implicit argument] i | | Capture.cs:7:17:7:17 | 0 | Capture.cs:7:13:7:17 | SSA def(i) | | Capture.cs:9:9:12:9 | SSA capture def(i) | Capture.cs:11:17:11:17 | access to local variable i | | Capture.cs:13:9:13:14 | this access | Capture.cs:23:9:23:14 | this access | @@ -10,7 +7,6 @@ | Capture.cs:23:9:23:14 | this access | Capture.cs:34:9:34:14 | this access | | Capture.cs:25:9:33:9 | this | Capture.cs:32:13:32:18 | this access | | Capture.cs:27:13:30:13 | SSA capture def(i) | Capture.cs:29:21:29:21 | access to local variable i | -| Capture.cs:31:13:31:17 | SSA def(i) | Capture.cs:32:13:32:20 | [implicit argument] i | | Capture.cs:31:17:31:17 | 1 | Capture.cs:31:13:31:17 | SSA def(i) | | Capture.cs:34:9:34:14 | this access | Capture.cs:40:9:40:15 | this access | | Capture.cs:38:17:38:17 | 0 | Capture.cs:38:13:38:17 | SSA def(i) | @@ -24,622 +20,505 @@ | Capture.cs:58:21:58:21 | 1 | Capture.cs:58:17:58:21 | SSA def(i) | | Capture.cs:61:17:61:17 | 1 | Capture.cs:61:13:61:17 | SSA def(i) | | Capture.cs:63:9:63:17 | SSA call def(i) | Capture.cs:64:13:64:13 | access to local variable i | -| LocalDataFlow.cs:49:30:49:30 | b | LocalDataFlow.cs:85:21:85:21 | access to parameter b | -| LocalDataFlow.cs:52:13:52:34 | SSA def(sink0) | LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | -| LocalDataFlow.cs:52:21:52:34 | "taint source" | LocalDataFlow.cs:52:13:52:34 | SSA def(sink0) | -| LocalDataFlow.cs:53:15:53:19 | [post] access to local variable sink0 | LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | -| LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | -| LocalDataFlow.cs:56:13:56:25 | SSA def(nonSink0) | LocalDataFlow.cs:57:15:57:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:56:24:56:25 | "" | LocalDataFlow.cs:56:13:56:25 | SSA def(nonSink0) | -| LocalDataFlow.cs:57:15:57:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:65:9:65:16 | access to local variable nonSink0 | -| LocalDataFlow.cs:57:15:57:22 | access to local variable nonSink0 | LocalDataFlow.cs:65:9:65:16 | access to local variable nonSink0 | -| LocalDataFlow.cs:60:13:60:25 | SSA def(sink1) | LocalDataFlow.cs:61:9:61:13 | access to local variable sink1 | -| LocalDataFlow.cs:60:21:60:25 | "abc" | LocalDataFlow.cs:60:13:60:25 | SSA def(sink1) | -| LocalDataFlow.cs:61:9:61:13 | access to local variable sink1 | LocalDataFlow.cs:61:9:61:22 | ... + ... | -| LocalDataFlow.cs:61:9:61:22 | ... + ... | LocalDataFlow.cs:61:9:61:22 | SSA def(sink1) | -| LocalDataFlow.cs:61:9:61:22 | SSA def(sink1) | LocalDataFlow.cs:62:15:62:19 | access to local variable sink1 | -| LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | LocalDataFlow.cs:61:9:61:22 | ... + ... | -| LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | LocalDataFlow.cs:169:20:169:24 | access to local variable sink0 | -| LocalDataFlow.cs:62:15:62:19 | [post] access to local variable sink1 | LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | -| LocalDataFlow.cs:62:15:62:19 | access to local variable sink1 | LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | -| LocalDataFlow.cs:65:9:65:16 | access to local variable nonSink0 | LocalDataFlow.cs:65:9:65:25 | ... + ... | -| LocalDataFlow.cs:65:9:65:25 | ... + ... | LocalDataFlow.cs:65:9:65:25 | SSA def(nonSink0) | -| LocalDataFlow.cs:65:9:65:25 | SSA def(nonSink0) | LocalDataFlow.cs:66:15:66:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:65:21:65:25 | "abc" | LocalDataFlow.cs:65:9:65:25 | ... + ... | -| LocalDataFlow.cs:66:15:66:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:73:20:73:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:66:15:66:22 | access to local variable nonSink0 | LocalDataFlow.cs:73:20:73:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:69:13:69:32 | SSA def(sink5) | LocalDataFlow.cs:70:15:70:19 | access to local variable sink5 | -| LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | LocalDataFlow.cs:69:21:69:32 | ... + ... | -| LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | LocalDataFlow.cs:169:33:169:37 | access to local variable sink1 | -| LocalDataFlow.cs:69:21:69:32 | ... + ... | LocalDataFlow.cs:69:13:69:32 | SSA def(sink5) | -| LocalDataFlow.cs:69:29:69:32 | "ok" | LocalDataFlow.cs:69:21:69:32 | ... + ... | -| LocalDataFlow.cs:70:15:70:19 | [post] access to local variable sink5 | LocalDataFlow.cs:77:22:77:26 | access to local variable sink5 | -| LocalDataFlow.cs:70:15:70:19 | access to local variable sink5 | LocalDataFlow.cs:77:22:77:26 | access to local variable sink5 | -| LocalDataFlow.cs:73:9:73:36 | SSA def(nonSink0) | LocalDataFlow.cs:74:15:74:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:73:20:73:27 | access to local variable nonSink0 | LocalDataFlow.cs:73:20:73:36 | ... + ... | -| LocalDataFlow.cs:73:20:73:36 | ... + ... | LocalDataFlow.cs:73:9:73:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:73:31:73:36 | "test" | LocalDataFlow.cs:73:20:73:36 | ... + ... | -| LocalDataFlow.cs:74:15:74:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:81:21:81:28 | access to local variable nonSink0 | -| LocalDataFlow.cs:74:15:74:22 | access to local variable nonSink0 | LocalDataFlow.cs:81:21:81:28 | access to local variable nonSink0 | -| LocalDataFlow.cs:77:13:77:27 | SSA def(sink6) | LocalDataFlow.cs:78:15:78:19 | access to local variable sink6 | -| LocalDataFlow.cs:77:22:77:26 | access to local variable sink5 | LocalDataFlow.cs:77:13:77:27 | SSA def(sink6) | -| LocalDataFlow.cs:78:15:78:19 | [post] access to local variable sink6 | LocalDataFlow.cs:85:31:85:35 | [b (line 49): false] access to local variable sink6 | -| LocalDataFlow.cs:78:15:78:19 | access to local variable sink6 | LocalDataFlow.cs:85:31:85:35 | [b (line 49): false] access to local variable sink6 | -| LocalDataFlow.cs:81:9:81:29 | SSA def(nonSink0) | LocalDataFlow.cs:82:15:82:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:81:21:81:28 | access to local variable nonSink0 | LocalDataFlow.cs:81:9:81:29 | SSA def(nonSink0) | -| LocalDataFlow.cs:85:13:85:35 | [b (line 49): false] SSA def(sink7) | LocalDataFlow.cs:86:15:86:19 | [b (line 49): false] access to local variable sink7 | -| LocalDataFlow.cs:85:13:85:35 | [b (line 49): true] SSA def(sink7) | LocalDataFlow.cs:86:15:86:19 | [b (line 49): true] access to local variable sink7 | -| LocalDataFlow.cs:85:21:85:21 | access to parameter b | LocalDataFlow.cs:89:20:89:20 | [b (line 49): false] access to parameter b | -| LocalDataFlow.cs:85:21:85:21 | access to parameter b | LocalDataFlow.cs:89:20:89:20 | [b (line 49): true] access to parameter b | -| LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | LocalDataFlow.cs:85:13:85:35 | [b (line 49): false] SSA def(sink7) | -| LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | LocalDataFlow.cs:85:13:85:35 | [b (line 49): true] SSA def(sink7) | -| LocalDataFlow.cs:85:25:85:27 | [b (line 49): true] "a" | LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | -| LocalDataFlow.cs:85:31:85:35 | [b (line 49): false] access to local variable sink6 | LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | -| LocalDataFlow.cs:86:15:86:19 | [b (line 49): false] access to local variable sink7 | LocalDataFlow.cs:89:9:89:36 | SSA phi(sink7) | -| LocalDataFlow.cs:86:15:86:19 | [b (line 49): true] access to local variable sink7 | LocalDataFlow.cs:89:9:89:36 | SSA phi(sink7) | -| LocalDataFlow.cs:89:9:89:36 | SSA def(nonSink0) | LocalDataFlow.cs:90:15:90:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:89:9:89:36 | SSA phi(sink7) | LocalDataFlow.cs:93:29:93:33 | access to local variable sink7 | -| LocalDataFlow.cs:89:20:89:36 | [b (line 49): false] ... ? ... : ... | LocalDataFlow.cs:89:9:89:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:89:20:89:36 | [b (line 49): true] ... ? ... : ... | LocalDataFlow.cs:89:9:89:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:89:24:89:28 | "abc" | LocalDataFlow.cs:89:20:89:36 | [b (line 49): true] ... ? ... : ... | -| LocalDataFlow.cs:89:32:89:36 | "def" | LocalDataFlow.cs:89:20:89:36 | [b (line 49): false] ... ? ... : ... | -| LocalDataFlow.cs:90:15:90:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:90:15:90:22 | access to local variable nonSink0 | LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:93:13:93:33 | SSA def(sink8) | LocalDataFlow.cs:94:15:94:19 | access to local variable sink8 | -| LocalDataFlow.cs:93:21:93:33 | (...) ... | LocalDataFlow.cs:93:13:93:33 | SSA def(sink8) | -| LocalDataFlow.cs:93:29:93:33 | access to local variable sink7 | LocalDataFlow.cs:93:21:93:33 | (...) ... | -| LocalDataFlow.cs:94:15:94:19 | [post] access to local variable sink8 | LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | -| LocalDataFlow.cs:94:15:94:19 | access to local variable sink8 | LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | -| LocalDataFlow.cs:97:13:97:39 | SSA def(nonSink3) | LocalDataFlow.cs:98:15:98:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:97:24:97:39 | (...) ... | LocalDataFlow.cs:97:13:97:39 | SSA def(nonSink3) | -| LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | LocalDataFlow.cs:97:24:97:39 | (...) ... | -| LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | LocalDataFlow.cs:105:20:105:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:101:13:101:35 | SSA def(sink9) | LocalDataFlow.cs:102:15:102:19 | access to local variable sink9 | -| LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | LocalDataFlow.cs:101:21:101:35 | ... as ... | -| LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | LocalDataFlow.cs:165:22:165:26 | access to local variable sink8 | -| LocalDataFlow.cs:101:21:101:35 | ... as ... | LocalDataFlow.cs:101:13:101:35 | SSA def(sink9) | -| LocalDataFlow.cs:102:15:102:19 | [post] access to local variable sink9 | LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | -| LocalDataFlow.cs:102:15:102:19 | access to local variable sink9 | LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | -| LocalDataFlow.cs:105:9:105:37 | SSA def(nonSink3) | LocalDataFlow.cs:106:15:106:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:105:20:105:27 | access to local variable nonSink0 | LocalDataFlow.cs:105:20:105:37 | ... as ... | -| LocalDataFlow.cs:105:20:105:27 | access to local variable nonSink0 | LocalDataFlow.cs:114:22:114:29 | access to local variable nonSink0 | -| LocalDataFlow.cs:105:20:105:37 | ... as ... | LocalDataFlow.cs:105:9:105:37 | SSA def(nonSink3) | -| LocalDataFlow.cs:106:15:106:22 | [post] access to local variable nonSink3 | LocalDataFlow.cs:171:33:171:40 | access to local variable nonSink3 | -| LocalDataFlow.cs:106:15:106:22 | access to local variable nonSink3 | LocalDataFlow.cs:171:33:171:40 | access to local variable nonSink3 | -| LocalDataFlow.cs:109:13:109:39 | SSA def(sink15) | LocalDataFlow.cs:110:15:110:20 | access to local variable sink15 | -| LocalDataFlow.cs:109:22:109:39 | [library code] call to method Parse | LocalDataFlow.cs:109:22:109:39 | call to method Parse | -| LocalDataFlow.cs:109:22:109:39 | call to method Parse | LocalDataFlow.cs:109:13:109:39 | SSA def(sink15) | -| LocalDataFlow.cs:109:34:109:38 | [post] access to local variable sink9 | LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | -| LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | LocalDataFlow.cs:109:22:109:39 | [library code] call to method Parse | -| LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | -| LocalDataFlow.cs:110:15:110:20 | access to local variable sink15 | LocalDataFlow.cs:161:22:161:27 | access to local variable sink15 | -| LocalDataFlow.cs:112:13:112:56 | SSA def(sink16) | LocalDataFlow.cs:113:15:113:20 | access to local variable sink16 | -| LocalDataFlow.cs:112:22:112:56 | [library code] call to method TryParse | LocalDataFlow.cs:112:22:112:56 | call to method TryParse | -| LocalDataFlow.cs:112:22:112:56 | call to method TryParse | LocalDataFlow.cs:112:13:112:56 | SSA def(sink16) | -| LocalDataFlow.cs:112:37:112:41 | [post] access to local variable sink9 | LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | -| LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | LocalDataFlow.cs:112:22:112:56 | [library code] call to method TryParse | -| LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | LocalDataFlow.cs:112:22:112:56 | [library code] call to method TryParse | -| LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | -| LocalDataFlow.cs:114:13:114:49 | SSA def(sink17) | LocalDataFlow.cs:115:15:115:20 | access to local variable sink17 | -| LocalDataFlow.cs:114:22:114:29 | [post] access to local variable nonSink0 | LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | -| LocalDataFlow.cs:114:22:114:29 | access to local variable nonSink0 | LocalDataFlow.cs:114:22:114:49 | [library code] call to method Replace | -| LocalDataFlow.cs:114:22:114:29 | access to local variable nonSink0 | LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | -| LocalDataFlow.cs:114:22:114:49 | [library code] call to method Replace | LocalDataFlow.cs:114:22:114:49 | call to method Replace | -| LocalDataFlow.cs:114:22:114:49 | [library code] call to method Replace | LocalDataFlow.cs:114:22:114:49 | call to method Replace | -| LocalDataFlow.cs:114:22:114:49 | call to method Replace | LocalDataFlow.cs:114:13:114:49 | SSA def(sink17) | -| LocalDataFlow.cs:114:44:114:48 | [post] access to local variable sink9 | LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | -| LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | LocalDataFlow.cs:114:22:114:49 | [library code] call to method Replace | -| LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | -| LocalDataFlow.cs:116:13:116:51 | SSA def(sink18) | LocalDataFlow.cs:117:15:117:20 | access to local variable sink18 | -| LocalDataFlow.cs:116:22:116:51 | [library code] call to method Format | LocalDataFlow.cs:116:22:116:51 | call to method Format | -| LocalDataFlow.cs:116:22:116:51 | [library code] call to method Format | LocalDataFlow.cs:116:22:116:51 | call to method Format | -| LocalDataFlow.cs:116:22:116:51 | call to method Format | LocalDataFlow.cs:116:13:116:51 | SSA def(sink18) | -| LocalDataFlow.cs:116:36:116:43 | [post] access to local variable nonSink0 | LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | LocalDataFlow.cs:116:22:116:51 | [library code] call to method Format | -| LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:116:46:116:50 | [post] access to local variable sink9 | LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | -| LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | LocalDataFlow.cs:116:22:116:51 | [library code] call to method Format | -| LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | -| LocalDataFlow.cs:117:15:117:20 | [post] access to local variable sink18 | LocalDataFlow.cs:118:36:118:41 | access to local variable sink18 | -| LocalDataFlow.cs:117:15:117:20 | access to local variable sink18 | LocalDataFlow.cs:118:36:118:41 | access to local variable sink18 | -| LocalDataFlow.cs:118:13:118:52 | SSA def(sink19) | LocalDataFlow.cs:119:15:119:20 | access to local variable sink19 | -| LocalDataFlow.cs:118:22:118:52 | [library code] call to method Format | LocalDataFlow.cs:118:22:118:52 | call to method Format | -| LocalDataFlow.cs:118:22:118:52 | [library code] call to method Format | LocalDataFlow.cs:118:22:118:52 | call to method Format | -| LocalDataFlow.cs:118:22:118:52 | call to method Format | LocalDataFlow.cs:118:13:118:52 | SSA def(sink19) | -| LocalDataFlow.cs:118:36:118:41 | access to local variable sink18 | LocalDataFlow.cs:118:22:118:52 | [library code] call to method Format | -| LocalDataFlow.cs:118:44:118:51 | [post] access to local variable nonSink0 | LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | LocalDataFlow.cs:118:22:118:52 | [library code] call to method Format | -| LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:120:13:120:38 | SSA def(sink45) | LocalDataFlow.cs:121:15:121:20 | access to local variable sink45 | -| LocalDataFlow.cs:120:22:120:38 | [library code] call to method Parse | LocalDataFlow.cs:120:22:120:38 | call to method Parse | -| LocalDataFlow.cs:120:22:120:38 | call to method Parse | LocalDataFlow.cs:120:13:120:38 | SSA def(sink45) | -| LocalDataFlow.cs:120:33:120:37 | [post] access to local variable sink9 | LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | -| LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | LocalDataFlow.cs:120:22:120:38 | [library code] call to method Parse | -| LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | -| LocalDataFlow.cs:123:13:123:56 | SSA def(sink46) | LocalDataFlow.cs:124:15:124:20 | access to local variable sink46 | -| LocalDataFlow.cs:123:22:123:56 | [library code] call to method TryParse | LocalDataFlow.cs:123:22:123:56 | call to method TryParse | -| LocalDataFlow.cs:123:22:123:56 | call to method TryParse | LocalDataFlow.cs:123:13:123:56 | SSA def(sink46) | -| LocalDataFlow.cs:123:36:123:40 | [post] access to local variable sink9 | LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | -| LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | LocalDataFlow.cs:123:22:123:56 | [library code] call to method TryParse | -| LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | LocalDataFlow.cs:123:22:123:56 | [library code] call to method TryParse | -| LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | -| LocalDataFlow.cs:124:15:124:20 | access to local variable sink46 | LocalDataFlow.cs:125:37:125:42 | access to local variable sink46 | -| LocalDataFlow.cs:125:13:125:43 | SSA def(sink47) | LocalDataFlow.cs:126:15:126:20 | access to local variable sink47 | -| LocalDataFlow.cs:125:22:125:43 | [library code] call to method ToByte | LocalDataFlow.cs:125:22:125:43 | call to method ToByte | -| LocalDataFlow.cs:125:22:125:43 | call to method ToByte | LocalDataFlow.cs:125:13:125:43 | SSA def(sink47) | -| LocalDataFlow.cs:125:37:125:42 | access to local variable sink46 | LocalDataFlow.cs:125:22:125:43 | [library code] call to method ToByte | -| LocalDataFlow.cs:126:15:126:20 | access to local variable sink47 | LocalDataFlow.cs:127:40:127:45 | access to local variable sink47 | -| LocalDataFlow.cs:127:13:127:46 | SSA def(sink49) | LocalDataFlow.cs:128:15:128:20 | access to local variable sink49 | -| LocalDataFlow.cs:127:22:127:46 | [library code] call to method Concat | LocalDataFlow.cs:127:22:127:46 | call to method Concat | -| LocalDataFlow.cs:127:22:127:46 | [library code] call to method Concat | LocalDataFlow.cs:127:22:127:46 | call to method Concat | -| LocalDataFlow.cs:127:22:127:46 | call to method Concat | LocalDataFlow.cs:127:13:127:46 | SSA def(sink49) | -| LocalDataFlow.cs:127:36:127:37 | "" | LocalDataFlow.cs:127:22:127:46 | [library code] call to method Concat | -| LocalDataFlow.cs:127:40:127:45 | (...) ... | LocalDataFlow.cs:127:22:127:46 | [library code] call to method Concat | -| LocalDataFlow.cs:127:40:127:45 | access to local variable sink47 | LocalDataFlow.cs:127:40:127:45 | (...) ... | -| LocalDataFlow.cs:128:15:128:20 | [post] access to local variable sink49 | LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | -| LocalDataFlow.cs:128:15:128:20 | access to local variable sink49 | LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | -| LocalDataFlow.cs:129:13:129:40 | SSA def(sink50) | LocalDataFlow.cs:130:15:130:20 | access to local variable sink50 | -| LocalDataFlow.cs:129:22:129:40 | [library code] call to method Copy | LocalDataFlow.cs:129:22:129:40 | call to method Copy | -| LocalDataFlow.cs:129:22:129:40 | call to method Copy | LocalDataFlow.cs:129:13:129:40 | SSA def(sink50) | -| LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | LocalDataFlow.cs:129:22:129:40 | [library code] call to method Copy | -| LocalDataFlow.cs:130:15:130:20 | [post] access to local variable sink50 | LocalDataFlow.cs:131:44:131:49 | access to local variable sink50 | -| LocalDataFlow.cs:130:15:130:20 | access to local variable sink50 | LocalDataFlow.cs:131:44:131:49 | access to local variable sink50 | -| LocalDataFlow.cs:131:13:131:54 | SSA def(sink51) | LocalDataFlow.cs:132:15:132:20 | access to local variable sink51 | -| LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | LocalDataFlow.cs:131:22:131:54 | call to method Join | -| LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | LocalDataFlow.cs:131:22:131:54 | call to method Join | -| LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | LocalDataFlow.cs:131:22:131:54 | call to method Join | -| LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | LocalDataFlow.cs:131:22:131:54 | call to method Join | -| LocalDataFlow.cs:131:22:131:54 | call to method Join | LocalDataFlow.cs:131:13:131:54 | SSA def(sink51) | -| LocalDataFlow.cs:131:34:131:37 | ", " | LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | -| LocalDataFlow.cs:131:40:131:41 | "" | LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | -| LocalDataFlow.cs:131:44:131:49 | access to local variable sink50 | LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | -| LocalDataFlow.cs:131:52:131:53 | "" | LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | -| LocalDataFlow.cs:132:15:132:20 | [post] access to local variable sink51 | LocalDataFlow.cs:133:35:133:40 | access to local variable sink51 | -| LocalDataFlow.cs:132:15:132:20 | access to local variable sink51 | LocalDataFlow.cs:133:35:133:40 | access to local variable sink51 | -| LocalDataFlow.cs:133:13:133:41 | SSA def(sink52) | LocalDataFlow.cs:134:15:134:20 | access to local variable sink52 | -| LocalDataFlow.cs:133:22:133:23 | "" | LocalDataFlow.cs:133:22:133:41 | [library code] call to method Insert | -| LocalDataFlow.cs:133:22:133:41 | [library code] call to method Insert | LocalDataFlow.cs:133:22:133:41 | call to method Insert | -| LocalDataFlow.cs:133:22:133:41 | [library code] call to method Insert | LocalDataFlow.cs:133:22:133:41 | call to method Insert | -| LocalDataFlow.cs:133:22:133:41 | call to method Insert | LocalDataFlow.cs:133:13:133:41 | SSA def(sink52) | -| LocalDataFlow.cs:133:35:133:40 | access to local variable sink51 | LocalDataFlow.cs:133:22:133:41 | [library code] call to method Insert | -| LocalDataFlow.cs:137:9:137:40 | SSA def(nonSink2) | LocalDataFlow.cs:138:15:138:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:137:20:137:40 | [library code] call to method Parse | LocalDataFlow.cs:137:20:137:40 | call to method Parse | -| LocalDataFlow.cs:137:20:137:40 | call to method Parse | LocalDataFlow.cs:137:9:137:40 | SSA def(nonSink2) | -| LocalDataFlow.cs:137:32:137:39 | [post] access to local variable nonSink0 | LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | LocalDataFlow.cs:137:20:137:40 | [library code] call to method Parse | -| LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:139:13:139:61 | SSA def(nonSink7) | LocalDataFlow.cs:140:15:140:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:139:24:139:61 | [library code] call to method TryParse | LocalDataFlow.cs:139:24:139:61 | call to method TryParse | -| LocalDataFlow.cs:139:24:139:61 | call to method TryParse | LocalDataFlow.cs:139:13:139:61 | SSA def(nonSink7) | -| LocalDataFlow.cs:139:39:139:46 | [post] access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | LocalDataFlow.cs:139:24:139:61 | [library code] call to method TryParse | -| LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | LocalDataFlow.cs:139:24:139:61 | [library code] call to method TryParse | -| LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:141:9:141:50 | SSA def(nonSink0) | LocalDataFlow.cs:142:15:142:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:141:20:141:27 | [post] access to local variable nonSink0 | LocalDataFlow.cs:141:42:141:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:50 | [library code] call to method Replace | -| LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | LocalDataFlow.cs:141:42:141:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:141:20:141:50 | [library code] call to method Replace | LocalDataFlow.cs:141:20:141:50 | call to method Replace | -| LocalDataFlow.cs:141:20:141:50 | [library code] call to method Replace | LocalDataFlow.cs:141:20:141:50 | call to method Replace | -| LocalDataFlow.cs:141:20:141:50 | call to method Replace | LocalDataFlow.cs:141:9:141:50 | SSA def(nonSink0) | -| LocalDataFlow.cs:141:42:141:49 | access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:50 | [library code] call to method Replace | -| LocalDataFlow.cs:142:15:142:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:142:15:142:22 | access to local variable nonSink0 | LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:143:9:143:52 | SSA def(nonSink0) | LocalDataFlow.cs:144:15:144:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:143:20:143:52 | [library code] call to method Format | LocalDataFlow.cs:143:20:143:52 | call to method Format | -| LocalDataFlow.cs:143:20:143:52 | [library code] call to method Format | LocalDataFlow.cs:143:20:143:52 | call to method Format | -| LocalDataFlow.cs:143:20:143:52 | call to method Format | LocalDataFlow.cs:143:9:143:52 | SSA def(nonSink0) | -| LocalDataFlow.cs:143:34:143:41 | [post] access to local variable nonSink0 | LocalDataFlow.cs:143:44:143:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | LocalDataFlow.cs:143:20:143:52 | [library code] call to method Format | -| LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | LocalDataFlow.cs:143:44:143:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:143:44:143:51 | access to local variable nonSink0 | LocalDataFlow.cs:143:20:143:52 | [library code] call to method Format | -| LocalDataFlow.cs:144:15:144:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:144:15:144:22 | access to local variable nonSink0 | LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:145:9:145:39 | SSA def(nonSink7) | LocalDataFlow.cs:146:15:146:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:145:20:145:39 | [library code] call to method Parse | LocalDataFlow.cs:145:20:145:39 | call to method Parse | -| LocalDataFlow.cs:145:20:145:39 | call to method Parse | LocalDataFlow.cs:145:9:145:39 | SSA def(nonSink7) | -| LocalDataFlow.cs:145:31:145:38 | [post] access to local variable nonSink0 | LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | LocalDataFlow.cs:145:20:145:39 | [library code] call to method Parse | -| LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:147:9:147:57 | SSA def(nonSink7) | LocalDataFlow.cs:148:15:148:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:147:20:147:57 | [library code] call to method TryParse | LocalDataFlow.cs:147:20:147:57 | call to method TryParse | -| LocalDataFlow.cs:147:20:147:57 | call to method TryParse | LocalDataFlow.cs:147:9:147:57 | SSA def(nonSink7) | -| LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | LocalDataFlow.cs:147:20:147:57 | [library code] call to method TryParse | -| LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | LocalDataFlow.cs:147:20:147:57 | [library code] call to method TryParse | -| LocalDataFlow.cs:148:15:148:22 | access to local variable nonSink7 | LocalDataFlow.cs:149:40:149:47 | access to local variable nonSink7 | -| LocalDataFlow.cs:149:13:149:48 | SSA def(nonSink14) | LocalDataFlow.cs:150:15:150:23 | access to local variable nonSink14 | -| LocalDataFlow.cs:149:25:149:48 | [library code] call to method ToByte | LocalDataFlow.cs:149:25:149:48 | call to method ToByte | -| LocalDataFlow.cs:149:25:149:48 | call to method ToByte | LocalDataFlow.cs:149:13:149:48 | SSA def(nonSink14) | -| LocalDataFlow.cs:149:40:149:47 | access to local variable nonSink7 | LocalDataFlow.cs:149:25:149:48 | [library code] call to method ToByte | -| LocalDataFlow.cs:149:40:149:47 | access to local variable nonSink7 | LocalDataFlow.cs:151:38:151:45 | access to local variable nonSink7 | -| LocalDataFlow.cs:151:9:151:46 | SSA def(nonSink0) | LocalDataFlow.cs:152:15:152:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:151:20:151:46 | [library code] call to method Concat | LocalDataFlow.cs:151:20:151:46 | call to method Concat | -| LocalDataFlow.cs:151:20:151:46 | [library code] call to method Concat | LocalDataFlow.cs:151:20:151:46 | call to method Concat | -| LocalDataFlow.cs:151:20:151:46 | call to method Concat | LocalDataFlow.cs:151:9:151:46 | SSA def(nonSink0) | -| LocalDataFlow.cs:151:34:151:35 | "" | LocalDataFlow.cs:151:20:151:46 | [library code] call to method Concat | -| LocalDataFlow.cs:151:38:151:45 | (...) ... | LocalDataFlow.cs:151:20:151:46 | [library code] call to method Concat | -| LocalDataFlow.cs:151:38:151:45 | access to local variable nonSink7 | LocalDataFlow.cs:151:38:151:45 | (...) ... | -| LocalDataFlow.cs:152:15:152:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:152:15:152:22 | access to local variable nonSink0 | LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:153:9:153:40 | SSA def(nonSink0) | LocalDataFlow.cs:154:15:154:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:153:20:153:40 | [library code] call to method Copy | LocalDataFlow.cs:153:20:153:40 | call to method Copy | -| LocalDataFlow.cs:153:20:153:40 | call to method Copy | LocalDataFlow.cs:153:9:153:40 | SSA def(nonSink0) | -| LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | LocalDataFlow.cs:153:20:153:40 | [library code] call to method Copy | -| LocalDataFlow.cs:154:15:154:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:155:42:155:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:154:15:154:22 | access to local variable nonSink0 | LocalDataFlow.cs:155:42:155:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:155:9:155:54 | SSA def(nonSink0) | LocalDataFlow.cs:156:15:156:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | LocalDataFlow.cs:155:20:155:54 | call to method Join | -| LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | LocalDataFlow.cs:155:20:155:54 | call to method Join | -| LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | LocalDataFlow.cs:155:20:155:54 | call to method Join | -| LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | LocalDataFlow.cs:155:20:155:54 | call to method Join | -| LocalDataFlow.cs:155:20:155:54 | call to method Join | LocalDataFlow.cs:155:9:155:54 | SSA def(nonSink0) | -| LocalDataFlow.cs:155:32:155:35 | ", " | LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | -| LocalDataFlow.cs:155:38:155:39 | "" | LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | -| LocalDataFlow.cs:155:42:155:49 | access to local variable nonSink0 | LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | -| LocalDataFlow.cs:155:52:155:53 | "" | LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | -| LocalDataFlow.cs:156:15:156:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:157:33:157:40 | access to local variable nonSink0 | -| LocalDataFlow.cs:156:15:156:22 | access to local variable nonSink0 | LocalDataFlow.cs:157:33:157:40 | access to local variable nonSink0 | -| LocalDataFlow.cs:157:9:157:41 | SSA def(nonSink0) | LocalDataFlow.cs:158:15:158:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:157:20:157:21 | "" | LocalDataFlow.cs:157:20:157:41 | [library code] call to method Insert | -| LocalDataFlow.cs:157:20:157:41 | [library code] call to method Insert | LocalDataFlow.cs:157:20:157:41 | call to method Insert | -| LocalDataFlow.cs:157:20:157:41 | [library code] call to method Insert | LocalDataFlow.cs:157:20:157:41 | call to method Insert | -| LocalDataFlow.cs:157:20:157:41 | call to method Insert | LocalDataFlow.cs:157:9:157:41 | SSA def(nonSink0) | -| LocalDataFlow.cs:157:33:157:40 | access to local variable nonSink0 | LocalDataFlow.cs:157:20:157:41 | [library code] call to method Insert | -| LocalDataFlow.cs:158:15:158:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:195:39:195:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:158:15:158:22 | access to local variable nonSink0 | LocalDataFlow.cs:195:39:195:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:161:13:161:32 | SSA def(sink20) | LocalDataFlow.cs:162:15:162:20 | access to local variable sink20 | -| LocalDataFlow.cs:161:22:161:27 | access to local variable sink15 | LocalDataFlow.cs:161:22:161:32 | ... > ... | -| LocalDataFlow.cs:161:22:161:32 | ... > ... | LocalDataFlow.cs:161:13:161:32 | SSA def(sink20) | -| LocalDataFlow.cs:162:15:162:20 | access to local variable sink20 | LocalDataFlow.cs:175:22:175:27 | access to local variable sink20 | -| LocalDataFlow.cs:163:13:163:40 | SSA def(sink21) | LocalDataFlow.cs:164:15:164:20 | access to local variable sink21 | -| LocalDataFlow.cs:163:22:163:26 | [post] access to local variable sink9 | LocalDataFlow.cs:183:37:183:41 | access to local variable sink9 | -| LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | LocalDataFlow.cs:163:22:163:40 | call to method Equals | -| LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | LocalDataFlow.cs:183:37:183:41 | access to local variable sink9 | -| LocalDataFlow.cs:163:22:163:40 | call to method Equals | LocalDataFlow.cs:163:13:163:40 | SSA def(sink21) | -| LocalDataFlow.cs:165:13:165:45 | SSA def(sink22) | LocalDataFlow.cs:166:15:166:20 | access to local variable sink22 | -| LocalDataFlow.cs:165:22:165:26 | [post] access to local variable sink8 | LocalDataFlow.cs:171:20:171:24 | access to local variable sink8 | -| LocalDataFlow.cs:165:22:165:26 | access to local variable sink8 | LocalDataFlow.cs:165:22:165:45 | call to method Equals | -| LocalDataFlow.cs:165:22:165:26 | access to local variable sink8 | LocalDataFlow.cs:171:20:171:24 | access to local variable sink8 | -| LocalDataFlow.cs:165:22:165:45 | call to method Equals | LocalDataFlow.cs:165:13:165:45 | SSA def(sink22) | -| LocalDataFlow.cs:165:43:165:44 | 41 | LocalDataFlow.cs:165:35:165:44 | (...) ... | -| LocalDataFlow.cs:169:9:169:38 | SSA def(nonSink7) | LocalDataFlow.cs:170:15:170:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:169:20:169:24 | [post] access to local variable sink0 | LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | -| LocalDataFlow.cs:169:20:169:24 | access to local variable sink0 | LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | -| LocalDataFlow.cs:169:20:169:38 | call to method Equals | LocalDataFlow.cs:169:9:169:38 | SSA def(nonSink7) | -| LocalDataFlow.cs:169:33:169:37 | [post] access to local variable sink1 | LocalDataFlow.cs:286:30:286:34 | access to local variable sink1 | -| LocalDataFlow.cs:169:33:169:37 | access to local variable sink1 | LocalDataFlow.cs:286:30:286:34 | access to local variable sink1 | -| LocalDataFlow.cs:171:9:171:41 | SSA def(nonSink7) | LocalDataFlow.cs:172:15:172:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:171:20:171:41 | call to method Equals | LocalDataFlow.cs:171:9:171:41 | SSA def(nonSink7) | -| LocalDataFlow.cs:172:15:172:22 | access to local variable nonSink7 | LocalDataFlow.cs:179:20:179:27 | access to local variable nonSink7 | -| LocalDataFlow.cs:175:13:175:36 | SSA def(sink25) | LocalDataFlow.cs:176:15:176:20 | access to local variable sink25 | -| LocalDataFlow.cs:175:22:175:27 | access to local variable sink20 | LocalDataFlow.cs:175:22:175:36 | ... \|\| ... | -| LocalDataFlow.cs:175:22:175:36 | ... \|\| ... | LocalDataFlow.cs:175:13:175:36 | SSA def(sink25) | -| LocalDataFlow.cs:175:32:175:36 | false | LocalDataFlow.cs:175:22:175:36 | ... \|\| ... | -| LocalDataFlow.cs:179:9:179:36 | SSA def(nonSink7) | LocalDataFlow.cs:180:15:180:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:179:20:179:27 | access to local variable nonSink7 | LocalDataFlow.cs:179:20:179:36 | ... \|\| ... | -| LocalDataFlow.cs:179:20:179:36 | ... \|\| ... | LocalDataFlow.cs:179:9:179:36 | SSA def(nonSink7) | -| LocalDataFlow.cs:179:32:179:36 | false | LocalDataFlow.cs:179:20:179:36 | ... \|\| ... | -| LocalDataFlow.cs:183:13:183:42 | SSA def(sink26) | LocalDataFlow.cs:184:15:184:20 | access to local variable sink26 | -| LocalDataFlow.cs:183:22:183:42 | [library code] object creation of type Uri | LocalDataFlow.cs:183:22:183:42 | object creation of type Uri | -| LocalDataFlow.cs:183:22:183:42 | object creation of type Uri | LocalDataFlow.cs:183:13:183:42 | SSA def(sink26) | -| LocalDataFlow.cs:183:37:183:41 | access to local variable sink9 | LocalDataFlow.cs:183:22:183:42 | [library code] object creation of type Uri | -| LocalDataFlow.cs:184:15:184:20 | [post] access to local variable sink26 | LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | -| LocalDataFlow.cs:184:15:184:20 | access to local variable sink26 | LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | -| LocalDataFlow.cs:185:13:185:38 | SSA def(sink27) | LocalDataFlow.cs:186:15:186:20 | access to local variable sink27 | -| LocalDataFlow.cs:185:22:185:27 | [post] access to local variable sink26 | LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | -| LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | LocalDataFlow.cs:185:22:185:38 | [library code] call to method ToString | -| LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | -| LocalDataFlow.cs:185:22:185:38 | [library code] call to method ToString | LocalDataFlow.cs:185:22:185:38 | call to method ToString | -| LocalDataFlow.cs:185:22:185:38 | call to method ToString | LocalDataFlow.cs:185:13:185:38 | SSA def(sink27) | -| LocalDataFlow.cs:187:13:187:40 | SSA def(sink28) | LocalDataFlow.cs:188:15:188:20 | access to local variable sink28 | -| LocalDataFlow.cs:187:22:187:27 | [post] access to local variable sink26 | LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | -| LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | LocalDataFlow.cs:187:22:187:40 | [library code] access to property PathAndQuery | -| LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | -| LocalDataFlow.cs:187:22:187:40 | [library code] access to property PathAndQuery | LocalDataFlow.cs:187:22:187:40 | access to property PathAndQuery | -| LocalDataFlow.cs:187:22:187:40 | access to property PathAndQuery | LocalDataFlow.cs:187:13:187:40 | SSA def(sink28) | -| LocalDataFlow.cs:189:13:189:33 | SSA def(sink29) | LocalDataFlow.cs:190:15:190:20 | access to local variable sink29 | -| LocalDataFlow.cs:189:22:189:27 | [post] access to local variable sink26 | LocalDataFlow.cs:191:22:191:27 | access to local variable sink26 | -| LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | LocalDataFlow.cs:189:22:189:33 | [library code] access to property Query | -| LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | LocalDataFlow.cs:191:22:191:27 | access to local variable sink26 | -| LocalDataFlow.cs:189:22:189:33 | [library code] access to property Query | LocalDataFlow.cs:189:22:189:33 | access to property Query | -| LocalDataFlow.cs:189:22:189:33 | access to property Query | LocalDataFlow.cs:189:13:189:33 | SSA def(sink29) | -| LocalDataFlow.cs:191:13:191:42 | SSA def(sink30) | LocalDataFlow.cs:192:15:192:20 | access to local variable sink30 | -| LocalDataFlow.cs:191:22:191:27 | access to local variable sink26 | LocalDataFlow.cs:191:22:191:42 | [library code] access to property OriginalString | -| LocalDataFlow.cs:191:22:191:42 | [library code] access to property OriginalString | LocalDataFlow.cs:191:22:191:42 | access to property OriginalString | -| LocalDataFlow.cs:191:22:191:42 | access to property OriginalString | LocalDataFlow.cs:191:13:191:42 | SSA def(sink30) | -| LocalDataFlow.cs:192:15:192:20 | [post] access to local variable sink30 | LocalDataFlow.cs:207:49:207:54 | access to local variable sink30 | -| LocalDataFlow.cs:192:15:192:20 | access to local variable sink30 | LocalDataFlow.cs:207:49:207:54 | access to local variable sink30 | -| LocalDataFlow.cs:195:13:195:47 | SSA def(nonSink8) | LocalDataFlow.cs:196:15:196:22 | access to local variable nonSink8 | -| LocalDataFlow.cs:195:24:195:47 | [library code] object creation of type Uri | LocalDataFlow.cs:195:24:195:47 | object creation of type Uri | -| LocalDataFlow.cs:195:24:195:47 | object creation of type Uri | LocalDataFlow.cs:195:13:195:47 | SSA def(nonSink8) | -| LocalDataFlow.cs:195:39:195:46 | access to local variable nonSink0 | LocalDataFlow.cs:195:24:195:47 | [library code] object creation of type Uri | -| LocalDataFlow.cs:196:15:196:22 | [post] access to local variable nonSink8 | LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:196:15:196:22 | access to local variable nonSink8 | LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:197:9:197:38 | SSA def(nonSink0) | LocalDataFlow.cs:198:15:198:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:197:20:197:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | LocalDataFlow.cs:197:20:197:38 | [library code] call to method ToString | -| LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:197:20:197:38 | [library code] call to method ToString | LocalDataFlow.cs:197:20:197:38 | call to method ToString | -| LocalDataFlow.cs:197:20:197:38 | call to method ToString | LocalDataFlow.cs:197:9:197:38 | SSA def(nonSink0) | -| LocalDataFlow.cs:199:9:199:40 | SSA def(nonSink0) | LocalDataFlow.cs:200:15:200:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:199:20:199:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | LocalDataFlow.cs:199:20:199:40 | [library code] access to property PathAndQuery | -| LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:199:20:199:40 | [library code] access to property PathAndQuery | LocalDataFlow.cs:199:20:199:40 | access to property PathAndQuery | -| LocalDataFlow.cs:199:20:199:40 | access to property PathAndQuery | LocalDataFlow.cs:199:9:199:40 | SSA def(nonSink0) | -| LocalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) | LocalDataFlow.cs:202:15:202:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:201:20:201:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:203:20:203:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | LocalDataFlow.cs:201:20:201:33 | [library code] access to property Query | -| LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | LocalDataFlow.cs:203:20:203:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:201:20:201:33 | [library code] access to property Query | LocalDataFlow.cs:201:20:201:33 | access to property Query | -| LocalDataFlow.cs:201:20:201:33 | access to property Query | LocalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) | -| LocalDataFlow.cs:203:9:203:42 | SSA def(nonSink0) | LocalDataFlow.cs:204:15:204:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:203:20:203:27 | access to local variable nonSink8 | LocalDataFlow.cs:203:20:203:42 | [library code] access to property OriginalString | -| LocalDataFlow.cs:203:20:203:42 | [library code] access to property OriginalString | LocalDataFlow.cs:203:20:203:42 | access to property OriginalString | -| LocalDataFlow.cs:203:20:203:42 | access to property OriginalString | LocalDataFlow.cs:203:9:203:42 | SSA def(nonSink0) | -| LocalDataFlow.cs:204:15:204:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:213:51:213:58 | access to local variable nonSink0 | -| LocalDataFlow.cs:204:15:204:22 | access to local variable nonSink0 | LocalDataFlow.cs:213:51:213:58 | access to local variable nonSink0 | -| LocalDataFlow.cs:207:13:207:55 | SSA def(sink31) | LocalDataFlow.cs:208:15:208:20 | access to local variable sink31 | -| LocalDataFlow.cs:207:22:207:55 | [library code] object creation of type StringReader | LocalDataFlow.cs:207:22:207:55 | object creation of type StringReader | -| LocalDataFlow.cs:207:22:207:55 | object creation of type StringReader | LocalDataFlow.cs:207:13:207:55 | SSA def(sink31) | -| LocalDataFlow.cs:207:49:207:54 | access to local variable sink30 | LocalDataFlow.cs:207:22:207:55 | [library code] object creation of type StringReader | -| LocalDataFlow.cs:208:15:208:20 | [post] access to local variable sink31 | LocalDataFlow.cs:209:22:209:27 | access to local variable sink31 | -| LocalDataFlow.cs:208:15:208:20 | access to local variable sink31 | LocalDataFlow.cs:209:22:209:27 | access to local variable sink31 | -| LocalDataFlow.cs:209:13:209:39 | SSA def(sink32) | LocalDataFlow.cs:210:15:210:20 | access to local variable sink32 | -| LocalDataFlow.cs:209:22:209:27 | access to local variable sink31 | LocalDataFlow.cs:209:22:209:39 | [library code] call to method ReadToEnd | -| LocalDataFlow.cs:209:22:209:39 | [library code] call to method ReadToEnd | LocalDataFlow.cs:209:22:209:39 | call to method ReadToEnd | -| LocalDataFlow.cs:209:22:209:39 | call to method ReadToEnd | LocalDataFlow.cs:209:13:209:39 | SSA def(sink32) | -| LocalDataFlow.cs:210:15:210:20 | [post] access to local variable sink32 | LocalDataFlow.cs:219:30:219:35 | access to local variable sink32 | -| LocalDataFlow.cs:210:15:210:20 | access to local variable sink32 | LocalDataFlow.cs:219:30:219:35 | access to local variable sink32 | -| LocalDataFlow.cs:213:13:213:59 | SSA def(nonSink9) | LocalDataFlow.cs:214:15:214:22 | access to local variable nonSink9 | -| LocalDataFlow.cs:213:24:213:59 | [library code] object creation of type StringReader | LocalDataFlow.cs:213:24:213:59 | object creation of type StringReader | -| LocalDataFlow.cs:213:24:213:59 | object creation of type StringReader | LocalDataFlow.cs:213:13:213:59 | SSA def(nonSink9) | -| LocalDataFlow.cs:213:51:213:58 | access to local variable nonSink0 | LocalDataFlow.cs:213:24:213:59 | [library code] object creation of type StringReader | -| LocalDataFlow.cs:214:15:214:22 | [post] access to local variable nonSink9 | LocalDataFlow.cs:215:20:215:27 | access to local variable nonSink9 | -| LocalDataFlow.cs:214:15:214:22 | access to local variable nonSink9 | LocalDataFlow.cs:215:20:215:27 | access to local variable nonSink9 | -| LocalDataFlow.cs:215:9:215:39 | SSA def(nonSink0) | LocalDataFlow.cs:216:15:216:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:215:20:215:27 | access to local variable nonSink9 | LocalDataFlow.cs:215:20:215:39 | [library code] call to method ReadToEnd | -| LocalDataFlow.cs:215:20:215:39 | [library code] call to method ReadToEnd | LocalDataFlow.cs:215:20:215:39 | call to method ReadToEnd | -| LocalDataFlow.cs:215:20:215:39 | call to method ReadToEnd | LocalDataFlow.cs:215:9:215:39 | SSA def(nonSink0) | -| LocalDataFlow.cs:216:15:216:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:225:28:225:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:216:15:216:22 | access to local variable nonSink0 | LocalDataFlow.cs:225:28:225:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:219:13:219:127 | SSA def(sink33) | LocalDataFlow.cs:220:15:220:20 | access to local variable sink33 | -| LocalDataFlow.cs:219:22:219:127 | (...) ... | LocalDataFlow.cs:219:13:219:127 | SSA def(sink33) | -| LocalDataFlow.cs:219:30:219:35 | access to local variable sink32 | LocalDataFlow.cs:219:30:219:48 | [library code] call to method Substring | -| LocalDataFlow.cs:219:30:219:48 | [library code] call to method Substring | LocalDataFlow.cs:219:30:219:48 | call to method Substring | -| LocalDataFlow.cs:219:30:219:48 | call to method Substring | LocalDataFlow.cs:219:30:219:67 | [library code] call to method ToLowerInvariant | -| LocalDataFlow.cs:219:30:219:67 | [library code] call to method ToLowerInvariant | LocalDataFlow.cs:219:30:219:67 | call to method ToLowerInvariant | -| LocalDataFlow.cs:219:30:219:67 | call to method ToLowerInvariant | LocalDataFlow.cs:219:30:219:77 | [library code] call to method ToUpper | -| LocalDataFlow.cs:219:30:219:77 | [library code] call to method ToUpper | LocalDataFlow.cs:219:30:219:77 | call to method ToUpper | -| LocalDataFlow.cs:219:30:219:77 | call to method ToUpper | LocalDataFlow.cs:219:30:219:87 | [library code] call to method Trim | -| LocalDataFlow.cs:219:30:219:87 | [library code] call to method Trim | LocalDataFlow.cs:219:30:219:87 | call to method Trim | -| LocalDataFlow.cs:219:30:219:87 | call to method Trim | LocalDataFlow.cs:219:30:219:105 | [library code] call to method Replace | -| LocalDataFlow.cs:219:30:219:105 | [library code] call to method Replace | LocalDataFlow.cs:219:30:219:105 | call to method Replace | -| LocalDataFlow.cs:219:30:219:105 | [library code] call to method Replace | LocalDataFlow.cs:219:30:219:105 | call to method Replace | -| LocalDataFlow.cs:219:30:219:105 | call to method Replace | LocalDataFlow.cs:219:30:219:119 | [library code] call to method Insert | -| LocalDataFlow.cs:219:30:219:119 | [library code] call to method Insert | LocalDataFlow.cs:219:30:219:119 | call to method Insert | -| LocalDataFlow.cs:219:30:219:119 | [library code] call to method Insert | LocalDataFlow.cs:219:30:219:119 | call to method Insert | -| LocalDataFlow.cs:219:30:219:119 | call to method Insert | LocalDataFlow.cs:219:30:219:127 | [library code] call to method Clone | -| LocalDataFlow.cs:219:30:219:119 | call to method Insert | LocalDataFlow.cs:219:30:219:127 | [library code] call to method Clone | -| LocalDataFlow.cs:219:30:219:127 | [library code] call to method Clone | LocalDataFlow.cs:219:30:219:127 | call to method Clone | -| LocalDataFlow.cs:219:30:219:127 | [library code] call to method Clone | LocalDataFlow.cs:219:30:219:127 | call to method Clone | -| LocalDataFlow.cs:219:30:219:127 | call to method Clone | LocalDataFlow.cs:219:22:219:127 | (...) ... | -| LocalDataFlow.cs:219:102:219:104 | "b" | LocalDataFlow.cs:219:30:219:105 | [library code] call to method Replace | -| LocalDataFlow.cs:219:117:219:118 | "" | LocalDataFlow.cs:219:30:219:119 | [library code] call to method Insert | -| LocalDataFlow.cs:220:15:220:20 | [post] access to local variable sink33 | LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | -| LocalDataFlow.cs:220:15:220:20 | access to local variable sink33 | LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | -| LocalDataFlow.cs:221:13:221:63 | SSA def(sink48) | LocalDataFlow.cs:222:15:222:20 | access to local variable sink48 | -| LocalDataFlow.cs:221:22:221:27 | [post] access to local variable sink33 | LocalDataFlow.cs:231:40:231:45 | access to local variable sink33 | -| LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | LocalDataFlow.cs:221:22:221:39 | [library code] call to method Normalize | -| LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | LocalDataFlow.cs:231:40:231:45 | access to local variable sink33 | -| LocalDataFlow.cs:221:22:221:39 | [library code] call to method Normalize | LocalDataFlow.cs:221:22:221:39 | call to method Normalize | -| LocalDataFlow.cs:221:22:221:39 | call to method Normalize | LocalDataFlow.cs:221:22:221:52 | [library code] call to method Remove | -| LocalDataFlow.cs:221:22:221:52 | [library code] call to method Remove | LocalDataFlow.cs:221:22:221:52 | call to method Remove | -| LocalDataFlow.cs:221:22:221:52 | call to method Remove | LocalDataFlow.cs:221:22:221:63 | [library code] call to method Split | -| LocalDataFlow.cs:221:22:221:63 | [library code] call to method Split | LocalDataFlow.cs:221:22:221:63 | call to method Split | -| LocalDataFlow.cs:221:22:221:63 | call to method Split | LocalDataFlow.cs:221:13:221:63 | SSA def(sink48) | -| LocalDataFlow.cs:225:9:225:127 | SSA def(nonSink0) | LocalDataFlow.cs:226:15:226:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:225:20:225:127 | (...) ... | LocalDataFlow.cs:225:9:225:127 | SSA def(nonSink0) | -| LocalDataFlow.cs:225:28:225:35 | access to local variable nonSink0 | LocalDataFlow.cs:225:28:225:48 | [library code] call to method Substring | -| LocalDataFlow.cs:225:28:225:48 | [library code] call to method Substring | LocalDataFlow.cs:225:28:225:48 | call to method Substring | -| LocalDataFlow.cs:225:28:225:48 | call to method Substring | LocalDataFlow.cs:225:28:225:67 | [library code] call to method ToLowerInvariant | -| LocalDataFlow.cs:225:28:225:67 | [library code] call to method ToLowerInvariant | LocalDataFlow.cs:225:28:225:67 | call to method ToLowerInvariant | -| LocalDataFlow.cs:225:28:225:67 | call to method ToLowerInvariant | LocalDataFlow.cs:225:28:225:77 | [library code] call to method ToUpper | -| LocalDataFlow.cs:225:28:225:77 | [library code] call to method ToUpper | LocalDataFlow.cs:225:28:225:77 | call to method ToUpper | -| LocalDataFlow.cs:225:28:225:77 | call to method ToUpper | LocalDataFlow.cs:225:28:225:87 | [library code] call to method Trim | -| LocalDataFlow.cs:225:28:225:87 | [library code] call to method Trim | LocalDataFlow.cs:225:28:225:87 | call to method Trim | -| LocalDataFlow.cs:225:28:225:87 | call to method Trim | LocalDataFlow.cs:225:28:225:105 | [library code] call to method Replace | -| LocalDataFlow.cs:225:28:225:105 | [library code] call to method Replace | LocalDataFlow.cs:225:28:225:105 | call to method Replace | -| LocalDataFlow.cs:225:28:225:105 | [library code] call to method Replace | LocalDataFlow.cs:225:28:225:105 | call to method Replace | -| LocalDataFlow.cs:225:28:225:105 | call to method Replace | LocalDataFlow.cs:225:28:225:119 | [library code] call to method Insert | -| LocalDataFlow.cs:225:28:225:119 | [library code] call to method Insert | LocalDataFlow.cs:225:28:225:119 | call to method Insert | -| LocalDataFlow.cs:225:28:225:119 | [library code] call to method Insert | LocalDataFlow.cs:225:28:225:119 | call to method Insert | -| LocalDataFlow.cs:225:28:225:119 | call to method Insert | LocalDataFlow.cs:225:28:225:127 | [library code] call to method Clone | -| LocalDataFlow.cs:225:28:225:119 | call to method Insert | LocalDataFlow.cs:225:28:225:127 | [library code] call to method Clone | -| LocalDataFlow.cs:225:28:225:127 | [library code] call to method Clone | LocalDataFlow.cs:225:28:225:127 | call to method Clone | -| LocalDataFlow.cs:225:28:225:127 | [library code] call to method Clone | LocalDataFlow.cs:225:28:225:127 | call to method Clone | -| LocalDataFlow.cs:225:28:225:127 | call to method Clone | LocalDataFlow.cs:225:20:225:127 | (...) ... | -| LocalDataFlow.cs:225:102:225:104 | "b" | LocalDataFlow.cs:225:28:225:105 | [library code] call to method Replace | -| LocalDataFlow.cs:225:117:225:118 | "" | LocalDataFlow.cs:225:28:225:119 | [library code] call to method Insert | -| LocalDataFlow.cs:226:15:226:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | -| LocalDataFlow.cs:226:15:226:22 | access to local variable nonSink0 | LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | -| LocalDataFlow.cs:227:13:227:68 | SSA def(nonSink15) | LocalDataFlow.cs:228:15:228:23 | access to local variable nonSink15 | -| LocalDataFlow.cs:227:25:227:32 | [post] access to local variable nonSink0 | LocalDataFlow.cs:240:43:240:50 | access to local variable nonSink0 | -| LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | LocalDataFlow.cs:227:25:227:44 | [library code] call to method Normalize | -| LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | LocalDataFlow.cs:240:43:240:50 | access to local variable nonSink0 | -| LocalDataFlow.cs:227:25:227:44 | [library code] call to method Normalize | LocalDataFlow.cs:227:25:227:44 | call to method Normalize | -| LocalDataFlow.cs:227:25:227:44 | call to method Normalize | LocalDataFlow.cs:227:25:227:57 | [library code] call to method Remove | -| LocalDataFlow.cs:227:25:227:57 | [library code] call to method Remove | LocalDataFlow.cs:227:25:227:57 | call to method Remove | -| LocalDataFlow.cs:227:25:227:57 | call to method Remove | LocalDataFlow.cs:227:25:227:68 | [library code] call to method Split | -| LocalDataFlow.cs:227:25:227:68 | [library code] call to method Split | LocalDataFlow.cs:227:25:227:68 | call to method Split | -| LocalDataFlow.cs:227:25:227:68 | call to method Split | LocalDataFlow.cs:227:13:227:68 | SSA def(nonSink15) | -| LocalDataFlow.cs:231:13:231:46 | SSA def(sink34) | LocalDataFlow.cs:232:15:232:20 | access to local variable sink34 | -| LocalDataFlow.cs:231:22:231:46 | [library code] object creation of type StringBuilder | LocalDataFlow.cs:231:22:231:46 | object creation of type StringBuilder | -| LocalDataFlow.cs:231:22:231:46 | object creation of type StringBuilder | LocalDataFlow.cs:231:13:231:46 | SSA def(sink34) | -| LocalDataFlow.cs:231:40:231:45 | access to local variable sink33 | LocalDataFlow.cs:231:22:231:46 | [library code] object creation of type StringBuilder | -| LocalDataFlow.cs:232:15:232:20 | [post] access to local variable sink34 | LocalDataFlow.cs:233:22:233:27 | access to local variable sink34 | -| LocalDataFlow.cs:232:15:232:20 | access to local variable sink34 | LocalDataFlow.cs:233:22:233:27 | access to local variable sink34 | -| LocalDataFlow.cs:233:13:233:38 | SSA def(sink35) | LocalDataFlow.cs:234:15:234:20 | access to local variable sink35 | -| LocalDataFlow.cs:233:22:233:27 | access to local variable sink34 | LocalDataFlow.cs:233:22:233:38 | [library code] call to method ToString | -| LocalDataFlow.cs:233:22:233:38 | [library code] call to method ToString | LocalDataFlow.cs:233:22:233:38 | call to method ToString | -| LocalDataFlow.cs:233:22:233:38 | call to method ToString | LocalDataFlow.cs:233:13:233:38 | SSA def(sink35) | -| LocalDataFlow.cs:234:15:234:20 | [post] access to local variable sink35 | LocalDataFlow.cs:236:27:236:32 | access to local variable sink35 | -| LocalDataFlow.cs:234:15:234:20 | access to local variable sink35 | LocalDataFlow.cs:236:27:236:32 | access to local variable sink35 | -| LocalDataFlow.cs:235:13:235:42 | SSA def(sink36) | LocalDataFlow.cs:236:9:236:14 | access to local variable sink36 | -| LocalDataFlow.cs:235:22:235:42 | [library code] object creation of type StringBuilder | LocalDataFlow.cs:235:22:235:42 | object creation of type StringBuilder | -| LocalDataFlow.cs:235:22:235:42 | object creation of type StringBuilder | LocalDataFlow.cs:235:13:235:42 | SSA def(sink36) | -| LocalDataFlow.cs:235:40:235:41 | "" | LocalDataFlow.cs:235:22:235:42 | [library code] object creation of type StringBuilder | -| LocalDataFlow.cs:236:9:236:14 | [post] access to local variable sink36 | LocalDataFlow.cs:237:15:237:20 | access to local variable sink36 | -| LocalDataFlow.cs:236:9:236:14 | access to local variable sink36 | LocalDataFlow.cs:237:15:237:20 | access to local variable sink36 | -| LocalDataFlow.cs:236:9:236:33 | [library code] call to method AppendLine | LocalDataFlow.cs:236:9:236:14 | access to local variable sink36 | -| LocalDataFlow.cs:236:27:236:32 | access to local variable sink35 | LocalDataFlow.cs:236:9:236:33 | [library code] call to method AppendLine | -| LocalDataFlow.cs:240:13:240:51 | SSA def(nonSink10) | LocalDataFlow.cs:241:15:241:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:240:25:240:51 | [library code] object creation of type StringBuilder | LocalDataFlow.cs:240:25:240:51 | object creation of type StringBuilder | -| LocalDataFlow.cs:240:25:240:51 | object creation of type StringBuilder | LocalDataFlow.cs:240:13:240:51 | SSA def(nonSink10) | -| LocalDataFlow.cs:240:43:240:50 | access to local variable nonSink0 | LocalDataFlow.cs:240:25:240:51 | [library code] object creation of type StringBuilder | -| LocalDataFlow.cs:241:15:241:23 | [post] access to local variable nonSink10 | LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | -| LocalDataFlow.cs:241:15:241:23 | access to local variable nonSink10 | LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | -| LocalDataFlow.cs:242:9:242:39 | SSA def(nonSink0) | LocalDataFlow.cs:243:15:243:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:242:20:242:28 | [post] access to local variable nonSink10 | LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | LocalDataFlow.cs:242:20:242:39 | [library code] call to method ToString | -| LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:242:20:242:39 | [library code] call to method ToString | LocalDataFlow.cs:242:20:242:39 | call to method ToString | -| LocalDataFlow.cs:242:20:242:39 | call to method ToString | LocalDataFlow.cs:242:9:242:39 | SSA def(nonSink0) | -| LocalDataFlow.cs:243:15:243:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:244:30:244:37 | access to local variable nonSink0 | -| LocalDataFlow.cs:243:15:243:22 | access to local variable nonSink0 | LocalDataFlow.cs:244:30:244:37 | access to local variable nonSink0 | -| LocalDataFlow.cs:244:9:244:17 | [post] access to local variable nonSink10 | LocalDataFlow.cs:245:15:245:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | LocalDataFlow.cs:245:15:245:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:244:9:244:38 | [library code] call to method AppendLine | LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:244:30:244:37 | access to local variable nonSink0 | LocalDataFlow.cs:244:9:244:38 | [library code] call to method AppendLine | -| LocalDataFlow.cs:248:13:248:52 | SSA def(taintedDataContract) | LocalDataFlow.cs:249:22:249:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:248:13:248:52 | SSA qualifier def(taintedDataContract.AList) | LocalDataFlow.cs:251:22:251:46 | access to property AList | -| LocalDataFlow.cs:248:35:248:52 | object creation of type DataContract | LocalDataFlow.cs:248:13:248:52 | SSA def(taintedDataContract) | -| LocalDataFlow.cs:249:13:249:48 | SSA def(sink53) | LocalDataFlow.cs:250:15:250:20 | access to local variable sink53 | -| LocalDataFlow.cs:249:22:249:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:249:22:249:40 | access to local variable taintedDataContract | LocalDataFlow.cs:249:22:249:48 | [library code] access to property AString | -| LocalDataFlow.cs:249:22:249:40 | access to local variable taintedDataContract | LocalDataFlow.cs:249:22:249:48 | access to property AString | -| LocalDataFlow.cs:249:22:249:40 | access to local variable taintedDataContract | LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:249:22:249:48 | [library code] access to property AString | LocalDataFlow.cs:249:22:249:48 | access to property AString | -| LocalDataFlow.cs:249:22:249:48 | access to property AString | LocalDataFlow.cs:249:13:249:48 | SSA def(sink53) | -| LocalDataFlow.cs:251:13:251:57 | SSA def(sink54) | LocalDataFlow.cs:252:15:252:20 | access to local variable sink54 | -| LocalDataFlow.cs:251:22:251:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:258:20:258:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | LocalDataFlow.cs:251:22:251:46 | [library code] access to property AList | -| LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | LocalDataFlow.cs:251:22:251:46 | access to property AList | -| LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | LocalDataFlow.cs:258:20:258:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:251:22:251:46 | [library code] access to property AList | LocalDataFlow.cs:251:22:251:46 | access to property AList | -| LocalDataFlow.cs:251:22:251:46 | [post] access to property AList | LocalDataFlow.cs:260:20:260:44 | access to property AList | -| LocalDataFlow.cs:251:22:251:46 | access to property AList | LocalDataFlow.cs:251:22:251:49 | access to indexer | -| LocalDataFlow.cs:251:22:251:46 | access to property AList | LocalDataFlow.cs:260:20:260:44 | access to property AList | -| LocalDataFlow.cs:251:22:251:49 | access to indexer | LocalDataFlow.cs:251:22:251:57 | [library code] access to property AString | -| LocalDataFlow.cs:251:22:251:49 | access to indexer | LocalDataFlow.cs:251:22:251:57 | access to property AString | -| LocalDataFlow.cs:251:22:251:57 | [library code] access to property AString | LocalDataFlow.cs:251:22:251:57 | access to property AString | -| LocalDataFlow.cs:251:22:251:57 | access to property AString | LocalDataFlow.cs:251:13:251:57 | SSA def(sink54) | -| LocalDataFlow.cs:255:13:255:55 | SSA def(nonTaintedDataContract) | LocalDataFlow.cs:256:20:256:41 | access to local variable nonTaintedDataContract | -| LocalDataFlow.cs:255:38:255:55 | object creation of type DataContract | LocalDataFlow.cs:255:13:255:55 | SSA def(nonTaintedDataContract) | -| LocalDataFlow.cs:256:9:256:49 | SSA def(nonSink0) | LocalDataFlow.cs:257:15:257:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:256:20:256:41 | access to local variable nonTaintedDataContract | LocalDataFlow.cs:256:20:256:49 | [library code] access to property AString | -| LocalDataFlow.cs:256:20:256:41 | access to local variable nonTaintedDataContract | LocalDataFlow.cs:256:20:256:49 | access to property AString | -| LocalDataFlow.cs:256:20:256:49 | [library code] access to property AString | LocalDataFlow.cs:256:20:256:49 | access to property AString | -| LocalDataFlow.cs:256:20:256:49 | access to property AString | LocalDataFlow.cs:256:9:256:49 | SSA def(nonSink0) | -| LocalDataFlow.cs:258:9:258:44 | SSA def(nonSink2) | LocalDataFlow.cs:259:15:259:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:258:20:258:38 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:260:20:260:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:258:20:258:38 | access to local variable taintedDataContract | LocalDataFlow.cs:260:20:260:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:258:20:258:44 | access to property AnInt | LocalDataFlow.cs:258:9:258:44 | SSA def(nonSink2) | -| LocalDataFlow.cs:260:9:260:53 | SSA def(nonSink2) | LocalDataFlow.cs:261:15:261:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:260:20:260:38 | access to local variable taintedDataContract | LocalDataFlow.cs:260:20:260:44 | [library code] access to property AList | -| LocalDataFlow.cs:260:20:260:38 | access to local variable taintedDataContract | LocalDataFlow.cs:260:20:260:44 | access to property AList | -| LocalDataFlow.cs:260:20:260:44 | [library code] access to property AList | LocalDataFlow.cs:260:20:260:44 | access to property AList | -| LocalDataFlow.cs:260:20:260:44 | access to property AList | LocalDataFlow.cs:260:20:260:47 | access to indexer | -| LocalDataFlow.cs:260:20:260:53 | access to property AnInt | LocalDataFlow.cs:260:9:260:53 | SSA def(nonSink2) | -| LocalDataFlow.cs:264:17:264:37 | SSA def(taintedTextBox) | LocalDataFlow.cs:265:22:265:35 | access to local variable taintedTextBox | -| LocalDataFlow.cs:264:34:264:37 | null | LocalDataFlow.cs:264:17:264:37 | SSA def(taintedTextBox) | -| LocalDataFlow.cs:265:13:265:40 | SSA def(sink60) | LocalDataFlow.cs:266:15:266:20 | access to local variable sink60 | -| LocalDataFlow.cs:265:22:265:35 | access to local variable taintedTextBox | LocalDataFlow.cs:265:22:265:40 | [library code] access to property Text | -| LocalDataFlow.cs:265:22:265:40 | [library code] access to property Text | LocalDataFlow.cs:265:22:265:40 | access to property Text | -| LocalDataFlow.cs:265:22:265:40 | access to property Text | LocalDataFlow.cs:265:13:265:40 | SSA def(sink60) | -| LocalDataFlow.cs:269:17:269:40 | SSA def(nonTaintedTextBox) | LocalDataFlow.cs:270:20:270:36 | access to local variable nonTaintedTextBox | -| LocalDataFlow.cs:269:37:269:40 | null | LocalDataFlow.cs:269:17:269:40 | SSA def(nonTaintedTextBox) | -| LocalDataFlow.cs:270:9:270:41 | SSA def(nonSink0) | LocalDataFlow.cs:271:15:271:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:270:20:270:36 | access to local variable nonTaintedTextBox | LocalDataFlow.cs:270:20:270:41 | [library code] access to property Text | -| LocalDataFlow.cs:270:20:270:41 | [library code] access to property Text | LocalDataFlow.cs:270:20:270:41 | access to property Text | -| LocalDataFlow.cs:270:20:270:41 | access to property Text | LocalDataFlow.cs:270:9:270:41 | SSA def(nonSink0) | -| LocalDataFlow.cs:274:13:274:51 | SSA def(sink67) | LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | -| LocalDataFlow.cs:274:22:274:51 | [library code] call to method Run | LocalDataFlow.cs:274:22:274:51 | call to method Run | -| LocalDataFlow.cs:274:22:274:51 | call to method Run | LocalDataFlow.cs:274:13:274:51 | SSA def(sink67) | -| LocalDataFlow.cs:274:31:274:50 | [output] (...) => ... | LocalDataFlow.cs:274:22:274:51 | [library code] call to method Run | -| LocalDataFlow.cs:275:15:275:20 | [post] access to local variable sink67 | LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | -| LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | -| LocalDataFlow.cs:276:13:276:33 | SSA def(sink68) | LocalDataFlow.cs:277:15:277:20 | access to local variable sink68 | -| LocalDataFlow.cs:276:22:276:33 | await ... | LocalDataFlow.cs:276:13:276:33 | SSA def(sink68) | -| LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | LocalDataFlow.cs:276:22:276:33 | await ... | -| LocalDataFlow.cs:280:13:280:42 | SSA def(nonSink21) | LocalDataFlow.cs:281:15:281:23 | access to local variable nonSink21 | -| LocalDataFlow.cs:280:25:280:42 | [library code] call to method Run | LocalDataFlow.cs:280:25:280:42 | call to method Run | -| LocalDataFlow.cs:280:25:280:42 | call to method Run | LocalDataFlow.cs:280:13:280:42 | SSA def(nonSink21) | -| LocalDataFlow.cs:280:34:280:41 | [output] (...) => ... | LocalDataFlow.cs:280:25:280:42 | [library code] call to method Run | -| LocalDataFlow.cs:281:15:281:23 | [post] access to local variable nonSink21 | LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | -| LocalDataFlow.cs:281:15:281:23 | access to local variable nonSink21 | LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | -| LocalDataFlow.cs:282:9:282:34 | SSA def(nonSink0) | LocalDataFlow.cs:283:15:283:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:282:20:282:34 | await ... | LocalDataFlow.cs:282:9:282:34 | SSA def(nonSink0) | -| LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | LocalDataFlow.cs:282:20:282:34 | await ... | -| LocalDataFlow.cs:283:15:283:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:290:28:290:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:283:15:283:22 | access to local variable nonSink0 | LocalDataFlow.cs:290:28:290:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:286:13:286:36 | SSA def(sink69) | LocalDataFlow.cs:287:15:287:20 | access to local variable sink69 | -| LocalDataFlow.cs:286:22:286:36 | $"..." | LocalDataFlow.cs:286:13:286:36 | SSA def(sink69) | -| LocalDataFlow.cs:286:24:286:28 | "test " | LocalDataFlow.cs:286:22:286:36 | $"..." | -| LocalDataFlow.cs:286:30:286:34 | access to local variable sink1 | LocalDataFlow.cs:286:22:286:36 | $"..." | -| LocalDataFlow.cs:290:9:290:37 | SSA def(nonSink0) | LocalDataFlow.cs:291:15:291:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:290:20:290:37 | $"..." | LocalDataFlow.cs:290:9:290:37 | SSA def(nonSink0) | -| LocalDataFlow.cs:290:22:290:26 | "test " | LocalDataFlow.cs:290:20:290:37 | $"..." | -| LocalDataFlow.cs:290:28:290:35 | access to local variable nonSink0 | LocalDataFlow.cs:290:20:290:37 | $"..." | -| LocalDataFlow.cs:291:15:291:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:298:31:298:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:291:15:291:22 | access to local variable nonSink0 | LocalDataFlow.cs:298:31:298:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:294:13:294:34 | SSA def(sink70) | LocalDataFlow.cs:295:15:295:20 | access to local variable sink70 | -| LocalDataFlow.cs:294:22:294:34 | ... = ... | LocalDataFlow.cs:294:13:294:34 | SSA def(sink70) | -| LocalDataFlow.cs:294:22:294:34 | SSA def(sink0) | LocalDataFlow.cs:326:34:326:38 | access to local variable sink0 | -| LocalDataFlow.cs:294:22:294:34 | SSA def(sink0) | LocalDataFlow.cs:327:22:327:26 | access to local variable sink0 | -| LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | LocalDataFlow.cs:294:22:294:34 | ... = ... | -| LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | LocalDataFlow.cs:294:22:294:34 | SSA def(sink0) | -| LocalDataFlow.cs:295:15:295:20 | [post] access to local variable sink70 | LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | -| LocalDataFlow.cs:295:15:295:20 | access to local variable sink70 | LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | -| LocalDataFlow.cs:298:9:298:38 | SSA def(nonSink0) | LocalDataFlow.cs:299:15:299:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:298:20:298:38 | ... = ... | LocalDataFlow.cs:298:9:298:38 | SSA def(nonSink0) | -| LocalDataFlow.cs:298:31:298:38 | access to local variable nonSink0 | LocalDataFlow.cs:298:20:298:38 | ... = ... | -| LocalDataFlow.cs:299:15:299:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | -| LocalDataFlow.cs:299:15:299:22 | access to local variable nonSink0 | LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | -| LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | LocalDataFlow.cs:302:23:302:35 | SSA def(sink71) | -| LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | LocalDataFlow.cs:310:17:310:22 | access to local variable sink70 | -| LocalDataFlow.cs:302:23:302:35 | SSA def(sink71) | LocalDataFlow.cs:303:19:303:24 | access to local variable sink71 | -| LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | LocalDataFlow.cs:306:25:306:40 | SSA def(nonSink16) | -| LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | LocalDataFlow.cs:318:17:318:24 | access to local variable nonSink0 | -| LocalDataFlow.cs:306:25:306:40 | SSA def(nonSink16) | LocalDataFlow.cs:307:19:307:27 | access to local variable nonSink16 | -| LocalDataFlow.cs:310:17:310:22 | access to local variable sink70 | LocalDataFlow.cs:312:18:312:30 | SSA def(sink72) | -| LocalDataFlow.cs:312:18:312:30 | SSA def(sink72) | LocalDataFlow.cs:313:23:313:28 | access to local variable sink72 | -| LocalDataFlow.cs:318:17:318:24 | access to local variable nonSink0 | LocalDataFlow.cs:320:18:320:33 | SSA def(nonSink17) | -| LocalDataFlow.cs:318:17:318:24 | access to local variable nonSink0 | LocalDataFlow.cs:326:22:326:29 | access to local variable nonSink0 | -| LocalDataFlow.cs:320:18:320:33 | SSA def(nonSink17) | LocalDataFlow.cs:321:23:321:31 | access to local variable nonSink17 | -| LocalDataFlow.cs:326:13:326:38 | SSA def(sink73) | LocalDataFlow.cs:328:15:328:20 | access to local variable sink73 | -| LocalDataFlow.cs:326:22:326:29 | access to local variable nonSink0 | LocalDataFlow.cs:326:22:326:38 | ... ?? ... | -| LocalDataFlow.cs:326:22:326:29 | access to local variable nonSink0 | LocalDataFlow.cs:327:31:327:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:326:22:326:38 | ... ?? ... | LocalDataFlow.cs:326:13:326:38 | SSA def(sink73) | -| LocalDataFlow.cs:326:34:326:38 | access to local variable sink0 | LocalDataFlow.cs:326:22:326:38 | ... ?? ... | -| LocalDataFlow.cs:326:34:326:38 | access to local variable sink0 | LocalDataFlow.cs:327:22:327:26 | access to local variable sink0 | -| LocalDataFlow.cs:327:13:327:38 | SSA def(sink74) | LocalDataFlow.cs:329:15:329:20 | access to local variable sink74 | -| LocalDataFlow.cs:327:22:327:26 | access to local variable sink0 | LocalDataFlow.cs:327:22:327:38 | ... ?? ... | -| LocalDataFlow.cs:327:22:327:38 | ... ?? ... | LocalDataFlow.cs:327:13:327:38 | SSA def(sink74) | -| LocalDataFlow.cs:327:31:327:38 | access to local variable nonSink0 | LocalDataFlow.cs:327:22:327:38 | ... ?? ... | -| LocalDataFlow.cs:347:28:347:30 | this | LocalDataFlow.cs:347:41:347:45 | this access | -| LocalDataFlow.cs:347:50:347:52 | this | LocalDataFlow.cs:347:56:347:60 | this access | -| LocalDataFlow.cs:347:50:347:52 | value | LocalDataFlow.cs:347:64:347:68 | access to parameter value | -| LocalDataFlow.cs:353:41:353:47 | tainted | LocalDataFlow.cs:355:15:355:21 | access to parameter tainted | -| LocalDataFlow.cs:358:44:358:53 | nonTainted | LocalDataFlow.cs:360:15:360:24 | access to parameter nonTainted | -| LocalDataFlow.cs:363:44:363:44 | x | LocalDataFlow.cs:366:21:366:21 | access to parameter x | -| LocalDataFlow.cs:363:67:363:68 | os | LocalDataFlow.cs:369:32:369:33 | access to parameter os | -| LocalDataFlow.cs:366:21:366:21 | access to parameter x | LocalDataFlow.cs:366:16:366:21 | ... = ... | -| LocalDataFlow.cs:369:32:369:33 | access to parameter os | LocalDataFlow.cs:369:26:369:33 | ... = ... | -| LocalDataFlow.cs:374:41:374:44 | args | LocalDataFlow.cs:376:29:376:32 | access to parameter args | -| LocalDataFlow.cs:376:29:376:32 | [post] access to parameter args | LocalDataFlow.cs:377:27:377:30 | access to parameter args | -| LocalDataFlow.cs:376:29:376:32 | access to parameter args | LocalDataFlow.cs:376:29:376:32 | call to operator implicit conversion | -| LocalDataFlow.cs:376:29:376:32 | access to parameter args | LocalDataFlow.cs:377:27:377:30 | access to parameter args | +| LocalDataFlow.cs:48:24:48:24 | b | LocalDataFlow.cs:84:21:84:21 | access to parameter b | +| LocalDataFlow.cs:51:13:51:34 | SSA def(sink0) | LocalDataFlow.cs:52:15:52:19 | access to local variable sink0 | +| LocalDataFlow.cs:51:21:51:34 | "taint source" | LocalDataFlow.cs:51:13:51:34 | SSA def(sink0) | +| LocalDataFlow.cs:52:15:52:19 | [post] access to local variable sink0 | LocalDataFlow.cs:60:18:60:22 | access to local variable sink0 | +| LocalDataFlow.cs:52:15:52:19 | access to local variable sink0 | LocalDataFlow.cs:60:18:60:22 | access to local variable sink0 | +| LocalDataFlow.cs:55:13:55:25 | SSA def(nonSink0) | LocalDataFlow.cs:56:15:56:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:55:24:55:25 | "" | LocalDataFlow.cs:55:13:55:25 | SSA def(nonSink0) | +| LocalDataFlow.cs:56:15:56:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:64:9:64:16 | access to local variable nonSink0 | +| LocalDataFlow.cs:56:15:56:22 | access to local variable nonSink0 | LocalDataFlow.cs:64:9:64:16 | access to local variable nonSink0 | +| LocalDataFlow.cs:59:13:59:25 | SSA def(sink1) | LocalDataFlow.cs:60:9:60:13 | access to local variable sink1 | +| LocalDataFlow.cs:59:21:59:25 | "abc" | LocalDataFlow.cs:59:13:59:25 | SSA def(sink1) | +| LocalDataFlow.cs:60:9:60:13 | access to local variable sink1 | LocalDataFlow.cs:60:9:60:22 | ... + ... | +| LocalDataFlow.cs:60:9:60:22 | ... + ... | LocalDataFlow.cs:60:9:60:22 | SSA def(sink1) | +| LocalDataFlow.cs:60:9:60:22 | SSA def(sink1) | LocalDataFlow.cs:61:15:61:19 | access to local variable sink1 | +| LocalDataFlow.cs:60:18:60:22 | access to local variable sink0 | LocalDataFlow.cs:60:9:60:22 | ... + ... | +| LocalDataFlow.cs:60:18:60:22 | access to local variable sink0 | LocalDataFlow.cs:168:20:168:24 | access to local variable sink0 | +| LocalDataFlow.cs:61:15:61:19 | [post] access to local variable sink1 | LocalDataFlow.cs:68:21:68:25 | access to local variable sink1 | +| LocalDataFlow.cs:61:15:61:19 | access to local variable sink1 | LocalDataFlow.cs:68:21:68:25 | access to local variable sink1 | +| LocalDataFlow.cs:64:9:64:16 | access to local variable nonSink0 | LocalDataFlow.cs:64:9:64:25 | ... + ... | +| LocalDataFlow.cs:64:9:64:25 | ... + ... | LocalDataFlow.cs:64:9:64:25 | SSA def(nonSink0) | +| LocalDataFlow.cs:64:9:64:25 | SSA def(nonSink0) | LocalDataFlow.cs:65:15:65:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:64:21:64:25 | "abc" | LocalDataFlow.cs:64:9:64:25 | ... + ... | +| LocalDataFlow.cs:65:15:65:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:72:20:72:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:65:15:65:22 | access to local variable nonSink0 | LocalDataFlow.cs:72:20:72:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:68:13:68:32 | SSA def(sink5) | LocalDataFlow.cs:69:15:69:19 | access to local variable sink5 | +| LocalDataFlow.cs:68:21:68:25 | access to local variable sink1 | LocalDataFlow.cs:68:21:68:32 | ... + ... | +| LocalDataFlow.cs:68:21:68:25 | access to local variable sink1 | LocalDataFlow.cs:168:33:168:37 | access to local variable sink1 | +| LocalDataFlow.cs:68:21:68:32 | ... + ... | LocalDataFlow.cs:68:13:68:32 | SSA def(sink5) | +| LocalDataFlow.cs:68:29:68:32 | "ok" | LocalDataFlow.cs:68:21:68:32 | ... + ... | +| LocalDataFlow.cs:69:15:69:19 | [post] access to local variable sink5 | LocalDataFlow.cs:76:22:76:26 | access to local variable sink5 | +| LocalDataFlow.cs:69:15:69:19 | access to local variable sink5 | LocalDataFlow.cs:76:22:76:26 | access to local variable sink5 | +| LocalDataFlow.cs:72:9:72:36 | SSA def(nonSink0) | LocalDataFlow.cs:73:15:73:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:72:20:72:27 | access to local variable nonSink0 | LocalDataFlow.cs:72:20:72:36 | ... + ... | +| LocalDataFlow.cs:72:20:72:36 | ... + ... | LocalDataFlow.cs:72:9:72:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:72:31:72:36 | "test" | LocalDataFlow.cs:72:20:72:36 | ... + ... | +| LocalDataFlow.cs:73:15:73:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:80:21:80:28 | access to local variable nonSink0 | +| LocalDataFlow.cs:73:15:73:22 | access to local variable nonSink0 | LocalDataFlow.cs:80:21:80:28 | access to local variable nonSink0 | +| LocalDataFlow.cs:76:13:76:27 | SSA def(sink6) | LocalDataFlow.cs:77:15:77:19 | access to local variable sink6 | +| LocalDataFlow.cs:76:22:76:26 | access to local variable sink5 | LocalDataFlow.cs:76:13:76:27 | SSA def(sink6) | +| LocalDataFlow.cs:77:15:77:19 | [post] access to local variable sink6 | LocalDataFlow.cs:84:31:84:35 | [b (line 48): false] access to local variable sink6 | +| LocalDataFlow.cs:77:15:77:19 | access to local variable sink6 | LocalDataFlow.cs:84:31:84:35 | [b (line 48): false] access to local variable sink6 | +| LocalDataFlow.cs:80:9:80:29 | SSA def(nonSink0) | LocalDataFlow.cs:81:15:81:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:80:21:80:28 | access to local variable nonSink0 | LocalDataFlow.cs:80:9:80:29 | SSA def(nonSink0) | +| LocalDataFlow.cs:84:13:84:35 | [b (line 48): false] SSA def(sink7) | LocalDataFlow.cs:85:15:85:19 | [b (line 48): false] access to local variable sink7 | +| LocalDataFlow.cs:84:13:84:35 | [b (line 48): true] SSA def(sink7) | LocalDataFlow.cs:85:15:85:19 | [b (line 48): true] access to local variable sink7 | +| LocalDataFlow.cs:84:21:84:21 | access to parameter b | LocalDataFlow.cs:88:20:88:20 | [b (line 48): false] access to parameter b | +| LocalDataFlow.cs:84:21:84:21 | access to parameter b | LocalDataFlow.cs:88:20:88:20 | [b (line 48): true] access to parameter b | +| LocalDataFlow.cs:84:21:84:35 | ... ? ... : ... | LocalDataFlow.cs:84:13:84:35 | [b (line 48): false] SSA def(sink7) | +| LocalDataFlow.cs:84:21:84:35 | ... ? ... : ... | LocalDataFlow.cs:84:13:84:35 | [b (line 48): true] SSA def(sink7) | +| LocalDataFlow.cs:84:25:84:27 | [b (line 48): true] "a" | LocalDataFlow.cs:84:21:84:35 | ... ? ... : ... | +| LocalDataFlow.cs:84:31:84:35 | [b (line 48): false] access to local variable sink6 | LocalDataFlow.cs:84:21:84:35 | ... ? ... : ... | +| LocalDataFlow.cs:85:15:85:19 | [b (line 48): false] access to local variable sink7 | LocalDataFlow.cs:88:9:88:36 | SSA phi(sink7) | +| LocalDataFlow.cs:85:15:85:19 | [b (line 48): true] access to local variable sink7 | LocalDataFlow.cs:88:9:88:36 | SSA phi(sink7) | +| LocalDataFlow.cs:88:9:88:36 | SSA def(nonSink0) | LocalDataFlow.cs:89:15:89:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:88:9:88:36 | SSA phi(sink7) | LocalDataFlow.cs:92:29:92:33 | access to local variable sink7 | +| LocalDataFlow.cs:88:20:88:36 | [b (line 48): false] ... ? ... : ... | LocalDataFlow.cs:88:9:88:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:88:20:88:36 | [b (line 48): true] ... ? ... : ... | LocalDataFlow.cs:88:9:88:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:88:24:88:28 | "abc" | LocalDataFlow.cs:88:20:88:36 | [b (line 48): true] ... ? ... : ... | +| LocalDataFlow.cs:88:32:88:36 | "def" | LocalDataFlow.cs:88:20:88:36 | [b (line 48): false] ... ? ... : ... | +| LocalDataFlow.cs:89:15:89:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:96:32:96:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:89:15:89:22 | access to local variable nonSink0 | LocalDataFlow.cs:96:32:96:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:92:13:92:33 | SSA def(sink8) | LocalDataFlow.cs:93:15:93:19 | access to local variable sink8 | +| LocalDataFlow.cs:92:21:92:33 | (...) ... | LocalDataFlow.cs:92:13:92:33 | SSA def(sink8) | +| LocalDataFlow.cs:92:29:92:33 | access to local variable sink7 | LocalDataFlow.cs:92:21:92:33 | (...) ... | +| LocalDataFlow.cs:93:15:93:19 | [post] access to local variable sink8 | LocalDataFlow.cs:100:21:100:25 | access to local variable sink8 | +| LocalDataFlow.cs:93:15:93:19 | access to local variable sink8 | LocalDataFlow.cs:100:21:100:25 | access to local variable sink8 | +| LocalDataFlow.cs:96:13:96:39 | SSA def(nonSink3) | LocalDataFlow.cs:97:15:97:22 | access to local variable nonSink3 | +| LocalDataFlow.cs:96:24:96:39 | (...) ... | LocalDataFlow.cs:96:13:96:39 | SSA def(nonSink3) | +| LocalDataFlow.cs:96:32:96:39 | access to local variable nonSink0 | LocalDataFlow.cs:96:24:96:39 | (...) ... | +| LocalDataFlow.cs:96:32:96:39 | access to local variable nonSink0 | LocalDataFlow.cs:104:20:104:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:100:13:100:35 | SSA def(sink9) | LocalDataFlow.cs:101:15:101:19 | access to local variable sink9 | +| LocalDataFlow.cs:100:21:100:25 | access to local variable sink8 | LocalDataFlow.cs:100:21:100:35 | ... as ... | +| LocalDataFlow.cs:100:21:100:25 | access to local variable sink8 | LocalDataFlow.cs:164:22:164:26 | access to local variable sink8 | +| LocalDataFlow.cs:100:21:100:35 | ... as ... | LocalDataFlow.cs:100:13:100:35 | SSA def(sink9) | +| LocalDataFlow.cs:101:15:101:19 | [post] access to local variable sink9 | LocalDataFlow.cs:108:34:108:38 | access to local variable sink9 | +| LocalDataFlow.cs:101:15:101:19 | access to local variable sink9 | LocalDataFlow.cs:108:34:108:38 | access to local variable sink9 | +| LocalDataFlow.cs:104:9:104:37 | SSA def(nonSink3) | LocalDataFlow.cs:105:15:105:22 | access to local variable nonSink3 | +| LocalDataFlow.cs:104:20:104:27 | access to local variable nonSink0 | LocalDataFlow.cs:104:20:104:37 | ... as ... | +| LocalDataFlow.cs:104:20:104:27 | access to local variable nonSink0 | LocalDataFlow.cs:113:22:113:29 | access to local variable nonSink0 | +| LocalDataFlow.cs:104:20:104:37 | ... as ... | LocalDataFlow.cs:104:9:104:37 | SSA def(nonSink3) | +| LocalDataFlow.cs:105:15:105:22 | [post] access to local variable nonSink3 | LocalDataFlow.cs:170:33:170:40 | access to local variable nonSink3 | +| LocalDataFlow.cs:105:15:105:22 | access to local variable nonSink3 | LocalDataFlow.cs:170:33:170:40 | access to local variable nonSink3 | +| LocalDataFlow.cs:108:13:108:39 | SSA def(sink15) | LocalDataFlow.cs:109:15:109:20 | access to local variable sink15 | +| LocalDataFlow.cs:108:22:108:39 | call to method Parse | LocalDataFlow.cs:108:13:108:39 | SSA def(sink15) | +| LocalDataFlow.cs:108:34:108:38 | [post] access to local variable sink9 | LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | +| LocalDataFlow.cs:108:34:108:38 | access to local variable sink9 | LocalDataFlow.cs:108:22:108:39 | call to method Parse | +| LocalDataFlow.cs:108:34:108:38 | access to local variable sink9 | LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | +| LocalDataFlow.cs:109:15:109:20 | access to local variable sink15 | LocalDataFlow.cs:160:22:160:27 | access to local variable sink15 | +| LocalDataFlow.cs:111:13:111:56 | SSA def(sink16) | LocalDataFlow.cs:112:15:112:20 | access to local variable sink16 | +| LocalDataFlow.cs:111:22:111:56 | call to method TryParse | LocalDataFlow.cs:111:13:111:56 | SSA def(sink16) | +| LocalDataFlow.cs:111:37:111:41 | [post] access to local variable sink9 | LocalDataFlow.cs:113:44:113:48 | access to local variable sink9 | +| LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | LocalDataFlow.cs:111:22:111:56 | call to method TryParse | +| LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | LocalDataFlow.cs:113:44:113:48 | access to local variable sink9 | +| LocalDataFlow.cs:113:13:113:49 | SSA def(sink17) | LocalDataFlow.cs:114:15:114:20 | access to local variable sink17 | +| LocalDataFlow.cs:113:22:113:29 | [post] access to local variable nonSink0 | LocalDataFlow.cs:115:36:115:43 | access to local variable nonSink0 | +| LocalDataFlow.cs:113:22:113:29 | access to local variable nonSink0 | LocalDataFlow.cs:113:22:113:49 | call to method Replace | +| LocalDataFlow.cs:113:22:113:29 | access to local variable nonSink0 | LocalDataFlow.cs:115:36:115:43 | access to local variable nonSink0 | +| LocalDataFlow.cs:113:22:113:49 | call to method Replace | LocalDataFlow.cs:113:13:113:49 | SSA def(sink17) | +| LocalDataFlow.cs:113:44:113:48 | [post] access to local variable sink9 | LocalDataFlow.cs:115:46:115:50 | access to local variable sink9 | +| LocalDataFlow.cs:113:44:113:48 | access to local variable sink9 | LocalDataFlow.cs:113:22:113:49 | call to method Replace | +| LocalDataFlow.cs:113:44:113:48 | access to local variable sink9 | LocalDataFlow.cs:115:46:115:50 | access to local variable sink9 | +| LocalDataFlow.cs:115:13:115:51 | SSA def(sink18) | LocalDataFlow.cs:116:15:116:20 | access to local variable sink18 | +| LocalDataFlow.cs:115:22:115:51 | call to method Format | LocalDataFlow.cs:115:13:115:51 | SSA def(sink18) | +| LocalDataFlow.cs:115:36:115:43 | [post] access to local variable nonSink0 | LocalDataFlow.cs:117:44:117:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:115:36:115:43 | access to local variable nonSink0 | LocalDataFlow.cs:115:22:115:51 | call to method Format | +| LocalDataFlow.cs:115:36:115:43 | access to local variable nonSink0 | LocalDataFlow.cs:117:44:117:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:115:46:115:50 | [post] access to local variable sink9 | LocalDataFlow.cs:119:33:119:37 | access to local variable sink9 | +| LocalDataFlow.cs:115:46:115:50 | access to local variable sink9 | LocalDataFlow.cs:115:22:115:51 | call to method Format | +| LocalDataFlow.cs:115:46:115:50 | access to local variable sink9 | LocalDataFlow.cs:119:33:119:37 | access to local variable sink9 | +| LocalDataFlow.cs:116:15:116:20 | [post] access to local variable sink18 | LocalDataFlow.cs:117:36:117:41 | access to local variable sink18 | +| LocalDataFlow.cs:116:15:116:20 | access to local variable sink18 | LocalDataFlow.cs:117:36:117:41 | access to local variable sink18 | +| LocalDataFlow.cs:117:13:117:52 | SSA def(sink19) | LocalDataFlow.cs:118:15:118:20 | access to local variable sink19 | +| LocalDataFlow.cs:117:22:117:52 | call to method Format | LocalDataFlow.cs:117:13:117:52 | SSA def(sink19) | +| LocalDataFlow.cs:117:36:117:41 | access to local variable sink18 | LocalDataFlow.cs:117:22:117:52 | call to method Format | +| LocalDataFlow.cs:117:44:117:51 | [post] access to local variable nonSink0 | LocalDataFlow.cs:136:32:136:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:117:44:117:51 | access to local variable nonSink0 | LocalDataFlow.cs:117:22:117:52 | call to method Format | +| LocalDataFlow.cs:117:44:117:51 | access to local variable nonSink0 | LocalDataFlow.cs:136:32:136:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:119:13:119:38 | SSA def(sink45) | LocalDataFlow.cs:120:15:120:20 | access to local variable sink45 | +| LocalDataFlow.cs:119:22:119:38 | call to method Parse | LocalDataFlow.cs:119:13:119:38 | SSA def(sink45) | +| LocalDataFlow.cs:119:33:119:37 | [post] access to local variable sink9 | LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | +| LocalDataFlow.cs:119:33:119:37 | access to local variable sink9 | LocalDataFlow.cs:119:22:119:38 | call to method Parse | +| LocalDataFlow.cs:119:33:119:37 | access to local variable sink9 | LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | +| LocalDataFlow.cs:122:13:122:56 | SSA def(sink46) | LocalDataFlow.cs:123:15:123:20 | access to local variable sink46 | +| LocalDataFlow.cs:122:22:122:56 | call to method TryParse | LocalDataFlow.cs:122:13:122:56 | SSA def(sink46) | +| LocalDataFlow.cs:122:36:122:40 | [post] access to local variable sink9 | LocalDataFlow.cs:162:22:162:26 | access to local variable sink9 | +| LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | LocalDataFlow.cs:122:22:122:56 | call to method TryParse | +| LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | LocalDataFlow.cs:162:22:162:26 | access to local variable sink9 | +| LocalDataFlow.cs:123:15:123:20 | access to local variable sink46 | LocalDataFlow.cs:124:37:124:42 | access to local variable sink46 | +| LocalDataFlow.cs:124:13:124:43 | SSA def(sink47) | LocalDataFlow.cs:125:15:125:20 | access to local variable sink47 | +| LocalDataFlow.cs:124:22:124:43 | call to method ToByte | LocalDataFlow.cs:124:13:124:43 | SSA def(sink47) | +| LocalDataFlow.cs:124:37:124:42 | access to local variable sink46 | LocalDataFlow.cs:124:22:124:43 | call to method ToByte | +| LocalDataFlow.cs:125:15:125:20 | access to local variable sink47 | LocalDataFlow.cs:126:40:126:45 | access to local variable sink47 | +| LocalDataFlow.cs:126:13:126:46 | SSA def(sink49) | LocalDataFlow.cs:127:15:127:20 | access to local variable sink49 | +| LocalDataFlow.cs:126:22:126:46 | call to method Concat | LocalDataFlow.cs:126:13:126:46 | SSA def(sink49) | +| LocalDataFlow.cs:126:36:126:37 | "" | LocalDataFlow.cs:126:22:126:46 | call to method Concat | +| LocalDataFlow.cs:126:40:126:45 | (...) ... | LocalDataFlow.cs:126:22:126:46 | call to method Concat | +| LocalDataFlow.cs:126:40:126:45 | access to local variable sink47 | LocalDataFlow.cs:126:40:126:45 | (...) ... | +| LocalDataFlow.cs:127:15:127:20 | [post] access to local variable sink49 | LocalDataFlow.cs:128:34:128:39 | access to local variable sink49 | +| LocalDataFlow.cs:127:15:127:20 | access to local variable sink49 | LocalDataFlow.cs:128:34:128:39 | access to local variable sink49 | +| LocalDataFlow.cs:128:13:128:40 | SSA def(sink50) | LocalDataFlow.cs:129:15:129:20 | access to local variable sink50 | +| LocalDataFlow.cs:128:22:128:40 | call to method Copy | LocalDataFlow.cs:128:13:128:40 | SSA def(sink50) | +| LocalDataFlow.cs:128:34:128:39 | access to local variable sink49 | LocalDataFlow.cs:128:22:128:40 | call to method Copy | +| LocalDataFlow.cs:129:15:129:20 | [post] access to local variable sink50 | LocalDataFlow.cs:130:59:130:64 | access to local variable sink50 | +| LocalDataFlow.cs:129:15:129:20 | access to local variable sink50 | LocalDataFlow.cs:130:59:130:64 | access to local variable sink50 | +| LocalDataFlow.cs:130:13:130:71 | SSA def(sink51) | LocalDataFlow.cs:131:15:131:20 | access to local variable sink51 | +| LocalDataFlow.cs:130:22:130:71 | call to method Join | LocalDataFlow.cs:130:13:130:71 | SSA def(sink51) | +| LocalDataFlow.cs:130:34:130:37 | ", " | LocalDataFlow.cs:130:22:130:71 | call to method Join | +| LocalDataFlow.cs:130:40:130:70 | array creation of type String[] | LocalDataFlow.cs:130:22:130:71 | call to method Join | +| LocalDataFlow.cs:130:53:130:70 | { ..., ... } | LocalDataFlow.cs:130:40:130:70 | array creation of type String[] | +| LocalDataFlow.cs:130:55:130:56 | "" | LocalDataFlow.cs:130:53:130:70 | { ..., ... } | +| LocalDataFlow.cs:130:59:130:64 | access to local variable sink50 | LocalDataFlow.cs:130:53:130:70 | { ..., ... } | +| LocalDataFlow.cs:130:67:130:68 | "" | LocalDataFlow.cs:130:53:130:70 | { ..., ... } | +| LocalDataFlow.cs:131:15:131:20 | [post] access to local variable sink51 | LocalDataFlow.cs:132:35:132:40 | access to local variable sink51 | +| LocalDataFlow.cs:131:15:131:20 | access to local variable sink51 | LocalDataFlow.cs:132:35:132:40 | access to local variable sink51 | +| LocalDataFlow.cs:132:13:132:41 | SSA def(sink52) | LocalDataFlow.cs:133:15:133:20 | access to local variable sink52 | +| LocalDataFlow.cs:132:22:132:23 | "" | LocalDataFlow.cs:132:22:132:41 | call to method Insert | +| LocalDataFlow.cs:132:22:132:41 | call to method Insert | LocalDataFlow.cs:132:13:132:41 | SSA def(sink52) | +| LocalDataFlow.cs:132:35:132:40 | access to local variable sink51 | LocalDataFlow.cs:132:22:132:41 | call to method Insert | +| LocalDataFlow.cs:136:9:136:40 | SSA def(nonSink2) | LocalDataFlow.cs:137:15:137:22 | access to local variable nonSink2 | +| LocalDataFlow.cs:136:20:136:40 | call to method Parse | LocalDataFlow.cs:136:9:136:40 | SSA def(nonSink2) | +| LocalDataFlow.cs:136:32:136:39 | [post] access to local variable nonSink0 | LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:136:32:136:39 | access to local variable nonSink0 | LocalDataFlow.cs:136:20:136:40 | call to method Parse | +| LocalDataFlow.cs:136:32:136:39 | access to local variable nonSink0 | LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:138:13:138:61 | SSA def(nonSink7) | LocalDataFlow.cs:139:15:139:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:138:24:138:61 | call to method TryParse | LocalDataFlow.cs:138:13:138:61 | SSA def(nonSink7) | +| LocalDataFlow.cs:138:39:138:46 | [post] access to local variable nonSink0 | LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | LocalDataFlow.cs:138:24:138:61 | call to method TryParse | +| LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:140:9:140:50 | SSA def(nonSink0) | LocalDataFlow.cs:141:15:141:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:140:20:140:27 | [post] access to local variable nonSink0 | LocalDataFlow.cs:140:42:140:49 | access to local variable nonSink0 | +| LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink0 | LocalDataFlow.cs:140:20:140:50 | call to method Replace | +| LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink0 | LocalDataFlow.cs:140:42:140:49 | access to local variable nonSink0 | +| LocalDataFlow.cs:140:20:140:50 | call to method Replace | LocalDataFlow.cs:140:9:140:50 | SSA def(nonSink0) | +| LocalDataFlow.cs:140:42:140:49 | access to local variable nonSink0 | LocalDataFlow.cs:140:20:140:50 | call to method Replace | +| LocalDataFlow.cs:141:15:141:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:142:34:142:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:141:15:141:22 | access to local variable nonSink0 | LocalDataFlow.cs:142:34:142:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:142:9:142:52 | SSA def(nonSink0) | LocalDataFlow.cs:143:15:143:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:142:20:142:52 | call to method Format | LocalDataFlow.cs:142:9:142:52 | SSA def(nonSink0) | +| LocalDataFlow.cs:142:34:142:41 | [post] access to local variable nonSink0 | LocalDataFlow.cs:142:44:142:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:142:34:142:41 | access to local variable nonSink0 | LocalDataFlow.cs:142:20:142:52 | call to method Format | +| LocalDataFlow.cs:142:34:142:41 | access to local variable nonSink0 | LocalDataFlow.cs:142:44:142:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:142:44:142:51 | access to local variable nonSink0 | LocalDataFlow.cs:142:20:142:52 | call to method Format | +| LocalDataFlow.cs:143:15:143:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:144:31:144:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:143:15:143:22 | access to local variable nonSink0 | LocalDataFlow.cs:144:31:144:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:144:9:144:39 | SSA def(nonSink7) | LocalDataFlow.cs:145:15:145:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:144:20:144:39 | call to method Parse | LocalDataFlow.cs:144:9:144:39 | SSA def(nonSink7) | +| LocalDataFlow.cs:144:31:144:38 | [post] access to local variable nonSink0 | LocalDataFlow.cs:146:34:146:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:144:31:144:38 | access to local variable nonSink0 | LocalDataFlow.cs:144:20:144:39 | call to method Parse | +| LocalDataFlow.cs:144:31:144:38 | access to local variable nonSink0 | LocalDataFlow.cs:146:34:146:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:146:9:146:57 | SSA def(nonSink7) | LocalDataFlow.cs:147:15:147:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:146:20:146:57 | call to method TryParse | LocalDataFlow.cs:146:9:146:57 | SSA def(nonSink7) | +| LocalDataFlow.cs:146:34:146:41 | access to local variable nonSink0 | LocalDataFlow.cs:146:20:146:57 | call to method TryParse | +| LocalDataFlow.cs:147:15:147:22 | access to local variable nonSink7 | LocalDataFlow.cs:148:40:148:47 | access to local variable nonSink7 | +| LocalDataFlow.cs:148:13:148:48 | SSA def(nonSink14) | LocalDataFlow.cs:149:15:149:23 | access to local variable nonSink14 | +| LocalDataFlow.cs:148:25:148:48 | call to method ToByte | LocalDataFlow.cs:148:13:148:48 | SSA def(nonSink14) | +| LocalDataFlow.cs:148:40:148:47 | access to local variable nonSink7 | LocalDataFlow.cs:148:25:148:48 | call to method ToByte | +| LocalDataFlow.cs:148:40:148:47 | access to local variable nonSink7 | LocalDataFlow.cs:150:38:150:45 | access to local variable nonSink7 | +| LocalDataFlow.cs:150:9:150:46 | SSA def(nonSink0) | LocalDataFlow.cs:151:15:151:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:150:20:150:46 | call to method Concat | LocalDataFlow.cs:150:9:150:46 | SSA def(nonSink0) | +| LocalDataFlow.cs:150:34:150:35 | "" | LocalDataFlow.cs:150:20:150:46 | call to method Concat | +| LocalDataFlow.cs:150:38:150:45 | (...) ... | LocalDataFlow.cs:150:20:150:46 | call to method Concat | +| LocalDataFlow.cs:150:38:150:45 | access to local variable nonSink7 | LocalDataFlow.cs:150:38:150:45 | (...) ... | +| LocalDataFlow.cs:151:15:151:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:152:32:152:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:151:15:151:22 | access to local variable nonSink0 | LocalDataFlow.cs:152:32:152:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:152:9:152:40 | SSA def(nonSink0) | LocalDataFlow.cs:153:15:153:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:152:20:152:40 | call to method Copy | LocalDataFlow.cs:152:9:152:40 | SSA def(nonSink0) | +| LocalDataFlow.cs:152:32:152:39 | access to local variable nonSink0 | LocalDataFlow.cs:152:20:152:40 | call to method Copy | +| LocalDataFlow.cs:153:15:153:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:154:57:154:64 | access to local variable nonSink0 | +| LocalDataFlow.cs:153:15:153:22 | access to local variable nonSink0 | LocalDataFlow.cs:154:57:154:64 | access to local variable nonSink0 | +| LocalDataFlow.cs:154:9:154:71 | SSA def(nonSink0) | LocalDataFlow.cs:155:15:155:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:154:20:154:71 | call to method Join | LocalDataFlow.cs:154:9:154:71 | SSA def(nonSink0) | +| LocalDataFlow.cs:154:32:154:35 | ", " | LocalDataFlow.cs:154:20:154:71 | call to method Join | +| LocalDataFlow.cs:154:38:154:70 | array creation of type String[] | LocalDataFlow.cs:154:20:154:71 | call to method Join | +| LocalDataFlow.cs:154:51:154:70 | { ..., ... } | LocalDataFlow.cs:154:38:154:70 | array creation of type String[] | +| LocalDataFlow.cs:154:53:154:54 | "" | LocalDataFlow.cs:154:51:154:70 | { ..., ... } | +| LocalDataFlow.cs:154:57:154:64 | access to local variable nonSink0 | LocalDataFlow.cs:154:51:154:70 | { ..., ... } | +| LocalDataFlow.cs:154:67:154:68 | "" | LocalDataFlow.cs:154:51:154:70 | { ..., ... } | +| LocalDataFlow.cs:155:15:155:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:156:33:156:40 | access to local variable nonSink0 | +| LocalDataFlow.cs:155:15:155:22 | access to local variable nonSink0 | LocalDataFlow.cs:156:33:156:40 | access to local variable nonSink0 | +| LocalDataFlow.cs:156:9:156:41 | SSA def(nonSink0) | LocalDataFlow.cs:157:15:157:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:156:20:156:21 | "" | LocalDataFlow.cs:156:20:156:41 | call to method Insert | +| LocalDataFlow.cs:156:20:156:41 | call to method Insert | LocalDataFlow.cs:156:9:156:41 | SSA def(nonSink0) | +| LocalDataFlow.cs:156:33:156:40 | access to local variable nonSink0 | LocalDataFlow.cs:156:20:156:41 | call to method Insert | +| LocalDataFlow.cs:157:15:157:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:194:39:194:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:157:15:157:22 | access to local variable nonSink0 | LocalDataFlow.cs:194:39:194:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:160:13:160:32 | SSA def(sink20) | LocalDataFlow.cs:161:15:161:20 | access to local variable sink20 | +| LocalDataFlow.cs:160:22:160:27 | access to local variable sink15 | LocalDataFlow.cs:160:22:160:32 | ... > ... | +| LocalDataFlow.cs:160:22:160:32 | ... > ... | LocalDataFlow.cs:160:13:160:32 | SSA def(sink20) | +| LocalDataFlow.cs:161:15:161:20 | access to local variable sink20 | LocalDataFlow.cs:174:22:174:27 | access to local variable sink20 | +| LocalDataFlow.cs:162:13:162:40 | SSA def(sink21) | LocalDataFlow.cs:163:15:163:20 | access to local variable sink21 | +| LocalDataFlow.cs:162:22:162:26 | [post] access to local variable sink9 | LocalDataFlow.cs:182:37:182:41 | access to local variable sink9 | +| LocalDataFlow.cs:162:22:162:26 | access to local variable sink9 | LocalDataFlow.cs:162:22:162:40 | call to method Equals | +| LocalDataFlow.cs:162:22:162:26 | access to local variable sink9 | LocalDataFlow.cs:182:37:182:41 | access to local variable sink9 | +| LocalDataFlow.cs:162:22:162:40 | call to method Equals | LocalDataFlow.cs:162:13:162:40 | SSA def(sink21) | +| LocalDataFlow.cs:164:13:164:45 | SSA def(sink22) | LocalDataFlow.cs:165:15:165:20 | access to local variable sink22 | +| LocalDataFlow.cs:164:22:164:26 | [post] access to local variable sink8 | LocalDataFlow.cs:170:20:170:24 | access to local variable sink8 | +| LocalDataFlow.cs:164:22:164:26 | access to local variable sink8 | LocalDataFlow.cs:164:22:164:45 | call to method Equals | +| LocalDataFlow.cs:164:22:164:26 | access to local variable sink8 | LocalDataFlow.cs:170:20:170:24 | access to local variable sink8 | +| LocalDataFlow.cs:164:22:164:45 | call to method Equals | LocalDataFlow.cs:164:13:164:45 | SSA def(sink22) | +| LocalDataFlow.cs:164:43:164:44 | 41 | LocalDataFlow.cs:164:35:164:44 | (...) ... | +| LocalDataFlow.cs:168:9:168:38 | SSA def(nonSink7) | LocalDataFlow.cs:169:15:169:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:168:20:168:24 | [post] access to local variable sink0 | LocalDataFlow.cs:281:30:281:34 | access to local variable sink0 | +| LocalDataFlow.cs:168:20:168:24 | access to local variable sink0 | LocalDataFlow.cs:281:30:281:34 | access to local variable sink0 | +| LocalDataFlow.cs:168:20:168:38 | call to method Equals | LocalDataFlow.cs:168:9:168:38 | SSA def(nonSink7) | +| LocalDataFlow.cs:168:33:168:37 | [post] access to local variable sink1 | LocalDataFlow.cs:273:30:273:34 | access to local variable sink1 | +| LocalDataFlow.cs:168:33:168:37 | access to local variable sink1 | LocalDataFlow.cs:273:30:273:34 | access to local variable sink1 | +| LocalDataFlow.cs:170:9:170:41 | SSA def(nonSink7) | LocalDataFlow.cs:171:15:171:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:170:20:170:41 | call to method Equals | LocalDataFlow.cs:170:9:170:41 | SSA def(nonSink7) | +| LocalDataFlow.cs:171:15:171:22 | access to local variable nonSink7 | LocalDataFlow.cs:178:20:178:27 | access to local variable nonSink7 | +| LocalDataFlow.cs:174:13:174:36 | SSA def(sink25) | LocalDataFlow.cs:175:15:175:20 | access to local variable sink25 | +| LocalDataFlow.cs:174:22:174:27 | access to local variable sink20 | LocalDataFlow.cs:174:22:174:36 | ... \|\| ... | +| LocalDataFlow.cs:174:22:174:36 | ... \|\| ... | LocalDataFlow.cs:174:13:174:36 | SSA def(sink25) | +| LocalDataFlow.cs:174:32:174:36 | false | LocalDataFlow.cs:174:22:174:36 | ... \|\| ... | +| LocalDataFlow.cs:178:9:178:36 | SSA def(nonSink7) | LocalDataFlow.cs:179:15:179:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:178:20:178:27 | access to local variable nonSink7 | LocalDataFlow.cs:178:20:178:36 | ... \|\| ... | +| LocalDataFlow.cs:178:20:178:36 | ... \|\| ... | LocalDataFlow.cs:178:9:178:36 | SSA def(nonSink7) | +| LocalDataFlow.cs:178:32:178:36 | false | LocalDataFlow.cs:178:20:178:36 | ... \|\| ... | +| LocalDataFlow.cs:182:13:182:42 | SSA def(sink26) | LocalDataFlow.cs:183:15:183:20 | access to local variable sink26 | +| LocalDataFlow.cs:182:22:182:42 | object creation of type Uri | LocalDataFlow.cs:182:13:182:42 | SSA def(sink26) | +| LocalDataFlow.cs:182:37:182:41 | access to local variable sink9 | LocalDataFlow.cs:182:22:182:42 | object creation of type Uri | +| LocalDataFlow.cs:183:15:183:20 | [post] access to local variable sink26 | LocalDataFlow.cs:184:22:184:27 | access to local variable sink26 | +| LocalDataFlow.cs:183:15:183:20 | access to local variable sink26 | LocalDataFlow.cs:184:22:184:27 | access to local variable sink26 | +| LocalDataFlow.cs:184:13:184:38 | SSA def(sink27) | LocalDataFlow.cs:185:15:185:20 | access to local variable sink27 | +| LocalDataFlow.cs:184:22:184:27 | [post] access to local variable sink26 | LocalDataFlow.cs:186:22:186:27 | access to local variable sink26 | +| LocalDataFlow.cs:184:22:184:27 | access to local variable sink26 | LocalDataFlow.cs:184:22:184:38 | call to method ToString | +| LocalDataFlow.cs:184:22:184:27 | access to local variable sink26 | LocalDataFlow.cs:186:22:186:27 | access to local variable sink26 | +| LocalDataFlow.cs:184:22:184:38 | call to method ToString | LocalDataFlow.cs:184:13:184:38 | SSA def(sink27) | +| LocalDataFlow.cs:186:13:186:40 | SSA def(sink28) | LocalDataFlow.cs:187:15:187:20 | access to local variable sink28 | +| LocalDataFlow.cs:186:22:186:27 | [post] access to local variable sink26 | LocalDataFlow.cs:188:22:188:27 | access to local variable sink26 | +| LocalDataFlow.cs:186:22:186:27 | access to local variable sink26 | LocalDataFlow.cs:186:22:186:40 | access to property PathAndQuery | +| LocalDataFlow.cs:186:22:186:27 | access to local variable sink26 | LocalDataFlow.cs:188:22:188:27 | access to local variable sink26 | +| LocalDataFlow.cs:186:22:186:40 | access to property PathAndQuery | LocalDataFlow.cs:186:13:186:40 | SSA def(sink28) | +| LocalDataFlow.cs:188:13:188:33 | SSA def(sink29) | LocalDataFlow.cs:189:15:189:20 | access to local variable sink29 | +| LocalDataFlow.cs:188:22:188:27 | [post] access to local variable sink26 | LocalDataFlow.cs:190:22:190:27 | access to local variable sink26 | +| LocalDataFlow.cs:188:22:188:27 | access to local variable sink26 | LocalDataFlow.cs:188:22:188:33 | access to property Query | +| LocalDataFlow.cs:188:22:188:27 | access to local variable sink26 | LocalDataFlow.cs:190:22:190:27 | access to local variable sink26 | +| LocalDataFlow.cs:188:22:188:33 | access to property Query | LocalDataFlow.cs:188:13:188:33 | SSA def(sink29) | +| LocalDataFlow.cs:190:13:190:42 | SSA def(sink30) | LocalDataFlow.cs:191:15:191:20 | access to local variable sink30 | +| LocalDataFlow.cs:190:22:190:27 | access to local variable sink26 | LocalDataFlow.cs:190:22:190:42 | access to property OriginalString | +| LocalDataFlow.cs:190:22:190:42 | access to property OriginalString | LocalDataFlow.cs:190:13:190:42 | SSA def(sink30) | +| LocalDataFlow.cs:191:15:191:20 | [post] access to local variable sink30 | LocalDataFlow.cs:206:49:206:54 | access to local variable sink30 | +| LocalDataFlow.cs:191:15:191:20 | access to local variable sink30 | LocalDataFlow.cs:206:49:206:54 | access to local variable sink30 | +| LocalDataFlow.cs:194:13:194:47 | SSA def(nonSink8) | LocalDataFlow.cs:195:15:195:22 | access to local variable nonSink8 | +| LocalDataFlow.cs:194:24:194:47 | object creation of type Uri | LocalDataFlow.cs:194:13:194:47 | SSA def(nonSink8) | +| LocalDataFlow.cs:194:39:194:46 | access to local variable nonSink0 | LocalDataFlow.cs:194:24:194:47 | object creation of type Uri | +| LocalDataFlow.cs:195:15:195:22 | [post] access to local variable nonSink8 | LocalDataFlow.cs:196:20:196:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:195:15:195:22 | access to local variable nonSink8 | LocalDataFlow.cs:196:20:196:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:196:9:196:38 | SSA def(nonSink0) | LocalDataFlow.cs:197:15:197:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:196:20:196:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:198:20:198:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:196:20:196:27 | access to local variable nonSink8 | LocalDataFlow.cs:196:20:196:38 | call to method ToString | +| LocalDataFlow.cs:196:20:196:27 | access to local variable nonSink8 | LocalDataFlow.cs:198:20:198:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:196:20:196:38 | call to method ToString | LocalDataFlow.cs:196:9:196:38 | SSA def(nonSink0) | +| LocalDataFlow.cs:198:9:198:40 | SSA def(nonSink0) | LocalDataFlow.cs:199:15:199:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:198:20:198:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:200:20:200:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:198:20:198:27 | access to local variable nonSink8 | LocalDataFlow.cs:198:20:198:40 | access to property PathAndQuery | +| LocalDataFlow.cs:198:20:198:27 | access to local variable nonSink8 | LocalDataFlow.cs:200:20:200:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:198:20:198:40 | access to property PathAndQuery | LocalDataFlow.cs:198:9:198:40 | SSA def(nonSink0) | +| LocalDataFlow.cs:200:9:200:33 | SSA def(nonSink0) | LocalDataFlow.cs:201:15:201:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:200:20:200:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:202:20:202:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:200:20:200:27 | access to local variable nonSink8 | LocalDataFlow.cs:200:20:200:33 | access to property Query | +| LocalDataFlow.cs:200:20:200:27 | access to local variable nonSink8 | LocalDataFlow.cs:202:20:202:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:200:20:200:33 | access to property Query | LocalDataFlow.cs:200:9:200:33 | SSA def(nonSink0) | +| LocalDataFlow.cs:202:9:202:42 | SSA def(nonSink0) | LocalDataFlow.cs:203:15:203:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:202:20:202:27 | access to local variable nonSink8 | LocalDataFlow.cs:202:20:202:42 | access to property OriginalString | +| LocalDataFlow.cs:202:20:202:42 | access to property OriginalString | LocalDataFlow.cs:202:9:202:42 | SSA def(nonSink0) | +| LocalDataFlow.cs:203:15:203:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:212:51:212:58 | access to local variable nonSink0 | +| LocalDataFlow.cs:203:15:203:22 | access to local variable nonSink0 | LocalDataFlow.cs:212:51:212:58 | access to local variable nonSink0 | +| LocalDataFlow.cs:206:13:206:55 | SSA def(sink31) | LocalDataFlow.cs:207:15:207:20 | access to local variable sink31 | +| LocalDataFlow.cs:206:22:206:55 | object creation of type StringReader | LocalDataFlow.cs:206:13:206:55 | SSA def(sink31) | +| LocalDataFlow.cs:206:49:206:54 | access to local variable sink30 | LocalDataFlow.cs:206:22:206:55 | object creation of type StringReader | +| LocalDataFlow.cs:207:15:207:20 | [post] access to local variable sink31 | LocalDataFlow.cs:208:22:208:27 | access to local variable sink31 | +| LocalDataFlow.cs:207:15:207:20 | access to local variable sink31 | LocalDataFlow.cs:208:22:208:27 | access to local variable sink31 | +| LocalDataFlow.cs:208:13:208:39 | SSA def(sink32) | LocalDataFlow.cs:209:15:209:20 | access to local variable sink32 | +| LocalDataFlow.cs:208:22:208:27 | access to local variable sink31 | LocalDataFlow.cs:208:22:208:39 | call to method ReadToEnd | +| LocalDataFlow.cs:208:22:208:39 | call to method ReadToEnd | LocalDataFlow.cs:208:13:208:39 | SSA def(sink32) | +| LocalDataFlow.cs:209:15:209:20 | [post] access to local variable sink32 | LocalDataFlow.cs:218:30:218:35 | access to local variable sink32 | +| LocalDataFlow.cs:209:15:209:20 | access to local variable sink32 | LocalDataFlow.cs:218:30:218:35 | access to local variable sink32 | +| LocalDataFlow.cs:212:13:212:59 | SSA def(nonSink9) | LocalDataFlow.cs:213:15:213:22 | access to local variable nonSink9 | +| LocalDataFlow.cs:212:24:212:59 | object creation of type StringReader | LocalDataFlow.cs:212:13:212:59 | SSA def(nonSink9) | +| LocalDataFlow.cs:212:51:212:58 | access to local variable nonSink0 | LocalDataFlow.cs:212:24:212:59 | object creation of type StringReader | +| LocalDataFlow.cs:213:15:213:22 | [post] access to local variable nonSink9 | LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink9 | +| LocalDataFlow.cs:213:15:213:22 | access to local variable nonSink9 | LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink9 | +| LocalDataFlow.cs:214:9:214:39 | SSA def(nonSink0) | LocalDataFlow.cs:215:15:215:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink9 | LocalDataFlow.cs:214:20:214:39 | call to method ReadToEnd | +| LocalDataFlow.cs:214:20:214:39 | call to method ReadToEnd | LocalDataFlow.cs:214:9:214:39 | SSA def(nonSink0) | +| LocalDataFlow.cs:215:15:215:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:224:28:224:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:215:15:215:22 | access to local variable nonSink0 | LocalDataFlow.cs:224:28:224:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:218:13:218:127 | SSA def(sink33) | LocalDataFlow.cs:219:15:219:20 | access to local variable sink33 | +| LocalDataFlow.cs:218:22:218:127 | (...) ... | LocalDataFlow.cs:218:13:218:127 | SSA def(sink33) | +| LocalDataFlow.cs:218:30:218:35 | access to local variable sink32 | LocalDataFlow.cs:218:30:218:48 | call to method Substring | +| LocalDataFlow.cs:218:30:218:48 | call to method Substring | LocalDataFlow.cs:218:30:218:67 | call to method ToLowerInvariant | +| LocalDataFlow.cs:218:30:218:67 | call to method ToLowerInvariant | LocalDataFlow.cs:218:30:218:77 | call to method ToUpper | +| LocalDataFlow.cs:218:30:218:77 | call to method ToUpper | LocalDataFlow.cs:218:30:218:87 | call to method Trim | +| LocalDataFlow.cs:218:30:218:87 | call to method Trim | LocalDataFlow.cs:218:30:218:105 | call to method Replace | +| LocalDataFlow.cs:218:30:218:105 | call to method Replace | LocalDataFlow.cs:218:30:218:119 | call to method Insert | +| LocalDataFlow.cs:218:30:218:119 | call to method Insert | LocalDataFlow.cs:218:30:218:127 | call to method Clone | +| LocalDataFlow.cs:218:30:218:127 | call to method Clone | LocalDataFlow.cs:218:22:218:127 | (...) ... | +| LocalDataFlow.cs:218:102:218:104 | "b" | LocalDataFlow.cs:218:30:218:105 | call to method Replace | +| LocalDataFlow.cs:218:117:218:118 | "" | LocalDataFlow.cs:218:30:218:119 | call to method Insert | +| LocalDataFlow.cs:219:15:219:20 | [post] access to local variable sink33 | LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | +| LocalDataFlow.cs:219:15:219:20 | access to local variable sink33 | LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | +| LocalDataFlow.cs:220:13:220:52 | SSA def(sink48) | LocalDataFlow.cs:221:15:221:20 | access to local variable sink48 | +| LocalDataFlow.cs:220:22:220:27 | [post] access to local variable sink33 | LocalDataFlow.cs:230:40:230:45 | access to local variable sink33 | +| LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | LocalDataFlow.cs:220:22:220:39 | call to method Normalize | +| LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | LocalDataFlow.cs:230:40:230:45 | access to local variable sink33 | +| LocalDataFlow.cs:220:22:220:39 | call to method Normalize | LocalDataFlow.cs:220:22:220:52 | call to method Remove | +| LocalDataFlow.cs:220:22:220:52 | call to method Remove | LocalDataFlow.cs:220:13:220:52 | SSA def(sink48) | +| LocalDataFlow.cs:224:9:224:127 | SSA def(nonSink0) | LocalDataFlow.cs:225:15:225:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:224:20:224:127 | (...) ... | LocalDataFlow.cs:224:9:224:127 | SSA def(nonSink0) | +| LocalDataFlow.cs:224:28:224:35 | access to local variable nonSink0 | LocalDataFlow.cs:224:28:224:48 | call to method Substring | +| LocalDataFlow.cs:224:28:224:48 | call to method Substring | LocalDataFlow.cs:224:28:224:67 | call to method ToLowerInvariant | +| LocalDataFlow.cs:224:28:224:67 | call to method ToLowerInvariant | LocalDataFlow.cs:224:28:224:77 | call to method ToUpper | +| LocalDataFlow.cs:224:28:224:77 | call to method ToUpper | LocalDataFlow.cs:224:28:224:87 | call to method Trim | +| LocalDataFlow.cs:224:28:224:87 | call to method Trim | LocalDataFlow.cs:224:28:224:105 | call to method Replace | +| LocalDataFlow.cs:224:28:224:105 | call to method Replace | LocalDataFlow.cs:224:28:224:119 | call to method Insert | +| LocalDataFlow.cs:224:28:224:119 | call to method Insert | LocalDataFlow.cs:224:28:224:127 | call to method Clone | +| LocalDataFlow.cs:224:28:224:127 | call to method Clone | LocalDataFlow.cs:224:20:224:127 | (...) ... | +| LocalDataFlow.cs:224:102:224:104 | "b" | LocalDataFlow.cs:224:28:224:105 | call to method Replace | +| LocalDataFlow.cs:224:117:224:118 | "" | LocalDataFlow.cs:224:28:224:119 | call to method Insert | +| LocalDataFlow.cs:225:15:225:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | +| LocalDataFlow.cs:225:15:225:22 | access to local variable nonSink0 | LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | +| LocalDataFlow.cs:226:13:226:57 | SSA def(nonSink15) | LocalDataFlow.cs:227:15:227:23 | access to local variable nonSink15 | +| LocalDataFlow.cs:226:25:226:32 | [post] access to local variable nonSink0 | LocalDataFlow.cs:239:43:239:50 | access to local variable nonSink0 | +| LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | LocalDataFlow.cs:226:25:226:44 | call to method Normalize | +| LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | LocalDataFlow.cs:239:43:239:50 | access to local variable nonSink0 | +| LocalDataFlow.cs:226:25:226:44 | call to method Normalize | LocalDataFlow.cs:226:25:226:57 | call to method Remove | +| LocalDataFlow.cs:226:25:226:57 | call to method Remove | LocalDataFlow.cs:226:13:226:57 | SSA def(nonSink15) | +| LocalDataFlow.cs:230:13:230:46 | SSA def(sink34) | LocalDataFlow.cs:231:15:231:20 | access to local variable sink34 | +| LocalDataFlow.cs:230:22:230:46 | object creation of type StringBuilder | LocalDataFlow.cs:230:13:230:46 | SSA def(sink34) | +| LocalDataFlow.cs:230:40:230:45 | access to local variable sink33 | LocalDataFlow.cs:230:22:230:46 | object creation of type StringBuilder | +| LocalDataFlow.cs:231:15:231:20 | [post] access to local variable sink34 | LocalDataFlow.cs:232:22:232:27 | access to local variable sink34 | +| LocalDataFlow.cs:231:15:231:20 | access to local variable sink34 | LocalDataFlow.cs:232:22:232:27 | access to local variable sink34 | +| LocalDataFlow.cs:232:13:232:38 | SSA def(sink35) | LocalDataFlow.cs:233:15:233:20 | access to local variable sink35 | +| LocalDataFlow.cs:232:22:232:27 | access to local variable sink34 | LocalDataFlow.cs:232:22:232:38 | call to method ToString | +| LocalDataFlow.cs:232:22:232:38 | call to method ToString | LocalDataFlow.cs:232:13:232:38 | SSA def(sink35) | +| LocalDataFlow.cs:233:15:233:20 | [post] access to local variable sink35 | LocalDataFlow.cs:235:27:235:32 | access to local variable sink35 | +| LocalDataFlow.cs:233:15:233:20 | access to local variable sink35 | LocalDataFlow.cs:235:27:235:32 | access to local variable sink35 | +| LocalDataFlow.cs:234:13:234:42 | SSA def(sink36) | LocalDataFlow.cs:235:9:235:14 | access to local variable sink36 | +| LocalDataFlow.cs:234:22:234:42 | object creation of type StringBuilder | LocalDataFlow.cs:234:13:234:42 | SSA def(sink36) | +| LocalDataFlow.cs:234:40:234:41 | "" | LocalDataFlow.cs:234:22:234:42 | object creation of type StringBuilder | +| LocalDataFlow.cs:235:9:235:14 | [post] access to local variable sink36 | LocalDataFlow.cs:236:15:236:20 | access to local variable sink36 | +| LocalDataFlow.cs:235:9:235:14 | access to local variable sink36 | LocalDataFlow.cs:236:15:236:20 | access to local variable sink36 | +| LocalDataFlow.cs:235:27:235:32 | access to local variable sink35 | LocalDataFlow.cs:235:9:235:14 | [post] access to local variable sink36 | +| LocalDataFlow.cs:235:27:235:32 | access to local variable sink35 | LocalDataFlow.cs:235:9:235:33 | call to method AppendLine | +| LocalDataFlow.cs:239:13:239:51 | SSA def(nonSink10) | LocalDataFlow.cs:240:15:240:23 | access to local variable nonSink10 | +| LocalDataFlow.cs:239:25:239:51 | object creation of type StringBuilder | LocalDataFlow.cs:239:13:239:51 | SSA def(nonSink10) | +| LocalDataFlow.cs:239:43:239:50 | access to local variable nonSink0 | LocalDataFlow.cs:239:25:239:51 | object creation of type StringBuilder | +| LocalDataFlow.cs:240:15:240:23 | [post] access to local variable nonSink10 | LocalDataFlow.cs:241:20:241:28 | access to local variable nonSink10 | +| LocalDataFlow.cs:240:15:240:23 | access to local variable nonSink10 | LocalDataFlow.cs:241:20:241:28 | access to local variable nonSink10 | +| LocalDataFlow.cs:241:9:241:39 | SSA def(nonSink0) | LocalDataFlow.cs:242:15:242:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:241:20:241:28 | [post] access to local variable nonSink10 | LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | +| LocalDataFlow.cs:241:20:241:28 | access to local variable nonSink10 | LocalDataFlow.cs:241:20:241:39 | call to method ToString | +| LocalDataFlow.cs:241:20:241:28 | access to local variable nonSink10 | LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | +| LocalDataFlow.cs:241:20:241:39 | call to method ToString | LocalDataFlow.cs:241:9:241:39 | SSA def(nonSink0) | +| LocalDataFlow.cs:242:15:242:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:243:30:243:37 | access to local variable nonSink0 | +| LocalDataFlow.cs:242:15:242:22 | access to local variable nonSink0 | LocalDataFlow.cs:243:30:243:37 | access to local variable nonSink0 | +| LocalDataFlow.cs:243:9:243:17 | [post] access to local variable nonSink10 | LocalDataFlow.cs:244:15:244:23 | access to local variable nonSink10 | +| LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | LocalDataFlow.cs:244:15:244:23 | access to local variable nonSink10 | +| LocalDataFlow.cs:243:30:243:37 | access to local variable nonSink0 | LocalDataFlow.cs:243:9:243:17 | [post] access to local variable nonSink10 | +| LocalDataFlow.cs:243:30:243:37 | access to local variable nonSink0 | LocalDataFlow.cs:243:9:243:38 | call to method AppendLine | +| LocalDataFlow.cs:247:13:247:52 | SSA def(taintedDataContract) | LocalDataFlow.cs:248:22:248:40 | access to local variable taintedDataContract | +| LocalDataFlow.cs:247:13:247:52 | SSA qualifier def(taintedDataContract.AList) | LocalDataFlow.cs:250:22:250:46 | access to property AList | +| LocalDataFlow.cs:247:35:247:52 | object creation of type DataContract | LocalDataFlow.cs:247:13:247:52 | SSA def(taintedDataContract) | +| LocalDataFlow.cs:248:13:248:48 | SSA def(sink53) | LocalDataFlow.cs:249:15:249:20 | access to local variable sink53 | +| LocalDataFlow.cs:248:22:248:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | +| LocalDataFlow.cs:248:22:248:40 | access to local variable taintedDataContract | LocalDataFlow.cs:248:22:248:48 | access to property AString | +| LocalDataFlow.cs:248:22:248:40 | access to local variable taintedDataContract | LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | +| LocalDataFlow.cs:248:22:248:48 | access to property AString | LocalDataFlow.cs:248:13:248:48 | SSA def(sink53) | +| LocalDataFlow.cs:250:13:250:57 | SSA def(sink54) | LocalDataFlow.cs:251:15:251:20 | access to local variable sink54 | +| LocalDataFlow.cs:250:22:250:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:257:20:257:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | LocalDataFlow.cs:250:22:250:46 | access to property AList | +| LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | LocalDataFlow.cs:257:20:257:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:250:22:250:46 | [post] access to property AList | LocalDataFlow.cs:259:20:259:44 | access to property AList | +| LocalDataFlow.cs:250:22:250:46 | access to property AList | LocalDataFlow.cs:250:22:250:49 | access to indexer | +| LocalDataFlow.cs:250:22:250:46 | access to property AList | LocalDataFlow.cs:259:20:259:44 | access to property AList | +| LocalDataFlow.cs:250:22:250:49 | access to indexer | LocalDataFlow.cs:250:22:250:57 | access to property AString | +| LocalDataFlow.cs:250:22:250:57 | access to property AString | LocalDataFlow.cs:250:13:250:57 | SSA def(sink54) | +| LocalDataFlow.cs:254:13:254:55 | SSA def(nonTaintedDataContract) | LocalDataFlow.cs:255:20:255:41 | access to local variable nonTaintedDataContract | +| LocalDataFlow.cs:254:38:254:55 | object creation of type DataContract | LocalDataFlow.cs:254:13:254:55 | SSA def(nonTaintedDataContract) | +| LocalDataFlow.cs:255:9:255:49 | SSA def(nonSink0) | LocalDataFlow.cs:256:15:256:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:255:20:255:41 | access to local variable nonTaintedDataContract | LocalDataFlow.cs:255:20:255:49 | access to property AString | +| LocalDataFlow.cs:255:20:255:49 | access to property AString | LocalDataFlow.cs:255:9:255:49 | SSA def(nonSink0) | +| LocalDataFlow.cs:257:9:257:44 | SSA def(nonSink2) | LocalDataFlow.cs:258:15:258:22 | access to local variable nonSink2 | +| LocalDataFlow.cs:257:20:257:38 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:259:20:259:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:257:20:257:38 | access to local variable taintedDataContract | LocalDataFlow.cs:259:20:259:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:257:20:257:44 | access to property AnInt | LocalDataFlow.cs:257:9:257:44 | SSA def(nonSink2) | +| LocalDataFlow.cs:259:9:259:53 | SSA def(nonSink2) | LocalDataFlow.cs:260:15:260:22 | access to local variable nonSink2 | +| LocalDataFlow.cs:259:20:259:38 | access to local variable taintedDataContract | LocalDataFlow.cs:259:20:259:44 | access to property AList | +| LocalDataFlow.cs:259:20:259:44 | access to property AList | LocalDataFlow.cs:259:20:259:47 | access to indexer | +| LocalDataFlow.cs:259:20:259:53 | access to property AnInt | LocalDataFlow.cs:259:9:259:53 | SSA def(nonSink2) | +| LocalDataFlow.cs:263:17:263:37 | SSA def(taintedTextBox) | LocalDataFlow.cs:264:22:264:35 | access to local variable taintedTextBox | +| LocalDataFlow.cs:263:34:263:37 | null | LocalDataFlow.cs:263:17:263:37 | SSA def(taintedTextBox) | +| LocalDataFlow.cs:264:13:264:40 | SSA def(sink60) | LocalDataFlow.cs:265:15:265:20 | access to local variable sink60 | +| LocalDataFlow.cs:264:22:264:35 | access to local variable taintedTextBox | LocalDataFlow.cs:264:22:264:40 | access to property Text | +| LocalDataFlow.cs:264:22:264:40 | access to property Text | LocalDataFlow.cs:264:13:264:40 | SSA def(sink60) | +| LocalDataFlow.cs:268:17:268:40 | SSA def(nonTaintedTextBox) | LocalDataFlow.cs:269:20:269:36 | access to local variable nonTaintedTextBox | +| LocalDataFlow.cs:268:37:268:40 | null | LocalDataFlow.cs:268:17:268:40 | SSA def(nonTaintedTextBox) | +| LocalDataFlow.cs:269:9:269:41 | SSA def(nonSink0) | LocalDataFlow.cs:270:15:270:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:269:20:269:36 | access to local variable nonTaintedTextBox | LocalDataFlow.cs:269:20:269:41 | access to property Text | +| LocalDataFlow.cs:269:20:269:41 | access to property Text | LocalDataFlow.cs:269:9:269:41 | SSA def(nonSink0) | +| LocalDataFlow.cs:270:15:270:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:277:28:277:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:270:15:270:22 | access to local variable nonSink0 | LocalDataFlow.cs:277:28:277:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:273:13:273:36 | SSA def(sink69) | LocalDataFlow.cs:274:15:274:20 | access to local variable sink69 | +| LocalDataFlow.cs:273:22:273:36 | $"..." | LocalDataFlow.cs:273:13:273:36 | SSA def(sink69) | +| LocalDataFlow.cs:273:24:273:28 | "test " | LocalDataFlow.cs:273:22:273:36 | $"..." | +| LocalDataFlow.cs:273:30:273:34 | access to local variable sink1 | LocalDataFlow.cs:273:22:273:36 | $"..." | +| LocalDataFlow.cs:277:9:277:37 | SSA def(nonSink0) | LocalDataFlow.cs:278:15:278:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:277:20:277:37 | $"..." | LocalDataFlow.cs:277:9:277:37 | SSA def(nonSink0) | +| LocalDataFlow.cs:277:22:277:26 | "test " | LocalDataFlow.cs:277:20:277:37 | $"..." | +| LocalDataFlow.cs:277:28:277:35 | access to local variable nonSink0 | LocalDataFlow.cs:277:20:277:37 | $"..." | +| LocalDataFlow.cs:278:15:278:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:285:31:285:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:278:15:278:22 | access to local variable nonSink0 | LocalDataFlow.cs:285:31:285:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:281:13:281:34 | SSA def(sink70) | LocalDataFlow.cs:282:15:282:20 | access to local variable sink70 | +| LocalDataFlow.cs:281:22:281:34 | ... = ... | LocalDataFlow.cs:281:13:281:34 | SSA def(sink70) | +| LocalDataFlow.cs:281:22:281:34 | SSA def(sink0) | LocalDataFlow.cs:313:34:313:38 | access to local variable sink0 | +| LocalDataFlow.cs:281:22:281:34 | SSA def(sink0) | LocalDataFlow.cs:314:22:314:26 | access to local variable sink0 | +| LocalDataFlow.cs:281:30:281:34 | access to local variable sink0 | LocalDataFlow.cs:281:22:281:34 | ... = ... | +| LocalDataFlow.cs:281:30:281:34 | access to local variable sink0 | LocalDataFlow.cs:281:22:281:34 | SSA def(sink0) | +| LocalDataFlow.cs:282:15:282:20 | [post] access to local variable sink70 | LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | +| LocalDataFlow.cs:282:15:282:20 | access to local variable sink70 | LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | +| LocalDataFlow.cs:285:9:285:38 | SSA def(nonSink0) | LocalDataFlow.cs:286:15:286:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:285:20:285:38 | ... = ... | LocalDataFlow.cs:285:9:285:38 | SSA def(nonSink0) | +| LocalDataFlow.cs:285:31:285:38 | access to local variable nonSink0 | LocalDataFlow.cs:285:20:285:38 | ... = ... | +| LocalDataFlow.cs:286:15:286:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | +| LocalDataFlow.cs:286:15:286:22 | access to local variable nonSink0 | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | +| LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | LocalDataFlow.cs:289:23:289:35 | SSA def(sink71) | +| LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | LocalDataFlow.cs:297:17:297:22 | access to local variable sink70 | +| LocalDataFlow.cs:289:23:289:35 | SSA def(sink71) | LocalDataFlow.cs:290:19:290:24 | access to local variable sink71 | +| LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | LocalDataFlow.cs:293:25:293:40 | SSA def(nonSink16) | +| LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | +| LocalDataFlow.cs:293:25:293:40 | SSA def(nonSink16) | LocalDataFlow.cs:294:19:294:27 | access to local variable nonSink16 | +| LocalDataFlow.cs:297:17:297:22 | access to local variable sink70 | LocalDataFlow.cs:299:18:299:30 | SSA def(sink72) | +| LocalDataFlow.cs:299:18:299:30 | SSA def(sink72) | LocalDataFlow.cs:300:23:300:28 | access to local variable sink72 | +| LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | LocalDataFlow.cs:307:18:307:33 | SSA def(nonSink17) | +| LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | LocalDataFlow.cs:313:22:313:29 | access to local variable nonSink0 | +| LocalDataFlow.cs:307:18:307:33 | SSA def(nonSink17) | LocalDataFlow.cs:308:23:308:31 | access to local variable nonSink17 | +| LocalDataFlow.cs:313:13:313:38 | SSA def(sink73) | LocalDataFlow.cs:315:15:315:20 | access to local variable sink73 | +| LocalDataFlow.cs:313:22:313:29 | access to local variable nonSink0 | LocalDataFlow.cs:313:22:313:38 | ... ?? ... | +| LocalDataFlow.cs:313:22:313:29 | access to local variable nonSink0 | LocalDataFlow.cs:314:31:314:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:313:22:313:38 | ... ?? ... | LocalDataFlow.cs:313:13:313:38 | SSA def(sink73) | +| LocalDataFlow.cs:313:34:313:38 | access to local variable sink0 | LocalDataFlow.cs:313:22:313:38 | ... ?? ... | +| LocalDataFlow.cs:313:34:313:38 | access to local variable sink0 | LocalDataFlow.cs:314:22:314:26 | access to local variable sink0 | +| LocalDataFlow.cs:314:13:314:38 | SSA def(sink74) | LocalDataFlow.cs:316:15:316:20 | access to local variable sink74 | +| LocalDataFlow.cs:314:22:314:26 | access to local variable sink0 | LocalDataFlow.cs:314:22:314:38 | ... ?? ... | +| LocalDataFlow.cs:314:22:314:38 | ... ?? ... | LocalDataFlow.cs:314:13:314:38 | SSA def(sink74) | +| LocalDataFlow.cs:314:31:314:38 | access to local variable nonSink0 | LocalDataFlow.cs:314:22:314:38 | ... ?? ... | +| LocalDataFlow.cs:334:28:334:30 | this | LocalDataFlow.cs:334:41:334:45 | this access | +| LocalDataFlow.cs:334:50:334:52 | this | LocalDataFlow.cs:334:56:334:60 | this access | +| LocalDataFlow.cs:334:50:334:52 | value | LocalDataFlow.cs:334:64:334:68 | access to parameter value | +| LocalDataFlow.cs:340:41:340:47 | tainted | LocalDataFlow.cs:342:15:342:21 | access to parameter tainted | +| LocalDataFlow.cs:345:44:345:53 | nonTainted | LocalDataFlow.cs:347:15:347:24 | access to parameter nonTainted | +| LocalDataFlow.cs:350:44:350:44 | x | LocalDataFlow.cs:353:21:353:21 | access to parameter x | +| LocalDataFlow.cs:350:67:350:68 | os | LocalDataFlow.cs:356:33:356:34 | access to parameter os | +| LocalDataFlow.cs:353:21:353:21 | access to parameter x | LocalDataFlow.cs:353:16:353:21 | ... = ... | +| LocalDataFlow.cs:356:33:356:34 | access to parameter os | LocalDataFlow.cs:356:27:356:34 | ... = ... | +| LocalDataFlow.cs:361:41:361:44 | args | LocalDataFlow.cs:363:29:363:32 | access to parameter args | +| LocalDataFlow.cs:363:29:363:32 | [post] access to parameter args | LocalDataFlow.cs:364:27:364:30 | access to parameter args | +| LocalDataFlow.cs:363:29:363:32 | access to parameter args | LocalDataFlow.cs:363:29:363:32 | call to operator implicit conversion | +| LocalDataFlow.cs:363:29:363:32 | access to parameter args | LocalDataFlow.cs:364:27:364:30 | access to parameter args | | SSA.cs:5:17:5:17 | SSA entry def(this.S) | SSA.cs:67:9:67:14 | access to field S | | SSA.cs:5:17:5:17 | this | SSA.cs:67:9:67:12 | this access | | SSA.cs:5:26:5:32 | tainted | SSA.cs:8:24:8:30 | access to parameter tainted | @@ -1011,12 +890,16 @@ | Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | Splitting.cs:52:9:52:9 | [b (line 46): true] access to local variable y | | Splitting.cs:51:17:51:36 | [b (line 46): false] array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): false] SSA def(y) | | Splitting.cs:51:17:51:36 | [b (line 46): true] array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | -| Splitting.cs:51:32:51:34 | [b (line 46): false] "a" | Splitting.cs:51:17:51:36 | [b (line 46): false] array creation of type String[] | -| Splitting.cs:51:32:51:34 | [b (line 46): true] "a" | Splitting.cs:51:17:51:36 | [b (line 46): true] array creation of type String[] | +| Splitting.cs:51:30:51:36 | [b (line 46): false] { ..., ... } | Splitting.cs:51:17:51:36 | [b (line 46): false] array creation of type String[] | +| Splitting.cs:51:30:51:36 | [b (line 46): true] { ..., ... } | Splitting.cs:51:17:51:36 | [b (line 46): true] array creation of type String[] | +| Splitting.cs:51:32:51:34 | [b (line 46): false] "a" | Splitting.cs:51:30:51:36 | [b (line 46): false] { ..., ... } | +| Splitting.cs:51:32:51:34 | [b (line 46): true] "a" | Splitting.cs:51:30:51:36 | [b (line 46): true] { ..., ... } | | Splitting.cs:52:9:52:9 | [b (line 46): false] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): false] access to local variable y | | Splitting.cs:52:9:52:9 | [b (line 46): true] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): true] access to local variable y | -| Splitting.cs:52:16:52:18 | [b (line 46): false] "b" | Splitting.cs:52:9:52:9 | [b (line 46): false] access to local variable y | -| Splitting.cs:52:16:52:18 | [b (line 46): true] "b" | Splitting.cs:52:9:52:9 | [b (line 46): true] access to local variable y | +| Splitting.cs:52:9:52:9 | [post] [b (line 46): false] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): false] access to local variable y | +| Splitting.cs:52:9:52:9 | [post] [b (line 46): true] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): true] access to local variable y | +| Splitting.cs:52:16:52:18 | [b (line 46): false] "b" | Splitting.cs:52:9:52:9 | [post] [b (line 46): false] access to local variable y | +| Splitting.cs:52:16:52:18 | [b (line 46): true] "b" | Splitting.cs:52:9:52:9 | [post] [b (line 46): true] access to local variable y | | Splitting.cs:53:9:53:20 | [b (line 46): false] SSA def(x) | Splitting.cs:54:17:54:17 | [b (line 46): false] access to local variable x | | Splitting.cs:53:9:53:20 | [b (line 46): true] SSA def(x) | Splitting.cs:54:17:54:17 | [b (line 46): true] access to local variable x | | Splitting.cs:53:13:53:13 | [b (line 46): false] access to local variable x | Splitting.cs:53:13:53:20 | [b (line 46): false] ... + ... | diff --git a/csharp/ql/test/library-tests/dataflow/modulusanalysis/ModulusAnalysis.cs b/csharp/ql/test/library-tests/dataflow/modulusanalysis/ModulusAnalysis.cs new file mode 100644 index 000000000000..8c55e74372be --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/modulusanalysis/ModulusAnalysis.cs @@ -0,0 +1,84 @@ +using System; +using System.Linq; + +class ModulusAnalysis +{ + const int c1 = 42; + const int c2 = 43; + + void M(int i, bool cond, int x, int y, int[] arr, int otherSeven) + { + var eq = i + 3; + + var mul = eq * c1 + 3; // congruent 3 mod 42 + + int seven = 7; + if (mul % c2 == seven) + { + System.Console.WriteLine(mul); // congruent 7 mod 43, 3 mod 42 + } + + if (otherSeven == 7) + { + if (mul % c2 == otherSeven) + { + System.Console.WriteLine(mul); // congruent 3 mod 42, 7 mod 43 missing + } + } + + var j = cond + ? i * 4 + 3 + : i * 8 + 7; + System.Console.WriteLine(j); // congruent 3 mod 4 + + if (x % c1 == 3 && y % c1 == 7) + { + System.Console.WriteLine(x + y); // congruent 10 mod 42 + } + + if (x % c1 == 3 && y % c1 == 7) + { + System.Console.WriteLine(x - y); // congruent 38 mod 42 + } + + var l = arr.Length * 4 - 11; // congruent 1 mod 4 + System.Console.WriteLine(l); + + l = GetArray().Length * 4 - 11; + System.Console.WriteLine(l); // congruent 1 mod 4 + + if (cond) + { + j = i * 4 + 3; + } + else + { + j = i * 8 + 7; + } + System.Console.WriteLine(j); // congruent 3 mod 4 or 7 mod 8 + + if (cond) + { + System.Console.WriteLine(j); // congruent 3 mod 4 + } + else + { + System.Console.WriteLine(j); // congruent 7 mod 8 + } + + var t = 64; + System.Console.WriteLine(t & 32); // congruent 0 mod 32 + System.Console.WriteLine(t & 16); // congruent 0 mod 16 + t = 1; + System.Console.WriteLine(t << 2); // congruent 0 mod 4 + + if ((x & 15) == 3) + { + System.Console.WriteLine(x); // congruent 3 mod 16 + } + } + + + + int[] GetArray(){ return new int[42]; } +} \ No newline at end of file diff --git a/csharp/ql/test/library-tests/dataflow/modulusanalysis/ModulusAnalysis.expected b/csharp/ql/test/library-tests/dataflow/modulusanalysis/ModulusAnalysis.expected new file mode 100644 index 000000000000..c7bacd769437 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/modulusanalysis/ModulusAnalysis.expected @@ -0,0 +1,138 @@ +| ModulusAnalysis.cs:6:15:6:21 | ... = ... | 0 | 42 | 0 | +| ModulusAnalysis.cs:6:20:6:21 | 42 | 0 | 42 | 0 | +| ModulusAnalysis.cs:7:15:7:21 | ... = ... | 0 | 43 | 0 | +| ModulusAnalysis.cs:7:20:7:21 | 43 | 0 | 43 | 0 | +| ModulusAnalysis.cs:11:18:11:18 | access to parameter i | SSA param(i) | 0 | 0 | +| ModulusAnalysis.cs:11:18:11:22 | ... + ... | SSA param(i) | 3 | 0 | +| ModulusAnalysis.cs:11:22:11:22 | 3 | 0 | 3 | 0 | +| ModulusAnalysis.cs:13:19:13:20 | access to local variable eq | SSA def(eq) | 0 | 0 | +| ModulusAnalysis.cs:13:19:13:20 | access to local variable eq | SSA param(i) | 3 | 0 | +| ModulusAnalysis.cs:13:19:13:25 | ... * ... | 0 | 0 | 42 | +| ModulusAnalysis.cs:13:19:13:29 | ... + ... | 0 | 3 | 42 | +| ModulusAnalysis.cs:13:24:13:25 | access to constant c1 | 0 | 42 | 0 | +| ModulusAnalysis.cs:13:24:13:25 | access to constant c1 | SSA entry def(ModulusAnalysis.c1) | 0 | 0 | +| ModulusAnalysis.cs:13:29:13:29 | 3 | 0 | 3 | 0 | +| ModulusAnalysis.cs:15:21:15:21 | 7 | 0 | 7 | 0 | +| ModulusAnalysis.cs:16:13:16:15 | access to local variable mul | 0 | 3 | 42 | +| ModulusAnalysis.cs:16:13:16:15 | access to local variable mul | SSA def(mul) | 0 | 0 | +| ModulusAnalysis.cs:16:19:16:20 | access to constant c2 | 0 | 43 | 0 | +| ModulusAnalysis.cs:16:19:16:20 | access to constant c2 | SSA entry def(ModulusAnalysis.c2) | 0 | 0 | +| ModulusAnalysis.cs:16:25:16:29 | access to local variable seven | 0 | 7 | 0 | +| ModulusAnalysis.cs:16:25:16:29 | access to local variable seven | SSA def(seven) | 0 | 0 | +| ModulusAnalysis.cs:18:38:18:40 | access to local variable mul | 0 | 3 | 42 | +| ModulusAnalysis.cs:18:38:18:40 | access to local variable mul | 0 | 7 | 43 | +| ModulusAnalysis.cs:18:38:18:40 | access to local variable mul | SSA def(mul) | 0 | 0 | +| ModulusAnalysis.cs:21:13:21:22 | access to parameter otherSeven | SSA param(otherSeven) | 0 | 0 | +| ModulusAnalysis.cs:21:27:21:27 | 7 | 0 | 7 | 0 | +| ModulusAnalysis.cs:23:17:23:19 | access to local variable mul | 0 | 3 | 42 | +| ModulusAnalysis.cs:23:17:23:19 | access to local variable mul | SSA def(mul) | 0 | 0 | +| ModulusAnalysis.cs:23:23:23:24 | access to constant c2 | 0 | 43 | 0 | +| ModulusAnalysis.cs:23:23:23:24 | access to constant c2 | SSA entry def(ModulusAnalysis.c2) | 0 | 0 | +| ModulusAnalysis.cs:23:29:23:38 | access to parameter otherSeven | 0 | 7 | 0 | +| ModulusAnalysis.cs:23:29:23:38 | access to parameter otherSeven | SSA param(otherSeven) | 0 | 0 | +| ModulusAnalysis.cs:25:42:25:44 | access to local variable mul | 0 | 3 | 42 | +| ModulusAnalysis.cs:25:42:25:44 | access to local variable mul | SSA def(mul) | 0 | 0 | +| ModulusAnalysis.cs:29:17:31:23 | ... ? ... : ... | 0 | 3 | 4 | +| ModulusAnalysis.cs:30:15:30:15 | access to parameter i | SSA param(i) | 0 | 0 | +| ModulusAnalysis.cs:30:15:30:19 | ... * ... | 0 | 0 | 4 | +| ModulusAnalysis.cs:30:15:30:23 | ... + ... | 0 | 3 | 4 | +| ModulusAnalysis.cs:30:19:30:19 | 4 | 0 | 4 | 0 | +| ModulusAnalysis.cs:30:23:30:23 | 3 | 0 | 3 | 0 | +| ModulusAnalysis.cs:31:15:31:15 | access to parameter i | SSA param(i) | 0 | 0 | +| ModulusAnalysis.cs:31:15:31:19 | ... * ... | 0 | 0 | 8 | +| ModulusAnalysis.cs:31:15:31:23 | ... + ... | 0 | 7 | 8 | +| ModulusAnalysis.cs:31:19:31:19 | 8 | 0 | 8 | 0 | +| ModulusAnalysis.cs:31:23:31:23 | 7 | 0 | 7 | 0 | +| ModulusAnalysis.cs:32:34:32:34 | access to local variable j | 0 | 3 | 4 | +| ModulusAnalysis.cs:32:34:32:34 | access to local variable j | [cond (line 9): false] SSA def(j) | 0 | 0 | +| ModulusAnalysis.cs:32:34:32:34 | access to local variable j | [cond (line 9): true] SSA def(j) | 0 | 0 | +| ModulusAnalysis.cs:34:13:34:13 | access to parameter x | SSA param(x) | 0 | 0 | +| ModulusAnalysis.cs:34:17:34:18 | access to constant c1 | 0 | 42 | 0 | +| ModulusAnalysis.cs:34:17:34:18 | access to constant c1 | SSA entry def(ModulusAnalysis.c1) | 0 | 0 | +| ModulusAnalysis.cs:34:23:34:23 | 3 | 0 | 3 | 0 | +| ModulusAnalysis.cs:34:28:34:28 | access to parameter y | SSA param(y) | 0 | 0 | +| ModulusAnalysis.cs:34:32:34:33 | access to constant c1 | 0 | 42 | 0 | +| ModulusAnalysis.cs:34:32:34:33 | access to constant c1 | SSA entry def(ModulusAnalysis.c1) | 0 | 0 | +| ModulusAnalysis.cs:34:38:34:38 | 7 | 0 | 7 | 0 | +| ModulusAnalysis.cs:36:38:36:38 | access to parameter x | 0 | 3 | 42 | +| ModulusAnalysis.cs:36:38:36:38 | access to parameter x | SSA param(x) | 0 | 0 | +| ModulusAnalysis.cs:36:38:36:42 | ... + ... | 0 | 10 | 42 | +| ModulusAnalysis.cs:36:38:36:42 | ... + ... | SSA param(x) | 7 | 42 | +| ModulusAnalysis.cs:36:38:36:42 | ... + ... | SSA param(y) | 3 | 42 | +| ModulusAnalysis.cs:36:42:36:42 | access to parameter y | 0 | 7 | 42 | +| ModulusAnalysis.cs:36:42:36:42 | access to parameter y | SSA param(y) | 0 | 0 | +| ModulusAnalysis.cs:39:13:39:13 | access to parameter x | SSA param(x) | 0 | 0 | +| ModulusAnalysis.cs:39:17:39:18 | access to constant c1 | 0 | 42 | 0 | +| ModulusAnalysis.cs:39:17:39:18 | access to constant c1 | SSA entry def(ModulusAnalysis.c1) | 0 | 0 | +| ModulusAnalysis.cs:39:23:39:23 | 3 | 0 | 3 | 0 | +| ModulusAnalysis.cs:39:28:39:28 | access to parameter y | SSA param(y) | 0 | 0 | +| ModulusAnalysis.cs:39:32:39:33 | access to constant c1 | 0 | 42 | 0 | +| ModulusAnalysis.cs:39:32:39:33 | access to constant c1 | SSA entry def(ModulusAnalysis.c1) | 0 | 0 | +| ModulusAnalysis.cs:39:38:39:38 | 7 | 0 | 7 | 0 | +| ModulusAnalysis.cs:41:38:41:38 | access to parameter x | 0 | 3 | 42 | +| ModulusAnalysis.cs:41:38:41:38 | access to parameter x | SSA param(x) | 0 | 0 | +| ModulusAnalysis.cs:41:38:41:42 | ... - ... | 0 | 38 | 42 | +| ModulusAnalysis.cs:41:38:41:42 | ... - ... | SSA param(x) | 35 | 42 | +| ModulusAnalysis.cs:41:42:41:42 | access to parameter y | 0 | 7 | 42 | +| ModulusAnalysis.cs:41:42:41:42 | access to parameter y | SSA param(y) | 0 | 0 | +| ModulusAnalysis.cs:44:17:44:26 | access to property Length | [cond (line 9): false] SSA untracked def(arr.Length) | 0 | 0 | +| ModulusAnalysis.cs:44:17:44:26 | access to property Length | [cond (line 9): true] SSA untracked def(arr.Length) | 0 | 0 | +| ModulusAnalysis.cs:44:17:44:30 | ... * ... | 0 | 0 | 4 | +| ModulusAnalysis.cs:44:17:44:35 | ... - ... | 0 | 1 | 4 | +| ModulusAnalysis.cs:44:30:44:30 | 4 | 0 | 4 | 0 | +| ModulusAnalysis.cs:44:34:44:35 | 11 | 0 | 11 | 0 | +| ModulusAnalysis.cs:45:34:45:34 | access to local variable l | 0 | 1 | 4 | +| ModulusAnalysis.cs:45:34:45:34 | access to local variable l | [cond (line 9): false] SSA def(l) | 0 | 0 | +| ModulusAnalysis.cs:45:34:45:34 | access to local variable l | [cond (line 9): true] SSA def(l) | 0 | 0 | +| ModulusAnalysis.cs:47:9:47:38 | ... = ... | 0 | 1 | 4 | +| ModulusAnalysis.cs:47:13:47:29 | access to property Length | access to property Length | 0 | 0 | +| ModulusAnalysis.cs:47:13:47:33 | ... * ... | 0 | 0 | 4 | +| ModulusAnalysis.cs:47:13:47:38 | ... - ... | 0 | 1 | 4 | +| ModulusAnalysis.cs:47:33:47:33 | 4 | 0 | 4 | 0 | +| ModulusAnalysis.cs:47:37:47:38 | 11 | 0 | 11 | 0 | +| ModulusAnalysis.cs:48:34:48:34 | access to local variable l | 0 | 1 | 4 | +| ModulusAnalysis.cs:48:34:48:34 | access to local variable l | [cond (line 9): false] SSA def(l) | 0 | 0 | +| ModulusAnalysis.cs:48:34:48:34 | access to local variable l | [cond (line 9): true] SSA def(l) | 0 | 0 | +| ModulusAnalysis.cs:52:13:52:25 | ... = ... | 0 | 3 | 4 | +| ModulusAnalysis.cs:52:17:52:17 | access to parameter i | SSA param(i) | 0 | 0 | +| ModulusAnalysis.cs:52:17:52:21 | ... * ... | 0 | 0 | 4 | +| ModulusAnalysis.cs:52:17:52:25 | ... + ... | 0 | 3 | 4 | +| ModulusAnalysis.cs:52:21:52:21 | 4 | 0 | 4 | 0 | +| ModulusAnalysis.cs:52:25:52:25 | 3 | 0 | 3 | 0 | +| ModulusAnalysis.cs:56:13:56:25 | ... = ... | 0 | 7 | 8 | +| ModulusAnalysis.cs:56:17:56:17 | access to parameter i | SSA param(i) | 0 | 0 | +| ModulusAnalysis.cs:56:17:56:21 | ... * ... | 0 | 0 | 8 | +| ModulusAnalysis.cs:56:17:56:25 | ... + ... | 0 | 7 | 8 | +| ModulusAnalysis.cs:56:21:56:21 | 8 | 0 | 8 | 0 | +| ModulusAnalysis.cs:56:25:56:25 | 7 | 0 | 7 | 0 | +| ModulusAnalysis.cs:58:34:58:34 | access to local variable j | 0 | 3 | 4 | +| ModulusAnalysis.cs:58:34:58:34 | access to local variable j | 0 | 7 | 8 | +| ModulusAnalysis.cs:58:34:58:34 | access to local variable j | [cond (line 9): false] SSA def(j) | 0 | 0 | +| ModulusAnalysis.cs:58:34:58:34 | access to local variable j | [cond (line 9): true] SSA def(j) | 0 | 0 | +| ModulusAnalysis.cs:62:38:62:38 | access to local variable j | 0 | 3 | 4 | +| ModulusAnalysis.cs:62:38:62:38 | access to local variable j | [cond (line 9): true] SSA def(j) | 0 | 0 | +| ModulusAnalysis.cs:66:38:66:38 | access to local variable j | 0 | 7 | 8 | +| ModulusAnalysis.cs:66:38:66:38 | access to local variable j | [cond (line 9): false] SSA def(j) | 0 | 0 | +| ModulusAnalysis.cs:69:17:69:18 | 64 | 0 | 64 | 0 | +| ModulusAnalysis.cs:70:34:70:34 | access to local variable t | 0 | 64 | 0 | +| ModulusAnalysis.cs:70:34:70:34 | access to local variable t | SSA def(t) | 0 | 0 | +| ModulusAnalysis.cs:70:34:70:39 | ... & ... | 0 | 0 | 32 | +| ModulusAnalysis.cs:70:34:70:39 | ... & ... | 0 | 0 | 64 | +| ModulusAnalysis.cs:70:38:70:39 | 32 | 0 | 32 | 0 | +| ModulusAnalysis.cs:71:34:71:34 | access to local variable t | 0 | 64 | 0 | +| ModulusAnalysis.cs:71:34:71:34 | access to local variable t | SSA def(t) | 0 | 0 | +| ModulusAnalysis.cs:71:34:71:39 | ... & ... | 0 | 0 | 16 | +| ModulusAnalysis.cs:71:34:71:39 | ... & ... | 0 | 0 | 64 | +| ModulusAnalysis.cs:71:38:71:39 | 16 | 0 | 16 | 0 | +| ModulusAnalysis.cs:72:9:72:13 | ... = ... | 0 | 1 | 0 | +| ModulusAnalysis.cs:72:13:72:13 | 1 | 0 | 1 | 0 | +| ModulusAnalysis.cs:73:34:73:34 | access to local variable t | 0 | 1 | 0 | +| ModulusAnalysis.cs:73:34:73:34 | access to local variable t | SSA def(t) | 0 | 0 | +| ModulusAnalysis.cs:73:34:73:39 | ... << ... | 0 | 0 | 4 | +| ModulusAnalysis.cs:73:39:73:39 | 2 | 0 | 2 | 0 | +| ModulusAnalysis.cs:75:14:75:14 | access to parameter x | SSA param(x) | 0 | 0 | +| ModulusAnalysis.cs:75:18:75:19 | 15 | 0 | 15 | 0 | +| ModulusAnalysis.cs:75:25:75:25 | 3 | 0 | 3 | 0 | +| ModulusAnalysis.cs:77:38:77:38 | access to parameter x | 0 | 3 | 16 | +| ModulusAnalysis.cs:77:38:77:38 | access to parameter x | SSA param(x) | 0 | 0 | +| ModulusAnalysis.cs:83:38:83:39 | 42 | 0 | 42 | 0 | diff --git a/csharp/ql/test/library-tests/dataflow/modulusanalysis/ModulusAnalysis.ql b/csharp/ql/test/library-tests/dataflow/modulusanalysis/ModulusAnalysis.ql new file mode 100644 index 000000000000..f92649fa5b25 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/modulusanalysis/ModulusAnalysis.ql @@ -0,0 +1,7 @@ +import csharp +import semmle.code.csharp.dataflow.ModulusAnalysis +import semmle.code.csharp.dataflow.Bound + +from Expr e, Bound b, int delta, int mod +where exprModulus(e, b, delta, mod) +select e, b.toString(), delta, mod diff --git a/docs/language/global-sphinx-files/_static/.gitkeep b/csharp/ql/test/library-tests/dataflow/signanalysis/MissingSign.expected similarity index 100% rename from docs/language/global-sphinx-files/_static/.gitkeep rename to csharp/ql/test/library-tests/dataflow/signanalysis/MissingSign.expected diff --git a/csharp/ql/test/library-tests/dataflow/signanalysis/MissingSign.ql b/csharp/ql/test/library-tests/dataflow/signanalysis/MissingSign.ql new file mode 100644 index 000000000000..836980829a33 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/signanalysis/MissingSign.ql @@ -0,0 +1,16 @@ +import csharp +import semmle.code.csharp.dataflow.SignAnalysis + +from Expr e +where + not exists(exprSign(e)) and + not e instanceof TypeAccess and + ( + e.getType() instanceof CharType or + e.getType() instanceof IntegralType or + e.getType() instanceof FloatingPointType or + e.getType() instanceof DecimalType or + e.getType() instanceof Enum or + e.getType() instanceof PointerType + ) +select e diff --git a/csharp/ql/test/library-tests/dataflow/signanalysis/SignAnalysis.cs b/csharp/ql/test/library-tests/dataflow/signanalysis/SignAnalysis.cs new file mode 100644 index 000000000000..de8f52d77f3c --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/signanalysis/SignAnalysis.cs @@ -0,0 +1,469 @@ +using System; +using System.Linq; +using System.Diagnostics; + +class SignAnalysis +{ + static int GetRandomValue() { return (new System.Random()).Next(0, 1000) - 500; } + + int RandomValue { get => GetRandomValue(); } + + int random = GetRandomValue(); + + int SsaSources(int p, int[] values) + { + var v = GetRandomValue(); + if (v < 0) + { + return v; + } + + v = RandomValue; + if (v < 0) + { + return v; + } + + v = p; + if (v < 0) + { + return v; + } + + v = random; + if (v < 0) + { + return v; + } + + v = values[0]; + if (v < 0) + { + return v; + } + + int x = values[1]; + v = x; + if (v < 0) + { + return v; + } + + return 0; + } + + void Operations(int i, int j, bool b) + { + if (i < 0 && j < 0) + { + var x = i + j; + System.Console.WriteLine(x); // strictly neg + x = i * j; + System.Console.WriteLine(x); // strictly pos + x = i / j; + System.Console.WriteLine(x); // pos + x = i - j; + System.Console.WriteLine(x); // no clue + x = i % j; + System.Console.WriteLine(x); // neg + x = i++; + System.Console.WriteLine(x); // strictly neg + x = i--; + System.Console.WriteLine(x); // neg + x = -i; + System.Console.WriteLine(x); // strictly pos + x = +i; + System.Console.WriteLine(x); // strictly neg + var l = (long)i; + System.Console.WriteLine(l); // strictly neg + + x = i; + x += i; + System.Console.WriteLine(x); // strictly neg + } + + if (i < 0 && j > 0) + { + var x = i + j; + System.Console.WriteLine(x); + x = i * j; + System.Console.WriteLine(x); // strictly neg + x = i / j; + System.Console.WriteLine(x); // neg + x = i - j; + System.Console.WriteLine(x); // strictly neg + x = i % j; + System.Console.WriteLine(x); // neg + x = b ? i : j; + System.Console.WriteLine(x); // any (except 0) + } + } + + void NumericalTypes() + { + var f = 4.2f; + System.Console.WriteLine(f); + var d = 4.2; + System.Console.WriteLine(d); + var de = 4.2m; + System.Console.WriteLine(de); + var c = 'a'; + System.Console.WriteLine(c); + } + + int f0; + + int f1; + + void Field0() + { + f0++; + System.Console.WriteLine(f0); // strictly positive + f0 = 0; + } + + void Field1() + { + f1++; + System.Console.WriteLine(f1); // no clue + f1 = -10; + } + + void Field2() + { + System.Console.WriteLine(f1); // no clue + } + + void Ctor() + { + var i = new Int32(); // const 0 value + i++; + System.Console.WriteLine(i); // strictly pos + } + + int Guards(int x, int y) + { + if (x < 0) + { + return x; // strictly negative + } + + if (y == 1) + { + return y; // strictly positive + } + + if (y is -1) + { + return y; // strictly negative + } + + if (x < y) + { + return y; // strictly positive + } + + var b = y == 1; + if (b) + { + return y; // strictly positive + } + + return 0; + } + + void Inconsistent() + { + var i = 1; + if (i < 0) + { + System.Console.WriteLine(i); // reported as strictly pos, although unreachable + } + } + + void SpecialValues(int[] ints) + { + System.Console.WriteLine(ints.Length); // positive + ints = new int[] { 1, 2, 3 }; + System.Console.WriteLine(ints.Length); // 3, so strictly positive + System.Console.WriteLine(ints.Count()); // positive + System.Console.WriteLine(ints.Count(i => i > 1)); // positive + + var s = "abc"; + System.Console.WriteLine(s.Length); // positive, could be strictly positive + + var enumerable = Enumerable.Empty(); + System.Console.WriteLine(enumerable.Count()); // positive + + var i = new int[,] { { 1, 1 }, { 1, 2 }, { 1, 3 } }; + System.Console.WriteLine(i.Length); // 6, so strictly positive + } + + void Phi1(int i) + { + if (i > 0) + { + System.Console.WriteLine(i); // strictly positive + } + else + { + System.Console.WriteLine(i); // negative + } + System.Console.WriteLine(i); // any + } + + void Phi2(int i) + { + if (i > 0) + { + System.Console.WriteLine(i); // strictly positive + } + else + { + if (i < 0) // negative + { + System.Console.WriteLine(i); // strictly negative + return; + } + } + System.Console.WriteLine(i); // positive, not found + } + + void Phi3(int i) + { + if (i > 0) + { + System.Console.WriteLine(i); // strictly positive + } + else + { + if (i < 0) // negative + { + System.Console.WriteLine(i); // strictly negative + } + else + { + System.Console.WriteLine(i); // zero, nothing is reported + } + } + } + + void Loop(int i, int j, int k) + { + if (i > 0) + { + while (i >= 0) // any + { + i--; // positive + System.Console.WriteLine(i); // any + } + System.Console.WriteLine(i); // strictly neg + } + + if (j > 0) + { + while (j > 0) + { + j--; // strictly pos + System.Console.WriteLine(j); // positive + } + System.Console.WriteLine(j); // reported negative, can only be 0 + } + + if (k > 0) + { + while (k > 0) + { + k--; // strictly pos + System.Console.WriteLine(k); // positive + + if (k == 5) // positive + { + break; + } + } + System.Console.WriteLine(k); // any + } + } + + void Assert(int i, bool b) + { + Debug.Assert(i > 0); + System.Console.WriteLine(i); // strictly positive + + if (b) + System.Console.WriteLine(i); // strictly positive + } + + void CheckedUnchecked(int i) + { + var x = unchecked(-1 * i * i); + if (x < 0) + { + System.Console.WriteLine(x); // strictly negative + } + + x = checked(-1 * i * i); + if (x < 0) + { + System.Console.WriteLine(x); // strictly negative + } + } + + void CharMinMax() + { + var min = char.MinValue; + var max = char.MaxValue; + var c = min + 1; + System.Console.WriteLine(c); // strictly positive + c = min - 1; + System.Console.WriteLine(c); // strictly negative + c = max + 1; + System.Console.WriteLine(c); // strictly positive + } + + void NullCoalesce(int? v) + { + if (v > 0) + { + var x = v ?? 1; + System.Console.WriteLine(x); // strictly positive + } + + if (v == null) + { + var x = v ?? 1; + System.Console.WriteLine(x); // strictly positive + } + + if (v < 0) + { + var x = v ?? 0; + System.Console.WriteLine(x); // negative + } + } + + async System.Threading.Tasks.Task Await() + { + var i = await System.Threading.Tasks.Task.FromResult(5); + if (i < 0) + { + System.Console.WriteLine(i); // strictly negative + } + } + + void Unsigned(uint i) + { + if (i != 0) // positive + { + System.Console.WriteLine(i); // strictly positive + } + } + + public int MyField = 0; + + void FieldAccess() + { + var x = new SignAnalysis(); + var y = x.MyField; + if (y < 0) + { + System.Console.WriteLine(y); // strictly negative + } + } + + private static unsafe void Pointer(float d) + { + float* dp = &d; + var x = *dp; + if (x < 0) + { + System.Console.WriteLine(x); // strictly negative + } + } + + [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit, Size = 15)] + struct MyStruct { } + + unsafe void Sizeof() + { + var x = sizeof(MyStruct); + System.Console.WriteLine(x); // strictly positive + } + + void SwitchCase(string s) + { + var x = s switch + { + "x" => 0, + _ => 2 + }; + System.Console.WriteLine(x); // positive + } + + void Capture() + { + var i = 1; + void Capture() + { + if (i > 0) + Console.WriteLine(i); // strictly positive + } + Capture(); + + if (i > 0) + Console.WriteLine(i); // strictly positive + } + + public struct MyStruct2 { public int F; } + void RefExpression(MyStruct2 s) + { + ref var x = ref s.F; + if (x < 0) + { + Console.WriteLine(x); // strictly negative + } + } + + enum MyEnum { A = 12, B, C } + void EnumOp(MyEnum x, MyEnum y) + { + var i = x - y; + if (i < 0) + { + System.Console.WriteLine(i); // strictly negative + } + } + + unsafe void PointerCast(byte* src, byte* dst) + { + var x = (int)(src - dst); + if (x < 0) + { + System.Console.WriteLine(x); // strictly negative + } + + byte[] buf = new byte[10]; + + fixed (byte* to = buf) + { + System.Console.WriteLine((int)to); + } + } + + uint Unsigned() { return 1; } + void UnsignedCheck(int i) + { + long l = Unsigned(); + if (l != 0) + { + System.Console.WriteLine(l); // strictly positive + } + + uint x = (uint)i; + x++; + System.Console.WriteLine(x); // strictly positive + } +} + +// semmle-extractor-options: /r:System.Linq.dll \ No newline at end of file diff --git a/csharp/ql/test/library-tests/dataflow/signanalysis/SignAnalysis.expected b/csharp/ql/test/library-tests/dataflow/signanalysis/SignAnalysis.expected new file mode 100644 index 000000000000..0e6cc20f05dc --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/signanalysis/SignAnalysis.expected @@ -0,0 +1,249 @@ +| SignAnalysis.cs:7:72:7:75 | 1000 | strictlyPositive | +| SignAnalysis.cs:7:80:7:82 | 500 | strictlyPositive | +| SignAnalysis.cs:18:20:18:20 | access to local variable v | strictlyNegative | +| SignAnalysis.cs:24:20:24:20 | access to local variable v | strictlyNegative | +| SignAnalysis.cs:30:20:30:20 | access to local variable v | strictlyNegative | +| SignAnalysis.cs:36:20:36:20 | access to local variable v | strictlyNegative | +| SignAnalysis.cs:42:20:42:20 | access to local variable v | strictlyNegative | +| SignAnalysis.cs:45:24:45:24 | 1 | strictlyPositive | +| SignAnalysis.cs:49:20:49:20 | access to local variable v | strictlyNegative | +| SignAnalysis.cs:59:17:59:25 | Int32 x = ... | strictlyNegative | +| SignAnalysis.cs:59:21:59:21 | access to parameter i | strictlyNegative | +| SignAnalysis.cs:59:21:59:25 | ... + ... | strictlyNegative | +| SignAnalysis.cs:59:25:59:25 | access to parameter j | strictlyNegative | +| SignAnalysis.cs:60:38:60:38 | access to local variable x | strictlyNegative | +| SignAnalysis.cs:61:13:61:21 | ... = ... | strictlyPositive | +| SignAnalysis.cs:61:17:61:17 | access to parameter i | strictlyNegative | +| SignAnalysis.cs:61:17:61:21 | ... * ... | strictlyPositive | +| SignAnalysis.cs:61:21:61:21 | access to parameter j | strictlyNegative | +| SignAnalysis.cs:62:38:62:38 | access to local variable x | strictlyPositive | +| SignAnalysis.cs:63:13:63:21 | ... = ... | positive | +| SignAnalysis.cs:63:17:63:17 | access to parameter i | strictlyNegative | +| SignAnalysis.cs:63:17:63:21 | ... / ... | positive | +| SignAnalysis.cs:63:21:63:21 | access to parameter j | strictlyNegative | +| SignAnalysis.cs:64:38:64:38 | access to local variable x | positive | +| SignAnalysis.cs:65:17:65:17 | access to parameter i | strictlyNegative | +| SignAnalysis.cs:65:21:65:21 | access to parameter j | strictlyNegative | +| SignAnalysis.cs:67:13:67:21 | ... = ... | negative | +| SignAnalysis.cs:67:17:67:17 | access to parameter i | strictlyNegative | +| SignAnalysis.cs:67:17:67:21 | ... % ... | negative | +| SignAnalysis.cs:67:21:67:21 | access to parameter j | strictlyNegative | +| SignAnalysis.cs:68:38:68:38 | access to local variable x | negative | +| SignAnalysis.cs:69:13:69:19 | ... = ... | strictlyNegative | +| SignAnalysis.cs:69:17:69:17 | access to parameter i | strictlyNegative | +| SignAnalysis.cs:69:17:69:19 | ...++ | strictlyNegative | +| SignAnalysis.cs:70:38:70:38 | access to local variable x | strictlyNegative | +| SignAnalysis.cs:71:13:71:19 | ... = ... | negative | +| SignAnalysis.cs:71:17:71:17 | access to parameter i | negative | +| SignAnalysis.cs:71:17:71:19 | ...-- | negative | +| SignAnalysis.cs:72:38:72:38 | access to local variable x | negative | +| SignAnalysis.cs:73:13:73:18 | ... = ... | strictlyPositive | +| SignAnalysis.cs:73:17:73:18 | -... | strictlyPositive | +| SignAnalysis.cs:73:18:73:18 | access to parameter i | strictlyNegative | +| SignAnalysis.cs:74:38:74:38 | access to local variable x | strictlyPositive | +| SignAnalysis.cs:75:13:75:18 | ... = ... | strictlyNegative | +| SignAnalysis.cs:75:17:75:18 | +... | strictlyNegative | +| SignAnalysis.cs:75:18:75:18 | access to parameter i | strictlyNegative | +| SignAnalysis.cs:76:38:76:38 | access to local variable x | strictlyNegative | +| SignAnalysis.cs:77:17:77:27 | Int64 l = ... | strictlyNegative | +| SignAnalysis.cs:77:21:77:27 | (...) ... | strictlyNegative | +| SignAnalysis.cs:77:27:77:27 | access to parameter i | strictlyNegative | +| SignAnalysis.cs:78:38:78:38 | access to local variable l | strictlyNegative | +| SignAnalysis.cs:80:13:80:17 | ... = ... | strictlyNegative | +| SignAnalysis.cs:80:17:80:17 | access to parameter i | strictlyNegative | +| SignAnalysis.cs:81:13:81:13 | access to local variable x | strictlyNegative | +| SignAnalysis.cs:81:13:81:18 | ... + ... | strictlyNegative | +| SignAnalysis.cs:81:13:81:18 | ... += ... | strictlyNegative | +| SignAnalysis.cs:81:13:81:18 | ... = ... | strictlyNegative | +| SignAnalysis.cs:81:18:81:18 | access to parameter i | strictlyNegative | +| SignAnalysis.cs:82:38:82:38 | access to local variable x | strictlyNegative | +| SignAnalysis.cs:87:21:87:21 | access to parameter i | strictlyNegative | +| SignAnalysis.cs:87:25:87:25 | access to parameter j | strictlyPositive | +| SignAnalysis.cs:89:13:89:21 | ... = ... | strictlyNegative | +| SignAnalysis.cs:89:17:89:17 | access to parameter i | strictlyNegative | +| SignAnalysis.cs:89:17:89:21 | ... * ... | strictlyNegative | +| SignAnalysis.cs:89:21:89:21 | access to parameter j | strictlyPositive | +| SignAnalysis.cs:90:38:90:38 | access to local variable x | strictlyNegative | +| SignAnalysis.cs:91:13:91:21 | ... = ... | negative | +| SignAnalysis.cs:91:17:91:17 | access to parameter i | strictlyNegative | +| SignAnalysis.cs:91:17:91:21 | ... / ... | negative | +| SignAnalysis.cs:91:21:91:21 | access to parameter j | strictlyPositive | +| SignAnalysis.cs:92:38:92:38 | access to local variable x | negative | +| SignAnalysis.cs:93:13:93:21 | ... = ... | strictlyNegative | +| SignAnalysis.cs:93:17:93:17 | access to parameter i | strictlyNegative | +| SignAnalysis.cs:93:17:93:21 | ... - ... | strictlyNegative | +| SignAnalysis.cs:93:21:93:21 | access to parameter j | strictlyPositive | +| SignAnalysis.cs:94:38:94:38 | access to local variable x | strictlyNegative | +| SignAnalysis.cs:95:13:95:21 | ... = ... | negative | +| SignAnalysis.cs:95:17:95:17 | access to parameter i | strictlyNegative | +| SignAnalysis.cs:95:17:95:21 | ... % ... | negative | +| SignAnalysis.cs:95:21:95:21 | access to parameter j | strictlyPositive | +| SignAnalysis.cs:96:38:96:38 | access to local variable x | negative | +| SignAnalysis.cs:97:21:97:21 | access to parameter i | strictlyNegative | +| SignAnalysis.cs:97:25:97:25 | access to parameter j | strictlyPositive | +| SignAnalysis.cs:104:13:104:20 | Single f = ... | strictlyPositive | +| SignAnalysis.cs:104:17:104:20 | 4.2 | strictlyPositive | +| SignAnalysis.cs:105:34:105:34 | access to local variable f | strictlyPositive | +| SignAnalysis.cs:106:13:106:19 | Double d = ... | strictlyPositive | +| SignAnalysis.cs:106:17:106:19 | 4.2 | strictlyPositive | +| SignAnalysis.cs:107:34:107:34 | access to local variable d | strictlyPositive | +| SignAnalysis.cs:108:13:108:21 | Decimal de = ... | strictlyPositive | +| SignAnalysis.cs:108:18:108:21 | 4.2 | strictlyPositive | +| SignAnalysis.cs:109:34:109:35 | access to local variable de | strictlyPositive | +| SignAnalysis.cs:110:13:110:13 | access to local variable c | positive | +| SignAnalysis.cs:110:13:110:19 | Char c = ... | strictlyPositive | +| SignAnalysis.cs:110:17:110:19 | a | strictlyPositive | +| SignAnalysis.cs:111:34:111:34 | access to local variable c | strictlyPositive | +| SignAnalysis.cs:120:9:120:10 | access to field f0 | positive | +| SignAnalysis.cs:120:9:120:12 | ...++ | positive | +| SignAnalysis.cs:121:34:121:35 | access to field f0 | strictlyPositive | +| SignAnalysis.cs:122:9:122:10 | access to field f0 | positive | +| SignAnalysis.cs:129:9:129:16 | ... = ... | strictlyNegative | +| SignAnalysis.cs:129:14:129:16 | -... | strictlyNegative | +| SignAnalysis.cs:129:15:129:16 | 10 | strictlyPositive | +| SignAnalysis.cs:141:34:141:34 | access to local variable i | strictlyPositive | +| SignAnalysis.cs:148:20:148:20 | access to parameter x | strictlyNegative | +| SignAnalysis.cs:151:18:151:18 | 1 | strictlyPositive | +| SignAnalysis.cs:153:20:153:20 | access to parameter y | strictlyPositive | +| SignAnalysis.cs:156:18:156:19 | -... | strictlyNegative | +| SignAnalysis.cs:156:19:156:19 | 1 | strictlyPositive | +| SignAnalysis.cs:158:20:158:20 | access to parameter y | strictlyNegative | +| SignAnalysis.cs:161:13:161:13 | access to parameter x | positive | +| SignAnalysis.cs:163:20:163:20 | access to parameter y | strictlyPositive | +| SignAnalysis.cs:166:22:166:22 | 1 | strictlyPositive | +| SignAnalysis.cs:169:20:169:20 | access to parameter y | strictlyPositive | +| SignAnalysis.cs:177:13:177:17 | Int32 i = ... | strictlyPositive | +| SignAnalysis.cs:177:17:177:17 | 1 | strictlyPositive | +| SignAnalysis.cs:178:13:178:13 | access to local variable i | strictlyPositive | +| SignAnalysis.cs:180:38:180:38 | access to local variable i | strictlyPositive | +| SignAnalysis.cs:186:34:186:44 | access to property Length | positive | +| SignAnalysis.cs:187:16:187:36 | 3 | strictlyPositive | +| SignAnalysis.cs:187:28:187:28 | 1 | strictlyPositive | +| SignAnalysis.cs:187:31:187:31 | 2 | strictlyPositive | +| SignAnalysis.cs:187:34:187:34 | 3 | strictlyPositive | +| SignAnalysis.cs:188:34:188:44 | access to property Length | strictlyPositive | +| SignAnalysis.cs:189:34:189:45 | call to method Count | positive | +| SignAnalysis.cs:190:34:190:55 | call to method Count | positive | +| SignAnalysis.cs:190:54:190:54 | 1 | strictlyPositive | +| SignAnalysis.cs:193:34:193:41 | access to property Length | positive | +| SignAnalysis.cs:196:34:196:51 | call to method Count | positive | +| SignAnalysis.cs:198:17:198:59 | 2 | strictlyPositive | +| SignAnalysis.cs:198:17:198:59 | 3 | strictlyPositive | +| SignAnalysis.cs:198:32:198:32 | 1 | strictlyPositive | +| SignAnalysis.cs:198:35:198:35 | 1 | strictlyPositive | +| SignAnalysis.cs:198:42:198:42 | 1 | strictlyPositive | +| SignAnalysis.cs:198:45:198:45 | 2 | strictlyPositive | +| SignAnalysis.cs:198:52:198:52 | 1 | strictlyPositive | +| SignAnalysis.cs:198:55:198:55 | 3 | strictlyPositive | +| SignAnalysis.cs:199:34:199:41 | access to property Length | strictlyPositive | +| SignAnalysis.cs:206:38:206:38 | access to parameter i | strictlyPositive | +| SignAnalysis.cs:210:38:210:38 | access to parameter i | negative | +| SignAnalysis.cs:219:38:219:38 | access to parameter i | strictlyPositive | +| SignAnalysis.cs:223:17:223:17 | access to parameter i | negative | +| SignAnalysis.cs:225:42:225:42 | access to parameter i | strictlyNegative | +| SignAnalysis.cs:236:38:236:38 | access to parameter i | strictlyPositive | +| SignAnalysis.cs:240:17:240:17 | access to parameter i | negative | +| SignAnalysis.cs:242:42:242:42 | access to parameter i | strictlyNegative | +| SignAnalysis.cs:257:17:257:17 | access to parameter i | positive | +| SignAnalysis.cs:257:17:257:19 | ...-- | positive | +| SignAnalysis.cs:260:38:260:38 | access to parameter i | strictlyNegative | +| SignAnalysis.cs:267:17:267:17 | access to parameter j | strictlyPositive | +| SignAnalysis.cs:267:17:267:19 | ...-- | strictlyPositive | +| SignAnalysis.cs:268:42:268:42 | access to parameter j | positive | +| SignAnalysis.cs:270:38:270:38 | access to parameter j | negative | +| SignAnalysis.cs:277:17:277:17 | access to parameter k | strictlyPositive | +| SignAnalysis.cs:277:17:277:19 | ...-- | strictlyPositive | +| SignAnalysis.cs:278:42:278:42 | access to parameter k | positive | +| SignAnalysis.cs:280:21:280:21 | access to parameter k | positive | +| SignAnalysis.cs:280:26:280:26 | 5 | strictlyPositive | +| SignAnalysis.cs:292:34:292:34 | access to parameter i | strictlyPositive | +| SignAnalysis.cs:295:38:295:38 | access to parameter i | strictlyPositive | +| SignAnalysis.cs:300:27:300:28 | -... | strictlyNegative | +| SignAnalysis.cs:300:28:300:28 | 1 | strictlyPositive | +| SignAnalysis.cs:303:38:303:38 | access to local variable x | strictlyNegative | +| SignAnalysis.cs:306:21:306:22 | -... | strictlyNegative | +| SignAnalysis.cs:306:22:306:22 | 1 | strictlyPositive | +| SignAnalysis.cs:309:38:309:38 | access to local variable x | strictlyNegative | +| SignAnalysis.cs:315:13:315:15 | access to local variable min | positive | +| SignAnalysis.cs:316:13:316:15 | access to local variable max | positive | +| SignAnalysis.cs:316:13:316:31 | Char max = ... | strictlyPositive | +| SignAnalysis.cs:316:19:316:31 | access to constant MaxValue | strictlyPositive | +| SignAnalysis.cs:317:13:317:23 | Int32 c = ... | strictlyPositive | +| SignAnalysis.cs:317:17:317:23 | ... + ... | strictlyPositive | +| SignAnalysis.cs:317:23:317:23 | 1 | strictlyPositive | +| SignAnalysis.cs:318:34:318:34 | access to local variable c | strictlyPositive | +| SignAnalysis.cs:319:9:319:19 | ... = ... | strictlyNegative | +| SignAnalysis.cs:319:13:319:19 | ... - ... | strictlyNegative | +| SignAnalysis.cs:319:19:319:19 | 1 | strictlyPositive | +| SignAnalysis.cs:320:34:320:34 | access to local variable c | strictlyNegative | +| SignAnalysis.cs:321:9:321:19 | ... = ... | strictlyPositive | +| SignAnalysis.cs:321:13:321:15 | (...) ... | strictlyPositive | +| SignAnalysis.cs:321:13:321:15 | access to local variable max | strictlyPositive | +| SignAnalysis.cs:321:13:321:19 | ... + ... | strictlyPositive | +| SignAnalysis.cs:321:19:321:19 | 1 | strictlyPositive | +| SignAnalysis.cs:322:34:322:34 | access to local variable c | strictlyPositive | +| SignAnalysis.cs:329:17:329:26 | Int32 x = ... | strictlyPositive | +| SignAnalysis.cs:329:21:329:21 | access to parameter v | strictlyPositive | +| SignAnalysis.cs:329:21:329:26 | ... ?? ... | strictlyPositive | +| SignAnalysis.cs:329:26:329:26 | 1 | strictlyPositive | +| SignAnalysis.cs:330:38:330:38 | access to local variable x | strictlyPositive | +| SignAnalysis.cs:335:17:335:26 | Int32 x = ... | strictlyPositive | +| SignAnalysis.cs:335:21:335:26 | ... ?? ... | strictlyPositive | +| SignAnalysis.cs:335:26:335:26 | 1 | strictlyPositive | +| SignAnalysis.cs:336:38:336:38 | access to local variable x | strictlyPositive | +| SignAnalysis.cs:341:17:341:26 | Int32 x = ... | negative | +| SignAnalysis.cs:341:21:341:21 | access to parameter v | strictlyNegative | +| SignAnalysis.cs:341:21:341:26 | ... ?? ... | negative | +| SignAnalysis.cs:342:38:342:38 | access to local variable x | negative | +| SignAnalysis.cs:348:62:348:62 | 5 | strictlyPositive | +| SignAnalysis.cs:351:38:351:38 | access to local variable i | strictlyNegative | +| SignAnalysis.cs:357:13:357:13 | access to parameter i | positive | +| SignAnalysis.cs:359:38:359:38 | access to parameter i | strictlyPositive | +| SignAnalysis.cs:371:38:371:38 | access to local variable y | strictlyNegative | +| SignAnalysis.cs:377:16:377:17 | access to local variable dp | positive | +| SignAnalysis.cs:377:16:377:22 | Single* dp = ... | positive | +| SignAnalysis.cs:377:21:377:22 | &... | positive | +| SignAnalysis.cs:378:18:378:19 | access to local variable dp | positive | +| SignAnalysis.cs:381:38:381:38 | access to local variable x | strictlyNegative | +| SignAnalysis.cs:385:50:385:99 | access to constant Explicit | strictlyPositive | +| SignAnalysis.cs:385:109:385:110 | 15 | strictlyPositive | +| SignAnalysis.cs:390:13:390:32 | Int32 x = ... | strictlyPositive | +| SignAnalysis.cs:390:17:390:32 | sizeof(..) | strictlyPositive | +| SignAnalysis.cs:391:34:391:34 | access to local variable x | strictlyPositive | +| SignAnalysis.cs:396:13:400:9 | Int32 x = ... | positive | +| SignAnalysis.cs:396:17:400:9 | ... switch { ... } | positive | +| SignAnalysis.cs:399:13:399:18 | ... => ... | strictlyPositive | +| SignAnalysis.cs:399:18:399:18 | 2 | strictlyPositive | +| SignAnalysis.cs:401:34:401:34 | access to local variable x | positive | +| SignAnalysis.cs:406:13:406:17 | Int32 i = ... | strictlyPositive | +| SignAnalysis.cs:406:17:406:17 | 1 | strictlyPositive | +| SignAnalysis.cs:410:35:410:35 | access to local variable i | strictlyPositive | +| SignAnalysis.cs:414:13:414:13 | access to local variable i | strictlyPositive | +| SignAnalysis.cs:415:31:415:31 | access to local variable i | strictlyPositive | +| SignAnalysis.cs:424:31:424:31 | access to local variable x | strictlyNegative | +| SignAnalysis.cs:428:19:428:19 | access to constant A | strictlyPositive | +| SignAnalysis.cs:428:19:428:24 | ... = ... | strictlyPositive | +| SignAnalysis.cs:428:23:428:24 | 12 | strictlyPositive | +| SignAnalysis.cs:434:38:434:38 | access to local variable i | strictlyNegative | +| SignAnalysis.cs:440:23:440:25 | access to parameter src | positive | +| SignAnalysis.cs:440:29:440:31 | access to parameter dst | positive | +| SignAnalysis.cs:443:38:443:38 | access to local variable x | strictlyNegative | +| SignAnalysis.cs:446:31:446:32 | 10 | strictlyPositive | +| SignAnalysis.cs:448:22:448:23 | access to local variable to | positive | +| SignAnalysis.cs:448:22:448:29 | Byte* to = ... | positive | +| SignAnalysis.cs:448:27:448:29 | (...) ... | positive | +| SignAnalysis.cs:450:38:450:44 | (...) ... | positive | +| SignAnalysis.cs:450:43:450:44 | access to local variable to | positive | +| SignAnalysis.cs:454:30:454:30 | 1 | strictlyPositive | +| SignAnalysis.cs:454:30:454:30 | (...) ... | strictlyPositive | +| SignAnalysis.cs:457:14:457:27 | Int64 l = ... | positive | +| SignAnalysis.cs:457:18:457:27 | (...) ... | positive | +| SignAnalysis.cs:457:18:457:27 | call to method Unsigned | positive | +| SignAnalysis.cs:458:13:458:13 | access to local variable l | positive | +| SignAnalysis.cs:460:38:460:38 | access to local variable l | strictlyPositive | +| SignAnalysis.cs:463:14:463:14 | access to local variable x | positive | +| SignAnalysis.cs:463:14:463:24 | UInt32 x = ... | positive | +| SignAnalysis.cs:463:18:463:24 | (...) ... | positive | +| SignAnalysis.cs:464:9:464:9 | access to local variable x | positive | +| SignAnalysis.cs:464:9:464:11 | ...++ | positive | +| SignAnalysis.cs:465:34:465:34 | access to local variable x | strictlyPositive | diff --git a/csharp/ql/test/library-tests/dataflow/signanalysis/SignAnalysis.ql b/csharp/ql/test/library-tests/dataflow/signanalysis/SignAnalysis.ql new file mode 100644 index 000000000000..4350e8f17427 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/signanalysis/SignAnalysis.ql @@ -0,0 +1,21 @@ +import csharp +import semmle.code.csharp.dataflow.SignAnalysis + +string getASignString(Expr e) { + positive(e) and + not strictlyPositive(e) and + result = "positive" + or + negative(e) and + not strictlyNegative(e) and + result = "negative" + or + strictlyPositive(e) and + result = "strictlyPositive" + or + strictlyNegative(e) and + result = "strictlyNegative" +} + +from Expr e +select e, strictconcat(string s | s = getASignString(e) | s, " ") diff --git a/csharp/ql/test/library-tests/dataflow/ssa/Capture.cs b/csharp/ql/test/library-tests/dataflow/ssa/Capture.cs index 0ac3945abaa6..d11947afed69 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/Capture.cs +++ b/csharp/ql/test/library-tests/dataflow/ssa/Capture.cs @@ -236,4 +236,22 @@ void M1() M3(); System.Console.WriteLine(i); } + + void M2() + { + int i = 0; + void CaptureWrite() + { + i = 1; + } + + void CaptureAndRef(ref int j) + { + CaptureWrite(); + j = 2; + } + + CaptureAndRef(ref i); // explicit definition only (no call definition) + System.Console.WriteLine(i); + } } diff --git a/csharp/ql/test/library-tests/dataflow/ssa/DefAdjacentRead.expected b/csharp/ql/test/library-tests/dataflow/ssa/DefAdjacentRead.expected index c10891ec2526..1a46a32d8fdf 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/DefAdjacentRead.expected +++ b/csharp/ql/test/library-tests/dataflow/ssa/DefAdjacentRead.expected @@ -30,6 +30,8 @@ | Capture.cs:203:28:203:30 | eh2 | Capture.cs:203:28:203:45 | MyEventHandler eh2 = ... | Capture.cs:204:27:204:29 | access to local variable eh2 | | Capture.cs:210:24:210:24 | p | Capture.cs:210:24:210:59 | Process p = ... | Capture.cs:213:17:213:17 | access to local variable p | | Capture.cs:212:30:212:35 | exited | Capture.cs:212:30:212:71 | EventHandler exited = ... | Capture.cs:213:29:213:34 | access to local variable exited | +| Capture.cs:242:13:242:13 | i | Capture.cs:242:13:242:17 | Int32 i = ... | Capture.cs:254:27:254:27 | access to local variable i | +| Capture.cs:242:13:242:13 | i | Capture.cs:254:27:254:27 | access to local variable i | Capture.cs:255:34:255:34 | access to local variable i | | Consistency.cs:7:25:7:25 | b | Consistency.cs:7:25:7:25 | b | Consistency.cs:11:17:11:17 | access to parameter b | | Consistency.cs:15:17:15:17 | i | Consistency.cs:15:17:15:21 | Int32 i = ... | Consistency.cs:16:17:16:17 | access to local variable i | | Consistency.cs:25:29:25:29 | c | Consistency.cs:25:29:25:29 | Consistency c | Consistency.cs:26:13:26:13 | access to local variable c | diff --git a/csharp/ql/test/library-tests/dataflow/ssa/IsLiveOutRefParameterDefinition.expected b/csharp/ql/test/library-tests/dataflow/ssa/IsLiveOutRefParameterDefinition.expected index fd9801dc6c62..7b1f6cb97693 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/IsLiveOutRefParameterDefinition.expected +++ b/csharp/ql/test/library-tests/dataflow/ssa/IsLiveOutRefParameterDefinition.expected @@ -1,4 +1,5 @@ | Capture.cs:81:28:81:28 | i | Capture.cs:81:34:81:36 | SSA def(i) | +| Capture.cs:248:36:248:36 | j | Capture.cs:251:13:251:17 | SSA def(j) | | Consistency.cs:30:30:30:30 | c | Consistency.cs:32:9:32:29 | SSA def(c) | | DefUse.cs:114:42:114:42 | i | DefUse.cs:114:47:114:52 | SSA def(i) | | DefUse.cs:116:42:116:42 | i | DefUse.cs:116:47:116:51 | SSA def(i) | diff --git a/csharp/ql/test/library-tests/dataflow/ssa/SsaCapturedVariableDef.expected b/csharp/ql/test/library-tests/dataflow/ssa/SsaCapturedVariableDef.expected index e1b4a0b52b2f..baa9311a09b7 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/SsaCapturedVariableDef.expected +++ b/csharp/ql/test/library-tests/dataflow/ssa/SsaCapturedVariableDef.expected @@ -4,11 +4,11 @@ | in | Capture.cs:8:13:8:13 | x | Capture.cs:15:13:15:17 | SSA def(x) | Capture.cs:19:24:23:13 | SSA capture def(x) | Capture.cs:25:13:25:15 | delegate call | false | | in | Capture.cs:8:13:8:13 | x | Capture.cs:43:9:43:13 | SSA def(x) | Capture.cs:19:24:23:13 | SSA capture def(x) | Capture.cs:44:9:44:12 | call to method M | true | | in | Capture.cs:17:17:17:17 | y | Capture.cs:17:17:17:21 | SSA def(y) | Capture.cs:19:24:23:13 | SSA capture def(y) | Capture.cs:25:13:25:15 | delegate call | false | -| in | Capture.cs:59:13:59:13 | i | Capture.cs:59:13:59:17 | SSA def(i) | Capture.cs:60:31:60:38 | SSA capture def(i) | Capture.cs:61:9:61:25 | call to method Select | false | -| in | Capture.cs:67:13:67:13 | c | Capture.cs:67:13:67:19 | SSA def(c) | Capture.cs:68:32:68:49 | SSA capture def(c) | Capture.cs:68:18:68:50 | call to method Where | false | -| in | Capture.cs:67:13:67:13 | c | Capture.cs:67:13:67:19 | SSA def(c) | Capture.cs:69:9:69:62 | SSA capture def(c) | Capture.cs:70:9:70:25 | call to method Select | false | -| in | Capture.cs:75:13:75:13 | i | Capture.cs:75:13:75:17 | SSA def(i) | Capture.cs:76:67:76:81 | SSA capture def(i) | Capture.cs:77:9:77:25 | call to method Select | false | -| in | Capture.cs:85:13:85:13 | b | Capture.cs:85:13:85:20 | SSA def(b) | Capture.cs:86:68:86:73 | SSA capture def(b) | Capture.cs:87:9:87:24 | call to method Where | false | +| in | Capture.cs:59:13:59:13 | i | Capture.cs:59:13:59:17 | SSA def(i) | Capture.cs:60:31:60:38 | SSA capture def(i) | Capture.cs:61:9:61:25 | call to method Select | true | +| in | Capture.cs:67:13:67:13 | c | Capture.cs:67:13:67:19 | SSA def(c) | Capture.cs:68:32:68:49 | SSA capture def(c) | Capture.cs:68:18:68:50 | call to method Where | true | +| in | Capture.cs:67:13:67:13 | c | Capture.cs:67:13:67:19 | SSA def(c) | Capture.cs:69:9:69:62 | SSA capture def(c) | Capture.cs:70:9:70:25 | call to method Select | true | +| in | Capture.cs:75:13:75:13 | i | Capture.cs:75:13:75:17 | SSA def(i) | Capture.cs:76:67:76:81 | SSA capture def(i) | Capture.cs:77:9:77:25 | call to method Select | true | +| in | Capture.cs:85:13:85:13 | b | Capture.cs:85:13:85:20 | SSA def(b) | Capture.cs:86:68:86:73 | SSA capture def(b) | Capture.cs:87:9:87:24 | call to method Where | true | | in | Capture.cs:94:13:94:13 | y | Capture.cs:94:13:94:18 | SSA def(y) | Capture.cs:96:12:100:9 | SSA capture def(y) | Capture.cs:96:9:100:10 | call to local function fn | true | | in | Capture.cs:94:13:94:13 | y | Capture.cs:94:13:94:18 | SSA def(y) | Capture.cs:96:12:100:9 | SSA capture def(y) | Capture.cs:103:9:107:10 | call to local function fn | true | | in | Capture.cs:114:13:114:13 | a | Capture.cs:114:13:114:18 | SSA def(a) | Capture.cs:115:9:119:9 | SSA capture def(a) | Capture.cs:120:9:120:12 | call to local function M1 | false | @@ -16,23 +16,23 @@ | in | Capture.cs:182:17:182:17 | i | Capture.cs:188:13:188:17 | SSA def(i) | Capture.cs:183:13:186:13 | SSA capture def(i) | Capture.cs:189:13:189:17 | call to local function M11 | false | | in | Capture.cs:197:17:197:17 | i | Capture.cs:197:17:197:21 | SSA def(i) | Capture.cs:198:33:198:44 | SSA capture def(i) | Capture.cs:200:13:200:19 | delegate call | false | | in | Capture.cs:197:17:197:17 | i | Capture.cs:197:17:197:21 | SSA def(i) | Capture.cs:203:34:203:45 | SSA capture def(i) | Capture.cs:200:13:200:19 | delegate call | false | -| in | Capture.cs:209:17:209:17 | i | Capture.cs:209:17:209:21 | SSA def(i) | Capture.cs:212:39:212:71 | SSA capture def(i) | Capture.cs:213:17:213:24 | access to event Exited | false | +| in | Capture.cs:209:17:209:17 | i | Capture.cs:209:17:209:21 | SSA def(i) | Capture.cs:212:39:212:71 | SSA capture def(i) | Capture.cs:213:17:213:24 | access to event Exited | true | | in | Capture.cs:229:13:229:13 | i | Capture.cs:232:9:232:13 | SSA def(i) | Capture.cs:231:9:231:49 | SSA capture def(i) | Capture.cs:233:9:233:12 | call to local function M2 | false | | in | Fields.cs:77:13:77:13 | f | Fields.cs:77:13:77:45 | SSA def(f) | Fields.cs:78:27:78:54 | SSA capture def(f) | Fields.cs:81:9:81:11 | delegate call | false | | in | Fields.cs:77:13:77:13 | f | Fields.cs:77:13:77:45 | SSA def(f) | Fields.cs:78:27:78:54 | SSA capture def(f) | Fields.cs:86:9:86:47 | call to method Select | true | -| in | Fields.cs:78:23:78:23 | a | Fields.cs:78:23:78:54 | SSA def(a) | Fields.cs:86:24:86:46 | SSA capture def(a) | Fields.cs:86:9:86:47 | call to method Select | false | -| in | Fields.cs:79:23:79:23 | b | Fields.cs:79:23:79:35 | SSA def(b) | Fields.cs:89:24:89:46 | SSA capture def(b) | Fields.cs:89:9:89:47 | call to method Select | false | +| in | Fields.cs:78:23:78:23 | a | Fields.cs:78:23:78:54 | SSA def(a) | Fields.cs:86:24:86:46 | SSA capture def(a) | Fields.cs:86:9:86:47 | call to method Select | true | +| in | Fields.cs:79:23:79:23 | b | Fields.cs:79:23:79:35 | SSA def(b) | Fields.cs:89:24:89:46 | SSA capture def(b) | Fields.cs:89:9:89:47 | call to method Select | true | | in | Properties.cs:73:13:73:13 | f | Properties.cs:73:13:73:32 | SSA def(f) | Properties.cs:74:27:74:54 | SSA capture def(f) | Properties.cs:77:9:77:11 | delegate call | false | | in | Properties.cs:73:13:73:13 | f | Properties.cs:73:13:73:32 | SSA def(f) | Properties.cs:74:27:74:54 | SSA capture def(f) | Properties.cs:82:9:82:47 | call to method Select | true | -| in | Properties.cs:74:23:74:23 | a | Properties.cs:74:23:74:54 | SSA def(a) | Properties.cs:82:24:82:46 | SSA capture def(a) | Properties.cs:82:9:82:47 | call to method Select | false | -| in | Properties.cs:75:23:75:23 | b | Properties.cs:75:23:75:35 | SSA def(b) | Properties.cs:85:24:85:46 | SSA capture def(b) | Properties.cs:85:9:85:47 | call to method Select | false | +| in | Properties.cs:74:23:74:23 | a | Properties.cs:74:23:74:54 | SSA def(a) | Properties.cs:82:24:82:46 | SSA capture def(a) | Properties.cs:82:9:82:47 | call to method Select | true | +| in | Properties.cs:75:23:75:23 | b | Properties.cs:75:23:75:35 | SSA def(b) | Properties.cs:85:24:85:46 | SSA capture def(b) | Properties.cs:85:9:85:47 | call to method Select | true | | out | Capture.cs:6:16:6:16 | i | Capture.cs:13:13:13:17 | SSA def(i) | Capture.cs:38:9:38:11 | SSA call def(i) | Capture.cs:38:9:38:11 | delegate call | false | | out | Capture.cs:8:13:8:13 | x | Capture.cs:15:13:15:17 | SSA def(x) | Capture.cs:38:9:38:11 | SSA call def(x) | Capture.cs:38:9:38:11 | delegate call | false | | out | Capture.cs:8:13:8:13 | x | Capture.cs:15:13:15:17 | SSA def(x) | Capture.cs:44:9:44:12 | SSA call def(x) | Capture.cs:44:9:44:12 | call to method M | true | | out | Capture.cs:29:13:29:13 | z | Capture.cs:30:28:30:32 | SSA def(z) | Capture.cs:32:9:32:11 | SSA call def(z) | Capture.cs:32:9:32:11 | delegate call | false | | out | Capture.cs:50:20:50:20 | a | Capture.cs:52:28:52:40 | SSA def(a) | Capture.cs:53:9:53:11 | SSA call def(a) | Capture.cs:53:9:53:11 | delegate call | false | -| out | Capture.cs:59:13:59:13 | i | Capture.cs:60:36:60:38 | SSA def(i) | Capture.cs:61:9:61:25 | SSA call def(i) | Capture.cs:61:9:61:25 | call to method Select | false | -| out | Capture.cs:75:13:75:13 | i | Capture.cs:76:80:76:80 | SSA def(i) | Capture.cs:77:9:77:25 | SSA call def(i) | Capture.cs:77:9:77:25 | call to method Select | false | +| out | Capture.cs:59:13:59:13 | i | Capture.cs:60:36:60:38 | SSA def(i) | Capture.cs:61:9:61:25 | SSA call def(i) | Capture.cs:61:9:61:25 | call to method Select | true | +| out | Capture.cs:75:13:75:13 | i | Capture.cs:76:80:76:80 | SSA def(i) | Capture.cs:77:9:77:25 | SSA call def(i) | Capture.cs:77:9:77:25 | call to method Select | true | | out | Capture.cs:130:13:130:13 | c | Capture.cs:133:13:133:17 | SSA def(c) | Capture.cs:136:9:136:12 | SSA call def(c) | Capture.cs:136:9:136:12 | call to local function M3 | false | | out | Capture.cs:139:13:139:13 | d | Capture.cs:142:13:142:17 | SSA def(d) | Capture.cs:144:9:144:12 | SSA call def(d) | Capture.cs:144:9:144:12 | call to local function M4 | false | | out | Capture.cs:168:13:168:13 | h | Capture.cs:174:17:174:21 | SSA def(h) | Capture.cs:176:13:176:16 | SSA call def(h) | Capture.cs:176:13:176:16 | call to local function M9 | false | diff --git a/csharp/ql/test/library-tests/dataflow/ssa/SsaDef.expected b/csharp/ql/test/library-tests/dataflow/ssa/SsaDef.expected index b8d50de56515..64b2ff156752 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/SsaDef.expected +++ b/csharp/ql/test/library-tests/dataflow/ssa/SsaDef.expected @@ -82,6 +82,9 @@ | Capture.cs:229:13:229:13 | i | Capture.cs:232:9:232:13 | SSA def(i) | | Capture.cs:229:13:229:13 | i | Capture.cs:235:21:235:25 | SSA def(i) | | Capture.cs:229:13:229:13 | i | Capture.cs:236:9:236:12 | SSA call def(i) | +| Capture.cs:242:13:242:13 | i | Capture.cs:242:13:242:17 | SSA def(i) | +| Capture.cs:242:13:242:13 | i | Capture.cs:254:27:254:27 | SSA def(i) | +| Capture.cs:248:36:248:36 | j | Capture.cs:251:13:251:17 | SSA def(j) | | Consistency.cs:7:25:7:25 | b | Consistency.cs:7:25:7:25 | SSA param(b) | | Consistency.cs:15:17:15:17 | i | Consistency.cs:15:17:15:21 | SSA def(i) | | Consistency.cs:15:17:15:17 | i | Consistency.cs:15:17:15:21 | [finally: exception(Exception)] SSA def(i) | diff --git a/csharp/ql/test/library-tests/dataflow/ssa/SsaDefElement.expected b/csharp/ql/test/library-tests/dataflow/ssa/SsaDefElement.expected index d824b98a50dc..bc176624df5c 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/SsaDefElement.expected +++ b/csharp/ql/test/library-tests/dataflow/ssa/SsaDefElement.expected @@ -82,6 +82,9 @@ | Capture.cs:232:9:232:13 | SSA def(i) | Capture.cs:232:9:232:13 | ... = ... | | Capture.cs:235:21:235:25 | SSA def(i) | Capture.cs:235:21:235:25 | ... = ... | | Capture.cs:236:9:236:12 | SSA call def(i) | Capture.cs:236:9:236:12 | call to local function M3 | +| Capture.cs:242:13:242:17 | SSA def(i) | Capture.cs:242:13:242:17 | Int32 i = ... | +| Capture.cs:251:13:251:17 | SSA def(j) | Capture.cs:251:13:251:17 | ... = ... | +| Capture.cs:254:27:254:27 | SSA def(i) | Capture.cs:254:9:254:28 | call to local function CaptureAndRef | | Consistency.cs:7:25:7:25 | SSA param(b) | Consistency.cs:7:25:7:25 | b | | Consistency.cs:15:17:15:21 | SSA def(i) | Consistency.cs:15:17:15:21 | Int32 i = ... | | Consistency.cs:15:17:15:21 | [finally: exception(Exception)] SSA def(i) | Consistency.cs:15:17:15:21 | Int32 i = ... | diff --git a/csharp/ql/test/library-tests/dataflow/ssa/SsaDefLastRead.expected b/csharp/ql/test/library-tests/dataflow/ssa/SsaDefLastRead.expected index 2dcd936457ec..72fc8e58359f 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/SsaDefLastRead.expected +++ b/csharp/ql/test/library-tests/dataflow/ssa/SsaDefLastRead.expected @@ -58,6 +58,8 @@ | Capture.cs:212:30:212:35 | exited | Capture.cs:212:30:212:71 | SSA def(exited) | Capture.cs:213:29:213:34 | access to local variable exited | | Capture.cs:229:13:229:13 | i | Capture.cs:231:9:231:49 | SSA capture def(i) | Capture.cs:231:47:231:47 | access to local variable i | | Capture.cs:229:13:229:13 | i | Capture.cs:236:9:236:12 | SSA call def(i) | Capture.cs:237:34:237:34 | access to local variable i | +| Capture.cs:242:13:242:13 | i | Capture.cs:242:13:242:17 | SSA def(i) | Capture.cs:254:27:254:27 | access to local variable i | +| Capture.cs:242:13:242:13 | i | Capture.cs:254:27:254:27 | SSA def(i) | Capture.cs:255:34:255:34 | access to local variable i | | Consistency.cs:7:25:7:25 | b | Consistency.cs:7:25:7:25 | SSA param(b) | Consistency.cs:11:17:11:17 | access to parameter b | | Consistency.cs:15:17:15:17 | i | Consistency.cs:15:17:15:21 | SSA def(i) | Consistency.cs:16:17:16:17 | access to local variable i | | Consistency.cs:15:17:15:17 | i | Consistency.cs:15:17:15:21 | [finally: exception(Exception)] SSA def(i) | Consistency.cs:16:17:16:17 | access to local variable i | diff --git a/csharp/ql/test/library-tests/dataflow/ssa/SsaExplicitDef.expected b/csharp/ql/test/library-tests/dataflow/ssa/SsaExplicitDef.expected index b25dbee614e4..6f5c8a4238b6 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/SsaExplicitDef.expected +++ b/csharp/ql/test/library-tests/dataflow/ssa/SsaExplicitDef.expected @@ -54,6 +54,9 @@ | Capture.cs:212:30:212:35 | exited | Capture.cs:212:30:212:71 | SSA def(exited) | Capture.cs:212:30:212:71 | EventHandler exited = ... | | Capture.cs:229:13:229:13 | i | Capture.cs:232:9:232:13 | SSA def(i) | Capture.cs:232:9:232:13 | ... = ... | | Capture.cs:229:13:229:13 | i | Capture.cs:235:21:235:25 | SSA def(i) | Capture.cs:235:21:235:25 | ... = ... | +| Capture.cs:242:13:242:13 | i | Capture.cs:242:13:242:17 | SSA def(i) | Capture.cs:242:13:242:17 | Int32 i = ... | +| Capture.cs:242:13:242:13 | i | Capture.cs:254:27:254:27 | SSA def(i) | Capture.cs:254:27:254:27 | access to local variable i | +| Capture.cs:248:36:248:36 | j | Capture.cs:251:13:251:17 | SSA def(j) | Capture.cs:251:13:251:17 | ... = ... | | Consistency.cs:7:25:7:25 | b | Consistency.cs:7:25:7:25 | SSA param(b) | Consistency.cs:7:25:7:25 | b | | Consistency.cs:15:17:15:17 | i | Consistency.cs:15:17:15:21 | SSA def(i) | Consistency.cs:15:17:15:21 | Int32 i = ... | | Consistency.cs:15:17:15:17 | i | Consistency.cs:15:17:15:21 | [finally: exception(Exception)] SSA def(i) | Consistency.cs:15:17:15:21 | Int32 i = ... | diff --git a/csharp/ql/test/library-tests/dataflow/ssa/SsaRead.expected b/csharp/ql/test/library-tests/dataflow/ssa/SsaRead.expected index 04134b73604f..1d236dd6588c 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/SsaRead.expected +++ b/csharp/ql/test/library-tests/dataflow/ssa/SsaRead.expected @@ -63,6 +63,8 @@ | Capture.cs:212:30:212:35 | exited | Capture.cs:212:30:212:71 | SSA def(exited) | Capture.cs:213:29:213:34 | access to local variable exited | | Capture.cs:229:13:229:13 | i | Capture.cs:231:9:231:49 | SSA capture def(i) | Capture.cs:231:47:231:47 | access to local variable i | | Capture.cs:229:13:229:13 | i | Capture.cs:236:9:236:12 | SSA call def(i) | Capture.cs:237:34:237:34 | access to local variable i | +| Capture.cs:242:13:242:13 | i | Capture.cs:242:13:242:17 | SSA def(i) | Capture.cs:254:27:254:27 | access to local variable i | +| Capture.cs:242:13:242:13 | i | Capture.cs:254:27:254:27 | SSA def(i) | Capture.cs:255:34:255:34 | access to local variable i | | Consistency.cs:7:25:7:25 | b | Consistency.cs:7:25:7:25 | SSA param(b) | Consistency.cs:11:17:11:17 | access to parameter b | | Consistency.cs:15:17:15:17 | i | Consistency.cs:15:17:15:21 | SSA def(i) | Consistency.cs:16:17:16:17 | access to local variable i | | Consistency.cs:15:17:15:17 | i | Consistency.cs:15:17:15:21 | [finally: exception(Exception)] SSA def(i) | Consistency.cs:16:17:16:17 | access to local variable i | diff --git a/csharp/ql/test/library-tests/dataflow/ssa/SsaUltimateDef.expected b/csharp/ql/test/library-tests/dataflow/ssa/SsaUltimateDef.expected index 91dce3c7740d..dd7aa8623b79 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/SsaUltimateDef.expected +++ b/csharp/ql/test/library-tests/dataflow/ssa/SsaUltimateDef.expected @@ -93,6 +93,9 @@ | Capture.cs:229:13:229:13 | i | Capture.cs:235:21:235:25 | SSA def(i) | Capture.cs:235:21:235:25 | SSA def(i) | | Capture.cs:229:13:229:13 | i | Capture.cs:236:9:236:12 | SSA call def(i) | Capture.cs:232:9:232:13 | SSA def(i) | | Capture.cs:229:13:229:13 | i | Capture.cs:236:9:236:12 | SSA call def(i) | Capture.cs:236:9:236:12 | SSA call def(i) | +| Capture.cs:242:13:242:13 | i | Capture.cs:242:13:242:17 | SSA def(i) | Capture.cs:242:13:242:17 | SSA def(i) | +| Capture.cs:242:13:242:13 | i | Capture.cs:254:27:254:27 | SSA def(i) | Capture.cs:254:27:254:27 | SSA def(i) | +| Capture.cs:248:36:248:36 | j | Capture.cs:251:13:251:17 | SSA def(j) | Capture.cs:251:13:251:17 | SSA def(j) | | Consistency.cs:7:25:7:25 | b | Consistency.cs:7:25:7:25 | SSA param(b) | Consistency.cs:7:25:7:25 | SSA param(b) | | Consistency.cs:15:17:15:17 | i | Consistency.cs:15:17:15:21 | SSA def(i) | Consistency.cs:15:17:15:21 | SSA def(i) | | Consistency.cs:15:17:15:17 | i | Consistency.cs:15:17:15:21 | [finally: exception(Exception)] SSA def(i) | Consistency.cs:15:17:15:21 | [finally: exception(Exception)] SSA def(i) | diff --git a/csharp/ql/test/library-tests/dataflow/types/Types.cs b/csharp/ql/test/library-tests/dataflow/types/Types.cs index 92f60ec551e3..9cb505004b79 100644 --- a/csharp/ql/test/library-tests/dataflow/types/Types.cs +++ b/csharp/ql/test/library-tests/dataflow/types/Types.cs @@ -128,4 +128,28 @@ void M10() } static object Through(object x) => x; + + class FieldA + { + public object Field; + + public virtual void M() { } + + public void CallM() => this.M(); + + static void M1(FieldB b, FieldC c) + { + b.Field = new object(); + b.CallM(); // no flow + c.Field = new object(); + c.CallM(); // flow + } + } + + class FieldB : FieldA { } + + class FieldC : FieldA + { + public override void M() => Sink(this.Field); + } } diff --git a/csharp/ql/test/library-tests/dataflow/types/Types.expected b/csharp/ql/test/library-tests/dataflow/types/Types.expected index 3101be8d8540..43b06fb7cba8 100644 --- a/csharp/ql/test/library-tests/dataflow/types/Types.expected +++ b/csharp/ql/test/library-tests/dataflow/types/Types.expected @@ -43,6 +43,13 @@ edges | Types.cs:121:26:121:33 | object creation of type E2 : Types.E.E2 | Types.cs:123:30:123:31 | access to local variable e2 : Types.E.E2 | | Types.cs:122:30:122:30 | access to local variable a : A | Types.cs:122:22:122:31 | call to method Through | | Types.cs:123:30:123:31 | access to local variable e2 : Types.E.E2 | Types.cs:123:22:123:32 | call to method Through | +| Types.cs:138:21:138:25 | this [Field] : Object | Types.cs:138:32:138:35 | this access [Field] : Object | +| Types.cs:138:32:138:35 | this access [Field] : Object | Types.cs:153:30:153:30 | this [Field] : Object | +| Types.cs:144:13:144:13 | [post] access to parameter c [Field] : Object | Types.cs:145:13:145:13 | access to parameter c [Field] : Object | +| Types.cs:144:23:144:34 | object creation of type Object : Object | Types.cs:144:13:144:13 | [post] access to parameter c [Field] : Object | +| Types.cs:145:13:145:13 | access to parameter c [Field] : Object | Types.cs:138:21:138:25 | this [Field] : Object | +| Types.cs:153:30:153:30 | this [Field] : Object | Types.cs:153:42:153:45 | this access [Field] : Object | +| Types.cs:153:42:153:45 | this access [Field] : Object | Types.cs:153:42:153:51 | access to field Field | nodes | Types.cs:7:21:7:25 | this : D | semmle.label | this : D | | Types.cs:7:32:7:35 | this access : D | semmle.label | this access : D | @@ -100,21 +107,30 @@ nodes | Types.cs:122:30:122:30 | access to local variable a : A | semmle.label | access to local variable a : A | | Types.cs:123:22:123:32 | call to method Through | semmle.label | call to method Through | | Types.cs:123:30:123:31 | access to local variable e2 : Types.E.E2 | semmle.label | access to local variable e2 : Types.E.E2 | +| Types.cs:138:21:138:25 | this [Field] : Object | semmle.label | this [Field] : Object | +| Types.cs:138:32:138:35 | this access [Field] : Object | semmle.label | this access [Field] : Object | +| Types.cs:144:13:144:13 | [post] access to parameter c [Field] : Object | semmle.label | [post] access to parameter c [Field] : Object | +| Types.cs:144:23:144:34 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| Types.cs:145:13:145:13 | access to parameter c [Field] : Object | semmle.label | access to parameter c [Field] : Object | +| Types.cs:153:30:153:30 | this [Field] : Object | semmle.label | this [Field] : Object | +| Types.cs:153:42:153:45 | this access [Field] : Object | semmle.label | this access [Field] : Object | +| Types.cs:153:42:153:51 | access to field Field | semmle.label | access to field Field | #select -| Types.cs:23:12:23:18 | object creation of type C : C | Types.cs:50:18:50:18 | access to local variable c | Types.cs:50:18:50:18 | access to local variable c | $@ | Types.cs:50:18:50:18 | access to local variable c | access to local variable c | -| Types.cs:25:12:25:18 | object creation of type C : C | Types.cs:63:33:63:36 | (...) ... | Types.cs:63:33:63:36 | (...) ... | $@ | Types.cs:63:33:63:36 | (...) ... | (...) ... | -| Types.cs:26:12:26:18 | object creation of type C : C | Types.cs:65:36:65:36 | access to parameter x | Types.cs:65:36:65:36 | access to parameter x | $@ | Types.cs:65:36:65:36 | access to parameter x | access to parameter x | -| Types.cs:27:12:27:18 | object creation of type C : C | Types.cs:67:48:67:48 | access to parameter x | Types.cs:67:48:67:48 | access to parameter x | $@ | Types.cs:67:48:67:48 | access to parameter x | access to parameter x | -| Types.cs:28:12:28:18 | object creation of type C : C | Types.cs:69:52:69:52 | access to parameter x | Types.cs:69:52:69:52 | access to parameter x | $@ | Types.cs:69:52:69:52 | access to parameter x | access to parameter x | -| Types.cs:30:12:30:18 | object creation of type C : C | Types.cs:80:18:80:18 | access to local variable b | Types.cs:80:18:80:18 | access to local variable b | $@ | Types.cs:80:18:80:18 | access to local variable b | access to local variable b | -| Types.cs:32:9:32:15 | object creation of type D : D | Types.cs:16:42:16:45 | this access | Types.cs:16:42:16:45 | this access | $@ | Types.cs:16:42:16:45 | this access | this access | -| Types.cs:33:9:33:15 | object creation of type D : D | Types.cs:16:42:16:45 | this access | Types.cs:16:42:16:45 | this access | $@ | Types.cs:16:42:16:45 | this access | this access | -| Types.cs:35:12:35:18 | object creation of type D : D | Types.cs:58:22:58:22 | access to local variable d | Types.cs:58:22:58:22 | access to local variable d | $@ | Types.cs:58:22:58:22 | access to local variable d | access to local variable d | -| Types.cs:37:12:37:18 | object creation of type D : D | Types.cs:65:36:65:36 | access to parameter x | Types.cs:65:36:65:36 | access to parameter x | $@ | Types.cs:65:36:65:36 | access to parameter x | access to parameter x | -| Types.cs:38:12:38:18 | object creation of type D : D | Types.cs:67:48:67:48 | access to parameter x | Types.cs:67:48:67:48 | access to parameter x | $@ | Types.cs:67:48:67:48 | access to parameter x | access to parameter x | -| Types.cs:39:12:39:18 | object creation of type D : D | Types.cs:69:52:69:52 | access to parameter x | Types.cs:69:52:69:52 | access to parameter x | $@ | Types.cs:69:52:69:52 | access to parameter x | access to parameter x | -| Types.cs:40:12:40:18 | object creation of type D : D | Types.cs:16:42:16:45 | this access | Types.cs:16:42:16:45 | this access | $@ | Types.cs:16:42:16:45 | this access | this access | -| Types.cs:43:20:43:23 | null : null | Types.cs:44:14:44:14 | access to local variable o | Types.cs:44:14:44:14 | access to local variable o | $@ | Types.cs:44:14:44:14 | access to local variable o | access to local variable o | -| Types.cs:110:25:110:32 | object creation of type E2 : Types.E.E2 | Types.cs:115:22:115:31 | access to field Field | Types.cs:115:22:115:31 | access to field Field | $@ | Types.cs:115:22:115:31 | access to field Field | access to field Field | -| Types.cs:120:25:120:31 | object creation of type A : A | Types.cs:122:22:122:31 | call to method Through | Types.cs:122:22:122:31 | call to method Through | $@ | Types.cs:122:22:122:31 | call to method Through | call to method Through | -| Types.cs:121:26:121:33 | object creation of type E2 : Types.E.E2 | Types.cs:123:22:123:32 | call to method Through | Types.cs:123:22:123:32 | call to method Through | $@ | Types.cs:123:22:123:32 | call to method Through | call to method Through | +| Types.cs:23:12:23:18 | object creation of type C : C | Types.cs:23:12:23:18 | object creation of type C : C | Types.cs:50:18:50:18 | access to local variable c | $@ | Types.cs:50:18:50:18 | access to local variable c | access to local variable c | +| Types.cs:25:12:25:18 | object creation of type C : C | Types.cs:25:12:25:18 | object creation of type C : C | Types.cs:63:33:63:36 | (...) ... | $@ | Types.cs:63:33:63:36 | (...) ... | (...) ... | +| Types.cs:26:12:26:18 | object creation of type C : C | Types.cs:26:12:26:18 | object creation of type C : C | Types.cs:65:36:65:36 | access to parameter x | $@ | Types.cs:65:36:65:36 | access to parameter x | access to parameter x | +| Types.cs:27:12:27:18 | object creation of type C : C | Types.cs:27:12:27:18 | object creation of type C : C | Types.cs:67:48:67:48 | access to parameter x | $@ | Types.cs:67:48:67:48 | access to parameter x | access to parameter x | +| Types.cs:28:12:28:18 | object creation of type C : C | Types.cs:28:12:28:18 | object creation of type C : C | Types.cs:69:52:69:52 | access to parameter x | $@ | Types.cs:69:52:69:52 | access to parameter x | access to parameter x | +| Types.cs:30:12:30:18 | object creation of type C : C | Types.cs:30:12:30:18 | object creation of type C : C | Types.cs:80:18:80:18 | access to local variable b | $@ | Types.cs:80:18:80:18 | access to local variable b | access to local variable b | +| Types.cs:32:9:32:15 | object creation of type D : D | Types.cs:32:9:32:15 | object creation of type D : D | Types.cs:16:42:16:45 | this access | $@ | Types.cs:16:42:16:45 | this access | this access | +| Types.cs:33:9:33:15 | object creation of type D : D | Types.cs:33:9:33:15 | object creation of type D : D | Types.cs:16:42:16:45 | this access | $@ | Types.cs:16:42:16:45 | this access | this access | +| Types.cs:35:12:35:18 | object creation of type D : D | Types.cs:35:12:35:18 | object creation of type D : D | Types.cs:58:22:58:22 | access to local variable d | $@ | Types.cs:58:22:58:22 | access to local variable d | access to local variable d | +| Types.cs:37:12:37:18 | object creation of type D : D | Types.cs:37:12:37:18 | object creation of type D : D | Types.cs:65:36:65:36 | access to parameter x | $@ | Types.cs:65:36:65:36 | access to parameter x | access to parameter x | +| Types.cs:38:12:38:18 | object creation of type D : D | Types.cs:38:12:38:18 | object creation of type D : D | Types.cs:67:48:67:48 | access to parameter x | $@ | Types.cs:67:48:67:48 | access to parameter x | access to parameter x | +| Types.cs:39:12:39:18 | object creation of type D : D | Types.cs:39:12:39:18 | object creation of type D : D | Types.cs:69:52:69:52 | access to parameter x | $@ | Types.cs:69:52:69:52 | access to parameter x | access to parameter x | +| Types.cs:40:12:40:18 | object creation of type D : D | Types.cs:40:12:40:18 | object creation of type D : D | Types.cs:16:42:16:45 | this access | $@ | Types.cs:16:42:16:45 | this access | this access | +| Types.cs:43:20:43:23 | null : null | Types.cs:43:20:43:23 | null : null | Types.cs:44:14:44:14 | access to local variable o | $@ | Types.cs:44:14:44:14 | access to local variable o | access to local variable o | +| Types.cs:110:25:110:32 | object creation of type E2 : Types.E.E2 | Types.cs:110:25:110:32 | object creation of type E2 : Types.E.E2 | Types.cs:115:22:115:31 | access to field Field | $@ | Types.cs:115:22:115:31 | access to field Field | access to field Field | +| Types.cs:120:25:120:31 | object creation of type A : A | Types.cs:120:25:120:31 | object creation of type A : A | Types.cs:122:22:122:31 | call to method Through | $@ | Types.cs:122:22:122:31 | call to method Through | call to method Through | +| Types.cs:121:26:121:33 | object creation of type E2 : Types.E.E2 | Types.cs:121:26:121:33 | object creation of type E2 : Types.E.E2 | Types.cs:123:22:123:32 | call to method Through | $@ | Types.cs:123:22:123:32 | call to method Through | call to method Through | +| Types.cs:144:23:144:34 | object creation of type Object : Object | Types.cs:144:23:144:34 | object creation of type Object : Object | Types.cs:153:42:153:51 | access to field Field | $@ | Types.cs:153:42:153:51 | access to field Field | access to field Field | diff --git a/csharp/ql/test/library-tests/dataflow/types/Types.ql b/csharp/ql/test/library-tests/dataflow/types/Types.ql index da3d8b63b616..57e42a5352ee 100644 --- a/csharp/ql/test/library-tests/dataflow/types/Types.ql +++ b/csharp/ql/test/library-tests/dataflow/types/Types.ql @@ -23,4 +23,4 @@ class Conf extends DataFlow::Configuration { from DataFlow::PathNode source, DataFlow::PathNode sink, Conf conf where conf.hasFlowPath(source, sink) -select source, sink, sink, "$@", sink, sink.toString() +select source, source, sink, "$@", sink, sink.toString() diff --git a/csharp/ql/test/library-tests/definitions/PrintAst.expected b/csharp/ql/test/library-tests/definitions/PrintAst.expected new file mode 100644 index 000000000000..5543a3363d5e --- /dev/null +++ b/csharp/ql/test/library-tests/definitions/PrintAst.expected @@ -0,0 +1,407 @@ +definitions.cs: +# 4| [NamespaceDeclaration] namespace ... { ... } +# 6| 1: [Class] StaticClass +# 8| 4: [ExtensionMethod] ExtensionMethod +#-----| 2: (Parameters) +# 8| 0: [Parameter] c1 +# 8| 1: [Parameter] args +# 9| 4: [BlockStmt] {...} +# 13| 2: [Enum] Enumeration +# 15| 5: [Field] e1 +# 15| 1: [AssignExpr] ... = ... +# 15| 0: [IntLiteral] 1 +# 15| 1: [MemberConstantAccess] access to constant e1 +# 15| 6: [Field] e2 +# 15| 1: [AssignExpr] ... = ... +# 15| 0: [IntLiteral] 2 +# 15| 1: [MemberConstantAccess] access to constant e2 +# 15| 7: [Field] e3 +# 18| 3: [Class] C1 +# 20| 4: [InstanceConstructor] C1 +#-----| 2: (Parameters) +# 20| 0: [Parameter] args +# 20| 4: [BlockStmt] {...} +# 22| 5: [Field] field1 +# 24| 6: [Property] property1 +# 26| 3: [Getter] get_property1 +# 26| 4: [BlockStmt] {...} +# 26| 0: [ReturnStmt] return ...; +# 26| 0: [FieldAccess] access to field field1 +# 27| 4: [Setter] set_property1 +#-----| 2: (Parameters) +# 27| 0: [Parameter] value +# 27| 4: [BlockStmt] {...} +# 27| 0: [ExprStmt] ...; +# 27| 0: [AssignExpr] ... = ... +# 27| 0: [ParameterAccess] access to parameter value +# 27| 1: [FieldAccess] access to field field1 +# 30| 7: [Method] f1 +#-----| 2: (Parameters) +# 30| 0: [Parameter] args +# 31| 4: [BlockStmt] {...} +# 32| 0: [LocalVariableDeclStmt] ... ...; +# 32| 0: [LocalVariableDeclAndInitExpr] C1 qualifier = ... +# 32| 0: [ThisAccess] this access +# 32| 1: [LocalVariableAccess] access to local variable qualifier +# 35| 1: [ExprStmt] ...; +# 35| 0: [MethodCall] call to method f1 +# 36| 2: [ExprStmt] ...; +# 36| 0: [MethodCall] call to method f1 +# 36| 0: [IntLiteral] 1 +# 37| 3: [ExprStmt] ...; +# 37| 0: [MethodCall] call to method f1 +# 37| 0: [IntLiteral] 1 +# 37| 1: [IntLiteral] 2 +# 39| 4: [ExprStmt] ...; +# 39| 0: [MethodCall] call to method f1 +# 39| -1: [ThisAccess] this access +# 40| 5: [ExprStmt] ...; +# 40| 0: [MethodCall] call to method f1 +# 40| -1: [ThisAccess] this access +# 40| 0: [IntLiteral] 1 +# 41| 6: [ExprStmt] ...; +# 41| 0: [MethodCall] call to method f1 +# 41| -1: [ThisAccess] this access +# 41| 0: [IntLiteral] 1 +# 41| 1: [IntLiteral] 2 +# 43| 7: [ExprStmt] ...; +# 43| 0: [MethodCall] call to method ExtensionMethod +# 43| -1: [ThisAccess] this access +# 44| 8: [ExprStmt] ...; +# 44| 0: [MethodCall] call to method ExtensionMethod +# 44| -1: [ThisAccess] this access +# 44| 0: [CastExpr] (...) ... +# 44| 0: [IntLiteral] 1 +# 45| 9: [ExprStmt] ...; +# 45| 0: [MethodCall] call to method ExtensionMethod +# 45| -1: [ThisAccess] this access +# 45| 0: [CastExpr] (...) ... +# 45| 0: [IntLiteral] 1 +# 45| 1: [CastExpr] (...) ... +# 45| 0: [IntLiteral] 2 +# 47| 10: [ExprStmt] ...; +# 47| 0: [MethodCall] call to method GenericFn +# 47| 0: [IntLiteral] 1 +# 48| 11: [ExprStmt] ...; +# 48| 0: [MethodCall] call to method GenericFn +# 48| -1: [ThisAccess] this access +# 48| 0: [IntLiteral] 2 +# 51| 12: [ExprStmt] ...; +# 51| 0: [ObjectCreation] object creation of type C1 +# 52| 13: [ExprStmt] ...; +# 52| 0: [ObjectCreation] object creation of type C1 +# 52| 0: [IntLiteral] 1 +# 53| 14: [ExprStmt] ...; +# 53| 0: [ObjectCreation] object creation of type C1 +# 53| 0: [IntLiteral] 1 +# 53| 1: [IntLiteral] 2 +# 56| 15: [LocalVariableDeclStmt] ... ...; +# 56| 0: [LocalVariableDeclAndInitExpr] Int32 x = ... +# 56| 0: [IntLiteral] 2 +# 56| 1: [LocalVariableAccess] access to local variable x +# 56| 1: [LocalVariableDeclAndInitExpr] Int32 y = ... +# 56| 0: [LocalVariableAccess] access to local variable x +# 56| 1: [LocalVariableAccess] access to local variable y +# 56| 2: [LocalVariableDeclAndInitExpr] Int32 z = ... +# 56| 0: [FieldAccess] access to field field1 +# 56| 1: [LocalVariableAccess] access to local variable z +# 56| 3: [LocalVariableDeclAndInitExpr] Int32 w = ... +# 56| 0: [ArrayAccess] access to array element +# 56| -1: [ParameterAccess] access to parameter args +# 56| 0: [IntLiteral] 0 +# 56| 1: [LocalVariableAccess] access to local variable w +# 57| 16: [LocalVariableDeclStmt] ... ...; +# 57| 0: [LocalVariableDeclAndInitExpr] Enumeration e = ... +# 57| 0: [MemberConstantAccess] access to constant e1 +# 57| -1: [TypeAccess] access to type Enumeration +# 57| 1: [LocalVariableAccess] access to local variable e +# 60| 17: [ExprStmt] ...; +# 60| 0: [AssignExpr] ... = ... +# 60| 0: [AddExpr] ... + ... +# 60| 0: [PropertyCall] access to property property1 +# 60| 1: [IntLiteral] 1 +# 60| 1: [PropertyCall] access to property property1 +# 63| 18: [LocalVariableDeclStmt] ... ...; +# 63| 0: [LocalVariableDeclAndInitExpr] C1[] array = ... +# 63| 0: [NullLiteral] null +# 63| 1: [LocalVariableAccess] access to local variable array +# 64| 19: [LocalVariableDeclStmt] ... ...; +# 64| 0: [LocalVariableDeclAndInitExpr] Nullable nullable = ... +# 64| 0: [NullLiteral] null +# 64| 1: [LocalVariableAccess] access to local variable nullable +# 67| 20: [LocalVariableDeclStmt] ... ...; +# 67| 0: [LocalVariableDeclAndInitExpr] Action m1 = ... +# 67| 0: [ImplicitDelegateCreation] delegate creation of type Action +# 67| 0: [MethodAccess] access to method GenericFn +# 67| 1: [LocalVariableAccess] access to local variable m1 +# 70| 8: [Method] VariableTypeUse +#-----| 2: (Parameters) +# 70| 0: [Parameter] c1 +# 71| 4: [BlockStmt] {...} +# 72| 0: [LocalVariableDeclStmt] ... ...; +# 72| 0: [LocalVariableDeclAndInitExpr] C1 c2 = ... +# 72| 0: [NullLiteral] null +# 72| 1: [LocalVariableAccess] access to local variable c2 +# 75| 9: [Method] GenericFn +#-----| 1: (Type parameters) +# 75| 0: [TypeParameter] T +#-----| 2: (Parameters) +# 75| 0: [Parameter] t +# 75| 4: [BlockStmt] {...} +# 78| 4: [Struct] S1 +# 80| 5: [Method] M +#-----| 2: (Parameters) +# 80| 0: [Parameter] ss +# 81| 4: [BlockStmt] {...} +# 82| 0: [TryStmt] try {...} ... +# 83| 0: [BlockStmt] {...} +# 84| 0: [LocalVariableDeclStmt] ... ...; +# 84| 0: [LocalVariableDeclAndInitExpr] String timestamp = ... +# 84| 0: [MethodCall] call to method ToString +# 84| -1: [PropertyCall] access to property Now +# 84| -1: [TypeAccess] access to type DateTime +# 84| 0: [StringLiteral] "HH:mm:ss" +# 84| 1: [LocalVariableAccess] access to local variable timestamp +# 86| 1: [SpecificCatchClause] catch (...) {...} +# 86| 0: [LocalVariableDeclExpr] Exception e +# 87| 1: [BlockStmt] {...} +# 88| 0: [ForeachStmt] foreach (... ... in ...) ... +# 88| 0: [LocalVariableDeclExpr] S1 s +# 88| 1: [ParameterAccess] access to parameter ss +# 89| 2: [BlockStmt] {...} +# 92| 1: [LocalVariableDeclStmt] ... ...; +# 92| 0: [LocalVariableDeclAndInitExpr] Type temp = ... +# 92| 0: [TypeofExpr] typeof(...) +# 92| 0: [TypeAccess] access to type S1[] +# 92| 1: [LocalVariableAccess] access to local variable temp +# 93| 2: [ReturnStmt] return ...; +# 93| 0: [ObjectCreation] object creation of type S1 +# 97| 5: [Class] A +# 99| 5: [DelegateType] EventHandler +# 101| 6: [Event] Click +# 101| 3: [AddEventAccessor] add_Click +#-----| 2: (Parameters) +# 101| 0: [Parameter] value +# 101| 4: [RemoveEventAccessor] remove_Click +#-----| 2: (Parameters) +# 101| 0: [Parameter] value +# 103| 7: [Method] M +# 104| 4: [BlockStmt] {...} +# 105| 0: [ExprStmt] ...; +# 105| 0: [AddEventExpr] ... += ... +# 105| 0: [ImplicitDelegateCreation] delegate creation of type EventHandler +# 105| 0: [MethodAccess] access to method M +# 105| 1: [EventAccess,EventCall] access to event Click +# 106| 1: [LocalFunctionStmt] LocalFunction(...) +# 106| 0: [LocalFunction] LocalFunction +# 106| 4: [BlockStmt] {...} +# 106| 2: [EmptyStmt] ; +# 107| 3: [ExprStmt] ...; +# 107| 0: [AddEventExpr] ... += ... +# 107| 0: [ImplicitDelegateCreation] delegate creation of type EventHandler +# 107| 0: [LocalFunctionAccess] access to local function LocalFunction +# 107| 1: [EventAccess,EventCall] access to event Click +# 108| 4: [ExprStmt] ...; +# 108| 0: [DelegateCall] delegate call +# 108| -1: [EventAccess,EventCall] access to event Click +# 112| 6: [Interface] I1 +# 114| 4: [Method] M2 +#-----| 1: (Type parameters) +# 114| 0: [TypeParameter] T +# 117| 7: [Interface] I2<> +#-----| 1: (Type parameters) +# 117| 0: [TypeParameter] T +# 119| 8: [Interface] I3 +#-----| 3: (Base types) +# 119| 1: [Interface] I2 +# 121| 9: [Class] B<> +#-----| 1: (Type parameters) +# 121| 0: [TypeParameter] T +#-----| 3: (Base types) +# 121| 0: [Class] A +# 121| 1: [Interface] I1 +# 121| 2: [Interface] I2 +# 123| 5: [Method] M +# 124| 4: [BlockStmt] {...} +# 125| 0: [ExprStmt] ...; +# 125| 0: [MethodCall] call to method M +# 125| -1: [BaseAccess] base access +# 128| 6: [Method] M2 +#-----| 1: (Type parameters) +# 128| 0: [TypeParameter] T +# 128| 4: [BlockStmt] {...} +# 130| 7: [Struct] S<> +#-----| 1: (Type parameters) +# 130| 0: [TypeParameter] T2 +#-----| 3: (Base types) +# 130| 1: [Interface] I3 +# 132| 8: [Method] Tuple +# 132| 4: [ThrowExpr] throw ... +# 132| 0: [ObjectCreation] object creation of type Exception +# 134| 9: [Indexer] Item +#-----| 1: (Parameters) +# 134| 0: [Parameter] a +# 134| 3: [Getter] get_Item +#-----| 2: (Parameters) +# 134| 0: [Parameter] a +# 134| 4: [BlockStmt] {...} +# 134| 0: [ReturnStmt] return ...; +# 134| 0: [DefaultValueExpr] default(...) +# 134| 0: [TypeAccess] access to type B +# 137| 10: [Class] C +# 139| 5: [Enum] E +# 140| 6: [Method] Pointer +# 140| 4: [ThrowExpr] throw ... +# 140| 0: [ObjectCreation] object creation of type Exception +# 140| 0: [MethodCall] call to method ToString +# 140| -1: [SizeofExpr] sizeof(..) +# 140| 0: [TypeAccess] access to type E* +# 143| 11: [Interface] I4 +# 145| 4: [Event] EH +# 145| 3: [AddEventAccessor] add_EH +#-----| 2: (Parameters) +# 145| 0: [Parameter] value +# 145| 4: [RemoveEventAccessor] remove_EH +#-----| 2: (Parameters) +# 145| 0: [Parameter] value +# 146| 5: [Method] M +# 147| 6: [Property] P +# 147| 3: [Getter] get_P +# 148| 7: [Indexer] Item +#-----| 1: (Parameters) +# 148| 0: [Parameter] eh +# 148| 3: [Getter] get_Item +#-----| 2: (Parameters) +# 148| 0: [Parameter] eh +# 151| 12: [Class] C4 +#-----| 3: (Base types) +# 151| 1: [Interface] I4 +# 153| 5: [Event] EH +# 153| 3: [AddEventAccessor] add_EH +#-----| 2: (Parameters) +# 153| 0: [Parameter] value +# 153| 4: [BlockStmt] {...} +# 153| 4: [RemoveEventAccessor] remove_EH +#-----| 2: (Parameters) +# 153| 0: [Parameter] value +# 153| 4: [BlockStmt] {...} +# 154| 6: [Method] M +# 154| 4: [ThrowExpr] throw ... +# 154| 0: [ObjectCreation] object creation of type Exception +# 155| 7: [Property] P +# 155| 3: [Getter] get_P +# 155| 4: [ThrowExpr] throw ... +# 155| 0: [ObjectCreation] object creation of type Exception +# 156| 8: [Indexer] Item +#-----| 1: (Parameters) +# 156| 0: [Parameter] eh +# 156| 3: [Getter] get_Item +#-----| 2: (Parameters) +# 156| 0: [Parameter] eh +# 156| 4: [BlockStmt] {...} +# 156| 0: [ReturnStmt] return ...; +# 156| 0: [CastExpr] (...) ... +# 156| 0: [ObjectCreation] object creation of type S1 +# 156| 1: [TypeAccess] access to type S1 +# 158| 9: [Class] Nested<> +#-----| 1: (Type parameters) +# 158| 0: [TypeParameter] T +# 160| 5: [Method] Create +# 160| 4: [BlockStmt] {...} +# 160| 0: [ReturnStmt] return ...; +# 160| 0: [ObjectCreation] object creation of type Nested<> +# 164| 13: [Class] C5 +# 166| 5: [Field] f +# 166| 1: [AssignExpr] ... = ... +# 166| 0: [MethodCall] call to method Create +# 166| -1: [TypeAccess] access to type Nested +# 166| -1: [TypeAccess] access to type C4 +# 166| 1: [FieldAccess] access to field f +# 167| 6: [Field] c1 +# 169| 7: [Method] M +# 170| 4: [BlockStmt] {...} +# 171| 0: [LocalVariableDeclStmt] ... ...; +# 171| 0: [LocalVariableDeclAndInitExpr] C1 c = ... +# 171| 0: [ObjectCreation] object creation of type C1 +# 171| 1: [LocalVariableAccess] access to local variable c +# 172| 1: [ExprStmt] ...; +# 172| 0: [AssignExpr] ... = ... +# 172| 0: [PropertyCall] access to property property1 +# 172| -1: [LocalVariableAccess] access to local variable c +# 172| 1: [PropertyCall] access to property property1 +# 172| -1: [LocalVariableAccess] access to local variable c +# 173| 2: [LocalVariableDeclStmt] ... ...; +# 173| 0: [LocalVariableDeclAndInitExpr] C5 c5 = ... +# 173| 0: [AsExpr] ... as ... +# 173| 0: [ObjectCreation] object creation of type C5 +# 173| 1: [TypeAccess] access to type C5 +# 173| 1: [LocalVariableAccess] access to local variable c5 +# 174| 3: [ExprStmt] ...; +# 174| 0: [AssignExpr] ... = ... +# 174| 0: [IntLiteral] 0 +# 174| 1: [PropertyCall] access to property property1 +# 174| -1: [FieldAccess] access to field c1 +# 174| -1: [LocalVariableAccess] access to local variable c5 +# 175| 4: [LocalVariableDeclStmt] ... ...; +# 175| 0: [LocalVariableDeclAndInitExpr] Boolean temp = ... +# 175| 0: [IsExpr] ... is ... +# 175| 0: [LocalVariableAccess] access to local variable c5 +# 175| 1: [TypeAccessPatternExpr] access to type Nested +# 175| 1: [LocalVariableAccess] access to local variable temp +# 179| 14: [Class] C6 +# 181| 5: [ExplicitConversionOperator] explicit conversion +#-----| 2: (Parameters) +# 181| 0: [Parameter] c +#-----| 0: (Attributes) +# 181| 1: [Attribute] [My(...)] +# 182| 4: [BlockStmt] {...} +# 183| 0: [ReturnStmt] return ...; +# 183| 0: [NullLiteral] null +# 186| 6: [Method] M +# 187| 4: [BlockStmt] {...} +# 188| 0: [ReturnStmt] return ...; +# 188| 0: [OperatorCall] call to operator explicit conversion +# 188| 0: [ThisAccess] this access +# 191| 7: [AddOperator] + +#-----| 2: (Parameters) +# 191| 0: [Parameter] x +# 191| 1: [Parameter] y +# 191| 4: [ParameterAccess] access to parameter x +# 194| 15: [Class] MyAttribute +#-----| 3: (Base types) +# 194| 0: [Class] Attribute +# 196| 16: [Class] C7 +# 198| 5: [Method] M +# 198| 4: [BlockStmt] {...} +# 200| 6: [Method] M2 +# 201| 4: [BlockStmt] {...} +# 202| 0: [ExprStmt] ...; +# 202| 0: [MethodCall] call to method M +# 202| -1: [TypeAccess] access to type C7 +# 206| 17: [Class] C8 +# 208| 5: [Method] F +# 209| 4: [BlockStmt] {...} +# 210| 0: [LocalVariableDeclStmt] ... ...; +# 210| 0: [LocalVariableDeclAndInitExpr] C8 c8a = ... +# 210| 0: [NullLiteral] null +# 210| 1: [LocalVariableAccess] access to local variable c8a +# 211| 1: [IfStmt] if (...) ... +# 211| 0: [IsExpr] ... is ... +# 211| 0: [LocalVariableAccess] access to local variable c8a +# 211| 1: [VariablePatternExpr] C8 c8b +# 212| 1: [ExprStmt] ...; +# 212| 0: [AssignExpr] ... = ... +# 212| 0: [LocalVariableAccess] access to local variable c8b +# 212| 1: [LocalVariableAccess] access to local variable c8a +# 213| 2: [SwitchStmt] switch (...) {...} +# 213| 0: [LocalVariableAccess] access to local variable c8a +# 215| 0: [CaseStmt] case ...: +# 215| 0: [VariablePatternExpr] C8 c8c +# 215| 1: [NEExpr] ... != ... +# 215| 0: [LocalVariableAccess] access to local variable c8c +# 215| 1: [NullLiteral] null +# 216| 1: [ExprStmt] ...; +# 216| 0: [AssignExpr] ... = ... +# 216| 0: [LocalVariableAccess] access to local variable c8c +# 216| 1: [LocalVariableAccess] access to local variable c8a +# 217| 2: [BreakStmt] break; diff --git a/csharp/ql/test/library-tests/definitions/PrintAst.qlref b/csharp/ql/test/library-tests/definitions/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/definitions/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/delegates/PrintAst.expected b/csharp/ql/test/library-tests/delegates/PrintAst.expected new file mode 100644 index 000000000000..0c73aa05ae10 --- /dev/null +++ b/csharp/ql/test/library-tests/delegates/PrintAst.expected @@ -0,0 +1,190 @@ +delegates.cs: +# 5| [NamespaceDeclaration] namespace ... { ... } +# 7| 1: [DelegateType] FooDelegate +#-----| 2: (Parameters) +# 7| 0: [Parameter] param +# 7| 1: [Parameter] condition +# 7| 2: [Parameter] args +# 9| 2: [DelegateType] D1 +#-----| 2: (Parameters) +# 9| 0: [Parameter] i +# 9| 1: [Parameter] d +# 11| 3: [Class] A +# 14| 5: [Method] M1 +#-----| 2: (Parameters) +# 14| 0: [Parameter] a +# 14| 1: [Parameter] b +# 14| 4: [BlockStmt] {...} +# 14| 0: [ReturnStmt] return ...; +# 14| 0: [CastExpr] (...) ... +# 14| 0: [AddExpr] ... + ... +# 14| 0: [CastExpr] (...) ... +# 14| 0: [ParameterAccess] access to parameter a +# 14| 1: [ParameterAccess] access to parameter b +# 14| 1: [TypeAccess] access to type Int32 +# 18| 4: [Class] B +# 21| 5: [DelegateType] D2 +#-----| 2: (Parameters) +# 21| 0: [Parameter] c +# 21| 1: [Parameter] d +# 23| 6: [Method] M1 +#-----| 2: (Parameters) +# 23| 0: [Parameter] f +# 23| 1: [Parameter] g +# 23| 4: [BlockStmt] {...} +# 23| 0: [ReturnStmt] return ...; +# 23| 0: [SubExpr] ... - ... +# 23| 0: [ParameterAccess] access to parameter f +# 23| 1: [CastExpr] (...) ... +# 23| 0: [ParameterAccess] access to parameter g +# 23| 1: [TypeAccess] access to type Int32 +# 25| 7: [Method] M2 +#-----| 2: (Parameters) +# 25| 0: [Parameter] k +# 25| 1: [Parameter] l +# 25| 4: [BlockStmt] {...} +# 27| 8: [Method] M3 +#-----| 2: (Parameters) +# 27| 0: [Parameter] g +# 27| 4: [BlockStmt] {...} +# 27| 0: [ReturnStmt] return ...; +# 27| 0: [AddExpr] ... + ... +# 27| 0: [UnaryMinusExpr] -... +# 27| 0: [ParameterAccess] access to parameter g +# 27| 1: [UnaryPlusExpr] +... +# 27| 0: [ParameterAccess] access to parameter g +# 29| 9: [Method] M4 +#-----| 2: (Parameters) +# 29| 0: [Parameter] g +# 29| 4: [BlockStmt] {...} +# 33| 5: [DelegateType] Predicate<> +#-----| 1: (Type parameters) +# 33| 0: [TypeParameter] T +#-----| 2: (Parameters) +# 33| 0: [Parameter] value +# 35| 6: [Class] X +# 38| 5: [Method] F +#-----| 2: (Parameters) +# 38| 0: [Parameter] i +# 38| 4: [BlockStmt] {...} +# 38| 0: [ReturnStmt] return ...; +# 38| 0: [LTExpr] ... < ... +# 38| 0: [ParameterAccess] access to parameter i +# 38| 1: [IntLiteral] 2 +# 40| 6: [Method] G +#-----| 2: (Parameters) +# 40| 0: [Parameter] s +# 40| 4: [BlockStmt] {...} +# 40| 0: [ReturnStmt] return ...; +# 40| 0: [BoolLiteral] false +# 44| 7: [DelegateType] D +#-----| 2: (Parameters) +# 44| 0: [Parameter] x +# 46| 8: [Class] C +# 49| 5: [Method] M1 +#-----| 2: (Parameters) +# 49| 0: [Parameter] i +# 49| 4: [BlockStmt] {...} +# 50| 6: [Method] M2 +#-----| 2: (Parameters) +# 50| 0: [Parameter] i +# 50| 4: [BlockStmt] {...} +# 51| 7: [Method] M3 +#-----| 2: (Parameters) +# 51| 0: [Parameter] i +# 51| 4: [BlockStmt] {...} +# 55| 9: [Class] Test +# 58| 5: [Method] Main +# 59| 4: [BlockStmt] {...} +# 60| 0: [LocalVariableDeclStmt] ... ...; +# 60| 0: [LocalVariableDeclAndInitExpr] D cd1 = ... +# 60| 0: [ExplicitDelegateCreation] delegate creation of type D +# 60| 0: [MethodAccess] access to method M1 +# 60| -1: [TypeAccess] access to type C +# 60| 1: [LocalVariableAccess] access to local variable cd1 +# 61| 1: [LocalVariableDeclStmt] ... ...; +# 61| 0: [LocalVariableDeclAndInitExpr] D cd2 = ... +# 61| 0: [ImplicitDelegateCreation] delegate creation of type D +# 61| 0: [MethodAccess] access to method M2 +# 61| -1: [TypeAccess] access to type C +# 61| 1: [LocalVariableAccess] access to local variable cd2 +# 62| 2: [LocalVariableDeclStmt] ... ...; +# 62| 0: [LocalVariableDeclAndInitExpr] D cd3 = ... +# 62| 0: [OperatorCall] call to operator + +# 62| 0: [LocalVariableAccess] access to local variable cd1 +# 62| 1: [LocalVariableAccess] access to local variable cd2 +# 62| 1: [LocalVariableAccess] access to local variable cd3 +# 63| 3: [LocalVariableDeclStmt] ... ...; +# 63| 0: [LocalVariableDeclAndInitExpr] D cd4 = ... +# 63| 0: [OperatorCall] call to operator + +# 63| 0: [LocalVariableAccess] access to local variable cd3 +# 63| 1: [LocalVariableAccess] access to local variable cd1 +# 63| 1: [LocalVariableAccess] access to local variable cd4 +# 64| 4: [LocalVariableDeclStmt] ... ...; +# 64| 0: [LocalVariableDeclAndInitExpr] D cd5 = ... +# 64| 0: [OperatorCall] call to operator - +# 64| 0: [LocalVariableAccess] access to local variable cd4 +# 64| 1: [LocalVariableAccess] access to local variable cd3 +# 64| 1: [LocalVariableAccess] access to local variable cd5 +# 65| 5: [ExprStmt] ...; +# 65| 0: [AssignAddExpr] ... += ... +# 65| 0: [LocalVariableAccess] access to local variable cd5 +# 65| 1: [LocalVariableAccess] access to local variable cd4 +# 66| 6: [ExprStmt] ...; +# 66| 0: [AssignSubExpr] ... -= ... +# 66| 0: [LocalVariableAccess] access to local variable cd1 +# 66| 1: [LocalVariableAccess] access to local variable cd4 +# 68| 7: [LocalVariableDeclStmt] ... ...; +# 68| 0: [LocalVariableDeclAndInitExpr] C c = ... +# 68| 0: [ObjectCreation] object creation of type C +# 68| 1: [LocalVariableAccess] access to local variable c +# 69| 8: [LocalVariableDeclStmt] ... ...; +# 69| 0: [LocalVariableDeclAndInitExpr] D cd6 = ... +# 69| 0: [ExplicitDelegateCreation] delegate creation of type D +# 69| 0: [MethodAccess] access to method M3 +# 69| -1: [LocalVariableAccess] access to local variable c +# 69| 1: [LocalVariableAccess] access to local variable cd6 +# 70| 9: [LocalVariableDeclStmt] ... ...; +# 70| 0: [LocalVariableDeclAndInitExpr] D cd7 = ... +# 70| 0: [ExplicitDelegateCreation] delegate creation of type D +# 70| 0: [LocalVariableAccess] access to local variable cd6 +# 70| 1: [LocalVariableAccess] access to local variable cd7 +# 72| 10: [ExprStmt] ...; +# 72| 0: [DelegateCall] delegate call +# 72| -1: [LocalVariableAccess] access to local variable cd1 +# 72| 0: [UnaryMinusExpr] -... +# 72| 0: [IntLiteral] 40 +# 73| 11: [LocalVariableDeclStmt] ... ...; +# 73| 0: [LocalVariableDeclAndInitExpr] Int32 x = ... +# 73| 0: [IntLiteral] 0 +# 73| 1: [LocalVariableAccess] access to local variable x +# 74| 12: [ExprStmt] ...; +# 74| 0: [DelegateCall] delegate call +# 74| -1: [LocalVariableAccess] access to local variable cd7 +# 74| 0: [AddExpr] ... + ... +# 74| 0: [IntLiteral] 34 +# 74| 1: [LocalVariableAccess] access to local variable x +# 76| 13: [LocalVariableDeclStmt] ... ...; +# 76| 0: [LocalVariableDeclAndInitExpr] Predicate pi = ... +# 76| 0: [ExplicitDelegateCreation] delegate creation of type Predicate +# 76| 0: [MethodAccess] access to method F +# 76| -1: [TypeAccess] access to type X +# 76| 1: [LocalVariableAccess] access to local variable pi +# 77| 14: [LocalVariableDeclStmt] ... ...; +# 77| 0: [LocalVariableDeclAndInitExpr] Predicate ps = ... +# 77| 0: [ImplicitDelegateCreation] delegate creation of type Predicate +# 77| 0: [MethodAccess] access to method G +# 77| -1: [TypeAccess] access to type X +# 77| 1: [LocalVariableAccess] access to local variable ps +# 79| 15: [LocalVariableDeclStmt] ... ...; +# 79| 0: [LocalVariableDeclAndInitExpr] Boolean b = ... +# 79| 0: [BitwiseAndExpr] ... & ... +# 79| 0: [DelegateCall] delegate call +# 79| -1: [LocalVariableAccess] access to local variable pi +# 79| 0: [IntLiteral] 3 +# 79| 1: [DelegateCall] delegate call +# 79| -1: [LocalVariableAccess] access to local variable ps +# 79| 0: [StringLiteral] "" +# 79| 1: [LocalVariableAccess] access to local variable b +# 81| 16: [LocalVariableDeclStmt] ... ...; +# 81| 0: [LocalVariableDeclExpr] ContextCallback d diff --git a/csharp/ql/test/library-tests/delegates/PrintAst.qlref b/csharp/ql/test/library-tests/delegates/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/delegates/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/dispatch/CallContext.expected b/csharp/ql/test/library-tests/dispatch/CallContext.expected new file mode 100644 index 000000000000..988fa363b9b9 --- /dev/null +++ b/csharp/ql/test/library-tests/dispatch/CallContext.expected @@ -0,0 +1,25 @@ +getADynamicTargetInCallContext +| TypeFlow.cs:33:9:33:18 | call to method Method | TypeFlow.cs:12:29:12:34 | Method | TypeFlow.cs:7:7:7:23 | call to method Run | +| TypeFlow.cs:33:9:33:18 | call to method Method | TypeFlow.cs:17:30:17:35 | Method | TypeFlow.cs:7:7:7:23 | call to method Run | +mayBenefitFromCallContext +| TypeFlow.cs:33:9:33:18 | call to method Method | +| ViableCallable.cs:12:9:12:28 | call to method M | +| ViableCallable.cs:14:9:14:15 | access to property Prop | +| ViableCallable.cs:14:19:14:25 | access to property Prop | +| ViableCallable.cs:16:9:16:23 | access to indexer | +| ViableCallable.cs:16:27:16:41 | access to indexer | +| ViableCallable.cs:18:9:18:16 | access to event Event | +| ViableCallable.cs:19:9:19:16 | access to event Event | +| ViableCallable.cs:22:9:22:30 | call to method M | +| ViableCallable.cs:24:9:24:15 | access to property Prop | +| ViableCallable.cs:24:19:24:25 | access to property Prop | +| ViableCallable.cs:26:9:26:23 | access to indexer | +| ViableCallable.cs:26:27:26:41 | access to indexer | +| ViableCallable.cs:28:9:28:16 | access to event Event | +| ViableCallable.cs:29:9:29:16 | access to event Event | +| ViableCallable.cs:235:9:235:15 | call to method M | +| ViableCallable.cs:284:9:284:15 | call to method M | +| ViableCallable.cs:287:9:287:20 | call to method M | +| ViableCallable.cs:412:9:412:18 | call to method M | +| ViableCallable.cs:456:9:456:30 | call to method M2 | +| ViableCallable.cs:462:9:462:30 | call to method M2 | diff --git a/csharp/ql/test/library-tests/dispatch/CallContext.ql b/csharp/ql/test/library-tests/dispatch/CallContext.ql new file mode 100644 index 000000000000..c21274b00950 --- /dev/null +++ b/csharp/ql/test/library-tests/dispatch/CallContext.ql @@ -0,0 +1,10 @@ +import csharp +import semmle.code.csharp.dispatch.Dispatch + +query predicate getADynamicTargetInCallContext( + DispatchCall call, Callable callable, DispatchCall ctx +) { + callable = call.getADynamicTargetInCallContext(ctx) +} + +query predicate mayBenefitFromCallContext(DispatchCall call) { call.mayBenefitFromCallContext() } diff --git a/csharp/ql/test/library-tests/dispatch/ViableCallable.cs b/csharp/ql/test/library-tests/dispatch/ViableCallable.cs index bcc68034b717..7fdd307edc80 100644 --- a/csharp/ql/test/library-tests/dispatch/ViableCallable.cs +++ b/csharp/ql/test/library-tests/dispatch/ViableCallable.cs @@ -438,7 +438,7 @@ void M1(int i) // Viable callables: C16.M1() this.M1(""); - // Viable callables: C16.M2() + // Viable callables: C17.M2() this.M2(() => i); } diff --git a/csharp/ql/test/library-tests/dynamic/PrintAst.expected b/csharp/ql/test/library-tests/dynamic/PrintAst.expected new file mode 100644 index 000000000000..adaec26beb3b --- /dev/null +++ b/csharp/ql/test/library-tests/dynamic/PrintAst.expected @@ -0,0 +1,252 @@ +dynamic.cs: +# 4| [Class] DynamicTest +# 6| 4: [InstanceConstructor] DynamicTest +#-----| 2: (Parameters) +# 6| 0: [Parameter] x +# 6| 4: [BlockStmt] {...} +# 8| 5: [Method] Main +#-----| 2: (Parameters) +# 8| 0: [Parameter] args +# 9| 4: [BlockStmt] {...} +# 10| 0: [LocalVariableDeclStmt] ... ...; +# 10| 0: [LocalVariableDeclAndInitExpr] DynamicTest dt = ... +# 10| 0: [ObjectCreation] object creation of type DynamicTest +# 10| 0: [IntLiteral] 0 +# 10| 1: [LocalVariableAccess] access to local variable dt +# 11| 1: [LocalVariableDeclStmt] ... ...; +# 11| 0: [LocalVariableDeclAndInitExpr] Int32[] array = ... +# 11| 0: [ArrayCreation] array creation of type Int32[] +# 11| -1: [ArrayInitializer] { ..., ... } +# 11| 0: [IntLiteral] 42 +# 11| 1: [LocalVariableAccess] access to local variable array +# 12| 2: [LocalVariableDeclStmt] ... ...; +# 12| 0: [LocalVariableDeclAndInitExpr] Action action = ... +# 12| 0: [LambdaExpr] (...) => ... +#-----| 2: (Parameters) +# 12| 0: [Parameter] x +# 12| 4: [BlockStmt] {...} +# 12| 1: [LocalVariableAccess] access to local variable action +# 13| 3: [LocalVariableDeclStmt] ... ...; +# 13| 0: [LocalVariableDeclAndInitExpr] dynamic d = ... +# 13| 0: [CastExpr] (...) ... +# 13| 0: [IntLiteral] 0 +# 13| 1: [LocalVariableAccess] access to local variable d +# 16| 4: [ExprStmt] ...; +# 16| 0: [DynamicObjectCreation] dynamic object creation of type DynamicTest +# 16| 0: [LocalVariableAccess] access to local variable d +# 17| 5: [ExprStmt] ...; +# 17| 0: [DynamicObjectCreation] dynamic object creation of type DynamicTest +# 17| -1: [ObjectInitializer] { ..., ... } +# 17| 0: [MemberInitializer] ... = ... +# 17| 0: [CastExpr] (...) ... +# 17| 0: [LocalVariableAccess] access to local variable d +# 17| 1: [FieldAccess] access to field Field +# 17| 0: [LocalVariableAccess] access to local variable d +# 18| 6: [ExprStmt] ...; +# 18| 0: [DynamicObjectCreation] dynamic object creation of type KeyValuePair +# 18| 0: [StringLiteral] "" +# 18| 1: [LocalVariableAccess] access to local variable d +# 19| 7: [ExprStmt] ...; +# 19| 0: [DynamicObjectCreation] dynamic object creation of type KeyValuePair +# 19| 0: [StringLiteral] "" +# 19| 1: [LocalVariableAccess] access to local variable d +# 22| 8: [ExprStmt] ...; +# 22| 0: [ObjectCreation] object creation of type DynamicTest +# 22| 0: [IntLiteral] 0 +# 23| 9: [ExprStmt] ...; +# 23| 0: [ObjectCreation] object creation of type DynamicTest +# 23| -1: [ObjectInitializer] { ..., ... } +# 23| 0: [MemberInitializer] ... = ... +# 23| 0: [CastExpr] (...) ... +# 23| 0: [LocalVariableAccess] access to local variable d +# 23| 1: [FieldAccess] access to field Field +# 23| 0: [IntLiteral] 0 +# 26| 10: [ExprStmt] ...; +# 26| 0: [DynamicMethodCall] dynamic call to method Bar +# 26| -1: [LocalVariableAccess] access to local variable d +# 26| 0: [StringLiteral] "" +# 27| 11: [ExprStmt] ...; +# 27| 0: [DynamicMethodCall] dynamic call to method Foo +# 27| 0: [LocalVariableAccess] access to local variable d +# 30| 12: [ExprStmt] ...; +# 30| 0: [MethodCall] call to method Bar +# 30| -1: [LocalVariableAccess] access to local variable dt +# 30| 0: [StringLiteral] "" +# 31| 13: [ExprStmt] ...; +# 31| 0: [MethodCall] call to method Foo +# 31| 0: [IntLiteral] 0 +# 34| 14: [ExprStmt] ...; +# 34| 0: [AssignExpr] ... = ... +# 34| 0: [CastExpr] (...) ... +# 34| 0: [IntLiteral] 0 +# 34| 1: [LocalVariableAccess] access to local variable d +# 35| 15: [ExprStmt] ...; +# 35| 0: [AssignExpr] ... = ... +# 35| 0: [DynamicOperatorCall] dynamic call to operator - +# 35| 0: [LocalVariableAccess] access to local variable d +# 35| 1: [LocalVariableAccess] access to local variable d +# 36| 16: [ExprStmt] ...; +# 36| 0: [AssignExpr] ... = ... +# 36| 0: [DynamicOperatorCall] dynamic call to operator + +# 36| 0: [LocalVariableAccess] access to local variable d +# 36| 1: [LocalVariableAccess] access to local variable d +# 36| 1: [LocalVariableAccess] access to local variable d +# 37| 17: [ExprStmt] ...; +# 37| 0: [AssignAddExpr] ... += ... +# 37| 0: [LocalVariableAccess] access to local variable d +# 37| 1: [LocalVariableAccess] access to local variable d +# 40| 18: [LocalVariableDeclStmt] ... ...; +# 40| 0: [LocalVariableDeclAndInitExpr] Int32 i = ... +# 40| 0: [IntLiteral] 0 +# 40| 1: [LocalVariableAccess] access to local variable i +# 41| 19: [ExprStmt] ...; +# 41| 0: [AssignExpr] ... = ... +# 41| 0: [UnaryMinusExpr] -... +# 41| 0: [LocalVariableAccess] access to local variable i +# 41| 1: [LocalVariableAccess] access to local variable i +# 42| 20: [ExprStmt] ...; +# 42| 0: [AssignExpr] ... = ... +# 42| 0: [AddExpr] ... + ... +# 42| 0: [LocalVariableAccess] access to local variable i +# 42| 1: [LocalVariableAccess] access to local variable i +# 42| 1: [LocalVariableAccess] access to local variable i +# 43| 21: [ExprStmt] ...; +# 43| 0: [AssignAddExpr] ... += ... +# 43| 0: [LocalVariableAccess] access to local variable i +# 43| 1: [LocalVariableAccess] access to local variable i +# 44| 22: [ExprStmt] ...; +# 44| 0: [PostIncrExpr] ...++ +# 44| 0: [LocalVariableAccess] access to local variable i +# 47| 23: [ExprStmt] ...; +# 47| 0: [DynamicOperatorCall] dynamic call to operator ++ +# 47| 0: [LocalVariableAccess] access to local variable d +# 50| 24: [ExprStmt] ...; +# 50| 0: [PostIncrExpr] ...++ +# 50| 0: [LocalVariableAccess] access to local variable i +# 53| 25: [ExprStmt] ...; +# 53| 0: [AssignExpr] ... = ... +# 53| 0: [IntLiteral] 0 +# 53| 1: [DynamicMemberAccess] dynamic access to member Field +# 53| -1: [LocalVariableAccess] access to local variable d +# 54| 26: [ExprStmt] ...; +# 54| 0: [AssignExpr] ... = ... +# 54| 0: [DynamicMemberAccess] dynamic access to member Prop +# 54| -1: [LocalVariableAccess] access to local variable d +# 54| 1: [DynamicMemberAccess] dynamic access to member Prop +# 54| -1: [LocalVariableAccess] access to local variable d +# 57| 27: [ExprStmt] ...; +# 57| 0: [AssignExpr] ... = ... +# 57| 0: [IntLiteral] 0 +# 57| 1: [FieldAccess] access to field Field +# 57| -1: [LocalVariableAccess] access to local variable dt +# 58| 28: [ExprStmt] ...; +# 58| 0: [AssignExpr] ... = ... +# 58| 0: [PropertyCall] access to property Prop +# 58| -1: [LocalVariableAccess] access to local variable dt +# 58| 1: [PropertyCall] access to property Prop +# 58| -1: [LocalVariableAccess] access to local variable dt +# 61| 29: [ExprStmt] ...; +# 61| 0: [AssignExpr] ... = ... +# 61| 0: [LocalVariableAccess] access to local variable array +# 61| 1: [LocalVariableAccess] access to local variable d +# 62| 30: [ExprStmt] ...; +# 62| 0: [AssignExpr] ... = ... +# 62| 0: [DynamicElementAccess] dynamic access to element +# 62| -1: [LocalVariableAccess] access to local variable d +# 62| 0: [IntLiteral] 0 +# 62| 1: [DynamicElementAccess] dynamic access to element +# 62| -1: [LocalVariableAccess] access to local variable d +# 62| 0: [IntLiteral] 0 +# 63| 31: [ExprStmt] ...; +# 63| 0: [AssignExpr] ... = ... +# 63| 0: [DynamicElementAccess] dynamic access to element +# 63| -1: [LocalVariableAccess] access to local variable d +# 63| 0: [IntLiteral] 0 +# 63| 1: [LocalVariableAccess] access to local variable d +# 66| 32: [ExprStmt] ...; +# 66| 0: [AssignExpr] ... = ... +# 66| 0: [CastExpr] (...) ... +# 66| 0: [IntLiteral] 0 +# 66| 1: [LocalVariableAccess] access to local variable d +# 67| 33: [ExprStmt] ...; +# 67| 0: [AssignExpr] ... = ... +# 67| 0: [CastExpr] (...) ... +# 67| 0: [IndexerCall] access to indexer +# 67| -1: [LocalVariableAccess] access to local variable dt +# 67| 0: [LocalVariableAccess] access to local variable d +# 67| 1: [IndexerCall] access to indexer +# 67| -1: [LocalVariableAccess] access to local variable dt +# 67| 0: [IntLiteral] 0 +# 68| 34: [ExprStmt] ...; +# 68| 0: [AssignExpr] ... = ... +# 68| 0: [CastExpr] (...) ... +# 68| 0: [IndexerCall] access to indexer +# 68| -1: [LocalVariableAccess] access to local variable dt +# 68| 0: [IntLiteral] 0 +# 68| 1: [LocalVariableAccess] access to local variable d +# 69| 35: [ExprStmt] ...; +# 69| 0: [AssignExpr] ... = ... +# 69| 0: [ArrayAccess] access to array element +# 69| -1: [LocalVariableAccess] access to local variable array +# 69| 0: [CastExpr] (...) ... +# 69| 0: [LocalVariableAccess] access to local variable d +# 69| 1: [ArrayAccess] access to array element +# 69| -1: [LocalVariableAccess] access to local variable array +# 69| 0: [IntLiteral] 0 +# 70| 36: [ExprStmt] ...; +# 70| 0: [AssignExpr] ... = ... +# 70| 0: [CastExpr] (...) ... +# 70| 0: [ArrayAccess] access to array element +# 70| -1: [LocalVariableAccess] access to local variable array +# 70| 0: [IntLiteral] 0 +# 70| 1: [LocalVariableAccess] access to local variable d +# 73| 37: [ExprStmt] ...; +# 73| 0: [DelegateCall] delegate call +# 73| -1: [LocalVariableAccess] access to local variable action +# 73| 0: [IntLiteral] 3 +# 74| 38: [ExprStmt] ...; +# 74| 0: [AssignExpr] ... = ... +# 74| 0: [LocalVariableAccess] access to local variable action +# 74| 1: [LocalVariableAccess] access to local variable d +# 75| 39: [ExprStmt] ...; +# 75| 0: [DelegateCall] delegate call +# 75| -1: [LocalVariableAccess] access to local variable d +# 75| 0: [IntLiteral] 42 +# 78| 6: [Method] Foo +#-----| 2: (Parameters) +# 78| 0: [Parameter] x +# 78| 4: [BlockStmt] {...} +# 79| 7: [Method] Foo +#-----| 2: (Parameters) +# 79| 0: [Parameter] x +# 79| 4: [BlockStmt] {...} +# 81| 8: [Method] Bar +#-----| 2: (Parameters) +# 81| 0: [Parameter] x +# 81| 4: [BlockStmt] {...} +# 83| 9: [IncrementOperator] ++ +#-----| 2: (Parameters) +# 83| 0: [Parameter] dt +# 84| 4: [BlockStmt] {...} +# 85| 0: [ReturnStmt] return ...; +# 85| 0: [ParameterAccess] access to parameter dt +# 88| 10: [Field] Field +# 90| 11: [Property] Prop +# 90| 3: [Getter] get_Prop +# 90| 4: [Setter] set_Prop +#-----| 2: (Parameters) +# 90| 0: [Parameter] value +# 92| 12: [Indexer] Item +#-----| 1: (Parameters) +# 92| 0: [Parameter] x +# 92| 3: [Getter] get_Item +#-----| 2: (Parameters) +# 92| 0: [Parameter] x +# 92| 4: [BlockStmt] {...} +# 92| 0: [ReturnStmt] return ...; +# 92| 0: [ParameterAccess] access to parameter x +# 92| 4: [Setter] set_Item +#-----| 2: (Parameters) +# 92| 0: [Parameter] x +# 92| 1: [Parameter] value +# 92| 4: [BlockStmt] {...} diff --git a/csharp/ql/test/library-tests/dynamic/PrintAst.qlref b/csharp/ql/test/library-tests/dynamic/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/dynamic/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/enums/Enums11.expected b/csharp/ql/test/library-tests/enums/Enums11.expected new file mode 100644 index 000000000000..715beb400ff5 --- /dev/null +++ b/csharp/ql/test/library-tests/enums/Enums11.expected @@ -0,0 +1,5 @@ +| enums.cs:28:18:28:18 | (...) ... | 1 | +| enums.cs:29:20:29:20 | (...) ... | 2 | +| enums.cs:30:20:30:20 | (...) ... | 4 | +| enums.cs:38:17:38:18 | 10 | 10 | +| enums.cs:40:23:40:32 | ... + ... | 11 | diff --git a/csharp/ql/test/library-tests/enums/Enums11.ql b/csharp/ql/test/library-tests/enums/Enums11.ql new file mode 100644 index 000000000000..36b2c005a213 --- /dev/null +++ b/csharp/ql/test/library-tests/enums/Enums11.ql @@ -0,0 +1,12 @@ +/** + * @name Test for enums + */ + +import csharp + +from Expr e +where + exists(Assignment a | a.getRValue() = e | + a.getParent().(Field).getDeclaringType() instanceof Enum + ) +select e, e.getValue() diff --git a/csharp/ql/test/library-tests/enums/PrintAst.expected b/csharp/ql/test/library-tests/enums/PrintAst.expected new file mode 100644 index 000000000000..446b4c018565 --- /dev/null +++ b/csharp/ql/test/library-tests/enums/PrintAst.expected @@ -0,0 +1,105 @@ +enums.cs: +# 5| [NamespaceDeclaration] namespace ... { ... } +# 7| 1: [Enum] Color +# 10| 5: [Field] Red +# 10| 6: [Field] Green +# 10| 7: [Field] Blue +# 14| 2: [Enum] LongColor +# 17| 5: [Field] Red +# 18| 6: [Field] Green +# 19| 7: [Field] Blue +# 23| 3: [Enum] E +# 25| 4: [Enum] ValueColor +# 28| 5: [Field] OneRed +# 28| 1: [AssignExpr] ... = ... +# 28| 0: [CastExpr] (...) ... +# 28| 0: [IntLiteral] 1 +# 28| 1: [MemberConstantAccess] access to constant OneRed +# 29| 6: [Field] TwoGreen +# 29| 1: [AssignExpr] ... = ... +# 29| 0: [CastExpr] (...) ... +# 29| 0: [IntLiteral] 2 +# 29| 1: [MemberConstantAccess] access to constant TwoGreen +# 30| 7: [Field] FourBlue +# 30| 1: [AssignExpr] ... = ... +# 30| 0: [CastExpr] (...) ... +# 30| 0: [IntLiteral] 4 +# 30| 1: [MemberConstantAccess] access to constant FourBlue +# 34| 5: [Enum] SparseColor +# 37| 5: [Field] Red +# 38| 6: [Field] Green +# 38| 1: [AssignExpr] ... = ... +# 38| 0: [IntLiteral] 10 +# 38| 1: [MemberConstantAccess] access to constant Green +# 39| 7: [Field] Blue +# 40| 8: [Field] AnotherBlue +# 40| 1: [AssignExpr] ... = ... +# 40| 0: [AddExpr] ... + ... +# 40| 0: [CastExpr] (...) ... +# 40| 0: [MemberConstantAccess] access to constant Blue +# 40| 1: [CastExpr] (...) ... +# 40| 0: [MemberConstantAccess] access to constant Red +# 40| 1: [MemberConstantAccess] access to constant AnotherBlue +# 44| 6: [Class] Test +# 47| 5: [Method] Main +# 48| 4: [BlockStmt] {...} +# 49| 0: [ExprStmt] ...; +# 49| 0: [MethodCall] call to method WriteLine +# 49| -1: [TypeAccess] access to type Console +# 49| 0: [MethodCall] call to method StringFromColor +# 49| 0: [MemberConstantAccess] access to constant Red +# 49| -1: [TypeAccess] access to type SparseColor +# 50| 1: [ExprStmt] ...; +# 50| 0: [MethodCall] call to method WriteLine +# 50| -1: [TypeAccess] access to type Console +# 50| 0: [MethodCall] call to method StringFromColor +# 50| 0: [MemberConstantAccess] access to constant Green +# 50| -1: [TypeAccess] access to type SparseColor +# 51| 2: [ExprStmt] ...; +# 51| 0: [MethodCall] call to method WriteLine +# 51| -1: [TypeAccess] access to type Console +# 51| 0: [MethodCall] call to method StringFromColor +# 51| 0: [MemberConstantAccess] access to constant Blue +# 51| -1: [TypeAccess] access to type SparseColor +# 54| 6: [Method] StringFromColor +#-----| 2: (Parameters) +# 54| 0: [Parameter] c +# 55| 4: [BlockStmt] {...} +# 56| 0: [SwitchStmt] switch (...) {...} +# 56| 0: [ParameterAccess] access to parameter c +# 58| 0: [ConstCase] case ...: +# 58| 0: [ConstantPatternExpr,MemberConstantAccess] access to constant Red +# 58| -1: [TypeAccess] access to type SparseColor +# 58| 1: [ReturnStmt] return ...; +# 58| 0: [MethodCall] call to method Format +# 58| -1: [TypeAccess] access to type String +# 58| 0: [StringLiteral] "Red = {0}" +# 58| 1: [CastExpr] (...) ... +# 58| 0: [CastExpr] (...) ... +# 58| 0: [ParameterAccess] access to parameter c +# 58| 1: [TypeAccess] access to type Int32 +# 59| 2: [ConstCase] case ...: +# 59| 0: [ConstantPatternExpr,MemberConstantAccess] access to constant Green +# 59| -1: [TypeAccess] access to type SparseColor +# 59| 3: [ReturnStmt] return ...; +# 59| 0: [MethodCall] call to method Format +# 59| -1: [TypeAccess] access to type String +# 59| 0: [StringLiteral] "Green = {0}" +# 59| 1: [CastExpr] (...) ... +# 59| 0: [CastExpr] (...) ... +# 59| 0: [ParameterAccess] access to parameter c +# 59| 1: [TypeAccess] access to type Int32 +# 60| 4: [ConstCase] case ...: +# 60| 0: [ConstantPatternExpr,MemberConstantAccess] access to constant Blue +# 60| -1: [TypeAccess] access to type SparseColor +# 60| 5: [ReturnStmt] return ...; +# 60| 0: [MethodCall] call to method Format +# 60| -1: [TypeAccess] access to type String +# 60| 0: [StringLiteral] "Blue = {0}" +# 60| 1: [CastExpr] (...) ... +# 60| 0: [CastExpr] (...) ... +# 60| 0: [ParameterAccess] access to parameter c +# 60| 1: [TypeAccess] access to type Int32 +# 61| 6: [DefaultCase] default: +# 61| 7: [ReturnStmt] return ...; +# 61| 0: [StringLiteral] "Invalid color" diff --git a/csharp/ql/test/library-tests/enums/PrintAst.qlref b/csharp/ql/test/library-tests/enums/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/enums/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/enums/enums.cs b/csharp/ql/test/library-tests/enums/enums.cs index df7df79c066d..784d4f64114e 100644 --- a/csharp/ql/test/library-tests/enums/enums.cs +++ b/csharp/ql/test/library-tests/enums/enums.cs @@ -37,7 +37,7 @@ enum SparseColor Red, Green = 10, Blue, - AnotherBlue = Blue + AnotherBlue = Blue + Red } diff --git a/csharp/ql/test/library-tests/events/PrintAst.expected b/csharp/ql/test/library-tests/events/PrintAst.expected new file mode 100644 index 000000000000..ca2c497bd7cd --- /dev/null +++ b/csharp/ql/test/library-tests/events/PrintAst.expected @@ -0,0 +1,149 @@ +events.cs: +# 5| [NamespaceDeclaration] namespace ... { ... } +# 7| 1: [DelegateType] EventHandler +#-----| 2: (Parameters) +# 7| 0: [Parameter] sender +# 7| 1: [Parameter] e +# 10| 2: [Class] Button +# 13| 5: [Event] Click +# 13| 3: [AddEventAccessor] add_Click +#-----| 2: (Parameters) +# 13| 0: [Parameter] value +# 13| 4: [RemoveEventAccessor] remove_Click +#-----| 2: (Parameters) +# 13| 0: [Parameter] value +# 15| 6: [Method] OnClick +#-----| 2: (Parameters) +# 15| 0: [Parameter] e +# 16| 4: [BlockStmt] {...} +# 17| 0: [IfStmt] if (...) ... +# 17| 0: [OperatorCall] call to operator != +# 17| 0: [EventAccess,EventCall] access to event Click +# 17| 1: [NullLiteral] null +# 18| 1: [ExprStmt] ...; +# 18| 0: [DelegateCall] delegate call +# 18| -1: [EventAccess,EventCall] access to event Click +# 18| 0: [ThisAccess] this access +# 18| 1: [ParameterAccess] access to parameter e +# 21| 7: [Method] Reset +# 22| 4: [BlockStmt] {...} +# 23| 0: [ExprStmt] ...; +# 23| 0: [AssignExpr] ... = ... +# 23| 0: [NullLiteral] null +# 23| 1: [EventAccess,EventCall] access to event Click +# 27| 3: [Class] LoginDialog +# 30| 4: [Field] OkButton +# 31| 5: [Field] CancelButton +# 33| 6: [InstanceConstructor] LoginDialog +# 34| 4: [BlockStmt] {...} +# 35| 0: [ExprStmt] ...; +# 35| 0: [AssignExpr] ... = ... +# 35| 0: [ObjectCreation] object creation of type Button +# 35| 1: [FieldAccess] access to field OkButton +# 36| 1: [ExprStmt] ...; +# 36| 0: [AddEventExpr] ... += ... +# 36| 0: [ExplicitDelegateCreation] delegate creation of type EventHandler +# 36| 0: [MethodAccess] access to method OkButtonClick +# 36| 1: [EventAccess,EventCall] access to event Click +# 36| -1: [FieldAccess] access to field OkButton +# 37| 2: [ExprStmt] ...; +# 37| 0: [AssignExpr] ... = ... +# 37| 0: [ObjectCreation] object creation of type Button +# 37| 1: [FieldAccess] access to field CancelButton +# 38| 3: [ExprStmt] ...; +# 38| 0: [RemoveEventExpr] ... -= ... +# 38| 0: [ExplicitDelegateCreation] delegate creation of type EventHandler +# 38| 0: [MethodAccess] access to method CancelButtonClick +# 38| 1: [EventAccess,EventCall] access to event Click +# 38| -1: [FieldAccess] access to field CancelButton +# 41| 7: [Method] OkButtonClick +#-----| 2: (Parameters) +# 41| 0: [Parameter] sender +# 41| 1: [Parameter] e +# 42| 4: [BlockStmt] {...} +# 45| 8: [Method] CancelButtonClick +#-----| 2: (Parameters) +# 45| 0: [Parameter] sender +# 45| 1: [Parameter] e +# 46| 4: [BlockStmt] {...} +# 51| 4: [Class] Control +# 54| 6: [Field] mouseDownEventKey +# 54| 1: [AssignExpr] ... = ... +# 54| 0: [ObjectCreation] object creation of type Object +# 54| 1: [FieldAccess] access to field mouseDownEventKey +# 55| 7: [Field] mouseUpEventKey +# 55| 1: [AssignExpr] ... = ... +# 55| 0: [ObjectCreation] object creation of type Object +# 55| 1: [FieldAccess] access to field mouseUpEventKey +# 58| 8: [Method] GetEventHandler +#-----| 2: (Parameters) +# 58| 0: [Parameter] key +# 58| 4: [BlockStmt] {...} +# 58| 0: [ReturnStmt] return ...; +# 58| 0: [NullLiteral] null +# 61| 9: [Method] AddEventHandler +#-----| 2: (Parameters) +# 61| 0: [Parameter] key +# 61| 1: [Parameter] handler +# 61| 4: [BlockStmt] {...} +# 64| 10: [Method] RemoveEventHandler +#-----| 2: (Parameters) +# 64| 0: [Parameter] key +# 64| 1: [Parameter] handler +# 64| 4: [BlockStmt] {...} +# 67| 11: [Event] MouseDown +# 69| 3: [AddEventAccessor] add_MouseDown +#-----| 2: (Parameters) +# 69| 0: [Parameter] value +# 69| 4: [BlockStmt] {...} +# 69| 0: [ExprStmt] ...; +# 69| 0: [MethodCall] call to method AddEventHandler +# 69| 0: [FieldAccess] access to field mouseDownEventKey +# 69| 1: [ParameterAccess] access to parameter value +# 70| 4: [RemoveEventAccessor] remove_MouseDown +#-----| 2: (Parameters) +# 70| 0: [Parameter] value +# 70| 4: [BlockStmt] {...} +# 70| 0: [ExprStmt] ...; +# 70| 0: [MethodCall] call to method RemoveEventHandler +# 70| 0: [FieldAccess] access to field mouseDownEventKey +# 70| 1: [ParameterAccess] access to parameter value +# 74| 12: [Event] MouseUp +# 76| 3: [AddEventAccessor] add_MouseUp +#-----| 2: (Parameters) +# 76| 0: [Parameter] value +# 76| 4: [BlockStmt] {...} +# 76| 0: [ExprStmt] ...; +# 76| 0: [MethodCall] call to method AddEventHandler +# 76| 0: [FieldAccess] access to field mouseUpEventKey +# 76| 1: [ParameterAccess] access to parameter value +# 77| 4: [RemoveEventAccessor] remove_MouseUp +#-----| 2: (Parameters) +# 77| 0: [Parameter] value +# 77| 4: [BlockStmt] {...} +# 77| 0: [ExprStmt] ...; +# 77| 0: [MethodCall] call to method RemoveEventHandler +# 77| 0: [FieldAccess] access to field mouseUpEventKey +# 77| 1: [ParameterAccess] access to parameter value +# 81| 13: [Method] OnMouseUp +#-----| 2: (Parameters) +# 81| 0: [Parameter] args +# 82| 4: [BlockStmt] {...} +# 83| 0: [LocalVariableDeclStmt] ... ...; +# 83| 0: [LocalVariableDeclExpr] EventHandler handler +# 84| 1: [ExprStmt] ...; +# 84| 0: [AssignExpr] ... = ... +# 84| 0: [CastExpr] (...) ... +# 84| 0: [MethodCall] call to method GetEventHandler +# 84| 0: [FieldAccess] access to field mouseUpEventKey +# 84| 1: [TypeAccess] access to type EventHandler +# 84| 1: [LocalVariableAccess] access to local variable handler +# 85| 2: [IfStmt] if (...) ... +# 85| 0: [OperatorCall] call to operator != +# 85| 0: [LocalVariableAccess] access to local variable handler +# 85| 1: [NullLiteral] null +# 86| 1: [ExprStmt] ...; +# 86| 0: [DelegateCall] delegate call +# 86| -1: [LocalVariableAccess] access to local variable handler +# 86| 0: [ThisAccess] this access +# 86| 1: [ParameterAccess] access to parameter args diff --git a/csharp/ql/test/library-tests/events/PrintAst.qlref b/csharp/ql/test/library-tests/events/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/events/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/exceptions/PrintAst.expected b/csharp/ql/test/library-tests/exceptions/PrintAst.expected new file mode 100644 index 000000000000..abcca7b9d3a1 --- /dev/null +++ b/csharp/ql/test/library-tests/exceptions/PrintAst.expected @@ -0,0 +1,503 @@ +exceptions.cs: +# 3| [Class] Class1 +# 5| 5: [Method] G +# 6| 4: [BlockStmt] {...} +# 9| 6: [Field] p +# 11| 7: [Method] TestNoThrow +# 12| 4: [BlockStmt] {...} +# 13| 0: [TryStmt] try {...} ... +# 38| -1: [BlockStmt] {...} +# 39| 0: [EmptyStmt] ; +# 14| 0: [BlockStmt] {...} +# 15| 0: [EmptyStmt] ; +# 17| 1: [SpecificCatchClause] catch (...) {...} +# 17| 0: [LocalVariableDeclExpr] NullReferenceException ex +# 18| 1: [BlockStmt] {...} +# 19| 0: [EmptyStmt] ; +# 21| 2: [SpecificCatchClause] catch (...) {...} +# 21| 0: [LocalVariableDeclExpr] OverflowException ex +# 22| 1: [BlockStmt] {...} +# 23| 0: [EmptyStmt] ; +# 25| 3: [SpecificCatchClause] catch (...) {...} +# 25| 0: [LocalVariableDeclExpr] OutOfMemoryException ex +# 26| 1: [BlockStmt] {...} +# 27| 0: [EmptyStmt] ; +# 29| 4: [SpecificCatchClause] catch (...) {...} +# 29| 0: [LocalVariableDeclExpr] DivideByZeroException ex +# 30| 1: [BlockStmt] {...} +# 31| 0: [EmptyStmt] ; +# 33| 5: [SpecificCatchClause] catch (...) {...} +# 33| 0: [LocalVariableDeclExpr] Exception ex +# 34| 1: [BlockStmt] {...} +# 35| 0: [EmptyStmt] ; +# 43| 8: [Method] TestCall +# 44| 4: [BlockStmt] {...} +# 45| 0: [TryStmt] try {...} ... +# 46| 0: [BlockStmt] {...} +# 47| 0: [EmptyStmt] ; +# 48| 1: [ExprStmt] ...; +# 48| 0: [MethodCall] call to method G +# 50| 1: [SpecificCatchClause] catch (...) {...} +# 50| 0: [LocalVariableDeclExpr] NullReferenceException ex +# 51| 1: [BlockStmt] {...} +# 52| 0: [EmptyStmt] ; +# 54| 2: [SpecificCatchClause] catch (...) {...} +# 54| 0: [LocalVariableDeclExpr] OverflowException ex +# 55| 1: [BlockStmt] {...} +# 56| 0: [EmptyStmt] ; +# 58| 3: [SpecificCatchClause] catch (...) {...} +# 58| 0: [LocalVariableDeclExpr] OutOfMemoryException ex +# 59| 1: [BlockStmt] {...} +# 60| 0: [EmptyStmt] ; +# 62| 4: [SpecificCatchClause] catch (...) {...} +# 62| 0: [LocalVariableDeclExpr] DivideByZeroException ex +# 63| 1: [BlockStmt] {...} +# 64| 0: [EmptyStmt] ; +# 66| 5: [GeneralCatchClause] catch {...} +# 67| 1: [BlockStmt] {...} +# 68| 0: [EmptyStmt] ; +# 72| 9: [Method] TestCreation +# 73| 4: [BlockStmt] {...} +# 74| 0: [TryStmt] try {...} ... +# 75| 0: [BlockStmt] {...} +# 76| 0: [EmptyStmt] ; +# 77| 1: [LocalVariableDeclStmt] ... ...; +# 77| 0: [LocalVariableDeclAndInitExpr] Class1 v = ... +# 77| 0: [ObjectCreation] object creation of type Class1 +# 77| 1: [LocalVariableAccess] access to local variable v +# 79| 1: [SpecificCatchClause] catch (...) {...} +# 79| 0: [LocalVariableDeclExpr] NullReferenceException ex +# 80| 1: [BlockStmt] {...} +# 81| 0: [EmptyStmt] ; +# 83| 2: [SpecificCatchClause] catch (...) {...} +# 83| 0: [LocalVariableDeclExpr] OverflowException ex +# 84| 1: [BlockStmt] {...} +# 85| 0: [EmptyStmt] ; +# 87| 3: [SpecificCatchClause] catch (...) {...} +# 87| 0: [LocalVariableDeclExpr] OutOfMemoryException ex +# 88| 1: [BlockStmt] {...} +# 89| 0: [EmptyStmt] ; +# 91| 4: [SpecificCatchClause] catch (...) {...} +# 91| 0: [LocalVariableDeclExpr] DivideByZeroException ex +# 92| 1: [BlockStmt] {...} +# 93| 0: [EmptyStmt] ; +# 95| 5: [SpecificCatchClause] catch (...) {...} +# 95| 0: [LocalVariableDeclExpr] Exception ex +# 96| 1: [BlockStmt] {...} +# 97| 0: [EmptyStmt] ; +# 101| 10: [Method] TestIntAdd +# 102| 4: [BlockStmt] {...} +# 103| 0: [TryStmt] try {...} ... +# 104| 0: [BlockStmt] {...} +# 105| 0: [EmptyStmt] ; +# 106| 1: [LocalVariableDeclStmt] ... ...; +# 106| 0: [LocalVariableDeclAndInitExpr] Int32 v = ... +# 106| 0: [AddExpr] ... + ... +# 106| 0: [IntLiteral] 1 +# 106| 1: [IntLiteral] 2 +# 106| 1: [LocalVariableAccess] access to local variable v +# 108| 1: [SpecificCatchClause] catch (...) {...} +# 108| 0: [LocalVariableDeclExpr] NullReferenceException ex +# 109| 1: [BlockStmt] {...} +# 110| 0: [EmptyStmt] ; +# 112| 2: [SpecificCatchClause] catch (...) {...} +# 112| 0: [LocalVariableDeclExpr] OverflowException ex +# 113| 1: [BlockStmt] {...} +# 114| 0: [EmptyStmt] ; +# 116| 3: [SpecificCatchClause] catch (...) {...} +# 116| 0: [LocalVariableDeclExpr] OutOfMemoryException ex +# 117| 1: [BlockStmt] {...} +# 118| 0: [EmptyStmt] ; +# 120| 4: [SpecificCatchClause] catch (...) {...} +# 120| 0: [LocalVariableDeclExpr] DivideByZeroException ex +# 121| 1: [BlockStmt] {...} +# 122| 0: [EmptyStmt] ; +# 124| 5: [SpecificCatchClause] catch (...) {...} +# 124| 0: [LocalVariableDeclExpr] Exception ex +# 125| 1: [BlockStmt] {...} +# 126| 0: [EmptyStmt] ; +# 130| 11: [Method] TestIntSub +# 131| 4: [BlockStmt] {...} +# 132| 0: [TryStmt] try {...} ... +# 133| 0: [BlockStmt] {...} +# 134| 0: [EmptyStmt] ; +# 135| 1: [LocalVariableDeclStmt] ... ...; +# 135| 0: [LocalVariableDeclAndInitExpr] Int32 v = ... +# 135| 0: [SubExpr] ... - ... +# 135| 0: [IntLiteral] 1 +# 135| 1: [IntLiteral] 2 +# 135| 1: [LocalVariableAccess] access to local variable v +# 137| 1: [SpecificCatchClause] catch (...) {...} +# 137| 0: [LocalVariableDeclExpr] NullReferenceException ex +# 138| 1: [BlockStmt] {...} +# 139| 0: [EmptyStmt] ; +# 141| 2: [SpecificCatchClause] catch (...) {...} +# 141| 0: [LocalVariableDeclExpr] OverflowException ex +# 142| 1: [BlockStmt] {...} +# 143| 0: [EmptyStmt] ; +# 145| 3: [SpecificCatchClause] catch (...) {...} +# 145| 0: [LocalVariableDeclExpr] OutOfMemoryException ex +# 146| 1: [BlockStmt] {...} +# 147| 0: [EmptyStmt] ; +# 149| 4: [SpecificCatchClause] catch (...) {...} +# 149| 0: [LocalVariableDeclExpr] DivideByZeroException ex +# 150| 1: [BlockStmt] {...} +# 151| 0: [EmptyStmt] ; +# 153| 5: [SpecificCatchClause] catch (...) {...} +# 153| 0: [LocalVariableDeclExpr] Exception ex +# 154| 1: [BlockStmt] {...} +# 155| 0: [EmptyStmt] ; +# 159| 12: [Method] TestIntMul +# 160| 4: [BlockStmt] {...} +# 161| 0: [TryStmt] try {...} ... +# 162| 0: [BlockStmt] {...} +# 163| 0: [EmptyStmt] ; +# 164| 1: [LocalVariableDeclStmt] ... ...; +# 164| 0: [LocalVariableDeclAndInitExpr] Int32 v = ... +# 164| 0: [MulExpr] ... * ... +# 164| 0: [IntLiteral] 1 +# 164| 1: [IntLiteral] 2 +# 164| 1: [LocalVariableAccess] access to local variable v +# 166| 1: [SpecificCatchClause] catch (...) {...} +# 166| 0: [LocalVariableDeclExpr] NullReferenceException ex +# 167| 1: [BlockStmt] {...} +# 168| 0: [EmptyStmt] ; +# 170| 2: [SpecificCatchClause] catch (...) {...} +# 170| 0: [LocalVariableDeclExpr] OverflowException ex +# 171| 1: [BlockStmt] {...} +# 172| 0: [EmptyStmt] ; +# 174| 3: [SpecificCatchClause] catch (...) {...} +# 174| 0: [LocalVariableDeclExpr] OutOfMemoryException ex +# 175| 1: [BlockStmt] {...} +# 176| 0: [EmptyStmt] ; +# 178| 4: [SpecificCatchClause] catch (...) {...} +# 178| 0: [LocalVariableDeclExpr] DivideByZeroException ex +# 179| 1: [BlockStmt] {...} +# 180| 0: [EmptyStmt] ; +# 182| 5: [SpecificCatchClause] catch (...) {...} +# 182| 0: [LocalVariableDeclExpr] Exception ex +# 183| 1: [BlockStmt] {...} +# 184| 0: [EmptyStmt] ; +# 188| 13: [Method] TestStringLiteral +# 189| 4: [BlockStmt] {...} +# 190| 0: [TryStmt] try {...} ... +# 191| 0: [BlockStmt] {...} +# 192| 0: [EmptyStmt] ; +# 193| 1: [LocalVariableDeclStmt] ... ...; +# 193| 0: [LocalVariableDeclAndInitExpr] String v = ... +# 193| 0: [StringLiteral] "" +# 193| 1: [LocalVariableAccess] access to local variable v +# 195| 1: [SpecificCatchClause] catch (...) {...} +# 195| 0: [LocalVariableDeclExpr] NullReferenceException ex +# 196| 1: [BlockStmt] {...} +# 197| 0: [EmptyStmt] ; +# 199| 2: [SpecificCatchClause] catch (...) {...} +# 199| 0: [LocalVariableDeclExpr] OverflowException ex +# 200| 1: [BlockStmt] {...} +# 201| 0: [EmptyStmt] ; +# 203| 3: [SpecificCatchClause] catch (...) {...} +# 203| 0: [LocalVariableDeclExpr] OutOfMemoryException ex +# 204| 1: [BlockStmt] {...} +# 205| 0: [EmptyStmt] ; +# 207| 4: [SpecificCatchClause] catch (...) {...} +# 207| 0: [LocalVariableDeclExpr] DivideByZeroException ex +# 208| 1: [BlockStmt] {...} +# 209| 0: [EmptyStmt] ; +# 211| 5: [SpecificCatchClause] catch (...) {...} +# 211| 0: [LocalVariableDeclExpr] Exception ex +# 212| 1: [BlockStmt] {...} +# 213| 0: [EmptyStmt] ; +# 217| 14: [Method] TestStringAdd +# 218| 4: [BlockStmt] {...} +# 219| 0: [TryStmt] try {...} ... +# 220| 0: [BlockStmt] {...} +# 221| 0: [LocalVariableDeclStmt] ... ...; +# 221| 0: [LocalVariableDeclAndInitExpr] String s = ... +# 221| 0: [StringLiteral] "" +# 221| 1: [LocalVariableAccess] access to local variable s +# 222| 1: [EmptyStmt] ; +# 223| 2: [LocalVariableDeclStmt] ... ...; +# 223| 0: [LocalVariableDeclAndInitExpr] String v = ... +# 223| 0: [AddExpr] ... + ... +# 223| 0: [LocalVariableAccess] access to local variable s +# 223| 1: [LocalVariableAccess] access to local variable s +# 223| 1: [LocalVariableAccess] access to local variable v +# 225| 1: [SpecificCatchClause] catch (...) {...} +# 225| 0: [LocalVariableDeclExpr] NullReferenceException ex +# 226| 1: [BlockStmt] {...} +# 227| 0: [EmptyStmt] ; +# 229| 2: [SpecificCatchClause] catch (...) {...} +# 229| 0: [LocalVariableDeclExpr] OverflowException ex +# 230| 1: [BlockStmt] {...} +# 231| 0: [EmptyStmt] ; +# 233| 3: [SpecificCatchClause] catch (...) {...} +# 233| 0: [LocalVariableDeclExpr] OutOfMemoryException ex +# 234| 1: [BlockStmt] {...} +# 235| 0: [EmptyStmt] ; +# 237| 4: [SpecificCatchClause] catch (...) {...} +# 237| 0: [LocalVariableDeclExpr] DivideByZeroException ex +# 238| 1: [BlockStmt] {...} +# 239| 0: [EmptyStmt] ; +# 241| 5: [SpecificCatchClause] catch (...) {...} +# 241| 0: [LocalVariableDeclExpr] Exception ex +# 242| 1: [BlockStmt] {...} +# 243| 0: [EmptyStmt] ; +# 247| 15: [Method] TestDivide +# 248| 4: [BlockStmt] {...} +# 249| 0: [TryStmt] try {...} ... +# 250| 0: [BlockStmt] {...} +# 251| 0: [EmptyStmt] ; +# 252| 1: [LocalVariableDeclStmt] ... ...; +# 252| 0: [LocalVariableDeclAndInitExpr] Int32 v = ... +# 252| 0: [DivExpr] ... / ... +# 252| 0: [IntLiteral] 1 +# 252| 1: [IntLiteral] 2 +# 252| 1: [LocalVariableAccess] access to local variable v +# 254| 1: [SpecificCatchClause] catch (...) {...} +# 254| 0: [LocalVariableDeclExpr] NullReferenceException ex +# 255| 1: [BlockStmt] {...} +# 256| 0: [EmptyStmt] ; +# 258| 2: [SpecificCatchClause] catch (...) {...} +# 258| 0: [LocalVariableDeclExpr] OverflowException ex +# 259| 1: [BlockStmt] {...} +# 260| 0: [EmptyStmt] ; +# 262| 3: [SpecificCatchClause] catch (...) {...} +# 262| 0: [LocalVariableDeclExpr] OutOfMemoryException ex +# 263| 1: [BlockStmt] {...} +# 264| 0: [EmptyStmt] ; +# 266| 4: [SpecificCatchClause] catch (...) {...} +# 266| 0: [LocalVariableDeclExpr] DivideByZeroException ex +# 267| 1: [BlockStmt] {...} +# 268| 0: [EmptyStmt] ; +# 270| 5: [SpecificCatchClause] catch (...) {...} +# 270| 0: [LocalVariableDeclExpr] Exception ex +# 271| 1: [BlockStmt] {...} +# 272| 0: [EmptyStmt] ; +# 276| 16: [Method] TestRemainder +# 277| 4: [BlockStmt] {...} +# 278| 0: [TryStmt] try {...} ... +# 279| 0: [BlockStmt] {...} +# 280| 0: [EmptyStmt] ; +# 281| 1: [LocalVariableDeclStmt] ... ...; +# 281| 0: [LocalVariableDeclAndInitExpr] Int32 v = ... +# 281| 0: [RemExpr] ... % ... +# 281| 0: [IntLiteral] 1 +# 281| 1: [IntLiteral] 2 +# 281| 1: [LocalVariableAccess] access to local variable v +# 283| 1: [SpecificCatchClause] catch (...) {...} +# 283| 0: [LocalVariableDeclExpr] NullReferenceException ex +# 284| 1: [BlockStmt] {...} +# 285| 0: [EmptyStmt] ; +# 287| 2: [SpecificCatchClause] catch (...) {...} +# 287| 0: [LocalVariableDeclExpr] OverflowException ex +# 288| 1: [BlockStmt] {...} +# 289| 0: [EmptyStmt] ; +# 291| 3: [SpecificCatchClause] catch (...) {...} +# 291| 0: [LocalVariableDeclExpr] OutOfMemoryException ex +# 292| 1: [BlockStmt] {...} +# 293| 0: [EmptyStmt] ; +# 295| 4: [SpecificCatchClause] catch (...) {...} +# 295| 0: [LocalVariableDeclExpr] DivideByZeroException ex +# 296| 1: [BlockStmt] {...} +# 297| 0: [EmptyStmt] ; +# 299| 5: [SpecificCatchClause] catch (...) {...} +# 299| 0: [LocalVariableDeclExpr] Exception ex +# 300| 1: [BlockStmt] {...} +# 301| 0: [EmptyStmt] ; +# 305| 17: [Method] TestMemberAccess +# 306| 4: [BlockStmt] {...} +# 307| 0: [TryStmt] try {...} ... +# 308| 0: [BlockStmt] {...} +# 309| 0: [EmptyStmt] ; +# 310| 1: [LocalVariableDeclStmt] ... ...; +# 310| 0: [LocalVariableDeclAndInitExpr] Int32 v = ... +# 310| 0: [FieldAccess] access to field p +# 310| -1: [ThisAccess] this access +# 310| 1: [LocalVariableAccess] access to local variable v +# 312| 1: [SpecificCatchClause] catch (...) {...} +# 312| 0: [LocalVariableDeclExpr] NullReferenceException ex +# 313| 1: [BlockStmt] {...} +# 314| 0: [EmptyStmt] ; +# 316| 2: [SpecificCatchClause] catch (...) {...} +# 316| 0: [LocalVariableDeclExpr] OverflowException ex +# 317| 1: [BlockStmt] {...} +# 318| 0: [EmptyStmt] ; +# 320| 3: [SpecificCatchClause] catch (...) {...} +# 320| 0: [LocalVariableDeclExpr] OutOfMemoryException ex +# 321| 1: [BlockStmt] {...} +# 322| 0: [EmptyStmt] ; +# 324| 4: [SpecificCatchClause] catch (...) {...} +# 324| 0: [LocalVariableDeclExpr] DivideByZeroException ex +# 325| 1: [BlockStmt] {...} +# 326| 0: [EmptyStmt] ; +# 328| 5: [SpecificCatchClause] catch (...) {...} +# 328| 0: [LocalVariableDeclExpr] Exception ex +# 329| 1: [BlockStmt] {...} +# 330| 0: [EmptyStmt] ; +# 334| 18: [Method] TestCast +# 335| 4: [BlockStmt] {...} +# 336| 0: [TryStmt] try {...} ... +# 337| 0: [BlockStmt] {...} +# 338| 0: [EmptyStmt] ; +# 339| 1: [LocalVariableDeclStmt] ... ...; +# 339| 0: [LocalVariableDeclAndInitExpr] Int16 v = ... +# 339| 0: [CastExpr] (...) ... +# 339| 0: [IntLiteral] 1 +# 339| 1: [TypeAccess] access to type Int16 +# 339| 1: [LocalVariableAccess] access to local variable v +# 341| 1: [SpecificCatchClause] catch (...) {...} +# 341| 0: [LocalVariableDeclExpr] NullReferenceException ex +# 342| 1: [BlockStmt] {...} +# 343| 0: [EmptyStmt] ; +# 345| 2: [SpecificCatchClause] catch (...) {...} +# 345| 0: [LocalVariableDeclExpr] OverflowException ex +# 346| 1: [BlockStmt] {...} +# 347| 0: [EmptyStmt] ; +# 349| 3: [SpecificCatchClause] catch (...) {...} +# 349| 0: [LocalVariableDeclExpr] OutOfMemoryException ex +# 350| 1: [BlockStmt] {...} +# 351| 0: [EmptyStmt] ; +# 353| 4: [SpecificCatchClause] catch (...) {...} +# 353| 0: [LocalVariableDeclExpr] DivideByZeroException ex +# 354| 1: [BlockStmt] {...} +# 355| 0: [EmptyStmt] ; +# 357| 5: [SpecificCatchClause] catch (...) {...} +# 357| 0: [LocalVariableDeclExpr] Exception ex +# 358| 1: [BlockStmt] {...} +# 359| 0: [EmptyStmt] ; +# 363| 19: [Method] TestThrow +# 364| 4: [BlockStmt] {...} +# 365| 0: [TryStmt] try {...} ... +# 366| 0: [BlockStmt] {...} +# 367| 0: [LocalVariableDeclStmt] ... ...; +# 367| 0: [LocalVariableDeclAndInitExpr] DivideByZeroException e = ... +# 367| 0: [ObjectCreation] object creation of type DivideByZeroException +# 367| 1: [LocalVariableAccess] access to local variable e +# 368| 1: [EmptyStmt] ; +# 369| 2: [ThrowStmt] throw ...; +# 369| 0: [LocalVariableAccess] access to local variable e +# 371| 1: [SpecificCatchClause] catch (...) {...} +# 371| 0: [LocalVariableDeclExpr] NullReferenceException ex +# 372| 1: [BlockStmt] {...} +# 373| 0: [EmptyStmt] ; +# 375| 2: [SpecificCatchClause] catch (...) {...} +# 375| 0: [LocalVariableDeclExpr] OverflowException ex +# 376| 1: [BlockStmt] {...} +# 377| 0: [EmptyStmt] ; +# 379| 3: [SpecificCatchClause] catch (...) {...} +# 379| 0: [LocalVariableDeclExpr] OutOfMemoryException ex +# 380| 1: [BlockStmt] {...} +# 381| 0: [EmptyStmt] ; +# 383| 4: [SpecificCatchClause] catch (...) {...} +# 383| 0: [LocalVariableDeclExpr] DivideByZeroException ex +# 384| 1: [BlockStmt] {...} +# 385| 0: [EmptyStmt] ; +# 387| 5: [SpecificCatchClause] catch (...) {...} +# 387| 0: [LocalVariableDeclExpr] Exception ex +# 388| 1: [BlockStmt] {...} +# 389| 0: [EmptyStmt] ; +# 393| 20: [Method] TestUnaryOperation +# 394| 4: [BlockStmt] {...} +# 395| 0: [TryStmt] try {...} ... +# 396| 0: [BlockStmt] {...} +# 397| 0: [LocalVariableDeclStmt] ... ...; +# 397| 0: [LocalVariableDeclAndInitExpr] Int32 a = ... +# 397| 0: [IntLiteral] 1 +# 397| 1: [LocalVariableAccess] access to local variable a +# 398| 1: [EmptyStmt] ; +# 399| 2: [ExprStmt] ...; +# 399| 0: [PreIncrExpr] ++... +# 399| 0: [LocalVariableAccess] access to local variable a +# 401| 1: [SpecificCatchClause] catch (...) {...} +# 401| 0: [LocalVariableDeclExpr] NullReferenceException ex +# 402| 1: [BlockStmt] {...} +# 403| 0: [EmptyStmt] ; +# 405| 2: [SpecificCatchClause] catch (...) {...} +# 405| 0: [LocalVariableDeclExpr] OverflowException ex +# 406| 1: [BlockStmt] {...} +# 407| 0: [EmptyStmt] ; +# 409| 3: [SpecificCatchClause] catch (...) {...} +# 409| 0: [LocalVariableDeclExpr] OutOfMemoryException ex +# 410| 1: [BlockStmt] {...} +# 411| 0: [EmptyStmt] ; +# 413| 4: [SpecificCatchClause] catch (...) {...} +# 413| 0: [LocalVariableDeclExpr] DivideByZeroException ex +# 414| 1: [BlockStmt] {...} +# 415| 0: [EmptyStmt] ; +# 417| 5: [SpecificCatchClause] catch (...) {...} +# 417| 0: [LocalVariableDeclExpr] Exception ex +# 418| 1: [BlockStmt] {...} +# 419| 0: [EmptyStmt] ; +# 423| 21: [Method] TestRethrow +# 424| 4: [BlockStmt] {...} +# 425| 0: [TryStmt] try {...} ... +# 426| 0: [BlockStmt] {...} +# 427| 0: [TryStmt] try {...} ... +# 428| 0: [BlockStmt] {...} +# 430| 1: [GeneralCatchClause] catch {...} +# 431| 1: [BlockStmt] {...} +# 432| 0: [EmptyStmt] ; +# 433| 1: [ThrowStmt] throw ...; +# 436| 1: [SpecificCatchClause] catch (...) {...} +# 436| 0: [LocalVariableDeclExpr] OutOfMemoryException ex +# 437| 1: [BlockStmt] {...} +# 438| 0: [EmptyStmt] ; +# 440| 2: [GeneralCatchClause] catch {...} +# 441| 1: [BlockStmt] {...} +# 442| 0: [EmptyStmt] ; +# 446| 22: [Method] TestSubtypeCast +# 447| 4: [BlockStmt] {...} +# 448| 0: [TryStmt] try {...} ... +# 449| 0: [BlockStmt] {...} +# 450| 0: [LocalVariableDeclStmt] ... ...; +# 450| 0: [LocalVariableDeclAndInitExpr] Object o = ... +# 450| 0: [NullLiteral] null +# 450| 1: [LocalVariableAccess] access to local variable o +# 451| 1: [EmptyStmt] ; +# 452| 2: [LocalVariableDeclStmt] ... ...; +# 452| 0: [LocalVariableDeclAndInitExpr] Class1 p = ... +# 452| 0: [CastExpr] (...) ... +# 452| 0: [LocalVariableAccess] access to local variable o +# 452| 1: [TypeAccess] access to type Class1 +# 452| 1: [LocalVariableAccess] access to local variable p +# 454| 1: [SpecificCatchClause] catch (...) {...} +# 454| 0: [LocalVariableDeclExpr] InvalidCastException ex +# 455| 1: [BlockStmt] {...} +# 456| 0: [EmptyStmt] ; +# 458| 2: [SpecificCatchClause] catch (...) {...} +# 458| 0: [LocalVariableDeclExpr] Exception ex +# 459| 1: [BlockStmt] {...} +# 460| 0: [EmptyStmt] ; +# 464| 23: [Method] TestDivideMaybeZero +#-----| 2: (Parameters) +# 464| 0: [Parameter] i +# 465| 4: [BlockStmt] {...} +# 466| 0: [TryStmt] try {...} ... +# 467| 0: [BlockStmt] {...} +# 468| 0: [EmptyStmt] ; +# 469| 1: [LocalVariableDeclStmt] ... ...; +# 469| 0: [LocalVariableDeclAndInitExpr] Int32 v = ... +# 469| 0: [DivExpr] ... / ... +# 469| 0: [IntLiteral] 1 +# 469| 1: [ParameterAccess] access to parameter i +# 469| 1: [LocalVariableAccess] access to local variable v +# 471| 1: [SpecificCatchClause] catch (...) {...} +# 471| 0: [LocalVariableDeclExpr] NullReferenceException ex +# 472| 1: [BlockStmt] {...} +# 473| 0: [EmptyStmt] ; +# 475| 2: [SpecificCatchClause] catch (...) {...} +# 475| 0: [LocalVariableDeclExpr] OverflowException ex +# 476| 1: [BlockStmt] {...} +# 477| 0: [EmptyStmt] ; +# 479| 3: [SpecificCatchClause] catch (...) {...} +# 479| 0: [LocalVariableDeclExpr] OutOfMemoryException ex +# 480| 1: [BlockStmt] {...} +# 481| 0: [EmptyStmt] ; +# 483| 4: [SpecificCatchClause] catch (...) {...} +# 483| 0: [LocalVariableDeclExpr] DivideByZeroException ex +# 484| 1: [BlockStmt] {...} +# 485| 0: [EmptyStmt] ; +# 487| 5: [SpecificCatchClause] catch (...) {...} +# 487| 0: [LocalVariableDeclExpr] Exception ex +# 488| 1: [BlockStmt] {...} +# 489| 0: [EmptyStmt] ; diff --git a/csharp/ql/test/library-tests/exceptions/PrintAst.qlref b/csharp/ql/test/library-tests/exceptions/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/exceptions/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/expressions/AnonymousMethod1.expected b/csharp/ql/test/library-tests/expressions/AnonymousMethod1.expected index 99cbc7b72803..a443b2e5f587 100644 --- a/csharp/ql/test/library-tests/expressions/AnonymousMethod1.expected +++ b/csharp/ql/test/library-tests/expressions/AnonymousMethod1.expected @@ -1 +1 @@ -| expressions.cs:443:33:443:66 | delegate(...) { ... } | +| expressions.cs:455:33:455:66 | delegate(...) { ... } | diff --git a/csharp/ql/test/library-tests/expressions/AnonymousMethod2.expected b/csharp/ql/test/library-tests/expressions/AnonymousMethod2.expected index 71d45f3859be..a4eb1c44ada0 100644 --- a/csharp/ql/test/library-tests/expressions/AnonymousMethod2.expected +++ b/csharp/ql/test/library-tests/expressions/AnonymousMethod2.expected @@ -1 +1 @@ -| expressions.cs:443:33:443:66 | delegate(...) { ... } | expressions.cs:443:47:443:47 | x | +| expressions.cs:455:33:455:66 | delegate(...) { ... } | expressions.cs:455:47:455:47 | x | diff --git a/csharp/ql/test/library-tests/expressions/AnonymousMethod3.expected b/csharp/ql/test/library-tests/expressions/AnonymousMethod3.expected index 99cbc7b72803..a443b2e5f587 100644 --- a/csharp/ql/test/library-tests/expressions/AnonymousMethod3.expected +++ b/csharp/ql/test/library-tests/expressions/AnonymousMethod3.expected @@ -1 +1 @@ -| expressions.cs:443:33:443:66 | delegate(...) { ... } | +| expressions.cs:455:33:455:66 | delegate(...) { ... } | diff --git a/csharp/ql/test/library-tests/expressions/AnonymousMethod4.expected b/csharp/ql/test/library-tests/expressions/AnonymousMethod4.expected index f1ea5fb30213..650c309ba907 100644 --- a/csharp/ql/test/library-tests/expressions/AnonymousMethod4.expected +++ b/csharp/ql/test/library-tests/expressions/AnonymousMethod4.expected @@ -1 +1 @@ -| expressions.cs:445:28:445:53 | delegate(...) { ... } | expressions.cs:445:28:445:53 | delegate(...) { ... } | +| expressions.cs:457:28:457:53 | delegate(...) { ... } | expressions.cs:457:28:457:53 | delegate(...) { ... } | diff --git a/csharp/ql/test/library-tests/expressions/AnonymousMethod5.expected b/csharp/ql/test/library-tests/expressions/AnonymousMethod5.expected index aa2ee29ffda7..2f79004d8efe 100644 --- a/csharp/ql/test/library-tests/expressions/AnonymousMethod5.expected +++ b/csharp/ql/test/library-tests/expressions/AnonymousMethod5.expected @@ -1 +1 @@ -| expressions.cs:445:28:445:53 | delegate(...) { ... } | expressions.cs:445:46:445:46 | access to local variable j | +| expressions.cs:457:28:457:53 | delegate(...) { ... } | expressions.cs:457:46:457:46 | access to local variable j | diff --git a/csharp/ql/test/library-tests/expressions/ArrayCreation11.expected b/csharp/ql/test/library-tests/expressions/ArrayCreation11.expected new file mode 100644 index 000000000000..2fa6120d6953 --- /dev/null +++ b/csharp/ql/test/library-tests/expressions/ArrayCreation11.expected @@ -0,0 +1,27 @@ +| expressions.cs:168:27:168:44 | array creation of type Object[] | expressions.cs:168:27:168:44 | 1 | true | +| expressions.cs:409:23:409:65 | array creation of type Int32[,] | expressions.cs:409:23:409:65 | 2 | true | +| expressions.cs:409:23:409:65 | array creation of type Int32[,] | expressions.cs:409:23:409:65 | 3 | true | +| expressions.cs:437:24:437:66 | array creation of type Int32[,] | expressions.cs:437:24:437:66 | 2 | true | +| expressions.cs:437:24:437:66 | array creation of type Int32[,] | expressions.cs:437:24:437:66 | 3 | true | +| expressions.cs:438:17:438:93 | array creation of type Int32[,,] | expressions.cs:438:17:438:93 | 2 | true | +| expressions.cs:438:17:438:93 | array creation of type Int32[,,] | expressions.cs:438:17:438:93 | 2 | true | +| expressions.cs:438:17:438:93 | array creation of type Int32[,,] | expressions.cs:438:17:438:93 | 3 | true | +| expressions.cs:439:17:443:13 | array creation of type Int32[,][,] | expressions.cs:439:17:443:13 | 2 | true | +| expressions.cs:439:17:443:13 | array creation of type Int32[,][,] | expressions.cs:439:17:443:13 | 3 | true | +| expressions.cs:441:19:441:45 | array creation of type Int32[,] | expressions.cs:441:19:441:45 | 2 | true | +| expressions.cs:441:19:441:45 | array creation of type Int32[,] | expressions.cs:441:19:441:45 | 2 | true | +| expressions.cs:441:48:441:82 | array creation of type Int32[,] | expressions.cs:441:48:441:82 | 2 | true | +| expressions.cs:441:48:441:82 | array creation of type Int32[,] | expressions.cs:441:48:441:82 | 3 | true | +| expressions.cs:441:85:441:122 | array creation of type Int32[,] | expressions.cs:441:85:441:122 | 2 | true | +| expressions.cs:441:85:441:122 | array creation of type Int32[,] | expressions.cs:441:85:441:122 | 3 | true | +| expressions.cs:442:19:442:45 | array creation of type Int32[,] | expressions.cs:442:19:442:45 | 2 | true | +| expressions.cs:442:19:442:45 | array creation of type Int32[,] | expressions.cs:442:19:442:45 | 2 | true | +| expressions.cs:442:48:442:82 | array creation of type Int32[,] | expressions.cs:442:48:442:82 | 2 | true | +| expressions.cs:442:48:442:82 | array creation of type Int32[,] | expressions.cs:442:48:442:82 | 3 | true | +| expressions.cs:442:85:442:122 | array creation of type Int32[,] | expressions.cs:442:85:442:122 | 2 | true | +| expressions.cs:442:85:442:122 | array creation of type Int32[,] | expressions.cs:442:85:442:122 | 3 | true | +| expressions.cs:444:17:444:123 | array creation of type Int32[,][] | expressions.cs:444:17:444:123 | 2 | true | +| expressions.cs:444:32:444:54 | array creation of type Int32[,] | expressions.cs:444:32:444:54 | 1 | true | +| expressions.cs:444:32:444:54 | array creation of type Int32[,] | expressions.cs:444:32:444:54 | 2 | true | +| expressions.cs:444:57:444:121 | array creation of type Int32[,] | expressions.cs:444:57:444:121 | 3 | true | +| expressions.cs:444:57:444:121 | array creation of type Int32[,] | expressions.cs:444:57:444:121 | 4 | true | diff --git a/csharp/ql/test/library-tests/expressions/ArrayCreation11.ql b/csharp/ql/test/library-tests/expressions/ArrayCreation11.ql new file mode 100644 index 000000000000..6d7a501fefaa --- /dev/null +++ b/csharp/ql/test/library-tests/expressions/ArrayCreation11.ql @@ -0,0 +1,13 @@ +/** + * @name Test for array creations + */ + +import csharp + +private boolean isImplicit(Expr expr) { + if expr.isImplicit() then result = true else result = false +} + +from ArrayCreation ac, Expr expr +where ac.isImplicitlySized() and not ac.isImplicitlyTyped() and expr = ac.getALengthArgument() +select ac, expr, isImplicit(expr) diff --git a/csharp/ql/test/library-tests/expressions/Lambda1.expected b/csharp/ql/test/library-tests/expressions/Lambda1.expected index 030ff70fac43..34e99d531ad5 100644 --- a/csharp/ql/test/library-tests/expressions/Lambda1.expected +++ b/csharp/ql/test/library-tests/expressions/Lambda1.expected @@ -1 +1 @@ -| expressions.cs:437:36:437:53 | (...) => ... | +| expressions.cs:449:36:449:53 | (...) => ... | diff --git a/csharp/ql/test/library-tests/expressions/Lambda2.expected b/csharp/ql/test/library-tests/expressions/Lambda2.expected index 6b9ab4d13af2..a59313cf13e6 100644 --- a/csharp/ql/test/library-tests/expressions/Lambda2.expected +++ b/csharp/ql/test/library-tests/expressions/Lambda2.expected @@ -1 +1 @@ -| expressions.cs:438:38:438:59 | (...) => ... | +| expressions.cs:450:38:450:59 | (...) => ... | diff --git a/csharp/ql/test/library-tests/expressions/Lambda3.expected b/csharp/ql/test/library-tests/expressions/Lambda3.expected index 0a17c1914d6f..f00475e2298d 100644 --- a/csharp/ql/test/library-tests/expressions/Lambda3.expected +++ b/csharp/ql/test/library-tests/expressions/Lambda3.expected @@ -1 +1 @@ -| expressions.cs:439:33:439:48 | (...) => ... | +| expressions.cs:451:33:451:48 | (...) => ... | diff --git a/csharp/ql/test/library-tests/expressions/Lambda4.expected b/csharp/ql/test/library-tests/expressions/Lambda4.expected index da7c72353aec..92b0dea6fa52 100644 --- a/csharp/ql/test/library-tests/expressions/Lambda4.expected +++ b/csharp/ql/test/library-tests/expressions/Lambda4.expected @@ -1 +1 @@ -| expressions.cs:440:36:440:64 | (...) => ... | +| expressions.cs:452:36:452:64 | (...) => ... | diff --git a/csharp/ql/test/library-tests/expressions/Lambda5.expected b/csharp/ql/test/library-tests/expressions/Lambda5.expected index cc846823df46..08d4b5546ae2 100644 --- a/csharp/ql/test/library-tests/expressions/Lambda5.expected +++ b/csharp/ql/test/library-tests/expressions/Lambda5.expected @@ -1 +1 @@ -| expressions.cs:441:20:441:34 | (...) => ... | +| expressions.cs:453:20:453:34 | (...) => ... | diff --git a/csharp/ql/test/library-tests/expressions/Lambda6.expected b/csharp/ql/test/library-tests/expressions/Lambda6.expected index 83d1caa259dc..55427d92103e 100644 --- a/csharp/ql/test/library-tests/expressions/Lambda6.expected +++ b/csharp/ql/test/library-tests/expressions/Lambda6.expected @@ -1 +1 @@ -| expressions.cs:442:23:442:47 | (...) => ... | +| expressions.cs:454:23:454:47 | (...) => ... | diff --git a/csharp/ql/test/library-tests/expressions/OperatorCall6.expected b/csharp/ql/test/library-tests/expressions/OperatorCall6.expected index 208e70975f36..4f483ef92e22 100644 --- a/csharp/ql/test/library-tests/expressions/OperatorCall6.expected +++ b/csharp/ql/test/library-tests/expressions/OperatorCall6.expected @@ -1,4 +1,4 @@ -| expressions.cs:458:20:458:27 | addition | expressions.cs:460:26:460:26 | access to parameter a | expressions.cs:473:40:473:40 | + | -| expressions.cs:458:20:458:27 | addition | expressions.cs:460:30:460:30 | access to parameter b | expressions.cs:473:40:473:40 | + | -| expressions.cs:458:20:458:27 | addition | expressions.cs:461:13:461:18 | access to local variable result | expressions.cs:473:40:473:40 | + | -| expressions.cs:458:20:458:27 | addition | expressions.cs:461:23:461:23 | access to parameter c | expressions.cs:473:40:473:40 | + | +| expressions.cs:470:20:470:27 | addition | expressions.cs:472:26:472:26 | access to parameter a | expressions.cs:485:40:485:40 | + | +| expressions.cs:470:20:470:27 | addition | expressions.cs:472:30:472:30 | access to parameter b | expressions.cs:485:40:485:40 | + | +| expressions.cs:470:20:470:27 | addition | expressions.cs:473:13:473:18 | access to local variable result | expressions.cs:485:40:485:40 | + | +| expressions.cs:470:20:470:27 | addition | expressions.cs:473:23:473:23 | access to parameter c | expressions.cs:485:40:485:40 | + | diff --git a/csharp/ql/test/library-tests/expressions/OperatorCall7.expected b/csharp/ql/test/library-tests/expressions/OperatorCall7.expected index b59bcd180fa9..46f56cef5ac9 100644 --- a/csharp/ql/test/library-tests/expressions/OperatorCall7.expected +++ b/csharp/ql/test/library-tests/expressions/OperatorCall7.expected @@ -1,2 +1,2 @@ -| expressions.cs:452:21:452:35 | delegateCombine | expressions.cs:450:11:450:23 | OperatorCalls | expressions.cs:455:13:455:27 | access to local variable PropertyChanged | expressions.cs:479:30:479:39 | MyDelegate | -| expressions.cs:452:21:452:35 | delegateCombine | expressions.cs:450:11:450:23 | OperatorCalls | expressions.cs:455:32:455:34 | access to parameter fun | expressions.cs:479:30:479:39 | MyDelegate | +| expressions.cs:464:21:464:35 | delegateCombine | expressions.cs:462:11:462:23 | OperatorCalls | expressions.cs:467:13:467:27 | access to local variable PropertyChanged | expressions.cs:491:30:491:39 | MyDelegate | +| expressions.cs:464:21:464:35 | delegateCombine | expressions.cs:462:11:462:23 | OperatorCalls | expressions.cs:467:32:467:34 | access to parameter fun | expressions.cs:491:30:491:39 | MyDelegate | diff --git a/csharp/ql/test/library-tests/expressions/PrintAst.expected b/csharp/ql/test/library-tests/expressions/PrintAst.expected new file mode 100644 index 000000000000..9e654a6eeb84 --- /dev/null +++ b/csharp/ql/test/library-tests/expressions/PrintAst.expected @@ -0,0 +1,1957 @@ +FoldedLiterals.cs: +# 1| [Class] FoldedLiterals +# 3| 5: [Method] Test +# 4| 4: [BlockStmt] {...} +# 6| 0: [LocalVariableDeclStmt] ... ...; +# 6| 0: [LocalVariableDeclAndInitExpr] Boolean b1 = ... +# 6| 0: [BoolLiteral] false +# 6| 1: [LocalVariableAccess] access to local variable b1 +# 7| 1: [LocalVariableDeclStmt] ... ...; +# 7| 0: [LocalVariableDeclAndInitExpr] Boolean b2 = ... +# 7| 0: [LogicalNotExpr] !... +# 7| 0: [BoolLiteral] false +# 7| 1: [LocalVariableAccess] access to local variable b2 +# 10| 2: [LocalVariableDeclStmt] ... ...; +# 10| 0: [LocalVariableDeclAndInitExpr] Char c0 = ... +# 10| 0: [CharLiteral] +# 10| 1: [LocalVariableAccess] access to local variable c0 +# 11| 3: [LocalVariableDeclStmt] ... ...; +# 11| 0: [LocalVariableDeclAndInitExpr] Int32 c1 = ... +# 11| 0: [UnaryPlusExpr] +... +# 11| 0: [CastExpr] (...) ... +# 11| 0: [CharLiteral] +# 11| 1: [LocalVariableAccess] access to local variable c1 +# 12| 4: [LocalVariableDeclStmt] ... ...; +# 12| 0: [LocalVariableDeclAndInitExpr] Int32 c2 = ... +# 12| 0: [UnaryMinusExpr] -... +# 13| 0: [CastExpr] (...) ... +# 13| 0: [CharLiteral] +# 12| 1: [LocalVariableAccess] access to local variable c2 +# 14| 5: [LocalVariableDeclStmt] ... ...; +# 14| 0: [LocalVariableDeclAndInitExpr] Int32 c3 = ... +# 14| 0: [ComplementExpr] ~... +# 14| 0: [CastExpr] (...) ... +# 14| 0: [CharLiteral] +# 14| 1: [LocalVariableAccess] access to local variable c3 +# 15| 6: [LocalVariableDeclStmt] ... ...; +# 15| 0: [LocalVariableDeclAndInitExpr] Char c4 = ... +# 15| 0: [CharLiteral] \ +# 15| 1: [LocalVariableAccess] access to local variable c4 +# 18| 7: [LocalVariableDeclStmt] ... ...; +# 18| 0: [LocalVariableDeclAndInitExpr] SByte sb0 = ... +# 18| 0: [CastExpr] (...) ... +# 18| 0: [IntLiteral] 1 +# 18| 1: [TypeAccess] access to type SByte +# 18| 1: [LocalVariableAccess] access to local variable sb0 +# 19| 8: [LocalVariableDeclStmt] ... ...; +# 19| 0: [LocalVariableDeclAndInitExpr] Int32 sb1 = ... +# 19| 0: [UnaryPlusExpr] +... +# 19| 0: [CastExpr] (...) ... +# 19| 0: [CastExpr] (...) ... +# 19| 0: [IntLiteral] 1 +# 19| 1: [TypeAccess] access to type SByte +# 19| 1: [LocalVariableAccess] access to local variable sb1 +# 20| 9: [LocalVariableDeclStmt] ... ...; +# 20| 0: [LocalVariableDeclAndInitExpr] Int32 sb2 = ... +# 20| 0: [UnaryMinusExpr] -... +# 20| 0: [CastExpr] (...) ... +# 20| 0: [CastExpr] (...) ... +# 20| 0: [IntLiteral] 1 +# 20| 1: [TypeAccess] access to type SByte +# 20| 1: [LocalVariableAccess] access to local variable sb2 +# 21| 10: [LocalVariableDeclStmt] ... ...; +# 21| 0: [LocalVariableDeclAndInitExpr] Int32 sb3 = ... +# 21| 0: [ComplementExpr] ~... +# 21| 0: [CastExpr] (...) ... +# 21| 0: [CastExpr] (...) ... +# 21| 0: [IntLiteral] 1 +# 21| 1: [TypeAccess] access to type SByte +# 21| 1: [LocalVariableAccess] access to local variable sb3 +# 24| 11: [LocalVariableDeclStmt] ... ...; +# 24| 0: [LocalVariableDeclAndInitExpr] Byte ub0 = ... +# 24| 0: [CastExpr] (...) ... +# 24| 0: [IntLiteral] 2 +# 24| 1: [TypeAccess] access to type Byte +# 24| 1: [LocalVariableAccess] access to local variable ub0 +# 25| 12: [LocalVariableDeclStmt] ... ...; +# 25| 0: [LocalVariableDeclAndInitExpr] Int32 ub1 = ... +# 25| 0: [UnaryPlusExpr] +... +# 25| 0: [CastExpr] (...) ... +# 25| 0: [CastExpr] (...) ... +# 25| 0: [IntLiteral] 2 +# 25| 1: [TypeAccess] access to type Byte +# 25| 1: [LocalVariableAccess] access to local variable ub1 +# 26| 13: [LocalVariableDeclStmt] ... ...; +# 26| 0: [LocalVariableDeclAndInitExpr] Int32 ub2 = ... +# 26| 0: [UnaryMinusExpr] -... +# 26| 0: [CastExpr] (...) ... +# 26| 0: [CastExpr] (...) ... +# 26| 0: [IntLiteral] 2 +# 26| 1: [TypeAccess] access to type Byte +# 26| 1: [LocalVariableAccess] access to local variable ub2 +# 27| 14: [LocalVariableDeclStmt] ... ...; +# 27| 0: [LocalVariableDeclAndInitExpr] Int32 ub3 = ... +# 27| 0: [ComplementExpr] ~... +# 27| 0: [CastExpr] (...) ... +# 27| 0: [CastExpr] (...) ... +# 27| 0: [IntLiteral] 2 +# 27| 1: [TypeAccess] access to type Byte +# 27| 1: [LocalVariableAccess] access to local variable ub3 +# 30| 15: [LocalVariableDeclStmt] ... ...; +# 30| 0: [LocalVariableDeclAndInitExpr] Int16 ss0 = ... +# 30| 0: [CastExpr] (...) ... +# 30| 0: [IntLiteral] 3 +# 30| 1: [TypeAccess] access to type Int16 +# 30| 1: [LocalVariableAccess] access to local variable ss0 +# 31| 16: [LocalVariableDeclStmt] ... ...; +# 31| 0: [LocalVariableDeclAndInitExpr] Int32 ss1 = ... +# 31| 0: [UnaryPlusExpr] +... +# 31| 0: [CastExpr] (...) ... +# 31| 0: [CastExpr] (...) ... +# 31| 0: [IntLiteral] 3 +# 31| 1: [TypeAccess] access to type Int16 +# 31| 1: [LocalVariableAccess] access to local variable ss1 +# 32| 17: [LocalVariableDeclStmt] ... ...; +# 32| 0: [LocalVariableDeclAndInitExpr] Int32 ss2 = ... +# 32| 0: [UnaryMinusExpr] -... +# 32| 0: [CastExpr] (...) ... +# 32| 0: [CastExpr] (...) ... +# 32| 0: [IntLiteral] 3 +# 32| 1: [TypeAccess] access to type Int16 +# 32| 1: [LocalVariableAccess] access to local variable ss2 +# 33| 18: [LocalVariableDeclStmt] ... ...; +# 33| 0: [LocalVariableDeclAndInitExpr] Int32 ss3 = ... +# 33| 0: [ComplementExpr] ~... +# 33| 0: [CastExpr] (...) ... +# 33| 0: [CastExpr] (...) ... +# 33| 0: [IntLiteral] 3 +# 33| 1: [TypeAccess] access to type Int16 +# 33| 1: [LocalVariableAccess] access to local variable ss3 +# 36| 19: [LocalVariableDeclStmt] ... ...; +# 36| 0: [LocalVariableDeclAndInitExpr] UInt16 us0 = ... +# 36| 0: [CastExpr] (...) ... +# 36| 0: [IntLiteral] 4 +# 36| 1: [TypeAccess] access to type UInt16 +# 36| 1: [LocalVariableAccess] access to local variable us0 +# 37| 20: [LocalVariableDeclStmt] ... ...; +# 37| 0: [LocalVariableDeclAndInitExpr] Int32 us1 = ... +# 37| 0: [UnaryPlusExpr] +... +# 37| 0: [CastExpr] (...) ... +# 37| 0: [CastExpr] (...) ... +# 37| 0: [IntLiteral] 4 +# 37| 1: [TypeAccess] access to type UInt16 +# 37| 1: [LocalVariableAccess] access to local variable us1 +# 38| 21: [LocalVariableDeclStmt] ... ...; +# 38| 0: [LocalVariableDeclAndInitExpr] Int32 us2 = ... +# 38| 0: [UnaryMinusExpr] -... +# 38| 0: [CastExpr] (...) ... +# 38| 0: [CastExpr] (...) ... +# 38| 0: [IntLiteral] 4 +# 38| 1: [TypeAccess] access to type UInt16 +# 38| 1: [LocalVariableAccess] access to local variable us2 +# 39| 22: [LocalVariableDeclStmt] ... ...; +# 39| 0: [LocalVariableDeclAndInitExpr] Int32 us3 = ... +# 39| 0: [ComplementExpr] ~... +# 39| 0: [CastExpr] (...) ... +# 39| 0: [CastExpr] (...) ... +# 39| 0: [IntLiteral] 4 +# 39| 1: [TypeAccess] access to type UInt16 +# 39| 1: [LocalVariableAccess] access to local variable us3 +# 42| 23: [LocalVariableDeclStmt] ... ...; +# 42| 0: [LocalVariableDeclAndInitExpr] Int32 i0 = ... +# 42| 0: [IntLiteral] 5 +# 42| 1: [LocalVariableAccess] access to local variable i0 +# 43| 24: [LocalVariableDeclStmt] ... ...; +# 43| 0: [LocalVariableDeclAndInitExpr] Int32 i1 = ... +# 43| 0: [UnaryPlusExpr] +... +# 43| 0: [IntLiteral] 5 +# 43| 1: [LocalVariableAccess] access to local variable i1 +# 44| 25: [LocalVariableDeclStmt] ... ...; +# 44| 0: [LocalVariableDeclAndInitExpr] Int32 i2 = ... +# 44| 0: [UnaryMinusExpr] -... +# 44| 0: [IntLiteral] 5 +# 44| 1: [LocalVariableAccess] access to local variable i2 +# 45| 26: [LocalVariableDeclStmt] ... ...; +# 45| 0: [LocalVariableDeclAndInitExpr] Int32 i3 = ... +# 45| 0: [ComplementExpr] ~... +# 45| 0: [IntLiteral] 5 +# 45| 1: [LocalVariableAccess] access to local variable i3 +# 48| 27: [LocalVariableDeclStmt] ... ...; +# 48| 0: [LocalVariableDeclAndInitExpr] UInt32 ui0 = ... +# 48| 0: [CastExpr] (...) ... +# 48| 0: [IntLiteral] 6 +# 48| 1: [LocalVariableAccess] access to local variable ui0 +# 49| 28: [LocalVariableDeclStmt] ... ...; +# 49| 0: [LocalVariableDeclAndInitExpr] Int32 ui1 = ... +# 49| 0: [UnaryPlusExpr] +... +# 49| 0: [IntLiteral] 6 +# 49| 1: [LocalVariableAccess] access to local variable ui1 +# 50| 29: [LocalVariableDeclStmt] ... ...; +# 50| 0: [LocalVariableDeclAndInitExpr] Int32 ui2 = ... +# 50| 0: [UnaryMinusExpr] -... +# 50| 0: [IntLiteral] 6 +# 50| 1: [LocalVariableAccess] access to local variable ui2 +# 51| 30: [LocalVariableDeclStmt] ... ...; +# 51| 0: [LocalVariableDeclAndInitExpr] Int32 ui3 = ... +# 51| 0: [ComplementExpr] ~... +# 51| 0: [IntLiteral] 6 +# 51| 1: [LocalVariableAccess] access to local variable ui3 +# 54| 31: [LocalVariableDeclStmt] ... ...; +# 54| 0: [LocalVariableDeclAndInitExpr] Int64 l0 = ... +# 54| 0: [LongLiteral] 7 +# 54| 1: [LocalVariableAccess] access to local variable l0 +# 55| 32: [LocalVariableDeclStmt] ... ...; +# 55| 0: [LocalVariableDeclAndInitExpr] Int64 l1 = ... +# 55| 0: [UnaryPlusExpr] +... +# 55| 0: [LongLiteral] 7 +# 55| 1: [LocalVariableAccess] access to local variable l1 +# 55| 33: [EmptyStmt] ; +# 56| 34: [LocalVariableDeclStmt] ... ...; +# 56| 0: [LocalVariableDeclAndInitExpr] Int64 l2 = ... +# 56| 0: [UnaryMinusExpr] -... +# 56| 0: [LongLiteral] 7 +# 56| 1: [LocalVariableAccess] access to local variable l2 +# 57| 35: [LocalVariableDeclStmt] ... ...; +# 57| 0: [LocalVariableDeclAndInitExpr] Int64 l3 = ... +# 57| 0: [ComplementExpr] ~... +# 57| 0: [LongLiteral] 7 +# 57| 1: [LocalVariableAccess] access to local variable l3 +# 60| 36: [LocalVariableDeclStmt] ... ...; +# 60| 0: [LocalVariableDeclAndInitExpr] UInt64 ul0 = ... +# 60| 0: [ULongLiteral] 8 +# 60| 1: [LocalVariableAccess] access to local variable ul0 +# 61| 37: [LocalVariableDeclStmt] ... ...; +# 61| 0: [LocalVariableDeclAndInitExpr] UInt64 ul1 = ... +# 61| 0: [UnaryPlusExpr] +... +# 61| 0: [ULongLiteral] 8 +# 61| 1: [LocalVariableAccess] access to local variable ul1 +# 62| 38: [LocalVariableDeclStmt] ... ...; +# 62| 0: [LocalVariableDeclAndInitExpr] UInt64 ul3 = ... +# 62| 0: [ComplementExpr] ~... +# 62| 0: [ULongLiteral] 8 +# 62| 1: [LocalVariableAccess] access to local variable ul3 +# 65| 39: [LocalVariableDeclStmt] ... ...; +# 65| 0: [LocalVariableDeclAndInitExpr] Single f0 = ... +# 65| 0: [FloatLiteral] 9 +# 65| 1: [LocalVariableAccess] access to local variable f0 +# 66| 40: [LocalVariableDeclStmt] ... ...; +# 66| 0: [LocalVariableDeclAndInitExpr] Single f1 = ... +# 66| 0: [UnaryPlusExpr] +... +# 66| 0: [FloatLiteral] 9 +# 66| 1: [LocalVariableAccess] access to local variable f1 +# 67| 41: [LocalVariableDeclStmt] ... ...; +# 67| 0: [LocalVariableDeclAndInitExpr] Single f2 = ... +# 67| 0: [UnaryMinusExpr] -... +# 67| 0: [FloatLiteral] 9 +# 67| 1: [LocalVariableAccess] access to local variable f2 +# 70| 42: [LocalVariableDeclStmt] ... ...; +# 70| 0: [LocalVariableDeclAndInitExpr] Double d0 = ... +# 70| 0: [DoubleLiteral] 10 +# 70| 1: [LocalVariableAccess] access to local variable d0 +# 71| 43: [LocalVariableDeclStmt] ... ...; +# 71| 0: [LocalVariableDeclAndInitExpr] Double d1 = ... +# 71| 0: [UnaryPlusExpr] +... +# 71| 0: [DoubleLiteral] 10 +# 71| 1: [LocalVariableAccess] access to local variable d1 +# 72| 44: [LocalVariableDeclStmt] ... ...; +# 72| 0: [LocalVariableDeclAndInitExpr] Double d2 = ... +# 72| 0: [UnaryMinusExpr] -... +# 72| 0: [DoubleLiteral] 10 +# 72| 1: [LocalVariableAccess] access to local variable d2 +# 75| 45: [LocalVariableDeclStmt] ... ...; +# 75| 0: [LocalVariableDeclAndInitExpr] Decimal m0 = ... +# 75| 0: [DecimalLiteral] 11 +# 75| 1: [LocalVariableAccess] access to local variable m0 +# 76| 46: [LocalVariableDeclStmt] ... ...; +# 76| 0: [LocalVariableDeclAndInitExpr] Decimal m1 = ... +# 76| 0: [UnaryPlusExpr] +... +# 76| 0: [DecimalLiteral] 11 +# 76| 1: [LocalVariableAccess] access to local variable m1 +# 77| 47: [LocalVariableDeclStmt] ... ...; +# 77| 0: [LocalVariableDeclAndInitExpr] Decimal m2 = ... +# 77| 0: [UnaryMinusExpr] -... +# 77| 0: [DecimalLiteral] 11 +# 77| 1: [LocalVariableAccess] access to local variable m2 +MethodAccess.cs: +# 3| [Class] MethodAccess +# 5| 5: [Method] M +# 6| 4: [BlockStmt] {...} +# 7| 0: [LocalFunctionStmt] M1(...) +# 7| 0: [LocalFunction] M1 +# 7| 4: [BlockStmt] {...} +# 7| 1: [EmptyStmt] ; +# 8| 2: [LocalVariableDeclStmt] ... ...; +# 8| 0: [LocalVariableDeclAndInitExpr] Action a = ... +# 8| 0: [ImplicitDelegateCreation] delegate creation of type Action +# 8| 0: [LocalFunctionAccess] access to local function M1 +# 8| 1: [LocalVariableAccess] access to local variable a +# 9| 3: [ExprStmt] ...; +# 9| 0: [AssignExpr] ... = ... +# 9| 0: [ImplicitDelegateCreation] delegate creation of type Action +# 9| 0: [MethodAccess] access to method M2 +# 9| 1: [LocalVariableAccess] access to local variable a +# 10| 4: [ExprStmt] ...; +# 10| 0: [AssignExpr] ... = ... +# 10| 0: [ImplicitDelegateCreation] delegate creation of type Action +# 10| 0: [MethodAccess] access to method M2 +# 10| -1: [ThisAccess] this access +# 10| 1: [LocalVariableAccess] access to local variable a +# 11| 5: [ExprStmt] ...; +# 11| 0: [AssignExpr] ... = ... +# 11| 0: [ImplicitDelegateCreation] delegate creation of type Action +# 11| 0: [MethodAccess] access to method M3 +# 11| 1: [LocalVariableAccess] access to local variable a +# 12| 6: [ExprStmt] ...; +# 12| 0: [AssignExpr] ... = ... +# 12| 0: [ImplicitDelegateCreation] delegate creation of type Action +# 12| 0: [MethodAccess] access to method M3 +# 12| -1: [TypeAccess] access to type MethodAccess +# 12| 1: [LocalVariableAccess] access to local variable a +# 15| 6: [Method] M2 +# 15| 4: [BlockStmt] {...} +# 17| 7: [Method] M3 +# 17| 4: [BlockStmt] {...} +Qualifiers.cs: +# 3| [Class] Qualifiers +# 5| 5: [Property] S +# 5| 3: [Getter] get_S +# 5| 4: [MethodCall] call to method Static +# 5| 0: [NullLiteral] null +# 7| 6: [Property] I +# 7| 3: [Getter] get_I +# 7| 4: [MethodCall] call to method Instance +# 9| 7: [Property] B +# 9| 3: [Getter] get_B +# 9| 4: [MethodCall] call to method Instance +# 9| -1: [ThisAccess] this access +# 11| 8: [Method] Static +#-----| 1: (Type parameters) +# 11| 0: [TypeParameter] T +#-----| 2: (Parameters) +# 11| 0: [Parameter] o +# 11| 4: [DefaultValueExpr] default(...) +# 11| 0: [TypeAccess] access to type T +# 13| 10: [Method] Instance +#-----| 1: (Type parameters) +# 13| 0: [TypeParameter] T +# 13| 4: [DefaultValueExpr] default(...) +# 13| 0: [TypeAccess] access to type T +ReducedExpression.cs: +# 2| [Class] ReducedClass +# 5| 5: [Field] ReducedExpression +# 5| 1: [AssignExpr] ... = ... +# 5| 0: [ConditionalExpr] ... ? ... : ... +# 5| 0: [BoolLiteral] true +# 5| 1: [IntLiteral] 10 +# 5| 2: [IntLiteral] 12 +# 5| 1: [MemberConstantAccess] access to constant ReducedExpression +expressions.cs: +# 5| [NamespaceDeclaration] namespace ... { ... } +# 7| 1: [Class] Class +# 10| 4: [Method] MainLiterals +# 11| 4: [BlockStmt] {...} +# 12| 0: [LocalVariableDeclStmt] ... ...; +# 12| 0: [LocalVariableDeclExpr] Boolean b +# 13| 1: [ExprStmt] ...; +# 13| 0: [AssignExpr] ... = ... +# 13| 0: [BoolLiteral] true +# 13| 1: [LocalVariableAccess] access to local variable b +# 14| 2: [ExprStmt] ...; +# 14| 0: [AssignExpr] ... = ... +# 14| 0: [BoolLiteral] false +# 14| 1: [LocalVariableAccess] access to local variable b +# 15| 3: [ExprStmt] ...; +# 15| 0: [AssignExpr] ... = ... +# 15| 0: [LogicalNotExpr] !... +# 15| 0: [LocalVariableAccess] access to local variable b +# 15| 1: [LocalVariableAccess] access to local variable b +# 16| 4: [LocalVariableDeclStmt] ... ...; +# 16| 0: [LocalVariableDeclAndInitExpr] Char c = ... +# 16| 0: [CharLiteral] @ +# 16| 1: [LocalVariableAccess] access to local variable c +# 17| 5: [LocalVariableDeclStmt] ... ...; +# 17| 0: [LocalVariableDeclExpr] Int32 i +# 18| 6: [ExprStmt] ...; +# 18| 0: [AssignExpr] ... = ... +# 18| 0: [IntLiteral] 1 +# 18| 1: [LocalVariableAccess] access to local variable i +# 19| 7: [ExprStmt] ...; +# 19| 0: [AssignExpr] ... = ... +# 19| 0: [UnaryMinusExpr] -... +# 19| 0: [LocalVariableAccess] access to local variable i +# 19| 1: [LocalVariableAccess] access to local variable i +# 20| 8: [LocalVariableDeclStmt] ... ...; +# 20| 0: [LocalVariableDeclExpr] Int64 l +# 21| 9: [ExprStmt] ...; +# 21| 0: [AssignExpr] ... = ... +# 21| 0: [LongLiteral] 8989898 +# 21| 1: [LocalVariableAccess] access to local variable l +# 22| 10: [LocalVariableDeclStmt] ... ...; +# 22| 0: [LocalVariableDeclExpr] UInt32 ui +# 23| 11: [ExprStmt] ...; +# 23| 0: [AssignExpr] ... = ... +# 23| 0: [UIntLiteral] 3 +# 23| 1: [LocalVariableAccess] access to local variable ui +# 24| 12: [LocalVariableDeclStmt] ... ...; +# 24| 0: [LocalVariableDeclExpr] UInt64 ul +# 25| 13: [ExprStmt] ...; +# 25| 0: [AssignExpr] ... = ... +# 25| 0: [ULongLiteral] 89898787897 +# 25| 1: [LocalVariableAccess] access to local variable ul +# 26| 14: [LocalVariableDeclStmt] ... ...; +# 26| 0: [LocalVariableDeclAndInitExpr] Single f = ... +# 26| 0: [FloatLiteral] 4.5 +# 26| 1: [LocalVariableAccess] access to local variable f +# 27| 15: [LocalVariableDeclStmt] ... ...; +# 27| 0: [LocalVariableDeclExpr] Double d +# 28| 16: [ExprStmt] ...; +# 28| 0: [AssignExpr] ... = ... +# 28| 0: [DoubleLiteral] 4.565 +# 28| 1: [LocalVariableAccess] access to local variable d +# 29| 17: [LocalVariableDeclStmt] ... ...; +# 29| 0: [LocalVariableDeclExpr] Decimal m +# 30| 18: [ExprStmt] ...; +# 30| 0: [AssignExpr] ... = ... +# 30| 0: [DecimalLiteral] 123.456 +# 30| 1: [LocalVariableAccess] access to local variable m +# 31| 19: [LocalVariableDeclStmt] ... ...; +# 31| 0: [LocalVariableDeclExpr] String s +# 32| 20: [ExprStmt] ...; +# 32| 0: [AssignExpr] ... = ... +# 32| 0: [StringLiteral] "test" +# 32| 1: [LocalVariableAccess] access to local variable s +# 33| 21: [LocalVariableDeclStmt] ... ...; +# 33| 0: [LocalVariableDeclExpr] Object o +# 34| 22: [ExprStmt] ...; +# 34| 0: [AssignExpr] ... = ... +# 34| 0: [NullLiteral] null +# 34| 1: [LocalVariableAccess] access to local variable o +# 37| 5: [Method] LogicalOperators +#-----| 2: (Parameters) +# 37| 0: [Parameter] a +# 37| 1: [Parameter] b +# 38| 4: [BlockStmt] {...} +# 39| 0: [LocalVariableDeclStmt] ... ...; +# 39| 0: [LocalVariableDeclAndInitExpr] Int32 x = ... +# 39| 0: [ConditionalExpr] ... ? ... : ... +# 39| 0: [ParameterAccess] access to parameter a +# 39| 1: [IntLiteral] 0 +# 39| 2: [IntLiteral] 42 +# 39| 1: [LocalVariableAccess] access to local variable x +# 40| 1: [LocalVariableDeclStmt] ... ...; +# 40| 0: [LocalVariableDeclAndInitExpr] Boolean c = ... +# 40| 0: [LogicalOrExpr] ... || ... +# 40| 0: [ParameterAccess] access to parameter b +# 40| 1: [GTExpr] ... > ... +# 40| 0: [LocalVariableAccess] access to local variable x +# 40| 1: [IntLiteral] 3 +# 40| 1: [LocalVariableAccess] access to local variable c +# 41| 2: [ReturnStmt] return ...; +# 41| 0: [LogicalAndExpr] ... && ... +# 41| 0: [LogicalAndExpr] ... && ... +# 41| 0: [ParameterAccess] access to parameter a +# 41| 1: [ParameterAccess] access to parameter b +# 41| 1: [LogicalNotExpr] !... +# 41| 0: [LocalVariableAccess] access to local variable c +# 44| 6: [Field] constant +# 44| 1: [AssignExpr] ... = ... +# 44| 0: [StringLiteral] "constant" +# 44| 1: [MemberConstantAccess] access to constant constant +# 45| 7: [Field] f +# 45| 1: [AssignExpr] ... = ... +# 45| 0: [IntLiteral] 0 +# 45| 1: [FieldAccess] access to field f +# 46| 8: [Field] name +# 48| 9: [StaticConstructor] Class +# 49| 4: [BlockStmt] {...} +# 51| 0: [ExprStmt] ...; +# 51| 0: [AssignExpr] ... = ... +# 51| 0: [StringLiteral] "" +# 51| 1: [FieldAccess] access to field name +# 51| -1: [TypeAccess] access to type Class +# 52| 1: [ExprStmt] ...; +# 52| 0: [MethodCall] call to method Foo +# 52| -1: [TypeAccess] access to type Class +# 53| 2: [ExprStmt] ...; +# 53| 0: [MethodCall] call to method Foo +# 56| 10: [InstanceConstructor] Class +# 56| 3: [ConstructorInitializer] call to constructor Class +# 56| 0: [IntLiteral] 0 +# 56| 4: [BlockStmt] {...} +# 58| 11: [InstanceConstructor] Class +#-----| 2: (Parameters) +# 58| 0: [Parameter] i +# 58| 4: [BlockStmt] {...} +# 60| 12: [Method] Foo +# 60| 4: [BlockStmt] {...} +# 62| 13: [Method] Bar +#-----| 2: (Parameters) +# 62| 0: [Parameter] x +# 62| 1: [Parameter] s +# 63| 4: [BlockStmt] {...} +# 64| 0: [ReturnStmt] return ...; +# 64| 0: [AddExpr] ... + ... +# 64| 0: [PropertyCall] access to property Length +# 64| -1: [ParameterAccess] access to parameter s +# 64| 1: [ParameterAccess] access to parameter x +# 67| 14: [IndexerProperty] Name +# 69| 3: [Getter] get_Name +# 69| 4: [BlockStmt] {...} +# 69| 0: [ReturnStmt] return ...; +# 69| 0: [FieldAccess] access to field name +# 70| 4: [Setter] set_Name +#-----| 2: (Parameters) +# 70| 0: [Parameter] value +# 70| 4: [BlockStmt] {...} +# 70| 0: [ExprStmt] ...; +# 70| 0: [AssignExpr] ... = ... +# 70| 0: [ParameterAccess] access to parameter value +# 70| 1: [FieldAccess] access to field name +# 73| 15: [Indexer] Item +#-----| 1: (Parameters) +# 73| 0: [Parameter] i +# 73| 1: [Parameter] s +# 75| 3: [Getter] get_Item +#-----| 2: (Parameters) +# 73| 0: [Parameter] i +# 73| 1: [Parameter] s +# 75| 4: [BlockStmt] {...} +# 75| 0: [ReturnStmt] return ...; +# 75| 0: [LogicalAndExpr] ... && ... +# 75| 0: [GTExpr] ... > ... +# 75| 0: [ParameterAccess] access to parameter i +# 75| 1: [IntLiteral] 2 +# 75| 1: [MethodCall] call to method Equals +# 75| -1: [ParameterAccess] access to parameter s +# 75| 0: [StringLiteral] "" +# 76| 4: [Setter] set_Item +#-----| 2: (Parameters) +# 73| 0: [Parameter] i +# 73| 1: [Parameter] s +# 76| 2: [Parameter] value +# 76| 4: [BlockStmt] {...} +# 76| 0: [IfStmt] if (...) ... +# 76| 0: [ParameterAccess] access to parameter value +# 76| 1: [ExprStmt] ...; +# 76| 0: [PostIncrExpr] ...++ +# 76| 0: [FieldAccess] access to field f +# 79| 16: [Method] MainAccesses +#-----| 2: (Parameters) +# 79| 0: [Parameter] other +# 79| 1: [Parameter] args +# 80| 4: [BlockStmt] {...} +# 81| 0: [ExprStmt] ...; +# 81| 0: [AssignExpr] ... = ... +# 81| 0: [StringLiteral] "aName" +# 81| 1: [PropertyCall] access to property Name +# 82| 1: [LocalVariableDeclStmt] ... ...; +# 82| 0: [LocalVariableDeclAndInitExpr] String n = ... +# 82| 0: [PropertyCall] access to property Name +# 82| -1: [ThisAccess] this access +# 82| 1: [LocalVariableAccess] access to local variable n +# 83| 2: [LocalVariableDeclStmt] ... ...; +# 83| 0: [LocalVariableDeclAndInitExpr] Int32 i = ... +# 83| 0: [MethodCall] call to method Bar +# 83| -1: [ObjectCreation] object creation of type Class +# 83| 0: [AddExpr] ... + ... +# 83| 0: [IntLiteral] 4 +# 83| 1: [IntLiteral] 2 +# 83| 1: [PropertyCall] access to property Name +# 83| 1: [LocalVariableAccess] access to local variable i +# 84| 3: [ExprStmt] ...; +# 84| 0: [AssignExpr] ... = ... +# 84| 0: [MemberConstantAccess] access to constant constant +# 84| 1: [PropertyCall] access to property Name +# 84| -1: [ParameterAccess] access to parameter other +# 85| 4: [ExprStmt] ...; +# 85| 0: [AssignExpr] ... = ... +# 85| 0: [IndexerCall] access to indexer +# 85| -1: [ThisAccess] this access +# 85| 0: [IntLiteral] 0 +# 85| 1: [StringLiteral] "" +# 85| 1: [IndexerCall] access to indexer +# 85| -1: [ParameterAccess] access to parameter other +# 85| 0: [LocalVariableAccess] access to local variable i +# 85| 1: [MemberConstantAccess] access to constant constant +# 85| -1: [TypeAccess] access to type Nested +# 86| 5: [LocalVariableDeclStmt] ... ...; +# 86| 0: [LocalVariableDeclAndInitExpr] Int32[] array = ... +# 86| 0: [ArrayCreation] array creation of type Int32[] +# 86| -1: [ArrayInitializer] { ..., ... } +# 86| 0: [CastExpr] (...) ... +# 86| 0: [ULongLiteral] 4 +# 86| 1: [TypeAccess] access to type Int32 +# 86| 1: [CastExpr] (...) ... +# 86| 0: [LongLiteral] 3 +# 86| 1: [TypeAccess] access to type Int32 +# 86| 1: [LocalVariableAccess] access to local variable array +# 87| 6: [ExprStmt] ...; +# 87| 0: [AssignExpr] ... = ... +# 87| 0: [IntLiteral] 5 +# 87| 1: [ArrayAccess] access to array element +# 87| -1: [LocalVariableAccess] access to local variable array +# 87| 0: [IntLiteral] 1 +# 91| 17: [Method] MainIsAsCast +#-----| 2: (Parameters) +# 91| 0: [Parameter] s +# 91| 1: [Parameter] o +# 91| 2: [Parameter] p +# 92| 4: [BlockStmt] {...} +# 93| 0: [IfStmt] if (...) ... +# 93| 0: [IsExpr] ... is ... +# 93| 0: [ParameterAccess] access to parameter o +# 93| 1: [TypeAccessPatternExpr] access to type Class +# 94| 1: [BlockStmt] {...} +# 95| 0: [LocalVariableDeclStmt] ... ...; +# 95| 0: [LocalVariableDeclAndInitExpr] Class c = ... +# 95| 0: [AsExpr] ... as ... +# 95| 0: [ParameterAccess] access to parameter o +# 95| 1: [TypeAccess] access to type Class +# 95| 1: [LocalVariableAccess] access to local variable c +# 96| 1: [LocalVariableDeclStmt] ... ...; +# 96| 0: [LocalVariableDeclAndInitExpr] Class d = ... +# 96| 0: [CastExpr] (...) ... +# 96| 0: [ParameterAccess] access to parameter p +# 96| 1: [TypeAccess] access to type Class +# 96| 1: [LocalVariableAccess] access to local variable d +# 98| 1: [LocalVariableDeclStmt] ... ...; +# 98| 0: [LocalVariableDeclAndInitExpr] Class x = ... +# 98| 0: [CastExpr] (...) ... +# 98| 0: [AsExpr] ... as ... +# 98| 0: [CastExpr] (...) ... +# 98| 0: [ParameterAccess] access to parameter o +# 98| 1: [TypeAccess] access to type Class +# 98| 1: [TypeAccess] access to type Object +# 98| 1: [TypeAccess] access to type Class +# 98| 1: [LocalVariableAccess] access to local variable x +# 99| 2: [LocalVariableDeclStmt] ... ...; +# 99| 0: [LocalVariableDeclAndInitExpr] Int32 i = ... +# 99| 0: [DefaultValueExpr] default(...) +# 99| 0: [TypeAccess] access to type Int32 +# 99| 1: [LocalVariableAccess] access to local variable i +# 100| 3: [ExprStmt] ...; +# 100| 0: [AssignExpr] ... = ... +# 100| 0: [AddExpr] ... + ... +# 100| 0: [AddExpr] ... + ... +# 100| 0: [ParameterAccess] access to parameter s +# 100| 1: [StringLiteral] " " +# 100| 1: [CastExpr] (...) ... +# 100| 0: [LocalVariableAccess] access to local variable i +# 100| 1: [ParameterAccess] access to parameter s +# 103| 18: [Class] Y<,> +#-----| 1: (Type parameters) +# 103| 0: [TypeParameter] T +# 103| 1: [TypeParameter] U +# 107| 19: [Class] X<> +#-----| 1: (Type parameters) +# 107| 0: [TypeParameter] T +# 110| 5: [Method] PrintTypes +# 111| 4: [BlockStmt] {...} +# 112| 0: [LocalVariableDeclStmt] ... ...; +# 112| 0: [LocalVariableDeclAndInitExpr] Type[] t = ... +# 112| 0: [ArrayCreation] array creation of type Type[] +# 112| -1: [ArrayInitializer] { ..., ... } +# 113| 0: [TypeofExpr] typeof(...) +# 113| 0: [TypeAccess] access to type Void +# 114| 1: [TypeofExpr] typeof(...) +# 114| 0: [TypeAccess] access to type Int32 +# 115| 2: [TypeofExpr] typeof(...) +# 115| 0: [TypeAccess] access to type Int32 +# 116| 3: [TypeofExpr] typeof(...) +# 116| 0: [TypeAccess] access to type String +# 117| 4: [TypeofExpr] typeof(...) +# 117| 0: [TypeAccess] access to type Double[] +# 118| 5: [TypeofExpr] typeof(...) +# 118| 0: [TypeAccess] access to type Void +# 119| 6: [TypeofExpr] typeof(...) +# 119| 0: [TypeAccess] access to type T +# 120| 7: [TypeofExpr] typeof(...) +# 120| 0: [TypeAccess] access to type X<> +# 121| 8: [TypeofExpr] typeof(...) +# 121| 0: [TypeAccess] access to type X> +# 122| 9: [TypeofExpr] typeof(...) +# 122| 0: [TypeAccess] access to type Y<,> +# 112| 1: [LocalVariableAccess] access to local variable t +# 124| 1: [LocalVariableDeclStmt] ... ...; +# 124| 0: [LocalVariableDeclAndInitExpr] T e = ... +# 124| 0: [DefaultValueExpr] default(...) +# 124| 0: [TypeAccess] access to type T +# 124| 1: [LocalVariableAccess] access to local variable e +# 129| 21: [Class] Nested +#-----| 3: (Base types) +# 129| 0: [Class] Class +# 133| 4: [InstanceConstructor] Nested +#-----| 2: (Parameters) +# 133| 0: [Parameter] i +# 133| 3: [ConstructorInitializer] call to constructor Class +# 133| 0: [AddExpr] ... + ... +# 133| 0: [ParameterAccess] access to parameter i +# 133| 1: [IntLiteral] 1 +# 133| 4: [BlockStmt] {...} +# 135| 5: [Method] OtherAccesses +# 136| 4: [BlockStmt] {...} +# 137| 0: [ExprStmt] ...; +# 137| 0: [AssignExpr] ... = ... +# 137| 0: [IntLiteral] 0 +# 137| 1: [FieldAccess] access to field f +# 137| -1: [ThisAccess] this access +# 138| 1: [ExprStmt] ...; +# 138| 0: [MethodCall] call to method MainAccesses +# 138| -1: [BaseAccess] base access +# 138| 0: [ThisAccess] this access +# 138| 1: [CastExpr] (...) ... +# 138| 0: [IntLiteral] 1 +# 138| 2: [CastExpr] (...) ... +# 138| 0: [IntLiteral] 2 +# 138| 3: [CastExpr] (...) ... +# 138| 0: [IntLiteral] 3 +# 138| 4: [CastExpr] (...) ... +# 138| 0: [IntLiteral] 4 +# 138| 5: [StringLiteral] "" +# 143| 22: [Method] MainLocalVarDecl +# 144| 4: [BlockStmt] {...} +# 145| 0: [LocalVariableDeclStmt] ... ...; +# 145| 0: [LocalVariableDeclExpr] Int32 a +# 146| 1: [LocalVariableDeclStmt] ... ...; +# 146| 0: [LocalVariableDeclAndInitExpr] Int32 b = ... +# 146| 0: [IntLiteral] 2 +# 146| 1: [LocalVariableAccess] access to local variable b +# 146| 1: [LocalVariableDeclAndInitExpr] Int32 c = ... +# 146| 0: [IntLiteral] 3 +# 146| 1: [LocalVariableAccess] access to local variable c +# 147| 2: [ExprStmt] ...; +# 147| 0: [AssignExpr] ... = ... +# 147| 0: [IntLiteral] 1 +# 147| 1: [LocalVariableAccess] access to local variable a +# 148| 3: [ExprStmt] ...; +# 148| 0: [MethodCall] call to method WriteLine +# 148| -1: [TypeAccess] access to type Console +# 148| 0: [AddExpr] ... + ... +# 148| 0: [AddExpr] ... + ... +# 148| 0: [LocalVariableAccess] access to local variable a +# 148| 1: [LocalVariableAccess] access to local variable b +# 148| 1: [LocalVariableAccess] access to local variable c +# 149| 4: [LocalVariableDeclStmt] ... ...; +# 149| 0: [LocalVariableDeclAndInitExpr] Int32 x = ... +# 149| 0: [IntLiteral] 45 +# 149| 1: [LocalVariableAccess] access to local variable x +# 150| 5: [LocalVariableDeclStmt] ... ...; +# 150| 0: [LocalVariableDeclAndInitExpr] String y = ... +# 150| 0: [StringLiteral] "test" +# 150| 1: [LocalVariableAccess] access to local variable y +# 153| 23: [Method] MainLocalConstDecl +# 154| 4: [BlockStmt] {...} +# 155| 0: [LocalConstantDeclStmt] const ... ...; +# 155| 0: [LocalVariableDeclAndInitExpr] Single pi = ... +# 155| 0: [FloatLiteral] 3.1415927 +# 155| 1: [LocalVariableAccess] access to local variable pi +# 156| 1: [LocalConstantDeclStmt] const ... ...; +# 156| 0: [LocalVariableDeclAndInitExpr] Int32 r = ... +# 156| 0: [AddExpr] ... + ... +# 156| 0: [IntLiteral] 10 +# 156| 1: [IntLiteral] 15 +# 156| 1: [LocalVariableAccess] access to local variable r +# 157| 2: [ExprStmt] ...; +# 157| 0: [MethodCall] call to method WriteLine +# 157| -1: [TypeAccess] access to type Console +# 157| 0: [MulExpr] ... * ... +# 157| 0: [MulExpr] ... * ... +# 157| 0: [LocalVariableAccess] access to local variable pi +# 157| 1: [CastExpr] (...) ... +# 157| 0: [LocalVariableAccess] access to local variable r +# 157| 1: [CastExpr] (...) ... +# 157| 0: [LocalVariableAccess] access to local variable r +# 160| 24: [Method] MainChecked +# 161| 4: [BlockStmt] {...} +# 162| 0: [LocalVariableDeclStmt] ... ...; +# 162| 0: [LocalVariableDeclAndInitExpr] String s = ... +# 162| 0: [CheckedExpr] checked (...) +# 162| 0: [PropertyCall] access to property Name +# 162| 1: [LocalVariableAccess] access to local variable s +# 163| 1: [LocalVariableDeclStmt] ... ...; +# 163| 0: [LocalVariableDeclAndInitExpr] Int32 t = ... +# 163| 0: [UncheckedExpr] unchecked (...) +# 163| 0: [AddExpr] ... + ... +# 163| 0: [FieldAccess] access to field f +# 163| 1: [IntLiteral] 20 +# 163| 1: [LocalVariableAccess] access to local variable t +# 166| 25: [Method] MainElementAccess +#-----| 2: (Parameters) +# 166| 0: [Parameter] i +# 167| 4: [BlockStmt] {...} +# 168| 0: [LocalVariableDeclStmt] ... ...; +# 168| 0: [LocalVariableDeclAndInitExpr] Object[] os = ... +# 168| 0: [ArrayCreation] array creation of type Object[] +# 168| -1: [ArrayInitializer] { ..., ... } +# 168| 0: [CastExpr] (...) ... +# 168| 0: [ParameterAccess] access to parameter i +# 168| 1: [LocalVariableAccess] access to local variable os +# 171| 26: [Method] MainDelegateAndMethodAccesses +# 172| 4: [BlockStmt] {...} +# 173| 0: [LocalVariableDeclStmt] ... ...; +# 173| 0: [LocalVariableDeclAndInitExpr] D cd1 = ... +# 173| 0: [ExplicitDelegateCreation] delegate creation of type D +# 173| 0: [MethodAccess] access to method M1 +# 173| -1: [TypeAccess] access to type C +# 173| 1: [LocalVariableAccess] access to local variable cd1 +# 174| 1: [LocalVariableDeclStmt] ... ...; +# 174| 0: [LocalVariableDeclAndInitExpr] D cd2 = ... +# 174| 0: [ImplicitDelegateCreation] delegate creation of type D +# 174| 0: [MethodAccess] access to method M2 +# 174| -1: [TypeAccess] access to type C +# 174| 1: [LocalVariableAccess] access to local variable cd2 +# 175| 2: [LocalVariableDeclStmt] ... ...; +# 175| 0: [LocalVariableDeclAndInitExpr] D cd3 = ... +# 175| 0: [OperatorCall] call to operator + +# 175| 0: [LocalVariableAccess] access to local variable cd1 +# 175| 1: [LocalVariableAccess] access to local variable cd2 +# 175| 1: [LocalVariableAccess] access to local variable cd3 +# 176| 3: [LocalVariableDeclStmt] ... ...; +# 176| 0: [LocalVariableDeclAndInitExpr] D cd4 = ... +# 176| 0: [OperatorCall] call to operator + +# 176| 0: [LocalVariableAccess] access to local variable cd3 +# 176| 1: [LocalVariableAccess] access to local variable cd1 +# 176| 1: [LocalVariableAccess] access to local variable cd4 +# 177| 4: [LocalVariableDeclStmt] ... ...; +# 177| 0: [LocalVariableDeclAndInitExpr] D cd5 = ... +# 177| 0: [OperatorCall] call to operator - +# 177| 0: [LocalVariableAccess] access to local variable cd4 +# 177| 1: [LocalVariableAccess] access to local variable cd3 +# 177| 1: [LocalVariableAccess] access to local variable cd5 +# 178| 5: [ExprStmt] ...; +# 178| 0: [AssignAddExpr] ... += ... +# 178| 0: [LocalVariableAccess] access to local variable cd5 +# 178| 1: [LocalVariableAccess] access to local variable cd4 +# 179| 6: [ExprStmt] ...; +# 179| 0: [AssignSubExpr] ... -= ... +# 179| 0: [LocalVariableAccess] access to local variable cd1 +# 179| 1: [LocalVariableAccess] access to local variable cd4 +# 181| 7: [LocalVariableDeclStmt] ... ...; +# 181| 0: [LocalVariableDeclAndInitExpr] C c = ... +# 181| 0: [ObjectCreation] object creation of type C +# 181| 1: [LocalVariableAccess] access to local variable c +# 182| 8: [LocalVariableDeclStmt] ... ...; +# 182| 0: [LocalVariableDeclAndInitExpr] D cd6 = ... +# 182| 0: [ExplicitDelegateCreation] delegate creation of type D +# 182| 0: [MethodAccess] access to method M3 +# 182| -1: [LocalVariableAccess] access to local variable c +# 182| 1: [LocalVariableAccess] access to local variable cd6 +# 183| 9: [LocalVariableDeclStmt] ... ...; +# 183| 0: [LocalVariableDeclAndInitExpr] D cd7 = ... +# 183| 0: [ExplicitDelegateCreation] delegate creation of type D +# 183| 0: [LocalVariableAccess] access to local variable cd6 +# 183| 1: [LocalVariableAccess] access to local variable cd7 +# 185| 10: [ExprStmt] ...; +# 185| 0: [DelegateCall] delegate call +# 185| -1: [LocalVariableAccess] access to local variable cd1 +# 185| 0: [UnaryMinusExpr] -... +# 185| 0: [IntLiteral] 40 +# 186| 11: [LocalVariableDeclStmt] ... ...; +# 186| 0: [LocalVariableDeclAndInitExpr] Int32 x = ... +# 186| 0: [IntLiteral] 0 +# 186| 1: [LocalVariableAccess] access to local variable x +# 187| 12: [ExprStmt] ...; +# 187| 0: [DelegateCall] delegate call +# 187| -1: [LocalVariableAccess] access to local variable cd7 +# 187| 0: [AddExpr] ... + ... +# 187| 0: [IntLiteral] 34 +# 187| 1: [LocalVariableAccess] access to local variable x +# 189| 13: [LocalVariableDeclStmt] ... ...; +# 189| 0: [LocalVariableDeclAndInitExpr] Predicate pi = ... +# 189| 0: [ExplicitDelegateCreation] delegate creation of type Predicate +# 189| 0: [MethodAccess] access to method F +# 189| -1: [TypeAccess] access to type X +# 189| 1: [LocalVariableAccess] access to local variable pi +# 190| 14: [LocalVariableDeclStmt] ... ...; +# 190| 0: [LocalVariableDeclAndInitExpr] Predicate ps = ... +# 190| 0: [ImplicitDelegateCreation] delegate creation of type Predicate +# 190| 0: [MethodAccess] access to method G +# 190| -1: [TypeAccess] access to type X +# 190| 1: [LocalVariableAccess] access to local variable ps +# 192| 15: [LocalVariableDeclStmt] ... ...; +# 192| 0: [LocalVariableDeclAndInitExpr] Boolean b = ... +# 192| 0: [BitwiseAndExpr] ... & ... +# 192| 0: [DelegateCall] delegate call +# 192| -1: [LocalVariableAccess] access to local variable pi +# 192| 0: [IntLiteral] 3 +# 192| 1: [DelegateCall] delegate call +# 192| -1: [LocalVariableAccess] access to local variable ps +# 192| 0: [StringLiteral] "" +# 192| 1: [LocalVariableAccess] access to local variable b +# 194| 16: [LocalVariableDeclStmt] ... ...; +# 194| 0: [LocalVariableDeclExpr] ContextCallback d +# 196| 17: [LocalFunctionStmt] LocalFunction(...) +# 196| 0: [LocalFunction] LocalFunction +#-----| 2: (Parameters) +# 196| 0: [Parameter] i +# 196| 4: [BlockStmt] {...} +# 196| 18: [EmptyStmt] ; +# 197| 19: [ExprStmt] ...; +# 197| 0: [AssignExpr] ... = ... +# 197| 0: [ExplicitDelegateCreation] delegate creation of type D +# 197| 0: [LocalFunctionAccess] access to local function LocalFunction +# 197| 1: [LocalVariableAccess] access to local variable cd1 +# 198| 20: [ExprStmt] ...; +# 198| 0: [AssignExpr] ... = ... +# 198| 0: [ImplicitDelegateCreation] delegate creation of type D +# 198| 0: [LocalFunctionAccess] access to local function LocalFunction +# 198| 1: [LocalVariableAccess] access to local variable cd1 +# 202| 2: [DelegateType] Predicate<> +#-----| 1: (Type parameters) +# 202| 0: [TypeParameter] T +#-----| 2: (Parameters) +# 202| 0: [Parameter] value +# 204| 3: [DelegateType] D +#-----| 2: (Parameters) +# 204| 0: [Parameter] x +# 206| 4: [Class] C +# 209| 5: [Method] M1 +#-----| 2: (Parameters) +# 209| 0: [Parameter] i +# 209| 4: [BlockStmt] {...} +# 210| 6: [Method] M2 +#-----| 2: (Parameters) +# 210| 0: [Parameter] i +# 210| 4: [BlockStmt] {...} +# 211| 7: [Method] M3 +#-----| 2: (Parameters) +# 211| 0: [Parameter] i +# 211| 4: [BlockStmt] {...} +# 215| 5: [Class] X +# 218| 5: [Method] F +#-----| 2: (Parameters) +# 218| 0: [Parameter] i +# 218| 4: [BlockStmt] {...} +# 218| 0: [ReturnStmt] return ...; +# 218| 0: [LTExpr] ... < ... +# 218| 0: [ParameterAccess] access to parameter i +# 218| 1: [IntLiteral] 2 +# 220| 6: [Method] G +#-----| 2: (Parameters) +# 220| 0: [Parameter] s +# 220| 4: [BlockStmt] {...} +# 220| 0: [ReturnStmt] return ...; +# 220| 0: [BoolLiteral] false +# 224| 6: [DelegateType] EventHandler +#-----| 2: (Parameters) +# 224| 0: [Parameter] sender +# 224| 1: [Parameter] e +# 226| 7: [Class] Button +# 229| 5: [Event] Click +# 229| 3: [AddEventAccessor] add_Click +#-----| 2: (Parameters) +# 229| 0: [Parameter] value +# 229| 4: [RemoveEventAccessor] remove_Click +#-----| 2: (Parameters) +# 229| 0: [Parameter] value +# 231| 6: [Method] OnClick +#-----| 2: (Parameters) +# 231| 0: [Parameter] e +# 232| 4: [BlockStmt] {...} +# 233| 0: [IfStmt] if (...) ... +# 233| 0: [OperatorCall] call to operator != +# 233| 0: [EventAccess,EventCall] access to event Click +# 233| 1: [NullLiteral] null +# 234| 1: [ExprStmt] ...; +# 234| 0: [DelegateCall] delegate call +# 234| -1: [EventAccess,EventCall] access to event Click +# 234| 0: [ThisAccess] this access +# 234| 1: [ParameterAccess] access to parameter e +# 237| 7: [Method] Reset +# 238| 4: [BlockStmt] {...} +# 239| 0: [ExprStmt] ...; +# 239| 0: [AssignExpr] ... = ... +# 239| 0: [NullLiteral] null +# 239| 1: [EventAccess,EventCall] access to event Click +# 243| 8: [Class] LoginDialog +# 246| 4: [Field] OkButton +# 247| 5: [Field] CancelButton +# 249| 6: [InstanceConstructor] LoginDialog +# 250| 4: [BlockStmt] {...} +# 251| 0: [ExprStmt] ...; +# 251| 0: [AssignExpr] ... = ... +# 251| 0: [ObjectCreation] object creation of type Button +# 251| 1: [FieldAccess] access to field OkButton +# 252| 1: [ExprStmt] ...; +# 252| 0: [AddEventExpr] ... += ... +# 252| 0: [ExplicitDelegateCreation] delegate creation of type EventHandler +# 252| 0: [MethodAccess] access to method OkButtonClick +# 252| 1: [EventAccess,EventCall] access to event Click +# 252| -1: [FieldAccess] access to field OkButton +# 253| 2: [ExprStmt] ...; +# 253| 0: [AssignExpr] ... = ... +# 253| 0: [ObjectCreation] object creation of type Button +# 253| 1: [FieldAccess] access to field CancelButton +# 254| 3: [ExprStmt] ...; +# 254| 0: [RemoveEventExpr] ... -= ... +# 254| 0: [ExplicitDelegateCreation] delegate creation of type EventHandler +# 254| 0: [MethodAccess] access to method CancelButtonClick +# 254| 1: [EventAccess,EventCall] access to event Click +# 254| -1: [FieldAccess] access to field CancelButton +# 257| 7: [Method] OkButtonClick +#-----| 2: (Parameters) +# 257| 0: [Parameter] sender +# 257| 1: [Parameter] e +# 258| 4: [BlockStmt] {...} +# 261| 8: [Method] CancelButtonClick +#-----| 2: (Parameters) +# 261| 0: [Parameter] sender +# 261| 1: [Parameter] e +# 262| 4: [BlockStmt] {...} +# 267| 9: [Class] IntVector +# 270| 4: [InstanceConstructor] IntVector +#-----| 2: (Parameters) +# 270| 0: [Parameter] length +# 270| 4: [BlockStmt] {...} +# 272| 5: [Property] Length +# 272| 3: [Getter] get_Length +# 272| 4: [BlockStmt] {...} +# 272| 0: [ReturnStmt] return ...; +# 272| 0: [IntLiteral] 4 +# 274| 6: [Indexer] Item +#-----| 1: (Parameters) +# 274| 0: [Parameter] index +# 274| 3: [Getter] get_Item +#-----| 2: (Parameters) +# 274| 0: [Parameter] index +# 274| 4: [BlockStmt] {...} +# 274| 0: [ReturnStmt] return ...; +# 274| 0: [IntLiteral] 0 +# 274| 4: [Setter] set_Item +#-----| 2: (Parameters) +# 274| 0: [Parameter] index +# 274| 1: [Parameter] value +# 274| 4: [BlockStmt] {...} +# 276| 7: [IncrementOperator] ++ +#-----| 2: (Parameters) +# 276| 0: [Parameter] iv +# 277| 4: [BlockStmt] {...} +# 278| 0: [LocalVariableDeclStmt] ... ...; +# 278| 0: [LocalVariableDeclAndInitExpr] IntVector temp = ... +# 278| 0: [ObjectCreation] object creation of type IntVector +# 278| 0: [PropertyCall] access to property Length +# 278| -1: [ParameterAccess] access to parameter iv +# 278| 1: [LocalVariableAccess] access to local variable temp +# 279| 1: [ForStmt] for (...;...;...) ... +# 279| -1: [LocalVariableDeclAndInitExpr] Int32 i = ... +# 279| 0: [IntLiteral] 0 +# 279| 1: [LocalVariableAccess] access to local variable i +# 279| 0: [LTExpr] ... < ... +# 279| 0: [LocalVariableAccess] access to local variable i +# 279| 1: [PropertyCall] access to property Length +# 279| -1: [ParameterAccess] access to parameter iv +# 279| 1: [PostIncrExpr] ...++ +# 279| 0: [LocalVariableAccess] access to local variable i +# 280| 2: [ExprStmt] ...; +# 280| 0: [AssignExpr] ... = ... +# 280| 0: [AddExpr] ... + ... +# 280| 0: [IndexerCall] access to indexer +# 280| -1: [ParameterAccess] access to parameter iv +# 280| 0: [LocalVariableAccess] access to local variable i +# 280| 1: [IntLiteral] 1 +# 280| 1: [IndexerCall] access to indexer +# 280| -1: [LocalVariableAccess] access to local variable temp +# 280| 0: [LocalVariableAccess] access to local variable i +# 281| 2: [ReturnStmt] return ...; +# 281| 0: [LocalVariableAccess] access to local variable temp +# 284| 8: [AddOperator] + +#-----| 2: (Parameters) +# 284| 0: [Parameter] iv1 +# 284| 1: [Parameter] iv2 +# 285| 4: [BlockStmt] {...} +# 286| 0: [ReturnStmt] return ...; +# 286| 0: [ParameterAccess] access to parameter iv1 +# 291| 10: [Class] TestUnaryOperator +# 294| 5: [Method] MainUnaryOperator +# 295| 4: [BlockStmt] {...} +# 296| 0: [LocalVariableDeclStmt] ... ...; +# 296| 0: [LocalVariableDeclAndInitExpr] IntVector iv1 = ... +# 296| 0: [ObjectCreation] object creation of type IntVector +# 296| 0: [IntLiteral] 4 +# 296| 1: [LocalVariableAccess] access to local variable iv1 +# 297| 1: [LocalVariableDeclStmt] ... ...; +# 297| 0: [LocalVariableDeclExpr] IntVector iv2 +# 298| 2: [ExprStmt] ...; +# 298| 0: [AssignExpr] ... = ... +# 298| 0: [OperatorCall] call to operator ++ +# 298| 0: [LocalVariableAccess] access to local variable iv1 +# 298| 1: [LocalVariableAccess] access to local variable iv2 +# 299| 3: [ExprStmt] ...; +# 299| 0: [AssignExpr] ... = ... +# 299| 0: [OperatorCall] call to operator ++ +# 299| 0: [LocalVariableAccess] access to local variable iv1 +# 299| 1: [LocalVariableAccess] access to local variable iv2 +# 300| 4: [LocalVariableDeclStmt] ... ...; +# 300| 0: [LocalVariableDeclAndInitExpr] IntVector iv3 = ... +# 300| 0: [OperatorCall] call to operator + +# 300| 0: [LocalVariableAccess] access to local variable iv1 +# 300| 1: [LocalVariableAccess] access to local variable iv2 +# 300| 1: [LocalVariableAccess] access to local variable iv3 +# 305| 11: [Struct] Digit +# 308| 5: [Field] value +# 310| 6: [InstanceConstructor] Digit +#-----| 2: (Parameters) +# 310| 0: [Parameter] value +# 311| 4: [BlockStmt] {...} +# 312| 0: [IfStmt] if (...) ... +# 312| 0: [LogicalOrExpr] ... || ... +# 312| 0: [LTExpr] ... < ... +# 312| 0: [CastExpr] (...) ... +# 312| 0: [ParameterAccess] access to parameter value +# 312| 1: [IntLiteral] 0 +# 312| 1: [GTExpr] ... > ... +# 312| 0: [CastExpr] (...) ... +# 312| 0: [ParameterAccess] access to parameter value +# 312| 1: [IntLiteral] 9 +# 313| 1: [ThrowStmt] throw ...; +# 313| 0: [ObjectCreation] object creation of type ArgumentException +# 314| 1: [ExprStmt] ...; +# 314| 0: [AssignExpr] ... = ... +# 314| 0: [ParameterAccess] access to parameter value +# 314| 1: [FieldAccess] access to field value +# 314| -1: [ThisAccess] this access +# 317| 7: [ImplicitConversionOperator] implicit conversion +#-----| 2: (Parameters) +# 317| 0: [Parameter] d +# 318| 4: [BlockStmt] {...} +# 319| 0: [ReturnStmt] return ...; +# 319| 0: [FieldAccess] access to field value +# 319| -1: [ParameterAccess] access to parameter d +# 322| 8: [ExplicitConversionOperator] explicit conversion +#-----| 2: (Parameters) +# 322| 0: [Parameter] b +# 323| 4: [BlockStmt] {...} +# 324| 0: [ReturnStmt] return ...; +# 324| 0: [ObjectCreation] object creation of type Digit +# 324| 0: [ParameterAccess] access to parameter b +# 329| 12: [Class] TestConversionOperator +# 332| 5: [Method] MainConversionOperator +# 333| 4: [BlockStmt] {...} +# 334| 0: [LocalVariableDeclStmt] ... ...; +# 334| 0: [LocalVariableDeclAndInitExpr] Digit d = ... +# 334| 0: [OperatorCall] call to operator explicit conversion +# 334| 0: [CastExpr] (...) ... +# 334| 0: [IntLiteral] 8 +# 334| 1: [LocalVariableAccess] access to local variable d +# 335| 1: [LocalVariableDeclStmt] ... ...; +# 335| 0: [LocalVariableDeclAndInitExpr] Byte b = ... +# 335| 0: [OperatorCall] call to operator implicit conversion +# 335| 0: [LocalVariableAccess] access to local variable d +# 335| 1: [LocalVariableAccess] access to local variable b +# 340| 13: [Class] Point +# 343| 5: [Field] x +# 343| 6: [Field] y +# 345| 7: [Property] X +# 345| 3: [Getter] get_X +# 345| 4: [BlockStmt] {...} +# 345| 0: [ReturnStmt] return ...; +# 345| 0: [FieldAccess] access to field x +# 345| 4: [Setter] set_X +#-----| 2: (Parameters) +# 345| 0: [Parameter] value +# 345| 4: [BlockStmt] {...} +# 345| 0: [ExprStmt] ...; +# 345| 0: [AssignExpr] ... = ... +# 345| 0: [ParameterAccess] access to parameter value +# 345| 1: [FieldAccess] access to field x +# 346| 8: [Property] Y +# 346| 3: [Getter] get_Y +# 346| 4: [BlockStmt] {...} +# 346| 0: [ReturnStmt] return ...; +# 346| 0: [FieldAccess] access to field y +# 346| 4: [Setter] set_Y +#-----| 2: (Parameters) +# 346| 0: [Parameter] value +# 346| 4: [BlockStmt] {...} +# 346| 0: [ExprStmt] ...; +# 346| 0: [AssignExpr] ... = ... +# 346| 0: [ParameterAccess] access to parameter value +# 346| 1: [FieldAccess] access to field y +# 350| 14: [Class] Rectangle +# 353| 5: [Field] p1 +# 353| 6: [Field] p2 +# 355| 7: [Property] P1 +# 355| 3: [Getter] get_P1 +# 355| 4: [BlockStmt] {...} +# 355| 0: [ReturnStmt] return ...; +# 355| 0: [FieldAccess] access to field p1 +# 355| 4: [Setter] set_P1 +#-----| 2: (Parameters) +# 355| 0: [Parameter] value +# 355| 4: [BlockStmt] {...} +# 355| 0: [ExprStmt] ...; +# 355| 0: [AssignExpr] ... = ... +# 355| 0: [ParameterAccess] access to parameter value +# 355| 1: [FieldAccess] access to field p1 +# 356| 8: [Property] P2 +# 356| 3: [Getter] get_P2 +# 356| 4: [BlockStmt] {...} +# 356| 0: [ReturnStmt] return ...; +# 356| 0: [FieldAccess] access to field p2 +# 356| 4: [Setter] set_P2 +#-----| 2: (Parameters) +# 356| 0: [Parameter] value +# 356| 4: [BlockStmt] {...} +# 356| 0: [ExprStmt] ...; +# 356| 0: [AssignExpr] ... = ... +# 356| 0: [ParameterAccess] access to parameter value +# 356| 1: [FieldAccess] access to field p2 +# 360| 15: [Class] Rectangle2 +# 363| 5: [Field] p1 +# 363| 1: [AssignExpr] ... = ... +# 363| 0: [ObjectCreation] object creation of type Point +# 363| 1: [FieldAccess] access to field p1 +# 364| 6: [Field] p2 +# 364| 1: [AssignExpr] ... = ... +# 364| 0: [ObjectCreation] object creation of type Point +# 364| 1: [FieldAccess] access to field p2 +# 366| 7: [Property] P1 +# 366| 3: [Getter] get_P1 +# 366| 4: [BlockStmt] {...} +# 366| 0: [ReturnStmt] return ...; +# 366| 0: [FieldAccess] access to field p1 +# 367| 8: [Property] P2 +# 367| 3: [Getter] get_P2 +# 367| 4: [BlockStmt] {...} +# 367| 0: [ReturnStmt] return ...; +# 367| 0: [FieldAccess] access to field p2 +# 371| 16: [Class] Contact +# 374| 5: [Field] name +# 375| 6: [Field] phoneNumbers +# 375| 1: [AssignExpr] ... = ... +# 375| 0: [ObjectCreation] object creation of type List +# 375| 1: [FieldAccess] access to field phoneNumbers +# 377| 7: [IndexerProperty] Name +# 377| 3: [Getter] get_Name +# 377| 4: [BlockStmt] {...} +# 377| 0: [ReturnStmt] return ...; +# 377| 0: [FieldAccess] access to field name +# 377| 4: [Setter] set_Name +#-----| 2: (Parameters) +# 377| 0: [Parameter] value +# 377| 4: [BlockStmt] {...} +# 377| 0: [ExprStmt] ...; +# 377| 0: [AssignExpr] ... = ... +# 377| 0: [ParameterAccess] access to parameter value +# 377| 1: [FieldAccess] access to field name +# 378| 8: [IndexerProperty] PhoneNumbers +# 378| 3: [Getter] get_PhoneNumbers +# 378| 4: [BlockStmt] {...} +# 378| 0: [ReturnStmt] return ...; +# 378| 0: [FieldAccess] access to field phoneNumbers +# 382| 17: [Class] TestCreations +# 385| 5: [Method] MainCreations +# 386| 4: [BlockStmt] {...} +# 387| 0: [LocalVariableDeclStmt] ... ...; +# 387| 0: [LocalVariableDeclAndInitExpr] Point a = ... +# 387| 0: [ObjectCreation] object creation of type Point +# 387| -1: [ObjectInitializer] { ..., ... } +# 387| 0: [MemberInitializer] ... = ... +# 387| 0: [IntLiteral] 0 +# 387| 1: [PropertyCall] access to property X +# 387| 1: [MemberInitializer] ... = ... +# 387| 0: [IntLiteral] 1 +# 387| 1: [PropertyCall] access to property Y +# 387| 1: [LocalVariableAccess] access to local variable a +# 388| 1: [LocalVariableDeclStmt] ... ...; +# 388| 0: [LocalVariableDeclAndInitExpr] Rectangle r = ... +# 388| 0: [ObjectCreation] object creation of type Rectangle +# 389| -1: [ObjectInitializer] { ..., ... } +# 390| 0: [MemberInitializer] ... = ... +# 390| 0: [ObjectCreation] object creation of type Point +# 390| -1: [ObjectInitializer] { ..., ... } +# 390| 0: [MemberInitializer] ... = ... +# 390| 0: [IntLiteral] 0 +# 390| 1: [PropertyCall] access to property X +# 390| 1: [MemberInitializer] ... = ... +# 390| 0: [IntLiteral] 1 +# 390| 1: [PropertyCall] access to property Y +# 390| 1: [PropertyCall] access to property P1 +# 391| 1: [MemberInitializer] ... = ... +# 391| 0: [ObjectCreation] object creation of type Point +# 391| -1: [ObjectInitializer] { ..., ... } +# 391| 0: [MemberInitializer] ... = ... +# 391| 0: [IntLiteral] 2 +# 391| 1: [PropertyCall] access to property X +# 391| 1: [MemberInitializer] ... = ... +# 391| 0: [IntLiteral] 3 +# 391| 1: [PropertyCall] access to property Y +# 391| 1: [PropertyCall] access to property P2 +# 388| 1: [LocalVariableAccess] access to local variable r +# 393| 2: [LocalVariableDeclStmt] ... ...; +# 393| 0: [LocalVariableDeclAndInitExpr] Rectangle2 r2 = ... +# 393| 0: [ObjectCreation] object creation of type Rectangle2 +# 394| -1: [ObjectInitializer] { ..., ... } +# 395| 0: [MemberInitializer] ... = ... +# 395| 0: [ObjectInitializer] { ..., ... } +# 395| 0: [MemberInitializer] ... = ... +# 395| 0: [IntLiteral] 0 +# 395| 1: [PropertyCall] access to property X +# 395| 1: [MemberInitializer] ... = ... +# 395| 0: [IntLiteral] 1 +# 395| 1: [PropertyCall] access to property Y +# 395| 1: [PropertyCall] access to property P1 +# 396| 1: [MemberInitializer] ... = ... +# 396| 0: [ObjectInitializer] { ..., ... } +# 396| 0: [MemberInitializer] ... = ... +# 396| 0: [IntLiteral] 2 +# 396| 1: [PropertyCall] access to property X +# 396| 1: [MemberInitializer] ... = ... +# 396| 0: [IntLiteral] 3 +# 396| 1: [PropertyCall] access to property Y +# 396| 1: [PropertyCall] access to property P2 +# 393| 1: [LocalVariableAccess] access to local variable r2 +# 398| 3: [LocalVariableDeclStmt] ... ...; +# 398| 0: [LocalVariableDeclAndInitExpr] List digits = ... +# 398| 0: [ObjectCreation] object creation of type List +# 398| -1: [CollectionInitializer] { ..., ... } +# 398| 0: [ElementInitializer] call to method Add +# 398| 0: [IntLiteral] 0 +# 398| 1: [ElementInitializer] call to method Add +# 398| 0: [IntLiteral] 1 +# 398| 2: [ElementInitializer] call to method Add +# 398| 0: [IntLiteral] 2 +# 398| 3: [ElementInitializer] call to method Add +# 398| 0: [IntLiteral] 3 +# 398| 4: [ElementInitializer] call to method Add +# 398| 0: [IntLiteral] 4 +# 398| 5: [ElementInitializer] call to method Add +# 398| 0: [IntLiteral] 5 +# 398| 6: [ElementInitializer] call to method Add +# 398| 0: [IntLiteral] 6 +# 398| 7: [ElementInitializer] call to method Add +# 398| 0: [IntLiteral] 7 +# 398| 8: [ElementInitializer] call to method Add +# 398| 0: [IntLiteral] 8 +# 398| 9: [ElementInitializer] call to method Add +# 398| 0: [IntLiteral] 9 +# 398| 1: [LocalVariableAccess] access to local variable digits +# 399| 4: [LocalVariableDeclStmt] ... ...; +# 399| 0: [LocalVariableDeclAndInitExpr] List contacts = ... +# 399| 0: [ObjectCreation] object creation of type List +# 399| -1: [CollectionInitializer] { ..., ... } +# 400| 0: [ElementInitializer] call to method Add +# 400| 0: [ObjectCreation] object creation of type Contact +# 400| -1: [ObjectInitializer] { ..., ... } +# 401| 0: [MemberInitializer] ... = ... +# 401| 0: [StringLiteral] "Chris Smith" +# 401| 1: [PropertyCall] access to property Name +# 402| 1: [MemberInitializer] ... = ... +# 402| 0: [CollectionInitializer] { ..., ... } +# 402| 0: [ElementInitializer] call to method Add +# 402| 0: [StringLiteral] "206-555-0101" +# 402| 1: [ElementInitializer] call to method Add +# 402| 0: [StringLiteral] "425-882-8080" +# 402| 1: [PropertyCall] access to property PhoneNumbers +# 404| 1: [ElementInitializer] call to method Add +# 404| 0: [ObjectCreation] object creation of type Contact +# 404| -1: [ObjectInitializer] { ..., ... } +# 405| 0: [MemberInitializer] ... = ... +# 405| 0: [StringLiteral] "Bob Harris" +# 405| 1: [PropertyCall] access to property Name +# 406| 1: [MemberInitializer] ... = ... +# 406| 0: [CollectionInitializer] { ..., ... } +# 406| 0: [ElementInitializer] call to method Add +# 406| 0: [StringLiteral] "650-555-0199" +# 406| 1: [PropertyCall] access to property PhoneNumbers +# 399| 1: [LocalVariableAccess] access to local variable contacts +# 409| 5: [LocalVariableDeclStmt] ... ...; +# 409| 0: [LocalVariableDeclAndInitExpr] Int32[,] is1 = ... +# 409| 0: [ArrayCreation] array creation of type Int32[,] +# 409| -1: [ArrayInitializer] { ..., ... } +# 409| 0: [ArrayInitializer] { ..., ... } +# 409| 0: [IntLiteral] 0 +# 409| 1: [IntLiteral] 1 +# 409| 1: [ArrayInitializer] { ..., ... } +# 409| 0: [IntLiteral] 2 +# 409| 1: [IntLiteral] 3 +# 409| 2: [ArrayInitializer] { ..., ... } +# 409| 0: [IntLiteral] 4 +# 409| 1: [IntLiteral] 5 +# 409| 1: [LocalVariableAccess] access to local variable is1 +# 410| 6: [LocalVariableDeclStmt] ... ...; +# 410| 0: [LocalVariableDeclAndInitExpr] Int32[,] is2 = ... +# 410| 0: [ArrayCreation] array creation of type Int32[,] +# 410| -1: [ArrayInitializer] { ..., ... } +# 410| 0: [ArrayInitializer] { ..., ... } +# 410| 0: [IntLiteral] 0 +# 410| 1: [IntLiteral] 1 +# 410| 1: [ArrayInitializer] { ..., ... } +# 410| 0: [IntLiteral] 2 +# 410| 1: [IntLiteral] 3 +# 410| 2: [ArrayInitializer] { ..., ... } +# 410| 0: [IntLiteral] 4 +# 410| 1: [IntLiteral] 5 +# 410| 0: [IntLiteral] 3 +# 410| 1: [IntLiteral] 2 +# 410| 1: [LocalVariableAccess] access to local variable is2 +# 411| 7: [LocalVariableDeclStmt] ... ...; +# 411| 0: [LocalVariableDeclAndInitExpr] Int32[][] is3 = ... +# 411| 0: [ArrayCreation] array creation of type Int32[][] +# 411| 0: [IntLiteral] 100 +# 411| 1: [LocalVariableAccess] access to local variable is3 +# 412| 8: [LocalVariableDeclStmt] ... ...; +# 412| 0: [LocalVariableDeclAndInitExpr] Int32[,] is4 = ... +# 412| 0: [ArrayCreation] array creation of type Int32[,] +# 412| 0: [IntLiteral] 100 +# 412| 1: [IntLiteral] 5 +# 412| 1: [LocalVariableAccess] access to local variable is4 +# 413| 9: [LocalVariableDeclStmt] ... ...; +# 413| 0: [LocalVariableDeclAndInitExpr] Int32[] is5 = ... +# 413| 0: [ArrayCreation] array creation of type Int32[] +# 413| -1: [ArrayInitializer] { ..., ... } +# 413| 0: [IntLiteral] 1 +# 413| 1: [IntLiteral] 10 +# 413| 2: [IntLiteral] 100 +# 413| 3: [IntLiteral] 1000 +# 413| 1: [LocalVariableAccess] access to local variable is5 +# 414| 10: [LocalVariableDeclStmt] ... ...; +# 414| 0: [LocalVariableDeclAndInitExpr] Double[] is6 = ... +# 414| 0: [ArrayCreation] array creation of type Double[] +# 414| -1: [ArrayInitializer] { ..., ... } +# 414| 0: [CastExpr] (...) ... +# 414| 0: [IntLiteral] 1 +# 414| 1: [DoubleLiteral] 1.5 +# 414| 2: [CastExpr] (...) ... +# 414| 0: [IntLiteral] 2 +# 414| 3: [DoubleLiteral] 2.5 +# 414| 1: [LocalVariableAccess] access to local variable is6 +# 415| 11: [LocalVariableDeclStmt] ... ...; +# 415| 0: [LocalVariableDeclAndInitExpr] String[,] is7 = ... +# 415| 0: [ArrayCreation] array creation of type String[,] +# 415| -1: [ArrayInitializer] { ..., ... } +# 415| 0: [ArrayInitializer] { ..., ... } +# 415| 0: [StringLiteral] "hello" +# 415| 1: [NullLiteral] null +# 415| 1: [ArrayInitializer] { ..., ... } +# 415| 0: [StringLiteral] "world" +# 415| 1: [StringLiteral] "!" +# 415| 1: [LocalVariableAccess] access to local variable is7 +# 416| 12: [LocalVariableDeclStmt] ... ...; +# 416| 0: [LocalVariableDeclAndInitExpr] <>__AnonType0[] contacts2 = ... +# 416| 0: [ArrayCreation] array creation of type <>__AnonType0[] +# 416| -1: [ArrayInitializer] { ..., ... } +# 417| 0: [AnonymousObjectCreation] object creation of type <>__AnonType0 +# 417| -1: [ObjectInitializer] { ..., ... } +# 418| 0: [MemberInitializer] ... = ... +# 418| 0: [StringLiteral] "Chris Smith" +# 418| 1: [PropertyCall] access to property Name +# 419| 1: [MemberInitializer] ... = ... +# 419| 0: [ArrayCreation] array creation of type String[] +# 419| -1: [ArrayInitializer] { ..., ... } +# 419| 0: [StringLiteral] "206-555-0101" +# 419| 1: [StringLiteral] "425-882-8080" +# 419| 1: [PropertyCall] access to property PhoneNumbers +# 421| 1: [AnonymousObjectCreation] object creation of type <>__AnonType0 +# 421| -1: [ObjectInitializer] { ..., ... } +# 422| 0: [MemberInitializer] ... = ... +# 422| 0: [StringLiteral] "Bob Harris" +# 422| 1: [PropertyCall] access to property Name +# 423| 1: [MemberInitializer] ... = ... +# 423| 0: [ArrayCreation] array creation of type String[] +# 423| -1: [ArrayInitializer] { ..., ... } +# 423| 0: [StringLiteral] "650-555-0199" +# 423| 1: [PropertyCall] access to property PhoneNumbers +# 416| 1: [LocalVariableAccess] access to local variable contacts2 +# 426| 13: [LocalVariableDeclStmt] ... ...; +# 426| 0: [LocalVariableDeclAndInitExpr] Int32 i = ... +# 426| 0: [IntLiteral] 1 +# 426| 1: [LocalVariableAccess] access to local variable i +# 427| 14: [LocalVariableDeclStmt] ... ...; +# 427| 0: [LocalVariableDeclAndInitExpr] List list1 = ... +# 427| 0: [ObjectCreation] object creation of type List +# 427| -1: [CollectionInitializer] { ..., ... } +# 427| 0: [ElementInitializer] call to method Add +# 427| 0: [AssignExpr] ... = ... +# 427| 0: [IntLiteral] 2 +# 427| 1: [LocalVariableAccess] access to local variable i +# 427| 1: [LocalVariableAccess] access to local variable list1 +# 428| 15: [LocalVariableDeclStmt] ... ...; +# 428| 0: [LocalVariableDeclAndInitExpr] List list2 = ... +# 428| 0: [ObjectCreation] object creation of type List +# 428| -1: [CollectionInitializer] { ..., ... } +# 428| 0: [ElementInitializer] call to method Add +# 428| 0: [AnonymousObjectCreation] object creation of type <>__AnonType1 +# 428| -1: [ObjectInitializer] { ..., ... } +# 428| 0: [MemberInitializer] ... = ... +# 428| 0: [IntLiteral] 2 +# 428| 1: [PropertyCall] access to property i +# 428| 1: [LocalVariableAccess] access to local variable list2 +# 429| 16: [LocalVariableDeclStmt] ... ...; +# 429| 0: [LocalVariableDeclAndInitExpr] List list3 = ... +# 429| 0: [ObjectCreation] object creation of type List +# 429| -1: [CollectionInitializer] { ..., ... } +# 429| 0: [ElementInitializer] call to method Add +# 429| 0: [EQExpr] ... == ... +# 429| 0: [LocalVariableAccess] access to local variable i +# 429| 1: [IntLiteral] 2 +# 429| 1: [LocalVariableAccess] access to local variable list3 +# 432| 6: [DelegateType] S +#-----| 2: (Parameters) +# 432| 0: [Parameter] x +# 432| 1: [Parameter] y +# 433| 7: [DelegateType] Unit +# 435| 8: [Method] MultiDimensionalArrayCreations +# 436| 4: [BlockStmt] {...} +# 437| 0: [LocalVariableDeclStmt] ... ...; +# 437| 0: [LocalVariableDeclAndInitExpr] Object o = ... +# 437| 0: [ArrayCreation] array creation of type Int32[,] +# 437| -1: [ArrayInitializer] { ..., ... } +# 437| 0: [ArrayInitializer] { ..., ... } +# 437| 0: [IntLiteral] 1 +# 437| 1: [IntLiteral] 2 +# 437| 1: [ArrayInitializer] { ..., ... } +# 437| 0: [IntLiteral] 3 +# 437| 1: [IntLiteral] 4 +# 437| 2: [ArrayInitializer] { ..., ... } +# 437| 0: [IntLiteral] 5 +# 437| 1: [IntLiteral] 6 +# 437| 1: [LocalVariableAccess] access to local variable o +# 438| 1: [ExprStmt] ...; +# 438| 0: [AssignExpr] ... = ... +# 438| 0: [ArrayCreation] array creation of type Int32[,,] +# 438| -1: [ArrayInitializer] { ..., ... } +# 438| 0: [ArrayInitializer] { ..., ... } +# 438| 0: [ArrayInitializer] { ..., ... } +# 438| 0: [IntLiteral] 1 +# 438| 1: [IntLiteral] 2 +# 438| 2: [IntLiteral] 3 +# 438| 1: [ArrayInitializer] { ..., ... } +# 438| 0: [IntLiteral] 4 +# 438| 1: [IntLiteral] 5 +# 438| 2: [IntLiteral] 6 +# 438| 1: [ArrayInitializer] { ..., ... } +# 438| 0: [ArrayInitializer] { ..., ... } +# 438| 0: [IntLiteral] 7 +# 438| 1: [IntLiteral] 8 +# 438| 2: [IntLiteral] 9 +# 438| 1: [ArrayInitializer] { ..., ... } +# 438| 0: [IntLiteral] 10 +# 438| 1: [IntLiteral] 11 +# 438| 2: [IntLiteral] 12 +# 438| 1: [LocalVariableAccess] access to local variable o +# 439| 2: [ExprStmt] ...; +# 439| 0: [AssignExpr] ... = ... +# 439| 0: [ArrayCreation] array creation of type Int32[,][,] +# 440| -1: [ArrayInitializer] { ..., ... } +# 441| 0: [ArrayInitializer] { ..., ... } +# 441| 0: [ArrayCreation] array creation of type Int32[,] +# 441| -1: [ArrayInitializer] { ..., ... } +# 441| 0: [ArrayInitializer] { ..., ... } +# 441| 0: [IntLiteral] 1 +# 441| 1: [IntLiteral] 3 +# 441| 1: [ArrayInitializer] { ..., ... } +# 441| 0: [IntLiteral] 5 +# 441| 1: [IntLiteral] 7 +# 441| 1: [ArrayCreation] array creation of type Int32[,] +# 441| -1: [ArrayInitializer] { ..., ... } +# 441| 0: [ArrayInitializer] { ..., ... } +# 441| 0: [IntLiteral] 0 +# 441| 1: [IntLiteral] 2 +# 441| 1: [ArrayInitializer] { ..., ... } +# 441| 0: [IntLiteral] 4 +# 441| 1: [IntLiteral] 6 +# 441| 2: [ArrayInitializer] { ..., ... } +# 441| 0: [IntLiteral] 8 +# 441| 1: [IntLiteral] 10 +# 441| 2: [ArrayCreation] array creation of type Int32[,] +# 441| -1: [ArrayInitializer] { ..., ... } +# 441| 0: [ArrayInitializer] { ..., ... } +# 441| 0: [IntLiteral] 11 +# 441| 1: [IntLiteral] 22 +# 441| 1: [ArrayInitializer] { ..., ... } +# 441| 0: [IntLiteral] 99 +# 441| 1: [IntLiteral] 88 +# 441| 2: [ArrayInitializer] { ..., ... } +# 441| 0: [IntLiteral] 0 +# 441| 1: [IntLiteral] 9 +# 442| 1: [ArrayInitializer] { ..., ... } +# 442| 0: [ArrayCreation] array creation of type Int32[,] +# 442| -1: [ArrayInitializer] { ..., ... } +# 442| 0: [ArrayInitializer] { ..., ... } +# 442| 0: [IntLiteral] 1 +# 442| 1: [IntLiteral] 3 +# 442| 1: [ArrayInitializer] { ..., ... } +# 442| 0: [IntLiteral] 5 +# 442| 1: [IntLiteral] 7 +# 442| 1: [ArrayCreation] array creation of type Int32[,] +# 442| -1: [ArrayInitializer] { ..., ... } +# 442| 0: [ArrayInitializer] { ..., ... } +# 442| 0: [IntLiteral] 0 +# 442| 1: [IntLiteral] 2 +# 442| 1: [ArrayInitializer] { ..., ... } +# 442| 0: [IntLiteral] 4 +# 442| 1: [IntLiteral] 6 +# 442| 2: [ArrayInitializer] { ..., ... } +# 442| 0: [IntLiteral] 8 +# 442| 1: [IntLiteral] 10 +# 442| 2: [ArrayCreation] array creation of type Int32[,] +# 442| -1: [ArrayInitializer] { ..., ... } +# 442| 0: [ArrayInitializer] { ..., ... } +# 442| 0: [IntLiteral] 11 +# 442| 1: [IntLiteral] 22 +# 442| 1: [ArrayInitializer] { ..., ... } +# 442| 0: [IntLiteral] 99 +# 442| 1: [IntLiteral] 88 +# 442| 2: [ArrayInitializer] { ..., ... } +# 442| 0: [IntLiteral] 0 +# 442| 1: [IntLiteral] 9 +# 439| 1: [LocalVariableAccess] access to local variable o +# 444| 3: [ExprStmt] ...; +# 444| 0: [AssignExpr] ... = ... +# 444| 0: [ArrayCreation] array creation of type Int32[,][] +# 444| -1: [ArrayInitializer] { ..., ... } +# 444| 0: [ArrayCreation] array creation of type Int32[,] +# 444| -1: [ArrayInitializer] { ..., ... } +# 444| 0: [ArrayInitializer] { ..., ... } +# 444| 0: [IntLiteral] 1 +# 444| 1: [IntLiteral] 2 +# 444| 1: [ArrayCreation] array creation of type Int32[,] +# 444| -1: [ArrayInitializer] { ..., ... } +# 444| 0: [ArrayInitializer] { ..., ... } +# 444| 0: [IntLiteral] 1 +# 444| 1: [IntLiteral] 2 +# 444| 2: [IntLiteral] 3 +# 444| 1: [ArrayInitializer] { ..., ... } +# 444| 0: [IntLiteral] 1 +# 444| 1: [IntLiteral] 2 +# 444| 2: [IntLiteral] 3 +# 444| 2: [ArrayInitializer] { ..., ... } +# 444| 0: [IntLiteral] 1 +# 444| 1: [IntLiteral] 2 +# 444| 2: [IntLiteral] 3 +# 444| 3: [ArrayInitializer] { ..., ... } +# 444| 0: [IntLiteral] 1 +# 444| 1: [IntLiteral] 2 +# 444| 2: [IntLiteral] 3 +# 444| 1: [LocalVariableAccess] access to local variable o +# 447| 9: [Method] MainAnonymousFunctions +# 448| 4: [BlockStmt] {...} +# 449| 0: [LocalVariableDeclStmt] ... ...; +# 449| 0: [LocalVariableDeclAndInitExpr] Func f1 = ... +# 449| 0: [LambdaExpr] (...) => ... +# 449| 0: [CastExpr] (...) ... +# 449| 0: [AddExpr] ... + ... +# 449| 0: [CastExpr] (...) ... +# 449| 0: [ParameterAccess] access to parameter x +# 449| 1: [IntLiteral] 1 +# 449| 1: [TypeAccess] access to type Byte +#-----| 2: (Parameters) +# 449| 0: [Parameter] x +# 449| 1: [LocalVariableAccess] access to local variable f1 +# 450| 1: [LocalVariableDeclStmt] ... ...; +# 450| 0: [LocalVariableDeclAndInitExpr] Func f2 = ... +# 450| 0: [LambdaExpr] (...) => ... +# 450| 0: [BlockStmt] {...} +# 450| 0: [ReturnStmt] return ...; +# 450| 0: [CastExpr] (...) ... +# 450| 0: [AddExpr] ... + ... +# 450| 0: [ParameterAccess] access to parameter x +# 450| 1: [IntLiteral] 1 +#-----| 2: (Parameters) +# 450| 0: [Parameter] x +# 450| 1: [LocalVariableAccess] access to local variable f2 +# 451| 2: [LocalVariableDeclStmt] ... ...; +# 451| 0: [LocalVariableDeclAndInitExpr] Func f3 = ... +# 451| 0: [LambdaExpr] (...) => ... +# 451| 0: [AddExpr] ... + ... +# 451| 0: [ParameterAccess] access to parameter x +# 451| 1: [IntLiteral] 1 +#-----| 2: (Parameters) +# 451| 0: [Parameter] x +# 451| 1: [LocalVariableAccess] access to local variable f3 +# 452| 3: [LocalVariableDeclStmt] ... ...; +# 452| 0: [LocalVariableDeclAndInitExpr] Func f4 = ... +# 452| 0: [LambdaExpr] (...) => ... +# 452| 0: [BlockStmt] {...} +# 452| 0: [ReturnStmt] return ...; +# 452| 0: [AddExpr] ... + ... +# 452| 0: [CastExpr] (...) ... +# 452| 0: [ParameterAccess] access to parameter x +# 452| 1: [StringLiteral] "" +#-----| 2: (Parameters) +# 452| 0: [Parameter] x +# 452| 1: [LocalVariableAccess] access to local variable f4 +# 453| 4: [LocalVariableDeclStmt] ... ...; +# 453| 0: [LocalVariableDeclAndInitExpr] S f5 = ... +# 453| 0: [LambdaExpr] (...) => ... +# 453| 0: [MulExpr] ... * ... +# 453| 0: [ParameterAccess] access to parameter x +# 453| 1: [ParameterAccess] access to parameter y +#-----| 2: (Parameters) +# 453| 0: [Parameter] x +# 453| 1: [Parameter] y +# 453| 1: [LocalVariableAccess] access to local variable f5 +# 454| 5: [LocalVariableDeclStmt] ... ...; +# 454| 0: [LocalVariableDeclAndInitExpr] Unit f6 = ... +# 454| 0: [LambdaExpr] (...) => ... +# 454| 0: [MethodCall] call to method WriteLine +# 454| -1: [TypeAccess] access to type Console +# 454| 1: [LocalVariableAccess] access to local variable f6 +# 455| 6: [LocalVariableDeclStmt] ... ...; +# 455| 0: [LocalVariableDeclAndInitExpr] Func f7 = ... +# 455| 0: [AnonymousMethodExpr] delegate(...) { ... } +# 455| 0: [BlockStmt] {...} +# 455| 0: [ReturnStmt] return ...; +# 455| 0: [AddExpr] ... + ... +# 455| 0: [ParameterAccess] access to parameter x +# 455| 1: [IntLiteral] 1 +#-----| 2: (Parameters) +# 455| 0: [Parameter] x +# 455| 1: [LocalVariableAccess] access to local variable f7 +# 456| 7: [LocalVariableDeclStmt] ... ...; +# 456| 0: [LocalVariableDeclAndInitExpr] Int32 j = ... +# 456| 0: [IntLiteral] 0 +# 456| 1: [LocalVariableAccess] access to local variable j +# 457| 8: [LocalVariableDeclStmt] ... ...; +# 457| 0: [LocalVariableDeclAndInitExpr] Func f8 = ... +# 457| 0: [AnonymousMethodExpr] delegate(...) { ... } +# 457| 0: [BlockStmt] {...} +# 457| 0: [ReturnStmt] return ...; +# 457| 0: [AddExpr] ... + ... +# 457| 0: [LocalVariableAccess] access to local variable j +# 457| 1: [IntLiteral] 1 +# 457| 1: [LocalVariableAccess] access to local variable f8 +# 462| 18: [Class] OperatorCalls +# 464| 5: [Method] delegateCombine +#-----| 2: (Parameters) +# 464| 0: [Parameter] fun +# 465| 4: [BlockStmt] {...} +# 466| 0: [LocalVariableDeclStmt] ... ...; +# 466| 0: [LocalVariableDeclAndInitExpr] MyDelegate PropertyChanged = ... +# 466| 0: [NullLiteral] null +# 466| 1: [LocalVariableAccess] access to local variable PropertyChanged +# 467| 1: [ExprStmt] ...; +# 467| 0: [AssignAddExpr] ... += ... +# 467| 0: [ParameterAccess] access to parameter fun +# 467| 1: [LocalVariableAccess] access to local variable PropertyChanged +# 470| 6: [Method] addition +#-----| 2: (Parameters) +# 470| 0: [Parameter] a +# 470| 1: [Parameter] b +# 470| 2: [Parameter] c +# 471| 4: [BlockStmt] {...} +# 472| 0: [LocalVariableDeclStmt] ... ...; +# 472| 0: [LocalVariableDeclAndInitExpr] Num result = ... +# 472| 0: [OperatorCall] call to operator + +# 472| 0: [ParameterAccess] access to parameter a +# 472| 1: [ParameterAccess] access to parameter b +# 472| 1: [LocalVariableAccess] access to local variable result +# 473| 1: [ExprStmt] ...; +# 473| 0: [AssignAddExpr] ... += ... +# 473| 0: [ParameterAccess] access to parameter c +# 473| 1: [LocalVariableAccess] access to local variable result +# 474| 2: [ReturnStmt] return ...; +# 474| 0: [LocalVariableAccess] access to local variable result +# 476| 7: [Class] Num +# 478| 4: [Field] value +# 480| 5: [InstanceConstructor] Num +#-----| 2: (Parameters) +# 480| 0: [Parameter] value +# 481| 4: [BlockStmt] {...} +# 482| 0: [ExprStmt] ...; +# 482| 0: [AssignExpr] ... = ... +# 482| 0: [ParameterAccess] access to parameter value +# 482| 1: [FieldAccess] access to field value +# 482| -1: [ThisAccess] this access +# 485| 6: [AddOperator] + +#-----| 2: (Parameters) +# 485| 0: [Parameter] c1 +# 485| 1: [Parameter] c2 +# 486| 4: [BlockStmt] {...} +# 487| 0: [ReturnStmt] return ...; +# 487| 0: [ObjectCreation] object creation of type Num +# 487| 0: [AddExpr] ... + ... +# 487| 0: [FieldAccess] access to field value +# 487| -1: [ParameterAccess] access to parameter c1 +# 487| 1: [FieldAccess] access to field value +# 487| -1: [ParameterAccess] access to parameter c2 +# 491| 8: [DelegateType] MyDelegate +#-----| 2: (Parameters) +# 491| 0: [Parameter] e +# 494| 19: [Class] ExpressionDepth +# 496| 5: [Field] d +# 496| 1: [AssignExpr] ... = ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 496| 1: [MemberConstantAccess] access to constant d +# 500| 20: [Class] TupleExprs +# 502| 5: [Method] Test +# 503| 4: [BlockStmt] {...} +# 504| 0: [LocalVariableDeclStmt] ... ...; +# 504| 0: [LocalVariableDeclAndInitExpr] (Int32,String) a = ... +# 504| 0: [DefaultValueExpr] default(...) +# 504| 0: [TypeAccess] access to type (Int32,String) +# 504| 1: [LocalVariableAccess] access to local variable a +# 505| 1: [LocalVariableDeclStmt] ... ...; +# 505| 0: [LocalVariableDeclAndInitExpr] (Boolean,Int32[],Object) b = ... +# 505| 0: [DefaultValueExpr] default(...) +# 505| 0: [TypeAccess] access to type (Boolean,Int32[],Object) +# 505| 1: [LocalVariableAccess] access to local variable b +# 506| 2: [LocalVariableDeclStmt] ... ...; +# 506| 0: [LocalVariableDeclAndInitExpr] Type x = ... +# 506| 0: [TypeofExpr] typeof(...) +# 506| 0: [TypeAccess] access to type (Int32,String) +# 506| 1: [LocalVariableAccess] access to local variable x +# 507| 3: [LocalVariableDeclStmt] ... ...; +# 507| 0: [LocalVariableDeclAndInitExpr] Type y = ... +# 507| 0: [TypeofExpr] typeof(...) +# 507| 0: [TypeAccess] access to type (Boolean,Int32[],dynamic) +# 507| 1: [LocalVariableAccess] access to local variable y diff --git a/csharp/ql/test/library-tests/expressions/PrintAst.qlref b/csharp/ql/test/library-tests/expressions/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/expressions/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/expressions/QualifiableExpr.expected b/csharp/ql/test/library-tests/expressions/QualifiableExpr.expected index 0013cee52a94..f5b5c0aa892c 100644 --- a/csharp/ql/test/library-tests/expressions/QualifiableExpr.expected +++ b/csharp/ql/test/library-tests/expressions/QualifiableExpr.expected @@ -65,7 +65,7 @@ | expressions.cs:377:43:377:46 | access to field name | expressions.cs:377:43:377:46 | this access | | expressions.cs:377:57:377:60 | access to field name | expressions.cs:377:57:377:60 | this access | | expressions.cs:378:57:378:68 | access to field phoneNumbers | expressions.cs:378:57:378:68 | this access | -| expressions.cs:442:29:442:47 | call to method WriteLine | expressions.cs:442:29:442:35 | access to type Console | -| expressions.cs:470:17:470:26 | access to field value | expressions.cs:470:17:470:20 | this access | -| expressions.cs:475:32:475:39 | access to field value | expressions.cs:475:32:475:33 | access to parameter c1 | -| expressions.cs:475:43:475:50 | access to field value | expressions.cs:475:43:475:44 | access to parameter c2 | +| expressions.cs:454:29:454:47 | call to method WriteLine | expressions.cs:454:29:454:35 | access to type Console | +| expressions.cs:482:17:482:26 | access to field value | expressions.cs:482:17:482:20 | this access | +| expressions.cs:487:32:487:39 | access to field value | expressions.cs:487:32:487:33 | access to parameter c1 | +| expressions.cs:487:43:487:50 | access to field value | expressions.cs:487:43:487:44 | access to parameter c2 | diff --git a/csharp/ql/test/library-tests/expressions/StripCasts.expected b/csharp/ql/test/library-tests/expressions/StripCasts.expected index bf16559809a8..6fdfa4be3d59 100644 --- a/csharp/ql/test/library-tests/expressions/StripCasts.expected +++ b/csharp/ql/test/library-tests/expressions/StripCasts.expected @@ -50,7 +50,7 @@ | expressions.cs:334:30:334:30 | (...) ... | expressions.cs:334:30:334:30 | 8 | | expressions.cs:414:31:414:31 | (...) ... | expressions.cs:414:31:414:31 | 1 | | expressions.cs:414:39:414:39 | (...) ... | expressions.cs:414:39:414:39 | 2 | -| expressions.cs:437:41:437:53 | (...) ... | expressions.cs:437:48:437:52 | ... + ... | -| expressions.cs:437:48:437:48 | (...) ... | expressions.cs:437:48:437:48 | access to parameter x | -| expressions.cs:438:52:438:56 | (...) ... | expressions.cs:438:52:438:56 | ... + ... | -| expressions.cs:440:56:440:56 | (...) ... | expressions.cs:440:56:440:56 | access to parameter x | +| expressions.cs:449:41:449:53 | (...) ... | expressions.cs:449:48:449:52 | ... + ... | +| expressions.cs:449:48:449:48 | (...) ... | expressions.cs:449:48:449:48 | access to parameter x | +| expressions.cs:450:52:450:56 | (...) ... | expressions.cs:450:52:450:56 | ... + ... | +| expressions.cs:452:56:452:56 | (...) ... | expressions.cs:452:56:452:56 | access to parameter x | diff --git a/csharp/ql/test/library-tests/expressions/Tuples1.expected b/csharp/ql/test/library-tests/expressions/Tuples1.expected index 70210471b036..ea05f07d8eb5 100644 --- a/csharp/ql/test/library-tests/expressions/Tuples1.expected +++ b/csharp/ql/test/library-tests/expressions/Tuples1.expected @@ -1,4 +1,4 @@ -| expressions.cs:492:29:492:41 | access to type (Int32,String) | expressions.cs:492:29:492:41 | (Int32,String) | -| expressions.cs:493:29:493:49 | access to type (Boolean,Int32[],Object) | expressions.cs:493:29:493:49 | (Boolean,Int32[],Object) | -| expressions.cs:494:28:494:40 | access to type (Int32,String) | expressions.cs:492:29:492:41 | (Int32,String) | -| expressions.cs:495:28:495:49 | access to type (Boolean,Int32[],dynamic) | expressions.cs:495:28:495:49 | (Boolean,Int32[],dynamic) | +| expressions.cs:504:29:504:41 | access to type (Int32,String) | expressions.cs:504:29:504:41 | (Int32,String) | +| expressions.cs:505:29:505:49 | access to type (Boolean,Int32[],Object) | expressions.cs:505:29:505:49 | (Boolean,Int32[],Object) | +| expressions.cs:506:28:506:40 | access to type (Int32,String) | expressions.cs:504:29:504:41 | (Int32,String) | +| expressions.cs:507:28:507:49 | access to type (Boolean,Int32[],dynamic) | expressions.cs:507:28:507:49 | (Boolean,Int32[],dynamic) | diff --git a/csharp/ql/test/library-tests/expressions/expressions.cs b/csharp/ql/test/library-tests/expressions/expressions.cs index aea2d80729c2..5d995e109857 100644 --- a/csharp/ql/test/library-tests/expressions/expressions.cs +++ b/csharp/ql/test/library-tests/expressions/expressions.cs @@ -432,6 +432,18 @@ void MainCreations() delegate int S(int x, int y); delegate void Unit(); + void MultiDimensionalArrayCreations() + { + object o = new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 } }; + o = new int[,,] { { { 1, 2, 3 }, { 4, 5, 6 } }, { { 7, 8, 9 }, { 10, 11, 12 } } }; + o = new int[,][,] + { + { new int[,] { {1,3}, {5,7} }, new int[,] { {0,2}, {4,6}, {8,10} }, new int[,] { {11,22}, {99,88}, {0,9} } }, + { new int[,] { {1,3}, {5,7} }, new int[,] { {0,2}, {4,6}, {8,10} }, new int[,] { {11,22}, {99,88}, {0,9} } } + }; + o = new int[][,] { new int[,] { { 1, 2 } }, new int[,] { { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 } } }; + } + void MainAnonymousFunctions() { Func f1 = x => (byte)(x + 1); // Implicitly typed, expression body diff --git a/csharp/ql/test/library-tests/exprorstmtparent/Callable.expected b/csharp/ql/test/library-tests/exprorstmtparent/Callable.expected index a1449d3574f2..be7a918193f0 100644 --- a/csharp/ql/test/library-tests/exprorstmtparent/Callable.expected +++ b/csharp/ql/test/library-tests/exprorstmtparent/Callable.expected @@ -1,16 +1,60 @@ +| A.cs:6:22:6:31 | get_P1 | A.cs:6:22:6:31 | throw ... | +| A.cs:6:22:6:31 | get_P1 | B.cs:5:22:5:22 | 0 | +| A.cs:7:21:7:23 | get_P2 | A.cs:7:25:7:39 | {...} | +| A.cs:7:21:7:23 | get_P2 | B.cs:6:25:6:37 | {...} | +| A.cs:7:41:7:43 | set_P2 | A.cs:7:45:7:59 | {...} | +| A.cs:7:41:7:43 | set_P2 | B.cs:6:43:6:45 | {...} | +| A.cs:8:16:8:16 | M | A.cs:8:23:8:32 | throw ... | +| A.cs:8:16:8:16 | M | B.cs:7:23:7:23 | 2 | | A.cs:14:31:14:31 | get_Item | A.cs:14:31:14:31 | access to parameter i | +| A.cs:14:31:14:31 | get_Item | B.cs:14:31:14:40 | throw ... | | A.cs:15:36:15:38 | get_Item | A.cs:15:40:15:52 | {...} | +| A.cs:15:36:15:38 | get_Item | B.cs:15:40:15:54 | {...} | | A.cs:15:54:15:56 | set_Item | A.cs:15:58:15:60 | {...} | +| A.cs:15:54:15:56 | set_Item | B.cs:15:60:15:62 | {...} | | A.cs:16:17:16:18 | M1 | A.cs:17:5:19:5 | {...} | +| A.cs:16:17:16:18 | M1 | B.cs:17:5:19:5 | {...} | | A.cs:18:9:18:22 | M2 | A.cs:18:21:18:21 | 0 | | A.cs:20:12:20:13 | C2 | A.cs:20:22:20:31 | {...} | +| A.cs:20:12:20:13 | C2 | B.cs:20:22:20:36 | {...} | | A.cs:21:12:21:13 | C2 | A.cs:21:27:21:29 | {...} | +| A.cs:21:12:21:13 | C2 | B.cs:21:27:21:29 | {...} | | A.cs:22:6:22:7 | ~C2 | A.cs:22:11:22:13 | {...} | +| A.cs:22:6:22:7 | ~C2 | B.cs:22:11:22:25 | {...} | | A.cs:23:28:23:35 | implicit conversion | A.cs:23:50:23:53 | null | +| A.cs:23:28:23:35 | implicit conversion | B.cs:23:50:23:59 | throw ... | +| A.cs:30:21:30:23 | get_P3 | A.cs:30:28:30:37 | throw ... | +| A.cs:36:9:36:10 | M1 | A.cs:36:14:36:28 | {...} | +| A.cs:36:9:36:10 | M1 | B.cs:34:17:34:17 | 0 | +| A.cs:37:9:37:10 | M2 | A.cs:37:14:37:28 | {...} | +| A.cs:37:9:37:10 | M2 | C.cs:3:17:3:17 | 0 | +| B.cs:5:22:5:22 | get_P1 | A.cs:6:22:6:31 | throw ... | | B.cs:5:22:5:22 | get_P1 | B.cs:5:22:5:22 | 0 | +| B.cs:6:21:6:23 | get_P2 | A.cs:7:25:7:39 | {...} | | B.cs:6:21:6:23 | get_P2 | B.cs:6:25:6:37 | {...} | +| B.cs:6:39:6:41 | set_P2 | A.cs:7:45:7:59 | {...} | | B.cs:6:39:6:41 | set_P2 | B.cs:6:43:6:45 | {...} | +| B.cs:7:16:7:16 | M | A.cs:8:23:8:32 | throw ... | | B.cs:7:16:7:16 | M | B.cs:7:23:7:23 | 2 | +| B.cs:14:31:14:40 | get_Item | A.cs:14:31:14:31 | access to parameter i | +| B.cs:14:31:14:40 | get_Item | B.cs:14:31:14:40 | throw ... | +| B.cs:15:36:15:38 | get_Item | A.cs:15:40:15:52 | {...} | +| B.cs:15:36:15:38 | get_Item | B.cs:15:40:15:54 | {...} | +| B.cs:15:56:15:58 | set_Item | A.cs:15:58:15:60 | {...} | +| B.cs:15:56:15:58 | set_Item | B.cs:15:60:15:62 | {...} | +| B.cs:16:17:16:18 | M1 | A.cs:17:5:19:5 | {...} | +| B.cs:16:17:16:18 | M1 | B.cs:17:5:19:5 | {...} | | B.cs:18:9:18:31 | M2 | B.cs:18:21:18:30 | throw ... | +| B.cs:20:12:20:13 | C2 | A.cs:20:22:20:31 | {...} | +| B.cs:20:12:20:13 | C2 | B.cs:20:22:20:36 | {...} | +| B.cs:21:12:21:13 | C2 | A.cs:21:27:21:29 | {...} | +| B.cs:21:12:21:13 | C2 | B.cs:21:27:21:29 | {...} | +| B.cs:22:6:22:7 | ~C2 | A.cs:22:11:22:13 | {...} | +| B.cs:22:6:22:7 | ~C2 | B.cs:22:11:22:25 | {...} | +| B.cs:23:28:23:35 | implicit conversion | A.cs:23:50:23:53 | null | +| B.cs:23:28:23:35 | implicit conversion | B.cs:23:50:23:59 | throw ... | +| B.cs:29:21:29:23 | get_P3 | A.cs:30:28:30:37 | throw ... | +| B.cs:34:9:34:10 | M1 | A.cs:36:14:36:28 | {...} | | B.cs:34:9:34:10 | M1 | B.cs:34:17:34:17 | 0 | +| C.cs:3:9:3:10 | M2 | A.cs:37:14:37:28 | {...} | | C.cs:3:9:3:10 | M2 | C.cs:3:17:3:17 | 0 | diff --git a/csharp/ql/test/library-tests/exprorstmtparent/Declaration.expected b/csharp/ql/test/library-tests/exprorstmtparent/Declaration.expected index 8faac77089e9..23072367947c 100644 --- a/csharp/ql/test/library-tests/exprorstmtparent/Declaration.expected +++ b/csharp/ql/test/library-tests/exprorstmtparent/Declaration.expected @@ -1,3 +1,11 @@ +| A.cs:4:7:4:8 | C1 | +| A.cs:6:16:6:17 | P1 | +| A.cs:6:22:6:31 | get_P1 | +| A.cs:7:16:7:17 | P2 | +| A.cs:7:21:7:23 | get_P2 | +| A.cs:7:41:7:43 | set_P2 | +| A.cs:7:41:7:43 | value | +| A.cs:8:16:8:16 | M | | A.cs:11:7:11:8 | C2 | | A.cs:13:16:13:16 | F | | A.cs:14:16:14:19 | Item | @@ -24,6 +32,12 @@ | A.cs:24:20:24:22 | get_P | | A.cs:24:25:24:27 | set_P | | A.cs:24:25:24:27 | value | +| A.cs:28:7:28:8 | C3 | +| A.cs:30:16:30:17 | P3 | +| A.cs:30:21:30:23 | get_P3 | +| A.cs:34:15:34:16 | C4 | +| A.cs:36:9:36:10 | M1 | +| A.cs:37:9:37:10 | M2 | | B.cs:3:7:3:8 | C1 | | B.cs:5:16:5:17 | P1 | | B.cs:5:22:5:22 | get_P1 | @@ -32,7 +46,32 @@ | B.cs:6:39:6:41 | set_P2 | | B.cs:6:39:6:41 | value | | B.cs:7:16:7:16 | M | +| B.cs:11:7:11:8 | C2 | +| B.cs:13:16:13:16 | F | +| B.cs:14:16:14:19 | Item | +| B.cs:14:25:14:25 | i | +| B.cs:14:25:14:25 | i | +| B.cs:14:31:14:40 | get_Item | +| B.cs:15:19:15:22 | Item | +| B.cs:15:31:15:31 | s | +| B.cs:15:31:15:31 | s | +| B.cs:15:31:15:31 | s | +| B.cs:15:36:15:38 | get_Item | +| B.cs:15:56:15:58 | set_Item | +| B.cs:15:56:15:58 | value | +| B.cs:16:17:16:18 | M1 | +| B.cs:16:24:16:24 | i | | B.cs:18:9:18:31 | M2 | +| B.cs:20:12:20:13 | C2 | +| B.cs:20:19:20:19 | i | +| B.cs:21:12:21:13 | C2 | +| B.cs:22:6:22:7 | ~C2 | +| B.cs:23:28:23:35 | implicit conversion | +| B.cs:23:44:23:44 | i | +| B.cs:24:16:24:16 | P | +| B.cs:24:20:24:22 | get_P | +| B.cs:24:25:24:27 | set_P | +| B.cs:24:25:24:27 | value | | B.cs:27:7:27:8 | C3 | | B.cs:29:16:29:17 | P3 | | B.cs:29:21:29:23 | get_P3 | diff --git a/csharp/ql/test/library-tests/exprorstmtparent/GetABody.expected b/csharp/ql/test/library-tests/exprorstmtparent/GetABody.expected deleted file mode 100644 index 591ffbb71f9f..000000000000 --- a/csharp/ql/test/library-tests/exprorstmtparent/GetABody.expected +++ /dev/null @@ -1,31 +0,0 @@ -| A.cs:14:31:14:31 | get_Item | A.cs:14:31:14:31 | access to parameter i | -| A.cs:14:31:14:31 | get_Item | B.cs:14:31:14:40 | throw ... | -| A.cs:15:36:15:38 | get_Item | A.cs:15:40:15:52 | {...} | -| A.cs:15:36:15:38 | get_Item | B.cs:15:40:15:54 | {...} | -| A.cs:15:54:15:56 | set_Item | A.cs:15:58:15:60 | {...} | -| A.cs:15:54:15:56 | set_Item | B.cs:15:60:15:62 | {...} | -| A.cs:16:17:16:18 | M1 | A.cs:17:5:19:5 | {...} | -| A.cs:16:17:16:18 | M1 | B.cs:17:5:19:5 | {...} | -| A.cs:18:9:18:22 | M2 | A.cs:18:21:18:21 | 0 | -| A.cs:20:12:20:13 | C2 | A.cs:20:22:20:31 | {...} | -| A.cs:20:12:20:13 | C2 | B.cs:20:22:20:36 | {...} | -| A.cs:21:12:21:13 | C2 | A.cs:21:27:21:29 | {...} | -| A.cs:21:12:21:13 | C2 | B.cs:21:27:21:29 | {...} | -| A.cs:22:6:22:7 | ~C2 | A.cs:22:11:22:13 | {...} | -| A.cs:22:6:22:7 | ~C2 | B.cs:22:11:22:25 | {...} | -| A.cs:23:28:23:35 | implicit conversion | A.cs:23:50:23:53 | null | -| A.cs:23:28:23:35 | implicit conversion | B.cs:23:50:23:59 | throw ... | -| B.cs:5:22:5:22 | get_P1 | A.cs:6:22:6:31 | throw ... | -| B.cs:5:22:5:22 | get_P1 | B.cs:5:22:5:22 | 0 | -| B.cs:6:21:6:23 | get_P2 | A.cs:7:25:7:39 | {...} | -| B.cs:6:21:6:23 | get_P2 | B.cs:6:25:6:37 | {...} | -| B.cs:6:39:6:41 | set_P2 | A.cs:7:45:7:59 | {...} | -| B.cs:6:39:6:41 | set_P2 | B.cs:6:43:6:45 | {...} | -| B.cs:7:16:7:16 | M | A.cs:8:23:8:32 | throw ... | -| B.cs:7:16:7:16 | M | B.cs:7:23:7:23 | 2 | -| B.cs:18:9:18:31 | M2 | B.cs:18:21:18:30 | throw ... | -| B.cs:29:21:29:23 | get_P3 | A.cs:30:28:30:37 | throw ... | -| B.cs:34:9:34:10 | M1 | A.cs:36:14:36:28 | {...} | -| B.cs:34:9:34:10 | M1 | B.cs:34:17:34:17 | 0 | -| C.cs:3:9:3:10 | M2 | A.cs:37:14:37:28 | {...} | -| C.cs:3:9:3:10 | M2 | C.cs:3:17:3:17 | 0 | diff --git a/csharp/ql/test/library-tests/exprorstmtparent/GetABody.ql b/csharp/ql/test/library-tests/exprorstmtparent/GetABody.ql deleted file mode 100644 index 4ad64da8618e..000000000000 --- a/csharp/ql/test/library-tests/exprorstmtparent/GetABody.ql +++ /dev/null @@ -1,4 +0,0 @@ -import csharp - -from Callable c -select c, c.getABody() diff --git a/csharp/ql/test/library-tests/exprorstmtparent/Indexer.expected b/csharp/ql/test/library-tests/exprorstmtparent/Indexer.expected index 552e5e3874d3..0ab6193a8e01 100644 --- a/csharp/ql/test/library-tests/exprorstmtparent/Indexer.expected +++ b/csharp/ql/test/library-tests/exprorstmtparent/Indexer.expected @@ -1 +1,4 @@ | A.cs:14:16:14:19 | Item | A.cs:14:31:14:31 | access to parameter i | +| A.cs:14:16:14:19 | Item | B.cs:14:31:14:40 | throw ... | +| B.cs:14:16:14:19 | Item | A.cs:14:31:14:31 | access to parameter i | +| B.cs:14:16:14:19 | Item | B.cs:14:31:14:40 | throw ... | diff --git a/csharp/ql/test/library-tests/exprorstmtparent/MultiImplementationsParent.expected b/csharp/ql/test/library-tests/exprorstmtparent/MultiImplementationsParent.expected deleted file mode 100644 index 19ecdd658110..000000000000 --- a/csharp/ql/test/library-tests/exprorstmtparent/MultiImplementationsParent.expected +++ /dev/null @@ -1,60 +0,0 @@ -| C2 | A.cs:20:12:20:13 | A.cs:20:12:20:13 | -| C2 | A.cs:21:12:21:13 | A.cs:21:12:21:13 | -| C2 | B.cs:20:12:20:13 | B.cs:20:12:20:13 | -| C2 | B.cs:21:12:21:13 | B.cs:21:12:21:13 | -| F | A.cs:13:16:13:16 | A.cs:13:16:13:16 | -| F | B.cs:13:16:13:16 | B.cs:13:16:13:16 | -| F | test.dll:0:0:0:0 | test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | -| Item | A.cs:14:16:14:19 | A.cs:14:16:14:19 | -| Item | B.cs:14:16:14:19 | B.cs:14:16:14:19 | -| Item | test.dll:0:0:0:0 | test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | -| M | A.cs:8:16:8:16 | A.cs:8:16:8:16 | -| M | B.cs:7:16:7:16 | B.cs:7:16:7:16 | -| M | test.dll:0:0:0:0 | test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | -| M1 | A.cs:16:17:16:18 | A.cs:16:17:16:18 | -| M1 | A.cs:36:9:36:10 | A.cs:36:9:36:10 | -| M1 | B.cs:16:17:16:18 | B.cs:16:17:16:18 | -| M1 | B.cs:34:9:34:10 | B.cs:34:9:34:10 | -| M1 | test.dll:0:0:0:0 | test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | -| M2 | A.cs:37:9:37:10 | A.cs:37:9:37:10 | -| M2 | C.cs:3:9:3:10 | C.cs:3:9:3:10 | -| M2 | test.dll:0:0:0:0 | test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | -| P | A.cs:24:16:24:16 | A.cs:24:16:24:16 | -| P | B.cs:24:16:24:16 | B.cs:24:16:24:16 | -| P | test.dll:0:0:0:0 | test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | -| P1 | A.cs:6:16:6:17 | A.cs:6:16:6:17 | -| P1 | B.cs:5:16:5:17 | B.cs:5:16:5:17 | -| P1 | test.dll:0:0:0:0 | test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | -| get_Item | A.cs:14:31:14:31 | A.cs:14:31:14:31 | -| get_Item | A.cs:15:36:15:38 | A.cs:15:36:15:38 | -| get_Item | B.cs:14:31:14:40 | B.cs:14:31:14:40 | -| get_Item | B.cs:15:36:15:38 | B.cs:15:36:15:38 | -| get_Item | test.dll:0:0:0:0 | test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | -| get_P | A.cs:24:20:24:22 | A.cs:24:20:24:22 | -| get_P | B.cs:24:20:24:22 | B.cs:24:20:24:22 | -| get_P | test.dll:0:0:0:0 | test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | -| get_P1 | A.cs:6:22:6:31 | A.cs:6:22:6:31 | -| get_P1 | B.cs:5:22:5:22 | B.cs:5:22:5:22 | -| get_P1 | test.dll:0:0:0:0 | test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | -| get_P2 | A.cs:7:21:7:23 | A.cs:7:21:7:23 | -| get_P2 | B.cs:6:21:6:23 | B.cs:6:21:6:23 | -| get_P2 | test.dll:0:0:0:0 | test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | -| get_P3 | A.cs:30:21:30:23 | A.cs:30:21:30:23 | -| get_P3 | B.cs:29:21:29:23 | B.cs:29:21:29:23 | -| get_P3 | test.dll:0:0:0:0 | test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | -| i | A.cs:16:24:16:24 | A.cs:16:24:16:24 | -| i | B.cs:16:24:16:24 | B.cs:16:24:16:24 | -| implicit conversion | A.cs:23:28:23:35 | A.cs:23:28:23:35 | -| implicit conversion | B.cs:23:28:23:35 | B.cs:23:28:23:35 | -| implicit conversion | test.dll:0:0:0:0 | test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | -| set_Item | A.cs:15:54:15:56 | A.cs:15:54:15:56 | -| set_Item | B.cs:15:56:15:58 | B.cs:15:56:15:58 | -| set_Item | test.dll:0:0:0:0 | test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | -| set_P | A.cs:24:25:24:27 | A.cs:24:25:24:27 | -| set_P | B.cs:24:25:24:27 | B.cs:24:25:24:27 | -| set_P | test.dll:0:0:0:0 | test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | -| set_P2 | A.cs:7:41:7:43 | A.cs:7:41:7:43 | -| set_P2 | B.cs:6:39:6:41 | B.cs:6:39:6:41 | -| set_P2 | test.dll:0:0:0:0 | test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | -| ~C2 | A.cs:22:6:22:7 | A.cs:22:6:22:7 | -| ~C2 | B.cs:22:6:22:7 | B.cs:22:6:22:7 | diff --git a/csharp/ql/test/library-tests/exprorstmtparent/MultiImplementationsParent.ql b/csharp/ql/test/library-tests/exprorstmtparent/MultiImplementationsParent.ql deleted file mode 100644 index 92cb1c32fdb5..000000000000 --- a/csharp/ql/test/library-tests/exprorstmtparent/MultiImplementationsParent.ql +++ /dev/null @@ -1,5 +0,0 @@ -import csharp -import semmle.code.csharp.ExprOrStmtParent - -from MultiImplementationsParent p -select p.toString(), p.getALocation() diff --git a/csharp/ql/test/library-tests/exprorstmtparent/Parameter.expected b/csharp/ql/test/library-tests/exprorstmtparent/Parameter.expected index 2bbf43a054a7..c17d356f4773 100644 --- a/csharp/ql/test/library-tests/exprorstmtparent/Parameter.expected +++ b/csharp/ql/test/library-tests/exprorstmtparent/Parameter.expected @@ -1 +1,4 @@ | A.cs:16:24:16:24 | i | A.cs:16:28:16:28 | 0 | +| A.cs:16:24:16:24 | i | B.cs:16:28:16:28 | 1 | +| B.cs:16:24:16:24 | i | A.cs:16:28:16:28 | 0 | +| B.cs:16:24:16:24 | i | B.cs:16:28:16:28 | 1 | diff --git a/csharp/ql/test/library-tests/exprorstmtparent/Property.expected b/csharp/ql/test/library-tests/exprorstmtparent/Property.expected index 4f04105b9181..4f71b86ae9d6 100644 --- a/csharp/ql/test/library-tests/exprorstmtparent/Property.expected +++ b/csharp/ql/test/library-tests/exprorstmtparent/Property.expected @@ -1,2 +1,8 @@ +| A.cs:6:16:6:17 | P1 | A.cs:6:22:6:31 | throw ... | body | +| A.cs:6:16:6:17 | P1 | B.cs:5:22:5:22 | 0 | body | | A.cs:24:16:24:16 | P | A.cs:24:34:24:34 | 0 | initializer | +| A.cs:24:16:24:16 | P | B.cs:24:34:24:34 | 1 | initializer | +| B.cs:5:16:5:17 | P1 | A.cs:6:22:6:31 | throw ... | body | | B.cs:5:16:5:17 | P1 | B.cs:5:22:5:22 | 0 | body | +| B.cs:24:16:24:16 | P | A.cs:24:34:24:34 | 0 | initializer | +| B.cs:24:16:24:16 | P | B.cs:24:34:24:34 | 1 | initializer | diff --git a/csharp/ql/test/library-tests/extractor/tagstack/Bodies.expected b/csharp/ql/test/library-tests/extractor/tagstack/Bodies.expected index e69de29bb2d1..147cd9914254 100644 --- a/csharp/ql/test/library-tests/extractor/tagstack/Bodies.expected +++ b/csharp/ql/test/library-tests/extractor/tagstack/Bodies.expected @@ -0,0 +1,2 @@ +| A.cs:5:12:5:13 | M1 | This method has multiple bodies. | +| B.cs:5:12:5:13 | M1 | This method has multiple bodies. | diff --git a/csharp/ql/test/library-tests/extractor/tagstack/Classes.expected b/csharp/ql/test/library-tests/extractor/tagstack/Classes.expected index 3163ed48abe9..33c9f5a6b3d5 100644 --- a/csharp/ql/test/library-tests/extractor/tagstack/Classes.expected +++ b/csharp/ql/test/library-tests/extractor/tagstack/Classes.expected @@ -1 +1,2 @@ | A.cs:3:7:3:7 | C | +| B.cs:3:7:3:7 | C | diff --git a/csharp/ql/test/library-tests/extractor/tagstack/Methods.expected b/csharp/ql/test/library-tests/extractor/tagstack/Methods.expected index bab64e4d86a6..27a65e160d5d 100644 --- a/csharp/ql/test/library-tests/extractor/tagstack/Methods.expected +++ b/csharp/ql/test/library-tests/extractor/tagstack/Methods.expected @@ -1,2 +1,4 @@ | A.cs:5:12:5:13 | M1 | | A.cs:6:10:6:11 | M2 | +| B.cs:5:12:5:13 | M1 | +| B.cs:6:10:6:11 | M3 | diff --git a/csharp/ql/test/library-tests/fields/PrintAst.expected b/csharp/ql/test/library-tests/fields/PrintAst.expected new file mode 100644 index 000000000000..b87bd043db2b --- /dev/null +++ b/csharp/ql/test/library-tests/fields/PrintAst.expected @@ -0,0 +1,185 @@ +fields.cs: +# 5| [NamespaceDeclaration] namespace ... { ... } +# 7| 1: [Class] A +# 10| 6: [Field] X +# 10| 1: [AssignExpr] ... = ... +# 10| 0: [IntLiteral] 1 +# 10| 1: [FieldAccess] access to field X +# 10| 7: [Field] Y +# 10| 8: [Field] Z +# 10| 1: [AssignExpr] ... = ... +# 10| 0: [IntLiteral] 100 +# 10| 1: [FieldAccess] access to field Z +# 13| 2: [Class] B +# 15| 6: [Field] X +# 15| 1: [AssignExpr] ... = ... +# 15| 0: [IntLiteral] 1 +# 15| 1: [FieldAccess] access to field X +# 16| 7: [Field] Y +# 17| 8: [Field] Z +# 17| 1: [AssignExpr] ... = ... +# 17| 0: [IntLiteral] 100 +# 17| 1: [FieldAccess] access to field Z +# 20| 3: [Class] C<> +#-----| 1: (Type parameters) +# 20| 0: [TypeParameter] V +# 23| 5: [Field] count +# 23| 1: [AssignExpr] ... = ... +# 23| 0: [IntLiteral] 0 +# 23| 1: [FieldAccess] access to field count +# 25| 6: [InstanceConstructor] C +# 25| 4: [BlockStmt] {...} +# 25| 0: [ExprStmt] ...; +# 25| 0: [PostIncrExpr] ...++ +# 25| 0: [FieldAccess] access to field count +# 27| 7: [Property] Count +# 27| 3: [Getter] get_Count +# 27| 4: [BlockStmt] {...} +# 27| 0: [ReturnStmt] return ...; +# 27| 0: [FieldAccess] access to field count +# 31| 4: [Class] Application +# 34| 6: [Field] finished +# 35| 7: [Field] x +# 35| 1: [AssignExpr] ... = ... +# 35| 0: [MethodCall] call to method Sqrt +# 35| -1: [TypeAccess] access to type Math +# 35| 0: [DoubleLiteral] 2 +# 35| 1: [FieldAccess] access to field x +# 36| 8: [Field] i +# 36| 1: [AssignExpr] ... = ... +# 36| 0: [IntLiteral] 100 +# 36| 1: [FieldAccess] access to field i +# 37| 9: [Field] s +# 37| 1: [AssignExpr] ... = ... +# 37| 0: [StringLiteral] "Hello" +# 37| 1: [FieldAccess] access to field s +# 39| 10: [Method] Main +# 40| 4: [BlockStmt] {...} +# 41| 0: [LocalVariableDeclStmt] ... ...; +# 41| 0: [LocalVariableDeclAndInitExpr] Decimal d = ... +# 41| 0: [MemberConstantAccess] access to constant MaxValue +# 41| -1: [TypeAccess] access to type Decimal +# 41| 1: [LocalVariableAccess] access to local variable d +# 42| 1: [LocalVariableDeclStmt] ... ...; +# 42| 0: [LocalVariableDeclAndInitExpr] C x1 = ... +# 42| 0: [ObjectCreation] object creation of type C +# 42| 1: [LocalVariableAccess] access to local variable x1 +# 43| 2: [ExprStmt] ...; +# 43| 0: [MethodCall] call to method WriteLine +# 43| -1: [TypeAccess] access to type Console +# 43| 0: [PropertyCall] access to property Count +# 43| -1: [TypeAccess] access to type C +# 44| 3: [LocalVariableDeclStmt] ... ...; +# 44| 0: [LocalVariableDeclAndInitExpr] C x2 = ... +# 44| 0: [ObjectCreation] object creation of type C +# 44| 1: [LocalVariableAccess] access to local variable x2 +# 45| 4: [ExprStmt] ...; +# 45| 0: [MethodCall] call to method WriteLine +# 45| -1: [TypeAccess] access to type Console +# 45| 0: [PropertyCall] access to property Count +# 45| -1: [TypeAccess] access to type C +# 50| 5: [Class] Color +# 53| 5: [Field] Black +# 53| 1: [AssignExpr] ... = ... +# 53| 0: [ObjectCreation] object creation of type Color +# 53| 0: [CastExpr] (...) ... +# 53| 0: [IntLiteral] 0 +# 53| 1: [CastExpr] (...) ... +# 53| 0: [IntLiteral] 0 +# 53| 2: [CastExpr] (...) ... +# 53| 0: [IntLiteral] 0 +# 53| 1: [FieldAccess] access to field Black +# 54| 6: [Field] White +# 54| 1: [AssignExpr] ... = ... +# 54| 0: [ObjectCreation] object creation of type Color +# 54| 0: [CastExpr] (...) ... +# 54| 0: [IntLiteral] 255 +# 54| 1: [CastExpr] (...) ... +# 54| 0: [IntLiteral] 255 +# 54| 2: [CastExpr] (...) ... +# 54| 0: [IntLiteral] 255 +# 54| 1: [FieldAccess] access to field White +# 56| 7: [InstanceConstructor] Color +#-----| 2: (Parameters) +# 56| 0: [Parameter] r +# 56| 1: [Parameter] g +# 56| 2: [Parameter] b +# 56| 4: [BlockStmt] {...} +# 60| 6: [Class] TestBindings +# 63| 6: [Field] a +# 63| 1: [AssignExpr] ... = ... +# 63| 0: [AddExpr] ... + ... +# 63| 0: [FieldAccess] access to field b +# 63| 1: [IntLiteral] 1 +# 63| 1: [FieldAccess] access to field a +# 64| 7: [Field] b +# 64| 1: [AssignExpr] ... = ... +# 64| 0: [AddExpr] ... + ... +# 64| 0: [FieldAccess] access to field a +# 64| 1: [IntLiteral] 1 +# 64| 1: [FieldAccess] access to field b +# 70| [NamespaceDeclaration] namespace ... { ... } +# 72| 1: [Class] A +# 74| 5: [Field] X +# 74| 1: [AssignExpr] ... = ... +# 74| 0: [AddExpr] ... + ... +# 74| 0: [MemberConstantAccess] access to constant Z +# 74| -1: [TypeAccess] access to type B +# 74| 1: [IntLiteral] 1 +# 74| 1: [MemberConstantAccess] access to constant X +# 75| 6: [Field] Y +# 75| 1: [AssignExpr] ... = ... +# 75| 0: [IntLiteral] 10 +# 75| 1: [MemberConstantAccess] access to constant Y +# 78| 2: [Class] B +# 80| 5: [Field] Z +# 80| 1: [AssignExpr] ... = ... +# 80| 0: [AddExpr] ... + ... +# 80| 0: [MemberConstantAccess] access to constant Y +# 80| -1: [TypeAccess] access to type A +# 80| 1: [IntLiteral] 1 +# 80| 1: [MemberConstantAccess] access to constant Z +# 83| 3: [Class] C +# 85| 4: [Field] Foo +# 85| 1: [AssignExpr] ... = ... +# 85| 0: [IntLiteral] 1 +# 85| 1: [MemberConstantAccess] access to constant Foo +# 86| 5: [Field] x +# 87| 6: [InstanceConstructor] C +# 88| 4: [BlockStmt] {...} +# 89| 0: [ExprStmt] ...; +# 89| 0: [AssignExpr] ... = ... +# 89| 0: [CastExpr] (...) ... +# 89| 0: [MemberConstantAccess] access to constant Foo +# 89| 1: [FieldAccess] access to field x +# 90| 1: [LocalVariableDeclStmt] ... ...; +# 90| 0: [LocalVariableDeclAndInitExpr] dynamic dyn = ... +# 90| 0: [CastExpr] (...) ... +# 90| 0: [MemberConstantAccess] access to constant Foo +# 90| 1: [LocalVariableAccess] access to local variable dyn +# 91| 2: [LocalVariableDeclStmt] ... ...; +# 91| 0: [LocalVariableDeclAndInitExpr] D d = ... +# 91| 0: [OperatorCall] call to operator implicit conversion +# 91| 0: [MemberConstantAccess] access to constant Foo +# 91| 1: [LocalVariableAccess] access to local variable d +# 92| 3: [LocalVariableDeclStmt] ... ...; +# 92| 0: [LocalVariableDeclAndInitExpr] C c = ... +# 92| 0: [ObjectCreation] object creation of type C +# 92| -1: [ObjectInitializer] { ..., ... } +# 92| 0: [MemberInitializer] ... = ... +# 92| 0: [CastExpr] (...) ... +# 92| 0: [MemberConstantAccess] access to constant Foo +# 92| 1: [FieldAccess] access to field x +# 92| 1: [LocalVariableAccess] access to local variable c +# 96| 4: [Class] D +# 98| 4: [InstanceConstructor] D +#-----| 2: (Parameters) +# 98| 0: [Parameter] d +# 99| 4: [BlockStmt] {...} +# 101| 5: [ImplicitConversionOperator] implicit conversion +#-----| 2: (Parameters) +# 101| 0: [Parameter] d +# 101| 4: [BlockStmt] {...} +# 101| 0: [ReturnStmt] return ...; +# 101| 0: [ObjectCreation] object creation of type D +# 101| 0: [ParameterAccess] access to parameter d diff --git a/csharp/ql/test/library-tests/fields/PrintAst.qlref b/csharp/ql/test/library-tests/fields/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/fields/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/generics/PrintAst.expected b/csharp/ql/test/library-tests/generics/PrintAst.expected new file mode 100644 index 000000000000..9d50bca4d68d --- /dev/null +++ b/csharp/ql/test/library-tests/generics/PrintAst.expected @@ -0,0 +1,547 @@ +Nesting.cs: +# 1| [Class] A<> +#-----| 1: (Type parameters) +# 1| 0: [TypeParameter] T1 +# 3| 5: [Method] MA1 +#-----| 2: (Parameters) +# 3| 0: [Parameter] x +# 3| 4: [BlockStmt] {...} +# 4| 6: [Method] MA2 +#-----| 1: (Type parameters) +# 4| 0: [TypeParameter] T2 +#-----| 2: (Parameters) +# 4| 0: [Parameter] x +# 4| 1: [Parameter] y +# 4| 4: [BlockStmt] {...} +# 6| 7: [Class] B<> +#-----| 1: (Type parameters) +# 6| 0: [TypeParameter] T3 +# 8| 5: [Method] MB1 +#-----| 2: (Parameters) +# 8| 0: [Parameter] x +# 8| 1: [Parameter] y +# 8| 4: [BlockStmt] {...} +# 9| 6: [Method] MB2 +#-----| 1: (Type parameters) +# 9| 0: [TypeParameter] T4 +#-----| 2: (Parameters) +# 9| 0: [Parameter] x +# 9| 1: [Parameter] y +# 9| 2: [Parameter] z +# 9| 4: [BlockStmt] {...} +# 12| 8: [Class] C +# 14| 5: [Method] MC1 +#-----| 2: (Parameters) +# 14| 0: [Parameter] x +# 14| 4: [BlockStmt] {...} +# 15| 6: [Method] MC2 +#-----| 1: (Type parameters) +# 15| 0: [TypeParameter] T5 +#-----| 2: (Parameters) +# 15| 0: [Parameter] x +# 15| 1: [Parameter] y +# 15| 4: [BlockStmt] {...} +# 17| 7: [Class] D<> +#-----| 1: (Type parameters) +# 17| 0: [TypeParameter] T6 +# 19| 5: [Method] MD1 +#-----| 2: (Parameters) +# 19| 0: [Parameter] x +# 19| 1: [Parameter] y +# 19| 4: [BlockStmt] {...} +# 20| 6: [Method] MD2 +#-----| 1: (Type parameters) +# 20| 0: [TypeParameter] T7 +#-----| 2: (Parameters) +# 20| 0: [Parameter] x +# 20| 1: [Parameter] y +# 20| 2: [Parameter] z +# 20| 4: [BlockStmt] {...} +# 24| 9: [Method] Construct +# 25| 4: [BlockStmt] {...} +# 26| 0: [LocalVariableDeclStmt] ... ...; +# 26| 0: [LocalVariableDeclAndInitExpr] A a1 = ... +# 26| 0: [ObjectCreation] object creation of type A +# 26| 1: [LocalVariableAccess] access to local variable a1 +# 27| 1: [ExprStmt] ...; +# 27| 0: [MethodCall] call to method MA1 +# 27| -1: [LocalVariableAccess] access to local variable a1 +# 27| 0: [IntLiteral] 0 +# 28| 2: [ExprStmt] ...; +# 28| 0: [MethodCall] call to method MA2 +# 28| -1: [LocalVariableAccess] access to local variable a1 +# 28| 0: [IntLiteral] 0 +# 28| 1: [StringLiteral] "" +# 30| 3: [LocalVariableDeclStmt] ... ...; +# 30| 0: [LocalVariableDeclAndInitExpr] A a2 = ... +# 30| 0: [ObjectCreation] object creation of type A +# 30| 1: [LocalVariableAccess] access to local variable a2 +# 31| 4: [ExprStmt] ...; +# 31| 0: [MethodCall] call to method MA1 +# 31| -1: [LocalVariableAccess] access to local variable a2 +# 31| 0: [StringLiteral] "" +# 32| 5: [ExprStmt] ...; +# 32| 0: [MethodCall] call to method MA2 +# 32| -1: [LocalVariableAccess] access to local variable a2 +# 32| 0: [StringLiteral] "" +# 32| 1: [IntLiteral] 0 +# 34| 6: [LocalVariableDeclStmt] ... ...; +# 34| 0: [LocalVariableDeclAndInitExpr] B b1 = ... +# 34| 0: [ObjectCreation] object creation of type B +# 34| 1: [LocalVariableAccess] access to local variable b1 +# 35| 7: [ExprStmt] ...; +# 35| 0: [MethodCall] call to method MB1 +# 35| -1: [LocalVariableAccess] access to local variable b1 +# 35| 0: [IntLiteral] 0 +# 35| 1: [StringLiteral] "" +# 36| 8: [ExprStmt] ...; +# 36| 0: [MethodCall] call to method MB2 +# 36| -1: [LocalVariableAccess] access to local variable b1 +# 36| 0: [IntLiteral] 0 +# 36| 1: [StringLiteral] "" +# 36| 2: [BoolLiteral] false +# 38| 9: [LocalVariableDeclStmt] ... ...; +# 38| 0: [LocalVariableDeclAndInitExpr] B b2 = ... +# 38| 0: [ObjectCreation] object creation of type B +# 38| 1: [LocalVariableAccess] access to local variable b2 +# 39| 10: [ExprStmt] ...; +# 39| 0: [MethodCall] call to method MB1 +# 39| -1: [LocalVariableAccess] access to local variable b2 +# 39| 0: [StringLiteral] "" +# 39| 1: [IntLiteral] 0 +# 40| 11: [ExprStmt] ...; +# 40| 0: [MethodCall] call to method MB2 +# 40| -1: [LocalVariableAccess] access to local variable b2 +# 40| 0: [StringLiteral] "" +# 40| 1: [IntLiteral] 0 +# 40| 2: [BoolLiteral] false +# 42| 12: [LocalVariableDeclStmt] ... ...; +# 42| 0: [LocalVariableDeclAndInitExpr] C c1 = ... +# 42| 0: [ObjectCreation] object creation of type C +# 42| 1: [LocalVariableAccess] access to local variable c1 +# 43| 13: [ExprStmt] ...; +# 43| 0: [MethodCall] call to method MC1 +# 43| -1: [LocalVariableAccess] access to local variable c1 +# 43| 0: [IntLiteral] 0 +# 44| 14: [ExprStmt] ...; +# 44| 0: [MethodCall] call to method MC2 +# 44| -1: [LocalVariableAccess] access to local variable c1 +# 44| 0: [IntLiteral] 0 +# 44| 1: [BoolLiteral] false +# 46| 15: [LocalVariableDeclStmt] ... ...; +# 46| 0: [LocalVariableDeclAndInitExpr] C c2 = ... +# 46| 0: [ObjectCreation] object creation of type C +# 46| 1: [LocalVariableAccess] access to local variable c2 +# 47| 16: [ExprStmt] ...; +# 47| 0: [MethodCall] call to method MC1 +# 47| -1: [LocalVariableAccess] access to local variable c2 +# 47| 0: [StringLiteral] "" +# 48| 17: [ExprStmt] ...; +# 48| 0: [MethodCall] call to method MC2 +# 48| -1: [LocalVariableAccess] access to local variable c2 +# 48| 0: [StringLiteral] "" +# 48| 1: [BoolLiteral] false +# 50| 18: [LocalVariableDeclStmt] ... ...; +# 50| 0: [LocalVariableDeclAndInitExpr] D d1 = ... +# 50| 0: [ObjectCreation] object creation of type D +# 50| 1: [LocalVariableAccess] access to local variable d1 +# 51| 19: [ExprStmt] ...; +# 51| 0: [MethodCall] call to method MD1 +# 51| -1: [LocalVariableAccess] access to local variable d1 +# 51| 0: [IntLiteral] 0 +# 51| 1: [BoolLiteral] false +# 52| 20: [ExprStmt] ...; +# 52| 0: [MethodCall] call to method MD2 +# 52| -1: [LocalVariableAccess] access to local variable d1 +# 52| 0: [IntLiteral] 0 +# 52| 1: [BoolLiteral] false +# 52| 2: [StringLiteral] "" +# 54| 21: [LocalVariableDeclStmt] ... ...; +# 54| 0: [LocalVariableDeclAndInitExpr] D d2 = ... +# 54| 0: [ObjectCreation] object creation of type D +# 54| 1: [LocalVariableAccess] access to local variable d2 +# 55| 22: [ExprStmt] ...; +# 55| 0: [MethodCall] call to method MD1 +# 55| -1: [LocalVariableAccess] access to local variable d2 +# 55| 0: [StringLiteral] "" +# 55| 1: [DecimalLiteral] 0 +# 56| 23: [ExprStmt] ...; +# 56| 0: [MethodCall] call to method MD2 +# 56| -1: [LocalVariableAccess] access to local variable d2 +# 56| 0: [StringLiteral] "" +# 56| 1: [DecimalLiteral] 0 +# 56| 2: [BoolLiteral] false +generics.cs: +# 5| [NamespaceDeclaration] namespace ... { ... } +# 7| 1: [DelegateType] GenericDelegate<> +#-----| 1: (Type parameters) +# 7| 0: [TypeParameter] T +#-----| 2: (Parameters) +# 7| 0: [Parameter] t +# 9| 2: [Class] A +# 13| 3: [Class] A<> +#-----| 1: (Type parameters) +# 13| 0: [TypeParameter] T +# 16| 5: [DelegateType] GenericDelegateInGenericClass<> +#-----| 1: (Type parameters) +# 16| 0: [TypeParameter] U +#-----| 2: (Parameters) +# 16| 0: [Parameter] t +# 16| 1: [Parameter] u +# 18| 6: [Method] bar +#-----| 1: (Type parameters) +# 18| 0: [TypeParameter] X +#-----| 2: (Parameters) +# 18| 0: [Parameter] x +# 18| 1: [Parameter] t +# 18| 4: [BlockStmt] {...} +# 18| 0: [LocalVariableDeclStmt] ... ...; +# 18| 0: [LocalVariableDeclExpr] A<> a +# 18| 1: [ReturnStmt] return ...; +# 18| 0: [ParameterAccess] access to parameter t +# 22| 4: [Class] B<> +#-----| 1: (Type parameters) +# 22| 0: [TypeParameter] T +# 25| 5: [Field] at +# 27| 6: [Field] name +# 29| 7: [Method] foo +# 29| 4: [BlockStmt] {...} +# 31| 8: [Method] fooParams +#-----| 2: (Parameters) +# 31| 0: [Parameter] ts +# 31| 4: [BlockStmt] {...} +# 33| 9: [Method] staticFoo +# 33| 4: [BlockStmt] {...} +# 35| 10: [IndexerProperty] Name +# 35| 3: [Getter] get_Name +# 35| 4: [BlockStmt] {...} +# 35| 0: [ReturnStmt] return ...; +# 35| 0: [FieldAccess] access to field name +# 35| 4: [Setter] set_Name +#-----| 2: (Parameters) +# 35| 0: [Parameter] value +# 35| 4: [BlockStmt] {...} +# 35| 0: [ExprStmt] ...; +# 35| 0: [AssignExpr] ... = ... +# 35| 0: [ParameterAccess] access to parameter value +# 35| 1: [FieldAccess] access to field name +# 37| 11: [Event] myEvent +# 37| 3: [AddEventAccessor] add_myEvent +#-----| 2: (Parameters) +# 37| 0: [Parameter] value +# 37| 4: [RemoveEventAccessor] remove_myEvent +#-----| 2: (Parameters) +# 37| 0: [Parameter] value +# 39| 12: [IncrementOperator] ++ +#-----| 2: (Parameters) +# 39| 0: [Parameter] a +# 40| 4: [BlockStmt] {...} +# 41| 0: [ReturnStmt] return ...; +# 41| 0: [ObjectCreation] object creation of type B<> +# 44| 13: [Destructor] ~B +# 44| 4: [BlockStmt] {...} +# 45| 14: [Method] f +#-----| 1: (Type parameters) +# 45| 0: [TypeParameter] X +# 45| 4: [BlockStmt] {...} +# 45| 0: [ExprStmt] ...; +# 45| 0: [ObjectCreation] object creation of type B +# 48| 5: [Class] Outer<> +#-----| 1: (Type parameters) +# 48| 0: [TypeParameter] T +# 51| 5: [Class] Inner<> +#-----| 1: (Type parameters) +# 51| 0: [TypeParameter] U +# 54| 5: [Field] t +# 55| 6: [Field] myFunc +# 60| 6: [Class] Grid<> +#-----| 1: (Type parameters) +# 60| 0: [TypeParameter] T +# 63| 5: [Field] NumRows +# 63| 1: [AssignExpr] ... = ... +# 63| 0: [IntLiteral] 26 +# 63| 1: [MemberConstantAccess] access to constant NumRows +# 64| 6: [Field] NumCols +# 64| 1: [AssignExpr] ... = ... +# 64| 0: [IntLiteral] 10 +# 64| 1: [MemberConstantAccess] access to constant NumCols +# 66| 7: [Field] cells +# 66| 1: [AssignExpr] ... = ... +# 66| 0: [ArrayCreation] array creation of type T[,] +# 66| 0: [MemberConstantAccess] access to constant NumRows +# 66| 1: [MemberConstantAccess] access to constant NumCols +# 66| 1: [FieldAccess] access to field cells +# 68| 8: [Indexer] Item +#-----| 1: (Parameters) +# 68| 0: [Parameter] i +# 70| 3: [Getter] get_Item +#-----| 2: (Parameters) +# 68| 0: [Parameter] i +# 70| 4: [BlockStmt] {...} +# 70| 0: [ReturnStmt] return ...; +# 70| 0: [ParameterAccess] access to parameter i +# 73| 9: [Indexer] Item +#-----| 1: (Parameters) +# 73| 0: [Parameter] c +# 73| 1: [Parameter] col +# 75| 3: [Getter] get_Item +#-----| 2: (Parameters) +# 73| 0: [Parameter] c +# 73| 1: [Parameter] col +# 76| 4: [BlockStmt] {...} +# 77| 0: [ExprStmt] ...; +# 77| 0: [AssignExpr] ... = ... +# 77| 0: [MethodCall] call to method ToUpper +# 77| -1: [TypeAccess] access to type Char +# 77| 0: [ParameterAccess] access to parameter c +# 77| 1: [ParameterAccess] access to parameter c +# 78| 1: [IfStmt] if (...) ... +# 78| 0: [LogicalOrExpr] ... || ... +# 78| 0: [LTExpr] ... < ... +# 78| 0: [CastExpr] (...) ... +# 78| 0: [ParameterAccess] access to parameter c +# 78| 1: [CastExpr] (...) ... +# 78| 0: [CharLiteral] A +# 78| 1: [GTExpr] ... > ... +# 78| 0: [CastExpr] (...) ... +# 78| 0: [ParameterAccess] access to parameter c +# 78| 1: [CastExpr] (...) ... +# 78| 0: [CharLiteral] Z +# 79| 1: [BlockStmt] {...} +# 80| 0: [ThrowStmt] throw ...; +# 80| 0: [ObjectCreation] object creation of type ArgumentException +# 82| 2: [IfStmt] if (...) ... +# 82| 0: [LogicalOrExpr] ... || ... +# 82| 0: [LTExpr] ... < ... +# 82| 0: [ParameterAccess] access to parameter col +# 82| 1: [IntLiteral] 0 +# 82| 1: [GEExpr] ... >= ... +# 82| 0: [ParameterAccess] access to parameter col +# 82| 1: [MemberConstantAccess] access to constant NumCols +# 83| 1: [BlockStmt] {...} +# 84| 0: [ThrowStmt] throw ...; +# 84| 0: [ObjectCreation] object creation of type IndexOutOfRangeException +# 86| 3: [ReturnStmt] return ...; +# 86| 0: [ArrayAccess] access to array element +# 86| -1: [FieldAccess] access to field cells +# 86| 0: [SubExpr] ... - ... +# 86| 0: [CastExpr] (...) ... +# 86| 0: [ParameterAccess] access to parameter c +# 86| 1: [CastExpr] (...) ... +# 86| 0: [CharLiteral] A +# 86| 1: [ParameterAccess] access to parameter col +# 88| 4: [Setter] set_Item +#-----| 2: (Parameters) +# 73| 0: [Parameter] c +# 73| 1: [Parameter] col +# 88| 2: [Parameter] value +# 89| 4: [BlockStmt] {...} +# 90| 0: [ExprStmt] ...; +# 90| 0: [AssignExpr] ... = ... +# 90| 0: [MethodCall] call to method ToUpper +# 90| -1: [TypeAccess] access to type Char +# 90| 0: [ParameterAccess] access to parameter c +# 90| 1: [ParameterAccess] access to parameter c +# 91| 1: [IfStmt] if (...) ... +# 91| 0: [LogicalOrExpr] ... || ... +# 91| 0: [LTExpr] ... < ... +# 91| 0: [CastExpr] (...) ... +# 91| 0: [ParameterAccess] access to parameter c +# 91| 1: [CastExpr] (...) ... +# 91| 0: [CharLiteral] A +# 91| 1: [GTExpr] ... > ... +# 91| 0: [CastExpr] (...) ... +# 91| 0: [ParameterAccess] access to parameter c +# 91| 1: [CastExpr] (...) ... +# 91| 0: [CharLiteral] Z +# 92| 1: [BlockStmt] {...} +# 93| 0: [ThrowStmt] throw ...; +# 93| 0: [ObjectCreation] object creation of type ArgumentException +# 95| 2: [IfStmt] if (...) ... +# 95| 0: [LogicalOrExpr] ... || ... +# 95| 0: [LTExpr] ... < ... +# 95| 0: [ParameterAccess] access to parameter col +# 95| 1: [IntLiteral] 0 +# 95| 1: [GEExpr] ... >= ... +# 95| 0: [ParameterAccess] access to parameter col +# 95| 1: [MemberConstantAccess] access to constant NumCols +# 96| 1: [BlockStmt] {...} +# 97| 0: [ThrowStmt] throw ...; +# 97| 0: [ObjectCreation] object creation of type IndexOutOfRangeException +# 99| 3: [ExprStmt] ...; +# 99| 0: [AssignExpr] ... = ... +# 99| 0: [ParameterAccess] access to parameter value +# 99| 1: [ArrayAccess] access to array element +# 99| -1: [FieldAccess] access to field cells +# 99| 0: [SubExpr] ... - ... +# 99| 0: [CastExpr] (...) ... +# 99| 0: [ParameterAccess] access to parameter c +# 99| 1: [CastExpr] (...) ... +# 99| 0: [CharLiteral] A +# 99| 1: [ParameterAccess] access to parameter col +# 105| 7: [Class] Test +# 108| 5: [Method] Main +# 109| 4: [BlockStmt] {...} +# 110| 0: [LocalVariableDeclStmt] ... ...; +# 110| 0: [LocalVariableDeclAndInitExpr] B bs = ... +# 110| 0: [ObjectCreation] object creation of type B +# 110| 1: [LocalVariableAccess] access to local variable bs +# 111| 1: [ExprStmt] ...; +# 111| 0: [AssignExpr] ... = ... +# 111| 0: [ObjectCreation] object creation of type A +# 111| 1: [FieldAccess] access to field at +# 111| -1: [LocalVariableAccess] access to local variable bs +# 112| 2: [ExprStmt] ...; +# 112| 0: [MethodCall] call to method foo +# 112| -1: [LocalVariableAccess] access to local variable bs +# 113| 3: [ExprStmt] ...; +# 113| 0: [MethodCall] call to method fooParams +# 113| -1: [LocalVariableAccess] access to local variable bs +# 113| 0: [StringLiteral] "a" +# 113| 1: [StringLiteral] "b" +# 115| 4: [ExprStmt] ...; +# 115| 0: [MethodCall] call to method staticFoo +# 115| -1: [TypeAccess] access to type B +# 117| 5: [ExprStmt] ...; +# 117| 0: [AssignExpr] ... = ... +# 117| 0: [StringLiteral] "" +# 117| 1: [PropertyCall] access to property Name +# 117| -1: [LocalVariableAccess] access to local variable bs +# 118| 6: [ExprStmt] ...; +# 118| 0: [AddEventExpr] ... += ... +# 118| 0: [ExplicitDelegateCreation] delegate creation of type GenericDelegate +# 118| 0: [MethodAccess] access to method f +# 118| 1: [EventAccess,EventCall] access to event myEvent +# 118| -1: [LocalVariableAccess] access to local variable bs +# 119| 7: [ExprStmt] ...; +# 119| 0: [OperatorCall] call to operator ++ +# 119| 0: [LocalVariableAccess] access to local variable bs +# 121| 8: [LocalVariableDeclStmt] ... ...; +# 121| 0: [LocalVariableDeclAndInitExpr] Grid g = ... +# 121| 0: [ObjectCreation] object creation of type Grid +# 121| 1: [LocalVariableAccess] access to local variable g +# 122| 9: [LocalVariableDeclStmt] ... ...; +# 122| 0: [LocalVariableDeclAndInitExpr] Int32 j = ... +# 122| 0: [IndexerCall] access to indexer +# 122| -1: [LocalVariableAccess] access to local variable g +# 122| 0: [CharLiteral] e +# 122| 1: [IntLiteral] 1 +# 122| 1: [LocalVariableAccess] access to local variable j +# 124| 10: [ExprStmt] ...; +# 124| 0: [AssignExpr] ... = ... +# 124| 0: [CastExpr] (...) ... +# 124| 0: [IntLiteral] 3 +# 124| 1: [FieldAccess] access to field t +# 124| -1: [ObjectCreation] object creation of type Inner +# 126| 11: [ExprStmt] ...; +# 126| 0: [MethodCall] call to method bar +# 126| -1: [ObjectCreation] object creation of type A +# 126| 0: [IntLiteral] 2 +# 126| 1: [StringLiteral] "" +# 127| 12: [ExprStmt] ...; +# 127| 0: [MethodCall] call to method bar +# 127| -1: [ObjectCreation] object creation of type A +# 127| 0: [ObjectCreation] object creation of type Test +# 127| 1: [IntLiteral] 2 +# 130| 6: [Method] f +#-----| 2: (Parameters) +# 130| 0: [Parameter] s +# 130| 4: [BlockStmt] {...} +# 130| 0: [ReturnStmt] return ...; +# 130| 0: [ParameterAccess] access to parameter s +# 134| 8: [Class] Subtle +# 137| 5: [Method] fs +#-----| 1: (Type parameters) +# 137| 0: [TypeParameter] X +#-----| 2: (Parameters) +# 137| 0: [Parameter] i +# 137| 4: [BlockStmt] {...} +# 139| 6: [Method] fs +#-----| 1: (Type parameters) +# 139| 0: [TypeParameter] X +#-----| 2: (Parameters) +# 139| 0: [Parameter] i +# 139| 1: [Parameter] j +# 139| 4: [BlockStmt] {...} +# 141| 7: [Method] fs +#-----| 2: (Parameters) +# 141| 0: [Parameter] i +# 141| 4: [BlockStmt] {...} +# 145| 9: [Class] Param<> +#-----| 1: (Type parameters) +# 145| 0: [TypeParameter] T +# 147| 5: [Enum] E +# 147| 5: [Field] x +# 150| 10: [Class] ConstructedMethods +# 152| 5: [Method] CM1 +#-----| 1: (Type parameters) +# 152| 0: [TypeParameter] T +# 152| 4: [BlockStmt] {...} +# 153| 8: [Method] CM2 +#-----| 1: (Type parameters) +# 153| 0: [TypeParameter] T +#-----| 2: (Parameters) +# 153| 0: [Parameter] t +# 153| 4: [BlockStmt] {...} +# 153| 0: [ReturnStmt] return ...; +# 153| 0: [ParameterAccess] access to parameter t +# 155| 11: [Class] Class<> +#-----| 1: (Type parameters) +# 155| 0: [TypeParameter] T1 +# 157| 5: [Method] CM3 +#-----| 1: (Type parameters) +# 157| 0: [TypeParameter] T2 +#-----| 2: (Parameters) +# 157| 0: [Parameter] t +# 157| 1: [Parameter] t1 +# 157| 4: [BlockStmt] {...} +# 157| 0: [ReturnStmt] return ...; +# 157| 0: [ParameterAccess] access to parameter t +# 160| 14: [Method] NonCM +# 160| 4: [BlockStmt] {...} +# 162| 15: [Method] CM +# 163| 4: [BlockStmt] {...} +# 164| 0: [ExprStmt] ...; +# 164| 0: [MethodCall] call to method CM1 +# 165| 1: [ExprStmt] ...; +# 165| 0: [MethodCall] call to method CM1 +# 166| 2: [ExprStmt] ...; +# 166| 0: [MethodCall] call to method CM2 +# 166| 0: [IntLiteral] 4 +# 167| 3: [ExprStmt] ...; +# 167| 0: [MethodCall] call to method CM2 +# 167| 0: [DoubleLiteral] 2 +# 168| 4: [ExprStmt] ...; +# 168| 0: [MethodCall] call to method CM3 +# 168| -1: [ObjectCreation] object creation of type Class +# 168| 0: [DoubleLiteral] 1 +# 168| 1: [IntLiteral] 2 +# 169| 5: [ExprStmt] ...; +# 169| 0: [MethodCall] call to method CM3 +# 169| -1: [ObjectCreation] object creation of type Class +# 169| 0: [DoubleLiteral] 1 +# 169| 1: [DoubleLiteral] 2 +# 173| 11: [Interface] Interface<> +#-----| 1: (Type parameters) +# 173| 0: [TypeParameter] T +# 175| 4: [Method] set +#-----| 2: (Parameters) +# 175| 0: [Parameter] t +# 178| 12: [Class] Inheritance<> +#-----| 1: (Type parameters) +# 178| 0: [TypeParameter] T +#-----| 3: (Base types) +# 178| 1: [Interface] Interface +# 180| 5: [Method] set +#-----| 2: (Parameters) +# 180| 0: [Parameter] t +# 180| 4: [BlockStmt] {...} +# 183| 13: [Class] InheritanceTest +# 185| 5: [Field] member +# 188| 14: [Interface] Interface2<,> +#-----| 1: (Type parameters) +# 188| 0: [TypeParameter] T1 +# 188| 1: [TypeParameter] T2 +# 190| 4: [Method] M +#-----| 2: (Parameters) +# 190| 0: [Parameter] x diff --git a/csharp/ql/test/library-tests/generics/PrintAst.qlref b/csharp/ql/test/library-tests/generics/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/generics/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/goto/PrintAst.expected b/csharp/ql/test/library-tests/goto/PrintAst.expected new file mode 100644 index 000000000000..7ee79e8ded20 --- /dev/null +++ b/csharp/ql/test/library-tests/goto/PrintAst.expected @@ -0,0 +1,42 @@ +goto.cs: +# 2| [Class] Goto +# 4| 5: [Method] Main +# 5| 4: [BlockStmt] {...} +# 6| 0: [BlockStmt] {...} +# 7| 0: [LabelStmt] s1: +# 7| 1: [GotoLabelStmt] goto ...; +# 9| 1: [LabelStmt] s2: +# 9| 2: [LocalVariableDeclStmt] ... ...; +# 9| 0: [LocalVariableDeclAndInitExpr] String s = ... +# 9| 0: [StringLiteral] "5" +# 9| 1: [LocalVariableAccess] access to local variable s +# 10| 3: [SwitchStmt] switch (...) {...} +# 10| 0: [LocalVariableAccess] access to local variable s +# 12| 0: [ConstCase] case ...: +# 12| 0: [ConstantPatternExpr,NullLiteral] null +# 12| 1: [LabelStmt] s3: +# 12| 2: [GotoCaseStmt] goto case ...; +# 12| 0: [StringLiteral] "1" +# 13| 3: [ConstCase] case ...: +# 13| 0: [ConstantPatternExpr,StringLiteral] "1" +# 13| 4: [LabelStmt] s4: +# 13| 5: [GotoCaseStmt] goto case ...; +# 13| 0: [StringLiteral] "2" +# 14| 6: [ConstCase] case ...: +# 14| 0: [ConstantPatternExpr,StringLiteral] "2" +# 14| 7: [LabelStmt] s5: +# 14| 8: [GotoLabelStmt] goto ...; +# 15| 9: [ConstCase] case ...: +# 15| 0: [ConstantPatternExpr,StringLiteral] "3" +# 15| 10: [LabelStmt] s6: +# 15| 11: [GotoDefaultStmt] goto default; +# 16| 12: [ConstCase] case ...: +# 16| 0: [ConstantPatternExpr,StringLiteral] "4" +# 16| 13: [LabelStmt] s7: +# 16| 14: [BreakStmt] break; +# 17| 15: [DefaultCase] default: +# 17| 16: [LabelStmt] s8: +# 17| 17: [GotoCaseStmt] goto case ...; +# 17| 0: [NullLiteral] null +# 19| 4: [LabelStmt] s9: +# 19| 5: [EmptyStmt] ; diff --git a/csharp/ql/test/library-tests/goto/PrintAst.qlref b/csharp/ql/test/library-tests/goto/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/goto/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/indexers/Indexers12.expected b/csharp/ql/test/library-tests/indexers/Indexers12.expected new file mode 100644 index 000000000000..a97b8216ef31 --- /dev/null +++ b/csharp/ql/test/library-tests/indexers/Indexers12.expected @@ -0,0 +1 @@ +| Item[int] | get_Item(int) | diff --git a/csharp/ql/test/library-tests/indexers/Indexers12.ql b/csharp/ql/test/library-tests/indexers/Indexers12.ql new file mode 100644 index 000000000000..189c239edb1e --- /dev/null +++ b/csharp/ql/test/library-tests/indexers/Indexers12.ql @@ -0,0 +1,8 @@ +import csharp + +from Indexer i, Accessor a, string s +where + i.getDeclaringType().hasQualifiedName("System", s) and + s.regexpMatch("Tuple<,*>") and + a = i.getAnAccessor() +select i.toStringWithTypes(), a.toStringWithTypes() diff --git a/csharp/ql/test/library-tests/indexers/PrintAst.expected b/csharp/ql/test/library-tests/indexers/PrintAst.expected new file mode 100644 index 000000000000..57f4bac0ef9d --- /dev/null +++ b/csharp/ql/test/library-tests/indexers/PrintAst.expected @@ -0,0 +1,322 @@ +indexers.cs: +# 5| [NamespaceDeclaration] namespace ... { ... } +# 8| 1: [Class] BitArray +# 11| 4: [Field] bits +# 12| 5: [Field] length +# 14| 6: [InstanceConstructor] BitArray +#-----| 2: (Parameters) +# 14| 0: [Parameter] length +# 15| 4: [BlockStmt] {...} +# 16| 0: [IfStmt] if (...) ... +# 16| 0: [LTExpr] ... < ... +# 16| 0: [ParameterAccess] access to parameter length +# 16| 1: [IntLiteral] 0 +# 17| 1: [ThrowStmt] throw ...; +# 17| 0: [ObjectCreation] object creation of type ArgumentException +# 18| 1: [ExprStmt] ...; +# 18| 0: [AssignExpr] ... = ... +# 18| 0: [ArrayCreation] array creation of type Int32[] +# 18| 0: [AddExpr] ... + ... +# 18| 0: [RShiftExpr] ... >> ... +# 18| 0: [SubExpr] ... - ... +# 18| 0: [ParameterAccess] access to parameter length +# 18| 1: [IntLiteral] 1 +# 18| 1: [IntLiteral] 5 +# 18| 1: [IntLiteral] 1 +# 18| 1: [FieldAccess] access to field bits +# 19| 2: [ExprStmt] ...; +# 19| 0: [AssignExpr] ... = ... +# 19| 0: [ParameterAccess] access to parameter length +# 19| 1: [FieldAccess] access to field length +# 19| -1: [ThisAccess] this access +# 22| 7: [Property] Length +# 22| 3: [Getter] get_Length +# 22| 4: [BlockStmt] {...} +# 22| 0: [ReturnStmt] return ...; +# 22| 0: [FieldAccess] access to field length +# 24| 8: [Indexer] Item +#-----| 1: (Parameters) +# 24| 0: [Parameter] index +# 26| 3: [Getter] get_Item +#-----| 2: (Parameters) +# 24| 0: [Parameter] index +# 27| 4: [BlockStmt] {...} +# 28| 0: [IfStmt] if (...) ... +# 28| 0: [LogicalOrExpr] ... || ... +# 28| 0: [LTExpr] ... < ... +# 28| 0: [ParameterAccess] access to parameter index +# 28| 1: [IntLiteral] 0 +# 28| 1: [GEExpr] ... >= ... +# 28| 0: [ParameterAccess] access to parameter index +# 28| 1: [FieldAccess] access to field length +# 29| 1: [BlockStmt] {...} +# 30| 0: [ThrowStmt] throw ...; +# 30| 0: [ObjectCreation] object creation of type IndexOutOfRangeException +# 32| 1: [ReturnStmt] return ...; +# 32| 0: [NEExpr] ... != ... +# 32| 0: [BitwiseAndExpr] ... & ... +# 32| 0: [ArrayAccess] access to array element +# 32| -1: [FieldAccess] access to field bits +# 32| 0: [RShiftExpr] ... >> ... +# 32| 0: [ParameterAccess] access to parameter index +# 32| 1: [IntLiteral] 5 +# 32| 1: [LShiftExpr] ... << ... +# 32| 0: [IntLiteral] 1 +# 32| 1: [ParameterAccess] access to parameter index +# 32| 1: [IntLiteral] 0 +# 34| 4: [Setter] set_Item +#-----| 2: (Parameters) +# 24| 0: [Parameter] index +# 34| 1: [Parameter] value +# 35| 4: [BlockStmt] {...} +# 36| 0: [IfStmt] if (...) ... +# 36| 0: [LogicalOrExpr] ... || ... +# 36| 0: [LTExpr] ... < ... +# 36| 0: [ParameterAccess] access to parameter index +# 36| 1: [IntLiteral] 0 +# 36| 1: [GEExpr] ... >= ... +# 36| 0: [ParameterAccess] access to parameter index +# 36| 1: [FieldAccess] access to field length +# 37| 1: [BlockStmt] {...} +# 38| 0: [ThrowStmt] throw ...; +# 38| 0: [ObjectCreation] object creation of type IndexOutOfRangeException +# 40| 1: [IfStmt] if (...) ... +# 40| 0: [ParameterAccess] access to parameter value +# 41| 1: [BlockStmt] {...} +# 42| 0: [ExprStmt] ...; +# 42| 0: [AssignOrExpr] ... |= ... +# 42| 0: [LShiftExpr] ... << ... +# 42| 0: [IntLiteral] 1 +# 42| 1: [ParameterAccess] access to parameter index +# 42| 1: [ArrayAccess] access to array element +# 42| -1: [FieldAccess] access to field bits +# 42| 0: [RShiftExpr] ... >> ... +# 42| 0: [ParameterAccess] access to parameter index +# 42| 1: [IntLiteral] 5 +# 45| 2: [BlockStmt] {...} +# 46| 0: [ExprStmt] ...; +# 46| 0: [AssignAndExpr] ... &= ... +# 46| 0: [ComplementExpr] ~... +# 46| 0: [LShiftExpr] ... << ... +# 46| 0: [IntLiteral] 1 +# 46| 1: [ParameterAccess] access to parameter index +# 46| 1: [ArrayAccess] access to array element +# 46| -1: [FieldAccess] access to field bits +# 46| 0: [RShiftExpr] ... >> ... +# 46| 0: [ParameterAccess] access to parameter index +# 46| 1: [IntLiteral] 5 +# 53| 2: [Class] CountPrimes +# 56| 5: [Method] Count +#-----| 2: (Parameters) +# 56| 0: [Parameter] max +# 57| 4: [BlockStmt] {...} +# 58| 0: [LocalVariableDeclStmt] ... ...; +# 58| 0: [LocalVariableDeclAndInitExpr] BitArray flags = ... +# 58| 0: [ObjectCreation] object creation of type BitArray +# 58| 0: [AddExpr] ... + ... +# 58| 0: [ParameterAccess] access to parameter max +# 58| 1: [IntLiteral] 1 +# 58| 1: [LocalVariableAccess] access to local variable flags +# 59| 1: [LocalVariableDeclStmt] ... ...; +# 59| 0: [LocalVariableDeclAndInitExpr] Int32 count = ... +# 59| 0: [IntLiteral] 1 +# 59| 1: [LocalVariableAccess] access to local variable count +# 60| 2: [ForStmt] for (...;...;...) ... +# 60| -1: [LocalVariableDeclAndInitExpr] Int32 i = ... +# 60| 0: [IntLiteral] 2 +# 60| 1: [LocalVariableAccess] access to local variable i +# 60| 0: [LEExpr] ... <= ... +# 60| 0: [LocalVariableAccess] access to local variable i +# 60| 1: [ParameterAccess] access to parameter max +# 60| 1: [PostIncrExpr] ...++ +# 60| 0: [LocalVariableAccess] access to local variable i +# 61| 2: [BlockStmt] {...} +# 62| 0: [IfStmt] if (...) ... +# 62| 0: [LogicalNotExpr] !... +# 62| 0: [IndexerCall] access to indexer +# 62| -1: [LocalVariableAccess] access to local variable flags +# 62| 0: [LocalVariableAccess] access to local variable i +# 63| 1: [BlockStmt] {...} +# 64| 0: [ForStmt] for (...;...;...) ... +# 64| -1: [LocalVariableDeclAndInitExpr] Int32 j = ... +# 64| 0: [MulExpr] ... * ... +# 64| 0: [LocalVariableAccess] access to local variable i +# 64| 1: [IntLiteral] 2 +# 64| 1: [LocalVariableAccess] access to local variable j +# 64| 0: [LEExpr] ... <= ... +# 64| 0: [LocalVariableAccess] access to local variable j +# 64| 1: [ParameterAccess] access to parameter max +# 64| 1: [AssignAddExpr] ... += ... +# 64| 0: [LocalVariableAccess] access to local variable i +# 64| 1: [LocalVariableAccess] access to local variable j +# 65| 2: [ExprStmt] ...; +# 65| 0: [AssignExpr] ... = ... +# 65| 0: [BoolLiteral] true +# 65| 1: [IndexerCall] access to indexer +# 65| -1: [LocalVariableAccess] access to local variable flags +# 65| 0: [LocalVariableAccess] access to local variable j +# 66| 1: [ExprStmt] ...; +# 66| 0: [PostIncrExpr] ...++ +# 66| 0: [LocalVariableAccess] access to local variable count +# 69| 3: [ReturnStmt] return ...; +# 69| 0: [LocalVariableAccess] access to local variable count +# 72| 6: [Method] Main +#-----| 2: (Parameters) +# 72| 0: [Parameter] args +# 73| 4: [BlockStmt] {...} +# 74| 0: [LocalVariableDeclStmt] ... ...; +# 74| 0: [LocalVariableDeclAndInitExpr] Int32 max = ... +# 74| 0: [MethodCall] call to method Parse +# 74| -1: [TypeAccess] access to type Int32 +# 74| 0: [ArrayAccess] access to array element +# 74| -1: [ParameterAccess] access to parameter args +# 74| 0: [IntLiteral] 0 +# 74| 1: [LocalVariableAccess] access to local variable max +# 75| 1: [LocalVariableDeclStmt] ... ...; +# 75| 0: [LocalVariableDeclAndInitExpr] Int32 count = ... +# 75| 0: [MethodCall] call to method Count +# 75| 0: [LocalVariableAccess] access to local variable max +# 75| 1: [LocalVariableAccess] access to local variable count +# 76| 2: [ExprStmt] ...; +# 76| 0: [MethodCall] call to method WriteLine +# 76| -1: [TypeAccess] access to type Console +# 76| 0: [StringLiteral] "Found {0} primes between 1 and {1}" +# 76| 1: [CastExpr] (...) ... +# 76| 0: [LocalVariableAccess] access to local variable count +# 76| 2: [CastExpr] (...) ... +# 76| 0: [LocalVariableAccess] access to local variable max +# 81| 3: [Class] Grid +# 84| 5: [Field] NumRows +# 84| 1: [AssignExpr] ... = ... +# 84| 0: [IntLiteral] 26 +# 84| 1: [MemberConstantAccess] access to constant NumRows +# 85| 6: [Field] NumCols +# 85| 1: [AssignExpr] ... = ... +# 85| 0: [IntLiteral] 10 +# 85| 1: [MemberConstantAccess] access to constant NumCols +# 87| 7: [Field] cells +# 87| 1: [AssignExpr] ... = ... +# 87| 0: [ArrayCreation] array creation of type Int32[,] +# 87| 0: [MemberConstantAccess] access to constant NumRows +# 87| 1: [MemberConstantAccess] access to constant NumCols +# 87| 1: [FieldAccess] access to field cells +# 89| 8: [Indexer] Item +#-----| 1: (Parameters) +# 89| 0: [Parameter] c +# 89| 1: [Parameter] col +# 91| 3: [Getter] get_Item +#-----| 2: (Parameters) +# 89| 0: [Parameter] c +# 89| 1: [Parameter] col +# 92| 4: [BlockStmt] {...} +# 93| 0: [ExprStmt] ...; +# 93| 0: [AssignExpr] ... = ... +# 93| 0: [MethodCall] call to method ToUpper +# 93| -1: [TypeAccess] access to type Char +# 93| 0: [ParameterAccess] access to parameter c +# 93| 1: [ParameterAccess] access to parameter c +# 94| 1: [IfStmt] if (...) ... +# 94| 0: [LogicalOrExpr] ... || ... +# 94| 0: [LTExpr] ... < ... +# 94| 0: [CastExpr] (...) ... +# 94| 0: [ParameterAccess] access to parameter c +# 94| 1: [CastExpr] (...) ... +# 94| 0: [CharLiteral] A +# 94| 1: [GTExpr] ... > ... +# 94| 0: [CastExpr] (...) ... +# 94| 0: [ParameterAccess] access to parameter c +# 94| 1: [CastExpr] (...) ... +# 94| 0: [CharLiteral] Z +# 95| 1: [BlockStmt] {...} +# 96| 0: [ThrowStmt] throw ...; +# 96| 0: [ObjectCreation] object creation of type ArgumentException +# 98| 2: [IfStmt] if (...) ... +# 98| 0: [LogicalOrExpr] ... || ... +# 98| 0: [LTExpr] ... < ... +# 98| 0: [ParameterAccess] access to parameter col +# 98| 1: [IntLiteral] 0 +# 98| 1: [GEExpr] ... >= ... +# 98| 0: [ParameterAccess] access to parameter col +# 98| 1: [MemberConstantAccess] access to constant NumCols +# 99| 1: [BlockStmt] {...} +# 100| 0: [ThrowStmt] throw ...; +# 100| 0: [ObjectCreation] object creation of type IndexOutOfRangeException +# 102| 3: [ReturnStmt] return ...; +# 102| 0: [ArrayAccess] access to array element +# 102| -1: [FieldAccess] access to field cells +# 102| 0: [SubExpr] ... - ... +# 102| 0: [CastExpr] (...) ... +# 102| 0: [ParameterAccess] access to parameter c +# 102| 1: [CastExpr] (...) ... +# 102| 0: [CharLiteral] A +# 102| 1: [ParameterAccess] access to parameter col +# 104| 4: [Setter] set_Item +#-----| 2: (Parameters) +# 89| 0: [Parameter] c +# 89| 1: [Parameter] col +# 104| 2: [Parameter] value +# 105| 4: [BlockStmt] {...} +# 106| 0: [ExprStmt] ...; +# 106| 0: [AssignExpr] ... = ... +# 106| 0: [MethodCall] call to method ToUpper +# 106| -1: [TypeAccess] access to type Char +# 106| 0: [ParameterAccess] access to parameter c +# 106| 1: [ParameterAccess] access to parameter c +# 107| 1: [IfStmt] if (...) ... +# 107| 0: [LogicalOrExpr] ... || ... +# 107| 0: [LTExpr] ... < ... +# 107| 0: [CastExpr] (...) ... +# 107| 0: [ParameterAccess] access to parameter c +# 107| 1: [CastExpr] (...) ... +# 107| 0: [CharLiteral] A +# 107| 1: [GTExpr] ... > ... +# 107| 0: [CastExpr] (...) ... +# 107| 0: [ParameterAccess] access to parameter c +# 107| 1: [CastExpr] (...) ... +# 107| 0: [CharLiteral] Z +# 108| 1: [BlockStmt] {...} +# 109| 0: [ThrowStmt] throw ...; +# 109| 0: [ObjectCreation] object creation of type ArgumentException +# 111| 2: [IfStmt] if (...) ... +# 111| 0: [LogicalOrExpr] ... || ... +# 111| 0: [LTExpr] ... < ... +# 111| 0: [ParameterAccess] access to parameter col +# 111| 1: [IntLiteral] 0 +# 111| 1: [GEExpr] ... >= ... +# 111| 0: [ParameterAccess] access to parameter col +# 111| 1: [MemberConstantAccess] access to constant NumCols +# 112| 1: [BlockStmt] {...} +# 113| 0: [ThrowStmt] throw ...; +# 113| 0: [ObjectCreation] object creation of type IndexOutOfRangeException +# 115| 3: [ExprStmt] ...; +# 115| 0: [AssignExpr] ... = ... +# 115| 0: [ParameterAccess] access to parameter value +# 115| 1: [ArrayAccess] access to array element +# 115| -1: [FieldAccess] access to field cells +# 115| 0: [SubExpr] ... - ... +# 115| 0: [CastExpr] (...) ... +# 115| 0: [ParameterAccess] access to parameter c +# 115| 1: [CastExpr] (...) ... +# 115| 0: [CharLiteral] A +# 115| 1: [ParameterAccess] access to parameter col +# 121| 4: [Class] DuplicateIndexerSignatures +# 123| 5: [Indexer] Item +#-----| 1: (Parameters) +# 123| 0: [Parameter] index +# 125| 3: [Getter] get_Item +#-----| 2: (Parameters) +# 123| 0: [Parameter] index +# 125| 4: [BlockStmt] {...} +# 125| 0: [ReturnStmt] return ...; +# 125| 0: [BoolLiteral] false +# 128| 6: [Indexer] Item +#-----| 1: (Parameters) +# 128| 0: [Parameter] c +# 128| 1: [Parameter] col +# 130| 3: [Getter] get_Item +#-----| 2: (Parameters) +# 128| 0: [Parameter] c +# 128| 1: [Parameter] col +# 130| 4: [BlockStmt] {...} +# 130| 0: [ReturnStmt] return ...; +# 130| 0: [IntLiteral] 0 diff --git a/csharp/ql/test/library-tests/indexers/PrintAst.qlref b/csharp/ql/test/library-tests/indexers/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/indexers/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/initializers/PrintAst.expected b/csharp/ql/test/library-tests/initializers/PrintAst.expected new file mode 100644 index 000000000000..b80326a17515 --- /dev/null +++ b/csharp/ql/test/library-tests/initializers/PrintAst.expected @@ -0,0 +1,58 @@ +initializers.cs: +# 3| [Class] S1 +# 5| 5: [Field] P1 +# 6| 6: [Property] P2 +# 6| 3: [Getter] get_P2 +# 6| 4: [Setter] set_P2 +#-----| 2: (Parameters) +# 6| 0: [Parameter] value +# 7| 7: [Property] P3 +# 7| 3: [Setter] set_P3 +#-----| 2: (Parameters) +# 7| 0: [Parameter] value +# 7| 4: [BlockStmt] {...} +# 10| [Class] S2 +#-----| 3: (Base types) +# 10| 1: [Interface] IEnumerable +# 12| 5: [Method] Add +#-----| 2: (Parameters) +# 12| 0: [Parameter] x +# 12| 4: [BlockStmt] {...} +# 13| 6: [Method] Add +#-----| 2: (Parameters) +# 13| 0: [Parameter] x +# 13| 1: [Parameter] y +# 13| 4: [BlockStmt] {...} +# 14| 7: [Method] GetEnumerator +# 14| 4: [BlockStmt] {...} +# 14| 0: [ReturnStmt] return ...; +# 14| 0: [NullLiteral] null +# 17| [Class] Test +# 19| 5: [Method] Main +#-----| 2: (Parameters) +# 19| 0: [Parameter] args +# 20| 4: [BlockStmt] {...} +# 21| 0: [ExprStmt] ...; +# 21| 0: [ObjectCreation] object creation of type S1 +# 21| -1: [ObjectInitializer] { ..., ... } +# 21| 0: [MemberInitializer] ... = ... +# 21| 0: [IntLiteral] 1 +# 21| 1: [FieldAccess] access to field P1 +# 21| 1: [MemberInitializer] ... = ... +# 21| 0: [IntLiteral] 2 +# 21| 1: [PropertyCall] access to property P2 +# 21| 2: [MemberInitializer] ... = ... +# 21| 0: [IntLiteral] 3 +# 21| 1: [PropertyCall] access to property P3 +# 22| 1: [ExprStmt] ...; +# 22| 0: [ObjectCreation] object creation of type S2 +# 22| -1: [CollectionInitializer] { ..., ... } +# 22| 0: [ElementInitializer] call to method Add +# 22| 0: [IntLiteral] 1 +# 22| 1: [ElementInitializer] call to method Add +# 22| 0: [IntLiteral] 2 +# 22| 2: [ElementInitializer] call to method Add +# 22| 0: [IntLiteral] 3 +# 22| 3: [ElementInitializer] call to method Add +# 22| 0: [IntLiteral] 4 +# 22| 1: [IntLiteral] 5 diff --git a/csharp/ql/test/library-tests/initializers/PrintAst.qlref b/csharp/ql/test/library-tests/initializers/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/initializers/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir.qlref b/csharp/ql/test/library-tests/ir/ir/raw_ir.qlref deleted file mode 100644 index 1f503d46e017..000000000000 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/csharp/ir/implementation/raw/PrintIR.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir_consistency.qlref b/csharp/ql/test/library-tests/ir/ir/raw_ir_consistency.qlref deleted file mode 100644 index 5a11b73c5443..000000000000 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir_consistency.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/csharp/ir/implementation/raw/IRConsistency.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.qlref b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.qlref deleted file mode 100644 index 90b5e8129f86..000000000000 --- a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.ql diff --git a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.qlref b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.qlref deleted file mode 100644 index ae9b0e757b9f..000000000000 --- a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/linq/PrintAst.expected b/csharp/ql/test/library-tests/linq/PrintAst.expected new file mode 100644 index 000000000000..bf38619f4d7e --- /dev/null +++ b/csharp/ql/test/library-tests/linq/PrintAst.expected @@ -0,0 +1,194 @@ +queries.cs: +# 5| [Class] Queries +# 7| 5: [Method] Queries1 +# 8| 4: [BlockStmt] {...} +# 9| 0: [LocalVariableDeclStmt] ... ...; +# 9| 0: [LocalVariableDeclAndInitExpr] IList list1 = ... +# 9| 0: [ObjectCreation] object creation of type List +# 9| -1: [CollectionInitializer] { ..., ... } +# 9| 0: [ElementInitializer] call to method Add +# 9| 0: [IntLiteral] 1 +# 9| 1: [ElementInitializer] call to method Add +# 9| 0: [IntLiteral] 2 +# 9| 2: [ElementInitializer] call to method Add +# 9| 0: [IntLiteral] 3 +# 9| 1: [LocalVariableAccess] access to local variable list1 +# 10| 1: [LocalVariableDeclStmt] ... ...; +# 10| 0: [LocalVariableDeclAndInitExpr] IList> list2 = ... +# 10| 0: [ObjectCreation] object creation of type List> +# 10| -1: [CollectionInitializer] { ..., ... } +# 10| 0: [ElementInitializer] call to method Add +# 10| 0: [LocalVariableAccess] access to local variable list1 +# 10| 1: [ElementInitializer] call to method Add +# 10| 0: [LocalVariableAccess] access to local variable list1 +# 10| 1: [LocalVariableAccess] access to local variable list2 +# 12| 2: [LocalVariableDeclStmt] ... ...; +# 12| 0: [LocalVariableDeclAndInitExpr] IEnumerable list3 = ... +# 16| 0: [MethodCall] call to method Select +# 15| 0: [MethodCall] call to method OrderBy +# 14| 0: [MethodCall] call to method Where +# 13| 0: [LocalVariableDeclAndInitExpr] Int32 a = ... +# 13| 0: [LocalVariableAccess] access to local variable list1 +# 13| 1: [LocalVariableAccess] access to local variable a +# 14| 1: [LogicalOrExpr] ... || ... +# 14| 0: [EQExpr] ... == ... +# 14| 0: [LocalVariableAccess] access to local variable a +# 14| 1: [IntLiteral] 2 +# 14| 1: [EQExpr] ... == ... +# 14| 0: [LocalVariableAccess] access to local variable a +# 14| 1: [IntLiteral] 3 +# 15| 1: [LocalVariableAccess] access to local variable a +# 16| 1: [AddExpr] ... + ... +# 16| 0: [LocalVariableAccess] access to local variable a +# 16| 1: [IntLiteral] 1 +# 12| 1: [LocalVariableAccess] access to local variable list3 +# 18| 3: [LocalVariableDeclStmt] ... ...; +# 18| 0: [LocalVariableDeclAndInitExpr] IEnumerable list4 = ... +# 18| 0: [MethodCall] call to method Select +# 18| -1: [MethodCall] call to method OrderBy +# 18| -1: [MethodCall] call to method Where +# 18| -1: [LocalVariableAccess] access to local variable list1 +# 19| 0: [LambdaExpr] (...) => ... +#-----| 2: (Parameters) +# 19| 0: [Parameter] a +# 19| 4: [LogicalOrExpr] ... || ... +# 19| 0: [EQExpr] ... == ... +# 19| 0: [ParameterAccess] access to parameter a +# 19| 1: [IntLiteral] 2 +# 19| 1: [EQExpr] ... == ... +# 19| 0: [ParameterAccess] access to parameter a +# 19| 1: [IntLiteral] 3 +# 20| 0: [LambdaExpr] (...) => ... +#-----| 2: (Parameters) +# 20| 0: [Parameter] a +# 20| 4: [ParameterAccess] access to parameter a +# 21| 0: [LambdaExpr] (...) => ... +#-----| 2: (Parameters) +# 21| 0: [Parameter] a +# 21| 4: [AddExpr] ... + ... +# 21| 0: [ParameterAccess] access to parameter a +# 21| 1: [IntLiteral] 1 +# 18| 1: [LocalVariableAccess] access to local variable list4 +# 23| 4: [LocalVariableDeclStmt] ... ...; +# 23| 0: [LocalVariableDeclAndInitExpr] IEnumerable list5 = ... +# 28| 0: [MethodCall] call to method +# 27| 0: [MethodCall] call to method Join +# 26| 0: [MethodCall] call to method Select +# 25| 0: [MethodCall] call to method SelectMany +# 24| 0: [LocalVariableDeclAndInitExpr] IList a = ... +# 24| 0: [LocalVariableAccess] access to local variable list2 +# 24| 1: [LocalVariableAccess] access to local variable a +# 25| 1: [LocalVariableDeclAndInitExpr] IList b = ... +# 25| 0: [LocalVariableAccess] access to local variable a +# 25| 1: [LocalVariableAccess] access to local variable b +# 25| 2: [LocalVariableAccess] access to local variable a +# 26| 1: [LocalVariableDeclAndInitExpr] Int32 next = ... +# 26| 0: [AddExpr] ... + ... +# 26| 0: [LocalVariableAccess] access to local variable b +# 26| 1: [IntLiteral] 1 +# 26| 1: [LocalVariableAccess] access to local variable next +# 26| 2: [AddExpr] ... + ... +# 26| 0: [LocalVariableAccess] access to local variable b +# 26| 1: [IntLiteral] 1 +# 27| 1: [LocalVariableDeclAndInitExpr] IList c = ... +# 27| 0: [LocalVariableAccess] access to local variable list1 +# 27| 1: [LocalVariableAccess] access to local variable c +# 27| 2: [LocalVariableAccess] access to local variable list1 +# 27| 3: [LocalVariableAccess] access to local variable next +# 27| 4: [LocalVariableAccess] access to local variable c +# 28| 1: [IntLiteral] 1 +# 23| 1: [LocalVariableAccess] access to local variable list5 +# 30| 5: [LocalVariableDeclStmt] ... ...; +# 30| 0: [LocalVariableDeclAndInitExpr] IEnumerable> list6 = ... +# 35| 0: [MethodCall] call to method GroupBy +# 34| 0: [MethodCall] call to method OrderByDescending +# 33| 0: [MethodCall] call to method Select +# 32| 0: [MethodCall] call to method SelectMany +# 31| 0: [LocalVariableDeclAndInitExpr] IList a = ... +# 31| 0: [LocalVariableAccess] access to local variable list2 +# 31| 1: [LocalVariableAccess] access to local variable a +# 32| 1: [LocalVariableDeclAndInitExpr] IList b = ... +# 32| 0: [LocalVariableAccess] access to local variable a +# 32| 1: [LocalVariableAccess] access to local variable b +# 32| 2: [LocalVariableAccess] access to local variable a +# 33| 1: [LocalVariableDeclAndInitExpr] Int32 next = ... +# 33| 0: [AddExpr] ... + ... +# 33| 0: [LocalVariableAccess] access to local variable b +# 33| 1: [IntLiteral] 1 +# 33| 1: [LocalVariableAccess] access to local variable next +# 33| 2: [AddExpr] ... + ... +# 33| 0: [LocalVariableAccess] access to local variable b +# 33| 1: [IntLiteral] 1 +# 34| 1: [MulExpr] ... * ... +# 34| 0: [LocalVariableAccess] access to local variable next +# 34| 1: [IntLiteral] 2 +# 35| 1: [LocalVariableAccess] access to local variable b +# 35| 2: [LocalVariableAccess] access to local variable next +# 30| 1: [LocalVariableAccess] access to local variable list6 +# 37| 6: [LocalVariableDeclStmt] ... ...; +# 37| 0: [LocalVariableDeclAndInitExpr] B list7 = ... +# 37| 0: [ObjectCreation] object creation of type B +# 37| 1: [LocalVariableAccess] access to local variable list7 +# 39| 7: [LocalVariableDeclStmt] ... ...; +# 39| 0: [LocalVariableDeclAndInitExpr] IEnumerable list8 = ... +# 41| 0: [MethodCall] call to method Select +# 40| 0: [LocalVariableDeclAndInitExpr] Object a = ... +# 40| 0: [LocalVariableAccess] access to local variable list7 +# 40| 1: [LocalVariableAccess] access to local variable a +# 41| 1: [LocalVariableAccess] access to local variable a +# 39| 1: [LocalVariableAccess] access to local variable list8 +# 43| 8: [LocalVariableDeclStmt] ... ...; +# 43| 0: [LocalVariableDeclAndInitExpr] C list9 = ... +# 43| 0: [ObjectCreation] object creation of type C +# 43| 1: [LocalVariableAccess] access to local variable list9 +# 45| 9: [LocalVariableDeclStmt] ... ...; +# 45| 0: [LocalVariableDeclAndInitExpr] IEnumerable list10 = ... +# 47| 0: [MethodCall] call to method Select +# 46| 0: [LocalVariableDeclAndInitExpr] Int32 a = ... +# 46| 0: [LocalVariableAccess] access to local variable list9 +# 46| 1: [LocalVariableAccess] access to local variable a +# 47| 1: [LocalVariableAccess] access to local variable a +# 45| 1: [LocalVariableAccess] access to local variable list10 +# 49| 10: [LocalVariableDeclStmt] ... ...; +# 49| 0: [LocalVariableDeclAndInitExpr] IEnumerable list11 = ... +# 51| 0: [MethodCall] call to method Select +# 50| 0: [LocalVariableDeclAndInitExpr] String a = ... +# 50| 0: [LocalVariableAccess] access to local variable list7 +# 50| 1: [LocalVariableAccess] access to local variable a +# 51| 1: [LocalVariableAccess] access to local variable a +# 49| 1: [LocalVariableAccess] access to local variable list11 +# 53| 11: [LocalVariableDeclStmt] ... ...; +# 53| 0: [LocalVariableDeclAndInitExpr] IEnumerable<(Int32,IEnumerable>)> list12 = ... +# 56| 0: [MethodCall] call to method +# 55| 0: [MethodCall] call to method GroupJoin +# 54| 0: [LocalVariableDeclAndInitExpr] Int32 a = ... +# 54| 0: [LocalVariableAccess] access to local variable list1 +# 54| 1: [LocalVariableAccess] access to local variable a +# 55| 1: [LocalVariableDeclAndInitExpr] IList> c = ... +# 55| 0: [LocalVariableAccess] access to local variable list2 +# 55| 1: [LocalVariableAccess] access to local variable c +# 55| 2: [LocalVariableAccess] access to local variable list2 +# 55| 3: [LocalVariableAccess] access to local variable a +# 55| 4: [IndexerCall] access to indexer +# 55| -1: [LocalVariableAccess] access to local variable c +# 55| 0: [IntLiteral] 0 +# 55| 5: [LocalVariableDeclAndInitExpr] IList> d = ... +# 55| 0: [LocalVariableAccess] access to local variable list2 +# 55| 1: [LocalVariableAccess] access to local variable d +# 56| 1: [TupleExpr] (..., ...) +# 56| 0: [LocalVariableAccess] access to local variable a +# 56| 1: [LocalVariableAccess] access to local variable d +# 53| 1: [LocalVariableAccess] access to local variable list12 +# 59| 6: [Class] A +#-----| 3: (Base types) +# 59| 1: [Interface] IEnumerable +# 61| 5: [Method] GetEnumerator +# 62| 4: [BlockStmt] {...} +# 63| 0: [ThrowStmt] throw ...; +# 63| 0: [ObjectCreation] object creation of type NotImplementedException +# 67| 7: [Class] B +#-----| 3: (Base types) +# 67| 0: [Class] A +# 69| 8: [Class] C +#-----| 3: (Base types) +# 69| 0: [Class] List diff --git a/csharp/ql/test/library-tests/linq/PrintAst.qlref b/csharp/ql/test/library-tests/linq/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/linq/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/members/PrintAst.expected b/csharp/ql/test/library-tests/members/PrintAst.expected new file mode 100644 index 000000000000..3a69ff413dff --- /dev/null +++ b/csharp/ql/test/library-tests/members/PrintAst.expected @@ -0,0 +1,184 @@ +Members.cs: +# 1| [NamespaceDeclaration] namespace ... { ... } +# 3| 1: [DelegateType] EventHandler +#-----| 2: (Parameters) +# 3| 0: [Parameter] sender +# 3| 1: [Parameter] e +# 6| 2: [Class] Class +# 9| 5: [Class] NestedClass +# 12| 5: [Method] Method +#-----| 1: (Type parameters) +# 12| 0: [TypeParameter] T +#-----| 2: (Parameters) +# 12| 0: [Parameter] t +# 12| 4: [MethodCall] call to method ToString +# 12| -1: [ParameterAccess] access to parameter t +# 14| 6: [Indexer] Item +#-----| 1: (Parameters) +# 14| 0: [Parameter] i +# 14| 3: [Getter] get_Item +#-----| 2: (Parameters) +# 14| 0: [Parameter] i +# 14| 4: [MethodCall] call to method ToString +# 14| -1: [ParameterAccess] access to parameter i +# 14| 4: [Setter] set_Item +#-----| 2: (Parameters) +# 14| 0: [Parameter] i +# 14| 1: [Parameter] value +# 14| 4: [BlockStmt] {...} +# 16| 7: [Field] Field +# 18| 8: [IndexerProperty] Prop +# 18| 3: [Getter] get_Prop +# 18| 4: [Setter] set_Prop +#-----| 2: (Parameters) +# 18| 0: [Parameter] value +# 20| 9: [Event] Event +# 20| 3: [AddEventAccessor] add_Event +#-----| 2: (Parameters) +# 20| 0: [Parameter] value +# 20| 4: [RemoveEventAccessor] remove_Event +#-----| 2: (Parameters) +# 20| 0: [Parameter] value +# 24| 6: [Method] Method +# 24| 4: [BlockStmt] {...} +# 26| 7: [Indexer] Item +#-----| 1: (Parameters) +# 26| 0: [Parameter] i +# 26| 3: [Getter] get_Item +#-----| 2: (Parameters) +# 26| 0: [Parameter] i +# 26| 4: [MethodCall] call to method ToString +# 26| -1: [ParameterAccess] access to parameter i +# 26| 4: [Setter] set_Item +#-----| 2: (Parameters) +# 26| 0: [Parameter] i +# 26| 1: [Parameter] value +# 26| 4: [BlockStmt] {...} +# 28| 8: [Field] Field +# 30| 9: [IndexerProperty] Prop +# 30| 3: [Getter] get_Prop +# 30| 4: [Setter] set_Prop +#-----| 2: (Parameters) +# 30| 0: [Parameter] value +# 32| 10: [Event] Event +# 32| 3: [AddEventAccessor] add_Event +#-----| 2: (Parameters) +# 32| 0: [Parameter] value +# 32| 4: [RemoveEventAccessor] remove_Event +#-----| 2: (Parameters) +# 32| 0: [Parameter] value +# 35| 3: [Class] Class2 +# 37| 5: [Class] NestedClass2 +# 39| 5: [Method] Method +#-----| 1: (Type parameters) +# 39| 0: [TypeParameter] T +#-----| 2: (Parameters) +# 39| 0: [Parameter] t +# 39| 4: [MethodCall] call to method ToString +# 39| -1: [ParameterAccess] access to parameter t +# 40| 6: [Indexer] Item +#-----| 1: (Parameters) +# 40| 0: [Parameter] i +# 40| 3: [Getter] get_Item +#-----| 2: (Parameters) +# 40| 0: [Parameter] i +# 40| 4: [MethodCall] call to method ToString +# 40| -1: [ParameterAccess] access to parameter i +# 40| 4: [Setter] set_Item +#-----| 2: (Parameters) +# 40| 0: [Parameter] i +# 40| 1: [Parameter] value +# 40| 4: [BlockStmt] {...} +# 41| 7: [Field] Field +# 42| 8: [IndexerProperty] Prop +# 42| 3: [Getter] get_Prop +# 42| 4: [Setter] set_Prop +#-----| 2: (Parameters) +# 42| 0: [Parameter] value +# 43| 9: [Event] Event +# 43| 3: [AddEventAccessor] add_Event +#-----| 2: (Parameters) +# 43| 0: [Parameter] value +# 43| 4: [RemoveEventAccessor] remove_Event +#-----| 2: (Parameters) +# 43| 0: [Parameter] value +# 46| 6: [Method] Method +# 46| 4: [BlockStmt] {...} +# 47| 7: [Indexer] Item +#-----| 1: (Parameters) +# 47| 0: [Parameter] i +# 47| 3: [Getter] get_Item +#-----| 2: (Parameters) +# 47| 0: [Parameter] i +# 47| 4: [MethodCall] call to method ToString +# 47| -1: [ParameterAccess] access to parameter i +# 47| 4: [Setter] set_Item +#-----| 2: (Parameters) +# 47| 0: [Parameter] i +# 47| 1: [Parameter] value +# 47| 4: [BlockStmt] {...} +# 48| 8: [Field] Field +# 49| 9: [IndexerProperty] Prop +# 49| 3: [Getter] get_Prop +# 49| 4: [Setter] set_Prop +#-----| 2: (Parameters) +# 49| 0: [Parameter] value +# 50| 10: [Event] Event +# 50| 3: [AddEventAccessor] add_Event +#-----| 2: (Parameters) +# 50| 0: [Parameter] value +# 50| 4: [RemoveEventAccessor] remove_Event +#-----| 2: (Parameters) +# 50| 0: [Parameter] value +# 54| 4: [Interface] Interface +# 56| 4: [Method] Method +# 57| 5: [Indexer] Item +#-----| 1: (Parameters) +# 57| 0: [Parameter] i +# 57| 3: [Getter] get_Item +#-----| 2: (Parameters) +# 57| 0: [Parameter] i +# 57| 4: [Setter] set_Item +#-----| 2: (Parameters) +# 57| 0: [Parameter] i +# 57| 1: [Parameter] value +# 58| 6: [IndexerProperty] Prop +# 58| 3: [Getter] get_Prop +# 58| 4: [Setter] set_Prop +#-----| 2: (Parameters) +# 58| 0: [Parameter] value +# 59| 7: [Event] Event +# 59| 3: [AddEventAccessor] add_Event +#-----| 2: (Parameters) +# 59| 0: [Parameter] value +# 59| 4: [RemoveEventAccessor] remove_Event +#-----| 2: (Parameters) +# 59| 0: [Parameter] value +# 62| 5: [Interface] Interface2 +# 64| 4: [Method] Method +# 65| 5: [Indexer] Item +#-----| 1: (Parameters) +# 65| 0: [Parameter] i +# 65| 3: [Getter] get_Item +#-----| 2: (Parameters) +# 65| 0: [Parameter] i +# 65| 4: [Setter] set_Item +#-----| 2: (Parameters) +# 65| 0: [Parameter] i +# 65| 1: [Parameter] value +# 66| 6: [IndexerProperty] Prop +# 66| 3: [Getter] get_Prop +# 66| 4: [Setter] set_Prop +#-----| 2: (Parameters) +# 66| 0: [Parameter] value +# 67| 7: [Event] Event +# 67| 3: [AddEventAccessor] add_Event +#-----| 2: (Parameters) +# 67| 0: [Parameter] value +# 67| 4: [RemoveEventAccessor] remove_Event +#-----| 2: (Parameters) +# 67| 0: [Parameter] value +# 71| 6: [Enum] Enum +# 73| 7: [Enum] Enum2 +# 76| 8: [Struct] Struct +# 78| 9: [Struct] Struct2 diff --git a/csharp/ql/test/library-tests/members/PrintAst.qlref b/csharp/ql/test/library-tests/members/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/members/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/methods/PrintAst.expected b/csharp/ql/test/library-tests/methods/PrintAst.expected new file mode 100644 index 000000000000..f1fcd161bb39 --- /dev/null +++ b/csharp/ql/test/library-tests/methods/PrintAst.expected @@ -0,0 +1,367 @@ +methods.cs: +# 3| [NamespaceDeclaration] namespace ... { ... } +# 6| 1: [Class] TestRef +# 9| 5: [Method] Swap +#-----| 2: (Parameters) +# 9| 0: [Parameter] x +# 9| 1: [Parameter] y +# 10| 4: [BlockStmt] {...} +# 11| 0: [LocalVariableDeclStmt] ... ...; +# 11| 0: [LocalVariableDeclAndInitExpr] Int32 temp = ... +# 11| 0: [ParameterAccess] access to parameter x +# 11| 1: [LocalVariableAccess] access to local variable temp +# 12| 1: [ExprStmt] ...; +# 12| 0: [AssignExpr] ... = ... +# 12| 0: [ParameterAccess] access to parameter y +# 12| 1: [ParameterAccess] access to parameter x +# 13| 2: [ExprStmt] ...; +# 13| 0: [AssignExpr] ... = ... +# 13| 0: [LocalVariableAccess] access to local variable temp +# 13| 1: [ParameterAccess] access to parameter y +# 16| 6: [Method] Main +# 17| 4: [BlockStmt] {...} +# 18| 0: [LocalVariableDeclStmt] ... ...; +# 18| 0: [LocalVariableDeclAndInitExpr] Int32 i = ... +# 18| 0: [IntLiteral] 1 +# 18| 1: [LocalVariableAccess] access to local variable i +# 18| 1: [LocalVariableDeclAndInitExpr] Int32 j = ... +# 18| 0: [IntLiteral] 2 +# 18| 1: [LocalVariableAccess] access to local variable j +# 19| 1: [ExprStmt] ...; +# 19| 0: [MethodCall] call to method Swap +# 19| 0: [LocalVariableAccess] access to local variable i +# 19| 1: [LocalVariableAccess] access to local variable j +# 20| 2: [ExprStmt] ...; +# 20| 0: [MethodCall] call to method WriteLine +# 20| -1: [TypeAccess] access to type Console +# 20| 0: [StringLiteral] "{0} {1}" +# 20| 1: [CastExpr] (...) ... +# 20| 0: [LocalVariableAccess] access to local variable i +# 20| 2: [CastExpr] (...) ... +# 20| 0: [LocalVariableAccess] access to local variable j +# 21| 3: [ExprStmt] ...; +# 21| 0: [MethodCall] call to method WriteLine +# 21| -1: [TypeAccess] access to type Console +# 21| 0: [StringLiteral] "{0} {1}" +# 21| 1: [CastExpr] (...) ... +# 21| 0: [LocalVariableAccess] access to local variable i +# 21| 2: [CastExpr] (...) ... +# 21| 0: [LocalVariableAccess] access to local variable j +# 25| 2: [Class] TestOut +# 28| 5: [Method] Divide +#-----| 2: (Parameters) +# 28| 0: [Parameter] x +# 28| 1: [Parameter] y +# 28| 2: [Parameter] result +# 28| 3: [Parameter] remainder +# 29| 4: [BlockStmt] {...} +# 30| 0: [ExprStmt] ...; +# 30| 0: [AssignExpr] ... = ... +# 30| 0: [DivExpr] ... / ... +# 30| 0: [ParameterAccess] access to parameter x +# 30| 1: [ParameterAccess] access to parameter y +# 30| 1: [ParameterAccess] access to parameter result +# 31| 1: [ExprStmt] ...; +# 31| 0: [AssignExpr] ... = ... +# 31| 0: [RemExpr] ... % ... +# 31| 0: [ParameterAccess] access to parameter x +# 31| 1: [ParameterAccess] access to parameter y +# 31| 1: [ParameterAccess] access to parameter remainder +# 34| 6: [Method] Main +# 35| 4: [BlockStmt] {...} +# 36| 0: [LocalVariableDeclStmt] ... ...; +# 36| 0: [LocalVariableDeclExpr] Int32 res +# 36| 1: [LocalVariableDeclExpr] Int32 rem +# 37| 1: [ExprStmt] ...; +# 37| 0: [MethodCall] call to method Divide +# 37| 0: [IntLiteral] 10 +# 37| 1: [IntLiteral] 3 +# 37| 2: [LocalVariableAccess] access to local variable res +# 37| 3: [LocalVariableAccess] access to local variable rem +# 38| 2: [ExprStmt] ...; +# 38| 0: [MethodCall] call to method WriteLine +# 38| -1: [TypeAccess] access to type Console +# 38| 0: [StringLiteral] "{0} {1}" +# 38| 1: [CastExpr] (...) ... +# 38| 0: [LocalVariableAccess] access to local variable res +# 38| 2: [CastExpr] (...) ... +# 38| 0: [LocalVariableAccess] access to local variable rem +# 42| 3: [Class] Console +# 45| 5: [Method] Write +#-----| 2: (Parameters) +# 45| 0: [Parameter] fmt +# 45| 1: [Parameter] args +# 45| 4: [BlockStmt] {...} +# 46| 6: [Method] WriteLine +#-----| 2: (Parameters) +# 46| 0: [Parameter] fmt +# 46| 1: [Parameter] args +# 46| 4: [BlockStmt] {...} +# 49| 4: [Class] TestOverloading +# 52| 5: [Method] F +# 53| 4: [BlockStmt] {...} +# 54| 0: [ExprStmt] ...; +# 54| 0: [MethodCall] call to method WriteLine +# 54| -1: [TypeAccess] access to type Console +# 54| 0: [StringLiteral] "F()" +# 57| 6: [Method] F +#-----| 2: (Parameters) +# 57| 0: [Parameter] x +# 58| 4: [BlockStmt] {...} +# 59| 0: [ExprStmt] ...; +# 59| 0: [MethodCall] call to method WriteLine +# 59| -1: [TypeAccess] access to type Console +# 59| 0: [StringLiteral] "F(object)" +# 62| 7: [Method] F +#-----| 2: (Parameters) +# 62| 0: [Parameter] x +# 63| 4: [BlockStmt] {...} +# 64| 0: [ExprStmt] ...; +# 64| 0: [MethodCall] call to method WriteLine +# 64| -1: [TypeAccess] access to type Console +# 64| 0: [StringLiteral] "F(int)" +# 67| 8: [Method] F +#-----| 2: (Parameters) +# 67| 0: [Parameter] x +# 68| 4: [BlockStmt] {...} +# 69| 0: [ExprStmt] ...; +# 69| 0: [MethodCall] call to method WriteLine +# 69| -1: [TypeAccess] access to type Console +# 69| 0: [StringLiteral] "F(double)" +# 72| 9: [Method] F +#-----| 1: (Type parameters) +# 72| 0: [TypeParameter] T +#-----| 2: (Parameters) +# 72| 0: [Parameter] x +# 73| 4: [BlockStmt] {...} +# 74| 0: [ExprStmt] ...; +# 74| 0: [MethodCall] call to method WriteLine +# 74| -1: [TypeAccess] access to type Console +# 74| 0: [StringLiteral] "F(T)" +# 77| 12: [Method] F +#-----| 2: (Parameters) +# 77| 0: [Parameter] x +# 77| 1: [Parameter] y +# 78| 4: [BlockStmt] {...} +# 79| 0: [ExprStmt] ...; +# 79| 0: [MethodCall] call to method WriteLine +# 79| -1: [TypeAccess] access to type Console +# 79| 0: [StringLiteral] "F(double, double)" +# 82| 13: [Method] Main +# 83| 4: [BlockStmt] {...} +# 84| 0: [ExprStmt] ...; +# 84| 0: [MethodCall] call to method F +# 85| 1: [ExprStmt] ...; +# 85| 0: [MethodCall] call to method F +# 85| 0: [IntLiteral] 1 +# 86| 2: [ExprStmt] ...; +# 86| 0: [MethodCall] call to method F +# 86| 0: [DoubleLiteral] 1 +# 87| 3: [ExprStmt] ...; +# 87| 0: [MethodCall] call to method F +# 87| 0: [StringLiteral] "abc" +# 88| 4: [ExprStmt] ...; +# 88| 0: [MethodCall] call to method F +# 88| 0: [CastExpr] (...) ... +# 88| 0: [IntLiteral] 1 +# 88| 1: [TypeAccess] access to type Double +# 89| 5: [ExprStmt] ...; +# 89| 0: [MethodCall] call to method F +# 89| 0: [CastExpr] (...) ... +# 89| 0: [IntLiteral] 1 +# 89| 1: [TypeAccess] access to type Object +# 90| 6: [ExprStmt] ...; +# 90| 0: [MethodCall] call to method F +# 90| 0: [IntLiteral] 1 +# 91| 7: [ExprStmt] ...; +# 91| 0: [MethodCall] call to method F +# 91| 0: [CastExpr] (...) ... +# 91| 0: [IntLiteral] 1 +# 91| 1: [CastExpr] (...) ... +# 91| 0: [IntLiteral] 1 +# 96| 5: [Class] Extensions +# 99| 4: [ExtensionMethod] ToInt32 +#-----| 2: (Parameters) +# 99| 0: [Parameter] s +# 100| 4: [BlockStmt] {...} +# 101| 0: [ReturnStmt] return ...; +# 101| 0: [MethodCall] call to method Parse +# 101| -1: [TypeAccess] access to type Int32 +# 101| 0: [ParameterAccess] access to parameter s +# 104| 5: [ExtensionMethod] ToBool +#-----| 2: (Parameters) +# 104| 0: [Parameter] s +# 104| 1: [Parameter] f +# 105| 4: [BlockStmt] {...} +# 106| 0: [ReturnStmt] return ...; +# 106| 0: [DelegateCall] delegate call +# 106| -1: [ParameterAccess] access to parameter f +# 106| 0: [ParameterAccess] access to parameter s +# 109| 6: [ExtensionMethod] Slice +#-----| 1: (Type parameters) +# 109| 0: [TypeParameter] T +#-----| 2: (Parameters) +# 109| 0: [Parameter] source +# 109| 1: [Parameter] index +# 109| 2: [Parameter] count +# 110| 4: [BlockStmt] {...} +# 111| 0: [IfStmt] if (...) ... +# 111| 0: [LogicalOrExpr] ... || ... +# 111| 0: [LogicalOrExpr] ... || ... +# 111| 0: [LTExpr] ... < ... +# 111| 0: [ParameterAccess] access to parameter index +# 111| 1: [IntLiteral] 0 +# 111| 1: [LTExpr] ... < ... +# 111| 0: [ParameterAccess] access to parameter count +# 111| 1: [IntLiteral] 0 +# 111| 1: [LTExpr] ... < ... +# 111| 0: [SubExpr] ... - ... +# 111| 0: [PropertyCall] access to property Length +# 111| -1: [ParameterAccess] access to parameter source +# 111| 1: [ParameterAccess] access to parameter index +# 111| 1: [ParameterAccess] access to parameter count +# 112| 1: [ThrowStmt] throw ...; +# 112| 0: [ObjectCreation] object creation of type ArgumentException +# 113| 1: [LocalVariableDeclStmt] ... ...; +# 113| 0: [LocalVariableDeclAndInitExpr] T[] result = ... +# 113| 0: [ArrayCreation] array creation of type T[] +# 113| 0: [ParameterAccess] access to parameter count +# 113| 1: [LocalVariableAccess] access to local variable result +# 114| 2: [ExprStmt] ...; +# 114| 0: [MethodCall] call to method Copy +# 114| -1: [TypeAccess] access to type Array +# 114| 0: [ParameterAccess] access to parameter source +# 114| 1: [ParameterAccess] access to parameter index +# 114| 2: [LocalVariableAccess] access to local variable result +# 114| 3: [IntLiteral] 0 +# 114| 4: [ParameterAccess] access to parameter count +# 115| 3: [ReturnStmt] return ...; +# 115| 0: [LocalVariableAccess] access to local variable result +# 118| 8: [Method] CallToInt32 +# 118| 4: [MethodCall] call to method ToInt32 +# 118| 0: [StringLiteral] "0" +# 121| 6: [Class] TestExtensions +# 124| 4: [Method] Main +# 125| 4: [BlockStmt] {...} +# 126| 0: [LocalVariableDeclStmt] ... ...; +# 126| 0: [LocalVariableDeclAndInitExpr] String[] strings = ... +# 126| 0: [ArrayCreation] array creation of type String[] +# 126| -1: [ArrayInitializer] { ..., ... } +# 126| 0: [StringLiteral] "1" +# 126| 1: [StringLiteral] "22" +# 126| 2: [StringLiteral] "333" +# 126| 3: [StringLiteral] "4444" +# 126| 1: [LocalVariableAccess] access to local variable strings +# 127| 1: [ForeachStmt] foreach (... ... in ...) ... +# 127| 0: [LocalVariableDeclExpr] String s +# 127| 1: [MethodCall] call to method Slice +# 127| -1: [LocalVariableAccess] access to local variable strings +# 127| 0: [IntLiteral] 1 +# 127| 1: [IntLiteral] 2 +# 128| 2: [BlockStmt] {...} +# 129| 0: [ExprStmt] ...; +# 129| 0: [MethodCall] call to method WriteLine +# 129| -1: [TypeAccess] access to type Console +# 129| 0: [MethodCall] call to method ToInt32 +# 129| -1: [LocalVariableAccess] access to local variable s +# 132| 2: [ExprStmt] ...; +# 132| 0: [MethodCall] call to method ToInt32 +# 132| -1: [TypeAccess] access to type Extensions +# 132| 0: [StringLiteral] "" +# 134| 3: [ExprStmt] ...; +# 134| 0: [MethodCall] call to method ToBool +# 134| -1: [TypeAccess] access to type Extensions +# 134| 0: [StringLiteral] "true" +# 134| 1: [ImplicitDelegateCreation] delegate creation of type Func +# 134| 0: [MethodAccess] access to method Parse +# 134| -1: [TypeAccess] access to type Boolean +# 139| 7: [Class] TestDefaultParameters +# 141| 4: [Method] Method1 +#-----| 2: (Parameters) +# 141| 0: [Parameter] x +# 141| 1: [Parameter] y +# 142| 4: [BlockStmt] {...} +# 145| 5: [Method] Method2 +#-----| 2: (Parameters) +# 145| 0: [Parameter] a +# 145| 1: [Parameter] b +# 145| 2: [Parameter] c +# 145| 1: [IntLiteral] 1 +# 145| 3: [Parameter] d +# 145| 1: [IntLiteral] 2 +# 145| 4: [Parameter] e +# 145| 1: [AddExpr] ... + ... +# 145| 0: [StringLiteral] "a" +# 145| 1: [StringLiteral] "b" +# 146| 4: [BlockStmt] {...} +# 149| 6: [InstanceConstructor] TestDefaultParameters +#-----| 2: (Parameters) +# 149| 0: [Parameter] x +# 150| 4: [BlockStmt] {...} +# 153| 7: [InstanceConstructor] TestDefaultParameters +#-----| 2: (Parameters) +# 153| 0: [Parameter] x +# 153| 1: [StringLiteral] "abc" +# 153| 1: [Parameter] y +# 153| 1: [ObjectCreation] object creation of type Double +# 154| 4: [BlockStmt] {...} +# 157| 8: [DelegateType] Del +#-----| 2: (Parameters) +# 157| 0: [Parameter] a +# 157| 1: [Parameter] b +# 157| 1: [IntLiteral] 12 +# 157| 2: [Parameter] c +# 157| 1: [ObjectCreation] object creation of type Double +# 159| 9: [Indexer] Item +#-----| 1: (Parameters) +# 159| 0: [Parameter] x +# 159| 1: [Parameter] y +# 159| 1: [IntLiteral] 0 +# 161| 3: [Getter] get_Item +#-----| 2: (Parameters) +# 159| 0: [Parameter] x +# 159| 1: [Parameter] y +# 159| 1: [IntLiteral] 0 +# 161| 4: [BlockStmt] {...} +# 161| 0: [ReturnStmt] return ...; +# 161| 0: [AddExpr] ... + ... +# 161| 0: [ParameterAccess] access to parameter x +# 161| 1: [ParameterAccess] access to parameter y +# 162| 4: [Setter] set_Item +#-----| 2: (Parameters) +# 159| 0: [Parameter] x +# 159| 1: [Parameter] y +# 159| 1: [IntLiteral] 0 +# 162| 2: [Parameter] value +# 162| 4: [BlockStmt] {...} +# 166| 8: [Class] TestDefaultExtensionParameters +# 168| 4: [ExtensionMethod] Plus +#-----| 2: (Parameters) +# 168| 0: [Parameter] left +# 168| 1: [Parameter] right +# 168| 1: [IntLiteral] 0 +# 169| 4: [BlockStmt] {...} +# 170| 0: [ReturnStmt] return ...; +# 170| 0: [AddExpr] ... + ... +# 170| 0: [ParameterAccess] access to parameter left +# 170| 1: [ParameterAccess] access to parameter right +# 173| 5: [ExtensionMethod] SkipTwo +#-----| 1: (Type parameters) +# 173| 0: [TypeParameter] T +#-----| 2: (Parameters) +# 173| 0: [Parameter] list +# 173| 1: [Parameter] i +# 173| 1: [IntLiteral] 1 +# 174| 4: [BlockStmt] {...} +# 175| 0: [ReturnStmt] return ...; +# 175| 0: [ParameterAccess] access to parameter list +# 178| 7: [ExtensionMethod] SkipTwoInt +#-----| 2: (Parameters) +# 178| 0: [Parameter] list +# 178| 1: [Parameter] i +# 178| 1: [IntLiteral] 1 +# 179| 4: [BlockStmt] {...} +# 180| 0: [ReturnStmt] return ...; +# 180| 0: [MethodCall] call to method SkipTwo +# 180| -1: [ParameterAccess] access to parameter list +# 180| 0: [ParameterAccess] access to parameter i diff --git a/csharp/ql/test/library-tests/methods/PrintAst.qlref b/csharp/ql/test/library-tests/methods/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/methods/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/namespaces/PrintAst.expected b/csharp/ql/test/library-tests/namespaces/PrintAst.expected new file mode 100644 index 000000000000..8025fdf4553b --- /dev/null +++ b/csharp/ql/test/library-tests/namespaces/PrintAst.expected @@ -0,0 +1,37 @@ +namespaces.cs: +# 5| [NamespaceDeclaration] namespace ... { ... } +# 8| 1: [Class] A +# 9| 2: [Class] B +# 13| [NamespaceDeclaration] namespace ... { ... } +# 16| 1: [NamespaceDeclaration] namespace ... { ... } +# 19| 1: [Class] A +# 20| 2: [Class] B +# 26| [NamespaceDeclaration] namespace ... { ... } +# 29| 1: [Class] A +# 33| [NamespaceDeclaration] namespace ... { ... } +# 36| 1: [Class] B +# 38| 2: [Struct] S +# 40| 3: [Interface] I +# 44| [NamespaceDeclaration] namespace ... { ... } +# 50| [NamespaceDeclaration] namespace ... { ... } +# 53| 1: [Class] A +# 57| [NamespaceDeclaration] namespace ... { ... } +# 64| 1: [Class] B +#-----| 3: (Base types) +# 64| 0: [Class] A +# 66| 2: [Class] C +#-----| 3: (Base types) +# 66| 0: [Class] A +# 70| [NamespaceDeclaration] namespace ... { ... } +# 73| 1: [Class] A<> +#-----| 1: (Type parameters) +# 73| 0: [TypeParameter] T +# 76| 5: [Class] B +# 80| 2: [Class] A +# 84| [NamespaceDeclaration] namespace ... { ... } +# 91| [NamespaceDeclaration] namespace ... { ... } +# 94| 1: [Class] A +# 97| [NamespaceDeclaration] namespace ... { ... } +# 102| 1: [Class] B +#-----| 3: (Base types) +# 102| 0: [Class] A diff --git a/csharp/ql/test/library-tests/namespaces/PrintAst.qlref b/csharp/ql/test/library-tests/namespaces/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/namespaces/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/nestedtypes/PrintAst.expected b/csharp/ql/test/library-tests/nestedtypes/PrintAst.expected new file mode 100644 index 000000000000..275afe9a2bc9 --- /dev/null +++ b/csharp/ql/test/library-tests/nestedtypes/PrintAst.expected @@ -0,0 +1,77 @@ +nestedtypes.cs: +# 5| [NamespaceDeclaration] namespace ... { ... } +# 8| 1: [Class] Base +# 11| 5: [Struct] S +# 13| 6: [Interface] I +# 15| 7: [DelegateType] MyDelegate +#-----| 2: (Parameters) +# 15| 0: [Parameter] s +# 17| 8: [Method] F +# 18| 4: [BlockStmt] {...} +# 19| 0: [ExprStmt] ...; +# 19| 0: [MethodCall] call to method WriteLine +# 19| -1: [TypeAccess] access to type Console +# 19| 0: [StringLiteral] "Base.F" +# 22| 9: [Class] C +# 26| 2: [Class] Derived +#-----| 3: (Base types) +# 26| 0: [Class] Base +# 29| 5: [Class] Nested +# 32| 5: [Method] G +# 33| 4: [BlockStmt] {...} +# 34| 0: [LocalVariableDeclStmt] ... ...; +# 34| 0: [LocalVariableDeclAndInitExpr] Derived d = ... +# 34| 0: [ObjectCreation] object creation of type Derived +# 34| 1: [LocalVariableAccess] access to local variable d +# 35| 1: [ExprStmt] ...; +# 35| 0: [MethodCall] call to method F +# 35| -1: [LocalVariableAccess] access to local variable d +# 42| 3: [Class] Test +# 45| 5: [Method] Main +# 46| 4: [BlockStmt] {...} +# 47| 0: [LocalVariableDeclStmt] ... ...; +# 47| 0: [LocalVariableDeclAndInitExpr] Nested n = ... +# 47| 0: [ObjectCreation] object creation of type Nested +# 47| 1: [LocalVariableAccess] access to local variable n +# 48| 1: [ExprStmt] ...; +# 48| 0: [MethodCall] call to method G +# 48| -1: [LocalVariableAccess] access to local variable n +# 53| 4: [Class] Outer<> +#-----| 1: (Type parameters) +# 53| 0: [TypeParameter] T +# 56| 5: [Class] Inner<> +#-----| 1: (Type parameters) +# 56| 0: [TypeParameter] U +# 59| 5: [Method] F +#-----| 2: (Parameters) +# 59| 0: [Parameter] t +# 59| 1: [Parameter] u +# 59| 4: [BlockStmt] {...} +# 63| 7: [Method] F +#-----| 2: (Parameters) +# 63| 0: [Parameter] t +# 64| 4: [BlockStmt] {...} +# 65| 0: [ExprStmt] ...; +# 65| 0: [MethodCall] call to method F +# 65| -1: [TypeAccess] access to type Inner +# 65| -1: [TypeAccess] access to type Outer<> +# 65| 0: [ParameterAccess] access to parameter t +# 65| 1: [StringLiteral] "abc" +# 68| 1: [ExprStmt] ...; +# 68| 0: [MethodCall] call to method F +# 68| -1: [TypeAccess] access to type Inner +# 68| -1: [TypeAccess] access to type Outer +# 68| 0: [IntLiteral] 3 +# 68| 1: [StringLiteral] "abc" +# 69| 2: [LocalVariableDeclStmt] ... ...; +# 69| 0: [LocalVariableDeclAndInitExpr] Type type = ... +# 69| 0: [TypeofExpr] typeof(...) +# 69| 0: [TypeAccess] access to type Inner<> +# 69| 1: [LocalVariableAccess] access to local variable type +# 74| 5: [Class] Outer2<> +#-----| 1: (Type parameters) +# 74| 0: [TypeParameter] T +# 77| 5: [Class] Inner2<> +#-----| 1: (Type parameters) +# 77| 0: [TypeParameter] T +# 80| 5: [Field] t diff --git a/csharp/ql/test/library-tests/nestedtypes/PrintAst.qlref b/csharp/ql/test/library-tests/nestedtypes/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/nestedtypes/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/operators/PrintAst.expected b/csharp/ql/test/library-tests/operators/PrintAst.expected new file mode 100644 index 000000000000..2aa62e022ca7 --- /dev/null +++ b/csharp/ql/test/library-tests/operators/PrintAst.expected @@ -0,0 +1,129 @@ +operators.cs: +# 5| [NamespaceDeclaration] namespace ... { ... } +# 7| 1: [Class] IntVector +# 10| 4: [InstanceConstructor] IntVector +#-----| 2: (Parameters) +# 10| 0: [Parameter] length +# 10| 4: [BlockStmt] {...} +# 12| 5: [Property] Length +# 12| 3: [Getter] get_Length +# 12| 4: [BlockStmt] {...} +# 12| 0: [ReturnStmt] return ...; +# 12| 0: [IntLiteral] 4 +# 14| 6: [Indexer] Item +#-----| 1: (Parameters) +# 14| 0: [Parameter] index +# 14| 3: [Getter] get_Item +#-----| 2: (Parameters) +# 14| 0: [Parameter] index +# 14| 4: [BlockStmt] {...} +# 14| 0: [ReturnStmt] return ...; +# 14| 0: [IntLiteral] 0 +# 14| 4: [Setter] set_Item +#-----| 2: (Parameters) +# 14| 0: [Parameter] index +# 14| 1: [Parameter] value +# 14| 4: [BlockStmt] {...} +# 16| 7: [IncrementOperator] ++ +#-----| 2: (Parameters) +# 16| 0: [Parameter] iv +# 17| 4: [BlockStmt] {...} +# 18| 0: [LocalVariableDeclStmt] ... ...; +# 18| 0: [LocalVariableDeclAndInitExpr] IntVector temp = ... +# 18| 0: [ObjectCreation] object creation of type IntVector +# 18| 0: [PropertyCall] access to property Length +# 18| -1: [ParameterAccess] access to parameter iv +# 18| 1: [LocalVariableAccess] access to local variable temp +# 19| 1: [ForStmt] for (...;...;...) ... +# 19| -1: [LocalVariableDeclAndInitExpr] Int32 i = ... +# 19| 0: [IntLiteral] 0 +# 19| 1: [LocalVariableAccess] access to local variable i +# 19| 0: [LTExpr] ... < ... +# 19| 0: [LocalVariableAccess] access to local variable i +# 19| 1: [PropertyCall] access to property Length +# 19| -1: [ParameterAccess] access to parameter iv +# 19| 1: [PostIncrExpr] ...++ +# 19| 0: [LocalVariableAccess] access to local variable i +# 20| 2: [ExprStmt] ...; +# 20| 0: [AssignExpr] ... = ... +# 20| 0: [AddExpr] ... + ... +# 20| 0: [IndexerCall] access to indexer +# 20| -1: [ParameterAccess] access to parameter iv +# 20| 0: [LocalVariableAccess] access to local variable i +# 20| 1: [IntLiteral] 1 +# 20| 1: [IndexerCall] access to indexer +# 20| -1: [LocalVariableAccess] access to local variable temp +# 20| 0: [LocalVariableAccess] access to local variable i +# 21| 2: [ReturnStmt] return ...; +# 21| 0: [LocalVariableAccess] access to local variable temp +# 26| 2: [Class] TestUnaryOperator +# 29| 5: [Method] Main +# 30| 4: [BlockStmt] {...} +# 31| 0: [LocalVariableDeclStmt] ... ...; +# 31| 0: [LocalVariableDeclAndInitExpr] IntVector iv1 = ... +# 31| 0: [ObjectCreation] object creation of type IntVector +# 31| 0: [IntLiteral] 4 +# 31| 1: [LocalVariableAccess] access to local variable iv1 +# 32| 1: [LocalVariableDeclStmt] ... ...; +# 32| 0: [LocalVariableDeclExpr] IntVector iv2 +# 33| 2: [ExprStmt] ...; +# 33| 0: [AssignExpr] ... = ... +# 33| 0: [OperatorCall] call to operator ++ +# 33| 0: [LocalVariableAccess] access to local variable iv1 +# 33| 1: [LocalVariableAccess] access to local variable iv2 +# 34| 3: [ExprStmt] ...; +# 34| 0: [AssignExpr] ... = ... +# 34| 0: [OperatorCall] call to operator ++ +# 34| 0: [LocalVariableAccess] access to local variable iv1 +# 34| 1: [LocalVariableAccess] access to local variable iv2 +# 39| 3: [Struct] Digit +# 42| 5: [Field] value +# 44| 6: [InstanceConstructor] Digit +#-----| 2: (Parameters) +# 44| 0: [Parameter] value +# 45| 4: [BlockStmt] {...} +# 46| 0: [IfStmt] if (...) ... +# 46| 0: [LogicalOrExpr] ... || ... +# 46| 0: [LTExpr] ... < ... +# 46| 0: [CastExpr] (...) ... +# 46| 0: [ParameterAccess] access to parameter value +# 46| 1: [IntLiteral] 0 +# 46| 1: [GTExpr] ... > ... +# 46| 0: [CastExpr] (...) ... +# 46| 0: [ParameterAccess] access to parameter value +# 46| 1: [IntLiteral] 9 +# 47| 1: [ThrowStmt] throw ...; +# 47| 0: [ObjectCreation] object creation of type ArgumentException +# 48| 1: [ExprStmt] ...; +# 48| 0: [AssignExpr] ... = ... +# 48| 0: [ParameterAccess] access to parameter value +# 48| 1: [FieldAccess] access to field value +# 48| -1: [ThisAccess] this access +# 51| 7: [ImplicitConversionOperator] implicit conversion +#-----| 2: (Parameters) +# 51| 0: [Parameter] d +# 52| 4: [BlockStmt] {...} +# 53| 0: [ReturnStmt] return ...; +# 53| 0: [FieldAccess] access to field value +# 53| -1: [ParameterAccess] access to parameter d +# 56| 8: [ExplicitConversionOperator] explicit conversion +#-----| 2: (Parameters) +# 56| 0: [Parameter] b +# 57| 4: [BlockStmt] {...} +# 58| 0: [ReturnStmt] return ...; +# 58| 0: [ObjectCreation] object creation of type Digit +# 58| 0: [ParameterAccess] access to parameter b +# 63| 4: [Class] TestConversionOperator +# 66| 5: [Method] Main +# 67| 4: [BlockStmt] {...} +# 68| 0: [LocalVariableDeclStmt] ... ...; +# 68| 0: [LocalVariableDeclAndInitExpr] Digit d = ... +# 68| 0: [OperatorCall] call to operator explicit conversion +# 68| 0: [CastExpr] (...) ... +# 68| 0: [IntLiteral] 8 +# 68| 1: [LocalVariableAccess] access to local variable d +# 69| 1: [LocalVariableDeclStmt] ... ...; +# 69| 0: [LocalVariableDeclAndInitExpr] Byte b = ... +# 69| 0: [OperatorCall] call to operator implicit conversion +# 69| 0: [LocalVariableAccess] access to local variable d +# 69| 1: [LocalVariableAccess] access to local variable b diff --git a/csharp/ql/test/library-tests/operators/PrintAst.qlref b/csharp/ql/test/library-tests/operators/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/operators/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/partial/MethodIsPartial.expected b/csharp/ql/test/library-tests/partial/MethodIsPartial.expected new file mode 100644 index 000000000000..8ee8f25b0c88 --- /dev/null +++ b/csharp/ql/test/library-tests/partial/MethodIsPartial.expected @@ -0,0 +1,7 @@ +| Partial.cs:3:18:3:39 | PartialMethodWithBody1 | true | +| Partial.cs:4:18:4:42 | PartialMethodWithoutBody1 | true | +| Partial.cs:5:17:5:23 | Method2 | false | +| Partial.cs:11:17:11:23 | Method3 | false | +| Partial.cs:16:18:16:42 | PartialMethodWithoutBody2 | true | +| Partial.cs:17:17:17:23 | Method4 | false | +| Partial.cs:22:17:22:23 | Method5 | false | diff --git a/csharp/ql/test/library-tests/partial/MethodIsPartial.ql b/csharp/ql/test/library-tests/partial/MethodIsPartial.ql new file mode 100644 index 000000000000..b7e50bd5a443 --- /dev/null +++ b/csharp/ql/test/library-tests/partial/MethodIsPartial.ql @@ -0,0 +1,7 @@ +import csharp + +private boolean isPartial(Method m) { if m.isPartial() then result = true else result = false } + +from Method m +where m.fromSource() +select m, isPartial(m) diff --git a/csharp/ql/test/library-tests/partial/Partial.cs b/csharp/ql/test/library-tests/partial/Partial.cs index e8efae8c52ff..1d54614fc86d 100644 --- a/csharp/ql/test/library-tests/partial/Partial.cs +++ b/csharp/ql/test/library-tests/partial/Partial.cs @@ -1,11 +1,23 @@ -partial class A +partial class TwoPartClass { - partial void M(); - public void M2() { } + partial void PartialMethodWithBody1(); + partial void PartialMethodWithoutBody1(); + public void Method2() { } } -partial class A +partial class TwoPartClass { - partial void M() { } - public void M3() { } + partial void PartialMethodWithBody1() { } + public void Method3() { } } + +partial class OnePartPartialClass +{ + partial void PartialMethodWithoutBody2(); + public void Method4() { } +} + +class NonPartialClass +{ + public void Method5() { } +} \ No newline at end of file diff --git a/csharp/ql/test/library-tests/partial/Partial1.expected b/csharp/ql/test/library-tests/partial/Partial1.expected index 3cc137e832fd..722482cac4f1 100644 --- a/csharp/ql/test/library-tests/partial/Partial1.expected +++ b/csharp/ql/test/library-tests/partial/Partial1.expected @@ -1,3 +1,6 @@ -| Partial.cs:1:15:1:15 | A | -| Partial.cs:3:18:3:18 | M | -| Partial.cs:7:15:7:15 | A | +| Partial.cs:1:15:1:26 | TwoPartClass | +| Partial.cs:3:18:3:39 | PartialMethodWithBody1 | +| Partial.cs:4:18:4:42 | PartialMethodWithoutBody1 | +| Partial.cs:8:15:8:26 | TwoPartClass | +| Partial.cs:14:15:14:33 | OnePartPartialClass | +| Partial.cs:16:18:16:42 | PartialMethodWithoutBody2 | diff --git a/csharp/ql/test/library-tests/partial/Partial2.expected b/csharp/ql/test/library-tests/partial/Partial2.expected index 079601bb4971..6723b575fc7d 100644 --- a/csharp/ql/test/library-tests/partial/Partial2.expected +++ b/csharp/ql/test/library-tests/partial/Partial2.expected @@ -1,6 +1,10 @@ -| Partial.cs:1:15:1:15 | A | Partial.cs:3:18:3:18 | M | -| Partial.cs:1:15:1:15 | A | Partial.cs:4:17:4:18 | M2 | -| Partial.cs:1:15:1:15 | A | Partial.cs:10:17:10:18 | M3 | -| Partial.cs:7:15:7:15 | A | Partial.cs:3:18:3:18 | M | -| Partial.cs:7:15:7:15 | A | Partial.cs:4:17:4:18 | M2 | -| Partial.cs:7:15:7:15 | A | Partial.cs:10:17:10:18 | M3 | +| Partial.cs:1:15:1:26 | TwoPartClass | Partial.cs:3:18:3:39 | PartialMethodWithBody1 | +| Partial.cs:1:15:1:26 | TwoPartClass | Partial.cs:4:18:4:42 | PartialMethodWithoutBody1 | +| Partial.cs:1:15:1:26 | TwoPartClass | Partial.cs:5:17:5:23 | Method2 | +| Partial.cs:1:15:1:26 | TwoPartClass | Partial.cs:11:17:11:23 | Method3 | +| Partial.cs:8:15:8:26 | TwoPartClass | Partial.cs:3:18:3:39 | PartialMethodWithBody1 | +| Partial.cs:8:15:8:26 | TwoPartClass | Partial.cs:4:18:4:42 | PartialMethodWithoutBody1 | +| Partial.cs:8:15:8:26 | TwoPartClass | Partial.cs:5:17:5:23 | Method2 | +| Partial.cs:8:15:8:26 | TwoPartClass | Partial.cs:11:17:11:23 | Method3 | +| Partial.cs:14:15:14:33 | OnePartPartialClass | Partial.cs:16:18:16:42 | PartialMethodWithoutBody2 | +| Partial.cs:14:15:14:33 | OnePartPartialClass | Partial.cs:17:17:17:23 | Method4 | diff --git a/csharp/ql/test/library-tests/partial/PartialMethodBody.expected b/csharp/ql/test/library-tests/partial/PartialMethodBody.expected new file mode 100644 index 000000000000..e6592704f1ae --- /dev/null +++ b/csharp/ql/test/library-tests/partial/PartialMethodBody.expected @@ -0,0 +1,3 @@ +| Partial.cs:3:18:3:39 | PartialMethodWithBody1 | true | +| Partial.cs:4:18:4:42 | PartialMethodWithoutBody1 | false | +| Partial.cs:16:18:16:42 | PartialMethodWithoutBody2 | false | diff --git a/csharp/ql/test/library-tests/partial/PartialMethodBody.ql b/csharp/ql/test/library-tests/partial/PartialMethodBody.ql new file mode 100644 index 000000000000..53cb9be250a7 --- /dev/null +++ b/csharp/ql/test/library-tests/partial/PartialMethodBody.ql @@ -0,0 +1,7 @@ +import csharp + +private boolean hasBody(Method m) { if m.hasBody() then result = true else result = false } + +from Method m +where m.fromSource() and m.isPartial() +select m, hasBody(m) diff --git a/csharp/ql/test/library-tests/partial/PrintAst.expected b/csharp/ql/test/library-tests/partial/PrintAst.expected new file mode 100644 index 000000000000..c250c86c66dd --- /dev/null +++ b/csharp/ql/test/library-tests/partial/PrintAst.expected @@ -0,0 +1,16 @@ +Partial.cs: +# 1| [Class] TwoPartClass +# 3| 5: [Method] PartialMethodWithBody1 +# 10| 4: [BlockStmt] {...} +# 4| 6: [Method] PartialMethodWithoutBody1 +# 5| 7: [Method] Method2 +# 5| 4: [BlockStmt] {...} +# 11| 8: [Method] Method3 +# 11| 4: [BlockStmt] {...} +# 14| [Class] OnePartPartialClass +# 16| 5: [Method] PartialMethodWithoutBody2 +# 17| 6: [Method] Method4 +# 17| 4: [BlockStmt] {...} +# 20| [Class] NonPartialClass +# 22| 5: [Method] Method5 +# 22| 4: [BlockStmt] {...} diff --git a/csharp/ql/test/library-tests/partial/PrintAst.qlref b/csharp/ql/test/library-tests/partial/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/partial/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/properties/PrintAst.expected b/csharp/ql/test/library-tests/properties/PrintAst.expected new file mode 100644 index 000000000000..8d3daf118f52 --- /dev/null +++ b/csharp/ql/test/library-tests/properties/PrintAst.expected @@ -0,0 +1,194 @@ +properties.cs: +# 5| [NamespaceDeclaration] namespace ... { ... } +# 7| 1: [Class] Button +# 10| 5: [Field] caption +# 12| 6: [IndexerProperty] Caption +# 15| 3: [Getter] get_Caption +# 15| 4: [BlockStmt] {...} +# 15| 0: [ReturnStmt] return ...; +# 15| 0: [FieldAccess] access to field caption +# 17| 4: [Setter] set_Caption +#-----| 2: (Parameters) +# 17| 0: [Parameter] value +# 18| 4: [BlockStmt] {...} +# 19| 0: [IfStmt] if (...) ... +# 19| 0: [NEExpr] ... != ... +# 19| 0: [FieldAccess] access to field caption +# 19| 1: [ParameterAccess] access to parameter value +# 20| 1: [BlockStmt] {...} +# 21| 0: [ExprStmt] ...; +# 21| 0: [AssignExpr] ... = ... +# 21| 0: [ParameterAccess] access to parameter value +# 21| 1: [FieldAccess] access to field caption +# 26| 7: [Method] Paint +# 27| 4: [BlockStmt] {...} +# 28| 0: [LocalVariableDeclStmt] ... ...; +# 28| 0: [LocalVariableDeclAndInitExpr] Button okButton = ... +# 28| 0: [ObjectCreation] object creation of type Button +# 28| 1: [LocalVariableAccess] access to local variable okButton +# 29| 1: [ExprStmt] ...; +# 29| 0: [AssignExpr] ... = ... +# 29| 0: [StringLiteral] "OK" +# 29| 1: [PropertyCall] access to property Caption +# 29| -1: [LocalVariableAccess] access to local variable okButton +# 30| 2: [LocalVariableDeclStmt] ... ...; +# 30| 0: [LocalVariableDeclAndInitExpr] String s = ... +# 30| 0: [PropertyCall] access to property Caption +# 30| -1: [LocalVariableAccess] access to local variable okButton +# 30| 1: [LocalVariableAccess] access to local variable s +# 34| 2: [Class] Counter +# 37| 5: [Field] next +# 39| 6: [Property] Next +# 41| 3: [Getter] get_Next +# 41| 4: [BlockStmt] {...} +# 41| 0: [ReturnStmt] return ...; +# 41| 0: [PostIncrExpr] ...++ +# 41| 0: [FieldAccess] access to field next +# 46| 3: [Class] Point +# 49| 5: [Property] X +# 49| 3: [Getter] get_X +# 49| 4: [Setter] set_X +#-----| 2: (Parameters) +# 49| 0: [Parameter] value +# 50| 6: [Property] Y +# 50| 3: [Getter] get_Y +# 50| 4: [Setter] set_Y +#-----| 2: (Parameters) +# 50| 0: [Parameter] value +# 54| 4: [Class] ReadOnlyPoint +# 57| 4: [Property] X +# 57| 3: [Getter] get_X +# 57| 4: [Setter] set_X +#-----| 2: (Parameters) +# 57| 0: [Parameter] value +# 58| 5: [Property] Y +# 58| 3: [Getter] get_Y +# 58| 4: [Setter] set_Y +#-----| 2: (Parameters) +# 58| 0: [Parameter] value +# 59| 6: [InstanceConstructor] ReadOnlyPoint +#-----| 2: (Parameters) +# 59| 0: [Parameter] x +# 59| 1: [Parameter] y +# 60| 4: [BlockStmt] {...} +# 61| 0: [ExprStmt] ...; +# 61| 0: [AssignExpr] ... = ... +# 61| 0: [ParameterAccess] access to parameter x +# 61| 1: [PropertyCall] access to property X +# 62| 1: [ExprStmt] ...; +# 62| 0: [AssignExpr] ... = ... +# 62| 0: [ParameterAccess] access to parameter y +# 62| 1: [PropertyCall] access to property Y +# 67| 5: [Class] A +# 69| 5: [Field] y +# 70| 6: [Property] X +# 70| 3: [Getter] get_X +# 70| 4: [BlockStmt] {...} +# 70| 0: [ReturnStmt] return ...; +# 70| 0: [IntLiteral] 0 +# 71| 7: [Property] Y +# 73| 3: [Getter] get_Y +# 73| 4: [BlockStmt] {...} +# 73| 0: [ReturnStmt] return ...; +# 73| 0: [FieldAccess] access to field y +# 74| 4: [Setter] set_Y +#-----| 2: (Parameters) +# 74| 0: [Parameter] value +# 74| 4: [BlockStmt] {...} +# 74| 0: [ExprStmt] ...; +# 74| 0: [AssignExpr] ... = ... +# 74| 0: [ParameterAccess] access to parameter value +# 74| 1: [FieldAccess] access to field y +# 76| 8: [Property] Z +# 76| 3: [Getter] get_Z +# 76| 4: [Setter] set_Z +#-----| 2: (Parameters) +# 76| 0: [Parameter] value +# 79| 6: [Class] B +#-----| 3: (Base types) +# 79| 0: [Class] A +# 81| 5: [Field] z +# 82| 6: [Property] X +# 82| 3: [Getter] get_X +# 82| 4: [BlockStmt] {...} +# 82| 0: [ReturnStmt] return ...; +# 82| 0: [AddExpr] ... + ... +# 82| 0: [PropertyCall] access to property X +# 82| -1: [BaseAccess] base access +# 82| 1: [IntLiteral] 1 +# 83| 7: [Property] Y +# 83| 3: [Setter] set_Y +#-----| 2: (Parameters) +# 83| 0: [Parameter] value +# 83| 4: [BlockStmt] {...} +# 83| 0: [ExprStmt] ...; +# 83| 0: [AssignExpr] ... = ... +# 83| 0: [ConditionalExpr] ... ? ... : ... +# 83| 0: [LTExpr] ... < ... +# 83| 0: [ParameterAccess] access to parameter value +# 83| 1: [IntLiteral] 0 +# 83| 1: [IntLiteral] 0 +# 83| 2: [ParameterAccess] access to parameter value +# 83| 1: [PropertyCall] access to property Y +# 83| -1: [BaseAccess] base access +# 84| 8: [Property] Z +# 86| 3: [Getter] get_Z +# 86| 4: [BlockStmt] {...} +# 86| 0: [ReturnStmt] return ...; +# 86| 0: [FieldAccess] access to field z +# 87| 4: [Setter] set_Z +#-----| 2: (Parameters) +# 87| 0: [Parameter] value +# 87| 4: [BlockStmt] {...} +# 87| 0: [ExprStmt] ...; +# 87| 0: [AssignExpr] ... = ... +# 87| 0: [ParameterAccess] access to parameter value +# 87| 1: [FieldAccess] access to field z +# 91| 7: [Class] Test +# 93| 5: [Property] Init +# 93| 3: [Setter] set_Init +#-----| 2: (Parameters) +# 93| 0: [Parameter] value +# 93| 4: [BlockStmt] {...} +# 94| 6: [Method] Main +# 95| 4: [BlockStmt] {...} +# 96| 0: [LocalVariableDeclStmt] ... ...; +# 96| 0: [LocalVariableDeclAndInitExpr] List ds = ... +# 96| 0: [ObjectCreation] object creation of type List +# 96| 1: [LocalVariableAccess] access to local variable ds +# 97| 1: [LocalVariableDeclStmt] ... ...; +# 97| 0: [LocalVariableDeclAndInitExpr] List os = ... +# 97| 0: [ObjectCreation] object creation of type List +# 97| 1: [LocalVariableAccess] access to local variable os +# 98| 2: [IfStmt] if (...) ... +# 98| 0: [EQExpr] ... == ... +# 98| 0: [PropertyCall] access to property Count +# 98| -1: [LocalVariableAccess] access to local variable ds +# 98| 1: [PropertyCall] access to property Count +# 98| -1: [LocalVariableAccess] access to local variable os +# 99| 1: [BlockStmt] {...} +# 104| 8: [Interface] InterfaceWithProperties +# 106| 4: [Property] Prop1 +# 106| 3: [Getter] get_Prop1 +# 107| 5: [Property] Prop2 +# 107| 3: [Setter] set_Prop2 +#-----| 2: (Parameters) +# 107| 0: [Parameter] value +# 110| 9: [Class] ImplementsProperties +#-----| 3: (Base types) +# 110| 1: [Interface] InterfaceWithProperties +# 112| 5: [Property] Prop1 +# 114| 3: [Getter] get_Prop1 +# 114| 4: [BlockStmt] {...} +# 114| 0: [ReturnStmt] return ...; +# 114| 0: [IntLiteral] 0 +# 117| 6: [Property] Prop2 +# 119| 3: [Setter] set_Prop2 +#-----| 2: (Parameters) +# 119| 0: [Parameter] value +# 119| 4: [BlockStmt] {...} +# 122| 7: [Property] Prop2 +# 124| 3: [Setter] set_Prop2 +#-----| 2: (Parameters) +# 124| 0: [Parameter] value +# 124| 4: [BlockStmt] {...} diff --git a/csharp/ql/test/library-tests/properties/PrintAst.qlref b/csharp/ql/test/library-tests/properties/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/properties/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/regressions/Program.cs b/csharp/ql/test/library-tests/regressions/Program.cs index e167ef6d7d98..b1a68ae486f3 100644 --- a/csharp/ql/test/library-tests/regressions/Program.cs +++ b/csharp/ql/test/library-tests/regressions/Program.cs @@ -87,7 +87,7 @@ class WhileIs void Test() { object x = null; - while(x is string s) + while (x is string s) { var y = s; } @@ -116,7 +116,7 @@ struct Point void F() { - new Point { x=1, y=2 }; + new Point { x = 1, y = 2 }; } } @@ -130,20 +130,20 @@ void F() class LocalVariableTags { - Func F = x => { int y=x; return y; }; + Func F = x => { int y = x; return y; }; private static Func _getter => (o, n) => { - object x = o; - return x; + object x = o; + return x; }; } -partial class C1 where T: DynamicType +partial class C1 where T : DynamicType { } -partial class C1 where T: DynamicType +partial class C1 where T : DynamicType { } @@ -173,8 +173,8 @@ class UsingDiscard { void F() { - foreach(var _ in new IDisposable[] { }) - using(_) + foreach (var _ in new IDisposable[] { }) + using (_) { } } @@ -189,4 +189,12 @@ class TupleMatching } } +class C2 { } + +class C3 : C2> { } + +class C4 : C2> { } + +class C5 : C4 { } + // semmle-extractor-options: /r:System.Dynamic.Runtime.dll diff --git a/csharp/ql/test/library-tests/regressions/TypeMentions.expected b/csharp/ql/test/library-tests/regressions/TypeMentions.expected index a5628fb53dbe..78bc230e7484 100644 --- a/csharp/ql/test/library-tests/regressions/TypeMentions.expected +++ b/csharp/ql/test/library-tests/regressions/TypeMentions.expected @@ -41,7 +41,7 @@ | Program.cs:75:5:75:7 | Int32 | | Program.cs:87:5:87:8 | Void | | Program.cs:89:9:89:14 | Object | -| Program.cs:90:20:90:25 | String | +| Program.cs:90:21:90:26 | String | | Program.cs:92:13:92:15 | String | | Program.cs:101:16:101:21 | Object | | Program.cs:104:5:104:8 | Void | @@ -63,11 +63,11 @@ | Program.cs:135:25:135:30 | Object | | Program.cs:135:33:135:38 | String | | Program.cs:135:41:135:46 | Object | -| Program.cs:137:10:137:15 | Object | +| Program.cs:137:9:137:14 | Object | | Program.cs:142:27:142:27 | T | -| Program.cs:142:30:142:40 | DynamicType | +| Program.cs:142:31:142:41 | DynamicType | | Program.cs:146:27:146:27 | T | -| Program.cs:146:30:146:40 | DynamicType | +| Program.cs:146:31:146:41 | DynamicType | | Program.cs:156:15:156:35 | TEmbeddedTypesManager | | Program.cs:156:39:156:58 | EmbeddedTypesManager<,> | | Program.cs:156:60:156:80 | TEmbeddedTypesManager | @@ -81,7 +81,7 @@ | Program.cs:164:5:164:12 | Int32*[][] | | Program.cs:169:5:169:10 | String | | Program.cs:174:5:174:8 | Void | -| Program.cs:176:17:176:19 | IDisposable | +| Program.cs:176:18:176:20 | IDisposable | | Program.cs:185:5:185:17 | (Int32,Object) | | Program.cs:185:6:185:8 | Int32 | | Program.cs:185:11:185:16 | Object | @@ -91,3 +91,11 @@ | Program.cs:187:9:187:25 | Nullable<(Object,Object)> | | Program.cs:187:10:187:15 | Object | | Program.cs:187:18:187:23 | Object | +| Program.cs:194:15:194:16 | C2> | +| Program.cs:194:18:194:19 | C4 | +| Program.cs:194:21:194:21 | T | +| Program.cs:196:15:196:16 | C2> | +| Program.cs:196:18:196:19 | C3 | +| Program.cs:196:21:196:21 | T | +| Program.cs:198:12:198:13 | C4 | +| Program.cs:198:15:198:16 | C5 | diff --git a/csharp/ql/test/library-tests/statements/PrintAst.expected b/csharp/ql/test/library-tests/statements/PrintAst.expected new file mode 100644 index 000000000000..11eac4e2c280 --- /dev/null +++ b/csharp/ql/test/library-tests/statements/PrintAst.expected @@ -0,0 +1,579 @@ +fixed.cs: +# 3| [Class] Fixed +# 5| 5: [Method] fixed1 +# 6| 4: [BlockStmt] {...} +# 7| 0: [LocalVariableDeclStmt] ... ...; +# 7| 0: [LocalVariableDeclAndInitExpr] Byte[] buffer = ... +# 7| 0: [ArrayCreation] array creation of type Byte[] +# 7| 0: [IntLiteral] 10 +# 7| 1: [LocalVariableAccess] access to local variable buffer +# 9| 1: [FixedStmt] fixed(...) { ... } +# 9| -1: [LocalVariableDeclAndInitExpr] Byte* pinned_buffer = ... +# 9| 0: [AddressOfExpr] &... +# 9| 0: [ArrayAccess] access to array element +# 9| -1: [LocalVariableAccess] access to local variable buffer +# 9| 0: [IntLiteral] 0 +# 9| 1: [LocalVariableAccess] access to local variable pinned_buffer +# 10| 0: [BlockStmt] {...} +# 11| 0: [LocalVariableDeclStmt] ... ...; +# 11| 0: [LocalVariableDeclAndInitExpr] Byte* t = ... +# 11| 0: [LocalVariableAccess] access to local variable pinned_buffer +# 11| 1: [LocalVariableAccess] access to local variable t +# 12| 1: [ExprStmt] ...; +# 12| 0: [MethodCall] call to method fixed1 +# 15| 2: [FixedStmt] fixed(...) { ... } +# 15| -1: [LocalVariableDeclAndInitExpr] Byte* pinned_buffer = ... +# 15| 0: [AddressOfExpr] &... +# 15| 0: [ArrayAccess] access to array element +# 15| -1: [LocalVariableAccess] access to local variable buffer +# 15| 0: [IntLiteral] 0 +# 15| 1: [LocalVariableAccess] access to local variable pinned_buffer +# 16| 0: [BlockStmt] {...} +# 19| 3: [FixedStmt] fixed(...) { ... } +# 19| -1: [LocalVariableDeclAndInitExpr] Byte* pinned_buffer = ... +# 19| 0: [AddressOfExpr] &... +# 19| 0: [ArrayAccess] access to array element +# 19| -1: [LocalVariableAccess] access to local variable buffer +# 19| 0: [IntLiteral] 0 +# 19| 1: [LocalVariableAccess] access to local variable pinned_buffer +# 19| 0: [EmptyStmt] ; +statements.cs: +# 5| [NamespaceDeclaration] namespace ... { ... } +# 7| 1: [Class] Class +# 10| 5: [Method] Main +# 11| 4: [BlockStmt] {...} +# 12| 0: [LabelStmt] block: +# 13| 1: [BlockStmt] {...} +# 14| 0: [BlockStmt] {...} +# 16| 1: [BlockStmt] {...} +# 17| 0: [BlockStmt] {...} +# 23| 6: [Method] MainEmpty +# 24| 4: [BlockStmt] {...} +# 25| 0: [LocalVariableDeclStmt] ... ...; +# 25| 0: [LocalVariableDeclAndInitExpr] Class c = ... +# 25| 0: [ObjectCreation] object creation of type Class +# 25| 1: [LocalVariableAccess] access to local variable c +# 26| 1: [EmptyStmt] ; +# 26| 2: [EmptyStmt] ; +# 26| 3: [EmptyStmt] ; +# 27| 4: [IfStmt] if (...) ... +# 27| 0: [BoolLiteral] true +# 27| 1: [EmptyStmt] ; +# 30| 7: [Method] MainLocalVarDecl +# 31| 4: [BlockStmt] {...} +# 32| 0: [LocalVariableDeclStmt] ... ...; +# 32| 0: [LocalVariableDeclExpr] Int32 a +# 33| 1: [LocalVariableDeclStmt] ... ...; +# 33| 0: [LocalVariableDeclAndInitExpr] Int32 b = ... +# 33| 0: [IntLiteral] 2 +# 33| 1: [LocalVariableAccess] access to local variable b +# 33| 1: [LocalVariableDeclAndInitExpr] Int32 c = ... +# 33| 0: [IntLiteral] 3 +# 33| 1: [LocalVariableAccess] access to local variable c +# 34| 2: [ExprStmt] ...; +# 34| 0: [AssignExpr] ... = ... +# 34| 0: [IntLiteral] 1 +# 34| 1: [LocalVariableAccess] access to local variable a +# 35| 3: [ExprStmt] ...; +# 35| 0: [MethodCall] call to method WriteLine +# 35| -1: [TypeAccess] access to type Console +# 35| 0: [AddExpr] ... + ... +# 35| 0: [AddExpr] ... + ... +# 35| 0: [LocalVariableAccess] access to local variable a +# 35| 1: [LocalVariableAccess] access to local variable b +# 35| 1: [LocalVariableAccess] access to local variable c +# 36| 4: [LocalVariableDeclStmt] ... ...; +# 36| 0: [LocalVariableDeclAndInitExpr] Int32 x = ... +# 36| 0: [IntLiteral] 45 +# 36| 1: [LocalVariableAccess] access to local variable x +# 37| 5: [LocalVariableDeclStmt] ... ...; +# 37| 0: [LocalVariableDeclAndInitExpr] String y = ... +# 37| 0: [StringLiteral] "test" +# 37| 1: [LocalVariableAccess] access to local variable y +# 40| 8: [Method] MainLocalConstDecl +# 41| 4: [BlockStmt] {...} +# 42| 0: [LocalConstantDeclStmt] const ... ...; +# 42| 0: [LocalVariableDeclAndInitExpr] Single pi = ... +# 42| 0: [FloatLiteral] 3.1415927 +# 42| 1: [LocalVariableAccess] access to local variable pi +# 43| 1: [LocalConstantDeclStmt] const ... ...; +# 43| 0: [LocalVariableDeclAndInitExpr] Int32 r = ... +# 43| 0: [AddExpr] ... + ... +# 43| 0: [IntLiteral] 5 +# 43| 1: [IntLiteral] 20 +# 43| 1: [LocalVariableAccess] access to local variable r +# 44| 2: [ExprStmt] ...; +# 44| 0: [MethodCall] call to method WriteLine +# 44| -1: [TypeAccess] access to type Console +# 44| 0: [MulExpr] ... * ... +# 44| 0: [MulExpr] ... * ... +# 44| 0: [LocalVariableAccess] access to local variable pi +# 44| 1: [CastExpr] (...) ... +# 44| 0: [LocalVariableAccess] access to local variable r +# 44| 1: [CastExpr] (...) ... +# 44| 0: [LocalVariableAccess] access to local variable r +# 47| 9: [Method] MainExpr +# 48| 4: [BlockStmt] {...} +# 49| 0: [LocalVariableDeclStmt] ... ...; +# 49| 0: [LocalVariableDeclExpr] Int32 i +# 50| 1: [ExprStmt] ...; +# 50| 0: [AssignExpr] ... = ... +# 50| 0: [IntLiteral] 123 +# 50| 1: [LocalVariableAccess] access to local variable i +# 51| 2: [ExprStmt] ...; +# 51| 0: [MethodCall] call to method WriteLine +# 51| -1: [TypeAccess] access to type Console +# 51| 0: [LocalVariableAccess] access to local variable i +# 52| 3: [ExprStmt] ...; +# 52| 0: [PostIncrExpr] ...++ +# 52| 0: [LocalVariableAccess] access to local variable i +# 53| 4: [ExprStmt] ...; +# 53| 0: [MethodCall] call to method WriteLine +# 53| -1: [TypeAccess] access to type Console +# 53| 0: [LocalVariableAccess] access to local variable i +# 56| 10: [Method] MainIf +#-----| 2: (Parameters) +# 56| 0: [Parameter] args +# 57| 4: [BlockStmt] {...} +# 58| 0: [IfStmt] if (...) ... +# 58| 0: [EQExpr] ... == ... +# 58| 0: [PropertyCall] access to property Length +# 58| -1: [ParameterAccess] access to parameter args +# 58| 1: [IntLiteral] 0 +# 59| 1: [BlockStmt] {...} +# 60| 0: [ExprStmt] ...; +# 60| 0: [MethodCall] call to method WriteLine +# 60| -1: [TypeAccess] access to type Console +# 60| 0: [StringLiteral] "No arguments" +# 63| 2: [BlockStmt] {...} +# 64| 0: [ExprStmt] ...; +# 64| 0: [MethodCall] call to method WriteLine +# 64| -1: [TypeAccess] access to type Console +# 64| 0: [StringLiteral] "One or more arguments" +# 69| 11: [Method] MainSwitch +#-----| 2: (Parameters) +# 69| 0: [Parameter] args +# 70| 4: [BlockStmt] {...} +# 71| 0: [LocalVariableDeclStmt] ... ...; +# 71| 0: [LocalVariableDeclAndInitExpr] Int32 n = ... +# 71| 0: [PropertyCall] access to property Length +# 71| -1: [ParameterAccess] access to parameter args +# 71| 1: [LocalVariableAccess] access to local variable n +# 72| 1: [SwitchStmt] switch (...) {...} +# 72| 0: [LocalVariableAccess] access to local variable n +# 74| 0: [ConstCase] case ...: +# 74| 0: [ConstantPatternExpr,IntLiteral] 0 +# 75| 1: [ExprStmt] ...; +# 75| 0: [MethodCall] call to method WriteLine +# 75| -1: [TypeAccess] access to type Console +# 75| 0: [StringLiteral] "No arguments" +# 76| 2: [BreakStmt] break; +# 77| 3: [ConstCase] case ...: +# 77| 0: [ConstantPatternExpr,IntLiteral] 1 +# 78| 4: [ExprStmt] ...; +# 78| 0: [MethodCall] call to method WriteLine +# 78| -1: [TypeAccess] access to type Console +# 78| 0: [StringLiteral] "One argument" +# 79| 5: [BreakStmt] break; +# 80| 6: [DefaultCase] default: +# 81| 7: [ExprStmt] ...; +# 81| 0: [MethodCall] call to method WriteLine +# 81| -1: [TypeAccess] access to type Console +# 81| 0: [StringLiteral] "{0} arguments" +# 81| 1: [CastExpr] (...) ... +# 81| 0: [LocalVariableAccess] access to local variable n +# 82| 8: [BreakStmt] break; +# 86| 12: [Method] StringSwitch +#-----| 2: (Parameters) +# 86| 0: [Parameter] foo +# 87| 4: [BlockStmt] {...} +# 88| 0: [SwitchStmt] switch (...) {...} +# 88| 0: [ParameterAccess] access to parameter foo +# 90| 0: [ConstCase] case ...: +# 90| 0: [ConstantPatternExpr,StringLiteral] "black" +# 91| 1: [ReturnStmt] return ...; +# 91| 0: [IntLiteral] 0 +# 92| 2: [ConstCase] case ...: +# 92| 0: [ConstantPatternExpr,StringLiteral] "red" +# 93| 3: [ReturnStmt] return ...; +# 93| 0: [IntLiteral] 1 +# 94| 4: [ConstCase] case ...: +# 94| 0: [ConstantPatternExpr,StringLiteral] "green" +# 95| 5: [ReturnStmt] return ...; +# 95| 0: [IntLiteral] 2 +# 96| 6: [ConstCase] case ...: +# 96| 0: [ConstantPatternExpr,StringLiteral] "yellow" +# 97| 7: [ReturnStmt] return ...; +# 97| 0: [IntLiteral] 3 +# 98| 8: [ConstCase] case ...: +# 98| 0: [ConstantPatternExpr,StringLiteral] "blue" +# 99| 9: [ReturnStmt] return ...; +# 99| 0: [IntLiteral] 4 +# 100| 10: [ConstCase] case ...: +# 100| 0: [ConstantPatternExpr,StringLiteral] "magenta" +# 101| 11: [ReturnStmt] return ...; +# 101| 0: [IntLiteral] 5 +# 102| 12: [ConstCase] case ...: +# 102| 0: [ConstantPatternExpr,StringLiteral] "cyan" +# 103| 13: [ReturnStmt] return ...; +# 103| 0: [IntLiteral] 6 +# 104| 14: [ConstCase] case ...: +# 104| 0: [ConstantPatternExpr,StringLiteral] "grey" +# 105| 15: [ConstCase] case ...: +# 105| 0: [ConstantPatternExpr,StringLiteral] "white" +# 106| 16: [ReturnStmt] return ...; +# 106| 0: [IntLiteral] 7 +# 108| 1: [ReturnStmt] return ...; +# 108| 0: [IntLiteral] 7 +# 111| 13: [Method] MainWhile +#-----| 2: (Parameters) +# 111| 0: [Parameter] args +# 112| 4: [BlockStmt] {...} +# 113| 0: [LocalVariableDeclStmt] ... ...; +# 113| 0: [LocalVariableDeclAndInitExpr] Int32 i = ... +# 113| 0: [IntLiteral] 0 +# 113| 1: [LocalVariableAccess] access to local variable i +# 114| 1: [WhileStmt] while (...) ... +# 114| 0: [LTExpr] ... < ... +# 114| 0: [LocalVariableAccess] access to local variable i +# 114| 1: [PropertyCall] access to property Length +# 114| -1: [ParameterAccess] access to parameter args +# 115| 1: [BlockStmt] {...} +# 116| 0: [ExprStmt] ...; +# 116| 0: [MethodCall] call to method WriteLine +# 116| -1: [TypeAccess] access to type Console +# 116| 0: [ArrayAccess] access to array element +# 116| -1: [ParameterAccess] access to parameter args +# 116| 0: [LocalVariableAccess] access to local variable i +# 117| 1: [ExprStmt] ...; +# 117| 0: [PostIncrExpr] ...++ +# 117| 0: [LocalVariableAccess] access to local variable i +# 121| 14: [Method] MainDo +# 122| 4: [BlockStmt] {...} +# 123| 0: [LocalVariableDeclStmt] ... ...; +# 123| 0: [LocalVariableDeclExpr] String s +# 124| 1: [DoStmt] do ... while (...); +# 128| 0: [NEExpr] ... != ... +# 128| 0: [LocalVariableAccess] access to local variable s +# 128| 1: [NullLiteral] null +# 125| 1: [BlockStmt] {...} +# 126| 0: [ExprStmt] ...; +# 126| 0: [AssignExpr] ... = ... +# 126| 0: [MethodCall] call to method ReadLine +# 126| -1: [TypeAccess] access to type Console +# 126| 1: [LocalVariableAccess] access to local variable s +# 127| 1: [IfStmt] if (...) ... +# 127| 0: [NEExpr] ... != ... +# 127| 0: [LocalVariableAccess] access to local variable s +# 127| 1: [NullLiteral] null +# 127| 1: [ExprStmt] ...; +# 127| 0: [MethodCall] call to method WriteLine +# 127| -1: [TypeAccess] access to type Console +# 127| 0: [LocalVariableAccess] access to local variable s +# 131| 15: [Method] MainFor +#-----| 2: (Parameters) +# 131| 0: [Parameter] args +# 132| 4: [BlockStmt] {...} +# 133| 0: [ForStmt] for (...;...;...) ... +# 133| -1: [LocalVariableDeclAndInitExpr] Int32 i = ... +# 133| 0: [IntLiteral] 0 +# 133| 1: [LocalVariableAccess] access to local variable i +# 133| 0: [LTExpr] ... < ... +# 133| 0: [LocalVariableAccess] access to local variable i +# 133| 1: [PropertyCall] access to property Length +# 133| -1: [ParameterAccess] access to parameter args +# 133| 1: [PostIncrExpr] ...++ +# 133| 0: [LocalVariableAccess] access to local variable i +# 134| 2: [BlockStmt] {...} +# 135| 0: [ExprStmt] ...; +# 135| 0: [MethodCall] call to method WriteLine +# 135| -1: [TypeAccess] access to type Console +# 135| 0: [ArrayAccess] access to array element +# 135| -1: [ParameterAccess] access to parameter args +# 135| 0: [LocalVariableAccess] access to local variable i +# 140| 16: [Method] MainForeach +#-----| 2: (Parameters) +# 140| 0: [Parameter] args +# 141| 4: [BlockStmt] {...} +# 142| 0: [ForeachStmt] foreach (... ... in ...) ... +# 142| 0: [LocalVariableDeclExpr] String s +# 142| 1: [ParameterAccess] access to parameter args +# 143| 2: [BlockStmt] {...} +# 144| 0: [ExprStmt] ...; +# 144| 0: [MethodCall] call to method WriteLine +# 144| -1: [TypeAccess] access to type Console +# 144| 0: [LocalVariableAccess] access to local variable s +# 148| 17: [Method] MainBreak +# 149| 4: [BlockStmt] {...} +# 150| 0: [WhileStmt] while (...) ... +# 150| 0: [BoolLiteral] true +# 151| 1: [BlockStmt] {...} +# 152| 0: [LocalVariableDeclStmt] ... ...; +# 152| 0: [LocalVariableDeclAndInitExpr] String s = ... +# 152| 0: [MethodCall] call to method ReadLine +# 152| -1: [TypeAccess] access to type Console +# 152| 1: [LocalVariableAccess] access to local variable s +# 153| 1: [IfStmt] if (...) ... +# 153| 0: [EQExpr] ... == ... +# 153| 0: [LocalVariableAccess] access to local variable s +# 153| 1: [NullLiteral] null +# 153| 1: [BreakStmt] break; +# 154| 2: [ExprStmt] ...; +# 154| 0: [MethodCall] call to method WriteLine +# 154| -1: [TypeAccess] access to type Console +# 154| 0: [LocalVariableAccess] access to local variable s +# 158| 18: [Method] MainContinue +#-----| 2: (Parameters) +# 158| 0: [Parameter] args +# 159| 4: [BlockStmt] {...} +# 160| 0: [ForStmt] for (...;...;...) ... +# 160| -1: [LocalVariableDeclAndInitExpr] Int32 i = ... +# 160| 0: [IntLiteral] 0 +# 160| 1: [LocalVariableAccess] access to local variable i +# 160| 0: [LTExpr] ... < ... +# 160| 0: [LocalVariableAccess] access to local variable i +# 160| 1: [PropertyCall] access to property Length +# 160| -1: [ParameterAccess] access to parameter args +# 160| 1: [PostIncrExpr] ...++ +# 160| 0: [LocalVariableAccess] access to local variable i +# 161| 2: [BlockStmt] {...} +# 162| 0: [IfStmt] if (...) ... +# 162| 0: [MethodCall] call to method StartsWith +# 162| -1: [ArrayAccess] access to array element +# 162| -1: [ParameterAccess] access to parameter args +# 162| 0: [LocalVariableAccess] access to local variable i +# 162| 0: [StringLiteral] "/" +# 162| 1: [ContinueStmt] continue; +# 163| 1: [ExprStmt] ...; +# 163| 0: [MethodCall] call to method WriteLine +# 163| -1: [TypeAccess] access to type Console +# 163| 0: [ArrayAccess] access to array element +# 163| -1: [ParameterAccess] access to parameter args +# 163| 0: [LocalVariableAccess] access to local variable i +# 167| 19: [Method] MainGoto +#-----| 2: (Parameters) +# 167| 0: [Parameter] args +# 168| 4: [BlockStmt] {...} +# 169| 0: [LocalVariableDeclStmt] ... ...; +# 169| 0: [LocalVariableDeclAndInitExpr] Int32 i = ... +# 169| 0: [IntLiteral] 0 +# 169| 1: [LocalVariableAccess] access to local variable i +# 170| 1: [GotoLabelStmt] goto ...; +# 171| 2: [LabelStmt] loop: +# 171| 3: [ExprStmt] ...; +# 171| 0: [MethodCall] call to method WriteLine +# 171| -1: [TypeAccess] access to type Console +# 171| 0: [ArrayAccess] access to array element +# 171| -1: [ParameterAccess] access to parameter args +# 171| 0: [PostIncrExpr] ...++ +# 171| 0: [LocalVariableAccess] access to local variable i +# 172| 4: [LabelStmt] check: +# 172| 5: [IfStmt] if (...) ... +# 172| 0: [LTExpr] ... < ... +# 172| 0: [LocalVariableAccess] access to local variable i +# 172| 1: [PropertyCall] access to property Length +# 172| -1: [ParameterAccess] access to parameter args +# 172| 1: [GotoLabelStmt] goto ...; +# 175| 20: [Method] Add +#-----| 2: (Parameters) +# 175| 0: [Parameter] a +# 175| 1: [Parameter] b +# 176| 4: [BlockStmt] {...} +# 177| 0: [ReturnStmt] return ...; +# 177| 0: [AddExpr] ... + ... +# 177| 0: [ParameterAccess] access to parameter a +# 177| 1: [ParameterAccess] access to parameter b +# 179| 21: [Method] MainReturn +# 180| 4: [BlockStmt] {...} +# 181| 0: [ExprStmt] ...; +# 181| 0: [MethodCall] call to method WriteLine +# 181| -1: [TypeAccess] access to type Console +# 181| 0: [MethodCall] call to method Add +# 181| 0: [IntLiteral] 1 +# 181| 1: [IntLiteral] 2 +# 182| 1: [ReturnStmt] return ...; +# 185| 22: [Method] Range +#-----| 2: (Parameters) +# 185| 0: [Parameter] from +# 185| 1: [Parameter] to +# 186| 4: [BlockStmt] {...} +# 187| 0: [ForStmt] for (...;...;...) ... +# 187| -1: [LocalVariableDeclAndInitExpr] Int32 i = ... +# 187| 0: [ParameterAccess] access to parameter from +# 187| 1: [LocalVariableAccess] access to local variable i +# 187| 0: [LTExpr] ... < ... +# 187| 0: [LocalVariableAccess] access to local variable i +# 187| 1: [ParameterAccess] access to parameter to +# 187| 1: [PostIncrExpr] ...++ +# 187| 0: [LocalVariableAccess] access to local variable i +# 188| 2: [BlockStmt] {...} +# 189| 0: [YieldReturnStmt] yield return ...; +# 189| 0: [LocalVariableAccess] access to local variable i +# 191| 1: [YieldBreakStmt] yield break; +# 193| 23: [Method] MainYield +# 194| 4: [BlockStmt] {...} +# 195| 0: [ForeachStmt] foreach (... ... in ...) ... +# 195| 0: [LocalVariableDeclExpr] Int32 x +# 195| 1: [MethodCall] call to method Range +# 195| 0: [UnaryMinusExpr] -... +# 195| 0: [IntLiteral] 10 +# 195| 1: [IntLiteral] 10 +# 196| 2: [BlockStmt] {...} +# 197| 0: [ExprStmt] ...; +# 197| 0: [MethodCall] call to method WriteLine +# 197| -1: [TypeAccess] access to type Console +# 197| 0: [LocalVariableAccess] access to local variable x +# 201| 24: [Method] Divide +#-----| 2: (Parameters) +# 201| 0: [Parameter] x +# 201| 1: [Parameter] y +# 202| 4: [BlockStmt] {...} +# 203| 0: [IfStmt] if (...) ... +# 203| 0: [EQExpr] ... == ... +# 203| 0: [ParameterAccess] access to parameter y +# 203| 1: [CastExpr] (...) ... +# 203| 0: [IntLiteral] 0 +# 203| 1: [ThrowStmt] throw ...; +# 203| 0: [ObjectCreation] object creation of type DivideByZeroException +# 204| 1: [ReturnStmt] return ...; +# 204| 0: [DivExpr] ... / ... +# 204| 0: [ParameterAccess] access to parameter x +# 204| 1: [ParameterAccess] access to parameter y +# 206| 25: [Method] MainTryThrow +#-----| 2: (Parameters) +# 206| 0: [Parameter] args +# 207| 4: [BlockStmt] {...} +# 208| 0: [TryStmt] try {...} ... +# 227| -1: [BlockStmt] {...} +# 228| 0: [ExprStmt] ...; +# 228| 0: [MethodCall] call to method WriteLine +# 228| -1: [TypeAccess] access to type Console +# 228| 0: [StringLiteral] "Good bye!" +# 209| 0: [BlockStmt] {...} +# 210| 0: [IfStmt] if (...) ... +# 210| 0: [NEExpr] ... != ... +# 210| 0: [PropertyCall] access to property Length +# 210| -1: [ParameterAccess] access to parameter args +# 210| 1: [IntLiteral] 2 +# 211| 1: [BlockStmt] {...} +# 212| 0: [ThrowStmt] throw ...; +# 212| 0: [ObjectCreation] object creation of type Exception +# 212| 0: [StringLiteral] "Two numbers required" +# 214| 1: [LocalVariableDeclStmt] ... ...; +# 214| 0: [LocalVariableDeclAndInitExpr] Double x = ... +# 214| 0: [MethodCall] call to method Parse +# 214| -1: [TypeAccess] access to type Double +# 214| 0: [ArrayAccess] access to array element +# 214| -1: [ParameterAccess] access to parameter args +# 214| 0: [IntLiteral] 0 +# 214| 1: [LocalVariableAccess] access to local variable x +# 215| 2: [LocalVariableDeclStmt] ... ...; +# 215| 0: [LocalVariableDeclAndInitExpr] Double y = ... +# 215| 0: [MethodCall] call to method Parse +# 215| -1: [TypeAccess] access to type Double +# 215| 0: [ArrayAccess] access to array element +# 215| -1: [ParameterAccess] access to parameter args +# 215| 0: [IntLiteral] 1 +# 215| 1: [LocalVariableAccess] access to local variable y +# 216| 3: [ExprStmt] ...; +# 216| 0: [MethodCall] call to method WriteLine +# 216| -1: [TypeAccess] access to type Console +# 216| 0: [MethodCall] call to method Divide +# 216| 0: [LocalVariableAccess] access to local variable x +# 216| 1: [LocalVariableAccess] access to local variable y +# 218| 1: [SpecificCatchClause] catch (...) {...} +# 218| 0: [LocalVariableDeclExpr] Exception e +# 219| 1: [BlockStmt] {...} +# 220| 0: [ExprStmt] ...; +# 220| 0: [MethodCall] call to method WriteLine +# 220| -1: [TypeAccess] access to type Console +# 220| 0: [PropertyCall] access to property Message +# 220| -1: [LocalVariableAccess] access to local variable e +# 222| 2: [GeneralCatchClause] catch {...} +# 223| 1: [BlockStmt] {...} +# 224| 0: [ExprStmt] ...; +# 224| 0: [MethodCall] call to method WriteLine +# 224| -1: [TypeAccess] access to type Console +# 224| 0: [StringLiteral] "Exception" +# 232| 26: [Method] MainCheckedUnchecked +# 233| 4: [BlockStmt] {...} +# 234| 0: [LocalVariableDeclStmt] ... ...; +# 234| 0: [LocalVariableDeclAndInitExpr] Int32 i = ... +# 234| 0: [MemberConstantAccess] access to constant MaxValue +# 234| -1: [TypeAccess] access to type Int32 +# 234| 1: [LocalVariableAccess] access to local variable i +# 235| 1: [CheckedStmt] checked {...} +# 236| 0: [BlockStmt] {...} +# 237| 0: [ExprStmt] ...; +# 237| 0: [MethodCall] call to method WriteLine +# 237| -1: [TypeAccess] access to type Console +# 237| 0: [AddExpr] ... + ... +# 237| 0: [LocalVariableAccess] access to local variable i +# 237| 1: [IntLiteral] 1 +# 239| 2: [UncheckedStmt] unchecked {...} +# 240| 0: [BlockStmt] {...} +# 241| 0: [ExprStmt] ...; +# 241| 0: [MethodCall] call to method WriteLine +# 241| -1: [TypeAccess] access to type Console +# 241| 0: [AddExpr] ... + ... +# 241| 0: [LocalVariableAccess] access to local variable i +# 241| 1: [IntLiteral] 1 +# 245| 27: [Class] AccountLock +# 247| 5: [Field] balance +# 248| 6: [Method] Withdraw +#-----| 2: (Parameters) +# 248| 0: [Parameter] amount +# 249| 4: [BlockStmt] {...} +# 250| 0: [LockStmt] lock (...) {...} +# 250| 0: [ThisAccess] this access +# 251| 1: [BlockStmt] {...} +# 252| 0: [IfStmt] if (...) ... +# 252| 0: [GTExpr] ... > ... +# 252| 0: [ParameterAccess] access to parameter amount +# 252| 1: [FieldAccess] access to field balance +# 253| 1: [BlockStmt] {...} +# 254| 0: [ThrowStmt] throw ...; +# 254| 0: [ObjectCreation] object creation of type Exception +# 254| 0: [StringLiteral] "Insufficient funds" +# 256| 1: [ExprStmt] ...; +# 256| 0: [AssignSubExpr] ... -= ... +# 256| 0: [ParameterAccess] access to parameter amount +# 256| 1: [FieldAccess] access to field balance +# 261| 28: [Method] MainUsing +# 262| 4: [BlockStmt] {...} +# 263| 0: [UsingBlockStmt] using (...) {...} +# 263| -1: [LocalVariableDeclAndInitExpr] TextWriter w = ... +# 263| 0: [MethodCall] call to method CreateText +# 263| -1: [TypeAccess] access to type File +# 263| 0: [StringLiteral] "test.txt" +# 263| 1: [LocalVariableAccess] access to local variable w +# 264| 1: [BlockStmt] {...} +# 265| 0: [ExprStmt] ...; +# 265| 0: [MethodCall] call to method WriteLine +# 265| -1: [LocalVariableAccess] access to local variable w +# 265| 0: [StringLiteral] "Line one" +# 266| 1: [ExprStmt] ...; +# 266| 0: [MethodCall] call to method WriteLine +# 266| -1: [LocalVariableAccess] access to local variable w +# 266| 0: [StringLiteral] "Line two" +# 267| 2: [ExprStmt] ...; +# 267| 0: [MethodCall] call to method WriteLine +# 267| -1: [LocalVariableAccess] access to local variable w +# 267| 0: [StringLiteral] "Line three" +# 269| 1: [UsingBlockStmt] using (...) {...} +# 269| 0: [MethodCall] call to method CreateText +# 269| -1: [TypeAccess] access to type File +# 269| 0: [StringLiteral] "test.txt" +# 270| 1: [BlockStmt] {...} +# 274| 29: [Method] MainLabeled +# 275| 4: [BlockStmt] {...} +# 276| 0: [GotoLabelStmt] goto ...; +# 277| 1: [LabelStmt] Label: +# 278| 2: [LocalVariableDeclStmt] ... ...; +# 278| 0: [LocalVariableDeclAndInitExpr] Int32 x = ... +# 278| 0: [IntLiteral] 23 +# 278| 1: [LocalVariableAccess] access to local variable x +# 279| 3: [ExprStmt] ...; +# 279| 0: [AssignExpr] ... = ... +# 279| 0: [IntLiteral] 9 +# 279| 1: [LocalVariableAccess] access to local variable x diff --git a/csharp/ql/test/library-tests/statements/PrintAst.qlref b/csharp/ql/test/library-tests/statements/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/statements/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/types/PrintAst.expected b/csharp/ql/test/library-tests/types/PrintAst.expected new file mode 100644 index 000000000000..db6915ac5559 --- /dev/null +++ b/csharp/ql/test/library-tests/types/PrintAst.expected @@ -0,0 +1,48 @@ +types.cs: +# 1| [NamespaceDeclaration] namespace ... { ... } +# 3| 1: [Class] Class +# 5| 5: [Method] BoolType +# 6| 6: [Method] CharType +# 7| 7: [Method] DecimalType +# 8| 8: [Method] SByteType +# 9| 9: [Method] ShortType +# 10| 10: [Method] IntType +# 11| 11: [Method] LongType +# 12| 12: [Method] ByteType +# 13| 13: [Method] UShortType +# 14| 14: [Method] UIntType +# 15| 15: [Method] ULongType +# 16| 16: [Method] FloatType +# 17| 17: [Method] DoubleType +# 18| 18: [Method] NullableType +# 19| 19: [Method] VoidType +# 20| 20: [Method] ArrayType +# 21| 21: [Method] ArrayArrayType +# 22| 22: [Method] ConstructedClassType +# 23| 23: [Method] ConstructedInterfaceType +# 24| 24: [Method] ConstructedStructType +# 25| 25: [Method] DelegateType +# 26| 26: [Method] PointerType +# 27| 27: [Method] PointerPointerType +# 28| 28: [Method] Map +# 29| 29: [Method] Null +# 30| 4: [BlockStmt] {...} +# 31| 0: [ReturnStmt] return ...; +# 31| 0: [NullLiteral] null +# 34| 2: [Enum] Enum +# 37| 3: [Struct] Struct +# 40| 4: [Interface] Interface +# 43| 5: [DelegateType] Delegate +# 44| 6: [Class] GenericClass<> +#-----| 1: (Type parameters) +# 44| 0: [TypeParameter] T +# 45| 7: [Interface] GenericInterface<> +#-----| 1: (Type parameters) +# 45| 0: [TypeParameter] T +# 46| 8: [Struct] GenericStruct<> +#-----| 1: (Type parameters) +# 46| 0: [TypeParameter] T +# 47| 9: [Class] Map<,> +#-----| 1: (Type parameters) +# 47| 0: [TypeParameter] U +# 47| 1: [TypeParameter] V diff --git a/csharp/ql/test/library-tests/types/PrintAst.qlref b/csharp/ql/test/library-tests/types/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/types/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/unsafe/PrintAst.expected b/csharp/ql/test/library-tests/unsafe/PrintAst.expected new file mode 100644 index 000000000000..079719907c78 --- /dev/null +++ b/csharp/ql/test/library-tests/unsafe/PrintAst.expected @@ -0,0 +1,116 @@ +unsafe.cs: +# 1| [NamespaceDeclaration] namespace ... { ... } +# 3| 1: [Class] Test +# 5| 5: [Method] Main +#-----| 2: (Parameters) +# 5| 0: [Parameter] args +# 6| 4: [BlockStmt] {...} +# 7| 0: [LocalVariableDeclStmt] ... ...; +# 7| 0: [LocalVariableDeclAndInitExpr] Int32 i = ... +# 7| 0: [IntLiteral] 42 +# 7| 1: [LocalVariableAccess] access to local variable i +# 8| 1: [LocalVariableDeclStmt] ... ...; +# 8| 0: [LocalVariableDeclAndInitExpr] Int32[] ia = ... +# 8| 0: [ArrayCreation] array creation of type Int32[] +# 8| 0: [IntLiteral] 2 +# 8| 1: [LocalVariableAccess] access to local variable ia +# 9| 2: [ExprStmt] ...; +# 9| 0: [AssignExpr] ... = ... +# 9| 0: [IntLiteral] 0 +# 9| 1: [ArrayAccess] access to array element +# 9| -1: [LocalVariableAccess] access to local variable ia +# 9| 0: [IntLiteral] 0 +# 10| 3: [ExprStmt] ...; +# 10| 0: [AssignExpr] ... = ... +# 10| 0: [IntLiteral] 1 +# 10| 1: [ArrayAccess] access to array element +# 10| -1: [LocalVariableAccess] access to local variable ia +# 10| 0: [IntLiteral] 1 +# 11| 4: [LocalVariableDeclStmt] ... ...; +# 11| 0: [LocalVariableDeclAndInitExpr] Int32* ip = ... +# 11| 0: [AddressOfExpr] &... +# 11| 0: [LocalVariableAccess] access to local variable i +# 11| 1: [LocalVariableAccess] access to local variable ip +# 12| 5: [ExprStmt] ...; +# 12| 0: [AssignExpr] ... = ... +# 12| 0: [AddExpr] ... + ... +# 12| 0: [LocalVariableAccess] access to local variable ip +# 12| 1: [IntLiteral] 1 +# 12| 1: [LocalVariableAccess] access to local variable ip +# 13| 6: [ExprStmt] ...; +# 13| 0: [AssignExpr] ... = ... +# 13| 0: [AddExpr] ... + ... +# 13| 0: [PointerIndirectionExpr] *... +# 13| 0: [LocalVariableAccess] access to local variable ip +# 13| 1: [LocalVariableAccess] access to local variable ip +# 13| 1: [LocalVariableAccess] access to local variable ip +# 14| 7: [ExprStmt] ...; +# 14| 0: [AssignExpr] ... = ... +# 14| 0: [AddExpr] ... + ... +# 14| 0: [PointerIndirectionExpr] *... +# 14| 0: [LocalVariableAccess] access to local variable ip +# 14| 1: [AddressOfExpr] &... +# 14| 0: [LocalVariableAccess] access to local variable i +# 14| 1: [LocalVariableAccess] access to local variable ip +# 15| 8: [LocalVariableDeclStmt] ... ...; +# 15| 0: [LocalVariableDeclAndInitExpr] Int32* ip42 = ... +# 15| 0: [AddressOfExpr] &... +# 15| 0: [LocalVariableAccess] access to local variable i +# 15| 1: [LocalVariableAccess] access to local variable ip42 +# 16| 9: [ExprStmt] ...; +# 16| 0: [PostIncrExpr] ...++ +# 16| 0: [LocalVariableAccess] access to local variable ip +# 17| 10: [ExprStmt] ...; +# 17| 0: [AssignExpr] ... = ... +# 17| 0: [SubExpr] ... - ... +# 17| 0: [LocalVariableAccess] access to local variable ip +# 17| 1: [IntLiteral] 1 +# 17| 1: [LocalVariableAccess] access to local variable ip +# 18| 11: [ExprStmt] ...; +# 18| 0: [AssignExpr] ... = ... +# 18| 0: [SizeofExpr] sizeof(..) +# 18| 0: [TypeAccess] access to type Char* +# 18| 1: [PointerIndirectionExpr] *... +# 18| 0: [LocalVariableAccess] access to local variable ip42 +# 19| 12: [LocalVariableDeclStmt] ... ...; +# 19| 0: [LocalVariableDeclAndInitExpr] Int64 distance = ... +# 19| 0: [SubExpr] ... - ... +# 19| 0: [LocalVariableAccess] access to local variable ip +# 19| 1: [LocalVariableAccess] access to local variable ip42 +# 19| 1: [LocalVariableAccess] access to local variable distance +# 22| 6: [Method] f +#-----| 2: (Parameters) +# 22| 0: [Parameter] p +# 23| 4: [BlockStmt] {...} +# 24| 0: [ExprStmt] ...; +# 24| 0: [MethodCall] call to method ToString +# 24| -1: [PointerIndirectionExpr] *... +# 24| 0: [ParameterAccess] access to parameter p +# 25| 1: [ExprStmt] ...; +# 25| 0: [MethodCall] call to method ToString +# 25| -1: [PointerIndirectionExpr] *... +# 25| 0: [ParameterAccess] access to parameter p +# 26| 2: [ExprStmt] ...; +# 26| 0: [MethodCall] call to method ToString +# 26| -1: [PointerIndirectionExpr] *... +# 26| 0: [AddExpr] ... + ... +# 26| 0: [ParameterAccess] access to parameter p +# 26| 1: [IntLiteral] 0 +# 30| 7: [Method] g +# 30| 4: [BlockStmt] {...} +# 32| 8: [Method] h +# 33| 4: [BlockStmt] {...} +# 34| 0: [UnsafeStmt] unsafe {...} +# 35| 0: [BlockStmt] {...} +# 36| 0: [LocalVariableDeclStmt] ... ...; +# 36| 0: [LocalVariableDeclAndInitExpr] Int32[] data = ... +# 36| 0: [ArrayCreation] array creation of type Int32[] +# 36| 0: [IntLiteral] 10 +# 36| 1: [LocalVariableAccess] access to local variable data +# 37| 1: [FixedStmt] fixed(...) { ... } +# 37| -1: [LocalVariableDeclAndInitExpr] Int32* p = ... +# 37| 0: [CastExpr] (...) ... +# 37| 0: [LocalVariableAccess] access to local variable data +# 37| 1: [LocalVariableAccess] access to local variable p +# 38| 0: [BlockStmt] {...} +# 44| 2: [Class] SafeClass diff --git a/csharp/ql/test/library-tests/unsafe/PrintAst.qlref b/csharp/ql/test/library-tests/unsafe/PrintAst.qlref new file mode 100644 index 000000000000..15af8b109dda --- /dev/null +++ b/csharp/ql/test/library-tests/unsafe/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.expected b/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.expected index 31ef1b638e64..18340a5d5c87 100644 --- a/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.expected +++ b/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.expected @@ -48,7 +48,7 @@ nodes | FormatInvalid.cs:108:23:108:25 | "}" | semmle.label | "}" | | FormatInvalid.cs:109:23:109:25 | "}" | semmle.label | "}" | | FormatInvalid.cs:110:23:110:25 | "}" | semmle.label | "}" | -| FormatInvalid.cs:115:56:115:58 | "}" | semmle.label | "}" | +| FormatInvalid.cs:115:56:115:58 | [assertion success] "}" | semmle.label | [assertion success] "}" | | FormatInvalid.cs:116:18:116:20 | "}" | semmle.label | "}" | | FormatInvalid.cs:117:40:117:42 | "}" | semmle.label | "}" | | FormatInvalidBad.cs:7:30:7:44 | "class {0} { }" | semmle.label | "class {0} { }" | @@ -93,7 +93,7 @@ edges | FormatInvalid.cs:108:24:108:25 | "}" | FormatInvalid.cs:108:23:108:25 | "}" | FormatInvalid.cs:108:23:108:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:108:9:108:32 | call to method Write | this | | FormatInvalid.cs:109:24:109:25 | "}" | FormatInvalid.cs:109:23:109:25 | "}" | FormatInvalid.cs:109:23:109:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:109:9:109:35 | call to method Write | this | | FormatInvalid.cs:110:24:110:25 | "}" | FormatInvalid.cs:110:23:110:25 | "}" | FormatInvalid.cs:110:23:110:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:110:9:110:38 | call to method Write | this | -| FormatInvalid.cs:115:57:115:58 | "}" | FormatInvalid.cs:115:56:115:58 | "}" | FormatInvalid.cs:115:56:115:58 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:115:9:115:63 | call to method Assert | this | +| FormatInvalid.cs:115:57:115:58 | "}" | FormatInvalid.cs:115:56:115:58 | [assertion success] "}" | FormatInvalid.cs:115:56:115:58 | [assertion success] "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:115:9:115:63 | call to method Assert | this | | FormatInvalid.cs:116:19:116:20 | "}" | FormatInvalid.cs:116:18:116:20 | "}" | FormatInvalid.cs:116:18:116:20 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:116:9:116:24 | call to method Write | this | | FormatInvalid.cs:117:41:117:42 | "}" | FormatInvalid.cs:117:40:117:42 | "}" | FormatInvalid.cs:117:40:117:42 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:117:9:117:47 | call to method Print | this | | FormatInvalidBad.cs:7:41:7:44 | "class {0} { }" | FormatInvalidBad.cs:7:30:7:44 | "class {0} { }" | FormatInvalidBad.cs:7:30:7:44 | "class {0} { }" | Invalid format string used in $@ formatting call. | FormatInvalidBad.cs:7:16:7:45 | call to method Format | this | diff --git a/csharp/ql/test/query-tests/Language Abuse/UselessCastToSelf/UselessCastToSelf.cs b/csharp/ql/test/query-tests/Language Abuse/UselessCastToSelf/UselessCastToSelf.cs index 47df3468b4a1..e36143d6b402 100644 --- a/csharp/ql/test/query-tests/Language Abuse/UselessCastToSelf/UselessCastToSelf.cs +++ b/csharp/ql/test/query-tests/Language Abuse/UselessCastToSelf/UselessCastToSelf.cs @@ -18,4 +18,13 @@ void f() var good6 = (Action)(delegate (int x) { }); var good7 = (Action)((int x) => { }); } + + enum Enum + { + A = 2, + B = 1 | A, + C = 1 | (int)A, // BAD + D = 9 | (32 << A), + E = 9 | (32 << (int)A) // BAD + } } diff --git a/csharp/ql/test/query-tests/Language Abuse/UselessCastToSelf/UselessCastToSelf.expected b/csharp/ql/test/query-tests/Language Abuse/UselessCastToSelf/UselessCastToSelf.expected index 28dcbbb9f6e0..f5c4b708253a 100644 --- a/csharp/ql/test/query-tests/Language Abuse/UselessCastToSelf/UselessCastToSelf.expected +++ b/csharp/ql/test/query-tests/Language Abuse/UselessCastToSelf/UselessCastToSelf.expected @@ -1,3 +1,5 @@ | UselessCastToSelf.cs:8:20:8:25 | (...) ... | This cast is redundant because the expression already has type Int32. | | UselessCastToSelf.cs:9:20:9:29 | (...) ... | This cast is redundant because the expression already has type Test. | | UselessCastToSelf.cs:10:20:10:31 | ... as ... | This cast is redundant because the expression already has type Test. | +| UselessCastToSelf.cs:26:17:26:22 | (...) ... | This cast is redundant because the expression already has type Int32. | +| UselessCastToSelf.cs:28:24:28:29 | (...) ... | This cast is redundant because the expression already has type Int32. | diff --git a/csharp/ql/test/query-tests/Likely Bugs/SelfAssignment/selfassigns.cs b/csharp/ql/test/query-tests/Likely Bugs/SelfAssignment/selfassigns.cs index 3553606275f9..6d1387a5e1db 100644 --- a/csharp/ql/test/query-tests/Likely Bugs/SelfAssignment/selfassigns.cs +++ b/csharp/ql/test/query-tests/Likely Bugs/SelfAssignment/selfassigns.cs @@ -82,4 +82,11 @@ public void NotOK(SelfAssigns obj, int y) this.Self.Self.Self.StringProp = Self.Self.Self.StringProp; intArray[1] = this.intArray[1 + 0]; } + + enum Enum + { + X = 42, + Y = 100, + Z + } } diff --git a/csharp/ql/test/query-tests/Metrics/Dependencies/ExternalDependencies/ExternalDependencies.expected b/csharp/ql/test/query-tests/Metrics/Dependencies/ExternalDependencies/ExternalDependencies.expected index 096443a411df..ca75d5f716ad 100644 --- a/csharp/ql/test/query-tests/Metrics/Dependencies/ExternalDependencies/ExternalDependencies.expected +++ b/csharp/ql/test/query-tests/Metrics/Dependencies/ExternalDependencies/ExternalDependencies.expected @@ -1,5 +1,5 @@ -| /query-tests/Metrics/Dependencies/ExternalDependencies/File1.cs<\|>System.Net.Http<\|>4.2.1.0 | 11 | -| /query-tests/Metrics/Dependencies/ExternalDependencies/File1.cs<\|>System.Private.DataContractSerialization<\|>4.1.4.0 | 2 | -| /query-tests/Metrics/Dependencies/ExternalDependencies/File1.cs<\|>System.Private.Xml<\|>4.0.1.0 | 2 | -| /query-tests/Metrics/Dependencies/ExternalDependencies/File1.cs<\|>System.Data.Common<\|>4.2.1.0 | 1 | -| /query-tests/Metrics/Dependencies/ExternalDependencies/File2.cs<\|>System.Net.Http<\|>4.2.1.0 | 1 | +| /query-tests/Metrics/Dependencies/ExternalDependencies/File1.cs<\|>System.Net.Http<\|>4.2.2.0 | 11 | +| /query-tests/Metrics/Dependencies/ExternalDependencies/File1.cs<\|>System.Private.DataContractSerialization<\|>4.1.5.0 | 2 | +| /query-tests/Metrics/Dependencies/ExternalDependencies/File1.cs<\|>System.Private.Xml<\|>4.0.2.0 | 2 | +| /query-tests/Metrics/Dependencies/ExternalDependencies/File1.cs<\|>System.Data.Common<\|>4.2.2.0 | 1 | +| /query-tests/Metrics/Dependencies/ExternalDependencies/File2.cs<\|>System.Net.Http<\|>4.2.2.0 | 1 | diff --git a/csharp/ql/test/query-tests/Metrics/Dependencies/ExternalDependencies/ExternalDependenciesSourceLinks.expected b/csharp/ql/test/query-tests/Metrics/Dependencies/ExternalDependencies/ExternalDependenciesSourceLinks.expected index 656ec8431144..e1fe8dd8d037 100644 --- a/csharp/ql/test/query-tests/Metrics/Dependencies/ExternalDependencies/ExternalDependenciesSourceLinks.expected +++ b/csharp/ql/test/query-tests/Metrics/Dependencies/ExternalDependencies/ExternalDependenciesSourceLinks.expected @@ -1,5 +1,5 @@ -| /query-tests/Metrics/Dependencies/ExternalDependencies/File1.cs<\|>System.Data.Common<\|>4.2.1.0 | File1.cs:0:0:0:0 | File1.cs | -| /query-tests/Metrics/Dependencies/ExternalDependencies/File1.cs<\|>System.Net.Http<\|>4.2.1.0 | File1.cs:0:0:0:0 | File1.cs | -| /query-tests/Metrics/Dependencies/ExternalDependencies/File1.cs<\|>System.Private.DataContractSerialization<\|>4.1.4.0 | File1.cs:0:0:0:0 | File1.cs | -| /query-tests/Metrics/Dependencies/ExternalDependencies/File1.cs<\|>System.Private.Xml<\|>4.0.1.0 | File1.cs:0:0:0:0 | File1.cs | -| /query-tests/Metrics/Dependencies/ExternalDependencies/File2.cs<\|>System.Net.Http<\|>4.2.1.0 | File2.cs:0:0:0:0 | File2.cs | +| /query-tests/Metrics/Dependencies/ExternalDependencies/File1.cs<\|>System.Data.Common<\|>4.2.2.0 | File1.cs:0:0:0:0 | File1.cs | +| /query-tests/Metrics/Dependencies/ExternalDependencies/File1.cs<\|>System.Net.Http<\|>4.2.2.0 | File1.cs:0:0:0:0 | File1.cs | +| /query-tests/Metrics/Dependencies/ExternalDependencies/File1.cs<\|>System.Private.DataContractSerialization<\|>4.1.5.0 | File1.cs:0:0:0:0 | File1.cs | +| /query-tests/Metrics/Dependencies/ExternalDependencies/File1.cs<\|>System.Private.Xml<\|>4.0.2.0 | File1.cs:0:0:0:0 | File1.cs | +| /query-tests/Metrics/Dependencies/ExternalDependencies/File2.cs<\|>System.Net.Http<\|>4.2.2.0 | File2.cs:0:0:0:0 | File2.cs | diff --git a/csharp/ql/test/query-tests/Nullness/Assert.cs b/csharp/ql/test/query-tests/Nullness/Assert.cs index c483d1f36d3c..a57ba59a861e 100644 --- a/csharp/ql/test/query-tests/Nullness/Assert.cs +++ b/csharp/ql/test/query-tests/Nullness/Assert.cs @@ -39,7 +39,7 @@ void Fn(bool b) Console.WriteLine(s.Length); // GOOD s = b ? null : ""; - Assert.IsFalse(s == null || b); + Assert.IsFalse(s == null || !b); Console.WriteLine(s.Length); // GOOD s = b ? null : ""; @@ -47,7 +47,7 @@ void Fn(bool b) Console.WriteLine(s.Length); // BAD (always) s = b ? null : ""; - Assert.IsFalse(s != null || b); + Assert.IsFalse(s != null || !b); Console.WriteLine(s.Length); // BAD (always) } } diff --git a/csharp/ql/test/query-tests/Nullness/E.cs b/csharp/ql/test/query-tests/Nullness/E.cs index 67b5267ffbec..511955e2b44b 100644 --- a/csharp/ql/test/query-tests/Nullness/E.cs +++ b/csharp/ql/test/query-tests/Nullness/E.cs @@ -385,6 +385,32 @@ static bool Ex37(E e1, E e2) return true; return e1.Long == e2.Long; // GOOD (false positive) } + + int Ex38(int? i) + { + i ??= 0; + return i.Value; // GOOD + } + + System.Drawing.Color Ex39(System.Drawing.Color? color) + { + color ??= System.Drawing.Color.White; + return color.Value; // GOOD + } + + int Ex40() + { + int? i = null; + i ??= null; + return i.Value; // BAD (always) + } + + int Ex41() + { + int? i = 1; + i ??= null; + return i.Value; // GOOD + } } public static class Extensions @@ -393,4 +419,4 @@ public static void M1(this string s) { } public static int M2(this string s) => s.Length; } -// semmle-extractor-options: /r:System.Linq.dll +// semmle-extractor-options: /r:System.Linq.dll /r:System.Drawing.Primitives.dll diff --git a/csharp/ql/test/query-tests/Nullness/EqualityCheck.expected b/csharp/ql/test/query-tests/Nullness/EqualityCheck.expected index 5f739e93c2b1..dc70346eea54 100644 --- a/csharp/ql/test/query-tests/Nullness/EqualityCheck.expected +++ b/csharp/ql/test/query-tests/Nullness/EqualityCheck.expected @@ -191,8 +191,11 @@ | E.cs:85:18:85:29 | ... != ... | false | E.cs:85:18:85:21 | access to parameter vals | E.cs:85:26:85:29 | null | | E.cs:85:18:85:29 | ... != ... | false | E.cs:85:26:85:29 | null | E.cs:85:18:85:21 | access to parameter vals | | E.cs:90:17:90:27 | access to local variable switchguard | match access to constant MY_CONST_A | E.cs:90:17:90:27 | access to local variable switchguard | E.cs:92:18:92:27 | access to constant MY_CONST_A | +| E.cs:90:17:90:27 | access to local variable switchguard | match access to constant MY_CONST_A | E.cs:92:18:92:27 | access to constant MY_CONST_A | E.cs:90:17:90:27 | access to local variable switchguard | | E.cs:90:17:90:27 | access to local variable switchguard | match access to constant MY_CONST_B | E.cs:90:17:90:27 | access to local variable switchguard | E.cs:97:18:97:27 | access to constant MY_CONST_B | +| E.cs:90:17:90:27 | access to local variable switchguard | match access to constant MY_CONST_B | E.cs:97:18:97:27 | access to constant MY_CONST_B | E.cs:90:17:90:27 | access to local variable switchguard | | E.cs:90:17:90:27 | access to local variable switchguard | match access to constant MY_CONST_C | E.cs:90:17:90:27 | access to local variable switchguard | E.cs:95:18:95:27 | access to constant MY_CONST_C | +| E.cs:90:17:90:27 | access to local variable switchguard | match access to constant MY_CONST_C | E.cs:95:18:95:27 | access to constant MY_CONST_C | E.cs:90:17:90:27 | access to local variable switchguard | | E.cs:126:21:126:29 | ... == ... | true | E.cs:126:21:126:24 | access to local variable step | E.cs:126:29:126:29 | 0 | | E.cs:126:21:126:29 | ... == ... | true | E.cs:126:29:126:29 | 0 | E.cs:126:21:126:24 | access to local variable step | | E.cs:153:13:153:24 | ... != ... | false | E.cs:153:13:153:16 | access to local variable obj2 | E.cs:153:21:153:24 | null | @@ -216,6 +219,7 @@ | E.cs:293:13:293:24 | ... == ... | true | E.cs:293:15:293:19 | call to method M2 | E.cs:293:24:293:24 | (...) ... | | E.cs:293:13:293:24 | ... == ... | true | E.cs:293:24:293:24 | (...) ... | E.cs:293:15:293:19 | call to method M2 | | E.cs:321:13:321:30 | ... is ... | true | E.cs:321:14:321:21 | ... ?? ... | E.cs:321:27:321:30 | null | +| E.cs:321:13:321:30 | ... is ... | true | E.cs:321:27:321:30 | null | E.cs:321:14:321:21 | ... ?? ... | | E.cs:355:13:355:21 | dynamic call to operator != | false | E.cs:355:13:355:13 | access to local variable x | E.cs:355:18:355:21 | null | | E.cs:355:13:355:21 | dynamic call to operator != | false | E.cs:355:18:355:21 | null | E.cs:355:13:355:13 | access to local variable x | | E.cs:362:13:362:29 | ... != ... | false | E.cs:362:13:362:13 | access to local variable x | E.cs:362:18:362:29 | (...) ... | diff --git a/csharp/ql/test/query-tests/Nullness/Implications.expected b/csharp/ql/test/query-tests/Nullness/Implications.expected index d7a06795fc21..8ac85c3fe789 100644 --- a/csharp/ql/test/query-tests/Nullness/Implications.expected +++ b/csharp/ql/test/query-tests/Nullness/Implications.expected @@ -66,7 +66,9 @@ | Assert.cs:13:13:13:25 | ... ? ... : ... | null | Assert.cs:13:17:13:20 | null | null | | Assert.cs:14:23:14:23 | access to local variable s | empty | Assert.cs:13:13:13:25 | ... ? ... : ... | empty | | Assert.cs:14:23:14:23 | access to local variable s | non-empty | Assert.cs:13:13:13:25 | ... ? ... : ... | non-empty | +| Assert.cs:14:23:14:23 | access to local variable s | non-null | Assert.cs:13:13:13:13 | access to parameter b | false | | Assert.cs:14:23:14:23 | access to local variable s | non-null | Assert.cs:13:13:13:25 | ... ? ... : ... | non-null | +| Assert.cs:14:23:14:23 | access to local variable s | null | Assert.cs:13:13:13:13 | access to parameter b | true | | Assert.cs:14:23:14:23 | access to local variable s | null | Assert.cs:13:13:13:25 | ... ? ... : ... | null | | Assert.cs:15:27:15:27 | access to local variable s | non-null | Assert.cs:13:13:13:25 | ... ? ... : ... | non-null | | Assert.cs:15:27:15:27 | access to local variable s | null | Assert.cs:13:13:13:25 | ... ? ... : ... | null | @@ -76,7 +78,9 @@ | Assert.cs:17:13:17:25 | ... ? ... : ... | null | Assert.cs:17:17:17:20 | null | null | | Assert.cs:18:26:18:26 | access to local variable s | empty | Assert.cs:17:13:17:25 | ... ? ... : ... | empty | | Assert.cs:18:26:18:26 | access to local variable s | non-empty | Assert.cs:17:13:17:25 | ... ? ... : ... | non-empty | +| Assert.cs:18:26:18:26 | access to local variable s | non-null | Assert.cs:17:13:17:13 | access to parameter b | false | | Assert.cs:18:26:18:26 | access to local variable s | non-null | Assert.cs:17:13:17:25 | ... ? ... : ... | non-null | +| Assert.cs:18:26:18:26 | access to local variable s | null | Assert.cs:17:13:17:13 | access to parameter b | true | | Assert.cs:18:26:18:26 | access to local variable s | null | Assert.cs:17:13:17:25 | ... ? ... : ... | null | | Assert.cs:19:27:19:27 | access to local variable s | non-null | Assert.cs:17:13:17:25 | ... ? ... : ... | non-null | | Assert.cs:19:27:19:27 | access to local variable s | null | Assert.cs:17:13:17:25 | ... ? ... : ... | null | @@ -164,8 +168,10 @@ | Assert.cs:42:24:42:32 | ... == ... | false | Assert.cs:42:24:42:24 | access to local variable s | non-null | | Assert.cs:42:24:42:32 | ... == ... | true | Assert.cs:41:13:41:13 | access to parameter b | true | | Assert.cs:42:24:42:32 | ... == ... | true | Assert.cs:42:24:42:24 | access to local variable s | null | -| Assert.cs:42:24:42:37 | ... \|\| ... | false | Assert.cs:42:24:42:32 | ... == ... | false | -| Assert.cs:42:24:42:37 | ... \|\| ... | false | Assert.cs:42:37:42:37 | access to parameter b | false | +| Assert.cs:42:24:42:38 | ... \|\| ... | false | Assert.cs:42:24:42:32 | ... == ... | false | +| Assert.cs:42:24:42:38 | ... \|\| ... | false | Assert.cs:42:37:42:38 | !... | false | +| Assert.cs:42:37:42:38 | !... | false | Assert.cs:42:38:42:38 | access to parameter b | true | +| Assert.cs:42:37:42:38 | !... | true | Assert.cs:42:38:42:38 | access to parameter b | false | | Assert.cs:43:27:43:27 | access to local variable s | non-null | Assert.cs:41:13:41:25 | ... ? ... : ... | non-null | | Assert.cs:43:27:43:27 | access to local variable s | null | Assert.cs:41:13:41:25 | ... ? ... : ... | null | | Assert.cs:45:13:45:25 | ... ? ... : ... | non-null | Assert.cs:45:13:45:13 | access to parameter b | false | @@ -196,8 +202,10 @@ | Assert.cs:50:24:50:32 | ... != ... | false | Assert.cs:50:24:50:24 | access to local variable s | null | | Assert.cs:50:24:50:32 | ... != ... | true | Assert.cs:49:13:49:13 | access to parameter b | false | | Assert.cs:50:24:50:32 | ... != ... | true | Assert.cs:50:24:50:24 | access to local variable s | non-null | -| Assert.cs:50:24:50:37 | ... \|\| ... | false | Assert.cs:50:24:50:32 | ... != ... | false | -| Assert.cs:50:24:50:37 | ... \|\| ... | false | Assert.cs:50:37:50:37 | access to parameter b | false | +| Assert.cs:50:24:50:38 | ... \|\| ... | false | Assert.cs:50:24:50:32 | ... != ... | false | +| Assert.cs:50:24:50:38 | ... \|\| ... | false | Assert.cs:50:37:50:38 | !... | false | +| Assert.cs:50:37:50:38 | !... | false | Assert.cs:50:38:50:38 | access to parameter b | true | +| Assert.cs:50:37:50:38 | !... | true | Assert.cs:50:38:50:38 | access to parameter b | false | | Assert.cs:51:27:51:27 | access to local variable s | non-null | Assert.cs:49:13:49:25 | ... ? ... : ... | non-null | | Assert.cs:51:27:51:27 | access to local variable s | null | Assert.cs:49:13:49:25 | ... ? ... : ... | null | | B.cs:12:13:12:24 | access to local variable eqCallAlways | non-null | B.cs:7:26:7:29 | null | non-null | @@ -320,7 +328,9 @@ | C.cs:55:18:55:36 | ... ? ... : ... | null | C.cs:55:28:55:31 | null | null | | C.cs:56:23:56:24 | access to local variable o2 | empty | C.cs:55:18:55:36 | ... ? ... : ... | empty | | C.cs:56:23:56:24 | access to local variable o2 | non-empty | C.cs:55:18:55:36 | ... ? ... : ... | non-empty | +| C.cs:56:23:56:24 | access to local variable o2 | non-null | C.cs:55:18:55:24 | call to method Maybe | false | | C.cs:56:23:56:24 | access to local variable o2 | non-null | C.cs:55:18:55:36 | ... ? ... : ... | non-null | +| C.cs:56:23:56:24 | access to local variable o2 | null | C.cs:55:18:55:24 | call to method Maybe | true | | C.cs:56:23:56:24 | access to local variable o2 | null | C.cs:55:18:55:36 | ... ? ... : ... | null | | C.cs:57:9:57:10 | access to local variable o2 | non-null | C.cs:55:18:55:36 | ... ? ... : ... | non-null | | C.cs:57:9:57:10 | access to local variable o2 | null | C.cs:55:18:55:36 | ... ? ... : ... | null | @@ -344,7 +354,9 @@ | C.cs:70:18:70:46 | ... ? ... : ... | non-null | C.cs:70:35:70:46 | object creation of type Object | non-null | | C.cs:70:18:70:46 | ... ? ... : ... | null | C.cs:70:18:70:24 | call to method Maybe | true | | C.cs:70:18:70:46 | ... ? ... : ... | null | C.cs:70:28:70:31 | null | null | +| C.cs:71:26:71:27 | access to local variable o3 | non-null | C.cs:70:18:70:24 | call to method Maybe | false | | C.cs:71:26:71:27 | access to local variable o3 | non-null | C.cs:70:18:70:46 | ... ? ... : ... | non-null | +| C.cs:71:26:71:27 | access to local variable o3 | null | C.cs:70:18:70:24 | call to method Maybe | true | | C.cs:71:26:71:27 | access to local variable o3 | null | C.cs:70:18:70:46 | ... ? ... : ... | null | | C.cs:72:9:72:10 | access to local variable o3 | non-null | C.cs:70:18:70:46 | ... ? ... : ... | non-null | | C.cs:72:9:72:10 | access to local variable o3 | null | C.cs:70:18:70:46 | ... ? ... : ... | null | @@ -1115,12 +1127,14 @@ | E.cs:176:13:176:14 | access to local variable b2 | true | E.cs:175:19:175:42 | ... ? ... : ... | true | | E.cs:176:13:176:22 | ... == ... | false | E.cs:176:13:176:14 | (...) ... | non-null | | E.cs:176:13:176:22 | ... == ... | true | E.cs:176:13:176:14 | (...) ... | null | +| E.cs:176:13:176:22 | ... == ... | true | E.cs:176:19:176:22 | null | non-null | | E.cs:180:13:180:23 | ... == ... | false | E.cs:180:13:180:15 | access to parameter obj | non-null | | E.cs:180:13:180:23 | ... == ... | true | E.cs:180:13:180:15 | access to parameter obj | null | | E.cs:184:13:184:14 | (...) ... | non-null | E.cs:184:13:184:14 | access to parameter b1 | non-null | | E.cs:184:13:184:14 | (...) ... | null | E.cs:184:13:184:14 | access to parameter b1 | null | | E.cs:184:13:184:22 | ... == ... | false | E.cs:184:13:184:14 | (...) ... | non-null | | E.cs:184:13:184:22 | ... == ... | true | E.cs:184:13:184:14 | (...) ... | null | +| E.cs:184:13:184:22 | ... == ... | true | E.cs:184:19:184:22 | null | non-null | | E.cs:193:19:193:29 | call to method ToString | non-null | E.cs:193:17:193:17 | access to parameter o | non-null | | E.cs:198:17:198:29 | ... ? ... : ... | non-null | E.cs:198:17:198:17 | access to parameter b | false | | E.cs:198:17:198:29 | ... ? ... : ... | non-null | E.cs:198:28:198:29 | "" | non-null | @@ -1256,6 +1270,26 @@ | E.cs:384:13:384:36 | ... && ... | true | E.cs:384:27:384:36 | ... == ... | true | | E.cs:384:27:384:36 | ... == ... | false | E.cs:384:27:384:28 | access to parameter e2 | non-null | | E.cs:384:27:384:36 | ... == ... | true | E.cs:384:27:384:28 | access to parameter e2 | null | +| E.cs:404:9:404:9 | access to local variable i | non-null | E.cs:403:18:403:21 | null | non-null | +| E.cs:404:9:404:9 | access to local variable i | null | E.cs:403:18:403:21 | null | null | +| E.cs:404:9:404:18 | ... = ... | non-null | E.cs:404:9:404:9 | access to local variable i | non-null | +| E.cs:404:9:404:18 | ... = ... | non-null | E.cs:404:9:404:18 | ... ?? ... | non-null | +| E.cs:404:9:404:18 | ... = ... | null | E.cs:404:9:404:9 | access to local variable i | null | +| E.cs:404:9:404:18 | ... = ... | null | E.cs:404:9:404:18 | ... ?? ... | null | +| E.cs:404:9:404:18 | ... ?? ... | null | E.cs:404:9:404:9 | access to local variable i | null | +| E.cs:404:9:404:18 | ... ?? ... | null | E.cs:404:15:404:18 | null | null | +| E.cs:405:16:405:16 | access to local variable i | non-null | E.cs:404:9:404:18 | ... ?? ... | non-null | +| E.cs:405:16:405:16 | access to local variable i | null | E.cs:404:9:404:18 | ... ?? ... | null | +| E.cs:411:9:411:9 | access to local variable i | non-null | E.cs:410:18:410:18 | (...) ... | non-null | +| E.cs:411:9:411:9 | access to local variable i | null | E.cs:410:18:410:18 | (...) ... | null | +| E.cs:411:9:411:18 | ... = ... | non-null | E.cs:411:9:411:9 | access to local variable i | non-null | +| E.cs:411:9:411:18 | ... = ... | non-null | E.cs:411:9:411:18 | ... ?? ... | non-null | +| E.cs:411:9:411:18 | ... = ... | null | E.cs:411:9:411:9 | access to local variable i | null | +| E.cs:411:9:411:18 | ... = ... | null | E.cs:411:9:411:18 | ... ?? ... | null | +| E.cs:411:9:411:18 | ... ?? ... | null | E.cs:411:9:411:9 | access to local variable i | null | +| E.cs:411:9:411:18 | ... ?? ... | null | E.cs:411:15:411:18 | null | null | +| E.cs:412:16:412:16 | access to local variable i | non-null | E.cs:411:9:411:18 | ... ?? ... | non-null | +| E.cs:412:16:412:16 | access to local variable i | null | E.cs:411:9:411:18 | ... ?? ... | null | | Forwarding.cs:9:13:9:30 | !... | false | Forwarding.cs:9:14:9:30 | call to method IsNullOrEmpty | true | | Forwarding.cs:9:13:9:30 | !... | true | Forwarding.cs:9:14:9:30 | call to method IsNullOrEmpty | false | | Forwarding.cs:9:14:9:14 | access to local variable s | empty | Forwarding.cs:7:20:7:23 | null | empty | diff --git a/csharp/ql/test/query-tests/Nullness/NullAlways.expected b/csharp/ql/test/query-tests/Nullness/NullAlways.expected index 01c054b9379e..2aaaeb87c56a 100644 --- a/csharp/ql/test/query-tests/Nullness/NullAlways.expected +++ b/csharp/ql/test/query-tests/Nullness/NullAlways.expected @@ -36,6 +36,7 @@ | E.cs:323:13:323:14 | access to parameter s1 | Variable $@ is always null here. | E.cs:319:29:319:30 | s1 | s1 | | E.cs:324:13:324:14 | access to parameter s2 | Variable $@ is always null here. | E.cs:319:40:319:41 | s2 | s2 | | E.cs:331:9:331:9 | access to local variable x | Variable $@ is always null here. | E.cs:330:13:330:13 | x | x | +| E.cs:405:16:405:16 | access to local variable i | Variable $@ is always null here. | E.cs:403:14:403:14 | i | i | | Forwarding.cs:36:31:36:31 | access to local variable s | Variable $@ is always null here. | Forwarding.cs:7:16:7:16 | s | s | | Forwarding.cs:40:27:40:27 | access to local variable s | Variable $@ is always null here. | Forwarding.cs:7:16:7:16 | s | s | | NullAlwaysBad.cs:9:30:9:30 | access to parameter s | Variable $@ is always null here. | NullAlwaysBad.cs:7:29:7:29 | s | s | diff --git a/csharp/ql/test/query-tests/Nullness/NullCheck.expected b/csharp/ql/test/query-tests/Nullness/NullCheck.expected index 1c2b22ca6b56..bf1d6480e643 100644 --- a/csharp/ql/test/query-tests/Nullness/NullCheck.expected +++ b/csharp/ql/test/query-tests/Nullness/NullCheck.expected @@ -1,5 +1,9 @@ | Assert.cs:10:22:10:30 | ... != ... | Assert.cs:10:22:10:22 | access to local variable s | false | true | | Assert.cs:10:22:10:30 | ... != ... | Assert.cs:10:22:10:22 | access to local variable s | true | false | +| Assert.cs:14:23:14:23 | access to local variable s | Assert.cs:14:23:14:23 | access to local variable s | non-null | false | +| Assert.cs:14:23:14:23 | access to local variable s | Assert.cs:14:23:14:23 | access to local variable s | null | true | +| Assert.cs:18:26:18:26 | access to local variable s | Assert.cs:18:26:18:26 | access to local variable s | non-null | false | +| Assert.cs:18:26:18:26 | access to local variable s | Assert.cs:18:26:18:26 | access to local variable s | null | true | | Assert.cs:22:23:22:31 | ... == ... | Assert.cs:22:23:22:23 | access to local variable s | false | false | | Assert.cs:22:23:22:31 | ... == ... | Assert.cs:22:23:22:23 | access to local variable s | true | true | | Assert.cs:26:23:26:31 | ... != ... | Assert.cs:26:23:26:23 | access to local variable s | false | true | @@ -60,6 +64,10 @@ | C.cs:41:22:41:30 | ... == ... | C.cs:41:22:41:22 | access to local variable s | true | true | | C.cs:45:22:45:30 | ... != ... | C.cs:45:22:45:22 | access to local variable s | false | true | | C.cs:45:22:45:30 | ... != ... | C.cs:45:22:45:22 | access to local variable s | true | false | +| C.cs:56:23:56:24 | access to local variable o2 | C.cs:56:23:56:24 | access to local variable o2 | non-null | false | +| C.cs:56:23:56:24 | access to local variable o2 | C.cs:56:23:56:24 | access to local variable o2 | null | true | +| C.cs:71:26:71:27 | access to local variable o3 | C.cs:71:26:71:27 | access to local variable o3 | non-null | false | +| C.cs:71:26:71:27 | access to local variable o3 | C.cs:71:26:71:27 | access to local variable o3 | null | true | | C.cs:78:13:78:24 | call to method IsNotNull | C.cs:78:23:78:23 | access to local variable o | false | true | | C.cs:78:13:78:24 | call to method IsNotNull | C.cs:78:23:78:23 | access to local variable o | true | false | | C.cs:82:14:82:22 | call to method IsNull | C.cs:82:21:82:21 | access to local variable o | false | false | @@ -219,10 +227,12 @@ | E.cs:175:19:175:29 | ... == ... | E.cs:175:19:175:21 | access to parameter obj | true | true | | E.cs:176:13:176:22 | ... == ... | E.cs:176:13:176:14 | (...) ... | false | false | | E.cs:176:13:176:22 | ... == ... | E.cs:176:13:176:14 | (...) ... | true | true | +| E.cs:176:13:176:22 | ... == ... | E.cs:176:19:176:22 | null | true | false | | E.cs:180:13:180:23 | ... == ... | E.cs:180:13:180:15 | access to parameter obj | false | false | | E.cs:180:13:180:23 | ... == ... | E.cs:180:13:180:15 | access to parameter obj | true | true | | E.cs:184:13:184:22 | ... == ... | E.cs:184:13:184:14 | (...) ... | false | false | | E.cs:184:13:184:22 | ... == ... | E.cs:184:13:184:14 | (...) ... | true | true | +| E.cs:184:13:184:22 | ... == ... | E.cs:184:19:184:22 | null | true | false | | E.cs:193:17:193:17 | access to parameter o | E.cs:193:17:193:17 | access to parameter o | non-null | false | | E.cs:193:17:193:17 | access to parameter o | E.cs:193:17:193:17 | access to parameter o | null | true | | E.cs:208:13:208:23 | ... is ... | E.cs:208:13:208:13 | access to parameter s | false | true | @@ -276,6 +286,14 @@ | E.cs:384:13:384:22 | ... == ... | E.cs:384:13:384:14 | access to parameter e1 | true | true | | E.cs:384:27:384:36 | ... == ... | E.cs:384:27:384:28 | access to parameter e2 | false | false | | E.cs:384:27:384:36 | ... == ... | E.cs:384:27:384:28 | access to parameter e2 | true | true | +| E.cs:391:9:391:9 | access to parameter i | E.cs:391:9:391:9 | access to parameter i | non-null | false | +| E.cs:391:9:391:9 | access to parameter i | E.cs:391:9:391:9 | access to parameter i | null | true | +| E.cs:397:9:397:13 | access to parameter color | E.cs:397:9:397:13 | access to parameter color | non-null | false | +| E.cs:397:9:397:13 | access to parameter color | E.cs:397:9:397:13 | access to parameter color | null | true | +| E.cs:404:9:404:9 | access to local variable i | E.cs:404:9:404:9 | access to local variable i | non-null | false | +| E.cs:404:9:404:9 | access to local variable i | E.cs:404:9:404:9 | access to local variable i | null | true | +| E.cs:411:9:411:9 | access to local variable i | E.cs:411:9:411:9 | access to local variable i | non-null | false | +| E.cs:411:9:411:9 | access to local variable i | E.cs:411:9:411:9 | access to local variable i | null | true | | Forwarding.cs:9:14:9:30 | call to method IsNullOrEmpty | Forwarding.cs:9:14:9:14 | access to local variable s | false | false | | Forwarding.cs:14:13:14:32 | call to method IsNotNullOrEmpty | Forwarding.cs:14:13:14:13 | access to local variable s | true | false | | Forwarding.cs:19:14:19:23 | call to method IsNull | Forwarding.cs:19:14:19:14 | access to local variable s | false | false | diff --git a/csharp/ql/test/query-tests/Nullness/NullMaybe.expected b/csharp/ql/test/query-tests/Nullness/NullMaybe.expected index 4d4f9344986f..6433b844ee02 100644 --- a/csharp/ql/test/query-tests/Nullness/NullMaybe.expected +++ b/csharp/ql/test/query-tests/Nullness/NullMaybe.expected @@ -30,14 +30,9 @@ nodes | Assert.cs:29:9:29:25 | [b (line 7): true] SSA def(s) | | Assert.cs:31:27:31:27 | access to local variable s | | Assert.cs:31:27:31:27 | access to local variable s | -| Assert.cs:45:9:45:25 | [b (line 7): false] SSA def(s) | | Assert.cs:45:9:45:25 | [b (line 7): true] SSA def(s) | -| Assert.cs:46:36:46:36 | [b (line 7): false] access to parameter b | -| Assert.cs:46:36:46:36 | [b (line 7): true] access to parameter b | | Assert.cs:47:27:47:27 | access to local variable s | -| Assert.cs:47:27:47:27 | access to local variable s | -| Assert.cs:49:9:49:25 | SSA def(s) | -| Assert.cs:50:37:50:37 | access to parameter b | +| Assert.cs:49:9:49:25 | [b (line 7): true] SSA def(s) | | Assert.cs:51:27:51:27 | access to local variable s | | B.cs:7:11:7:29 | SSA def(eqCallAlways) | | B.cs:10:11:10:30 | SSA def(neqCallAlways) | @@ -370,6 +365,9 @@ nodes | E.cs:384:27:384:28 | access to parameter e2 | | E.cs:386:16:386:17 | access to parameter e1 | | E.cs:386:27:386:28 | access to parameter e2 | +| E.cs:404:9:404:18 | SSA def(i) | +| E.cs:404:9:404:18 | SSA def(i) | +| E.cs:405:16:405:16 | access to local variable i | | Forwarding.cs:7:16:7:23 | SSA def(s) | | Forwarding.cs:14:9:17:9 | if (...) ... | | Forwarding.cs:19:9:22:9 | if (...) ... | @@ -420,12 +418,8 @@ edges | Assert.cs:21:9:21:25 | [b (line 7): true] SSA def(s) | Assert.cs:23:27:23:27 | access to local variable s | | Assert.cs:29:9:29:25 | [b (line 7): false] SSA def(s) | Assert.cs:31:27:31:27 | access to local variable s | | Assert.cs:29:9:29:25 | [b (line 7): true] SSA def(s) | Assert.cs:31:27:31:27 | access to local variable s | -| Assert.cs:45:9:45:25 | [b (line 7): false] SSA def(s) | Assert.cs:46:36:46:36 | [b (line 7): false] access to parameter b | -| Assert.cs:45:9:45:25 | [b (line 7): true] SSA def(s) | Assert.cs:46:36:46:36 | [b (line 7): true] access to parameter b | -| Assert.cs:46:36:46:36 | [b (line 7): false] access to parameter b | Assert.cs:47:27:47:27 | access to local variable s | -| Assert.cs:46:36:46:36 | [b (line 7): true] access to parameter b | Assert.cs:47:27:47:27 | access to local variable s | -| Assert.cs:49:9:49:25 | SSA def(s) | Assert.cs:50:37:50:37 | access to parameter b | -| Assert.cs:50:37:50:37 | access to parameter b | Assert.cs:51:27:51:27 | access to local variable s | +| Assert.cs:45:9:45:25 | [b (line 7): true] SSA def(s) | Assert.cs:47:27:47:27 | access to local variable s | +| Assert.cs:49:9:49:25 | [b (line 7): true] SSA def(s) | Assert.cs:51:27:51:27 | access to local variable s | | B.cs:7:11:7:29 | SSA def(eqCallAlways) | B.cs:13:13:13:24 | access to local variable eqCallAlways | | B.cs:10:11:10:30 | SSA def(neqCallAlways) | B.cs:13:13:13:36 | ...; | | B.cs:10:11:10:30 | SSA def(neqCallAlways) | B.cs:15:9:16:26 | if (...) ... | @@ -719,6 +713,8 @@ edges | E.cs:384:9:385:24 | if (...) ... | E.cs:384:27:384:28 | access to parameter e2 | | E.cs:384:9:385:24 | if (...) ... | E.cs:386:27:386:28 | access to parameter e2 | | E.cs:384:27:384:28 | access to parameter e2 | E.cs:386:16:386:17 | access to parameter e1 | +| E.cs:404:9:404:18 | SSA def(i) | E.cs:405:16:405:16 | access to local variable i | +| E.cs:404:9:404:18 | SSA def(i) | E.cs:405:16:405:16 | access to local variable i | | Forwarding.cs:7:16:7:23 | SSA def(s) | Forwarding.cs:14:9:17:9 | if (...) ... | | Forwarding.cs:14:9:17:9 | if (...) ... | Forwarding.cs:19:9:22:9 | if (...) ... | | Forwarding.cs:19:9:22:9 | if (...) ... | Forwarding.cs:24:9:27:9 | if (...) ... | diff --git a/csharp/ql/test/query-tests/ReadOnlyContainer/ReadOnlyContainer.cs b/csharp/ql/test/query-tests/ReadOnlyContainer/ReadOnlyContainer.cs index 0befa88d0198..1159e50cae63 100755 --- a/csharp/ql/test/query-tests/ReadOnlyContainer/ReadOnlyContainer.cs +++ b/csharp/ql/test/query-tests/ReadOnlyContainer/ReadOnlyContainer.cs @@ -152,6 +152,21 @@ void f8(object arguments) break; } } + + void f9() + { + var l1 = new MyList(); // BAD + var x1 = l1[0]; + + var l2 = new MyList(); // GOOD + var x2 = l2[0]; + l2.Prop = 42; + } + + class MyList : List + { + public int Prop { get { return 0; } set { Add(value); } } + } } // semmle-extractor-options: /r:System.Collections.dll diff --git a/csharp/ql/test/query-tests/ReadOnlyContainer/ReadOnlyContainer.expected b/csharp/ql/test/query-tests/ReadOnlyContainer/ReadOnlyContainer.expected index 39e5f5e96284..a8e778c2b80c 100755 --- a/csharp/ql/test/query-tests/ReadOnlyContainer/ReadOnlyContainer.expected +++ b/csharp/ql/test/query-tests/ReadOnlyContainer/ReadOnlyContainer.expected @@ -8,4 +8,5 @@ | ReadOnlyContainer.cs:91:13:91:14 | v8 | The contents of this container are never initialized. | | ReadOnlyContainer.cs:96:13:96:14 | v9 | The contents of this container are never initialized. | | ReadOnlyContainer.cs:99:13:99:15 | v10 | The contents of this container are never initialized. | -| ReadOnlyContainer.cs:121:13:121:15 | v11 | The contents of this container are never initialized. | \ No newline at end of file +| ReadOnlyContainer.cs:121:13:121:15 | v11 | The contents of this container are never initialized. | +| ReadOnlyContainer.cs:158:13:158:14 | l1 | The contents of this container are never initialized. | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-022/ZipSlip/ZipSlip.expected b/csharp/ql/test/query-tests/Security Features/CWE-022/ZipSlip/ZipSlip.expected index 223fcf616c20..ccfaf8853694 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-022/ZipSlip/ZipSlip.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-022/ZipSlip/ZipSlip.expected @@ -1,25 +1,45 @@ edges -| ZipSlip.cs:16:52:16:65 | access to property FullName : String | ZipSlip.cs:32:41:32:52 | access to local variable destFilePath | -| ZipSlip.cs:16:52:16:65 | access to property FullName : String | ZipSlip.cs:36:45:36:56 | access to local variable destFilePath | -| ZipSlip.cs:16:52:16:65 | access to property FullName : String | ZipSlip.cs:40:41:40:52 | access to local variable destFilePath | -| ZipSlip.cs:19:31:19:44 | access to property FullName : String | ZipSlip.cs:24:41:24:52 | access to local variable destFileName | -| ZipSlip.cs:62:72:62:85 | access to property FullName : String | ZipSlip.cs:69:74:69:85 | access to local variable destFilePath | -| ZipSlip.cs:62:72:62:85 | access to property FullName : String | ZipSlip.cs:76:71:76:82 | access to local variable destFilePath | -| ZipSlip.cs:62:72:62:85 | access to property FullName : String | ZipSlip.cs:83:57:83:68 | access to local variable destFilePath | -| ZipSlip.cs:62:72:62:85 | access to property FullName : String | ZipSlip.cs:91:58:91:69 | access to local variable destFilePath | -| ZipSlipBad.cs:9:59:9:72 | access to property FullName : String | ZipSlipBad.cs:10:29:10:40 | access to local variable destFileName | +| ZipSlip.cs:16:35:16:66 | call to method GetFullPath : String | ZipSlip.cs:31:71:31:78 | access to local variable fullPath : String | +| ZipSlip.cs:16:35:16:66 | call to method GetFullPath : String | ZipSlip.cs:39:81:39:88 | access to local variable fullPath : String | +| ZipSlip.cs:16:52:16:65 | access to property FullName : String | ZipSlip.cs:16:35:16:66 | call to method GetFullPath : String | +| ZipSlip.cs:19:31:19:44 | access to property FullName : String | ZipSlip.cs:23:71:23:74 | access to local variable file : String | +| ZipSlip.cs:23:43:23:75 | call to method Combine : String | ZipSlip.cs:24:41:24:52 | access to local variable destFileName | +| ZipSlip.cs:23:71:23:74 | access to local variable file : String | ZipSlip.cs:23:43:23:75 | call to method Combine : String | +| ZipSlip.cs:31:43:31:79 | call to method Combine : String | ZipSlip.cs:32:41:32:52 | access to local variable destFilePath | +| ZipSlip.cs:31:43:31:79 | call to method Combine : String | ZipSlip.cs:36:45:36:56 | access to local variable destFilePath | +| ZipSlip.cs:31:71:31:78 | access to local variable fullPath : String | ZipSlip.cs:31:43:31:79 | call to method Combine : String | +| ZipSlip.cs:39:36:39:90 | call to method GetFullPath : String | ZipSlip.cs:40:41:40:52 | access to local variable destFilePath | +| ZipSlip.cs:39:53:39:89 | call to method Combine : String | ZipSlip.cs:39:36:39:90 | call to method GetFullPath : String | +| ZipSlip.cs:39:81:39:88 | access to local variable fullPath : String | ZipSlip.cs:39:53:39:89 | call to method Combine : String | +| ZipSlip.cs:62:47:62:86 | call to method Combine : String | ZipSlip.cs:69:74:69:85 | access to local variable destFilePath | +| ZipSlip.cs:62:47:62:86 | call to method Combine : String | ZipSlip.cs:76:71:76:82 | access to local variable destFilePath | +| ZipSlip.cs:62:47:62:86 | call to method Combine : String | ZipSlip.cs:83:57:83:68 | access to local variable destFilePath | +| ZipSlip.cs:62:47:62:86 | call to method Combine : String | ZipSlip.cs:91:58:91:69 | access to local variable destFilePath | +| ZipSlip.cs:62:72:62:85 | access to property FullName : String | ZipSlip.cs:62:47:62:86 | call to method Combine : String | +| ZipSlipBad.cs:9:31:9:73 | call to method Combine : String | ZipSlipBad.cs:10:29:10:40 | access to local variable destFileName | +| ZipSlipBad.cs:9:59:9:72 | access to property FullName : String | ZipSlipBad.cs:9:31:9:73 | call to method Combine : String | nodes +| ZipSlip.cs:16:35:16:66 | call to method GetFullPath : String | semmle.label | call to method GetFullPath : String | | ZipSlip.cs:16:52:16:65 | access to property FullName : String | semmle.label | access to property FullName : String | | ZipSlip.cs:19:31:19:44 | access to property FullName : String | semmle.label | access to property FullName : String | +| ZipSlip.cs:23:43:23:75 | call to method Combine : String | semmle.label | call to method Combine : String | +| ZipSlip.cs:23:71:23:74 | access to local variable file : String | semmle.label | access to local variable file : String | | ZipSlip.cs:24:41:24:52 | access to local variable destFileName | semmle.label | access to local variable destFileName | +| ZipSlip.cs:31:43:31:79 | call to method Combine : String | semmle.label | call to method Combine : String | +| ZipSlip.cs:31:71:31:78 | access to local variable fullPath : String | semmle.label | access to local variable fullPath : String | | ZipSlip.cs:32:41:32:52 | access to local variable destFilePath | semmle.label | access to local variable destFilePath | | ZipSlip.cs:36:45:36:56 | access to local variable destFilePath | semmle.label | access to local variable destFilePath | +| ZipSlip.cs:39:36:39:90 | call to method GetFullPath : String | semmle.label | call to method GetFullPath : String | +| ZipSlip.cs:39:53:39:89 | call to method Combine : String | semmle.label | call to method Combine : String | +| ZipSlip.cs:39:81:39:88 | access to local variable fullPath : String | semmle.label | access to local variable fullPath : String | | ZipSlip.cs:40:41:40:52 | access to local variable destFilePath | semmle.label | access to local variable destFilePath | +| ZipSlip.cs:62:47:62:86 | call to method Combine : String | semmle.label | call to method Combine : String | | ZipSlip.cs:62:72:62:85 | access to property FullName : String | semmle.label | access to property FullName : String | | ZipSlip.cs:69:74:69:85 | access to local variable destFilePath | semmle.label | access to local variable destFilePath | | ZipSlip.cs:76:71:76:82 | access to local variable destFilePath | semmle.label | access to local variable destFilePath | | ZipSlip.cs:83:57:83:68 | access to local variable destFilePath | semmle.label | access to local variable destFilePath | | ZipSlip.cs:91:58:91:69 | access to local variable destFilePath | semmle.label | access to local variable destFilePath | +| ZipSlipBad.cs:9:31:9:73 | call to method Combine : String | semmle.label | call to method Combine : String | | ZipSlipBad.cs:9:59:9:72 | access to property FullName : String | semmle.label | access to property FullName : String | | ZipSlipBad.cs:10:29:10:40 | access to local variable destFileName | semmle.label | access to local variable destFileName | #select diff --git a/csharp/ql/test/query-tests/Security Features/CWE-079/StoredXSS/XSS.expected b/csharp/ql/test/query-tests/Security Features/CWE-079/StoredXSS/XSS.expected index 8f04dc6f81ae..a661a86c71cc 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-079/StoredXSS/XSS.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-079/StoredXSS/XSS.expected @@ -1,10 +1,14 @@ edges -| XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | XSS.cs:26:32:26:51 | call to method ToString | -| XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | XSS.cs:27:29:27:48 | call to method ToString | -| XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | XSS.cs:28:26:28:45 | call to method ToString | +| XSS.cs:25:13:25:21 | [post] access to local variable userInput [[]] : String | XSS.cs:26:32:26:40 | access to local variable userInput [[]] : String | +| XSS.cs:25:13:25:21 | [post] access to local variable userInput [[]] : String | XSS.cs:27:29:27:37 | access to local variable userInput [[]] : String | +| XSS.cs:25:13:25:21 | [post] access to local variable userInput [[]] : String | XSS.cs:28:26:28:34 | access to local variable userInput [[]] : String | +| XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | XSS.cs:25:48:25:67 | access to property Text : String | +| XSS.cs:25:48:25:67 | access to property Text : String | XSS.cs:25:13:25:21 | [post] access to local variable userInput [[]] : String | +| XSS.cs:26:32:26:40 | access to local variable userInput [[]] : String | XSS.cs:26:32:26:51 | call to method ToString | +| XSS.cs:27:29:27:37 | access to local variable userInput [[]] : String | XSS.cs:27:29:27:48 | call to method ToString | +| XSS.cs:28:26:28:34 | access to local variable userInput [[]] : String | XSS.cs:28:26:28:45 | call to method ToString | | XSS.cs:37:27:37:53 | access to property QueryString : NameValueCollection | XSS.cs:38:36:38:39 | access to local variable name | | XSS.cs:57:27:57:65 | access to property QueryString : NameValueCollection | XSS.cs:59:22:59:25 | access to local variable name | -| XSS.cs:65:27:65:65 | access to property QueryString : NameValueCollection | XSS.cs:69:13:69:49 | access to property OutputStream | | XSS.cs:75:27:75:53 | access to property QueryString : NameValueCollection | XSS.cs:76:36:76:39 | access to local variable name | | XSS.cs:78:28:78:42 | access to property Request : HttpRequestBase | XSS.cs:79:36:79:40 | access to local variable name2 | | XSS.cs:85:27:85:53 | access to property QueryString : NameValueCollection | XSS.cs:86:28:86:31 | access to local variable name | @@ -19,7 +23,6 @@ edges | XSS.cs:28:26:28:45 | call to method ToString | XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | XSS.cs:28:26:28:45 | call to method ToString | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | User-provided value | | XSS.cs:38:36:38:39 | access to local variable name | XSS.cs:37:27:37:53 | access to property QueryString : NameValueCollection | XSS.cs:38:36:38:39 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:37:27:37:53 | access to property QueryString : NameValueCollection | User-provided value | | XSS.cs:59:22:59:25 | access to local variable name | XSS.cs:57:27:57:65 | access to property QueryString : NameValueCollection | XSS.cs:59:22:59:25 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:57:27:57:65 | access to property QueryString : NameValueCollection | User-provided value | -| XSS.cs:69:13:69:49 | access to property OutputStream | XSS.cs:65:27:65:65 | access to property QueryString : NameValueCollection | XSS.cs:69:13:69:49 | access to property OutputStream | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:65:27:65:65 | access to property QueryString : NameValueCollection | User-provided value | | XSS.cs:76:36:76:39 | access to local variable name | XSS.cs:75:27:75:53 | access to property QueryString : NameValueCollection | XSS.cs:76:36:76:39 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:75:27:75:53 | access to property QueryString : NameValueCollection | User-provided value | | XSS.cs:79:36:79:40 | access to local variable name2 | XSS.cs:78:28:78:42 | access to property Request : HttpRequestBase | XSS.cs:79:36:79:40 | access to local variable name2 | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:78:28:78:42 | access to property Request : HttpRequestBase | User-provided value | | XSS.cs:86:28:86:31 | access to local variable name | XSS.cs:85:27:85:53 | access to property QueryString : NameValueCollection | XSS.cs:86:28:86:31 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:85:27:85:53 | access to property QueryString : NameValueCollection | User-provided value | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-079/XSS/XSS.expected b/csharp/ql/test/query-tests/Security Features/CWE-079/XSS/XSS.expected index 81946f1054ed..36d8ecfb339c 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-079/XSS/XSS.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-079/XSS/XSS.expected @@ -2,11 +2,16 @@ edges | XSSAspNet.cs:20:25:20:43 | access to property QueryString : NameValueCollection | XSSAspNet.cs:27:30:27:34 | access to local variable sayHi | | XSSAspNet.cs:20:25:20:43 | access to property QueryString : NameValueCollection | XSSAspNet.cs:37:40:37:44 | access to local variable sayHi | | XSSAspNet.cs:44:28:44:46 | access to property QueryString : NameValueCollection | XSSAspNet.cs:44:28:44:55 | access to indexer | -| XSSAspNetCore.cs:21:52:21:64 | access to property Query : IQueryCollection | XSSAspNetCore.cs:21:52:21:76 | call to operator implicit conversion | +| XSSAspNetCore.cs:21:52:21:64 | access to property Query : IQueryCollection | XSSAspNetCore.cs:21:52:21:76 | access to indexer : StringValues | +| XSSAspNetCore.cs:21:52:21:76 | access to indexer : StringValues | XSSAspNetCore.cs:21:52:21:76 | call to operator implicit conversion | | XSSAspNetCore.cs:40:56:40:58 | foo : String | XSSAspNetCore.cs:44:51:44:53 | access to parameter foo | -| XSSAspNetCore.cs:58:43:58:55 | access to property Query : IQueryCollection | XSSAspNetCore.cs:58:43:58:73 | call to method ToString | +| XSSAspNetCore.cs:58:43:58:55 | access to property Query : IQueryCollection | XSSAspNetCore.cs:58:43:58:62 | access to indexer : StringValues | +| XSSAspNetCore.cs:58:43:58:62 | access to indexer : StringValues | XSSAspNetCore.cs:58:43:58:73 | call to method ToString | +| XSSAspNetCore.cs:61:44:61:56 | access to property Query : IQueryCollection | XSSAspNetCore.cs:61:44:61:63 | access to indexer : StringValues | | XSSAspNetCore.cs:61:44:61:56 | access to property Query : IQueryCollection | XSSAspNetCore.cs:61:44:61:66 | access to indexer | -| XSSAspNetCore.cs:72:51:72:65 | access to property Headers : IHeaderDictionary | XSSAspNetCore.cs:72:51:72:72 | call to operator implicit conversion | +| XSSAspNetCore.cs:61:44:61:63 | access to indexer : StringValues | XSSAspNetCore.cs:61:44:61:66 | access to indexer | +| XSSAspNetCore.cs:72:51:72:65 | access to property Headers : IHeaderDictionary | XSSAspNetCore.cs:72:51:72:72 | access to indexer : StringValues | +| XSSAspNetCore.cs:72:51:72:72 | access to indexer : StringValues | XSSAspNetCore.cs:72:51:72:72 | call to operator implicit conversion | #select | XSSAspNet.cs:27:30:27:34 | access to local variable sayHi | XSSAspNet.cs:20:25:20:43 | access to property QueryString : NameValueCollection | XSSAspNet.cs:27:30:27:34 | access to local variable sayHi | $@ flows to here and is written to HTML or JavaScript: System.Web.WebPages.WebPage.WriteLiteral() method. | XSSAspNet.cs:20:25:20:43 | access to property QueryString : NameValueCollection | User-provided value | | XSSAspNet.cs:37:40:37:44 | access to local variable sayHi | XSSAspNet.cs:20:25:20:43 | access to property QueryString : NameValueCollection | XSSAspNet.cs:37:40:37:44 | access to local variable sayHi | $@ flows to here and is written to HTML or JavaScript: System.Web.WebPages.WebPage.WriteLiteralTo() method. | XSSAspNet.cs:20:25:20:43 | access to property QueryString : NameValueCollection | User-provided value | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-112/MissingXMLValidation.expected b/csharp/ql/test/query-tests/Security Features/CWE-112/MissingXMLValidation.expected index b9abafda2f46..38c31c17825f 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-112/MissingXMLValidation.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-112/MissingXMLValidation.expected @@ -1,16 +1,26 @@ edges -| MissingXMLValidation.cs:14:34:14:56 | access to property QueryString : NameValueCollection | MissingXMLValidation.cs:18:26:18:58 | object creation of type StringReader | -| MissingXMLValidation.cs:14:34:14:56 | access to property QueryString : NameValueCollection | MissingXMLValidation.cs:23:26:23:58 | object creation of type StringReader | -| MissingXMLValidation.cs:14:34:14:56 | access to property QueryString : NameValueCollection | MissingXMLValidation.cs:29:26:29:58 | object creation of type StringReader | -| MissingXMLValidation.cs:14:34:14:56 | access to property QueryString : NameValueCollection | MissingXMLValidation.cs:37:26:37:58 | object creation of type StringReader | -| MissingXMLValidation.cs:14:34:14:56 | access to property QueryString : NameValueCollection | MissingXMLValidation.cs:47:26:47:58 | object creation of type StringReader | +| MissingXMLValidation.cs:14:34:14:56 | access to property QueryString : NameValueCollection | MissingXMLValidation.cs:18:43:18:57 | access to local variable userProvidedXml : String | +| MissingXMLValidation.cs:14:34:14:56 | access to property QueryString : NameValueCollection | MissingXMLValidation.cs:23:43:23:57 | access to local variable userProvidedXml : String | +| MissingXMLValidation.cs:14:34:14:56 | access to property QueryString : NameValueCollection | MissingXMLValidation.cs:29:43:29:57 | access to local variable userProvidedXml : String | +| MissingXMLValidation.cs:14:34:14:56 | access to property QueryString : NameValueCollection | MissingXMLValidation.cs:37:43:37:57 | access to local variable userProvidedXml : String | +| MissingXMLValidation.cs:14:34:14:56 | access to property QueryString : NameValueCollection | MissingXMLValidation.cs:47:43:47:57 | access to local variable userProvidedXml : String | +| MissingXMLValidation.cs:18:43:18:57 | access to local variable userProvidedXml : String | MissingXMLValidation.cs:18:26:18:58 | object creation of type StringReader | +| MissingXMLValidation.cs:23:43:23:57 | access to local variable userProvidedXml : String | MissingXMLValidation.cs:23:26:23:58 | object creation of type StringReader | +| MissingXMLValidation.cs:29:43:29:57 | access to local variable userProvidedXml : String | MissingXMLValidation.cs:29:26:29:58 | object creation of type StringReader | +| MissingXMLValidation.cs:37:43:37:57 | access to local variable userProvidedXml : String | MissingXMLValidation.cs:37:26:37:58 | object creation of type StringReader | +| MissingXMLValidation.cs:47:43:47:57 | access to local variable userProvidedXml : String | MissingXMLValidation.cs:47:26:47:58 | object creation of type StringReader | nodes | MissingXMLValidation.cs:14:34:14:56 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection | | MissingXMLValidation.cs:18:26:18:58 | object creation of type StringReader | semmle.label | object creation of type StringReader | +| MissingXMLValidation.cs:18:43:18:57 | access to local variable userProvidedXml : String | semmle.label | access to local variable userProvidedXml : String | | MissingXMLValidation.cs:23:26:23:58 | object creation of type StringReader | semmle.label | object creation of type StringReader | +| MissingXMLValidation.cs:23:43:23:57 | access to local variable userProvidedXml : String | semmle.label | access to local variable userProvidedXml : String | | MissingXMLValidation.cs:29:26:29:58 | object creation of type StringReader | semmle.label | object creation of type StringReader | +| MissingXMLValidation.cs:29:43:29:57 | access to local variable userProvidedXml : String | semmle.label | access to local variable userProvidedXml : String | | MissingXMLValidation.cs:37:26:37:58 | object creation of type StringReader | semmle.label | object creation of type StringReader | +| MissingXMLValidation.cs:37:43:37:57 | access to local variable userProvidedXml : String | semmle.label | access to local variable userProvidedXml : String | | MissingXMLValidation.cs:47:26:47:58 | object creation of type StringReader | semmle.label | object creation of type StringReader | +| MissingXMLValidation.cs:47:43:47:57 | access to local variable userProvidedXml : String | semmle.label | access to local variable userProvidedXml : String | #select | MissingXMLValidation.cs:18:26:18:58 | object creation of type StringReader | MissingXMLValidation.cs:14:34:14:56 | access to property QueryString : NameValueCollection | MissingXMLValidation.cs:18:26:18:58 | object creation of type StringReader | $@ flows to here and is processed as XML without validation because there is no 'XmlReaderSettings' instance specifying schema validation. | MissingXMLValidation.cs:14:34:14:56 | access to property QueryString | User-provided value | | MissingXMLValidation.cs:23:26:23:58 | object creation of type StringReader | MissingXMLValidation.cs:14:34:14:56 | access to property QueryString : NameValueCollection | MissingXMLValidation.cs:23:26:23:58 | object creation of type StringReader | $@ flows to here and is processed as XML without validation because the 'XmlReaderSettings' instance does not specify the 'ValidationType' as 'Schema'. | MissingXMLValidation.cs:14:34:14:56 | access to property QueryString | User-provided value | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-327/InsufficientKeySize/InsufficientKeySize.cs b/csharp/ql/test/query-tests/Security Features/CWE-327/InsufficientKeySize/InsufficientKeySize.cs index 4ec825ddd63f..90be31d0a07f 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-327/InsufficientKeySize/InsufficientKeySize.cs +++ b/csharp/ql/test/query-tests/Security Features/CWE-327/InsufficientKeySize/InsufficientKeySize.cs @@ -13,18 +13,18 @@ public void CryptoMethod() // GOOD: Key size is greater than 128 new RC2CryptoServiceProvider().EffectiveKeySize = 256; - // BAD: Key size is less than 1024. + // BAD: Key size is less than 2048. DSACryptoServiceProvider dsaBad = new DSACryptoServiceProvider(512); - // GOOD: Key size defaults to 1024. + // GOOD: Key size defaults to 2048. DSACryptoServiceProvider dsaGood1 = new DSACryptoServiceProvider(); - // GOOD: Key size is greater than 1024. + // GOOD: Key size is greater than 2048. DSACryptoServiceProvider dsaGood2 = new DSACryptoServiceProvider(2048); - // BAD: Key size is less than 1024. + // BAD: Key size is less than 2048. RSACryptoServiceProvider rsaBad = new RSACryptoServiceProvider(512); - // GOOD: Key size defaults to 1024. + // GOOD: Key size defaults to 2048. RSACryptoServiceProvider rsaGood1 = new RSACryptoServiceProvider(); - // GOOD: Key size is greater than 1024. + // GOOD: Key size is greater than 2048. RSACryptoServiceProvider rsaGood2 = new RSACryptoServiceProvider(2048); } } diff --git a/csharp/ql/test/query-tests/Security Features/CWE-327/InsufficientKeySize/InsufficientKeySize.expected b/csharp/ql/test/query-tests/Security Features/CWE-327/InsufficientKeySize/InsufficientKeySize.expected index dc03302c7f35..feb87da77d28 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-327/InsufficientKeySize/InsufficientKeySize.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-327/InsufficientKeySize/InsufficientKeySize.expected @@ -1,3 +1,3 @@ | InsufficientKeySize.cs:10:9:10:60 | ... = ... | Key size should be at least 128 bits for RC2 encryption. | -| InsufficientKeySize.cs:17:43:17:75 | object creation of type DSACryptoServiceProvider | Key size should be at least 1024 bits for DSA encryption. | -| InsufficientKeySize.cs:24:43:24:75 | object creation of type RSACryptoServiceProvider | Key size should be at least 1024 bits for RSA encryption. | +| InsufficientKeySize.cs:17:43:17:75 | object creation of type DSACryptoServiceProvider | Key size should be at least 2048 bits for DSA encryption. | +| InsufficientKeySize.cs:24:43:24:75 | object creation of type RSACryptoServiceProvider | Key size should be at least 2048 bits for RSA encryption. | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-338/InsecureRandomness.expected b/csharp/ql/test/query-tests/Security Features/CWE-338/InsecureRandomness.expected index b6aff7ad8aa4..138451c31dcb 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-338/InsecureRandomness.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-338/InsecureRandomness.expected @@ -1,8 +1,14 @@ edges -| InsecureRandomness.cs:28:23:28:43 | (...) ... : Int32 | InsecureRandomness.cs:31:16:31:32 | call to method ToString : String | +| InsecureRandomness.cs:28:13:28:16 | [post] access to local variable data [[]] : Int32 | InsecureRandomness.cs:29:57:29:60 | access to local variable data [[]] : Int32 | +| InsecureRandomness.cs:28:23:28:43 | (...) ... : Int32 | InsecureRandomness.cs:28:13:28:16 | [post] access to local variable data [[]] : Int32 | | InsecureRandomness.cs:28:29:28:43 | call to method Next : Int32 | InsecureRandomness.cs:28:23:28:43 | (...) ... : Int32 | +| InsecureRandomness.cs:29:13:29:18 | [post] access to local variable result [[]] : String | InsecureRandomness.cs:31:16:31:21 | access to local variable result [[]] : String | +| InsecureRandomness.cs:29:27:29:61 | call to method GetString : String | InsecureRandomness.cs:29:13:29:18 | [post] access to local variable result [[]] : String | +| InsecureRandomness.cs:29:57:29:60 | access to local variable data [[]] : Int32 | InsecureRandomness.cs:29:27:29:61 | call to method GetString : String | +| InsecureRandomness.cs:31:16:31:21 | access to local variable result [[]] : String | InsecureRandomness.cs:31:16:31:32 | call to method ToString : String | | InsecureRandomness.cs:31:16:31:32 | call to method ToString : String | InsecureRandomness.cs:12:27:12:50 | call to method InsecureRandomString | -| InsecureRandomness.cs:60:31:60:39 | call to method Next : Int32 | InsecureRandomness.cs:62:16:62:32 | call to method ToString : String | +| InsecureRandomness.cs:60:31:60:39 | call to method Next : Int32 | InsecureRandomness.cs:62:16:62:21 | access to local variable result : String | +| InsecureRandomness.cs:62:16:62:21 | access to local variable result : String | InsecureRandomness.cs:62:16:62:32 | call to method ToString : String | | InsecureRandomness.cs:62:16:62:32 | call to method ToString : String | InsecureRandomness.cs:13:20:13:56 | call to method InsecureRandomStringFromSelection | | InsecureRandomness.cs:72:31:72:39 | call to method Next : Int32 | InsecureRandomness.cs:74:16:74:21 | access to local variable result : String | | InsecureRandomness.cs:74:16:74:21 | access to local variable result : String | InsecureRandomness.cs:14:20:14:54 | call to method InsecureRandomStringFromIndexer | @@ -10,10 +16,16 @@ nodes | InsecureRandomness.cs:12:27:12:50 | call to method InsecureRandomString | semmle.label | call to method InsecureRandomString | | InsecureRandomness.cs:13:20:13:56 | call to method InsecureRandomStringFromSelection | semmle.label | call to method InsecureRandomStringFromSelection | | InsecureRandomness.cs:14:20:14:54 | call to method InsecureRandomStringFromIndexer | semmle.label | call to method InsecureRandomStringFromIndexer | +| InsecureRandomness.cs:28:13:28:16 | [post] access to local variable data [[]] : Int32 | semmle.label | [post] access to local variable data [[]] : Int32 | | InsecureRandomness.cs:28:23:28:43 | (...) ... : Int32 | semmle.label | (...) ... : Int32 | | InsecureRandomness.cs:28:29:28:43 | call to method Next : Int32 | semmle.label | call to method Next : Int32 | +| InsecureRandomness.cs:29:13:29:18 | [post] access to local variable result [[]] : String | semmle.label | [post] access to local variable result [[]] : String | +| InsecureRandomness.cs:29:27:29:61 | call to method GetString : String | semmle.label | call to method GetString : String | +| InsecureRandomness.cs:29:57:29:60 | access to local variable data [[]] : Int32 | semmle.label | access to local variable data [[]] : Int32 | +| InsecureRandomness.cs:31:16:31:21 | access to local variable result [[]] : String | semmle.label | access to local variable result [[]] : String | | InsecureRandomness.cs:31:16:31:32 | call to method ToString : String | semmle.label | call to method ToString : String | | InsecureRandomness.cs:60:31:60:39 | call to method Next : Int32 | semmle.label | call to method Next : Int32 | +| InsecureRandomness.cs:62:16:62:21 | access to local variable result : String | semmle.label | access to local variable result : String | | InsecureRandomness.cs:62:16:62:32 | call to method ToString : String | semmle.label | call to method ToString : String | | InsecureRandomness.cs:72:31:72:39 | call to method Next : Int32 | semmle.label | call to method Next : Int32 | | InsecureRandomness.cs:74:16:74:21 | access to local variable result : String | semmle.label | access to local variable result : String | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-601/UrlRedirect/UrlRedirect.expected b/csharp/ql/test/query-tests/Security Features/CWE-601/UrlRedirect/UrlRedirect.expected index afcc216fc020..2ed9af3f8f20 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-601/UrlRedirect/UrlRedirect.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-601/UrlRedirect/UrlRedirect.expected @@ -4,15 +4,19 @@ edges | UrlRedirect.cs:39:44:39:66 | access to property QueryString : NameValueCollection | UrlRedirect.cs:39:44:39:74 | access to indexer | | UrlRedirect.cs:40:47:40:69 | access to property QueryString : NameValueCollection | UrlRedirect.cs:40:47:40:77 | access to indexer | | UrlRedirectCore.cs:15:44:15:48 | value : String | UrlRedirectCore.cs:18:22:18:26 | access to parameter value | -| UrlRedirectCore.cs:15:44:15:48 | value : String | UrlRedirectCore.cs:21:44:21:48 | call to operator implicit conversion | -| UrlRedirectCore.cs:15:44:15:48 | value : String | UrlRedirectCore.cs:27:46:27:50 | call to operator implicit conversion | +| UrlRedirectCore.cs:15:44:15:48 | value : String | UrlRedirectCore.cs:21:44:21:48 | access to parameter value : String | +| UrlRedirectCore.cs:15:44:15:48 | value : String | UrlRedirectCore.cs:27:46:27:50 | access to parameter value : String | | UrlRedirectCore.cs:15:44:15:48 | value : String | UrlRedirectCore.cs:33:66:33:70 | access to parameter value | -| UrlRedirectCore.cs:15:44:15:48 | value : String | UrlRedirectCore.cs:36:49:36:53 | call to operator implicit conversion | +| UrlRedirectCore.cs:15:44:15:48 | value : String | UrlRedirectCore.cs:36:49:36:53 | access to parameter value : String | | UrlRedirectCore.cs:15:44:15:48 | value : String | UrlRedirectCore.cs:39:69:39:73 | access to parameter value | | UrlRedirectCore.cs:15:44:15:48 | value : String | UrlRedirectCore.cs:42:39:42:53 | ... + ... | +| UrlRedirectCore.cs:21:44:21:48 | access to parameter value : String | UrlRedirectCore.cs:21:44:21:48 | call to operator implicit conversion | +| UrlRedirectCore.cs:27:46:27:50 | access to parameter value : String | UrlRedirectCore.cs:27:46:27:50 | call to operator implicit conversion | +| UrlRedirectCore.cs:36:49:36:53 | access to parameter value : String | UrlRedirectCore.cs:36:49:36:53 | call to operator implicit conversion | | UrlRedirectCore.cs:47:51:47:55 | value : String | UrlRedirectCore.cs:50:28:50:32 | access to parameter value | -| UrlRedirectCore.cs:47:51:47:55 | value : String | UrlRedirectCore.cs:55:32:55:45 | object creation of type Uri | +| UrlRedirectCore.cs:47:51:47:55 | value : String | UrlRedirectCore.cs:55:40:55:44 | access to parameter value : String | | UrlRedirectCore.cs:47:51:47:55 | value : String | UrlRedirectCore.cs:58:31:58:35 | access to parameter value | +| UrlRedirectCore.cs:55:40:55:44 | access to parameter value : String | UrlRedirectCore.cs:55:32:55:45 | object creation of type Uri | nodes | UrlRedirect.cs:14:31:14:53 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection | | UrlRedirect.cs:14:31:14:61 | access to indexer | semmle.label | access to indexer | @@ -24,15 +28,19 @@ nodes | UrlRedirect.cs:49:29:49:31 | access to local variable url | semmle.label | access to local variable url | | UrlRedirectCore.cs:15:44:15:48 | value : String | semmle.label | value : String | | UrlRedirectCore.cs:18:22:18:26 | access to parameter value | semmle.label | access to parameter value | +| UrlRedirectCore.cs:21:44:21:48 | access to parameter value : String | semmle.label | access to parameter value : String | | UrlRedirectCore.cs:21:44:21:48 | call to operator implicit conversion | semmle.label | call to operator implicit conversion | +| UrlRedirectCore.cs:27:46:27:50 | access to parameter value : String | semmle.label | access to parameter value : String | | UrlRedirectCore.cs:27:46:27:50 | call to operator implicit conversion | semmle.label | call to operator implicit conversion | | UrlRedirectCore.cs:33:66:33:70 | access to parameter value | semmle.label | access to parameter value | +| UrlRedirectCore.cs:36:49:36:53 | access to parameter value : String | semmle.label | access to parameter value : String | | UrlRedirectCore.cs:36:49:36:53 | call to operator implicit conversion | semmle.label | call to operator implicit conversion | | UrlRedirectCore.cs:39:69:39:73 | access to parameter value | semmle.label | access to parameter value | | UrlRedirectCore.cs:42:39:42:53 | ... + ... | semmle.label | ... + ... | | UrlRedirectCore.cs:47:51:47:55 | value : String | semmle.label | value : String | | UrlRedirectCore.cs:50:28:50:32 | access to parameter value | semmle.label | access to parameter value | | UrlRedirectCore.cs:55:32:55:45 | object creation of type Uri | semmle.label | object creation of type Uri | +| UrlRedirectCore.cs:55:40:55:44 | access to parameter value : String | semmle.label | access to parameter value : String | | UrlRedirectCore.cs:58:31:58:35 | access to parameter value | semmle.label | access to parameter value | #select | UrlRedirect.cs:14:31:14:61 | access to indexer | UrlRedirect.cs:14:31:14:53 | access to property QueryString : NameValueCollection | UrlRedirect.cs:14:31:14:61 | access to indexer | Untrusted URL redirection due to $@. | UrlRedirect.cs:14:31:14:53 | access to property QueryString | user-provided value | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-807/ConditionalBypass.expected b/csharp/ql/test/query-tests/Security Features/CWE-807/ConditionalBypass.expected index c969d8a9befb..72c7464ba38a 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-807/ConditionalBypass.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-807/ConditionalBypass.expected @@ -1,32 +1,44 @@ edges | ConditionalBypass.cs:14:26:14:48 | access to property QueryString : NameValueCollection | ConditionalBypass.cs:18:13:18:30 | ... == ... | -| ConditionalBypass.cs:21:34:21:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:24:13:24:29 | access to property Value : String | -| ConditionalBypass.cs:21:34:21:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:29:13:29:29 | access to property Value : String | +| ConditionalBypass.cs:21:34:21:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:24:13:24:23 | access to local variable adminCookie : HttpCookie | +| ConditionalBypass.cs:21:34:21:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:29:13:29:23 | access to local variable adminCookie : HttpCookie | +| ConditionalBypass.cs:24:13:24:23 | access to local variable adminCookie : HttpCookie | ConditionalBypass.cs:24:13:24:29 | access to property Value : String | | ConditionalBypass.cs:24:13:24:29 | access to property Value : String | ConditionalBypass.cs:24:13:24:45 | call to method Equals | +| ConditionalBypass.cs:29:13:29:23 | access to local variable adminCookie : HttpCookie | ConditionalBypass.cs:29:13:29:29 | access to property Value : String | | ConditionalBypass.cs:29:13:29:29 | access to property Value : String | ConditionalBypass.cs:29:13:29:40 | ... == ... | -| ConditionalBypass.cs:44:32:44:66 | call to method GetHostByAddress : IPHostEntry | ConditionalBypass.cs:46:13:46:29 | access to property HostName : String | -| ConditionalBypass.cs:44:32:44:66 | call to method GetHostByAddress : IPHostEntry | ConditionalBypass.cs:51:13:51:29 | access to property HostName | +| ConditionalBypass.cs:44:32:44:66 | call to method GetHostByAddress : IPHostEntry | ConditionalBypass.cs:46:13:46:20 | access to local variable hostInfo : IPHostEntry | +| ConditionalBypass.cs:44:32:44:66 | call to method GetHostByAddress : IPHostEntry | ConditionalBypass.cs:51:13:51:20 | access to local variable hostInfo : IPHostEntry | +| ConditionalBypass.cs:46:13:46:20 | access to local variable hostInfo : IPHostEntry | ConditionalBypass.cs:46:13:46:29 | access to property HostName : String | | ConditionalBypass.cs:46:13:46:29 | access to property HostName : String | ConditionalBypass.cs:46:13:46:46 | ... == ... | -| ConditionalBypass.cs:72:34:72:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:74:13:74:29 | access to property Value : String | +| ConditionalBypass.cs:51:13:51:20 | access to local variable hostInfo : IPHostEntry | ConditionalBypass.cs:51:13:51:29 | access to property HostName | +| ConditionalBypass.cs:72:34:72:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:74:13:74:23 | access to local variable adminCookie : HttpCookie | +| ConditionalBypass.cs:74:13:74:23 | access to local variable adminCookie : HttpCookie | ConditionalBypass.cs:74:13:74:29 | access to property Value : String | | ConditionalBypass.cs:74:13:74:29 | access to property Value : String | ConditionalBypass.cs:74:13:74:40 | ... == ... | -| ConditionalBypass.cs:85:34:85:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:86:13:86:29 | access to property Value : String | +| ConditionalBypass.cs:85:34:85:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:86:13:86:23 | access to local variable adminCookie : HttpCookie | +| ConditionalBypass.cs:86:13:86:23 | access to local variable adminCookie : HttpCookie | ConditionalBypass.cs:86:13:86:29 | access to property Value : String | | ConditionalBypass.cs:86:13:86:29 | access to property Value : String | ConditionalBypass.cs:86:13:86:40 | ... == ... | nodes | ConditionalBypass.cs:14:26:14:48 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection | | ConditionalBypass.cs:18:13:18:30 | ... == ... | semmle.label | ... == ... | | ConditionalBypass.cs:21:34:21:52 | access to property Cookies : HttpCookieCollection | semmle.label | access to property Cookies : HttpCookieCollection | +| ConditionalBypass.cs:24:13:24:23 | access to local variable adminCookie : HttpCookie | semmle.label | access to local variable adminCookie : HttpCookie | | ConditionalBypass.cs:24:13:24:29 | access to property Value : String | semmle.label | access to property Value : String | | ConditionalBypass.cs:24:13:24:45 | call to method Equals | semmle.label | call to method Equals | +| ConditionalBypass.cs:29:13:29:23 | access to local variable adminCookie : HttpCookie | semmle.label | access to local variable adminCookie : HttpCookie | | ConditionalBypass.cs:29:13:29:29 | access to property Value : String | semmle.label | access to property Value : String | | ConditionalBypass.cs:29:13:29:40 | ... == ... | semmle.label | ... == ... | | ConditionalBypass.cs:44:32:44:66 | call to method GetHostByAddress : IPHostEntry | semmle.label | call to method GetHostByAddress : IPHostEntry | +| ConditionalBypass.cs:46:13:46:20 | access to local variable hostInfo : IPHostEntry | semmle.label | access to local variable hostInfo : IPHostEntry | | ConditionalBypass.cs:46:13:46:29 | access to property HostName : String | semmle.label | access to property HostName : String | | ConditionalBypass.cs:46:13:46:46 | ... == ... | semmle.label | ... == ... | +| ConditionalBypass.cs:51:13:51:20 | access to local variable hostInfo : IPHostEntry | semmle.label | access to local variable hostInfo : IPHostEntry | | ConditionalBypass.cs:51:13:51:29 | access to property HostName | semmle.label | access to property HostName | | ConditionalBypass.cs:72:34:72:52 | access to property Cookies : HttpCookieCollection | semmle.label | access to property Cookies : HttpCookieCollection | +| ConditionalBypass.cs:74:13:74:23 | access to local variable adminCookie : HttpCookie | semmle.label | access to local variable adminCookie : HttpCookie | | ConditionalBypass.cs:74:13:74:29 | access to property Value : String | semmle.label | access to property Value : String | | ConditionalBypass.cs:74:13:74:40 | ... == ... | semmle.label | ... == ... | | ConditionalBypass.cs:85:34:85:52 | access to property Cookies : HttpCookieCollection | semmle.label | access to property Cookies : HttpCookieCollection | +| ConditionalBypass.cs:86:13:86:23 | access to local variable adminCookie : HttpCookie | semmle.label | access to local variable adminCookie : HttpCookie | | ConditionalBypass.cs:86:13:86:29 | access to property Value : String | semmle.label | access to property Value : String | | ConditionalBypass.cs:86:13:86:40 | ... == ... | semmle.label | ... == ... | #select diff --git a/csharp/ql/test/query-tests/Security Features/CWE-838/InappropriateEncoding.expected b/csharp/ql/test/query-tests/Security Features/CWE-838/InappropriateEncoding.expected index 3bdac85df068..0dd5f0c1e2cb 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-838/InappropriateEncoding.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-838/InappropriateEncoding.expected @@ -3,7 +3,8 @@ edges | InappropriateEncoding.cs:15:28:15:40 | call to method Encode : String | InappropriateEncoding.cs:20:46:20:51 | access to local variable query1 | | InappropriateEncoding.cs:36:28:36:55 | call to method UrlEncode : String | InappropriateEncoding.cs:37:32:37:43 | access to local variable encodedValue | | InappropriateEncoding.cs:36:28:36:55 | call to method UrlEncode : String | InappropriateEncoding.cs:38:22:38:59 | ... + ... | -| InappropriateEncoding.cs:36:28:36:55 | call to method UrlEncode : String | InappropriateEncoding.cs:39:22:39:71 | call to method Format | +| InappropriateEncoding.cs:36:28:36:55 | call to method UrlEncode : String | InappropriateEncoding.cs:39:59:39:70 | access to local variable encodedValue : String | +| InappropriateEncoding.cs:39:59:39:70 | access to local variable encodedValue : String | InappropriateEncoding.cs:39:22:39:71 | call to method Format | | InappropriateEncoding.cs:57:28:57:56 | call to method HtmlEncode : String | InappropriateEncoding.cs:58:31:58:42 | access to local variable encodedValue | | InappropriateEncoding.cs:68:16:68:42 | call to method Replace : String | InappropriateEncoding.cs:15:28:15:40 | call to method Encode : String | | SqlEncode.cs:16:62:16:87 | call to method Replace : String | SqlEncode.cs:17:46:17:50 | access to local variable query | @@ -20,6 +21,7 @@ nodes | InappropriateEncoding.cs:37:32:37:43 | access to local variable encodedValue | semmle.label | access to local variable encodedValue | | InappropriateEncoding.cs:38:22:38:59 | ... + ... | semmle.label | ... + ... | | InappropriateEncoding.cs:39:22:39:71 | call to method Format | semmle.label | call to method Format | +| InappropriateEncoding.cs:39:59:39:70 | access to local variable encodedValue : String | semmle.label | access to local variable encodedValue : String | | InappropriateEncoding.cs:57:28:57:56 | call to method HtmlEncode : String | semmle.label | call to method HtmlEncode : String | | InappropriateEncoding.cs:58:31:58:42 | access to local variable encodedValue | semmle.label | access to local variable encodedValue | | InappropriateEncoding.cs:68:16:68:42 | call to method Replace : String | semmle.label | call to method Replace : String | diff --git a/csharp/ql/test/query-tests/Stubs/MinimalStubsFromSource.expected b/csharp/ql/test/query-tests/Stubs/MinimalStubsFromSource.expected index 5c7911617f30..967642a861fc 100644 --- a/csharp/ql/test/query-tests/Stubs/MinimalStubsFromSource.expected +++ b/csharp/ql/test/query-tests/Stubs/MinimalStubsFromSource.expected @@ -1 +1 @@ -| // This file contains auto-generated code.\n// original-extractor-options: /r:System.Text.RegularExpressions.dll /r:System.Collections.Specialized.dll /r:System.Net.dll /r:System.Web.dll /r:System.Net.HttpListener.dll /r:System.Collections.Specialized.dll /r:System.Private.Uri.dll /r:System.Runtime.Extensions.dll /r:System.Linq.Parallel.dll /r:System.Collections.Concurrent.dll /r:System.Linq.Expressions.dll /r:System.Collections.dll /r:System.Linq.Queryable.dll /r:System.Linq.dll /r:System.Collections.NonGeneric.dll /r:System.ObjectModel.dll /r:System.ComponentModel.TypeConverter.dll /r:System.IO.Compression.dll /r:System.IO.Pipes.dll /r:System.Net.Primitives.dll /r:System.Net.Security.dll /r:System.Security.Cryptography.Primitives.dll /r:System.Text.RegularExpressions.dll ${testdir}/../../resources/stubs/System.Web.cs /r:System.Runtime.Serialization.Primitives.dll\n\nnamespace System\n{\n// Generated from `System.Uri` in `System.Private.Uri, Version=4.0.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Uri : System.Runtime.Serialization.ISerializable\n{\n public override bool Equals(object comparand) => throw null;\n public override int GetHashCode() => throw null;\n public override string ToString() => throw null;\n void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) => throw null;\n}\n\nnamespace Collections\n{\n// Generated from `System.Collections.SortedList` in `System.Collections.NonGeneric, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class SortedList : System.ICloneable, System.Collections.IEnumerable, System.Collections.IDictionary, System.Collections.ICollection\n{\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n public virtual System.Collections.ICollection Keys { get => throw null; }\n public virtual System.Collections.ICollection Values { get => throw null; }\n public virtual System.Collections.IDictionaryEnumerator GetEnumerator() => throw null;\n public virtual bool Contains(object key) => throw null;\n public virtual bool IsFixedSize { get => throw null; }\n public virtual bool IsReadOnly { get => throw null; }\n public virtual bool IsSynchronized { get => throw null; }\n public virtual int Count { get => throw null; }\n public virtual object Clone() => throw null;\n public virtual object GetByIndex(int index) => throw null;\n public virtual object SyncRoot { get => throw null; }\n public virtual object this[object key] { get => throw null; set => throw null; }\n public virtual void Add(object key, object value) => throw null;\n public virtual void Clear() => throw null;\n public virtual void CopyTo(System.Array array, int arrayIndex) => throw null;\n public virtual void Remove(object key) => throw null;\n}\n\nnamespace Generic\n{\n// Generated from `System.Collections.Generic.Stack<>` in `System.Collections, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Stack : System.Collections.IEnumerable, System.Collections.ICollection, System.Collections.Generic.IReadOnlyCollection, System.Collections.Generic.IEnumerable\n{\n System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() => throw null;\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n bool System.Collections.ICollection.IsSynchronized { get => throw null; }\n object System.Collections.ICollection.SyncRoot { get => throw null; }\n public T Peek() => throw null;\n public int Count { get => throw null; }\n void System.Collections.ICollection.CopyTo(System.Array array, int arrayIndex) => throw null;\n}\n\n}\nnamespace Specialized\n{\n// Generated from `System.Collections.Specialized.NameObjectCollectionBase` in `System.Collections.Specialized, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nabstract public class NameObjectCollectionBase : System.Runtime.Serialization.ISerializable, System.Runtime.Serialization.IDeserializationCallback, System.Collections.IEnumerable, System.Collections.ICollection\n{\n bool System.Collections.ICollection.IsSynchronized { get => throw null; }\n object System.Collections.ICollection.SyncRoot { get => throw null; }\n public virtual System.Collections.IEnumerator GetEnumerator() => throw null;\n public virtual int Count { get => throw null; }\n public virtual void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) => throw null;\n public virtual void OnDeserialization(object sender) => throw null;\n void System.Collections.ICollection.CopyTo(System.Array array, int index) => throw null;\n}\n\n// Generated from `System.Collections.Specialized.NameValueCollection` in `System.Collections.Specialized, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class NameValueCollection : System.Collections.Specialized.NameObjectCollectionBase\n{\n public string this[string name] { get => throw null; set => throw null; }\n}\n\n}\n}\nnamespace IO\n{\n// Generated from `System.IO.StringReader` in `System.Runtime.Extensions, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class StringReader : System.IO.TextReader\n{\n protected override void Dispose(bool disposing) => throw null;\n public StringReader(string s) => throw null;\n public override System.Threading.Tasks.Task ReadAsync(System.Char[] buffer, int index, int count) => throw null;\n public override System.Threading.Tasks.Task ReadBlockAsync(System.Char[] buffer, int index, int count) => throw null;\n public override System.Threading.Tasks.Task ReadLineAsync() => throw null;\n public override System.Threading.Tasks.Task ReadToEndAsync() => throw null;\n public override System.Threading.Tasks.ValueTask ReadAsync(System.Memory buffer, System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.ValueTask ReadBlockAsync(System.Memory buffer, System.Threading.CancellationToken cancellationToken) => throw null;\n public override int Peek() => throw null;\n public override int Read() => throw null;\n public override int Read(System.Char[] buffer, int index, int count) => throw null;\n public override int Read(System.Span buffer) => throw null;\n public override int ReadBlock(System.Span buffer) => throw null;\n public override string ReadLine() => throw null;\n public override string ReadToEnd() => throw null;\n public override void Close() => throw null;\n}\n\n}\nnamespace Linq\n{\n// Generated from `System.Linq.Enumerable` in `System.Linq, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nstatic public class Enumerable\n{\n public static System.Collections.Generic.IEnumerable Select(this System.Collections.Generic.IEnumerable source, System.Func selector) => throw null;\n}\n\n// Generated from `System.Linq.IQueryable` in `System.Linq.Expressions, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic interface IQueryable : System.Collections.IEnumerable\n{\n}\n\n// Generated from `System.Linq.ParallelEnumerable` in `System.Linq.Parallel, Version=4.0.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nstatic public class ParallelEnumerable\n{\n public static System.Linq.ParallelQuery AsParallel(this System.Collections.IEnumerable source) => throw null;\n}\n\n// Generated from `System.Linq.ParallelQuery` in `System.Linq.Parallel, Version=4.0.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class ParallelQuery : System.Collections.IEnumerable\n{\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n}\n\n// Generated from `System.Linq.Queryable` in `System.Linq.Queryable, Version=4.0.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nstatic public class Queryable\n{\n public static System.Linq.IQueryable AsQueryable(this System.Collections.IEnumerable source) => throw null;\n}\n\n}\nnamespace Runtime\n{\nnamespace Serialization\n{\n// Generated from `System.Runtime.Serialization.DataContractAttribute` in `System.Runtime.Serialization.Primitives, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class DataContractAttribute : System.Attribute\n{\n public DataContractAttribute() => throw null;\n}\n\n// Generated from `System.Runtime.Serialization.DataMemberAttribute` in `System.Runtime.Serialization.Primitives, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class DataMemberAttribute : System.Attribute\n{\n public DataMemberAttribute() => throw null;\n}\n\n}\n}\nnamespace Text\n{\nnamespace RegularExpressions\n{\n// Generated from `System.Text.RegularExpressions.Capture` in `System.Text.RegularExpressions, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Capture\n{\n public override string ToString() => throw null;\n}\n\n// Generated from `System.Text.RegularExpressions.Group` in `System.Text.RegularExpressions, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Group : System.Text.RegularExpressions.Capture\n{\n}\n\n// Generated from `System.Text.RegularExpressions.Match` in `System.Text.RegularExpressions, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Match : System.Text.RegularExpressions.Group\n{\n}\n\n// Generated from `System.Text.RegularExpressions.RegexOptions` in `System.Text.RegularExpressions, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic enum RegexOptions\n{\n IgnoreCase,\n}\n\n// Generated from `System.Text.RegularExpressions.Regex` in `System.Text.RegularExpressions, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Regex : System.Runtime.Serialization.ISerializable\n{\n public Regex(string pattern) => throw null;\n public Regex(string pattern, System.Text.RegularExpressions.RegexOptions options, System.TimeSpan matchTimeout) => throw null;\n public System.Text.RegularExpressions.Match Match(string input) => throw null;\n public override string ToString() => throw null;\n public static System.Text.RegularExpressions.Match Match(string input, string pattern) => throw null;\n public static System.Text.RegularExpressions.Match Match(string input, string pattern, System.Text.RegularExpressions.RegexOptions options, System.TimeSpan matchTimeout) => throw null;\n public string Replace(string input, string replacement) => throw null;\n void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo si, System.Runtime.Serialization.StreamingContext context) => throw null;\n}\n\n}\n}\n}\n | +| // This file contains auto-generated code.\n// original-extractor-options: /r:System.Text.RegularExpressions.dll /r:System.Collections.Specialized.dll /r:System.Net.dll /r:System.Web.dll /r:System.Net.HttpListener.dll /r:System.Collections.Specialized.dll /r:System.Private.Uri.dll /r:System.Runtime.Extensions.dll /r:System.Linq.Parallel.dll /r:System.Collections.Concurrent.dll /r:System.Linq.Expressions.dll /r:System.Collections.dll /r:System.Linq.Queryable.dll /r:System.Linq.dll /r:System.Collections.NonGeneric.dll /r:System.ObjectModel.dll /r:System.ComponentModel.TypeConverter.dll /r:System.IO.Compression.dll /r:System.IO.Pipes.dll /r:System.Net.Primitives.dll /r:System.Net.Security.dll /r:System.Security.Cryptography.Primitives.dll /r:System.Text.RegularExpressions.dll ${testdir}/../../resources/stubs/System.Web.cs /r:System.Runtime.Serialization.Primitives.dll\n\nnamespace System\n{\n// Generated from `System.Uri` in `System.Private.Uri, Version=4.0.6.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Uri : System.Runtime.Serialization.ISerializable\n{\n public override bool Equals(object comparand) => throw null;\n public override int GetHashCode() => throw null;\n public override string ToString() => throw null;\n void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) => throw null;\n}\n\nnamespace Collections\n{\n// Generated from `System.Collections.SortedList` in `System.Collections.NonGeneric, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class SortedList : System.ICloneable, System.Collections.IEnumerable, System.Collections.IDictionary, System.Collections.ICollection\n{\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n public virtual System.Collections.ICollection Keys { get => throw null; }\n public virtual System.Collections.ICollection Values { get => throw null; }\n public virtual System.Collections.IDictionaryEnumerator GetEnumerator() => throw null;\n public virtual bool Contains(object key) => throw null;\n public virtual bool IsFixedSize { get => throw null; }\n public virtual bool IsReadOnly { get => throw null; }\n public virtual bool IsSynchronized { get => throw null; }\n public virtual int Count { get => throw null; }\n public virtual object Clone() => throw null;\n public virtual object GetByIndex(int index) => throw null;\n public virtual object SyncRoot { get => throw null; }\n public virtual object this[object key] { get => throw null; set => throw null; }\n public virtual void Add(object key, object value) => throw null;\n public virtual void Clear() => throw null;\n public virtual void CopyTo(System.Array array, int arrayIndex) => throw null;\n public virtual void Remove(object key) => throw null;\n}\n\nnamespace Generic\n{\n// Generated from `System.Collections.Generic.Stack<>` in `System.Collections, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Stack : System.Collections.IEnumerable, System.Collections.ICollection, System.Collections.Generic.IReadOnlyCollection, System.Collections.Generic.IEnumerable\n{\n System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() => throw null;\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n bool System.Collections.ICollection.IsSynchronized { get => throw null; }\n object System.Collections.ICollection.SyncRoot { get => throw null; }\n public T Peek() => throw null;\n public int Count { get => throw null; }\n void System.Collections.ICollection.CopyTo(System.Array array, int arrayIndex) => throw null;\n}\n\n}\nnamespace Specialized\n{\n// Generated from `System.Collections.Specialized.NameObjectCollectionBase` in `System.Collections.Specialized, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nabstract public class NameObjectCollectionBase : System.Runtime.Serialization.ISerializable, System.Runtime.Serialization.IDeserializationCallback, System.Collections.IEnumerable, System.Collections.ICollection\n{\n bool System.Collections.ICollection.IsSynchronized { get => throw null; }\n object System.Collections.ICollection.SyncRoot { get => throw null; }\n public virtual System.Collections.IEnumerator GetEnumerator() => throw null;\n public virtual int Count { get => throw null; }\n public virtual void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) => throw null;\n public virtual void OnDeserialization(object sender) => throw null;\n void System.Collections.ICollection.CopyTo(System.Array array, int index) => throw null;\n}\n\n// Generated from `System.Collections.Specialized.NameValueCollection` in `System.Collections.Specialized, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class NameValueCollection : System.Collections.Specialized.NameObjectCollectionBase\n{\n public string this[string name] { get => throw null; set => throw null; }\n}\n\n}\n}\nnamespace IO\n{\n// Generated from `System.IO.StringReader` in `System.Runtime.Extensions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class StringReader : System.IO.TextReader\n{\n protected override void Dispose(bool disposing) => throw null;\n public StringReader(string s) => throw null;\n public override System.Threading.Tasks.Task ReadAsync(System.Char[] buffer, int index, int count) => throw null;\n public override System.Threading.Tasks.Task ReadBlockAsync(System.Char[] buffer, int index, int count) => throw null;\n public override System.Threading.Tasks.Task ReadLineAsync() => throw null;\n public override System.Threading.Tasks.Task ReadToEndAsync() => throw null;\n public override System.Threading.Tasks.ValueTask ReadAsync(System.Memory buffer, System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.ValueTask ReadBlockAsync(System.Memory buffer, System.Threading.CancellationToken cancellationToken) => throw null;\n public override int Peek() => throw null;\n public override int Read() => throw null;\n public override int Read(System.Char[] buffer, int index, int count) => throw null;\n public override int Read(System.Span buffer) => throw null;\n public override int ReadBlock(System.Span buffer) => throw null;\n public override string ReadLine() => throw null;\n public override string ReadToEnd() => throw null;\n public override void Close() => throw null;\n}\n\n}\nnamespace Linq\n{\n// Generated from `System.Linq.Enumerable` in `System.Linq, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nstatic public class Enumerable\n{\n public static System.Collections.Generic.IEnumerable Select(this System.Collections.Generic.IEnumerable source, System.Func selector) => throw null;\n}\n\n// Generated from `System.Linq.IQueryable` in `System.Linq.Expressions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic interface IQueryable : System.Collections.IEnumerable\n{\n}\n\n// Generated from `System.Linq.ParallelEnumerable` in `System.Linq.Parallel, Version=4.0.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nstatic public class ParallelEnumerable\n{\n public static System.Linq.ParallelQuery AsParallel(this System.Collections.IEnumerable source) => throw null;\n}\n\n// Generated from `System.Linq.ParallelQuery` in `System.Linq.Parallel, Version=4.0.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class ParallelQuery : System.Collections.IEnumerable\n{\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n}\n\n// Generated from `System.Linq.Queryable` in `System.Linq.Queryable, Version=4.0.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nstatic public class Queryable\n{\n public static System.Linq.IQueryable AsQueryable(this System.Collections.IEnumerable source) => throw null;\n}\n\n}\nnamespace Runtime\n{\nnamespace Serialization\n{\n// Generated from `System.Runtime.Serialization.DataContractAttribute` in `System.Runtime.Serialization.Primitives, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class DataContractAttribute : System.Attribute\n{\n public DataContractAttribute() => throw null;\n}\n\n// Generated from `System.Runtime.Serialization.DataMemberAttribute` in `System.Runtime.Serialization.Primitives, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class DataMemberAttribute : System.Attribute\n{\n public DataMemberAttribute() => throw null;\n}\n\n}\n}\nnamespace Text\n{\nnamespace RegularExpressions\n{\n// Generated from `System.Text.RegularExpressions.Capture` in `System.Text.RegularExpressions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Capture\n{\n public override string ToString() => throw null;\n}\n\n// Generated from `System.Text.RegularExpressions.Group` in `System.Text.RegularExpressions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Group : System.Text.RegularExpressions.Capture\n{\n}\n\n// Generated from `System.Text.RegularExpressions.Match` in `System.Text.RegularExpressions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Match : System.Text.RegularExpressions.Group\n{\n}\n\n// Generated from `System.Text.RegularExpressions.RegexOptions` in `System.Text.RegularExpressions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic enum RegexOptions\n{\n IgnoreCase,\n}\n\n// Generated from `System.Text.RegularExpressions.Regex` in `System.Text.RegularExpressions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Regex : System.Runtime.Serialization.ISerializable\n{\n public Regex(string pattern) => throw null;\n public Regex(string pattern, System.Text.RegularExpressions.RegexOptions options, System.TimeSpan matchTimeout) => throw null;\n public System.Text.RegularExpressions.Match Match(string input) => throw null;\n public override string ToString() => throw null;\n public static System.Text.RegularExpressions.Match Match(string input, string pattern) => throw null;\n public static System.Text.RegularExpressions.Match Match(string input, string pattern, System.Text.RegularExpressions.RegexOptions options, System.TimeSpan matchTimeout) => throw null;\n public string Replace(string input, string replacement) => throw null;\n void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo si, System.Runtime.Serialization.StreamingContext context) => throw null;\n}\n\n}\n}\n}\n | diff --git a/csharp/tools/autobuild.cmd b/csharp/tools/autobuild.cmd new file mode 100644 index 000000000000..7d24060ff46b --- /dev/null +++ b/csharp/tools/autobuild.cmd @@ -0,0 +1,4 @@ +@echo off + +type NUL && "%CODEQL_EXTRACTOR_CSHARP_ROOT%/tools/%CODEQL_PLATFORM%/Semmle.Autobuild.CSharp.exe" +exit /b %ERRORLEVEL% diff --git a/csharp/tools/autobuild.sh b/csharp/tools/autobuild.sh new file mode 100755 index 000000000000..e8e007a10d74 --- /dev/null +++ b/csharp/tools/autobuild.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +set -eu + +if [ "$CODEQL_PLATFORM" != "linux64" ] && [ "$CODEQL_PLATFORM" != "osx64" ] ; then + echo "Automatic build detection for $CODEQL_PLATFORM is not implemented." + exit 1 +fi + +"$CODEQL_EXTRACTOR_CSHARP_ROOT/tools/$CODEQL_PLATFORM/Semmle.Autobuild.CSharp" || exit $? diff --git a/csharp/tools/linux64/compiler-tracing.spec b/csharp/tools/linux64/compiler-tracing.spec new file mode 100644 index 000000000000..a4d46ad6e294 --- /dev/null +++ b/csharp/tools/linux64/compiler-tracing.spec @@ -0,0 +1,9 @@ +**/mcs.exe: +**/csc.exe: + invoke ${config_dir}/Semmle.Extraction.CSharp.Driver + prepend --compiler + prepend "${compiler}" + prepend --cil +**/mono*: +**/dotnet: + invoke ${config_dir}/extract-csharp.sh diff --git a/csharp/tools/linux64/extract-csharp.sh b/csharp/tools/linux64/extract-csharp.sh new file mode 100755 index 000000000000..ec7013bf03eb --- /dev/null +++ b/csharp/tools/linux64/extract-csharp.sh @@ -0,0 +1,16 @@ +#!/bin/bash +echo extract-csharp.sh: Called with arguments: "$@" + +extractor="$CODEQL_EXTRACTOR_CSHARP_ROOT/tools/$CODEQL_PLATFORM/Semmle.Extraction.CSharp.Driver" + +for i in "$@" +do + shift + if [[ `basename -- "$i"` =~ csc.exe|mcs.exe|csc.dll ]] + then + echo extract-csharp.sh: exec $extractor --cil $@ + exec "$extractor" --compiler $i --cil $@ + fi +done + +echo extract-csharp.sh: Not a compiler invocation diff --git a/csharp/tools/osx64/compiler-tracing.spec b/csharp/tools/osx64/compiler-tracing.spec new file mode 100644 index 000000000000..e68f2f5ed984 --- /dev/null +++ b/csharp/tools/osx64/compiler-tracing.spec @@ -0,0 +1,24 @@ +**/mcs.exe: +**/csc.exe: + invoke ${config_dir}/Semmle.Extraction.CSharp.Driver + prepend --compiler + prepend "${compiler}" + prepend --cil +**/mono*: +**/dotnet: + invoke ${config_dir}/extract-csharp.sh +/usr/bin/codesign: + replace yes + invoke /usr/bin/env + prepend /usr/bin/codesign + trace no +/usr/bin/pkill: + replace yes + invoke /usr/bin/env + prepend /usr/bin/pkill + trace no +/usr/bin/pgrep: + replace yes + invoke /usr/bin/env + prepend /usr/bin/pgrep + trace no diff --git a/csharp/tools/osx64/extract-csharp.sh b/csharp/tools/osx64/extract-csharp.sh new file mode 100755 index 000000000000..ec7013bf03eb --- /dev/null +++ b/csharp/tools/osx64/extract-csharp.sh @@ -0,0 +1,16 @@ +#!/bin/bash +echo extract-csharp.sh: Called with arguments: "$@" + +extractor="$CODEQL_EXTRACTOR_CSHARP_ROOT/tools/$CODEQL_PLATFORM/Semmle.Extraction.CSharp.Driver" + +for i in "$@" +do + shift + if [[ `basename -- "$i"` =~ csc.exe|mcs.exe|csc.dll ]] + then + echo extract-csharp.sh: exec $extractor --cil $@ + exec "$extractor" --compiler $i --cil $@ + fi +done + +echo extract-csharp.sh: Not a compiler invocation diff --git a/csharp/tools/pre-finalize.cmd b/csharp/tools/pre-finalize.cmd new file mode 100644 index 000000000000..b6e7abab41b9 --- /dev/null +++ b/csharp/tools/pre-finalize.cmd @@ -0,0 +1,15 @@ +@echo off + +type NUL && "%CODEQL_DIST%\codeql" database index-files ^ + --include-extension=.config ^ + --include-extension=.csproj ^ + --include-extension=.props ^ + --include-extension=.xml ^ + --size-limit 10m ^ + --language xml ^ + -- ^ + "%CODEQL_EXTRACTOR_CSHARP_WIP_DATABASE%" +IF %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL% + +type NUL && "%CODEQL_JAVA_HOME%\bin\java.exe" -jar "%CODEQL_EXTRACTOR_CSHARP_ROOT%\tools\extractor-asp.jar" . +exit /b %ERRORLEVEL% diff --git a/csharp/tools/pre-finalize.sh b/csharp/tools/pre-finalize.sh new file mode 100755 index 000000000000..0e8ab78c9fd5 --- /dev/null +++ b/csharp/tools/pre-finalize.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +set -eu + +"$CODEQL_DIST/codeql" database index-files \ + --include-extension=.config \ + --include-extension=.csproj \ + --include-extension=.props \ + --include-extension=.xml \ + --size-limit 10m \ + --language xml \ + -- \ + "$CODEQL_EXTRACTOR_CSHARP_WIP_DATABASE" + +"$CODEQL_JAVA_HOME/bin/java" -jar "$CODEQL_EXTRACTOR_CSHARP_ROOT/tools/extractor-asp.jar" . diff --git a/csharp/tools/win64/compiler-tracing.spec b/csharp/tools/win64/compiler-tracing.spec new file mode 100644 index 000000000000..72ef54a8cabb --- /dev/null +++ b/csharp/tools/win64/compiler-tracing.spec @@ -0,0 +1,9 @@ +**\fakes*.exe: +**\moles*.exe: + order compiler + trace no +**\csc*.exe: + invoke ${config_dir}\Semmle.Extraction.CSharp.Driver.exe + prepend --compiler + prepend "${compiler}" + prepend --cil diff --git a/csharp/upgrades/f2aa2d4ac31309bd83ab633d0f40e8a442767bd1/old.dbscheme b/csharp/upgrades/f2aa2d4ac31309bd83ab633d0f40e8a442767bd1/old.dbscheme new file mode 100644 index 000000000000..f2aa2d4ac313 --- /dev/null +++ b/csharp/upgrades/f2aa2d4ac31309bd83ab633d0f40e8a442767bd1/old.dbscheme @@ -0,0 +1,1889 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * csc f1.cs f2.cs f3.cs + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + 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 + * + * csc f1.cs f2.cs f3.cs + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | --compiler + * 1 | *path to compiler* + * 2 | --cil + * 3 | f1.cs + * 4 | f2.cs + * 5 | f3.cs + */ +#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 + * + * csc f1.cs f2.cs f3.cs + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.cs + * 1 | f2.cs + * 2 | f3.cs + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The references used by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | ref1.dll + * 1 | ref2.dll + * 2 | ref3.dll + */ +#keyset[id, num] +compilation_referencing_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( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : 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 +); + +extractor_messages( + unique int id: @extractor_message, + int severity: int ref, + string origin : string ref, + string text : string ref, + string entity : string ref, + int location: @location_default ref, + string stack_trace : string 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 artifacts + */ + +externalDefects( + unique int id: @externalDefect, + string queryPath: string ref, + int location: @location ref, + string message: string ref, + float severity: float ref); + +externalMetrics( + unique int id: @externalMetric, + string queryPath: string ref, + int location: @location ref, + float value: float ref); + +externalData( + int id: @externalDataElement, + string path: string ref, + int column: int ref, + string value: string ref); + +snapshotDate( + unique date snapshotDate: date ref); + +sourceLocationPrefix( + string prefix: string ref); + +/* + * Duplicate code + */ + +duplicateCode( + unique int id: @duplication, + string relativePath: string ref, + int equivClass: int ref); + +similarCode( + unique int id: @similarity, + string relativePath: string ref, + int equivClass: int ref); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id: @duplication_or_similarity ref, + int offset: int ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +/* + * C# dbscheme + */ + +/** ELEMENTS **/ + +@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration + | @using_directive | @type_parameter_constraints | @external_element + | @xmllocatable | @asp_element | @namespace; + +@declaration = @callable | @generic | @assignable | @namespace; + +@named_element = @namespace | @declaration; + +@declaration_with_accessors = @property | @indexer | @event; + +@assignable = @variable | @assignable_with_accessors | @event; + +@assignable_with_accessors = @property | @indexer; + +@external_element = @externalMetric | @externalDefect | @externalDataElement; + +@attributable = @assembly | @field | @parameter | @operator | @method | @constructor + | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors; + +/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/ + +@location = @location_default | @assembly; + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +@sourceline = @file | @callable | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref); + +assemblies( + unique int id: @assembly, + int file: @file ref, + string fullname: string ref, + string name: string ref, + string version: string ref); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref); + +@container = @folder | @file ; + +containerparent( + int parent: @container ref, + unique int child: @container ref); + +file_extraction_mode( + unique int file: @file ref, + int mode: int ref + /* 0 = normal, 1 = standalone extractor */ + ); + +/** NAMESPACES **/ + +@type_container = @namespace | @type; + +namespaces( + unique int id: @namespace, + string name: string ref); + +namespace_declarations( + unique int id: @namespace_declaration, + int namespace_id: @namespace ref); + +namespace_declaration_location( + unique int id: @namespace_declaration ref, + int loc: @location ref); + +parent_namespace( + unique int child_id: @type_container ref, + int namespace_id: @namespace ref); + +@declaration_or_directive = @namespace_declaration | @type | @using_directive; + +parent_namespace_declaration( + int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes + int namespace_id: @namespace_declaration ref); + +@using_directive = @using_namespace_directive | @using_static_directive; + +using_namespace_directives( + unique int id: @using_namespace_directive, + int namespace_id: @namespace ref); + +using_static_directives( + unique int id: @using_static_directive, + int type_id: @type_or_ref ref); + +using_directive_location( + unique int id: @using_directive ref, + int loc: @location ref); + +/** TYPES **/ + +types( + unique int id: @type, + int kind: int ref, + string name: string ref); + +case @type.kind of + 1 = @bool_type +| 2 = @char_type +| 3 = @decimal_type +| 4 = @sbyte_type +| 5 = @short_type +| 6 = @int_type +| 7 = @long_type +| 8 = @byte_type +| 9 = @ushort_type +| 10 = @uint_type +| 11 = @ulong_type +| 12 = @float_type +| 13 = @double_type +| 14 = @enum_type +| 15 = @struct_type +| 17 = @class_type +| 19 = @interface_type +| 20 = @delegate_type +| 21 = @null_type +| 22 = @type_parameter +| 23 = @pointer_type +| 24 = @nullable_type +| 25 = @array_type +| 26 = @void_type +| 27 = @int_ptr_type +| 28 = @uint_ptr_type +| 29 = @dynamic_type +| 30 = @arglist_type +| 31 = @unknown_type +| 32 = @tuple_type + ; + +@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type; +@integral_type = @signed_integral_type | @unsigned_integral_type; +@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type; +@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type; +@floating_point_type = @float_type | @double_type; +@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type + | @uint_ptr_type | @tuple_type; +@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type + | @dynamic_type; +@value_or_ref_type = @value_type | @ref_type; + +typerefs( + unique int id: @typeref, + string name: string ref); + +typeref_type( + int id: @typeref ref, + unique int typeId: @type ref); + +@type_or_ref = @type | @typeref; + +array_element_type( + unique int array: @array_type ref, + int dimension: int ref, + int rank: int ref, + int element: @type_or_ref ref); + +nullable_underlying_type( + unique int nullable: @nullable_type ref, + int underlying: @type_or_ref ref); + +pointer_referent_type( + unique int pointer: @pointer_type ref, + int referent: @type_or_ref ref); + +enum_underlying_type( + unique int enum_id: @enum_type ref, + int underlying_type_id: @type_or_ref ref); + +delegate_return_type( + unique int delegate_id: @delegate_type ref, + int return_type_id: @type_or_ref ref); + +extend( + unique int sub: @type ref, + int super: @type_or_ref ref); + +@interface_or_ref = @interface_type | @typeref; + +implement( + int sub: @type ref, + int super: @type_or_ref ref); + +type_location( + int id: @type ref, + int loc: @location ref); + +tuple_underlying_type( + unique int tuple: @tuple_type ref, + int struct: @type_or_ref ref); + +#keyset[tuple, index] +tuple_element( + int tuple: @tuple_type ref, + int index: int ref, + unique int field: @field ref); + +attributes( + unique int id: @attribute, + int type_id: @type_or_ref ref, + int target: @attributable ref); + +attribute_location( + int id: @attribute ref, + int loc: @location ref); + +@type_mention_parent = @element | @type_mention; + +type_mention( + unique int id: @type_mention, + int type_id: @type_or_ref ref, + int parent: @type_mention_parent ref); + +type_mention_location( + unique int id: @type_mention ref, + int loc: @location ref); + +@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic; + +/** + * A direct annotation on an entity, for example `string? x;`. + * + * Annotations: + * 2 = reftype is not annotated "!" + * 3 = reftype is annotated "?" + * 4 = readonly ref type / in parameter + * 5 = ref type parameter, return or local variable + * 6 = out parameter + * + * Note that the annotation depends on the element it annotates. + * @assignable: The annotation is on the type of the assignable, for example the variable type. + * @type_parameter: The annotation is on the reftype constraint + * @callable: The annotation is on the return type + * @array_type: The annotation is on the element type + */ +type_annotation(int id: @has_type_annotation ref, int annotation: int ref); + +nullability(unique int nullability: @nullability, int kind: int ref); + +case @nullability.kind of + 0 = @oblivious +| 1 = @not_annotated +| 2 = @annotated +; + +#keyset[parent, index] +nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref) + +type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref); + +/** + * The nullable flow state of an expression, as determined by Roslyn. + * 0 = none (default, not populated) + * 1 = not null + * 2 = maybe null + */ +expr_flowstate(unique int id: @expr ref, int state: int ref); + +/** GENERICS **/ + +@generic = @type | @method | @local_function; + +type_parameters( + unique int id: @type_parameter ref, + int index: int ref, + int generic_id: @generic ref, + int variance: int ref /* none = 0, out = 1, in = 2 */); + +#keyset[constructed_id, index] +type_arguments( + int id: @type_or_ref ref, + int index: int ref, + int constructed_id: @generic_or_ref ref); + +@generic_or_ref = @generic | @typeref; + +constructed_generic( + unique int constructed: @generic ref, + int generic: @generic_or_ref ref); + +type_parameter_constraints( + unique int id: @type_parameter_constraints, + int param_id: @type_parameter ref); + +type_parameter_constraints_location( + int id: @type_parameter_constraints ref, + int loc: @location ref); + +general_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int kind: int ref /* class = 1, struct = 2, new = 3 */); + +specific_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref); + +specific_type_parameter_nullability( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref, + int nullability: @nullability ref); + +/** MODIFIERS */ + +@modifiable = @modifiable_direct | @event_accessor; + +@modifiable_direct = @member | @accessor | @local_function; + +modifiers( + unique int id: @modifier, + string name: string ref); + +has_modifiers( + int id: @modifiable_direct ref, + int mod_id: @modifier ref); + +compiler_generated(unique int id: @modifiable_direct ref); + +/** MEMBERS **/ + +@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type; + +@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr; + +@virtualizable = @method | @property | @indexer | @event; + +exprorstmt_name( + unique int parent_id: @named_exprorstmt ref, + string name: string ref); + +nested_types( + unique int id: @type ref, + int declaring_type_id: @type ref, + int unbound_id: @type ref); + +properties( + unique int id: @property, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @property ref); + +property_location( + int id: @property ref, + int loc: @location ref); + +indexers( + unique int id: @indexer, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @indexer ref); + +indexer_location( + int id: @indexer ref, + int loc: @location ref); + +accessors( + unique int id: @accessor, + int kind: int ref, + string name: string ref, + int declaring_member_id: @member ref, + int unbound_id: @accessor ref); + +case @accessor.kind of + 1 = @getter +| 2 = @setter + ; + +accessor_location( + int id: @accessor ref, + int loc: @location ref); + +events( + unique int id: @event, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @event ref); + +event_location( + int id: @event ref, + int loc: @location ref); + +event_accessors( + unique int id: @event_accessor, + int kind: int ref, + string name: string ref, + int declaring_event_id: @event ref, + int unbound_id: @event_accessor ref); + +case @event_accessor.kind of + 1 = @add_event_accessor +| 2 = @remove_event_accessor + ; + +event_accessor_location( + int id: @event_accessor ref, + int loc: @location ref); + +operators( + unique int id: @operator, + string name: string ref, + string symbol: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @operator ref); + +operator_location( + int id: @operator ref, + int loc: @location ref); + +constant_value( + int id: @variable ref, + string value: string ref); + +/** CALLABLES **/ + +@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function; + +@callable_accessor = @accessor | @event_accessor; + +methods( + unique int id: @method, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @method ref); + +method_location( + int id: @method ref, + int loc: @location ref); + +constructors( + unique int id: @constructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @constructor ref); + +constructor_location( + int id: @constructor ref, + int loc: @location ref); + +destructors( + unique int id: @destructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @destructor ref); + +destructor_location( + int id: @destructor ref, + int loc: @location ref); + +overrides( + int id: @callable ref, + int base_id: @callable ref); + +explicitly_implements( + unique int id: @member ref, + int interface_id: @interface_or_ref ref); + +local_functions( + unique int id: @local_function, + string name: string ref, + int return_type: @type ref, + int unbound_id: @local_function ref); + +local_function_stmts( + unique int fn: @local_function_stmt ref, + int stmt: @local_function ref); + +/** VARIABLES **/ + +@variable = @local_scope_variable | @field; + +@local_scope_variable = @local_variable | @parameter; + +fields( + unique int id: @field, + int kind: int ref, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @field ref); + +case @field.kind of + 1 = @addressable_field +| 2 = @constant + ; + +field_location( + int id: @field ref, + int loc: @location ref); + +localvars( + unique int id: @local_variable, + int kind: int ref, + string name: string ref, + int implicitly_typed: int ref /* 0 = no, 1 = yes */, + int type_id: @type_or_ref ref, + int parent_id: @local_var_decl_expr ref); + +case @local_variable.kind of + 1 = @addressable_local_variable +| 2 = @local_constant +| 3 = @local_variable_ref + ; + +localvar_location( + unique int id: @local_variable ref, + int loc: @location ref); + +@parameterizable = @callable | @delegate_type | @indexer; + +#keyset[name, parent_id] +#keyset[index, parent_id] +params( + unique int id: @parameter, + string name: string ref, + int type_id: @type_or_ref ref, + int index: int ref, + int mode: int ref, /* value = 0, ref = 1, out = 2, array = 3, this = 4 */ + int parent_id: @parameterizable ref, + int unbound_id: @parameter ref); + +param_location( + int id: @parameter ref, + int loc: @location ref); + +/** STATEMENTS **/ + +@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent; + +statements( + unique int id: @stmt, + int kind: int ref); + +#keyset[index, parent] +stmt_parent( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_stmt_parent = @callable; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +stmt_parent_top_level( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @top_level_stmt_parent ref); + +case @stmt.kind of + 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @switch_stmt +| 5 = @while_stmt +| 6 = @do_stmt +| 7 = @for_stmt +| 8 = @foreach_stmt +| 9 = @break_stmt +| 10 = @continue_stmt +| 11 = @goto_stmt +| 12 = @goto_case_stmt +| 13 = @goto_default_stmt +| 14 = @throw_stmt +| 15 = @return_stmt +| 16 = @yield_stmt +| 17 = @try_stmt +| 18 = @checked_stmt +| 19 = @unchecked_stmt +| 20 = @lock_stmt +| 21 = @using_block_stmt +| 22 = @var_decl_stmt +| 23 = @const_decl_stmt +| 24 = @empty_stmt +| 25 = @unsafe_stmt +| 26 = @fixed_stmt +| 27 = @label_stmt +| 28 = @catch +| 29 = @case_stmt +| 30 = @local_function_stmt +| 31 = @using_decl_stmt + ; + +@using_stmt = @using_block_stmt | @using_decl_stmt; + +@labeled_stmt = @label_stmt | @case; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt; + +@cond_stmt = @if_stmt | @switch_stmt; + +@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt; + +@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt + | @yield_stmt; + +@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt; + + +stmt_location( + unique int id: @stmt ref, + int loc: @location ref); + +catch_type( + unique int catch_id: @catch ref, + int type_id: @type_or_ref ref, + int kind: int ref /* explicit = 1, implicit = 2 */); + +/** EXPRESSIONS **/ + +expressions( + unique int id: @expr, + int kind: int ref, + int type_id: @type_or_ref ref); + +#keyset[index, parent] +expr_parent( + unique int expr: @expr ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter; + +@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +expr_parent_top_level( + unique int expr: @expr ref, + int index: int ref, + int parent: @top_level_exprorstmt_parent ref); + +case @expr.kind of +/* literal */ + 1 = @bool_literal_expr +| 2 = @char_literal_expr +| 3 = @decimal_literal_expr +| 4 = @int_literal_expr +| 5 = @long_literal_expr +| 6 = @uint_literal_expr +| 7 = @ulong_literal_expr +| 8 = @float_literal_expr +| 9 = @double_literal_expr +| 10 = @string_literal_expr +| 11 = @null_literal_expr +/* primary & unary */ +| 12 = @this_access_expr +| 13 = @base_access_expr +| 14 = @local_variable_access_expr +| 15 = @parameter_access_expr +| 16 = @field_access_expr +| 17 = @property_access_expr +| 18 = @method_access_expr +| 19 = @event_access_expr +| 20 = @indexer_access_expr +| 21 = @array_access_expr +| 22 = @type_access_expr +| 23 = @typeof_expr +| 24 = @method_invocation_expr +| 25 = @delegate_invocation_expr +| 26 = @operator_invocation_expr +| 27 = @cast_expr +| 28 = @object_creation_expr +| 29 = @explicit_delegate_creation_expr +| 30 = @implicit_delegate_creation_expr +| 31 = @array_creation_expr +| 32 = @default_expr +| 33 = @plus_expr +| 34 = @minus_expr +| 35 = @bit_not_expr +| 36 = @log_not_expr +| 37 = @post_incr_expr +| 38 = @post_decr_expr +| 39 = @pre_incr_expr +| 40 = @pre_decr_expr +/* multiplicative */ +| 41 = @mul_expr +| 42 = @div_expr +| 43 = @rem_expr +/* additive */ +| 44 = @add_expr +| 45 = @sub_expr +/* shift */ +| 46 = @lshift_expr +| 47 = @rshift_expr +/* relational */ +| 48 = @lt_expr +| 49 = @gt_expr +| 50 = @le_expr +| 51 = @ge_expr +/* equality */ +| 52 = @eq_expr +| 53 = @ne_expr +/* logical */ +| 54 = @bit_and_expr +| 55 = @bit_xor_expr +| 56 = @bit_or_expr +| 57 = @log_and_expr +| 58 = @log_or_expr +/* type testing */ +| 59 = @is_expr +| 60 = @as_expr +/* null coalescing */ +| 61 = @null_coalescing_expr +/* conditional */ +| 62 = @conditional_expr +/* assignment */ +| 63 = @simple_assign_expr +| 64 = @assign_add_expr +| 65 = @assign_sub_expr +| 66 = @assign_mul_expr +| 67 = @assign_div_expr +| 68 = @assign_rem_expr +| 69 = @assign_and_expr +| 70 = @assign_xor_expr +| 71 = @assign_or_expr +| 72 = @assign_lshift_expr +| 73 = @assign_rshift_expr +/* more */ +| 74 = @object_init_expr +| 75 = @collection_init_expr +| 76 = @array_init_expr +| 77 = @checked_expr +| 78 = @unchecked_expr +| 79 = @constructor_init_expr +| 80 = @add_event_expr +| 81 = @remove_event_expr +| 82 = @par_expr +| 83 = @local_var_decl_expr +| 84 = @lambda_expr +| 85 = @anonymous_method_expr +| 86 = @namespace_expr +/* dynamic */ +| 92 = @dynamic_element_access_expr +| 93 = @dynamic_member_access_expr +/* unsafe */ +| 100 = @pointer_indirection_expr +| 101 = @address_of_expr +| 102 = @sizeof_expr +/* async */ +| 103 = @await_expr +/* C# 6.0 */ +| 104 = @nameof_expr +| 105 = @interpolated_string_expr +| 106 = @unknown_expr +/* C# 7.0 */ +| 107 = @throw_expr +| 108 = @tuple_expr +| 109 = @local_function_invocation_expr +| 110 = @ref_expr +| 111 = @discard_expr +/* C# 8.0 */ +| 112 = @range_expr +| 113 = @index_expr +| 114 = @switch_expr +| 115 = @recursive_pattern_expr +| 116 = @property_pattern_expr +| 117 = @positional_pattern_expr +| 118 = @switch_case_expr +| 119 = @assign_coalesce_expr +| 120 = @suppress_nullable_warning_expr +| 121 = @namespace_access_expr +; + +@switch = @switch_stmt | @switch_expr; +@case = @case_stmt | @switch_case_expr; +@pattern_match = @case | @is_expr; + +@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr; +@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr; +@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr + | @string_literal_expr | @null_literal_expr; + +@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr; +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr | @assign_coalesce_expr; +@assign_event_expr = @add_event_expr | @remove_event_expr; + +@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr + | @assign_rem_expr +@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr + | @assign_lshift_expr | @assign_rshift_expr; + +@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr + | @method_access_expr | @type_access_expr | @dynamic_member_access_expr; +@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr; +@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr; + +@local_variable_access = @local_variable_access_expr | @local_var_decl_expr; +@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access; +@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr; + +@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr + | @event_access_expr | @dynamic_member_access_expr; + +@objectorcollection_init_expr = @object_init_expr | @collection_init_expr; + +@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; + +@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; +@incr_op_expr = @pre_incr_expr | @post_incr_expr; +@decr_op_expr = @pre_decr_expr | @post_decr_expr; +@mut_op_expr = @incr_op_expr | @decr_op_expr; +@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr; +@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr; + +@ternary_log_op_expr = @conditional_expr; +@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr; +@un_log_op_expr = @log_not_expr; +@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr; + +@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr + | @rshift_expr; +@un_bit_op_expr = @bit_not_expr; +@bit_expr = @un_bit_op_expr | @bin_bit_op_expr; + +@equality_op_expr = @eq_expr | @ne_expr; +@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; +@comp_expr = @equality_op_expr | @rel_op_expr; + +@op_expr = @assign_expr | @un_op | @bin_op | @ternary_op; + +@ternary_op = @ternary_log_op_expr; +@bin_op = @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr; +@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr + | @pointer_indirection_expr | @address_of_expr; + +@anonymous_function_expr = @lambda_expr | @anonymous_method_expr; + +@call = @method_invocation_expr | @constructor_init_expr | @operator_invocation_expr + | @delegate_invocation_expr | @object_creation_expr | @call_access_expr + | @local_function_invocation_expr; + +@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr; + +@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr + | @object_creation_expr | @method_invocation_expr | @operator_invocation_expr; + +@throw_element = @throw_expr | @throw_stmt; + +implicitly_typed_array_creation( + unique int id: @array_creation_expr ref); + +explicitly_sized_array_creation( + unique int id: @array_creation_expr ref); + +stackalloc_array_creation( + unique int id: @array_creation_expr ref); + +mutator_invocation_mode( + unique int id: @operator_invocation_expr ref, + int mode: int ref /* prefix = 1, postfix = 2*/); + +expr_compiler_generated( + unique int id: @expr ref); + +expr_value( + unique int id: @expr ref, + string value: string ref); + +expr_call( + unique int caller_id: @expr ref, + int target_id: @callable ref); + +expr_access( + unique int accesser_id: @access_expr ref, + int target_id: @accessible ref); + +@accessible = @method | @assignable | @local_function | @namespace; + +expr_location( + unique int id: @expr ref, + int loc: @location ref); + +dynamic_member_name( + unique int id: @late_bindable_expr ref, + string name: string ref); + +@qualifiable_expr = @member_access_expr + | @method_invocation_expr + | @element_access_expr; + +conditional_access( + unique int id: @qualifiable_expr ref); + +expr_argument( + unique int id: @expr ref, + int mode: int ref); + /* mode is the same as params: value = 0, ref = 1, out = 2 */ + +expr_argument_name( + unique int id: @expr ref, + string name: string ref); + +/** CONTROL/DATA FLOW **/ + +@control_flow_element = @stmt | @expr; + +/* 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; + +/* Comments */ + +commentline( + unique int id: @commentline, + int kind: int ref, + string text: string ref, + string rawtext: string ref); + +case @commentline.kind of + 0 = @singlelinecomment +| 1 = @xmldoccomment +| 2 = @multilinecomment; + +commentline_location( + unique int id: @commentline ref, + int loc: @location ref); + +commentblock( + unique int id : @commentblock); + +commentblock_location( + unique int id: @commentblock ref, + int loc: @location ref); + +commentblock_binding( + int id: @commentblock ref, + int entity: @element ref, + int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */ + +commentblock_child( + int id: @commentblock ref, + int commentline: @commentline ref, + int index: int ref); + +/* ASP.NET */ + +case @asp_element.kind of + 0=@asp_close_tag +| 1=@asp_code +| 2=@asp_comment +| 3=@asp_data_binding +| 4=@asp_directive +| 5=@asp_open_tag +| 6=@asp_quoted_string +| 7=@asp_text +| 8=@asp_xml_directive; + +@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string; + +asp_elements( + unique int id: @asp_element, + int kind: int ref, + int loc: @location ref); + +asp_comment_server(unique int comment: @asp_comment ref); +asp_code_inline(unique int code: @asp_code ref); +asp_directive_attribute( + int directive: @asp_directive ref, + int index: int ref, + string name: string ref, + int value: @asp_quoted_string ref); +asp_directive_name( + unique int directive: @asp_directive ref, + string name: string ref); +asp_element_body( + unique int element: @asp_element ref, + string body: string ref); +asp_tag_attribute( + int tag: @asp_open_tag ref, + int index: int ref, + string name: string ref, + int attribute: @asp_attribute ref); +asp_tag_name( + unique int tag: @asp_open_tag ref, + string name: string ref); +asp_tag_isempty(int tag: @asp_open_tag ref); + +/* Common Intermediate Language - CIL */ + +case @cil_instruction.opcode of + 0 = @cil_nop +| 1 = @cil_break +| 2 = @cil_ldarg_0 +| 3 = @cil_ldarg_1 +| 4 = @cil_ldarg_2 +| 5 = @cil_ldarg_3 +| 6 = @cil_ldloc_0 +| 7 = @cil_ldloc_1 +| 8 = @cil_ldloc_2 +| 9 = @cil_ldloc_3 +| 10 = @cil_stloc_0 +| 11 = @cil_stloc_1 +| 12 = @cil_stloc_2 +| 13 = @cil_stloc_3 +| 14 = @cil_ldarg_s +| 15 = @cil_ldarga_s +| 16 = @cil_starg_s +| 17 = @cil_ldloc_s +| 18 = @cil_ldloca_s +| 19 = @cil_stloc_s +| 20 = @cil_ldnull +| 21 = @cil_ldc_i4_m1 +| 22 = @cil_ldc_i4_0 +| 23 = @cil_ldc_i4_1 +| 24 = @cil_ldc_i4_2 +| 25 = @cil_ldc_i4_3 +| 26 = @cil_ldc_i4_4 +| 27 = @cil_ldc_i4_5 +| 28 = @cil_ldc_i4_6 +| 29 = @cil_ldc_i4_7 +| 30 = @cil_ldc_i4_8 +| 31 = @cil_ldc_i4_s +| 32 = @cil_ldc_i4 +| 33 = @cil_ldc_i8 +| 34 = @cil_ldc_r4 +| 35 = @cil_ldc_r8 +| 37 = @cil_dup +| 38 = @cil_pop +| 39 = @cil_jmp +| 40 = @cil_call +| 41 = @cil_calli +| 42 = @cil_ret +| 43 = @cil_br_s +| 44 = @cil_brfalse_s +| 45 = @cil_brtrue_s +| 46 = @cil_beq_s +| 47 = @cil_bge_s +| 48 = @cil_bgt_s +| 49 = @cil_ble_s +| 50 = @cil_blt_s +| 51 = @cil_bne_un_s +| 52 = @cil_bge_un_s +| 53 = @cil_bgt_un_s +| 54 = @cil_ble_un_s +| 55 = @cil_blt_un_s +| 56 = @cil_br +| 57 = @cil_brfalse +| 58 = @cil_brtrue +| 59 = @cil_beq +| 60 = @cil_bge +| 61 = @cil_bgt +| 62 = @cil_ble +| 63 = @cil_blt +| 64 = @cil_bne_un +| 65 = @cil_bge_un +| 66 = @cil_bgt_un +| 67 = @cil_ble_un +| 68 = @cil_blt_un +| 69 = @cil_switch +| 70 = @cil_ldind_i1 +| 71 = @cil_ldind_u1 +| 72 = @cil_ldind_i2 +| 73 = @cil_ldind_u2 +| 74 = @cil_ldind_i4 +| 75 = @cil_ldind_u4 +| 76 = @cil_ldind_i8 +| 77 = @cil_ldind_i +| 78 = @cil_ldind_r4 +| 79 = @cil_ldind_r8 +| 80 = @cil_ldind_ref +| 81 = @cil_stind_ref +| 82 = @cil_stind_i1 +| 83 = @cil_stind_i2 +| 84 = @cil_stind_i4 +| 85 = @cil_stind_i8 +| 86 = @cil_stind_r4 +| 87 = @cil_stind_r8 +| 88 = @cil_add +| 89 = @cil_sub +| 90 = @cil_mul +| 91 = @cil_div +| 92 = @cil_div_un +| 93 = @cil_rem +| 94 = @cil_rem_un +| 95 = @cil_and +| 96 = @cil_or +| 97 = @cil_xor +| 98 = @cil_shl +| 99 = @cil_shr +| 100 = @cil_shr_un +| 101 = @cil_neg +| 102 = @cil_not +| 103 = @cil_conv_i1 +| 104 = @cil_conv_i2 +| 105 = @cil_conv_i4 +| 106 = @cil_conv_i8 +| 107 = @cil_conv_r4 +| 108 = @cil_conv_r8 +| 109 = @cil_conv_u4 +| 110 = @cil_conv_u8 +| 111 = @cil_callvirt +| 112 = @cil_cpobj +| 113 = @cil_ldobj +| 114 = @cil_ldstr +| 115 = @cil_newobj +| 116 = @cil_castclass +| 117 = @cil_isinst +| 118 = @cil_conv_r_un +| 121 = @cil_unbox +| 122 = @cil_throw +| 123 = @cil_ldfld +| 124 = @cil_ldflda +| 125 = @cil_stfld +| 126 = @cil_ldsfld +| 127 = @cil_ldsflda +| 128 = @cil_stsfld +| 129 = @cil_stobj +| 130 = @cil_conv_ovf_i1_un +| 131 = @cil_conv_ovf_i2_un +| 132 = @cil_conv_ovf_i4_un +| 133 = @cil_conv_ovf_i8_un +| 134 = @cil_conv_ovf_u1_un +| 135 = @cil_conv_ovf_u2_un +| 136 = @cil_conv_ovf_u4_un +| 137 = @cil_conv_ovf_u8_un +| 138 = @cil_conv_ovf_i_un +| 139 = @cil_conv_ovf_u_un +| 140 = @cil_box +| 141 = @cil_newarr +| 142 = @cil_ldlen +| 143 = @cil_ldelema +| 144 = @cil_ldelem_i1 +| 145 = @cil_ldelem_u1 +| 146 = @cil_ldelem_i2 +| 147 = @cil_ldelem_u2 +| 148 = @cil_ldelem_i4 +| 149 = @cil_ldelem_u4 +| 150 = @cil_ldelem_i8 +| 151 = @cil_ldelem_i +| 152 = @cil_ldelem_r4 +| 153 = @cil_ldelem_r8 +| 154 = @cil_ldelem_ref +| 155 = @cil_stelem_i +| 156 = @cil_stelem_i1 +| 157 = @cil_stelem_i2 +| 158 = @cil_stelem_i4 +| 159 = @cil_stelem_i8 +| 160 = @cil_stelem_r4 +| 161 = @cil_stelem_r8 +| 162 = @cil_stelem_ref +| 163 = @cil_ldelem +| 164 = @cil_stelem +| 165 = @cil_unbox_any +| 179 = @cil_conv_ovf_i1 +| 180 = @cil_conv_ovf_u1 +| 181 = @cil_conv_ovf_i2 +| 182 = @cil_conv_ovf_u2 +| 183 = @cil_conv_ovf_i4 +| 184 = @cil_conv_ovf_u4 +| 185 = @cil_conv_ovf_i8 +| 186 = @cil_conv_ovf_u8 +| 194 = @cil_refanyval +| 195 = @cil_ckinfinite +| 198 = @cil_mkrefany +| 208 = @cil_ldtoken +| 209 = @cil_conv_u2 +| 210 = @cil_conv_u1 +| 211 = @cil_conv_i +| 212 = @cil_conv_ovf_i +| 213 = @cil_conv_ovf_u +| 214 = @cil_add_ovf +| 215 = @cil_add_ovf_un +| 216 = @cil_mul_ovf +| 217 = @cil_mul_ovf_un +| 218 = @cil_sub_ovf +| 219 = @cil_sub_ovf_un +| 220 = @cil_endfinally +| 221 = @cil_leave +| 222 = @cil_leave_s +| 223 = @cil_stind_i +| 224 = @cil_conv_u +| 65024 = @cil_arglist +| 65025 = @cil_ceq +| 65026 = @cil_cgt +| 65027 = @cil_cgt_un +| 65028 = @cil_clt +| 65029 = @cil_clt_un +| 65030 = @cil_ldftn +| 65031 = @cil_ldvirtftn +| 65033 = @cil_ldarg +| 65034 = @cil_ldarga +| 65035 = @cil_starg +| 65036 = @cil_ldloc +| 65037 = @cil_ldloca +| 65038 = @cil_stloc +| 65039 = @cil_localloc +| 65041 = @cil_endfilter +| 65042 = @cil_unaligned +| 65043 = @cil_volatile +| 65044 = @cil_tail +| 65045 = @cil_initobj +| 65046 = @cil_constrained +| 65047 = @cil_cpblk +| 65048 = @cil_initblk +| 65050 = @cil_rethrow +| 65052 = @cil_sizeof +| 65053 = @cil_refanytype +| 65054 = @cil_readonly +; + +// CIL ignored instructions + +@cil_ignore = @cil_nop | @cil_break | @cil_volatile | @cil_unaligned; + +// CIL local/parameter/field access + +@cil_ldarg_any = @cil_ldarg_0 | @cil_ldarg_1 | @cil_ldarg_2 | @cil_ldarg_3 | @cil_ldarg_s | @cil_ldarga_s | @cil_ldarg | @cil_ldarga; +@cil_starg_any = @cil_starg | @cil_starg_s; + +@cil_ldloc_any = @cil_ldloc_0 | @cil_ldloc_1 | @cil_ldloc_2 | @cil_ldloc_3 | @cil_ldloc_s | @cil_ldloca_s | @cil_ldloc | @cil_ldloca; +@cil_stloc_any = @cil_stloc_0 | @cil_stloc_1 | @cil_stloc_2 | @cil_stloc_3 | @cil_stloc_s | @cil_stloc; + +@cil_ldfld_any = @cil_ldfld | @cil_ldsfld | @cil_ldsflda | @cil_ldflda; +@cil_stfld_any = @cil_stfld | @cil_stsfld; + +@cil_local_access = @cil_stloc_any | @cil_ldloc_any; +@cil_arg_access = @cil_starg_any | @cil_ldarg_any; +@cil_read_access = @cil_ldloc_any | @cil_ldarg_any | @cil_ldfld_any; +@cil_write_access = @cil_stloc_any | @cil_starg_any | @cil_stfld_any; + +@cil_stack_access = @cil_local_access | @cil_arg_access; +@cil_field_access = @cil_ldfld_any | @cil_stfld_any; + +@cil_access = @cil_read_access | @cil_write_access; + +// CIL constant/literal instructions + +@cil_ldc_i = @cil_ldc_i4_any | @cil_ldc_i8; + +@cil_ldc_i4_any = @cil_ldc_i4_m1 | @cil_ldc_i4_0 | @cil_ldc_i4_1 | @cil_ldc_i4_2 | @cil_ldc_i4_3 | + @cil_ldc_i4_4 | @cil_ldc_i4_5 | @cil_ldc_i4_6 | @cil_ldc_i4_7 | @cil_ldc_i4_8 | @cil_ldc_i4_s | @cil_ldc_i4; + +@cil_ldc_r = @cil_ldc_r4 | @cil_ldc_r8; + +@cil_literal = @cil_ldnull | @cil_ldc_i | @cil_ldc_r | @cil_ldstr; + +// Control flow + +@cil_conditional_jump = @cil_binary_jump | @cil_unary_jump; +@cil_binary_jump = @cil_beq_s | @cil_bge_s | @cil_bgt_s | @cil_ble_s | @cil_blt_s | + @cil_bne_un_s | @cil_bge_un_s | @cil_bgt_un_s | @cil_ble_un_s | @cil_blt_un_s | + @cil_beq | @cil_bge | @cil_bgt | @cil_ble | @cil_blt | + @cil_bne_un | @cil_bge_un | @cil_bgt_un | @cil_ble_un | @cil_blt_un; +@cil_unary_jump = @cil_brfalse_s | @cil_brtrue_s | @cil_brfalse | @cil_brtrue | @cil_switch; +@cil_unconditional_jump = @cil_br | @cil_br_s | @cil_leave_any; +@cil_leave_any = @cil_leave | @cil_leave_s; +@cil_jump = @cil_unconditional_jump | @cil_conditional_jump; + +// CIL call instructions + +@cil_call_any = @cil_jmp | @cil_call | @cil_calli | @cil_tail | @cil_callvirt | @cil_newobj; + +// CIL expression instructions + +@cil_expr = @cil_literal | @cil_binary_expr | @cil_unary_expr | @cil_call_any | @cil_read_access | + @cil_newarr | @cil_ldtoken | @cil_sizeof | + @cil_ldftn | @cil_ldvirtftn | @cil_localloc | @cil_mkrefany | @cil_refanytype | @cil_arglist | @cil_dup; + +@cil_unary_expr = + @cil_conversion_operation | @cil_unary_arithmetic_operation | @cil_unary_bitwise_operation| + @cil_ldlen | @cil_isinst | @cil_box | @cil_ldobj | @cil_castclass | @cil_unbox_any | + @cil_ldind | @cil_unbox; + +@cil_conversion_operation = + @cil_conv_i1 | @cil_conv_i2 | @cil_conv_i4 | @cil_conv_i8 | + @cil_conv_u1 | @cil_conv_u2 | @cil_conv_u4 | @cil_conv_u8 | + @cil_conv_ovf_i | @cil_conv_ovf_i_un | @cil_conv_ovf_i1 | @cil_conv_ovf_i1_un | + @cil_conv_ovf_i2 | @cil_conv_ovf_i2_un | @cil_conv_ovf_i4 | @cil_conv_ovf_i4_un | + @cil_conv_ovf_i8 | @cil_conv_ovf_i8_un | @cil_conv_ovf_u | @cil_conv_ovf_u_un | + @cil_conv_ovf_u1 | @cil_conv_ovf_u1_un | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_ovf_u4 | @cil_conv_ovf_u4_un | @cil_conv_ovf_u8 | @cil_conv_ovf_u8_un | + @cil_conv_r4 | @cil_conv_r8 | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_i | @cil_conv_u | @cil_conv_r_un; + +@cil_ldind = @cil_ldind_i | @cil_ldind_i1 | @cil_ldind_i2 | @cil_ldind_i4 | @cil_ldind_i8 | + @cil_ldind_r4 | @cil_ldind_r8 | @cil_ldind_ref | @cil_ldind_u1 | @cil_ldind_u2 | @cil_ldind_u4; + +@cil_stind = @cil_stind_i | @cil_stind_i1 | @cil_stind_i2 | @cil_stind_i4 | @cil_stind_i8 | + @cil_stind_r4 | @cil_stind_r8 | @cil_stind_ref; + +@cil_bitwise_operation = @cil_binary_bitwise_operation | @cil_unary_bitwise_operation; + +@cil_binary_bitwise_operation = @cil_and | @cil_or | @cil_xor | @cil_shr | @cil_shr | @cil_shr_un | @cil_shl; + +@cil_binary_arithmetic_operation = @cil_add | @cil_sub | @cil_mul | @cil_div | @cil_div_un | + @cil_rem | @cil_rem_un | @cil_add_ovf | @cil_add_ovf_un | @cil_mul_ovf | @cil_mul_ovf_un | + @cil_sub_ovf | @cil_sub_ovf_un; + +@cil_unary_bitwise_operation = @cil_not; + +@cil_binary_expr = @cil_binary_arithmetic_operation | @cil_binary_bitwise_operation | @cil_read_array | @cil_comparison_operation; + +@cil_unary_arithmetic_operation = @cil_neg; + +@cil_comparison_operation = @cil_cgt_un | @cil_ceq | @cil_cgt | @cil_clt | @cil_clt_un; + +// Elements that retrieve an address of something +@cil_read_ref = @cil_ldloca_s | @cil_ldarga_s | @cil_ldflda | @cil_ldsflda | @cil_ldelema; + +// CIL array instructions + +@cil_read_array = + @cil_ldelem | @cil_ldelema | @cil_ldelem_i1 | @cil_ldelem_ref | @cil_ldelem_i | + @cil_ldelem_i1 | @cil_ldelem_i2 | @cil_ldelem_i4 | @cil_ldelem_i8 | @cil_ldelem_r4 | + @cil_ldelem_r8 | @cil_ldelem_u1 | @cil_ldelem_u2 | @cil_ldelem_u4; + +@cil_write_array = @cil_stelem | @cil_stelem_ref | + @cil_stelem_i | @cil_stelem_i1 | @cil_stelem_i2 | @cil_stelem_i4 | @cil_stelem_i8 | + @cil_stelem_r4 | @cil_stelem_r8; + +@cil_throw_any = @cil_throw | @cil_rethrow; + +#keyset[impl, index] +cil_instruction( + unique int id: @cil_instruction, + int opcode: int ref, + int index: int ref, + int impl: @cil_method_implementation ref); + +cil_jump( + unique int instruction: @cil_jump ref, + int target: @cil_instruction ref); + +cil_access( + unique int instruction: @cil_instruction ref, + int target: @cil_accessible ref); + +cil_value( + unique int instruction: @cil_literal ref, + string value: string ref); + +#keyset[instruction, index] +cil_switch( + int instruction: @cil_switch ref, + int index: int ref, + int target: @cil_instruction ref); + +cil_instruction_location( + unique int id: @cil_instruction ref, + int loc: @location ref); + +cil_type_location( + int id: @cil_type ref, + int loc: @location ref); + +cil_method_location( + int id: @cil_method ref, + int loc: @location ref); + +@cil_namespace = @namespace; + +@cil_type_container = @cil_type | @cil_namespace | @cil_method; + +case @cil_type.kind of + 0 = @cil_valueorreftype +| 1 = @cil_typeparameter +| 2 = @cil_array_type +| 3 = @cil_pointer_type +; + +cil_type( + unique int id: @cil_type, + string name: string ref, + int kind: int ref, + int parent: @cil_type_container ref, + int sourceDecl: @cil_type ref); + +cil_pointer_type( + unique int id: @cil_pointer_type ref, + int pointee: @cil_type ref); + +cil_array_type( + unique int id: @cil_array_type ref, + int element_type: @cil_type ref, + int rank: int ref); + +cil_method( + unique int id: @cil_method, + string name: string ref, + int parent: @cil_type ref, + int return_type: @cil_type ref); + +cil_method_source_declaration( + unique int method: @cil_method ref, + int source: @cil_method ref); + +cil_method_implementation( + unique int id: @cil_method_implementation, + int method: @cil_method ref, + int location: @assembly ref); + +cil_implements( + int id: @cil_method ref, + int decl: @cil_method ref); + +#keyset[parent, name] +cil_field( + unique int id: @cil_field, + int parent: @cil_type ref, + string name: string ref, + int field_type: @cil_type ref); + +@cil_element = @cil_instruction | @cil_declaration | @cil_handler | @cil_attribute | @cil_namespace; +@cil_named_element = @cil_declaration | @cil_namespace; +@cil_declaration = @cil_variable | @cil_method | @cil_type | @cil_member; +@cil_accessible = @cil_declaration; +@cil_variable = @cil_field | @cil_stack_variable; +@cil_stack_variable = @cil_local_variable | @cil_parameter; +@cil_member = @cil_method | @cil_type | @cil_field | @cil_property | @cil_event; + +#keyset[method, index] +cil_parameter( + unique int id: @cil_parameter, + int method: @cil_method ref, + int index: int ref, + int param_type: @cil_type ref); + +cil_parameter_in(unique int id: @cil_parameter ref); +cil_parameter_out(unique int id: @cil_parameter ref); + +cil_setter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_getter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_adder(unique int event: @cil_event ref, + int method: @cil_method ref); + +cil_remover(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_raiser(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_property( + unique int id: @cil_property, + int parent: @cil_type ref, + string name: string ref, + int property_type: @cil_type ref); + +#keyset[parent, name] +cil_event(unique int id: @cil_event, + int parent: @cil_type ref, + string name: string ref, + int event_type: @cil_type ref); + +#keyset[impl, index] +cil_local_variable( + unique int id: @cil_local_variable, + int impl: @cil_method_implementation ref, + int index: int ref, + int var_type: @cil_type ref); + +// CIL handlers (exception handlers etc). + +case @cil_handler.kind of + 0 = @cil_catch_handler +| 1 = @cil_filter_handler +| 2 = @cil_finally_handler +| 4 = @cil_fault_handler +; + +#keyset[impl, index] +cil_handler( + unique int id: @cil_handler, + int impl: @cil_method_implementation ref, + int index: int ref, + int kind: int ref, + int try_start: @cil_instruction ref, + int try_end: @cil_instruction ref, + int handler_start: @cil_instruction ref); + +cil_handler_filter( + unique int id: @cil_handler ref, + int filter_start: @cil_instruction ref); + +cil_handler_type( + unique int id: @cil_handler ref, + int catch_type: @cil_type ref); + +@cil_controlflow_node = @cil_entry_point | @cil_instruction; + +@cil_entry_point = @cil_method_implementation | @cil_handler; + +@cil_dataflow_node = @cil_instruction | @cil_variable | @cil_method; + +cil_method_stack_size( + unique int method: @cil_method_implementation ref, + int size: int ref); + +// CIL modifiers + +cil_public(int id: @cil_member ref); +cil_private(int id: @cil_member ref); +cil_protected(int id: @cil_member ref); +cil_internal(int id: @cil_member ref); +cil_static(int id: @cil_member ref); +cil_sealed(int id: @cil_member ref); +cil_virtual(int id: @cil_method ref); +cil_abstract(int id: @cil_member ref); +cil_class(int id: @cil_type ref); +cil_interface(int id: @cil_type ref); +cil_security(int id: @cil_member ref); +cil_requiresecobject(int id: @cil_method ref); +cil_specialname(int id: @cil_method ref); +cil_newslot(int id: @cil_method ref); + +cil_base_class(unique int id: @cil_type ref, int base: @cil_type ref); +cil_base_interface(int id: @cil_type ref, int base: @cil_type ref); + +#keyset[unbound, index] +cil_type_parameter( + int unbound: @cil_member ref, + int index: int ref, + int param: @cil_typeparameter ref); + +#keyset[bound, index] +cil_type_argument( + int bound: @cil_member ref, + int index: int ref, + int t: @cil_type ref); + +// CIL type parameter constraints + +cil_typeparam_covariant(int tp: @cil_typeparameter ref); +cil_typeparam_contravariant(int tp: @cil_typeparameter ref); +cil_typeparam_class(int tp: @cil_typeparameter ref); +cil_typeparam_struct(int tp: @cil_typeparameter ref); +cil_typeparam_new(int tp: @cil_typeparameter ref); +cil_typeparam_constraint(int tp: @cil_typeparameter ref, int supertype: @cil_type ref); + +// CIL attributes + +cil_attribute( + unique int attributeid: @cil_attribute, + int element: @cil_declaration ref, + int constructor: @cil_method ref); + +#keyset[attribute_id, param] +cil_attribute_named_argument( + int attribute_id: @cil_attribute ref, + string param: string ref, + string value: string ref); + +#keyset[attribute_id, index] +cil_attribute_positional_argument( + int attribute_id: @cil_attribute ref, + int index: int ref, + string value: string ref); + + +// Common .Net data model covering both C# and CIL + +// Common elements +@dotnet_element = @element | @cil_element; +@dotnet_named_element = @named_element | @cil_named_element; +@dotnet_callable = @callable | @cil_method; +@dotnet_variable = @variable | @cil_variable; +@dotnet_field = @field | @cil_field; +@dotnet_parameter = @parameter | @cil_parameter; +@dotnet_declaration = @declaration | @cil_declaration; +@dotnet_member = @member | @cil_member; +@dotnet_event = @event | @cil_event; +@dotnet_property = @property | @cil_property | @indexer; + +// Common types +@dotnet_type = @type | @cil_type; +@dotnet_call = @call | @cil_call_any; +@dotnet_throw = @throw_element | @cil_throw_any; +@dotnet_valueorreftype = @cil_valueorreftype | @value_or_ref_type | @cil_array_type | @void_type; +@dotnet_typeparameter = @type_parameter | @cil_typeparameter; +@dotnet_array_type = @array_type | @cil_array_type; +@dotnet_pointer_type = @pointer_type | @cil_pointer_type; +@dotnet_type_parameter = @type_parameter | @cil_typeparameter; +@dotnet_generic = @dotnet_valueorreftype | @dotnet_callable; + +// Attributes +@dotnet_attribute = @attribute | @cil_attribute; + +// Expressions +@dotnet_expr = @expr | @cil_expr; + +// Literals +@dotnet_literal = @literal_expr | @cil_literal; +@dotnet_string_literal = @string_literal_expr | @cil_ldstr; +@dotnet_int_literal = @integer_literal_expr | @cil_ldc_i; +@dotnet_float_literal = @float_literal_expr | @cil_ldc_r; +@dotnet_null_literal = @null_literal_expr | @cil_ldnull; + +@metadata_entity = @cil_method | @cil_type | @cil_field | @cil_property | @field | @property | + @callable | @value_or_ref_type | @void_type; + +#keyset[entity, location] +metadata_handle(int entity : @metadata_entity ref, int location: @assembly ref, int handle: int ref) diff --git a/csharp/upgrades/f2aa2d4ac31309bd83ab633d0f40e8a442767bd1/semmlecode.csharp.dbscheme b/csharp/upgrades/f2aa2d4ac31309bd83ab633d0f40e8a442767bd1/semmlecode.csharp.dbscheme new file mode 100644 index 000000000000..ddd39829bb71 --- /dev/null +++ b/csharp/upgrades/f2aa2d4ac31309bd83ab633d0f40e8a442767bd1/semmlecode.csharp.dbscheme @@ -0,0 +1,1889 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * csc f1.cs f2.cs f3.cs + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + 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 + * + * csc f1.cs f2.cs f3.cs + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | --compiler + * 1 | *path to compiler* + * 2 | --cil + * 3 | f1.cs + * 4 | f2.cs + * 5 | f3.cs + */ +#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 + * + * csc f1.cs f2.cs f3.cs + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.cs + * 1 | f2.cs + * 2 | f3.cs + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The references used by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | ref1.dll + * 1 | ref2.dll + * 2 | ref3.dll + */ +#keyset[id, num] +compilation_referencing_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( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : 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 +); + +extractor_messages( + unique int id: @extractor_message, + int severity: int ref, + string origin : string ref, + string text : string ref, + string entity : string ref, + int location: @location_default ref, + string stack_trace : string 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 artifacts + */ + +externalDefects( + unique int id: @externalDefect, + string queryPath: string ref, + int location: @location ref, + string message: string ref, + float severity: float ref); + +externalMetrics( + unique int id: @externalMetric, + string queryPath: string ref, + int location: @location ref, + float value: float ref); + +externalData( + int id: @externalDataElement, + string path: string ref, + int column: int ref, + string value: string ref); + +snapshotDate( + unique date snapshotDate: date ref); + +sourceLocationPrefix( + string prefix: string ref); + +/* + * Duplicate code + */ + +duplicateCode( + unique int id: @duplication, + string relativePath: string ref, + int equivClass: int ref); + +similarCode( + unique int id: @similarity, + string relativePath: string ref, + int equivClass: int ref); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id: @duplication_or_similarity ref, + int offset: int ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +/* + * C# dbscheme + */ + +/** ELEMENTS **/ + +@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration + | @using_directive | @type_parameter_constraints | @external_element + | @xmllocatable | @asp_element | @namespace; + +@declaration = @callable | @generic | @assignable | @namespace; + +@named_element = @namespace | @declaration; + +@declaration_with_accessors = @property | @indexer | @event; + +@assignable = @variable | @assignable_with_accessors | @event; + +@assignable_with_accessors = @property | @indexer; + +@external_element = @externalMetric | @externalDefect | @externalDataElement; + +@attributable = @assembly | @field | @parameter | @operator | @method | @constructor + | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors; + +/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/ + +@location = @location_default | @assembly; + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +@sourceline = @file | @callable | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref); + +assemblies( + unique int id: @assembly, + int file: @file ref, + string fullname: string ref, + string name: string ref, + string version: string ref); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref); + +@container = @folder | @file ; + +containerparent( + int parent: @container ref, + unique int child: @container ref); + +file_extraction_mode( + unique int file: @file ref, + int mode: int ref + /* 0 = normal, 1 = standalone extractor */ + ); + +/** NAMESPACES **/ + +@type_container = @namespace | @type; + +namespaces( + unique int id: @namespace, + string name: string ref); + +namespace_declarations( + unique int id: @namespace_declaration, + int namespace_id: @namespace ref); + +namespace_declaration_location( + unique int id: @namespace_declaration ref, + int loc: @location ref); + +parent_namespace( + unique int child_id: @type_container ref, + int namespace_id: @namespace ref); + +@declaration_or_directive = @namespace_declaration | @type | @using_directive; + +parent_namespace_declaration( + int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes + int namespace_id: @namespace_declaration ref); + +@using_directive = @using_namespace_directive | @using_static_directive; + +using_namespace_directives( + unique int id: @using_namespace_directive, + int namespace_id: @namespace ref); + +using_static_directives( + unique int id: @using_static_directive, + int type_id: @type_or_ref ref); + +using_directive_location( + unique int id: @using_directive ref, + int loc: @location ref); + +/** TYPES **/ + +types( + unique int id: @type, + int kind: int ref, + string name: string ref); + +case @type.kind of + 1 = @bool_type +| 2 = @char_type +| 3 = @decimal_type +| 4 = @sbyte_type +| 5 = @short_type +| 6 = @int_type +| 7 = @long_type +| 8 = @byte_type +| 9 = @ushort_type +| 10 = @uint_type +| 11 = @ulong_type +| 12 = @float_type +| 13 = @double_type +| 14 = @enum_type +| 15 = @struct_type +| 17 = @class_type +| 19 = @interface_type +| 20 = @delegate_type +| 21 = @null_type +| 22 = @type_parameter +| 23 = @pointer_type +| 24 = @nullable_type +| 25 = @array_type +| 26 = @void_type +| 27 = @int_ptr_type +| 28 = @uint_ptr_type +| 29 = @dynamic_type +| 30 = @arglist_type +| 31 = @unknown_type +| 32 = @tuple_type + ; + +@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type; +@integral_type = @signed_integral_type | @unsigned_integral_type; +@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type; +@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type; +@floating_point_type = @float_type | @double_type; +@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type + | @uint_ptr_type | @tuple_type; +@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type + | @dynamic_type; +@value_or_ref_type = @value_type | @ref_type; + +typerefs( + unique int id: @typeref, + string name: string ref); + +typeref_type( + int id: @typeref ref, + unique int typeId: @type ref); + +@type_or_ref = @type | @typeref; + +array_element_type( + unique int array: @array_type ref, + int dimension: int ref, + int rank: int ref, + int element: @type_or_ref ref); + +nullable_underlying_type( + unique int nullable: @nullable_type ref, + int underlying: @type_or_ref ref); + +pointer_referent_type( + unique int pointer: @pointer_type ref, + int referent: @type_or_ref ref); + +enum_underlying_type( + unique int enum_id: @enum_type ref, + int underlying_type_id: @type_or_ref ref); + +delegate_return_type( + unique int delegate_id: @delegate_type ref, + int return_type_id: @type_or_ref ref); + +extend( + unique int sub: @type ref, + int super: @type_or_ref ref); + +@interface_or_ref = @interface_type | @typeref; + +implement( + int sub: @type ref, + int super: @type_or_ref ref); + +type_location( + int id: @type ref, + int loc: @location ref); + +tuple_underlying_type( + unique int tuple: @tuple_type ref, + int struct: @type_or_ref ref); + +#keyset[tuple, index] +tuple_element( + int tuple: @tuple_type ref, + int index: int ref, + unique int field: @field ref); + +attributes( + unique int id: @attribute, + int type_id: @type_or_ref ref, + int target: @attributable ref); + +attribute_location( + int id: @attribute ref, + int loc: @location ref); + +@type_mention_parent = @element | @type_mention; + +type_mention( + unique int id: @type_mention, + int type_id: @type_or_ref ref, + int parent: @type_mention_parent ref); + +type_mention_location( + unique int id: @type_mention ref, + int loc: @location ref); + +@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic; + +/** + * A direct annotation on an entity, for example `string? x;`. + * + * Annotations: + * 2 = reftype is not annotated "!" + * 3 = reftype is annotated "?" + * 4 = readonly ref type / in parameter + * 5 = ref type parameter, return or local variable + * 6 = out parameter + * + * Note that the annotation depends on the element it annotates. + * @assignable: The annotation is on the type of the assignable, for example the variable type. + * @type_parameter: The annotation is on the reftype constraint + * @callable: The annotation is on the return type + * @array_type: The annotation is on the element type + */ +type_annotation(int id: @has_type_annotation ref, int annotation: int ref); + +nullability(unique int nullability: @nullability, int kind: int ref); + +case @nullability.kind of + 0 = @oblivious +| 1 = @not_annotated +| 2 = @annotated +; + +#keyset[parent, index] +nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref) + +type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref); + +/** + * The nullable flow state of an expression, as determined by Roslyn. + * 0 = none (default, not populated) + * 1 = not null + * 2 = maybe null + */ +expr_flowstate(unique int id: @expr ref, int state: int ref); + +/** GENERICS **/ + +@generic = @type | @method | @local_function; + +type_parameters( + unique int id: @type_parameter ref, + int index: int ref, + int generic_id: @generic ref, + int variance: int ref /* none = 0, out = 1, in = 2 */); + +#keyset[constructed_id, index] +type_arguments( + int id: @type_or_ref ref, + int index: int ref, + int constructed_id: @generic_or_ref ref); + +@generic_or_ref = @generic | @typeref; + +constructed_generic( + unique int constructed: @generic ref, + int generic: @generic_or_ref ref); + +type_parameter_constraints( + unique int id: @type_parameter_constraints, + int param_id: @type_parameter ref); + +type_parameter_constraints_location( + int id: @type_parameter_constraints ref, + int loc: @location ref); + +general_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int kind: int ref /* class = 1, struct = 2, new = 3 */); + +specific_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref); + +specific_type_parameter_nullability( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref, + int nullability: @nullability ref); + +/** MODIFIERS */ + +@modifiable = @modifiable_direct | @event_accessor; + +@modifiable_direct = @member | @accessor | @local_function; + +modifiers( + unique int id: @modifier, + string name: string ref); + +has_modifiers( + int id: @modifiable_direct ref, + int mod_id: @modifier ref); + +compiler_generated(unique int id: @modifiable_direct ref); + +/** MEMBERS **/ + +@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type; + +@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr; + +@virtualizable = @method | @property | @indexer | @event; + +exprorstmt_name( + unique int parent_id: @named_exprorstmt ref, + string name: string ref); + +nested_types( + unique int id: @type ref, + int declaring_type_id: @type ref, + int unbound_id: @type ref); + +properties( + unique int id: @property, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @property ref); + +property_location( + int id: @property ref, + int loc: @location ref); + +indexers( + unique int id: @indexer, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @indexer ref); + +indexer_location( + int id: @indexer ref, + int loc: @location ref); + +accessors( + unique int id: @accessor, + int kind: int ref, + string name: string ref, + int declaring_member_id: @member ref, + int unbound_id: @accessor ref); + +case @accessor.kind of + 1 = @getter +| 2 = @setter + ; + +accessor_location( + int id: @accessor ref, + int loc: @location ref); + +events( + unique int id: @event, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @event ref); + +event_location( + int id: @event ref, + int loc: @location ref); + +event_accessors( + unique int id: @event_accessor, + int kind: int ref, + string name: string ref, + int declaring_event_id: @event ref, + int unbound_id: @event_accessor ref); + +case @event_accessor.kind of + 1 = @add_event_accessor +| 2 = @remove_event_accessor + ; + +event_accessor_location( + int id: @event_accessor ref, + int loc: @location ref); + +operators( + unique int id: @operator, + string name: string ref, + string symbol: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @operator ref); + +operator_location( + int id: @operator ref, + int loc: @location ref); + +constant_value( + int id: @variable ref, + string value: string ref); + +/** CALLABLES **/ + +@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function; + +@callable_accessor = @accessor | @event_accessor; + +methods( + unique int id: @method, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @method ref); + +method_location( + int id: @method ref, + int loc: @location ref); + +constructors( + unique int id: @constructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @constructor ref); + +constructor_location( + int id: @constructor ref, + int loc: @location ref); + +destructors( + unique int id: @destructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @destructor ref); + +destructor_location( + int id: @destructor ref, + int loc: @location ref); + +overrides( + int id: @callable ref, + int base_id: @callable ref); + +explicitly_implements( + int id: @member ref, + int interface_id: @interface_or_ref ref); + +local_functions( + unique int id: @local_function, + string name: string ref, + int return_type: @type ref, + int unbound_id: @local_function ref); + +local_function_stmts( + unique int fn: @local_function_stmt ref, + int stmt: @local_function ref); + +/** VARIABLES **/ + +@variable = @local_scope_variable | @field; + +@local_scope_variable = @local_variable | @parameter; + +fields( + unique int id: @field, + int kind: int ref, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @field ref); + +case @field.kind of + 1 = @addressable_field +| 2 = @constant + ; + +field_location( + int id: @field ref, + int loc: @location ref); + +localvars( + unique int id: @local_variable, + int kind: int ref, + string name: string ref, + int implicitly_typed: int ref /* 0 = no, 1 = yes */, + int type_id: @type_or_ref ref, + int parent_id: @local_var_decl_expr ref); + +case @local_variable.kind of + 1 = @addressable_local_variable +| 2 = @local_constant +| 3 = @local_variable_ref + ; + +localvar_location( + unique int id: @local_variable ref, + int loc: @location ref); + +@parameterizable = @callable | @delegate_type | @indexer; + +#keyset[name, parent_id] +#keyset[index, parent_id] +params( + unique int id: @parameter, + string name: string ref, + int type_id: @type_or_ref ref, + int index: int ref, + int mode: int ref, /* value = 0, ref = 1, out = 2, array = 3, this = 4 */ + int parent_id: @parameterizable ref, + int unbound_id: @parameter ref); + +param_location( + int id: @parameter ref, + int loc: @location ref); + +/** STATEMENTS **/ + +@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent; + +statements( + unique int id: @stmt, + int kind: int ref); + +#keyset[index, parent] +stmt_parent( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_stmt_parent = @callable; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +stmt_parent_top_level( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @top_level_stmt_parent ref); + +case @stmt.kind of + 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @switch_stmt +| 5 = @while_stmt +| 6 = @do_stmt +| 7 = @for_stmt +| 8 = @foreach_stmt +| 9 = @break_stmt +| 10 = @continue_stmt +| 11 = @goto_stmt +| 12 = @goto_case_stmt +| 13 = @goto_default_stmt +| 14 = @throw_stmt +| 15 = @return_stmt +| 16 = @yield_stmt +| 17 = @try_stmt +| 18 = @checked_stmt +| 19 = @unchecked_stmt +| 20 = @lock_stmt +| 21 = @using_block_stmt +| 22 = @var_decl_stmt +| 23 = @const_decl_stmt +| 24 = @empty_stmt +| 25 = @unsafe_stmt +| 26 = @fixed_stmt +| 27 = @label_stmt +| 28 = @catch +| 29 = @case_stmt +| 30 = @local_function_stmt +| 31 = @using_decl_stmt + ; + +@using_stmt = @using_block_stmt | @using_decl_stmt; + +@labeled_stmt = @label_stmt | @case; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt; + +@cond_stmt = @if_stmt | @switch_stmt; + +@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt; + +@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt + | @yield_stmt; + +@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt; + + +stmt_location( + unique int id: @stmt ref, + int loc: @location ref); + +catch_type( + unique int catch_id: @catch ref, + int type_id: @type_or_ref ref, + int kind: int ref /* explicit = 1, implicit = 2 */); + +/** EXPRESSIONS **/ + +expressions( + unique int id: @expr, + int kind: int ref, + int type_id: @type_or_ref ref); + +#keyset[index, parent] +expr_parent( + unique int expr: @expr ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter; + +@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +expr_parent_top_level( + unique int expr: @expr ref, + int index: int ref, + int parent: @top_level_exprorstmt_parent ref); + +case @expr.kind of +/* literal */ + 1 = @bool_literal_expr +| 2 = @char_literal_expr +| 3 = @decimal_literal_expr +| 4 = @int_literal_expr +| 5 = @long_literal_expr +| 6 = @uint_literal_expr +| 7 = @ulong_literal_expr +| 8 = @float_literal_expr +| 9 = @double_literal_expr +| 10 = @string_literal_expr +| 11 = @null_literal_expr +/* primary & unary */ +| 12 = @this_access_expr +| 13 = @base_access_expr +| 14 = @local_variable_access_expr +| 15 = @parameter_access_expr +| 16 = @field_access_expr +| 17 = @property_access_expr +| 18 = @method_access_expr +| 19 = @event_access_expr +| 20 = @indexer_access_expr +| 21 = @array_access_expr +| 22 = @type_access_expr +| 23 = @typeof_expr +| 24 = @method_invocation_expr +| 25 = @delegate_invocation_expr +| 26 = @operator_invocation_expr +| 27 = @cast_expr +| 28 = @object_creation_expr +| 29 = @explicit_delegate_creation_expr +| 30 = @implicit_delegate_creation_expr +| 31 = @array_creation_expr +| 32 = @default_expr +| 33 = @plus_expr +| 34 = @minus_expr +| 35 = @bit_not_expr +| 36 = @log_not_expr +| 37 = @post_incr_expr +| 38 = @post_decr_expr +| 39 = @pre_incr_expr +| 40 = @pre_decr_expr +/* multiplicative */ +| 41 = @mul_expr +| 42 = @div_expr +| 43 = @rem_expr +/* additive */ +| 44 = @add_expr +| 45 = @sub_expr +/* shift */ +| 46 = @lshift_expr +| 47 = @rshift_expr +/* relational */ +| 48 = @lt_expr +| 49 = @gt_expr +| 50 = @le_expr +| 51 = @ge_expr +/* equality */ +| 52 = @eq_expr +| 53 = @ne_expr +/* logical */ +| 54 = @bit_and_expr +| 55 = @bit_xor_expr +| 56 = @bit_or_expr +| 57 = @log_and_expr +| 58 = @log_or_expr +/* type testing */ +| 59 = @is_expr +| 60 = @as_expr +/* null coalescing */ +| 61 = @null_coalescing_expr +/* conditional */ +| 62 = @conditional_expr +/* assignment */ +| 63 = @simple_assign_expr +| 64 = @assign_add_expr +| 65 = @assign_sub_expr +| 66 = @assign_mul_expr +| 67 = @assign_div_expr +| 68 = @assign_rem_expr +| 69 = @assign_and_expr +| 70 = @assign_xor_expr +| 71 = @assign_or_expr +| 72 = @assign_lshift_expr +| 73 = @assign_rshift_expr +/* more */ +| 74 = @object_init_expr +| 75 = @collection_init_expr +| 76 = @array_init_expr +| 77 = @checked_expr +| 78 = @unchecked_expr +| 79 = @constructor_init_expr +| 80 = @add_event_expr +| 81 = @remove_event_expr +| 82 = @par_expr +| 83 = @local_var_decl_expr +| 84 = @lambda_expr +| 85 = @anonymous_method_expr +| 86 = @namespace_expr +/* dynamic */ +| 92 = @dynamic_element_access_expr +| 93 = @dynamic_member_access_expr +/* unsafe */ +| 100 = @pointer_indirection_expr +| 101 = @address_of_expr +| 102 = @sizeof_expr +/* async */ +| 103 = @await_expr +/* C# 6.0 */ +| 104 = @nameof_expr +| 105 = @interpolated_string_expr +| 106 = @unknown_expr +/* C# 7.0 */ +| 107 = @throw_expr +| 108 = @tuple_expr +| 109 = @local_function_invocation_expr +| 110 = @ref_expr +| 111 = @discard_expr +/* C# 8.0 */ +| 112 = @range_expr +| 113 = @index_expr +| 114 = @switch_expr +| 115 = @recursive_pattern_expr +| 116 = @property_pattern_expr +| 117 = @positional_pattern_expr +| 118 = @switch_case_expr +| 119 = @assign_coalesce_expr +| 120 = @suppress_nullable_warning_expr +| 121 = @namespace_access_expr +; + +@switch = @switch_stmt | @switch_expr; +@case = @case_stmt | @switch_case_expr; +@pattern_match = @case | @is_expr; + +@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr; +@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr; +@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr + | @string_literal_expr | @null_literal_expr; + +@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr; +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr | @assign_coalesce_expr; +@assign_event_expr = @add_event_expr | @remove_event_expr; + +@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr + | @assign_rem_expr +@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr + | @assign_lshift_expr | @assign_rshift_expr; + +@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr + | @method_access_expr | @type_access_expr | @dynamic_member_access_expr; +@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr; +@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr; + +@local_variable_access = @local_variable_access_expr | @local_var_decl_expr; +@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access; +@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr; + +@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr + | @event_access_expr | @dynamic_member_access_expr; + +@objectorcollection_init_expr = @object_init_expr | @collection_init_expr; + +@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; + +@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; +@incr_op_expr = @pre_incr_expr | @post_incr_expr; +@decr_op_expr = @pre_decr_expr | @post_decr_expr; +@mut_op_expr = @incr_op_expr | @decr_op_expr; +@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr; +@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr; + +@ternary_log_op_expr = @conditional_expr; +@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr; +@un_log_op_expr = @log_not_expr; +@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr; + +@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr + | @rshift_expr; +@un_bit_op_expr = @bit_not_expr; +@bit_expr = @un_bit_op_expr | @bin_bit_op_expr; + +@equality_op_expr = @eq_expr | @ne_expr; +@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; +@comp_expr = @equality_op_expr | @rel_op_expr; + +@op_expr = @assign_expr | @un_op | @bin_op | @ternary_op; + +@ternary_op = @ternary_log_op_expr; +@bin_op = @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr; +@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr + | @pointer_indirection_expr | @address_of_expr; + +@anonymous_function_expr = @lambda_expr | @anonymous_method_expr; + +@call = @method_invocation_expr | @constructor_init_expr | @operator_invocation_expr + | @delegate_invocation_expr | @object_creation_expr | @call_access_expr + | @local_function_invocation_expr; + +@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr; + +@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr + | @object_creation_expr | @method_invocation_expr | @operator_invocation_expr; + +@throw_element = @throw_expr | @throw_stmt; + +implicitly_typed_array_creation( + unique int id: @array_creation_expr ref); + +explicitly_sized_array_creation( + unique int id: @array_creation_expr ref); + +stackalloc_array_creation( + unique int id: @array_creation_expr ref); + +mutator_invocation_mode( + unique int id: @operator_invocation_expr ref, + int mode: int ref /* prefix = 1, postfix = 2*/); + +expr_compiler_generated( + unique int id: @expr ref); + +expr_value( + unique int id: @expr ref, + string value: string ref); + +expr_call( + unique int caller_id: @expr ref, + int target_id: @callable ref); + +expr_access( + unique int accesser_id: @access_expr ref, + int target_id: @accessible ref); + +@accessible = @method | @assignable | @local_function | @namespace; + +expr_location( + unique int id: @expr ref, + int loc: @location ref); + +dynamic_member_name( + unique int id: @late_bindable_expr ref, + string name: string ref); + +@qualifiable_expr = @member_access_expr + | @method_invocation_expr + | @element_access_expr; + +conditional_access( + unique int id: @qualifiable_expr ref); + +expr_argument( + unique int id: @expr ref, + int mode: int ref); + /* mode is the same as params: value = 0, ref = 1, out = 2 */ + +expr_argument_name( + unique int id: @expr ref, + string name: string ref); + +/** CONTROL/DATA FLOW **/ + +@control_flow_element = @stmt | @expr; + +/* 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; + +/* Comments */ + +commentline( + unique int id: @commentline, + int kind: int ref, + string text: string ref, + string rawtext: string ref); + +case @commentline.kind of + 0 = @singlelinecomment +| 1 = @xmldoccomment +| 2 = @multilinecomment; + +commentline_location( + unique int id: @commentline ref, + int loc: @location ref); + +commentblock( + unique int id : @commentblock); + +commentblock_location( + unique int id: @commentblock ref, + int loc: @location ref); + +commentblock_binding( + int id: @commentblock ref, + int entity: @element ref, + int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */ + +commentblock_child( + int id: @commentblock ref, + int commentline: @commentline ref, + int index: int ref); + +/* ASP.NET */ + +case @asp_element.kind of + 0=@asp_close_tag +| 1=@asp_code +| 2=@asp_comment +| 3=@asp_data_binding +| 4=@asp_directive +| 5=@asp_open_tag +| 6=@asp_quoted_string +| 7=@asp_text +| 8=@asp_xml_directive; + +@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string; + +asp_elements( + unique int id: @asp_element, + int kind: int ref, + int loc: @location ref); + +asp_comment_server(unique int comment: @asp_comment ref); +asp_code_inline(unique int code: @asp_code ref); +asp_directive_attribute( + int directive: @asp_directive ref, + int index: int ref, + string name: string ref, + int value: @asp_quoted_string ref); +asp_directive_name( + unique int directive: @asp_directive ref, + string name: string ref); +asp_element_body( + unique int element: @asp_element ref, + string body: string ref); +asp_tag_attribute( + int tag: @asp_open_tag ref, + int index: int ref, + string name: string ref, + int attribute: @asp_attribute ref); +asp_tag_name( + unique int tag: @asp_open_tag ref, + string name: string ref); +asp_tag_isempty(int tag: @asp_open_tag ref); + +/* Common Intermediate Language - CIL */ + +case @cil_instruction.opcode of + 0 = @cil_nop +| 1 = @cil_break +| 2 = @cil_ldarg_0 +| 3 = @cil_ldarg_1 +| 4 = @cil_ldarg_2 +| 5 = @cil_ldarg_3 +| 6 = @cil_ldloc_0 +| 7 = @cil_ldloc_1 +| 8 = @cil_ldloc_2 +| 9 = @cil_ldloc_3 +| 10 = @cil_stloc_0 +| 11 = @cil_stloc_1 +| 12 = @cil_stloc_2 +| 13 = @cil_stloc_3 +| 14 = @cil_ldarg_s +| 15 = @cil_ldarga_s +| 16 = @cil_starg_s +| 17 = @cil_ldloc_s +| 18 = @cil_ldloca_s +| 19 = @cil_stloc_s +| 20 = @cil_ldnull +| 21 = @cil_ldc_i4_m1 +| 22 = @cil_ldc_i4_0 +| 23 = @cil_ldc_i4_1 +| 24 = @cil_ldc_i4_2 +| 25 = @cil_ldc_i4_3 +| 26 = @cil_ldc_i4_4 +| 27 = @cil_ldc_i4_5 +| 28 = @cil_ldc_i4_6 +| 29 = @cil_ldc_i4_7 +| 30 = @cil_ldc_i4_8 +| 31 = @cil_ldc_i4_s +| 32 = @cil_ldc_i4 +| 33 = @cil_ldc_i8 +| 34 = @cil_ldc_r4 +| 35 = @cil_ldc_r8 +| 37 = @cil_dup +| 38 = @cil_pop +| 39 = @cil_jmp +| 40 = @cil_call +| 41 = @cil_calli +| 42 = @cil_ret +| 43 = @cil_br_s +| 44 = @cil_brfalse_s +| 45 = @cil_brtrue_s +| 46 = @cil_beq_s +| 47 = @cil_bge_s +| 48 = @cil_bgt_s +| 49 = @cil_ble_s +| 50 = @cil_blt_s +| 51 = @cil_bne_un_s +| 52 = @cil_bge_un_s +| 53 = @cil_bgt_un_s +| 54 = @cil_ble_un_s +| 55 = @cil_blt_un_s +| 56 = @cil_br +| 57 = @cil_brfalse +| 58 = @cil_brtrue +| 59 = @cil_beq +| 60 = @cil_bge +| 61 = @cil_bgt +| 62 = @cil_ble +| 63 = @cil_blt +| 64 = @cil_bne_un +| 65 = @cil_bge_un +| 66 = @cil_bgt_un +| 67 = @cil_ble_un +| 68 = @cil_blt_un +| 69 = @cil_switch +| 70 = @cil_ldind_i1 +| 71 = @cil_ldind_u1 +| 72 = @cil_ldind_i2 +| 73 = @cil_ldind_u2 +| 74 = @cil_ldind_i4 +| 75 = @cil_ldind_u4 +| 76 = @cil_ldind_i8 +| 77 = @cil_ldind_i +| 78 = @cil_ldind_r4 +| 79 = @cil_ldind_r8 +| 80 = @cil_ldind_ref +| 81 = @cil_stind_ref +| 82 = @cil_stind_i1 +| 83 = @cil_stind_i2 +| 84 = @cil_stind_i4 +| 85 = @cil_stind_i8 +| 86 = @cil_stind_r4 +| 87 = @cil_stind_r8 +| 88 = @cil_add +| 89 = @cil_sub +| 90 = @cil_mul +| 91 = @cil_div +| 92 = @cil_div_un +| 93 = @cil_rem +| 94 = @cil_rem_un +| 95 = @cil_and +| 96 = @cil_or +| 97 = @cil_xor +| 98 = @cil_shl +| 99 = @cil_shr +| 100 = @cil_shr_un +| 101 = @cil_neg +| 102 = @cil_not +| 103 = @cil_conv_i1 +| 104 = @cil_conv_i2 +| 105 = @cil_conv_i4 +| 106 = @cil_conv_i8 +| 107 = @cil_conv_r4 +| 108 = @cil_conv_r8 +| 109 = @cil_conv_u4 +| 110 = @cil_conv_u8 +| 111 = @cil_callvirt +| 112 = @cil_cpobj +| 113 = @cil_ldobj +| 114 = @cil_ldstr +| 115 = @cil_newobj +| 116 = @cil_castclass +| 117 = @cil_isinst +| 118 = @cil_conv_r_un +| 121 = @cil_unbox +| 122 = @cil_throw +| 123 = @cil_ldfld +| 124 = @cil_ldflda +| 125 = @cil_stfld +| 126 = @cil_ldsfld +| 127 = @cil_ldsflda +| 128 = @cil_stsfld +| 129 = @cil_stobj +| 130 = @cil_conv_ovf_i1_un +| 131 = @cil_conv_ovf_i2_un +| 132 = @cil_conv_ovf_i4_un +| 133 = @cil_conv_ovf_i8_un +| 134 = @cil_conv_ovf_u1_un +| 135 = @cil_conv_ovf_u2_un +| 136 = @cil_conv_ovf_u4_un +| 137 = @cil_conv_ovf_u8_un +| 138 = @cil_conv_ovf_i_un +| 139 = @cil_conv_ovf_u_un +| 140 = @cil_box +| 141 = @cil_newarr +| 142 = @cil_ldlen +| 143 = @cil_ldelema +| 144 = @cil_ldelem_i1 +| 145 = @cil_ldelem_u1 +| 146 = @cil_ldelem_i2 +| 147 = @cil_ldelem_u2 +| 148 = @cil_ldelem_i4 +| 149 = @cil_ldelem_u4 +| 150 = @cil_ldelem_i8 +| 151 = @cil_ldelem_i +| 152 = @cil_ldelem_r4 +| 153 = @cil_ldelem_r8 +| 154 = @cil_ldelem_ref +| 155 = @cil_stelem_i +| 156 = @cil_stelem_i1 +| 157 = @cil_stelem_i2 +| 158 = @cil_stelem_i4 +| 159 = @cil_stelem_i8 +| 160 = @cil_stelem_r4 +| 161 = @cil_stelem_r8 +| 162 = @cil_stelem_ref +| 163 = @cil_ldelem +| 164 = @cil_stelem +| 165 = @cil_unbox_any +| 179 = @cil_conv_ovf_i1 +| 180 = @cil_conv_ovf_u1 +| 181 = @cil_conv_ovf_i2 +| 182 = @cil_conv_ovf_u2 +| 183 = @cil_conv_ovf_i4 +| 184 = @cil_conv_ovf_u4 +| 185 = @cil_conv_ovf_i8 +| 186 = @cil_conv_ovf_u8 +| 194 = @cil_refanyval +| 195 = @cil_ckinfinite +| 198 = @cil_mkrefany +| 208 = @cil_ldtoken +| 209 = @cil_conv_u2 +| 210 = @cil_conv_u1 +| 211 = @cil_conv_i +| 212 = @cil_conv_ovf_i +| 213 = @cil_conv_ovf_u +| 214 = @cil_add_ovf +| 215 = @cil_add_ovf_un +| 216 = @cil_mul_ovf +| 217 = @cil_mul_ovf_un +| 218 = @cil_sub_ovf +| 219 = @cil_sub_ovf_un +| 220 = @cil_endfinally +| 221 = @cil_leave +| 222 = @cil_leave_s +| 223 = @cil_stind_i +| 224 = @cil_conv_u +| 65024 = @cil_arglist +| 65025 = @cil_ceq +| 65026 = @cil_cgt +| 65027 = @cil_cgt_un +| 65028 = @cil_clt +| 65029 = @cil_clt_un +| 65030 = @cil_ldftn +| 65031 = @cil_ldvirtftn +| 65033 = @cil_ldarg +| 65034 = @cil_ldarga +| 65035 = @cil_starg +| 65036 = @cil_ldloc +| 65037 = @cil_ldloca +| 65038 = @cil_stloc +| 65039 = @cil_localloc +| 65041 = @cil_endfilter +| 65042 = @cil_unaligned +| 65043 = @cil_volatile +| 65044 = @cil_tail +| 65045 = @cil_initobj +| 65046 = @cil_constrained +| 65047 = @cil_cpblk +| 65048 = @cil_initblk +| 65050 = @cil_rethrow +| 65052 = @cil_sizeof +| 65053 = @cil_refanytype +| 65054 = @cil_readonly +; + +// CIL ignored instructions + +@cil_ignore = @cil_nop | @cil_break | @cil_volatile | @cil_unaligned; + +// CIL local/parameter/field access + +@cil_ldarg_any = @cil_ldarg_0 | @cil_ldarg_1 | @cil_ldarg_2 | @cil_ldarg_3 | @cil_ldarg_s | @cil_ldarga_s | @cil_ldarg | @cil_ldarga; +@cil_starg_any = @cil_starg | @cil_starg_s; + +@cil_ldloc_any = @cil_ldloc_0 | @cil_ldloc_1 | @cil_ldloc_2 | @cil_ldloc_3 | @cil_ldloc_s | @cil_ldloca_s | @cil_ldloc | @cil_ldloca; +@cil_stloc_any = @cil_stloc_0 | @cil_stloc_1 | @cil_stloc_2 | @cil_stloc_3 | @cil_stloc_s | @cil_stloc; + +@cil_ldfld_any = @cil_ldfld | @cil_ldsfld | @cil_ldsflda | @cil_ldflda; +@cil_stfld_any = @cil_stfld | @cil_stsfld; + +@cil_local_access = @cil_stloc_any | @cil_ldloc_any; +@cil_arg_access = @cil_starg_any | @cil_ldarg_any; +@cil_read_access = @cil_ldloc_any | @cil_ldarg_any | @cil_ldfld_any; +@cil_write_access = @cil_stloc_any | @cil_starg_any | @cil_stfld_any; + +@cil_stack_access = @cil_local_access | @cil_arg_access; +@cil_field_access = @cil_ldfld_any | @cil_stfld_any; + +@cil_access = @cil_read_access | @cil_write_access; + +// CIL constant/literal instructions + +@cil_ldc_i = @cil_ldc_i4_any | @cil_ldc_i8; + +@cil_ldc_i4_any = @cil_ldc_i4_m1 | @cil_ldc_i4_0 | @cil_ldc_i4_1 | @cil_ldc_i4_2 | @cil_ldc_i4_3 | + @cil_ldc_i4_4 | @cil_ldc_i4_5 | @cil_ldc_i4_6 | @cil_ldc_i4_7 | @cil_ldc_i4_8 | @cil_ldc_i4_s | @cil_ldc_i4; + +@cil_ldc_r = @cil_ldc_r4 | @cil_ldc_r8; + +@cil_literal = @cil_ldnull | @cil_ldc_i | @cil_ldc_r | @cil_ldstr; + +// Control flow + +@cil_conditional_jump = @cil_binary_jump | @cil_unary_jump; +@cil_binary_jump = @cil_beq_s | @cil_bge_s | @cil_bgt_s | @cil_ble_s | @cil_blt_s | + @cil_bne_un_s | @cil_bge_un_s | @cil_bgt_un_s | @cil_ble_un_s | @cil_blt_un_s | + @cil_beq | @cil_bge | @cil_bgt | @cil_ble | @cil_blt | + @cil_bne_un | @cil_bge_un | @cil_bgt_un | @cil_ble_un | @cil_blt_un; +@cil_unary_jump = @cil_brfalse_s | @cil_brtrue_s | @cil_brfalse | @cil_brtrue | @cil_switch; +@cil_unconditional_jump = @cil_br | @cil_br_s | @cil_leave_any; +@cil_leave_any = @cil_leave | @cil_leave_s; +@cil_jump = @cil_unconditional_jump | @cil_conditional_jump; + +// CIL call instructions + +@cil_call_any = @cil_jmp | @cil_call | @cil_calli | @cil_tail | @cil_callvirt | @cil_newobj; + +// CIL expression instructions + +@cil_expr = @cil_literal | @cil_binary_expr | @cil_unary_expr | @cil_call_any | @cil_read_access | + @cil_newarr | @cil_ldtoken | @cil_sizeof | + @cil_ldftn | @cil_ldvirtftn | @cil_localloc | @cil_mkrefany | @cil_refanytype | @cil_arglist | @cil_dup; + +@cil_unary_expr = + @cil_conversion_operation | @cil_unary_arithmetic_operation | @cil_unary_bitwise_operation| + @cil_ldlen | @cil_isinst | @cil_box | @cil_ldobj | @cil_castclass | @cil_unbox_any | + @cil_ldind | @cil_unbox; + +@cil_conversion_operation = + @cil_conv_i1 | @cil_conv_i2 | @cil_conv_i4 | @cil_conv_i8 | + @cil_conv_u1 | @cil_conv_u2 | @cil_conv_u4 | @cil_conv_u8 | + @cil_conv_ovf_i | @cil_conv_ovf_i_un | @cil_conv_ovf_i1 | @cil_conv_ovf_i1_un | + @cil_conv_ovf_i2 | @cil_conv_ovf_i2_un | @cil_conv_ovf_i4 | @cil_conv_ovf_i4_un | + @cil_conv_ovf_i8 | @cil_conv_ovf_i8_un | @cil_conv_ovf_u | @cil_conv_ovf_u_un | + @cil_conv_ovf_u1 | @cil_conv_ovf_u1_un | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_ovf_u4 | @cil_conv_ovf_u4_un | @cil_conv_ovf_u8 | @cil_conv_ovf_u8_un | + @cil_conv_r4 | @cil_conv_r8 | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_i | @cil_conv_u | @cil_conv_r_un; + +@cil_ldind = @cil_ldind_i | @cil_ldind_i1 | @cil_ldind_i2 | @cil_ldind_i4 | @cil_ldind_i8 | + @cil_ldind_r4 | @cil_ldind_r8 | @cil_ldind_ref | @cil_ldind_u1 | @cil_ldind_u2 | @cil_ldind_u4; + +@cil_stind = @cil_stind_i | @cil_stind_i1 | @cil_stind_i2 | @cil_stind_i4 | @cil_stind_i8 | + @cil_stind_r4 | @cil_stind_r8 | @cil_stind_ref; + +@cil_bitwise_operation = @cil_binary_bitwise_operation | @cil_unary_bitwise_operation; + +@cil_binary_bitwise_operation = @cil_and | @cil_or | @cil_xor | @cil_shr | @cil_shr | @cil_shr_un | @cil_shl; + +@cil_binary_arithmetic_operation = @cil_add | @cil_sub | @cil_mul | @cil_div | @cil_div_un | + @cil_rem | @cil_rem_un | @cil_add_ovf | @cil_add_ovf_un | @cil_mul_ovf | @cil_mul_ovf_un | + @cil_sub_ovf | @cil_sub_ovf_un; + +@cil_unary_bitwise_operation = @cil_not; + +@cil_binary_expr = @cil_binary_arithmetic_operation | @cil_binary_bitwise_operation | @cil_read_array | @cil_comparison_operation; + +@cil_unary_arithmetic_operation = @cil_neg; + +@cil_comparison_operation = @cil_cgt_un | @cil_ceq | @cil_cgt | @cil_clt | @cil_clt_un; + +// Elements that retrieve an address of something +@cil_read_ref = @cil_ldloca_s | @cil_ldarga_s | @cil_ldflda | @cil_ldsflda | @cil_ldelema; + +// CIL array instructions + +@cil_read_array = + @cil_ldelem | @cil_ldelema | @cil_ldelem_i1 | @cil_ldelem_ref | @cil_ldelem_i | + @cil_ldelem_i1 | @cil_ldelem_i2 | @cil_ldelem_i4 | @cil_ldelem_i8 | @cil_ldelem_r4 | + @cil_ldelem_r8 | @cil_ldelem_u1 | @cil_ldelem_u2 | @cil_ldelem_u4; + +@cil_write_array = @cil_stelem | @cil_stelem_ref | + @cil_stelem_i | @cil_stelem_i1 | @cil_stelem_i2 | @cil_stelem_i4 | @cil_stelem_i8 | + @cil_stelem_r4 | @cil_stelem_r8; + +@cil_throw_any = @cil_throw | @cil_rethrow; + +#keyset[impl, index] +cil_instruction( + unique int id: @cil_instruction, + int opcode: int ref, + int index: int ref, + int impl: @cil_method_implementation ref); + +cil_jump( + unique int instruction: @cil_jump ref, + int target: @cil_instruction ref); + +cil_access( + unique int instruction: @cil_instruction ref, + int target: @cil_accessible ref); + +cil_value( + unique int instruction: @cil_literal ref, + string value: string ref); + +#keyset[instruction, index] +cil_switch( + int instruction: @cil_switch ref, + int index: int ref, + int target: @cil_instruction ref); + +cil_instruction_location( + unique int id: @cil_instruction ref, + int loc: @location ref); + +cil_type_location( + int id: @cil_type ref, + int loc: @location ref); + +cil_method_location( + int id: @cil_method ref, + int loc: @location ref); + +@cil_namespace = @namespace; + +@cil_type_container = @cil_type | @cil_namespace | @cil_method; + +case @cil_type.kind of + 0 = @cil_valueorreftype +| 1 = @cil_typeparameter +| 2 = @cil_array_type +| 3 = @cil_pointer_type +; + +cil_type( + unique int id: @cil_type, + string name: string ref, + int kind: int ref, + int parent: @cil_type_container ref, + int sourceDecl: @cil_type ref); + +cil_pointer_type( + unique int id: @cil_pointer_type ref, + int pointee: @cil_type ref); + +cil_array_type( + unique int id: @cil_array_type ref, + int element_type: @cil_type ref, + int rank: int ref); + +cil_method( + unique int id: @cil_method, + string name: string ref, + int parent: @cil_type ref, + int return_type: @cil_type ref); + +cil_method_source_declaration( + unique int method: @cil_method ref, + int source: @cil_method ref); + +cil_method_implementation( + unique int id: @cil_method_implementation, + int method: @cil_method ref, + int location: @assembly ref); + +cil_implements( + int id: @cil_method ref, + int decl: @cil_method ref); + +#keyset[parent, name] +cil_field( + unique int id: @cil_field, + int parent: @cil_type ref, + string name: string ref, + int field_type: @cil_type ref); + +@cil_element = @cil_instruction | @cil_declaration | @cil_handler | @cil_attribute | @cil_namespace; +@cil_named_element = @cil_declaration | @cil_namespace; +@cil_declaration = @cil_variable | @cil_method | @cil_type | @cil_member; +@cil_accessible = @cil_declaration; +@cil_variable = @cil_field | @cil_stack_variable; +@cil_stack_variable = @cil_local_variable | @cil_parameter; +@cil_member = @cil_method | @cil_type | @cil_field | @cil_property | @cil_event; + +#keyset[method, index] +cil_parameter( + unique int id: @cil_parameter, + int method: @cil_method ref, + int index: int ref, + int param_type: @cil_type ref); + +cil_parameter_in(unique int id: @cil_parameter ref); +cil_parameter_out(unique int id: @cil_parameter ref); + +cil_setter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_getter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_adder(unique int event: @cil_event ref, + int method: @cil_method ref); + +cil_remover(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_raiser(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_property( + unique int id: @cil_property, + int parent: @cil_type ref, + string name: string ref, + int property_type: @cil_type ref); + +#keyset[parent, name] +cil_event(unique int id: @cil_event, + int parent: @cil_type ref, + string name: string ref, + int event_type: @cil_type ref); + +#keyset[impl, index] +cil_local_variable( + unique int id: @cil_local_variable, + int impl: @cil_method_implementation ref, + int index: int ref, + int var_type: @cil_type ref); + +// CIL handlers (exception handlers etc). + +case @cil_handler.kind of + 0 = @cil_catch_handler +| 1 = @cil_filter_handler +| 2 = @cil_finally_handler +| 4 = @cil_fault_handler +; + +#keyset[impl, index] +cil_handler( + unique int id: @cil_handler, + int impl: @cil_method_implementation ref, + int index: int ref, + int kind: int ref, + int try_start: @cil_instruction ref, + int try_end: @cil_instruction ref, + int handler_start: @cil_instruction ref); + +cil_handler_filter( + unique int id: @cil_handler ref, + int filter_start: @cil_instruction ref); + +cil_handler_type( + unique int id: @cil_handler ref, + int catch_type: @cil_type ref); + +@cil_controlflow_node = @cil_entry_point | @cil_instruction; + +@cil_entry_point = @cil_method_implementation | @cil_handler; + +@cil_dataflow_node = @cil_instruction | @cil_variable | @cil_method; + +cil_method_stack_size( + unique int method: @cil_method_implementation ref, + int size: int ref); + +// CIL modifiers + +cil_public(int id: @cil_member ref); +cil_private(int id: @cil_member ref); +cil_protected(int id: @cil_member ref); +cil_internal(int id: @cil_member ref); +cil_static(int id: @cil_member ref); +cil_sealed(int id: @cil_member ref); +cil_virtual(int id: @cil_method ref); +cil_abstract(int id: @cil_member ref); +cil_class(int id: @cil_type ref); +cil_interface(int id: @cil_type ref); +cil_security(int id: @cil_member ref); +cil_requiresecobject(int id: @cil_method ref); +cil_specialname(int id: @cil_method ref); +cil_newslot(int id: @cil_method ref); + +cil_base_class(unique int id: @cil_type ref, int base: @cil_type ref); +cil_base_interface(int id: @cil_type ref, int base: @cil_type ref); + +#keyset[unbound, index] +cil_type_parameter( + int unbound: @cil_member ref, + int index: int ref, + int param: @cil_typeparameter ref); + +#keyset[bound, index] +cil_type_argument( + int bound: @cil_member ref, + int index: int ref, + int t: @cil_type ref); + +// CIL type parameter constraints + +cil_typeparam_covariant(int tp: @cil_typeparameter ref); +cil_typeparam_contravariant(int tp: @cil_typeparameter ref); +cil_typeparam_class(int tp: @cil_typeparameter ref); +cil_typeparam_struct(int tp: @cil_typeparameter ref); +cil_typeparam_new(int tp: @cil_typeparameter ref); +cil_typeparam_constraint(int tp: @cil_typeparameter ref, int supertype: @cil_type ref); + +// CIL attributes + +cil_attribute( + unique int attributeid: @cil_attribute, + int element: @cil_declaration ref, + int constructor: @cil_method ref); + +#keyset[attribute_id, param] +cil_attribute_named_argument( + int attribute_id: @cil_attribute ref, + string param: string ref, + string value: string ref); + +#keyset[attribute_id, index] +cil_attribute_positional_argument( + int attribute_id: @cil_attribute ref, + int index: int ref, + string value: string ref); + + +// Common .Net data model covering both C# and CIL + +// Common elements +@dotnet_element = @element | @cil_element; +@dotnet_named_element = @named_element | @cil_named_element; +@dotnet_callable = @callable | @cil_method; +@dotnet_variable = @variable | @cil_variable; +@dotnet_field = @field | @cil_field; +@dotnet_parameter = @parameter | @cil_parameter; +@dotnet_declaration = @declaration | @cil_declaration; +@dotnet_member = @member | @cil_member; +@dotnet_event = @event | @cil_event; +@dotnet_property = @property | @cil_property | @indexer; + +// Common types +@dotnet_type = @type | @cil_type; +@dotnet_call = @call | @cil_call_any; +@dotnet_throw = @throw_element | @cil_throw_any; +@dotnet_valueorreftype = @cil_valueorreftype | @value_or_ref_type | @cil_array_type | @void_type; +@dotnet_typeparameter = @type_parameter | @cil_typeparameter; +@dotnet_array_type = @array_type | @cil_array_type; +@dotnet_pointer_type = @pointer_type | @cil_pointer_type; +@dotnet_type_parameter = @type_parameter | @cil_typeparameter; +@dotnet_generic = @dotnet_valueorreftype | @dotnet_callable; + +// Attributes +@dotnet_attribute = @attribute | @cil_attribute; + +// Expressions +@dotnet_expr = @expr | @cil_expr; + +// Literals +@dotnet_literal = @literal_expr | @cil_literal; +@dotnet_string_literal = @string_literal_expr | @cil_ldstr; +@dotnet_int_literal = @integer_literal_expr | @cil_ldc_i; +@dotnet_float_literal = @float_literal_expr | @cil_ldc_r; +@dotnet_null_literal = @null_literal_expr | @cil_ldnull; + +@metadata_entity = @cil_method | @cil_type | @cil_field | @cil_property | @field | @property | + @callable | @value_or_ref_type | @void_type; + +#keyset[entity, location] +metadata_handle(int entity : @metadata_entity ref, int location: @assembly ref, int handle: int ref) diff --git a/csharp/upgrades/f2aa2d4ac31309bd83ab633d0f40e8a442767bd1/upgrade.properties b/csharp/upgrades/f2aa2d4ac31309bd83ab633d0f40e8a442767bd1/upgrade.properties new file mode 100644 index 000000000000..75d52d62e13a --- /dev/null +++ b/csharp/upgrades/f2aa2d4ac31309bd83ab633d0f40e8a442767bd1/upgrade.properties @@ -0,0 +1,2 @@ +description: Removed uniqueness constraint from 'explicitly_implements' relation +compatibility: full diff --git a/docs/language/README.rst b/docs/language/README.rst index 552323611994..d47dc641b4da 100644 --- a/docs/language/README.rst +++ b/docs/language/README.rst @@ -103,7 +103,7 @@ generates html slide shows in the ```` directory when run from the ``ql-training`` source directory. For more information about creating slides for QL training and variant analysis -examples, see the `template slide deck `__. +examples, see the `template slide deck `__. Viewing the current version of the CodeQL documentation ******************************************************* diff --git a/docs/language/global-sphinx-files/_static/custom.css_t b/docs/language/global-sphinx-files/_static/custom.css_t index 482cefea5e98..927660034fe1 100644 --- a/docs/language/global-sphinx-files/_static/custom.css_t +++ b/docs/language/global-sphinx-files/_static/custom.css_t @@ -1,305 +1,85 @@ /* - * Sphinx stylesheet to add some customizations to the default Alabaster theme. + * This Sphinx stylesheet adds some customizations to the default Alabaster theme. * * The source for the default stylesheet can be found at * https://github.com/bitprophet/alabaster/blob/master/alabaster/static/alabaster.css_t * + * For the classes provided by the primer, see https://unpkg.com/@primer/css/dist/primer.css */ -div.body h1 { - margin-top: 1em; -} - -div.wrapper { - padding-top: 78px; - margin-bottom: 0px; - height: 637px; -} - -/* -- HEADER ------------------------------------------------------------------------------- */ - -div.header { - background-color: #140f46; - top:0; - position: fixed; - width: 100%; - padding: 0 30px 30px 30px; -} -.textContainer { - margin: auto; -} - -/*div.logocontainer { - width: 50%; -}*/ -#siteBanner { - position: fixed; - width: 100%; - height: 4.5rem; - margin: 0; - padding: 0 20px 0 30px; - background-color: #140f46; - opacity: 0.95; - transform: translate3d(0px, 0px, 0px); - z-index: 1; -} -#siteBanner input { - border-width: 0; - /*color: rgb(244, 244, 244); - background-color: #140f46; - font-size: 0.9rem;*/ - letter-spacing: 0.1rem; - /*width: 12rem;*/ -} -#siteBanner input:focus, -#siteBanner textarea:focus, -#siteBanner select:focus{ - outline: none; -} -svg.Header-logo-white { - display: inline; -} -svg.Header-logo-purple { - display: none; -} +/* -- CODE SNIPPETS ----------------------------------------------------------------------- */ -div.linkcontainer { - /*width: 50%;*/ - margin-left: auto; - margin-top: -1.3rem; - padding-right: 50px; +code { + font-size: 0.9em !important; /* makes code snippets in headings the correct size */ } -div.linkbar { - float:right; -} -.linkbar a { - color: White; - font-size: 18px; - margin-left: 20px; - text-decoration: none; -} - - -.linkbar a:hover { - text-decoration: underline; -} -.small-bar { - float:right; - display:none; -} - -.small-bar a { - color: White; - font-size: 18px; - margin-left: 20px; - text-decoration: none; -} -.small-bar a:hover { - text-decoration: underline; -} - -#Header-logo { - text-decoration: none; - position: relative; - width: 98px; - height: 20px; -} - -#Header-logo > * { - margin-top: 1.7rem; -} +/* -- MAIN BODY ---------------------------------------------------------------------------- */ -svg.Header-logo-white { - display: inline; +main { + min-height: calc(100vh - 68px); } - -/* -- DOCUMENT ------------------------------------------------------------------------------- */ - -div.document { - width: 100%; +div.body { + max-width: 100%; + min-width: unset; padding: 0; - margin: 0 0 30px 0; } -div.documentwrapper { - width: 90%; - box-shadow: 0.1rem 0.4rem 1.5rem #d0cee4; - margin: 20px 20px 20px 20px; - padding-bottom: 50px; -} -div.mainBox { - margin-left: calc(30% + 25px); /* Allow 25px for the width of the ToC scrollbar */ +div.body li { + margin: 0 0 0.5em 0; /* Increase spacing between list items */ } -div.privacy { - text-align: right; - padding-right: 5%; - padding-bottom: 20px; +article { + min-height: calc(100vh - 145px); /* Makes sure GitHub footer stays at bottom of viewport */ } /* -- SIDEBAR ------------------------------------------------------------------------------- */ -div.navBox { - overflow-y:auto; - width:29%; - padding-left: 25px; - position: fixed; - height: calc(100% - 108px); - z-index: 100; - background-color: #FFFFFF; - padding-top: 30px; +.SideNav { + max-height: 100vh; /* Makes sure sidebar doesn't cover GitHub footer */ } -.navBox li { +.SideNav li { margin: 10px 0 10px 0px; } -.navBox ul, .navBox ol, .navBox li { +.SideNav ul, .SideNav ol, .SideNav li { list-style-type: none; } -.navBox ul li a { +.SideNav ul li a { border-bottom: none; + color: black; } -.navBox ul li a:hover { +.SideNav ul li a:hover { font-weight: bold; border-bottom: none; } -.navBox a.current { +.SideNav a.current { font-weight: bold; text-decoration: underline; } -/* -- SMALL SCREEN ------------------------------------------------------------------------------- */ - -@media screen and (max-width: 875px){ - - #siteBanner { - position: relative; - } - div.wrapper { - /*margin-top:-100px;*/ - flex-direction: column; - height: 100%; - width: 100%; - padding-top: 0px; - } - div.mainBox { - margin: 0 10px 0 10px; - position: relative; - height: 100%; - width: 100%; - } - div.documentwrapper { - padding-left: 20px; - width:100%; - box-shadow: none; - margin: 0; - padding-left:0; - } - - div.navBox { - position: relative; - width: 100%; - border-color: #2f1695; - } - body { - margin: 0; - padding: 0; - overflow: inherit; - width:95%; - } - - div.body { - min-width: unset; - } - div.linkbar { - display: none; - - } - .small-bar { - display: inherit; - } - - ul { - margin: 10px 20px 10px 20px; - } - - div.privacy { - padding-right: 0%; - } +/* -- BREADCRUMBS --------------------------------------------------------------------------------*/ +div.related ul { + padding: 0; } - -/* -- PRINT VIEW ----------------------------------------------------------------------------*/ -@media print { - div.navBox { - display: none; - } +/* -- LINKS --------------------------------------------------------------------------------------*/ - #siteBanner { - display: none; - } - - div.wrapper { - /*margin-top:-100px;*/ - flex-direction: column; - height: 100%; - width: 100%; - padding-top: 0px; - } - div.mainBox { - margin: 0 10px 0 10px; - position: relative; - height: 100%; - width: 100%; - } - div.documentwrapper { - padding-left: 20px; - width:100%; - box-shadow: none; - margin: 0; - padding-left:0; - } - - body { - margin: 0; - padding: 0; - overflow: inherit; - width:95%; - } - - div.body { - min-width: unset; - } - div.linkbar { - display: none; - - } - .small-bar { - display: inherit; - } - - ul { - margin: 10px 20px 10px 20px; - } - - div.privacy { - display: none; - } +a.reference { + border-bottom: none; } -/* -- MAIN BODY ---------------------------------------------------------------------------- */ +a.reference:hover { + text-decoration: none; +} -div.body { - max-width: 100%; /* overrule 800px in basic.css */ -} +/* -- ADMONITIONS ---------------------------------------------------------------------------- */ /* * Override default styling for "admonitions". @@ -337,8 +117,11 @@ pre { border: 1px solid #BBB; background: #F6F6F6; border-radius: 5px; + white-space: pre-wrap; } +/* -- QL SYNTAX HIGHLIGHTING -------------------------------------------------- */ + /* * Use more appropriate colors for syntax highlighting * @@ -354,35 +137,25 @@ pre { .highlight .kt { color: #7a65cd; font-weight: bold } /* built-in type keywords */ .highlight .kr { color: #333; font-style: italic } /* annotations */ -/* -- INDEX -------------------------------------------------------------------------------- */ + +/* -- SEARCH PAGE ---------------------------------------------------------------------------- */ + +div.context { /* hide rst search snippets */ + display: none; +} + +/* -- INDEX ---------------------------------------------------------------------------------------- */ table.indextable li > a { text-decoration: unset; } +/* -- ANCHOR LINKS ------------------------------------------------------------------------------- */ -/* -- FOOTER ------------------------------------------------------------------------------- */ -div.footer { - display: none; - /* background-color: #2F1695; */ - /* color: #FFFFFF; */ - /* padding: 30px; */ - /* margin: 0; */ - /* width: calc(100% - 60px); */ /* Allow for 2 x 30px of padding (at left & right side) */ - /* position: fixed; */ - /* bottom: 0; */ -} +/* make anchor highlighting more sensible */ -/* Adjust anchor targets to allow for the fixed banner */ -div.documentwrapper a[name], -div.documentwrapper :target::before, -div.footnote-group a[name], -div.footnote-group :target::before - { - content: ""; - display: block; - height: 78px; /* Height of banner */ - margin-top: -78px; /* Prevent this showing as a gap */ +dt:target::before { + background-color: white; } /* -- CSV TABLE STYLING ------------------------------------------------------------------------------- */ @@ -444,4 +217,39 @@ blockquote.pull-quote > :last-child { .toggle .name.open:after { content: " ▼"; +} + +/* -- PRINT VIEW ----------------------------------------------------------------------------*/ + +@media print { + + div.SideNav { + display: none; + } + + body { + margin: 0; + padding: 0; + overflow: inherit; + width:95%; + } + + div.privacy { + display: none; + } +} + +/* -- SMALL SCREEN ------------------------------------------------------------------------------- */ + +@media screen and (max-width: 875px) { + + /* Overrides strange behaviour caused by default styles */ + + body { + padding: 0; + } + + div.footer { + display: block; + } } \ No newline at end of file diff --git a/docs/language/global-sphinx-files/_static/primer.css b/docs/language/global-sphinx-files/_static/primer.css new file mode 100644 index 000000000000..47c60f18fd01 --- /dev/null +++ b/docs/language/global-sphinx-files/_static/primer.css @@ -0,0 +1,14785 @@ +/*! + * Primer CSS + * https://primer.style + * + * Released under MIT license. + */ + +/*! + * @primer/css/core + * http://primer.style/css + * + * Released under MIT license. Copyright (c) 2019 GitHub Inc. + */ + +.octicon { + display: inline-block; + vertical-align: text-top; + fill: currentColor +} + +/*! normalize.css v4.1.1 | MIT License | github.com/necolas/normalize.css */ + +html { + font-family: sans-serif; + -ms-text-size-adjust: 100%; + -webkit-text-size-adjust: 100% +} + +body { + margin: 0 +} + +article, aside, details, figcaption, figure, footer, header, main, menu, nav, section { + display: block +} + +summary { + display: list-item +} + +audio, canvas, progress, video { + display: inline-block +} + +audio:not([controls]) { + display: none; + height: 0 +} + +progress { + vertical-align: baseline +} + +template, [hidden] { + display: none !important +} + +a { + background-color: transparent +} + +a:active, a:hover { + outline-width: 0 +} + +abbr[title] { + border-bottom: none; + text-decoration: underline; + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted +} + +b, strong { + font-weight: inherit +} + +b, strong { + font-weight: bolder +} + +dfn { + font-style: italic +} + +h1 { + font-size: 2em; + margin: 0.67em 0 +} + +mark { + background-color: #ff0; + color: #1b1f23 +} + +small { + font-size: 80% +} + +sub, sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline +} + +sub { + bottom: -0.25em +} + +sup { + top: -0.5em +} + +img { + border-style: none +} + +svg:not(:root) { + overflow: hidden +} + +code, kbd, pre, samp { + font-family: monospace, monospace; + font-size: 1em +} + +figure { + margin: 1em 40px +} + +hr { + box-sizing: content-box; + height: 0; + overflow: visible +} + +button, input, select, textarea { + font: inherit; + margin: 0 +} + +optgroup { + font-weight: 600 +} + +button, input { + overflow: visible +} + +button, select { + text-transform: none +} + +button, html [type="button"], [type="reset"], [type="submit"] { + -webkit-appearance: button +} + +button::-moz-focus-inner, [type="button"]::-moz-focus-inner, [type="reset"]::-moz-focus-inner, [type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0 +} + +button:-moz-focusring, [type="button"]:-moz-focusring, [type="reset"]:-moz-focusring, [type="submit"]:-moz-focusring { + outline: 1px dotted ButtonText +} + +fieldset { + border: 1px solid silver; + margin: 0 2px; + padding: 0.35em 0.625em .75em +} + +legend { + box-sizing: border-box; + color: inherit; + display: table; + max-width: 100%; + padding: 0; + white-space: normal +} + +textarea { + overflow: auto +} + +[type="checkbox"], [type="radio"] { + box-sizing: border-box; + padding: 0 +} + +[type="number"]::-webkit-inner-spin-button, [type="number"]::-webkit-outer-spin-button { + height: auto +} + +[type="search"] { + -webkit-appearance: textfield; + outline-offset: -2px +} + +[type="search"]::-webkit-search-cancel-button, [type="search"]::-webkit-search-decoration { + -webkit-appearance: none +} + +::-webkit-input-placeholder { + color: inherit; + opacity: 0.54 +} + +::-webkit-file-upload-button { + -webkit-appearance: button; + font: inherit +} + +* { + box-sizing: border-box +} + +input, select, textarea, button { + font-family: inherit; + font-size: inherit; + line-height: inherit +} + +body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; + font-size: 14px; + line-height: 1.5; + color: #24292e; + background-color: #fff +} + +a { + color: #0366d6; + text-decoration: none +} + +a:hover { + text-decoration: underline +} + +b, strong { + font-weight: 600 +} + +hr, .rule { + height: 0; + margin: 15px 0; + overflow: hidden; + background: transparent; + border: 0; + border-bottom: 1px solid #dfe2e5 +} + +hr::before, .rule::before { + display: table; + content: "" +} + +hr::after, .rule::after { + display: table; + clear: both; + content: "" +} + +table { + border-spacing: 0; + border-collapse: collapse +} + +td, th { + padding: 0 +} + +button { + cursor: pointer; + border-radius: 0 +} + +[hidden][hidden] { + display: none !important +} + +details summary { + cursor: pointer +} + +details:not([open])>*:not(summary) { + display: none !important +} + +kbd { + display: inline-block; + padding: 3px 5px; + font: 11px "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace; + line-height: 10px; + color: #444d56; + vertical-align: middle; + background-color: #fafbfc; + border: solid 1px #d1d5da; + border-bottom-color: #d1d5da; + border-radius: 6px; + box-shadow: inset 0 -1px 0 #d1d5da +} + +h1, h2, h3, h4, h5, h6 { + margin-top: 0; + margin-bottom: 0 +} + +h1 { + font-size: 32px; + font-weight: 600 +} + +h2 { + font-size: 24px; + font-weight: 600 +} + +h3 { + font-size: 20px; + font-weight: 600 +} + +h4 { + font-size: 16px; + font-weight: 600 +} + +h5 { + font-size: 14px; + font-weight: 600 +} + +h6 { + font-size: 12px; + font-weight: 600 +} + +p { + margin-top: 0; + margin-bottom: 10px +} + +small { + font-size: 90% +} + +blockquote { + margin: 0 +} + +ul, ol { + padding-left: 0; + margin-top: 0; + margin-bottom: 0 +} + +ol ol, ul ol { + list-style-type: lower-roman +} + +ul ul ol, ul ol ol, ol ul ol, ol ol ol { + list-style-type: lower-alpha +} + +dd { + margin-left: 0 +} + +tt, code { + font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace; + font-size: 12px +} + +pre { + margin-top: 0; + margin-bottom: 0; + font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace; + font-size: 12px +} + +.octicon { + vertical-align: text-bottom +} + +.Box { + background-color: #fff; + border: 1px #e1e4e8 solid; + border-radius: 6px +} + +.Box--condensed { + line-height: 1.25 +} + +.Box--condensed .Box-header { + padding: 8px 16px +} + +.Box--condensed .Box-body { + padding: 8px 16px +} + +.Box--condensed .Box-footer { + padding: 8px 16px +} + +.Box--condensed .Box-btn-octicon.btn-octicon { + padding: 8px 16px; + margin: -8px -16px; + line-height: 1.25 +} + +.Box--condensed .Box-row { + padding: 8px 16px +} + +.Box--spacious .Box-header { + padding: 24px; + line-height: 1.25 +} + +.Box--spacious .Box-title { + font-size: 20px +} + +.Box--spacious .Box-body { + padding: 24px +} + +.Box--spacious .Box-footer { + padding: 24px +} + +.Box--spacious .Box-btn-octicon.btn-octicon { + padding: 24px; + margin: -24px -24px +} + +.Box--spacious .Box-row { + padding: 24px +} + +.Box-header { + padding: 16px; + margin: -1px -1px 0; + background-color: #f6f8fa; + border-color: #e1e4e8; + border-style: solid; + border-width: 1px; + border-top-left-radius: 6px; + border-top-right-radius: 6px +} + +.Box-title { + font-size: 14px; + font-weight: 600 +} + +.Box-body { + padding: 16px; + border-bottom: 1px solid #e1e4e8 +} + +.Box-body:last-of-type { + margin-bottom: -1px; + border-bottom-right-radius: 6px; + border-bottom-left-radius: 6px +} + +.Box-row { + padding: 16px; + margin-top: -1px; + list-style-type: none; + border-top: 1px #e1e4e8 solid +} + +.Box-row:first-of-type { + border-top-left-radius: 6px; + border-top-right-radius: 6px +} + +.Box-row:last-of-type { + border-bottom-right-radius: 6px; + border-bottom-left-radius: 6px +} + +.Box-row.Box-row--unread, .Box-row.unread { + box-shadow: 2px 0 0 #0366d6 inset +} + +.Box-row.navigation-focus .Box-row--drag-button { + color: #0366d6; + cursor: grab; + opacity: 100 +} + +.Box-row.navigation-focus.is-dragging .Box-row--drag-button { + cursor: grabbing +} + +.Box-row.navigation-focus.sortable-chosen { + background-color: #fafbfc +} + +.Box-row.navigation-focus.sortable-ghost { + background-color: #f6f8fa +} + +.Box-row.navigation-focus.sortable-ghost .Box-row--drag-hide { + opacity: 0 +} + +.Box-row--focus-gray.navigation-focus { + background-color: #f6f8fa +} + +.Box-row--focus-blue.navigation-focus { + background-color: #f1f8ff +} + +.Box-row--hover-gray:hover { + background-color: #f6f8fa +} + +.Box-row--hover-blue:hover { + background-color: #f1f8ff +} + +@media (min-width: 768px) { + .Box-row-link { + color: #24292e; + text-decoration: none + } + .Box-row-link:hover { + color: #0366d6; + text-decoration: none + } +} + +.Box-row--drag-button { + opacity: 0 +} + +.Box-footer { + padding: 16px; + margin-top: -1px; + border-top: 1px #e1e4e8 solid +} + +.Box--scrollable { + max-height: 324px; + overflow: scroll +} + +.Box--blue { + border-color: #c8e1ff +} + +.Box--blue .Box-header { + background-color: #f1f8ff; + border-color: #c8e1ff +} + +.Box--blue .Box-body { + border-color: #c8e1ff +} + +.Box--blue .Box-row { + border-color: #c8e1ff +} + +.Box--blue .Box-footer { + border-color: #c8e1ff +} + +.Box--danger { + border-color: #d73a49 +} + +.Box--danger .Box-row:first-of-type { + border-color: #d73a49 +} + +.Box--danger .Box-body:last-of-type { + border-color: #d73a49 +} + +.Box-header--blue { + background-color: #f1f8ff; + border-color: #c8e1ff +} + +.Box-row--yellow { + background-color: #fffbdd +} + +.Box-row--blue { + background-color: #f1f8ff +} + +.Box-row--gray { + background-color: #f6f8fa +} + +.Box-btn-octicon.btn-octicon { + padding: 16px 16px; + margin: -16px -16px; + line-height: 1.5 +} + +.breadcrumb-item { + display: inline-block; + margin-left: -0.35em; + white-space: nowrap; + list-style: none +} + +.breadcrumb-item::after { + padding-right: .5em; + padding-left: .5em; + color: #e1e4e8; + content: "/" +} + +.breadcrumb-item:first-child { + margin-left: 0 +} + +.breadcrumb-item-selected, .breadcrumb-item[aria-current]:not([aria-current=false]) { + color: #586069 +} + +.breadcrumb-item-selected::after, .breadcrumb-item[aria-current]:not([aria-current=false])::after { + content: none +} + +.btn { + position: relative; + display: inline-block; + padding: 5px 16px; + font-size: 14px; + font-weight: 500; + line-height: 20px; + white-space: nowrap; + vertical-align: middle; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + border: 1px solid; + border-radius: 6px; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none +} + +.btn:hover { + text-decoration: none +} + +.btn:disabled, .btn.disabled, .btn[aria-disabled=true] { + cursor: default +} + +.btn:disabled .octicon, .btn.disabled .octicon, .btn[aria-disabled=true] .octicon { + color: inherit +} + +.btn i { + font-style: normal; + font-weight: 500; + opacity: 0.75 +} + +.btn .octicon { + margin-right: 4px; + color: #6a737d; + vertical-align: text-bottom +} + +.btn .octicon:only-child { + margin-right: 0 +} + +.btn .Counter { + margin-left: 2px; + color: inherit; + text-shadow: none; + vertical-align: top; + background-color: rgba(27, 31, 35, 0.08) +} + +.btn .dropdown-caret { + margin-left: 4px; + opacity: 0.8 +} + +.btn { + color: #24292e; + background-color: #fafbfc; + border-color: rgba(27, 31, 35, 0.15); + box-shadow: 0 1px 0 rgba(27, 31, 35, 0.04), inset 0 1px 0 rgba(255, 255, 255, 0.25); + transition: background-color 0.2s cubic-bezier(0.3, 0, 0.5, 1) +} + +.btn:hover, .btn.hover, [open]>.btn { + background-color: #f3f4f6; + transition-duration: 0.1s +} + +.btn:active, .btn.selected, .btn[aria-selected=true] { + background-color: #edeff2; + box-shadow: inset 0 1px 0 rgba(225, 228, 232, 0.2); + transition: none +} + +.btn:disabled, .btn.disabled, .btn[aria-disabled=true] { + color: #959da5; + background-color: #fafbfc; + border-color: rgba(27, 31, 35, 0.15) +} + +.btn:focus, .btn.focus { + outline: 1px dotted transparent; + outline-offset: 2px; + box-shadow: 0 0 0 3px rgba(3, 102, 214, 0.3) +} + +.btn-primary { + color: #fff; + background-color: #2ea44f; + border-color: rgba(27, 31, 35, 0.15); + box-shadow: 0 1px 0 rgba(27, 31, 35, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.03) +} + +.btn-primary:hover, .btn-primary.hover, [open]>.btn-primary { + background-color: #2c974b +} + +.btn-primary:active, .btn-primary.selected, .btn-primary[aria-selected=true] { + background-color: #2a8f47; + box-shadow: inset 0 1px 0 rgba(20, 70, 32, 0.2) +} + +.btn-primary:disabled, .btn-primary.disabled, .btn-primary[aria-disabled=true] { + color: rgba(255, 255, 255, 0.8); + background-color: #94d3a2; + border-color: rgba(27, 31, 35, 0.1); + box-shadow: 0 1px 0 rgba(27, 31, 35, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.03) +} + +.btn-primary:focus, .btn-primary.focus { + box-shadow: 0 0 0 3px rgba(46, 164, 79, 0.4) +} + +.btn-primary .Counter { + color: inherit; + background-color: rgba(255, 255, 255, 0.2) +} + +.btn-primary .octicon { + color: rgba(255, 255, 255, 0.8) +} + +.btn-danger { + color: #cb2431; + transition: none +} + +.btn-danger:hover, [open]>.btn-danger { + color: #fff; + background-color: #cb2431; + border-color: rgba(27, 31, 35, 0.15); + box-shadow: 0 1px 0 rgba(27, 31, 35, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.03) +} + +.btn-danger:hover .Counter, [open]>.btn-danger .Counter { + background-color: rgba(255, 255, 255, 0.2) +} + +.btn-danger:hover .octicon, [open]>.btn-danger .octicon { + color: inherit +} + +.btn-danger:active, .btn-danger.selected, .btn-danger[aria-selected=true] { + color: #fff; + background-color: #be222e; + border-color: rgba(27, 31, 35, 0.15); + box-shadow: inset 0 1px 0 rgba(134, 24, 29, 0.2) +} + +.btn-danger:disabled, .btn-danger.disabled, .btn-danger[aria-disabled=true] { + color: rgba(203, 36, 49, 0.5); + background-color: #fafbfc; + border-color: rgba(27, 31, 35, 0.15); + box-shadow: 0 1px 0 rgba(27, 31, 35, 0.04), inset 0 1px 0 rgba(255, 255, 255, 0.25) +} + +.btn-danger:disabled .Counter, .btn-danger.disabled .Counter, .btn-danger[aria-disabled=true] .Counter { + background-color: rgba(203, 36, 49, 0.05) +} + +.btn-danger:focus { + box-shadow: 0 0 0 3px rgba(203, 36, 49, 0.4) +} + +.btn-danger .Counter { + color: inherit; + background-color: rgba(203, 36, 49, 0.1) +} + +.btn-outline { + color: #0366d6; + transition: none +} + +.btn-outline:hover, [open]>.btn-outline { + color: #fff; + background-color: #0366d6; + border-color: rgba(27, 31, 35, 0.15); + box-shadow: 0 1px 0 rgba(27, 31, 35, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.03) +} + +.btn-outline:hover .Counter, [open]>.btn-outline .Counter { + background-color: rgba(255, 255, 255, 0.2) +} + +.btn-outline:hover .octicon, [open]>.btn-outline .octicon { + color: inherit +} + +.btn-outline:active, .btn-outline.selected, .btn-outline[aria-selected=true] { + color: #fff; + background-color: #035fc7; + border-color: rgba(27, 31, 35, 0.15); + box-shadow: inset 0 1px 0 rgba(5, 38, 76, 0.2) +} + +.btn-outline:disabled, .btn-outline.disabled, .btn-outline[aria-disabled=true] { + color: rgba(3, 102, 214, 0.5); + background-color: #fafbfc; + border-color: rgba(27, 31, 35, 0.15); + box-shadow: 0 1px 0 rgba(27, 31, 35, 0.04), inset 0 1px 0 rgba(255, 255, 255, 0.25) +} + +.btn-outline:disabled .Counter, .btn-outline.disabled .Counter, .btn-outline[aria-disabled=true] .Counter { + background-color: rgba(3, 102, 214, 0.05) +} + +.btn-outline:focus { + box-shadow: 0 0 0 3px rgba(3, 102, 214, 0.4) +} + +.btn-outline .Counter { + color: inherit; + background-color: rgba(3, 102, 214, 0.1) +} + +.btn-blue { + color: #fff; + background-color: #0361cc; + background-image: linear-gradient(-180deg, #0679fc 0%, #0361cc 90%) +} + +.btn-blue:focus, .btn-blue.focus { + box-shadow: 0 0 0 0.2em rgba(6, 121, 252, 0.4) +} + +.btn-blue:hover, .btn-blue.hover { + background-color: #035cc2; + background-image: linear-gradient(-180deg, #0374f4 0%, #035cc2 90%); + background-position: -.5em; + border-color: rgba(27, 31, 35, 0.5) +} + +.btn-blue:active, .btn-blue.selected, .btn-blue[aria-selected=true], [open]>.btn-blue { + background-color: #045cc1; + background-image: none; + border-color: rgba(27, 31, 35, 0.5); + box-shadow: inset 0 0.15em 0.3em rgba(27, 31, 35, 0.15) +} + +.btn-blue:disabled, .btn-blue.disabled, .btn-blue[aria-disabled=true] { + color: rgba(255, 255, 255, 0.75); + background-color: #81b0e5; + background-image: none; + border-color: rgba(27, 31, 35, 0.15); + box-shadow: none +} + +.btn-blue .Counter { + color: #0366d6; + background-color: #fff +} + +.btn-sm { + padding: 3px 12px; + font-size: 12px; + line-height: 20px +} + +.btn-sm .octicon { + vertical-align: text-top +} + +.btn-large { + padding: .75em 1.5em; + font-size: inherit; + line-height: 1.5; + border-radius: 0.5em +} + +.btn-block { + display: block; + width: 100%; + text-align: center +} + +.BtnGroup { + display: inline-block; + vertical-align: middle +} + +.BtnGroup::before { + display: table; + content: "" +} + +.BtnGroup::after { + display: table; + clear: both; + content: "" +} + +.BtnGroup+.BtnGroup, .BtnGroup+.btn { + margin-left: 4px +} + +.BtnGroup-item { + position: relative; + float: left; + border-right-width: 0; + border-radius: 0 +} + +.BtnGroup-item:first-child { + border-top-left-radius: 6px; + border-bottom-left-radius: 6px +} + +.BtnGroup-item:last-child { + border-right-width: 1px; + border-top-right-radius: 6px; + border-bottom-right-radius: 6px +} + +.BtnGroup-item.selected, .BtnGroup-item[aria-selected=true], .BtnGroup-item:focus, .BtnGroup-item:active, .BtnGroup-item:hover { + border-right-width: 1px +} + +.BtnGroup-item.selected+.BtnGroup-item, .BtnGroup-item.selected+.BtnGroup-parent .BtnGroup-item, .BtnGroup-item[aria-selected=true]+.BtnGroup-item, .BtnGroup-item[aria-selected=true]+.BtnGroup-parent .BtnGroup-item, .BtnGroup-item:focus+.BtnGroup-item, .BtnGroup-item:focus+.BtnGroup-parent .BtnGroup-item, .BtnGroup-item:active+.BtnGroup-item, .BtnGroup-item:active+.BtnGroup-parent .BtnGroup-item, .BtnGroup-item:hover+.BtnGroup-item, .BtnGroup-item:hover+.BtnGroup-parent .BtnGroup-item { + border-left-width: 0 +} + +.BtnGroup-parent { + float: left +} + +.BtnGroup-parent:first-child .BtnGroup-item { + border-top-left-radius: 6px; + border-bottom-left-radius: 6px +} + +.BtnGroup-parent:last-child .BtnGroup-item { + border-right-width: 1px; + border-top-right-radius: 6px; + border-bottom-right-radius: 6px +} + +.BtnGroup-parent .BtnGroup-item { + border-right-width: 0; + border-radius: 0 +} + +.BtnGroup-parent.selected .BtnGroup-item, .BtnGroup-parent[aria-selected=true] .BtnGroup-item, .BtnGroup-parent:focus .BtnGroup-item, .BtnGroup-parent:active .BtnGroup-item, .BtnGroup-parent:hover .BtnGroup-item { + border-right-width: 1px +} + +.BtnGroup-parent.selected+.BtnGroup-item, .BtnGroup-parent.selected+.BtnGroup-parent .BtnGroup-item, .BtnGroup-parent[aria-selected=true]+.BtnGroup-item, .BtnGroup-parent[aria-selected=true]+.BtnGroup-parent .BtnGroup-item, .BtnGroup-parent:focus+.BtnGroup-item, .BtnGroup-parent:focus+.BtnGroup-parent .BtnGroup-item, .BtnGroup-parent:active+.BtnGroup-item, .BtnGroup-parent:active+.BtnGroup-parent .BtnGroup-item, .BtnGroup-parent:hover+.BtnGroup-item, .BtnGroup-parent:hover+.BtnGroup-parent .BtnGroup-item { + border-left-width: 0 +} + +.BtnGroup-item:focus, .BtnGroup-item:active, .BtnGroup-parent:focus, .BtnGroup-parent:active { + z-index: 1 +} + +.btn-link { + display: inline-block; + padding: 0; + font-size: inherit; + color: #0366d6; + text-decoration: none; + white-space: nowrap; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + background-color: transparent; + border: 0; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none +} + +.btn-link:hover { + text-decoration: underline +} + +.btn-link:disabled, .btn-link:disabled:hover, .btn-link[aria-disabled=true], .btn-link[aria-disabled=true]:hover { + color: rgba(88, 96, 105, 0.5); + cursor: default +} + +.btn-invisible { + color: #0366d6; + background-color: transparent; + border: 0; + border-radius: 0; + box-shadow: none +} + +.btn-invisible:hover, .btn-invisible:active, .btn-invisible:focus, .btn-invisible.selected, .btn-invisible[aria-selected=true], .btn-invisible.zeroclipboard-is-hover, .btn-invisible.zeroclipboard-is-active { + color: #0366d6; + background: none; + outline: none; + box-shadow: none +} + +.btn-octicon { + display: inline-block; + padding: 5px; + margin-left: 5px; + line-height: 1; + color: #586069; + vertical-align: middle; + background: transparent; + border: 0 +} + +.btn-octicon:hover { + color: #0366d6 +} + +.btn-octicon.disabled, .btn-octicon[aria-disabled=true] { + color: #959da5; + cursor: default +} + +.btn-octicon.disabled:hover, .btn-octicon[aria-disabled=true]:hover { + color: #959da5 +} + +.btn-octicon-danger:hover { + color: #cb2431 +} + +.close-button { + padding: 0; + background: transparent; + border: 0; + outline: none +} + +.hidden-text-expander { + display: block +} + +.hidden-text-expander.inline { + position: relative; + top: -1px; + display: inline-block; + margin-left: 5px; + line-height: 0 +} + +.hidden-text-expander a, .ellipsis-expander { + display: inline-block; + height: 12px; + padding: 0 5px 5px; + font-size: 12px; + font-weight: 600; + line-height: 6px; + color: #444d56; + text-decoration: none; + vertical-align: middle; + background: #dfe2e5; + border: 0; + border-radius: 1px +} + +.hidden-text-expander a:hover, .ellipsis-expander:hover { + text-decoration: none; + background-color: #c6cbd1 +} + +.hidden-text-expander a:active, .ellipsis-expander:active { + color: #fff; + background-color: #2188ff +} + +.btn-with-count { + float: left; + border-top-right-radius: 0; + border-bottom-right-radius: 0 +} + +.btn-with-count:focus { + z-index: 1 +} + +.social-count { + position: relative; + float: left; + padding: 3px 12px; + font-size: 12px; + font-weight: 600; + line-height: 20px; + color: #24292e; + vertical-align: middle; + background-color: #fff; + border: 1px solid rgba(27, 31, 35, 0.15); + border-left: 0; + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; + box-shadow: 0 1px 0 rgba(27, 31, 35, 0.04), inset 0 1px 0 rgba(255, 255, 255, 0.25) +} + +.social-count:hover, .social-count:active { + text-decoration: none +} + +.social-count:hover { + color: #0366d6; + cursor: pointer +} + +.social-count:focus { + z-index: 1; + outline: 0; + box-shadow: 0 0 0 3px rgba(3, 102, 214, 0.3) +} + +.TableObject { + display: table +} + +.TableObject-item { + display: table-cell; + width: 1%; + white-space: nowrap; + vertical-align: middle +} + +.TableObject-item--primary { + width: 99% +} + +fieldset { + padding: 0; + margin: 0; + border: 0 +} + +label { + font-weight: 600 +} + +.form-control, .form-select { + padding: 5px 12px; + font-size: 14px; + line-height: 20px; + color: #24292e; + vertical-align: middle; + background-color: #fff; + background-repeat: no-repeat; + background-position: right 8px center; + border: 1px solid #e1e4e8; + border-radius: 6px; + outline: none; + box-shadow: inset 0 1px 0 rgba(225, 228, 232, 0.2) +} + +.form-control.focus, .form-control:focus, .form-select.focus, .form-select:focus { + border-color: #0366d6; + outline: none; + box-shadow: 0 0 0 3px rgba(3, 102, 214, 0.3) +} + +.form-control[disabled], .form-select[disabled] { + color: #959da5; + background-color: #f3f4f6 +} + +@supports (-webkit-touch-callout: none) { + .form-control, .form-select { + font-size: 16px + } + @media (min-width: 768px) { + .form-control, .form-select { + font-size: 14px + } + } +} + +textarea.form-control { + padding-top: 8px; + padding-bottom: 8px; + line-height: 1.5 +} + +.input-contrast { + background-color: #fafbfc +} + +.input-contrast:focus { + background-color: #fff +} + +.input-dark { + color: #fff; + background-color: rgba(255, 255, 255, 0.15); + border-color: transparent; + box-shadow: none +} + +.input-dark:-ms-input-placeholder { + color: inherit; + opacity: 0.6 +} + +.input-dark::-ms-input-placeholder { + color: inherit; + opacity: 0.6 +} + +.input-dark::placeholder { + color: inherit; + opacity: 0.6 +} + +.input-dark.focus, .input-dark:focus { + border-color: rgba(27, 31, 35, 0.3); + box-shadow: 0 0 0 0.2em rgba(121, 184, 255, 0.4) +} + +:-ms-input-placeholder { + color: #6a737d; + opacity: 1 +} + +::-ms-input-placeholder { + color: #6a737d; + opacity: 1 +} + +::placeholder { + color: #6a737d; + opacity: 1 +} + +.input-sm { + padding-top: 3px; + padding-bottom: 3px; + font-size: 12px; + line-height: 20px +} + +.input-lg { + font-size: 16px +} + +.input-block { + display: block; + width: 100% +} + +.input-monospace { + font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace +} + +.input-hide-webkit-autofill::-webkit-contacts-auto-fill-button { + position: absolute; + right: 0; + display: none !important; + pointer-events: none; + visibility: hidden +} + +.form-checkbox { + padding-left: 20px; + margin: 15px 0; + vertical-align: middle +} + +.form-checkbox label em.highlight { + position: relative; + left: -4px; + padding: 2px 4px; + font-style: normal; + background: #fffbdd; + border-radius: 6px +} + +.form-checkbox input[type=checkbox], .form-checkbox input[type=radio] { + float: left; + margin: 5px 0 0 -20px; + vertical-align: middle +} + +.form-checkbox .note { + display: block; + margin: 0; + font-size: 12px; + font-weight: 400; + color: #586069 +} + +.form-checkbox-details { + display: none +} + +.form-checkbox-details-trigger:checked~* .form-checkbox-details, .form-checkbox-details-trigger:checked~.form-checkbox-details { + display: block +} + +.hfields { + margin: 15px 0 +} + +.hfields::before { + display: table; + content: "" +} + +.hfields::after { + display: table; + clear: both; + content: "" +} + +.hfields .form-group { + float: left; + margin: 0 30px 0 0 +} + +.hfields .form-group dt label, .hfields .form-group .form-group-header label { + display: inline-block; + margin: 5px 0 0; + color: #586069 +} + +.hfields .form-group dt img, .hfields .form-group .form-group-header img { + position: relative; + top: -2px +} + +.hfields .btn { + float: left; + margin: 28px 25px 0 -20px +} + +.hfields .form-select { + margin-top: 5px +} + +input::-webkit-outer-spin-button, input::-webkit-inner-spin-button { + margin: 0; + -webkit-appearance: none; + appearance: none +} + +.form-actions::before { + display: table; + content: "" +} + +.form-actions::after { + display: table; + clear: both; + content: "" +} + +.form-actions .btn { + float: right +} + +.form-actions .btn+.btn { + margin-right: 5px +} + +.form-warning { + padding: 8px 10px; + margin: 10px 0; + font-size: 14px; + color: #735c0f; + background: #fffbdd; + border: 1px solid #f9c513; + border-radius: 6px +} + +.form-warning p { + margin: 0; + line-height: 1.5 +} + +.form-warning a { + font-weight: 600 +} + +.form-select { + display: inline-block; + max-width: 100%; + height: 32px; + padding-right: 24px; + background-color: #fff; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAUCAMAAACzvE1FAAAADFBMVEUzMzMzMzMzMzMzMzMKAG/3AAAAA3RSTlMAf4C/aSLHAAAAPElEQVR42q3NMQ4AIAgEQTn//2cLdRKppSGzBYwzVXvznNWs8C58CiussPJj8h6NwgorrKRdTvuV9v16Afn0AYFOB7aYAAAAAElFTkSuQmCC"); + background-repeat: no-repeat; + background-position: right 8px center; + background-size: 8px 10px; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none +} + +.form-select::-ms-expand { + opacity: 0 +} + +.form-select[multiple] { + height: auto +} + +.select-sm { + height: 28px; + padding-top: 3px; + padding-bottom: 3px; + font-size: 12px +} + +.select-sm[multiple] { + height: auto; + min-height: 0 +} + +.form-group { + margin: 15px 0 +} + +.form-group .form-control { + width: 440px; + max-width: 100%; + margin-right: 5px; + background-color: #fafbfc +} + +.form-group .form-control:focus { + background-color: #fff +} + +.form-group .form-control.shorter { + width: 130px +} + +.form-group .form-control.short { + width: 250px +} + +.form-group .form-control.long { + width: 100% +} + +.form-group textarea.form-control { + width: 100%; + height: 200px; + min-height: 200px +} + +.form-group textarea.form-control.short { + height: 50px; + min-height: 50px +} + +.form-group dt, .form-group .form-group-header { + margin: 0 0 6px +} + +.form-group label { + position: relative +} + +.form-group.flattened dt, .form-group.flattened .form-group-header { + float: left; + margin: 0; + line-height: 32px +} + +.form-group.flattened dd, .form-group.flattened .form-group-body { + line-height: 32px +} + +.form-group dd h4, .form-group .form-group-body h4 { + margin: 4px 0 0 +} + +.form-group dd h4.is-error, .form-group .form-group-body h4.is-error { + color: #cb2431 +} + +.form-group dd h4.is-success, .form-group .form-group-body h4.is-success { + color: #22863a +} + +.form-group dd h4+.note, .form-group .form-group-body h4+.note { + margin-top: 0 +} + +.form-group.required dt label::after, .form-group.required .form-group-header label::after { + padding-left: 5px; + color: #cb2431; + content: "*" +} + +.form-group .success, .form-group .error, .form-group .indicator { + display: none; + font-size: 12px; + font-weight: 600 +} + +.form-group.loading { + opacity: 0.5 +} + +.form-group.loading .indicator { + display: inline +} + +.form-group.loading .spinner { + display: inline-block; + vertical-align: middle +} + +.form-group.successful .success { + display: inline; + color: #22863a +} + +.form-group.successed .success, .form-group.successed .warning, .form-group.successed .error, .form-group.warn .success, .form-group.warn .warning, .form-group.warn .error, .form-group.errored .success, .form-group.errored .warning, .form-group.errored .error { + position: absolute; + z-index: 10; + display: block; + max-width: 450px; + padding: 4px 8px; + margin: 8px 0 0; + font-size: 12px; + font-weight: 400; + border-style: solid; + border-width: 1px; + border-radius: 6px +} + +.form-group.successed .success::after, .form-group.successed .success::before, .form-group.successed .warning::after, .form-group.successed .warning::before, .form-group.successed .error::after, .form-group.successed .error::before, .form-group.warn .success::after, .form-group.warn .success::before, .form-group.warn .warning::after, .form-group.warn .warning::before, .form-group.warn .error::after, .form-group.warn .error::before, .form-group.errored .success::after, .form-group.errored .success::before, .form-group.errored .warning::after, .form-group.errored .warning::before, .form-group.errored .error::after, .form-group.errored .error::before { + position: absolute; + bottom: 100%; + left: 10px; + z-index: 15; + width: 0; + height: 0; + pointer-events: none; + content: " "; + border: solid transparent +} + +.form-group.successed .success::after, .form-group.successed .warning::after, .form-group.successed .error::after, .form-group.warn .success::after, .form-group.warn .warning::after, .form-group.warn .error::after, .form-group.errored .success::after, .form-group.errored .warning::after, .form-group.errored .error::after { + border-width: 5px +} + +.form-group.successed .success::before, .form-group.successed .warning::before, .form-group.successed .error::before, .form-group.warn .success::before, .form-group.warn .warning::before, .form-group.warn .error::before, .form-group.errored .success::before, .form-group.errored .warning::before, .form-group.errored .error::before { + margin-left: -1px; + border-width: 6px +} + +.form-group.successed .success { + color: #144620; + background-color: #dcffe4; + border-color: #34d058 +} + +.form-group.successed .success::after { + border-bottom-color: #dcffe4 +} + +.form-group.successed .success::before { + border-bottom-color: #34d058 +} + +.form-group.warn .form-control { + border-color: #f9c513 +} + +.form-group.warn .warning { + background-color: #fff5b1; + border-color: #f9c513 +} + +.form-group.warn .warning::after { + border-bottom-color: #fff5b1 +} + +.form-group.warn .warning::before { + border-bottom-color: #f9c513 +} + +.form-group.errored .form-control { + border-color: #cb2431 +} + +.form-group.errored label { + color: #cb2431 +} + +.form-group.errored .error { + background-color: #ffeef0; + border-color: #f97583 +} + +.form-group.errored .error::after { + border-bottom-color: #ffeef0 +} + +.form-group.errored .error::before { + border-bottom-color: #f97583 +} + +.note { + min-height: 17px; + margin: 4px 0 2px; + font-size: 12px; + color: #586069 +} + +.note .spinner { + margin-right: 3px; + vertical-align: middle +} + +dl.form-group>dd .form-control.is-autocheck-loading, dl.form-group>dd .form-control.is-autocheck-successful, dl.form-group>dd .form-control.is-autocheck-errored, .form-group>.form-group-body .form-control.is-autocheck-loading, .form-group>.form-group-body .form-control.is-autocheck-successful, .form-group>.form-group-body .form-control.is-autocheck-errored { + padding-right: 30px +} + +dl.form-group>dd .form-control.is-autocheck-loading, .form-group>.form-group-body .form-control.is-autocheck-loading { + background-image: url("/images/spinners/octocat-spinner-16px.gif") +} + +dl.form-group>dd .form-control.is-autocheck-successful, .form-group>.form-group-body .form-control.is-autocheck-successful { + background-image: url("/images/modules/ajax/success.png") +} + +dl.form-group>dd .form-control.is-autocheck-errored, .form-group>.form-group-body .form-control.is-autocheck-errored { + background-image: url("/images/modules/ajax/error.png") +} + +@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-moz-min-device-pixel-ratio: 2), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { + dl.form-group>dd .form-control.is-autocheck-loading, dl.form-group>dd .form-control.is-autocheck-successful, dl.form-group>dd .form-control.is-autocheck-errored, .form-group>.form-group-body .form-control.is-autocheck-loading, .form-group>.form-group-body .form-control.is-autocheck-successful, .form-group>.form-group-body .form-control.is-autocheck-errored { + background-size: 16px 16px + } + dl.form-group>dd .form-control.is-autocheck-loading, .form-group>.form-group-body .form-control.is-autocheck-loading { + background-image: url("/images/spinners/octocat-spinner-32.gif") + } + dl.form-group>dd .form-control.is-autocheck-successful, .form-group>.form-group-body .form-control.is-autocheck-successful { + background-image: url("/images/modules/ajax/success@2x.png") + } + dl.form-group>dd .form-control.is-autocheck-errored, .form-group>.form-group-body .form-control.is-autocheck-errored { + background-image: url("/images/modules/ajax/error@2x.png") + } +} + +.status-indicator { + display: inline-block; + width: 16px; + height: 16px; + margin-left: 5px +} + +.status-indicator .octicon { + display: none +} + +.status-indicator-success::before { + content: "" +} + +.status-indicator-success .octicon-check { + display: inline-block; + color: #28a745; + fill: #28a745 +} + +.status-indicator-success .octicon-x { + display: none +} + +.status-indicator-failed::before { + content: "" +} + +.status-indicator-failed .octicon-check { + display: none +} + +.status-indicator-failed .octicon-x { + display: inline-block; + color: #cb2431; + fill: #d73a49 +} + +.status-indicator-loading { + width: 16px; + background-image: url("/images/spinners/octocat-spinner-32-EAF2F5.gif"); + background-repeat: no-repeat; + background-position: 0 0; + background-size: 16px +} + +.inline-form { + display: inline-block +} + +.inline-form .btn-plain { + background-color: transparent; + border: 0 +} + +.drag-and-drop { + padding: 7px 10px; + margin: 0; + font-size: 13px; + line-height: 16px; + color: #586069; + background-color: #fafbfc; + border: 1px solid #c3c8cf; + border-top: 0; + border-bottom-right-radius: 6px; + border-bottom-left-radius: 6px +} + +.drag-and-drop .default, .drag-and-drop .loading, .drag-and-drop .error { + display: none +} + +.drag-and-drop .error { + color: #cb2431 +} + +.drag-and-drop img { + vertical-align: top +} + +.is-default .drag-and-drop .default { + display: inline-block +} + +.is-uploading .drag-and-drop .loading { + display: inline-block +} + +.is-bad-file .drag-and-drop .bad-file { + display: inline-block +} + +.is-duplicate-filename .drag-and-drop .duplicate-filename { + display: inline-block +} + +.is-too-big .drag-and-drop .too-big { + display: inline-block +} + +.is-hidden-file .drag-and-drop .hidden-file { + display: inline-block +} + +.is-empty .drag-and-drop .empty { + display: inline-block +} + +.is-bad-permissions .drag-and-drop .bad-permissions { + display: inline-block +} + +.is-repository-required .drag-and-drop .repository-required { + display: inline-block +} + +.drag-and-drop-error-info { + font-weight: 400; + color: #586069 +} + +.drag-and-drop-error-info a { + color: #0366d6 +} + +.is-failed .drag-and-drop .failed-request { + display: inline-block +} + +.manual-file-chooser { + position: absolute; + width: 240px; + padding: 5px; + margin-left: -80px; + cursor: pointer; + opacity: 0.0001 +} + +.manual-file-chooser:hover+.manual-file-chooser-text { + text-decoration: underline +} + +.btn .manual-file-chooser { + top: 0; + padding: 0; + line-height: 34px +} + +.upload-enabled textarea { + display: block; + border-bottom: 1px dashed #dfe2e5; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0 +} + +.upload-enabled.focused { + border-radius: 6px; + box-shadow: inset 0 1px 2px rgba(27, 31, 35, 0.075), 0 0 0 0.2em rgba(3, 102, 214, 0.3) +} + +.upload-enabled.focused .form-control { + box-shadow: none +} + +.upload-enabled.focused .drag-and-drop { + border-color: #4a9eff +} + +.dragover textarea, .dragover .drag-and-drop { + box-shadow: #c9ff00 0 0 3px +} + +.write-content { + position: relative +} + +.previewable-comment-form { + position: relative +} + +.previewable-comment-form .tabnav { + position: relative; + padding: 8px 8px 0 +} + +.previewable-comment-form .comment { + border: 1px solid #c3c8cf +} + +.previewable-comment-form .comment-form-error { + margin-bottom: 8px +} + +.previewable-comment-form .write-content, .previewable-comment-form .preview-content { + display: none; + margin: 0 8px 8px +} + +.previewable-comment-form.write-selected .write-content, .previewable-comment-form.preview-selected .preview-content { + display: block +} + +.previewable-comment-form textarea { + display: block; + width: 100%; + min-height: 100px; + max-height: 500px; + padding: 8px; + resize: vertical +} + +.form-action-spacious { + margin-top: 10px +} + +div.composer { + margin-top: 0; + border: 0 +} + +.composer .comment-form-textarea { + height: 200px; + min-height: 200px +} + +.composer .tabnav { + margin: 0 0 10px +} + +h2.account { + margin: 15px 0 0; + font-size: 18px; + font-weight: 400; + color: #586069 +} + +p.explain { + position: relative; + font-size: 12px; + color: #586069 +} + +p.explain strong { + color: #24292e +} + +p.explain .octicon { + margin-right: 5px; + color: #959da5 +} + +p.explain .minibutton { + top: -4px; + float: right +} + +.form-group label { + position: static +} + +.input-group { + display: table +} + +.input-group .form-control { + position: relative; + width: 100% +} + +.input-group .form-control:focus { + z-index: 2 +} + +.input-group .form-control+.btn { + margin-left: 0 +} + +.input-group.inline { + display: inline-table +} + +.input-group .form-control, .input-group-button { + display: table-cell +} + +.input-group-button { + width: 1%; + vertical-align: middle +} + +.input-group .form-control:first-child, .input-group-button:first-child .btn { + border-top-right-radius: 0; + border-bottom-right-radius: 0 +} + +.input-group-button:first-child .btn { + margin-right: -1px +} + +.input-group .form-control:last-child, .input-group-button:last-child .btn { + border-top-left-radius: 0; + border-bottom-left-radius: 0 +} + +.input-group-button:last-child .btn { + margin-left: -1px +} + +.radio-group::before { + display: table; + content: "" +} + +.radio-group::after { + display: table; + clear: both; + content: "" +} + +.radio-label { + float: left; + padding: 6px 16px 6px 36px; + margin-left: -1px; + font-size: 14px; + line-height: 20px; + color: #24292e; + cursor: pointer; + border: 1px solid #e1e4e8 +} + +:checked+.radio-label { + position: relative; + z-index: 1; + border-color: #0366d6 +} + +.radio-label:first-of-type { + margin-left: 0; + border-top-left-radius: 6px; + border-bottom-left-radius: 6px +} + +.radio-label:last-of-type { + border-top-right-radius: 6px; + border-bottom-right-radius: 6px +} + +.radio-input { + z-index: 3; + float: left; + margin: 10px -32px 0 16px +} + +.container-sm { + max-width: 544px; + margin-right: auto; + margin-left: auto +} + +.container-md { + max-width: 768px; + margin-right: auto; + margin-left: auto +} + +.container-lg { + max-width: 1012px; + margin-right: auto; + margin-left: auto +} + +.container-xl { + max-width: 1280px; + margin-right: auto; + margin-left: auto +} + +.col-1 { + width: 8.33333% +} + +.col-2 { + width: 16.66667% +} + +.col-3 { + width: 25% +} + +.col-4 { + width: 33.33333% +} + +.col-5 { + width: 41.66667% +} + +.col-6 { + width: 50% +} + +.col-7 { + width: 58.33333% +} + +.col-8 { + width: 66.66667% +} + +.col-9 { + width: 75% +} + +.col-10 { + width: 83.33333% +} + +.col-11 { + width: 91.66667% +} + +.col-12 { + width: 100% +} + +@media (min-width: 544px) { + .col-sm-1 { + width: 8.33333% + } + .col-sm-2 { + width: 16.66667% + } + .col-sm-3 { + width: 25% + } + .col-sm-4 { + width: 33.33333% + } + .col-sm-5 { + width: 41.66667% + } + .col-sm-6 { + width: 50% + } + .col-sm-7 { + width: 58.33333% + } + .col-sm-8 { + width: 66.66667% + } + .col-sm-9 { + width: 75% + } + .col-sm-10 { + width: 83.33333% + } + .col-sm-11 { + width: 91.66667% + } + .col-sm-12 { + width: 100% + } +} + +@media (min-width: 768px) { + .col-md-1 { + width: 8.33333% + } + .col-md-2 { + width: 16.66667% + } + .col-md-3 { + width: 25% + } + .col-md-4 { + width: 33.33333% + } + .col-md-5 { + width: 41.66667% + } + .col-md-6 { + width: 50% + } + .col-md-7 { + width: 58.33333% + } + .col-md-8 { + width: 66.66667% + } + .col-md-9 { + width: 75% + } + .col-md-10 { + width: 83.33333% + } + .col-md-11 { + width: 91.66667% + } + .col-md-12 { + width: 100% + } +} + +@media (min-width: 1012px) { + .col-lg-1 { + width: 8.33333% + } + .col-lg-2 { + width: 16.66667% + } + .col-lg-3 { + width: 25% + } + .col-lg-4 { + width: 33.33333% + } + .col-lg-5 { + width: 41.66667% + } + .col-lg-6 { + width: 50% + } + .col-lg-7 { + width: 58.33333% + } + .col-lg-8 { + width: 66.66667% + } + .col-lg-9 { + width: 75% + } + .col-lg-10 { + width: 83.33333% + } + .col-lg-11 { + width: 91.66667% + } + .col-lg-12 { + width: 100% + } +} + +@media (min-width: 1280px) { + .col-xl-1 { + width: 8.33333% + } + .col-xl-2 { + width: 16.66667% + } + .col-xl-3 { + width: 25% + } + .col-xl-4 { + width: 33.33333% + } + .col-xl-5 { + width: 41.66667% + } + .col-xl-6 { + width: 50% + } + .col-xl-7 { + width: 58.33333% + } + .col-xl-8 { + width: 66.66667% + } + .col-xl-9 { + width: 75% + } + .col-xl-10 { + width: 83.33333% + } + .col-xl-11 { + width: 91.66667% + } + .col-xl-12 { + width: 100% + } +} + +.gutter { + margin-right: -16px; + margin-left: -16px +} + +.gutter>[class*="col-"] { + padding-right: 16px !important; + padding-left: 16px !important +} + +.gutter-condensed { + margin-right: -8px; + margin-left: -8px +} + +.gutter-condensed>[class*="col-"] { + padding-right: 8px !important; + padding-left: 8px !important +} + +.gutter-spacious { + margin-right: -24px; + margin-left: -24px +} + +.gutter-spacious>[class*="col-"] { + padding-right: 24px !important; + padding-left: 24px !important +} + +@media (min-width: 544px) { + .gutter-sm { + margin-right: -16px; + margin-left: -16px + } + .gutter-sm>[class*="col-"] { + padding-right: 16px !important; + padding-left: 16px !important + } + .gutter-sm-condensed { + margin-right: -8px; + margin-left: -8px + } + .gutter-sm-condensed>[class*="col-"] { + padding-right: 8px !important; + padding-left: 8px !important + } + .gutter-sm-spacious { + margin-right: -24px; + margin-left: -24px + } + .gutter-sm-spacious>[class*="col-"] { + padding-right: 24px !important; + padding-left: 24px !important + } +} + +@media (min-width: 768px) { + .gutter-md { + margin-right: -16px; + margin-left: -16px + } + .gutter-md>[class*="col-"] { + padding-right: 16px !important; + padding-left: 16px !important + } + .gutter-md-condensed { + margin-right: -8px; + margin-left: -8px + } + .gutter-md-condensed>[class*="col-"] { + padding-right: 8px !important; + padding-left: 8px !important + } + .gutter-md-spacious { + margin-right: -24px; + margin-left: -24px + } + .gutter-md-spacious>[class*="col-"] { + padding-right: 24px !important; + padding-left: 24px !important + } +} + +@media (min-width: 1012px) { + .gutter-lg { + margin-right: -16px; + margin-left: -16px + } + .gutter-lg>[class*="col-"] { + padding-right: 16px !important; + padding-left: 16px !important + } + .gutter-lg-condensed { + margin-right: -8px; + margin-left: -8px + } + .gutter-lg-condensed>[class*="col-"] { + padding-right: 8px !important; + padding-left: 8px !important + } + .gutter-lg-spacious { + margin-right: -24px; + margin-left: -24px + } + .gutter-lg-spacious>[class*="col-"] { + padding-right: 24px !important; + padding-left: 24px !important + } +} + +@media (min-width: 1280px) { + .gutter-xl { + margin-right: -16px; + margin-left: -16px + } + .gutter-xl>[class*="col-"] { + padding-right: 16px !important; + padding-left: 16px !important + } + .gutter-xl-condensed { + margin-right: -8px; + margin-left: -8px + } + .gutter-xl-condensed>[class*="col-"] { + padding-right: 8px !important; + padding-left: 8px !important + } + .gutter-xl-spacious { + margin-right: -24px; + margin-left: -24px + } + .gutter-xl-spacious>[class*="col-"] { + padding-right: 24px !important; + padding-left: 24px !important + } +} + +.offset-1 { + margin-left: 8.33333% !important +} + +.offset-2 { + margin-left: 16.66667% !important +} + +.offset-3 { + margin-left: 25% !important +} + +.offset-4 { + margin-left: 33.33333% !important +} + +.offset-5 { + margin-left: 41.66667% !important +} + +.offset-6 { + margin-left: 50% !important +} + +.offset-7 { + margin-left: 58.33333% !important +} + +.offset-8 { + margin-left: 66.66667% !important +} + +.offset-9 { + margin-left: 75% !important +} + +.offset-10 { + margin-left: 83.33333% !important +} + +.offset-11 { + margin-left: 91.66667% !important +} + +@media (min-width: 544px) { + .offset-sm-1 { + margin-left: 8.33333% !important + } + .offset-sm-2 { + margin-left: 16.66667% !important + } + .offset-sm-3 { + margin-left: 25% !important + } + .offset-sm-4 { + margin-left: 33.33333% !important + } + .offset-sm-5 { + margin-left: 41.66667% !important + } + .offset-sm-6 { + margin-left: 50% !important + } + .offset-sm-7 { + margin-left: 58.33333% !important + } + .offset-sm-8 { + margin-left: 66.66667% !important + } + .offset-sm-9 { + margin-left: 75% !important + } + .offset-sm-10 { + margin-left: 83.33333% !important + } + .offset-sm-11 { + margin-left: 91.66667% !important + } +} + +@media (min-width: 768px) { + .offset-md-1 { + margin-left: 8.33333% !important + } + .offset-md-2 { + margin-left: 16.66667% !important + } + .offset-md-3 { + margin-left: 25% !important + } + .offset-md-4 { + margin-left: 33.33333% !important + } + .offset-md-5 { + margin-left: 41.66667% !important + } + .offset-md-6 { + margin-left: 50% !important + } + .offset-md-7 { + margin-left: 58.33333% !important + } + .offset-md-8 { + margin-left: 66.66667% !important + } + .offset-md-9 { + margin-left: 75% !important + } + .offset-md-10 { + margin-left: 83.33333% !important + } + .offset-md-11 { + margin-left: 91.66667% !important + } +} + +@media (min-width: 1012px) { + .offset-lg-1 { + margin-left: 8.33333% !important + } + .offset-lg-2 { + margin-left: 16.66667% !important + } + .offset-lg-3 { + margin-left: 25% !important + } + .offset-lg-4 { + margin-left: 33.33333% !important + } + .offset-lg-5 { + margin-left: 41.66667% !important + } + .offset-lg-6 { + margin-left: 50% !important + } + .offset-lg-7 { + margin-left: 58.33333% !important + } + .offset-lg-8 { + margin-left: 66.66667% !important + } + .offset-lg-9 { + margin-left: 75% !important + } + .offset-lg-10 { + margin-left: 83.33333% !important + } + .offset-lg-11 { + margin-left: 91.66667% !important + } +} + +@media (min-width: 1280px) { + .offset-xl-1 { + margin-left: 8.33333% !important + } + .offset-xl-2 { + margin-left: 16.66667% !important + } + .offset-xl-3 { + margin-left: 25% !important + } + .offset-xl-4 { + margin-left: 33.33333% !important + } + .offset-xl-5 { + margin-left: 41.66667% !important + } + .offset-xl-6 { + margin-left: 50% !important + } + .offset-xl-7 { + margin-left: 58.33333% !important + } + .offset-xl-8 { + margin-left: 66.66667% !important + } + .offset-xl-9 { + margin-left: 75% !important + } + .offset-xl-10 { + margin-left: 83.33333% !important + } + .offset-xl-11 { + margin-left: 91.66667% !important + } +} + +.menu { + margin-bottom: 16px; + list-style: none; + background-color: #fff; + border: 1px #e1e4e8 solid; + border-radius: 6px +} + +.menu-item { + position: relative; + display: block; + padding: 8px 16px; + color: #1b1f23; + border-bottom: 1px solid #eaecef +} + +.menu-item:first-child { + border-top: 0; + border-top-left-radius: 6px; + border-top-right-radius: 6px +} + +.menu-item:first-child::before { + border-top-left-radius: 6px +} + +.menu-item:last-child { + border-bottom: 0; + border-bottom-right-radius: 6px; + border-bottom-left-radius: 6px +} + +.menu-item:last-child::before { + border-bottom-left-radius: 6px +} + +.menu-item:focus, .menu-item:hover { + text-decoration: none; + background-color: #f6f8fa; + outline: none +} + +.menu-item:active { + background-color: #fafbfc +} + +.menu-item.selected, .menu-item[aria-selected=true], .menu-item[aria-current]:not([aria-current=false]) { + cursor: default +} + +.menu-item.selected::before, .menu-item[aria-selected=true]::before, .menu-item[aria-current]:not([aria-current=false])::before { + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 2px; + content: ""; + background-color: #f9826c +} + +.menu-item .octicon { + width: 16px; + margin-right: 8px; + color: #959da5; + text-align: center +} + +.menu-item .Counter { + float: right; + margin-left: 4px +} + +.menu-item .menu-warning { + float: right; + color: #86181d +} + +.menu-item .avatar { + float: left; + margin-right: 4px +} + +.menu-item.alert .Counter { + color: #cb2431 +} + +.menu-heading { + display: block; + padding: 8px 16px; + margin-top: 0; + margin-bottom: 0; + font-size: inherit; + font-weight: 600; + color: #1b1f23; + border-bottom: 1px solid #eaecef +} + +.menu-heading:hover { + text-decoration: none +} + +.menu-heading:first-child { + border-top-left-radius: 6px; + border-top-right-radius: 6px +} + +.menu-heading:last-child { + border-bottom: 0; + border-bottom-right-radius: 6px; + border-bottom-left-radius: 6px +} + +.tabnav { + margin-top: 0; + margin-bottom: 16px; + border-bottom: 1px #e1e4e8 solid +} + +.tabnav-tabs { + display: flex; + margin-bottom: -1px; + overflow: auto +} + +.tabnav-tab { + display: inline-block; + flex-shrink: 0; + padding: 8px 16px; + font-size: 14px; + line-height: 23px; + color: #24292e; + text-decoration: none; + background-color: transparent; + border: 1px solid transparent; + border-bottom: 0 +} + +.tabnav-tab.selected, .tabnav-tab[aria-selected=true], .tabnav-tab[aria-current]:not([aria-current=false]) { + background-color: #fff; + border-color: #e1e4e8; + border-radius: 6px 6px 0 0 +} + +.tabnav-tab:hover, .tabnav-tab:focus { + color: #586069; + text-decoration: none +} + +.tabnav-tab:active { + color: #6a737d +} + +.tabnav-tab .octicon { + margin-right: 4px; + color: #959da5 +} + +.tabnav-tab .Counter { + margin-left: 4px +} + +.tabnav-extra { + display: inline-block; + padding-top: 10px; + margin-left: 10px; + font-size: 12px; + color: #586069 +} + +.tabnav-extra>.octicon { + margin-right: 2px +} + +a.tabnav-extra:hover { + color: #0366d6; + text-decoration: none +} + +.tabnav-btn { + margin-left: 8px +} + +.filter-list { + list-style-type: none +} + +.filter-list.small .filter-item { + padding: 6px 12px; + font-size: 12px +} + +.filter-list.pjax-active .filter-item { + color: #586069; + background-color: transparent +} + +.filter-list.pjax-active .filter-item.pjax-active { + color: #fff; + background-color: #0366d6 +} + +.filter-item { + position: relative; + display: block; + padding: 8px 16px; + margin-bottom: 4px; + overflow: hidden; + font-size: 14px; + color: #586069; + text-decoration: none; + text-overflow: ellipsis; + white-space: nowrap; + cursor: pointer; + border-radius: 6px +} + +.filter-item:hover { + text-decoration: none; + background-color: #f6f8fa +} + +.filter-item.selected, .filter-item[aria-selected=true], .filter-item[aria-current]:not([aria-current=false]) { + color: #fff; + background-color: #0366d6 +} + +.filter-item .count { + float: right; + font-weight: 600 +} + +.filter-item .bar { + position: absolute; + top: 2px; + right: 0; + bottom: 2px; + z-index: -1; + display: inline-block; + background-color: #eff3f6 +} + +.SideNav { + background-color: #fafbfc +} + +.SideNav-item { + position: relative; + display: block; + width: 100%; + padding: 12px 16px; + color: #1b1f23; + text-align: left; + background-color: transparent; + border: 0; + border-top: 1px solid #eaecef +} + +.SideNav-item:first-child { + border-top: 0 +} + +.SideNav-item:last-child { + box-shadow: 0 1px 0 #e1e4e8 +} + +.SideNav-item::before { + position: absolute; + top: 0; + bottom: 0; + left: 0; + z-index: 1; + width: 2px; + pointer-events: none; + content: "" +} + +.SideNav-item:hover, .SideNav-item:focus { + text-decoration: none; + background-color: #f6f8fa; + outline: none +} + +.SideNav-item:active { + background-color: #fafbfc +} + +.SideNav-item[aria-current]:not([aria-current=false]), .SideNav-item[aria-selected="true"] { + background-color: #fff +} + +.SideNav-item[aria-current]:not([aria-current=false])::before, .SideNav-item[aria-selected="true"]::before { + background-color: #f9826c +} + +.SideNav-icon { + width: 16px; + margin-right: 8px; + color: #6a737d +} + +.SideNav-subItem { + position: relative; + display: block; + width: 100%; + padding: 4px 0; + color: #0366d6; + text-align: left; + background-color: transparent; + border: 0 +} + +.SideNav-subItem:hover, .SideNav-subItem:focus { + color: #24292e; + text-decoration: none; + outline: none +} + +.SideNav-subItem[aria-current]:not([aria-current=false]), .SideNav-subItem[aria-selected="true"] { + font-weight: 500; + color: #24292e +} + +.subnav { + margin-bottom: 20px +} + +.subnav::before { + display: table; + content: "" +} + +.subnav::after { + display: table; + clear: both; + content: "" +} + +.subnav-bordered { + padding-bottom: 20px; + border-bottom: 1px solid #eaecef +} + +.subnav-flush { + margin-bottom: 0 +} + +.subnav-item { + position: relative; + float: left; + padding: 5px 16px; + font-weight: 500; + line-height: 20px; + color: #24292e; + border: 1px #e1e4e8 solid +} + +.subnav-item+.subnav-item { + margin-left: -1px +} + +.subnav-item:hover, .subnav-item:focus { + text-decoration: none; + background-color: #f6f8fa +} + +.subnav-item.selected, .subnav-item[aria-selected=true], .subnav-item[aria-current]:not([aria-current=false]) { + z-index: 2; + color: #fff; + background-color: #0366d6; + border-color: #005cc5 +} + +.subnav-item:first-child { + border-top-left-radius: 6px; + border-bottom-left-radius: 6px +} + +.subnav-item:last-child { + border-top-right-radius: 6px; + border-bottom-right-radius: 6px +} + +.subnav-search { + position: relative; + margin-left: 12px +} + +.subnav-search-input { + width: 320px; + padding-left: 32px; + color: #586069 +} + +.subnav-search-input-wide { + width: 500px +} + +.subnav-search-icon { + position: absolute; + top: 9px; + left: 8px; + display: block; + color: #959da5; + text-align: center; + pointer-events: none +} + +.subnav-search-context .btn { + color: #444d56; + border-top-right-radius: 0; + border-bottom-right-radius: 0 +} + +.subnav-search-context .btn:hover, .subnav-search-context .btn:focus, .subnav-search-context .btn:active, .subnav-search-context .btn.selected { + z-index: 2 +} + +.subnav-search-context+.subnav-search { + margin-left: -1px +} + +.subnav-search-context+.subnav-search .subnav-search-input { + border-top-left-radius: 0; + border-bottom-left-radius: 0 +} + +.subnav-search-context .select-menu-modal-holder { + z-index: 30 +} + +.subnav-search-context .select-menu-modal { + width: 220px +} + +.subnav-search-context .select-menu-item-icon { + color: inherit +} + +.subnav-spacer-right { + padding-right: 12px +} + +.UnderlineNav { + display: flex; + overflow-x: auto; + overflow-y: hidden; + box-shadow: inset 0 -1px 0 #e1e4e8; + justify-content: space-between +} + +.UnderlineNav-body { + display: flex +} + +.UnderlineNav-item { + padding: 8px 16px; + font-size: 14px; + line-height: 30px; + color: #1b1f23; + text-align: center; + white-space: nowrap; + background-color: transparent; + border: 0; + border-bottom: 2px solid rgba(209, 213, 218, 0); + transition: border-bottom-color 0.36s ease-in +} + +.UnderlineNav-item:hover, .UnderlineNav-item:focus { + text-decoration: none; + border-bottom-color: #d1d5da; + outline: 1px dotted transparent; + outline-offset: -1px; + transition-timing-function: ease-out; + transition-duration: 0.12s +} + +.UnderlineNav-item.selected, .UnderlineNav-item[role=tab][aria-selected=true], .UnderlineNav-item[aria-current]:not([aria-current=false]) { + font-weight: 600; + border-bottom-color: #f9826c; + outline: 1px dotted transparent; + outline-offset: -1px +} + +.UnderlineNav-item.selected .UnderlineNav-octicon, .UnderlineNav-item[role=tab][aria-selected=true] .UnderlineNav-octicon, .UnderlineNav-item[aria-current]:not([aria-current=false]) .UnderlineNav-octicon { + color: #586069 +} + +.UnderlineNav--right { + justify-content: flex-end +} + +.UnderlineNav--right .UnderlineNav-actions { + flex: 1 1 auto +} + +.UnderlineNav-actions { + align-self: center +} + +.UnderlineNav--full { + display: block +} + +.UnderlineNav-octicon { + margin-right: 4px; + color: #959da5 +} + +.UnderlineNav .Counter { + margin-left: 4px +} + +.UnderlineNav-container { + display: flex; + justify-content: space-between +} + +.pagination a, .pagination span, .pagination em { + display: inline-block; + min-width: 32px; + padding: 5px 10px; + font-style: normal; + line-height: 20px; + color: #24292e; + text-align: center; + white-space: nowrap; + vertical-align: middle; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + border: 1px solid transparent; + border-radius: 6px; + transition: border-color 0.2s cubic-bezier(0.3, 0, 0.5, 1) +} + +.pagination a:hover, .pagination a:focus, .pagination span:hover, .pagination span:focus, .pagination em:hover, .pagination em:focus { + text-decoration: none; + border-color: #e1e4e8; + outline: 0; + transition-duration: 0.1s +} + +.pagination a:active, .pagination span:active, .pagination em:active { + border-color: #eaecef; + transition: none +} + +.pagination .previous_page, .pagination .next_page { + color: #0366d6 +} + +.pagination .current, .pagination .current:hover, .pagination [aria-current]:not([aria-current=false]) { + color: #fff; + background-color: #0366d6; + border-color: transparent +} + +.pagination .gap, .pagination .disabled, .pagination [aria-disabled=true], .pagination .gap:hover, .pagination .disabled:hover, .pagination [aria-disabled=true]:hover { + color: #6a737d; + cursor: default; + border-color: transparent +} + +@supports ((-webkit-clip-path: polygon(50% 0, 100% 50%, 50% 100%)) or (clip-path: polygon(50% 0, 100% 50%, 50% 100%))) { + .pagination .previous_page::before, .pagination .next_page::after { + display: inline-block; + width: 16px; + height: 16px; + vertical-align: text-bottom; + content: ""; + background-color: currentColor + } + .pagination .previous_page::before { + margin-right: 4px; + -webkit-clip-path: polygon(9.8px 12.8px, 8.7px 12.8px, 4.5px 8.5px, 4.5px 7.5px, 8.7px 3.2px, 9.8px 4.3px, 6.1px 8px, 9.8px 11.7px, 9.8px 12.8px); + clip-path: polygon(9.8px 12.8px, 8.7px 12.8px, 4.5px 8.5px, 4.5px 7.5px, 8.7px 3.2px, 9.8px 4.3px, 6.1px 8px, 9.8px 11.7px, 9.8px 12.8px) + } + .pagination .next_page::after { + margin-left: 4px; + -webkit-clip-path: polygon(6.2px 3.2px, 7.3px 3.2px, 11.5px 7.5px, 11.5px 8.5px, 7.3px 12.8px, 6.2px 11.7px, 9.9px 8px, 6.2px 4.3px, 6.2px 3.2px); + clip-path: polygon(6.2px 3.2px, 7.3px 3.2px, 11.5px 7.5px, 11.5px 8.5px, 7.3px 12.8px, 6.2px 11.7px, 9.9px 8px, 6.2px 4.3px, 6.2px 3.2px) + } +} + +.paginate-container { + margin-top: 16px; + margin-bottom: 16px; + text-align: center +} + +.paginate-container .pagination { + display: inline-block +} + +.tooltipped { + position: relative +} + +.tooltipped::after { + position: absolute; + z-index: 1000000; + display: none; + padding: .5em .75em; + font: normal normal 11px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; + -webkit-font-smoothing: subpixel-antialiased; + color: #fff; + text-align: center; + text-decoration: none; + text-shadow: none; + text-transform: none; + letter-spacing: normal; + word-wrap: break-word; + white-space: pre; + pointer-events: none; + content: attr(aria-label); + background: #1b1f23; + border-radius: 6px; + opacity: 0 +} + +.tooltipped::before { + position: absolute; + z-index: 1000001; + display: none; + width: 0; + height: 0; + color: #1b1f23; + pointer-events: none; + content: ""; + border: 6px solid transparent; + opacity: 0 +} + +@keyframes tooltip-appear { + from { + opacity: 0 + } + to { + opacity: 1 + } +} + +.tooltipped:hover::before, .tooltipped:hover::after, .tooltipped:active::before, .tooltipped:active::after, .tooltipped:focus::before, .tooltipped:focus::after { + display: inline-block; + text-decoration: none; + animation-name: tooltip-appear; + animation-duration: .1s; + animation-fill-mode: forwards; + animation-timing-function: ease-in; + animation-delay: .4s +} + +.tooltipped-no-delay:hover::before, .tooltipped-no-delay:hover::after, .tooltipped-no-delay:active::before, .tooltipped-no-delay:active::after, .tooltipped-no-delay:focus::before, .tooltipped-no-delay:focus::after { + animation-delay: 0s +} + +.tooltipped-multiline:hover::after, .tooltipped-multiline:active::after, .tooltipped-multiline:focus::after { + display: table-cell +} + +.tooltipped-s::after, .tooltipped-se::after, .tooltipped-sw::after { + top: 100%; + right: 50%; + margin-top: 6px +} + +.tooltipped-s::before, .tooltipped-se::before, .tooltipped-sw::before { + top: auto; + right: 50%; + bottom: -7px; + margin-right: -6px; + border-bottom-color: #1b1f23 +} + +.tooltipped-se::after { + right: auto; + left: 50%; + margin-left: -16px +} + +.tooltipped-sw::after { + margin-right: -16px +} + +.tooltipped-n::after, .tooltipped-ne::after, .tooltipped-nw::after { + right: 50%; + bottom: 100%; + margin-bottom: 6px +} + +.tooltipped-n::before, .tooltipped-ne::before, .tooltipped-nw::before { + top: -7px; + right: 50%; + bottom: auto; + margin-right: -6px; + border-top-color: #1b1f23 +} + +.tooltipped-ne::after { + right: auto; + left: 50%; + margin-left: -16px +} + +.tooltipped-nw::after { + margin-right: -16px +} + +.tooltipped-s::after, .tooltipped-n::after { + transform: translateX(50%) +} + +.tooltipped-w::after { + right: 100%; + bottom: 50%; + margin-right: 6px; + transform: translateY(50%) +} + +.tooltipped-w::before { + top: 50%; + bottom: 50%; + left: -7px; + margin-top: -6px; + border-left-color: #1b1f23 +} + +.tooltipped-e::after { + bottom: 50%; + left: 100%; + margin-left: 6px; + transform: translateY(50%) +} + +.tooltipped-e::before { + top: 50%; + right: -7px; + bottom: 50%; + margin-top: -6px; + border-right-color: #1b1f23 +} + +.tooltipped-align-right-1::after, .tooltipped-align-right-2::after { + right: 0; + margin-right: 0 +} + +.tooltipped-align-right-1::before { + right: 10px +} + +.tooltipped-align-right-2::before { + right: 15px +} + +.tooltipped-align-left-1::after, .tooltipped-align-left-2::after { + left: 0; + margin-left: 0 +} + +.tooltipped-align-left-1::before { + left: 5px +} + +.tooltipped-align-left-2::before { + left: 10px +} + +.tooltipped-multiline::after { + width: -webkit-max-content; + width: -moz-max-content; + width: max-content; + max-width: 250px; + word-wrap: break-word; + white-space: pre-line; + border-collapse: separate +} + +.tooltipped-multiline.tooltipped-s::after, .tooltipped-multiline.tooltipped-n::after { + right: auto; + left: 50%; + transform: translateX(-50%) +} + +.tooltipped-multiline.tooltipped-w::after, .tooltipped-multiline.tooltipped-e::after { + right: 100% +} + +@media screen and (min-width: 0\0) { + .tooltipped-multiline::after { + width: 250px + } +} + +.tooltipped-sticky::before, .tooltipped-sticky::after { + display: inline-block +} + +.tooltipped-sticky.tooltipped-multiline::after { + display: table-cell +} + +.css-truncate.css-truncate-overflow, .css-truncate .css-truncate-overflow, .css-truncate.css-truncate-target, .css-truncate .css-truncate-target { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap +} + +.css-truncate.css-truncate-target, .css-truncate .css-truncate-target { + display: inline-block; + max-width: 125px; + vertical-align: top +} + +.css-truncate.expandable.zeroclipboard-is-hover .css-truncate-target, .css-truncate.expandable.zeroclipboard-is-hover.css-truncate-target, .css-truncate.expandable:hover .css-truncate-target, .css-truncate.expandable:hover.css-truncate-target { + max-width: 10000px !important +} + +.anim-fade-in { + animation-name: fade-in; + animation-duration: 1s; + animation-timing-function: ease-in-out +} + +.anim-fade-in.fast { + animation-duration: 300ms +} + +@keyframes fade-in { + 0% { + opacity: 0 + } + 100% { + opacity: 1 + } +} + +.anim-fade-out { + animation-name: fade-out; + animation-duration: 1s; + animation-timing-function: ease-out +} + +.anim-fade-out.fast { + animation-duration: 0.3s +} + +@keyframes fade-out { + 0% { + opacity: 1 + } + 100% { + opacity: 0 + } +} + +.anim-fade-up { + opacity: 0; + animation-name: fade-up; + animation-duration: 0.3s; + animation-fill-mode: forwards; + animation-timing-function: ease-out; + animation-delay: 1s +} + +@keyframes fade-up { + 0% { + opacity: 0.8; + transform: translateY(100%) + } + 100% { + opacity: 1; + transform: translateY(0) + } +} + +.anim-fade-down { + animation-name: fade-down; + animation-duration: 0.3s; + animation-fill-mode: forwards; + animation-timing-function: ease-in +} + +@keyframes fade-down { + 0% { + opacity: 1; + transform: translateY(0) + } + 100% { + opacity: 0.5; + transform: translateY(100%) + } +} + +.anim-grow-x { + width: 0%; + animation-name: grow-x; + animation-duration: 0.3s; + animation-fill-mode: forwards; + animation-timing-function: ease; + animation-delay: 0.5s +} + +@keyframes grow-x { + to { + width: 100% + } +} + +.anim-shrink-x { + animation-name: shrink-x; + animation-duration: 0.3s; + animation-fill-mode: forwards; + animation-timing-function: ease-in-out; + animation-delay: 0.5s +} + +@keyframes shrink-x { + to { + width: 0% + } +} + +.anim-scale-in { + animation-name: scale-in; + animation-duration: 0.15s; + animation-timing-function: cubic-bezier(0.2, 0, 0.13, 1.5) +} + +@keyframes scale-in { + 0% { + opacity: 0; + transform: scale(0.5) + } + 100% { + opacity: 1; + transform: scale(1) + } +} + +.anim-pulse { + animation-name: pulse; + animation-duration: 2s; + animation-timing-function: linear; + animation-iteration-count: infinite +} + +@keyframes pulse { + 0% { + opacity: 0.3 + } + 10% { + opacity: 1 + } + 100% { + opacity: 0.3 + } +} + +.anim-pulse-in { + animation-name: pulse-in; + animation-duration: 0.5s +} + +@keyframes pulse-in { + 0% { + transform: scale3d(1, 1, 1) + } + 50% { + transform: scale3d(1.1, 1.1, 1.1) + } + 100% { + transform: scale3d(1, 1, 1) + } +} + +.hover-grow { + transition: transform 0.3s; + -webkit-backface-visibility: hidden; + backface-visibility: hidden +} + +.hover-grow:hover { + transform: scale(1.025) +} + +.border-x { + border-right: 1px #e1e4e8 solid !important; + border-left: 1px #e1e4e8 solid !important +} + +.border-y { + border-top: 1px #e1e4e8 solid !important; + border-bottom: 1px #e1e4e8 solid !important +} + +.border { + border: 1px #e1e4e8 solid !important +} + +.border-0 { + border: 0 !important +} + +.border-top { + border-top: 1px #e1e4e8 solid !important +} + +.border-right { + border-right: 1px #e1e4e8 solid !important +} + +.border-bottom { + border-bottom: 1px #e1e4e8 solid !important +} + +.border-left { + border-left: 1px #e1e4e8 solid !important +} + +.border-top-0 { + border-top: 0 !important +} + +.border-right-0 { + border-right: 0 !important +} + +.border-bottom-0 { + border-bottom: 0 !important +} + +.border-left-0 { + border-left: 0 !important +} + +.rounded { + border-radius: 6px !important +} + +.rounded-0 { + border-radius: 0 !important +} + +.rounded-1 { + border-radius: 4px !important +} + +.rounded-2 { + border-radius: 6px !important +} + +.rounded-3 { + border-radius: 8px !important +} + +.rounded-top-0 { + border-top-left-radius: 0 !important; + border-top-right-radius: 0 !important +} + +.rounded-top-1 { + border-top-left-radius: 4px !important; + border-top-right-radius: 4px !important +} + +.rounded-top-2 { + border-top-left-radius: 6px !important; + border-top-right-radius: 6px !important +} + +.rounded-top-3 { + border-top-left-radius: 8px !important; + border-top-right-radius: 8px !important +} + +.rounded-right-0 { + border-top-right-radius: 0 !important; + border-bottom-right-radius: 0 !important +} + +.rounded-right-1 { + border-top-right-radius: 4px !important; + border-bottom-right-radius: 4px !important +} + +.rounded-right-2 { + border-top-right-radius: 6px !important; + border-bottom-right-radius: 6px !important +} + +.rounded-right-3 { + border-top-right-radius: 8px !important; + border-bottom-right-radius: 8px !important +} + +.rounded-bottom-0 { + border-bottom-right-radius: 0 !important; + border-bottom-left-radius: 0 !important +} + +.rounded-bottom-1 { + border-bottom-right-radius: 4px !important; + border-bottom-left-radius: 4px !important +} + +.rounded-bottom-2 { + border-bottom-right-radius: 6px !important; + border-bottom-left-radius: 6px !important +} + +.rounded-bottom-3 { + border-bottom-right-radius: 8px !important; + border-bottom-left-radius: 8px !important +} + +.rounded-left-0 { + border-bottom-left-radius: 0 !important; + border-top-left-radius: 0 !important +} + +.rounded-left-1 { + border-bottom-left-radius: 4px !important; + border-top-left-radius: 4px !important +} + +.rounded-left-2 { + border-bottom-left-radius: 6px !important; + border-top-left-radius: 6px !important +} + +.rounded-left-3 { + border-bottom-left-radius: 8px !important; + border-top-left-radius: 8px !important +} + +@media (min-width: 544px) { + .border-sm { + border: 1px #e1e4e8 solid !important + } + .border-sm-0 { + border: 0 !important + } + .border-sm-top { + border-top: 1px #e1e4e8 solid !important + } + .border-sm-right { + border-right: 1px #e1e4e8 solid !important + } + .border-sm-bottom { + border-bottom: 1px #e1e4e8 solid !important + } + .border-sm-left { + border-left: 1px #e1e4e8 solid !important + } + .border-sm-top-0 { + border-top: 0 !important + } + .border-sm-right-0 { + border-right: 0 !important + } + .border-sm-bottom-0 { + border-bottom: 0 !important + } + .border-sm-left-0 { + border-left: 0 !important + } + .rounded-sm { + border-radius: 6px !important + } + .rounded-sm-0 { + border-radius: 0 !important + } + .rounded-sm-1 { + border-radius: 4px !important + } + .rounded-sm-2 { + border-radius: 6px !important + } + .rounded-sm-3 { + border-radius: 8px !important + } + .rounded-sm-top-0 { + border-top-left-radius: 0 !important; + border-top-right-radius: 0 !important + } + .rounded-sm-top-1 { + border-top-left-radius: 4px !important; + border-top-right-radius: 4px !important + } + .rounded-sm-top-2 { + border-top-left-radius: 6px !important; + border-top-right-radius: 6px !important + } + .rounded-sm-top-3 { + border-top-left-radius: 8px !important; + border-top-right-radius: 8px !important + } + .rounded-sm-right-0 { + border-top-right-radius: 0 !important; + border-bottom-right-radius: 0 !important + } + .rounded-sm-right-1 { + border-top-right-radius: 4px !important; + border-bottom-right-radius: 4px !important + } + .rounded-sm-right-2 { + border-top-right-radius: 6px !important; + border-bottom-right-radius: 6px !important + } + .rounded-sm-right-3 { + border-top-right-radius: 8px !important; + border-bottom-right-radius: 8px !important + } + .rounded-sm-bottom-0 { + border-bottom-right-radius: 0 !important; + border-bottom-left-radius: 0 !important + } + .rounded-sm-bottom-1 { + border-bottom-right-radius: 4px !important; + border-bottom-left-radius: 4px !important + } + .rounded-sm-bottom-2 { + border-bottom-right-radius: 6px !important; + border-bottom-left-radius: 6px !important + } + .rounded-sm-bottom-3 { + border-bottom-right-radius: 8px !important; + border-bottom-left-radius: 8px !important + } + .rounded-sm-left-0 { + border-bottom-left-radius: 0 !important; + border-top-left-radius: 0 !important + } + .rounded-sm-left-1 { + border-bottom-left-radius: 4px !important; + border-top-left-radius: 4px !important + } + .rounded-sm-left-2 { + border-bottom-left-radius: 6px !important; + border-top-left-radius: 6px !important + } + .rounded-sm-left-3 { + border-bottom-left-radius: 8px !important; + border-top-left-radius: 8px !important + } +} + +@media (min-width: 768px) { + .border-md { + border: 1px #e1e4e8 solid !important + } + .border-md-0 { + border: 0 !important + } + .border-md-top { + border-top: 1px #e1e4e8 solid !important + } + .border-md-right { + border-right: 1px #e1e4e8 solid !important + } + .border-md-bottom { + border-bottom: 1px #e1e4e8 solid !important + } + .border-md-left { + border-left: 1px #e1e4e8 solid !important + } + .border-md-top-0 { + border-top: 0 !important + } + .border-md-right-0 { + border-right: 0 !important + } + .border-md-bottom-0 { + border-bottom: 0 !important + } + .border-md-left-0 { + border-left: 0 !important + } + .rounded-md { + border-radius: 6px !important + } + .rounded-md-0 { + border-radius: 0 !important + } + .rounded-md-1 { + border-radius: 4px !important + } + .rounded-md-2 { + border-radius: 6px !important + } + .rounded-md-3 { + border-radius: 8px !important + } + .rounded-md-top-0 { + border-top-left-radius: 0 !important; + border-top-right-radius: 0 !important + } + .rounded-md-top-1 { + border-top-left-radius: 4px !important; + border-top-right-radius: 4px !important + } + .rounded-md-top-2 { + border-top-left-radius: 6px !important; + border-top-right-radius: 6px !important + } + .rounded-md-top-3 { + border-top-left-radius: 8px !important; + border-top-right-radius: 8px !important + } + .rounded-md-right-0 { + border-top-right-radius: 0 !important; + border-bottom-right-radius: 0 !important + } + .rounded-md-right-1 { + border-top-right-radius: 4px !important; + border-bottom-right-radius: 4px !important + } + .rounded-md-right-2 { + border-top-right-radius: 6px !important; + border-bottom-right-radius: 6px !important + } + .rounded-md-right-3 { + border-top-right-radius: 8px !important; + border-bottom-right-radius: 8px !important + } + .rounded-md-bottom-0 { + border-bottom-right-radius: 0 !important; + border-bottom-left-radius: 0 !important + } + .rounded-md-bottom-1 { + border-bottom-right-radius: 4px !important; + border-bottom-left-radius: 4px !important + } + .rounded-md-bottom-2 { + border-bottom-right-radius: 6px !important; + border-bottom-left-radius: 6px !important + } + .rounded-md-bottom-3 { + border-bottom-right-radius: 8px !important; + border-bottom-left-radius: 8px !important + } + .rounded-md-left-0 { + border-bottom-left-radius: 0 !important; + border-top-left-radius: 0 !important + } + .rounded-md-left-1 { + border-bottom-left-radius: 4px !important; + border-top-left-radius: 4px !important + } + .rounded-md-left-2 { + border-bottom-left-radius: 6px !important; + border-top-left-radius: 6px !important + } + .rounded-md-left-3 { + border-bottom-left-radius: 8px !important; + border-top-left-radius: 8px !important + } +} + +@media (min-width: 1012px) { + .border-lg { + border: 1px #e1e4e8 solid !important + } + .border-lg-0 { + border: 0 !important + } + .border-lg-top { + border-top: 1px #e1e4e8 solid !important + } + .border-lg-right { + border-right: 1px #e1e4e8 solid !important + } + .border-lg-bottom { + border-bottom: 1px #e1e4e8 solid !important + } + .border-lg-left { + border-left: 1px #e1e4e8 solid !important + } + .border-lg-top-0 { + border-top: 0 !important + } + .border-lg-right-0 { + border-right: 0 !important + } + .border-lg-bottom-0 { + border-bottom: 0 !important + } + .border-lg-left-0 { + border-left: 0 !important + } + .rounded-lg { + border-radius: 6px !important + } + .rounded-lg-0 { + border-radius: 0 !important + } + .rounded-lg-1 { + border-radius: 4px !important + } + .rounded-lg-2 { + border-radius: 6px !important + } + .rounded-lg-3 { + border-radius: 8px !important + } + .rounded-lg-top-0 { + border-top-left-radius: 0 !important; + border-top-right-radius: 0 !important + } + .rounded-lg-top-1 { + border-top-left-radius: 4px !important; + border-top-right-radius: 4px !important + } + .rounded-lg-top-2 { + border-top-left-radius: 6px !important; + border-top-right-radius: 6px !important + } + .rounded-lg-top-3 { + border-top-left-radius: 8px !important; + border-top-right-radius: 8px !important + } + .rounded-lg-right-0 { + border-top-right-radius: 0 !important; + border-bottom-right-radius: 0 !important + } + .rounded-lg-right-1 { + border-top-right-radius: 4px !important; + border-bottom-right-radius: 4px !important + } + .rounded-lg-right-2 { + border-top-right-radius: 6px !important; + border-bottom-right-radius: 6px !important + } + .rounded-lg-right-3 { + border-top-right-radius: 8px !important; + border-bottom-right-radius: 8px !important + } + .rounded-lg-bottom-0 { + border-bottom-right-radius: 0 !important; + border-bottom-left-radius: 0 !important + } + .rounded-lg-bottom-1 { + border-bottom-right-radius: 4px !important; + border-bottom-left-radius: 4px !important + } + .rounded-lg-bottom-2 { + border-bottom-right-radius: 6px !important; + border-bottom-left-radius: 6px !important + } + .rounded-lg-bottom-3 { + border-bottom-right-radius: 8px !important; + border-bottom-left-radius: 8px !important + } + .rounded-lg-left-0 { + border-bottom-left-radius: 0 !important; + border-top-left-radius: 0 !important + } + .rounded-lg-left-1 { + border-bottom-left-radius: 4px !important; + border-top-left-radius: 4px !important + } + .rounded-lg-left-2 { + border-bottom-left-radius: 6px !important; + border-top-left-radius: 6px !important + } + .rounded-lg-left-3 { + border-bottom-left-radius: 8px !important; + border-top-left-radius: 8px !important + } +} + +@media (min-width: 1280px) { + .border-xl { + border: 1px #e1e4e8 solid !important + } + .border-xl-0 { + border: 0 !important + } + .border-xl-top { + border-top: 1px #e1e4e8 solid !important + } + .border-xl-right { + border-right: 1px #e1e4e8 solid !important + } + .border-xl-bottom { + border-bottom: 1px #e1e4e8 solid !important + } + .border-xl-left { + border-left: 1px #e1e4e8 solid !important + } + .border-xl-top-0 { + border-top: 0 !important + } + .border-xl-right-0 { + border-right: 0 !important + } + .border-xl-bottom-0 { + border-bottom: 0 !important + } + .border-xl-left-0 { + border-left: 0 !important + } + .rounded-xl { + border-radius: 6px !important + } + .rounded-xl-0 { + border-radius: 0 !important + } + .rounded-xl-1 { + border-radius: 4px !important + } + .rounded-xl-2 { + border-radius: 6px !important + } + .rounded-xl-3 { + border-radius: 8px !important + } + .rounded-xl-top-0 { + border-top-left-radius: 0 !important; + border-top-right-radius: 0 !important + } + .rounded-xl-top-1 { + border-top-left-radius: 4px !important; + border-top-right-radius: 4px !important + } + .rounded-xl-top-2 { + border-top-left-radius: 6px !important; + border-top-right-radius: 6px !important + } + .rounded-xl-top-3 { + border-top-left-radius: 8px !important; + border-top-right-radius: 8px !important + } + .rounded-xl-right-0 { + border-top-right-radius: 0 !important; + border-bottom-right-radius: 0 !important + } + .rounded-xl-right-1 { + border-top-right-radius: 4px !important; + border-bottom-right-radius: 4px !important + } + .rounded-xl-right-2 { + border-top-right-radius: 6px !important; + border-bottom-right-radius: 6px !important + } + .rounded-xl-right-3 { + border-top-right-radius: 8px !important; + border-bottom-right-radius: 8px !important + } + .rounded-xl-bottom-0 { + border-bottom-right-radius: 0 !important; + border-bottom-left-radius: 0 !important + } + .rounded-xl-bottom-1 { + border-bottom-right-radius: 4px !important; + border-bottom-left-radius: 4px !important + } + .rounded-xl-bottom-2 { + border-bottom-right-radius: 6px !important; + border-bottom-left-radius: 6px !important + } + .rounded-xl-bottom-3 { + border-bottom-right-radius: 8px !important; + border-bottom-left-radius: 8px !important + } + .rounded-xl-left-0 { + border-bottom-left-radius: 0 !important; + border-top-left-radius: 0 !important + } + .rounded-xl-left-1 { + border-bottom-left-radius: 4px !important; + border-top-left-radius: 4px !important + } + .rounded-xl-left-2 { + border-bottom-left-radius: 6px !important; + border-top-left-radius: 6px !important + } + .rounded-xl-left-3 { + border-bottom-left-radius: 8px !important; + border-top-left-radius: 8px !important + } +} + +.circle { + border-radius: 50% !important +} + +.border-dashed { + border-style: dashed !important +} + +.border-blue { + border-color: #0366d6 !important +} + +.border-blue-light { + border-color: #c8e1ff !important +} + +.border-green { + border-color: #34d058 !important +} + +.border-green-light { + border-color: #a2cbac !important +} + +.border-red { + border-color: #d73a49 !important +} + +.border-red-light { + border-color: #f97583 !important +} + +.border-purple { + border-color: #6f42c1 !important +} + +.border-yellow { + border-color: #f9c513 !important +} + +.border-gray-light { + border-color: #eaecef !important +} + +.border-gray-dark { + border-color: #d1d5da !important +} + +.border-black-fade { + border-color: rgba(27, 31, 35, 0.15) !important +} + +.border-white-fade { + border-color: rgba(255, 255, 255, 0.15) !important +} + +.border-white-fade-15 { + border-color: rgba(255, 255, 255, 0.15) !important +} + +.border-white-fade-30 { + border-color: rgba(255, 255, 255, 0.3) !important +} + +.border-white-fade-50 { + border-color: rgba(255, 255, 255, 0.5) !important +} + +.border-white-fade-70 { + border-color: rgba(255, 255, 255, 0.7) !important +} + +.border-white-fade-85 { + border-color: rgba(255, 255, 255, 0.85) !important +} + +.box-shadow { + box-shadow: 0 1px 0 rgba(27, 31, 35, 0.04) !important +} + +.box-shadow-medium { + box-shadow: 0 3px 6px rgba(149, 157, 165, 0.15) !important +} + +.box-shadow-large { + box-shadow: 0 8px 24px rgba(149, 157, 165, 0.2) !important +} + +.box-shadow-extra-large { + box-shadow: 0 12px 48px rgba(149, 157, 165, 0.3) !important +} + +.box-shadow-none { + box-shadow: none !important +} + +.bg-white { + background-color: #fff !important +} + +.bg-blue { + background-color: #0366d6 !important +} + +.bg-blue-light { + background-color: #f1f8ff !important +} + +.bg-gray-dark { + background-color: #24292e !important +} + +.bg-gray { + background-color: #f6f8fa !important +} + +.bg-gray-light { + background-color: #fafbfc !important +} + +.bg-green { + background-color: #28a745 !important +} + +.bg-green-light { + background-color: #dcffe4 !important +} + +.bg-red { + background-color: #d73a49 !important +} + +.bg-red-light { + background-color: #ffeef0 !important +} + +.bg-yellow { + background-color: #ffd33d !important +} + +.bg-yellow-light { + background-color: #fff5b1 !important +} + +.bg-yellow-dark { + background-color: #dbab09 !important +} + +.bg-purple { + background-color: #6f42c1 !important +} + +.bg-pink { + background-color: #ea4aaa !important +} + +.bg-purple-light { + background-color: #f5f0ff !important +} + +.bg-orange { + background-color: #d15704 !important +} + +.color-gray-0 { + color: #fafbfc !important +} + +.bg-gray-0 { + background-color: #fafbfc !important +} + +.color-gray-1 { + color: #f6f8fa !important +} + +.bg-gray-1 { + background-color: #f6f8fa !important +} + +.color-gray-2 { + color: #e1e4e8 !important +} + +.bg-gray-2 { + background-color: #e1e4e8 !important +} + +.color-gray-3 { + color: #d1d5da !important +} + +.bg-gray-3 { + background-color: #d1d5da !important +} + +.color-gray-4 { + color: #959da5 !important +} + +.bg-gray-4 { + background-color: #959da5 !important +} + +.color-gray-5 { + color: #6a737d !important +} + +.bg-gray-5 { + background-color: #6a737d !important +} + +.color-gray-6 { + color: #586069 !important +} + +.bg-gray-6 { + background-color: #586069 !important +} + +.color-gray-7 { + color: #444d56 !important +} + +.bg-gray-7 { + background-color: #444d56 !important +} + +.color-gray-8 { + color: #2f363d !important +} + +.bg-gray-8 { + background-color: #2f363d !important +} + +.color-gray-9 { + color: #24292e !important +} + +.bg-gray-9 { + background-color: #24292e !important +} + +.color-blue-0 { + color: #f1f8ff !important +} + +.bg-blue-0 { + background-color: #f1f8ff !important +} + +.color-blue-1 { + color: #dbedff !important +} + +.bg-blue-1 { + background-color: #dbedff !important +} + +.color-blue-2 { + color: #c8e1ff !important +} + +.bg-blue-2 { + background-color: #c8e1ff !important +} + +.color-blue-3 { + color: #79b8ff !important +} + +.bg-blue-3 { + background-color: #79b8ff !important +} + +.color-blue-4 { + color: #2188ff !important +} + +.bg-blue-4 { + background-color: #2188ff !important +} + +.color-blue-5 { + color: #0366d6 !important +} + +.bg-blue-5 { + background-color: #0366d6 !important +} + +.color-blue-6 { + color: #005cc5 !important +} + +.bg-blue-6 { + background-color: #005cc5 !important +} + +.color-blue-7 { + color: #044289 !important +} + +.bg-blue-7 { + background-color: #044289 !important +} + +.color-blue-8 { + color: #032f62 !important +} + +.bg-blue-8 { + background-color: #032f62 !important +} + +.color-blue-9 { + color: #05264c !important +} + +.bg-blue-9 { + background-color: #05264c !important +} + +.color-green-0 { + color: #f0fff4 !important +} + +.bg-green-0 { + background-color: #f0fff4 !important +} + +.color-green-1 { + color: #dcffe4 !important +} + +.bg-green-1 { + background-color: #dcffe4 !important +} + +.color-green-2 { + color: #bef5cb !important +} + +.bg-green-2 { + background-color: #bef5cb !important +} + +.color-green-3 { + color: #85e89d !important +} + +.bg-green-3 { + background-color: #85e89d !important +} + +.color-green-4 { + color: #34d058 !important +} + +.bg-green-4 { + background-color: #34d058 !important +} + +.color-green-5 { + color: #28a745 !important +} + +.bg-green-5 { + background-color: #28a745 !important +} + +.color-green-6 { + color: #22863a !important +} + +.bg-green-6 { + background-color: #22863a !important +} + +.color-green-7 { + color: #176f2c !important +} + +.bg-green-7 { + background-color: #176f2c !important +} + +.color-green-8 { + color: #165c26 !important +} + +.bg-green-8 { + background-color: #165c26 !important +} + +.color-green-9 { + color: #144620 !important +} + +.bg-green-9 { + background-color: #144620 !important +} + +.color-yellow-0 { + color: #fffdef !important +} + +.bg-yellow-0 { + background-color: #fffdef !important +} + +.color-yellow-1 { + color: #fffbdd !important +} + +.bg-yellow-1 { + background-color: #fffbdd !important +} + +.color-yellow-2 { + color: #fff5b1 !important +} + +.bg-yellow-2 { + background-color: #fff5b1 !important +} + +.color-yellow-3 { + color: #ffea7f !important +} + +.bg-yellow-3 { + background-color: #ffea7f !important +} + +.color-yellow-4 { + color: #ffdf5d !important +} + +.bg-yellow-4 { + background-color: #ffdf5d !important +} + +.color-yellow-5 { + color: #ffd33d !important +} + +.bg-yellow-5 { + background-color: #ffd33d !important +} + +.color-yellow-6 { + color: #f9c513 !important +} + +.bg-yellow-6 { + background-color: #f9c513 !important +} + +.color-yellow-7 { + color: #dbab09 !important +} + +.bg-yellow-7 { + background-color: #dbab09 !important +} + +.color-yellow-8 { + color: #b08800 !important +} + +.bg-yellow-8 { + background-color: #b08800 !important +} + +.color-yellow-9 { + color: #735c0f !important +} + +.bg-yellow-9 { + background-color: #735c0f !important +} + +.color-orange-0 { + color: #fff8f2 !important +} + +.bg-orange-0 { + background-color: #fff8f2 !important +} + +.color-orange-1 { + color: #ffebda !important +} + +.bg-orange-1 { + background-color: #ffebda !important +} + +.color-orange-2 { + color: #ffd1ac !important +} + +.bg-orange-2 { + background-color: #ffd1ac !important +} + +.color-orange-3 { + color: #ffab70 !important +} + +.bg-orange-3 { + background-color: #ffab70 !important +} + +.color-orange-4 { + color: #fb8532 !important +} + +.bg-orange-4 { + background-color: #fb8532 !important +} + +.color-orange-5 { + color: #f66a0a !important +} + +.bg-orange-5 { + background-color: #f66a0a !important +} + +.color-orange-6 { + color: #e36209 !important +} + +.bg-orange-6 { + background-color: #e36209 !important +} + +.color-orange-7 { + color: #d15704 !important +} + +.bg-orange-7 { + background-color: #d15704 !important +} + +.color-orange-8 { + color: #c24e00 !important +} + +.bg-orange-8 { + background-color: #c24e00 !important +} + +.color-orange-9 { + color: #a04100 !important +} + +.bg-orange-9 { + background-color: #a04100 !important +} + +.color-red-0 { + color: #ffeef0 !important +} + +.bg-red-0 { + background-color: #ffeef0 !important +} + +.color-red-1 { + color: #ffdce0 !important +} + +.bg-red-1 { + background-color: #ffdce0 !important +} + +.color-red-2 { + color: #fdaeb7 !important +} + +.bg-red-2 { + background-color: #fdaeb7 !important +} + +.color-red-3 { + color: #f97583 !important +} + +.bg-red-3 { + background-color: #f97583 !important +} + +.color-red-4 { + color: #ea4a5a !important +} + +.bg-red-4 { + background-color: #ea4a5a !important +} + +.color-red-5 { + color: #d73a49 !important +} + +.bg-red-5 { + background-color: #d73a49 !important +} + +.color-red-6 { + color: #cb2431 !important +} + +.bg-red-6 { + background-color: #cb2431 !important +} + +.color-red-7 { + color: #b31d28 !important +} + +.bg-red-7 { + background-color: #b31d28 !important +} + +.color-red-8 { + color: #9e1c23 !important +} + +.bg-red-8 { + background-color: #9e1c23 !important +} + +.color-red-9 { + color: #86181d !important +} + +.bg-red-9 { + background-color: #86181d !important +} + +.color-purple-0 { + color: #f5f0ff !important +} + +.bg-purple-0 { + background-color: #f5f0ff !important +} + +.color-purple-1 { + color: #e6dcfd !important +} + +.bg-purple-1 { + background-color: #e6dcfd !important +} + +.color-purple-2 { + color: #d1bcf9 !important +} + +.bg-purple-2 { + background-color: #d1bcf9 !important +} + +.color-purple-3 { + color: #b392f0 !important +} + +.bg-purple-3 { + background-color: #b392f0 !important +} + +.color-purple-4 { + color: #8a63d2 !important +} + +.bg-purple-4 { + background-color: #8a63d2 !important +} + +.color-purple-5 { + color: #6f42c1 !important +} + +.bg-purple-5 { + background-color: #6f42c1 !important +} + +.color-purple-6 { + color: #5a32a3 !important +} + +.bg-purple-6 { + background-color: #5a32a3 !important +} + +.color-purple-7 { + color: #4c2889 !important +} + +.bg-purple-7 { + background-color: #4c2889 !important +} + +.color-purple-8 { + color: #3a1d6e !important +} + +.bg-purple-8 { + background-color: #3a1d6e !important +} + +.color-purple-9 { + color: #29134e !important +} + +.bg-purple-9 { + background-color: #29134e !important +} + +.color-pink-0 { + color: #ffeef8 !important +} + +.bg-pink-0 { + background-color: #ffeef8 !important +} + +.color-pink-1 { + color: #fedbf0 !important +} + +.bg-pink-1 { + background-color: #fedbf0 !important +} + +.color-pink-2 { + color: #f9b3dd !important +} + +.bg-pink-2 { + background-color: #f9b3dd !important +} + +.color-pink-3 { + color: #f692ce !important +} + +.bg-pink-3 { + background-color: #f692ce !important +} + +.color-pink-4 { + color: #ec6cb9 !important +} + +.bg-pink-4 { + background-color: #ec6cb9 !important +} + +.color-pink-5 { + color: #ea4aaa !important +} + +.bg-pink-5 { + background-color: #ea4aaa !important +} + +.color-pink-6 { + color: #d03592 !important +} + +.bg-pink-6 { + background-color: #d03592 !important +} + +.color-pink-7 { + color: #b93a86 !important +} + +.bg-pink-7 { + background-color: #b93a86 !important +} + +.color-pink-8 { + color: #99306f !important +} + +.bg-pink-8 { + background-color: #99306f !important +} + +.color-pink-9 { + color: #6d224f !important +} + +.bg-pink-9 { + background-color: #6d224f !important +} + +.bg-shade-gradient { + background-image: linear-gradient(180deg, rgba(27, 31, 35, 0.065), rgba(27, 31, 35, 0)) !important; + background-repeat: no-repeat !important; + background-size: 100% 200px !important +} + +.text-blue { + color: #0366d6 !important +} + +.text-red { + color: #cb2431 !important +} + +.text-gray-light { + color: #6a737d !important +} + +.text-gray { + color: #586069 !important +} + +.text-gray-dark { + color: #24292e !important +} + +.text-green { + color: #22863a !important +} + +.text-yellow { + color: #b08800 !important +} + +.text-orange { + color: #a04100 !important +} + +.text-orange-light { + color: #e36209 !important +} + +.text-purple { + color: #6f42c1 !important +} + +.text-pink { + color: #ea4aaa !important +} + +.text-white { + color: #fff !important +} + +.text-inherit { + color: inherit !important +} + +.link-gray { + color: #586069 !important +} + +.link-gray:hover { + color: #0366d6 !important +} + +.link-gray-dark { + color: #24292e !important +} + +.link-gray-dark:hover { + color: #0366d6 !important +} + +.link-hover-blue:hover { + color: #0366d6 !important +} + +.muted-link { + color: #586069 !important +} + +.muted-link:hover { + color: #0366d6 !important; + text-decoration: none +} + +.details-overlay[open]>summary::before { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 80; + display: block; + cursor: default; + content: " "; + background: transparent +} + +.details-overlay-dark[open]>summary::before { + z-index: 99; + background: rgba(27, 31, 35, 0.5) +} + +.details-reset>summary { + list-style: none +} + +.details-reset>summary::before { + display: none +} + +.details-reset>summary::-webkit-details-marker { + display: none +} + +.flex-row { + flex-direction: row !important +} + +.flex-row-reverse { + flex-direction: row-reverse !important +} + +.flex-column { + flex-direction: column !important +} + +.flex-column-reverse { + flex-direction: column-reverse !important +} + +.flex-wrap { + flex-wrap: wrap !important +} + +.flex-nowrap { + flex-wrap: nowrap !important +} + +.flex-wrap-reverse { + flex-wrap: wrap-reverse !important +} + +.flex-justify-start { + justify-content: flex-start !important +} + +.flex-justify-end { + justify-content: flex-end !important +} + +.flex-justify-center { + justify-content: center !important +} + +.flex-justify-between { + justify-content: space-between !important +} + +.flex-justify-around { + justify-content: space-around !important +} + +.flex-items-start { + align-items: flex-start !important +} + +.flex-items-end { + align-items: flex-end !important +} + +.flex-items-center { + align-items: center !important +} + +.flex-items-baseline { + align-items: baseline !important +} + +.flex-items-stretch { + align-items: stretch !important +} + +.flex-content-start { + align-content: flex-start !important +} + +.flex-content-end { + align-content: flex-end !important +} + +.flex-content-center { + align-content: center !important +} + +.flex-content-between { + align-content: space-between !important +} + +.flex-content-around { + align-content: space-around !important +} + +.flex-content-stretch { + align-content: stretch !important +} + +.flex-1 { + flex: 1 !important +} + +.flex-auto { + flex: auto !important +} + +.flex-grow-0 { + flex-grow: 0 !important +} + +.flex-shrink-0 { + flex-shrink: 0 !important +} + +.flex-self-auto { + align-self: auto !important +} + +.flex-self-start { + align-self: flex-start !important +} + +.flex-self-end { + align-self: flex-end !important +} + +.flex-self-center { + align-self: center !important +} + +.flex-self-baseline { + align-self: baseline !important +} + +.flex-self-stretch { + align-self: stretch !important +} + +.flex-order-1 { + order: 1 !important +} + +.flex-order-2 { + order: 2 !important +} + +.flex-order-none { + order: inherit !important +} + +@media (min-width: 544px) { + .flex-sm-row { + flex-direction: row !important + } + .flex-sm-row-reverse { + flex-direction: row-reverse !important + } + .flex-sm-column { + flex-direction: column !important + } + .flex-sm-column-reverse { + flex-direction: column-reverse !important + } + .flex-sm-wrap { + flex-wrap: wrap !important + } + .flex-sm-nowrap { + flex-wrap: nowrap !important + } + .flex-sm-wrap-reverse { + flex-wrap: wrap-reverse !important + } + .flex-sm-justify-start { + justify-content: flex-start !important + } + .flex-sm-justify-end { + justify-content: flex-end !important + } + .flex-sm-justify-center { + justify-content: center !important + } + .flex-sm-justify-between { + justify-content: space-between !important + } + .flex-sm-justify-around { + justify-content: space-around !important + } + .flex-sm-items-start { + align-items: flex-start !important + } + .flex-sm-items-end { + align-items: flex-end !important + } + .flex-sm-items-center { + align-items: center !important + } + .flex-sm-items-baseline { + align-items: baseline !important + } + .flex-sm-items-stretch { + align-items: stretch !important + } + .flex-sm-content-start { + align-content: flex-start !important + } + .flex-sm-content-end { + align-content: flex-end !important + } + .flex-sm-content-center { + align-content: center !important + } + .flex-sm-content-between { + align-content: space-between !important + } + .flex-sm-content-around { + align-content: space-around !important + } + .flex-sm-content-stretch { + align-content: stretch !important + } + .flex-sm-1 { + flex: 1 !important + } + .flex-sm-auto { + flex: auto !important + } + .flex-sm-grow-0 { + flex-grow: 0 !important + } + .flex-sm-shrink-0 { + flex-shrink: 0 !important + } + .flex-sm-self-auto { + align-self: auto !important + } + .flex-sm-self-start { + align-self: flex-start !important + } + .flex-sm-self-end { + align-self: flex-end !important + } + .flex-sm-self-center { + align-self: center !important + } + .flex-sm-self-baseline { + align-self: baseline !important + } + .flex-sm-self-stretch { + align-self: stretch !important + } + .flex-sm-order-1 { + order: 1 !important + } + .flex-sm-order-2 { + order: 2 !important + } + .flex-sm-order-none { + order: inherit !important + } +} + +@media (min-width: 768px) { + .flex-md-row { + flex-direction: row !important + } + .flex-md-row-reverse { + flex-direction: row-reverse !important + } + .flex-md-column { + flex-direction: column !important + } + .flex-md-column-reverse { + flex-direction: column-reverse !important + } + .flex-md-wrap { + flex-wrap: wrap !important + } + .flex-md-nowrap { + flex-wrap: nowrap !important + } + .flex-md-wrap-reverse { + flex-wrap: wrap-reverse !important + } + .flex-md-justify-start { + justify-content: flex-start !important + } + .flex-md-justify-end { + justify-content: flex-end !important + } + .flex-md-justify-center { + justify-content: center !important + } + .flex-md-justify-between { + justify-content: space-between !important + } + .flex-md-justify-around { + justify-content: space-around !important + } + .flex-md-items-start { + align-items: flex-start !important + } + .flex-md-items-end { + align-items: flex-end !important + } + .flex-md-items-center { + align-items: center !important + } + .flex-md-items-baseline { + align-items: baseline !important + } + .flex-md-items-stretch { + align-items: stretch !important + } + .flex-md-content-start { + align-content: flex-start !important + } + .flex-md-content-end { + align-content: flex-end !important + } + .flex-md-content-center { + align-content: center !important + } + .flex-md-content-between { + align-content: space-between !important + } + .flex-md-content-around { + align-content: space-around !important + } + .flex-md-content-stretch { + align-content: stretch !important + } + .flex-md-1 { + flex: 1 !important + } + .flex-md-auto { + flex: auto !important + } + .flex-md-grow-0 { + flex-grow: 0 !important + } + .flex-md-shrink-0 { + flex-shrink: 0 !important + } + .flex-md-self-auto { + align-self: auto !important + } + .flex-md-self-start { + align-self: flex-start !important + } + .flex-md-self-end { + align-self: flex-end !important + } + .flex-md-self-center { + align-self: center !important + } + .flex-md-self-baseline { + align-self: baseline !important + } + .flex-md-self-stretch { + align-self: stretch !important + } + .flex-md-order-1 { + order: 1 !important + } + .flex-md-order-2 { + order: 2 !important + } + .flex-md-order-none { + order: inherit !important + } +} + +@media (min-width: 1012px) { + .flex-lg-row { + flex-direction: row !important + } + .flex-lg-row-reverse { + flex-direction: row-reverse !important + } + .flex-lg-column { + flex-direction: column !important + } + .flex-lg-column-reverse { + flex-direction: column-reverse !important + } + .flex-lg-wrap { + flex-wrap: wrap !important + } + .flex-lg-nowrap { + flex-wrap: nowrap !important + } + .flex-lg-wrap-reverse { + flex-wrap: wrap-reverse !important + } + .flex-lg-justify-start { + justify-content: flex-start !important + } + .flex-lg-justify-end { + justify-content: flex-end !important + } + .flex-lg-justify-center { + justify-content: center !important + } + .flex-lg-justify-between { + justify-content: space-between !important + } + .flex-lg-justify-around { + justify-content: space-around !important + } + .flex-lg-items-start { + align-items: flex-start !important + } + .flex-lg-items-end { + align-items: flex-end !important + } + .flex-lg-items-center { + align-items: center !important + } + .flex-lg-items-baseline { + align-items: baseline !important + } + .flex-lg-items-stretch { + align-items: stretch !important + } + .flex-lg-content-start { + align-content: flex-start !important + } + .flex-lg-content-end { + align-content: flex-end !important + } + .flex-lg-content-center { + align-content: center !important + } + .flex-lg-content-between { + align-content: space-between !important + } + .flex-lg-content-around { + align-content: space-around !important + } + .flex-lg-content-stretch { + align-content: stretch !important + } + .flex-lg-1 { + flex: 1 !important + } + .flex-lg-auto { + flex: auto !important + } + .flex-lg-grow-0 { + flex-grow: 0 !important + } + .flex-lg-shrink-0 { + flex-shrink: 0 !important + } + .flex-lg-self-auto { + align-self: auto !important + } + .flex-lg-self-start { + align-self: flex-start !important + } + .flex-lg-self-end { + align-self: flex-end !important + } + .flex-lg-self-center { + align-self: center !important + } + .flex-lg-self-baseline { + align-self: baseline !important + } + .flex-lg-self-stretch { + align-self: stretch !important + } + .flex-lg-order-1 { + order: 1 !important + } + .flex-lg-order-2 { + order: 2 !important + } + .flex-lg-order-none { + order: inherit !important + } +} + +@media (min-width: 1280px) { + .flex-xl-row { + flex-direction: row !important + } + .flex-xl-row-reverse { + flex-direction: row-reverse !important + } + .flex-xl-column { + flex-direction: column !important + } + .flex-xl-column-reverse { + flex-direction: column-reverse !important + } + .flex-xl-wrap { + flex-wrap: wrap !important + } + .flex-xl-nowrap { + flex-wrap: nowrap !important + } + .flex-xl-wrap-reverse { + flex-wrap: wrap-reverse !important + } + .flex-xl-justify-start { + justify-content: flex-start !important + } + .flex-xl-justify-end { + justify-content: flex-end !important + } + .flex-xl-justify-center { + justify-content: center !important + } + .flex-xl-justify-between { + justify-content: space-between !important + } + .flex-xl-justify-around { + justify-content: space-around !important + } + .flex-xl-items-start { + align-items: flex-start !important + } + .flex-xl-items-end { + align-items: flex-end !important + } + .flex-xl-items-center { + align-items: center !important + } + .flex-xl-items-baseline { + align-items: baseline !important + } + .flex-xl-items-stretch { + align-items: stretch !important + } + .flex-xl-content-start { + align-content: flex-start !important + } + .flex-xl-content-end { + align-content: flex-end !important + } + .flex-xl-content-center { + align-content: center !important + } + .flex-xl-content-between { + align-content: space-between !important + } + .flex-xl-content-around { + align-content: space-around !important + } + .flex-xl-content-stretch { + align-content: stretch !important + } + .flex-xl-1 { + flex: 1 !important + } + .flex-xl-auto { + flex: auto !important + } + .flex-xl-grow-0 { + flex-grow: 0 !important + } + .flex-xl-shrink-0 { + flex-shrink: 0 !important + } + .flex-xl-self-auto { + align-self: auto !important + } + .flex-xl-self-start { + align-self: flex-start !important + } + .flex-xl-self-end { + align-self: flex-end !important + } + .flex-xl-self-center { + align-self: center !important + } + .flex-xl-self-baseline { + align-self: baseline !important + } + .flex-xl-self-stretch { + align-self: stretch !important + } + .flex-xl-order-1 { + order: 1 !important + } + .flex-xl-order-2 { + order: 2 !important + } + .flex-xl-order-none { + order: inherit !important + } +} + +.position-static { + position: static !important +} + +.position-relative { + position: relative !important +} + +.position-absolute { + position: absolute !important +} + +.position-fixed { + position: fixed !important +} + +.position-sticky { + position: -webkit-sticky !important; + position: sticky !important +} + +@media (min-width: 544px) { + .position-sm-static { + position: static !important + } + .position-sm-relative { + position: relative !important + } + .position-sm-absolute { + position: absolute !important + } + .position-sm-fixed { + position: fixed !important + } + .position-sm-sticky { + position: -webkit-sticky !important; + position: sticky !important + } +} + +@media (min-width: 768px) { + .position-md-static { + position: static !important + } + .position-md-relative { + position: relative !important + } + .position-md-absolute { + position: absolute !important + } + .position-md-fixed { + position: fixed !important + } + .position-md-sticky { + position: -webkit-sticky !important; + position: sticky !important + } +} + +@media (min-width: 1012px) { + .position-lg-static { + position: static !important + } + .position-lg-relative { + position: relative !important + } + .position-lg-absolute { + position: absolute !important + } + .position-lg-fixed { + position: fixed !important + } + .position-lg-sticky { + position: -webkit-sticky !important; + position: sticky !important + } +} + +@media (min-width: 1280px) { + .position-xl-static { + position: static !important + } + .position-xl-relative { + position: relative !important + } + .position-xl-absolute { + position: absolute !important + } + .position-xl-fixed { + position: fixed !important + } + .position-xl-sticky { + position: -webkit-sticky !important; + position: sticky !important + } +} + +.top-0 { + top: 0 !important +} + +.right-0 { + right: 0 !important +} + +.bottom-0 { + bottom: 0 !important +} + +.left-0 { + left: 0 !important +} + +.top-auto { + top: auto !important +} + +.right-auto { + right: auto !important +} + +.bottom-auto { + bottom: auto !important +} + +.left-auto { + left: auto !important +} + +@media (min-width: 544px) { + .top-sm-0 { + top: 0 !important + } + .right-sm-0 { + right: 0 !important + } + .bottom-sm-0 { + bottom: 0 !important + } + .left-sm-0 { + left: 0 !important + } + .top-sm-auto { + top: auto !important + } + .right-sm-auto { + right: auto !important + } + .bottom-sm-auto { + bottom: auto !important + } + .left-sm-auto { + left: auto !important + } +} + +@media (min-width: 768px) { + .top-md-0 { + top: 0 !important + } + .right-md-0 { + right: 0 !important + } + .bottom-md-0 { + bottom: 0 !important + } + .left-md-0 { + left: 0 !important + } + .top-md-auto { + top: auto !important + } + .right-md-auto { + right: auto !important + } + .bottom-md-auto { + bottom: auto !important + } + .left-md-auto { + left: auto !important + } +} + +@media (min-width: 1012px) { + .top-lg-0 { + top: 0 !important + } + .right-lg-0 { + right: 0 !important + } + .bottom-lg-0 { + bottom: 0 !important + } + .left-lg-0 { + left: 0 !important + } + .top-lg-auto { + top: auto !important + } + .right-lg-auto { + right: auto !important + } + .bottom-lg-auto { + bottom: auto !important + } + .left-lg-auto { + left: auto !important + } +} + +@media (min-width: 1280px) { + .top-xl-0 { + top: 0 !important + } + .right-xl-0 { + right: 0 !important + } + .bottom-xl-0 { + bottom: 0 !important + } + .left-xl-0 { + left: 0 !important + } + .top-xl-auto { + top: auto !important + } + .right-xl-auto { + right: auto !important + } + .bottom-xl-auto { + bottom: auto !important + } + .left-xl-auto { + left: auto !important + } +} + +.v-align-middle { + vertical-align: middle !important +} + +.v-align-top { + vertical-align: top !important +} + +.v-align-bottom { + vertical-align: bottom !important +} + +.v-align-text-top { + vertical-align: text-top !important +} + +.v-align-text-bottom { + vertical-align: text-bottom !important +} + +.v-align-baseline { + vertical-align: baseline !important +} + +.overflow-visible { + overflow: visible !important +} + +.overflow-x-visible { + overflow-x: visible !important +} + +.overflow-y-visible { + overflow-y: visible !important +} + +.overflow-hidden { + overflow: hidden !important +} + +.overflow-x-hidden { + overflow-x: hidden !important +} + +.overflow-y-hidden { + overflow-y: hidden !important +} + +.overflow-auto { + overflow: auto !important +} + +.overflow-x-auto { + overflow-x: auto !important +} + +.overflow-y-auto { + overflow-y: auto !important +} + +.overflow-scroll { + overflow: scroll !important +} + +.overflow-x-scroll { + overflow-x: scroll !important +} + +.overflow-y-scroll { + overflow-y: scroll !important +} + +@media (min-width: 544px) { + .overflow-sm-visible { + overflow: visible !important + } + .overflow-sm-x-visible { + overflow-x: visible !important + } + .overflow-sm-y-visible { + overflow-y: visible !important + } + .overflow-sm-hidden { + overflow: hidden !important + } + .overflow-sm-x-hidden { + overflow-x: hidden !important + } + .overflow-sm-y-hidden { + overflow-y: hidden !important + } + .overflow-sm-auto { + overflow: auto !important + } + .overflow-sm-x-auto { + overflow-x: auto !important + } + .overflow-sm-y-auto { + overflow-y: auto !important + } + .overflow-sm-scroll { + overflow: scroll !important + } + .overflow-sm-x-scroll { + overflow-x: scroll !important + } + .overflow-sm-y-scroll { + overflow-y: scroll !important + } +} + +@media (min-width: 768px) { + .overflow-md-visible { + overflow: visible !important + } + .overflow-md-x-visible { + overflow-x: visible !important + } + .overflow-md-y-visible { + overflow-y: visible !important + } + .overflow-md-hidden { + overflow: hidden !important + } + .overflow-md-x-hidden { + overflow-x: hidden !important + } + .overflow-md-y-hidden { + overflow-y: hidden !important + } + .overflow-md-auto { + overflow: auto !important + } + .overflow-md-x-auto { + overflow-x: auto !important + } + .overflow-md-y-auto { + overflow-y: auto !important + } + .overflow-md-scroll { + overflow: scroll !important + } + .overflow-md-x-scroll { + overflow-x: scroll !important + } + .overflow-md-y-scroll { + overflow-y: scroll !important + } +} + +@media (min-width: 1012px) { + .overflow-lg-visible { + overflow: visible !important + } + .overflow-lg-x-visible { + overflow-x: visible !important + } + .overflow-lg-y-visible { + overflow-y: visible !important + } + .overflow-lg-hidden { + overflow: hidden !important + } + .overflow-lg-x-hidden { + overflow-x: hidden !important + } + .overflow-lg-y-hidden { + overflow-y: hidden !important + } + .overflow-lg-auto { + overflow: auto !important + } + .overflow-lg-x-auto { + overflow-x: auto !important + } + .overflow-lg-y-auto { + overflow-y: auto !important + } + .overflow-lg-scroll { + overflow: scroll !important + } + .overflow-lg-x-scroll { + overflow-x: scroll !important + } + .overflow-lg-y-scroll { + overflow-y: scroll !important + } +} + +@media (min-width: 1280px) { + .overflow-xl-visible { + overflow: visible !important + } + .overflow-xl-x-visible { + overflow-x: visible !important + } + .overflow-xl-y-visible { + overflow-y: visible !important + } + .overflow-xl-hidden { + overflow: hidden !important + } + .overflow-xl-x-hidden { + overflow-x: hidden !important + } + .overflow-xl-y-hidden { + overflow-y: hidden !important + } + .overflow-xl-auto { + overflow: auto !important + } + .overflow-xl-x-auto { + overflow-x: auto !important + } + .overflow-xl-y-auto { + overflow-y: auto !important + } + .overflow-xl-scroll { + overflow: scroll !important + } + .overflow-xl-x-scroll { + overflow-x: scroll !important + } + .overflow-xl-y-scroll { + overflow-y: scroll !important + } +} + +.clearfix::before { + display: table; + content: "" +} + +.clearfix::after { + display: table; + clear: both; + content: "" +} + +.float-left { + float: left !important +} + +.float-right { + float: right !important +} + +.float-none { + float: none !important +} + +@media (min-width: 544px) { + .float-sm-left { + float: left !important + } + .float-sm-right { + float: right !important + } + .float-sm-none { + float: none !important + } +} + +@media (min-width: 768px) { + .float-md-left { + float: left !important + } + .float-md-right { + float: right !important + } + .float-md-none { + float: none !important + } +} + +@media (min-width: 1012px) { + .float-lg-left { + float: left !important + } + .float-lg-right { + float: right !important + } + .float-lg-none { + float: none !important + } +} + +@media (min-width: 1280px) { + .float-xl-left { + float: left !important + } + .float-xl-right { + float: right !important + } + .float-xl-none { + float: none !important + } +} + +.width-fit { + max-width: 100% !important +} + +.width-full { + width: 100% !important +} + +.height-fit { + max-height: 100% !important +} + +.height-full { + height: 100% !important +} + +.min-width-0 { + min-width: 0 !important +} + +.width-auto { + width: auto !important +} + +.direction-rtl { + direction: rtl !important +} + +.direction-ltr { + direction: ltr !important +} + +@media (min-width: 544px) { + .width-sm-auto { + width: auto !important + } + .direction-sm-rtl { + direction: rtl !important + } + .direction-sm-ltr { + direction: ltr !important + } +} + +@media (min-width: 768px) { + .width-md-auto { + width: auto !important + } + .direction-md-rtl { + direction: rtl !important + } + .direction-md-ltr { + direction: ltr !important + } +} + +@media (min-width: 1012px) { + .width-lg-auto { + width: auto !important + } + .direction-lg-rtl { + direction: rtl !important + } + .direction-lg-ltr { + direction: ltr !important + } +} + +@media (min-width: 1280px) { + .width-xl-auto { + width: auto !important + } + .direction-xl-rtl { + direction: rtl !important + } + .direction-xl-ltr { + direction: ltr !important + } +} + +.m-0 { + margin: 0 !important +} + +.mt-0 { + margin-top: 0 !important +} + +.mr-0 { + margin-right: 0 !important +} + +.mb-0 { + margin-bottom: 0 !important +} + +.ml-0 { + margin-left: 0 !important +} + +.mx-0 { + margin-right: 0 !important; + margin-left: 0 !important +} + +.my-0 { + margin-top: 0 !important; + margin-bottom: 0 !important +} + +.m-1 { + margin: 4px !important +} + +.mt-1 { + margin-top: 4px !important +} + +.mr-1 { + margin-right: 4px !important +} + +.mb-1 { + margin-bottom: 4px !important +} + +.ml-1 { + margin-left: 4px !important +} + +.mt-n1 { + margin-top: -4px !important +} + +.mr-n1 { + margin-right: -4px !important +} + +.mb-n1 { + margin-bottom: -4px !important +} + +.ml-n1 { + margin-left: -4px !important +} + +.mx-1 { + margin-right: 4px !important; + margin-left: 4px !important +} + +.my-1 { + margin-top: 4px !important; + margin-bottom: 4px !important +} + +.m-2 { + margin: 8px !important +} + +.mt-2 { + margin-top: 8px !important +} + +.mr-2 { + margin-right: 8px !important +} + +.mb-2 { + margin-bottom: 8px !important +} + +.ml-2 { + margin-left: 8px !important +} + +.mt-n2 { + margin-top: -8px !important +} + +.mr-n2 { + margin-right: -8px !important +} + +.mb-n2 { + margin-bottom: -8px !important +} + +.ml-n2 { + margin-left: -8px !important +} + +.mx-2 { + margin-right: 8px !important; + margin-left: 8px !important +} + +.my-2 { + margin-top: 8px !important; + margin-bottom: 8px !important +} + +.m-3 { + margin: 16px !important +} + +.mt-3 { + margin-top: 16px !important +} + +.mr-3 { + margin-right: 16px !important +} + +.mb-3 { + margin-bottom: 16px !important +} + +.ml-3 { + margin-left: 16px !important +} + +.mt-n3 { + margin-top: -16px !important +} + +.mr-n3 { + margin-right: -16px !important +} + +.mb-n3 { + margin-bottom: -16px !important +} + +.ml-n3 { + margin-left: -16px !important +} + +.mx-3 { + margin-right: 16px !important; + margin-left: 16px !important +} + +.my-3 { + margin-top: 16px !important; + margin-bottom: 16px !important +} + +.m-4 { + margin: 24px !important +} + +.mt-4 { + margin-top: 24px !important +} + +.mr-4 { + margin-right: 24px !important +} + +.mb-4 { + margin-bottom: 24px !important +} + +.ml-4 { + margin-left: 24px !important +} + +.mt-n4 { + margin-top: -24px !important +} + +.mr-n4 { + margin-right: -24px !important +} + +.mb-n4 { + margin-bottom: -24px !important +} + +.ml-n4 { + margin-left: -24px !important +} + +.mx-4 { + margin-right: 24px !important; + margin-left: 24px !important +} + +.my-4 { + margin-top: 24px !important; + margin-bottom: 24px !important +} + +.m-5 { + margin: 32px !important +} + +.mt-5 { + margin-top: 32px !important +} + +.mr-5 { + margin-right: 32px !important +} + +.mb-5 { + margin-bottom: 32px !important +} + +.ml-5 { + margin-left: 32px !important +} + +.mt-n5 { + margin-top: -32px !important +} + +.mr-n5 { + margin-right: -32px !important +} + +.mb-n5 { + margin-bottom: -32px !important +} + +.ml-n5 { + margin-left: -32px !important +} + +.mx-5 { + margin-right: 32px !important; + margin-left: 32px !important +} + +.my-5 { + margin-top: 32px !important; + margin-bottom: 32px !important +} + +.m-6 { + margin: 40px !important +} + +.mt-6 { + margin-top: 40px !important +} + +.mr-6 { + margin-right: 40px !important +} + +.mb-6 { + margin-bottom: 40px !important +} + +.ml-6 { + margin-left: 40px !important +} + +.mt-n6 { + margin-top: -40px !important +} + +.mr-n6 { + margin-right: -40px !important +} + +.mb-n6 { + margin-bottom: -40px !important +} + +.ml-n6 { + margin-left: -40px !important +} + +.mx-6 { + margin-right: 40px !important; + margin-left: 40px !important +} + +.my-6 { + margin-top: 40px !important; + margin-bottom: 40px !important +} + +.mx-auto { + margin-right: auto !important; + margin-left: auto !important +} + +@media (min-width: 544px) { + .m-sm-0 { + margin: 0 !important + } + .mt-sm-0 { + margin-top: 0 !important + } + .mr-sm-0 { + margin-right: 0 !important + } + .mb-sm-0 { + margin-bottom: 0 !important + } + .ml-sm-0 { + margin-left: 0 !important + } + .mx-sm-0 { + margin-right: 0 !important; + margin-left: 0 !important + } + .my-sm-0 { + margin-top: 0 !important; + margin-bottom: 0 !important + } + .m-sm-1 { + margin: 4px !important + } + .mt-sm-1 { + margin-top: 4px !important + } + .mr-sm-1 { + margin-right: 4px !important + } + .mb-sm-1 { + margin-bottom: 4px !important + } + .ml-sm-1 { + margin-left: 4px !important + } + .mt-sm-n1 { + margin-top: -4px !important + } + .mr-sm-n1 { + margin-right: -4px !important + } + .mb-sm-n1 { + margin-bottom: -4px !important + } + .ml-sm-n1 { + margin-left: -4px !important + } + .mx-sm-1 { + margin-right: 4px !important; + margin-left: 4px !important + } + .my-sm-1 { + margin-top: 4px !important; + margin-bottom: 4px !important + } + .m-sm-2 { + margin: 8px !important + } + .mt-sm-2 { + margin-top: 8px !important + } + .mr-sm-2 { + margin-right: 8px !important + } + .mb-sm-2 { + margin-bottom: 8px !important + } + .ml-sm-2 { + margin-left: 8px !important + } + .mt-sm-n2 { + margin-top: -8px !important + } + .mr-sm-n2 { + margin-right: -8px !important + } + .mb-sm-n2 { + margin-bottom: -8px !important + } + .ml-sm-n2 { + margin-left: -8px !important + } + .mx-sm-2 { + margin-right: 8px !important; + margin-left: 8px !important + } + .my-sm-2 { + margin-top: 8px !important; + margin-bottom: 8px !important + } + .m-sm-3 { + margin: 16px !important + } + .mt-sm-3 { + margin-top: 16px !important + } + .mr-sm-3 { + margin-right: 16px !important + } + .mb-sm-3 { + margin-bottom: 16px !important + } + .ml-sm-3 { + margin-left: 16px !important + } + .mt-sm-n3 { + margin-top: -16px !important + } + .mr-sm-n3 { + margin-right: -16px !important + } + .mb-sm-n3 { + margin-bottom: -16px !important + } + .ml-sm-n3 { + margin-left: -16px !important + } + .mx-sm-3 { + margin-right: 16px !important; + margin-left: 16px !important + } + .my-sm-3 { + margin-top: 16px !important; + margin-bottom: 16px !important + } + .m-sm-4 { + margin: 24px !important + } + .mt-sm-4 { + margin-top: 24px !important + } + .mr-sm-4 { + margin-right: 24px !important + } + .mb-sm-4 { + margin-bottom: 24px !important + } + .ml-sm-4 { + margin-left: 24px !important + } + .mt-sm-n4 { + margin-top: -24px !important + } + .mr-sm-n4 { + margin-right: -24px !important + } + .mb-sm-n4 { + margin-bottom: -24px !important + } + .ml-sm-n4 { + margin-left: -24px !important + } + .mx-sm-4 { + margin-right: 24px !important; + margin-left: 24px !important + } + .my-sm-4 { + margin-top: 24px !important; + margin-bottom: 24px !important + } + .m-sm-5 { + margin: 32px !important + } + .mt-sm-5 { + margin-top: 32px !important + } + .mr-sm-5 { + margin-right: 32px !important + } + .mb-sm-5 { + margin-bottom: 32px !important + } + .ml-sm-5 { + margin-left: 32px !important + } + .mt-sm-n5 { + margin-top: -32px !important + } + .mr-sm-n5 { + margin-right: -32px !important + } + .mb-sm-n5 { + margin-bottom: -32px !important + } + .ml-sm-n5 { + margin-left: -32px !important + } + .mx-sm-5 { + margin-right: 32px !important; + margin-left: 32px !important + } + .my-sm-5 { + margin-top: 32px !important; + margin-bottom: 32px !important + } + .m-sm-6 { + margin: 40px !important + } + .mt-sm-6 { + margin-top: 40px !important + } + .mr-sm-6 { + margin-right: 40px !important + } + .mb-sm-6 { + margin-bottom: 40px !important + } + .ml-sm-6 { + margin-left: 40px !important + } + .mt-sm-n6 { + margin-top: -40px !important + } + .mr-sm-n6 { + margin-right: -40px !important + } + .mb-sm-n6 { + margin-bottom: -40px !important + } + .ml-sm-n6 { + margin-left: -40px !important + } + .mx-sm-6 { + margin-right: 40px !important; + margin-left: 40px !important + } + .my-sm-6 { + margin-top: 40px !important; + margin-bottom: 40px !important + } + .mx-sm-auto { + margin-right: auto !important; + margin-left: auto !important + } +} + +@media (min-width: 768px) { + .m-md-0 { + margin: 0 !important + } + .mt-md-0 { + margin-top: 0 !important + } + .mr-md-0 { + margin-right: 0 !important + } + .mb-md-0 { + margin-bottom: 0 !important + } + .ml-md-0 { + margin-left: 0 !important + } + .mx-md-0 { + margin-right: 0 !important; + margin-left: 0 !important + } + .my-md-0 { + margin-top: 0 !important; + margin-bottom: 0 !important + } + .m-md-1 { + margin: 4px !important + } + .mt-md-1 { + margin-top: 4px !important + } + .mr-md-1 { + margin-right: 4px !important + } + .mb-md-1 { + margin-bottom: 4px !important + } + .ml-md-1 { + margin-left: 4px !important + } + .mt-md-n1 { + margin-top: -4px !important + } + .mr-md-n1 { + margin-right: -4px !important + } + .mb-md-n1 { + margin-bottom: -4px !important + } + .ml-md-n1 { + margin-left: -4px !important + } + .mx-md-1 { + margin-right: 4px !important; + margin-left: 4px !important + } + .my-md-1 { + margin-top: 4px !important; + margin-bottom: 4px !important + } + .m-md-2 { + margin: 8px !important + } + .mt-md-2 { + margin-top: 8px !important + } + .mr-md-2 { + margin-right: 8px !important + } + .mb-md-2 { + margin-bottom: 8px !important + } + .ml-md-2 { + margin-left: 8px !important + } + .mt-md-n2 { + margin-top: -8px !important + } + .mr-md-n2 { + margin-right: -8px !important + } + .mb-md-n2 { + margin-bottom: -8px !important + } + .ml-md-n2 { + margin-left: -8px !important + } + .mx-md-2 { + margin-right: 8px !important; + margin-left: 8px !important + } + .my-md-2 { + margin-top: 8px !important; + margin-bottom: 8px !important + } + .m-md-3 { + margin: 16px !important + } + .mt-md-3 { + margin-top: 16px !important + } + .mr-md-3 { + margin-right: 16px !important + } + .mb-md-3 { + margin-bottom: 16px !important + } + .ml-md-3 { + margin-left: 16px !important + } + .mt-md-n3 { + margin-top: -16px !important + } + .mr-md-n3 { + margin-right: -16px !important + } + .mb-md-n3 { + margin-bottom: -16px !important + } + .ml-md-n3 { + margin-left: -16px !important + } + .mx-md-3 { + margin-right: 16px !important; + margin-left: 16px !important + } + .my-md-3 { + margin-top: 16px !important; + margin-bottom: 16px !important + } + .m-md-4 { + margin: 24px !important + } + .mt-md-4 { + margin-top: 24px !important + } + .mr-md-4 { + margin-right: 24px !important + } + .mb-md-4 { + margin-bottom: 24px !important + } + .ml-md-4 { + margin-left: 24px !important + } + .mt-md-n4 { + margin-top: -24px !important + } + .mr-md-n4 { + margin-right: -24px !important + } + .mb-md-n4 { + margin-bottom: -24px !important + } + .ml-md-n4 { + margin-left: -24px !important + } + .mx-md-4 { + margin-right: 24px !important; + margin-left: 24px !important + } + .my-md-4 { + margin-top: 24px !important; + margin-bottom: 24px !important + } + .m-md-5 { + margin: 32px !important + } + .mt-md-5 { + margin-top: 32px !important + } + .mr-md-5 { + margin-right: 32px !important + } + .mb-md-5 { + margin-bottom: 32px !important + } + .ml-md-5 { + margin-left: 32px !important + } + .mt-md-n5 { + margin-top: -32px !important + } + .mr-md-n5 { + margin-right: -32px !important + } + .mb-md-n5 { + margin-bottom: -32px !important + } + .ml-md-n5 { + margin-left: -32px !important + } + .mx-md-5 { + margin-right: 32px !important; + margin-left: 32px !important + } + .my-md-5 { + margin-top: 32px !important; + margin-bottom: 32px !important + } + .m-md-6 { + margin: 40px !important + } + .mt-md-6 { + margin-top: 40px !important + } + .mr-md-6 { + margin-right: 40px !important + } + .mb-md-6 { + margin-bottom: 40px !important + } + .ml-md-6 { + margin-left: 40px !important + } + .mt-md-n6 { + margin-top: -40px !important + } + .mr-md-n6 { + margin-right: -40px !important + } + .mb-md-n6 { + margin-bottom: -40px !important + } + .ml-md-n6 { + margin-left: -40px !important + } + .mx-md-6 { + margin-right: 40px !important; + margin-left: 40px !important + } + .my-md-6 { + margin-top: 40px !important; + margin-bottom: 40px !important + } + .mx-md-auto { + margin-right: auto !important; + margin-left: auto !important + } +} + +@media (min-width: 1012px) { + .m-lg-0 { + margin: 0 !important + } + .mt-lg-0 { + margin-top: 0 !important + } + .mr-lg-0 { + margin-right: 0 !important + } + .mb-lg-0 { + margin-bottom: 0 !important + } + .ml-lg-0 { + margin-left: 0 !important + } + .mx-lg-0 { + margin-right: 0 !important; + margin-left: 0 !important + } + .my-lg-0 { + margin-top: 0 !important; + margin-bottom: 0 !important + } + .m-lg-1 { + margin: 4px !important + } + .mt-lg-1 { + margin-top: 4px !important + } + .mr-lg-1 { + margin-right: 4px !important + } + .mb-lg-1 { + margin-bottom: 4px !important + } + .ml-lg-1 { + margin-left: 4px !important + } + .mt-lg-n1 { + margin-top: -4px !important + } + .mr-lg-n1 { + margin-right: -4px !important + } + .mb-lg-n1 { + margin-bottom: -4px !important + } + .ml-lg-n1 { + margin-left: -4px !important + } + .mx-lg-1 { + margin-right: 4px !important; + margin-left: 4px !important + } + .my-lg-1 { + margin-top: 4px !important; + margin-bottom: 4px !important + } + .m-lg-2 { + margin: 8px !important + } + .mt-lg-2 { + margin-top: 8px !important + } + .mr-lg-2 { + margin-right: 8px !important + } + .mb-lg-2 { + margin-bottom: 8px !important + } + .ml-lg-2 { + margin-left: 8px !important + } + .mt-lg-n2 { + margin-top: -8px !important + } + .mr-lg-n2 { + margin-right: -8px !important + } + .mb-lg-n2 { + margin-bottom: -8px !important + } + .ml-lg-n2 { + margin-left: -8px !important + } + .mx-lg-2 { + margin-right: 8px !important; + margin-left: 8px !important + } + .my-lg-2 { + margin-top: 8px !important; + margin-bottom: 8px !important + } + .m-lg-3 { + margin: 16px !important + } + .mt-lg-3 { + margin-top: 16px !important + } + .mr-lg-3 { + margin-right: 16px !important + } + .mb-lg-3 { + margin-bottom: 16px !important + } + .ml-lg-3 { + margin-left: 16px !important + } + .mt-lg-n3 { + margin-top: -16px !important + } + .mr-lg-n3 { + margin-right: -16px !important + } + .mb-lg-n3 { + margin-bottom: -16px !important + } + .ml-lg-n3 { + margin-left: -16px !important + } + .mx-lg-3 { + margin-right: 16px !important; + margin-left: 16px !important + } + .my-lg-3 { + margin-top: 16px !important; + margin-bottom: 16px !important + } + .m-lg-4 { + margin: 24px !important + } + .mt-lg-4 { + margin-top: 24px !important + } + .mr-lg-4 { + margin-right: 24px !important + } + .mb-lg-4 { + margin-bottom: 24px !important + } + .ml-lg-4 { + margin-left: 24px !important + } + .mt-lg-n4 { + margin-top: -24px !important + } + .mr-lg-n4 { + margin-right: -24px !important + } + .mb-lg-n4 { + margin-bottom: -24px !important + } + .ml-lg-n4 { + margin-left: -24px !important + } + .mx-lg-4 { + margin-right: 24px !important; + margin-left: 24px !important + } + .my-lg-4 { + margin-top: 24px !important; + margin-bottom: 24px !important + } + .m-lg-5 { + margin: 32px !important + } + .mt-lg-5 { + margin-top: 32px !important + } + .mr-lg-5 { + margin-right: 32px !important + } + .mb-lg-5 { + margin-bottom: 32px !important + } + .ml-lg-5 { + margin-left: 32px !important + } + .mt-lg-n5 { + margin-top: -32px !important + } + .mr-lg-n5 { + margin-right: -32px !important + } + .mb-lg-n5 { + margin-bottom: -32px !important + } + .ml-lg-n5 { + margin-left: -32px !important + } + .mx-lg-5 { + margin-right: 32px !important; + margin-left: 32px !important + } + .my-lg-5 { + margin-top: 32px !important; + margin-bottom: 32px !important + } + .m-lg-6 { + margin: 40px !important + } + .mt-lg-6 { + margin-top: 40px !important + } + .mr-lg-6 { + margin-right: 40px !important + } + .mb-lg-6 { + margin-bottom: 40px !important + } + .ml-lg-6 { + margin-left: 40px !important + } + .mt-lg-n6 { + margin-top: -40px !important + } + .mr-lg-n6 { + margin-right: -40px !important + } + .mb-lg-n6 { + margin-bottom: -40px !important + } + .ml-lg-n6 { + margin-left: -40px !important + } + .mx-lg-6 { + margin-right: 40px !important; + margin-left: 40px !important + } + .my-lg-6 { + margin-top: 40px !important; + margin-bottom: 40px !important + } + .mx-lg-auto { + margin-right: auto !important; + margin-left: auto !important + } +} + +@media (min-width: 1280px) { + .m-xl-0 { + margin: 0 !important + } + .mt-xl-0 { + margin-top: 0 !important + } + .mr-xl-0 { + margin-right: 0 !important + } + .mb-xl-0 { + margin-bottom: 0 !important + } + .ml-xl-0 { + margin-left: 0 !important + } + .mx-xl-0 { + margin-right: 0 !important; + margin-left: 0 !important + } + .my-xl-0 { + margin-top: 0 !important; + margin-bottom: 0 !important + } + .m-xl-1 { + margin: 4px !important + } + .mt-xl-1 { + margin-top: 4px !important + } + .mr-xl-1 { + margin-right: 4px !important + } + .mb-xl-1 { + margin-bottom: 4px !important + } + .ml-xl-1 { + margin-left: 4px !important + } + .mt-xl-n1 { + margin-top: -4px !important + } + .mr-xl-n1 { + margin-right: -4px !important + } + .mb-xl-n1 { + margin-bottom: -4px !important + } + .ml-xl-n1 { + margin-left: -4px !important + } + .mx-xl-1 { + margin-right: 4px !important; + margin-left: 4px !important + } + .my-xl-1 { + margin-top: 4px !important; + margin-bottom: 4px !important + } + .m-xl-2 { + margin: 8px !important + } + .mt-xl-2 { + margin-top: 8px !important + } + .mr-xl-2 { + margin-right: 8px !important + } + .mb-xl-2 { + margin-bottom: 8px !important + } + .ml-xl-2 { + margin-left: 8px !important + } + .mt-xl-n2 { + margin-top: -8px !important + } + .mr-xl-n2 { + margin-right: -8px !important + } + .mb-xl-n2 { + margin-bottom: -8px !important + } + .ml-xl-n2 { + margin-left: -8px !important + } + .mx-xl-2 { + margin-right: 8px !important; + margin-left: 8px !important + } + .my-xl-2 { + margin-top: 8px !important; + margin-bottom: 8px !important + } + .m-xl-3 { + margin: 16px !important + } + .mt-xl-3 { + margin-top: 16px !important + } + .mr-xl-3 { + margin-right: 16px !important + } + .mb-xl-3 { + margin-bottom: 16px !important + } + .ml-xl-3 { + margin-left: 16px !important + } + .mt-xl-n3 { + margin-top: -16px !important + } + .mr-xl-n3 { + margin-right: -16px !important + } + .mb-xl-n3 { + margin-bottom: -16px !important + } + .ml-xl-n3 { + margin-left: -16px !important + } + .mx-xl-3 { + margin-right: 16px !important; + margin-left: 16px !important + } + .my-xl-3 { + margin-top: 16px !important; + margin-bottom: 16px !important + } + .m-xl-4 { + margin: 24px !important + } + .mt-xl-4 { + margin-top: 24px !important + } + .mr-xl-4 { + margin-right: 24px !important + } + .mb-xl-4 { + margin-bottom: 24px !important + } + .ml-xl-4 { + margin-left: 24px !important + } + .mt-xl-n4 { + margin-top: -24px !important + } + .mr-xl-n4 { + margin-right: -24px !important + } + .mb-xl-n4 { + margin-bottom: -24px !important + } + .ml-xl-n4 { + margin-left: -24px !important + } + .mx-xl-4 { + margin-right: 24px !important; + margin-left: 24px !important + } + .my-xl-4 { + margin-top: 24px !important; + margin-bottom: 24px !important + } + .m-xl-5 { + margin: 32px !important + } + .mt-xl-5 { + margin-top: 32px !important + } + .mr-xl-5 { + margin-right: 32px !important + } + .mb-xl-5 { + margin-bottom: 32px !important + } + .ml-xl-5 { + margin-left: 32px !important + } + .mt-xl-n5 { + margin-top: -32px !important + } + .mr-xl-n5 { + margin-right: -32px !important + } + .mb-xl-n5 { + margin-bottom: -32px !important + } + .ml-xl-n5 { + margin-left: -32px !important + } + .mx-xl-5 { + margin-right: 32px !important; + margin-left: 32px !important + } + .my-xl-5 { + margin-top: 32px !important; + margin-bottom: 32px !important + } + .m-xl-6 { + margin: 40px !important + } + .mt-xl-6 { + margin-top: 40px !important + } + .mr-xl-6 { + margin-right: 40px !important + } + .mb-xl-6 { + margin-bottom: 40px !important + } + .ml-xl-6 { + margin-left: 40px !important + } + .mt-xl-n6 { + margin-top: -40px !important + } + .mr-xl-n6 { + margin-right: -40px !important + } + .mb-xl-n6 { + margin-bottom: -40px !important + } + .ml-xl-n6 { + margin-left: -40px !important + } + .mx-xl-6 { + margin-right: 40px !important; + margin-left: 40px !important + } + .my-xl-6 { + margin-top: 40px !important; + margin-bottom: 40px !important + } + .mx-xl-auto { + margin-right: auto !important; + margin-left: auto !important + } +} + +.p-0 { + padding: 0 !important +} + +.pt-0 { + padding-top: 0 !important +} + +.pr-0 { + padding-right: 0 !important +} + +.pb-0 { + padding-bottom: 0 !important +} + +.pl-0 { + padding-left: 0 !important +} + +.px-0 { + padding-right: 0 !important; + padding-left: 0 !important +} + +.py-0 { + padding-top: 0 !important; + padding-bottom: 0 !important +} + +.p-1 { + padding: 4px !important +} + +.pt-1 { + padding-top: 4px !important +} + +.pr-1 { + padding-right: 4px !important +} + +.pb-1 { + padding-bottom: 4px !important +} + +.pl-1 { + padding-left: 4px !important +} + +.px-1 { + padding-right: 4px !important; + padding-left: 4px !important +} + +.py-1 { + padding-top: 4px !important; + padding-bottom: 4px !important +} + +.p-2 { + padding: 8px !important +} + +.pt-2 { + padding-top: 8px !important +} + +.pr-2 { + padding-right: 8px !important +} + +.pb-2 { + padding-bottom: 8px !important +} + +.pl-2 { + padding-left: 8px !important +} + +.px-2 { + padding-right: 8px !important; + padding-left: 8px !important +} + +.py-2 { + padding-top: 8px !important; + padding-bottom: 8px !important +} + +.p-3 { + padding: 16px !important +} + +.pt-3 { + padding-top: 16px !important +} + +.pr-3 { + padding-right: 16px !important +} + +.pb-3 { + padding-bottom: 16px !important +} + +.pl-3 { + padding-left: 16px !important +} + +.px-3 { + padding-right: 16px !important; + padding-left: 16px !important +} + +.py-3 { + padding-top: 16px !important; + padding-bottom: 16px !important +} + +.p-4 { + padding: 24px !important +} + +.pt-4 { + padding-top: 24px !important +} + +.pr-4 { + padding-right: 24px !important +} + +.pb-4 { + padding-bottom: 24px !important +} + +.pl-4 { + padding-left: 24px !important +} + +.px-4 { + padding-right: 24px !important; + padding-left: 24px !important +} + +.py-4 { + padding-top: 24px !important; + padding-bottom: 24px !important +} + +.p-5 { + padding: 32px !important +} + +.pt-5 { + padding-top: 32px !important +} + +.pr-5 { + padding-right: 32px !important +} + +.pb-5 { + padding-bottom: 32px !important +} + +.pl-5 { + padding-left: 32px !important +} + +.px-5 { + padding-right: 32px !important; + padding-left: 32px !important +} + +.py-5 { + padding-top: 32px !important; + padding-bottom: 32px !important +} + +.p-6 { + padding: 40px !important +} + +.pt-6 { + padding-top: 40px !important +} + +.pr-6 { + padding-right: 40px !important +} + +.pb-6 { + padding-bottom: 40px !important +} + +.pl-6 { + padding-left: 40px !important +} + +.px-6 { + padding-right: 40px !important; + padding-left: 40px !important +} + +.py-6 { + padding-top: 40px !important; + padding-bottom: 40px !important +} + +@media (min-width: 544px) { + .p-sm-0 { + padding: 0 !important + } + .pt-sm-0 { + padding-top: 0 !important + } + .pr-sm-0 { + padding-right: 0 !important + } + .pb-sm-0 { + padding-bottom: 0 !important + } + .pl-sm-0 { + padding-left: 0 !important + } + .px-sm-0 { + padding-right: 0 !important; + padding-left: 0 !important + } + .py-sm-0 { + padding-top: 0 !important; + padding-bottom: 0 !important + } + .p-sm-1 { + padding: 4px !important + } + .pt-sm-1 { + padding-top: 4px !important + } + .pr-sm-1 { + padding-right: 4px !important + } + .pb-sm-1 { + padding-bottom: 4px !important + } + .pl-sm-1 { + padding-left: 4px !important + } + .px-sm-1 { + padding-right: 4px !important; + padding-left: 4px !important + } + .py-sm-1 { + padding-top: 4px !important; + padding-bottom: 4px !important + } + .p-sm-2 { + padding: 8px !important + } + .pt-sm-2 { + padding-top: 8px !important + } + .pr-sm-2 { + padding-right: 8px !important + } + .pb-sm-2 { + padding-bottom: 8px !important + } + .pl-sm-2 { + padding-left: 8px !important + } + .px-sm-2 { + padding-right: 8px !important; + padding-left: 8px !important + } + .py-sm-2 { + padding-top: 8px !important; + padding-bottom: 8px !important + } + .p-sm-3 { + padding: 16px !important + } + .pt-sm-3 { + padding-top: 16px !important + } + .pr-sm-3 { + padding-right: 16px !important + } + .pb-sm-3 { + padding-bottom: 16px !important + } + .pl-sm-3 { + padding-left: 16px !important + } + .px-sm-3 { + padding-right: 16px !important; + padding-left: 16px !important + } + .py-sm-3 { + padding-top: 16px !important; + padding-bottom: 16px !important + } + .p-sm-4 { + padding: 24px !important + } + .pt-sm-4 { + padding-top: 24px !important + } + .pr-sm-4 { + padding-right: 24px !important + } + .pb-sm-4 { + padding-bottom: 24px !important + } + .pl-sm-4 { + padding-left: 24px !important + } + .px-sm-4 { + padding-right: 24px !important; + padding-left: 24px !important + } + .py-sm-4 { + padding-top: 24px !important; + padding-bottom: 24px !important + } + .p-sm-5 { + padding: 32px !important + } + .pt-sm-5 { + padding-top: 32px !important + } + .pr-sm-5 { + padding-right: 32px !important + } + .pb-sm-5 { + padding-bottom: 32px !important + } + .pl-sm-5 { + padding-left: 32px !important + } + .px-sm-5 { + padding-right: 32px !important; + padding-left: 32px !important + } + .py-sm-5 { + padding-top: 32px !important; + padding-bottom: 32px !important + } + .p-sm-6 { + padding: 40px !important + } + .pt-sm-6 { + padding-top: 40px !important + } + .pr-sm-6 { + padding-right: 40px !important + } + .pb-sm-6 { + padding-bottom: 40px !important + } + .pl-sm-6 { + padding-left: 40px !important + } + .px-sm-6 { + padding-right: 40px !important; + padding-left: 40px !important + } + .py-sm-6 { + padding-top: 40px !important; + padding-bottom: 40px !important + } +} + +@media (min-width: 768px) { + .p-md-0 { + padding: 0 !important + } + .pt-md-0 { + padding-top: 0 !important + } + .pr-md-0 { + padding-right: 0 !important + } + .pb-md-0 { + padding-bottom: 0 !important + } + .pl-md-0 { + padding-left: 0 !important + } + .px-md-0 { + padding-right: 0 !important; + padding-left: 0 !important + } + .py-md-0 { + padding-top: 0 !important; + padding-bottom: 0 !important + } + .p-md-1 { + padding: 4px !important + } + .pt-md-1 { + padding-top: 4px !important + } + .pr-md-1 { + padding-right: 4px !important + } + .pb-md-1 { + padding-bottom: 4px !important + } + .pl-md-1 { + padding-left: 4px !important + } + .px-md-1 { + padding-right: 4px !important; + padding-left: 4px !important + } + .py-md-1 { + padding-top: 4px !important; + padding-bottom: 4px !important + } + .p-md-2 { + padding: 8px !important + } + .pt-md-2 { + padding-top: 8px !important + } + .pr-md-2 { + padding-right: 8px !important + } + .pb-md-2 { + padding-bottom: 8px !important + } + .pl-md-2 { + padding-left: 8px !important + } + .px-md-2 { + padding-right: 8px !important; + padding-left: 8px !important + } + .py-md-2 { + padding-top: 8px !important; + padding-bottom: 8px !important + } + .p-md-3 { + padding: 16px !important + } + .pt-md-3 { + padding-top: 16px !important + } + .pr-md-3 { + padding-right: 16px !important + } + .pb-md-3 { + padding-bottom: 16px !important + } + .pl-md-3 { + padding-left: 16px !important + } + .px-md-3 { + padding-right: 16px !important; + padding-left: 16px !important + } + .py-md-3 { + padding-top: 16px !important; + padding-bottom: 16px !important + } + .p-md-4 { + padding: 24px !important + } + .pt-md-4 { + padding-top: 24px !important + } + .pr-md-4 { + padding-right: 24px !important + } + .pb-md-4 { + padding-bottom: 24px !important + } + .pl-md-4 { + padding-left: 24px !important + } + .px-md-4 { + padding-right: 24px !important; + padding-left: 24px !important + } + .py-md-4 { + padding-top: 24px !important; + padding-bottom: 24px !important + } + .p-md-5 { + padding: 32px !important + } + .pt-md-5 { + padding-top: 32px !important + } + .pr-md-5 { + padding-right: 32px !important + } + .pb-md-5 { + padding-bottom: 32px !important + } + .pl-md-5 { + padding-left: 32px !important + } + .px-md-5 { + padding-right: 32px !important; + padding-left: 32px !important + } + .py-md-5 { + padding-top: 32px !important; + padding-bottom: 32px !important + } + .p-md-6 { + padding: 40px !important + } + .pt-md-6 { + padding-top: 40px !important + } + .pr-md-6 { + padding-right: 40px !important + } + .pb-md-6 { + padding-bottom: 40px !important + } + .pl-md-6 { + padding-left: 40px !important + } + .px-md-6 { + padding-right: 40px !important; + padding-left: 40px !important + } + .py-md-6 { + padding-top: 40px !important; + padding-bottom: 40px !important + } +} + +@media (min-width: 1012px) { + .p-lg-0 { + padding: 0 !important + } + .pt-lg-0 { + padding-top: 0 !important + } + .pr-lg-0 { + padding-right: 0 !important + } + .pb-lg-0 { + padding-bottom: 0 !important + } + .pl-lg-0 { + padding-left: 0 !important + } + .px-lg-0 { + padding-right: 0 !important; + padding-left: 0 !important + } + .py-lg-0 { + padding-top: 0 !important; + padding-bottom: 0 !important + } + .p-lg-1 { + padding: 4px !important + } + .pt-lg-1 { + padding-top: 4px !important + } + .pr-lg-1 { + padding-right: 4px !important + } + .pb-lg-1 { + padding-bottom: 4px !important + } + .pl-lg-1 { + padding-left: 4px !important + } + .px-lg-1 { + padding-right: 4px !important; + padding-left: 4px !important + } + .py-lg-1 { + padding-top: 4px !important; + padding-bottom: 4px !important + } + .p-lg-2 { + padding: 8px !important + } + .pt-lg-2 { + padding-top: 8px !important + } + .pr-lg-2 { + padding-right: 8px !important + } + .pb-lg-2 { + padding-bottom: 8px !important + } + .pl-lg-2 { + padding-left: 8px !important + } + .px-lg-2 { + padding-right: 8px !important; + padding-left: 8px !important + } + .py-lg-2 { + padding-top: 8px !important; + padding-bottom: 8px !important + } + .p-lg-3 { + padding: 16px !important + } + .pt-lg-3 { + padding-top: 16px !important + } + .pr-lg-3 { + padding-right: 16px !important + } + .pb-lg-3 { + padding-bottom: 16px !important + } + .pl-lg-3 { + padding-left: 16px !important + } + .px-lg-3 { + padding-right: 16px !important; + padding-left: 16px !important + } + .py-lg-3 { + padding-top: 16px !important; + padding-bottom: 16px !important + } + .p-lg-4 { + padding: 24px !important + } + .pt-lg-4 { + padding-top: 24px !important + } + .pr-lg-4 { + padding-right: 24px !important + } + .pb-lg-4 { + padding-bottom: 24px !important + } + .pl-lg-4 { + padding-left: 24px !important + } + .px-lg-4 { + padding-right: 24px !important; + padding-left: 24px !important + } + .py-lg-4 { + padding-top: 24px !important; + padding-bottom: 24px !important + } + .p-lg-5 { + padding: 32px !important + } + .pt-lg-5 { + padding-top: 32px !important + } + .pr-lg-5 { + padding-right: 32px !important + } + .pb-lg-5 { + padding-bottom: 32px !important + } + .pl-lg-5 { + padding-left: 32px !important + } + .px-lg-5 { + padding-right: 32px !important; + padding-left: 32px !important + } + .py-lg-5 { + padding-top: 32px !important; + padding-bottom: 32px !important + } + .p-lg-6 { + padding: 40px !important + } + .pt-lg-6 { + padding-top: 40px !important + } + .pr-lg-6 { + padding-right: 40px !important + } + .pb-lg-6 { + padding-bottom: 40px !important + } + .pl-lg-6 { + padding-left: 40px !important + } + .px-lg-6 { + padding-right: 40px !important; + padding-left: 40px !important + } + .py-lg-6 { + padding-top: 40px !important; + padding-bottom: 40px !important + } +} + +@media (min-width: 1280px) { + .p-xl-0 { + padding: 0 !important + } + .pt-xl-0 { + padding-top: 0 !important + } + .pr-xl-0 { + padding-right: 0 !important + } + .pb-xl-0 { + padding-bottom: 0 !important + } + .pl-xl-0 { + padding-left: 0 !important + } + .px-xl-0 { + padding-right: 0 !important; + padding-left: 0 !important + } + .py-xl-0 { + padding-top: 0 !important; + padding-bottom: 0 !important + } + .p-xl-1 { + padding: 4px !important + } + .pt-xl-1 { + padding-top: 4px !important + } + .pr-xl-1 { + padding-right: 4px !important + } + .pb-xl-1 { + padding-bottom: 4px !important + } + .pl-xl-1 { + padding-left: 4px !important + } + .px-xl-1 { + padding-right: 4px !important; + padding-left: 4px !important + } + .py-xl-1 { + padding-top: 4px !important; + padding-bottom: 4px !important + } + .p-xl-2 { + padding: 8px !important + } + .pt-xl-2 { + padding-top: 8px !important + } + .pr-xl-2 { + padding-right: 8px !important + } + .pb-xl-2 { + padding-bottom: 8px !important + } + .pl-xl-2 { + padding-left: 8px !important + } + .px-xl-2 { + padding-right: 8px !important; + padding-left: 8px !important + } + .py-xl-2 { + padding-top: 8px !important; + padding-bottom: 8px !important + } + .p-xl-3 { + padding: 16px !important + } + .pt-xl-3 { + padding-top: 16px !important + } + .pr-xl-3 { + padding-right: 16px !important + } + .pb-xl-3 { + padding-bottom: 16px !important + } + .pl-xl-3 { + padding-left: 16px !important + } + .px-xl-3 { + padding-right: 16px !important; + padding-left: 16px !important + } + .py-xl-3 { + padding-top: 16px !important; + padding-bottom: 16px !important + } + .p-xl-4 { + padding: 24px !important + } + .pt-xl-4 { + padding-top: 24px !important + } + .pr-xl-4 { + padding-right: 24px !important + } + .pb-xl-4 { + padding-bottom: 24px !important + } + .pl-xl-4 { + padding-left: 24px !important + } + .px-xl-4 { + padding-right: 24px !important; + padding-left: 24px !important + } + .py-xl-4 { + padding-top: 24px !important; + padding-bottom: 24px !important + } + .p-xl-5 { + padding: 32px !important + } + .pt-xl-5 { + padding-top: 32px !important + } + .pr-xl-5 { + padding-right: 32px !important + } + .pb-xl-5 { + padding-bottom: 32px !important + } + .pl-xl-5 { + padding-left: 32px !important + } + .px-xl-5 { + padding-right: 32px !important; + padding-left: 32px !important + } + .py-xl-5 { + padding-top: 32px !important; + padding-bottom: 32px !important + } + .p-xl-6 { + padding: 40px !important + } + .pt-xl-6 { + padding-top: 40px !important + } + .pr-xl-6 { + padding-right: 40px !important + } + .pb-xl-6 { + padding-bottom: 40px !important + } + .pl-xl-6 { + padding-left: 40px !important + } + .px-xl-6 { + padding-right: 40px !important; + padding-left: 40px !important + } + .py-xl-6 { + padding-top: 40px !important; + padding-bottom: 40px !important + } +} + +.p-responsive { + padding-right: 16px !important; + padding-left: 16px !important +} + +@media (min-width: 544px) { + .p-responsive { + padding-right: 40px !important; + padding-left: 40px !important + } +} + +@media (min-width: 1012px) { + .p-responsive { + padding-right: 16px !important; + padding-left: 16px !important + } +} + +.h1 { + font-size: 26px !important +} + +@media (min-width: 768px) { + .h1 { + font-size: 32px !important + } +} + +.h2 { + font-size: 22px !important +} + +@media (min-width: 768px) { + .h2 { + font-size: 24px !important + } +} + +.h3 { + font-size: 18px !important +} + +@media (min-width: 768px) { + .h3 { + font-size: 20px !important + } +} + +.h4 { + font-size: 16px !important +} + +.h5 { + font-size: 14px !important +} + +.h6 { + font-size: 12px !important +} + +.h1, .h2, .h3, .h4, .h5, .h6 { + font-weight: 600 !important +} + +.f1 { + font-size: 26px !important +} + +@media (min-width: 768px) { + .f1 { + font-size: 32px !important + } +} + +.f2 { + font-size: 22px !important +} + +@media (min-width: 768px) { + .f2 { + font-size: 24px !important + } +} + +.f3 { + font-size: 18px !important +} + +@media (min-width: 768px) { + .f3 { + font-size: 20px !important + } +} + +.f4 { + font-size: 16px !important +} + +@media (min-width: 768px) { + .f4 { + font-size: 16px !important + } +} + +.f5 { + font-size: 14px !important +} + +.f6 { + font-size: 12px !important +} + +.f00-light { + font-size: 40px !important; + font-weight: 300 !important +} + +@media (min-width: 768px) { + .f00-light { + font-size: 48px !important + } +} + +.f0-light { + font-size: 32px !important; + font-weight: 300 !important +} + +@media (min-width: 768px) { + .f0-light { + font-size: 40px !important + } +} + +.f1-light { + font-size: 26px !important; + font-weight: 300 !important +} + +@media (min-width: 768px) { + .f1-light { + font-size: 32px !important + } +} + +.f2-light { + font-size: 22px !important; + font-weight: 300 !important +} + +@media (min-width: 768px) { + .f2-light { + font-size: 24px !important + } +} + +.f3-light { + font-size: 18px !important; + font-weight: 300 !important +} + +@media (min-width: 768px) { + .f3-light { + font-size: 20px !important + } +} + +.text-small { + font-size: 12px !important +} + +.lead { + margin-bottom: 30px; + font-size: 20px; + font-weight: 300; + color: #586069 +} + +.lh-condensed-ultra { + line-height: 1 !important +} + +.lh-condensed { + line-height: 1.25 !important +} + +.lh-default { + line-height: 1.5 !important +} + +.lh-0 { + line-height: 0 !important +} + +@media (min-width: 544px) { + .lh-sm-condensed-ultra { + line-height: 1 !important + } + .lh-sm-condensed { + line-height: 1.25 !important + } + .lh-sm-default { + line-height: 1.5 !important + } + .lh-sm-0 { + line-height: 0 !important + } +} + +@media (min-width: 768px) { + .lh-md-condensed-ultra { + line-height: 1 !important + } + .lh-md-condensed { + line-height: 1.25 !important + } + .lh-md-default { + line-height: 1.5 !important + } + .lh-md-0 { + line-height: 0 !important + } +} + +@media (min-width: 1012px) { + .lh-lg-condensed-ultra { + line-height: 1 !important + } + .lh-lg-condensed { + line-height: 1.25 !important + } + .lh-lg-default { + line-height: 1.5 !important + } + .lh-lg-0 { + line-height: 0 !important + } +} + +@media (min-width: 1280px) { + .lh-xl-condensed-ultra { + line-height: 1 !important + } + .lh-xl-condensed { + line-height: 1.25 !important + } + .lh-xl-default { + line-height: 1.5 !important + } + .lh-xl-0 { + line-height: 0 !important + } +} + +.text-right { + text-align: right !important +} + +.text-left { + text-align: left !important +} + +.text-center { + text-align: center !important +} + +@media (min-width: 544px) { + .text-sm-right { + text-align: right !important + } + .text-sm-left { + text-align: left !important + } + .text-sm-center { + text-align: center !important + } +} + +@media (min-width: 768px) { + .text-md-right { + text-align: right !important + } + .text-md-left { + text-align: left !important + } + .text-md-center { + text-align: center !important + } +} + +@media (min-width: 1012px) { + .text-lg-right { + text-align: right !important + } + .text-lg-left { + text-align: left !important + } + .text-lg-center { + text-align: center !important + } +} + +@media (min-width: 1280px) { + .text-xl-right { + text-align: right !important + } + .text-xl-left { + text-align: left !important + } + .text-xl-center { + text-align: center !important + } +} + +.text-normal { + font-weight: 400 !important +} + +.text-bold { + font-weight: 600 !important +} + +.text-italic { + font-style: italic !important +} + +.text-uppercase { + text-transform: uppercase !important +} + +.text-underline { + text-decoration: underline !important +} + +.no-underline { + text-decoration: none !important +} + +.no-wrap { + white-space: nowrap !important +} + +.ws-normal { + white-space: normal !important +} + +.break-word { + word-break: break-word !important; + word-wrap: break-word !important; + overflow-wrap: break-word !important +} + +.wb-break-all { + word-break: break-all !important +} + +.text-emphasized { + font-weight: 600; + color: #24292e +} + +.list-style-none { + list-style: none !important +} + +.text-shadow-dark { + text-shadow: 0 1px 1px rgba(27, 31, 35, 0.25), 0 1px 25px rgba(27, 31, 35, 0.75) +} + +.text-shadow-light { + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5) +} + +.text-mono { + font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace !important +} + +.user-select-none { + -webkit-user-select: none !important; + -moz-user-select: none !important; + -ms-user-select: none !important; + user-select: none !important +} + +.d-block { + display: block !important +} + +.d-flex { + display: flex !important +} + +.d-inline { + display: inline !important +} + +.d-inline-block { + display: inline-block !important +} + +.d-inline-flex { + display: inline-flex !important +} + +.d-none { + display: none !important +} + +.d-table { + display: table !important +} + +.d-table-cell { + display: table-cell !important +} + +@media (min-width: 544px) { + .d-sm-block { + display: block !important + } + .d-sm-flex { + display: flex !important + } + .d-sm-inline { + display: inline !important + } + .d-sm-inline-block { + display: inline-block !important + } + .d-sm-inline-flex { + display: inline-flex !important + } + .d-sm-none { + display: none !important + } + .d-sm-table { + display: table !important + } + .d-sm-table-cell { + display: table-cell !important + } +} + +@media (min-width: 768px) { + .d-md-block { + display: block !important + } + .d-md-flex { + display: flex !important + } + .d-md-inline { + display: inline !important + } + .d-md-inline-block { + display: inline-block !important + } + .d-md-inline-flex { + display: inline-flex !important + } + .d-md-none { + display: none !important + } + .d-md-table { + display: table !important + } + .d-md-table-cell { + display: table-cell !important + } +} + +@media (min-width: 1012px) { + .d-lg-block { + display: block !important + } + .d-lg-flex { + display: flex !important + } + .d-lg-inline { + display: inline !important + } + .d-lg-inline-block { + display: inline-block !important + } + .d-lg-inline-flex { + display: inline-flex !important + } + .d-lg-none { + display: none !important + } + .d-lg-table { + display: table !important + } + .d-lg-table-cell { + display: table-cell !important + } +} + +@media (min-width: 1280px) { + .d-xl-block { + display: block !important + } + .d-xl-flex { + display: flex !important + } + .d-xl-inline { + display: inline !important + } + .d-xl-inline-block { + display: inline-block !important + } + .d-xl-inline-flex { + display: inline-flex !important + } + .d-xl-none { + display: none !important + } + .d-xl-table { + display: table !important + } + .d-xl-table-cell { + display: table-cell !important + } +} + +.v-hidden { + visibility: hidden !important +} + +.v-visible { + visibility: visible !important +} + +@media (max-width: 543px) { + .hide-sm { + display: none !important + } +} + +@media (min-width: 544px) and (max-width: 767px) { + .hide-md { + display: none !important + } +} + +@media (min-width: 768px) and (max-width: 1011px) { + .hide-lg { + display: none !important + } +} + +@media (min-width: 1012px) { + .hide-xl { + display: none !important + } +} + +.table-fixed { + table-layout: fixed !important +} + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + word-wrap: normal; + border: 0 +} + +.show-on-focus { + position: absolute; + width: 1px; + height: 1px; + margin: 0; + overflow: hidden; + clip: rect(1px, 1px, 1px, 1px) +} + +.show-on-focus:focus { + z-index: 20; + width: auto; + height: auto; + clip: auto +} + +/*! + * @primer/css/product + * http://primer.style/css + * + * Released under MIT license. Copyright (c) 2019 GitHub Inc. + */ + +.flash { + position: relative; + padding: 20px 16px; + color: #24292e; + border-style: solid; + border-width: 1px; + border-radius: 6px +} + +.flash p:last-child { + margin-bottom: 0 +} + +.flash .octicon { + margin-right: 12px +} + +.flash-messages { + margin-bottom: 24px +} + +.flash-close { + float: right; + padding: 16px; + margin: -16px; + text-align: center; + cursor: pointer; + background: none; + border: 0; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none +} + +.flash-close:hover { + opacity: 0.7 +} + +.flash-close:active { + opacity: 0.5 +} + +.flash-close .octicon { + margin-right: 0 +} + +.flash-action { + float: right; + margin-top: -3px; + margin-left: 24px; + background-clip: padding-box +} + +.flash { + background-color: #dbedff; + border-color: rgba(4, 66, 137, 0.2) +} + +.flash .octicon { + color: rgba(4, 66, 137, 0.6) +} + +.flash-warn { + background-color: #fffbdd; + border-color: rgba(176, 136, 0, 0.2) +} + +.flash-warn .octicon { + color: #b08800 +} + +.flash-error { + background-color: #ffe3e6; + border-color: rgba(158, 28, 35, 0.2) +} + +.flash-error .octicon { + color: rgba(158, 28, 35, 0.6) +} + +.flash-success { + background-color: #dcffe4; + border-color: rgba(23, 111, 44, 0.2) +} + +.flash-success .octicon { + color: rgba(23, 111, 44, 0.8) +} + +.flash-full { + margin-top: -1px; + border-width: 1px 0; + border-radius: 0 +} + +.flash-banner { + position: fixed; + top: 0; + z-index: 90; + width: 100%; + border-top: 0; + border-right: 0; + border-left: 0; + border-radius: 0 +} + +.warning { + padding: .5em; + margin-bottom: 0.8em; + font-weight: 600; + background-color: #fffbdd +} + +.autocomplete-results { + position: absolute; + z-index: 99; + width: 100%; + max-height: 20em; + overflow-y: auto; + font-size: 13px; + list-style: none; + background: #fff; + border: 1px #e1e4e8 solid; + border-radius: 6px; + box-shadow: 0 3px 6px rgba(149, 157, 165, 0.15) +} + +.autocomplete-item { + display: block; + width: 100%; + padding: 4px 8px; + overflow: hidden; + font-weight: 600; + color: #24292e; + text-align: left; + text-decoration: none; + text-overflow: ellipsis; + white-space: nowrap; + cursor: pointer; + background-color: #fff; + border: 0 +} + +.autocomplete-item:hover, .autocomplete-item.selected, .autocomplete-item[aria-selected=true], .autocomplete-item.navigation-focus { + color: #fff; + text-decoration: none; + background-color: #0366d6 +} + +.autocomplete-item:hover *, .autocomplete-item.selected *, .autocomplete-item[aria-selected=true] *, .autocomplete-item.navigation-focus * { + color: inherit !important +} + +.suggester { + position: relative; + top: 0; + left: 0; + min-width: 180px; + padding: 0; + margin: 0; + margin-top: 24px; + list-style: none; + cursor: pointer; + background: #fff; + border: 1px #e1e4e8 solid; + border-radius: 6px; + box-shadow: 0 3px 6px rgba(149, 157, 165, 0.15) +} + +.suggester li { + display: block; + padding: 4px 8px; + font-weight: 500; + border-bottom: 1px solid #eaecef +} + +.suggester li small { + font-weight: 400; + color: #586069 +} + +.suggester li:last-child { + border-bottom: 0; + border-bottom-right-radius: 6px; + border-bottom-left-radius: 6px +} + +.suggester li:first-child { + border-top-left-radius: 6px; + border-top-right-radius: 6px +} + +.suggester li:hover, .suggester li[aria-selected="true"], .suggester li.navigation-focus { + color: #fff; + text-decoration: none; + background: #0366d6 +} + +.suggester li:hover small, .suggester li[aria-selected="true"] small, .suggester li.navigation-focus small { + color: #fff +} + +.suggester-container { + position: absolute; + top: 0; + left: 0; + z-index: 30 +} + +@media (max-width: 544px) { + .page-responsive .suggester-container { + right: 8px !important; + left: 8px !important + } + .page-responsive .suggester li { + padding: 8px 16px + } +} + +.avatar { + display: inline-block; + overflow: hidden; + line-height: 1; + vertical-align: middle; + border-radius: 6px +} + +.avatar-link { + float: left; + line-height: 1 +} + +.avatar-group-item { + display: inline-block; + margin-bottom: 3px +} + +.avatar-1, .avatar-2, .avatar-small { + border-radius: 4px +} + +.avatar-1 { + width: 16px; + height: 16px +} + +.avatar-2 { + width: 20px; + height: 20px +} + +.avatar-3 { + width: 24px; + height: 24px +} + +.avatar-4 { + width: 28px; + height: 28px +} + +.avatar-5 { + width: 32px; + height: 32px +} + +.avatar-6 { + width: 40px; + height: 40px +} + +.avatar-7 { + width: 48px; + height: 48px +} + +.avatar-8 { + width: 64px; + height: 64px +} + +.avatar-parent-child { + position: relative +} + +.avatar-child { + position: absolute; + right: -15%; + bottom: -9%; + background-color: #fff; + border-radius: 4px; + box-shadow: -2px -2px 0 rgba(255, 255, 255, 0.8) +} + +.AvatarStack { + position: relative; + min-width: 26px; + height: 20px +} + +.AvatarStack .AvatarStack-body { + position: absolute +} + +.AvatarStack.AvatarStack--two { + min-width: 36px +} + +.AvatarStack.AvatarStack--three-plus { + min-width: 46px +} + +.AvatarStack-body { + display: flex; + background: #fff +} + +.AvatarStack-body .avatar { + position: relative; + z-index: 2; + display: flex; + width: 20px; + height: 20px; + box-sizing: content-box; + margin-right: -11px; + background-color: #fff; + border-right: 1px solid #fff; + border-radius: 4px; + transition: margin 0.1s ease-in-out +} + +.AvatarStack-body .avatar:first-child { + z-index: 3 +} + +.AvatarStack-body .avatar:last-child { + z-index: 1; + border-right: 0 +} + +.AvatarStack-body .avatar img { + border-radius: 4px +} + +.AvatarStack-body .avatar:nth-child(n+4) { + display: none; + opacity: 0 +} + +.AvatarStack-body:hover .avatar { + margin-right: 3px +} + +.AvatarStack-body:hover .avatar:nth-child(n+4) { + display: flex; + opacity: 1 +} + +.AvatarStack-body:hover .avatar-more { + display: none !important +} + +.avatar.avatar-more { + z-index: 1; + margin-right: 0; + background: #f6f8fa +} + +.avatar.avatar-more::before, .avatar.avatar-more::after { + position: absolute; + display: block; + height: 20px; + content: ""; + border-radius: 2px; + outline: 1px solid #fff +} + +.avatar.avatar-more::before { + width: 17px; + background: #e1e4e8 +} + +.avatar.avatar-more::after { + width: 14px; + background: #d1d5da +} + +.AvatarStack--right .AvatarStack-body { + right: 0; + flex-direction: row-reverse +} + +.AvatarStack--right .AvatarStack-body:hover .avatar { + margin-right: 0; + margin-left: 3px +} + +.AvatarStack--right .avatar.avatar-more { + background: #d1d5da +} + +.AvatarStack--right .avatar.avatar-more::before { + width: 5px +} + +.AvatarStack--right .avatar.avatar-more::after { + width: 2px; + background: #f6f8fa +} + +.AvatarStack--right .avatar { + margin-right: 0; + margin-left: -11px; + border-right: 0; + border-left: 1px solid #fff +} + +.CircleBadge { + display: flex; + align-items: center; + justify-content: center; + background-color: #fff; + border-radius: 50%; + box-shadow: 0 3px 6px rgba(149, 157, 165, 0.15) +} + +.CircleBadge-icon { + max-width: 60% !important; + height: auto !important; + max-height: 55% !important +} + +.CircleBadge--small { + width: 56px; + height: 56px +} + +.CircleBadge--medium { + width: 96px; + height: 96px +} + +.CircleBadge--large { + width: 128px; + height: 128px +} + +.DashedConnection { + position: relative +} + +.DashedConnection::before { + position: absolute; + top: 50%; + left: 0; + width: 100%; + content: ""; + border-bottom: 2px dashed #e1e4e8 +} + +.DashedConnection .CircleBadge { + position: relative +} + +.blankslate { + position: relative; + padding: 32px; + text-align: center +} + +.blankslate code { + padding: 2px 5px 3px; + font-size: 14px; + background: #fff; + border: 1px solid #eaecef; + border-radius: 6px +} + +.blankslate img { + width: 56px; + height: 56px +} + +.blankslate-icon { + margin-right: 4px; + margin-bottom: 8px; + margin-left: 4px; + color: #a3aab1 +} + +.blankslate-capped { + border-radius: 0 0 6px 6px +} + +.blankslate-spacious { + padding: 80px 40px +} + +.blankslate-narrow { + max-width: 485px; + margin: 0 auto +} + +.blankslate-large img { + width: 80px; + height: 80px +} + +.blankslate-large h3 { + margin: 16px 0; + font-size: 24px +} + +.blankslate-large p { + font-size: 16px +} + +.blankslate-clean-background { + border: 0 +} + +.branch-name { + display: inline-block; + padding: 2px 6px; + font: 12px "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace; + color: rgba(27, 31, 35, 0.6); + background-color: #eaf5ff; + border-radius: 6px +} + +.branch-name .octicon { + margin: 1px -2px 0 0; + color: #a8bbd0 +} + +a.branch-name { + color: #0366d6 +} + +.dropdown { + position: relative +} + +.dropdown-caret { + display: inline-block; + width: 0; + height: 0; + vertical-align: middle; + content: ""; + border-style: solid; + border-width: 4px 4px 0; + border-right-color: transparent; + border-bottom-color: transparent; + border-left-color: transparent +} + +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 100; + width: 160px; + padding-top: 4px; + padding-bottom: 4px; + margin-top: 2px; + list-style: none; + background-color: #fff; + background-clip: padding-box; + border: 1px #e1e4e8 solid; + border-radius: 6px; + box-shadow: 0 8px 24px rgba(149, 157, 165, 0.2) +} + +.dropdown-menu::before, .dropdown-menu::after { + position: absolute; + display: inline-block; + content: "" +} + +.dropdown-menu::before { + border: 8px solid transparent; + border-bottom-color: rgba(27, 31, 35, 0.15) +} + +.dropdown-menu::after { + border: 7px solid transparent; + border-bottom-color: #fff +} + +.dropdown-menu>ul { + list-style: none +} + +.dropdown-menu-no-overflow { + width: auto +} + +.dropdown-menu-no-overflow .dropdown-item { + padding: 4px 16px; + overflow: visible; + text-overflow: inherit +} + +.dropdown-item { + display: block; + padding: 4px 8px 4px 16px; + overflow: hidden; + color: #24292e; + text-overflow: ellipsis; + white-space: nowrap +} + +.dropdown-item:focus, .dropdown-item:hover { + color: #fff; + text-decoration: none; + background-color: #0366d6; + outline: none +} + +.dropdown-item:focus>.octicon, .dropdown-item:hover>.octicon { + color: inherit; + opacity: 1 +} + +.dropdown-item.btn-link { + width: 100%; + text-align: left +} + +.dropdown-signout { + width: 100%; + text-align: left; + background: none; + border: 0 +} + +.dropdown-divider { + display: block; + height: 0; + margin: 8px 0; + border-top: 1px #e1e4e8 solid +} + +.dropdown-header { + padding: 4px 16px; + font-size: 12px; + color: #586069 +} + +.dropdown-item[aria-checked="false"] .octicon-check { + display: none +} + +.dropdown-menu-w { + top: 0; + right: 100%; + left: auto; + width: auto; + margin-top: 0; + margin-right: 8px +} + +.dropdown-menu-w::before { + top: 10px; + right: -16px; + left: auto; + border-color: transparent; + border-left-color: rgba(27, 31, 35, 0.15) +} + +.dropdown-menu-w::after { + top: 11px; + right: -14px; + left: auto; + border-color: transparent; + border-left-color: #fff +} + +.dropdown-menu-e { + top: 0; + left: 100%; + width: auto; + margin-top: 0; + margin-left: 8px +} + +.dropdown-menu-e::before { + top: 8px; + left: -16px; + border-color: transparent; + border-right-color: rgba(27, 31, 35, 0.15) +} + +.dropdown-menu-e::after { + top: 11px; + left: -14px; + border-color: transparent; + border-right-color: #fff +} + +.dropdown-menu-ne { + top: auto; + bottom: 100%; + left: 0; + margin-bottom: 3px +} + +.dropdown-menu-ne::before, .dropdown-menu-ne::after { + top: auto; + right: auto +} + +.dropdown-menu-ne::before { + bottom: -8px; + left: 9px; + border-top: 8px solid rgba(27, 31, 35, 0.15); + border-right: 8px solid transparent; + border-bottom: 0; + border-left: 8px solid transparent +} + +.dropdown-menu-ne::after { + bottom: -7px; + left: 10px; + border-top: 7px solid #fff; + border-right: 7px solid transparent; + border-bottom: 0; + border-left: 7px solid transparent +} + +.dropdown-menu-s { + right: 50%; + left: auto; + transform: translateX(50%) +} + +.dropdown-menu-s::before { + top: -16px; + right: 50%; + transform: translateX(50%) +} + +.dropdown-menu-s::after { + top: -14px; + right: 50%; + transform: translateX(50%) +} + +.dropdown-menu-sw { + right: 0; + left: auto +} + +.dropdown-menu-sw::before { + top: -16px; + right: 9px; + left: auto +} + +.dropdown-menu-sw::after { + top: -14px; + right: 10px; + left: auto +} + +.dropdown-menu-se::before { + top: -16px; + left: 9px +} + +.dropdown-menu-se::after { + top: -14px; + left: 10px +} + +.dropdown-menu-dark { + color: #fff; + background: #2f363d; + border-color: #444d56; + box-shadow: 0 8px 24px rgba(149, 157, 165, 0.2) +} + +.dropdown-menu-dark::before { + border-bottom-color: #444d56 +} + +.dropdown-menu-dark::after { + border-bottom-color: #2f363d +} + +.dropdown-menu-dark .dropdown-header { + color: #d1d5da +} + +.dropdown-menu-dark .dropdown-divider { + border-top-color: #444d56 +} + +.dropdown-menu-dark .dropdown-item { + color: inherit +} + +.dropdown-menu-dark.dropdown-menu-w::before { + border-color: transparent transparent transparent #444d56 +} + +.dropdown-menu-dark.dropdown-menu-w::after { + border-color: transparent transparent transparent #2f363d +} + +.dropdown-menu-dark.dropdown-menu-e::before { + border-color: transparent #444d56 transparent transparent +} + +.dropdown-menu-dark.dropdown-menu-e::after { + border-color: transparent #2f363d transparent transparent +} + +.dropdown-menu-dark.dropdown-menu-ne::before { + border-color: #444d56 transparent transparent transparent +} + +.dropdown-menu-dark.dropdown-menu-ne::after { + border-color: #2f363d transparent transparent transparent +} + +.Header { + z-index: 32; + display: flex; + padding: 16px; + font-size: 14px; + line-height: 1.5; + color: rgba(255, 255, 255, 0.7); + background-color: #24292e; + align-items: center; + flex-wrap: nowrap +} + +.Header-item { + display: flex; + margin-right: 16px; + align-self: stretch; + align-items: center; + flex-wrap: nowrap +} + +.Header-item--full { + flex: auto +} + +.Header-link { + font-weight: 600; + color: #fff; + white-space: nowrap +} + +.Header-link:hover, .Header-link:focus { + color: rgba(255, 255, 255, 0.7); + text-decoration: none +} + +.IssueLabel { + display: inline-block; + padding: 0 7px; + font-size: 12px; + font-weight: 500; + line-height: 18px; + border: 1px solid transparent; + border-radius: 2em +} + +.IssueLabel .g-emoji { + position: relative; + top: -0.05em; + display: inline-block; + font-size: 1em; + line-height: 1 +} + +.IssueLabel:hover { + text-decoration: none +} + +.IssueLabel--big { + padding-right: 10px; + padding-left: 10px; + line-height: 22px +} + +.labels { + position: relative +} + +.label, .Label { + display: inline-block; + padding: 0 7px; + font-size: 12px; + font-weight: 500; + line-height: 18px; + border: 1px solid transparent; + border-radius: 2em; + background-color: transparent !important; + border-color: #e1e4e8 +} + +.label:hover, .Label:hover { + text-decoration: none +} + +.Label--large { + padding-right: 10px; + padding-left: 10px; + line-height: 22px +} + +.Label--inline { + display: inline; + padding: 0.1667em 0.5em; + font-size: 0.9em +} + +.Label--outline, .Label--gray { + color: #586069; + border-color: #e1e4e8 +} + +.Label--gray-darker { + color: #24292e; + border-color: #6a737d +} + +.Label--yellow { + color: #735c0f; + border-color: #b08800 +} + +.Label--orange { + color: #c24e00; + border-color: #f66a0a +} + +.Label--red { + color: #cb2431; + border-color: #cb2431 +} + +.Label--outline-green, .Label--green { + color: #22863a; + border-color: #28a745 +} + +.Label--blue { + color: #0366d6; + border-color: #0366d6 +} + +.Label--purple { + color: #6f42c1; + border-color: #8a63d2 +} + +.Label--pink { + color: #d03592; + border-color: #ec6cb9 +} + +.state, .State { + display: inline-block; + padding: 5px 12px; + font-size: 14px; + font-weight: 500; + line-height: 20px; + color: #fff; + text-align: center; + white-space: nowrap; + background-color: #6a737d; + border: 1px solid transparent; + border-radius: 2em +} + +.State--green { + background-color: #28a745 +} + +.State--red { + background-color: #d73a49 +} + +.State--purple { + background-color: #6f42c1 +} + +.State--small { + padding: 0 10px; + font-size: 12px; + line-height: 24px +} + +.State--small .octicon { + width: 1em +} + +.Counter { + display: inline-block; + min-width: 20px; + padding: 0 6px; + font-size: 12px; + font-weight: 500; + line-height: 18px; + color: #24292e; + text-align: center; + background-color: rgba(209, 213, 218, 0.5); + border: 1px solid transparent; + border-radius: 2em +} + +.Counter:empty { + display: none +} + +.Counter .octicon { + vertical-align: text-top; + opacity: 0.8 +} + +.Counter--gray-light { + color: #6a737d +} + +.Counter--gray { + color: #fff; + background-color: #6a737d +} + +.diffstat { + font-size: 12px; + font-weight: 600; + color: #586069; + white-space: nowrap; + cursor: default +} + +.diffstat-block-deleted, .diffstat-block-added, .diffstat-block-neutral { + display: inline-block; + width: 8px; + height: 8px; + margin-left: 1px; + outline-offset: -1px +} + +.diffstat-block-deleted { + background-color: #cb2431; + outline: 1px dashed transparent +} + +.diffstat-block-added { + background-color: #2cbe4e; + outline: 1px solid transparent +} + +.diffstat-block-neutral { + background-color: #d1d5da; + outline: 1px dotted transparent +} + +.AnimatedEllipsis { + display: inline-block; + overflow: hidden; + vertical-align: bottom +} + +.AnimatedEllipsis::after { + display: inline-block; + content: "..."; + animation: AnimatedEllipsis-keyframes 1.2s steps(4, jump-none) infinite +} + +@keyframes AnimatedEllipsis-keyframes { + 0% { + transform: translateX(-100%) + } +} + +.markdown-body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; + font-size: 16px; + line-height: 1.5; + word-wrap: break-word +} + +.markdown-body kbd { + display: inline-block; + padding: 3px 5px; + font: 11px "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace; + line-height: 10px; + color: #444d56; + vertical-align: middle; + background-color: #fafbfc; + border: solid 1px #d1d5da; + border-bottom-color: #d1d5da; + border-radius: 6px; + box-shadow: inset 0 -1px 0 #d1d5da +} + +.markdown-body::before { + display: table; + content: "" +} + +.markdown-body::after { + display: table; + clear: both; + content: "" +} + +.markdown-body>*:first-child { + margin-top: 0 !important +} + +.markdown-body>*:last-child { + margin-bottom: 0 !important +} + +.markdown-body a:not([href]) { + color: inherit; + text-decoration: none +} + +.markdown-body .absent { + color: #cb2431 +} + +.markdown-body .anchor { + float: left; + padding-right: 4px; + margin-left: -20px; + line-height: 1 +} + +.markdown-body .anchor:focus { + outline: none +} + +.markdown-body p, .markdown-body blockquote, .markdown-body ul, .markdown-body ol, .markdown-body dl, .markdown-body table, .markdown-body pre, .markdown-body details { + margin-top: 0; + margin-bottom: 16px +} + +.markdown-body hr { + height: .25em; + padding: 0; + margin: 24px 0; + background-color: #e1e4e8; + border: 0 +} + +.markdown-body blockquote { + padding: 0 1em; + color: #6a737d; + border-left: 0.25em solid #dfe2e5 +} + +.markdown-body blockquote>:first-child { + margin-top: 0 +} + +.markdown-body blockquote>:last-child { + margin-bottom: 0 +} + +.markdown-body h1, .markdown-body h2, .markdown-body h3, .markdown-body h4, .markdown-body h5, .markdown-body h6 { + margin-top: 24px; + margin-bottom: 16px; + font-weight: 600; + line-height: 1.25 +} + +.markdown-body h1 .octicon-link, .markdown-body h2 .octicon-link, .markdown-body h3 .octicon-link, .markdown-body h4 .octicon-link, .markdown-body h5 .octicon-link, .markdown-body h6 .octicon-link { + color: #1b1f23; + vertical-align: middle; + visibility: hidden +} + +.markdown-body h1:hover .anchor, .markdown-body h2:hover .anchor, .markdown-body h3:hover .anchor, .markdown-body h4:hover .anchor, .markdown-body h5:hover .anchor, .markdown-body h6:hover .anchor { + text-decoration: none +} + +.markdown-body h1:hover .anchor .octicon-link, .markdown-body h2:hover .anchor .octicon-link, .markdown-body h3:hover .anchor .octicon-link, .markdown-body h4:hover .anchor .octicon-link, .markdown-body h5:hover .anchor .octicon-link, .markdown-body h6:hover .anchor .octicon-link { + visibility: visible +} + +.markdown-body h1 tt, .markdown-body h1 code, .markdown-body h2 tt, .markdown-body h2 code, .markdown-body h3 tt, .markdown-body h3 code, .markdown-body h4 tt, .markdown-body h4 code, .markdown-body h5 tt, .markdown-body h5 code, .markdown-body h6 tt, .markdown-body h6 code { + font-size: inherit +} + +.markdown-body h1 { + padding-bottom: 0.3em; + font-size: 2em; + border-bottom: 1px solid #eaecef +} + +.markdown-body h2 { + padding-bottom: 0.3em; + font-size: 1.5em; + border-bottom: 1px solid #eaecef +} + +.markdown-body h3 { + font-size: 1.25em +} + +.markdown-body h4 { + font-size: 1em +} + +.markdown-body h5 { + font-size: 0.875em +} + +.markdown-body h6 { + font-size: 0.85em; + color: #6a737d +} + +.markdown-body ul, .markdown-body ol { + padding-left: 2em +} + +.markdown-body ul.no-list, .markdown-body ol.no-list { + padding: 0; + list-style-type: none +} + +.markdown-body ul ul, .markdown-body ul ol, .markdown-body ol ol, .markdown-body ol ul { + margin-top: 0; + margin-bottom: 0 +} + +.markdown-body li { + word-wrap: break-all +} + +.markdown-body li>p { + margin-top: 16px +} + +.markdown-body li+li { + margin-top: .25em +} + +.markdown-body dl { + padding: 0 +} + +.markdown-body dl dt { + padding: 0; + margin-top: 16px; + font-size: 1em; + font-style: italic; + font-weight: 600 +} + +.markdown-body dl dd { + padding: 0 16px; + margin-bottom: 16px +} + +.markdown-body table { + display: block; + width: 100%; + width: -webkit-max-content; + width: -moz-max-content; + width: max-content; + max-width: 100%; + overflow: auto +} + +.markdown-body table th { + font-weight: 600 +} + +.markdown-body table th, .markdown-body table td { + padding: 6px 13px; + border: 1px solid #dfe2e5 +} + +.markdown-body table tr { + background-color: #fff; + border-top: 1px solid #c6cbd1 +} + +.markdown-body table tr:nth-child(2n) { + background-color: #f6f8fa +} + +.markdown-body table img { + background-color: transparent +} + +.markdown-body img { + max-width: 100%; + box-sizing: content-box; + background-color: #fff +} + +.markdown-body img[align=right] { + padding-left: 20px +} + +.markdown-body img[align=left] { + padding-right: 20px +} + +.markdown-body .emoji { + max-width: none; + vertical-align: text-top; + background-color: transparent +} + +.markdown-body span.frame { + display: block; + overflow: hidden +} + +.markdown-body span.frame>span { + display: block; + float: left; + width: auto; + padding: 7px; + margin: 13px 0 0; + overflow: hidden; + border: 1px solid #dfe2e5 +} + +.markdown-body span.frame span img { + display: block; + float: left +} + +.markdown-body span.frame span span { + display: block; + padding: 5px 0 0; + clear: both; + color: #24292e +} + +.markdown-body span.align-center { + display: block; + overflow: hidden; + clear: both +} + +.markdown-body span.align-center>span { + display: block; + margin: 13px auto 0; + overflow: hidden; + text-align: center +} + +.markdown-body span.align-center span img { + margin: 0 auto; + text-align: center +} + +.markdown-body span.align-right { + display: block; + overflow: hidden; + clear: both +} + +.markdown-body span.align-right>span { + display: block; + margin: 13px 0 0; + overflow: hidden; + text-align: right +} + +.markdown-body span.align-right span img { + margin: 0; + text-align: right +} + +.markdown-body span.float-left { + display: block; + float: left; + margin-right: 13px; + overflow: hidden +} + +.markdown-body span.float-left span { + margin: 13px 0 0 +} + +.markdown-body span.float-right { + display: block; + float: right; + margin-left: 13px; + overflow: hidden +} + +.markdown-body span.float-right>span { + display: block; + margin: 13px auto 0; + overflow: hidden; + text-align: right +} + +.markdown-body code, .markdown-body tt { + padding: 0.2em 0.4em; + margin: 0; + font-size: 85%; + background-color: rgba(27, 31, 35, 0.05); + border-radius: 6px +} + +.markdown-body code br, .markdown-body tt br { + display: none +} + +.markdown-body del code { + text-decoration: inherit +} + +.markdown-body pre { + word-wrap: normal +} + +.markdown-body pre>code { + padding: 0; + margin: 0; + font-size: 100%; + word-break: normal; + white-space: pre; + background: transparent; + border: 0 +} + +.markdown-body .highlight { + margin-bottom: 16px +} + +.markdown-body .highlight pre { + margin-bottom: 0; + word-break: normal +} + +.markdown-body .highlight pre, .markdown-body pre { + padding: 16px; + overflow: auto; + font-size: 85%; + line-height: 1.45; + background-color: #f6f8fa; + border-radius: 6px +} + +.markdown-body pre code, .markdown-body pre tt { + display: inline; + max-width: auto; + padding: 0; + margin: 0; + overflow: visible; + line-height: inherit; + word-wrap: normal; + background-color: transparent; + border: 0 +} + +.markdown-body .csv-data td, .markdown-body .csv-data th { + padding: 5px; + overflow: hidden; + font-size: 12px; + line-height: 1; + text-align: left; + white-space: nowrap +} + +.markdown-body .csv-data .blob-num { + padding: 10px 8px 9px; + text-align: right; + background: #fff; + border: 0 +} + +.markdown-body .csv-data tr { + border-top: 0 +} + +.markdown-body .csv-data th { + font-weight: 600; + background: #f6f8fa; + border-top: 0 +} + +.Popover { + position: absolute; + z-index: 100 +} + +.Popover-message { + position: relative; + width: 232px; + margin-right: auto; + margin-left: auto +} + +.Popover-message::before, .Popover-message::after { + position: absolute; + left: 50%; + display: inline-block; + content: "" +} + +.Popover-message::before { + top: -16px; + margin-left: -9px; + border: 8px solid transparent; + border-bottom-color: rgba(27, 31, 35, 0.15) +} + +.Popover-message::after { + top: -14px; + margin-left: -8px; + border: 7px solid transparent; + border-bottom-color: #fff +} + +.Popover-message--bottom::before, .Popover-message--bottom::after, .Popover-message--bottom-right::before, .Popover-message--bottom-right::after, .Popover-message--bottom-left::before, .Popover-message--bottom-left::after { + top: auto; + border-bottom-color: transparent +} + +.Popover-message--bottom::before, .Popover-message--bottom-right::before, .Popover-message--bottom-left::before { + bottom: -16px; + border-top-color: rgba(27, 31, 35, 0.15) +} + +.Popover-message--bottom::after, .Popover-message--bottom-right::after, .Popover-message--bottom-left::after { + bottom: -14px; + border-top-color: #fff +} + +.Popover-message--top-right, .Popover-message--bottom-right { + right: -9px; + margin-right: 0 +} + +.Popover-message--top-right::before, .Popover-message--top-right::after, .Popover-message--bottom-right::before, .Popover-message--bottom-right::after { + left: auto; + margin-left: 0 +} + +.Popover-message--top-right::before, .Popover-message--bottom-right::before { + right: 20px +} + +.Popover-message--top-right::after, .Popover-message--bottom-right::after { + right: 21px +} + +.Popover-message--top-left, .Popover-message--bottom-left { + left: -9px; + margin-left: 0 +} + +.Popover-message--top-left::before, .Popover-message--top-left::after, .Popover-message--bottom-left::before, .Popover-message--bottom-left::after { + left: 24px; + margin-left: 0 +} + +.Popover-message--top-left::after, .Popover-message--bottom-left::after { + left: 25px +} + +.Popover-message--right::before, .Popover-message--right::after, .Popover-message--right-top::before, .Popover-message--right-top::after, .Popover-message--right-bottom::before, .Popover-message--right-bottom::after, .Popover-message--left::before, .Popover-message--left::after, .Popover-message--left-top::before, .Popover-message--left-top::after, .Popover-message--left-bottom::before, .Popover-message--left-bottom::after { + top: 50%; + left: auto; + margin-left: 0; + border-bottom-color: transparent +} + +.Popover-message--right::before, .Popover-message--right-top::before, .Popover-message--right-bottom::before, .Popover-message--left::before, .Popover-message--left-top::before, .Popover-message--left-bottom::before { + margin-top: -9px +} + +.Popover-message--right::after, .Popover-message--right-top::after, .Popover-message--right-bottom::after, .Popover-message--left::after, .Popover-message--left-top::after, .Popover-message--left-bottom::after { + margin-top: -8px +} + +.Popover-message--right::before, .Popover-message--right-top::before, .Popover-message--right-bottom::before { + right: -16px; + border-left-color: rgba(27, 31, 35, 0.15) +} + +.Popover-message--right::after, .Popover-message--right-top::after, .Popover-message--right-bottom::after { + right: -14px; + border-left-color: #fff +} + +.Popover-message--left::before, .Popover-message--left-top::before, .Popover-message--left-bottom::before { + left: -16px; + border-right-color: rgba(27, 31, 35, 0.15) +} + +.Popover-message--left::after, .Popover-message--left-top::after, .Popover-message--left-bottom::after { + left: -14px; + border-right-color: #fff +} + +.Popover-message--right-top::before, .Popover-message--right-top::after, .Popover-message--left-top::before, .Popover-message--left-top::after { + top: 24px +} + +.Popover-message--right-bottom::before, .Popover-message--right-bottom::after, .Popover-message--left-bottom::before, .Popover-message--left-bottom::after { + top: auto +} + +.Popover-message--right-bottom::before, .Popover-message--left-bottom::before { + bottom: 16px +} + +.Popover-message--right-bottom::after, .Popover-message--left-bottom::after { + bottom: 17px +} + +@media (min-width: 544px) { + .Popover-message--large { + min-width: 320px + } +} + +.Progress { + display: flex; + height: 8px; + overflow: hidden; + background-color: #e1e4e8; + border-radius: 6px; + outline: 1px solid transparent +} + +.Progress--large { + height: 10px +} + +.Progress--small { + height: 5px +} + +.Progress-item { + outline: 2px solid transparent +} + +.Progress-item+.Progress-item { + margin-left: 2px +} + +.SelectMenu { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 99; + display: flex; + padding: 16px; + pointer-events: none; + flex-direction: column +} + +@media (min-width: 544px) { + .SelectMenu { + position: absolute; + top: auto; + right: auto; + bottom: auto; + left: auto; + padding: 0 + } +} + +.SelectMenu::before { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + pointer-events: none; + content: ""; + background-color: rgba(27, 31, 35, 0.5) +} + +@media (min-width: 544px) { + .SelectMenu::before { + display: none + } +} + +.SelectMenu-modal { + position: relative; + z-index: 99; + display: flex; + max-height: 66%; + margin: auto 0; + overflow: hidden; + pointer-events: auto; + flex-direction: column; + background-color: #fff; + border-radius: 12px; + box-shadow: 0 0 18px rgba(27, 31, 35, 0.4); + animation: SelectMenu-modal-animation 0.12s cubic-bezier(0, 0.1, 0.1, 1) backwards +} + +@keyframes SelectMenu-modal-animation { + 0% { + opacity: 0; + transform: scale(0.9) + } +} + +@keyframes SelectMenu-modal-animation--sm { + 0% { + opacity: 0; + transform: translateY(-16px) + } +} + +@media (min-width: 544px) { + .SelectMenu-modal { + width: 300px; + height: auto; + max-height: 480px; + margin: 8px 0 16px 0; + font-size: 12px; + border: 1px #e1e4e8 solid; + border-radius: 6px; + box-shadow: 0 8px 24px rgba(149, 157, 165, 0.2); + animation-name: SelectMenu-modal-animation--sm + } +} + +.SelectMenu-header { + display: flex; + padding: 16px; + flex: none; + align-items: center; + border-bottom: 1px solid #eaecef +} + +@media (min-width: 544px) { + .SelectMenu-header { + padding: 7px 7px 7px 16px + } +} + +.SelectMenu-title { + flex: 1; + font-size: 14px; + font-weight: 600 +} + +@media (min-width: 544px) { + .SelectMenu-title { + font-size: inherit + } +} + +.SelectMenu-closeButton { + padding: 16px; + margin: -16px; + line-height: 1; + color: #959da5; + background-color: transparent; + border: 0 +} + +@media (min-width: 544px) { + .SelectMenu-closeButton { + padding: 8px; + margin: -8px -7px + } +} + +.SelectMenu-filter { + padding: 16px; + margin: 0; + border-bottom: 1px solid #eaecef +} + +@media (min-width: 544px) { + .SelectMenu-filter { + padding: 8px + } +} + +.SelectMenu-input { + display: block; + width: 100% +} + +@media (min-width: 544px) { + .SelectMenu-input { + font-size: 14px + } +} + +.SelectMenu-list { + position: relative; + padding: 0; + margin: 0; + margin-bottom: -1px; + flex: auto; + overflow-x: hidden; + overflow-y: auto; + background-color: #fff; + -webkit-overflow-scrolling: touch +} + +.SelectMenu-item { + display: flex; + align-items: center; + width: 100%; + padding: 16px; + overflow: hidden; + color: #24292e; + text-align: left; + cursor: pointer; + background-color: #fff; + border: 0; + border-bottom: 1px solid #eaecef +} + +@media (min-width: 544px) { + .SelectMenu-item { + padding-top: 7px; + padding-bottom: 7px + } +} + +.SelectMenu-list--borderless .SelectMenu-item { + border-bottom: 0 +} + +.SelectMenu-icon { + width: 16px; + margin-right: 8px; + flex-shrink: 0 +} + +.SelectMenu-icon--check { + visibility: hidden; + transition: transform 0.12s cubic-bezier(0.5, 0.1, 1, 0.5), visibility 0s 0.12s linear; + transform: scale(0) +} + +.SelectMenu-tabs { + display: flex; + flex-shrink: 0; + overflow-x: auto; + overflow-y: hidden; + box-shadow: inset 0 -1px 0 #eaecef; + -webkit-overflow-scrolling: touch +} + +.SelectMenu-tabs::-webkit-scrollbar { + display: none +} + +@media (min-width: 544px) { + .SelectMenu-tabs { + padding: 8px 8px 0 8px + } +} + +.SelectMenu-tab { + flex: 1; + padding: 8px 16px; + font-size: 12px; + font-weight: 500; + color: #6a737d; + text-align: center; + background-color: transparent; + border: 0; + box-shadow: inset 0 -1px 0 #eaecef +} + +@media (min-width: 544px) { + .SelectMenu-tab { + flex: none; + padding: 4px 16px; + border: 1px solid transparent; + border-bottom-width: 0; + border-top-left-radius: 6px; + border-top-right-radius: 6px + } +} + +.SelectMenu-tab[aria-selected="true"] { + z-index: 1; + color: #24292e; + cursor: default; + background-color: #fff; + box-shadow: 0 0 0 1px #eaecef +} + +@media (min-width: 544px) { + .SelectMenu-tab[aria-selected="true"] { + border-color: #eaecef; + box-shadow: none + } +} + +.SelectMenu-message { + padding: 7px 16px; + text-align: center; + background-color: #fff; + border-bottom: 1px solid #eaecef +} + +.SelectMenu-blankslate, .SelectMenu-loading { + padding: 24px 16px; + text-align: center; + background-color: #fff +} + +.SelectMenu-divider { + padding: 4px 16px; + margin: 0; + font-size: 12px; + font-weight: 500; + color: #6a737d; + background-color: #f6f8fa; + border-bottom: 1px solid #eaecef +} + +.SelectMenu-list--borderless .SelectMenu-divider { + border-top: 1px solid #eaecef +} + +.SelectMenu-list--borderless .SelectMenu-divider:empty { + padding: 0; + border-top: 0 +} + +.SelectMenu-footer { + z-index: 0; + padding: 8px 16px; + font-size: 12px; + color: #6a737d; + text-align: center; + border-top: 1px solid #eaecef +} + +@media (min-width: 544px) { + .SelectMenu-footer { + padding: 7px 16px + } +} + +.SelectMenu--hasFilter .SelectMenu-modal { + height: 80%; + max-height: none; + margin-top: 0 +} + +@media (min-width: 544px) { + .SelectMenu--hasFilter .SelectMenu-modal { + height: auto; + max-height: 480px; + margin-top: 8px + } +} + +.SelectMenu-closeButton:focus, .SelectMenu-tab:focus, .SelectMenu-item:focus { + outline: 0 +} + +.SelectMenu-item:hover { + text-decoration: none +} + +.SelectMenu-item[aria-checked=true] { + font-weight: 500; + color: #24292e +} + +.SelectMenu-item[aria-checked=true] .SelectMenu-icon--check { + visibility: visible; + transition: transform 0.12s cubic-bezier(0, 0, 0.2, 1), visibility 0s linear; + transform: scale(1) +} + +.SelectMenu-item:disabled, .SelectMenu-item[aria-disabled=true] { + color: #6a737d; + pointer-events: none +} + +@media (hover: hover) { + body:not(.intent-mouse) .SelectMenu-closeButton:focus, .SelectMenu-closeButton:hover { + color: #24292e + } + .SelectMenu-closeButton:active { + color: #586069 + } + body:not(.intent-mouse) .SelectMenu-item:focus, .SelectMenu-item:hover { + background-color: #f6f8fa + } + .SelectMenu-item:active { + background-color: #fafbfc + } + body:not(.intent-mouse) .SelectMenu-tab:focus { + background-color: #dbedff + } + .SelectMenu-tab:hover { + color: #24292e + } + .SelectMenu-tab:not([aria-selected="true"]):active { + color: #24292e; + background-color: #f6f8fa + } +} + +@media (hover: none) { + .SelectMenu-item:focus, .SelectMenu-item:active { + background-color: #fafbfc + } + .SelectMenu-item { + -webkit-tap-highlight-color: rgba(209, 213, 218, 0.5) + } +} + +.Subhead { + display: flex; + padding-bottom: 8px; + margin-bottom: 16px; + border-bottom: 1px #e1e4e8 solid; + flex-flow: row wrap +} + +.Subhead--spacious { + margin-top: 40px +} + +.Subhead-heading { + font-size: 24px; + font-weight: 400; + flex: 1 1 auto +} + +.Subhead-heading--danger { + font-weight: 600; + color: #cb2431 +} + +.Subhead-description { + font-size: 14px; + color: #586069; + flex: 1 100% +} + +.Subhead-actions { + align-self: center; + justify-content: flex-end +} + +.TimelineItem { + position: relative; + display: flex; + padding: 16px 0; + margin-left: 16px +} + +.TimelineItem::before { + position: absolute; + top: 0; + bottom: 0; + left: 0; + display: block; + width: 2px; + content: ""; + background-color: #e1e4e8 +} + +.TimelineItem:target .TimelineItem-badge { + border-color: #2188ff; + box-shadow: 0 0 0.2em #c8e1ff +} + +.TimelineItem-badge { + position: relative; + z-index: 1; + display: flex; + width: 32px; + height: 32px; + margin-right: 8px; + margin-left: -15px; + color: #444d56; + align-items: center; + background-color: #e1e4e8; + border: 2px solid #fff; + border-radius: 50%; + justify-content: center; + flex-shrink: 0 +} + +.TimelineItem-body { + min-width: 0; + max-width: 100%; + margin-top: 4px; + color: #444d56; + flex: auto +} + +.TimelineItem-avatar { + position: absolute; + left: -72px; + z-index: 1 +} + +.TimelineItem-break { + position: relative; + z-index: 1; + height: 24px; + margin: 0; + margin-bottom: -16px; + margin-left: -56px; + background-color: #fff; + border: 0; + border-top: 4px solid #e1e4e8 +} + +.TimelineItem--condensed { + padding-top: 4px; + padding-bottom: 0 +} + +.TimelineItem--condensed:last-child { + padding-bottom: 16px +} + +.TimelineItem--condensed .TimelineItem-badge { + height: 16px; + margin-top: 8px; + margin-bottom: 8px; + color: #959da5; + background-color: #fff; + border: 0 +} + +.Toast { + display: flex; + margin: 8px; + color: #1b1f23; + background-color: #fff; + border-radius: 6px; + box-shadow: inset 0 0 0 1px #e1e4e8, 0 8px 24px rgba(149, 157, 165, 0.2) +} + +@media (min-width: 544px) { + .Toast { + width: -webkit-max-content; + width: -moz-max-content; + width: max-content; + max-width: 450px; + margin: 16px + } +} + +.Toast-icon { + display: flex; + align-items: center; + justify-content: center; + width: 48px; + flex-shrink: 0; + color: #fff; + background-color: #0366d6; + border-top-left-radius: inherit; + border-bottom-left-radius: inherit +} + +.Toast-content { + padding: 16px +} + +.Toast-dismissButton { + max-height: 54px; + padding: 16px; + background-color: transparent; + border: 0 +} + +.Toast-dismissButton:focus, .Toast-dismissButton:hover { + color: #586069; + outline: none +} + +.Toast-dismissButton:active { + color: #959da5 +} + +.Toast--error .Toast-icon { + background-color: #d73a49 +} + +.Toast--warning .Toast-icon { + color: #24292e; + background-color: #f9c513 +} + +.Toast--success .Toast-icon { + background-color: #28a745 +} + +.Toast--loading .Toast-icon { + background-color: #586069 +} + +.Toast--animateIn { + animation: Toast--animateIn 0.18s cubic-bezier(0.22, 0.61, 0.36, 1) backwards +} + +@keyframes Toast--animateIn { + 0% { + opacity: 0; + transform: translateY(100%) + } +} + +.Toast--animateOut { + animation: Toast--animateOut 0.18s cubic-bezier(0.55, 0.06, 0.68, 0.19) forwards +} + +@keyframes Toast--animateOut { + 100% { + pointer-events: none; + opacity: 0; + transform: translateY(100%) + } +} + +.Toast--spinner { + animation: Toast--spinner 1000ms linear infinite +} + +@keyframes Toast--spinner { + from { + transform: rotate(0deg) + } + to { + transform: rotate(360deg) + } +} + +/*! + * @primer/css/marketing + * http://primer.style/css + * + * Released under MIT license. Copyright (c) 2019 GitHub Inc. + */ + +@font-face { + font-family: Inter; + font-style: normal; + font-weight: 400; + src: local("Inter"), local("Inter-Regular"), url("/fonts/Inter-Regular.woff") format("woff"); + font-display: swap +} + +@font-face { + font-family: Inter; + font-style: normal; + font-weight: 500; + src: local("Inter Medium"), local("Inter-Medium"), url("/fonts/Inter-Medium.woff") format("woff"); + font-display: swap +} + +@font-face { + font-family: Inter; + font-style: normal; + font-weight: 600; + src: local("Inter Bold"), local("Inter-Bold"), url("/fonts/Inter-Bold.woff") format("woff"); + font-display: swap +} + +@font-face { + font-family: Inter; + font-style: normal; + font-weight: 400; + src: local("Inter"), local("Inter-Regular"), url("/fonts/Inter-Regular.woff") format("woff"); + font-display: swap +} + +@font-face { + font-family: Inter; + font-style: normal; + font-weight: 500; + src: local("Inter Medium"), local("Inter-Medium"), url("/fonts/Inter-Medium.woff") format("woff"); + font-display: swap +} + +@font-face { + font-family: Inter; + font-style: normal; + font-weight: 600; + src: local("Inter Bold"), local("Inter-Bold"), url("/fonts/Inter-Bold.woff") format("woff"); + font-display: swap +} + +.h000-mktg, .h00-mktg, .h0-mktg, .h1-mktg, .h2-mktg, .h3-mktg, .h4-mktg, .h5-mktg, .h6-mktg, .lead-mktg { + font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; + font-weight: 500 +} + +.h000-mktg { + font-size: 48px !important +} + +@media (min-width: 768px) { + .h000-mktg { + font-size: 64px !important + } +} + +.h00-mktg { + font-size: 40px !important +} + +@media (min-width: 768px) { + .h00-mktg { + font-size: 48px !important + } +} + +.h0-mktg { + font-size: 32px !important +} + +@media (min-width: 768px) { + .h0-mktg { + font-size: 40px !important + } +} + +.h1-mktg { + font-size: 26px !important +} + +@media (min-width: 768px) { + .h1-mktg { + font-size: 32px !important + } +} + +.h2-mktg { + font-size: 22px !important +} + +@media (min-width: 768px) { + .h2-mktg { + font-size: 24px !important + } +} + +.h3-mktg { + font-size: 18px !important +} + +@media (min-width: 768px) { + .h3-mktg { + font-size: 20px !important + } +} + +.h4-mktg { + font-size: 16px !important +} + +.h5-mktg { + font-size: 14px !important +} + +.h6-mktg { + font-size: 12px !important +} + +.lead-mktg { + font-size: 20px; + font-weight: 400 +} + +.pullquote { + padding-top: 0; + padding-bottom: 0; + padding-left: 8px; + margin-bottom: 24px; + font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace; + font-size: 16px; + line-height: 1.4; + color: #586069; + border-left: 3px solid #e1e4e8 +} + +@media (min-width: 768px) { + .pullquote { + padding-left: 12px; + margin-bottom: 32px; + margin-left: -15px; + font-size: 18px; + line-height: 1.5 + } +} + +@font-face { + font-family: Inter; + font-style: normal; + font-weight: 400; + src: local("Inter"), local("Inter-Regular"), url("/fonts/Inter-Regular.woff") format("woff"); + font-display: swap +} + +@font-face { + font-family: Inter; + font-style: normal; + font-weight: 500; + src: local("Inter Medium"), local("Inter-Medium"), url("/fonts/Inter-Medium.woff") format("woff"); + font-display: swap +} + +@font-face { + font-family: Inter; + font-style: normal; + font-weight: 600; + src: local("Inter Bold"), local("Inter-Bold"), url("/fonts/Inter-Bold.woff") format("woff"); + font-display: swap +} + +.btn-mktg { + display: inline-block; + padding: 16px 24px; + font-size: 14px; + font-weight: 500; + color: #fff; + white-space: nowrap; + vertical-align: middle; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + background-color: #1074e7; + border: 1px solid #1074e7; + border-radius: 6px; + transition: .2s; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none +} + +.btn-mktg:hover { + text-decoration: none; + background-color: #0366d6; + border-color: #0366d6 +} + +.btn-mktg:focus { + outline: 0; + box-shadow: 0 0 0 0.2em rgba(3, 102, 214, 0.3) +} + +.btn-mktg:disabled, .btn-mktg.disabled, .btn-mktg[aria-disabled=true] { + pointer-events: none; + cursor: default; + opacity: 0.65 +} + +.btn-primary-mktg { + background-color: #2ebc4f; + border-color: #2ebc4f +} + +.btn-primary-mktg:hover { + background-color: #28a745; + border-color: #28a745 +} + +.btn-primary-mktg:focus { + box-shadow: 0 0 0 0.2em rgba(40, 167, 69, 0.3) +} + +.btn-large-mktg { + padding: 20px 32px; + font-size: 16px +} + +.btn-outline-mktg { + color: #1074e7; + background-color: rgba(255, 255, 255, 0); + border-color: rgba(16, 116, 231, 0.5) +} + +.btn-outline-mktg:hover { + color: #0366d6; + text-decoration: none; + background-color: rgba(255, 255, 255, 0); + border-color: #1074e7 +} + +.btn-transparent { + color: #fff; + background-color: transparent; + background-image: none; + border: 1px solid rgba(255, 255, 255, 0.5) +} + +.btn-transparent:hover, .btn-transparent:active { + color: #2f363d; + background-color: #fff; + background-image: none; + border-color: #fff +} + +@font-face { + font-family: Inter; + font-style: normal; + font-weight: 400; + src: local("Inter"), local("Inter-Regular"), url("/fonts/Inter-Regular.woff") format("woff"); + font-display: swap +} + +@font-face { + font-family: Inter; + font-style: normal; + font-weight: 500; + src: local("Inter Medium"), local("Inter-Medium"), url("/fonts/Inter-Medium.woff") format("woff"); + font-display: swap +} + +@font-face { + font-family: Inter; + font-style: normal; + font-weight: 600; + src: local("Inter Bold"), local("Inter-Bold"), url("/fonts/Inter-Bold.woff") format("woff"); + font-display: swap +} + +.grayscale { + filter: grayscale(100%) +} + +.top-0 { + top: 0 !important +} + +.right-0 { + right: 0 !important +} + +.bottom-0 { + bottom: 0 !important +} + +.left-0 { + left: 0 !important +} + +.top-n0 { + top: 0 !important +} + +.right-n0 { + right: 0 !important +} + +.bottom-n0 { + bottom: 0 !important +} + +.left-n0 { + left: 0 !important +} + +.top-1 { + top: 4px !important +} + +.right-1 { + right: 4px !important +} + +.bottom-1 { + bottom: 4px !important +} + +.left-1 { + left: 4px !important +} + +.top-n1 { + top: -4px !important +} + +.right-n1 { + right: -4px !important +} + +.bottom-n1 { + bottom: -4px !important +} + +.left-n1 { + left: -4px !important +} + +.top-2 { + top: 8px !important +} + +.right-2 { + right: 8px !important +} + +.bottom-2 { + bottom: 8px !important +} + +.left-2 { + left: 8px !important +} + +.top-n2 { + top: -8px !important +} + +.right-n2 { + right: -8px !important +} + +.bottom-n2 { + bottom: -8px !important +} + +.left-n2 { + left: -8px !important +} + +.top-3 { + top: 16px !important +} + +.right-3 { + right: 16px !important +} + +.bottom-3 { + bottom: 16px !important +} + +.left-3 { + left: 16px !important +} + +.top-n3 { + top: -16px !important +} + +.right-n3 { + right: -16px !important +} + +.bottom-n3 { + bottom: -16px !important +} + +.left-n3 { + left: -16px !important +} + +.top-4 { + top: 24px !important +} + +.right-4 { + right: 24px !important +} + +.bottom-4 { + bottom: 24px !important +} + +.left-4 { + left: 24px !important +} + +.top-n4 { + top: -24px !important +} + +.right-n4 { + right: -24px !important +} + +.bottom-n4 { + bottom: -24px !important +} + +.left-n4 { + left: -24px !important +} + +.top-5 { + top: 32px !important +} + +.right-5 { + right: 32px !important +} + +.bottom-5 { + bottom: 32px !important +} + +.left-5 { + left: 32px !important +} + +.top-n5 { + top: -32px !important +} + +.right-n5 { + right: -32px !important +} + +.bottom-n5 { + bottom: -32px !important +} + +.left-n5 { + left: -32px !important +} + +.top-6 { + top: 40px !important +} + +.right-6 { + right: 40px !important +} + +.bottom-6 { + bottom: 40px !important +} + +.left-6 { + left: 40px !important +} + +.top-n6 { + top: -40px !important +} + +.right-n6 { + right: -40px !important +} + +.bottom-n6 { + bottom: -40px !important +} + +.left-n6 { + left: -40px !important +} + +.top-7 { + top: 48px !important +} + +.right-7 { + right: 48px !important +} + +.bottom-7 { + bottom: 48px !important +} + +.left-7 { + left: 48px !important +} + +.top-n7 { + top: -48px !important +} + +.right-n7 { + right: -48px !important +} + +.bottom-n7 { + bottom: -48px !important +} + +.left-n7 { + left: -48px !important +} + +.top-8 { + top: 64px !important +} + +.right-8 { + right: 64px !important +} + +.bottom-8 { + bottom: 64px !important +} + +.left-8 { + left: 64px !important +} + +.top-n8 { + top: -64px !important +} + +.right-n8 { + right: -64px !important +} + +.bottom-n8 { + bottom: -64px !important +} + +.left-n8 { + left: -64px !important +} + +.top-9 { + top: 80px !important +} + +.right-9 { + right: 80px !important +} + +.bottom-9 { + bottom: 80px !important +} + +.left-9 { + left: 80px !important +} + +.top-n9 { + top: -80px !important +} + +.right-n9 { + right: -80px !important +} + +.bottom-n9 { + bottom: -80px !important +} + +.left-n9 { + left: -80px !important +} + +.top-10 { + top: 96px !important +} + +.right-10 { + right: 96px !important +} + +.bottom-10 { + bottom: 96px !important +} + +.left-10 { + left: 96px !important +} + +.top-n10 { + top: -96px !important +} + +.right-n10 { + right: -96px !important +} + +.bottom-n10 { + bottom: -96px !important +} + +.left-n10 { + left: -96px !important +} + +.top-11 { + top: 112px !important +} + +.right-11 { + right: 112px !important +} + +.bottom-11 { + bottom: 112px !important +} + +.left-11 { + left: 112px !important +} + +.top-n11 { + top: -112px !important +} + +.right-n11 { + right: -112px !important +} + +.bottom-n11 { + bottom: -112px !important +} + +.left-n11 { + left: -112px !important +} + +.top-12 { + top: 128px !important +} + +.right-12 { + right: 128px !important +} + +.bottom-12 { + bottom: 128px !important +} + +.left-12 { + left: 128px !important +} + +.top-n12 { + top: -128px !important +} + +.right-n12 { + right: -128px !important +} + +.bottom-n12 { + bottom: -128px !important +} + +.left-n12 { + left: -128px !important +} + +@media (min-width: 768px) { + .top-md-0 { + top: 0 !important + } + .right-md-0 { + right: 0 !important + } + .bottom-md-0 { + bottom: 0 !important + } + .left-md-0 { + left: 0 !important + } + .top-md-n0 { + top: 0 !important + } + .right-md-n0 { + right: 0 !important + } + .bottom-md-n0 { + bottom: 0 !important + } + .left-md-n0 { + left: 0 !important + } + .top-md-1 { + top: 4px !important + } + .right-md-1 { + right: 4px !important + } + .bottom-md-1 { + bottom: 4px !important + } + .left-md-1 { + left: 4px !important + } + .top-md-n1 { + top: -4px !important + } + .right-md-n1 { + right: -4px !important + } + .bottom-md-n1 { + bottom: -4px !important + } + .left-md-n1 { + left: -4px !important + } + .top-md-2 { + top: 8px !important + } + .right-md-2 { + right: 8px !important + } + .bottom-md-2 { + bottom: 8px !important + } + .left-md-2 { + left: 8px !important + } + .top-md-n2 { + top: -8px !important + } + .right-md-n2 { + right: -8px !important + } + .bottom-md-n2 { + bottom: -8px !important + } + .left-md-n2 { + left: -8px !important + } + .top-md-3 { + top: 16px !important + } + .right-md-3 { + right: 16px !important + } + .bottom-md-3 { + bottom: 16px !important + } + .left-md-3 { + left: 16px !important + } + .top-md-n3 { + top: -16px !important + } + .right-md-n3 { + right: -16px !important + } + .bottom-md-n3 { + bottom: -16px !important + } + .left-md-n3 { + left: -16px !important + } + .top-md-4 { + top: 24px !important + } + .right-md-4 { + right: 24px !important + } + .bottom-md-4 { + bottom: 24px !important + } + .left-md-4 { + left: 24px !important + } + .top-md-n4 { + top: -24px !important + } + .right-md-n4 { + right: -24px !important + } + .bottom-md-n4 { + bottom: -24px !important + } + .left-md-n4 { + left: -24px !important + } + .top-md-5 { + top: 32px !important + } + .right-md-5 { + right: 32px !important + } + .bottom-md-5 { + bottom: 32px !important + } + .left-md-5 { + left: 32px !important + } + .top-md-n5 { + top: -32px !important + } + .right-md-n5 { + right: -32px !important + } + .bottom-md-n5 { + bottom: -32px !important + } + .left-md-n5 { + left: -32px !important + } + .top-md-6 { + top: 40px !important + } + .right-md-6 { + right: 40px !important + } + .bottom-md-6 { + bottom: 40px !important + } + .left-md-6 { + left: 40px !important + } + .top-md-n6 { + top: -40px !important + } + .right-md-n6 { + right: -40px !important + } + .bottom-md-n6 { + bottom: -40px !important + } + .left-md-n6 { + left: -40px !important + } + .top-md-7 { + top: 48px !important + } + .right-md-7 { + right: 48px !important + } + .bottom-md-7 { + bottom: 48px !important + } + .left-md-7 { + left: 48px !important + } + .top-md-n7 { + top: -48px !important + } + .right-md-n7 { + right: -48px !important + } + .bottom-md-n7 { + bottom: -48px !important + } + .left-md-n7 { + left: -48px !important + } + .top-md-8 { + top: 64px !important + } + .right-md-8 { + right: 64px !important + } + .bottom-md-8 { + bottom: 64px !important + } + .left-md-8 { + left: 64px !important + } + .top-md-n8 { + top: -64px !important + } + .right-md-n8 { + right: -64px !important + } + .bottom-md-n8 { + bottom: -64px !important + } + .left-md-n8 { + left: -64px !important + } + .top-md-9 { + top: 80px !important + } + .right-md-9 { + right: 80px !important + } + .bottom-md-9 { + bottom: 80px !important + } + .left-md-9 { + left: 80px !important + } + .top-md-n9 { + top: -80px !important + } + .right-md-n9 { + right: -80px !important + } + .bottom-md-n9 { + bottom: -80px !important + } + .left-md-n9 { + left: -80px !important + } + .top-md-10 { + top: 96px !important + } + .right-md-10 { + right: 96px !important + } + .bottom-md-10 { + bottom: 96px !important + } + .left-md-10 { + left: 96px !important + } + .top-md-n10 { + top: -96px !important + } + .right-md-n10 { + right: -96px !important + } + .bottom-md-n10 { + bottom: -96px !important + } + .left-md-n10 { + left: -96px !important + } + .top-md-11 { + top: 112px !important + } + .right-md-11 { + right: 112px !important + } + .bottom-md-11 { + bottom: 112px !important + } + .left-md-11 { + left: 112px !important + } + .top-md-n11 { + top: -112px !important + } + .right-md-n11 { + right: -112px !important + } + .bottom-md-n11 { + bottom: -112px !important + } + .left-md-n11 { + left: -112px !important + } + .top-md-12 { + top: 128px !important + } + .right-md-12 { + right: 128px !important + } + .bottom-md-12 { + bottom: 128px !important + } + .left-md-12 { + left: 128px !important + } + .top-md-n12 { + top: -128px !important + } + .right-md-n12 { + right: -128px !important + } + .bottom-md-n12 { + bottom: -128px !important + } + .left-md-n12 { + left: -128px !important + } +} + +@media (min-width: 1012px) { + .top-lg-0 { + top: 0 !important + } + .right-lg-0 { + right: 0 !important + } + .bottom-lg-0 { + bottom: 0 !important + } + .left-lg-0 { + left: 0 !important + } + .top-lg-n0 { + top: 0 !important + } + .right-lg-n0 { + right: 0 !important + } + .bottom-lg-n0 { + bottom: 0 !important + } + .left-lg-n0 { + left: 0 !important + } + .top-lg-1 { + top: 4px !important + } + .right-lg-1 { + right: 4px !important + } + .bottom-lg-1 { + bottom: 4px !important + } + .left-lg-1 { + left: 4px !important + } + .top-lg-n1 { + top: -4px !important + } + .right-lg-n1 { + right: -4px !important + } + .bottom-lg-n1 { + bottom: -4px !important + } + .left-lg-n1 { + left: -4px !important + } + .top-lg-2 { + top: 8px !important + } + .right-lg-2 { + right: 8px !important + } + .bottom-lg-2 { + bottom: 8px !important + } + .left-lg-2 { + left: 8px !important + } + .top-lg-n2 { + top: -8px !important + } + .right-lg-n2 { + right: -8px !important + } + .bottom-lg-n2 { + bottom: -8px !important + } + .left-lg-n2 { + left: -8px !important + } + .top-lg-3 { + top: 16px !important + } + .right-lg-3 { + right: 16px !important + } + .bottom-lg-3 { + bottom: 16px !important + } + .left-lg-3 { + left: 16px !important + } + .top-lg-n3 { + top: -16px !important + } + .right-lg-n3 { + right: -16px !important + } + .bottom-lg-n3 { + bottom: -16px !important + } + .left-lg-n3 { + left: -16px !important + } + .top-lg-4 { + top: 24px !important + } + .right-lg-4 { + right: 24px !important + } + .bottom-lg-4 { + bottom: 24px !important + } + .left-lg-4 { + left: 24px !important + } + .top-lg-n4 { + top: -24px !important + } + .right-lg-n4 { + right: -24px !important + } + .bottom-lg-n4 { + bottom: -24px !important + } + .left-lg-n4 { + left: -24px !important + } + .top-lg-5 { + top: 32px !important + } + .right-lg-5 { + right: 32px !important + } + .bottom-lg-5 { + bottom: 32px !important + } + .left-lg-5 { + left: 32px !important + } + .top-lg-n5 { + top: -32px !important + } + .right-lg-n5 { + right: -32px !important + } + .bottom-lg-n5 { + bottom: -32px !important + } + .left-lg-n5 { + left: -32px !important + } + .top-lg-6 { + top: 40px !important + } + .right-lg-6 { + right: 40px !important + } + .bottom-lg-6 { + bottom: 40px !important + } + .left-lg-6 { + left: 40px !important + } + .top-lg-n6 { + top: -40px !important + } + .right-lg-n6 { + right: -40px !important + } + .bottom-lg-n6 { + bottom: -40px !important + } + .left-lg-n6 { + left: -40px !important + } + .top-lg-7 { + top: 48px !important + } + .right-lg-7 { + right: 48px !important + } + .bottom-lg-7 { + bottom: 48px !important + } + .left-lg-7 { + left: 48px !important + } + .top-lg-n7 { + top: -48px !important + } + .right-lg-n7 { + right: -48px !important + } + .bottom-lg-n7 { + bottom: -48px !important + } + .left-lg-n7 { + left: -48px !important + } + .top-lg-8 { + top: 64px !important + } + .right-lg-8 { + right: 64px !important + } + .bottom-lg-8 { + bottom: 64px !important + } + .left-lg-8 { + left: 64px !important + } + .top-lg-n8 { + top: -64px !important + } + .right-lg-n8 { + right: -64px !important + } + .bottom-lg-n8 { + bottom: -64px !important + } + .left-lg-n8 { + left: -64px !important + } + .top-lg-9 { + top: 80px !important + } + .right-lg-9 { + right: 80px !important + } + .bottom-lg-9 { + bottom: 80px !important + } + .left-lg-9 { + left: 80px !important + } + .top-lg-n9 { + top: -80px !important + } + .right-lg-n9 { + right: -80px !important + } + .bottom-lg-n9 { + bottom: -80px !important + } + .left-lg-n9 { + left: -80px !important + } + .top-lg-10 { + top: 96px !important + } + .right-lg-10 { + right: 96px !important + } + .bottom-lg-10 { + bottom: 96px !important + } + .left-lg-10 { + left: 96px !important + } + .top-lg-n10 { + top: -96px !important + } + .right-lg-n10 { + right: -96px !important + } + .bottom-lg-n10 { + bottom: -96px !important + } + .left-lg-n10 { + left: -96px !important + } + .top-lg-11 { + top: 112px !important + } + .right-lg-11 { + right: 112px !important + } + .bottom-lg-11 { + bottom: 112px !important + } + .left-lg-11 { + left: 112px !important + } + .top-lg-n11 { + top: -112px !important + } + .right-lg-n11 { + right: -112px !important + } + .bottom-lg-n11 { + bottom: -112px !important + } + .left-lg-n11 { + left: -112px !important + } + .top-lg-12 { + top: 128px !important + } + .right-lg-12 { + right: 128px !important + } + .bottom-lg-12 { + bottom: 128px !important + } + .left-lg-12 { + left: 128px !important + } + .top-lg-n12 { + top: -128px !important + } + .right-lg-n12 { + right: -128px !important + } + .bottom-lg-n12 { + bottom: -128px !important + } + .left-lg-n12 { + left: -128px !important + } +} + +.offset-n1 { + margin-left: -8.33333% +} + +.offset-n2 { + margin-left: -16.66667% +} + +.offset-n3 { + margin-left: -25% +} + +.offset-n4 { + margin-left: -33.33333% +} + +.offset-n5 { + margin-left: -41.66667% +} + +.offset-n6 { + margin-left: -50% +} + +.offset-n7 { + margin-left: -58.33333% +} + +@media (min-width: 544px) { + .offset-sm-n1 { + margin-left: -8.33333% + } + .offset-sm-n2 { + margin-left: -16.66667% + } + .offset-sm-n3 { + margin-left: -25% + } + .offset-sm-n4 { + margin-left: -33.33333% + } + .offset-sm-n5 { + margin-left: -41.66667% + } + .offset-sm-n6 { + margin-left: -50% + } + .offset-sm-n7 { + margin-left: -58.33333% + } +} + +@media (min-width: 768px) { + .offset-md-n1 { + margin-left: -8.33333% + } + .offset-md-n2 { + margin-left: -16.66667% + } + .offset-md-n3 { + margin-left: -25% + } + .offset-md-n4 { + margin-left: -33.33333% + } + .offset-md-n5 { + margin-left: -41.66667% + } + .offset-md-n6 { + margin-left: -50% + } + .offset-md-n7 { + margin-left: -58.33333% + } +} + +@media (min-width: 1012px) { + .offset-lg-n1 { + margin-left: -8.33333% + } + .offset-lg-n2 { + margin-left: -16.66667% + } + .offset-lg-n3 { + margin-left: -25% + } + .offset-lg-n4 { + margin-left: -33.33333% + } + .offset-lg-n5 { + margin-left: -41.66667% + } + .offset-lg-n6 { + margin-left: -50% + } + .offset-lg-n7 { + margin-left: -58.33333% + } +} + +@media (min-width: 1280px) { + .offset-xl-n1 { + margin-left: -8.33333% + } + .offset-xl-n2 { + margin-left: -16.66667% + } + .offset-xl-n3 { + margin-left: -25% + } + .offset-xl-n4 { + margin-left: -33.33333% + } + .offset-xl-n5 { + margin-left: -41.66667% + } + .offset-xl-n6 { + margin-left: -50% + } + .offset-xl-n7 { + margin-left: -58.33333% + } +} + +.mt-0 { + margin-top: 0 !important +} + +.mb-0 { + margin-bottom: 0 !important +} + +.my-0 { + margin-top: 0 !important; + margin-bottom: 0 !important +} + +.mt-1 { + margin-top: 4px !important +} + +.mb-1 { + margin-bottom: 4px !important +} + +.my-1 { + margin-top: 4px !important; + margin-bottom: 4px !important +} + +.mt-2 { + margin-top: 8px !important +} + +.mb-2 { + margin-bottom: 8px !important +} + +.my-2 { + margin-top: 8px !important; + margin-bottom: 8px !important +} + +.mt-3 { + margin-top: 16px !important +} + +.mb-3 { + margin-bottom: 16px !important +} + +.my-3 { + margin-top: 16px !important; + margin-bottom: 16px !important +} + +.mt-4 { + margin-top: 24px !important +} + +.mb-4 { + margin-bottom: 24px !important +} + +.my-4 { + margin-top: 24px !important; + margin-bottom: 24px !important +} + +.mt-5 { + margin-top: 32px !important +} + +.mb-5 { + margin-bottom: 32px !important +} + +.my-5 { + margin-top: 32px !important; + margin-bottom: 32px !important +} + +.mt-6 { + margin-top: 40px !important +} + +.mb-6 { + margin-bottom: 40px !important +} + +.my-6 { + margin-top: 40px !important; + margin-bottom: 40px !important +} + +.mt-7 { + margin-top: 48px !important +} + +.mb-7 { + margin-bottom: 48px !important +} + +.my-7 { + margin-top: 48px !important; + margin-bottom: 48px !important +} + +.mt-8 { + margin-top: 64px !important +} + +.mb-8 { + margin-bottom: 64px !important +} + +.my-8 { + margin-top: 64px !important; + margin-bottom: 64px !important +} + +.mt-9 { + margin-top: 80px !important +} + +.mb-9 { + margin-bottom: 80px !important +} + +.my-9 { + margin-top: 80px !important; + margin-bottom: 80px !important +} + +.mt-10 { + margin-top: 96px !important +} + +.mb-10 { + margin-bottom: 96px !important +} + +.my-10 { + margin-top: 96px !important; + margin-bottom: 96px !important +} + +.mt-11 { + margin-top: 112px !important +} + +.mb-11 { + margin-bottom: 112px !important +} + +.my-11 { + margin-top: 112px !important; + margin-bottom: 112px !important +} + +.mt-12 { + margin-top: 128px !important +} + +.mb-12 { + margin-bottom: 128px !important +} + +.my-12 { + margin-top: 128px !important; + margin-bottom: 128px !important +} + +@media (min-width: 544px) { + .mt-sm-0 { + margin-top: 0 !important + } + .mb-sm-0 { + margin-bottom: 0 !important + } + .my-sm-0 { + margin-top: 0 !important; + margin-bottom: 0 !important + } + .mt-sm-1 { + margin-top: 4px !important + } + .mb-sm-1 { + margin-bottom: 4px !important + } + .my-sm-1 { + margin-top: 4px !important; + margin-bottom: 4px !important + } + .mt-sm-2 { + margin-top: 8px !important + } + .mb-sm-2 { + margin-bottom: 8px !important + } + .my-sm-2 { + margin-top: 8px !important; + margin-bottom: 8px !important + } + .mt-sm-3 { + margin-top: 16px !important + } + .mb-sm-3 { + margin-bottom: 16px !important + } + .my-sm-3 { + margin-top: 16px !important; + margin-bottom: 16px !important + } + .mt-sm-4 { + margin-top: 24px !important + } + .mb-sm-4 { + margin-bottom: 24px !important + } + .my-sm-4 { + margin-top: 24px !important; + margin-bottom: 24px !important + } + .mt-sm-5 { + margin-top: 32px !important + } + .mb-sm-5 { + margin-bottom: 32px !important + } + .my-sm-5 { + margin-top: 32px !important; + margin-bottom: 32px !important + } + .mt-sm-6 { + margin-top: 40px !important + } + .mb-sm-6 { + margin-bottom: 40px !important + } + .my-sm-6 { + margin-top: 40px !important; + margin-bottom: 40px !important + } + .mt-sm-7 { + margin-top: 48px !important + } + .mb-sm-7 { + margin-bottom: 48px !important + } + .my-sm-7 { + margin-top: 48px !important; + margin-bottom: 48px !important + } + .mt-sm-8 { + margin-top: 64px !important + } + .mb-sm-8 { + margin-bottom: 64px !important + } + .my-sm-8 { + margin-top: 64px !important; + margin-bottom: 64px !important + } + .mt-sm-9 { + margin-top: 80px !important + } + .mb-sm-9 { + margin-bottom: 80px !important + } + .my-sm-9 { + margin-top: 80px !important; + margin-bottom: 80px !important + } + .mt-sm-10 { + margin-top: 96px !important + } + .mb-sm-10 { + margin-bottom: 96px !important + } + .my-sm-10 { + margin-top: 96px !important; + margin-bottom: 96px !important + } + .mt-sm-11 { + margin-top: 112px !important + } + .mb-sm-11 { + margin-bottom: 112px !important + } + .my-sm-11 { + margin-top: 112px !important; + margin-bottom: 112px !important + } + .mt-sm-12 { + margin-top: 128px !important + } + .mb-sm-12 { + margin-bottom: 128px !important + } + .my-sm-12 { + margin-top: 128px !important; + margin-bottom: 128px !important + } +} + +@media (min-width: 768px) { + .mt-md-0 { + margin-top: 0 !important + } + .mb-md-0 { + margin-bottom: 0 !important + } + .my-md-0 { + margin-top: 0 !important; + margin-bottom: 0 !important + } + .mt-md-1 { + margin-top: 4px !important + } + .mb-md-1 { + margin-bottom: 4px !important + } + .my-md-1 { + margin-top: 4px !important; + margin-bottom: 4px !important + } + .mt-md-2 { + margin-top: 8px !important + } + .mb-md-2 { + margin-bottom: 8px !important + } + .my-md-2 { + margin-top: 8px !important; + margin-bottom: 8px !important + } + .mt-md-3 { + margin-top: 16px !important + } + .mb-md-3 { + margin-bottom: 16px !important + } + .my-md-3 { + margin-top: 16px !important; + margin-bottom: 16px !important + } + .mt-md-4 { + margin-top: 24px !important + } + .mb-md-4 { + margin-bottom: 24px !important + } + .my-md-4 { + margin-top: 24px !important; + margin-bottom: 24px !important + } + .mt-md-5 { + margin-top: 32px !important + } + .mb-md-5 { + margin-bottom: 32px !important + } + .my-md-5 { + margin-top: 32px !important; + margin-bottom: 32px !important + } + .mt-md-6 { + margin-top: 40px !important + } + .mb-md-6 { + margin-bottom: 40px !important + } + .my-md-6 { + margin-top: 40px !important; + margin-bottom: 40px !important + } + .mt-md-7 { + margin-top: 48px !important + } + .mb-md-7 { + margin-bottom: 48px !important + } + .my-md-7 { + margin-top: 48px !important; + margin-bottom: 48px !important + } + .mt-md-8 { + margin-top: 64px !important + } + .mb-md-8 { + margin-bottom: 64px !important + } + .my-md-8 { + margin-top: 64px !important; + margin-bottom: 64px !important + } + .mt-md-9 { + margin-top: 80px !important + } + .mb-md-9 { + margin-bottom: 80px !important + } + .my-md-9 { + margin-top: 80px !important; + margin-bottom: 80px !important + } + .mt-md-10 { + margin-top: 96px !important + } + .mb-md-10 { + margin-bottom: 96px !important + } + .my-md-10 { + margin-top: 96px !important; + margin-bottom: 96px !important + } + .mt-md-11 { + margin-top: 112px !important + } + .mb-md-11 { + margin-bottom: 112px !important + } + .my-md-11 { + margin-top: 112px !important; + margin-bottom: 112px !important + } + .mt-md-12 { + margin-top: 128px !important + } + .mb-md-12 { + margin-bottom: 128px !important + } + .my-md-12 { + margin-top: 128px !important; + margin-bottom: 128px !important + } +} + +@media (min-width: 1012px) { + .mt-lg-0 { + margin-top: 0 !important + } + .mb-lg-0 { + margin-bottom: 0 !important + } + .my-lg-0 { + margin-top: 0 !important; + margin-bottom: 0 !important + } + .mt-lg-1 { + margin-top: 4px !important + } + .mb-lg-1 { + margin-bottom: 4px !important + } + .my-lg-1 { + margin-top: 4px !important; + margin-bottom: 4px !important + } + .mt-lg-2 { + margin-top: 8px !important + } + .mb-lg-2 { + margin-bottom: 8px !important + } + .my-lg-2 { + margin-top: 8px !important; + margin-bottom: 8px !important + } + .mt-lg-3 { + margin-top: 16px !important + } + .mb-lg-3 { + margin-bottom: 16px !important + } + .my-lg-3 { + margin-top: 16px !important; + margin-bottom: 16px !important + } + .mt-lg-4 { + margin-top: 24px !important + } + .mb-lg-4 { + margin-bottom: 24px !important + } + .my-lg-4 { + margin-top: 24px !important; + margin-bottom: 24px !important + } + .mt-lg-5 { + margin-top: 32px !important + } + .mb-lg-5 { + margin-bottom: 32px !important + } + .my-lg-5 { + margin-top: 32px !important; + margin-bottom: 32px !important + } + .mt-lg-6 { + margin-top: 40px !important + } + .mb-lg-6 { + margin-bottom: 40px !important + } + .my-lg-6 { + margin-top: 40px !important; + margin-bottom: 40px !important + } + .mt-lg-7 { + margin-top: 48px !important + } + .mb-lg-7 { + margin-bottom: 48px !important + } + .my-lg-7 { + margin-top: 48px !important; + margin-bottom: 48px !important + } + .mt-lg-8 { + margin-top: 64px !important + } + .mb-lg-8 { + margin-bottom: 64px !important + } + .my-lg-8 { + margin-top: 64px !important; + margin-bottom: 64px !important + } + .mt-lg-9 { + margin-top: 80px !important + } + .mb-lg-9 { + margin-bottom: 80px !important + } + .my-lg-9 { + margin-top: 80px !important; + margin-bottom: 80px !important + } + .mt-lg-10 { + margin-top: 96px !important + } + .mb-lg-10 { + margin-bottom: 96px !important + } + .my-lg-10 { + margin-top: 96px !important; + margin-bottom: 96px !important + } + .mt-lg-11 { + margin-top: 112px !important + } + .mb-lg-11 { + margin-bottom: 112px !important + } + .my-lg-11 { + margin-top: 112px !important; + margin-bottom: 112px !important + } + .mt-lg-12 { + margin-top: 128px !important + } + .mb-lg-12 { + margin-bottom: 128px !important + } + .my-lg-12 { + margin-top: 128px !important; + margin-bottom: 128px !important + } +} + +@media (min-width: 1280px) { + .mt-xl-0 { + margin-top: 0 !important + } + .mb-xl-0 { + margin-bottom: 0 !important + } + .my-xl-0 { + margin-top: 0 !important; + margin-bottom: 0 !important + } + .mt-xl-1 { + margin-top: 4px !important + } + .mb-xl-1 { + margin-bottom: 4px !important + } + .my-xl-1 { + margin-top: 4px !important; + margin-bottom: 4px !important + } + .mt-xl-2 { + margin-top: 8px !important + } + .mb-xl-2 { + margin-bottom: 8px !important + } + .my-xl-2 { + margin-top: 8px !important; + margin-bottom: 8px !important + } + .mt-xl-3 { + margin-top: 16px !important + } + .mb-xl-3 { + margin-bottom: 16px !important + } + .my-xl-3 { + margin-top: 16px !important; + margin-bottom: 16px !important + } + .mt-xl-4 { + margin-top: 24px !important + } + .mb-xl-4 { + margin-bottom: 24px !important + } + .my-xl-4 { + margin-top: 24px !important; + margin-bottom: 24px !important + } + .mt-xl-5 { + margin-top: 32px !important + } + .mb-xl-5 { + margin-bottom: 32px !important + } + .my-xl-5 { + margin-top: 32px !important; + margin-bottom: 32px !important + } + .mt-xl-6 { + margin-top: 40px !important + } + .mb-xl-6 { + margin-bottom: 40px !important + } + .my-xl-6 { + margin-top: 40px !important; + margin-bottom: 40px !important + } + .mt-xl-7 { + margin-top: 48px !important + } + .mb-xl-7 { + margin-bottom: 48px !important + } + .my-xl-7 { + margin-top: 48px !important; + margin-bottom: 48px !important + } + .mt-xl-8 { + margin-top: 64px !important + } + .mb-xl-8 { + margin-bottom: 64px !important + } + .my-xl-8 { + margin-top: 64px !important; + margin-bottom: 64px !important + } + .mt-xl-9 { + margin-top: 80px !important + } + .mb-xl-9 { + margin-bottom: 80px !important + } + .my-xl-9 { + margin-top: 80px !important; + margin-bottom: 80px !important + } + .mt-xl-10 { + margin-top: 96px !important + } + .mb-xl-10 { + margin-bottom: 96px !important + } + .my-xl-10 { + margin-top: 96px !important; + margin-bottom: 96px !important + } + .mt-xl-11 { + margin-top: 112px !important + } + .mb-xl-11 { + margin-bottom: 112px !important + } + .my-xl-11 { + margin-top: 112px !important; + margin-bottom: 112px !important + } + .mt-xl-12 { + margin-top: 128px !important + } + .mb-xl-12 { + margin-bottom: 128px !important + } + .my-xl-12 { + margin-top: 128px !important; + margin-bottom: 128px !important + } +} + +.p-0 { + padding: 0 !important +} + +.pt-0 { + padding-top: 0 !important +} + +.pr-0 { + padding-right: 0 !important +} + +.pb-0 { + padding-bottom: 0 !important +} + +.pl-0 { + padding-left: 0 !important +} + +.py-0 { + padding-top: 0 !important; + padding-bottom: 0 !important +} + +.p-1 { + padding: 4px !important +} + +.pt-1 { + padding-top: 4px !important +} + +.pr-1 { + padding-right: 4px !important +} + +.pb-1 { + padding-bottom: 4px !important +} + +.pl-1 { + padding-left: 4px !important +} + +.py-1 { + padding-top: 4px !important; + padding-bottom: 4px !important +} + +.p-2 { + padding: 8px !important +} + +.pt-2 { + padding-top: 8px !important +} + +.pr-2 { + padding-right: 8px !important +} + +.pb-2 { + padding-bottom: 8px !important +} + +.pl-2 { + padding-left: 8px !important +} + +.py-2 { + padding-top: 8px !important; + padding-bottom: 8px !important +} + +.p-3 { + padding: 16px !important +} + +.pt-3 { + padding-top: 16px !important +} + +.pr-3 { + padding-right: 16px !important +} + +.pb-3 { + padding-bottom: 16px !important +} + +.pl-3 { + padding-left: 16px !important +} + +.py-3 { + padding-top: 16px !important; + padding-bottom: 16px !important +} + +.p-4 { + padding: 24px !important +} + +.pt-4 { + padding-top: 24px !important +} + +.pr-4 { + padding-right: 24px !important +} + +.pb-4 { + padding-bottom: 24px !important +} + +.pl-4 { + padding-left: 24px !important +} + +.py-4 { + padding-top: 24px !important; + padding-bottom: 24px !important +} + +.p-5 { + padding: 32px !important +} + +.pt-5 { + padding-top: 32px !important +} + +.pr-5 { + padding-right: 32px !important +} + +.pb-5 { + padding-bottom: 32px !important +} + +.pl-5 { + padding-left: 32px !important +} + +.py-5 { + padding-top: 32px !important; + padding-bottom: 32px !important +} + +.p-6 { + padding: 40px !important +} + +.pt-6 { + padding-top: 40px !important +} + +.pr-6 { + padding-right: 40px !important +} + +.pb-6 { + padding-bottom: 40px !important +} + +.pl-6 { + padding-left: 40px !important +} + +.py-6 { + padding-top: 40px !important; + padding-bottom: 40px !important +} + +.p-7 { + padding: 48px !important +} + +.pt-7 { + padding-top: 48px !important +} + +.pr-7 { + padding-right: 48px !important +} + +.pb-7 { + padding-bottom: 48px !important +} + +.pl-7 { + padding-left: 48px !important +} + +.py-7 { + padding-top: 48px !important; + padding-bottom: 48px !important +} + +.p-8 { + padding: 64px !important +} + +.pt-8 { + padding-top: 64px !important +} + +.pr-8 { + padding-right: 64px !important +} + +.pb-8 { + padding-bottom: 64px !important +} + +.pl-8 { + padding-left: 64px !important +} + +.py-8 { + padding-top: 64px !important; + padding-bottom: 64px !important +} + +.p-9 { + padding: 80px !important +} + +.pt-9 { + padding-top: 80px !important +} + +.pr-9 { + padding-right: 80px !important +} + +.pb-9 { + padding-bottom: 80px !important +} + +.pl-9 { + padding-left: 80px !important +} + +.py-9 { + padding-top: 80px !important; + padding-bottom: 80px !important +} + +.p-10 { + padding: 96px !important +} + +.pt-10 { + padding-top: 96px !important +} + +.pr-10 { + padding-right: 96px !important +} + +.pb-10 { + padding-bottom: 96px !important +} + +.pl-10 { + padding-left: 96px !important +} + +.py-10 { + padding-top: 96px !important; + padding-bottom: 96px !important +} + +.p-11 { + padding: 112px !important +} + +.pt-11 { + padding-top: 112px !important +} + +.pr-11 { + padding-right: 112px !important +} + +.pb-11 { + padding-bottom: 112px !important +} + +.pl-11 { + padding-left: 112px !important +} + +.py-11 { + padding-top: 112px !important; + padding-bottom: 112px !important +} + +.p-12 { + padding: 128px !important +} + +.pt-12 { + padding-top: 128px !important +} + +.pr-12 { + padding-right: 128px !important +} + +.pb-12 { + padding-bottom: 128px !important +} + +.pl-12 { + padding-left: 128px !important +} + +.py-12 { + padding-top: 128px !important; + padding-bottom: 128px !important +} + +@media (min-width: 544px) { + .p-sm-0 { + padding: 0 !important + } + .pt-sm-0 { + padding-top: 0 !important + } + .pr-sm-0 { + padding-right: 0 !important + } + .pb-sm-0 { + padding-bottom: 0 !important + } + .pl-sm-0 { + padding-left: 0 !important + } + .py-sm-0 { + padding-top: 0 !important; + padding-bottom: 0 !important + } + .p-sm-1 { + padding: 4px !important + } + .pt-sm-1 { + padding-top: 4px !important + } + .pr-sm-1 { + padding-right: 4px !important + } + .pb-sm-1 { + padding-bottom: 4px !important + } + .pl-sm-1 { + padding-left: 4px !important + } + .py-sm-1 { + padding-top: 4px !important; + padding-bottom: 4px !important + } + .p-sm-2 { + padding: 8px !important + } + .pt-sm-2 { + padding-top: 8px !important + } + .pr-sm-2 { + padding-right: 8px !important + } + .pb-sm-2 { + padding-bottom: 8px !important + } + .pl-sm-2 { + padding-left: 8px !important + } + .py-sm-2 { + padding-top: 8px !important; + padding-bottom: 8px !important + } + .p-sm-3 { + padding: 16px !important + } + .pt-sm-3 { + padding-top: 16px !important + } + .pr-sm-3 { + padding-right: 16px !important + } + .pb-sm-3 { + padding-bottom: 16px !important + } + .pl-sm-3 { + padding-left: 16px !important + } + .py-sm-3 { + padding-top: 16px !important; + padding-bottom: 16px !important + } + .p-sm-4 { + padding: 24px !important + } + .pt-sm-4 { + padding-top: 24px !important + } + .pr-sm-4 { + padding-right: 24px !important + } + .pb-sm-4 { + padding-bottom: 24px !important + } + .pl-sm-4 { + padding-left: 24px !important + } + .py-sm-4 { + padding-top: 24px !important; + padding-bottom: 24px !important + } + .p-sm-5 { + padding: 32px !important + } + .pt-sm-5 { + padding-top: 32px !important + } + .pr-sm-5 { + padding-right: 32px !important + } + .pb-sm-5 { + padding-bottom: 32px !important + } + .pl-sm-5 { + padding-left: 32px !important + } + .py-sm-5 { + padding-top: 32px !important; + padding-bottom: 32px !important + } + .p-sm-6 { + padding: 40px !important + } + .pt-sm-6 { + padding-top: 40px !important + } + .pr-sm-6 { + padding-right: 40px !important + } + .pb-sm-6 { + padding-bottom: 40px !important + } + .pl-sm-6 { + padding-left: 40px !important + } + .py-sm-6 { + padding-top: 40px !important; + padding-bottom: 40px !important + } + .p-sm-7 { + padding: 48px !important + } + .pt-sm-7 { + padding-top: 48px !important + } + .pr-sm-7 { + padding-right: 48px !important + } + .pb-sm-7 { + padding-bottom: 48px !important + } + .pl-sm-7 { + padding-left: 48px !important + } + .py-sm-7 { + padding-top: 48px !important; + padding-bottom: 48px !important + } + .p-sm-8 { + padding: 64px !important + } + .pt-sm-8 { + padding-top: 64px !important + } + .pr-sm-8 { + padding-right: 64px !important + } + .pb-sm-8 { + padding-bottom: 64px !important + } + .pl-sm-8 { + padding-left: 64px !important + } + .py-sm-8 { + padding-top: 64px !important; + padding-bottom: 64px !important + } + .p-sm-9 { + padding: 80px !important + } + .pt-sm-9 { + padding-top: 80px !important + } + .pr-sm-9 { + padding-right: 80px !important + } + .pb-sm-9 { + padding-bottom: 80px !important + } + .pl-sm-9 { + padding-left: 80px !important + } + .py-sm-9 { + padding-top: 80px !important; + padding-bottom: 80px !important + } + .p-sm-10 { + padding: 96px !important + } + .pt-sm-10 { + padding-top: 96px !important + } + .pr-sm-10 { + padding-right: 96px !important + } + .pb-sm-10 { + padding-bottom: 96px !important + } + .pl-sm-10 { + padding-left: 96px !important + } + .py-sm-10 { + padding-top: 96px !important; + padding-bottom: 96px !important + } + .p-sm-11 { + padding: 112px !important + } + .pt-sm-11 { + padding-top: 112px !important + } + .pr-sm-11 { + padding-right: 112px !important + } + .pb-sm-11 { + padding-bottom: 112px !important + } + .pl-sm-11 { + padding-left: 112px !important + } + .py-sm-11 { + padding-top: 112px !important; + padding-bottom: 112px !important + } + .p-sm-12 { + padding: 128px !important + } + .pt-sm-12 { + padding-top: 128px !important + } + .pr-sm-12 { + padding-right: 128px !important + } + .pb-sm-12 { + padding-bottom: 128px !important + } + .pl-sm-12 { + padding-left: 128px !important + } + .py-sm-12 { + padding-top: 128px !important; + padding-bottom: 128px !important + } +} + +@media (min-width: 768px) { + .p-md-0 { + padding: 0 !important + } + .pt-md-0 { + padding-top: 0 !important + } + .pr-md-0 { + padding-right: 0 !important + } + .pb-md-0 { + padding-bottom: 0 !important + } + .pl-md-0 { + padding-left: 0 !important + } + .py-md-0 { + padding-top: 0 !important; + padding-bottom: 0 !important + } + .p-md-1 { + padding: 4px !important + } + .pt-md-1 { + padding-top: 4px !important + } + .pr-md-1 { + padding-right: 4px !important + } + .pb-md-1 { + padding-bottom: 4px !important + } + .pl-md-1 { + padding-left: 4px !important + } + .py-md-1 { + padding-top: 4px !important; + padding-bottom: 4px !important + } + .p-md-2 { + padding: 8px !important + } + .pt-md-2 { + padding-top: 8px !important + } + .pr-md-2 { + padding-right: 8px !important + } + .pb-md-2 { + padding-bottom: 8px !important + } + .pl-md-2 { + padding-left: 8px !important + } + .py-md-2 { + padding-top: 8px !important; + padding-bottom: 8px !important + } + .p-md-3 { + padding: 16px !important + } + .pt-md-3 { + padding-top: 16px !important + } + .pr-md-3 { + padding-right: 16px !important + } + .pb-md-3 { + padding-bottom: 16px !important + } + .pl-md-3 { + padding-left: 16px !important + } + .py-md-3 { + padding-top: 16px !important; + padding-bottom: 16px !important + } + .p-md-4 { + padding: 24px !important + } + .pt-md-4 { + padding-top: 24px !important + } + .pr-md-4 { + padding-right: 24px !important + } + .pb-md-4 { + padding-bottom: 24px !important + } + .pl-md-4 { + padding-left: 24px !important + } + .py-md-4 { + padding-top: 24px !important; + padding-bottom: 24px !important + } + .p-md-5 { + padding: 32px !important + } + .pt-md-5 { + padding-top: 32px !important + } + .pr-md-5 { + padding-right: 32px !important + } + .pb-md-5 { + padding-bottom: 32px !important + } + .pl-md-5 { + padding-left: 32px !important + } + .py-md-5 { + padding-top: 32px !important; + padding-bottom: 32px !important + } + .p-md-6 { + padding: 40px !important + } + .pt-md-6 { + padding-top: 40px !important + } + .pr-md-6 { + padding-right: 40px !important + } + .pb-md-6 { + padding-bottom: 40px !important + } + .pl-md-6 { + padding-left: 40px !important + } + .py-md-6 { + padding-top: 40px !important; + padding-bottom: 40px !important + } + .p-md-7 { + padding: 48px !important + } + .pt-md-7 { + padding-top: 48px !important + } + .pr-md-7 { + padding-right: 48px !important + } + .pb-md-7 { + padding-bottom: 48px !important + } + .pl-md-7 { + padding-left: 48px !important + } + .py-md-7 { + padding-top: 48px !important; + padding-bottom: 48px !important + } + .p-md-8 { + padding: 64px !important + } + .pt-md-8 { + padding-top: 64px !important + } + .pr-md-8 { + padding-right: 64px !important + } + .pb-md-8 { + padding-bottom: 64px !important + } + .pl-md-8 { + padding-left: 64px !important + } + .py-md-8 { + padding-top: 64px !important; + padding-bottom: 64px !important + } + .p-md-9 { + padding: 80px !important + } + .pt-md-9 { + padding-top: 80px !important + } + .pr-md-9 { + padding-right: 80px !important + } + .pb-md-9 { + padding-bottom: 80px !important + } + .pl-md-9 { + padding-left: 80px !important + } + .py-md-9 { + padding-top: 80px !important; + padding-bottom: 80px !important + } + .p-md-10 { + padding: 96px !important + } + .pt-md-10 { + padding-top: 96px !important + } + .pr-md-10 { + padding-right: 96px !important + } + .pb-md-10 { + padding-bottom: 96px !important + } + .pl-md-10 { + padding-left: 96px !important + } + .py-md-10 { + padding-top: 96px !important; + padding-bottom: 96px !important + } + .p-md-11 { + padding: 112px !important + } + .pt-md-11 { + padding-top: 112px !important + } + .pr-md-11 { + padding-right: 112px !important + } + .pb-md-11 { + padding-bottom: 112px !important + } + .pl-md-11 { + padding-left: 112px !important + } + .py-md-11 { + padding-top: 112px !important; + padding-bottom: 112px !important + } + .p-md-12 { + padding: 128px !important + } + .pt-md-12 { + padding-top: 128px !important + } + .pr-md-12 { + padding-right: 128px !important + } + .pb-md-12 { + padding-bottom: 128px !important + } + .pl-md-12 { + padding-left: 128px !important + } + .py-md-12 { + padding-top: 128px !important; + padding-bottom: 128px !important + } +} + +@media (min-width: 1012px) { + .p-lg-0 { + padding: 0 !important + } + .pt-lg-0 { + padding-top: 0 !important + } + .pr-lg-0 { + padding-right: 0 !important + } + .pb-lg-0 { + padding-bottom: 0 !important + } + .pl-lg-0 { + padding-left: 0 !important + } + .py-lg-0 { + padding-top: 0 !important; + padding-bottom: 0 !important + } + .p-lg-1 { + padding: 4px !important + } + .pt-lg-1 { + padding-top: 4px !important + } + .pr-lg-1 { + padding-right: 4px !important + } + .pb-lg-1 { + padding-bottom: 4px !important + } + .pl-lg-1 { + padding-left: 4px !important + } + .py-lg-1 { + padding-top: 4px !important; + padding-bottom: 4px !important + } + .p-lg-2 { + padding: 8px !important + } + .pt-lg-2 { + padding-top: 8px !important + } + .pr-lg-2 { + padding-right: 8px !important + } + .pb-lg-2 { + padding-bottom: 8px !important + } + .pl-lg-2 { + padding-left: 8px !important + } + .py-lg-2 { + padding-top: 8px !important; + padding-bottom: 8px !important + } + .p-lg-3 { + padding: 16px !important + } + .pt-lg-3 { + padding-top: 16px !important + } + .pr-lg-3 { + padding-right: 16px !important + } + .pb-lg-3 { + padding-bottom: 16px !important + } + .pl-lg-3 { + padding-left: 16px !important + } + .py-lg-3 { + padding-top: 16px !important; + padding-bottom: 16px !important + } + .p-lg-4 { + padding: 24px !important + } + .pt-lg-4 { + padding-top: 24px !important + } + .pr-lg-4 { + padding-right: 24px !important + } + .pb-lg-4 { + padding-bottom: 24px !important + } + .pl-lg-4 { + padding-left: 24px !important + } + .py-lg-4 { + padding-top: 24px !important; + padding-bottom: 24px !important + } + .p-lg-5 { + padding: 32px !important + } + .pt-lg-5 { + padding-top: 32px !important + } + .pr-lg-5 { + padding-right: 32px !important + } + .pb-lg-5 { + padding-bottom: 32px !important + } + .pl-lg-5 { + padding-left: 32px !important + } + .py-lg-5 { + padding-top: 32px !important; + padding-bottom: 32px !important + } + .p-lg-6 { + padding: 40px !important + } + .pt-lg-6 { + padding-top: 40px !important + } + .pr-lg-6 { + padding-right: 40px !important + } + .pb-lg-6 { + padding-bottom: 40px !important + } + .pl-lg-6 { + padding-left: 40px !important + } + .py-lg-6 { + padding-top: 40px !important; + padding-bottom: 40px !important + } + .p-lg-7 { + padding: 48px !important + } + .pt-lg-7 { + padding-top: 48px !important + } + .pr-lg-7 { + padding-right: 48px !important + } + .pb-lg-7 { + padding-bottom: 48px !important + } + .pl-lg-7 { + padding-left: 48px !important + } + .py-lg-7 { + padding-top: 48px !important; + padding-bottom: 48px !important + } + .p-lg-8 { + padding: 64px !important + } + .pt-lg-8 { + padding-top: 64px !important + } + .pr-lg-8 { + padding-right: 64px !important + } + .pb-lg-8 { + padding-bottom: 64px !important + } + .pl-lg-8 { + padding-left: 64px !important + } + .py-lg-8 { + padding-top: 64px !important; + padding-bottom: 64px !important + } + .p-lg-9 { + padding: 80px !important + } + .pt-lg-9 { + padding-top: 80px !important + } + .pr-lg-9 { + padding-right: 80px !important + } + .pb-lg-9 { + padding-bottom: 80px !important + } + .pl-lg-9 { + padding-left: 80px !important + } + .py-lg-9 { + padding-top: 80px !important; + padding-bottom: 80px !important + } + .p-lg-10 { + padding: 96px !important + } + .pt-lg-10 { + padding-top: 96px !important + } + .pr-lg-10 { + padding-right: 96px !important + } + .pb-lg-10 { + padding-bottom: 96px !important + } + .pl-lg-10 { + padding-left: 96px !important + } + .py-lg-10 { + padding-top: 96px !important; + padding-bottom: 96px !important + } + .p-lg-11 { + padding: 112px !important + } + .pt-lg-11 { + padding-top: 112px !important + } + .pr-lg-11 { + padding-right: 112px !important + } + .pb-lg-11 { + padding-bottom: 112px !important + } + .pl-lg-11 { + padding-left: 112px !important + } + .py-lg-11 { + padding-top: 112px !important; + padding-bottom: 112px !important + } + .p-lg-12 { + padding: 128px !important + } + .pt-lg-12 { + padding-top: 128px !important + } + .pr-lg-12 { + padding-right: 128px !important + } + .pb-lg-12 { + padding-bottom: 128px !important + } + .pl-lg-12 { + padding-left: 128px !important + } + .py-lg-12 { + padding-top: 128px !important; + padding-bottom: 128px !important + } +} + +@media (min-width: 1280px) { + .p-xl-0 { + padding: 0 !important + } + .pt-xl-0 { + padding-top: 0 !important + } + .pr-xl-0 { + padding-right: 0 !important + } + .pb-xl-0 { + padding-bottom: 0 !important + } + .pl-xl-0 { + padding-left: 0 !important + } + .py-xl-0 { + padding-top: 0 !important; + padding-bottom: 0 !important + } + .p-xl-1 { + padding: 4px !important + } + .pt-xl-1 { + padding-top: 4px !important + } + .pr-xl-1 { + padding-right: 4px !important + } + .pb-xl-1 { + padding-bottom: 4px !important + } + .pl-xl-1 { + padding-left: 4px !important + } + .py-xl-1 { + padding-top: 4px !important; + padding-bottom: 4px !important + } + .p-xl-2 { + padding: 8px !important + } + .pt-xl-2 { + padding-top: 8px !important + } + .pr-xl-2 { + padding-right: 8px !important + } + .pb-xl-2 { + padding-bottom: 8px !important + } + .pl-xl-2 { + padding-left: 8px !important + } + .py-xl-2 { + padding-top: 8px !important; + padding-bottom: 8px !important + } + .p-xl-3 { + padding: 16px !important + } + .pt-xl-3 { + padding-top: 16px !important + } + .pr-xl-3 { + padding-right: 16px !important + } + .pb-xl-3 { + padding-bottom: 16px !important + } + .pl-xl-3 { + padding-left: 16px !important + } + .py-xl-3 { + padding-top: 16px !important; + padding-bottom: 16px !important + } + .p-xl-4 { + padding: 24px !important + } + .pt-xl-4 { + padding-top: 24px !important + } + .pr-xl-4 { + padding-right: 24px !important + } + .pb-xl-4 { + padding-bottom: 24px !important + } + .pl-xl-4 { + padding-left: 24px !important + } + .py-xl-4 { + padding-top: 24px !important; + padding-bottom: 24px !important + } + .p-xl-5 { + padding: 32px !important + } + .pt-xl-5 { + padding-top: 32px !important + } + .pr-xl-5 { + padding-right: 32px !important + } + .pb-xl-5 { + padding-bottom: 32px !important + } + .pl-xl-5 { + padding-left: 32px !important + } + .py-xl-5 { + padding-top: 32px !important; + padding-bottom: 32px !important + } + .p-xl-6 { + padding: 40px !important + } + .pt-xl-6 { + padding-top: 40px !important + } + .pr-xl-6 { + padding-right: 40px !important + } + .pb-xl-6 { + padding-bottom: 40px !important + } + .pl-xl-6 { + padding-left: 40px !important + } + .py-xl-6 { + padding-top: 40px !important; + padding-bottom: 40px !important + } + .p-xl-7 { + padding: 48px !important + } + .pt-xl-7 { + padding-top: 48px !important + } + .pr-xl-7 { + padding-right: 48px !important + } + .pb-xl-7 { + padding-bottom: 48px !important + } + .pl-xl-7 { + padding-left: 48px !important + } + .py-xl-7 { + padding-top: 48px !important; + padding-bottom: 48px !important + } + .p-xl-8 { + padding: 64px !important + } + .pt-xl-8 { + padding-top: 64px !important + } + .pr-xl-8 { + padding-right: 64px !important + } + .pb-xl-8 { + padding-bottom: 64px !important + } + .pl-xl-8 { + padding-left: 64px !important + } + .py-xl-8 { + padding-top: 64px !important; + padding-bottom: 64px !important + } + .p-xl-9 { + padding: 80px !important + } + .pt-xl-9 { + padding-top: 80px !important + } + .pr-xl-9 { + padding-right: 80px !important + } + .pb-xl-9 { + padding-bottom: 80px !important + } + .pl-xl-9 { + padding-left: 80px !important + } + .py-xl-9 { + padding-top: 80px !important; + padding-bottom: 80px !important + } + .p-xl-10 { + padding: 96px !important + } + .pt-xl-10 { + padding-top: 96px !important + } + .pr-xl-10 { + padding-right: 96px !important + } + .pb-xl-10 { + padding-bottom: 96px !important + } + .pl-xl-10 { + padding-left: 96px !important + } + .py-xl-10 { + padding-top: 96px !important; + padding-bottom: 96px !important + } + .p-xl-11 { + padding: 112px !important + } + .pt-xl-11 { + padding-top: 112px !important + } + .pr-xl-11 { + padding-right: 112px !important + } + .pb-xl-11 { + padding-bottom: 112px !important + } + .pl-xl-11 { + padding-left: 112px !important + } + .py-xl-11 { + padding-top: 112px !important; + padding-bottom: 112px !important + } + .p-xl-12 { + padding: 128px !important + } + .pt-xl-12 { + padding-top: 128px !important + } + .pr-xl-12 { + padding-right: 128px !important + } + .pb-xl-12 { + padding-bottom: 128px !important + } + .pl-xl-12 { + padding-left: 128px !important + } + .py-xl-12 { + padding-top: 128px !important; + padding-bottom: 128px !important + } +} + +/*# sourceMappingURL=primer.css.map */ \ No newline at end of file diff --git a/docs/language/global-sphinx-files/_templates/layout.html b/docs/language/global-sphinx-files/_templates/layout.html index 2c9efa4fe095..d064b4fe6b8d 100644 --- a/docs/language/global-sphinx-files/_templates/layout.html +++ b/docs/language/global-sphinx-files/_templates/layout.html @@ -1,10 +1,9 @@ {# - Override alabaster/layout.html template to add a header - with the Semmle logo. - This header (including the SVG logo) is copied from the Semmle - documentation home page at help.semmle.com. - - It also adds some JavaScript (in the footer) to allow collapsible sections. + Override alabaster/layout.html template to customize the template + used to generate the CodeQL documentation. + + The classes used in this template are provided by the GitHub Primer https://primer.style/css/. + The CSS for the primer can be found at https://unpkg.com/@primer/css/dist/primer.css The source for the default Alabaster stylesheet can be found at: https://github.com/bitprophet/alabaster/blob/master/alabaster/layout.html @@ -12,116 +11,179 @@ {%- extends "alabaster/layout.html" %} +{%- macro customrelbar() %} + +{%- endmacro %} + {%- block extrahead %} - - - - {{ super() }} - - {% if theme_touch_icon %} - - {% endif %} - {% if theme_canonical_url %} - - {% endif %} - + +CodeQL docs + + + + {% endblock %} {%- block content %} - - - -
    -
    - -